tomcat-connectors-1.2.50-src/0000755000000000000020000000000014655113621014317 5ustar rootbintomcat-connectors-1.2.50-src/README.txt0000644000000000000020000000232614655113617016025 0ustar rootbin Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Building the Web Server Connectors ================================== 1) Install the web server 2) Go to the "native" subdirectory cd native 3) Proceed with the instructions in BUILDING.txt. Building the Docs ================= 1) Make sure you have Java and "ant" installed and "ant" is found in your PATH 2) Go to the "xdocs" subdirectory cd xdocs 3) Call "ant" ant 4) The resulting documentation can be in the directory build/docs. tomcat-connectors-1.2.50-src/conf/0000755000000000000020000000000014655113621015244 5ustar rootbintomcat-connectors-1.2.50-src/conf/workers.properties0000644000000000000020000001351314655113617021066 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Note that the distributed version of this file requires modification # before it is usable. # # Reference documentation: http://tomcat.apache.org/connectors-doc/reference/workers.html # # As a general note, the characters $( and ) are used to reference # property values in other properties. # # Whenever you see a set of lines such as: # x=value # y=$(x)othervalue # # the final value for y will be "valueothervalue" # Define two status worker: # - jk-status for read-only use # - jk-manager for read/write use worker.list=jk-status worker.jk-status.type=status worker.jk-status.read_only=true worker.list=jk-manager worker.jk-manager.type=status # We define a load balancer worker # with name "balancer" worker.list=balancer worker.balancer.type=lb # error_escalation_time: seconds, default = recover_time/2 (=30) # Determines, how fast a detected error should switch from # local error state to global error state # Since: 1.2.28 worker.balancer.error_escalation_time=0 # - max_reply_timeouts: number, default=0 # If there are to many reply timeouts, a worker # is put into the error state, i.e. it will become # unavailable for all sessions residing on the respective # Tomcat. The number of tolerated reply timeouts is # configured with max_reply_timeouts. The number of # timeouts occuring is divided by 2 once a minute and the # resulting counter is compared against max_reply_timeouts. # If you set max_reply_timeouts to N and the errors are # occuring equally distributed over time, you will # tolerate N/2 errors per minute. If they occur in a burst # you will tolerate N errors. # Since: 1.2.24 worker.balancer.max_reply_timeouts=10 # Now we add members to the load balancer # First member is "node1", most # attributes are inherited from the # template "worker.template". worker.balancer.balance_workers=node1 worker.node1.reference=worker.template worker.node1.host=localhost worker.node1.port=8109 # Activation allows to configure # whether this node should actually be used # A: active (use node fully) # D: disabled (only use, if sticky session needs this node) # S: stopped (do not use) # Since: 1.2.19 worker.node1.activation=A # Second member is "node2", most # attributes are inherited from the # template "worker.template". worker.balancer.balance_workers=node2 worker.node2.reference=worker.template worker.node2.host=localhost worker.node2.port=8209 # Activation allows to configure # whether this node should actually be used # A: active (use node fully) # D: disabled (only use, if sticky session needs this node) # S: stopped (do not use) # Since: 1.2.19 worker.node2.activation=A # Finally we put the parameters # which should apply to all our ajp13 # workers into the referenced template # - Type is ajp13 worker.template.type=ajp13 # - socket_connect_timeout: milliseconds, default=0 # Since: 1.2.27 worker.template.socket_connect_timeout=5000 # - socket_keepalive: boolean, default=false # Should we send TCP keepalive packets # when connection is idle (socket option)? worker.template.socket_keepalive=true # - ping_mode: Character, default=none # When should we use cping/cpong connection probing? # C = directly after establishing a new connection # P = directly before sending each request # I = in regular intervals for idle connections # using the watchdog thread # A = all of the above # Since: 1.2.27 worker.template.ping_mode=A # - ping_timeout: milliseconds, default=10000 # Wait timeout for cpong after cping # Can be overwritten for modes C and P # Using connect_timeout and prepost_timeout. # Since: 1.2.27 worker.template.ping_timeout=10000 # - connection_pool_minsize: number, default=connection_pool_size # Lower pool size when shrinking pool due # to idle connections # We want all connections to be closed when # idle for a long time in order to prevent # firewall problems. # Since: 1.2.16 worker.template.connection_pool_minsize=0 # - connection_pool_timeout: seconds, default=0 # Idle time, before a connection is eligible # for being closed (pool shrinking). # This should be the same value as keepAliveTimeout # (if it is set explicitly) or connectionTimeout # in the Tomcat AJP connector, but there it is # milliseconds, here seconds. worker.template.connection_pool_timeout=600 # - reply_timeout: milliseconds, default=0 # Any pause longer than this timeout during waiting # for a part of the reply will abort handling the request # in mod_jk. The request will proceed running in # Tomcat, but the web server resources will be freed # and an error is send to the client. # For individual requests, the timeout can be overwritten # by the Apache environment variable JK_REPLY_TIMEOUT. # JK_REPLY_TIMEOUT since: 1.2.27 worker.template.reply_timeout=300000 # - recovery_options: number, default=0 # Bit mask to configure, if a request, which was send # to a backend successfully, should be retried on another backend # in case there's a problem with the response. # Value "3" disables retries, whenever a part of the request was # successfully send to the backend. worker.template.recovery_options=3 tomcat-connectors-1.2.50-src/conf/httpd-jk.conf0000644000000000000020000001147414655113617017654 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Configuration Example for mod_jk # used in combination with Apache 2.2.x # Change the path and file name of the module, in case # you have installed it outside of httpd, or using # a versioned file name. LoadModule jk_module modules/mod_jk.so # We need a workers file exactly once # and in the global server JkWorkersFile conf/workers.properties # Our JK error log # You can (and should) use rotatelogs here JkLogFile logs/mod_jk.log # Our JK log level (trace,debug,info,warn,error) JkLogLevel info # Our JK shared memory file JkShmFile logs/mod_jk.shm # Define a new log format you can use in any CustomLog in order # to add mod_jk specific information to your access log. # LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" \"%{Set-Cookie}o\" %{pid}P %{tid}P %{JK_LB_FIRST_NAME}n %{JK_LB_LAST_NAME}n ACC %{JK_LB_LAST_ACCESSED}n ERR %{JK_LB_LAST_ERRORS}n BSY %{JK_LB_LAST_BUSY}n %{JK_LB_LAST_STATE}n %D" extended_jk # This option will reject all requests, which contain an # encoded percent sign (%25) or backslash (%5C) in the URL # If you are sure, that your webapp doesn't use such # URLs, enable the option to prevent double encoding attacks. # Since: 1.2.24 # JkOptions +RejectUnsafeURI # After setting JkStripSession to "On", mod_jk will # strip all ";jsessionid=..." from request URLs it # does *not* forward to a backend. # This is useful, if all links in a webapp use # URLencoded session IDs and parts of the static # content should be delivered directly by Apache. # Of course you can also do it with mod_rewrite. # Since: 1.2.21 # JkStripSession On # Start a separate thread for internal tasks like # idle connection probing, connection pool resizing # and load value decay. # Run these tasks every JkWatchdogInterval seconds. # Since: 1.2.27 JkWatchdogInterval 60 # Configure access to jk-status and jk-manager # If you want to make this available in a virtual host, # either move this block into the virtual host # or copy it logically there by including "JkMountCopy On" # in the virtual host. # Add an appropriate authentication method here! # Inside Location we can omit the URL in JkMount JkMount jk-status Require ip 127.0.0.1 # Inside Location we can omit the URL in JkMount JkMount jk-manager Require ip 127.0.0.1 # If you want to put all mounts into an external file # that gets reloaded automatically after changes # (with a default latency of 1 minute), # you can define the name of the file here. # JkMountFile conf/extra/uriworkermap.properties # Example for Mounting a context to the worker "balancer" # The URL syntax "a|b" instantiates two mounts at once, # the first one is "a", the second one is "ab". # JkMount /myapp|/* balancer # Example for UnMounting requests for all workers # using a simple URL pattern # Since: 1.2.26 # JkUnMount /myapp/static/* * # Example for UnMounting requests for a named worker # JkUnMount /myapp/images/* balancer # Example for UnMounting requests using regexps # SetEnvIf REQUEST_URI "\.(htm|html|css|gif|jpg|js)$" no-jk # Example for setting a reply timeout depending on the request URL # Since: 1.2.27 # SetEnvIf Request_URI "/transactions/" JK_REPLY_TIMEOUT=600000 # Example for disabling reply timeouts for certain request URLs # Since: 1.2.27 # SetEnvIf Request_URI "/reports/" JK_REPLY_TIMEOUT=0 # IMPORTANT: Mounts and virtual hosts # If you are using VirtualHost elements, you # - can put mounts only used in some virtual host into its VirtualHost element # - can copy all global mounts to it using "JkMountCopy On" inside the VirtualHost # - can copy all global mounts to all virtual hosts by putting # "JkMountCopy All" into the global server # Since: 1.2.26 tomcat-connectors-1.2.50-src/conf/uriworkermap.properties0000644000000000000020000000266514655113617022127 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # uriworkermap.properties # # Use for IIS or with the Apache web server as an alternative # to JkMount and JkUnmount # # This file provides sample mappings for the example # worker "balancer" defined in workermap.properties. # The general syntax for this file is: # [URL]=[Worker name] /admin/*=balancer /manager/*=balancer /examples/*=balancer # Optionally filter out all .jpg files inside that context # For no mapping the url has to start with exclamation mark (!) !/examples/*.jpg=balancer # # Mount jk status and manager # For production servers you will need to # secure the access to the /jk-manager and # /jk-status urls # /jk-manager=jk-manager /jk-status=jk-status tomcat-connectors-1.2.50-src/NOTICE0000644000000000000020000000070714655113617015234 0ustar rootbinApache Tomcat Connectors Copyright 2002-2024 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). This software contains code derived from UNIX V7, Copyright(C) Caldera International Inc. The ISAPI Redirector component of this software uses and bundles the PCRE library which is under a BSD license. For copyright notices and license details see the file iis/pcre/LICENCE. tomcat-connectors-1.2.50-src/LICENSE0000644000000000000020000003243514655113617015340 0ustar rootbin Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. TOMCAT CONNECTORS SUBCOMPONENTS: The Tomcat Connectors includes a number of subcomponents with separate copyright notices and license terms. Your use of the source code for the these subcomponents is subject to the terms and conditions of the following licenses. From native/common/ap_snprintf.c: * * cvt - IEEE floating point formatting routines. * Derived from UNIX V7, Copyright(C) Caldera International Inc. * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code and documentation must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed or owned by Caldera International, Inc. Neither the name of Caldera International, Inc. nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. 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. tomcat-connectors-1.2.50-src/HOWTO-RELEASE.txt0000644000000000000020000001507614655113617017054 0ustar rootbin Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. How to do a mod_jk 1.2 Release ============================== Clone a clean copy of tomcat/connectors from git to make sure you don't have any lingering configure or build files. This will make sure that the source distribution created is clean. We assume, that you cloned out git@github.com:apache/tomcat-connectors.git to a directory named mod_jk. All further path names will be relative to this directory. If you haven't already, add your public PGP key to KEYS. Add a preliminary note about the new release to the docs -------------------------------------------------------- Candidate pages are: xdocs/index.xml xdocs/news/.xml We can't add a final release date though. Update version numbers as needed -------------------------------- Do a find for all the docs which include the previous version string and replace it with the new version. These are the docs I found which had to be updated: native/iis/README xdocs/build.xml xdocs/index.xml xdocs/news/.xml tools/dist/README.html tools/dist/binaries/windows/README.html Check version numbers in the files that are listed in the section "Update source for next version" below: native/configure.ac native/common/jk_version.h xdocs/miscellaneous/changelog.xml After updating revision numbers, commit your changes to git. Tag tomcat-connectors in git ---------------------------- Use the pattern below for tagging the tomcat-connectors directory. TAG=JK_{MAJOR_REVISION}_{MINOR_REVISION}_{RELEASE} Here is an example for mod_jk 1.2.50 git commit -a -m "Tag JK_1_2_50" git tag JK_1_2_50 git push origin JK_1_2_50 # reset main Build the mod_jk 1.2 documentation ---------------------------------- cd xdocs ant After checking the documentation carefully (produced in build/docs), see https://svn.apache.org/viewvc/tomcat/site/trunk/README.txt?view=markup for instructions on how to deploy the site docs. Create the new source distribution ---------------------------------- A tool named jkrelease.sh in the directory tools creates a release tarball and a zip including signature files. Here is an example for mod_jk 1.2.50 ./jkrelease.sh -R git -v 1.2.50 -h Upload source distribution and documentation to www.apache.org ------------------------------------------------------------------- First update the KEYS on the server if you have added a new pgp key. scp KEYS to the /www/www.apache.org/dist/tomcat/tomcat-connectors directory on the people.apache.org server. scp tomcat-connectors-1.2.29-src.tar.gz* to /www/www.apache.org/dist/tomcat/tomcat-connectors/jk/source scp tomcat-connectors-1.2.29-src.zip* to /www/www.apache.org/dist/tomcat/tomcat-connectors/jk/source ssh to people.apache.org and cd to the /www/www.apache.org/dist/tomcat/tomcat-connectors/jk directory. Modify README.html and update it to the current version. Remove the symlinks for current if present and replace them with a soft link to the new source distribution files. ln -s source/tomcat-connectors-1.2.29-src.tar.gz tomcat-connectors-src-current.tar.gz ln -s source/tomcat-connectors-1.2.29-src.tar.gz.asc tomcat-connectors-src-current.tar.gz.asc ln -s source/tomcat-connectors-1.2.29-src.tar.zip tomcat-connectors-src-current.zip ln -s source/tomcat-connectors-1.2.29-src.zip.asc tomcat-connectors-src-current.zip.asc Make sure the group write bit is set on all files and directories in the jk directory. chmod -R g+w /www/www.apache.org/dist/tomcat/tomcat-connectors/jk Build binaries and upload distributions to www.apache.org -------------------------------------------------------------- Build mod_jk for a specific web server and OS. Package it as appropriate for the OS and sign the archive using PGP. Please include the ASF License, the generated docs, and the tools. Please name the distribution as follows: tomcat-connectors-{version}-{os-version-cpu}-{web server-version}.(tar.gz|zip) scp the binary distribution and pgp signature file to the appropriate binaries/{os} directory. Make sure the group write bit is on for all files you upload. Update source for next version ------------------------------ native/configure.ac: Update version in AC_INIT macro. native/common/jk_version.h: Update variables JK_VERMAJOR, JK_VERMINOR, JK_VERFIX, JK_VERSTRING, and JK_VERISRELEASE. xdocs/miscellaneous/changelog.xml: Start a new section for the new version. Remove old release distributions from www.apache.org ---------------------------------------------------- Verify that the old versions of the source and binary distributions are available at /www/archive.apache.org/dist/tomcat/tomcat-connectors/jk . Copy old source distributions and binaries as needed, then remove the old source and binary distributions. Arrange the downloads_tomcat-connectors.cgi ------------------------------------------- Check tomcat-site out: svn co https://svn.apache.org/repos/asf/tomcat/site site-tomcat Arrange the file: xdocs/download-connectors.xml, updating all occurrences of the version number to the just released version. Update xdocs/index.xml to reflect the new release of Tomcat Connectors. Run ant from the site-tomcat directory to regenerate the corresponding html file: docs/site/download-connectors.html Commit it after checking carefully the changes. Connect to people.apache.org and update the tomcat.apache.org site image, the site tomcat.apache.org should reflect the change after a while: cd /x1/www/tomcat.apache.org/site/downloads svn update downloads_tomcat-connectors.html Announcements ------------- The release distribution directories are mirrored so that the releases can be downloaded from multiple sites. Please wait 24 hours before sending out the announcement so that the mirrors get a chance to get the new release distributions. Send an email announcement to announce@tomcat.apache.org, users@tomcat.apache.org, dev@tomcat.apache.org and announce@apache.org. tomcat-connectors-1.2.50-src/tools/0000755000000000000020000000000014655113617015464 5ustar rootbintomcat-connectors-1.2.50-src/tools/dist/0000755000000000000020000000000014655113617016427 5ustar rootbintomcat-connectors-1.2.50-src/tools/dist/README.html0000644000000000000020000000523514655113617020257 0ustar rootbin

Download from your nearest mirror site!

Do not download from www.apache.org. Please use a mirror site to help us save apache.org bandwidth. Go here to find your nearest mirror.

Binary Releases

Are available in the binaries/ directory. Every binary distribution contains an install script. See README for details.

Current Releases

For details on current releases, please see the Apache Tomcat Connectors Download Page.

Note; the -src.zip versions of Apache Tomcat Connectors are nearly identical to the .tar.gz versions. However, they offer the source files in DOS/Windows CR/LF text format, and include the Winows build files. These -src.zip files do NOT contain binaries! See the binaries/windows/ directory for the Windows binary distributions.

Older Releases

Only current, recommended releases are available on www.apache.org and the mirror sites. Older releases can be obtained from the archive site.

PGP Signatures

All of the release distribution packages have been digitally signed (using PGP or GPG) by the Apache Tomcat Group members that constructed them. There will be an accompanying distribution.asc file in the same directory as the distribution. The PGP keys can be found at the MIT key repository and within this project's KEYS file.

Always use the signature files to verify the authenticity of the distribution, e.g.,

% pgpk -a KEYS
% pgpv tomcat-connectors-1.2.50-src.tar.gz.asc
or,
% pgp -ka KEYS
% pgp tomcat-connectors-1.2.50-src.tar.gz.asc
or,
% gpg --import KEYS
% gpg --verify tomcat-connectors-1.2.50-src.tar.gz.asc

We provide SHA512 hashes as an alternative to validate the integrity of the downloaded files. The program sha512sum is included in many unix distributions. They are also available as part of GNU Coreutils. Windows users can use Cyohash.

tomcat-connectors-1.2.50-src/tools/dist/HEADER.html0000644000000000000020000000125014655113617020243 0ustar rootbin

Index of /dist/tomcat/tomcat-connectors/jk

Apache Tomcat Connectors Source Code Distributions

This download page includes only the sources to compile and build Apache Tomcat Connectors yourself with the proper tools. Download the precompiled distribution for your platform from binaries/.

Important Notices

tomcat-connectors-1.2.50-src/tools/dist/.htaccess0000644000000000000020000000145614655113617020233 0ustar rootbin# Directives controlling the display of server-generated directory listings. IndexOptions DescriptionWidth=34 AddDescription "OpenPGP ASCII armored signature" .asc AddDescription "MD5 checksum file" .md5 AddDescription "SHA1 checksum file" .sha1 AddDescription "SHA256 checksum file" .sha256 AddDescription "ZIP compressed archive" .zip AddDescription "GZIP compressed document" .gz AddDescription "Unix tar archive" .tar AddDescription "GZIP compressed tar archive" .tgz AddDescription "plain text document" .txt AddDescription "Unified diff patch" .diff AddDescription "shared object file" .so AddDescription "dynamically linked library" .dll AddIcon /icons/generic.sec.gif .asc .key AddIcon /icons/patch.gif .diff AddIcon /icons/screw2.gif .md5 AddIcon /icons/screw2.gif .sha1 AddIcon /icons/screw2.gif .sha256 tomcat-connectors-1.2.50-src/tools/dist/binaries/0000755000000000000020000000000014655113617020223 5ustar rootbintomcat-connectors-1.2.50-src/tools/dist/binaries/windows/0000755000000000000020000000000014655113617021715 5ustar rootbintomcat-connectors-1.2.50-src/tools/dist/binaries/windows/README.html0000644000000000000020000000467414655113617023553 0ustar rootbin

Download from your nearest mirror site!

Please do not download from www.apache.org. Use a mirror site to help us save apache.org bandwidth and to speed up your download. Click here to find your nearest mirror.

Windows Users, Read These First...

Warning: TCP/IP networking must be installed

TCP/IP must be correctly installed, configured and running in order to install and use Apache Tomcat Connectors on Windows.

Warning about the Quality of Service driver

We suggest disabling the "Quality of Service" (or QoS) network driver from Microsoft if you primarily use the machine as an Web Server, as connector does not support the QoS extensions to the WinSock API.

Warning about Firewall and similar software

Most Firewall programs, Web Spam filters and other TCP/IP driver-based products (including spyware!) do not correctly implement the entire WinSock API. The shortcuts taken by the developers of such products could cause connector to fail.

The current stable release is 1.2.50

See the Apache Tomcat Connectors changelog for the complete list of features and bugs fixed in this release.

Debugging and Source Code

You can find a corresponding -symbols.zip archive of the debugging databases in the symbols/ directory, these are typically not needed. This -symbols.zip archive can be unpacked into the web server installation directory, providing all of the .pdb diagnostic files allowing most Windows debugging tools (and the Dr. Watson utility) to produce useful crash analysis.

You will find the source code package in the /dist/tomcat-connectors/jk/ source tree. The -src.zip file contains only source and build files, and contains no binary executable files.

This binary release was created with Microsoft Windows DDK 7.1, using a more recent Platform SDK.

tomcat-connectors-1.2.50-src/tools/dist/binaries/windows/HEADER.html0000644000000000000020000000070514655113617023535 0ustar rootbin

Index of /dist/tomcat/tomcat-connectors/jk/binaries/windows

Important Notices

Download from your nearest mirror site!

tomcat-connectors-1.2.50-src/tools/dist/binaries/windows/symbols/0000755000000000000020000000000014655113617023405 5ustar rootbintomcat-connectors-1.2.50-src/tools/dist/binaries/windows/symbols/README.html0000644000000000000020000000242014655113617025226 0ustar rootbin

Download from your nearest mirror site!

Binary Diagnostic Symbol Downloads

We now distribute a -symbols.zip file containing the precise debugging symbols corresponding to each released binary distribution. For the typical user, there is no need to download these archives.

These -symbols.zip packages contain the .pdb diagnostic symbol files (which correpsond to the distributed binary release) and can be used by nearly all modern Windows debugging tools, including the freely available WinDbg utility. They are most useful for the core developers to review crash dumps generated by Dr. Watson if Apache experiences a General Protection Fault. They also provide additional backtrace details in Dr. Watson crash log files, if they are installed into the Apache directory which is experiencing General Protection Fault or other crash issues.

If you don't understand a word of this, and a developer did not personally ask you to install them to help troubleshoot a problem, please trust that you do not need these files to install or run Apache Tomcat Connectors.

tomcat-connectors-1.2.50-src/tools/dist/binaries/windows/symbols/HEADER.html0000644000000000000020000000063214655113617025224 0ustar rootbin

Index of /dist/tomcat/tomcat-connectors/jk/binaries/windows/symbols

Important Notices

Download from your nearest mirror site!

tomcat-connectors-1.2.50-src/tools/lineends.pl0000755000000000000020000001201214655113617017621 0ustar rootbin#!/usr/bin/perl # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Heuristically converts line endings to the current OS's preferred format # # All existing line endings must be identical (e.g. lf's only, or even # the accedental cr.cr.lf sequence.) If some lines end lf, and others as # cr.lf, the file is presumed binary. If the cr character appears anywhere # except prefixed to an lf, the file is presumed binary. If there is no # change in the resulting file size, or the file is binary, the conversion # is discarded. # # Todo: Handle NULL stdin characters gracefully. # use strict; use IO::File; use File::Find; # The ignore list is '-' seperated, with this leading hyphen and # trailing hyphens in ever concatinated list below. my $ignore = "-"; # Image formats $ignore .= "gif-jpg-jpeg-png-ico-bmp-"; # Archive formats $ignore .= "tar-gz-z-zip-jar-war-bz2-tgz-"; # Many document formats $ignore .= "eps-psd-pdf-ai-"; # Some encodings $ignore .= "ucs2-ucs4-"; # Some binary objects $ignore .= "class-so-dll-exe-obj-a-o-lo-slo-sl-dylib-"; # Some build env files $ignore .= "mcp-xdc-ncb-opt-pdb-ilk-sbr-"; my $ignorepat = ''; my $preservedate = 1; my $forceending = 0; my $givenpaths = 0; my $notnative = 0; while (defined $ARGV[0]) { if ($ARGV[0] eq '--touch') { $preservedate = 0; } elsif ($ARGV[0] eq '--nocr') { $notnative = -1; } elsif ($ARGV[0] eq '--cr') { $notnative = 1; } elsif ($ARGV[0] eq '--force') { $forceending = 1; } elsif ($ARGV[0] eq '--FORCE') { $forceending = 2; } elsif ($ARGV[0] eq '--ignore' && $#ARGV >= 1) { shift; $ignorepat = $ARGV[0]; } elsif ($ARGV[0] =~ m/^-/) { die "What is " . $ARGV[0] . " supposed to mean?\n\n" . "Syntax:\t$0 [option()s] [path(s)]\n\n" . <<'OUTCH' Where: paths specifies the top level directory to convert (default of '.') options are; --cr keep/add one ^M --nocr remove ^M's --touch the datestamp (default: keeps date/attribs) --force mismatched corrections (unbalanced ^M's) --FORCE all files regardless of file name! --ignore PAT Do not convert files with full name matching regexp PAT OUTCH } else { find(\&totxt, $ARGV[0]); print "scanned " . $ARGV[0] . "\n"; $givenpaths = 1; } shift @ARGV; } if (!$givenpaths) { find(\&totxt, '.'); print "did .\n"; } sub totxt { my $oname = $_; my $tname = '.#' . $_; if (!-f) { return; } my @exts = split /\./; if ($forceending < 2) { if ($ignorepat ne '' && $File::Find::name =~ /$ignorepat/o) { return; } my $ext; while ($#exts && ($ext = pop(@exts))) { if ($ignore =~ m|-$ext-|i) { return; } } } my @ostat = stat($oname); my $srcfl = new IO::File $oname, "r" or die; my $dstfl = new IO::File $tname, "w" or die; my ($t, $n); binmode $srcfl; if ($notnative) { binmode $dstfl; } undef $t; while (<$srcfl>) { if (s/(\r*)\n$/\n/) { $n = length $1; if (!defined $t) { $t = $n; } if (!$forceending && (($n != $t) || m/\r/)) { print "mismatch in " .$oname. ":" .$n. " expected " .$t. "\n"; undef $t; last; } elsif ($notnative > 0) { s/\n$/\r\n/; } } print $dstfl $_; } if (defined $t && (tell $srcfl == tell $dstfl)) { undef $t; } undef $srcfl; undef $dstfl; if (defined $t) { unlink $oname or die; rename $tname, $oname or die; my @anames = ($oname); if ($preservedate) { utime $ostat[9], $ostat[9], @anames; } chmod $ostat[2] & 07777, @anames; chown $ostat[5], $ostat[6], @anames; print "Converted file " . $oname . " to text in " . $File::Find::dir . "\n"; } else { unlink $tname or die; } } tomcat-connectors-1.2.50-src/tools/reports/0000755000000000000020000000000014655113617017162 5ustar rootbintomcat-connectors-1.2.50-src/tools/reports/README.txt0000644000000000000020000000266614655113617020672 0ustar rootbin Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This directory contains perl scripts which can be used to generate statistics for tomcat requests and errors logged by mod_jk. See the comments in the scripts for more details. A great deal of statistical data is generated but at this time only long term trend graphs are being created and no reports. This is only a start. Many more graphs and reports could be generated from the data. Please consider contributing back any new reports or graphs you create. Thanks. Requires the following perl modules and libraries: GD 1.8.x graphics library http://www.boutell.com/gd/. GD 1.4.x perl module. GD Graph perl module. GD TextUtil perl module. StatisticsDescriptive perl module. tomcat-connectors-1.2.50-src/tools/reports/tomcat_reports.pl0000755000000000000020000003010414655113617022565 0ustar rootbin#!/usr/local/bin/perl # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Author: Glenn Nielsen # Script for generating reports and graphs using statistical data generated # by the tomcat_trend.pl script. # # The following graphs are created: # # tomcat_request.png # Long term trend graph of total number of tomcat requests handled # # tomcat_median.png # Long term overall trend graph of tomcat request latency median # # tomcat_deviation.png # Long term overall trend graph of tomcat request mean and standard deviation # # tomcat_error.png # Long term trend graph of requests rejected by tomcat. Shows requests rejected # when tomcat has no request processors available. Can be an indicator that tomcat # is overloaded or having other scaling problems. # # tomcat_client.png # Long term trend graph of requests forward to tomcat which were aborted by the remote # client (browser). You will normally see some aborted requests. High numbers of these # can be an indicator that tomcat is overloaded or there are requests which have very high # latency. # # tomcat_reports.pl use GD; use GD::Graph; use GD::Graph::Data; use GD::Graph::lines; use GD::Graph::linespoints; use Statistics::Descriptive; use Time::Local; # Constants %MON = ('JAN' => 0, 'Jan' => 0, 'FEB' => 1, 'Feb' => 1, 'MAR' => 2, 'Mar' => 2, 'APR' => 3, 'Apr' => 3, 'MAY' => 4, 'May' => 4, 'JUN' => 5, 'Jun' => 5, 'JUL' => 6, 'Jul' => 6, 'AUG' => 7, 'Aug' => 7, 'SEP' => 8, 'Sep' => 8, 'OCT' => 9, 'Oct' => 9, 'NOV' => 10, 'Nov' => 10, 'DEC' => 11, 'Dec' => 11,); @Months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); # Check the args $archivedir = $ARGV[0]; $reportdir = $ARGV[1]; die "Usage: $0 archivedir reportdir" unless( length($archivedir) && ($reportdir) ); die "Archive Directory $archivedir doesn't exist" unless( -d $archivedir); die "Report Directory $reportdir doesn't exist" unless( -d $reportdir); # Read in data from file die "Archive Directory $archivedir has no global.data file" unless( -e "$archivedir/global.data" ); @Data = `tail -365 $archivedir/global.data`; $numdays = $#Data; $daycounter = $numdays; foreach( @Data ) { $line = $_; chomp($line); ($date,$count,$median,$mean,$stddev,$min,$max,$client_gone,$tomcat_full) = split /\s+/,$line; # print "$daycounter $date $count $median $mean $stdev $min $max $client_gone $tomcat_full\n"; $start_time = $date unless $start_time>0; $end_time = $date; push @days,int($daycounter/7); push @count,$count; push @median,$median; push @mean,$mean; push @stddev,$mean+$stddev; push @min,$min; push @max,$max; push @client_gone,$client_gone; push @tomcat_full,$tomcat_full; $daycounter--; } ($day,$mon,$year) = (localtime($start_time))[3..5]; $year += 1900; $startdate = "$Months[$mon] $day, $year"; ($day,$mon,$year) = (localtime($end_time))[3..5]; $year += 1900; $enddate = "$Months[$mon] $day, $year"; # Output request trend graph $outfile = "$reportdir/tomcat_request.png"; unlink $outfile; $stats = Statistics::Descriptive::Sparse->new(); $stats->add_data(@count); $max = $stats->max(); $min = $stats->min(); &RequestGraph(); # Output median latency trend graph $outfile = "$reportdir/tomcat_median.png"; unlink $outfile; $stats = Statistics::Descriptive::Sparse->new(); $stats->add_data(@median); $max = $stats->max(); $min = $stats->min(); &MedianGraph(); # Output latency deviation trend graph $outfile = "$reportdir/tomcat_deviation.png"; unlink $outfile; $stats = Statistics::Descriptive::Sparse->new(); $stats->add_data(@stddev); $stats->add_data(@mean); $max = $stats->max(); $min = $stats->min(); &DeviationGraph(); # Output request error trend graph $outfile = "$reportdir/tomcat_error.png"; unlink $outfile; $stats = Statistics::Descriptive::Sparse->new(); $stats->add_data(@tomcat_full); $max = $stats->max(); $min = $stats->min(); &ErrorGraph(); # Output request error trend graph $outfile = "$reportdir/tomcat_client.png"; unlink $outfile; $stats = Statistics::Descriptive::Sparse->new(); $stats->add_data(@client_gone); $max = $stats->max(); $min = $stats->min(); &ClientGraph(); exit; sub RequestGraph { $graph = GD::Graph::lines->new(800,600); @data = (\@days,\@count); $div = 100; $div = 500 if $max >= 2000; $div = 1000 if $max >= 5000; $div = 5000 if $max >= 20000; $div = 10000 if $max >= 50000; $div = 50000 if $max >= 200000; $div = 100000 if $max >= 500000; $div = 500000 if $max >= 2000000; $div = 1000000 if $max >= 5000000; $ymax = (int($max/$div) + 1)*$div; $ymin = int($min/$div)*$div; $ytick = ($ymax - $ymin)/$div; $graph->set( y_label => 'Requests', title => "Tomcat Requests by Day from $startdate to $enddate", y_min_value => $ymin, y_max_value => $ymax, y_tick_number => $ytick, y_number_format => \&val_format, x_label => 'Weeks Ago', x_label_skip => 7, x_tick_offset => $numdays%7, dclrs => [ qw(green) ], legend_placement => 'BC' ) or warn $graph->error; $graph->set_legend( 'Requests' ); $graph->set_title_font(GD::gdGiantFont); $graph->set_x_axis_font(GD::gdSmallFont); $graph->set_y_axis_font(GD::gdSmallFont); $graph->set_legend_font(GD::gdSmallFont); $gd = $graph->plot(\@data); die "Graph Plot Failed: " . $graph->error unless defined $gd; open IMG, ">$outfile" or die $!; print IMG $gd->png or die $gd->error; close IMG; } sub MedianGraph { $graph = GD::Graph::lines->new(800,600); @data = (\@days,\@median); $div = .05; $div = .1 if $max >= .5; $div = .5 if $max >= 2; $div = 1 if $max >= 5; $div = 5 if $max >= 20; $div = 10 if $max >= 50; $div = 50 if $max >= 200; $div = 100 if $max >= 500; $ymax = (int($max/$div) + 1)*$div; $ytick = $ymax/$div; $graph->set( y_label => 'Latency (Seconds)', title => "Tomcat Request Median Latency by Day from $startdate to $enddate", y_min_value => 0, y_max_value => $ymax, y_tick_number => $ytick, y_number_format => \&val_format, x_label => 'Weeks Ago', x_label_skip => 7, x_tick_offset => $numdays%7, dclrs => [ qw(green) ], legend_placement => 'BC' ) or warn $graph->error; $graph->set_legend( 'Median' ); $graph->set_title_font(GD::gdGiantFont); $graph->set_x_axis_font(GD::gdSmallFont); $graph->set_y_axis_font(GD::gdSmallFont); $graph->set_legend_font(GD::gdSmallFont); $gd = $graph->plot(\@data); die "Graph Plot Failed: " . $graph->error unless defined $gd; open IMG, ">$outfile" or die $!; print IMG $gd->png or die $gd->error; close IMG; } sub DeviationGraph { $graph = GD::Graph::lines->new(800,600); @data = (\@days,\@mean,\@stddev); $div = .1; $div = .5 if $max >= 2; $div = 1 if $max >= 5; $div = 5 if $max >= 20; $div = 10 if $max >= 50; $div = 50 if $max >= 200; $div = 100 if $max >= 500; $ymax = (int($max/$div) + 1)*$div; $ytick = $ymax/$div; $graph->set( y_label => 'Latency (Seconds)', title => "Tomcat Request Latency Mean and Deviation by Day from $startdate to $enddate", y_max_value => $ymax, y_tick_number => $ytick, x_label => 'Weeks Ago', x_label_skip => 7, x_tick_offset => $numdays%7, dclrs => [ qw(green yellow) ], legend_placement => 'BC' ) or warn $graph->error; $graph->set_legend( 'Mean', 'Mean plus Standard Deviation' ); $graph->set_title_font(GD::gdGiantFont); $graph->set_x_axis_font(GD::gdSmallFont); $graph->set_y_axis_font(GD::gdSmallFont); $graph->set_legend_font(GD::gdSmallFont); $gd = $graph->plot(\@data); die "Graph Plot Failed: " . $graph->error unless defined $gd; open IMG, ">$outfile" or die $!; print IMG $gd->png or die $gd->error; close IMG; } sub ErrorGraph { $graph = GD::Graph::lines->new(800,600); @data = (\@days,\@tomcat_full); $div = 5; $div = 10 if $max >=100; $div = 50 if $max >= 200; $div = 100 if $max >= 1000; $div = 500 if $max >= 2000; $div = 1000 if $max >= 5000; $div = 5000 if $max >= 20000; $div = 10000 if $max >= 50000; $div = 50000 if $max >= 200000; $div = 100000 if $max >= 500000; $div = 500000 if $max >= 2000000; $div = 1000000 if $max >= 5000000; $ymax = (int($max/$div) + 1)*$div; $ymin = int($min/$div)*$div; $ytick = ($ymax - $ymin)/$div; $graph->set( y_label => 'Requests', title => "Tomcat Rejected Request by Day from $startdate to $enddate", y_min_value => $ymin, y_max_value => $ymax, y_tick_number => $ytick, y_number_format => \&val_format, x_label => 'Weeks Ago', x_label_skip => 7, x_tick_offset => $numdays%7, dclrs => [ qw(green) ], legend_placement => 'BC' ) or warn $graph->error; $graph->set_legend( 'Tomcat Rejected Requests' ); $graph->set_title_font(GD::gdGiantFont); $graph->set_x_axis_font(GD::gdSmallFont); $graph->set_y_axis_font(GD::gdSmallFont); $graph->set_legend_font(GD::gdSmallFont); $gd = $graph->plot(\@data); die "Graph Plot Failed: " . $graph->error unless defined $gd; open IMG, ">$outfile" or die $!; print IMG $gd->png or die $gd->error; close IMG; } sub ClientGraph { $graph = GD::Graph::lines->new(800,600); @data = (\@days,\@client_gone); $div = 5; $div = 10 if $max >=100; $div = 50 if $max >= 200; $div = 100 if $max >= 1000; $div = 500 if $max >= 2000; $div = 1000 if $max >= 5000; $div = 5000 if $max >= 20000; $div = 10000 if $max >= 50000; $div = 50000 if $max >= 200000; $div = 100000 if $max >= 500000; $div = 500000 if $max >= 2000000; $div = 1000000 if $max >= 5000000; $ymax = (int($max/$div) + 1)*$div; $ymin = int($min/$div)*$div; $ytick = ($ymax - $ymin)/$div; $graph->set( y_label => 'Requests', title => "Tomcat Client Aborted Requests by Day from $startdate to $enddate", y_min_value => $ymin, y_max_value => $ymax, y_tick_number => $ytick, y_number_format => \&val_format, x_label => 'Weeks Ago', x_label_skip => 7, x_tick_offset => $numdays%7, dclrs => [ qw(green) ], legend_placement => 'BC' ) or warn $graph->error; $graph->set_legend( 'Tomcat Client Aborted Requests' ); $graph->set_title_font(GD::gdGiantFont); $graph->set_x_axis_font(GD::gdSmallFont); $graph->set_y_axis_font(GD::gdSmallFont); $graph->set_legend_font(GD::gdSmallFont); $gd = $graph->plot(\@data); die "Graph Plot Failed: " . $graph->error unless defined $gd; open IMG, ">$outfile" or die $!; print IMG $gd->png or die $gd->error; close IMG; } sub val_format { my $value = shift; my $ret; $ret = $value; if( $ret =~ /\./ ) { $ret =~ s/\.(\d\d\d).*/\.$1/; } else { $ret =~ s/(\d+)(\d\d\d)$/$1,$2/; $ret =~ s/(\d+)(\d\d\d),(\d\d\d)$/$1,$2,$3/; } return $ret; } sub size_format { my $value = shift; my $ret; if( $max >= 5000 ) { $value = int(($value/1024)+.5); } $ret = $value; $ret =~ s/(\d+)(\d\d\d)$/$1,$2/; $ret =~ s/(\d+)(\d\d\d),(\d\d\d)$/$1,$2,$3/; return $ret; } tomcat-connectors-1.2.50-src/tools/reports/tomcat_trend.pl0000755000000000000020000003264314655113617022215 0ustar rootbin#!/usr/local/bin/perl # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Author: Glenn Nielsen # Script for analyzing mod_jk.log data when logging tomcat request data using # the JkRequestLogFormat Apache mod_jk configuration. # # Generates statistics for request latency and errors. Archives the generated # data to files for later use in long term trend graphs and reports. # # tomcat_trend.pl use FileHandle; use Statistics::Descriptive; use Time::Local; # Constants %MON = ('JAN' => 0, 'Jan' => 0, 'FEB' => 1, 'Feb' => 1, 'MAR' => 2, 'Mar' => 2, 'APR' => 3, 'Apr' => 3, 'MAY' => 4, 'May' => 4, 'JUN' => 5, 'Jun' => 5, 'JUL' => 6, 'Jul' => 6, 'AUG' => 7, 'Aug' => 7, 'SEP' => 8, 'Sep' => 8, 'OCT' => 9, 'Oct' => 9, 'NOV' => 10, 'Nov' => 10, 'DEC' => 11, 'Dec' => 11,); @Months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); # Check the args $logdir= $ARGV[0]; $archivedir = $ARGV[1]; die "Usage: $0 logdir archivedir" unless( length($logdir) && length($archivedir) ); die "Log Directory $logdir doesn't exist" unless( -d $logdir); die "Archive Directory $archivedir doesn't exist" unless( -d $archivedir); # Get start date from global.data if it exists if( -e "$archivedir/global.data" ) { # Get the start date from the last entry in global.data @tail = `tail -1 $archivedir/global.data`; $startdate = (split /\s+/,$tail[0])[0]; ($day, $mon, $year) = (localtime($startdate))[3..5]; if ($day == 31) { $day=1; $month++; if ($month > 11) { $month=0; $year++; } } $startdate = timelocal(0,0,0,$day+1,$mon,$year); } ($day, $mon, $year) = (localtime(time))[3..5]; $curdate = timelocal(0,0,0,$day,$mon,$year); print "Today: " . scalar(localtime($curdate)) . "\n"; # Get the log files names and date they start @logs = `ls -1 $logdir/mod_jk.log*`; foreach( @logs ) { $logfile = $_; chomp($logfile); next if ( $logfile =~ /\.(bz2|gz|zip)$/ ); @head = `head -1 $logfile`; ($mon, $day, $time, $year) = (split /\s+/,$head[0])[1..4]; ($hour, $min, $sec) = split /:/,$time; $year =~ s/\]$//; $logtime = timelocal($sec,$min,$hour,$day,$MON{$mon},$year-1900); $modjklog{$logtime} = $logfile; } # Set the startdate if this is the first time processing the logs # If we have a startdate, remove log files we con't need to process foreach $logtime ( sort {$a <=> $b} keys %modjklog ) { # If logs haven't been processed before, set startdate to time of # first log entry if( $startdate !~ /^\d+$/ ) { $startdate = $logtime; ($day, $mon, $year) = (localtime($startdate))[3..5]; $startdate = timelocal(0,0,0,$day,$mon,$year); last; } if( $logtime > $startdate ) { last; } # Save the previous log file since start date may start here $prevlogfile = $modjklog{$logtime}; $prevlogtime = $logtime; # Remove log files we don't need to process delete $modjklog{$logtime}; } # Add back in the previous log file where we need to start processing if( defined $prevlogtime ) { $modjklog{$prevlogtime} = $prevlogfile; } print "StartDate: " . scalar(localtime($startdate)) . "\n"; $processdate = $startdate; foreach $key ( sort {$a <=> $b} keys %modjklog ) { $logtime = $processdate; $logfile = $modjklog{$key}; print "Processing log: $logfile\n"; last if( $key >= $curdate ); $fh = new FileHandle "<$logfile"; die "Open of logfile $logfile failed: $!" unless defined $fh; while( $line = $fh->getline) { chomp($line); ($mon, $day, $time, $year) = (split /\s+/,$line)[1..4]; ($hour, $min, $sec) = split /:/,$time; $year =~ s/\]$//; if( $day !~ /^\d+/ || $hour !~ /^\d+/ || $min!~ /^\d+/ || $sec !~ /^\d+/ ) { print "Unknown log entry: $origline\n" unless $origline =~ /\.c /; next; } $logtime = timelocal($sec,$min,$hour,$day,$MON{$mon},$year-1900); if( $logtime > $processdate ) { $origline = $line; # Strip off the leading date and time $line =~ s/^\[.*\] //; # See if this is a new 5 minute period $interval = int($logtime/300); if( $interval != $previnterval ) { if( defined $previnterval ) { &IntervalStats(\%Global,\%Interval,$previnterval*300); } undef %Interval; undef @IntervalLatency; undef %IntervalWorkers; $Interval{tomcat_full} = 0; $Interval{client_gone} = 0; $Interval{latency} = \@IntervalLatency; $Interval{workers} = \%IntervalWorkers; $previnterval = $interval; } # See if this is a new day if( $day != $prevday ) { if( defined $prevday ) { &DailyStats($processdate,\%Global); } undef %Global; undef %GlobalWorkers; undef @GlobalLatency; $Global{tomcat_full} = 0; $Global{client_gone} = 0; $Global{interval} = ""; $Global{latency} = \@GlobalLatency; $Global{workers} = \%GlobalWorkers; $Global{errors} = ""; $prevday = $day; $processdate = $logtime; } # Stop processing if logtime is today last if( $logtime >= $curdate ); if( $line =~ /\d\)\]{0,1}: / ) { # Handle a mod_jk error if( $line =~ /(jk_tcp_socket_recvfull failed|ERROR: Receiving from tomcat failed)/ ) { $Global{tomcat_full}++; $Interval{tomcat_full}++; } elsif( $line =~ /(ajp_process_callback - write failed|ERROR sending data to client. Connection aborted or network problems|Client connection aborted or network problems)/ ) { $Global{client_gone}++; $Interval{client_gone}++; } next; } else { # Handle a mod_jk request log entry $line =~ s/^\[.*\] //; $line =~ s/\"(GET|POST|OPTIONS|HEAD)[^\"]*\" //; $line =~ s/[\?\;].*\"//; $line =~ s/\"//g; ($work, $host, $page, $status, $latency) = split /\s+/,$line; $page =~ s/\/\//\//g; $page =~ s/\.\//\//g; if( length($work) <= 0 || length($host) <= 0 || length($page) <= 0 || $status !~ /^\d+$/ || $latency !~ /^\d+\.\d+$/ ) { print "Unknown log entry: $origline\n" unless $origline =~ /\.c /; next; } # Throw out abnormally long requests and log them as an error if( $latency >= 1800 ) { $Global{errors} .= "Error: $page has an HTTP status of $status and an "; $Global{errors} .= "abnormally long request latency of $latency seconds\n"; next; } # Save the data by day for Global, Worker, and Host push @{$Global{latency}},$latency; $workers = $Global{workers}; if( !defined $$workers{$work} ) { undef @{"$work"}; undef %{"$work"}; undef %{"$work-hosts"}; ${"$work"}{latency} = \@{"$work"}; ${"$work"}{hosts} = \%{"$work-hosts"}; ${"$work"}{interval} = ""; $$workers{$work} = \%{"$work"}; } $worker = $$workers{$work}; push @{$$worker{latency}},$latency; if( !defined $$worker{hosts}{$host} ) { undef @{"$work-$host"}; undef %{"$work-$host"}; undef %{"$work-$host-pages"}; ${"$work-$host"}{latency} = \@{"$work-$host"}; ${"$work-$host"}{pages} = \%{"$work-$host-pages"}; ${"$work-$host"}{interval} = ""; $$worker{hosts}{$host} = \%{"$work-$host"}; } $hoster = $$worker{hosts}{$host}; push @{$$hoster{latency}},$latency; if( !defined $$hoster{pages}{$page} ) { undef @{"$work-$host-$page"}; $$hoster{pages}{$page} = \@{"$work-$host-$page"}; } push @{$$hoster{pages}{$page}},$latency; # Save the data by 5 minute interval for Global, Worker, and Host push @{$Interval{latency}},$latency; $workers = $Interval{workers}; if( !defined $$workers{"$work"} ) { undef @{"int-$work"}; undef %{"int-$work"}; undef %{"int-$work-hosts"}; ${"int-$work"}{latency} = \@{"int-$work"}; ${"int-$work"}{hosts} = \%{"int-$work-hosts"}; $$workers{$work} = \%{"int-$work"}; } $worker = $$workers{$work}; push @{$$worker{latency}},$latency; if( !defined $$worker{hosts}{$host} ) { undef @{"int-$work-$host"}; undef %{"int-$work-$host"}; ${"int-$work-$host"}{latency} = \@{"int-$work-$host"}; $$worker{hosts}{$host} = \%{"int-$work-$host"}; } $hoster = $$worker{hosts}{$host}; push @{$$hoster{latency}},$latency; } } } undef $fh; } # If the last log file ends before switch to the current day, # output the last days data if( $logtime < $curdate ) { &IntervalStats(\%Global,\%Interval,$previnterval*300); &DailyStats($processdate,\%Global); } exit; sub IntervalStats($$$) { my $global = $_[0]; my $data = $_[1]; my $interval = $_[2]; ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($$data{latency}); $$global{interval} .= "$interval $count $median $mean $stddev $min $max $$data{client_gone} $$data{tomcat_full}\n"; foreach $work ( keys %{$$data{workers}} ) { $worker = $$data{workers}{$work}; $gworker = $$global{workers}{$work}; ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($$worker{latency}); $$gworker{interval} .= "$interval $count $median $mean $stddev $min $max\n"; foreach $host ( keys %{$$worker{hosts}} ) { $hoster = $$worker{hosts}{$host}; $ghoster = $$gworker{hosts}{$host}; ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($$hoster{latency}); $$ghoster{interval} .= "$interval $count $median $mean $stddev $min $max\n"; } } } sub DailyStats($$) { my $date = $_[0]; my $data = $_[1]; &SaveStats($data,$date,"","global"); &SaveFile($$data{interval},$date,"","daily"); foreach $work ( keys %{$$data{workers}} ) { $worker = $$data{workers}{$work}; &SaveStats($worker,$date,$work,"global"); &SaveFile($$worker{interval},$date,$work,"daily"); foreach $host ( keys %{$$worker{hosts}} ) { $hoster = $$worker{hosts}{$host}; &SaveStats($hoster,$date,"$work/$host","global"); &SaveFile($$hoster{interval},$date,"$work/$host","daily"); $pagedata = ""; foreach $page ( sort keys %{$$hoster{pages}} ) { $pager = $$hoster{pages}{$page}; ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($pager); $pagedata .= "$page $count $median $mean $stddev $min $max\n"; } $pagedata .= $$data{errors}; &SaveFile($pagedata,$date,"$work/$host","request"); } } } sub CalcStats($) { my $data = $_[0]; $stats = Statistics::Descriptive::Full->new(); $stats->add_data(@{$data}); $median = $stats->median(); $mean = $stats->mean(); $stddev = $stats->standard_deviation(); $max = $stats->max(); $min = $stats->min(); $count = $stats->count(); return ($count,$median,$mean,$stddev,$min,$max); } sub SaveStats($$$$) { my $data = $_[0]; my $date = $_[1]; my $dir = $_[2]; my $file = $_[3]; if( length($dir) > 0 ) { $dir = "$archivedir/$dir"; } else { $dir = $archivedir; } mkdir "$dir",0755; $outfile = "$dir/${file}.data"; ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($$data{latency}); open DATA, ">>$outfile" or die $!; print DATA "$date $count $median $mean $stddev $min $max"; print DATA " $$data{client_gone} $$data{tomcat_full}" if defined $$data{tomcat_full}; print DATA "\n"; close DATA; } sub SaveFile($$$$) { my $data = $_[0]; my $date = $_[1]; my $dir = $_[2]; my $file = $_[3]; my ($day, $mon, $year); ($day, $mon, $year) = (localtime($date))[3..5]; $year += 1900; $mon++; $mon = "0$mon" if $mon < 10; $day = "0$day" if $day < 10; $file = "$year-$mon-$day-$file"; if( length($dir) > 0 ) { $dir = "$archivedir/$dir"; } else { $dir = $archivedir; } mkdir "$dir",0755; $outfile = "$dir/${file}.data"; open DATA, ">>$outfile" or die $!; print DATA $data; close DATA; } tomcat-connectors-1.2.50-src/tools/jkrelease.sh0000755000000000000020000003167614655113617020005 0ustar rootbin#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Make sure to set your path so that we can find # the following binaries: # cd, mkdir, cp, rm, find # svn or git # ant # libtoolize, aclocal, autoheader, automake, autoconf # tar, zip, gzip # gpg # And any one of: w3m, elinks, links (links2) SVN_REPOS="http://svn.apache.org/repos/asf/tomcat/jk" GIT_REPOS="https://gitbox.apache.org/repos/asf/tomcat-connectors.git" JK_CVST="tomcat-connectors" JK_OWNER="root" JK_GROUP="bin" JK_TOOLS="`pwd`" COPY_JK="README.txt HOWTO-RELEASE.txt .gitignore native jkstatus support tools xdocs" COPY_NATIVE="LICENSE NOTICE" COPY_BUILD="docs" COPY_CONF="httpd-jk.conf uriworkermap.properties workers.properties" SIGN_OPTS="" #################### NO CHANGE BELOW THIS LINE ############## #################### FUNCTIONS ############## usage() { echo "Usage:: $0 -R (git|svn) -v VERSION [-f] [-r revision_or_hash] [-t tag | -b BRANCH | -T | -d DIR]" echo " -R: Use git or svn to check out from repos" echo " -v: version to package" echo " -f: force, do not validate tag against version" echo " -h: create text documentation for html" echo " -t: tag to use if different from version" echo " -r: revision or hash to package, only allowed in" echo " combination with '-b BRANCH', '-T' or '-d DIR'" echo " -b: package from branch BRANCH" echo " -T: package from trunk/main" echo " -d: package from local directory" echo " -o: owner used for creating tar archive" echo " -g: group used for creating tar archive" echo " -p: GNU PG passphrrase used for signing" echo " -k: ID of GNU PG key to use for signing" } copy_files() { src=$1 target=$2 list="$3" mkdir -p $target for item in $list do echo "Copying $item from $src ..." cp -pr $src/$item $target/ done } #################### MAIN ############## txtgen=n conflict=0 rev_allowed=0 while getopts :R:v:t:r:b:d:p:k:o:g:Tfh c do case $c in R) repos=$OPTARG;; v) version=$OPTARG;; t) tag=$OPTARG conflict=$(($conflict+1));; r) revision=$OPTARG;; k) SIGN_OPTS="--default-key=$OPTARG $SIGN_OPTS";; p) SIGN_OPTS="--passphrase=$OPTARG $SIGN_OPTS";; o) JK_OWNER=$OPTARG;; g) JK_GROUP=$OPTARG;; b) branch=$OPTARG conflict=$(($conflict+1)) rev_allowed=1;; T) trunk=trunk conflict=$(($conflict+1)) rev_allowed=1;; d) local_dir=$OPTARG conflict=$(($conflict+1)) rev_allowed=1;; f) force='y';; h) txtgen='y';; \:) usage exit 2;; \?) usage exit 2;; esac done shift `expr $OPTIND - 1` if [ "X$repos" == "Xgit" ] then USE_GIT=1 REPOS=$GIT_REPOS JK_REPOS_URL=$REPOS elif [ "X$repos" == "Xsvn" ] then USE_GIT=0 REPOS=$SVN_REPOS else usage echo "Option '-R git' or '-R svn' must be set." exit 2 fi if [ $conflict -gt 1 ] then usage echo "Only one of the options '-t', '-b', '-T' and '-d' is allowed." exit 2 fi if [ -n "$revision" ] then if [ $rev_allowed -eq 0 ] then usage echo "Option '-r revision' only allowed in combination with '-b BRANCH', '-T' or '-d DIR'" exit 2 fi fi if [ -n "$local_dir" ] then echo "Caution: Packaging from directory!" echo "Make sure the directory is committed." answer="x" while [ "$answer" != "y" -a "$answer" != "n" ] do echo "Do you want to proceed? [y/n]" read answer done if [ "$answer" != "y" ] then echo "Aborting." exit 4 fi fi if [ -z "$version" ] then usage exit 2 fi if [ -n "$revision" ] then if [ $USE_GIT -eq 0 ] then revision="-r $revision" fi fi if [ -n "$trunk" ] then if [ $USE_GIT -eq 1 ] then JK_REV=`git ls-remote $REPOS refs/heads/main | awk '{print $1}'` if [ -z "$JK_REV" ] then echo "No git hash found via 'git ls-remote $REPOS refs/heads/main'" exit 3 fi JK_SUFFIX=-${JK_REV} JK_DIST=${JK_CVST}-${version}-dev${JK_SUFFIX}-src else JK_REPOS_URL="${REPOS}/trunk" repos_use_url="`svn help info | grep URL`" if [ -n "$repos_use_url" ] then JK_REPOS_INFO_PATH="${JK_REPOS_URL}" else JK_REPOS_INFO_PATH=. fi JK_REV=`svn info $revision $JK_REPOS_INFO_PATH | awk '$1 == "Revision:" {print $2}'` if [ -z "$JK_REV" ] then echo "No svn revision found at '$JK_REPOS_URL'" exit 3 fi JK_SUFFIX=-${JK_REV} JK_DIST=${JK_CVST}-${version}-dev${JK_SUFFIX}-src fi elif [ -n "$branch" ] then if [ $USE_GIT -eq 1 ] then JK_REV=`git ls-remote $REPOS refs/heads/$branch | awk '{print $1}'` if [ -z "$JK_REV" ] then echo "No git hash found via 'git ls-remote $REPOS refs/heads/$branch'" exit 3 fi JK_SUFFIX=-${JK_BRANCH}-${JK_REV} JK_DIST=${JK_CVST}-${version}-dev${JK_SUFFIX}-src else JK_BRANCH=`echo $branch | sed -e 's#/#__#g'` JK_REPOS_URL="${REPOS}/branches/$branch" JK_REV=`svn info $revision ${JK_REPOS_URL} | awk '$1 == "Revision:" {print $2}'` if [ -z "$JK_REV" ] then echo "No svn revision found at '$JK_REPOS_URL'" exit 3 fi JK_SUFFIX=-${JK_BRANCH}-${JK_REV} JK_DIST=${JK_CVST}-${version}-dev${JK_SUFFIX}-src fi elif [ -n "$local_dir" ] then if [ ! -d "$local_dir" ] then echo "Directory '$local_dir' does not exist - Aborting!" exit 6 fi if [ $USE_GIT -eq 1 ] then JK_REV=`git --git-dir=$local_dir rev-parse HEAD` if [ -z "$JK_REV" ] then echo "No git hash found via 'git rev-parse --short HEAD' in `pwd`" exit 3 fi JK_SUFFIX=-local-`date +%Y%m%d%H%M%S`-${JK_REV} JK_DIST=${JK_CVST}-${version}-dev${JK_SUFFIX}-src else JK_REPOS_URL="$local_dir" JK_REV=`svn info $revision ${JK_REPOS_URL} | awk '$1 == "Revision:" {print $2}'` if [ -z "$JK_REV" ] then echo "No svn revision found at '$JK_REPOS_URL'" exit 3 fi JK_SUFFIX=-local-`date +%Y%m%d%H%M%S`-${JK_REV} JK_DIST=${JK_CVST}-${version}-dev${JK_SUFFIX}-src fi else JK_TAG=`echo $version | sed -e 's#^#JK_#' -e 's#\.#_#g'` if [ $USE_GIT -eq 1 ] then if [ -n "$tag" ] then if [ -z "$force" ] then echo $tag | grep "^$JK_TAG" > /dev/null 2>&1 if [ "X$tag" != "X$JK_TAG" ] then echo "Tag '$tag' doesn't belong to version '$version'." echo "Force by using '-f' if you are sure." exit 5 fi fi JK_REV=`git ls-remote $REPOS refs/tags/$tag | awk '{print $1}'` if [ -z "$JK_REV" ] then echo "No git hash found via 'git ls-remote $REPOS refs/tags/$tag'" exit 3 fi JK_SUFFIX=-tag-${tag}-${JK_REV} else JK_REV=`git ls-remote $REPOS refs/tags/$JK_TAG | awk '{print $1}'` if [ -z "$JK_REV" ] then echo "No git hash found via 'git ls-remote $REPOS refs/tags/$JK_TAG'" exit 3 fi JK_SUFFIX='' fi JK_DIST=${JK_CVST}-${version}${JK_SUFFIX}-src else if [ -n "$tag" ] then if [ -z "$force" ] then echo $tag | grep "^$JK_TAG" > /dev/null 2>&1 if [ $? -gt 0 ] then echo "Tag '$tag' doesn't belong to version '$version'." echo "Force using '-f' if you are sure." exit 5 fi fi JK_TAG=$tag fi JK_REPOS_URL="${REPOS}/tags/${JK_TAG}" JK_DIST=${JK_CVST}-${version}-src fi fi echo "Using checkout URL: $JK_REPOS_URL" echo "Rolling into file $JK_DIST.*" sleep 2 umask 022 rm -rf ${JK_DIST} 2>/dev/null || true rm -rf ${JK_DIST}.* 2>/dev/null || true mkdir -p ${JK_DIST}.tmp if [ $USE_GIT -eq 0 ] then svn export $revision "${JK_REPOS_URL}" ${JK_DIST}.tmp/jk if [ $? -ne 0 ] then echo "svn export failed" exit 1 fi else if [ -n "$local_dir" ] then git --git-dir=$work_space/.git --work-tree=${JK_DIST}.tmp/jk checkout $JK_REV if [ $? -ne 0 ] then echo "git checkout for version $version hash '$JK_REV' from local '$work_space/.git' to directory '${JK_DIST}.tmp/jk' failed" exit 1 fi else git clone --no-checkout "${JK_REPOS_URL}" ${JK_DIST}.tmp/jk if [ $? -ne 0 ] then echo "git clone '${JK_REPOS_URL}' to '${JK_DIST}.tmp/jk' failed" exit 1 fi git --git-dir=${JK_DIST}.tmp/jk/.git --work-tree=${JK_DIST}.tmp/jk checkout $JK_REV if [ $? -ne 0 ] then echo "git checkout for version $version hash '$JK_REV' from cloned '${JK_REPOS_URL}' in directory '${JK_DIST}.tmp/jk' failed" exit 1 fi fi fi # Build documentation. cd ${JK_DIST}.tmp/jk/xdocs ant cd ../../.. # Copying things into the source distribution copy_files ${JK_DIST}.tmp/jk $JK_DIST "$COPY_JK" copy_files ${JK_DIST}.tmp/jk/native $JK_DIST "$COPY_NATIVE" copy_files ${JK_DIST}.tmp/jk/build $JK_DIST "$COPY_BUILD" copy_files ${JK_DIST}.tmp/jk/conf $JK_DIST/conf "$COPY_CONF" # Remove extra directories and files targetdir=${JK_DIST} rm -f ${targetdir}/native/build.xml rm -f ${targetdir}/native/NOTICE rm -f ${targetdir}/native/LICENSE find ${JK_DIST} -name .cvsignore -exec rm -rf \{\} \; find ${JK_DIST} -name CVS -exec rm -rf \{\} \; find ${JK_DIST} -name .svn -exec rm -rf \{\} \; find ${JK_DIST} -name .git -exec rm -rf \{\} \; cd ${JK_DIST}/native if [ $txtgen = y ] then # Check for links, elinks or w3m W3MOPTS="-dump -cols 80 -t 4 -S -O UTF-8 -T text/html" ELNKOPTS="-dump -dump-width 80 -dump-charset UTF-8 -no-numbering -no-home -no-references" LNKOPTS="-dump -width 80 -codepage UTF-8 -no-g -html-numbered-links 0" LYXOPTS="-dump -width=80 -nolist -nostatus -noprint -assume_local_charset=UTF-8" failed=true for tool in `echo "w3m elinks links lynx"` do found=false for dir in `echo ${PATH} | sed 's!^:!.:!;s!:$!:.!;s!::!:.:!g;s!:! !g'` do if [ -x ${dir}/${tool} ] then found=true break fi done # Try to run it if ${found} then case ${tool} in w3m) TOOL="w3m $W3MOPTS" ;; links) TOOL="links $LNKOPTS" ;; elinks) TOOL="elinks $ELNKOPTS" ;; lynx) TOOL="lynx $LYXOPTS" ;; esac rm -f CHANGES echo "Creating the CHANGES file using '$TOOL' ..." ${TOOL} ../docs/miscellaneous/changelog.html | awk '/Preface/ {o=1} o>0' > CHANGES 2>/dev/null if [ -f CHANGES -a -s CHANGES ] then failed=false break fi fi done if [ ${failed} = "true" ] then echo "Can't convert html to text (CHANGES)" exit 1 fi # Export text docs echo "Creating the NEWS file using '$TOOL' ..." rm -f NEWS touch NEWS for news in `ls -r ../xdocs/news/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].xml` do print=`echo $news | sed -e 's#xdocs/news#docs/news#' -e 's#\.xml#.html#'` echo "Adding $print to NEWS file ..." ${TOOL} $print | awk '/[0-9][0-9][0-9][0-9] News/ {o=1} o>0' >> NEWS done if [ ! -s NEWS ] then echo "Can't convert html to text (NEWS)" exit 1 fi fi # Generate configure et. al. ./buildconf.sh cd ../../ # Pack tar cfz ${JK_DIST}.tar.gz --owner="${JK_OWNER}" --group="${JK_GROUP}" ${JK_DIST} || exit 1 perl ${JK_DIST}/tools/lineends.pl --ignore '.*/pcre/testdata/.*' --cr ${JK_DIST} zip -9 -r ${JK_DIST}.zip ${JK_DIST} # Create detached signature and verify it archive=${JK_DIST}.tar.gz . ${JK_TOOLS}/signfile.sh ${SIGN_OPTS} $archive archive=${JK_DIST}.zip . ${JK_TOOLS}/signfile.sh ${SIGN_OPTS} $archive # Cleanup working dirs rm -rf ${JK_DIST}.tmp rm -rf ${JK_DIST} tomcat-connectors-1.2.50-src/tools/jkbindist.sh0000755000000000000020000000606614655113617020014 0ustar rootbin#!/bin/bash # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Create windows binary distribution archive # prefix="tomcat-connectors" tools="`pwd`" sign="" #################### NO CHANGE BELOW THIS LINE ############## #################### FUNCTIONS ############## usage() { echo "Usage:: $0 -v VERSION -w WEBSERVER -o OS -a ARCH " echo " -v: version to package" echo " -w: package for web server" echo " -o: Operating System" echo " -a: Architecture" echo " -p: GNU PG passphrrase used for signing" echo " -k: ID of GNU PG key to use for signing" } while getopts :v:w:o:a:p:k: c do case $c in v) version=$OPTARG;; w) websrv=$OPTARG;; k) sign="--default-key=$OPTARG $sign";; p) sign="--passphrase=$OPTARG $sign";; o) opsys=$OPTARG;; a) arch=$OPTARG;; \:) usage exit 2;; \?) usage exit 2;; esac done shift `expr $OPTIND - 1` if [ -z "$version" -o -z "$websrv" ] then usage exit 2 fi if [ -z "$opsys" ] then opsys="`uname -s | tr [A-Z] [a-z]`" case "$opsys" in cygwin*) opsys=windows ;; esac fi if [ -z "$arch" ] then arch="`uname -m`" fi if [ ! -f "$1" ] then usage exit 2 fi case "$websrv" in httpd*) webdesc="Apache HTTP Server" ;; iis*) webdesc="Microsoft IIS Web Server" ;; *) echo "Unknown web server: $webserv" echo " Supported are: httpd, iis, nsapi" ;; esac dist=${prefix}-${version}-${opsys}-${arch}-${websrv} dtop=${tools}/.. copy="LICENSE NOTICE" rm -f ${copy} 2>/dev/null rm -f ${dist} 2>/dev/null rm -f ${dist}.* 2>/dev/null cat << EOF > README Apache Tomcat Connectors - $version Here you'll find module binaries for $webdesc. Check the online documentation at http://tomcat.apache.org/connectors-doc/ for installation instructions. The Apache Tomcat Project http://tomcat.apache.org EOF umask 022 for i in ${copy} do if [ -f ${dtop}/$i ] then cp ${dtop}/$i . else cp ${dtop}/native/$i . fi unix2dos $i done unix2dos README #chmod 755 $1 # Pack archive=${dist}.zip zip -9 -j ${archive} $@ README ${copy} # Sign . ${tools}/signfile.sh ${sign} ${archive} # Cleanup rm -f README ${copy} 2>/dev/null tomcat-connectors-1.2.50-src/tools/signfile.sh0000755000000000000020000000311714655113617017625 0ustar rootbin#!/bin/bash # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. gpgopts="-ba" for o do case "$o" in *=*) a=`echo "$o" | sed 's/^[-_a-zA-Z0-9]*=//'` ;; *) a='' ;; esac case "$o" in --default-key=* ) gpgopts="$gpgopts --default-key $a" shift ;; --passphrase=* ) gpgopts="$gpgopts --passphrase $a" shift ;; * ) break ;; esac done # Try to locate a SHA512 binary sha512_bin="`which sha512sum 2>/dev/null || type sha512sum 2>&1`" if [ -x "$sha512_bin" ]; then SHA512SUM="$sha512_bin --binary " else SHA512SUM="echo 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 " fi for o do echo "Signing $o" gpg $gpgopts $o $SHA512SUM $o > $o.sha512 done tomcat-connectors-1.2.50-src/.gitignore0000644000000000000020000000005214655113617016311 0ustar rootbin.project .settings build build.properties tomcat-connectors-1.2.50-src/support/0000755000000000000020000000000014655113617016040 5ustar rootbintomcat-connectors-1.2.50-src/support/jk_ws.m40000644000000000000020000001527214655113617017426 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl -------------------------------------------------------------------------- dnl Author Henri Gomez dnl dnl Inspired by Pier works on webapp m4 macros :) dnl -------------------------------------------------------------------------- dnl -------------------------------------------------------------------------- dnl JK_WS_DIR dnl Set the WebServer source dir. dnl $1 => Webserver name dnl $2 => Webserver vars prefix name dnl $3 => File which should be present dnl $4 => Server specific source directory dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_WS_DIR], [ tempval="" AC_ARG_WITH( [$1], [ --with-$1=DIR Location of $1 source dir ], [ case "${withval}" in ""|"yes"|"YES"|"true"|"TRUE") AC_MSG_ERROR(valid $1 source dir location required) ;; "no"|"NO"|"false"|"FALSE") AC_MSG_ERROR(Don't use with/without $1 if you don't have $1) ;; *) tempval="${withval}" if ${TEST} ! -d ${tempval} ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi if ${TEST} ! -f ${tempval}/$3; then AC_MSG_ERROR(can't locate ${tempval}/$3) fi if ${TEST} ! -z "$tempval" ; then $2_BUILD="true" $2_CFLAGS="-I ${tempval}/include" $2_DIR=${tempval} $2_HOME="${tempval}" $2_LIBDIR="" if ${TEST} -d ${withval}/include ; then $2_INCL="-I${tempval}/include" $2_INCDIR="${tempval}/include" fi if ${TEST} -d ${withval}/src/include ; then # read osdir from the existing apache. osdir=`${GREP} '^OSDIR=' ${withval}/src/Makefile.config | ${SED} -e 's:^OSDIR=.*/os:os:'` if ${TEST} -z "${osdir}" ; then osdir=os/unix fi $2_INCL="-I${tempval}/src/include -I${withval}/src/${osdir}" $2_INCDIR="${tempval}/src/include" fi if ${TEST} -d ${tempval}/srclib/apr ; then # Apache 2 contains apr. if ${TEST} ! -f ${tempval}/srclib/apr/config.status ; then AC_MSG_ERROR(configure Apache2 before mod_jk) fi osdir=`${GREP} @OSDIR@ ${tempval}/srclib/apr/config.status | sed 's:s,@OSDIR@,::' | sed 's:,;t t::'` $2_INCL="-I${tempval}/include -I${withval}/os/${osdir}" $2_LIBEXEC=`${GREP} "^exp_libexecdir =" ${tempval}/build/config_vars.mk | sed 's:exp_libexecdir = ::'` LIBTOOL=${tempval}/srclib/apr/libtool APR_INCDIR=-I${tempval}/srclib/apr/include APR_CFLAGS=`${tempval}/srclib/apr/apr-config --cflags` APR_UTIL_INCDIR=-I${tempval}/srclib/apr-util/include APR_LIBDIR_LA=`${tempval}/srclib/apr/apr-config --apr-la-file` $2_LIBDIR=${tempval}/lib AC_SUBST(APR_INCDIR) AC_SUBST(APR_CFLAGS) AC_SUBST(APR_INCDIR) AC_SUBST(APR_UTIL_INCDIR) fi $2_LDFLAGS="" WEBSERVERS="${WEBSERVERS} $4" AC_SUBST($2_BUILD) AC_SUBST($2_CFLAGS) AC_SUBST($2_DIR) AC_SUBST($2_HOME) AC_SUBST($2_INCL) AC_SUBST($2_INCDIR) AC_SUBST($2_LDFLAGS) AC_SUBST($2_LIBDIR) fi ;; esac ]) if ${TEST} -z "$tempval" ; then AC_MSG_RESULT(not provided) else AC_MSG_RESULT(${tempval}) fi unset tempval ]) dnl -------------------------------------------------------------------------- dnl JK_WS_INCDIR dnl Set the WebServer include dir. dnl $1 => Webserver name dnl $2 => Webserver vars prefix name dnl $3 => File which should be present dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_WS_INCDIR], [ tempval="" AC_ARG_WITH( [$1-include], [ --with-$1-include=DIR Location of $1 include dir ], [ case "${withval}" in ""|"yes"|"YES"|"true"|"TRUE") ;; "no"|"NO"|"false"|"FALSE") AC_MSG_ERROR(valid $1 include dir location required) ;; *) tempval="${withval}" if ${TEST} ! -d ${tempval} ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi if ${TEST} ! -f ${tempval}/$3; then AC_MSG_ERROR(can't locate ${tempval}/$3) fi if ${TEST} ! -z "$tempval" ; then $2_BUILD="" $2_CFLAGS="-I${tempval}" $2_CLEAN="" $2_DIR="" $2_INCDIR=${tempval} AC_MSG_RESULT($2_INCDIR) AC_SUBST($2_BUILD) AC_SUBST($2_CFLAGS) AC_SUBST($2_CLEAN) AC_SUBST($2_DIR) AC_SUBST($2_INCDIR) fi ;; esac ]) unset tempval ]) dnl -------------------------------------------------------------------------- dnl JK_WS_LIBDIR dnl Set the WebServer library dir. dnl $1 => Webserver name dnl $2 => Webserver vars prefix name dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_WS_LIBDIR], [ tempval="" AC_ARG_WITH( [$1-lib], [ --with-$1-lib=DIR Location of $1 lib dir ], [ case "${withval}" in ""|"yes"|"YES"|"true"|"TRUE") ;; "no"|"NO"|"false"|"FALSE") AC_MSG_ERROR(valid $1 lib directory location required) ;; *) tempval="${withval}" if ${TEST} ! -d ${tempval} ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi if ${TEST} ! -z "$tempval" ; then $2_BUILD="" $2_CLEAN="" $2_DIR="" $2_LIBDIR=${tempval} $2_LDFLAGS="" AC_MSG_RESULT($2_LIBDIR) AC_SUBST($2_BUILD) AC_SUBST($2_CLEAN) AC_SUBST($2_DIR) AC_SUBST($2_LIBDIR) AC_SUBST($2_LDFLAGS) fi ;; esac ]) unset tempval ]) dnl vi:set sts=2 sw=2 autoindent: tomcat-connectors-1.2.50-src/support/jk_dominohome.m40000644000000000000020000000440514655113617021127 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl -------------------------------------------------------------------------- dnl Author Andy Armstrong dnl Shamelessly cribbed from Henri Gomez dnl dnl He was inspired by Pier works on webapp m4 macros :) dnl -------------------------------------------------------------------------- dnl -------------------------------------------------------------------------- dnl JK_DOMHOME dnl Set the Domino Home directory. dnl $1 => Domino Name dnl $2 => Domino VarName dnl $3 => File which should be present dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_DOMHOME], [ tempval="" AC_MSG_CHECKING([for $1 location]) AC_ARG_WITH( [$1], [ --with-$1=DIR Location of $1 ], [ case "${withval}" in ""|"yes"|"YES"|"true"|"TRUE") ;; "no"|"NO"|"false"|"FALSE") AC_MSG_ERROR(valid $1 location required) ;; *) tempval="${withval}" if ${TEST} ! -d ${tempval} ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi if ${TEST} ! -f ${tempval}/$3; then AC_MSG_ERROR(can't locate ${tempval}/$3) fi ;; esac ]) if ${TEST} -z "$tempval" ; then AC_MSG_RESULT(not provided) else [$2]=${tempval} AC_MSG_RESULT(${[$2]}) fi unset tempval ]) dnl vi:set sts=2 sw=2 autoindent: tomcat-connectors-1.2.50-src/support/jk_tchome.m40000644000000000000020000000427514655113617020255 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl -------------------------------------------------------------------------- dnl Author Henri Gomez dnl dnl Inspired by Pier works on webapp m4 macros :) dnl -------------------------------------------------------------------------- dnl -------------------------------------------------------------------------- dnl JK_TCHOME dnl Set the Tomcat Home directory. dnl $1 => Tomcat Name dnl $2 => Tomcat VarName dnl $3 => File which should be present dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_TCHOME], [ tempval="" AC_MSG_CHECKING([for $1 location]) AC_ARG_WITH( [$1], [ --with-$1=DIR Location of $1 ], [ case "${withval}" in ""|"yes"|"YES"|"true"|"TRUE") ;; "no"|"NO"|"false"|"FALSE") AC_MSG_ERROR(valid $1 location required) ;; *) tempval="${withval}" if ${TEST} ! -d ${tempval} ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi if ${TEST} ! -f ${tempval}/$3; then AC_MSG_ERROR(can't locate ${tempval}/$3) fi ;; esac ]) if ${TEST} -z "$tempval" ; then AC_MSG_RESULT(not provided) else [$2]=${tempval} AC_MSG_RESULT(${[$2]}) fi unset tempval ]) dnl vi:set sts=2 sw=2 autoindent: tomcat-connectors-1.2.50-src/support/jk_apache_static.m40000644000000000000020000001144714655113617021565 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl -------------------------------------------------------------------------- dnl Author Henri Gomez dnl dnl Inspired by Pier works on webapp m4 macros :) dnl -------------------------------------------------------------------------- dnl Apache-2.0 needs the os subdirectory to include os.h dnl this include is copy from os/config.m4 sinclude(os_apache.m4) dnl -------------------------------------------------------------------------- dnl JK_APACHE_STATIC dnl Set the APACHE 1.3/2.0 source dir. dnl $1 => apache source dir to detect ("", 2) dnl $2 => apache 1.3 build dir dnl $3 => apache 2.0 build dir dnl dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_APACHE_STATIC], [ tempval="" AC_ARG_WITH( [apache$1], [ --with-apache$1=DIR Location of Apache$2 source dir], [ if ${TEST} ${use_apxs$1} ; then AC_MSG_ERROR([Sorry cannot use --with-apxs= and --with-apache= together, please choose one]) fi AC_MSG_CHECKING([for Apache source directory (assume static build)]) if ${TEST} -n "${withval}" && ${TEST} -d "${withval}" ; then if ${TEST} -d "${withval}/src" ; then # handle the case where people use relative paths to # the apache source directory by pre-pending the current # build directory to the path. there are probably # errors with this if configure is run while in a # different directory than what you are in at the time if ${TEST} -n "`${ECHO} ${withval}|${GREP} \"^\.\.\"`" ; then withval=`pwd`/${withval} fi APACHE$1_DIR=${withval} use_static="true" AC_MSG_RESULT(${APACHE$1_DIR}) AC_MSG_CHECKING(for Apache include directory) if ${TEST} -d "${withval}/src/include" ; then # read osdir from the existing apache. osdir=`${GREP} '^OSDIR=' ${withval}/src/Makefile.config | ${SED} -e 's:^OSDIR=.*/os:os:'` if ${TEST} -z "${osdir}" ; then osdir=os/unix fi APACHE$1_DIR=${withval} APACHE$1_HOME=${withval} APACHE$1_INCL="-I${withval}/src/include -I${withval}/src/${osdir}" EXTRA_CFLAGS="" EXTRA_CPPFLAGS="" REPORTED_SERVER="apache-1.3" SERVER_DIR="$3" use_static="true" use_apache13="true" AC_MSG_RESULT([${APACHE$1_INCL}, version 1.3]) else AC_MSG_ERROR([Sorry Apache 1.2.x is no longer supported.]) fi else if ${TEST} -d "${withval}/include" ; then # osdir for Apache20. APACHE$1_DIR=${withval} APACHE$1_HOME=${withval} APACHE$1_INCL="-I${withval}/include -I${withval}/srclib/apr/include -I${withval}/os/${OS_APACHE_DIR} -I${withval}/srclib/apr-util/include" EXTRA_CFLAGS="" EXTRA_CPPFLAGS="" REPORTED_SERVER="apache-2.0" SERVER_DIR="$3" use_static="true" use_apache2="true" APACHE$1_INCL="-I${withval}/include -I${withval}/srclib/apr/include -I${withval}/os/${OS_APACHE_DIR} -I${withval}/srclib/apr-util/include" AC_MSG_RESULT(${APACHE$1_DIR}) JK_CHANNEL_APR_SOCKET="\${JK}jk_channel_apr_socket\${OEXT}" JK_POOL_APR="\${JK}jk_pool_apr\${OEXT}" HAS_APR="-DHAS_APR" fi fi fi dnl Make sure we have a result. if ${TEST} -z "$WEBSERVER" ; then AC_MSG_ERROR([Directory $apache_dir is not a valid Apache source distribution]) fi # VT: Now, which one I'm supposed to use? Let's figure it out later configure_apache=true configure_src=true AC_MSG_RESULT([building connector for \"$WEBSERVER\"]) ], [ AC_MSG_RESULT(no apache$1 dir given) ]) dnl vi:set sts=2 sw=2 autoindent: tomcat-connectors-1.2.50-src/support/apache.m40000644000000000000020000001436014655113617017527 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl dnl apache.m4: autoconf macro for Apache/apxs dnl dnl dnl check for apxs. dnl AC_DEFUN(JTC_CHECK_APXS,[ WEBSERVER="" apache_dir="" apache_include="" APXS="apxs" AC_ARG_WITH(apxs, [ --with-apxs[=FILE] Build shared Apache module. FILE is the optional pathname to the apxs tool; defaults to finding apxs in your PATH.], [ case "${withval}" in y | yes | true) find_apxs=true ;; n | no | false) find_apxs=false ;; *) find_apxs=false ;; esac if ${TEST} ${find_apxs} ; then AC_MSG_RESULT([need to check for Perl first, apxs depends on it...]) AC_PATH_PROG(PERL,perl,$PATH)dnl if ${TEST} ${find_apxs} ; then APXS=${withval} else AC_PATH_PROG(APXS,apxs,$PATH)dnl fi if ${TEST} -n "${APXS}" ; then dnl Seems that we have it, but have to check if it is OK first if ${TEST} ! -x "${APXS}" ; then AC_MSG_ERROR(Invalid location for apxs: '${APXS}') fi $APXS -q PREFIX >/dev/null 2>/dev/null || apxs_support=false if ${TEST} "${apxs_support}" = "false" ; then AC_MSG_RESULT(could not find apxs) AC_MSG_ERROR(You must specify a valid --with-apxs path) fi dnl test apache version $RM -rf test $APXS -n test -g APA=`grep STANDARD20 test/mod_test.c` $RM -rf test if ${TEST} -z "$APA" ; then WEBSERVER="apache-1.3" else WEBSERVER="apache-2.0" fi AC_MSG_RESULT([building connector for \"$WEBSERVER\"]) AC_SUBST(APXS) dnl apache_dir and apache_include are also needed. apache_dir=`$APXS -q PREFIX` apache_include="-I`$APXS -q INCLUDEDIR`" fi fi ], [ AC_MSG_RESULT(no apxs given) ]) ])dnl dnl dnl check for apache (static link). dnl AC_DEFUN(JTC_CHECK_APACHE,[ dnl it is copied from the configure of JServ ;=) dnl and adapted. apache_dir_is_src="false" AC_ARG_WITH(apache, [ --with-apache=DIR Build static Apache module. DIR is the pathname to the Apache source directory.], [ if ${TEST} ! -z "$WEBSERVER" ; then AC_MSG_ERROR([Sorry cannot use --with-apxs=${APXS} and --with-apache=${withval} togother, please choose one of both]) fi AC_MSG_CHECKING([for Apache source directory (assume static build)]) if ${TEST} -n "${withval}" && ${TEST} -d "${withval}" ; then if ${TEST} -d "${withval}/src" ; then # handle the case where people use relative paths to # the apache source directory by pre-pending the current # build directory to the path. there are probably # errors with this if configure is run while in a # different directory than what you are in at the time if ${TEST} -n "`${ECHO} ${withval}|${GREP} \"^\.\.\"`" ; then withval=`pwd`/${withval} fi apache_dir=${withval} apache_dir_is_src="true" AC_MSG_RESULT(${apache_dir}) AC_MSG_CHECKING(for Apache include directory) if ${TEST} -d "${withval}/src/include" ; then # read osdir from the existing apache. osdir=`${GREP} '^OSDIR=' ${withval}/src/Makefile.config | ${SED} -e 's:^OSDIR=.*/os:os:'` if ${TEST} -z "${osdir}" ; then osdir=os/unix fi apache_include="-I${withval}/src/include \ -I${withval}/src/${osdir}" WEBSERVER="apache-1.3" AC_MSG_RESULT([${apache_include}, version 1.3]) else AC_MSG_ERROR([Sorry Apache 1.2.x is no longer supported.]) fi else if ${TEST} -d "${withval}/include" ; then # osdir for Apache20. WEBSERVER="apache-2.0" apache_dir=${withval} apache_dir_is_src="true" AC_MSG_RESULT(${apache_dir}) fi fi fi dnl Make sure we have a result. if ${TEST} -z "$WEBSERVER" ; then AC_MSG_ERROR([Directory $apache_dir is not a valid Apache source distribution]) fi # VT: Now, which one I'm supposed to use? Let's figure it out later configure_apache=true configure_src=true AC_MSG_RESULT([building connector for \"$WEBSERVER\"]) ], [ AC_MSG_RESULT(no apache given) ]) AC_SUBST(apache_include) APACHE_DIR=${apache_dir} AC_SUBST(APACHE_DIR) ]) dnl dnl check for EAPI (static link only). dnl AC_DEFUN(JTC_CHECK_EAPI,[ dnl CFLAGS for EAPI mod_ssl (Apache 1.3) dnl it also allows the CFLAGS environment variable. CFLAGS="${CFLAGS}" AC_ARG_ENABLE( EAPI, [ --enable-EAPI Enable EAPI support (mod_ssl, Apache 1.3)], [ case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DEAPI" AC_MSG_RESULT([...Enabling EAPI Support...]) ;; esac ]) AC_SUBST(CFLAGS) ]) dnl dnl set flags for apxs. dnl AC_DEFUN(JTC_SET_APXS_FLAGS,[ dnl the APXSCFLAGS is given by apxs to the C compiler dnl the APXSLDFLAGS is given to the linker (for APRVARS). APXSLDFLAGS="" APXSCFLAGS="" if ${TEST} -n "${CFLAGS}" ; then APXSCFLAGS="${CFLAGS}" fi dnl the APXSLDFLAGS is normaly empty but APXSCFLAGS is not. if ${TEST} -n "${LDFLAGS}" ; then APXSLDFLAGS="-Wl,${LDFLAGS}" fi AC_SUBST(APXSCFLAGS) AC_SUBST(APXSLDFLAGS) ]) tomcat-connectors-1.2.50-src/support/os_apache.m40000644000000000000020000000250714655113617020230 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl copied from httpd-2.0/os/config.m4 dnl OS changed to OS_APACHE and OS_DIR to OS_APACHE_DIR AC_MSG_CHECKING(for target platform) #PLATFORM=`${CONFIG_SHELL-/bin/sh} $ac_config_guess` PLATFORM=$host case "$PLATFORM" in *beos*) OS_APACHE="beos" OS_APACHE_DIR=$OS_APACHE ;; *pc-os2_emx*) OS_APACHE="os2" OS_APACHE_DIR=$OS_APACHE ;; bs2000*) OS_APACHE="unix" OS_APACHE_DIR=bs2000 # only the OS_APACHE_DIR is platform specific. ;; *) OS_APACHE="unix" OS_APACHE_DIR=$OS_APACHE;; esac AC_MSG_RESULT($OS_APACHE) tomcat-connectors-1.2.50-src/support/jk_pcre.m40000644000000000000020000000233414655113617017721 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl AC_DEFUN( [JK_PCRE], [ AC_ARG_WITH(pcre, [ --with-pcre Build pcre support], [ case "${withval}" in y | yes | true) use_pcre=true ;; n | no | false) use_pcre=false ;; *) use_pcre=true ;; esac if ${TEST} ${use_pcre} ; then HAS_PCRE="-I${includedir} -DHAS_PCRE" PCRE_LIBS="-L${libdir} -lpcre -lpcreposix" fi ]) ]) dnl vi:set sts=2 sw=2 autoindent: tomcat-connectors-1.2.50-src/support/jk_apxs.m40000644000000000000020000001262114655113617017743 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl -------------------------------------------------------------------------- dnl Author Henri Gomez dnl dnl Inspired by Pier works on webapp m4 macros :) dnl -------------------------------------------------------------------------- dnl -------------------------------------------------------------------------- dnl JK_APXS dnl dnl Get APXS to be used, determine if Apache 1.3 or 2.0 are target dnl $1 => blank/2 if you want to detect Apache 1.3 & 2.0 dnl $2 => comment for --with-apxs dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_APXS], [ tempval="" AC_ARG_WITH(apxs$1, [ --with-apxs$1[=FILE] $2], [ case "${withval}" in y | yes | true) find_apxs=true ;; n | no | false) find_apxs=false ;; *) find_apxs=false ;; esac if ${TEST} ${find_apxs} ; then AC_MSG_RESULT([need to check for Perl first, apxs depends on it...]) AC_PATH_PROG(PERL,perl,$PATH)dnl if ${TEST} ${find_apxs} ; then APXS$1=${withval} else AC_PATH_PROG(APXS$1,apxs$1,$PATH)dnl fi use_apxs$1=true; if ${TEST} -n "${APXS$1}" ; then dnl Seems that we have it, but have to check if it is OK first if ${TEST} ! -x "${APXS$1}" ; then AC_MSG_ERROR(Invalid location for apxs: '${APXS$1}') fi ${APXS$1} -q PREFIX >/dev/null 2>/dev/null || apxs_support=false if ${TEST} "${apxs_support}" = "false" ; then AC_MSG_RESULT(could not find ${APXS$1}) AC_MSG_ERROR(You must specify a valid --with-apxs$1 path) fi dnl apache_dir and apache_include are also needed. APACHE$1_HOME=`${APXS$1} -q PREFIX` APACHE$1_INCL="-I`${APXS$1} -q INCLUDEDIR`" APACHE$1_INCDIR="`${APXS$1} -q INCLUDEDIR`" APACHE$1_LIBEXEC="`${APXS$1} -q LIBEXECDIR`" APACHE$1_CC="`${APXS$1} -q CC`" dnl test apache version APA=`${GREP} STANDARD20 ${APXS$1}` dnl check if we have an apxs for Apache 1.3 or 2.0 if ${TEST} -z "$APA" ; then if ${TEST} ! -z "$1" ; then AC_MSG_ERROR(Do not use --with-apxs$1 but --with-apxs) fi WEBSERVERS="${WEBSERVERS} server/apache13" RWEBSERVER="apache-1.3" APXS$1_CFLAGS="`${APXS$1} -q CFLAGS`" APXS$1_CPPFLAGS="" else if ${TEST} -z "$1" ; then AC_MSG_ERROR(Do not use --with-apxs but --with-apxs2) fi WEBSERVERS="${WEBSERVERS} server/apache2" RWEBSERVER="apache-2.0" APACHE2_CONFIG_VARS=${apache_dir}/build/config_vars.mk JK_CHANNEL_APR_SOCKET="\${JK}jk_channel_apr_socket\${OEXT}" JK_POOL_APR="\${JK}jk_pool_apr\${OEXT}" APXS$1_CFLAGS="`${APXS$1} -q CFLAGS` `${APXS$1} -q EXTRA_CFLAGS`" APXS$1_CPPFLAGS="`${APXS$1} -q EXTRA_CPPFLAGS`" APR_INCDIR="-I`${APXS$1} -q APR_INCLUDEDIR`" APR_UTIL_INCDIR="-I`${APXS$1} -q APU_INCLUDEDIR`" APACHE2_LIBDIR="`${APXS$1} -q LIBDIR`" LIBTOOL=`${APXS$1} -q LIBTOOL` if ${TEST} -f ${APACHE2_LIBDIR}/libapr-1.so \ -o -f ${APACHE2_LIBDIR}/libapr-1.sl \ -o -f ${APACHE2_LIBDIR}/libapr-1.dylib; then APR_LIBS="-L${APACHE2_LIBDIR} -lapr-1" elif ${TEST} -f ${APACHE2_LIBDIR}/libapr-0.so \ -o -f ${APACHE2_LIBDIR}/libapr-0.sl \ -o -f ${APACHE2_LIBDIR}/libapr-0.dylib; then APR_LIBS="-L${APACHE2_LIBDIR} -lapr-0" elif ${TEST} -f ${APACHE2_LIBDIR}/libapr.so \ -o -f ${APACHE2_LIBDIR}/libapr.sl \ -o -f ${APACHE2_LIBDIR}/libapr.dylib; then APR_LIBS="-L${APACHE2_LIBDIR} -lapr" else AC_MSG_ERROR(can't locate libapr) fi fi AC_MSG_RESULT([building connector for \"$RWEBSERVER\"]) fi fi ], [ AC_MSG_RESULT(no apxs$1 given) ]) unset tempval AC_SUBST(APXS$1) AC_SUBST(APXS$1_CFLAGS) AC_SUBST(APACHE$1_CONFIG_VARS) AC_SUBST(APXS$1_CPPFLAGS) AC_SUBST(APACHE$1_DIR) AC_SUBST(APACHE$1_HOME) AC_SUBST(APACHE$1_INCDIR) AC_SUBST(APACHE$1_INCL) AC_SUBST(APACHE$1_LIBEXEC) AC_SUBST(APACHE$1_LIBDIR) AC_SUBST(APACHE$1_CC) AC_SUBST(APXS$1_LDFLAGS) AC_SUBST(APR_LIBS) ]) dnl vi:set sts=2 sw=2 autoindent: tomcat-connectors-1.2.50-src/support/get_ver.awk0000644000000000000020000000571514655113617020207 0ustar rootbinBEGIN { # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # fetch mod_jk version numbers from input file and writes them to STDOUT while ((getline < ARGV[1]) > 0) { if (match ($0, /^#define JK_VERMAJOR [^"]+/)) { jk_ver_major = substr($3, 1, length($3)); } else if (match ($0, /^#define JK_VERMINOR [^"]+/)) { jk_ver_minor = substr($3, 1, length($3)); } else if (match ($0, /^#define JK_VERFIX [^"]+/)) { jk_ver_fix = substr($3, 1, length($3)); } else if (match ($0, /^#define JK_VERISRELEASE [^"]+/)) { jk_ver_isrelease = substr($3, 1, length($3)); } else if (match ($0, /^#define JK_VERBETA [^"]+/)) { jk_ver_isbeta = substr($3, 1, length($3)); } else if (match ($0, /^#define JK_BETASTRING [^"]+/)) { jk_ver_betastr = substr($3, 2, length($3) - 2); } } jk_ver = jk_ver_major "," jk_ver_minor "," jk_ver_fix; jk_ver_str = jk_ver_major "." jk_ver_minor "." jk_ver_fix; if (jk_ver_isrelease != 1) { jk_ver_str = jk_ver_str "-dev"; } if (jk_ver_isbeta == 1) { jk_ver_str = jk_ver_str "-beta-" jk_ver_betastr; } # fetch Apache version numbers from input file and writes them to STDOUT if (ARGV[2]) { if (match (ARGV[2], /ap_release.h/)) { while ((getline < ARGV[2]) > 0) { if (match ($0, /^#define AP_SERVER_MAJORVERSION "[^"]+"/)) { ap_ver_major = substr($3, 2, length($3) - 2); } else if (match ($0, /^#define AP_SERVER_MINORVERSION "[^"]+"/)) { ap_ver_minor = substr($3, 2, length($3) - 2); } else if (match ($0, /^#define AP_SERVER_PATCHLEVEL/)) { ap_ver_str_patch = substr($3, 2, length($3) - 2); if (match (ap_ver_str_patch, /[0-9][0-9]*/)) { ap_ver_patch = substr(ap_ver_str_patch, RSTART, RLENGTH); } } } ap_ver_str = ap_ver_major "." ap_ver_minor "." ap_ver_str_patch; } if (match (ARGV[2], /httpd.h/)) { while ((getline < ARGV[2]) > 0) { if (match ($0, /^#define SERVER_BASEREVISION "[^"]+"/)) { ap_ver_str = substr($3, 2, length($3) - 2); } } } print "AP_VERSION_STR = " ap_ver_str ""; } print "JK_VERSION = " jk_ver ""; print "JK_VERSION_STR = " jk_ver_str ""; } tomcat-connectors-1.2.50-src/support/jk_exec.m40000644000000000000020000000540214655113617017713 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl -------------------------------------------------------------------------- dnl dnl Inspired by Pier works on webapp m4 macros :) dnl -------------------------------------------------------------------------- dnl -------------------------------------------------------------------------- dnl JK_EXEC dnl Execute a program filtering its output (pretty printing). dnl dnl Parameters: dnl $1 => name of the variable containing the return value (error code). dnl $2 => name of the binary/script to invoke dnl $3 => message used for pretty printing output dnl $4 => the directory where the command must be executed dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_EXEC], [ jk_exec_curdir="`pwd`" if test -d "$4" ; then cd "$4" else AC_MSG_ERROR([can't switch to directory $4]) fi echo " invoking \"$2\"" echo " in directory \"$4\"" echo "-1" > retvalue.tmp set $2 jk_exec_file=[$]1 if test ! -x "${jk_exec_file}" ; then cd "${jk_exec_curdir}" AC_MSG_ERROR([cannot find or execute \"${jk_exec_file}\" in \"$4\"]) exit 1 fi unset jk_exec_file { $2 echo echo "jk_exec_retvalue $?" } | { jk_exec_ret=0 while true ; do read jk_exec_first jk_exec_line if test ! "$?" -eq "0" ; then break else if test "${jk_exec_first}" = "jk_exec_retvalue" ; then jk_exec_ret="${jk_exec_line}" else if test -n "${jk_exec_line}" ; then echo " $3: ${jk_exec_first} ${jk_exec_line}" fi fi fi done echo "${jk_exec_ret}" > retvalue.tmp unset jk_exec_first unset jk_exec_line unset jk_exec_ret } $1="`cat retvalue.tmp`" rm -f retvalue.tmp echo " execution of \"$2\"" echo " returned with value \"${$1}\"" cd "${jk_exec_curdir}" unset jk_exec_curdir ]) tomcat-connectors-1.2.50-src/support/jk_apr.m40000644000000000000020000002355514655113617017562 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl -------------------------------------------------------------------------- dnl Author Henri Gomez dnl dnl Inspired by Pier works on webapp m4 macros :) dnl -------------------------------------------------------------------------- dnl -------------------------------------------------------------------------- dnl JK_APR_THREADS dnl Configure APR threading for use with --with-apr. dnl Result goes into APR_CONFIGURE_ARGS dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_APR_THREADS], [ AC_ARG_ENABLE( [apr-threads], [ --enable-apr-threads Configure APR threading for use with --with-apr ], [ case "${enableval}" in ""|"yes"|"YES"|"true"|"TRUE") APR_CONFIGURE_ARGS="--enable-threads ${APR_CONFIGURE_ARGS}" ;; "no"|"NO"|"false"|"FALSE") APR_CONFIGURE_ARGS="--disable-threads ${APR_CONFIGURE_ARGS}" ;; *) APR_CONFIGURE_ARGS="--enable-threads=${enableval} ${APR_CONFIGURE_ARGS}" esac ]) ]) dnl -------------------------------------------------------------------------- dnl JK_APR dnl Set the APR source dir. dnl $1 => File which should be present dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_APR], [ tempval="" AC_ARG_WITH( [apr], [ --with-apr=DIR Location of APR source dir ], [ case "${withval}" in ""|"yes"|"YES"|"true"|"TRUE") AC_MSG_ERROR(valid apr source dir location required) ;; "no"|"NO"|"false"|"FALSE") AC_MSG_ERROR(valid apr source dir location required) ;; *) tempval="${withval}" if ${TEST} ! -d ${tempval} ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi if ${TEST} ! -f ${tempval}/$1; then AC_MSG_ERROR(can't locate ${tempval}/$1) fi if ${TEST} ! -z "$tempval" ; then APR_BUILD="apr-build" APR_CFLAGS="-I ${tempval}/include" APR_CLEAN="apr-clean" APR_DIR=${tempval} APR_INCDIR="${tempval}/include" AC_MSG_RESULT(configuring apr...) tempret="0" JK_EXEC( [tempret], [${SHELL} ./configure --prefix=${APR_DIR} --with-installbuilddir=${APR_DIR}/instbuild --disable-shared ${APR_CONFIGURE_ARGS}], [apr], [${APR_DIR}]) if ${TEST} "${tempret}" = "0"; then AC_MSG_RESULT(apr configure ok) else AC_MSG_ERROR(apr configure failed with ${tempret}) fi JK_APR_LIBNAME(apr_libname,${APR_DIR}) APR_LDFLAGS="${APR_DIR}/lib/${apr_libname}" APR_LIBDIR="" use_apr=true COMMON_APR_OBJECTS="\${COMMON_APR_OBJECTS}" fi ;; esac ]) unset tempret unset tempval unset apr_libname ]) dnl -------------------------------------------------------------------------- dnl JK_APR_UTIL dnl Set the APR-UTIL source dir. dnl $1 => File which should be present dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_APR_UTIL], [ tempval="" AC_ARG_WITH( [apr-util], [ --with-apr-util=DIR Location of APR-UTIL source dir ], [ case "${withval}" in ""|"yes"|"YES"|"true"|"TRUE") AC_MSG_ERROR(valid apr-util source dir location required) ;; "no"|"NO"|"false"|"FALSE") AC_MSG_ERROR(valid apr-util source dir location required) ;; *) tempval="${withval}" if ${TEST} ! -d ${tempval} ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi if ${TEST} ! -f ${tempval}/$1; then AC_MSG_ERROR(can't locate ${tempval}/$1) fi if ${TEST} -z "${APR_BUILD}"; then AC_MSG_ERROR([--with-apr and --with-apr-util must be used together]) fi if ${TEST} ! -z "$tempval" ; then APR_UTIL_DIR=${tempval} APR_CFLAGS="${APR_CFLAGS} -I ${APR_UTIL_DIR}/include" APR_UTIL_INCDIR="${APR_UTIL_DIR}/include" AC_MSG_RESULT(configuring apr-util...) tempret="0" JK_EXEC( [tempret], [${SHELL} ./configure --prefix=${APR_UTIL_DIR} --with-apr=${APR_DIR}], [apr-util], [${APR_UTIL_DIR}]) if ${TEST} "${tempret}" = "0"; then AC_MSG_RESULT(apr-util configure ok) else AC_MSG_ERROR(apr-util configure failed with ${tempret}) fi JK_APR_UTIL_LIBNAME(apr_util_libname,${APR_UTIL_DIR}) APR_LDFLAGS="${APR_LDFLAGS} ${APR_UTIL_DIR}/lib/${apr_util_libname}" APR_UTIL_LIBDIR="" use_apr=true COMMON_APR_OBJECTS="\${COMMON_APR_OBJECTS}" fi ;; esac ]) unset tempret unset tempval unset apr_util_libname ]) dnl -------------------------------------------------------------------------- dnl JK_APR_INCDIR dnl Set the APR include dir. dnl $1 => File which should be present dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_APR_INCDIR], [ tempval="" AC_ARG_WITH( [apr-include], [ --with-apr-include=DIR Location of APR include dir ], [ case "${withval}" in ""|"yes"|"YES"|"true"|"TRUE") ;; "no"|"NO"|"false"|"FALSE") AC_MSG_ERROR(valid apr include dir location required) ;; *) tempval="${withval}" if ${TEST} ! -d ${tempval} ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi if ${TEST} ! -f ${tempval}/$1; then AC_MSG_ERROR(can't locate ${tempval}/$1) fi if ${TEST} ! -z "$tempval" ; then APR_BUILD="" APR_CFLAGS="-I${tempval}" APR_CLEAN="" APR_DIR="" APR_INCDIR=${tempval} COMMON_APR_OBJECTS="\${COMMON_APR_OBJECTS}" use_apr=true fi ;; esac ]) unset tempval ]) dnl -------------------------------------------------------------------------- dnl JK_APR_LIBDIR dnl Set the APR library dir. dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_APR_LIBDIR], [ tempval="" AC_ARG_WITH( [apr-lib], [ --with-apr-lib=DIR Location of APR lib dir ], [ case "${withval}" in ""|"yes"|"YES"|"true"|"TRUE") ;; "no"|"NO"|"false"|"FALSE") AC_MSG_ERROR(valid apr lib dir location required) ;; *) tempval="${withval}" if ${TEST} ! -d ${tempval} ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi if ${TEST} ! -z "$tempval" ; then APR_BUILD="" APR_CLEAN="" APR_DIR="" APR_LIBDIR=${tempval} APR_LDFLAGS="`apr-config --link-ld` -L${tempval}" COMMON_APR_OBJECTS="\${COMMON_APR_OBJECTS}" use_apr=true fi ;; esac ]) unset tempval ]) dnl -------------------------------------------------------------------------- dnl JK_APR_LIBNAME dnl Retrieve the complete name of the library. dnl $1 => Environment variable name for the returned value dnl $2 => APR sources directory dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_APR_LIBNAME], [ AC_MSG_CHECKING([for apr APR_LIBNAME]) if ${TEST} ! -f "$2/apr-config" ; then AC_MSG_ERROR([cannot find apr-config file in $2]) fi jk_apr_get_tempval=`$2/apr-config --link-libtool 2> /dev/null` if ${TEST} -z "${jk_apr_get_tempval}" ; then AC_MSG_ERROR([$2/apr-config --link-libtool failed]) fi jk_apr_get_tempval=`basename ${jk_apr_get_tempval}` $1="${jk_apr_get_tempval}" AC_MSG_RESULT([${jk_apr_get_tempval}]) unset jk_apr_get_tempval ]) dnl -------------------------------------------------------------------------- dnl JK_APR_UTIL_LIBNAME dnl Retrieve the complete name of the library. dnl $1 => Environment variable name for the returned value dnl $2 => APR_UTIL sources directory dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_APR_UTIL_LIBNAME], [ AC_MSG_CHECKING([for apr-util APR_UTIL_LIBNAME]) if ${TEST} ! -f "$2/apu-config" ; then AC_MSG_ERROR([cannot find apu-config file in $2]) fi jk_apu_get_tempval=`$2/apu-config --link-libtool 2> /dev/null` if ${TEST} -z "${jk_apu_get_tempval}" ; then AC_MSG_ERROR([$2/apu-config --link-libtool failed]) fi jk_apu_get_tempval=`basename ${jk_apu_get_tempval}` $1="${jk_apu_get_tempval}" AC_MSG_RESULT([${jk_apu_get_tempval}]) unset jk_apu_get_tempval ]) dnl vi:set sts=2 sw=2 autoindent: tomcat-connectors-1.2.50-src/support/jk_java.m40000644000000000000020000001453014655113617017712 0ustar rootbindnl dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl -------------------------------------------------------------------------- dnl Author Henri Gomez dnl dnl Inspired by Pier works on webapp m4 macros :) dnl -------------------------------------------------------------------------- dnl -------------------------------------------------------------------------- dnl JK_JDK dnl dnl Detection of JDK location and Java Platform (1.1, 1.2, 1.3, 1.4) dnl result goes in JAVA_HOME / JAVA_PLATFORM (1 -> 1.1, 2 -> 1.2 and higher) dnl dnl -------------------------------------------------------------------------- AC_DEFUN( [JK_JNI], [ AC_ARG_WITH(jni, [ --with-jni Build jni support], [ case "${withval}" in y | yes | true) use_jni=true ;; n | no | false) use_jni=false ;; *) use_jni=true ;; esac if ${TEST} "${use_jni}" = "true"; then HAVE_JNI="-DHAVE_JNI" JNI_BUILD="jni-build" fi ]) ]) AC_DEFUN( [JK_JDK], [ if ${TEST} "${use_jni}" = "true"; then tempval="" AC_MSG_CHECKING([for JDK location (please wait)]) if ${TEST} -n "${JAVA_HOME}" ; then JAVA_HOME_ENV="${JAVA_HOME}" else JAVA_HOME_ENV="" fi JAVA_HOME="" JAVA_PLATFORM="" AC_ARG_WITH( [java-home], [ --with-java-home=DIR Location of JDK directory.], [ # This stuff works if the command line parameter --with-java-home was # specified, so it takes priority rightfully. tempval=${withval} if ${TEST} ! -d "${tempval}" ; then AC_MSG_ERROR(Not a directory: ${tempval}) fi JAVA_HOME=${tempval} AC_MSG_RESULT(${JAVA_HOME}) ], [ # This works if the parameter was NOT specified, so it's a good time # to see what the enviroment says. # Since Sun uses JAVA_HOME a lot, we check it first and ignore the # JAVA_HOME, otherwise just use whatever JAVA_HOME was specified. if ${TEST} -n "${JAVA_HOME_ENV}" ; then JAVA_HOME=${JAVA_HOME_ENV} AC_MSG_RESULT(${JAVA_HOME_ENV} from environment) fi ]) if ${TEST} -z "${JAVA_HOME}" ; then # Oh well, nobody set neither JAVA_HOME nor JAVA_HOME, have to guess # The following code is based on the code submitted by Henner Zeller # for ${srcdir}/src/scripts/package/rpm/ApacheJServ.spec # Two variables will be set as a result: # # JAVA_HOME # JAVA_PLATFORM AC_MSG_CHECKING([Try to guess JDK location]) for JAVA_PREFIX in /usr/local /usr/local/lib /usr /usr/lib /opt /usr/java ; do for JAVA_PLATFORM in 4 3 2 1 ; do for subversion in .9 .8 .7 .6 .5 .4 .3 .2 .1 "" ; do for VARIANT in IBMJava2- java java- jdk jdk-; do GUESS="${JAVA_PREFIX}/${VARIANT}1.${JAVA_PLATFORM}${subversion}" dnl AC_MSG_CHECKING([${GUESS}]) if ${TEST} -d "${GUESS}/bin" & ${TEST} -d "${GUESS}/include" ; then JAVA_HOME="${GUESS}" AC_MSG_RESULT([${GUESS}]) break fi done if ${TEST} -n "${JAVA_HOME}" ; then break; fi done if ${TEST} -n "${JAVA_HOME}" ; then break; fi done if ${TEST} -n "${JAVA_HOME}" ; then break; fi done if ${TEST} ! -n "${JAVA_HOME}" ; then AC_MSG_ERROR(can't locate a valid JDK location) fi fi if ${TEST} -n "${JAVA_PLATFORM}"; then AC_MSG_RESULT(Java Platform detected - 1.${JAVA_PLATFORM}) else AC_MSG_CHECKING(Java platform) fi AC_ARG_WITH(java-platform, [ --with-java-platform[=2] Force the Java platform (value is 1 for 1.1.x or 2 for 1.2.x or greater)], [ case "${withval}" in "1"|"2") JAVA_PLATFORM=${withval} ;; *) AC_MSG_ERROR(invalid java platform provided) ;; esac ], [ if ${TEST} -n "${JAVA_PLATFORM}"; then AC_MSG_RESULT(Java Platform detected - 1.${JAVA_PLATFORM}) else AC_MSG_CHECKING(Java platform) fi ]) AC_MSG_RESULT(${JAVA_PLATFORM}) unset tempval else # no jni, then make sure JAVA_HOME is not picked up from env JAVA_HOME="" JAVA_PLATFORM="" fi ]) AC_DEFUN( [JK_JDK_OS], [ if ${TEST} "${use_jni}" = "true"; then tempval="" OS="" AC_ARG_WITH(os-type, [ --with-os-type[=SUBDIR] Location of JDK os-type subdirectory.], [ tempval=${withval} if ${TEST} ! -d "${JAVA_HOME}/${tempval}" ; then AC_MSG_ERROR(Not a directory: ${JAVA_HOME}/${tempval}) fi OS = ${tempval} ], [ AC_MSG_CHECKING(os_type directory) if ${TEST} -f ${JAVA_HOME}/include/jni_md.h; then OS="" else for f in ${JAVA_HOME}/include/*/jni_md.h; do if ${TEST} -f $f; then OS=`dirname ${f}` OS=`basename ${OS}` echo " ${OS}" fi done if ${TEST} -z "${OS}"; then AC_MSG_RESULT(Cannot find jni_md.h in ${JAVA_HOME}/${OS}) AC_MSG_ERROR(You should retry --with-os-type=SUBDIR) fi fi ]) fi ]) dnl vi:set sts=2 sw=2 autoindent: tomcat-connectors-1.2.50-src/native/0000755000000000000020000000000014655113624015610 5ustar rootbintomcat-connectors-1.2.50-src/native/iis/0000755000000000000020000000000014655113617016376 5ustar rootbintomcat-connectors-1.2.50-src/native/iis/isapi_install.vbs0000644000000000000020000001437114655113617021753 0ustar rootbin' ' Licensed to the Apache Software Foundation (ASF) under one or more ' contributor license agreements. See the NOTICE file distributed with ' this work for additional information regarding copyright ownership. ' The ASF licenses this file to You under the Apache License, Version 2.0 ' (the "License"); you may not use this file except in compliance with ' the License. You may obtain a copy of the License at ' ' http://www.apache.org/licenses/LICENSE-2.0 ' ' Unless required by applicable law or agreed to in writing, software ' distributed under the License is distributed on an "AS IS" BASIS, ' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ' See the License for the specific language governing permissions and ' limitations under the License. ' ' ========================================================================= ' Description: Install script for Tomcat ISAPI redirector ' Author: Peter S. Horne ' ========================================================================= ' ' This script automatically installs the tomcat isapi_redirector for use in ' both out-of and in-process installations on IIS/Win2K. See the command line ' usage section for usage instructions. ' ' Check the command line ' set args = wscript.arguments if args.count <> 6 then info "" info "Tomcat ISAPI Redirector Installation Utility" info "usage: isapi_install " info " server: The Web Server Name (for example 'Default Web Site')" info " fdir: the full path to the directory that contains the isapi filter" info " worker: Full path and file name of the worker properties file" info " mount: Full path and file name of the worker mount properties file" info " log: Full path and file name of the log file" info " level: The log level emerg | info" info "(Re-runs are ok and will change/reset settings)" info "" fail "Incorrect Arguments" end if ' Setup the args serverName = args(0) filterDir = args(1) filterName = "jakarta" filterLib = "\isapi_redirect.dll" workerFile = args(2) mountFile = args(3) logFile = args(4) logLevel = args(5) ' ' Get a shell ' dim shell set shell = WScript.CreateObject("WScript.Shell") ' ' Find the indicated server from all the servers in the service ' Note: they aren't all Web! ' set service = GetObject("IIS://LocalHost/W3SVC" ) serverId = "" for each thing in service if thing.Class = "IIsWebServer" then if thing.ServerComment = serverName then set server = thing serverId = thing.name exit for end if end if next if serverId = "" then fail "Server " + serverName + " not found." info "Found Server <" + serverName + "> at index [" + serverId + "]." ' ' Stop everything to release any dlls - needed for a re-install ' ' info "Stopping server <" + serverName + ">..." ' server.stop ' info "Done" ' ' Get a handle to the filters for the server - we process all errors ' On Error Resume Next dim filters set filters = GetObject("IIS://LocalHost/W3SVC/" + serverId + "/Filters") if err then err.clear info "Filters not found for server - creating" set filters = server.create( "IIsFilters", "Filters" ) filters.setInfo if err then fail "Error Creating Filters" end if info "Got Filters" ' ' Create the filter - if it fails then delete it and try again ' name = filterName info "Creating Filter - " + filterName dim filter set filter = filters.Create( "IISFilter", filterName ) if err then err.clear info "Filter exists - deleting" filters.delete "IISFilter", filterName if err then fail "Error Deleting Filter" set filter = filters.Create( "IISFilter", filterName ) if err then fail "Error Creating Filter" end if info "Created Filter" ' ' Set the filter info and save it ' filter.FilterPath = filterDir + filterLib filter.FilterEnabled=true filter.description = filterName filter.notifyOrderHigh = true filter.setInfo ' ' Set the load order - only if it's not in the list already ' on error goto 0 loadOrders = filters.FilterLoadOrder list = Split( loadOrders, "," ) found = false for each item in list if Trim( item ) = filterName then found = true next if found = false then info "Filter is not in load order - adding now." if len(loadOrders) <> 0 then loadOrders = loadOrders + "," filters.FilterLoadOrder = loadOrders + filterName filters.setInfo info "Filter added." else info "Filter already exists in load order - no update required." end if ' ' Set the registry up ' regRoot = "HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0\" err.clear on error resume next shell.RegDelete( regRoot ) if err then info "Entering Registry Information for the first time" else info "Deleted existing Registry Setting" end if on error goto 0 info "Updating Registry" shell.RegWrite regRoot + "extension_uri", "/jakarta/isapi_redirect.dll" shell.RegWrite regRoot + "log_file", logFile shell.RegWrite regRoot + "log_level", logLevel shell.RegWrite regRoot + "worker_file", workerFile shell.RegWrite regRoot + "worker_mount_file", mountFile info "Registry Settings Created" ' ' Finally, create the virtual directory matching th extension uri ' on error goto 0 set root = GetObject( "IIS://LocalHost/W3SVC/" + serverID + "/ROOT" ) on error resume next set vdir = root.Create("IISWebVirtualDir", filterName ) if err then info "Directory exists - deleting" on error resume next root.delete "IISWebVirtualDir", filterName root.setInfo if err then fail "Error Deleting Directory" set vdir = root.create("IISWebVirtualDir", filterName ) if err then fail "Error Creating Directory" end if info "Directory Created" ' Set the directory information - make it an application directory info "Setting Directory Information" vdir.AppCreate2 1 vdir.AccessExecute = TRUE vdir.AppFriendlyName = filterName vdir.AccessRead = false vdir.ContentIndexed = false vdir.Path = filterDir vdir.setInfo if err then fail "Error saving new directory" info "Directory Saved" ' ' Re Start ' ' info "Starting server <" + serverName + ">..." ' server.start ' info "Done" info "All done... Bye." wscript.quit(0) ' ' Helper function for snafus ' function fail( message ) wscript.echo "E: " + message wscript.quit(1) end function ' ' Helper function for info ' function info( message ) wscript.echo " " + message end function tomcat-connectors-1.2.50-src/native/iis/jk_isapi_plugin.c0000644000000000000020000040006414655113617021715 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: ISAPI plugin for IIS/PWS * * Author: Gal Shachor * * Author: Larry Isaacs * * Author: Ignacio J. Ortega * * Author: Mladen Turk * ***************************************************************************/ /* * Define WIN32 API we are going to use. */ #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0502 #endif #include #include #include #include #include #include "jk_global.h" #include "jk_url.h" #include "jk_util.h" #include "jk_map.h" #include "jk_pool.h" #include "jk_service.h" #include "jk_worker.h" #include "jk_uri_worker_map.h" #include "jk_shm.h" #include "jk_ajp13.h" #include "pcre.h" #ifndef POSIX_MALLOC_THRESHOLD #define POSIX_MALLOC_THRESHOLD 10 #endif #ifndef HSE_REQ_SET_FLUSH_FLAG #define HSE_REQ_SET_FLUSH_FLAG (HSE_REQ_END_RESERVED + 43) #endif #include #define VERSION_STRING "Tomcat/ISAPI/" JK_EXPOSED_VERSION #define FULL_VERSION_STRING "Tomcat/ISAPI/" JK_FULL_EXPOSED_VERSION #define SHM_DEF_PREFIX "JK_" #define DEFAULT_WORKER_NAME "ajp13" /* * This is default value found inside httpd.conf * for MaxClients */ #define DEFAULT_WORKER_THREADS 250 #define RES_BUFFER_SIZE 64 #define HDR_BUFFER_SIZE 1024 /* * We use special headers to pass values from the filter to the * extension. These values are: * * 1. The real URI before redirection took place * 2. The name of the worker to be used. * 3. The contents of the Translate header, if any * */ #define URI_HEADER_NAME_BASE "TOMCATURI" #define QUERY_HEADER_NAME_BASE "TOMCATQUERY" #define REQUEST_ID_HEADER_NAME_BASE "TOMCATREQUESTID" #define WORKER_HEADER_NAME_BASE "TOMCATWORKER" #define WORKER_HEADER_INDEX_BASE "TOMCATWORKERIDX" #define TOMCAT_TRANSLATE_HEADER_NAME_BASE "TOMCATTRANSLATE" #ifndef USE_CGI_HEADERS #define CONTENT_LENGTH "CONTENT-LENGTH:" #define ALL_HEADERS "ALL_RAW" #else #define ALL_HEADERS "ALL_HTTP" #endif /* The HTTP_ form of the header for use in ExtensionProc */ #define HTTP_HEADER_PREFIX "HTTP_" #ifdef USE_CGI_HEADERS #define HTTP_HEADER_PREFIX_LEN 5 #endif /* The template used to construct our unique headers * from the base name and module instance */ #define HEADER_TEMPLATE "%s%p:" #define HTTP_HEADER_TEMPLATE HTTP_HEADER_PREFIX "%s%p" static char URI_HEADER_NAME[RES_BUFFER_SIZE]; static char QUERY_HEADER_NAME[RES_BUFFER_SIZE]; static char REQUEST_ID_HEADER_NAME[RES_BUFFER_SIZE]; static char WORKER_HEADER_NAME[RES_BUFFER_SIZE]; static char TOMCAT_TRANSLATE_HEADER_NAME[RES_BUFFER_SIZE]; static char WORKER_HEADER_INDEX[RES_BUFFER_SIZE]; /* The variants of the special headers after IIS adds * "HTTP_" to the front of them */ static char HTTP_URI_HEADER_NAME[RES_BUFFER_SIZE]; static char HTTP_QUERY_HEADER_NAME[RES_BUFFER_SIZE]; static char HTTP_REQUEST_ID_HEADER_NAME[RES_BUFFER_SIZE]; static char HTTP_WORKER_HEADER_NAME[RES_BUFFER_SIZE]; static char HTTP_WORKER_HEADER_INDEX[RES_BUFFER_SIZE]; #define REGISTRY_LOCATION "Software\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0" #define W3SVC_REGISTRY_KEY "SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters" #define EXTENSION_URI_TAG "extension_uri" #define URI_SELECT_TAG "uri_select" #define URI_SELECT_PARSED_VERB "parsed" #define URI_SELECT_UNPARSED_VERB "unparsed" #define URI_SELECT_ESCAPED_VERB "escaped" #define URI_SELECT_PROXY_VERB "proxy" #define URI_REWRITE_TAG "rewrite_rule_file" #define SHM_SIZE_TAG "shm_size" #define WORKER_MOUNT_RELOAD_TAG "worker_mount_reload" #define STRIP_SESSION_TAG "strip_session" #define AUTH_COMPLETE_TAG "auth_complete" #define REJECT_UNSAFE_TAG "reject_unsafe" #define COLLAPSE_SLASHES_TAG "collapse_slashes" #define WATCHDOG_INTERVAL_TAG "watchdog_interval" #define ENABLE_CHUNKED_ENCODING_TAG "enable_chunked_encoding" #define ERROR_PAGE_TAG "error_page" #define FLUSH_PACKETS_TAG "flush_packets" #define REQUEST_ID_HEADER_TAG "request_id_header" #define LOG_ROTATION_TIME_TAG "log_rotationtime" #define LOG_FILESIZE_TAG "log_filesize" /* HTTP standard headers */ #define TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE "Transfer-Encoding: chunked" #define TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE_LEN 26 #define TRANSFER_ENCODING_HEADER_NAME "Transfer-Encoding" #define TRANSFER_ENCODING_HEADER_NAME_LEN 17 #define TRANSFER_ENCODING_IDENTITY_VALUE "identity" #define TRANSFER_ENCODING_CHUNKED_VALUE "chunked" #define TRANSFER_ENCODING_CHUNKED_VALUE_LEN 7 #define CONTENT_LENGTH_HEADER_NAME "Content-Length" #define CONTENT_LENGTH_HEADER_NAME_LEN 14 #define CONNECTION_HEADER_NAME "Connection" #define CONNECTION_CLOSE_VALUE "Close" #define TRANSLATE_HEADER "Translate:" #define TRANSLATE_HEADER_NAME "Translate" #define TRANSLATE_HEADER_NAME_LC "translate" /* HTTP protocol CRLF */ #define CRLF "\r\n" #define CRLF_LEN 2 #define NIL "" /* Transfer-Encoding: chunked content trailer */ #define CHUNKED_ENCODING_TRAILER "0\r\n\r\n" #define CHUNKED_ENCODING_TRAILER_LEN 5 #define BAD_REQUEST -1 #define BAD_PATH -2 #define MAX_SERVERNAME 1024 #define MAX_INSTANCEID 32 /* UUID Template and buffer size */ #define UUID_TEMPLATE "%08X-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X" #define UUID_BUFFER_SIZE 50 char HTML_ERROR_HEAD[] = "\n" "\n" "\n\n" "\n" "\n"; #define HTML_ERROR_BODY_FMT "%s!\n\n\n

%s!

\n

\n%s\n

\n" char HTML_ERROR_TAIL[] = "

\n
 
 
 
 \n" FULL_VERSION_STRING "\n" "
 \n" "


\n" "

\n" "Copyright © 1999-2020 Apache Software Foundation
\n" "All Rights Reserved\n" "

\n\n\n"; static struct error_reasons { int status; const char *reason; const char *title; const char *description; } error_reasons[] = { { 100, "Continue", NULL, NULL }, { 101, "Switching Protocols", NULL, NULL }, { 200, "OK", NULL, NULL }, { 201, "Created", NULL, NULL }, { 202, "Accepted", NULL, NULL }, { 203, "Non-Authoritative Information", NULL, NULL }, { 204, "No Content", NULL, NULL }, { 205, "Reset Content", NULL, NULL }, { 206, "Partial Content", NULL, NULL }, { 300, "Multiple Choices", NULL, NULL }, { 301, "Moved Permanently", NULL, NULL }, { 302, "Moved Temporarily", NULL, NULL }, { 303, "See Other", NULL, NULL }, { 304, "Not Modified", NULL, NULL }, { 305, "Use Proxy", NULL, NULL }, { 400, "Bad Request", "Bad Request", "Your browser (or proxy) sent a request that " "this server could not understand." }, { 401, "Unauthorized", "Access is denied due to invalid credentials", "You do not have permission to view this directory or " "page using the credentials that you supplied." }, { 402, "Payment Required", NULL, NULL }, { 403, "Forbidden", "Access is denied", "You do not have permission to view this directory or page " "using the credentials that you supplied." }, { 404, "Not Found", "The requested URL was not found on this server", "If you entered the URL manually please check your " "spelling and try again." }, { 405, "Method Not Allowed", "HTTP method used to access this page is not allowed", "The page you are looking for cannot be displayed because an " "invalid method (HTTP method) was used to attempt access." }, { 406, "Not Acceptable", "Client browser does not accept the MIME type of the requested page", "The page you are looking for cannot be opened by your browser " "because it has a file name extension that your browser " "does not accept." }, { 407, "Proxy Authentication Required", NULL, "The client must first authenticate itself with the proxy." }, { 408, "Request Timeout", NULL, "The client did not produce a request within the time " "that the server was prepared to wait." }, { 409, "Conflict", NULL, "The request could not be completed due to a conflict with " "the current state of the resource." }, { 410, "Gone", NULL, "The requested resource is no longer available at the " "server and no forwarding address is known." }, { 411, "Length Required", NULL, "The server refuses to accept the request without a " "defined Content-Length." }, { 412, "Precondition Failed", NULL, "The precondition given in one or more of the request " "header fields evaluated to false when it was tested on the server." }, { 413, "Request Entity Too Large", NULL, "The HTTP method does not allow the data transmitted, " "or the data volume exceeds the capacity limit." }, { 414, "Request-URI Too Long", "Submitted URI too large", "The length of the requested URL exceeds the capacity limit " "for this server. The request cannot be processed." }, { 415, "Unsupported Media Type", NULL, "The server is refusing to service the request because the " "entity of the request is in a format not supported by the " "requested resource for the requested method." }, { 500, "Internal Server Error", NULL, "The server encountered an internal error and was " "unable to complete your request." }, { 501, "Not Implemented", NULL, "The server does not support the functionality required " "to fulfill the request." }, { 502, "Bad Gateway", NULL, "There is a problem with the page you are looking for, " "and it cannot be displayed. When the Web server (while " "acting as a gateway or proxy) contacted the upstream content " "server, it received an invalid response from the content server." }, { 503, "Service Unavailable", "Service Temporarily Unavailable", "The server is temporarily unable to service your " "request due to maintenance downtime or capacity problems. " "Please try again later." }, { 504, "Gateway Timeout", NULL, "The server, while acting as a gateway or proxy, " "did not receive a timely response from the upstream server." }, { 505, "HTTP Version Not Supported", NULL, "The server does not support, or refuses to support, the " "HTTP protocol version that was used in the request message." }, { 0, NULL, NULL, NULL } }; #define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)") #define JK_TOLOWER(x) ((char)tolower((BYTE)(x))) #define ISIZEOF(X) (int)sizeof(X) #define GET_SERVER_VARIABLE_VALUE(name, place, def) \ do { \ (place) = dup_server_value(private_data->lpEcb, \ (name), \ &private_data->p, \ def); \ } while(0) #define GET_SERVER_VARIABLE_VALUE_INT(name, place, def) \ do { \ char _tb[RES_BUFFER_SIZE]; \ if (get_server_value(private_data->lpEcb, \ (name), \ _tb, \ RES_BUFFER_SIZE)) { \ (place) = atoi(_tb); \ if (((place) == 0) && (errno == EINVAL || \ errno == ERANGE)) { \ (place) = def; \ } \ } \ else { \ (place) = def; \ } } while(0) static char dll_file_path[MAX_PATH]; static char ini_file_name[MAX_PATH]; static char ini_mutex_name[MAX_PATH]; static int using_ini_file = JK_FALSE; static HANDLE init_cs = NULL; static volatile int is_inited = JK_FALSE; static volatile int is_mapread = JK_FALSE; static BOOL dll_process_detach = FALSE; static jk_uri_worker_map_t *uw_map = NULL; static jk_map_t *workers_map = NULL; static jk_map_t *rewrite_map = NULL; static jk_map_t *rregexp_map = NULL; static jk_map_t *jk_environment_map = NULL; static jk_logger_t *logger = NULL; static JK_CRIT_SEC log_cs; static char *CONTENT_TYPE = "Content-Type:text/html\r\n\r\n"; static char extension_uri[INTERNET_MAX_URL_LENGTH]; static char log_file[MAX_PATH * 2]; static char log_file_effective[MAX_PATH * 2]; static int log_level = JK_LOG_DEF_LEVEL; static long log_rotationtime = 0; static time_t log_next_rotate_time = 0; static ULONGLONG log_filesize = 0; static char shm_loaded_name[MAX_PATH] = {0}; static char worker_file[MAX_PATH * 2]; static char worker_mount_file[MAX_PATH * 2] = {0}; static int worker_mount_reload = JK_URIMAP_DEF_RELOAD; static char rewrite_rule_file[MAX_PATH * 2] = {0}; static int shm_config_size = -1; static int strip_session = 0; static int use_auth_notification_flags = 1; static int chunked_encoding_enabled = JK_FALSE; static int reject_unsafe = 0; static volatile int watchdog_interval = 0; static HANDLE watchdog_handle = NULL; static char error_page_buf[INTERNET_MAX_URL_LENGTH] = {0}; static char *error_page = NULL; static int flush_packets = JK_FALSE; static char request_id_header_buf[HDR_BUFFER_SIZE] = {0}; static char *request_id_header = NULL; static char *request_id_header_colon = NULL; #define URI_SELECT_OPT_PARSED 0 #define URI_SELECT_OPT_UNPARSED 1 #define URI_SELECT_OPT_ESCAPED 2 #define URI_SELECT_OPT_PROXY 3 static int uri_select_option = URI_SELECT_OPT_PROXY; static jk_worker_env_t worker_env; typedef struct isapi_private_data_t isapi_private_data_t; struct isapi_private_data_t { jk_pool_t p; unsigned int bytes_read_so_far; int chunk_content; /* Whether we're responding with Transfer-Encoding: chunked content */ char *err_hdrs; LPEXTENSION_CONTROL_BLOCK lpEcb; }; typedef struct isapi_log_data_t isapi_log_data_t; struct isapi_log_data_t { char uri[INTERNET_MAX_URL_LENGTH]; char query[INTERNET_MAX_URL_LENGTH]; int request_matched; /* Whether this request (within a multi-request connection) was handled and needs the log values adjusted */ }; typedef struct iis_info_t iis_info_t; struct iis_info_t { int major; /* The major version */ int minor; /* The minor version */ DWORD filter_notify_event; /* The primary filter SF_NOTIFY_* event */ }; static iis_info_t iis_info; static int JK_METHOD start_response(jk_ws_service_t *s, int status, const char *reason, const char *const *header_names, const char *const *header_values, unsigned int num_of_headers); static int JK_METHOD iis_read(jk_ws_service_t *s, void *b, unsigned int l, unsigned int *a); static int JK_METHOD iis_write(jk_ws_service_t *s, const void *b, unsigned int l); static int JK_METHOD iis_done(jk_ws_service_t *s); static int init_ws_service(isapi_private_data_t * private_data, jk_ws_service_t *s, char **worker_name); static int init_jk(char *serverName); static int JK_METHOD iis_log_to_file(jk_logger_t *l, int level, int used, char *what); static BOOL initialize_extension(void); static int read_registry_init_data(jk_log_context_t *log_ctx); static int get_config_parameter(LPVOID src, const char *tag, char *val, size_t sz); static int get_config_bool(LPVOID src, const char *tag, int def); static int get_config_int(LPVOID src, const char *tag, int def); static int get_registry_config_parameter(HKEY hkey, const char *tag, char *b, size_t sz); static int get_registry_config_number(HKEY hkey, const char *tag, int *val); static BOOL get_server_value(LPEXTENSION_CONTROL_BLOCK lpEcb, char *name, char *buf, size_t bufsz); static char *dup_server_value(LPEXTENSION_CONTROL_BLOCK lpEcb, const char *name, jk_pool_t *p, const char *def); static int base64_encode_cert_len(int len); static int base64_encode_cert(char *encoded, const char *string, int len); static int get_iis_info(iis_info_t *info); static int isapi_write_client(isapi_private_data_t *p, const char *buf, unsigned int write_length, jk_log_context_t *log_ctx); static char *path_merge(const char *root, const char *path); static int is_path_relative(const char *path); static char x2c(const char *what) { register char digit; digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); digit *= 16; digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); return (digit); } static int unescape_url(char *url) { register int x, y, badesc, badpath; badesc = 0; badpath = 0; for (x = 0, y = 0; url[y]; ++x, ++y) { if (url[y] != '%') url[x] = url[y]; else { if (!isxdigit(url[y + 1]) || !isxdigit(url[y + 2])) { badesc = 1; url[x] = '%'; } else { url[x] = x2c(&url[y + 1]); y += 2; if (url[x] == '/' || url[x] == '\0') badpath = 1; } } } url[x] = '\0'; if (badesc) return BAD_REQUEST; else if (badpath) return BAD_PATH; else return 0; } /* Apache code to escape a URL */ #define T_OS_ESCAPE_PATH (4) static const BYTE test_char_table[256] = { 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 7, 6, 1, 6, 1, 1, 9, 9, 1, 0, 8, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 15, 15, 8, 15, 15, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 7, 15, 1, 14, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }; #define TEST_CHAR(c, f) (test_char_table[(unsigned int)(c)] & (f)) static const char c2x_table[] = "0123456789abcdef"; static BYTE *c2x(unsigned int what, BYTE *where) { *where++ = '%'; *where++ = c2x_table[what >> 4]; *where++ = c2x_table[what & 0xf]; return where; } static const char *status_reason(int status) { struct error_reasons *r; r = error_reasons; while (r->status <= status) { if (r->status == status) return r->reason; else r++; } return "No Reason"; } static const char *status_title(int status) { struct error_reasons *r; r = error_reasons; while (r->status <= status) { if (r->status == status) { if (r->title) return r->title; else return r->reason; } else r++; } return "Unknown Error"; } static const char *status_description(int status) { struct error_reasons *r; r = error_reasons; while (r->status <= status) { if (r->status == status) { if (r->description) return r->description; else return r->reason; } else r++; } return "Unknown Error"; } static int escape_url(const char *path, char *dest, int destsize) { const BYTE *s = (const BYTE *)path; BYTE *d = (BYTE *)dest; BYTE *e = d + destsize - 1; BYTE *ee = d + destsize - 3; while (*s) { if (TEST_CHAR(*s, T_OS_ESCAPE_PATH)) { if (d >= ee) return JK_FALSE; d = c2x(*s, d); } else { if (d >= e) return JK_FALSE; *d++ = *s; } ++s; } *d = '\0'; return JK_TRUE; } /* * Find the first occurrence of find in s. */ static char *stristr(const char *s, const char *find) { char c, sc; size_t len; if ((c = JK_TOLOWER(*find++)) != 0) { len = strlen(find); do { do { if ((sc = JK_TOLOWER(*s++)) == 0) return (NULL); } while (sc != c); } while (strnicmp(s, find, len) != 0); s--; } return ((char *)s); } static void write_error_response(PHTTP_FILTER_CONTEXT pfc, int err) { char status[1024]; char body[8192] = ""; DWORD len; /* reject !!! */ pfc->AddResponseHeaders(pfc, CONTENT_TYPE, 0); StringCbPrintf(status, sizeof(status), "%d %s", err, status_reason(err)); pfc->ServerSupportFunction(pfc, SF_REQ_SEND_RESPONSE_HEADER, status, 0, 0); len = ISIZEOF(HTML_ERROR_HEAD) - 1; pfc->WriteClient(pfc, HTML_ERROR_HEAD, &len, HSE_IO_SYNC); StringCbPrintf(body, sizeof(body), HTML_ERROR_BODY_FMT, status_reason(err), status_title(err), status_description(err)); len = lstrlenA(body); pfc->WriteClient(pfc, body, &len, HSE_IO_SYNC); len = ISIZEOF(HTML_ERROR_TAIL) - 1; pfc->WriteClient(pfc, HTML_ERROR_TAIL, &len, HSE_IO_SYNC); } static void write_error_message(LPEXTENSION_CONTROL_BLOCK lpEcb, int err, const char *err_hdrs, jk_log_context_t *l) { DWORD len; char status[1024]; char body[8192] = ""; if (error_page) { char error_page_url[INTERNET_MAX_URL_LENGTH] = ""; DWORD len_of_error_page; StringCbPrintf(error_page_url, INTERNET_MAX_URL_LENGTH, error_page, err); len_of_error_page = lstrlenA(error_page_url); if (!lpEcb->ServerSupportFunction(lpEcb->ConnID, HSE_REQ_SEND_URL_REDIRECT_RESP, error_page_url, &len_of_error_page, NULL)) { lpEcb->dwHttpStatusCode = err; } else { return; } } lpEcb->dwHttpStatusCode = err; StringCbPrintf(status, sizeof(status), "%d %s", err, status_reason(err)); /* XXX: Should we allow something beside 401? */ if (err_hdrs && err == 401) { /* Include extra error headers */ HRESULT hr = StringCbCopy(body, sizeof(body), err_hdrs); if (FAILED(hr) || strlen(body) > (8191 - strlen(CONTENT_TYPE))) { /* Header is too long. */ jk_log(l, JK_LOG_WARNING, "error header too long (%d bytes requested).", lstrlenA(err_hdrs)); body[0] = '\0'; } } StringCbCat(body, sizeof(body), CONTENT_TYPE); lpEcb->ServerSupportFunction(lpEcb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, status, 0, (LPDWORD)body); /* First write the HEAD */ len = ISIZEOF(HTML_ERROR_HEAD) - 1; lpEcb->WriteClient(lpEcb->ConnID, HTML_ERROR_HEAD, &len, HSE_IO_SYNC); StringCbPrintf(body, sizeof(body), HTML_ERROR_BODY_FMT, status_reason(err), status_title(err), status_description(err)); len = lstrlenA(body); lpEcb->WriteClient(lpEcb->ConnID, body, &len, HSE_IO_SYNC); len = ISIZEOF(HTML_ERROR_TAIL) - 1; lpEcb->WriteClient(lpEcb->ConnID, HTML_ERROR_TAIL, &len, HSE_IO_SYNC); } static int JK_METHOD start_response(jk_ws_service_t *s, int status, const char *reason, const char *const *header_names, const char *const *header_values, unsigned int num_of_headers) { int rv = JK_TRUE; isapi_private_data_t *p; jk_log_context_t *l = s->log_ctx; JK_TRACE_ENTER(l); if (s == NULL || s->ws_private == NULL) { JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } if (status < 100 || status > 1000) { jk_log(l, JK_LOG_ERROR, "invalid status %d", status); JK_TRACE_EXIT(l); return JK_FALSE; } p = s->ws_private; /* If we use proxy error pages, still pass * through context headers needed for special status codes. */ if (s->extension.use_server_error_pages && status >= s->extension.use_server_error_pages) { if (status == JK_HTTP_UNAUTHORIZED) { int found = JK_FALSE; unsigned int h; for (h = 0; h < num_of_headers; h++) { if (!strcasecmp(header_names[h], "WWW-Authenticate")) { p->err_hdrs = jk_pool_strcatv(&p->p, "WWW-Authenticate:", header_values[h], CRLF, NULL); found = JK_TRUE; } } if (found == JK_FALSE) { jk_log(l, JK_LOG_INFO, "origin server sent 401 without" " WWW-Authenticate header"); } } return JK_TRUE; } if (!s->response_started) { char *status_str = NULL; char *headers_str = NULL; BOOL keep_alive = FALSE; /* Whether the downstream or us can supply content length */ BOOL rc; size_t i, len_of_headers = 0; s->response_started = JK_TRUE; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Starting response for URI '%s' (protocol %s)", s->req_uri, s->protocol); } /* * Create the status line */ if (!reason) { reason = status_reason(status); } status_str = (char *)malloc((6 + strlen(reason))); StringCbPrintf(status_str, 6 + strlen(reason), "%d %s", status, reason); if (chunked_encoding_enabled) { /* Check if we've got an HTTP/1.1 response */ if (!strcasecmp(s->protocol, "HTTP/1.1")) { keep_alive = TRUE; /* Chunking only when HTTP/1.1 client and enabled */ p->chunk_content = JK_TRUE; } } /* * Create response headers string */ /* Calculate length of headers block */ for (i = 0; i < num_of_headers; i++) { len_of_headers += strlen(header_names[i]); len_of_headers += strlen(header_values[i]); len_of_headers += 4; /* extra for colon, space and crlf */ } /* * Exclude status codes that MUST NOT include message bodies */ if ((status == 204) || (status == 205) || (status == 304)) { p->chunk_content = JK_FALSE; /* Keep alive is still possible */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Response status %d implies no message body", status); } if (p->chunk_content) { for (i = 0; i < num_of_headers; i++) { /* Check the downstream response to see whether * it's appropriate to chunk the response content * and whether it supports keeping the connection open. * This implements the rules for HTTP/1.1 message length determination * with the exception of multipart/byteranges media types. * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 */ if (!strcasecmp(CONTENT_LENGTH_HEADER_NAME, header_names[i])) { p->chunk_content = JK_FALSE; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Response specifies Content-Length"); } else if (!strcasecmp(CONNECTION_HEADER_NAME, header_names[i]) && !strcasecmp(CONNECTION_CLOSE_VALUE, header_values[i])) { keep_alive = FALSE; p->chunk_content = JK_FALSE; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Response specifies Connection: Close"); } else if (!strcasecmp(TRANSFER_ENCODING_HEADER_NAME, header_names[i]) && !strcasecmp(TRANSFER_ENCODING_IDENTITY_VALUE, header_values[i])) { /* HTTP states that this must include 'chunked' as the last value. * 'identity' is the same as absence of the header */ p->chunk_content = JK_FALSE; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Response specifies Transfer-Encoding"); } } /* Provide room in the buffer for the Transfer-Encoding header if we use it. */ len_of_headers += TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE_LEN + 2; } /* Allocate and init the headers string */ len_of_headers += 3; /* crlf and terminating null char */ headers_str = (char *)malloc(len_of_headers); headers_str[0] = '\0'; /* Copy headers into headers block for sending */ for (i = 0; i < num_of_headers; i++) { StringCbCat(headers_str, len_of_headers, header_names[i]); StringCbCat(headers_str, len_of_headers, ": "); StringCbCat(headers_str, len_of_headers, header_values[i]); StringCbCat(headers_str, len_of_headers, CRLF); } if (p->chunk_content) { /* Configure the response if chunked encoding is used */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Using Transfer-Encoding: chunked"); /** We will supply the transfer-encoding to allow IIS to keep the connection open */ keep_alive = TRUE; /* Indicate to the client that the content will be chunked - We've already reserved space for this */ StringCbCat(headers_str, len_of_headers, TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE); StringCbCat(headers_str, len_of_headers, CRLF); } /* Terminate the headers */ StringCbCat(headers_str, len_of_headers, CRLF); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "%ssing Keep-Alive", (keep_alive ? "U" : "Not u")); if (keep_alive) { HSE_SEND_HEADER_EX_INFO hi; /* Fill in the response */ hi.pszStatus = status_str; hi.pszHeader = headers_str; hi.cchStatus = lstrlenA(status_str); hi.cchHeader = lstrlenA(headers_str); /* * Using the extended form of the API means we have to get this right, * i.e. IIS won't keep connections open if there's a Content-Length and close them if there isn't. */ hi.fKeepConn = keep_alive; /* Send the response to the client */ rc = p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &hi, NULL, NULL); } else { /* Old style response - forces Connection: close if Tomcat response doesn't specify necessary details to allow keep alive */ rc = p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, status_str, 0, (LPDWORD)headers_str); } if (!rc) { jk_log(l, JK_LOG_ERROR, "HSE_REQ_SEND_RESPONSE_HEADER%s failed with error=%d (0x%08x)", (keep_alive ? "_EX" : ""), GetLastError(), GetLastError()); rv = JK_FALSE; } if (headers_str) free(headers_str); if (status_str) free(status_str); } JK_TRACE_EXIT(l); return rv; } static int JK_METHOD iis_read(jk_ws_service_t *s, void *b, unsigned int l, unsigned int *a) { isapi_private_data_t *p; jk_log_context_t *log_ctx = s->log_ctx; JK_TRACE_ENTER(log_ctx); if (s == NULL || s->ws_private == NULL) { JK_LOG_NULL_PARAMS(log_ctx); JK_TRACE_EXIT(log_ctx); return JK_FALSE; } if (a == NULL || b == NULL) { /* XXX: Do we really need those useless checks? */ JK_LOG_NULL_PARAMS(log_ctx); JK_TRACE_EXIT(log_ctx); return JK_FALSE; } p = s->ws_private; if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "Preparing to read %d bytes. " "ECB reports %d bytes total, with %d available.", l, p->lpEcb->cbTotalBytes, p->lpEcb->cbAvailable); } *a = 0; if (l) { char *buf = b; DWORD already_read = p->lpEcb->cbAvailable - p->bytes_read_so_far; if (already_read >= l) { if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "Already read %d bytes - supplying %d bytes from buffer", already_read, l); } memcpy(buf, p->lpEcb->lpbData + p->bytes_read_so_far, l); p->bytes_read_so_far += l; *a = l; } else { /* * Try to copy what we already have */ if (already_read > 0) { if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "Supplying %d bytes from buffer", already_read); } memcpy(buf, p->lpEcb->lpbData + p->bytes_read_so_far, already_read); buf += already_read; l -= already_read; p->bytes_read_so_far = p->lpEcb->cbAvailable; *a = already_read; } /* * Now try to read from the client ... */ if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "Attempting to read %d bytes from client", l); } if (p->lpEcb->ReadClient(p->lpEcb->ConnID, buf, &l)) { /* ReadClient will succeed with dwSize == 0 for last chunk if request chunk encoded */ *a += l; } else { jk_log(log_ctx, JK_LOG_ERROR, "ReadClient failed with %d (0x%08x)", GetLastError(), GetLastError()); JK_TRACE_EXIT(log_ctx); return JK_FALSE; } } } JK_TRACE_EXIT(log_ctx); return JK_TRUE; } /* * Writes a buffer to the ISAPI response. */ static int isapi_write_client(isapi_private_data_t *p, const char *buf, unsigned int write_length, jk_log_context_t *l) { unsigned int written = 0; DWORD try_to_write = 0; JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Writing %d bytes of data to client", write_length); while (written < write_length) { try_to_write = write_length - written; if (!p->lpEcb->WriteClient(p->lpEcb->ConnID, (LPVOID)(buf + written), &try_to_write, HSE_IO_SYNC)) { jk_log(l, JK_LOG_ERROR, "WriteClient failed with %d (0x%08x)", GetLastError(), GetLastError()); JK_TRACE_EXIT(l); return JK_FALSE; } written += try_to_write; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Wrote %d bytes of data successfully", try_to_write); } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Write content to the response. * If chunked encoding has been enabled and the client supports it *(and it's appropriate for the response), then this will write a * single "Transfer-Encoding: chunked" chunk */ static int JK_METHOD iis_write(jk_ws_service_t *s, const void *b, unsigned int l) { isapi_private_data_t *p; const char *buf = (const char *)b; jk_log_context_t *log_ctx = s->log_ctx; JK_TRACE_ENTER(log_ctx); if (!l) { JK_TRACE_EXIT(log_ctx); return JK_TRUE; } if (s == NULL || s->ws_private == NULL || b == NULL) { JK_LOG_NULL_PARAMS(log_ctx); JK_TRACE_EXIT(log_ctx); return JK_FALSE; } p = s->ws_private; if (!s->response_started) { start_response(s, 200, NULL, NULL, NULL, 0); } if (p->chunk_content == JK_FALSE) { if (isapi_write_client(p, buf, l, log_ctx) == JK_FALSE) { JK_TRACE_EXIT(log_ctx); return JK_FALSE; } } else { char chunk_header[RES_BUFFER_SIZE]; /* Construct chunk header : HEX CRLF*/ StringCbPrintf(chunk_header, RES_BUFFER_SIZE, "%X%s", l, CRLF); if (iis_info.major >= 6) { HSE_RESPONSE_VECTOR response_vector; HSE_VECTOR_ELEMENT response_elements[3]; response_elements[0].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER; response_elements[0].pvContext = chunk_header; response_elements[0].cbOffset = 0; response_elements[0].cbSize = strlen(chunk_header); response_elements[1].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER; response_elements[1].pvContext = (PVOID)buf; response_elements[1].cbOffset = 0; response_elements[1].cbSize = l; response_elements[2].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER; response_elements[2].pvContext = CRLF; response_elements[2].cbOffset = 0; response_elements[2].cbSize = CRLF_LEN; response_vector.dwFlags = HSE_IO_SYNC; response_vector.pszStatus = NULL; response_vector.pszHeaders = NULL; response_vector.nElementCount = 3; response_vector.lpElementArray = response_elements; if (JK_IS_DEBUG_LEVEL(log_ctx)) jk_log(log_ctx, JK_LOG_DEBUG, "Using vector write for chunk encoded %d byte chunk", l); if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID, HSE_REQ_VECTOR_SEND, &response_vector, NULL, NULL)) { jk_log(log_ctx, JK_LOG_ERROR, "Vector write of chunk encoded response failed with %d (0x%08x)", GetLastError(), GetLastError()); JK_TRACE_EXIT(log_ctx); return JK_FALSE; } } else { /* Write chunk header */ if (JK_IS_DEBUG_LEVEL(log_ctx)) jk_log(log_ctx, JK_LOG_DEBUG, "Using chunked encoding - writing chunk header for %d byte chunk", l); if (!isapi_write_client(p, chunk_header, lstrlenA(chunk_header), log_ctx)) { jk_log(log_ctx, JK_LOG_ERROR, "WriteClient for chunk header failed"); JK_TRACE_EXIT(log_ctx); return JK_FALSE; } /* Write chunk body (or simple body block) */ if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "Writing %s of size %d", (p->chunk_content ? "chunk body" : "simple response"), l); } if (!isapi_write_client(p, buf, l, log_ctx)) { jk_log(log_ctx, JK_LOG_ERROR, "WriteClient for response body chunk failed"); JK_TRACE_EXIT(log_ctx); return JK_FALSE; } /* Write chunk trailer */ if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "Using chunked encoding - writing chunk trailer"); } if (!isapi_write_client(p, CRLF, CRLF_LEN, log_ctx)) { jk_log(log_ctx, JK_LOG_ERROR, "WriteClient for chunk trailer failed"); JK_TRACE_EXIT(log_ctx); return JK_FALSE; } } } JK_TRACE_EXIT(log_ctx); return JK_TRUE; } /** * In the case of a Transfer-Encoding: chunked response, this will write the terminator chunk. */ static int JK_METHOD iis_done(jk_ws_service_t *s) { isapi_private_data_t *p; jk_log_context_t *l = s->log_ctx; JK_TRACE_ENTER(l); if (s == NULL || s->ws_private == NULL) { JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } p = s->ws_private; if (p->chunk_content == JK_FALSE) { JK_TRACE_EXIT(l); return JK_TRUE; } /* Write last chunk + terminator */ if (iis_info.major >= 6) { HSE_RESPONSE_VECTOR response_vector; HSE_VECTOR_ELEMENT response_elements[1]; response_elements[0].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER; response_elements[0].pvContext = CHUNKED_ENCODING_TRAILER; response_elements[0].cbOffset = 0; response_elements[0].cbSize = CHUNKED_ENCODING_TRAILER_LEN; /* HSE_IO_FINAL_SEND lets IIS process the response to the client before we return */ response_vector.dwFlags = HSE_IO_SYNC | HSE_IO_FINAL_SEND; response_vector.pszStatus = NULL; response_vector.pszHeaders = NULL; response_vector.nElementCount = 1; response_vector.lpElementArray = response_elements; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Using vector write to terminate chunk encoded response."); if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID, HSE_REQ_VECTOR_SEND, &response_vector, NULL, NULL)) { jk_log(l, JK_LOG_ERROR, "Vector termination of chunk encoded response failed with %d (0x%08x)", GetLastError(), GetLastError()); JK_TRACE_EXIT(l); return JK_FALSE; } } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Terminating chunk encoded response"); if (!isapi_write_client(p, CHUNKED_ENCODING_TRAILER, CHUNKED_ENCODING_TRAILER_LEN, l)) { jk_log(l, JK_LOG_ERROR, "WriteClient for chunked response terminator failed with %d (0x%08x)", GetLastError(), GetLastError()); JK_TRACE_EXIT(l); return JK_FALSE; } } JK_TRACE_EXIT(l); return JK_TRUE; } BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer) { BOOL rv = TRUE; ULONG http_filter_revision = HTTP_FILTER_REVISION; pVer->dwFilterVersion = pVer->dwServerFilterVersion; if (pVer->dwFilterVersion > http_filter_revision) { pVer->dwFilterVersion = http_filter_revision; } WaitForSingleObject(init_cs, INFINITE); if (!is_inited) { rv = initialize_extension(); } ReleaseMutex(init_cs); if (iis_info.major < 5 || (iis_info.major == 5 && iis_info.minor < 1)) { SetLastError(ERROR_OLD_WIN_VERSION); return FALSE; } pVer->dwFlags = SF_NOTIFY_ORDER_HIGH | SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT | SF_NOTIFY_LOG | iis_info.filter_notify_event; StringCbCopy(pVer->lpszFilterDesc, SF_MAX_FILTER_DESC_LEN, (VERSION_STRING)); return rv; } /** The max number of regex captures that can be expanded by ap_pregsub */ #define AP_MAX_REG_MATCH 10 /* The structure representing a compiled regular expression. */ typedef struct { void *re_pcre; const char *fake; } ap_regex_t; /* The structure in which a captured offset is returned. */ typedef struct { int rm_so; int rm_eo; } ap_regmatch_t; /************************************************* * Free store held by a regex * *************************************************/ static void ap_regfree(ap_regex_t *preg) { (pcre_free)(preg->re_pcre); } /************************************************* * Compile a regular expression * *************************************************/ /* Arguments: preg points to a structure for recording the compiled expression pattern the pattern to compile Returns: JK_TRUE on success JK_FALSE on failure */ static int ap_regcomp(ap_regex_t *preg, const char *pattern) { const char *errorptr; int erroffset; preg->re_pcre = pcre_compile(pattern, 0, &errorptr, &erroffset, NULL); if (preg->re_pcre == NULL) return JK_FALSE; return JK_TRUE; } /************************************************* * Match a regular expression * *************************************************/ /* Unfortunately, PCRE requires 3 ints of working space for each captured substring, so we have to get and release working store instead of just using the POSIX structures as was done in earlier releases when PCRE needed only 2 ints. However, if the number of possible capturing brackets is small, use a block of store on the stack, to reduce the use of malloc/free. The threshold is in a macro that can be changed at configure time. */ static int ap_regexec(const ap_regex_t *preg, const char *string, int nmatch, ap_regmatch_t pmatch[]) { int rc; int *ovector = NULL; int small_ovector[POSIX_MALLOC_THRESHOLD * 3]; int allocated_ovector = 0; if (nmatch > 0) { if (nmatch <= POSIX_MALLOC_THRESHOLD) { ovector = &(small_ovector[0]); } else { ovector = (int *)malloc(sizeof(int) * nmatch * 3); if (ovector == NULL) return -1; allocated_ovector = 1; } } rc = pcre_exec((const pcre *)preg->re_pcre, NULL, string, lstrlenA(string), 0, 0, ovector, nmatch * 3); if (rc == 0) rc = nmatch; /* All captured slots were filled in */ if (rc >= 0) { int i; for (i = 0; i < rc; i++) { pmatch[i].rm_so = ovector[i*2]; pmatch[i].rm_eo = ovector[i*2+1]; } for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1; } if (allocated_ovector) free(ovector); return rc; } /* This function substitutes for $0-$9, filling in regular expression * submatches. Pass it the same nmatch and pmatch arguments that you * passed ap_regexec(). pmatch should not be greater than the maximum number * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t. * * input should be the string with the $-expressions, source should be the * string that was matched against. * * It returns the substituted string, or NULL on error. * * Parts of this code are based on Henry Spencer's regsub(), from his * AT&T V8 regexp package. */ static char *ap_pregsub(const char *input, const char *source, int nmatch, ap_regmatch_t pmatch[]) { const char *src = input; char *dest, *dst; char c; int no; int len; if (!source) return NULL; if (!nmatch) return strdup(src); /* First pass, find the size */ len = 0; while ((c = *src++) != '\0') { if (c == '&') no = 0; else if (c == '$' && isdigit((unsigned char)*src)) no = *src++ - '0'; else no = 10; if (no > 9) { /* Ordinary character. */ if (c == '\\' && (*src == '$' || *src == '&')) c = *src++; len++; } else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { len += pmatch[no].rm_eo - pmatch[no].rm_so; } } dest = dst = calloc(1, len + 1); /* Now actually fill in the string */ src = input; while ((c = *src++) != '\0') { if (c == '&') no = 0; else if (c == '$' && isdigit((unsigned char)*src)) no = *src++ - '0'; else no = 10; if (no > 9) { /* Ordinary character. */ if (c == '\\' && (*src == '$' || *src == '&')) c = *src++; *dst++ = c; } else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { len = pmatch[no].rm_eo - pmatch[no].rm_so; memcpy(dst, source + pmatch[no].rm_so, len); dst += len; } } *dst = '\0'; return dest; } static char *simple_rewrite(jk_pool_t *p, const char *uri) { if (rewrite_map) { int i; for (i = 0; i < jk_map_size(rewrite_map); i++) { size_t len; const char *src = jk_map_name_at(rewrite_map, i); if (*src == '~') continue; /* Skip regexp rewrites */ len = strlen(src); if (strncmp(uri, src, len) == 0) { return jk_pool_strcat(p, jk_map_value_at(rewrite_map, i), uri + len); } } } return NULL; } static char *rregex_rewrite(jk_pool_t *p, const char *uri) { int nmatch; ap_regmatch_t regm[AP_MAX_REG_MATCH]; if (rregexp_map) { int i; for (i = 0; i < jk_map_size(rregexp_map); i++) { ap_regex_t *regexp = (ap_regex_t *)jk_map_value_at(rregexp_map, i); nmatch = ap_regexec(regexp, uri, AP_MAX_REG_MATCH, regm); if (nmatch > 0) { char *subs; if (nmatch > AP_MAX_REG_MATCH) { nmatch = AP_MAX_REG_MATCH; } subs = ap_pregsub(regexp->fake, uri, nmatch, regm); if (subs) { char *buf, *ptr; size_t orgsz = strlen(uri); size_t subsz = strlen(subs); size_t lefts = orgsz - regm[0].rm_eo; ptr = buf = jk_pool_alloc(p, regm[0].rm_so + subsz + lefts + 1); memcpy(buf, uri, regm[0].rm_so); ptr += regm[0].rm_so; memcpy(ptr, subs, subsz); ptr += subsz; memcpy(ptr, uri + regm[0].rm_eo, lefts); ptr[lefts] = '\0'; return buf; } } } } return NULL; } static __inline void clear_header(PHTTP_FILTER_PREPROC_HEADERS pfp, PHTTP_FILTER_CONTEXT pfc, LPSTR lpszName) { pfp->SetHeader(pfc, lpszName, NIL); } static __inline LPSTR get_pheader(jk_pool_t *pool, PHTTP_FILTER_PREPROC_HEADERS pfp, PHTTP_FILTER_CONTEXT pfc, LPSTR lpszName, LPSTR lpszBuf, size_t bsize) { LPSTR rv = lpszBuf; DWORD dwLen = (DWORD)bsize; if (!pfp->GetHeader(pfc, lpszName, lpszBuf, &dwLen)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL; if ((rv = jk_pool_alloc(pool, dwLen)) == NULL) return NULL; /* Try again with dynamic buffer */ if (!pfp->GetHeader(pfc, lpszName, rv, &dwLen)) return NULL; } return rv; } static DWORD handle_notify_event(PHTTP_FILTER_CONTEXT pfc, PHTTP_FILTER_PREPROC_HEADERS pfp) { int rc; DWORD rv = SF_STATUS_REQ_NEXT_NOTIFICATION; const char *worker = NULL; rule_extension_t *extensions; int worker_index = -1; int port = 0; jk_pool_atom_t pbuf[HUGE_POOL_SIZE]; jk_pool_t pool; char *uri_undec = NULL; char *cleanuri = NULL; char *uri = NULL; char *host = NULL; char *request_id = NULL; char *translate = NULL; char szHB[HDR_BUFFER_SIZE] = "/"; char szUB[HDR_BUFFER_SIZE] = ""; char szRIDB[512] = ""; char szTB[16] = ""; char szPB[16] = ""; char swindex[32] = ""; char *query; DWORD len; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; l->logger = logger; l->id = "FILTER"; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Filter started"); jk_open_pool(&pool, pbuf, sizeof(jk_pool_atom_t) * HUGE_POOL_SIZE); /* * Just in case somebody set these headers in the request! */ clear_header(pfp, pfc, URI_HEADER_NAME); clear_header(pfp, pfc, QUERY_HEADER_NAME); clear_header(pfp, pfc, REQUEST_ID_HEADER_NAME); clear_header(pfp, pfc, WORKER_HEADER_NAME); clear_header(pfp, pfc, WORKER_HEADER_INDEX); clear_header(pfp, pfc, TOMCAT_TRANSLATE_HEADER_NAME); /* * Suppress logging of original uri/query when we don't map a URL */ if (pfc->pFilterContext) { isapi_log_data_t *ld = (isapi_log_data_t *)pfc->pFilterContext; ld->request_matched = JK_FALSE; } uri = get_pheader(&pool, pfp, pfc, "url", szUB, sizeof(szUB)); if (uri == NULL) { jk_log(l, JK_LOG_ERROR, "error while getting the url"); return SF_STATUS_REQ_ERROR; } if (*uri == '\0') { /* Empty url */ return SF_STATUS_REQ_NEXT_NOTIFICATION; } query = strchr(uri, '?'); if (query) { *query++ = '\0'; if (*query) query = jk_pool_strdup(&pool, query); else query = NULL; } /* Duplicate unparsed uri */ uri_undec = jk_pool_strdup(&pool, uri); rc = unescape_url(uri); if (rc == BAD_REQUEST) { jk_log(l, JK_LOG_ERROR, "[%s] contains one or more invalid escape sequences.", uri); write_error_response(pfc, 400); rv = SF_STATUS_REQ_FINISHED; goto cleanup; } if (rc == BAD_PATH) { jk_log(l, JK_LOG_EMERG, "[%s] contains forbidden escape sequences.", uri); write_error_response(pfc, 404); rv = SF_STATUS_REQ_FINISHED; goto cleanup; } cleanuri = jk_pool_strdup(&pool, uri); if (jk_servlet_normalize(cleanuri, l)) { write_error_response(pfc, 404); rv = SF_STATUS_REQ_FINISHED; goto cleanup; } len = ISIZEOF(szHB) - 1; if (pfc->GetServerVariable(pfc, "SERVER_NAME", &szHB[1], &len) && len > 1) { len = ISIZEOF(szPB); if (pfc->GetServerVariable(pfc, "SERVER_PORT", szPB, &len)) port = atoi(szPB); if (port != 0 && port != 80 && port != 443) { host = jk_pool_strcatv(&pool, szHB, ":", szPB, NULL); } else host = szHB; } worker = map_uri_to_worker_ext(uw_map, cleanuri, host, &extensions, &worker_index, l); /* * Check if somebody is feading us with his own TOMCAT data headers. * We reject such postings ! */ if (worker) { char *forwardURI; char *rewriteURI; isapi_log_data_t *ld; BOOL rs; /* This is a servlet, should redirect ... */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "[%s] is a servlet url - should redirect to %s", uri, worker); /* get URI we should forward */ if (uri_select_option == URI_SELECT_OPT_UNPARSED) { /* get original unparsed URI */ forwardURI = uri_undec; } else if (uri_select_option == URI_SELECT_OPT_ESCAPED) { size_t elen = strlen(uri) * 3 + 1; char *escuri = jk_pool_alloc(&pool, elen); if (!escape_url(uri, escuri, (int)elen)) { jk_log(l, JK_LOG_ERROR, "[%s] re-encoding request exceeds maximum buffer size.", uri); write_error_response(pfc, 400); rv = SF_STATUS_REQ_FINISHED; goto cleanup; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "fowarding escaped URI [%s]", escuri); forwardURI = escuri; } else if (uri_select_option == URI_SELECT_OPT_PROXY) { size_t elen = strlen(uri) * 3 + 1; char *escuri = jk_pool_alloc(&pool, elen); if (!jk_canonenc(uri, escuri, (int)elen)) { jk_log(l, JK_LOG_ERROR, "[%s] re-encoding request exceeds maximum buffer size.", uri); write_error_response(pfc, 400); rv = SF_STATUS_REQ_FINISHED; goto cleanup; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "fowarding escaped URI [%s]", escuri); forwardURI = escuri; } else { forwardURI = uri; } /* Do a simple rewrite . * Note that URI can be escaped, so thus the rule has * to be in that case. * * TODO: Add more advanced regexp rewrite. */ rewriteURI = simple_rewrite(&pool, forwardURI); if (rewriteURI == NULL) rewriteURI = rregex_rewrite(&pool, forwardURI); if (rewriteURI) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "rewritten URI [%s]->[%s]", forwardURI, rewriteURI); } forwardURI = rewriteURI; } itoa(worker_index, swindex, 10); rs = pfp->AddHeader(pfc, URI_HEADER_NAME, forwardURI); if (rs && query) rs = pfp->AddHeader(pfc, QUERY_HEADER_NAME, query); request_id = get_pheader(&pool, pfp, pfc, request_id_header, szRIDB, sizeof(szRIDB)); if (request_id == NULL || *request_id == '\0') { char uuid[UUID_BUFFER_SIZE]; GUID guid; HRESULT hr = CoCreateGuid(&guid); if (FAILED(hr)) { jk_log(l, JK_LOG_WARNING, "Could not create UUID for request id"); request_id = "NO-ID"; } else { _snprintf_s(uuid, sizeof(uuid), _TRUNCATE, UUID_TEMPLATE, guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); request_id = jk_pool_strdup(&pool, uuid); l->id = request_id; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Created request id [%s]", request_id); } } } else { l->id = request_id; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Received request id [%s]", request_id); } } rs = rs && pfp->AddHeader(pfc, REQUEST_ID_HEADER_NAME, request_id); rs = rs && pfp->AddHeader(pfc, WORKER_HEADER_NAME, (LPSTR)worker); rs = rs && pfp->AddHeader(pfc, WORKER_HEADER_INDEX, swindex); rs = rs && pfp->SetHeader(pfc, "url", extension_uri); if (!rs) { jk_log(l, JK_LOG_ERROR, "error while adding request headers"); SetLastError(ERROR_INVALID_PARAMETER); rv = SF_STATUS_REQ_ERROR; goto cleanup; } translate = get_pheader(&pool, pfp, pfc, TRANSLATE_HEADER, szTB, sizeof(szTB)); /* Move Translate: header to a temporary header so * that the extension proc will be called. * This allows the servlet to handle 'Translate: f'. */ if (translate != NULL && *translate != '\0') { if (!pfp->AddHeader(pfc, TOMCAT_TRANSLATE_HEADER_NAME, translate)) { jk_log(l, JK_LOG_ERROR, "error while adding Tomcat-Translate headers"); rv = SF_STATUS_REQ_ERROR; goto cleanup; } clear_header(pfp, pfc, TRANSLATE_HEADER); } ld = (isapi_log_data_t *)pfc->pFilterContext; if (ld == NULL) { ld = (isapi_log_data_t *)pfc->AllocMem(pfc, sizeof(isapi_log_data_t), 0); if (ld == NULL) { jk_log(l, JK_LOG_ERROR, "error while allocating memory"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); rv = SF_STATUS_REQ_ERROR; goto cleanup; } pfc->pFilterContext = ld; } memset(ld, 0, sizeof(isapi_log_data_t)); StringCbCopy(ld->uri, sizeof(ld->uri), forwardURI); if (query) StringCbCopy(ld->query, sizeof(ld->query), query); ld->request_matched = JK_TRUE; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "forwarding to : %s", extension_uri); jk_log(l, JK_LOG_DEBUG, "forward URI : %s%s", URI_HEADER_NAME, forwardURI); if (query) jk_log(l, JK_LOG_DEBUG, "forward query : %s%s", QUERY_HEADER_NAME, query); jk_log(l, JK_LOG_DEBUG, "request id: %s%s", REQUEST_ID_HEADER_NAME, request_id); jk_log(l, JK_LOG_DEBUG, "forward worker: %s%s", WORKER_HEADER_NAME, worker); jk_log(l, JK_LOG_DEBUG, "worker index : %s%s", WORKER_HEADER_INDEX, swindex); } } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "[%s] is not a servlet url", uri_undec); if (strip_session) { if (jk_strip_session_id(uri_undec, JK_PATH_SESSION_IDENTIFIER, l)) { pfp->SetHeader(pfc, "url", uri_undec); } } } cleanup: jk_close_pool(&pool); return rv; } DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc, DWORD dwNotificationType, LPVOID pvNotification) { /* Initialise jk */ EnterCriticalSection(&log_cs); if (is_inited && !is_mapread) { char serverName[MAX_SERVERNAME] = ""; char instanceId[MAX_INSTANCEID] = ""; DWORD dwLen = MAX_SERVERNAME - MAX_INSTANCEID - 1; if (pfc->GetServerVariable(pfc, "SERVER_NAME", serverName, &dwLen)) { dwLen = MAX_INSTANCEID; if (pfc->GetServerVariable(pfc, "INSTANCE_ID", instanceId, &dwLen)) { if (dwLen > 1) { StringCbCat(serverName, MAX_SERVERNAME, "_"); StringCbCat(serverName, MAX_SERVERNAME, instanceId); } } if (!is_mapread) { WaitForSingleObject(init_cs, INFINITE); if (!is_mapread) is_mapread = init_jk(serverName); ReleaseMutex(init_cs); } } /* If we can't read the map we become dormant */ if (!is_mapread) is_inited = JK_FALSE; } LeaveCriticalSection(&log_cs); if (!is_inited) { /* In case the initialization failed * return error. This will make entire IIS * unusable like with Apache servers */ SetLastError(ERROR_INVALID_FUNCTION); return SF_STATUS_REQ_ERROR; } if (iis_info.filter_notify_event == dwNotificationType) { return handle_notify_event(pfc, pvNotification); } else if (dwNotificationType == SF_NOTIFY_LOG) { if (pfc->pFilterContext) { isapi_log_data_t *ld = (isapi_log_data_t *)pfc->pFilterContext; if (ld->request_matched) { HTTP_FILTER_LOG *pl = (HTTP_FILTER_LOG *)pvNotification; pl->pszTarget = ld->uri; pl->pszParameters = ld->query; } } } return SF_STATUS_REQ_NEXT_NOTIFICATION; } BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO * pVer) { BOOL rv = TRUE; pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR); StringCbCopy(pVer->lpszExtensionDesc, HSE_MAX_EXT_DLL_NAME_LEN, (VERSION_STRING)); WaitForSingleObject(init_cs, INFINITE); if (!is_inited) { rv = initialize_extension(); } ReleaseMutex(init_cs); return rv; } DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpEcb) { DWORD rc = HSE_STATUS_ERROR; isapi_private_data_t private_data; jk_ws_service_t s; jk_pool_atom_t buf[SMALL_POOL_SIZE]; char *worker_name; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; char id[HDR_BUFFER_SIZE]; DWORD idLen = HDR_BUFFER_SIZE; l->logger = logger; if (lpEcb->GetServerVariable(lpEcb->ConnID, HTTP_REQUEST_ID_HEADER_NAME, id, &idLen)) { l->id = id; } else { l->id = "EXTENSION"; } lpEcb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR; JK_TRACE_ENTER(l); /* Initialise jk */ EnterCriticalSection(&log_cs); if (is_inited && !is_mapread) { char serverName[MAX_SERVERNAME] = ""; char instanceId[MAX_INSTANCEID] = ""; DWORD dwLen = MAX_SERVERNAME - MAX_INSTANCEID - 1; if (lpEcb->GetServerVariable(lpEcb->ConnID, "SERVER_NAME", serverName, &dwLen)) { dwLen = MAX_INSTANCEID; if (lpEcb->GetServerVariable(lpEcb->ConnID, "INSTANCE_ID", instanceId, &dwLen)) { if (dwLen > 1) { StringCbCat(serverName, MAX_SERVERNAME, "_"); StringCbCat(serverName, MAX_SERVERNAME, instanceId); } } if (!is_mapread) { WaitForSingleObject(init_cs, INFINITE); if (!is_mapread) is_mapread = init_jk(serverName); ReleaseMutex(init_cs); } } if (!is_mapread) is_inited = JK_FALSE; } LeaveCriticalSection(&log_cs); if (!is_inited) { jk_log(l, JK_LOG_ERROR, "not initialized"); JK_TRACE_EXIT(l); return HSE_STATUS_ERROR; } if (!watchdog_interval) wc_maintain(l); jk_init_ws_service(&s); jk_open_pool(&private_data.p, buf, sizeof(buf)); private_data.bytes_read_so_far = 0; private_data.lpEcb = lpEcb; private_data.chunk_content = JK_FALSE; s.ws_private = &private_data; s.pool = &private_data.p; /* Needs to be replaced by a pool allocated ctx in init_ws_service() */ s.log_ctx = l; if (flush_packets) { lpEcb->ServerSupportFunction(lpEcb->ConnID, HSE_REQ_SET_FLUSH_FLAG, (LPVOID) TRUE, NULL, NULL); } if (init_ws_service(&private_data, &s, &worker_name)) { jk_endpoint_t *e = NULL; jk_worker_t *worker = wc_get_worker_for_name(worker_name, l); /* Replace by a pool allocated ctx from init_ws_service() */ l = s.log_ctx; if (!worker) { jk_log(l, JK_LOG_ERROR, "could not get a worker for name %s", worker_name); jk_close_pool(&private_data.p); JK_TRACE_EXIT(l); return rc; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "got a worker for name %s", worker_name); if (worker->get_endpoint(worker, &e, l)) { int is_error = JK_HTTP_SERVER_ERROR; int result; if ((result = e->service(e, &s, l, &is_error)) > 0) { if (s.extension.use_server_error_pages && s.http_response_status >= s.extension.use_server_error_pages) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Forwarding status=%d" " for worker=%s", s.http_response_status, worker_name); lpEcb->dwHttpStatusCode = s.http_response_status; write_error_message(lpEcb, s.http_response_status, private_data.err_hdrs, l); } else { rc = HSE_STATUS_SUCCESS; lpEcb->dwHttpStatusCode = s.http_response_status; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "service() returned OK"); } } else { if ((result == JK_CLIENT_ERROR) && (is_error == JK_HTTP_OK)) { jk_log(l, JK_LOG_INFO, "service() failed because client aborted connection"); } else { jk_log(l, JK_LOG_ERROR, "service() failed with http error %d", is_error); } lpEcb->dwHttpStatusCode = is_error; write_error_message(lpEcb, is_error, private_data.err_hdrs, l); } e->done(&e, l); } else { int is_error = JK_HTTP_SERVER_BUSY; jk_log(l, JK_LOG_ERROR, "Failed to obtain an endpoint to service request - " "your connection_pool_size is probably less than the threads in your web server!"); lpEcb->dwHttpStatusCode = is_error; write_error_message(lpEcb, is_error, private_data.err_hdrs, l); } } else { jk_log(l, JK_LOG_ERROR, "failed to init service for request."); } jk_close_pool(&private_data.p); JK_TRACE_EXIT(l); return rc; } BOOL WINAPI TerminateExtension(DWORD dwFlags) { return TerminateFilter(dwFlags); } BOOL WINAPI TerminateFilter(DWORD dwFlags) { jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; UNREFERENCED_PARAMETER(dwFlags); l->logger = logger; l->id = "TERMINATE_FILTER"; if (dll_process_detach) { /* Simple case */ if (!is_inited) return TRUE; watchdog_interval = 0; if (watchdog_handle) { WaitForSingleObject(watchdog_handle, INFINITE); CloseHandle(watchdog_handle); watchdog_handle = NULL; } jk_shm_close(l); if (logger) jk_close_file_logger(&logger); return TRUE; } EnterCriticalSection(&log_cs); if (!is_inited) { LeaveCriticalSection(&log_cs); return TRUE; } WaitForSingleObject(init_cs, INFINITE); if (is_inited) { is_inited = JK_FALSE; jk_log(l, JK_LOG_INFO, "%s stopping", (FULL_VERSION_STRING)); watchdog_interval = 0; if (watchdog_handle) { WaitForSingleObject(watchdog_handle, INFINITE); CloseHandle(watchdog_handle); watchdog_handle = NULL; } wc_close(l); if (is_mapread) { uri_worker_map_free(&uw_map, l); is_mapread = JK_FALSE; } if (workers_map) { jk_map_free(&workers_map); } if (rewrite_map) { jk_map_free(&rewrite_map); } if (rregexp_map) { int i; for (i = 0; i < jk_map_size(rregexp_map); i++) { ap_regex_t *regexp = (ap_regex_t *)jk_map_value_at(rregexp_map, i); if (regexp) { ap_regfree(regexp); free(regexp); } } jk_map_free(&rregexp_map); } jk_shm_close(l); if (logger) { jk_close_file_logger(&logger); } } ReleaseMutex(init_cs); LeaveCriticalSection(&log_cs); return TRUE; } BOOL WINAPI DllMain(HINSTANCE hInst, /* Instance Handle of the DLL */ ULONG ulReason, /* Reason why NT called this DLL */ LPVOID lpReserved) /* Reserved parameter for future use */ { char fname[MAX_PATH]; UNREFERENCED_PARAMETER(lpReserved); switch (ulReason) { case DLL_PROCESS_ATTACH: if (GetModuleFileName(hInst, fname, sizeof(fname) - 12)) { char *p = strrchr(fname, '.'); if (p) { *p = '\0'; StringCbCopy(ini_file_name, MAX_PATH, fname); StringCbCat(ini_file_name, MAX_PATH, ".properties"); StringCbCopy(ini_mutex_name, MAX_PATH, "Local\\JK_"); StringCbCat(ini_mutex_name, MAX_PATH, fname); StringCbCat(ini_mutex_name, MAX_PATH, "_mutex"); p = &ini_mutex_name[10]; while (*p) { if (!isalnum((unsigned char)*p)) *p = '_'; else *p = toupper(*p); p++; } } else { /* Cannot obtain file name ? */ return FALSE; } if ((p = strrchr(fname, '\\'))) { *p++ = '\0'; StringCbCopy(dll_file_path, MAX_PATH, fname); jk_map_alloc(&jk_environment_map); jk_map_add(jk_environment_map, "JKISAPI_PATH", dll_file_path); jk_map_add(jk_environment_map, "JKISAPI_NAME", p); } else { /* Cannot obtain file name ? */ return JK_FALSE; } } else { return JK_FALSE; } /* Construct redirector headers to use for this redirector instance */ StringCbPrintf(URI_HEADER_NAME, RES_BUFFER_SIZE, HEADER_TEMPLATE, URI_HEADER_NAME_BASE, hInst); StringCbPrintf(QUERY_HEADER_NAME, RES_BUFFER_SIZE, HEADER_TEMPLATE, QUERY_HEADER_NAME_BASE, hInst); StringCbPrintf(REQUEST_ID_HEADER_NAME, RES_BUFFER_SIZE, HEADER_TEMPLATE, REQUEST_ID_HEADER_NAME_BASE, hInst); StringCbPrintf(WORKER_HEADER_NAME, RES_BUFFER_SIZE, HEADER_TEMPLATE, WORKER_HEADER_NAME_BASE, hInst); StringCbPrintf(WORKER_HEADER_INDEX, RES_BUFFER_SIZE, HEADER_TEMPLATE, WORKER_HEADER_INDEX_BASE, hInst); StringCbPrintf(TOMCAT_TRANSLATE_HEADER_NAME, RES_BUFFER_SIZE, HEADER_TEMPLATE, TOMCAT_TRANSLATE_HEADER_NAME_BASE, hInst); /* Construct the HTTP_ headers that will be seen in ExtensionProc */ StringCbPrintf(HTTP_URI_HEADER_NAME, RES_BUFFER_SIZE, HTTP_HEADER_TEMPLATE, URI_HEADER_NAME_BASE, hInst); StringCbPrintf(HTTP_QUERY_HEADER_NAME, RES_BUFFER_SIZE, HTTP_HEADER_TEMPLATE, QUERY_HEADER_NAME_BASE, hInst); StringCbPrintf(HTTP_REQUEST_ID_HEADER_NAME, RES_BUFFER_SIZE, HTTP_HEADER_TEMPLATE, REQUEST_ID_HEADER_NAME_BASE, hInst); StringCbPrintf(HTTP_WORKER_HEADER_NAME, RES_BUFFER_SIZE, HTTP_HEADER_TEMPLATE, WORKER_HEADER_NAME_BASE, hInst); StringCbPrintf(HTTP_WORKER_HEADER_INDEX, RES_BUFFER_SIZE, HTTP_HEADER_TEMPLATE, WORKER_HEADER_INDEX_BASE, hInst); InitializeCriticalSection(&log_cs); init_cs = CreateMutex(jk_get_sa_with_null_dacl(), FALSE, ini_mutex_name); if (init_cs == NULL && GetLastError() == ERROR_ALREADY_EXISTS) init_cs = OpenMutex(MUTEX_ALL_ACCESS, FALSE, ini_mutex_name); if (init_cs == NULL) return JK_FALSE; break; case DLL_PROCESS_DETACH: dll_process_detach = TRUE; __try { TerminateFilter(HSE_TERM_MUST_UNLOAD); } __except(1) { } if (init_cs != NULL) CloseHandle(init_cs); DeleteCriticalSection(&log_cs); break; default: break; } return TRUE; } static DWORD WINAPI watchdog_thread(void *param) { int i; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; l->logger = logger; l->id = "WATCHDOG"; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Watchdog thread initialized with %u second interval", watchdog_interval); } while (watchdog_interval) { for (i = 0; i < (watchdog_interval * 10); i++) { if (!watchdog_interval) break; Sleep(100); } if (!watchdog_interval) break; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Watchdog thread running"); } if (worker_mount_file[0]) { jk_shm_lock(); uri_worker_map_update(uw_map, 0, l); jk_shm_unlock(); } wc_maintain(l); } if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Watchdog thread finished"); } return 0; } /* * Reinitializes the logger, formatting the log file name if rotation is enabled, * and calculating the next rotation time if applicable. */ static int init_logger(int rotate) { int rc = JK_TRUE; int log_open = rotate; /* log is assumed open if a rotate is requested */ char *log_file_name; char log_file_name_buf[MAX_PATH*2]; jk_logger_t *org = NULL; /* If log rotation is enabled, format the log filename */ if ((log_rotationtime > 0) || (log_filesize > 0)) { time_t t; t = time(NULL); if (log_rotationtime > 0) { /* Align time to rotationtime intervals */ t = (t / log_rotationtime) * log_rotationtime; /* Calculate rotate time */ log_next_rotate_time = t + log_rotationtime; } log_file_name = log_file_name_buf; if (strchr(log_file, '%')) { struct tm *tm_now; /* If there are % format patterns in the log file name, * treat it as a strftime format */ tm_now = localtime(&t); strftime(log_file_name, sizeof(log_file_name_buf), log_file, tm_now); } else { /* Otherwise append the number of seconds to the base name */ StringCbPrintf(log_file_name, sizeof(log_file_name_buf), "%s.%d", log_file, (long)t); } } else { log_file_name = log_file; } /* Close the current log file if required, and the effective log file name has changed */ if (log_open && strncmp(log_file_name, log_file_effective, strlen(log_file_name)) != 0) { FILE* lf = ((jk_file_logger_t*)logger->logger_private)->logfile; fprintf(lf, "Log rotated to %s\n", log_file_name); fflush(lf); org = logger; log_open = JK_FALSE; } if (!log_open) { if (jk_open_file_logger(&logger, log_file_name, log_level)) { logger->log = iis_log_to_file; /* Remember the current log file name for the next potential rotate */ StringCbCopy(log_file_effective, sizeof(log_file_effective), log_file_name); rc = JK_TRUE; } else { logger = org; org = NULL; rc = JK_FALSE; } } if (org) jk_close_file_logger(&org); return rc; } /* * Checks whether the log needs to be rotated. Must be called while holding the log lock. * The behaviour here is based on the Apache rotatelogs program. * http://httpd.apache.org/docs/2.0/programs/rotatelogs.html */ static int JK_METHOD rotate_log_file(void) { int rc = JK_TRUE; int rotate = JK_FALSE; if (log_rotationtime > 0) { time_t t = time(NULL); if (t >= log_next_rotate_time) { rotate = JK_TRUE; } } else if (log_filesize > 0 && logger) { LARGE_INTEGER filesize; HANDLE h = (HANDLE)_get_osfhandle(fileno(((jk_file_logger_t *)(logger)->logger_private)->logfile)); GetFileSizeEx(h, &filesize); if ((ULONGLONG)filesize.QuadPart >= log_filesize) { rotate = JK_TRUE; } } if (rotate) { rc = init_logger(JK_TRUE); } return rc; } /* * Log messages to the log file, rotating the log when required. */ static int JK_METHOD iis_log_to_file(jk_logger_t *l, int level, int used, char *what) { int rc = JK_FALSE; if (l && (l->level <= level || level == JK_LOG_REQUEST_LEVEL) && l->logger_private && what && used > 0) { jk_file_logger_t *p = l->logger_private; rc = JK_TRUE; if (p->logfile) { #if 0 what[used++] = '\r'; #endif what[used++] = '\n'; what[used] = '\0'; /* Perform logging within critical section to protect rotation */ EnterCriticalSection(&log_cs); if (rotate_log_file() && logger) { /* The rotation process will reallocate the jk_logger_t structure, so refetch */ FILE *rotated = ((jk_file_logger_t *)logger->logger_private)->logfile; fputs(what, rotated); fflush(rotated); } LeaveCriticalSection(&log_cs); } } return rc; } static int init_jk(char *serverName) { char *p, shm_name[MAX_PATH]; int i, rc = JK_FALSE; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; init_logger(JK_FALSE); l->logger = logger; l->id = "INIT_JK"; /* TODO: Use System logging to notify the user that * we cannot open the configured log file. */ StringCbCopy(shm_name, MAX_PATH, SHM_DEF_PREFIX); jk_log(l, JK_LOG_INFO, "Starting " FULL_VERSION_STRING); StringCbCat(shm_name, MAX_PATH, serverName); StringCbCat(shm_name, MAX_PATH, "_"); StringCbCat(shm_name, MAX_PATH, extension_uri + 1); if ((p = strrchr(shm_name, '.'))) *p = '\0'; jk_set_worker_def_cache_size(DEFAULT_WORKER_THREADS); /* Logging the initialization type: registry or properties file in virtual dir */ if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Detected IIS version %d.%d", iis_info.major, iis_info.minor); if (using_ini_file) { jk_log(l, JK_LOG_DEBUG, "Using ini file %s.", ini_file_name); } else { jk_log(l, JK_LOG_DEBUG, "Using registry."); } jk_log(l, JK_LOG_DEBUG, "Using log file %s.", log_file); jk_log(l, JK_LOG_DEBUG, "Using log level %d.", log_level); jk_log(l, JK_LOG_DEBUG, "Using log rotation time %d seconds.", log_rotationtime); jk_log(l, JK_LOG_DEBUG, "Using log file size %d bytes.", log_filesize); jk_log(l, JK_LOG_DEBUG, "Using extension uri %s.", extension_uri); jk_log(l, JK_LOG_DEBUG, "Using worker file %s.", worker_file); jk_log(l, JK_LOG_DEBUG, "Using worker mount file %s.", worker_mount_file); jk_log(l, JK_LOG_DEBUG, "Using rewrite rule file %s.", rewrite_rule_file); jk_log(l, JK_LOG_DEBUG, "Using uri select %d.", uri_select_option); jk_log(l, JK_LOG_DEBUG, "Using%s chunked encoding.", (chunked_encoding_enabled ? "" : " no")); jk_log(l, JK_LOG_DEBUG, "Using notification event %s (0x%08x)", (iis_info.filter_notify_event == SF_NOTIFY_AUTH_COMPLETE) ? "SF_NOTIFY_AUTH_COMPLETE" : ((iis_info.filter_notify_event == SF_NOTIFY_PREPROC_HEADERS) ? "SF_NOTIFY_PREPROC_HEADERS" : "UNKNOWN"), iis_info.filter_notify_event); if (error_page) { jk_log(l, JK_LOG_DEBUG, "Using error page '%s'.", error_page); } jk_log(l, JK_LOG_DEBUG, "Using uri header %s.", URI_HEADER_NAME); jk_log(l, JK_LOG_DEBUG, "Using query header %s.", QUERY_HEADER_NAME); jk_log(l, JK_LOG_DEBUG, "Using request id header %s.", REQUEST_ID_HEADER_NAME); jk_log(l, JK_LOG_DEBUG, "Using worker header %s.", WORKER_HEADER_NAME); jk_log(l, JK_LOG_DEBUG, "Using worker index %s.", WORKER_HEADER_INDEX); jk_log(l, JK_LOG_DEBUG, "Using translate header %s.", TOMCAT_TRANSLATE_HEADER_NAME); jk_log(l, JK_LOG_DEBUG, "Using a default of %d connections per pool.", DEFAULT_WORKER_THREADS); if (request_id_header) { jk_log(l, JK_LOG_DEBUG, "Using incoming request id header '%s'.", request_id_header); } } if ((log_rotationtime > 0) && (log_filesize > 0)) { jk_log(l, JK_LOG_WARNING, "%s is defined in configuration, but will be ignored because %s is set. ", LOG_FILESIZE_TAG, LOG_ROTATION_TIME_TAG); } if (rewrite_rule_file[0] && jk_map_alloc(&rewrite_map)) { if (jk_map_read_properties(rewrite_map, NULL, rewrite_rule_file, NULL, JK_MAP_HANDLE_RAW, l)) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Loaded rewrite rule file %s.", rewrite_rule_file); } jk_map_alloc(&rregexp_map); for (i = 0; i < jk_map_size(rewrite_map); i++) { const char *src = jk_map_name_at(rewrite_map, i); if (*src == '~') { ap_regex_t *regexp = malloc(sizeof(ap_regex_t)); const char *val = jk_map_value_at(rewrite_map, i); /* Skip leading tilde */ src++; regexp->fake = val; if (ap_regcomp(regexp, src) == JK_TRUE) { jk_map_add(rregexp_map, src, regexp); if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Added regular expression rule %s -> %s", src, regexp->fake); } } else { jk_log(l, JK_LOG_ERROR, "Unable to compile regular expression %s", src); free(regexp); } } } } else { jk_map_free(&rewrite_map); rewrite_map = NULL; } } if (uri_worker_map_alloc(&uw_map, NULL, l)) { rc = JK_FALSE; if (reject_unsafe) uw_map->reject_unsafe = 1; else uw_map->reject_unsafe = 0; uw_map->reload = worker_mount_reload; if (worker_mount_file[0]) { uw_map->fname = worker_mount_file; rc = uri_worker_map_load(uw_map, l); } } if (rc) { rc = JK_FALSE; if (jk_map_alloc(&workers_map)) { if (jk_map_read_properties(workers_map, NULL, worker_file, NULL, JK_MAP_HANDLE_DUPLICATES, l)) { int rv = -1; /* we add the URI->WORKER MAP since workers using AJP14 will feed it */ if (jk_map_resolve_references(workers_map, "worker.", 1, 1, l) == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "Error in resolving configuration references"); } /* * Create named shared memory for each server */ if (shm_config_size == -1) { shm_config_size = jk_shm_calculate_size(workers_map, l); } else if (shm_config_size > 0) { jk_log(l, JK_LOG_WARNING, "The optimal shared memory size can now be determined automatically."); jk_log(l, JK_LOG_WARNING, "You can remove the shm_size attribute if you want to use the optimal size."); } if ((shm_config_size > 0) && (rv = jk_shm_open(shm_name, shm_config_size, l)) != 0) { jk_log(l, JK_LOG_ERROR, "Initializing shm:%s errno=%d. Load balancing workers will not function properly", jk_shm_name(), rv); } if (rv != 0 && (rv = jk_shm_open(NULL, shm_config_size, l)) != 0) { /* Do not try to open the worker if we cannot create * the shared memory segment or heap memory. */ jk_log(l, JK_LOG_EMERG, "Initializing shm:%s errno=%d. Cannot continue", jk_shm_name(), rv); jk_map_free(&workers_map); workers_map = NULL; return JK_FALSE; } else { if (shm_loaded_name[0]) { if (strcmp(shm_loaded_name, shm_name)) { jk_log(l, JK_LOG_WARNING, "Loading different shared memory %s. Already loaded %s", shm_name, shm_loaded_name); } } else { StringCbCopy(shm_loaded_name, MAX_PATH, shm_name); } } worker_env.uri_to_worker = uw_map; worker_env.server_name = serverName; worker_env.pool = NULL; if (wc_open(workers_map, &worker_env, l)) { rc = JK_TRUE; uri_worker_map_ext(uw_map, l); uri_worker_map_switch(uw_map, l); } else { jk_shm_close(l); } } else { jk_log(l, JK_LOG_EMERG, "Unable to read worker file %s. (errno=%d, err=%s)", worker_file, errno, strerror(errno)); } if (rc != JK_TRUE) { jk_map_free(&workers_map); workers_map = NULL; } } } if (rc) { if (watchdog_interval) { DWORD wi; watchdog_handle = CreateThread(NULL, 0, watchdog_thread, NULL, 0, &wi); if (!watchdog_handle) { jk_log(l, JK_LOG_EMERG, "Error %d (0x%08x) creating Watchdog thread", GetLastError(), GetLastError()); watchdog_interval = 0; } } jk_log(l, JK_LOG_INFO, "%s initialized", (FULL_VERSION_STRING)); } return rc; } static BOOL initialize_extension(void) { jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; l->logger = logger; l->id = "INIT_EXTENSION"; if (read_registry_init_data(l)) { if (get_iis_info(&iis_info) != JK_TRUE) { jk_log(l, JK_LOG_ERROR, "Could not retrieve IIS version from registry"); } else { if (use_auth_notification_flags) iis_info.filter_notify_event = SF_NOTIFY_AUTH_COMPLETE; else iis_info.filter_notify_event = SF_NOTIFY_PREPROC_HEADERS; } is_inited = JK_TRUE; } return is_inited; } int parse_uri_select(const char *uri_select) { if (!strcasecmp(uri_select, URI_SELECT_PARSED_VERB)) return URI_SELECT_OPT_PARSED; if (!strcasecmp(uri_select, URI_SELECT_UNPARSED_VERB)) return URI_SELECT_OPT_UNPARSED; if (!strcasecmp(uri_select, URI_SELECT_ESCAPED_VERB)) return URI_SELECT_OPT_ESCAPED; if (!strcasecmp(uri_select, URI_SELECT_PROXY_VERB)) return URI_SELECT_OPT_PROXY; return -1; } static int read_registry_init_data(jk_log_context_t *l) { char tmpbuf[MAX_PATH]; int ok = JK_FALSE; LPVOID src; HKEY hkey; int remain; jk_map_t *map = NULL; remain = jk_check_buffer_size(); if (remain < 0) { jk_log(l, JK_LOG_ERROR, "mod_jk: JK_MAX_ATTRIBUTE_NAME_LEN in jk_util.c is too small, " "increase by %d", -1 * remain); } if (jk_map_alloc(&map)) { if (jk_map_read_properties(map, jk_environment_map, ini_file_name, NULL, JK_MAP_HANDLE_DUPLICATES, l)) { using_ini_file = JK_TRUE; src = map; } else { jk_map_free(&map); } } if (!using_ini_file) { long rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_LOCATION, (DWORD)0, KEY_READ, &hkey); if (ERROR_SUCCESS != rc) { return JK_FALSE; } else { src = hkey; } } if (!get_config_parameter(src, JK_LOG_FILE_TAG, log_file, sizeof(log_file))) goto cleanup; if (is_path_relative(log_file)) { char *fp = path_merge(dll_file_path, log_file); if (fp) { StringCbCopy(log_file, sizeof(log_file), fp); free(fp); } } if (get_config_parameter(src, JK_LOG_LEVEL_TAG, tmpbuf, sizeof(tmpbuf))) { log_level = jk_parse_log_level(tmpbuf); } if (get_config_parameter(src, LOG_ROTATION_TIME_TAG, tmpbuf, sizeof(tmpbuf))) { log_rotationtime = atol(tmpbuf); if (log_rotationtime < 0) { log_rotationtime = 0; } } if (get_config_parameter(src, LOG_FILESIZE_TAG, tmpbuf, sizeof(tmpbuf))) { int tl = lstrlenA(tmpbuf); if (tl > 0) { /* rotatelogs has an 'M' suffix on filesize, which we optionally support for consistency */ if (tmpbuf[tl - 1] == 'M') { tmpbuf[tl - 1] = '\0'; } log_filesize = atol(tmpbuf); if (log_filesize < 0) { log_filesize = 0; } /* Convert to MB as per Apache rotatelogs */ log_filesize *= (1000 * 1000); } } if (!get_config_parameter(src, EXTENSION_URI_TAG, extension_uri, sizeof(extension_uri))) goto cleanup; if (!get_config_parameter(src, JK_WORKER_FILE_TAG, worker_file, sizeof(worker_file))) goto cleanup; if (is_path_relative(worker_file)) { char *fp = path_merge(dll_file_path, worker_file); if (fp) { StringCbCopy(worker_file, sizeof(worker_file), fp); free(fp); } } if (!get_config_parameter(src, JK_MOUNT_FILE_TAG, worker_mount_file, sizeof(worker_mount_file))) goto cleanup; if (is_path_relative(worker_mount_file)) { char *fp = path_merge(dll_file_path, worker_mount_file); if (fp) { StringCbCopy(worker_mount_file, sizeof(worker_mount_file), fp); free(fp); } } if (get_config_parameter(src, URI_REWRITE_TAG, rewrite_rule_file, sizeof(rewrite_rule_file))) { if (is_path_relative(rewrite_rule_file)) { char *fp = path_merge(dll_file_path, rewrite_rule_file); if (fp) { StringCbCopy(rewrite_rule_file, sizeof(rewrite_rule_file), fp); free(fp); } } } if (get_config_parameter(src, URI_SELECT_TAG, tmpbuf, sizeof(tmpbuf))) { int opt = parse_uri_select(tmpbuf); if (opt >= 0) { uri_select_option = opt; } else { jk_log(l, JK_LOG_ERROR, "Invalid value '%s' for configuration item '" URI_SELECT_TAG "'", tmpbuf); } } if (get_config_parameter(src, COLLAPSE_SLASHES_TAG, tmpbuf, sizeof(tmpbuf))) { jk_log(l, JK_LOG_ERROR, "Configuration item '" COLLAPSE_SLASHES_TAG "' is deprecated and will be ignored"); } shm_config_size = get_config_int(src, SHM_SIZE_TAG, -1); worker_mount_reload = get_config_int(src, WORKER_MOUNT_RELOAD_TAG, JK_URIMAP_DEF_RELOAD); strip_session = get_config_bool(src, STRIP_SESSION_TAG, JK_FALSE); use_auth_notification_flags = get_config_int(src, AUTH_COMPLETE_TAG, 1); reject_unsafe = get_config_bool(src, REJECT_UNSAFE_TAG, JK_FALSE); watchdog_interval = get_config_int(src, WATCHDOG_INTERVAL_TAG, 0); if (watchdog_interval < 0) watchdog_interval = 0; chunked_encoding_enabled = get_config_bool(src, ENABLE_CHUNKED_ENCODING_TAG, JK_FALSE); flush_packets = get_config_bool(src, FLUSH_PACKETS_TAG, JK_FALSE); if (get_config_parameter(src, ERROR_PAGE_TAG, error_page_buf, sizeof(error_page_buf))) { error_page = error_page_buf; } if (get_config_parameter(src, REQUEST_ID_HEADER_TAG, request_id_header_buf, sizeof(request_id_header_buf))) { size_t size = strlen(request_id_header_buf); if (size + 2 <= sizeof(request_id_header_buf)) { request_id_header_buf[size + 1] = '\0'; request_id_header_buf[size] = ':'; } request_id_header = request_id_header_buf; } ok = JK_TRUE; cleanup: if (using_ini_file) { jk_map_free(&map); } else { RegCloseKey(hkey); } return ok; } static int get_config_parameter(LPVOID src, const char *tag, char *val, size_t sz) { const char *tmp = NULL; if (using_ini_file) { tmp = jk_map_get_string((jk_map_t*)src, tag, NULL); if (tmp && (strlen(tmp) < sz)) { StringCbCopy(val, sz, tmp); return JK_TRUE; } else { return JK_FALSE; } } else { return get_registry_config_parameter((HKEY)src, tag, val, sz); } } static int get_config_int(LPVOID src, const char *tag, int def) { if (using_ini_file) { return jk_map_get_int((jk_map_t*)src, tag, def); } else { int val; if (get_registry_config_number(src, tag, &val)) { return val; } else { return def; } } } static int get_config_bool(LPVOID src, const char *tag, int def) { if (using_ini_file) { return jk_map_get_bool((jk_map_t*)src, tag, def); } else { char tmpbuf[128]; if (get_registry_config_parameter(src, tag, tmpbuf, sizeof(tmpbuf))) { return jk_get_bool_code(tmpbuf, def); } else { return def; } } } static int get_registry_config_parameter(HKEY hkey, const char *tag, char *b, size_t sz) { DWORD type = 0; LONG lrc; DWORD ssz = (DWORD)sz -1; b[ssz] = '\0'; /* Null terminate in case RegQueryValueEx doesn't */ lrc = RegQueryValueEx(hkey, tag, NULL, &type, (LPBYTE)b, &ssz); if ((ERROR_SUCCESS != lrc) || (type != REG_SZ)) { return JK_FALSE; } return JK_TRUE; } static int get_registry_config_number(HKEY hkey, const char *tag, int *val) { DWORD type = 0; DWORD data = 0; DWORD sz = sizeof(DWORD); LONG lrc; lrc = RegQueryValueEx(hkey, tag, NULL, &type, (LPBYTE)&data, &sz); if ((ERROR_SUCCESS != lrc) || (type != REG_DWORD)) { return JK_FALSE; } *val = (int)data; return JK_TRUE; } static int init_ws_service(isapi_private_data_t * private_data, jk_ws_service_t *s, char **worker_name) { char *all_headers; int worker_index = -1; rule_extension_t *e; char temp_buf[64]; BOOL unknown_content_length = FALSE; unsigned int cnt = 0; char *tmp; jk_log_context_t *l = s->log_ctx; JK_TRACE_ENTER(l); s->start_response = start_response; s->read = iis_read; s->write = iis_write; s->done = iis_done; l = jk_pool_alloc(s->pool, sizeof(jk_log_context_t)); l->logger = logger; l->id = "INIT_WS_SERVICE"; GET_SERVER_VARIABLE_VALUE(HTTP_REQUEST_ID_HEADER_NAME, l->id, "NO-ID"); s->log_ctx = l; GET_SERVER_VARIABLE_VALUE(HTTP_URI_HEADER_NAME, s->req_uri, NULL); if (s->req_uri == NULL) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "No URI header value provided. Defaulting to old behaviour"); s->query_string = private_data->lpEcb->lpszQueryString; *worker_name = DEFAULT_WORKER_NAME; GET_SERVER_VARIABLE_VALUE("URL", s->req_uri, ""); if (unescape_url(s->req_uri) < 0) { JK_TRACE_EXIT(l); return JK_FALSE; } jk_servlet_normalize(s->req_uri, l); } else { GET_SERVER_VARIABLE_VALUE(HTTP_QUERY_HEADER_NAME, s->query_string, ""); GET_SERVER_VARIABLE_VALUE(HTTP_WORKER_HEADER_NAME, (*worker_name), ""); GET_SERVER_VARIABLE_VALUE_INT(HTTP_WORKER_HEADER_INDEX, worker_index, -1); } if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %s", HTTP_WORKER_HEADER_NAME, (*worker_name)); jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %d", HTTP_WORKER_HEADER_INDEX, worker_index); jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %s", HTTP_URI_HEADER_NAME, s->req_uri); jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %s", HTTP_QUERY_HEADER_NAME, s->query_string); jk_log(l, JK_LOG_DEBUG, "Read extension header %s: %s", HTTP_REQUEST_ID_HEADER_NAME, s->log_ctx->id); } GET_SERVER_VARIABLE_VALUE("AUTH_TYPE", s->auth_type, NULL); GET_SERVER_VARIABLE_VALUE("REMOTE_USER", s->remote_user, NULL); GET_SERVER_VARIABLE_VALUE("SERVER_PROTOCOL", s->protocol, ""); GET_SERVER_VARIABLE_VALUE("REMOTE_HOST", s->remote_host, ""); GET_SERVER_VARIABLE_VALUE("REMOTE_ADDR", s->remote_addr, ""); GET_SERVER_VARIABLE_VALUE("REMOTE_PORT", s->remote_port, ""); GET_SERVER_VARIABLE_VALUE("SERVER_NAME", s->server_name, ""); GET_SERVER_VARIABLE_VALUE("LOCAL_ADDR", s->local_addr, ""); GET_SERVER_VARIABLE_VALUE_INT("SERVER_PORT", s->server_port, 80); GET_SERVER_VARIABLE_VALUE("SERVER_SOFTWARE", s->server_software, ""); GET_SERVER_VARIABLE_VALUE_INT("SERVER_PORT_SECURE", s->is_ssl, 0); s->method = private_data->lpEcb->lpszMethod; /* Check for Transfer Encoding */ if (get_server_value(private_data->lpEcb, "HTTP_TRANSFER_ENCODING", temp_buf, sizeof(temp_buf))) { if (strcasecmp(temp_buf, TRANSFER_ENCODING_CHUNKED_VALUE) == 0) { s->is_chunked = JK_TRUE; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Request is Transfer-Encoding: chunked"); } } else { /* XXX: What to do with non chunked T-E ? */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Unsupported Transfer-Encoding: %s", temp_buf); } } if (private_data->lpEcb->cbTotalBytes == 0xFFFFFFFF) { /* We have size larger then 4Gb or Transfer-Encoding: chunked * ReadClient should be called until no more data is returned */ unknown_content_length = TRUE; } else { /* Use the IIS provided content length */ s->content_length = (jk_uint64_t)private_data->lpEcb->cbTotalBytes; } e = get_uri_to_worker_ext(uw_map, worker_index); if (e) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Applying service extensions"); s->extension.reply_timeout = e->reply_timeout; s->extension.sticky_ignore = e->sticky_ignore; s->extension.stateless = e->stateless; s->extension.use_server_error_pages = e->use_server_error_pages; if (e->activation) { s->extension.activation = jk_pool_alloc(s->pool, e->activation_size * sizeof(int)); memcpy(s->extension.activation, e->activation, e->activation_size * sizeof(int)); } if (e->fail_on_status_size > 0) { s->extension.fail_on_status_size = e->fail_on_status_size; s->extension.fail_on_status = jk_pool_alloc(s->pool, e->fail_on_status_size * sizeof(int)); memcpy(s->extension.fail_on_status, e->fail_on_status, e->fail_on_status_size * sizeof(int)); } if (e->session_cookie) { s->extension.session_cookie = jk_pool_strdup(s->pool, e->session_cookie); } if (e->session_path) { s->extension.session_path = jk_pool_strdup(s->pool, e->session_path); } if (e->set_session_cookie) { s->extension.set_session_cookie = e->set_session_cookie; } if (e->session_cookie_path) { s->extension.session_cookie_path = jk_pool_strdup(s->pool, e->session_cookie_path); } } s->uw_map = uw_map; /* * Add SSL IIS environment */ if (s->is_ssl) { char *ssl_env_names[9] = { "CERT_ISSUER", "CERT_SUBJECT", "CERT_COOKIE", "HTTPS_SERVER_SUBJECT", "CERT_FLAGS", "HTTPS_SECRETKEYSIZE", "CERT_SERIALNUMBER", "HTTPS_SERVER_ISSUER", "HTTPS_KEYSIZE" }; char *ssl_env_values[9] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; unsigned int i; unsigned int num_of_vars = 0; for (i = 0; i < 9; i++) { GET_SERVER_VARIABLE_VALUE(ssl_env_names[i], ssl_env_values[i], NULL); if (ssl_env_values[i]) { num_of_vars++; } } /* XXX: To make the isapi plugin more consistent with the other web servers */ /* we should also set s->ssl_cipher, s->ssl_session, and s->ssl_key_size. */ if (num_of_vars) { unsigned int j = 0; s->attributes_names = jk_pool_alloc(&private_data->p, num_of_vars * sizeof(char *)); s->attributes_values = jk_pool_alloc(&private_data->p, num_of_vars * sizeof(char *)); if (!s->attributes_names || !s->attributes_values) { JK_TRACE_EXIT(l); return JK_FALSE; } for (i = 0; i < 9; i++) { if (ssl_env_values[i]) { s->attributes_names[j] = ssl_env_names[i]; s->attributes_values[j] = ssl_env_values[i]; j++; } } s->num_attributes = num_of_vars; if (ssl_env_values[4] && ssl_env_values[4][0] == '1') { CERT_CONTEXT_EX cc; BYTE *cb = jk_pool_alloc(&private_data->p, AJP13_MAX_PACKET_SIZE); if (!cb) { JK_TRACE_EXIT(l); return JK_FALSE; } cc.cbAllocated = AJP13_MAX_PACKET_SIZE; cc.CertContext.pbCertEncoded = cb; cc.CertContext.cbCertEncoded = 0; if (private_data->lpEcb->ServerSupportFunction(private_data->lpEcb->ConnID, HSE_REQ_GET_CERT_INFO_EX, &cc, NULL, NULL) != FALSE) { jk_log(l, JK_LOG_DEBUG, "Client Certificate encoding:%d sz:%d flags:%ld", cc.CertContext. dwCertEncodingType & X509_ASN_ENCODING, cc.CertContext.cbCertEncoded, cc.dwCertificateFlags); s->ssl_cert = jk_pool_alloc(&private_data->p, base64_encode_cert_len(cc.CertContext.cbCertEncoded)); s->ssl_cert_len = base64_encode_cert(s->ssl_cert, cb, cc.CertContext.cbCertEncoded) - 1; } } } } GET_SERVER_VARIABLE_VALUE(ALL_HEADERS, all_headers, NULL); if (!all_headers) { JK_TRACE_EXIT(l); return JK_FALSE; } for (tmp = all_headers; *tmp; tmp++) { if (*tmp == '\n') { cnt++; } } if (cnt) { char *headers_buf = all_headers; unsigned int i; BOOL need_content_length_header = FALSE; if (s->content_length == 0 && unknown_content_length == FALSE) { /* Add content-length=0 only if really zero */ need_content_length_header = TRUE; } /* allocate an extra header slot in case we need to add a content-length header */ s->headers_names = jk_pool_alloc(&private_data->p, (cnt + 1) * sizeof(char *)); s->headers_values = jk_pool_alloc(&private_data->p, (cnt + 1) * sizeof(char *)); if (!s->headers_names || !s->headers_values) { JK_TRACE_EXIT(l); return JK_FALSE; } for (i = 0, tmp = headers_buf; *tmp && i < cnt;) { int real_header = JK_TRUE; #ifdef USE_CGI_HEADERS /* Skip the HTTP_ prefix to the beginning of the header name */ tmp += HTTP_HEADER_PREFIX_LEN; #endif if (!strnicmp(tmp, URI_HEADER_NAME, strlen(URI_HEADER_NAME)) || !strnicmp(tmp, WORKER_HEADER_NAME, strlen(WORKER_HEADER_NAME)) || !strnicmp(tmp, WORKER_HEADER_INDEX, strlen(WORKER_HEADER_INDEX)) || !strnicmp(tmp, QUERY_HEADER_NAME, strlen(QUERY_HEADER_NAME)) || !strnicmp(tmp, REQUEST_ID_HEADER_NAME, strlen(REQUEST_ID_HEADER_NAME))) { /* Skip redirector headers */ cnt--; real_header = JK_FALSE; } else if (!strnicmp(tmp, CONTENT_LENGTH, sizeof(CONTENT_LENGTH) - 1)) { need_content_length_header = FALSE; /* If the content-length is unknown * or larger then 4Gb do not send it. * IIS can also create a synthetic Content-Length header to make * lpcbTotalBytes and the CONTENT_LENGTH server variable agree * on small requests where the entire chunk encoded message is * read into the available buffer. */ if (unknown_content_length || s->is_chunked) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Disregarding Content-Length in request - content is %s", s->is_chunked ? "chunked" : "unknown length"); } cnt--; real_header = JK_FALSE; } else { s->headers_names[i] = tmp; } } else if (!strnicmp(tmp, TOMCAT_TRANSLATE_HEADER_NAME, strlen(TOMCAT_TRANSLATE_HEADER_NAME))) { s->headers_names[i] = TRANSLATE_HEADER_NAME_LC; } else { s->headers_names[i] = tmp; } while (':' != *tmp && *tmp) { #ifdef USE_CGI_HEADERS if (real_header) { if ('_' == *tmp) { *tmp = '-'; } else { *tmp = JK_TOLOWER(*tmp); } } #endif tmp++; } *tmp++ = '\0'; /* Skip all the WS chars after the ':' to the beginning of the header value */ while (' ' == *tmp || '\t' == *tmp || '\v' == *tmp) { tmp++; } if (real_header) { s->headers_values[i] = tmp; } while (*tmp && *tmp != '\n' && *tmp != '\r') { tmp++; } *tmp++ = '\0'; /* skip CR LF */ while (*tmp == '\n' || *tmp == '\r') { tmp++; } if (real_header) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Forwarding request header %s : %s", s->headers_names[i], s->headers_values[i]); } i++; } } /* Add a content-length = 0 header if needed. * Ajp13 assumes an absent content-length header means an unknown, * but non-zero length body. */ if (need_content_length_header) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Incoming request needs explicit Content-Length: 0 in AJP13"); } s->headers_names[cnt] = "Content-Length"; s->headers_values[cnt] = "0"; cnt++; } s->num_headers = cnt; } else { JK_TRACE_EXIT(l); return JK_FALSE; } /* Dump all connection param so we can trace what's going to * the remote tomcat */ if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Service protocol=%s method=%s host=%s addr=%s name=%s port=%d " "auth=%s user=%s uri=%s", STRNULL_FOR_NULL(s->protocol), STRNULL_FOR_NULL(s->method), STRNULL_FOR_NULL(s->remote_host), STRNULL_FOR_NULL(s->remote_addr), STRNULL_FOR_NULL(s->server_name), s->server_port, STRNULL_FOR_NULL(s->auth_type), STRNULL_FOR_NULL(s->remote_user), STRNULL_FOR_NULL(s->req_uri)); jk_log(l, JK_LOG_DEBUG, "Service request headers=%d attributes=%d " "chunked=%s content-length=%" JK_UINT64_T_FMT " available=%u", s->num_headers, s->num_attributes, (s->is_chunked == JK_TRUE) ? "yes" : "no", s->content_length, private_data->lpEcb->cbTotalBytes); } JK_TRACE_EXIT(l); return JK_TRUE; } static BOOL get_server_value(LPEXTENSION_CONTROL_BLOCK lpEcb, char *name, char *buf, size_t bufsz) { DWORD sz = (DWORD)bufsz; buf[0] = '\0'; return lpEcb->GetServerVariable(lpEcb->ConnID, name, buf, &sz); } static char *dup_server_value(LPEXTENSION_CONTROL_BLOCK lpEcb, const char *name, jk_pool_t *p, const char *def) { DWORD sz = HDR_BUFFER_SIZE; char buf[HDR_BUFFER_SIZE]; char *dp; if (lpEcb->GetServerVariable(lpEcb->ConnID, (LPSTR)name, buf, &sz)) { if (sz <= 1) { return def == NULL ? NULL : jk_pool_strdup(p, def); } return jk_pool_strdup(p, buf); } if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return NULL; if ((dp = jk_pool_alloc(p, sz))) { if (lpEcb->GetServerVariable(lpEcb->ConnID, (LPSTR)name, dp, &sz)) return dp; } return NULL; } static const char begin_cert[] = "-----BEGIN CERTIFICATE-----\r\n"; static const char end_cert[] = "-----END CERTIFICATE-----\r\n"; static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static int base64_encode_cert_len(int len) { int n = ((len + 2) / 3 * 4) + 1; /* base64 encoded size */ n += (n + 63 / 64) * 2; /* add CRLF's */ n += sizeof(begin_cert) + sizeof(end_cert) - 2; /* add enclosing strings. */ return n; } static int base64_encode_cert(char *encoded, const char *string, int len) { int i, c; char *p; const char *t; p = encoded; t = begin_cert; while (*t != '\0') *p++ = *t++; c = 0; for (i = 0; i < len - 2; i += 3) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; *p++ = basis_64[((string[i] & 0x3) << 4) | ((int)(string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int)(string[i + 2] & 0xC0) >> 6)]; *p++ = basis_64[string[i + 2] & 0x3F]; c += 4; if (c >= 64) { *p++ = '\r'; *p++ = '\n'; c = 0; } } if (i < len) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; if (i == (len - 1)) { *p++ = basis_64[((string[i] & 0x3) << 4)]; *p++ = '='; } else { *p++ = basis_64[((string[i] & 0x3) << 4) | ((int)(string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; } *p++ = '='; c++; } if (c != 0) { *p++ = '\r'; *p++ = '\n'; } t = end_cert; while (*t != '\0') *p++ = *t++; *p++ = '\0'; return (int)(p - encoded); } /** * Determine version info and the primary notification event */ static int get_iis_info(iis_info_t* iis_info) { HKEY hkey; int rv = JK_FALSE; iis_info->major = 0; iis_info->minor = 0; /* Retrieve the IIS version Major/Minor */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, W3SVC_REGISTRY_KEY, 0, KEY_READ, &hkey) == ERROR_SUCCESS) { if (get_registry_config_number(hkey, "MajorVersion", &iis_info->major) == JK_TRUE && get_registry_config_number(hkey, "MinorVersion", &iis_info->minor) == JK_TRUE) { rv = JK_TRUE; } CloseHandle(hkey); } return rv; } /* * 1. Remove //?/ prefix * 2. Replace UNC/ with // */ static __inline char *NO2UNC(char *fname) { if (fname[0] == '/' && fname[1] == '/' && fname[2] == '?' && fname[3] == '/') { fname += 4; if (fname[0] == 'U' && fname[1] == 'N' && fname[2] == 'C' && fname[3] == '/') { fname += 2; *fname = '/'; } else if (fname[0] == 'U' && fname[1] == 'N' && fname[2] == '/' && fname[3] == '/') { fname += 2; /* Already modified in-place. */ fname += 2; } } return fname; } static __inline void FS2BSA(char *str) { for (; *str != 0; str++) { if (*str == '/') *str = '\\'; } } static __inline void BS2FSA(char *str) { for (; *str != 0; str++) { if (*str == '\\') *str = '/'; } } #define NON_UNC_PATH_LENGTH 248 #define IS_PATH_SEP(C) ((C) == '/' || (C) == '\0') #define IS_DRIVE_CHAR(C) (((C) >= 'A' && (C) <= 'Z') || \ ((C) >= 'a' && (C) <= 'z')) #define _INS_TRAILING_PATH_SEP(s, l) \ if (l > 0 && s[l - 1] != '/') s[l++] = '/', s[l] = '\0' #define _DEL_TRAILING_PATH_SEP(s, l) \ do { \ if (l > 1 && s[l - 1] == '/') { \ if (s[l - 2] != '/' && s[l - 2] != ':') \ s[--l] = '\0'; \ } \ } while(0) static char *skip_prefix(char *path, char **sp) { size_t size; char *cp; /* Convert everything to forward slashes */ BS2FSA(path); /* Remove \\?\ and replace \\?\UNC\ with \\ */ path = NO2UNC(path); size = strlen(path); *sp = path; if (size < 2) { if (path[0] == ' ') { /* Single Trailing space is invalid path */ SetLastError(ERROR_BAD_PATHNAME); return 0; } return path; } else { /* Remove any trailing slash unless this is * a single slash path. */ _DEL_TRAILING_PATH_SEP(path, size); if (path[size - 1] == ' ' || path[size - 1] == '.') { /* Trailing space and dot are invalid file or dir names */ SetLastError(ERROR_BAD_PATHNAME); return 0; } } if (size > 1 && path[1] == ':' && IS_DRIVE_CHAR(path[0])) { /* Never go above C: */ path += 2; } else if (path[0] == '/' && path[1] == '/') { /* Never go above //share/ */ if (path[2] == '.' && path[3] == '/') { /* This is probably //./pipe/ */ return path; } cp = strchr(path + 2, '/'); if (cp != 0) path = cp; else { /* We only have //share */ return path; } } return path; } static char *relative_path(char *path, int* remain) { char *sp; char *cp; int ch = '/'; path = skip_prefix(path, &sp); if (!path) return 0; if (path != sp) { /* Unexpected. Expected a relative path, but it starts with C: or //share/ */ SetLastError(ERROR_BAD_PATHNAME); return 0; } cp = path; while (*path) { if (IS_PATH_SEP(ch) && *path == '.') { /* nd: number of consecutive dot characters */ int nd = 0; while (path[nd] == '.') nd++; if (IS_PATH_SEP(path[nd])) { if (nd > 2) { SetLastError(ERROR_BAD_PATHNAME); return 0; } path += nd; if (*path) path++; if (nd > 1) { if (cp > sp + 1) { cp--; while (cp > sp) { if (IS_PATH_SEP(*(cp - 1))) break; cp--; } } else { (*remain)++; } } } else { ch = *cp++ = *path++; } } else { ch = *cp++ = *path++; } } *cp = '\0'; return sp; } static char *path_merge(const char *root, const char *path) { char merge[8192]; char dir[MAX_PATH]; char *rel; char *out = 0; size_t sz; size_t rsz; int remain = 0; if (root == NULL || path == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } if (FAILED(StringCbCopy(dir, MAX_PATH, root))) { SetLastError(ERROR_FILENAME_EXCED_RANGE); return 0; } if (FAILED(StringCbCopy(merge, 8190, path))) { /* TODO: Use dynamic buffer with larger size */ SetLastError(ERROR_FILENAME_EXCED_RANGE); return 0; } sz = strlen(merge); rsz = strlen(dir); /* Normalize path */ if ((rel = relative_path(merge, &remain))) { size_t bl; if (remain > 0) { char *skip = dir + rsz - 1; char *spr; char *start = skip_prefix(dir, &spr); if (*skip == '/') skip--; while (remain > 0 && skip >= start) { if (*skip == '/') { remain--; } skip--; } if (remain > 0) { SetLastError(ERROR_BAD_PATHNAME); return 0; } if (skip < start) { skip = start; } *++skip = '\0'; } /* one additional byte for trailing '\0', * one additional byte for eventual path * separator between dir and merge */ bl = strlen(dir) + sz + 2; out = malloc(bl); if (out == 0) return 0; /* Prepend dir */ StringCbCopy(out, bl, dir); sz = strlen(out); BS2FSA(out); _INS_TRAILING_PATH_SEP(out, sz); if ((IS_DRIVE_CHAR(rel[0]) && rel[1] == ':')) rel += 2; if (rel[0] == '/') ++rel; if (*rel != '\0') StringCbCopy(out + sz, bl - sz, rel); FS2BSA(out); } return out; } static int is_path_relative(const char *path) { if ((IS_DRIVE_CHAR(path[0]) && path[1] == ':') || path[0] == '/' || path[0] == '\\') return 0; else return 1; } tomcat-connectors-1.2.50-src/native/iis/isapi.def0000644000000000000020000000164514655113617020171 0ustar rootbin; Licensed to the Apache Software Foundation (ASF) under one or more ; contributor license agreements. See the NOTICE file distributed with ; this work for additional information regarding copyright ownership. ; The ASF licenses this file to You under the Apache License, Version 2.0 ; (the "License"); you may not use this file except in compliance with ; the License. You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; LIBRARY "isapi_redirect" EXPORTS HttpFilterProc GetFilterVersion GetExtensionVersion HttpExtensionProc TerminateFilter TerminateExtension tomcat-connectors-1.2.50-src/native/iis/Makefile.vc0000644000000000000020000000667214655113617020460 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # PROJECT = isapi_redirect # Tools CC = cl.exe LINK = link.exe RC = rc.exe MT = mt.exe !IF !DEFINED(BUILD_CPU) || "$(BUILD_CPU)" == "" !ERROR Must specify BUILD_CPU matching compiler x86 or x64 !ENDIF !IF "$(BUILD_CPU)" == "x86" CPUFLAGS = -D_X86_=1 MACHINE = X86 !ELSE CPUFLAGS = -DWIN64 -D_WIN64 MACHINE = AMD64 !ENDIF !IF !DEFINED(WINVER) || "$(WINVER)" == "" WINVER = 0x0601 !ENDIF BUILDBIN = $(WORKDIR)\$(PROJECT).dll BUILDRES = $(WORKDIR)\$(PROJECT).res BUILDPDB = $(WORKDIR)\$(PROJECT).pdb BUILDMFT = $(BUILDBIN).manifest PCRELIB = .\pcre\$(WORKDIR)\pcre.lib WORKDIR = $(BUILD_CPU)_RELEASE CLEANTARGET = rd /s /q $(WORKDIR) MAKEWORKDIR = md $(WORKDIR) CFLAGS = $(CFLAGS) -DNDEBUG -DWIN32 -D_WINNT -DWINNT -D_WIN32_WINNT=$(WINVER) -DWINVER=$(WINVER) -DHAVE_CONFIG_H $(CPUFLAGS) CFLAGS = $(CFLAGS) -DPCRE_STATIC -DJK_ISAPI -DISAPI_EXPORTS $(EXTRA_CFLAGS) CLOPTS = /c /nologo -MD -W3 -O2 -Ob2 -Zi -EHsc PDBFLAGS = -Fo$(WORKDIR)\ -Fd$(WORKDIR)\$(PROJECT) LFLAGS = /nologo /DLL /INCREMENTAL:NO /DEBUG /OPT:REF /SUBSYSTEM:WINDOWS /MACHINE:$(MACHINE) $(EXTRA_LDFLAGS) LDLIBS = Ole32.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib strsafe.lib $(EXTRA_LIBS) INCDIR = -I.\pcre -I..\common OBJECTS = \ $(WORKDIR)\jk_ajp12_worker.obj \ $(WORKDIR)\jk_ajp13.obj \ $(WORKDIR)\jk_ajp13_worker.obj \ $(WORKDIR)\jk_ajp14.obj \ $(WORKDIR)\jk_ajp14_worker.obj \ $(WORKDIR)\jk_ajp_common.obj \ $(WORKDIR)\jk_connect.obj \ $(WORKDIR)\jk_context.obj \ $(WORKDIR)\jk_isapi_plugin.obj \ $(WORKDIR)\jk_lb_worker.obj \ $(WORKDIR)\jk_map.obj \ $(WORKDIR)\jk_md5.obj \ $(WORKDIR)\jk_msg_buff.obj \ $(WORKDIR)\jk_pool.obj \ $(WORKDIR)\jk_shm.obj \ $(WORKDIR)\jk_sockbuf.obj \ $(WORKDIR)\jk_status.obj \ $(WORKDIR)\jk_uri_worker_map.obj \ $(WORKDIR)\jk_url.obj \ $(WORKDIR)\jk_util.obj \ $(WORKDIR)\jk_worker.obj all : libpcre $(WORKDIR) $(BUILDBIN) $(WORKDIR) : @$(MAKEWORKDIR) .c{$(WORKDIR)}.obj: $(CC) $(CLOPTS) $(CFLAGS) $(INCDIR) $(PDBFLAGS) $< {..\common}.c{$(WORKDIR)}.obj: $(CC) $(CLOPTS) $(CFLAGS) $(INCDIR) $(PDBFLAGS) $< $(BUILDRES): ..\common\jk.rc $(RC) /l 0x409 /n /i ..\common /d JK_ISAPI /d NDEBUG /fo $(BUILDRES) ..\common\jk.rc libpcre: @cd .\pcre @$(MAKE) -f Makefile.vc WINVER=$(WINVER) BUILD_CPU=$(BUILD_CPU) CPUFLAGS="$(CPUFLAGS)" @cd .. $(BUILDBIN): $(WORKDIR) $(OBJECTS) $(BUILDRES) $(LINK) $(LFLAGS) $(OBJECTS) $(PCRELIB) $(BUILDRES) $(LDLIBS) /def:isapi.def /out:$(BUILDBIN) /pdb:$(BUILDPDB) @if exist $(BUILDMFT) \ $(MT) -nologo -manifest $(BUILDMFT) -outputresource:$(BUILDBIN);2 clean: @cd .\pcre @$(MAKE) -f Makefile.vc clean @cd .. @-$(CLEANTARGET) 2>NUL tomcat-connectors-1.2.50-src/native/iis/pcre/0000755000000000000020000000000014655113617017327 5ustar rootbintomcat-connectors-1.2.50-src/native/iis/pcre/pcre_chartables.c0000644000000000000020000001725014655113617022621 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This file contains character tables that are used when no external tables are passed to PCRE by the application that calls it. The tables are used only for characters whose code values are less than 256. This is a default version of the tables that assumes ASCII encoding. A program called dftables (which is distributed with PCRE) can be used to build alternative versions of this file. This is necessary if you are running in an EBCDIC environment, or if you want to default to a different encoding, for example ISO-8859-1. When dftables is run, it creates these tables in the current locale. If PCRE is configured with --enable-rebuild-chartables, this happens automatically. The following #includes are present because without them gcc 4.x may remove the array definition from the final binary if PCRE is built into a static library and dead code stripping is activated. This leads to link errors. Pulling in the header ensures that the array gets flagged as "someone outside this compilation unit might reference this" and so it will always be supplied to the linker. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" const pcre_uint8 PRIV(default_tables)[] = { /* This table is a lower casing table. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119, 120,121,122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119, 120,121,122,123,124,125,126,127, 128,129,130,131,132,133,134,135, 136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151, 152,153,154,155,156,157,158,159, 160,161,162,163,164,165,166,167, 168,169,170,171,172,173,174,175, 176,177,178,179,180,181,182,183, 184,185,186,187,188,189,190,191, 192,193,194,195,196,197,198,199, 200,201,202,203,204,205,206,207, 208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223, 224,225,226,227,228,229,230,231, 232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247, 248,249,250,251,252,253,254,255, /* This table is a case flipping table. */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103, 104,105,106,107,108,109,110,111, 112,113,114,115,116,117,118,119, 120,121,122, 91, 92, 93, 94, 95, 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127, 128,129,130,131,132,133,134,135, 136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151, 152,153,154,155,156,157,158,159, 160,161,162,163,164,165,166,167, 168,169,170,171,172,173,174,175, 176,177,178,179,180,181,182,183, 184,185,186,187,188,189,190,191, 192,193,194,195,196,197,198,199, 200,201,202,203,204,205,206,207, 208,209,210,211,212,213,214,215, 216,217,218,219,220,221,222,223, 224,225,226,227,228,229,230,231, 232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247, 248,249,250,251,252,253,254,255, /* This table contains bit maps for various character classes. Each map is 32 bytes long and the bits run from the least significant end of each byte. The classes that have their own maps are: space, xdigit, digit, upper, lower, word, graph, print, punct, and cntrl. Other classes are built from combinations. */ 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03, 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc, 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* This table identifies various classes of character by individual bits: 0x01 white space character 0x02 letter 0x04 decimal digit 0x08 hexadecimal digit 0x10 alphanumeric or '_' 0x80 regular expression metacharacter or binary zero */ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */ 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */ 0x12,0x12,0x12,0x80,0x80,0x00,0x80,0x10, /* X - _ */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */ 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ /* End of pcre_chartables.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_byte_order.c0000644000000000000020000002201714655113617022644 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2014 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains an internal function that tests a compiled pattern to see if it was compiled with the opposite endianness. If so, it uses an auxiliary local function to flip the appropriate bytes. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" /************************************************* * Swap byte functions * *************************************************/ /* The following functions swap the bytes of a pcre_uint16 and pcre_uint32 value. Arguments: value any number Returns: the byte swapped value */ static pcre_uint32 swap_uint32(pcre_uint32 value) { return ((value & 0x000000ff) << 24) | ((value & 0x0000ff00) << 8) | ((value & 0x00ff0000) >> 8) | (value >> 24); } static pcre_uint16 swap_uint16(pcre_uint16 value) { return (value >> 8) | (value << 8); } /************************************************* * Test for a byte-flipped compiled regex * *************************************************/ /* This function swaps the bytes of a compiled pattern usually loaded form the disk. It also sets the tables pointer, which is likely an invalid pointer after reload. Arguments: argument_re points to the compiled expression extra_data points to extra data or is NULL tables points to the character tables or NULL Returns: 0 if the swap is successful, negative on error */ #if defined COMPILE_PCRE8 PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *argument_re, pcre_extra *extra_data, const unsigned char *tables) #elif defined COMPILE_PCRE16 PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *argument_re, pcre16_extra *extra_data, const unsigned char *tables) #elif defined COMPILE_PCRE32 PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *argument_re, pcre32_extra *extra_data, const unsigned char *tables) #endif { REAL_PCRE *re = (REAL_PCRE *)argument_re; pcre_study_data *study; #ifndef COMPILE_PCRE8 pcre_uchar *ptr; int length; #if defined SUPPORT_UTF && defined COMPILE_PCRE16 BOOL utf; BOOL utf16_char; #endif /* SUPPORT_UTF && COMPILE_PCRE16 */ #endif /* !COMPILE_PCRE8 */ if (re == NULL) return PCRE_ERROR_NULL; if (re->magic_number == MAGIC_NUMBER) { if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE; re->tables = tables; return 0; } if (re->magic_number != REVERSED_MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; if ((swap_uint32(re->flags) & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE; re->magic_number = MAGIC_NUMBER; re->size = swap_uint32(re->size); re->options = swap_uint32(re->options); re->flags = swap_uint32(re->flags); re->limit_match = swap_uint32(re->limit_match); re->limit_recursion = swap_uint32(re->limit_recursion); #if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 re->first_char = swap_uint16(re->first_char); re->req_char = swap_uint16(re->req_char); #elif defined COMPILE_PCRE32 re->first_char = swap_uint32(re->first_char); re->req_char = swap_uint32(re->req_char); #endif re->max_lookbehind = swap_uint16(re->max_lookbehind); re->top_bracket = swap_uint16(re->top_bracket); re->top_backref = swap_uint16(re->top_backref); re->name_table_offset = swap_uint16(re->name_table_offset); re->name_entry_size = swap_uint16(re->name_entry_size); re->name_count = swap_uint16(re->name_count); re->ref_count = swap_uint16(re->ref_count); re->tables = tables; if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0) { study = (pcre_study_data *)extra_data->study_data; study->size = swap_uint32(study->size); study->flags = swap_uint32(study->flags); study->minlength = swap_uint32(study->minlength); } #ifndef COMPILE_PCRE8 ptr = (pcre_uchar *)re + re->name_table_offset; length = re->name_count * re->name_entry_size; #if defined SUPPORT_UTF && defined COMPILE_PCRE16 utf = (re->options & PCRE_UTF16) != 0; utf16_char = FALSE; #endif /* SUPPORT_UTF && COMPILE_PCRE16 */ while(TRUE) { /* Swap previous characters. */ while (length-- > 0) { #if defined COMPILE_PCRE16 *ptr = swap_uint16(*ptr); #elif defined COMPILE_PCRE32 *ptr = swap_uint32(*ptr); #endif ptr++; } #if defined SUPPORT_UTF && defined COMPILE_PCRE16 if (utf16_char) { if (HAS_EXTRALEN(ptr[-1])) { /* We know that there is only one extra character in UTF-16. */ *ptr = swap_uint16(*ptr); ptr++; } } utf16_char = FALSE; #endif /* SUPPORT_UTF */ /* Get next opcode. */ length = 0; #if defined COMPILE_PCRE16 *ptr = swap_uint16(*ptr); #elif defined COMPILE_PCRE32 *ptr = swap_uint32(*ptr); #endif switch (*ptr) { case OP_END: return 0; #if defined SUPPORT_UTF && defined COMPILE_PCRE16 case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: case OP_UPTO: case OP_MINUPTO: case OP_EXACT: case OP_POSSTAR: case OP_POSPLUS: case OP_POSQUERY: case OP_POSUPTO: case OP_STARI: case OP_MINSTARI: case OP_PLUSI: case OP_MINPLUSI: case OP_QUERYI: case OP_MINQUERYI: case OP_UPTOI: case OP_MINUPTOI: case OP_EXACTI: case OP_POSSTARI: case OP_POSPLUSI: case OP_POSQUERYI: case OP_POSUPTOI: case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: case OP_NOTUPTO: case OP_NOTMINUPTO: case OP_NOTEXACT: case OP_NOTPOSSTAR: case OP_NOTPOSPLUS: case OP_NOTPOSQUERY: case OP_NOTPOSUPTO: case OP_NOTSTARI: case OP_NOTMINSTARI: case OP_NOTPLUSI: case OP_NOTMINPLUSI: case OP_NOTQUERYI: case OP_NOTMINQUERYI: case OP_NOTUPTOI: case OP_NOTMINUPTOI: case OP_NOTEXACTI: case OP_NOTPOSSTARI: case OP_NOTPOSPLUSI: case OP_NOTPOSQUERYI: case OP_NOTPOSUPTOI: if (utf) utf16_char = TRUE; #endif /* Fall through. */ default: length = PRIV(OP_lengths)[*ptr] - 1; break; case OP_CLASS: case OP_NCLASS: /* Skip the character bit map. */ ptr += 32/sizeof(pcre_uchar); length = 0; break; case OP_XCLASS: /* Reverse the size of the XCLASS instance. */ ptr++; #if defined COMPILE_PCRE16 *ptr = swap_uint16(*ptr); #elif defined COMPILE_PCRE32 *ptr = swap_uint32(*ptr); #endif #ifndef COMPILE_PCRE32 if (LINK_SIZE > 1) { /* LINK_SIZE can be 1 or 2 in 16 bit mode. */ ptr++; *ptr = swap_uint16(*ptr); } #endif ptr++; length = (GET(ptr, -LINK_SIZE)) - (1 + LINK_SIZE + 1); #if defined COMPILE_PCRE16 *ptr = swap_uint16(*ptr); #elif defined COMPILE_PCRE32 *ptr = swap_uint32(*ptr); #endif if ((*ptr & XCL_MAP) != 0) { /* Skip the character bit map. */ ptr += 32/sizeof(pcre_uchar); length -= 32/sizeof(pcre_uchar); } break; } ptr++; } /* Control should never reach here in 16/32 bit mode. */ #else /* In 8-bit mode, the pattern does not need to be processed. */ return 0; #endif /* !COMPILE_PCRE8 */ } /* End of pcre_byte_order.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/config.h0000644000000000000020000000102314655113617020741 0ustar rootbin/* config.h. */ #define HAVE_LIMITS_H 1 #define HAVE_LONG_LONG 1 #define HAVE_MEMMOVE 1 #define HAVE_SYS_STAT_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_UNSIGNED_LONG_LONG 1 #define HAVE_WINDOWS_H 1 #define HAVE__STRTOI64 1 #define LINK_SIZE 2 #define MATCH_LIMIT 10000000 #define MATCH_LIMIT_RECURSION MATCH_LIMIT #define MAX_NAME_COUNT 10000 #define MAX_NAME_SIZE 32 #define NEWLINE 10 #define PARENS_NEST_LIMIT 250 #define PCREGREP_BUFSIZE 20480 #define PCRE_STATIC 1 #define POSIX_MALLOC_THRESHOLD 10 #define SUPPORT_PCRE8 1 tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_tables.c0000644000000000000020000007014614655113617021766 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ #ifndef PCRE_INCLUDED /* This module contains some fixed tables that are used by more than one of the PCRE code modules. The tables are also #included by the pcretest program, which uses macros to change their names from _pcre_xxx to xxxx, thereby avoiding name clashes with the library. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" #endif /* PCRE_INCLUDED */ /* Table of sizes for the fixed-length opcodes. It's defined in a macro so that the definition is next to the definition of the opcodes in pcre_internal.h. */ const pcre_uint8 PRIV(OP_lengths)[] = { OP_LENGTHS }; /* Tables of horizontal and vertical whitespace characters, suitable for adding to classes. */ const pcre_uint32 PRIV(hspace_list)[] = { HSPACE_LIST }; const pcre_uint32 PRIV(vspace_list)[] = { VSPACE_LIST }; /************************************************* * Tables for UTF-8 support * *************************************************/ /* These are the breakpoints for different numbers of bytes in a UTF-8 character. */ #if (defined SUPPORT_UTF && defined COMPILE_PCRE8) \ || (defined PCRE_INCLUDED && (defined SUPPORT_PCRE16 || defined SUPPORT_PCRE32)) /* These tables are also required by pcretest in 16- or 32-bit mode. */ const int PRIV(utf8_table1)[] = { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff}; const int PRIV(utf8_table1_size) = sizeof(PRIV(utf8_table1)) / sizeof(int); /* These are the indicator bits and the mask for the data bits to set in the first byte of a character, indexed by the number of additional bytes. */ const int PRIV(utf8_table2)[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}; const int PRIV(utf8_table3)[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; /* Table of the number of extra bytes, indexed by the first byte masked with 0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */ const pcre_uint8 PRIV(utf8_table4)[] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; #endif /* (SUPPORT_UTF && COMPILE_PCRE8) || (PCRE_INCLUDED && SUPPORT_PCRE[16|32])*/ #ifdef SUPPORT_UTF /* Table to translate from particular type value to the general value. */ const pcre_uint32 PRIV(ucp_gentype)[] = { ucp_C, ucp_C, ucp_C, ucp_C, ucp_C, /* Cc, Cf, Cn, Co, Cs */ ucp_L, ucp_L, ucp_L, ucp_L, ucp_L, /* Ll, Lu, Lm, Lo, Lt */ ucp_M, ucp_M, ucp_M, /* Mc, Me, Mn */ ucp_N, ucp_N, ucp_N, /* Nd, Nl, No */ ucp_P, ucp_P, ucp_P, ucp_P, ucp_P, /* Pc, Pd, Pe, Pf, Pi */ ucp_P, ucp_P, /* Ps, Po */ ucp_S, ucp_S, ucp_S, ucp_S, /* Sc, Sk, Sm, So */ ucp_Z, ucp_Z, ucp_Z /* Zl, Zp, Zs */ }; /* This table encodes the rules for finding the end of an extended grapheme cluster. Every code point has a grapheme break property which is one of the ucp_gbXX values defined in ucp.h. The 2-dimensional table is indexed by the properties of two adjacent code points. The left property selects a word from the table, and the right property selects a bit from that word like this: ucp_gbtable[left-property] & (1 << right-property) The value is non-zero if a grapheme break is NOT permitted between the relevant two code points. The breaking rules are as follows: 1. Break at the start and end of text (pretty obviously). 2. Do not break between a CR and LF; otherwise, break before and after controls. 3. Do not break Hangul syllable sequences, the rules for which are: L may be followed by L, V, LV or LVT LV or V may be followed by V or T LVT or T may be followed by T 4. Do not break before extending characters. The next two rules are only for extended grapheme clusters (but that's what we are implementing). 5. Do not break before SpacingMarks. 6. Do not break after Prepend characters. 7. Otherwise, break everywhere. */ const pcre_uint32 PRIV(ucp_gbtable[]) = { (1< #include #include // defines the Arg class // This isn't technically needed here, but we include it // anyway so folks who include pcrecpp.h don't have to. #include namespace pcrecpp { #define PCRE_SET_OR_CLEAR(b, o) \ if (b) all_options_ |= (o); else all_options_ &= ~(o); \ return *this #define PCRE_IS_SET(o) \ (all_options_ & o) == o /***** Compiling regular expressions: the RE class *****/ // RE_Options allow you to set options to be passed along to pcre, // along with other options we put on top of pcre. // Only 9 modifiers, plus match_limit and match_limit_recursion, // are supported now. class PCRECPP_EXP_DEFN RE_Options { public: // constructor RE_Options() : match_limit_(0), match_limit_recursion_(0), all_options_(0) {} // alternative constructor. // To facilitate transfer of legacy code from C programs // // This lets you do // RE(pattern, RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).PartialMatch(str); // But new code is better off doing // RE(pattern, // RE_Options().set_caseless(true).set_multiline(true)).PartialMatch(str); RE_Options(int option_flags) : match_limit_(0), match_limit_recursion_(0), all_options_(option_flags) {} // we're fine with the default destructor, copy constructor, etc. // accessors and mutators int match_limit() const { return match_limit_; }; RE_Options &set_match_limit(int limit) { match_limit_ = limit; return *this; } int match_limit_recursion() const { return match_limit_recursion_; }; RE_Options &set_match_limit_recursion(int limit) { match_limit_recursion_ = limit; return *this; } bool caseless() const { return PCRE_IS_SET(PCRE_CASELESS); } RE_Options &set_caseless(bool x) { PCRE_SET_OR_CLEAR(x, PCRE_CASELESS); } bool multiline() const { return PCRE_IS_SET(PCRE_MULTILINE); } RE_Options &set_multiline(bool x) { PCRE_SET_OR_CLEAR(x, PCRE_MULTILINE); } bool dotall() const { return PCRE_IS_SET(PCRE_DOTALL); } RE_Options &set_dotall(bool x) { PCRE_SET_OR_CLEAR(x, PCRE_DOTALL); } bool extended() const { return PCRE_IS_SET(PCRE_EXTENDED); } RE_Options &set_extended(bool x) { PCRE_SET_OR_CLEAR(x, PCRE_EXTENDED); } bool dollar_endonly() const { return PCRE_IS_SET(PCRE_DOLLAR_ENDONLY); } RE_Options &set_dollar_endonly(bool x) { PCRE_SET_OR_CLEAR(x, PCRE_DOLLAR_ENDONLY); } bool extra() const { return PCRE_IS_SET(PCRE_EXTRA); } RE_Options &set_extra(bool x) { PCRE_SET_OR_CLEAR(x, PCRE_EXTRA); } bool ungreedy() const { return PCRE_IS_SET(PCRE_UNGREEDY); } RE_Options &set_ungreedy(bool x) { PCRE_SET_OR_CLEAR(x, PCRE_UNGREEDY); } bool utf8() const { return PCRE_IS_SET(PCRE_UTF8); } RE_Options &set_utf8(bool x) { PCRE_SET_OR_CLEAR(x, PCRE_UTF8); } bool no_auto_capture() const { return PCRE_IS_SET(PCRE_NO_AUTO_CAPTURE); } RE_Options &set_no_auto_capture(bool x) { PCRE_SET_OR_CLEAR(x, PCRE_NO_AUTO_CAPTURE); } RE_Options &set_all_options(int opt) { all_options_ = opt; return *this; } int all_options() const { return all_options_ ; } // TODO: add other pcre flags private: int match_limit_; int match_limit_recursion_; int all_options_; }; // These functions return some common RE_Options static inline RE_Options UTF8() { return RE_Options().set_utf8(true); } static inline RE_Options CASELESS() { return RE_Options().set_caseless(true); } static inline RE_Options MULTILINE() { return RE_Options().set_multiline(true); } static inline RE_Options DOTALL() { return RE_Options().set_dotall(true); } static inline RE_Options EXTENDED() { return RE_Options().set_extended(true); } // Interface for regular expression matching. Also corresponds to a // pre-compiled regular expression. An "RE" object is safe for // concurrent use by multiple threads. class PCRECPP_EXP_DEFN RE { public: // We provide implicit conversions from strings so that users can // pass in a string or a "const char*" wherever an "RE" is expected. RE(const string& pat) { Init(pat, NULL); } RE(const string& pat, const RE_Options& option) { Init(pat, &option); } RE(const char* pat) { Init(pat, NULL); } RE(const char* pat, const RE_Options& option) { Init(pat, &option); } RE(const unsigned char* pat) { Init(reinterpret_cast(pat), NULL); } RE(const unsigned char* pat, const RE_Options& option) { Init(reinterpret_cast(pat), &option); } // Copy constructor & assignment - note that these are expensive // because they recompile the expression. RE(const RE& re) { Init(re.pattern_, &re.options_); } const RE& operator=(const RE& re) { if (this != &re) { Cleanup(); // This is the code that originally came from Google // Init(re.pattern_.c_str(), &re.options_); // This is the replacement from Ari Pollak Init(re.pattern_, &re.options_); } return *this; } ~RE(); // The string specification for this RE. E.g. // RE re("ab*c?d+"); // re.pattern(); // "ab*c?d+" const string& pattern() const { return pattern_; } // If RE could not be created properly, returns an error string. // Else returns the empty string. const string& error() const { return *error_; } /***** The useful part: the matching interface *****/ // This is provided so one can do pattern.ReplaceAll() just as // easily as ReplaceAll(pattern-text, ....) bool FullMatch(const StringPiece& text, const Arg& ptr1 = no_arg, const Arg& ptr2 = no_arg, const Arg& ptr3 = no_arg, const Arg& ptr4 = no_arg, const Arg& ptr5 = no_arg, const Arg& ptr6 = no_arg, const Arg& ptr7 = no_arg, const Arg& ptr8 = no_arg, const Arg& ptr9 = no_arg, const Arg& ptr10 = no_arg, const Arg& ptr11 = no_arg, const Arg& ptr12 = no_arg, const Arg& ptr13 = no_arg, const Arg& ptr14 = no_arg, const Arg& ptr15 = no_arg, const Arg& ptr16 = no_arg) const; bool PartialMatch(const StringPiece& text, const Arg& ptr1 = no_arg, const Arg& ptr2 = no_arg, const Arg& ptr3 = no_arg, const Arg& ptr4 = no_arg, const Arg& ptr5 = no_arg, const Arg& ptr6 = no_arg, const Arg& ptr7 = no_arg, const Arg& ptr8 = no_arg, const Arg& ptr9 = no_arg, const Arg& ptr10 = no_arg, const Arg& ptr11 = no_arg, const Arg& ptr12 = no_arg, const Arg& ptr13 = no_arg, const Arg& ptr14 = no_arg, const Arg& ptr15 = no_arg, const Arg& ptr16 = no_arg) const; bool Consume(StringPiece* input, const Arg& ptr1 = no_arg, const Arg& ptr2 = no_arg, const Arg& ptr3 = no_arg, const Arg& ptr4 = no_arg, const Arg& ptr5 = no_arg, const Arg& ptr6 = no_arg, const Arg& ptr7 = no_arg, const Arg& ptr8 = no_arg, const Arg& ptr9 = no_arg, const Arg& ptr10 = no_arg, const Arg& ptr11 = no_arg, const Arg& ptr12 = no_arg, const Arg& ptr13 = no_arg, const Arg& ptr14 = no_arg, const Arg& ptr15 = no_arg, const Arg& ptr16 = no_arg) const; bool FindAndConsume(StringPiece* input, const Arg& ptr1 = no_arg, const Arg& ptr2 = no_arg, const Arg& ptr3 = no_arg, const Arg& ptr4 = no_arg, const Arg& ptr5 = no_arg, const Arg& ptr6 = no_arg, const Arg& ptr7 = no_arg, const Arg& ptr8 = no_arg, const Arg& ptr9 = no_arg, const Arg& ptr10 = no_arg, const Arg& ptr11 = no_arg, const Arg& ptr12 = no_arg, const Arg& ptr13 = no_arg, const Arg& ptr14 = no_arg, const Arg& ptr15 = no_arg, const Arg& ptr16 = no_arg) const; bool Replace(const StringPiece& rewrite, string *str) const; int GlobalReplace(const StringPiece& rewrite, string *str) const; bool Extract(const StringPiece &rewrite, const StringPiece &text, string *out) const; // Escapes all potentially meaningful regexp characters in // 'unquoted'. The returned string, used as a regular expression, // will exactly match the original string. For example, // 1.5-2.0? // may become: // 1\.5\-2\.0\? // Note QuoteMeta behaves the same as perl's QuoteMeta function, // *except* that it escapes the NUL character (\0) as backslash + 0, // rather than backslash + NUL. static string QuoteMeta(const StringPiece& unquoted); /***** Generic matching interface *****/ // Type of match (TODO: Should be restructured as part of RE_Options) enum Anchor { UNANCHORED, // No anchoring ANCHOR_START, // Anchor at start only ANCHOR_BOTH // Anchor at start and end }; // General matching routine. Stores the length of the match in // "*consumed" if successful. bool DoMatch(const StringPiece& text, Anchor anchor, int* consumed, const Arg* const* args, int n) const; // Return the number of capturing subpatterns, or -1 if the // regexp wasn't valid on construction. int NumberOfCapturingGroups() const; // The default value for an argument, to indicate the end of the argument // list. This must be used only in optional argument defaults. It should NOT // be passed explicitly. Some people have tried to use it like this: // // FullMatch(x, y, &z, no_arg, &w); // // This is a mistake, and will not work. static Arg no_arg; private: void Init(const string& pattern, const RE_Options* options); void Cleanup(); // Match against "text", filling in "vec" (up to "vecsize" * 2/3) with // pairs of integers for the beginning and end positions of matched // text. The first pair corresponds to the entire matched text; // subsequent pairs correspond, in order, to parentheses-captured // matches. Returns the number of pairs (one more than the number of // the last subpattern with a match) if matching was successful // and zero if the match failed. // I.e. for RE("(foo)|(bar)|(baz)") it will return 2, 3, and 4 when matching // against "foo", "bar", and "baz" respectively. // When matching RE("(foo)|hello") against "hello", it will return 1. // But the values for all subpattern are filled in into "vec". int TryMatch(const StringPiece& text, int startpos, Anchor anchor, bool empty_ok, int *vec, int vecsize) const; // Append the "rewrite" string, with backslash subsitutions from "text" // and "vec", to string "out". bool Rewrite(string *out, const StringPiece& rewrite, const StringPiece& text, int *vec, int veclen) const; // internal implementation for DoMatch bool DoMatchImpl(const StringPiece& text, Anchor anchor, int* consumed, const Arg* const args[], int n, int* vec, int vecsize) const; // Compile the regexp for the specified anchoring mode pcre* Compile(Anchor anchor); string pattern_; RE_Options options_; pcre* re_full_; // For full matches pcre* re_partial_; // For partial matches const string* error_; // Error indicator (or points to empty string) }; } // namespace pcrecpp #endif /* _PCRECPP_H */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_newline.c0000644000000000000020000001402414655113617022146 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2012 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains internal functions for testing newlines when more than one kind of newline is to be recognized. When a newline is found, its length is returned. In principle, we could implement several newline "types", each referring to a different set of newline characters. At present, PCRE supports only NLTYPE_FIXED, which gets handled without these functions, NLTYPE_ANYCRLF, and NLTYPE_ANY. The full list of Unicode newline characters is taken from http://unicode.org/unicode/reports/tr18/. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" /************************************************* * Check for newline at given position * *************************************************/ /* It is guaranteed that the initial value of ptr is less than the end of the string that is being processed. Arguments: ptr pointer to possible newline type the newline type endptr pointer to the end of the string lenptr where to return the length utf TRUE if in utf mode Returns: TRUE or FALSE */ BOOL PRIV(is_newline)(PCRE_PUCHAR ptr, int type, PCRE_PUCHAR endptr, int *lenptr, BOOL utf) { pcre_uint32 c; (void)utf; #ifdef SUPPORT_UTF if (utf) { GETCHAR(c, ptr); } else #endif /* SUPPORT_UTF */ c = *ptr; /* Note that this function is called only for ANY or ANYCRLF. */ if (type == NLTYPE_ANYCRLF) switch(c) { case CHAR_LF: *lenptr = 1; return TRUE; case CHAR_CR: *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1; return TRUE; default: return FALSE; } /* NLTYPE_ANY */ else switch(c) { #ifdef EBCDIC case CHAR_NEL: #endif case CHAR_LF: case CHAR_VT: case CHAR_FF: *lenptr = 1; return TRUE; case CHAR_CR: *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1; return TRUE; #ifndef EBCDIC #ifdef COMPILE_PCRE8 case CHAR_NEL: *lenptr = utf? 2 : 1; return TRUE; case 0x2028: /* LS */ case 0x2029: *lenptr = 3; return TRUE; /* PS */ #else /* COMPILE_PCRE16 || COMPILE_PCRE32 */ case CHAR_NEL: case 0x2028: /* LS */ case 0x2029: *lenptr = 1; return TRUE; /* PS */ #endif /* COMPILE_PCRE8 */ #endif /* Not EBCDIC */ default: return FALSE; } } /************************************************* * Check for newline at previous position * *************************************************/ /* It is guaranteed that the initial value of ptr is greater than the start of the string that is being processed. Arguments: ptr pointer to possible newline type the newline type startptr pointer to the start of the string lenptr where to return the length utf TRUE if in utf mode Returns: TRUE or FALSE */ BOOL PRIV(was_newline)(PCRE_PUCHAR ptr, int type, PCRE_PUCHAR startptr, int *lenptr, BOOL utf) { pcre_uint32 c; (void)utf; ptr--; #ifdef SUPPORT_UTF if (utf) { BACKCHAR(ptr); GETCHAR(c, ptr); } else #endif /* SUPPORT_UTF */ c = *ptr; /* Note that this function is called only for ANY or ANYCRLF. */ if (type == NLTYPE_ANYCRLF) switch(c) { case CHAR_LF: *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1; return TRUE; case CHAR_CR: *lenptr = 1; return TRUE; default: return FALSE; } /* NLTYPE_ANY */ else switch(c) { case CHAR_LF: *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1; return TRUE; #ifdef EBCDIC case CHAR_NEL: #endif case CHAR_VT: case CHAR_FF: case CHAR_CR: *lenptr = 1; return TRUE; #ifndef EBCDIC #ifdef COMPILE_PCRE8 case CHAR_NEL: *lenptr = utf? 2 : 1; return TRUE; case 0x2028: /* LS */ case 0x2029: *lenptr = 3; return TRUE; /* PS */ #else /* COMPILE_PCRE16 || COMPILE_PCRE32 */ case CHAR_NEL: case 0x2028: /* LS */ case 0x2029: *lenptr = 1; return TRUE; /* PS */ #endif /* COMPILE_PCRE8 */ #endif /* NotEBCDIC */ default: return FALSE; } } /* End of pcre_newline.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_scanner.h0000644000000000000020000001471014655113617022145 0ustar rootbin// Copyright (c) 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: Sanjay Ghemawat // // Regular-expression based scanner for parsing an input stream. // // Example 1: parse a sequence of "var = number" entries from input: // // Scanner scanner(input); // string var; // int number; // scanner.SetSkipExpression("\\s+"); // Skip any white space we encounter // while (scanner.Consume("(\\w+) = (\\d+)", &var, &number)) { // ...; // } #ifndef _PCRE_SCANNER_H #define _PCRE_SCANNER_H #include #include #include #include #include namespace pcrecpp { class PCRECPP_EXP_DEFN Scanner { public: Scanner(); explicit Scanner(const std::string& input); ~Scanner(); // Return current line number. The returned line-number is // one-based. I.e. it returns 1 + the number of consumed newlines. // // Note: this method may be slow. It may take time proportional to // the size of the input. int LineNumber() const; // Return the byte-offset that the scanner is looking in the // input data; int Offset() const; // Return true iff the start of the remaining input matches "re" bool LookingAt(const RE& re) const; // Return true iff all of the following are true // a. the start of the remaining input matches "re", // b. if any arguments are supplied, matched sub-patterns can be // parsed and stored into the arguments. // If it returns true, it skips over the matched input and any // following input that matches the "skip" regular expression. bool Consume(const RE& re, const Arg& arg0 = RE::no_arg, const Arg& arg1 = RE::no_arg, const Arg& arg2 = RE::no_arg // TODO: Allow more arguments? ); // Set the "skip" regular expression. If after consuming some data, // a prefix of the input matches this RE, it is automatically // skipped. For example, a programming language scanner would use // a skip RE that matches white space and comments. // // scanner.SetSkipExpression("\\s+|//.*|/[*](.|\n)*?[*]/"); // // Skipping repeats as long as it succeeds. We used to let people do // this by writing "(...)*" in the regular expression, but that added // up to lots of recursive calls within the pcre library, so now we // control repetition explicitly via the function call API. // // You can pass NULL for "re" if you do not want any data to be skipped. void Skip(const char* re); // DEPRECATED; does *not* repeat void SetSkipExpression(const char* re); // Temporarily pause "skip"ing. This // Skip("Foo"); code ; DisableSkip(); code; EnableSkip() // is similar to // Skip("Foo"); code ; Skip(NULL); code ; Skip("Foo"); // but avoids creating/deleting new RE objects. void DisableSkip(); // Reenable previously paused skipping. Any prefix of the input // that matches the skip pattern is immediately dropped. void EnableSkip(); /***** Special wrappers around SetSkip() for some common idioms *****/ // Arranges to skip whitespace, C comments, C++ comments. // The overall RE is a disjunction of the following REs: // \\s whitespace // //.*\n C++ comment // /[*](.|\n)*?[*]/ C comment (x*? means minimal repetitions of x) // We get repetition via the semantics of SetSkipExpression, not by using * void SkipCXXComments() { SetSkipExpression("\\s|//.*\n|/[*](?:\n|.)*?[*]/"); } void set_save_comments(bool comments) { save_comments_ = comments; } bool save_comments() { return save_comments_; } // Append to vector ranges the comments found in the // byte range [start,end] (inclusive) of the input data. // Only comments that were extracted entirely within that // range are returned: no range splitting of atomically-extracted // comments is performed. void GetComments(int start, int end, std::vector *ranges); // Append to vector ranges the comments added // since the last time this was called. This // functionality is provided for efficiency when // interleaving scanning with parsing. void GetNextComments(std::vector *ranges); private: std::string data_; // All the input data StringPiece input_; // Unprocessed input RE* skip_; // If non-NULL, RE for skipping input bool should_skip_; // If true, use skip_ bool skip_repeat_; // If true, repeat skip_ as long as it works bool save_comments_; // If true, aggregate the skip expression // the skipped comments // TODO: later consider requiring that the StringPieces be added // in order by their start position std::vector *comments_; // the offset into comments_ that has been returned by GetNextComments int comments_offset_; // helper function to consume *skip_ and honour // save_comments_ void ConsumeSkip(); }; } // namespace pcrecpp #endif /* _PCRE_SCANNER_H */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre.h0000644000000000000020000007574614655113617020454 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* This is the public header file for the PCRE library, to be #included by applications that call the PCRE functions. Copyright (c) 1997-2014 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ #ifndef _PCRE_H #define _PCRE_H /* The current PCRE version information. */ #define PCRE_MAJOR 8 #define PCRE_MINOR 45 #define PCRE_PRERELEASE #define PCRE_DATE 2021-06-15 /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE, the appropriate export setting is defined in pcre_internal.h, which includes this file. So we don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */ #if defined(_WIN32) && !defined(PCRE_STATIC) # ifndef PCRE_EXP_DECL # define PCRE_EXP_DECL extern __declspec(dllimport) # endif # ifdef __cplusplus # ifndef PCRECPP_EXP_DECL # define PCRECPP_EXP_DECL extern __declspec(dllimport) # endif # ifndef PCRECPP_EXP_DEFN # define PCRECPP_EXP_DEFN __declspec(dllimport) # endif # endif #endif /* By default, we use the standard "extern" declarations. */ #ifndef PCRE_EXP_DECL # ifdef __cplusplus # define PCRE_EXP_DECL extern "C" # else # define PCRE_EXP_DECL extern # endif #endif #ifdef __cplusplus # ifndef PCRECPP_EXP_DECL # define PCRECPP_EXP_DECL extern # endif # ifndef PCRECPP_EXP_DEFN # define PCRECPP_EXP_DEFN # endif #endif /* Have to include stdlib.h in order to ensure that size_t is defined; it is needed here for malloc. */ #include /* Allow for C++ users */ #ifdef __cplusplus extern "C" { #endif /* Public options. Some are compile-time only, some are run-time only, and some are both. Most of the compile-time options are saved with the compiled regex so that they can be inspected during studying (and therefore JIT compiling). Note that pcre_study() has its own set of options. Originally, all the options defined here used distinct bits. However, almost all the bits in a 32-bit word are now used, so in order to conserve them, option bits that were previously only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may also be used for compile-time options that affect only compiling and are not relevant for studying or JIT compiling. Some options for pcre_compile() change its behaviour but do not affect the behaviour of the execution functions. Other options are passed through to the execution functions and affect their behaviour, with or without affecting the behaviour of pcre_compile(). Options that can be passed to pcre_compile() are tagged Cx below, with these variants: C1 Affects compile only C2 Does not affect compile; affects exec, dfa_exec C3 Affects compile, exec, dfa_exec C4 Affects compile, exec, dfa_exec, study C5 Affects compile, exec, study Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged with E and D, respectively. They take precedence over C3, C4, and C5 settings passed from pcre_compile(). Those that are compatible with JIT execution are flagged with J. */ #define PCRE_CASELESS 0x00000001 /* C1 */ #define PCRE_MULTILINE 0x00000002 /* C1 */ #define PCRE_DOTALL 0x00000004 /* C1 */ #define PCRE_EXTENDED 0x00000008 /* C1 */ #define PCRE_ANCHORED 0x00000010 /* C4 E D */ #define PCRE_DOLLAR_ENDONLY 0x00000020 /* C2 */ #define PCRE_EXTRA 0x00000040 /* C1 */ #define PCRE_NOTBOL 0x00000080 /* E D J */ #define PCRE_NOTEOL 0x00000100 /* E D J */ #define PCRE_UNGREEDY 0x00000200 /* C1 */ #define PCRE_NOTEMPTY 0x00000400 /* E D J */ #define PCRE_UTF8 0x00000800 /* C4 ) */ #define PCRE_UTF16 0x00000800 /* C4 ) Synonyms */ #define PCRE_UTF32 0x00000800 /* C4 ) */ #define PCRE_NO_AUTO_CAPTURE 0x00001000 /* C1 */ #define PCRE_NO_UTF8_CHECK 0x00002000 /* C1 E D J ) */ #define PCRE_NO_UTF16_CHECK 0x00002000 /* C1 E D J ) Synonyms */ #define PCRE_NO_UTF32_CHECK 0x00002000 /* C1 E D J ) */ #define PCRE_AUTO_CALLOUT 0x00004000 /* C1 */ #define PCRE_PARTIAL_SOFT 0x00008000 /* E D J ) Synonyms */ #define PCRE_PARTIAL 0x00008000 /* E D J ) */ /* This pair use the same bit. */ #define PCRE_NEVER_UTF 0x00010000 /* C1 ) Overlaid */ #define PCRE_DFA_SHORTEST 0x00010000 /* D ) Overlaid */ /* This pair use the same bit. */ #define PCRE_NO_AUTO_POSSESS 0x00020000 /* C1 ) Overlaid */ #define PCRE_DFA_RESTART 0x00020000 /* D ) Overlaid */ #define PCRE_FIRSTLINE 0x00040000 /* C3 */ #define PCRE_DUPNAMES 0x00080000 /* C1 */ #define PCRE_NEWLINE_CR 0x00100000 /* C3 E D */ #define PCRE_NEWLINE_LF 0x00200000 /* C3 E D */ #define PCRE_NEWLINE_CRLF 0x00300000 /* C3 E D */ #define PCRE_NEWLINE_ANY 0x00400000 /* C3 E D */ #define PCRE_NEWLINE_ANYCRLF 0x00500000 /* C3 E D */ #define PCRE_BSR_ANYCRLF 0x00800000 /* C3 E D */ #define PCRE_BSR_UNICODE 0x01000000 /* C3 E D */ #define PCRE_JAVASCRIPT_COMPAT 0x02000000 /* C5 */ #define PCRE_NO_START_OPTIMIZE 0x04000000 /* C2 E D ) Synonyms */ #define PCRE_NO_START_OPTIMISE 0x04000000 /* C2 E D ) */ #define PCRE_PARTIAL_HARD 0x08000000 /* E D J */ #define PCRE_NOTEMPTY_ATSTART 0x10000000 /* E D J */ #define PCRE_UCP 0x20000000 /* C3 */ /* Exec-time and get/set-time error codes */ #define PCRE_ERROR_NOMATCH (-1) #define PCRE_ERROR_NULL (-2) #define PCRE_ERROR_BADOPTION (-3) #define PCRE_ERROR_BADMAGIC (-4) #define PCRE_ERROR_UNKNOWN_OPCODE (-5) #define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */ #define PCRE_ERROR_NOMEMORY (-6) #define PCRE_ERROR_NOSUBSTRING (-7) #define PCRE_ERROR_MATCHLIMIT (-8) #define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ #define PCRE_ERROR_BADUTF8 (-10) /* Same for 8/16/32 */ #define PCRE_ERROR_BADUTF16 (-10) /* Same for 8/16/32 */ #define PCRE_ERROR_BADUTF32 (-10) /* Same for 8/16/32 */ #define PCRE_ERROR_BADUTF8_OFFSET (-11) /* Same for 8/16 */ #define PCRE_ERROR_BADUTF16_OFFSET (-11) /* Same for 8/16 */ #define PCRE_ERROR_PARTIAL (-12) #define PCRE_ERROR_BADPARTIAL (-13) #define PCRE_ERROR_INTERNAL (-14) #define PCRE_ERROR_BADCOUNT (-15) #define PCRE_ERROR_DFA_UITEM (-16) #define PCRE_ERROR_DFA_UCOND (-17) #define PCRE_ERROR_DFA_UMLIMIT (-18) #define PCRE_ERROR_DFA_WSSIZE (-19) #define PCRE_ERROR_DFA_RECURSE (-20) #define PCRE_ERROR_RECURSIONLIMIT (-21) #define PCRE_ERROR_NULLWSLIMIT (-22) /* No longer actually used */ #define PCRE_ERROR_BADNEWLINE (-23) #define PCRE_ERROR_BADOFFSET (-24) #define PCRE_ERROR_SHORTUTF8 (-25) #define PCRE_ERROR_SHORTUTF16 (-25) /* Same for 8/16 */ #define PCRE_ERROR_RECURSELOOP (-26) #define PCRE_ERROR_JIT_STACKLIMIT (-27) #define PCRE_ERROR_BADMODE (-28) #define PCRE_ERROR_BADENDIANNESS (-29) #define PCRE_ERROR_DFA_BADRESTART (-30) #define PCRE_ERROR_JIT_BADOPTION (-31) #define PCRE_ERROR_BADLENGTH (-32) #define PCRE_ERROR_UNSET (-33) /* Specific error codes for UTF-8 validity checks */ #define PCRE_UTF8_ERR0 0 #define PCRE_UTF8_ERR1 1 #define PCRE_UTF8_ERR2 2 #define PCRE_UTF8_ERR3 3 #define PCRE_UTF8_ERR4 4 #define PCRE_UTF8_ERR5 5 #define PCRE_UTF8_ERR6 6 #define PCRE_UTF8_ERR7 7 #define PCRE_UTF8_ERR8 8 #define PCRE_UTF8_ERR9 9 #define PCRE_UTF8_ERR10 10 #define PCRE_UTF8_ERR11 11 #define PCRE_UTF8_ERR12 12 #define PCRE_UTF8_ERR13 13 #define PCRE_UTF8_ERR14 14 #define PCRE_UTF8_ERR15 15 #define PCRE_UTF8_ERR16 16 #define PCRE_UTF8_ERR17 17 #define PCRE_UTF8_ERR18 18 #define PCRE_UTF8_ERR19 19 #define PCRE_UTF8_ERR20 20 #define PCRE_UTF8_ERR21 21 #define PCRE_UTF8_ERR22 22 /* Unused (was non-character) */ /* Specific error codes for UTF-16 validity checks */ #define PCRE_UTF16_ERR0 0 #define PCRE_UTF16_ERR1 1 #define PCRE_UTF16_ERR2 2 #define PCRE_UTF16_ERR3 3 #define PCRE_UTF16_ERR4 4 /* Unused (was non-character) */ /* Specific error codes for UTF-32 validity checks */ #define PCRE_UTF32_ERR0 0 #define PCRE_UTF32_ERR1 1 #define PCRE_UTF32_ERR2 2 /* Unused (was non-character) */ #define PCRE_UTF32_ERR3 3 /* Request types for pcre_fullinfo() */ #define PCRE_INFO_OPTIONS 0 #define PCRE_INFO_SIZE 1 #define PCRE_INFO_CAPTURECOUNT 2 #define PCRE_INFO_BACKREFMAX 3 #define PCRE_INFO_FIRSTBYTE 4 #define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */ #define PCRE_INFO_FIRSTTABLE 5 #define PCRE_INFO_LASTLITERAL 6 #define PCRE_INFO_NAMEENTRYSIZE 7 #define PCRE_INFO_NAMECOUNT 8 #define PCRE_INFO_NAMETABLE 9 #define PCRE_INFO_STUDYSIZE 10 #define PCRE_INFO_DEFAULT_TABLES 11 #define PCRE_INFO_OKPARTIAL 12 #define PCRE_INFO_JCHANGED 13 #define PCRE_INFO_HASCRORLF 14 #define PCRE_INFO_MINLENGTH 15 #define PCRE_INFO_JIT 16 #define PCRE_INFO_JITSIZE 17 #define PCRE_INFO_MAXLOOKBEHIND 18 #define PCRE_INFO_FIRSTCHARACTER 19 #define PCRE_INFO_FIRSTCHARACTERFLAGS 20 #define PCRE_INFO_REQUIREDCHAR 21 #define PCRE_INFO_REQUIREDCHARFLAGS 22 #define PCRE_INFO_MATCHLIMIT 23 #define PCRE_INFO_RECURSIONLIMIT 24 #define PCRE_INFO_MATCH_EMPTY 25 /* Request types for pcre_config(). Do not re-arrange, in order to remain compatible. */ #define PCRE_CONFIG_UTF8 0 #define PCRE_CONFIG_NEWLINE 1 #define PCRE_CONFIG_LINK_SIZE 2 #define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 #define PCRE_CONFIG_MATCH_LIMIT 4 #define PCRE_CONFIG_STACKRECURSE 5 #define PCRE_CONFIG_UNICODE_PROPERTIES 6 #define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7 #define PCRE_CONFIG_BSR 8 #define PCRE_CONFIG_JIT 9 #define PCRE_CONFIG_UTF16 10 #define PCRE_CONFIG_JITTARGET 11 #define PCRE_CONFIG_UTF32 12 #define PCRE_CONFIG_PARENS_LIMIT 13 /* Request types for pcre_study(). Do not re-arrange, in order to remain compatible. */ #define PCRE_STUDY_JIT_COMPILE 0x0001 #define PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE 0x0002 #define PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE 0x0004 #define PCRE_STUDY_EXTRA_NEEDED 0x0008 /* Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine these bits, just add new ones on the end, in order to remain compatible. */ #define PCRE_EXTRA_STUDY_DATA 0x0001 #define PCRE_EXTRA_MATCH_LIMIT 0x0002 #define PCRE_EXTRA_CALLOUT_DATA 0x0004 #define PCRE_EXTRA_TABLES 0x0008 #define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010 #define PCRE_EXTRA_MARK 0x0020 #define PCRE_EXTRA_EXECUTABLE_JIT 0x0040 /* Types */ struct real_pcre8_or_16; /* declaration; the definition is private */ typedef struct real_pcre8_or_16 pcre; struct real_pcre8_or_16; /* declaration; the definition is private */ typedef struct real_pcre8_or_16 pcre16; struct real_pcre32; /* declaration; the definition is private */ typedef struct real_pcre32 pcre32; struct real_pcre_jit_stack; /* declaration; the definition is private */ typedef struct real_pcre_jit_stack pcre_jit_stack; struct real_pcre16_jit_stack; /* declaration; the definition is private */ typedef struct real_pcre16_jit_stack pcre16_jit_stack; struct real_pcre32_jit_stack; /* declaration; the definition is private */ typedef struct real_pcre32_jit_stack pcre32_jit_stack; /* If PCRE is compiled with 16 bit character support, PCRE_UCHAR16 must contain a 16 bit wide signed data type. Otherwise it can be a dummy data type since pcre16 functions are not implemented. There is a check for this in pcre_internal.h. */ #ifndef PCRE_UCHAR16 #define PCRE_UCHAR16 unsigned short #endif #ifndef PCRE_SPTR16 #define PCRE_SPTR16 const PCRE_UCHAR16 * #endif /* If PCRE is compiled with 32 bit character support, PCRE_UCHAR32 must contain a 32 bit wide signed data type. Otherwise it can be a dummy data type since pcre32 functions are not implemented. There is a check for this in pcre_internal.h. */ #ifndef PCRE_UCHAR32 #define PCRE_UCHAR32 unsigned int #endif #ifndef PCRE_SPTR32 #define PCRE_SPTR32 const PCRE_UCHAR32 * #endif /* When PCRE is compiled as a C++ library, the subject pointer type can be replaced with a custom type. For conventional use, the public interface is a const char *. */ #ifndef PCRE_SPTR #define PCRE_SPTR const char * #endif /* The structure for passing additional data to pcre_exec(). This is defined in such as way as to be extensible. Always add new fields at the end, in order to remain compatible. */ typedef struct pcre_extra { unsigned long int flags; /* Bits for which fields are set */ void *study_data; /* Opaque data from pcre_study() */ unsigned long int match_limit; /* Maximum number of calls to match() */ void *callout_data; /* Data passed back in callouts */ const unsigned char *tables; /* Pointer to character tables */ unsigned long int match_limit_recursion; /* Max recursive calls to match() */ unsigned char **mark; /* For passing back a mark pointer */ void *executable_jit; /* Contains a pointer to a compiled jit code */ } pcre_extra; /* Same structure as above, but with 16 bit char pointers. */ typedef struct pcre16_extra { unsigned long int flags; /* Bits for which fields are set */ void *study_data; /* Opaque data from pcre_study() */ unsigned long int match_limit; /* Maximum number of calls to match() */ void *callout_data; /* Data passed back in callouts */ const unsigned char *tables; /* Pointer to character tables */ unsigned long int match_limit_recursion; /* Max recursive calls to match() */ PCRE_UCHAR16 **mark; /* For passing back a mark pointer */ void *executable_jit; /* Contains a pointer to a compiled jit code */ } pcre16_extra; /* Same structure as above, but with 32 bit char pointers. */ typedef struct pcre32_extra { unsigned long int flags; /* Bits for which fields are set */ void *study_data; /* Opaque data from pcre_study() */ unsigned long int match_limit; /* Maximum number of calls to match() */ void *callout_data; /* Data passed back in callouts */ const unsigned char *tables; /* Pointer to character tables */ unsigned long int match_limit_recursion; /* Max recursive calls to match() */ PCRE_UCHAR32 **mark; /* For passing back a mark pointer */ void *executable_jit; /* Contains a pointer to a compiled jit code */ } pcre32_extra; /* The structure for passing out data via the pcre_callout_function. We use a structure so that new fields can be added on the end in future versions, without changing the API of the function, thereby allowing old clients to work without modification. */ typedef struct pcre_callout_block { int version; /* Identifies version of block */ /* ------------------------ Version 0 ------------------------------- */ int callout_number; /* Number compiled into pattern */ int *offset_vector; /* The offset vector */ PCRE_SPTR subject; /* The subject being matched */ int subject_length; /* The length of the subject */ int start_match; /* Offset to start of this match attempt */ int current_position; /* Where we currently are in the subject */ int capture_top; /* Max current capture */ int capture_last; /* Most recently closed capture */ void *callout_data; /* Data passed in with the call */ /* ------------------- Added for Version 1 -------------------------- */ int pattern_position; /* Offset to next item in the pattern */ int next_item_length; /* Length of next item in the pattern */ /* ------------------- Added for Version 2 -------------------------- */ const unsigned char *mark; /* Pointer to current mark or NULL */ /* ------------------------------------------------------------------ */ } pcre_callout_block; /* Same structure as above, but with 16 bit char pointers. */ typedef struct pcre16_callout_block { int version; /* Identifies version of block */ /* ------------------------ Version 0 ------------------------------- */ int callout_number; /* Number compiled into pattern */ int *offset_vector; /* The offset vector */ PCRE_SPTR16 subject; /* The subject being matched */ int subject_length; /* The length of the subject */ int start_match; /* Offset to start of this match attempt */ int current_position; /* Where we currently are in the subject */ int capture_top; /* Max current capture */ int capture_last; /* Most recently closed capture */ void *callout_data; /* Data passed in with the call */ /* ------------------- Added for Version 1 -------------------------- */ int pattern_position; /* Offset to next item in the pattern */ int next_item_length; /* Length of next item in the pattern */ /* ------------------- Added for Version 2 -------------------------- */ const PCRE_UCHAR16 *mark; /* Pointer to current mark or NULL */ /* ------------------------------------------------------------------ */ } pcre16_callout_block; /* Same structure as above, but with 32 bit char pointers. */ typedef struct pcre32_callout_block { int version; /* Identifies version of block */ /* ------------------------ Version 0 ------------------------------- */ int callout_number; /* Number compiled into pattern */ int *offset_vector; /* The offset vector */ PCRE_SPTR32 subject; /* The subject being matched */ int subject_length; /* The length of the subject */ int start_match; /* Offset to start of this match attempt */ int current_position; /* Where we currently are in the subject */ int capture_top; /* Max current capture */ int capture_last; /* Most recently closed capture */ void *callout_data; /* Data passed in with the call */ /* ------------------- Added for Version 1 -------------------------- */ int pattern_position; /* Offset to next item in the pattern */ int next_item_length; /* Length of next item in the pattern */ /* ------------------- Added for Version 2 -------------------------- */ const PCRE_UCHAR32 *mark; /* Pointer to current mark or NULL */ /* ------------------------------------------------------------------ */ } pcre32_callout_block; /* Indirection for store get and free functions. These can be set to alternative malloc/free functions if required. Special ones are used in the non-recursive case for "frames". There is also an optional callout function that is triggered by the (?) regex item. For Virtual Pascal, these definitions have to take another form. */ #ifndef VPCOMPAT PCRE_EXP_DECL void *(*pcre_malloc)(size_t); PCRE_EXP_DECL void (*pcre_free)(void *); PCRE_EXP_DECL void *(*pcre_stack_malloc)(size_t); PCRE_EXP_DECL void (*pcre_stack_free)(void *); PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *); PCRE_EXP_DECL int (*pcre_stack_guard)(void); PCRE_EXP_DECL void *(*pcre16_malloc)(size_t); PCRE_EXP_DECL void (*pcre16_free)(void *); PCRE_EXP_DECL void *(*pcre16_stack_malloc)(size_t); PCRE_EXP_DECL void (*pcre16_stack_free)(void *); PCRE_EXP_DECL int (*pcre16_callout)(pcre16_callout_block *); PCRE_EXP_DECL int (*pcre16_stack_guard)(void); PCRE_EXP_DECL void *(*pcre32_malloc)(size_t); PCRE_EXP_DECL void (*pcre32_free)(void *); PCRE_EXP_DECL void *(*pcre32_stack_malloc)(size_t); PCRE_EXP_DECL void (*pcre32_stack_free)(void *); PCRE_EXP_DECL int (*pcre32_callout)(pcre32_callout_block *); PCRE_EXP_DECL int (*pcre32_stack_guard)(void); #else /* VPCOMPAT */ PCRE_EXP_DECL void *pcre_malloc(size_t); PCRE_EXP_DECL void pcre_free(void *); PCRE_EXP_DECL void *pcre_stack_malloc(size_t); PCRE_EXP_DECL void pcre_stack_free(void *); PCRE_EXP_DECL int pcre_callout(pcre_callout_block *); PCRE_EXP_DECL int pcre_stack_guard(void); PCRE_EXP_DECL void *pcre16_malloc(size_t); PCRE_EXP_DECL void pcre16_free(void *); PCRE_EXP_DECL void *pcre16_stack_malloc(size_t); PCRE_EXP_DECL void pcre16_stack_free(void *); PCRE_EXP_DECL int pcre16_callout(pcre16_callout_block *); PCRE_EXP_DECL int pcre16_stack_guard(void); PCRE_EXP_DECL void *pcre32_malloc(size_t); PCRE_EXP_DECL void pcre32_free(void *); PCRE_EXP_DECL void *pcre32_stack_malloc(size_t); PCRE_EXP_DECL void pcre32_stack_free(void *); PCRE_EXP_DECL int pcre32_callout(pcre32_callout_block *); PCRE_EXP_DECL int pcre32_stack_guard(void); #endif /* VPCOMPAT */ /* User defined callback which provides a stack just before the match starts. */ typedef pcre_jit_stack *(*pcre_jit_callback)(void *); typedef pcre16_jit_stack *(*pcre16_jit_callback)(void *); typedef pcre32_jit_stack *(*pcre32_jit_callback)(void *); /* Exported PCRE functions */ PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *, const unsigned char *); PCRE_EXP_DECL pcre16 *pcre16_compile(PCRE_SPTR16, int, const char **, int *, const unsigned char *); PCRE_EXP_DECL pcre32 *pcre32_compile(PCRE_SPTR32, int, const char **, int *, const unsigned char *); PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **, int *, const unsigned char *); PCRE_EXP_DECL pcre16 *pcre16_compile2(PCRE_SPTR16, int, int *, const char **, int *, const unsigned char *); PCRE_EXP_DECL pcre32 *pcre32_compile2(PCRE_SPTR32, int, int *, const char **, int *, const unsigned char *); PCRE_EXP_DECL int pcre_config(int, void *); PCRE_EXP_DECL int pcre16_config(int, void *); PCRE_EXP_DECL int pcre32_config(int, void *); PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *, int *, int, const char *, char *, int); PCRE_EXP_DECL int pcre16_copy_named_substring(const pcre16 *, PCRE_SPTR16, int *, int, PCRE_SPTR16, PCRE_UCHAR16 *, int); PCRE_EXP_DECL int pcre32_copy_named_substring(const pcre32 *, PCRE_SPTR32, int *, int, PCRE_SPTR32, PCRE_UCHAR32 *, int); PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int, char *, int); PCRE_EXP_DECL int pcre16_copy_substring(PCRE_SPTR16, int *, int, int, PCRE_UCHAR16 *, int); PCRE_EXP_DECL int pcre32_copy_substring(PCRE_SPTR32, int *, int, int, PCRE_UCHAR32 *, int); PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *, const char *, int, int, int, int *, int , int *, int); PCRE_EXP_DECL int pcre16_dfa_exec(const pcre16 *, const pcre16_extra *, PCRE_SPTR16, int, int, int, int *, int , int *, int); PCRE_EXP_DECL int pcre32_dfa_exec(const pcre32 *, const pcre32_extra *, PCRE_SPTR32, int, int, int, int *, int , int *, int); PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR, int, int, int, int *, int); PCRE_EXP_DECL int pcre16_exec(const pcre16 *, const pcre16_extra *, PCRE_SPTR16, int, int, int, int *, int); PCRE_EXP_DECL int pcre32_exec(const pcre32 *, const pcre32_extra *, PCRE_SPTR32, int, int, int, int *, int); PCRE_EXP_DECL int pcre_jit_exec(const pcre *, const pcre_extra *, PCRE_SPTR, int, int, int, int *, int, pcre_jit_stack *); PCRE_EXP_DECL int pcre16_jit_exec(const pcre16 *, const pcre16_extra *, PCRE_SPTR16, int, int, int, int *, int, pcre16_jit_stack *); PCRE_EXP_DECL int pcre32_jit_exec(const pcre32 *, const pcre32_extra *, PCRE_SPTR32, int, int, int, int *, int, pcre32_jit_stack *); PCRE_EXP_DECL void pcre_free_substring(const char *); PCRE_EXP_DECL void pcre16_free_substring(PCRE_SPTR16); PCRE_EXP_DECL void pcre32_free_substring(PCRE_SPTR32); PCRE_EXP_DECL void pcre_free_substring_list(const char **); PCRE_EXP_DECL void pcre16_free_substring_list(PCRE_SPTR16 *); PCRE_EXP_DECL void pcre32_free_substring_list(PCRE_SPTR32 *); PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int, void *); PCRE_EXP_DECL int pcre16_fullinfo(const pcre16 *, const pcre16_extra *, int, void *); PCRE_EXP_DECL int pcre32_fullinfo(const pcre32 *, const pcre32_extra *, int, void *); PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *, int *, int, const char *, const char **); PCRE_EXP_DECL int pcre16_get_named_substring(const pcre16 *, PCRE_SPTR16, int *, int, PCRE_SPTR16, PCRE_SPTR16 *); PCRE_EXP_DECL int pcre32_get_named_substring(const pcre32 *, PCRE_SPTR32, int *, int, PCRE_SPTR32, PCRE_SPTR32 *); PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *); PCRE_EXP_DECL int pcre16_get_stringnumber(const pcre16 *, PCRE_SPTR16); PCRE_EXP_DECL int pcre32_get_stringnumber(const pcre32 *, PCRE_SPTR32); PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *, char **, char **); PCRE_EXP_DECL int pcre16_get_stringtable_entries(const pcre16 *, PCRE_SPTR16, PCRE_UCHAR16 **, PCRE_UCHAR16 **); PCRE_EXP_DECL int pcre32_get_stringtable_entries(const pcre32 *, PCRE_SPTR32, PCRE_UCHAR32 **, PCRE_UCHAR32 **); PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int, const char **); PCRE_EXP_DECL int pcre16_get_substring(PCRE_SPTR16, int *, int, int, PCRE_SPTR16 *); PCRE_EXP_DECL int pcre32_get_substring(PCRE_SPTR32, int *, int, int, PCRE_SPTR32 *); PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int, const char ***); PCRE_EXP_DECL int pcre16_get_substring_list(PCRE_SPTR16, int *, int, PCRE_SPTR16 **); PCRE_EXP_DECL int pcre32_get_substring_list(PCRE_SPTR32, int *, int, PCRE_SPTR32 **); PCRE_EXP_DECL const unsigned char *pcre_maketables(void); PCRE_EXP_DECL const unsigned char *pcre16_maketables(void); PCRE_EXP_DECL const unsigned char *pcre32_maketables(void); PCRE_EXP_DECL int pcre_refcount(pcre *, int); PCRE_EXP_DECL int pcre16_refcount(pcre16 *, int); PCRE_EXP_DECL int pcre32_refcount(pcre32 *, int); PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **); PCRE_EXP_DECL pcre16_extra *pcre16_study(const pcre16 *, int, const char **); PCRE_EXP_DECL pcre32_extra *pcre32_study(const pcre32 *, int, const char **); PCRE_EXP_DECL void pcre_free_study(pcre_extra *); PCRE_EXP_DECL void pcre16_free_study(pcre16_extra *); PCRE_EXP_DECL void pcre32_free_study(pcre32_extra *); PCRE_EXP_DECL const char *pcre_version(void); PCRE_EXP_DECL const char *pcre16_version(void); PCRE_EXP_DECL const char *pcre32_version(void); /* Utility functions for byte order swaps. */ PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *, pcre_extra *, const unsigned char *); PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *, pcre16_extra *, const unsigned char *); PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *, pcre32_extra *, const unsigned char *); PCRE_EXP_DECL int pcre16_utf16_to_host_byte_order(PCRE_UCHAR16 *, PCRE_SPTR16, int, int *, int); PCRE_EXP_DECL int pcre32_utf32_to_host_byte_order(PCRE_UCHAR32 *, PCRE_SPTR32, int, int *, int); /* JIT compiler related functions. */ PCRE_EXP_DECL pcre_jit_stack *pcre_jit_stack_alloc(int, int); PCRE_EXP_DECL pcre16_jit_stack *pcre16_jit_stack_alloc(int, int); PCRE_EXP_DECL pcre32_jit_stack *pcre32_jit_stack_alloc(int, int); PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *); PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *); PCRE_EXP_DECL void pcre32_jit_stack_free(pcre32_jit_stack *); PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *, pcre_jit_callback, void *); PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *, pcre16_jit_callback, void *); PCRE_EXP_DECL void pcre32_assign_jit_stack(pcre32_extra *, pcre32_jit_callback, void *); PCRE_EXP_DECL void pcre_jit_free_unused_memory(void); PCRE_EXP_DECL void pcre16_jit_free_unused_memory(void); PCRE_EXP_DECL void pcre32_jit_free_unused_memory(void); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* End of pcre.h */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_config.c0000644000000000000020000001156714655113617021763 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2012 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains the external function pcre_config(). */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* Keep the original link size. */ static int real_link_size = LINK_SIZE; #include "pcre_internal.h" /************************************************* * Return info about what features are configured * *************************************************/ /* This function has an extensible interface so that additional items can be added compatibly. Arguments: what what information is required where where to put the information Returns: 0 if data returned, negative on error */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_config(int what, void *where) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_config(int what, void *where) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_config(int what, void *where) #endif { switch (what) { case PCRE_CONFIG_UTF8: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 *((int *)where) = 0; return PCRE_ERROR_BADOPTION; #else #if defined SUPPORT_UTF *((int *)where) = 1; #else *((int *)where) = 0; #endif break; #endif case PCRE_CONFIG_UTF16: #if defined COMPILE_PCRE8 || defined COMPILE_PCRE32 *((int *)where) = 0; return PCRE_ERROR_BADOPTION; #else #if defined SUPPORT_UTF *((int *)where) = 1; #else *((int *)where) = 0; #endif break; #endif case PCRE_CONFIG_UTF32: #if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 *((int *)where) = 0; return PCRE_ERROR_BADOPTION; #else #if defined SUPPORT_UTF *((int *)where) = 1; #else *((int *)where) = 0; #endif break; #endif case PCRE_CONFIG_UNICODE_PROPERTIES: #ifdef SUPPORT_UCP *((int *)where) = 1; #else *((int *)where) = 0; #endif break; case PCRE_CONFIG_JIT: #ifdef SUPPORT_JIT *((int *)where) = 1; #else *((int *)where) = 0; #endif break; case PCRE_CONFIG_JITTARGET: #ifdef SUPPORT_JIT *((const char **)where) = PRIV(jit_get_target)(); #else *((const char **)where) = NULL; #endif break; case PCRE_CONFIG_NEWLINE: *((int *)where) = NEWLINE; break; case PCRE_CONFIG_BSR: #ifdef BSR_ANYCRLF *((int *)where) = 1; #else *((int *)where) = 0; #endif break; case PCRE_CONFIG_LINK_SIZE: *((int *)where) = real_link_size; break; case PCRE_CONFIG_POSIX_MALLOC_THRESHOLD: *((int *)where) = POSIX_MALLOC_THRESHOLD; break; case PCRE_CONFIG_PARENS_LIMIT: *((unsigned long int *)where) = PARENS_NEST_LIMIT; break; case PCRE_CONFIG_MATCH_LIMIT: *((unsigned long int *)where) = MATCH_LIMIT; break; case PCRE_CONFIG_MATCH_LIMIT_RECURSION: *((unsigned long int *)where) = MATCH_LIMIT_RECURSION; break; case PCRE_CONFIG_STACKRECURSE: #ifdef NO_RECURSE *((int *)where) = 0; #else *((int *)where) = 1; #endif break; default: return PCRE_ERROR_BADOPTION; } return 0; } /* End of pcre_config.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_valid_utf8.c0000644000000000000020000002373714655113617022565 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains an internal function for validating UTF-8 character strings. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" /************************************************* * Validate a UTF-8 string * *************************************************/ /* This function is called (optionally) at the start of compile or match, to check that a supposed UTF-8 string is actually valid. The early check means that subsequent code can assume it is dealing with a valid string. The check can be turned off for maximum performance, but the consequences of supplying an invalid string are then undefined. Originally, this function checked according to RFC 2279, allowing for values in the range 0 to 0x7fffffff, up to 6 bytes long, but ensuring that they were in the canonical format. Once somebody had pointed out RFC 3629 to me (it obsoletes 2279), additional restrictions were applied. The values are now limited to be between 0 and 0x0010ffff, no more than 4 bytes long, and the subrange 0xd000 to 0xdfff is excluded. However, the format of 5-byte and 6-byte characters is still checked. From release 8.13 more information about the details of the error are passed back in the returned value: PCRE_UTF8_ERR0 No error PCRE_UTF8_ERR1 Missing 1 byte at the end of the string PCRE_UTF8_ERR2 Missing 2 bytes at the end of the string PCRE_UTF8_ERR3 Missing 3 bytes at the end of the string PCRE_UTF8_ERR4 Missing 4 bytes at the end of the string PCRE_UTF8_ERR5 Missing 5 bytes at the end of the string PCRE_UTF8_ERR6 2nd-byte's two top bits are not 0x80 PCRE_UTF8_ERR7 3rd-byte's two top bits are not 0x80 PCRE_UTF8_ERR8 4th-byte's two top bits are not 0x80 PCRE_UTF8_ERR9 5th-byte's two top bits are not 0x80 PCRE_UTF8_ERR10 6th-byte's two top bits are not 0x80 PCRE_UTF8_ERR11 5-byte character is not permitted by RFC 3629 PCRE_UTF8_ERR12 6-byte character is not permitted by RFC 3629 PCRE_UTF8_ERR13 4-byte character with value > 0x10ffff is not permitted PCRE_UTF8_ERR14 3-byte character with value 0xd000-0xdfff is not permitted PCRE_UTF8_ERR15 Overlong 2-byte sequence PCRE_UTF8_ERR16 Overlong 3-byte sequence PCRE_UTF8_ERR17 Overlong 4-byte sequence PCRE_UTF8_ERR18 Overlong 5-byte sequence (won't ever occur) PCRE_UTF8_ERR19 Overlong 6-byte sequence (won't ever occur) PCRE_UTF8_ERR20 Isolated 0x80 byte (not within UTF-8 character) PCRE_UTF8_ERR21 Byte with the illegal value 0xfe or 0xff PCRE_UTF8_ERR22 Unused (was non-character) Arguments: string points to the string length length of string, or -1 if the string is zero-terminated errp pointer to an error position offset variable Returns: = 0 if the string is a valid UTF-8 string > 0 otherwise, setting the offset of the bad character */ int PRIV(valid_utf)(PCRE_PUCHAR string, int length, int *erroroffset) { #ifdef SUPPORT_UTF register PCRE_PUCHAR p; if (length < 0) { for (p = string; *p != 0; p++); length = (int)(p - string); } for (p = string; length-- > 0; p++) { register pcre_uchar ab, c, d; c = *p; if (c < 128) continue; /* ASCII character */ if (c < 0xc0) /* Isolated 10xx xxxx byte */ { *erroroffset = (int)(p - string); return PCRE_UTF8_ERR20; } if (c >= 0xfe) /* Invalid 0xfe or 0xff bytes */ { *erroroffset = (int)(p - string); return PCRE_UTF8_ERR21; } ab = PRIV(utf8_table4)[c & 0x3f]; /* Number of additional bytes */ if (length < ab) { *erroroffset = (int)(p - string); /* Missing bytes */ return ab - length; /* Codes ERR1 to ERR5 */ } length -= ab; /* Length remaining */ /* Check top bits in the second byte */ if (((d = *(++p)) & 0xc0) != 0x80) { *erroroffset = (int)(p - string) - 1; return PCRE_UTF8_ERR6; } /* For each length, check that the remaining bytes start with the 0x80 bit set and not the 0x40 bit. Then check for an overlong sequence, and for the excluded range 0xd800 to 0xdfff. */ switch (ab) { /* 2-byte character. No further bytes to check for 0x80. Check first byte for for xx00 000x (overlong sequence). */ case 1: if ((c & 0x3e) == 0) { *erroroffset = (int)(p - string) - 1; return PCRE_UTF8_ERR15; } break; /* 3-byte character. Check third byte for 0x80. Then check first 2 bytes for 1110 0000, xx0x xxxx (overlong sequence) or 1110 1101, 1010 xxxx (0xd800 - 0xdfff) */ case 2: if ((*(++p) & 0xc0) != 0x80) /* Third byte */ { *erroroffset = (int)(p - string) - 2; return PCRE_UTF8_ERR7; } if (c == 0xe0 && (d & 0x20) == 0) { *erroroffset = (int)(p - string) - 2; return PCRE_UTF8_ERR16; } if (c == 0xed && d >= 0xa0) { *erroroffset = (int)(p - string) - 2; return PCRE_UTF8_ERR14; } break; /* 4-byte character. Check 3rd and 4th bytes for 0x80. Then check first 2 bytes for for 1111 0000, xx00 xxxx (overlong sequence), then check for a character greater than 0x0010ffff (f4 8f bf bf) */ case 3: if ((*(++p) & 0xc0) != 0x80) /* Third byte */ { *erroroffset = (int)(p - string) - 2; return PCRE_UTF8_ERR7; } if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */ { *erroroffset = (int)(p - string) - 3; return PCRE_UTF8_ERR8; } if (c == 0xf0 && (d & 0x30) == 0) { *erroroffset = (int)(p - string) - 3; return PCRE_UTF8_ERR17; } if (c > 0xf4 || (c == 0xf4 && d > 0x8f)) { *erroroffset = (int)(p - string) - 3; return PCRE_UTF8_ERR13; } break; /* 5-byte and 6-byte characters are not allowed by RFC 3629, and will be rejected by the length test below. However, we do the appropriate tests here so that overlong sequences get diagnosed, and also in case there is ever an option for handling these larger code points. */ /* 5-byte character. Check 3rd, 4th, and 5th bytes for 0x80. Then check for 1111 1000, xx00 0xxx */ case 4: if ((*(++p) & 0xc0) != 0x80) /* Third byte */ { *erroroffset = (int)(p - string) - 2; return PCRE_UTF8_ERR7; } if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */ { *erroroffset = (int)(p - string) - 3; return PCRE_UTF8_ERR8; } if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */ { *erroroffset = (int)(p - string) - 4; return PCRE_UTF8_ERR9; } if (c == 0xf8 && (d & 0x38) == 0) { *erroroffset = (int)(p - string) - 4; return PCRE_UTF8_ERR18; } break; /* 6-byte character. Check 3rd-6th bytes for 0x80. Then check for 1111 1100, xx00 00xx. */ case 5: if ((*(++p) & 0xc0) != 0x80) /* Third byte */ { *erroroffset = (int)(p - string) - 2; return PCRE_UTF8_ERR7; } if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */ { *erroroffset = (int)(p - string) - 3; return PCRE_UTF8_ERR8; } if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */ { *erroroffset = (int)(p - string) - 4; return PCRE_UTF8_ERR9; } if ((*(++p) & 0xc0) != 0x80) /* Sixth byte */ { *erroroffset = (int)(p - string) - 5; return PCRE_UTF8_ERR10; } if (c == 0xfc && (d & 0x3c) == 0) { *erroroffset = (int)(p - string) - 5; return PCRE_UTF8_ERR19; } break; } /* Character is valid under RFC 2279, but 4-byte and 5-byte characters are excluded by RFC 3629. The pointer p is currently at the last byte of the character. */ if (ab > 3) { *erroroffset = (int)(p - string) - ab; return (ab == 4)? PCRE_UTF8_ERR11 : PCRE_UTF8_ERR12; } } #else /* Not SUPPORT_UTF */ (void)(string); /* Keep picky compilers happy */ (void)(length); (void)(erroroffset); #endif return PCRE_UTF8_ERR0; /* This indicates success */ } /* End of pcre_valid_utf8.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_string_utils.c0000644000000000000020000001241214655113617023232 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2014 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains internal functions for comparing and finding the length of strings for different data item sizes. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" #ifndef COMPILE_PCRE8 /************************************************* * Compare string utilities * *************************************************/ /* The following two functions compares two strings. Basically a strcmp for non 8 bit characters. Arguments: str1 first string str2 second string Returns: 0 if both string are equal (like strcmp), 1 otherwise */ int PRIV(strcmp_uc_uc)(const pcre_uchar *str1, const pcre_uchar *str2) { pcre_uchar c1; pcre_uchar c2; while (*str1 != '\0' || *str2 != '\0') { c1 = *str1++; c2 = *str2++; if (c1 != c2) return ((c1 > c2) << 1) - 1; } /* Both length and characters must be equal. */ return 0; } #ifdef COMPILE_PCRE32 int PRIV(strcmp_uc_uc_utf)(const pcre_uchar *str1, const pcre_uchar *str2) { pcre_uchar c1; pcre_uchar c2; while (*str1 != '\0' || *str2 != '\0') { c1 = UCHAR21INC(str1); c2 = UCHAR21INC(str2); if (c1 != c2) return ((c1 > c2) << 1) - 1; } /* Both length and characters must be equal. */ return 0; } #endif /* COMPILE_PCRE32 */ int PRIV(strcmp_uc_c8)(const pcre_uchar *str1, const char *str2) { const pcre_uint8 *ustr2 = (pcre_uint8 *)str2; pcre_uchar c1; pcre_uchar c2; while (*str1 != '\0' || *ustr2 != '\0') { c1 = *str1++; c2 = (pcre_uchar)*ustr2++; if (c1 != c2) return ((c1 > c2) << 1) - 1; } /* Both length and characters must be equal. */ return 0; } #ifdef COMPILE_PCRE32 int PRIV(strcmp_uc_c8_utf)(const pcre_uchar *str1, const char *str2) { const pcre_uint8 *ustr2 = (pcre_uint8 *)str2; pcre_uchar c1; pcre_uchar c2; while (*str1 != '\0' || *ustr2 != '\0') { c1 = UCHAR21INC(str1); c2 = (pcre_uchar)*ustr2++; if (c1 != c2) return ((c1 > c2) << 1) - 1; } /* Both length and characters must be equal. */ return 0; } #endif /* COMPILE_PCRE32 */ /* The following two functions compares two, fixed length strings. Basically an strncmp for non 8 bit characters. Arguments: str1 first string str2 second string num size of the string Returns: 0 if both string are equal (like strcmp), 1 otherwise */ int PRIV(strncmp_uc_uc)(const pcre_uchar *str1, const pcre_uchar *str2, unsigned int num) { pcre_uchar c1; pcre_uchar c2; while (num-- > 0) { c1 = *str1++; c2 = *str2++; if (c1 != c2) return ((c1 > c2) << 1) - 1; } /* Both length and characters must be equal. */ return 0; } int PRIV(strncmp_uc_c8)(const pcre_uchar *str1, const char *str2, unsigned int num) { const pcre_uint8 *ustr2 = (pcre_uint8 *)str2; pcre_uchar c1; pcre_uchar c2; while (num-- > 0) { c1 = *str1++; c2 = (pcre_uchar)*ustr2++; if (c1 != c2) return ((c1 > c2) << 1) - 1; } /* Both length and characters must be equal. */ return 0; } /* The following function returns with the length of a zero terminated string. Basically an strlen for non 8 bit characters. Arguments: str string Returns: length of the string */ unsigned int PRIV(strlen_uc)(const pcre_uchar *str) { unsigned int len = 0; while (*str++ != 0) len++; return len; } #endif /* !COMPILE_PCRE8 */ /* End of pcre_string_utils.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_get.c0000644000000000000020000005457214655113617021300 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2012 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains some convenience functions for extracting substrings from the subject string after a regex match has succeeded. The original idea for these functions came from Scott Wimer. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" /************************************************* * Find number for named string * *************************************************/ /* This function is used by the get_first_set() function below, as well as being generally available. It assumes that names are unique. Arguments: code the compiled regex stringname the name whose number is required Returns: the number of the named parentheses, or a negative number (PCRE_ERROR_NOSUBSTRING) if not found */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_stringnumber(const pcre *code, const char *stringname) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_stringnumber(const pcre16 *code, PCRE_SPTR16 stringname) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_get_stringnumber(const pcre32 *code, PCRE_SPTR32 stringname) #endif { int rc; int entrysize; int top, bot; pcre_uchar *nametable; #ifdef COMPILE_PCRE8 if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) return rc; if (top <= 0) return PCRE_ERROR_NOSUBSTRING; if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) return rc; if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) return rc; #endif #ifdef COMPILE_PCRE16 if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) return rc; if (top <= 0) return PCRE_ERROR_NOSUBSTRING; if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) return rc; if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) return rc; #endif #ifdef COMPILE_PCRE32 if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) return rc; if (top <= 0) return PCRE_ERROR_NOSUBSTRING; if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) return rc; if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) return rc; #endif bot = 0; while (top > bot) { int mid = (top + bot) / 2; pcre_uchar *entry = nametable + entrysize*mid; int c = STRCMP_UC_UC((pcre_uchar *)stringname, (pcre_uchar *)(entry + IMM2_SIZE)); if (c == 0) return GET2(entry, 0); if (c > 0) bot = mid + 1; else top = mid; } return PCRE_ERROR_NOSUBSTRING; } /************************************************* * Find (multiple) entries for named string * *************************************************/ /* This is used by the get_first_set() function below, as well as being generally available. It is used when duplicated names are permitted. Arguments: code the compiled regex stringname the name whose entries required firstptr where to put the pointer to the first entry lastptr where to put the pointer to the last entry Returns: the length of each entry, or a negative number (PCRE_ERROR_NOSUBSTRING) if not found */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_stringtable_entries(const pcre *code, const char *stringname, char **firstptr, char **lastptr) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_stringtable_entries(const pcre16 *code, PCRE_SPTR16 stringname, PCRE_UCHAR16 **firstptr, PCRE_UCHAR16 **lastptr) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_get_stringtable_entries(const pcre32 *code, PCRE_SPTR32 stringname, PCRE_UCHAR32 **firstptr, PCRE_UCHAR32 **lastptr) #endif { int rc; int entrysize; int top, bot; pcre_uchar *nametable, *lastentry; #ifdef COMPILE_PCRE8 if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) return rc; if (top <= 0) return PCRE_ERROR_NOSUBSTRING; if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) return rc; if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) return rc; #endif #ifdef COMPILE_PCRE16 if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) return rc; if (top <= 0) return PCRE_ERROR_NOSUBSTRING; if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) return rc; if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) return rc; #endif #ifdef COMPILE_PCRE32 if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0) return rc; if (top <= 0) return PCRE_ERROR_NOSUBSTRING; if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0) return rc; if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0) return rc; #endif lastentry = nametable + entrysize * (top - 1); bot = 0; while (top > bot) { int mid = (top + bot) / 2; pcre_uchar *entry = nametable + entrysize*mid; int c = STRCMP_UC_UC((pcre_uchar *)stringname, (pcre_uchar *)(entry + IMM2_SIZE)); if (c == 0) { pcre_uchar *first = entry; pcre_uchar *last = entry; while (first > nametable) { if (STRCMP_UC_UC((pcre_uchar *)stringname, (pcre_uchar *)(first - entrysize + IMM2_SIZE)) != 0) break; first -= entrysize; } while (last < lastentry) { if (STRCMP_UC_UC((pcre_uchar *)stringname, (pcre_uchar *)(last + entrysize + IMM2_SIZE)) != 0) break; last += entrysize; } #if defined COMPILE_PCRE8 *firstptr = (char *)first; *lastptr = (char *)last; #elif defined COMPILE_PCRE16 *firstptr = (PCRE_UCHAR16 *)first; *lastptr = (PCRE_UCHAR16 *)last; #elif defined COMPILE_PCRE32 *firstptr = (PCRE_UCHAR32 *)first; *lastptr = (PCRE_UCHAR32 *)last; #endif return entrysize; } if (c > 0) bot = mid + 1; else top = mid; } return PCRE_ERROR_NOSUBSTRING; } /************************************************* * Find first set of multiple named strings * *************************************************/ /* This function allows for duplicate names in the table of named substrings. It returns the number of the first one that was set in a pattern match. Arguments: code the compiled regex stringname the name of the capturing substring ovector the vector of matched substrings stringcount number of captured substrings Returns: the number of the first that is set, or the number of the last one if none are set, or a negative number on error */ #if defined COMPILE_PCRE8 static int get_first_set(const pcre *code, const char *stringname, int *ovector, int stringcount) #elif defined COMPILE_PCRE16 static int get_first_set(const pcre16 *code, PCRE_SPTR16 stringname, int *ovector, int stringcount) #elif defined COMPILE_PCRE32 static int get_first_set(const pcre32 *code, PCRE_SPTR32 stringname, int *ovector, int stringcount) #endif { const REAL_PCRE *re = (const REAL_PCRE *)code; int entrysize; pcre_uchar *entry; #if defined COMPILE_PCRE8 char *first, *last; #elif defined COMPILE_PCRE16 PCRE_UCHAR16 *first, *last; #elif defined COMPILE_PCRE32 PCRE_UCHAR32 *first, *last; #endif #if defined COMPILE_PCRE8 if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0) return pcre_get_stringnumber(code, stringname); entrysize = pcre_get_stringtable_entries(code, stringname, &first, &last); #elif defined COMPILE_PCRE16 if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0) return pcre16_get_stringnumber(code, stringname); entrysize = pcre16_get_stringtable_entries(code, stringname, &first, &last); #elif defined COMPILE_PCRE32 if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0) return pcre32_get_stringnumber(code, stringname); entrysize = pcre32_get_stringtable_entries(code, stringname, &first, &last); #endif if (entrysize <= 0) return entrysize; for (entry = (pcre_uchar *)first; entry <= (pcre_uchar *)last; entry += entrysize) { int n = GET2(entry, 0); if (n < stringcount && ovector[n*2] >= 0) return n; } return GET2(entry, 0); } /************************************************* * Copy captured string to given buffer * *************************************************/ /* This function copies a single captured substring into a given buffer. Note that we use memcpy() rather than strncpy() in case there are binary zeros in the string. Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) stringnumber the number of the required substring buffer where to put the substring size the size of the buffer Returns: if successful: the length of the copied string, not including the zero that is put on the end; can be zero if not successful: PCRE_ERROR_NOMEMORY (-6) buffer too small PCRE_ERROR_NOSUBSTRING (-7) no such captured substring */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_copy_substring(const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int size) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_copy_substring(PCRE_SPTR16 subject, int *ovector, int stringcount, int stringnumber, PCRE_UCHAR16 *buffer, int size) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_copy_substring(PCRE_SPTR32 subject, int *ovector, int stringcount, int stringnumber, PCRE_UCHAR32 *buffer, int size) #endif { int yield; if (stringnumber < 0 || stringnumber >= stringcount) return PCRE_ERROR_NOSUBSTRING; stringnumber *= 2; yield = ovector[stringnumber+1] - ovector[stringnumber]; if (size < yield + 1) return PCRE_ERROR_NOMEMORY; memcpy(buffer, subject + ovector[stringnumber], IN_UCHARS(yield)); buffer[yield] = 0; return yield; } /************************************************* * Copy named captured string to given buffer * *************************************************/ /* This function copies a single captured substring into a given buffer, identifying it by name. If the regex permits duplicate names, the first substring that is set is chosen. Arguments: code the compiled regex subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) stringname the name of the required substring buffer where to put the substring size the size of the buffer Returns: if successful: the length of the copied string, not including the zero that is put on the end; can be zero if not successful: PCRE_ERROR_NOMEMORY (-6) buffer too small PCRE_ERROR_NOSUBSTRING (-7) no such captured substring */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_copy_named_substring(const pcre *code, const char *subject, int *ovector, int stringcount, const char *stringname, char *buffer, int size) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_copy_named_substring(const pcre16 *code, PCRE_SPTR16 subject, int *ovector, int stringcount, PCRE_SPTR16 stringname, PCRE_UCHAR16 *buffer, int size) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_copy_named_substring(const pcre32 *code, PCRE_SPTR32 subject, int *ovector, int stringcount, PCRE_SPTR32 stringname, PCRE_UCHAR32 *buffer, int size) #endif { int n = get_first_set(code, stringname, ovector, stringcount); if (n <= 0) return n; #if defined COMPILE_PCRE8 return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size); #elif defined COMPILE_PCRE16 return pcre16_copy_substring(subject, ovector, stringcount, n, buffer, size); #elif defined COMPILE_PCRE32 return pcre32_copy_substring(subject, ovector, stringcount, n, buffer, size); #endif } /************************************************* * Copy all captured strings to new store * *************************************************/ /* This function gets one chunk of store and builds a list of pointers and all of the captured substrings in it. A NULL pointer is put on the end of the list. Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) listptr set to point to the list of pointers Returns: if successful: 0 if not successful: PCRE_ERROR_NOMEMORY (-6) failed to get store */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_substring_list(PCRE_SPTR16 subject, int *ovector, int stringcount, PCRE_SPTR16 **listptr) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_get_substring_list(PCRE_SPTR32 subject, int *ovector, int stringcount, PCRE_SPTR32 **listptr) #endif { int i; int size = sizeof(pcre_uchar *); int double_count = stringcount * 2; pcre_uchar **stringlist; pcre_uchar *p; for (i = 0; i < double_count; i += 2) { size += sizeof(pcre_uchar *) + IN_UCHARS(1); if (ovector[i+1] > ovector[i]) size += IN_UCHARS(ovector[i+1] - ovector[i]); } stringlist = (pcre_uchar **)(PUBL(malloc))(size); if (stringlist == NULL) return PCRE_ERROR_NOMEMORY; #if defined COMPILE_PCRE8 *listptr = (const char **)stringlist; #elif defined COMPILE_PCRE16 *listptr = (PCRE_SPTR16 *)stringlist; #elif defined COMPILE_PCRE32 *listptr = (PCRE_SPTR32 *)stringlist; #endif p = (pcre_uchar *)(stringlist + stringcount + 1); for (i = 0; i < double_count; i += 2) { int len = (ovector[i+1] > ovector[i])? (ovector[i+1] - ovector[i]) : 0; memcpy(p, subject + ovector[i], IN_UCHARS(len)); *stringlist++ = p; p += len; *p++ = 0; } *stringlist = NULL; return 0; } /************************************************* * Free store obtained by get_substring_list * *************************************************/ /* This function exists for the benefit of people calling PCRE from non-C programs that can call its functions, but not free() or (PUBL(free))() directly. Argument: the result of a previous pcre_get_substring_list() Returns: nothing */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre_free_substring_list(const char **pointer) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre16_free_substring_list(PCRE_SPTR16 *pointer) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre32_free_substring_list(PCRE_SPTR32 *pointer) #endif { (PUBL(free))((void *)pointer); } /************************************************* * Copy captured string to new store * *************************************************/ /* This function copies a single captured substring into a piece of new store Arguments: subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) stringnumber the number of the required substring stringptr where to put a pointer to the substring Returns: if successful: the length of the string, not including the zero that is put on the end; can be zero if not successful: PCRE_ERROR_NOMEMORY (-6) failed to get store PCRE_ERROR_NOSUBSTRING (-7) substring not present */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_substring(PCRE_SPTR16 subject, int *ovector, int stringcount, int stringnumber, PCRE_SPTR16 *stringptr) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_get_substring(PCRE_SPTR32 subject, int *ovector, int stringcount, int stringnumber, PCRE_SPTR32 *stringptr) #endif { int yield; pcre_uchar *substring; if (stringnumber < 0 || stringnumber >= stringcount) return PCRE_ERROR_NOSUBSTRING; stringnumber *= 2; yield = ovector[stringnumber+1] - ovector[stringnumber]; substring = (pcre_uchar *)(PUBL(malloc))(IN_UCHARS(yield + 1)); if (substring == NULL) return PCRE_ERROR_NOMEMORY; memcpy(substring, subject + ovector[stringnumber], IN_UCHARS(yield)); substring[yield] = 0; #if defined COMPILE_PCRE8 *stringptr = (const char *)substring; #elif defined COMPILE_PCRE16 *stringptr = (PCRE_SPTR16)substring; #elif defined COMPILE_PCRE32 *stringptr = (PCRE_SPTR32)substring; #endif return yield; } /************************************************* * Copy named captured string to new store * *************************************************/ /* This function copies a single captured substring, identified by name, into new store. If the regex permits duplicate names, the first substring that is set is chosen. Arguments: code the compiled regex subject the subject string that was matched ovector pointer to the offsets table stringcount the number of substrings that were captured (i.e. the yield of the pcre_exec call, unless that was zero, in which case it should be 1/3 of the offset table size) stringname the name of the required substring stringptr where to put the pointer Returns: if successful: the length of the copied string, not including the zero that is put on the end; can be zero if not successful: PCRE_ERROR_NOMEMORY (-6) couldn't get memory PCRE_ERROR_NOSUBSTRING (-7) no such captured substring */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_get_named_substring(const pcre *code, const char *subject, int *ovector, int stringcount, const char *stringname, const char **stringptr) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_get_named_substring(const pcre16 *code, PCRE_SPTR16 subject, int *ovector, int stringcount, PCRE_SPTR16 stringname, PCRE_SPTR16 *stringptr) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_get_named_substring(const pcre32 *code, PCRE_SPTR32 subject, int *ovector, int stringcount, PCRE_SPTR32 stringname, PCRE_SPTR32 *stringptr) #endif { int n = get_first_set(code, stringname, ovector, stringcount); if (n <= 0) return n; #if defined COMPILE_PCRE8 return pcre_get_substring(subject, ovector, stringcount, n, stringptr); #elif defined COMPILE_PCRE16 return pcre16_get_substring(subject, ovector, stringcount, n, stringptr); #elif defined COMPILE_PCRE32 return pcre32_get_substring(subject, ovector, stringcount, n, stringptr); #endif } /************************************************* * Free store obtained by get_substring * *************************************************/ /* This function exists for the benefit of people calling PCRE from non-C programs that can call its functions, but not free() or (PUBL(free))() directly. Argument: the result of a previous pcre_get_substring() Returns: nothing */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre_free_substring(const char *pointer) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre16_free_substring(PCRE_SPTR16 pointer) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN void PCRE_CALL_CONVENTION pcre32_free_substring(PCRE_SPTR32 pointer) #endif { (PUBL(free))((void *)pointer); } /* End of pcre_get.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_study.c0000644000000000000020000013671214655113617021666 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2012 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains the external function pcre_study(), along with local supporting functions. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" #define SET_BIT(c) start_bits[c/8] |= (1 << (c&7)) /* Returns from set_start_bits() */ enum { SSB_FAIL, SSB_DONE, SSB_CONTINUE, SSB_UNKNOWN }; /************************************************* * Find the minimum subject length for a group * *************************************************/ /* Scan a parenthesized group and compute the minimum length of subject that is needed to match it. This is a lower bound; it does not mean there is a string of that length that matches. In UTF8 mode, the result is in characters rather than bytes. Arguments: re compiled pattern block code pointer to start of group (the bracket) startcode pointer to start of the whole pattern's code options the compiling options recurses chain of recurse_check to catch mutual recursion countptr pointer to call count (to catch over complexity) Returns: the minimum length -1 if \C in UTF-8 mode or (*ACCEPT) was encountered -2 internal error (missing capturing bracket) -3 internal error (opcode not listed) */ static int find_minlength(const REAL_PCRE *re, const pcre_uchar *code, const pcre_uchar *startcode, int options, recurse_check *recurses, int *countptr) { int length = -1; /* PCRE_UTF16 has the same value as PCRE_UTF8. */ BOOL utf = (options & PCRE_UTF8) != 0; BOOL had_recurse = FALSE; recurse_check this_recurse; register int branchlength = 0; register pcre_uchar *cc = (pcre_uchar *)code + 1 + LINK_SIZE; if ((*countptr)++ > 1000) return -1; /* too complex */ if (*code == OP_CBRA || *code == OP_SCBRA || *code == OP_CBRAPOS || *code == OP_SCBRAPOS) cc += IMM2_SIZE; /* Scan along the opcodes for this branch. If we get to the end of the branch, check the length against that of the other branches. */ for (;;) { int d, min; pcre_uchar *cs, *ce; register pcre_uchar op = *cc; switch (op) { case OP_COND: case OP_SCOND: /* If there is only one branch in a condition, the implied branch has zero length, so we don't add anything. This covers the DEFINE "condition" automatically. */ cs = cc + GET(cc, 1); if (*cs != OP_ALT) { cc = cs + 1 + LINK_SIZE; break; } /* Otherwise we can fall through and treat it the same as any other subpattern. */ case OP_CBRA: case OP_SCBRA: case OP_BRA: case OP_SBRA: case OP_CBRAPOS: case OP_SCBRAPOS: case OP_BRAPOS: case OP_SBRAPOS: case OP_ONCE: case OP_ONCE_NC: d = find_minlength(re, cc, startcode, options, recurses, countptr); if (d < 0) return d; branchlength += d; do cc += GET(cc, 1); while (*cc == OP_ALT); cc += 1 + LINK_SIZE; break; /* ACCEPT makes things far too complicated; we have to give up. */ case OP_ACCEPT: case OP_ASSERT_ACCEPT: return -1; /* Reached end of a branch; if it's a ket it is the end of a nested call. If it's ALT it is an alternation in a nested call. If it is END it's the end of the outer call. All can be handled by the same code. If an ACCEPT was previously encountered, use the length that was in force at that time, and pass back the shortest ACCEPT length. */ case OP_ALT: case OP_KET: case OP_KETRMAX: case OP_KETRMIN: case OP_KETRPOS: case OP_END: if (length < 0 || (!had_recurse && branchlength < length)) length = branchlength; if (op != OP_ALT) return length; cc += 1 + LINK_SIZE; branchlength = 0; had_recurse = FALSE; break; /* Skip over assertive subpatterns */ case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do cc += GET(cc, 1); while (*cc == OP_ALT); /* Fall through */ /* Skip over things that don't match chars */ case OP_REVERSE: case OP_CREF: case OP_DNCREF: case OP_RREF: case OP_DNRREF: case OP_DEF: case OP_CALLOUT: case OP_SOD: case OP_SOM: case OP_EOD: case OP_EODN: case OP_CIRC: case OP_CIRCM: case OP_DOLL: case OP_DOLLM: case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: cc += PRIV(OP_lengths)[*cc]; break; /* Skip over a subpattern that has a {0} or {0,x} quantifier */ case OP_BRAZERO: case OP_BRAMINZERO: case OP_BRAPOSZERO: case OP_SKIPZERO: cc += PRIV(OP_lengths)[*cc]; do cc += GET(cc, 1); while (*cc == OP_ALT); cc += 1 + LINK_SIZE; break; /* Handle literal characters and + repetitions */ case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: case OP_PLUS: case OP_PLUSI: case OP_MINPLUS: case OP_MINPLUSI: case OP_POSPLUS: case OP_POSPLUSI: case OP_NOTPLUS: case OP_NOTPLUSI: case OP_NOTMINPLUS: case OP_NOTMINPLUSI: case OP_NOTPOSPLUS: case OP_NOTPOSPLUSI: branchlength++; cc += 2; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEPOSPLUS: branchlength++; cc += (cc[1] == OP_PROP || cc[1] == OP_NOTPROP)? 4 : 2; break; /* Handle exact repetitions. The count is already in characters, but we need to skip over a multibyte character in UTF8 mode. */ case OP_EXACT: case OP_EXACTI: case OP_NOTEXACT: case OP_NOTEXACTI: branchlength += GET2(cc,1); cc += 2 + IMM2_SIZE; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; case OP_TYPEEXACT: branchlength += GET2(cc,1); cc += 2 + IMM2_SIZE + ((cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0); break; /* Handle single-char non-literal matchers */ case OP_PROP: case OP_NOTPROP: cc += 2; /* Fall through */ case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: case OP_ALLANY: case OP_EXTUNI: case OP_HSPACE: case OP_NOT_HSPACE: case OP_VSPACE: case OP_NOT_VSPACE: branchlength++; cc++; break; /* "Any newline" might match two characters, but it also might match just one. */ case OP_ANYNL: branchlength += 1; cc++; break; /* The single-byte matcher means we can't proceed in UTF-8 mode. (In non-UTF-8 mode \C will actually be turned into OP_ALLANY, so won't ever appear, but leave the code, just in case.) */ case OP_ANYBYTE: #ifdef SUPPORT_UTF if (utf) return -1; #endif branchlength++; cc++; break; /* For repeated character types, we have to test for \p and \P, which have an extra two bytes of parameters. */ case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEPOSSTAR: case OP_TYPEPOSQUERY: if (cc[1] == OP_PROP || cc[1] == OP_NOTPROP) cc += 2; cc += PRIV(OP_lengths)[op]; break; case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEPOSUPTO: if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP) cc += 2; cc += PRIV(OP_lengths)[op]; break; /* Check a class for variable quantification */ case OP_CLASS: case OP_NCLASS: #if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case OP_XCLASS: /* The original code caused an unsigned overflow in 64 bit systems, so now we use a conditional statement. */ if (op == OP_XCLASS) cc += GET(cc, 1); else cc += PRIV(OP_lengths)[OP_CLASS]; #else cc += PRIV(OP_lengths)[OP_CLASS]; #endif switch (*cc) { case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRPOSPLUS: branchlength++; /* Fall through */ case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSSTAR: case OP_CRPOSQUERY: cc++; break; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: branchlength += GET2(cc,1); cc += 1 + 2 * IMM2_SIZE; break; default: branchlength++; break; } break; /* Backreferences and subroutine calls are treated in the same way: we find the minimum length for the subpattern. A recursion, however, causes an a flag to be set that causes the length of this branch to be ignored. The logic is that a recursion can only make sense if there is another alternation that stops the recursing. That will provide the minimum length (when no recursion happens). A backreference within the group that it is referencing behaves in the same way. If PCRE_JAVASCRIPT_COMPAT is set, a backreference to an unset bracket matches an empty string (by default it causes a matching failure), so in that case we must set the minimum length to zero. */ case OP_DNREF: /* Duplicate named pattern back reference */ case OP_DNREFI: if ((options & PCRE_JAVASCRIPT_COMPAT) == 0) { int count = GET2(cc, 1+IMM2_SIZE); pcre_uchar *slot = (pcre_uchar *)re + re->name_table_offset + GET2(cc, 1) * re->name_entry_size; d = INT_MAX; while (count-- > 0) { ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(slot, 0)); if (cs == NULL) return -2; do ce += GET(ce, 1); while (*ce == OP_ALT); if (cc > cs && cc < ce) /* Simple recursion */ { d = 0; had_recurse = TRUE; break; } else { recurse_check *r = recurses; for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; if (r != NULL) /* Mutual recursion */ { d = 0; had_recurse = TRUE; break; } else { int dd; this_recurse.prev = recurses; this_recurse.group = cs; dd = find_minlength(re, cs, startcode, options, &this_recurse, countptr); if (dd < d) d = dd; } } slot += re->name_entry_size; } } else d = 0; cc += 1 + 2*IMM2_SIZE; goto REPEAT_BACK_REFERENCE; case OP_REF: /* Single back reference */ case OP_REFI: if ((options & PCRE_JAVASCRIPT_COMPAT) == 0) { ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(cc, 1)); if (cs == NULL) return -2; do ce += GET(ce, 1); while (*ce == OP_ALT); if (cc > cs && cc < ce) /* Simple recursion */ { d = 0; had_recurse = TRUE; } else { recurse_check *r = recurses; for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; if (r != NULL) /* Mutual recursion */ { d = 0; had_recurse = TRUE; } else { this_recurse.prev = recurses; this_recurse.group = cs; d = find_minlength(re, cs, startcode, options, &this_recurse, countptr); } } } else d = 0; cc += 1 + IMM2_SIZE; /* Handle repeated back references */ REPEAT_BACK_REFERENCE: switch (*cc) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSSTAR: case OP_CRPOSQUERY: min = 0; cc++; break; case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRPOSPLUS: min = 1; cc++; break; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: min = GET2(cc, 1); cc += 1 + 2 * IMM2_SIZE; break; default: min = 1; break; } branchlength += min * d; break; /* We can easily detect direct recursion, but not mutual recursion. This is caught by a recursion depth count. */ case OP_RECURSE: cs = ce = (pcre_uchar *)startcode + GET(cc, 1); do ce += GET(ce, 1); while (*ce == OP_ALT); if (cc > cs && cc < ce) /* Simple recursion */ had_recurse = TRUE; else { recurse_check *r = recurses; for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; if (r != NULL) /* Mutual recursion */ had_recurse = TRUE; else { this_recurse.prev = recurses; this_recurse.group = cs; branchlength += find_minlength(re, cs, startcode, options, &this_recurse, countptr); } } cc += 1 + LINK_SIZE; break; /* Anything else does not or need not match a character. We can get the item's length from the table, but for those that can match zero occurrences of a character, we must take special action for UTF-8 characters. As it happens, the "NOT" versions of these opcodes are used at present only for ASCII characters, so they could be omitted from this list. However, in future that may change, so we include them here so as not to leave a gotcha for a future maintainer. */ case OP_UPTO: case OP_UPTOI: case OP_NOTUPTO: case OP_NOTUPTOI: case OP_MINUPTO: case OP_MINUPTOI: case OP_NOTMINUPTO: case OP_NOTMINUPTOI: case OP_POSUPTO: case OP_POSUPTOI: case OP_NOTPOSUPTO: case OP_NOTPOSUPTOI: case OP_STAR: case OP_STARI: case OP_NOTSTAR: case OP_NOTSTARI: case OP_MINSTAR: case OP_MINSTARI: case OP_NOTMINSTAR: case OP_NOTMINSTARI: case OP_POSSTAR: case OP_POSSTARI: case OP_NOTPOSSTAR: case OP_NOTPOSSTARI: case OP_QUERY: case OP_QUERYI: case OP_NOTQUERY: case OP_NOTQUERYI: case OP_MINQUERY: case OP_MINQUERYI: case OP_NOTMINQUERY: case OP_NOTMINQUERYI: case OP_POSQUERY: case OP_POSQUERYI: case OP_NOTPOSQUERY: case OP_NOTPOSQUERYI: cc += PRIV(OP_lengths)[op]; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; /* Skip these, but we need to add in the name length. */ case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: cc += PRIV(OP_lengths)[op] + cc[1]; break; /* The remaining opcodes are just skipped over. */ case OP_CLOSE: case OP_COMMIT: case OP_FAIL: case OP_PRUNE: case OP_SET_SOM: case OP_SKIP: case OP_THEN: cc += PRIV(OP_lengths)[op]; break; /* This should not occur: we list all opcodes explicitly so that when new ones get added they are properly considered. */ default: return -3; } } /* Control never gets here */ } /************************************************* * Set a bit and maybe its alternate case * *************************************************/ /* Given a character, set its first byte's bit in the table, and also the corresponding bit for the other version of a letter if we are caseless. In UTF-8 mode, for characters greater than 127, we can only do the caseless thing when Unicode property support is available. Arguments: start_bits points to the bit map p points to the character caseless the caseless flag cd the block with char table pointers utf TRUE for UTF-8 / UTF-16 / UTF-32 mode Returns: pointer after the character */ static const pcre_uchar * set_table_bit(pcre_uint8 *start_bits, const pcre_uchar *p, BOOL caseless, compile_data *cd, BOOL utf) { pcre_uint32 c = *p; #ifdef COMPILE_PCRE8 SET_BIT(c); #ifdef SUPPORT_UTF if (utf && c > 127) { GETCHARINC(c, p); #ifdef SUPPORT_UCP if (caseless) { pcre_uchar buff[6]; c = UCD_OTHERCASE(c); (void)PRIV(ord2utf)(c, buff); SET_BIT(buff[0]); } #endif /* Not SUPPORT_UCP */ return p; } #else /* Not SUPPORT_UTF */ (void)(utf); /* Stops warning for unused parameter */ #endif /* SUPPORT_UTF */ /* Not UTF-8 mode, or character is less than 127. */ if (caseless && (cd->ctypes[c] & ctype_letter) != 0) SET_BIT(cd->fcc[c]); return p + 1; #endif /* COMPILE_PCRE8 */ #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 if (c > 0xff) { c = 0xff; caseless = FALSE; } SET_BIT(c); #ifdef SUPPORT_UTF if (utf && c > 127) { GETCHARINC(c, p); #ifdef SUPPORT_UCP if (caseless) { c = UCD_OTHERCASE(c); if (c > 0xff) c = 0xff; SET_BIT(c); } #endif /* SUPPORT_UCP */ return p; } #else /* Not SUPPORT_UTF */ (void)(utf); /* Stops warning for unused parameter */ #endif /* SUPPORT_UTF */ if (caseless && (cd->ctypes[c] & ctype_letter) != 0) SET_BIT(cd->fcc[c]); return p + 1; #endif } /************************************************* * Set bits for a positive character type * *************************************************/ /* This function sets starting bits for a character type. In UTF-8 mode, we can only do a direct setting for bytes less than 128, as otherwise there can be confusion with bytes in the middle of UTF-8 characters. In a "traditional" environment, the tables will only recognize ASCII characters anyway, but in at least one Windows environment, some higher bytes bits were set in the tables. So we deal with that case by considering the UTF-8 encoding. Arguments: start_bits the starting bitmap cbit type the type of character wanted table_limit 32 for non-UTF-8; 16 for UTF-8 cd the block with char table pointers Returns: nothing */ static void set_type_bits(pcre_uint8 *start_bits, int cbit_type, unsigned int table_limit, compile_data *cd) { register pcre_uint32 c; for (c = 0; c < table_limit; c++) start_bits[c] |= cd->cbits[c+cbit_type]; #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (table_limit == 32) return; for (c = 128; c < 256; c++) { if ((cd->cbits[c/8] & (1 << (c&7))) != 0) { pcre_uchar buff[6]; (void)PRIV(ord2utf)(c, buff); SET_BIT(buff[0]); } } #endif } /************************************************* * Set bits for a negative character type * *************************************************/ /* This function sets starting bits for a negative character type such as \D. In UTF-8 mode, we can only do a direct setting for bytes less than 128, as otherwise there can be confusion with bytes in the middle of UTF-8 characters. Unlike in the positive case, where we can set appropriate starting bits for specific high-valued UTF-8 characters, in this case we have to set the bits for all high-valued characters. The lowest is 0xc2, but we overkill by starting at 0xc0 (192) for simplicity. Arguments: start_bits the starting bitmap cbit type the type of character wanted table_limit 32 for non-UTF-8; 16 for UTF-8 cd the block with char table pointers Returns: nothing */ static void set_nottype_bits(pcre_uint8 *start_bits, int cbit_type, unsigned int table_limit, compile_data *cd) { register pcre_uint32 c; for (c = 0; c < table_limit; c++) start_bits[c] |= ~cd->cbits[c+cbit_type]; #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (table_limit != 32) for (c = 24; c < 32; c++) start_bits[c] = 0xff; #endif } /************************************************* * Create bitmap of starting bytes * *************************************************/ /* This function scans a compiled unanchored expression recursively and attempts to build a bitmap of the set of possible starting bytes. As time goes by, we may be able to get more clever at doing this. The SSB_CONTINUE return is useful for parenthesized groups in patterns such as (a*)b where the group provides some optional starting bytes but scanning must continue at the outer level to find at least one mandatory byte. At the outermost level, this function fails unless the result is SSB_DONE. Arguments: code points to an expression start_bits points to a 32-byte table, initialized to 0 utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode cd the block with char table pointers Returns: SSB_FAIL => Failed to find any starting bytes SSB_DONE => Found mandatory starting bytes SSB_CONTINUE => Found optional starting bytes SSB_UNKNOWN => Hit an unrecognized opcode */ static int set_start_bits(const pcre_uchar *code, pcre_uint8 *start_bits, BOOL utf, compile_data *cd) { register pcre_uint32 c; int yield = SSB_DONE; #if defined SUPPORT_UTF && defined COMPILE_PCRE8 int table_limit = utf? 16:32; #else int table_limit = 32; #endif #if 0 /* ========================================================================= */ /* The following comment and code was inserted in January 1999. In May 2006, when it was observed to cause compiler warnings about unused values, I took it out again. If anybody is still using OS/2, they will have to put it back manually. */ /* This next statement and the later reference to dummy are here in order to trick the optimizer of the IBM C compiler for OS/2 into generating correct code. Apparently IBM isn't going to fix the problem, and we would rather not disable optimization (in this module it actually makes a big difference, and the pcre module can use all the optimization it can get). */ volatile int dummy; /* ========================================================================= */ #endif do { BOOL try_next = TRUE; const pcre_uchar *tcode = code + 1 + LINK_SIZE; if (*code == OP_CBRA || *code == OP_SCBRA || *code == OP_CBRAPOS || *code == OP_SCBRAPOS) tcode += IMM2_SIZE; while (try_next) /* Loop for items in this branch */ { int rc; switch(*tcode) { /* If we reach something we don't understand, it means a new opcode has been created that hasn't been added to this code. Hopefully this problem will be discovered during testing. */ default: return SSB_UNKNOWN; /* Fail for a valid opcode that implies no starting bits. */ case OP_ACCEPT: case OP_ASSERT_ACCEPT: case OP_ALLANY: case OP_ANY: case OP_ANYBYTE: case OP_CIRC: case OP_CIRCM: case OP_CLOSE: case OP_COMMIT: case OP_COND: case OP_CREF: case OP_DEF: case OP_DNCREF: case OP_DNREF: case OP_DNREFI: case OP_DNRREF: case OP_DOLL: case OP_DOLLM: case OP_END: case OP_EOD: case OP_EODN: case OP_EXTUNI: case OP_FAIL: case OP_MARK: case OP_NOT: case OP_NOTEXACT: case OP_NOTEXACTI: case OP_NOTI: case OP_NOTMINPLUS: case OP_NOTMINPLUSI: case OP_NOTMINQUERY: case OP_NOTMINQUERYI: case OP_NOTMINSTAR: case OP_NOTMINSTARI: case OP_NOTMINUPTO: case OP_NOTMINUPTOI: case OP_NOTPLUS: case OP_NOTPLUSI: case OP_NOTPOSPLUS: case OP_NOTPOSPLUSI: case OP_NOTPOSQUERY: case OP_NOTPOSQUERYI: case OP_NOTPOSSTAR: case OP_NOTPOSSTARI: case OP_NOTPOSUPTO: case OP_NOTPOSUPTOI: case OP_NOTPROP: case OP_NOTQUERY: case OP_NOTQUERYI: case OP_NOTSTAR: case OP_NOTSTARI: case OP_NOTUPTO: case OP_NOTUPTOI: case OP_NOT_HSPACE: case OP_NOT_VSPACE: case OP_PRUNE: case OP_PRUNE_ARG: case OP_RECURSE: case OP_REF: case OP_REFI: case OP_REVERSE: case OP_RREF: case OP_SCOND: case OP_SET_SOM: case OP_SKIP: case OP_SKIP_ARG: case OP_SOD: case OP_SOM: case OP_THEN: case OP_THEN_ARG: return SSB_FAIL; /* A "real" property test implies no starting bits, but the fake property PT_CLIST identifies a list of characters. These lists are short, as they are used for characters with more than one "other case", so there is no point in recognizing them for OP_NOTPROP. */ case OP_PROP: if (tcode[1] != PT_CLIST) return SSB_FAIL; { const pcre_uint32 *p = PRIV(ucd_caseless_sets) + tcode[2]; while ((c = *p++) < NOTACHAR) { #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (utf) { pcre_uchar buff[6]; (void)PRIV(ord2utf)(c, buff); c = buff[0]; } #endif if (c > 0xff) SET_BIT(0xff); else SET_BIT(c); } } try_next = FALSE; break; /* We can ignore word boundary tests. */ case OP_WORD_BOUNDARY: case OP_NOT_WORD_BOUNDARY: tcode++; break; /* If we hit a bracket or a positive lookahead assertion, recurse to set bits from within the subpattern. If it can't find anything, we have to give up. If it finds some mandatory character(s), we are done for this branch. Otherwise, carry on scanning after the subpattern. */ case OP_BRA: case OP_SBRA: case OP_CBRA: case OP_SCBRA: case OP_BRAPOS: case OP_SBRAPOS: case OP_CBRAPOS: case OP_SCBRAPOS: case OP_ONCE: case OP_ONCE_NC: case OP_ASSERT: rc = set_start_bits(tcode, start_bits, utf, cd); if (rc == SSB_FAIL || rc == SSB_UNKNOWN) return rc; if (rc == SSB_DONE) try_next = FALSE; else { do tcode += GET(tcode, 1); while (*tcode == OP_ALT); tcode += 1 + LINK_SIZE; } break; /* If we hit ALT or KET, it means we haven't found anything mandatory in this branch, though we might have found something optional. For ALT, we continue with the next alternative, but we have to arrange that the final result from subpattern is SSB_CONTINUE rather than SSB_DONE. For KET, return SSB_CONTINUE: if this is the top level, that indicates failure, but after a nested subpattern, it causes scanning to continue. */ case OP_ALT: yield = SSB_CONTINUE; try_next = FALSE; break; case OP_KET: case OP_KETRMAX: case OP_KETRMIN: case OP_KETRPOS: return SSB_CONTINUE; /* Skip over callout */ case OP_CALLOUT: tcode += 2 + 2*LINK_SIZE; break; /* Skip over lookbehind and negative lookahead assertions */ case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do tcode += GET(tcode, 1); while (*tcode == OP_ALT); tcode += 1 + LINK_SIZE; break; /* BRAZERO does the bracket, but carries on. */ case OP_BRAZERO: case OP_BRAMINZERO: case OP_BRAPOSZERO: rc = set_start_bits(++tcode, start_bits, utf, cd); if (rc == SSB_FAIL || rc == SSB_UNKNOWN) return rc; /* ========================================================================= See the comment at the head of this function concerning the next line, which was an old fudge for the benefit of OS/2. dummy = 1; ========================================================================= */ do tcode += GET(tcode,1); while (*tcode == OP_ALT); tcode += 1 + LINK_SIZE; break; /* SKIPZERO skips the bracket. */ case OP_SKIPZERO: tcode++; do tcode += GET(tcode,1); while (*tcode == OP_ALT); tcode += 1 + LINK_SIZE; break; /* Single-char * or ? sets the bit and tries the next item */ case OP_STAR: case OP_MINSTAR: case OP_POSSTAR: case OP_QUERY: case OP_MINQUERY: case OP_POSQUERY: tcode = set_table_bit(start_bits, tcode + 1, FALSE, cd, utf); break; case OP_STARI: case OP_MINSTARI: case OP_POSSTARI: case OP_QUERYI: case OP_MINQUERYI: case OP_POSQUERYI: tcode = set_table_bit(start_bits, tcode + 1, TRUE, cd, utf); break; /* Single-char upto sets the bit and tries the next */ case OP_UPTO: case OP_MINUPTO: case OP_POSUPTO: tcode = set_table_bit(start_bits, tcode + 1 + IMM2_SIZE, FALSE, cd, utf); break; case OP_UPTOI: case OP_MINUPTOI: case OP_POSUPTOI: tcode = set_table_bit(start_bits, tcode + 1 + IMM2_SIZE, TRUE, cd, utf); break; /* At least one single char sets the bit and stops */ case OP_EXACT: tcode += IMM2_SIZE; /* Fall through */ case OP_CHAR: case OP_PLUS: case OP_MINPLUS: case OP_POSPLUS: (void)set_table_bit(start_bits, tcode + 1, FALSE, cd, utf); try_next = FALSE; break; case OP_EXACTI: tcode += IMM2_SIZE; /* Fall through */ case OP_CHARI: case OP_PLUSI: case OP_MINPLUSI: case OP_POSPLUSI: (void)set_table_bit(start_bits, tcode + 1, TRUE, cd, utf); try_next = FALSE; break; /* Special spacing and line-terminating items. These recognize specific lists of characters. The difference between VSPACE and ANYNL is that the latter can match the two-character CRLF sequence, but that is not relevant for finding the first character, so their code here is identical. */ case OP_HSPACE: SET_BIT(CHAR_HT); SET_BIT(CHAR_SPACE); #ifdef SUPPORT_UTF if (utf) { #ifdef COMPILE_PCRE8 SET_BIT(0xC2); /* For U+00A0 */ SET_BIT(0xE1); /* For U+1680, U+180E */ SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */ SET_BIT(0xE3); /* For U+3000 */ #elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xA0); SET_BIT(0xFF); /* For characters > 255 */ #endif /* COMPILE_PCRE[8|16|32] */ } else #endif /* SUPPORT_UTF */ { #ifndef EBCDIC SET_BIT(0xA0); #endif /* Not EBCDIC */ #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xFF); /* For characters > 255 */ #endif /* COMPILE_PCRE[16|32] */ } try_next = FALSE; break; case OP_ANYNL: case OP_VSPACE: SET_BIT(CHAR_LF); SET_BIT(CHAR_VT); SET_BIT(CHAR_FF); SET_BIT(CHAR_CR); #ifdef SUPPORT_UTF if (utf) { #ifdef COMPILE_PCRE8 SET_BIT(0xC2); /* For U+0085 */ SET_BIT(0xE2); /* For U+2028, U+2029 */ #elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(CHAR_NEL); SET_BIT(0xFF); /* For characters > 255 */ #endif /* COMPILE_PCRE[8|16|32] */ } else #endif /* SUPPORT_UTF */ { SET_BIT(CHAR_NEL); #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xFF); /* For characters > 255 */ #endif } try_next = FALSE; break; /* Single character types set the bits and stop. Note that if PCRE_UCP is set, we do not see these op codes because \d etc are converted to properties. Therefore, these apply in the case when only characters less than 256 are recognized to match the types. */ case OP_NOT_DIGIT: set_nottype_bits(start_bits, cbit_digit, table_limit, cd); try_next = FALSE; break; case OP_DIGIT: set_type_bits(start_bits, cbit_digit, table_limit, cd); try_next = FALSE; break; /* The cbit_space table has vertical tab as whitespace; we no longer have to play fancy tricks because Perl added VT to its whitespace at release 5.18. PCRE added it at release 8.34. */ case OP_NOT_WHITESPACE: set_nottype_bits(start_bits, cbit_space, table_limit, cd); try_next = FALSE; break; case OP_WHITESPACE: set_type_bits(start_bits, cbit_space, table_limit, cd); try_next = FALSE; break; case OP_NOT_WORDCHAR: set_nottype_bits(start_bits, cbit_word, table_limit, cd); try_next = FALSE; break; case OP_WORDCHAR: set_type_bits(start_bits, cbit_word, table_limit, cd); try_next = FALSE; break; /* One or more character type fudges the pointer and restarts, knowing it will hit a single character type and stop there. */ case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEPOSPLUS: tcode++; break; case OP_TYPEEXACT: tcode += 1 + IMM2_SIZE; break; /* Zero or more repeats of character types set the bits and then try again. */ case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEPOSUPTO: tcode += IMM2_SIZE; /* Fall through */ case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPOSSTAR: case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEPOSQUERY: switch(tcode[1]) { default: case OP_ANY: case OP_ALLANY: return SSB_FAIL; case OP_HSPACE: SET_BIT(CHAR_HT); SET_BIT(CHAR_SPACE); #ifdef SUPPORT_UTF if (utf) { #ifdef COMPILE_PCRE8 SET_BIT(0xC2); /* For U+00A0 */ SET_BIT(0xE1); /* For U+1680, U+180E */ SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */ SET_BIT(0xE3); /* For U+3000 */ #elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xA0); SET_BIT(0xFF); /* For characters > 255 */ #endif /* COMPILE_PCRE[8|16|32] */ } else #endif /* SUPPORT_UTF */ #ifndef EBCDIC SET_BIT(0xA0); #endif /* Not EBCDIC */ break; case OP_ANYNL: case OP_VSPACE: SET_BIT(CHAR_LF); SET_BIT(CHAR_VT); SET_BIT(CHAR_FF); SET_BIT(CHAR_CR); #ifdef SUPPORT_UTF if (utf) { #ifdef COMPILE_PCRE8 SET_BIT(0xC2); /* For U+0085 */ SET_BIT(0xE2); /* For U+2028, U+2029 */ #elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(CHAR_NEL); SET_BIT(0xFF); /* For characters > 255 */ #endif /* COMPILE_PCRE16 */ } else #endif /* SUPPORT_UTF */ SET_BIT(CHAR_NEL); break; case OP_NOT_DIGIT: set_nottype_bits(start_bits, cbit_digit, table_limit, cd); break; case OP_DIGIT: set_type_bits(start_bits, cbit_digit, table_limit, cd); break; /* The cbit_space table has vertical tab as whitespace; we no longer have to play fancy tricks because Perl added VT to its whitespace at release 5.18. PCRE added it at release 8.34. */ case OP_NOT_WHITESPACE: set_nottype_bits(start_bits, cbit_space, table_limit, cd); break; case OP_WHITESPACE: set_type_bits(start_bits, cbit_space, table_limit, cd); break; case OP_NOT_WORDCHAR: set_nottype_bits(start_bits, cbit_word, table_limit, cd); break; case OP_WORDCHAR: set_type_bits(start_bits, cbit_word, table_limit, cd); break; } tcode += 2; break; /* Character class where all the information is in a bit map: set the bits and either carry on or not, according to the repeat count. If it was a negative class, and we are operating with UTF-8 characters, any byte with a value >= 0xc4 is a potentially valid starter because it starts a character with a value > 255. */ #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: if ((tcode[1 + LINK_SIZE] & XCL_HASPROP) != 0) return SSB_FAIL; /* All bits are set. */ if ((tcode[1 + LINK_SIZE] & XCL_MAP) == 0 && (tcode[1 + LINK_SIZE] & XCL_NOT) != 0) return SSB_FAIL; #endif /* Fall through */ case OP_NCLASS: #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (utf) { start_bits[24] |= 0xf0; /* Bits for 0xc4 - 0xc8 */ memset(start_bits+25, 0xff, 7); /* Bits for 0xc9 - 0xff */ } #endif #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SET_BIT(0xFF); /* For characters > 255 */ #endif /* Fall through */ case OP_CLASS: { pcre_uint8 *map; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 map = NULL; if (*tcode == OP_XCLASS) { if ((tcode[1 + LINK_SIZE] & XCL_MAP) != 0) map = (pcre_uint8 *)(tcode + 1 + LINK_SIZE + 1); tcode += GET(tcode, 1); } else #endif { tcode++; map = (pcre_uint8 *)tcode; tcode += 32 / sizeof(pcre_uchar); } /* In UTF-8 mode, the bits in a bit map correspond to character values, not to byte values. However, the bit map we are constructing is for byte values. So we have to do a conversion for characters whose value is > 127. In fact, there are only two possible starting bytes for characters in the range 128 - 255. */ #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 if (map != NULL) #endif { #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (utf) { for (c = 0; c < 16; c++) start_bits[c] |= map[c]; for (c = 128; c < 256; c++) { if ((map[c/8] & (1 << (c&7))) != 0) { int d = (c >> 6) | 0xc0; /* Set bit for this starter */ start_bits[d/8] |= (1 << (d&7)); /* and then skip on to the */ c = (c & 0xc0) + 0x40 - 1; /* next relevant character. */ } } } else #endif { /* In non-UTF-8 mode, the two bit maps are completely compatible. */ for (c = 0; c < 32; c++) start_bits[c] |= map[c]; } } /* Advance past the bit map, and act on what follows. For a zero minimum repeat, continue; otherwise stop processing. */ switch (*tcode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSSTAR: case OP_CRPOSQUERY: tcode++; break; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: if (GET2(tcode, 1) == 0) tcode += 1 + 2 * IMM2_SIZE; else try_next = FALSE; break; default: try_next = FALSE; break; } } break; /* End of bitmap class handling */ } /* End of switch */ } /* End of try_next loop */ code += GET(code, 1); /* Advance to next branch */ } while (*code == OP_ALT); return yield; } /************************************************* * Study a compiled expression * *************************************************/ /* This function is handed a compiled expression that it must study to produce information that will speed up the matching. It returns a pcre[16]_extra block which then gets handed back to pcre_exec(). Arguments: re points to the compiled expression options contains option bits errorptr points to where to place error messages; set NULL unless error Returns: pointer to a pcre[16]_extra block, with study_data filled in and the appropriate flags set; NULL on error or if no optimization possible */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN pcre_extra * PCRE_CALL_CONVENTION pcre_study(const pcre *external_re, int options, const char **errorptr) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN pcre16_extra * PCRE_CALL_CONVENTION pcre16_study(const pcre16 *external_re, int options, const char **errorptr) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN pcre32_extra * PCRE_CALL_CONVENTION pcre32_study(const pcre32 *external_re, int options, const char **errorptr) #endif { int min; int count = 0; BOOL bits_set = FALSE; pcre_uint8 start_bits[32]; PUBL(extra) *extra = NULL; pcre_study_data *study; const pcre_uint8 *tables; pcre_uchar *code; compile_data compile_block; const REAL_PCRE *re = (const REAL_PCRE *)external_re; *errorptr = NULL; if (re == NULL || re->magic_number != MAGIC_NUMBER) { *errorptr = "argument is not a compiled regular expression"; return NULL; } if ((re->flags & PCRE_MODE) == 0) { #if defined COMPILE_PCRE8 *errorptr = "argument not compiled in 8 bit mode"; #elif defined COMPILE_PCRE16 *errorptr = "argument not compiled in 16 bit mode"; #elif defined COMPILE_PCRE32 *errorptr = "argument not compiled in 32 bit mode"; #endif return NULL; } if ((options & ~PUBLIC_STUDY_OPTIONS) != 0) { *errorptr = "unknown or incorrect option bit(s) set"; return NULL; } code = (pcre_uchar *)re + re->name_table_offset + (re->name_count * re->name_entry_size); /* For an anchored pattern, or an unanchored pattern that has a first char, or a multiline pattern that matches only at "line starts", there is no point in seeking a list of starting bytes. */ if ((re->options & PCRE_ANCHORED) == 0 && (re->flags & (PCRE_FIRSTSET|PCRE_STARTLINE)) == 0) { int rc; /* Set the character tables in the block that is passed around */ tables = re->tables; #if defined COMPILE_PCRE8 if (tables == NULL) (void)pcre_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES, (void *)(&tables)); #elif defined COMPILE_PCRE16 if (tables == NULL) (void)pcre16_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES, (void *)(&tables)); #elif defined COMPILE_PCRE32 if (tables == NULL) (void)pcre32_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES, (void *)(&tables)); #endif compile_block.lcc = tables + lcc_offset; compile_block.fcc = tables + fcc_offset; compile_block.cbits = tables + cbits_offset; compile_block.ctypes = tables + ctypes_offset; /* See if we can find a fixed set of initial characters for the pattern. */ memset(start_bits, 0, 32 * sizeof(pcre_uint8)); rc = set_start_bits(code, start_bits, (re->options & PCRE_UTF8) != 0, &compile_block); bits_set = rc == SSB_DONE; if (rc == SSB_UNKNOWN) { *errorptr = "internal error: opcode not recognized"; return NULL; } } /* Find the minimum length of subject string. */ switch(min = find_minlength(re, code, code, re->options, NULL, &count)) { case -2: *errorptr = "internal error: missing capturing bracket"; return NULL; case -3: *errorptr = "internal error: opcode not recognized"; return NULL; default: break; } /* If a set of starting bytes has been identified, or if the minimum length is greater than zero, or if JIT optimization has been requested, or if PCRE_STUDY_EXTRA_NEEDED is set, get a pcre[16]_extra block and a pcre_study_data block. The study data is put in the latter, which is pointed to by the former, which may also get additional data set later by the calling program. At the moment, the size of pcre_study_data is fixed. We nevertheless save it in a field for returning via the pcre_fullinfo() function so that if it becomes variable in the future, we don't have to change that code. */ if (bits_set || min > 0 || (options & ( #ifdef SUPPORT_JIT PCRE_STUDY_JIT_COMPILE | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE | PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE | #endif PCRE_STUDY_EXTRA_NEEDED)) != 0) { extra = (PUBL(extra) *)(PUBL(malloc)) (sizeof(PUBL(extra)) + sizeof(pcre_study_data)); if (extra == NULL) { *errorptr = "failed to get memory"; return NULL; } study = (pcre_study_data *)((char *)extra + sizeof(PUBL(extra))); extra->flags = PCRE_EXTRA_STUDY_DATA; extra->study_data = study; study->size = sizeof(pcre_study_data); study->flags = 0; /* Set the start bits always, to avoid unset memory errors if the study data is written to a file, but set the flag only if any of the bits are set, to save time looking when none are. */ if (bits_set) { study->flags |= PCRE_STUDY_MAPPED; memcpy(study->start_bits, start_bits, sizeof(start_bits)); } else memset(study->start_bits, 0, 32 * sizeof(pcre_uint8)); #ifdef PCRE_DEBUG if (bits_set) { pcre_uint8 *ptr = start_bits; int i; printf("Start bits:\n"); for (i = 0; i < 32; i++) printf("%3d: %02x%s", i * 8, *ptr++, ((i + 1) & 0x7) != 0? " " : "\n"); } #endif /* Always set the minlength value in the block, because the JIT compiler makes use of it. However, don't set the bit unless the length is greater than zero - the interpretive pcre_exec() and pcre_dfa_exec() needn't waste time checking the zero case. */ if (min > 0) { study->flags |= PCRE_STUDY_MINLEN; study->minlength = min; } else study->minlength = 0; /* If JIT support was compiled and requested, attempt the JIT compilation. If no starting bytes were found, and the minimum length is zero, and JIT compilation fails, abandon the extra block and return NULL, unless PCRE_STUDY_EXTRA_NEEDED is set. */ #ifdef SUPPORT_JIT extra->executable_jit = NULL; if ((options & PCRE_STUDY_JIT_COMPILE) != 0) PRIV(jit_compile)(re, extra, JIT_COMPILE); if ((options & PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE) != 0) PRIV(jit_compile)(re, extra, JIT_PARTIAL_SOFT_COMPILE); if ((options & PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE) != 0) PRIV(jit_compile)(re, extra, JIT_PARTIAL_HARD_COMPILE); if (study->flags == 0 && (extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) == 0 && (options & PCRE_STUDY_EXTRA_NEEDED) == 0) { #if defined COMPILE_PCRE8 pcre_free_study(extra); #elif defined COMPILE_PCRE16 pcre16_free_study(extra); #elif defined COMPILE_PCRE32 pcre32_free_study(extra); #endif extra = NULL; } #endif } return extra; } /************************************************* * Free the study data * *************************************************/ /* This function frees the memory that was obtained by pcre_study(). Argument: a pointer to the pcre[16]_extra block Returns: nothing */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN void pcre_free_study(pcre_extra *extra) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN void pcre16_free_study(pcre16_extra *extra) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN void pcre32_free_study(pcre32_extra *extra) #endif { if (extra == NULL) return; #ifdef SUPPORT_JIT if ((extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 && extra->executable_jit != NULL) PRIV(jit_free)(extra->executable_jit); #endif PUBL(free)(extra); } /* End of pcre_study.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_exec.c0000644000000000000020000065224314655113617021444 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2021 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains pcre_exec(), the externally visible function that does pattern matching using an NFA algorithm, trying to mimic Perl as closely as possible. There are also some static supporting functions. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define NLBLOCK md /* Block containing newline information */ #define PSSTART start_subject /* Field containing processed string start */ #define PSEND end_subject /* Field containing processed string end */ #include "pcre_internal.h" /* Undefine some potentially clashing cpp symbols */ #undef min #undef max /* The md->capture_last field uses the lower 16 bits for the last captured substring (which can never be greater than 65535) and a bit in the top half to mean "capture vector overflowed". This odd way of doing things was implemented when it was realized that preserving and restoring the overflow bit whenever the last capture number was saved/restored made for a neater interface, and doing it this way saved on (a) another variable, which would have increased the stack frame size (a big NO-NO in PCRE) and (b) another separate set of save/restore instructions. The following defines are used in implementing this. */ #define CAPLMASK 0x0000ffff /* The bits used for last_capture */ #define OVFLMASK 0xffff0000 /* The bits used for the overflow flag */ #define OVFLBIT 0x00010000 /* The bit that is set for overflow */ /* Values for setting in md->match_function_type to indicate two special types of call to match(). We do it this way to save on using another stack variable, as stack usage is to be discouraged. */ #define MATCH_CONDASSERT 1 /* Called to check a condition assertion */ #define MATCH_CBEGROUP 2 /* Could-be-empty unlimited repeat group */ /* Non-error returns from the match() function. Error returns are externally defined PCRE_ERROR_xxx codes, which are all negative. */ #define MATCH_MATCH 1 #define MATCH_NOMATCH 0 /* Special internal returns from the match() function. Make them sufficiently negative to avoid the external error codes. */ #define MATCH_ACCEPT (-999) #define MATCH_KETRPOS (-998) #define MATCH_ONCE (-997) /* The next 5 must be kept together and in sequence so that a test that checks for any one of them can use a range. */ #define MATCH_COMMIT (-996) #define MATCH_PRUNE (-995) #define MATCH_SKIP (-994) #define MATCH_SKIP_ARG (-993) #define MATCH_THEN (-992) #define MATCH_BACKTRACK_MAX MATCH_THEN #define MATCH_BACKTRACK_MIN MATCH_COMMIT /* Maximum number of ints of offset to save on the stack for recursive calls. If the offset vector is bigger, malloc is used. This should be a multiple of 3, because the offset vector is always a multiple of 3 long. */ #define REC_STACK_SAVE_MAX 30 /* Min and max values for the common repeats; for the maxima, 0 => infinity */ static const char rep_min[] = { 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, }; static const char rep_max[] = { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, }; #ifdef PCRE_DEBUG /************************************************* * Debugging function to print chars * *************************************************/ /* Print a sequence of chars in printable format, stopping at the end of the subject if the requested. Arguments: p points to characters length number to print is_subject TRUE if printing from within md->start_subject md pointer to matching data block, if is_subject is TRUE Returns: nothing */ static void pchars(const pcre_uchar *p, int length, BOOL is_subject, match_data *md) { pcre_uint32 c; BOOL utf = md->utf; if (is_subject && length > md->end_subject - p) length = md->end_subject - p; while (length-- > 0) if (isprint(c = UCHAR21INCTEST(p))) printf("%c", (char)c); else printf("\\x{%02x}", c); } #endif /************************************************* * Match a back-reference * *************************************************/ /* Normally, if a back reference hasn't been set, the length that is passed is negative, so the match always fails. However, in JavaScript compatibility mode, the length passed is zero. Note that in caseless UTF-8 mode, the number of subject bytes matched may be different to the number of reference bytes. Arguments: offset index into the offset vector eptr pointer into the subject length length of reference to be matched (number of bytes) md points to match data block caseless TRUE if caseless Returns: >= 0 the number of subject bytes matched -1 no match -2 partial match; always given if at end subject */ static int match_ref(int offset, register PCRE_PUCHAR eptr, int length, match_data *md, BOOL caseless) { PCRE_PUCHAR eptr_start = eptr; register PCRE_PUCHAR p = md->start_subject + md->offset_vector[offset]; #if defined SUPPORT_UTF && defined SUPPORT_UCP BOOL utf = md->utf; #endif #ifdef PCRE_DEBUG if (eptr >= md->end_subject) printf("matching subject "); else { printf("matching subject "); pchars(eptr, length, TRUE, md); } printf(" against backref "); pchars(p, length, FALSE, md); printf("\n"); #endif /* Always fail if reference not set (and not JavaScript compatible - in that case the length is passed as zero). */ if (length < 0) return -1; /* Separate the caseless case for speed. In UTF-8 mode we can only do this properly if Unicode properties are supported. Otherwise, we can check only ASCII characters. */ if (caseless) { #if defined SUPPORT_UTF && defined SUPPORT_UCP if (utf) { /* Match characters up to the end of the reference. NOTE: the number of data units matched may differ, because in UTF-8 there are some characters whose upper and lower case versions code have different numbers of bytes. For example, U+023A (2 bytes in UTF-8) is the upper case version of U+2C65 (3 bytes in UTF-8); a sequence of 3 of the former uses 6 bytes, as does a sequence of two of the latter. It is important, therefore, to check the length along the reference, not along the subject (earlier code did this wrong). */ PCRE_PUCHAR endptr = p + length; while (p < endptr) { pcre_uint32 c, d; const ucd_record *ur; if (eptr >= md->end_subject) return -2; /* Partial match */ GETCHARINC(c, eptr); GETCHARINC(d, p); ur = GET_UCD(d); if (c != d && c != d + ur->other_case) { const pcre_uint32 *pp = PRIV(ucd_caseless_sets) + ur->caseset; for (;;) { if (c < *pp) return -1; if (c == *pp++) break; } } } } else #endif /* The same code works when not in UTF-8 mode and in UTF-8 mode when there is no UCP support. */ { while (length-- > 0) { pcre_uint32 cc, cp; if (eptr >= md->end_subject) return -2; /* Partial match */ cc = UCHAR21TEST(eptr); cp = UCHAR21TEST(p); if (TABLE_GET(cp, md->lcc, cp) != TABLE_GET(cc, md->lcc, cc)) return -1; p++; eptr++; } } } /* In the caseful case, we can just compare the bytes, whether or not we are in UTF-8 mode. */ else { while (length-- > 0) { if (eptr >= md->end_subject) return -2; /* Partial match */ if (UCHAR21INCTEST(p) != UCHAR21INCTEST(eptr)) return -1; } } return (int)(eptr - eptr_start); } /*************************************************************************** **************************************************************************** RECURSION IN THE match() FUNCTION The match() function is highly recursive, though not every recursive call increases the recursive depth. Nevertheless, some regular expressions can cause it to recurse to a great depth. I was writing for Unix, so I just let it call itself recursively. This uses the stack for saving everything that has to be saved for a recursive call. On Unix, the stack can be large, and this works fine. It turns out that on some non-Unix-like systems there are problems with programs that use a lot of stack. (This despite the fact that every last chip has oodles of memory these days, and techniques for extending the stack have been known for decades.) So.... There is a fudge, triggered by defining NO_RECURSE, which avoids recursive calls by keeping local variables that need to be preserved in blocks of memory obtained from malloc() instead instead of on the stack. Macros are used to achieve this so that the actual code doesn't look very different to what it always used to. The original heap-recursive code used longjmp(). However, it seems that this can be very slow on some operating systems. Following a suggestion from Stan Switzer, the use of longjmp() has been abolished, at the cost of having to provide a unique number for each call to RMATCH. There is no way of generating a sequence of numbers at compile time in C. I have given them names, to make them stand out more clearly. Crude tests on x86 Linux show a small speedup of around 5-8%. However, on FreeBSD, avoiding longjmp() more than halves the time taken to run the standard tests. Furthermore, not using longjmp() means that local dynamic variables don't have indeterminate values; this has meant that the frame size can be reduced because the result can be "passed back" by straight setting of the variable instead of being passed in the frame. **************************************************************************** ***************************************************************************/ /* Numbers for RMATCH calls. When this list is changed, the code at HEAP_RETURN below must be updated in sync. */ enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10, RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20, RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30, RM31, RM32, RM33, RM34, RM35, RM36, RM37, RM38, RM39, RM40, RM41, RM42, RM43, RM44, RM45, RM46, RM47, RM48, RM49, RM50, RM51, RM52, RM53, RM54, RM55, RM56, RM57, RM58, RM59, RM60, RM61, RM62, RM63, RM64, RM65, RM66, RM67 }; /* These versions of the macros use the stack, as normal. There are debugging versions and production versions. Note that the "rw" argument of RMATCH isn't actually used in this definition. */ #ifndef NO_RECURSE #define REGISTER register #ifdef PCRE_DEBUG #define RMATCH(ra,rb,rc,rd,re,rw) \ { \ printf("match() called in line %d\n", __LINE__); \ rrc = match(ra,rb,mstart,rc,rd,re,rdepth+1); \ printf("to line %d\n", __LINE__); \ } #define RRETURN(ra) \ { \ printf("match() returned %d from line %d\n", ra, __LINE__); \ return ra; \ } #else #define RMATCH(ra,rb,rc,rd,re,rw) \ rrc = match(ra,rb,mstart,rc,rd,re,rdepth+1) #define RRETURN(ra) return ra #endif #else /* These versions of the macros manage a private stack on the heap. Note that the "rd" argument of RMATCH isn't actually used in this definition. It's the md argument of match(), which never changes. */ #define REGISTER #define RMATCH(ra,rb,rc,rd,re,rw)\ {\ heapframe *newframe = frame->Xnextframe;\ if (newframe == NULL)\ {\ newframe = (heapframe *)(PUBL(stack_malloc))(sizeof(heapframe));\ if (newframe == NULL) RRETURN(PCRE_ERROR_NOMEMORY);\ newframe->Xnextframe = NULL;\ frame->Xnextframe = newframe;\ }\ frame->Xwhere = rw;\ newframe->Xeptr = ra;\ newframe->Xecode = rb;\ newframe->Xmstart = mstart;\ newframe->Xoffset_top = rc;\ newframe->Xeptrb = re;\ newframe->Xrdepth = frame->Xrdepth + 1;\ newframe->Xprevframe = frame;\ frame = newframe;\ DPRINTF(("restarting from line %d\n", __LINE__));\ goto HEAP_RECURSE;\ L_##rw:\ DPRINTF(("jumped back to line %d\n", __LINE__));\ } #define RRETURN(ra)\ {\ heapframe *oldframe = frame;\ frame = oldframe->Xprevframe;\ if (frame != NULL)\ {\ rrc = ra;\ goto HEAP_RETURN;\ }\ return ra;\ } /* Structure for remembering the local variables in a private frame */ typedef struct heapframe { struct heapframe *Xprevframe; struct heapframe *Xnextframe; /* Function arguments that may change */ PCRE_PUCHAR Xeptr; const pcre_uchar *Xecode; PCRE_PUCHAR Xmstart; int Xoffset_top; eptrblock *Xeptrb; unsigned int Xrdepth; /* Function local variables */ PCRE_PUCHAR Xcallpat; #ifdef SUPPORT_UTF PCRE_PUCHAR Xcharptr; #endif PCRE_PUCHAR Xdata; PCRE_PUCHAR Xnext; PCRE_PUCHAR Xpp; PCRE_PUCHAR Xprev; PCRE_PUCHAR Xsaved_eptr; recursion_info Xnew_recursive; BOOL Xcur_is_word; BOOL Xcondition; BOOL Xprev_is_word; #ifdef SUPPORT_UCP int Xprop_type; unsigned int Xprop_value; int Xprop_fail_result; int Xoclength; pcre_uchar Xocchars[6]; #endif int Xcodelink; int Xctype; unsigned int Xfc; int Xfi; int Xlength; int Xmax; int Xmin; unsigned int Xnumber; int Xoffset; unsigned int Xop; pcre_int32 Xsave_capture_last; int Xsave_offset1, Xsave_offset2, Xsave_offset3; int Xstacksave[REC_STACK_SAVE_MAX]; eptrblock Xnewptrb; /* Where to jump back to */ int Xwhere; } heapframe; #endif /*************************************************************************** ***************************************************************************/ /************************************************* * Match from current position * *************************************************/ /* This function is called recursively in many circumstances. Whenever it returns a negative (error) response, the outer incarnation must also return the same response. */ /* These macros pack up tests that are used for partial matching, and which appear several times in the code. We set the "hit end" flag if the pointer is at the end of the subject and also past the start of the subject (i.e. something has been matched). For hard partial matching, we then return immediately. The second one is used when we already know we are past the end of the subject. */ #define CHECK_PARTIAL()\ if (md->partial != 0 && eptr >= md->end_subject && \ eptr > md->start_used_ptr) \ { \ md->hitend = TRUE; \ if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); \ } #define SCHECK_PARTIAL()\ if (md->partial != 0 && eptr > md->start_used_ptr) \ { \ md->hitend = TRUE; \ if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); \ } /* Performance note: It might be tempting to extract commonly used fields from the md structure (e.g. utf, end_subject) into individual variables to improve performance. Tests using gcc on a SPARC disproved this; in the first case, it made performance worse. Arguments: eptr pointer to current character in subject ecode pointer to current position in compiled code mstart pointer to the current match start position (can be modified by encountering \K) offset_top current top pointer md pointer to "static" info for the match eptrb pointer to chain of blocks containing eptr at start of brackets - for testing for empty matches rdepth the recursion depth Returns: MATCH_MATCH if matched ) these values are >= 0 MATCH_NOMATCH if failed to match ) a negative MATCH_xxx value for PRUNE, SKIP, etc a negative PCRE_ERROR_xxx value if aborted by an error condition (e.g. stopped by repeated call or recursion limit) */ static int match(REGISTER PCRE_PUCHAR eptr, REGISTER const pcre_uchar *ecode, PCRE_PUCHAR mstart, int offset_top, match_data *md, eptrblock *eptrb, unsigned int rdepth) { /* These variables do not need to be preserved over recursion in this function, so they can be ordinary variables in all cases. Mark some of them with "register" because they are used a lot in loops. */ register int rrc; /* Returns from recursive calls */ register int i; /* Used for loops not involving calls to RMATCH() */ register pcre_uint32 c; /* Character values not kept over RMATCH() calls */ register BOOL utf; /* Local copy of UTF flag for speed */ BOOL minimize, possessive; /* Quantifier options */ BOOL caseless; int condcode; /* When recursion is not being used, all "local" variables that have to be preserved over calls to RMATCH() are part of a "frame". We set up the top-level frame on the stack here; subsequent instantiations are obtained from the heap whenever RMATCH() does a "recursion". See the macro definitions above. Putting the top-level on the stack rather than malloc-ing them all gives a performance boost in many cases where there is not much "recursion". */ #ifdef NO_RECURSE heapframe *frame = (heapframe *)md->match_frames_base; /* Copy in the original argument variables */ frame->Xeptr = eptr; frame->Xecode = ecode; frame->Xmstart = mstart; frame->Xoffset_top = offset_top; frame->Xeptrb = eptrb; frame->Xrdepth = rdepth; /* This is where control jumps back to to effect "recursion" */ HEAP_RECURSE: /* Macros make the argument variables come from the current frame */ #define eptr frame->Xeptr #define ecode frame->Xecode #define mstart frame->Xmstart #define offset_top frame->Xoffset_top #define eptrb frame->Xeptrb #define rdepth frame->Xrdepth /* Ditto for the local variables */ #ifdef SUPPORT_UTF #define charptr frame->Xcharptr #endif #define callpat frame->Xcallpat #define codelink frame->Xcodelink #define data frame->Xdata #define next frame->Xnext #define pp frame->Xpp #define prev frame->Xprev #define saved_eptr frame->Xsaved_eptr #define new_recursive frame->Xnew_recursive #define cur_is_word frame->Xcur_is_word #define condition frame->Xcondition #define prev_is_word frame->Xprev_is_word #ifdef SUPPORT_UCP #define prop_type frame->Xprop_type #define prop_value frame->Xprop_value #define prop_fail_result frame->Xprop_fail_result #define oclength frame->Xoclength #define occhars frame->Xocchars #endif #define ctype frame->Xctype #define fc frame->Xfc #define fi frame->Xfi #define length frame->Xlength #define max frame->Xmax #define min frame->Xmin #define number frame->Xnumber #define offset frame->Xoffset #define op frame->Xop #define save_capture_last frame->Xsave_capture_last #define save_offset1 frame->Xsave_offset1 #define save_offset2 frame->Xsave_offset2 #define save_offset3 frame->Xsave_offset3 #define stacksave frame->Xstacksave #define newptrb frame->Xnewptrb /* When recursion is being used, local variables are allocated on the stack and get preserved during recursion in the normal way. In this environment, fi and i, and fc and c, can be the same variables. */ #else /* NO_RECURSE not defined */ #define fi i #define fc c /* Many of the following variables are used only in small blocks of the code. My normal style of coding would have declared them within each of those blocks. However, in order to accommodate the version of this code that uses an external "stack" implemented on the heap, it is easier to declare them all here, so the declarations can be cut out in a block. The only declarations within blocks below are for variables that do not have to be preserved over a recursive call to RMATCH(). */ #ifdef SUPPORT_UTF const pcre_uchar *charptr; #endif const pcre_uchar *callpat; const pcre_uchar *data; const pcre_uchar *next; PCRE_PUCHAR pp; const pcre_uchar *prev; PCRE_PUCHAR saved_eptr; recursion_info new_recursive; BOOL cur_is_word; BOOL condition; BOOL prev_is_word; #ifdef SUPPORT_UCP int prop_type; unsigned int prop_value; int prop_fail_result; int oclength; pcre_uchar occhars[6]; #endif int codelink; int ctype; int length; int max; int min; unsigned int number; int offset; unsigned int op; pcre_int32 save_capture_last; int save_offset1, save_offset2, save_offset3; int stacksave[REC_STACK_SAVE_MAX]; eptrblock newptrb; /* There is a special fudge for calling match() in a way that causes it to measure the size of its basic stack frame when the stack is being used for recursion. The second argument (ecode) being NULL triggers this behaviour. It cannot normally ever be NULL. The return is the negated value of the frame size. */ if (ecode == NULL) { if (rdepth == 0) return match((PCRE_PUCHAR)&rdepth, NULL, NULL, 0, NULL, NULL, 1); else { int len = (int)((char *)&rdepth - (char *)eptr); return (len > 0)? -len : len; } } #endif /* NO_RECURSE */ /* To save space on the stack and in the heap frame, I have doubled up on some of the local variables that are used only in localised parts of the code, but still need to be preserved over recursive calls of match(). These macros define the alternative names that are used. */ #define allow_zero cur_is_word #define cbegroup condition #define code_offset codelink #define condassert condition #define matched_once prev_is_word #define foc number #define save_mark data /* These statements are here to stop the compiler complaining about unitialized variables. */ #ifdef SUPPORT_UCP prop_value = 0; prop_fail_result = 0; #endif /* This label is used for tail recursion, which is used in a few cases even when NO_RECURSE is not defined, in order to reduce the amount of stack that is used. Thanks to Ian Taylor for noticing this possibility and sending the original patch. */ TAIL_RECURSE: /* OK, now we can get on with the real code of the function. Recursive calls are specified by the macro RMATCH and RRETURN is used to return. When NO_RECURSE is *not* defined, these just turn into a recursive call to match() and a "return", respectively (possibly with some debugging if PCRE_DEBUG is defined). However, RMATCH isn't like a function call because it's quite a complicated macro. It has to be used in one particular way. This shouldn't, however, impact performance when true recursion is being used. */ #ifdef SUPPORT_UTF utf = md->utf; /* Local copy of the flag */ #else utf = FALSE; #endif /* First check that we haven't called match() too many times, or that we haven't exceeded the recursive call limit. */ if (md->match_call_count++ >= md->match_limit) RRETURN(PCRE_ERROR_MATCHLIMIT); if (rdepth >= md->match_limit_recursion) RRETURN(PCRE_ERROR_RECURSIONLIMIT); /* At the start of a group with an unlimited repeat that may match an empty string, the variable md->match_function_type is set to MATCH_CBEGROUP. It is done this way to save having to use another function argument, which would take up space on the stack. See also MATCH_CONDASSERT below. When MATCH_CBEGROUP is set, add the current subject pointer to the chain of such remembered pointers, to be checked when we hit the closing ket, in order to break infinite loops that match no characters. When match() is called in other circumstances, don't add to the chain. The MATCH_CBEGROUP feature must NOT be used with tail recursion, because the memory block that is used is on the stack, so a new one may be required for each match(). */ if (md->match_function_type == MATCH_CBEGROUP) { newptrb.epb_saved_eptr = eptr; newptrb.epb_prev = eptrb; eptrb = &newptrb; md->match_function_type = 0; } /* Now start processing the opcodes. */ for (;;) { minimize = possessive = FALSE; op = *ecode; switch(op) { case OP_MARK: md->nomatch_mark = ecode + 2; md->mark = NULL; /* In case previously set by assertion */ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md, eptrb, RM55); if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT || rrc == MATCH_KETRPOS) && md->mark == NULL) md->mark = ecode + 2; /* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an argument, and we must check whether that argument matches this MARK's argument. It is passed back in md->start_match_ptr (an overloading of that variable). If it does match, we reset that variable to the current subject position and return MATCH_SKIP. Otherwise, pass back the return code unaltered. */ else if (rrc == MATCH_SKIP_ARG && STRCMP_UC_UC_TEST(ecode + 2, md->start_match_ptr) == 0) { md->start_match_ptr = eptr; RRETURN(MATCH_SKIP); } RRETURN(rrc); case OP_FAIL: RRETURN(MATCH_NOMATCH); case OP_COMMIT: RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM52); if (rrc != MATCH_NOMATCH) RRETURN(rrc); RRETURN(MATCH_COMMIT); case OP_PRUNE: RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM51); if (rrc != MATCH_NOMATCH) RRETURN(rrc); RRETURN(MATCH_PRUNE); case OP_PRUNE_ARG: md->nomatch_mark = ecode + 2; md->mark = NULL; /* In case previously set by assertion */ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md, eptrb, RM56); if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) && md->mark == NULL) md->mark = ecode + 2; if (rrc != MATCH_NOMATCH) RRETURN(rrc); RRETURN(MATCH_PRUNE); case OP_SKIP: RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM53); if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->start_match_ptr = eptr; /* Pass back current position */ RRETURN(MATCH_SKIP); /* Note that, for Perl compatibility, SKIP with an argument does NOT set nomatch_mark. When a pattern match ends with a SKIP_ARG for which there was not a matching mark, we have to re-run the match, ignoring the SKIP_ARG that failed and any that precede it (either they also failed, or were not triggered). To do this, we maintain a count of executed SKIP_ARGs. If a SKIP_ARG gets to top level, the match is re-run with md->ignore_skip_arg set to the count of the one that failed. */ case OP_SKIP_ARG: md->skip_arg_count++; if (md->skip_arg_count <= md->ignore_skip_arg) { ecode += PRIV(OP_lengths)[*ecode] + ecode[1]; break; } RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md, eptrb, RM57); if (rrc != MATCH_NOMATCH) RRETURN(rrc); /* Pass back the current skip name by overloading md->start_match_ptr and returning the special MATCH_SKIP_ARG return code. This will either be caught by a matching MARK, or get to the top, where it causes a rematch with md->ignore_skip_arg set to the value of md->skip_arg_count. */ md->start_match_ptr = ecode + 2; RRETURN(MATCH_SKIP_ARG); /* For THEN (and THEN_ARG) we pass back the address of the opcode, so that the branch in which it occurs can be determined. Overload the start of match pointer to do this. */ case OP_THEN: RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM54); if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->start_match_ptr = ecode; RRETURN(MATCH_THEN); case OP_THEN_ARG: md->nomatch_mark = ecode + 2; md->mark = NULL; /* In case previously set by assertion */ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md, eptrb, RM58); if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) && md->mark == NULL) md->mark = ecode + 2; if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->start_match_ptr = ecode; RRETURN(MATCH_THEN); /* Handle an atomic group that does not contain any capturing parentheses. This can be handled like an assertion. Prior to 8.13, all atomic groups were handled this way. In 8.13, the code was changed as below for ONCE, so that backups pass through the group and thereby reset captured values. However, this uses a lot more stack, so in 8.20, atomic groups that do not contain any captures generate OP_ONCE_NC, which can be handled in the old, less stack intensive way. Check the alternative branches in turn - the matching won't pass the KET for this kind of subpattern. If any one branch matches, we carry on as at the end of a normal bracket, leaving the subject pointer, but resetting the start-of-match value in case it was changed by \K. */ case OP_ONCE_NC: prev = ecode; saved_eptr = eptr; save_mark = md->mark; do { RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM64); if (rrc == MATCH_MATCH) /* Note: _not_ MATCH_ACCEPT */ { mstart = md->start_match_ptr; break; } if (rrc == MATCH_THEN) { next = ecode + GET(ecode,1); if (md->start_match_ptr < next && (*ecode == OP_ALT || *next == OP_ALT)) rrc = MATCH_NOMATCH; } if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += GET(ecode,1); md->mark = save_mark; } while (*ecode == OP_ALT); /* If hit the end of the group (which could be repeated), fail */ if (*ecode != OP_ONCE_NC && *ecode != OP_ALT) RRETURN(MATCH_NOMATCH); /* Continue as from after the group, updating the offsets high water mark, since extracts may have been taken. */ do ecode += GET(ecode, 1); while (*ecode == OP_ALT); offset_top = md->end_offset_top; eptr = md->end_match_ptr; /* For a non-repeating ket, just continue at this level. This also happens for a repeating ket if no characters were matched in the group. This is the forcible breaking of infinite loops as implemented in Perl 5.005. */ if (*ecode == OP_KET || eptr == saved_eptr) { ecode += 1+LINK_SIZE; break; } /* The repeating kets try the rest of the pattern or restart from the preceding bracket, in the appropriate order. The second "call" of match() uses tail recursion, to avoid using another stack frame. */ if (*ecode == OP_KETRMIN) { RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM65); if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode = prev; goto TAIL_RECURSE; } else /* OP_KETRMAX */ { RMATCH(eptr, prev, offset_top, md, eptrb, RM66); if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += 1 + LINK_SIZE; goto TAIL_RECURSE; } /* Control never gets here */ /* Handle a capturing bracket, other than those that are possessive with an unlimited repeat. If there is space in the offset vector, save the current subject position in the working slot at the top of the vector. We mustn't change the current values of the data slot, because they may be set from a previous iteration of this group, and be referred to by a reference inside the group. A failure to match might occur after the group has succeeded, if something later on doesn't match. For this reason, we need to restore the working value and also the values of the final offsets, in case they were set by a previous iteration of the same bracket. If there isn't enough space in the offset vector, treat this as if it were a non-capturing bracket. Don't worry about setting the flag for the error case here; that is handled in the code for KET. */ case OP_CBRA: case OP_SCBRA: number = GET2(ecode, 1+LINK_SIZE); offset = number << 1; #ifdef PCRE_DEBUG printf("start bracket %d\n", number); printf("subject="); pchars(eptr, 16, TRUE, md); printf("\n"); #endif if (offset < md->offset_max) { save_offset1 = md->offset_vector[offset]; save_offset2 = md->offset_vector[offset+1]; save_offset3 = md->offset_vector[md->offset_end - number]; save_capture_last = md->capture_last; save_mark = md->mark; DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3)); md->offset_vector[md->offset_end - number] = (int)(eptr - md->start_subject); for (;;) { if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP; RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM1); if (rrc == MATCH_ONCE) break; /* Backing up through an atomic group */ /* If we backed up to a THEN, check whether it is within the current branch by comparing the address of the THEN that is passed back with the end of the branch. If it is within the current branch, and the branch is one of two or more alternatives (it either starts or ends with OP_ALT), we have reached the limit of THEN's action, so convert the return code to NOMATCH, which will cause normal backtracking to happen from now on. Otherwise, THEN is passed back to an outer alternative. This implements Perl's treatment of parenthesized groups, where a group not containing | does not affect the current alternative, that is, (X) is NOT the same as (X|(*F)). */ if (rrc == MATCH_THEN) { next = ecode + GET(ecode,1); if (md->start_match_ptr < next && (*ecode == OP_ALT || *next == OP_ALT)) rrc = MATCH_NOMATCH; } /* Anything other than NOMATCH is passed back. */ if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->capture_last = save_capture_last; ecode += GET(ecode, 1); md->mark = save_mark; if (*ecode != OP_ALT) break; } DPRINTF(("bracket %d failed\n", number)); md->offset_vector[offset] = save_offset1; md->offset_vector[offset+1] = save_offset2; md->offset_vector[md->offset_end - number] = save_offset3; /* At this point, rrc will be one of MATCH_ONCE or MATCH_NOMATCH. */ RRETURN(rrc); } /* FALL THROUGH ... Insufficient room for saving captured contents. Treat as a non-capturing bracket. */ /* VVVVVVVVVVVVVVVVVVVVVVVVV */ /* VVVVVVVVVVVVVVVVVVVVVVVVV */ DPRINTF(("insufficient capture room: treat as non-capturing\n")); /* VVVVVVVVVVVVVVVVVVVVVVVVV */ /* VVVVVVVVVVVVVVVVVVVVVVVVV */ /* Non-capturing or atomic group, except for possessive with unlimited repeat and ONCE group with no captures. Loop for all the alternatives. When we get to the final alternative within the brackets, we used to return the result of a recursive call to match() whatever happened so it was possible to reduce stack usage by turning this into a tail recursion, except in the case of a possibly empty group. However, now that there is the possiblity of (*THEN) occurring in the final alternative, this optimization is no longer always possible. We can optimize if we know there are no (*THEN)s in the pattern; at present this is the best that can be done. MATCH_ONCE is returned when the end of an atomic group is successfully reached, but subsequent matching fails. It passes back up the tree (causing captured values to be reset) until the original atomic group level is reached. This is tested by comparing md->once_target with the start of the group. At this point, the return is converted into MATCH_NOMATCH so that previous backup points can be taken. */ case OP_ONCE: case OP_BRA: case OP_SBRA: DPRINTF(("start non-capturing bracket\n")); for (;;) { if (op >= OP_SBRA || op == OP_ONCE) md->match_function_type = MATCH_CBEGROUP; /* If this is not a possibly empty group, and there are no (*THEN)s in the pattern, and this is the final alternative, optimize as described above. */ else if (!md->hasthen && ecode[GET(ecode, 1)] != OP_ALT) { ecode += PRIV(OP_lengths)[*ecode]; goto TAIL_RECURSE; } /* In all other cases, we have to make another call to match(). */ save_mark = md->mark; save_capture_last = md->capture_last; RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM2); /* See comment in the code for capturing groups above about handling THEN. */ if (rrc == MATCH_THEN) { next = ecode + GET(ecode,1); if (md->start_match_ptr < next && (*ecode == OP_ALT || *next == OP_ALT)) rrc = MATCH_NOMATCH; } if (rrc != MATCH_NOMATCH) { if (rrc == MATCH_ONCE) { const pcre_uchar *scode = ecode; if (*scode != OP_ONCE) /* If not at start, find it */ { while (*scode == OP_ALT) scode += GET(scode, 1); scode -= GET(scode, 1); } if (md->once_target == scode) rrc = MATCH_NOMATCH; } RRETURN(rrc); } ecode += GET(ecode, 1); md->mark = save_mark; if (*ecode != OP_ALT) break; md->capture_last = save_capture_last; } RRETURN(MATCH_NOMATCH); /* Handle possessive capturing brackets with an unlimited repeat. We come here from BRAZERO with allow_zero set TRUE. The offset_vector values are handled similarly to the normal case above. However, the matching is different. The end of these brackets will always be OP_KETRPOS, which returns MATCH_KETRPOS without going further in the pattern. By this means we can handle the group by iteration rather than recursion, thereby reducing the amount of stack needed. */ case OP_CBRAPOS: case OP_SCBRAPOS: allow_zero = FALSE; POSSESSIVE_CAPTURE: number = GET2(ecode, 1+LINK_SIZE); offset = number << 1; #ifdef PCRE_DEBUG printf("start possessive bracket %d\n", number); printf("subject="); pchars(eptr, 16, TRUE, md); printf("\n"); #endif if (offset >= md->offset_max) goto POSSESSIVE_NON_CAPTURE; matched_once = FALSE; code_offset = (int)(ecode - md->start_code); save_offset1 = md->offset_vector[offset]; save_offset2 = md->offset_vector[offset+1]; save_offset3 = md->offset_vector[md->offset_end - number]; save_capture_last = md->capture_last; DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3)); /* Each time round the loop, save the current subject position for use when the group matches. For MATCH_MATCH, the group has matched, so we restart it with a new subject starting position, remembering that we had at least one match. For MATCH_NOMATCH, carry on with the alternatives, as usual. If we haven't matched any alternatives in any iteration, check to see if a previous iteration matched. If so, the group has matched; continue from afterwards. Otherwise it has failed; restore the previous capture values before returning NOMATCH. */ for (;;) { md->offset_vector[md->offset_end - number] = (int)(eptr - md->start_subject); if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP; RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM63); if (rrc == MATCH_KETRPOS) { offset_top = md->end_offset_top; ecode = md->start_code + code_offset; save_capture_last = md->capture_last; matched_once = TRUE; mstart = md->start_match_ptr; /* In case \K changed it */ if (eptr == md->end_match_ptr) /* Matched an empty string */ { do ecode += GET(ecode, 1); while (*ecode == OP_ALT); break; } eptr = md->end_match_ptr; continue; } /* See comment in the code for capturing groups above about handling THEN. */ if (rrc == MATCH_THEN) { next = ecode + GET(ecode,1); if (md->start_match_ptr < next && (*ecode == OP_ALT || *next == OP_ALT)) rrc = MATCH_NOMATCH; } if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->capture_last = save_capture_last; ecode += GET(ecode, 1); if (*ecode != OP_ALT) break; } if (!matched_once) { md->offset_vector[offset] = save_offset1; md->offset_vector[offset+1] = save_offset2; md->offset_vector[md->offset_end - number] = save_offset3; } if (allow_zero || matched_once) { ecode += 1 + LINK_SIZE; break; } RRETURN(MATCH_NOMATCH); /* Non-capturing possessive bracket with unlimited repeat. We come here from BRAZERO with allow_zero = TRUE. The code is similar to the above, without the capturing complication. It is written out separately for speed and cleanliness. */ case OP_BRAPOS: case OP_SBRAPOS: allow_zero = FALSE; POSSESSIVE_NON_CAPTURE: matched_once = FALSE; code_offset = (int)(ecode - md->start_code); save_capture_last = md->capture_last; for (;;) { if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP; RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb, RM48); if (rrc == MATCH_KETRPOS) { offset_top = md->end_offset_top; ecode = md->start_code + code_offset; matched_once = TRUE; mstart = md->start_match_ptr; /* In case \K reset it */ if (eptr == md->end_match_ptr) /* Matched an empty string */ { do ecode += GET(ecode, 1); while (*ecode == OP_ALT); break; } eptr = md->end_match_ptr; continue; } /* See comment in the code for capturing groups above about handling THEN. */ if (rrc == MATCH_THEN) { next = ecode + GET(ecode,1); if (md->start_match_ptr < next && (*ecode == OP_ALT || *next == OP_ALT)) rrc = MATCH_NOMATCH; } if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += GET(ecode, 1); if (*ecode != OP_ALT) break; md->capture_last = save_capture_last; } if (matched_once || allow_zero) { ecode += 1 + LINK_SIZE; break; } RRETURN(MATCH_NOMATCH); /* Control never reaches here. */ /* Conditional group: compilation checked that there are no more than two branches. If the condition is false, skipping the first branch takes us past the end of the item if there is only one branch, but that's exactly what we want. */ case OP_COND: case OP_SCOND: /* The variable codelink will be added to ecode when the condition is false, to get to the second branch. Setting it to the offset to the ALT or KET, then incrementing ecode achieves this effect. We now have ecode pointing to the condition or callout. */ codelink = GET(ecode, 1); /* Offset to the second branch */ ecode += 1 + LINK_SIZE; /* From this opcode */ /* Because of the way auto-callout works during compile, a callout item is inserted between OP_COND and an assertion condition. */ if (*ecode == OP_CALLOUT) { if (PUBL(callout) != NULL) { PUBL(callout_block) cb; cb.version = 2; /* Version 1 of the callout block */ cb.callout_number = ecode[1]; cb.offset_vector = md->offset_vector; #if defined COMPILE_PCRE8 cb.subject = (PCRE_SPTR)md->start_subject; #elif defined COMPILE_PCRE16 cb.subject = (PCRE_SPTR16)md->start_subject; #elif defined COMPILE_PCRE32 cb.subject = (PCRE_SPTR32)md->start_subject; #endif cb.subject_length = (int)(md->end_subject - md->start_subject); cb.start_match = (int)(mstart - md->start_subject); cb.current_position = (int)(eptr - md->start_subject); cb.pattern_position = GET(ecode, 2); cb.next_item_length = GET(ecode, 2 + LINK_SIZE); cb.capture_top = offset_top/2; cb.capture_last = md->capture_last & CAPLMASK; /* Internal change requires this for API compatibility. */ if (cb.capture_last == 0) cb.capture_last = -1; cb.callout_data = md->callout_data; cb.mark = md->nomatch_mark; if ((rrc = (*PUBL(callout))(&cb)) > 0) RRETURN(MATCH_NOMATCH); if (rrc < 0) RRETURN(rrc); } /* Advance ecode past the callout, so it now points to the condition. We must adjust codelink so that the value of ecode+codelink is unchanged. */ ecode += PRIV(OP_lengths)[OP_CALLOUT]; codelink -= PRIV(OP_lengths)[OP_CALLOUT]; } /* Test the various possible conditions */ condition = FALSE; switch(condcode = *ecode) { case OP_RREF: /* Numbered group recursion test */ if (md->recursive != NULL) /* Not recursing => FALSE */ { unsigned int recno = GET2(ecode, 1); /* Recursion group number*/ condition = (recno == RREF_ANY || recno == md->recursive->group_num); } break; case OP_DNRREF: /* Duplicate named group recursion test */ if (md->recursive != NULL) { int count = GET2(ecode, 1 + IMM2_SIZE); pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size; while (count-- > 0) { unsigned int recno = GET2(slot, 0); condition = recno == md->recursive->group_num; if (condition) break; slot += md->name_entry_size; } } break; case OP_CREF: /* Numbered group used test */ offset = GET2(ecode, 1) << 1; /* Doubled ref number */ condition = offset < offset_top && md->offset_vector[offset] >= 0; break; case OP_DNCREF: /* Duplicate named group used test */ { int count = GET2(ecode, 1 + IMM2_SIZE); pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size; while (count-- > 0) { offset = GET2(slot, 0) << 1; condition = offset < offset_top && md->offset_vector[offset] >= 0; if (condition) break; slot += md->name_entry_size; } } break; case OP_DEF: /* DEFINE - always false */ case OP_FAIL: /* From optimized (?!) condition */ break; /* The condition is an assertion. Call match() to evaluate it - setting md->match_function_type to MATCH_CONDASSERT causes it to stop at the end of an assertion. */ default: md->match_function_type = MATCH_CONDASSERT; RMATCH(eptr, ecode, offset_top, md, NULL, RM3); if (rrc == MATCH_MATCH) { if (md->end_offset_top > offset_top) offset_top = md->end_offset_top; /* Captures may have happened */ condition = TRUE; /* Advance ecode past the assertion to the start of the first branch, but adjust it so that the general choosing code below works. If the assertion has a quantifier that allows zero repeats we must skip over the BRAZERO. This is a lunatic thing to do, but somebody did! */ if (*ecode == OP_BRAZERO) ecode++; ecode += GET(ecode, 1); while (*ecode == OP_ALT) ecode += GET(ecode, 1); ecode += 1 + LINK_SIZE - PRIV(OP_lengths)[condcode]; } /* PCRE doesn't allow the effect of (*THEN) to escape beyond an assertion; it is therefore treated as NOMATCH. Any other return is an error. */ else if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) { RRETURN(rrc); /* Need braces because of following else */ } break; } /* Choose branch according to the condition */ ecode += condition? PRIV(OP_lengths)[condcode] : codelink; /* We are now at the branch that is to be obeyed. As there is only one, we can use tail recursion to avoid using another stack frame, except when there is unlimited repeat of a possibly empty group. In the latter case, a recursive call to match() is always required, unless the second alternative doesn't exist, in which case we can just plough on. Note that, for compatibility with Perl, the | in a conditional group is NOT treated as creating two alternatives. If a THEN is encountered in the branch, it propagates out to the enclosing alternative (unless nested in a deeper set of alternatives, of course). */ if (condition || ecode[-(1+LINK_SIZE)] == OP_ALT) { if (op != OP_SCOND) { goto TAIL_RECURSE; } md->match_function_type = MATCH_CBEGROUP; RMATCH(eptr, ecode, offset_top, md, eptrb, RM49); RRETURN(rrc); } /* Condition false & no alternative; continue after the group. */ else { } break; /* Before OP_ACCEPT there may be any number of OP_CLOSE opcodes, to close any currently open capturing brackets. */ case OP_CLOSE: number = GET2(ecode, 1); /* Must be less than 65536 */ offset = number << 1; #ifdef PCRE_DEBUG printf("end bracket %d at *ACCEPT", number); printf("\n"); #endif md->capture_last = (md->capture_last & OVFLMASK) | number; if (offset >= md->offset_max) md->capture_last |= OVFLBIT; else { md->offset_vector[offset] = md->offset_vector[md->offset_end - number]; md->offset_vector[offset+1] = (int)(eptr - md->start_subject); /* If this group is at or above the current highwater mark, ensure that any groups between the current high water mark and this group are marked unset and then update the high water mark. */ if (offset >= offset_top) { register int *iptr = md->offset_vector + offset_top; register int *iend = md->offset_vector + offset; while (iptr < iend) *iptr++ = -1; offset_top = offset + 2; } } ecode += 1 + IMM2_SIZE; break; /* End of the pattern, either real or forced. */ case OP_END: case OP_ACCEPT: case OP_ASSERT_ACCEPT: /* If we have matched an empty string, fail if not in an assertion and not in a recursion if either PCRE_NOTEMPTY is set, or if PCRE_NOTEMPTY_ATSTART is set and we have matched at the start of the subject. In both cases, backtracking will then try other alternatives, if any. */ if (eptr == mstart && op != OP_ASSERT_ACCEPT && md->recursive == NULL && (md->notempty || (md->notempty_atstart && mstart == md->start_subject + md->start_offset))) RRETURN(MATCH_NOMATCH); /* Otherwise, we have a match. */ md->end_match_ptr = eptr; /* Record where we ended */ md->end_offset_top = offset_top; /* and how many extracts were taken */ md->start_match_ptr = mstart; /* and the start (\K can modify) */ /* For some reason, the macros don't work properly if an expression is given as the argument to RRETURN when the heap is in use. */ rrc = (op == OP_END)? MATCH_MATCH : MATCH_ACCEPT; RRETURN(rrc); /* Assertion brackets. Check the alternative branches in turn - the matching won't pass the KET for an assertion. If any one branch matches, the assertion is true. Lookbehind assertions have an OP_REVERSE item at the start of each branch to move the current point backwards, so the code at this level is identical to the lookahead case. When the assertion is part of a condition, we want to return immediately afterwards. The caller of this incarnation of the match() function will have set MATCH_CONDASSERT in md->match_function type, and one of these opcodes will be the first opcode that is processed. We use a local variable that is preserved over calls to match() to remember this case. */ case OP_ASSERT: case OP_ASSERTBACK: save_mark = md->mark; if (md->match_function_type == MATCH_CONDASSERT) { condassert = TRUE; md->match_function_type = 0; } else condassert = FALSE; /* Loop for each branch */ do { RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM4); /* A match means that the assertion is true; break out of the loop that matches its alternatives. */ if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) { mstart = md->start_match_ptr; /* In case \K reset it */ break; } /* If not matched, restore the previous mark setting. */ md->mark = save_mark; /* See comment in the code for capturing groups above about handling THEN. */ if (rrc == MATCH_THEN) { next = ecode + GET(ecode,1); if (md->start_match_ptr < next && (*ecode == OP_ALT || *next == OP_ALT)) rrc = MATCH_NOMATCH; } /* Anything other than NOMATCH causes the entire assertion to fail, passing back the return code. This includes COMMIT, SKIP, PRUNE and an uncaptured THEN, which means they take their normal effect. This consistent approach does not always have exactly the same effect as in Perl. */ if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode += GET(ecode, 1); } while (*ecode == OP_ALT); /* Continue for next alternative */ /* If we have tried all the alternative branches, the assertion has failed. If not, we broke out after a match. */ if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH); /* If checking an assertion for a condition, return MATCH_MATCH. */ if (condassert) RRETURN(MATCH_MATCH); /* Continue from after a successful assertion, updating the offsets high water mark, since extracts may have been taken during the assertion. */ do ecode += GET(ecode,1); while (*ecode == OP_ALT); ecode += 1 + LINK_SIZE; offset_top = md->end_offset_top; continue; /* Negative assertion: all branches must fail to match for the assertion to succeed. */ case OP_ASSERT_NOT: case OP_ASSERTBACK_NOT: save_mark = md->mark; if (md->match_function_type == MATCH_CONDASSERT) { condassert = TRUE; md->match_function_type = 0; } else condassert = FALSE; /* Loop for each alternative branch. */ do { RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM5); md->mark = save_mark; /* Always restore the mark setting */ switch(rrc) { case MATCH_MATCH: /* A successful match means */ case MATCH_ACCEPT: /* the assertion has failed. */ RRETURN(MATCH_NOMATCH); case MATCH_NOMATCH: /* Carry on with next branch */ break; /* See comment in the code for capturing groups above about handling THEN. */ case MATCH_THEN: next = ecode + GET(ecode,1); if (md->start_match_ptr < next && (*ecode == OP_ALT || *next == OP_ALT)) { rrc = MATCH_NOMATCH; break; } /* Otherwise fall through. */ /* COMMIT, SKIP, PRUNE, and an uncaptured THEN cause the whole assertion to fail to match, without considering any more alternatives. Failing to match means the assertion is true. This is a consistent approach, but does not always have the same effect as in Perl. */ case MATCH_COMMIT: case MATCH_SKIP: case MATCH_SKIP_ARG: case MATCH_PRUNE: do ecode += GET(ecode,1); while (*ecode == OP_ALT); goto NEG_ASSERT_TRUE; /* Break out of alternation loop */ /* Anything else is an error */ default: RRETURN(rrc); } /* Continue with next branch */ ecode += GET(ecode,1); } while (*ecode == OP_ALT); /* All branches in the assertion failed to match. */ NEG_ASSERT_TRUE: if (condassert) RRETURN(MATCH_MATCH); /* Condition assertion */ ecode += 1 + LINK_SIZE; /* Continue with current branch */ continue; /* Move the subject pointer back. This occurs only at the start of each branch of a lookbehind assertion. If we are too close to the start to move back, this match function fails. When working with UTF-8 we move back a number of characters, not bytes. */ case OP_REVERSE: #ifdef SUPPORT_UTF if (utf) { i = GET(ecode, 1); while (i-- > 0) { eptr--; if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); BACKCHAR(eptr); } } else #endif /* No UTF-8 support, or not in UTF-8 mode: count is byte count */ { eptr -= GET(ecode, 1); if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH); } /* Save the earliest consulted character, then skip to next op code */ if (eptr < md->start_used_ptr) md->start_used_ptr = eptr; ecode += 1 + LINK_SIZE; break; /* The callout item calls an external function, if one is provided, passing details of the match so far. This is mainly for debugging, though the function is able to force a failure. */ case OP_CALLOUT: if (PUBL(callout) != NULL) { PUBL(callout_block) cb; cb.version = 2; /* Version 1 of the callout block */ cb.callout_number = ecode[1]; cb.offset_vector = md->offset_vector; #if defined COMPILE_PCRE8 cb.subject = (PCRE_SPTR)md->start_subject; #elif defined COMPILE_PCRE16 cb.subject = (PCRE_SPTR16)md->start_subject; #elif defined COMPILE_PCRE32 cb.subject = (PCRE_SPTR32)md->start_subject; #endif cb.subject_length = (int)(md->end_subject - md->start_subject); cb.start_match = (int)(mstart - md->start_subject); cb.current_position = (int)(eptr - md->start_subject); cb.pattern_position = GET(ecode, 2); cb.next_item_length = GET(ecode, 2 + LINK_SIZE); cb.capture_top = offset_top/2; cb.capture_last = md->capture_last & CAPLMASK; /* Internal change requires this for API compatibility. */ if (cb.capture_last == 0) cb.capture_last = -1; cb.callout_data = md->callout_data; cb.mark = md->nomatch_mark; if ((rrc = (*PUBL(callout))(&cb)) > 0) RRETURN(MATCH_NOMATCH); if (rrc < 0) RRETURN(rrc); } ecode += 2 + 2*LINK_SIZE; break; /* Recursion either matches the current regex, or some subexpression. The offset data is the offset to the starting bracket from the start of the whole pattern. (This is so that it works from duplicated subpatterns.) The state of the capturing groups is preserved over recursion, and re-instated afterwards. We don't know how many are started and not yet finished (offset_top records the completed total) so we just have to save all the potential data. There may be up to 65535 such values, which is too large to put on the stack, but using malloc for small numbers seems expensive. As a compromise, the stack is used when there are no more than REC_STACK_SAVE_MAX values to store; otherwise malloc is used. There are also other values that have to be saved. We use a chained sequence of blocks that actually live on the stack. Thanks to Robin Houston for the original version of this logic. It has, however, been hacked around a lot, so he is not to blame for the current way it works. */ case OP_RECURSE: { recursion_info *ri; unsigned int recno; callpat = md->start_code + GET(ecode, 1); recno = (callpat == md->start_code)? 0 : GET2(callpat, 1 + LINK_SIZE); /* Check for repeating a recursion without advancing the subject pointer. This should catch convoluted mutual recursions. (Some simple cases are caught at compile time.) */ for (ri = md->recursive; ri != NULL; ri = ri->prevrec) if (recno == ri->group_num && eptr == ri->subject_position) RRETURN(PCRE_ERROR_RECURSELOOP); /* Add to "recursing stack" */ new_recursive.group_num = recno; new_recursive.saved_capture_last = md->capture_last; new_recursive.subject_position = eptr; new_recursive.prevrec = md->recursive; md->recursive = &new_recursive; /* Where to continue from afterwards */ ecode += 1 + LINK_SIZE; /* Now save the offset data */ new_recursive.saved_max = md->offset_end; if (new_recursive.saved_max <= REC_STACK_SAVE_MAX) new_recursive.offset_save = stacksave; else { new_recursive.offset_save = (int *)(PUBL(malloc))(new_recursive.saved_max * sizeof(int)); if (new_recursive.offset_save == NULL) RRETURN(PCRE_ERROR_NOMEMORY); } memcpy(new_recursive.offset_save, md->offset_vector, new_recursive.saved_max * sizeof(int)); /* OK, now we can do the recursion. After processing each alternative, restore the offset data and the last captured value. If there were nested recursions, md->recursive might be changed, so reset it before looping. */ DPRINTF(("Recursing into group %d\n", new_recursive.group_num)); cbegroup = (*callpat >= OP_SBRA); do { if (cbegroup) md->match_function_type = MATCH_CBEGROUP; RMATCH(eptr, callpat + PRIV(OP_lengths)[*callpat], offset_top, md, eptrb, RM6); memcpy(md->offset_vector, new_recursive.offset_save, new_recursive.saved_max * sizeof(int)); md->capture_last = new_recursive.saved_capture_last; md->recursive = new_recursive.prevrec; if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) { DPRINTF(("Recursion matched\n")); if (new_recursive.offset_save != stacksave) (PUBL(free))(new_recursive.offset_save); /* Set where we got to in the subject, and reset the start in case it was changed by \K. This *is* propagated back out of a recursion, for Perl compatibility. */ eptr = md->end_match_ptr; mstart = md->start_match_ptr; goto RECURSION_MATCHED; /* Exit loop; end processing */ } /* PCRE does not allow THEN, SKIP, PRUNE or COMMIT to escape beyond a recursion; they cause a NOMATCH for the entire recursion. These codes are defined in a range that can be tested for. */ if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX) { if (new_recursive.offset_save != stacksave) (PUBL(free))(new_recursive.offset_save); RRETURN(MATCH_NOMATCH); } /* Any return code other than NOMATCH is an error. */ if (rrc != MATCH_NOMATCH) { DPRINTF(("Recursion gave error %d\n", rrc)); if (new_recursive.offset_save != stacksave) (PUBL(free))(new_recursive.offset_save); RRETURN(rrc); } md->recursive = &new_recursive; callpat += GET(callpat, 1); } while (*callpat == OP_ALT); DPRINTF(("Recursion didn't match\n")); md->recursive = new_recursive.prevrec; if (new_recursive.offset_save != stacksave) (PUBL(free))(new_recursive.offset_save); RRETURN(MATCH_NOMATCH); } RECURSION_MATCHED: break; /* An alternation is the end of a branch; scan along to find the end of the bracketed group and go to there. */ case OP_ALT: do ecode += GET(ecode,1); while (*ecode == OP_ALT); break; /* BRAZERO, BRAMINZERO and SKIPZERO occur just before a bracket group, indicating that it may occur zero times. It may repeat infinitely, or not at all - i.e. it could be ()* or ()? or even (){0} in the pattern. Brackets with fixed upper repeat limits are compiled as a number of copies, with the optional ones preceded by BRAZERO or BRAMINZERO. */ case OP_BRAZERO: next = ecode + 1; RMATCH(eptr, next, offset_top, md, eptrb, RM10); if (rrc != MATCH_NOMATCH) RRETURN(rrc); do next += GET(next, 1); while (*next == OP_ALT); ecode = next + 1 + LINK_SIZE; break; case OP_BRAMINZERO: next = ecode + 1; do next += GET(next, 1); while (*next == OP_ALT); RMATCH(eptr, next + 1+LINK_SIZE, offset_top, md, eptrb, RM11); if (rrc != MATCH_NOMATCH) RRETURN(rrc); ecode++; break; case OP_SKIPZERO: next = ecode+1; do next += GET(next,1); while (*next == OP_ALT); ecode = next + 1 + LINK_SIZE; break; /* BRAPOSZERO occurs before a possessive bracket group. Don't do anything here; just jump to the group, with allow_zero set TRUE. */ case OP_BRAPOSZERO: op = *(++ecode); allow_zero = TRUE; if (op == OP_CBRAPOS || op == OP_SCBRAPOS) goto POSSESSIVE_CAPTURE; goto POSSESSIVE_NON_CAPTURE; /* End of a group, repeated or non-repeating. */ case OP_KET: case OP_KETRMIN: case OP_KETRMAX: case OP_KETRPOS: prev = ecode - GET(ecode, 1); /* If this was a group that remembered the subject start, in order to break infinite repeats of empty string matches, retrieve the subject start from the chain. Otherwise, set it NULL. */ if (*prev >= OP_SBRA || *prev == OP_ONCE) { saved_eptr = eptrb->epb_saved_eptr; /* Value at start of group */ eptrb = eptrb->epb_prev; /* Backup to previous group */ } else saved_eptr = NULL; /* If we are at the end of an assertion group or a non-capturing atomic group, stop matching and return MATCH_MATCH, but record the current high water mark for use by positive assertions. We also need to record the match start in case it was changed by \K. */ if ((*prev >= OP_ASSERT && *prev <= OP_ASSERTBACK_NOT) || *prev == OP_ONCE_NC) { md->end_match_ptr = eptr; /* For ONCE_NC */ md->end_offset_top = offset_top; md->start_match_ptr = mstart; RRETURN(MATCH_MATCH); /* Sets md->mark */ } /* For capturing groups we have to check the group number back at the start and if necessary complete handling an extraction by setting the offsets and bumping the high water mark. Whole-pattern recursion is coded as a recurse into group 0, so it won't be picked up here. Instead, we catch it when the OP_END is reached. Other recursion is handled here. We just have to record the current subject position and start match pointer and give a MATCH return. */ if (*prev == OP_CBRA || *prev == OP_SCBRA || *prev == OP_CBRAPOS || *prev == OP_SCBRAPOS) { number = GET2(prev, 1+LINK_SIZE); offset = number << 1; #ifdef PCRE_DEBUG printf("end bracket %d", number); printf("\n"); #endif /* Handle a recursively called group. */ if (md->recursive != NULL && md->recursive->group_num == number) { md->end_match_ptr = eptr; md->start_match_ptr = mstart; RRETURN(MATCH_MATCH); } /* Deal with capturing */ md->capture_last = (md->capture_last & OVFLMASK) | number; if (offset >= md->offset_max) md->capture_last |= OVFLBIT; else { /* If offset is greater than offset_top, it means that we are "skipping" a capturing group, and that group's offsets must be marked unset. In earlier versions of PCRE, all the offsets were unset at the start of matching, but this doesn't work because atomic groups and assertions can cause a value to be set that should later be unset. Example: matching /(?>(a))b|(a)c/ against "ac". This sets group 1 as part of the atomic group, but this is not on the final matching path, so must be unset when 2 is set. (If there is no group 2, there is no problem, because offset_top will then be 2, indicating no capture.) */ if (offset > offset_top) { register int *iptr = md->offset_vector + offset_top; register int *iend = md->offset_vector + offset; while (iptr < iend) *iptr++ = -1; } /* Now make the extraction */ md->offset_vector[offset] = md->offset_vector[md->offset_end - number]; md->offset_vector[offset+1] = (int)(eptr - md->start_subject); if (offset_top <= offset) offset_top = offset + 2; } } /* OP_KETRPOS is a possessive repeating ket. Remember the current position, and return the MATCH_KETRPOS. This makes it possible to do the repeats one at a time from the outer level, thus saving stack. This must precede the empty string test - in this case that test is done at the outer level. */ if (*ecode == OP_KETRPOS) { md->start_match_ptr = mstart; /* In case \K reset it */ md->end_match_ptr = eptr; md->end_offset_top = offset_top; RRETURN(MATCH_KETRPOS); } /* For an ordinary non-repeating ket, just continue at this level. This also happens for a repeating ket if no characters were matched in the group. This is the forcible breaking of infinite loops as implemented in Perl 5.005. For a non-repeating atomic group that includes captures, establish a backup point by processing the rest of the pattern at a lower level. If this results in a NOMATCH return, pass MATCH_ONCE back to the original OP_ONCE level, thereby bypassing intermediate backup points, but resetting any captures that happened along the way. */ if (*ecode == OP_KET || eptr == saved_eptr) { if (*prev == OP_ONCE) { RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM12); if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->once_target = prev; /* Level at which to change to MATCH_NOMATCH */ RRETURN(MATCH_ONCE); } ecode += 1 + LINK_SIZE; /* Carry on at this level */ break; } /* The normal repeating kets try the rest of the pattern or restart from the preceding bracket, in the appropriate order. In the second case, we can use tail recursion to avoid using another stack frame, unless we have an an atomic group or an unlimited repeat of a group that can match an empty string. */ if (*ecode == OP_KETRMIN) { RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM7); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (*prev == OP_ONCE) { RMATCH(eptr, prev, offset_top, md, eptrb, RM8); if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->once_target = prev; /* Level at which to change to MATCH_NOMATCH */ RRETURN(MATCH_ONCE); } if (*prev >= OP_SBRA) /* Could match an empty string */ { RMATCH(eptr, prev, offset_top, md, eptrb, RM50); RRETURN(rrc); } ecode = prev; goto TAIL_RECURSE; } else /* OP_KETRMAX */ { RMATCH(eptr, prev, offset_top, md, eptrb, RM13); if (rrc == MATCH_ONCE && md->once_target == prev) rrc = MATCH_NOMATCH; if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (*prev == OP_ONCE) { RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM9); if (rrc != MATCH_NOMATCH) RRETURN(rrc); md->once_target = prev; RRETURN(MATCH_ONCE); } ecode += 1 + LINK_SIZE; goto TAIL_RECURSE; } /* Control never gets here */ /* Not multiline mode: start of subject assertion, unless notbol. */ case OP_CIRC: if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH); /* Start of subject assertion */ case OP_SOD: if (eptr != md->start_subject) RRETURN(MATCH_NOMATCH); ecode++; break; /* Multiline mode: start of subject unless notbol, or after any newline. */ case OP_CIRCM: if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH); if (eptr != md->start_subject && (eptr == md->end_subject || !WAS_NEWLINE(eptr))) RRETURN(MATCH_NOMATCH); ecode++; break; /* Start of match assertion */ case OP_SOM: if (eptr != md->start_subject + md->start_offset) RRETURN(MATCH_NOMATCH); ecode++; break; /* Reset the start of match point */ case OP_SET_SOM: mstart = eptr; ecode++; break; /* Multiline mode: assert before any newline, or before end of subject unless noteol is set. */ case OP_DOLLM: if (eptr < md->end_subject) { if (!IS_NEWLINE(eptr)) { if (md->partial != 0 && eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && UCHAR21TEST(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } RRETURN(MATCH_NOMATCH); } } else { if (md->noteol) RRETURN(MATCH_NOMATCH); SCHECK_PARTIAL(); } ecode++; break; /* Not multiline mode: assert before a terminating newline or before end of subject unless noteol is set. */ case OP_DOLL: if (md->noteol) RRETURN(MATCH_NOMATCH); if (!md->endonly) goto ASSERT_NL_OR_EOS; /* ... else fall through for endonly */ /* End of subject assertion (\z) */ case OP_EOD: if (eptr < md->end_subject) RRETURN(MATCH_NOMATCH); SCHECK_PARTIAL(); ecode++; break; /* End of subject or ending \n assertion (\Z) */ case OP_EODN: ASSERT_NL_OR_EOS: if (eptr < md->end_subject && (!IS_NEWLINE(eptr) || eptr != md->end_subject - md->nllen)) { if (md->partial != 0 && eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && UCHAR21TEST(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } RRETURN(MATCH_NOMATCH); } /* Either at end of string or \n before end. */ SCHECK_PARTIAL(); ecode++; break; /* Word boundary assertions */ case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: { /* Find out if the previous and current characters are "word" characters. It takes a bit more work in UTF-8 mode. Characters > 255 are assumed to be "non-word" characters. Remember the earliest consulted character for partial matching. */ #ifdef SUPPORT_UTF if (utf) { /* Get status of previous character */ if (eptr == md->start_subject) prev_is_word = FALSE; else { PCRE_PUCHAR lastptr = eptr - 1; BACKCHAR(lastptr); if (lastptr < md->start_used_ptr) md->start_used_ptr = lastptr; GETCHAR(c, lastptr); #ifdef SUPPORT_UCP if (md->use_ucp) { if (c == '_') prev_is_word = TRUE; else { int cat = UCD_CATEGORY(c); prev_is_word = (cat == ucp_L || cat == ucp_N); } } else #endif prev_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0; } /* Get status of next character */ if (eptr >= md->end_subject) { SCHECK_PARTIAL(); cur_is_word = FALSE; } else { GETCHAR(c, eptr); #ifdef SUPPORT_UCP if (md->use_ucp) { if (c == '_') cur_is_word = TRUE; else { int cat = UCD_CATEGORY(c); cur_is_word = (cat == ucp_L || cat == ucp_N); } } else #endif cur_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0; } } else #endif /* Not in UTF-8 mode, but we may still have PCRE_UCP set, and for consistency with the behaviour of \w we do use it in this case. */ { /* Get status of previous character */ if (eptr == md->start_subject) prev_is_word = FALSE; else { if (eptr <= md->start_used_ptr) md->start_used_ptr = eptr - 1; #ifdef SUPPORT_UCP if (md->use_ucp) { c = eptr[-1]; if (c == '_') prev_is_word = TRUE; else { int cat = UCD_CATEGORY(c); prev_is_word = (cat == ucp_L || cat == ucp_N); } } else #endif prev_is_word = MAX_255(eptr[-1]) && ((md->ctypes[eptr[-1]] & ctype_word) != 0); } /* Get status of next character */ if (eptr >= md->end_subject) { SCHECK_PARTIAL(); cur_is_word = FALSE; } else #ifdef SUPPORT_UCP if (md->use_ucp) { c = *eptr; if (c == '_') cur_is_word = TRUE; else { int cat = UCD_CATEGORY(c); cur_is_word = (cat == ucp_L || cat == ucp_N); } } else #endif cur_is_word = MAX_255(*eptr) && ((md->ctypes[*eptr] & ctype_word) != 0); } /* Now see if the situation is what we want */ if ((*ecode++ == OP_WORD_BOUNDARY)? cur_is_word == prev_is_word : cur_is_word != prev_is_word) RRETURN(MATCH_NOMATCH); } break; /* Match any single character type except newline; have to take care with CRLF newlines and partial matching. */ case OP_ANY: if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); if (md->partial != 0 && eptr == md->end_subject - 1 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && UCHAR21TEST(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } /* Fall through */ /* Match any single character whatsoever. */ case OP_ALLANY: if (eptr >= md->end_subject) /* DO NOT merge the eptr++ here; it must */ { /* not be updated before SCHECK_PARTIAL. */ SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } eptr++; #ifdef SUPPORT_UTF if (utf) ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++); #endif ecode++; break; /* Match a single byte, even in UTF-8 mode. This opcode really does match any byte, even newline, independent of the setting of PCRE_DOTALL. */ case OP_ANYBYTE: if (eptr >= md->end_subject) /* DO NOT merge the eptr++ here; it must */ { /* not be updated before SCHECK_PARTIAL. */ SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } eptr++; ecode++; break; case OP_NOT_DIGIT: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ( #if defined SUPPORT_UTF || !(defined COMPILE_PCRE8) c < 256 && #endif (md->ctypes[c] & ctype_digit) != 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_DIGIT: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ( #if defined SUPPORT_UTF || !(defined COMPILE_PCRE8) c > 255 || #endif (md->ctypes[c] & ctype_digit) == 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_NOT_WHITESPACE: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ( #if defined SUPPORT_UTF || !(defined COMPILE_PCRE8) c < 256 && #endif (md->ctypes[c] & ctype_space) != 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_WHITESPACE: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ( #if defined SUPPORT_UTF || !(defined COMPILE_PCRE8) c > 255 || #endif (md->ctypes[c] & ctype_space) == 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_NOT_WORDCHAR: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ( #if defined SUPPORT_UTF || !(defined COMPILE_PCRE8) c < 256 && #endif (md->ctypes[c] & ctype_word) != 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_WORDCHAR: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ( #if defined SUPPORT_UTF || !(defined COMPILE_PCRE8) c > 255 || #endif (md->ctypes[c] & ctype_word) == 0 ) RRETURN(MATCH_NOMATCH); ecode++; break; case OP_ANYNL: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); switch(c) { default: RRETURN(MATCH_NOMATCH); case CHAR_CR: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); } else if (UCHAR21TEST(eptr) == CHAR_LF) eptr++; break; case CHAR_LF: break; case CHAR_VT: case CHAR_FF: case CHAR_NEL: #ifndef EBCDIC case 0x2028: case 0x2029: #endif /* Not EBCDIC */ if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } ecode++; break; case OP_NOT_HSPACE: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); switch(c) { HSPACE_CASES: RRETURN(MATCH_NOMATCH); /* Byte and multibyte cases */ default: break; } ecode++; break; case OP_HSPACE: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); switch(c) { HSPACE_CASES: break; /* Byte and multibyte cases */ default: RRETURN(MATCH_NOMATCH); } ecode++; break; case OP_NOT_VSPACE: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); switch(c) { VSPACE_CASES: RRETURN(MATCH_NOMATCH); default: break; } ecode++; break; case OP_VSPACE: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); switch(c) { VSPACE_CASES: break; default: RRETURN(MATCH_NOMATCH); } ecode++; break; #ifdef SUPPORT_UCP /* Check the next character by Unicode property. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ case OP_PROP: case OP_NOTPROP: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); { const pcre_uint32 *cp; const ucd_record *prop = GET_UCD(c); switch(ecode[1]) { case PT_ANY: if (op == OP_NOTPROP) RRETURN(MATCH_NOMATCH); break; case PT_LAMP: if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt) == (op == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; case PT_GC: if ((ecode[2] != PRIV(ucp_gentype)[prop->chartype]) == (op == OP_PROP)) RRETURN(MATCH_NOMATCH); break; case PT_PC: if ((ecode[2] != prop->chartype) == (op == OP_PROP)) RRETURN(MATCH_NOMATCH); break; case PT_SC: if ((ecode[2] != prop->script) == (op == OP_PROP)) RRETURN(MATCH_NOMATCH); break; /* These are specials */ case PT_ALNUM: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N) == (op == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ switch(c) { HSPACE_CASES: VSPACE_CASES: if (op == OP_NOTPROP) RRETURN(MATCH_NOMATCH); break; default: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == (op == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; } break; case PT_WORD: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE) == (op == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; case PT_CLIST: cp = PRIV(ucd_caseless_sets) + ecode[2]; for (;;) { if (c < *cp) { if (op == OP_PROP) { RRETURN(MATCH_NOMATCH); } else break; } if (c == *cp++) { if (op == OP_PROP) break; else { RRETURN(MATCH_NOMATCH); } } } break; case PT_UCNC: if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || c >= 0xe000) == (op == OP_NOTPROP)) RRETURN(MATCH_NOMATCH); break; /* This should never occur */ default: RRETURN(PCRE_ERROR_INTERNAL); } ecode += 3; } break; /* Match an extended Unicode sequence. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ case OP_EXTUNI: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } else { int lgb, rgb; GETCHARINCTEST(c, eptr); lgb = UCD_GRAPHBREAK(c); while (eptr < md->end_subject) { int len = 1; if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } rgb = UCD_GRAPHBREAK(c); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; lgb = rgb; eptr += len; } } CHECK_PARTIAL(); ecode++; break; #endif /* SUPPORT_UCP */ /* Match a back reference, possibly repeatedly. Look past the end of the item to see if there is repeat information following. The code is similar to that for character classes, but repeated for efficiency. Then obey similar code to character type repeats - written out again for speed. However, if the referenced string is the empty string, always treat it as matched, any number of times (otherwise there could be infinite loops). If the reference is unset, there are two possibilities: (a) In the default, Perl-compatible state, set the length negative; this ensures that every attempt at a match fails. We can't just fail here, because of the possibility of quantifiers with zero minima. (b) If the JavaScript compatibility flag is set, set the length to zero so that the back reference matches an empty string. Otherwise, set the length to the length of what was matched by the referenced subpattern. The OP_REF and OP_REFI opcodes are used for a reference to a numbered group or to a non-duplicated named group. For a duplicated named group, OP_DNREF and OP_DNREFI are used. In this case we must scan the list of groups to which the name refers, and use the first one that is set. */ case OP_DNREF: case OP_DNREFI: caseless = op == OP_DNREFI; { int count = GET2(ecode, 1+IMM2_SIZE); pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size; ecode += 1 + 2*IMM2_SIZE; /* Setting the default length first and initializing 'offset' avoids compiler warnings in the REF_REPEAT code. */ length = (md->jscript_compat)? 0 : -1; offset = 0; while (count-- > 0) { offset = GET2(slot, 0) << 1; if (offset < offset_top && md->offset_vector[offset] >= 0) { length = md->offset_vector[offset+1] - md->offset_vector[offset]; break; } slot += md->name_entry_size; } } goto REF_REPEAT; case OP_REF: case OP_REFI: caseless = op == OP_REFI; offset = GET2(ecode, 1) << 1; /* Doubled ref number */ ecode += 1 + IMM2_SIZE; if (offset >= offset_top || md->offset_vector[offset] < 0) length = (md->jscript_compat)? 0 : -1; else length = md->offset_vector[offset+1] - md->offset_vector[offset]; /* Set up for repetition, or handle the non-repeated case */ REF_REPEAT: switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: c = *ecode++ - OP_CRSTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; break; case OP_CRRANGE: case OP_CRMINRANGE: minimize = (*ecode == OP_CRMINRANGE); min = GET2(ecode, 1); max = GET2(ecode, 1 + IMM2_SIZE); if (max == 0) max = INT_MAX; ecode += 1 + 2 * IMM2_SIZE; break; default: /* No repeat follows */ if ((length = match_ref(offset, eptr, length, md, caseless)) < 0) { if (length == -2) eptr = md->end_subject; /* Partial match */ CHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } eptr += length; continue; /* With the main loop */ } /* Handle repeated back references. If the length of the reference is zero, just continue with the main loop. If the length is negative, it means the reference is unset in non-Java-compatible mode. If the minimum is zero, we can continue at the same level without recursion. For any other minimum, carrying on will result in NOMATCH. */ if (length == 0) continue; if (length < 0 && min == 0) continue; /* First, ensure the minimum number of matches are present. We get back the length of the reference string explicitly rather than passing the address of eptr, so that eptr can be a register variable. */ for (i = 1; i <= min; i++) { int slength; if ((slength = match_ref(offset, eptr, length, md, caseless)) < 0) { if (slength == -2) eptr = md->end_subject; /* Partial match */ CHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } eptr += slength; } /* If min = max, continue at the same level without recursion. They are not both allowed to be zero. */ if (min == max) continue; /* If minimizing, keep trying and advancing the pointer */ if (minimize) { for (fi = min;; fi++) { int slength; RMATCH(eptr, ecode, offset_top, md, eptrb, RM14); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if ((slength = match_ref(offset, eptr, length, md, caseless)) < 0) { if (slength == -2) eptr = md->end_subject; /* Partial match */ CHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } eptr += slength; } /* Control never gets here */ } /* If maximizing, find the longest string and work backwards */ else { pp = eptr; for (i = min; i < max; i++) { int slength; if ((slength = match_ref(offset, eptr, length, md, caseless)) < 0) { /* Can't use CHECK_PARTIAL because we don't want to update eptr in the soft partial matching case. */ if (slength == -2 && md->partial != 0 && md->end_subject > md->start_used_ptr) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } break; } eptr += slength; } while (eptr >= pp) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM15); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr -= length; } RRETURN(MATCH_NOMATCH); } /* Control never gets here */ /* Match a bit-mapped character class, possibly repeatedly. This op code is used when all the characters in the class have values in the range 0-255, and either the matching is caseful, or the characters are in the range 0-127 when UTF-8 processing is enabled. The only difference between OP_CLASS and OP_NCLASS occurs when a data character outside the range is encountered. First, look past the end of the item to see if there is repeat information following. Then obey similar code to character type repeats - written out again for speed. */ case OP_NCLASS: case OP_CLASS: { /* The data variable is saved across frames, so the byte map needs to be stored there. */ #define BYTE_MAP ((pcre_uint8 *)data) data = ecode + 1; /* Save for matching */ ecode += 1 + (32 / sizeof(pcre_uchar)); /* Advance past the item */ switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSSTAR: case OP_CRPOSPLUS: case OP_CRPOSQUERY: c = *ecode++ - OP_CRSTAR; if (c < OP_CRPOSSTAR - OP_CRSTAR) minimize = (c & 1) != 0; else possessive = TRUE; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; break; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: minimize = (*ecode == OP_CRMINRANGE); possessive = (*ecode == OP_CRPOSRANGE); min = GET2(ecode, 1); max = GET2(ecode, 1 + IMM2_SIZE); if (max == 0) max = INT_MAX; ecode += 1 + 2 * IMM2_SIZE; break; default: /* No repeat follows */ min = max = 1; break; } /* First, ensure the minimum number of matches are present. */ #ifdef SUPPORT_UTF if (utf) { for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(c, eptr); if (c > 255) { if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); } else if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); } } else #endif /* Not UTF mode */ { for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } c = *eptr++; #ifndef COMPILE_PCRE8 if (c > 255) { if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); } else #endif if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); } } /* If max == min we can continue with the main loop without the need to recurse. */ if (min == max) continue; /* If minimizing, keep testing the rest of the expression and advancing the pointer while it matches the class. */ if (minimize) { #ifdef SUPPORT_UTF if (utf) { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM16); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(c, eptr); if (c > 255) { if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); } else if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); } } else #endif /* Not UTF mode */ { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM17); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } c = *eptr++; #ifndef COMPILE_PCRE8 if (c > 255) { if (op == OP_CLASS) RRETURN(MATCH_NOMATCH); } else #endif if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ } /* If maximizing, find the longest possible run, then work backwards. */ else { pp = eptr; #ifdef SUPPORT_UTF if (utf) { for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); if (c > 255) { if (op == OP_CLASS) break; } else if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) break; eptr += len; } if (possessive) continue; /* No backtracking */ for (;;) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM18); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (eptr-- <= pp) break; /* Stop if tried at original pos */ BACKCHAR(eptr); } } else #endif /* Not UTF mode */ { for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } c = *eptr; #ifndef COMPILE_PCRE8 if (c > 255) { if (op == OP_CLASS) break; } else #endif if ((BYTE_MAP[c/8] & (1 << (c&7))) == 0) break; eptr++; } if (possessive) continue; /* No backtracking */ while (eptr >= pp) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM19); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; } } RRETURN(MATCH_NOMATCH); } #undef BYTE_MAP } /* Control never gets here */ /* Match an extended character class. In the 8-bit library, this opcode is encountered only when UTF-8 mode mode is supported. In the 16-bit and 32-bit libraries, codepoints greater than 255 may be encountered even when UTF is not supported. */ #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: { data = ecode + 1 + LINK_SIZE; /* Save for matching */ ecode += GET(ecode, 1); /* Advance past the item */ switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSSTAR: case OP_CRPOSPLUS: case OP_CRPOSQUERY: c = *ecode++ - OP_CRSTAR; if (c < OP_CRPOSSTAR - OP_CRSTAR) minimize = (c & 1) != 0; else possessive = TRUE; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; break; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: minimize = (*ecode == OP_CRMINRANGE); possessive = (*ecode == OP_CRPOSRANGE); min = GET2(ecode, 1); max = GET2(ecode, 1 + IMM2_SIZE); if (max == 0) max = INT_MAX; ecode += 1 + 2 * IMM2_SIZE; break; default: /* No repeat follows */ min = max = 1; break; } /* First, ensure the minimum number of matches are present. */ for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if (!PRIV(xclass)(c, data, utf)) RRETURN(MATCH_NOMATCH); } /* If max == min we can continue with the main loop without the need to recurse. */ if (min == max) continue; /* If minimizing, keep testing the rest of the expression and advancing the pointer while it matches the class. */ if (minimize) { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM20); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if (!PRIV(xclass)(c, data, utf)) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ } /* If maximizing, find the longest possible run, then work backwards. */ else { pp = eptr; for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } #ifdef SUPPORT_UTF GETCHARLENTEST(c, eptr, len); #else c = *eptr; #endif if (!PRIV(xclass)(c, data, utf)) break; eptr += len; } if (possessive) continue; /* No backtracking */ for(;;) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM21); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (eptr-- <= pp) break; /* Stop if tried at original pos */ #ifdef SUPPORT_UTF if (utf) BACKCHAR(eptr); #endif } RRETURN(MATCH_NOMATCH); } /* Control never gets here */ } #endif /* End of XCLASS */ /* Match a single character, casefully */ case OP_CHAR: #ifdef SUPPORT_UTF if (utf) { length = 1; ecode++; GETCHARLEN(fc, ecode, length); if (length > md->end_subject - eptr) { CHECK_PARTIAL(); /* Not SCHECK_PARTIAL() */ RRETURN(MATCH_NOMATCH); } while (length-- > 0) if (*ecode++ != UCHAR21INC(eptr)) RRETURN(MATCH_NOMATCH); } else #endif /* Not UTF mode */ { if (md->end_subject - eptr < 1) { SCHECK_PARTIAL(); /* This one can use SCHECK_PARTIAL() */ RRETURN(MATCH_NOMATCH); } if (ecode[1] != *eptr++) RRETURN(MATCH_NOMATCH); ecode += 2; } break; /* Match a single character, caselessly. If we are at the end of the subject, give up immediately. */ case OP_CHARI: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } #ifdef SUPPORT_UTF if (utf) { length = 1; ecode++; GETCHARLEN(fc, ecode, length); /* If the pattern character's value is < 128, we have only one byte, and we know that its other case must also be one byte long, so we can use the fast lookup table. We know that there is at least one byte left in the subject. */ if (fc < 128) { pcre_uint32 cc = UCHAR21(eptr); if (md->lcc[fc] != TABLE_GET(cc, md->lcc, cc)) RRETURN(MATCH_NOMATCH); ecode++; eptr++; } /* Otherwise we must pick up the subject character. Note that we cannot use the value of "length" to check for sufficient bytes left, because the other case of the character may have more or fewer bytes. */ else { pcre_uint32 dc; GETCHARINC(dc, eptr); ecode += length; /* If we have Unicode property support, we can use it to test the other case of the character, if there is one. */ if (fc != dc) { #ifdef SUPPORT_UCP if (dc != UCD_OTHERCASE(fc)) #endif RRETURN(MATCH_NOMATCH); } } } else #endif /* SUPPORT_UTF */ /* Not UTF mode */ { if (TABLE_GET(ecode[1], md->lcc, ecode[1]) != TABLE_GET(*eptr, md->lcc, *eptr)) RRETURN(MATCH_NOMATCH); eptr++; ecode += 2; } break; /* Match a single character repeatedly. */ case OP_EXACT: case OP_EXACTI: min = max = GET2(ecode, 1); ecode += 1 + IMM2_SIZE; goto REPEATCHAR; case OP_POSUPTO: case OP_POSUPTOI: possessive = TRUE; /* Fall through */ case OP_UPTO: case OP_UPTOI: case OP_MINUPTO: case OP_MINUPTOI: min = 0; max = GET2(ecode, 1); minimize = *ecode == OP_MINUPTO || *ecode == OP_MINUPTOI; ecode += 1 + IMM2_SIZE; goto REPEATCHAR; case OP_POSSTAR: case OP_POSSTARI: possessive = TRUE; min = 0; max = INT_MAX; ecode++; goto REPEATCHAR; case OP_POSPLUS: case OP_POSPLUSI: possessive = TRUE; min = 1; max = INT_MAX; ecode++; goto REPEATCHAR; case OP_POSQUERY: case OP_POSQUERYI: possessive = TRUE; min = 0; max = 1; ecode++; goto REPEATCHAR; case OP_STAR: case OP_STARI: case OP_MINSTAR: case OP_MINSTARI: case OP_PLUS: case OP_PLUSI: case OP_MINPLUS: case OP_MINPLUSI: case OP_QUERY: case OP_QUERYI: case OP_MINQUERY: case OP_MINQUERYI: c = *ecode++ - ((op < OP_STARI)? OP_STAR : OP_STARI); minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single-character matches. We first check for the minimum number of characters. If the minimum equals the maximum, we are done. Otherwise, if minimizing, check the rest of the pattern for a match; if there isn't one, advance up to the maximum, one character at a time. If maximizing, advance up to the maximum number of matching characters, until eptr is past the end of the maximum run. If possessive, we are then done (no backing up). Otherwise, match at this position; anything other than no match is immediately returned. For nomatch, back up one character, unless we are matching \R and the last thing matched was \r\n, in which case, back up two bytes. When we reach the first optional character position, we can save stack by doing a tail recurse. The various UTF/non-UTF and caseful/caseless cases are handled separately, for speed. */ REPEATCHAR: #ifdef SUPPORT_UTF if (utf) { length = 1; charptr = ecode; GETCHARLEN(fc, ecode, length); ecode += length; /* Handle multibyte character matching specially here. There is support for caseless matching if UCP support is present. */ if (length > 1) { #ifdef SUPPORT_UCP pcre_uint32 othercase; if (op >= OP_STARI && /* Caseless */ (othercase = UCD_OTHERCASE(fc)) != fc) oclength = PRIV(ord2utf)(othercase, occhars); else oclength = 0; #endif /* SUPPORT_UCP */ for (i = 1; i <= min; i++) { if (eptr <= md->end_subject - length && memcmp(eptr, charptr, IN_UCHARS(length)) == 0) eptr += length; #ifdef SUPPORT_UCP else if (oclength > 0 && eptr <= md->end_subject - oclength && memcmp(eptr, occhars, IN_UCHARS(oclength)) == 0) eptr += oclength; #endif /* SUPPORT_UCP */ else { CHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } } if (min == max) continue; if (minimize) { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM22); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr <= md->end_subject - length && memcmp(eptr, charptr, IN_UCHARS(length)) == 0) eptr += length; #ifdef SUPPORT_UCP else if (oclength > 0 && eptr <= md->end_subject - oclength && memcmp(eptr, occhars, IN_UCHARS(oclength)) == 0) eptr += oclength; #endif /* SUPPORT_UCP */ else { CHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ } else /* Maximize */ { pp = eptr; for (i = min; i < max; i++) { if (eptr <= md->end_subject - length && memcmp(eptr, charptr, IN_UCHARS(length)) == 0) eptr += length; #ifdef SUPPORT_UCP else if (oclength > 0 && eptr <= md->end_subject - oclength && memcmp(eptr, occhars, IN_UCHARS(oclength)) == 0) eptr += oclength; #endif /* SUPPORT_UCP */ else { CHECK_PARTIAL(); break; } } if (possessive) continue; /* No backtracking */ for(;;) { if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM23); if (rrc != MATCH_NOMATCH) RRETURN(rrc); #ifdef SUPPORT_UCP eptr--; BACKCHAR(eptr); #else /* without SUPPORT_UCP */ eptr -= length; #endif /* SUPPORT_UCP */ } } /* Control never gets here */ } /* If the length of a UTF-8 character is 1, we fall through here, and obey the code as for non-UTF-8 characters below, though in this case the value of fc will always be < 128. */ } else #endif /* SUPPORT_UTF */ /* When not in UTF-8 mode, load a single-byte character. */ fc = *ecode++; /* The value of fc at this point is always one character, though we may or may not be in UTF mode. The code is duplicated for the caseless and caseful cases, for speed, since matching characters is likely to be quite common. First, ensure the minimum number of matches are present. If min = max, continue at the same level without recursing. Otherwise, if minimizing, keep trying the rest of the expression and advancing one matching character if failing, up to the maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ DPRINTF(("matching %c{%d,%d} against subject %.*s\n", fc, min, max, max, (char *)eptr)); if (op >= OP_STARI) /* Caseless */ { #ifdef COMPILE_PCRE8 /* fc must be < 128 if UTF is enabled. */ foc = md->fcc[fc]; #else #ifdef SUPPORT_UTF #ifdef SUPPORT_UCP if (utf && fc > 127) foc = UCD_OTHERCASE(fc); #else if (utf && fc > 127) foc = fc; #endif /* SUPPORT_UCP */ else #endif /* SUPPORT_UTF */ foc = TABLE_GET(fc, md->fcc, fc); #endif /* COMPILE_PCRE8 */ for (i = 1; i <= min; i++) { pcre_uint32 cc; /* Faster than pcre_uchar */ if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } cc = UCHAR21TEST(eptr); if (fc != cc && foc != cc) RRETURN(MATCH_NOMATCH); eptr++; } if (min == max) continue; if (minimize) { for (fi = min;; fi++) { pcre_uint32 cc; /* Faster than pcre_uchar */ RMATCH(eptr, ecode, offset_top, md, eptrb, RM24); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } cc = UCHAR21TEST(eptr); if (fc != cc && foc != cc) RRETURN(MATCH_NOMATCH); eptr++; } /* Control never gets here */ } else /* Maximize */ { pp = eptr; for (i = min; i < max; i++) { pcre_uint32 cc; /* Faster than pcre_uchar */ if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } cc = UCHAR21TEST(eptr); if (fc != cc && foc != cc) break; eptr++; } if (possessive) continue; /* No backtracking */ for (;;) { if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM25); eptr--; if (rrc != MATCH_NOMATCH) RRETURN(rrc); } /* Control never gets here */ } } /* Caseful comparisons (includes all multi-byte characters) */ else { for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (fc != UCHAR21INCTEST(eptr)) RRETURN(MATCH_NOMATCH); } if (min == max) continue; if (minimize) { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM26); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (fc != UCHAR21INCTEST(eptr)) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ } else /* Maximize */ { pp = eptr; for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (fc != UCHAR21TEST(eptr)) break; eptr++; } if (possessive) continue; /* No backtracking */ for (;;) { if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM27); eptr--; if (rrc != MATCH_NOMATCH) RRETURN(rrc); } /* Control never gets here */ } } /* Control never gets here */ /* Match a negated single one-byte character. The character we are checking can be multibyte. */ case OP_NOT: case OP_NOTI: if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } #ifdef SUPPORT_UTF if (utf) { register pcre_uint32 ch, och; ecode++; GETCHARINC(ch, ecode); GETCHARINC(c, eptr); if (op == OP_NOT) { if (ch == c) RRETURN(MATCH_NOMATCH); } else { #ifdef SUPPORT_UCP if (ch > 127) och = UCD_OTHERCASE(ch); #else if (ch > 127) och = ch; #endif /* SUPPORT_UCP */ else och = TABLE_GET(ch, md->fcc, ch); if (ch == c || och == c) RRETURN(MATCH_NOMATCH); } } else #endif { register pcre_uint32 ch = ecode[1]; c = *eptr++; if (ch == c || (op == OP_NOTI && TABLE_GET(ch, md->fcc, ch) == c)) RRETURN(MATCH_NOMATCH); ecode += 2; } break; /* Match a negated single one-byte character repeatedly. This is almost a repeat of the code for a repeated single character, but I haven't found a nice way of commoning these up that doesn't require a test of the positive/negative option for each character match. Maybe that wouldn't add very much to the time taken, but character matching *is* what this is all about... */ case OP_NOTEXACT: case OP_NOTEXACTI: min = max = GET2(ecode, 1); ecode += 1 + IMM2_SIZE; goto REPEATNOTCHAR; case OP_NOTUPTO: case OP_NOTUPTOI: case OP_NOTMINUPTO: case OP_NOTMINUPTOI: min = 0; max = GET2(ecode, 1); minimize = *ecode == OP_NOTMINUPTO || *ecode == OP_NOTMINUPTOI; ecode += 1 + IMM2_SIZE; goto REPEATNOTCHAR; case OP_NOTPOSSTAR: case OP_NOTPOSSTARI: possessive = TRUE; min = 0; max = INT_MAX; ecode++; goto REPEATNOTCHAR; case OP_NOTPOSPLUS: case OP_NOTPOSPLUSI: possessive = TRUE; min = 1; max = INT_MAX; ecode++; goto REPEATNOTCHAR; case OP_NOTPOSQUERY: case OP_NOTPOSQUERYI: possessive = TRUE; min = 0; max = 1; ecode++; goto REPEATNOTCHAR; case OP_NOTPOSUPTO: case OP_NOTPOSUPTOI: possessive = TRUE; min = 0; max = GET2(ecode, 1); ecode += 1 + IMM2_SIZE; goto REPEATNOTCHAR; case OP_NOTSTAR: case OP_NOTSTARI: case OP_NOTMINSTAR: case OP_NOTMINSTARI: case OP_NOTPLUS: case OP_NOTPLUSI: case OP_NOTMINPLUS: case OP_NOTMINPLUSI: case OP_NOTQUERY: case OP_NOTQUERYI: case OP_NOTMINQUERY: case OP_NOTMINQUERYI: c = *ecode++ - ((op >= OP_NOTSTARI)? OP_NOTSTARI: OP_NOTSTAR); minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single-byte matches. */ REPEATNOTCHAR: GETCHARINCTEST(fc, ecode); /* The code is duplicated for the caseless and caseful cases, for speed, since matching characters is likely to be quite common. First, ensure the minimum number of matches are present. If min = max, continue at the same level without recursing. Otherwise, if minimizing, keep trying the rest of the expression and advancing one matching character if failing, up to the maximum. Alternatively, if maximizing, find the maximum number of characters and work backwards. */ DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", fc, min, max, max, (char *)eptr)); if (op >= OP_NOTSTARI) /* Caseless */ { #ifdef SUPPORT_UTF #ifdef SUPPORT_UCP if (utf && fc > 127) foc = UCD_OTHERCASE(fc); #else if (utf && fc > 127) foc = fc; #endif /* SUPPORT_UCP */ else #endif /* SUPPORT_UTF */ foc = TABLE_GET(fc, md->fcc, fc); #ifdef SUPPORT_UTF if (utf) { register pcre_uint32 d; for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(d, eptr); if (fc == d || (unsigned int)foc == d) RRETURN(MATCH_NOMATCH); } } else #endif /* SUPPORT_UTF */ /* Not UTF mode */ { for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (fc == *eptr || foc == *eptr) RRETURN(MATCH_NOMATCH); eptr++; } } if (min == max) continue; if (minimize) { #ifdef SUPPORT_UTF if (utf) { register pcre_uint32 d; for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM28); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(d, eptr); if (fc == d || (unsigned int)foc == d) RRETURN(MATCH_NOMATCH); } } else #endif /*SUPPORT_UTF */ /* Not UTF mode */ { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM29); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (fc == *eptr || foc == *eptr) RRETURN(MATCH_NOMATCH); eptr++; } } /* Control never gets here */ } /* Maximize case */ else { pp = eptr; #ifdef SUPPORT_UTF if (utf) { register pcre_uint32 d; for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(d, eptr, len); if (fc == d || (unsigned int)foc == d) break; eptr += len; } if (possessive) continue; /* No backtracking */ for(;;) { if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM30); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; BACKCHAR(eptr); } } else #endif /* SUPPORT_UTF */ /* Not UTF mode */ { for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (fc == *eptr || foc == *eptr) break; eptr++; } if (possessive) continue; /* No backtracking */ for (;;) { if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM31); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; } } /* Control never gets here */ } } /* Caseful comparisons */ else { #ifdef SUPPORT_UTF if (utf) { register pcre_uint32 d; for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(d, eptr); if (fc == d) RRETURN(MATCH_NOMATCH); } } else #endif /* Not UTF mode */ { for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (fc == *eptr++) RRETURN(MATCH_NOMATCH); } } if (min == max) continue; if (minimize) { #ifdef SUPPORT_UTF if (utf) { register pcre_uint32 d; for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM32); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(d, eptr); if (fc == d) RRETURN(MATCH_NOMATCH); } } else #endif /* Not UTF mode */ { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM33); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (fc == *eptr++) RRETURN(MATCH_NOMATCH); } } /* Control never gets here */ } /* Maximize case */ else { pp = eptr; #ifdef SUPPORT_UTF if (utf) { register pcre_uint32 d; for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(d, eptr, len); if (fc == d) break; eptr += len; } if (possessive) continue; /* No backtracking */ for(;;) { if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM34); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; BACKCHAR(eptr); } } else #endif /* Not UTF mode */ { for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (fc == *eptr) break; eptr++; } if (possessive) continue; /* No backtracking */ for (;;) { if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM35); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; } } /* Control never gets here */ } } /* Control never gets here */ /* Match a single character type repeatedly; several different opcodes share code. This is very similar to the code for single characters, but we repeat it in the interests of efficiency. */ case OP_TYPEEXACT: min = max = GET2(ecode, 1); minimize = TRUE; ecode += 1 + IMM2_SIZE; goto REPEATTYPE; case OP_TYPEUPTO: case OP_TYPEMINUPTO: min = 0; max = GET2(ecode, 1); minimize = *ecode == OP_TYPEMINUPTO; ecode += 1 + IMM2_SIZE; goto REPEATTYPE; case OP_TYPEPOSSTAR: possessive = TRUE; min = 0; max = INT_MAX; ecode++; goto REPEATTYPE; case OP_TYPEPOSPLUS: possessive = TRUE; min = 1; max = INT_MAX; ecode++; goto REPEATTYPE; case OP_TYPEPOSQUERY: possessive = TRUE; min = 0; max = 1; ecode++; goto REPEATTYPE; case OP_TYPEPOSUPTO: possessive = TRUE; min = 0; max = GET2(ecode, 1); ecode += 1 + IMM2_SIZE; goto REPEATTYPE; case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: c = *ecode++ - OP_TYPESTAR; minimize = (c & 1) != 0; min = rep_min[c]; /* Pick up values from tables; */ max = rep_max[c]; /* zero for max => infinity */ if (max == 0) max = INT_MAX; /* Common code for all repeated single character type matches. Note that in UTF-8 mode, '.' matches a character of any length, but for the other character types, the valid characters are all one-byte long. */ REPEATTYPE: ctype = *ecode++; /* Code for the character type */ #ifdef SUPPORT_UCP if (ctype == OP_PROP || ctype == OP_NOTPROP) { prop_fail_result = ctype == OP_NOTPROP; prop_type = *ecode++; prop_value = *ecode++; } else prop_type = -1; #endif /* First, ensure the minimum number of matches are present. Use inline code for maximizing the speed, and do the type test once at the start (i.e. keep it out of the loop). Separate the UTF-8 code completely as that is tidier. Also separate the UCP code, which can be the same for both UTF-8 and single-bytes. */ if (min > 0) { #ifdef SUPPORT_UCP if (prop_type >= 0) { switch(prop_type) { case PT_ANY: if (prop_fail_result) RRETURN(MATCH_NOMATCH); for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); } break; case PT_LAMP: for (i = 1; i <= min; i++) { int chartype; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); chartype = UCD_CHARTYPE(c); if ((chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt) == prop_fail_result) RRETURN(MATCH_NOMATCH); } break; case PT_GC: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ((UCD_CATEGORY(c) == prop_value) == prop_fail_result) RRETURN(MATCH_NOMATCH); } break; case PT_PC: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ((UCD_CHARTYPE(c) == prop_value) == prop_fail_result) RRETURN(MATCH_NOMATCH); } break; case PT_SC: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ((UCD_SCRIPT(c) == prop_value) == prop_fail_result) RRETURN(MATCH_NOMATCH); } break; case PT_ALNUM: for (i = 1; i <= min; i++) { int category; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); category = UCD_CATEGORY(c); if ((category == ucp_L || category == ucp_N) == prop_fail_result) RRETURN(MATCH_NOMATCH); } break; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); switch(c) { HSPACE_CASES: VSPACE_CASES: if (prop_fail_result) RRETURN(MATCH_NOMATCH); break; default: if ((UCD_CATEGORY(c) == ucp_Z) == prop_fail_result) RRETURN(MATCH_NOMATCH); break; } } break; case PT_WORD: for (i = 1; i <= min; i++) { int category; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); category = UCD_CATEGORY(c); if ((category == ucp_L || category == ucp_N || c == CHAR_UNDERSCORE) == prop_fail_result) RRETURN(MATCH_NOMATCH); } break; case PT_CLIST: for (i = 1; i <= min; i++) { const pcre_uint32 *cp; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); cp = PRIV(ucd_caseless_sets) + prop_value; for (;;) { if (c < *cp) { if (prop_fail_result) break; else { RRETURN(MATCH_NOMATCH); } } if (c == *cp++) { if (prop_fail_result) { RRETURN(MATCH_NOMATCH); } else break; } } } break; case PT_UCNC: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || c >= 0xe000) == prop_fail_result) RRETURN(MATCH_NOMATCH); } break; /* This should not occur */ default: RRETURN(PCRE_ERROR_INTERNAL); } } /* Match extended Unicode sequences. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ else if (ctype == OP_EXTUNI) { for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } else { int lgb, rgb; GETCHARINCTEST(c, eptr); lgb = UCD_GRAPHBREAK(c); while (eptr < md->end_subject) { int len = 1; if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } rgb = UCD_GRAPHBREAK(c); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; lgb = rgb; eptr += len; } } CHECK_PARTIAL(); } } else #endif /* SUPPORT_UCP */ /* Handle all other cases when the coding is UTF-8 */ #ifdef SUPPORT_UTF if (utf) switch(ctype) { case OP_ANY: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); if (md->partial != 0 && eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && UCHAR21(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } eptr++; ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++); } break; case OP_ALLANY: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } eptr++; ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++); } break; case OP_ANYBYTE: if (eptr > md->end_subject - min) RRETURN(MATCH_NOMATCH); eptr += min; break; case OP_ANYNL: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(c, eptr); switch(c) { default: RRETURN(MATCH_NOMATCH); case CHAR_CR: if (eptr < md->end_subject && UCHAR21(eptr) == CHAR_LF) eptr++; break; case CHAR_LF: break; case CHAR_VT: case CHAR_FF: case CHAR_NEL: #ifndef EBCDIC case 0x2028: case 0x2029: #endif /* Not EBCDIC */ if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } } break; case OP_NOT_HSPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(c, eptr); switch(c) { HSPACE_CASES: RRETURN(MATCH_NOMATCH); /* Byte and multibyte cases */ default: break; } } break; case OP_HSPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(c, eptr); switch(c) { HSPACE_CASES: break; /* Byte and multibyte cases */ default: RRETURN(MATCH_NOMATCH); } } break; case OP_NOT_VSPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(c, eptr); switch(c) { VSPACE_CASES: RRETURN(MATCH_NOMATCH); default: break; } } break; case OP_VSPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(c, eptr); switch(c) { VSPACE_CASES: break; default: RRETURN(MATCH_NOMATCH); } } break; case OP_NOT_DIGIT: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINC(c, eptr); if (c < 128 && (md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); } break; case OP_DIGIT: for (i = 1; i <= min; i++) { pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } cc = UCHAR21(eptr); if (cc >= 128 || (md->ctypes[cc] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); eptr++; /* No need to skip more bytes - we know it's a 1-byte character */ } break; case OP_NOT_WHITESPACE: for (i = 1; i <= min; i++) { pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } cc = UCHAR21(eptr); if (cc < 128 && (md->ctypes[cc] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); eptr++; ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++); } break; case OP_WHITESPACE: for (i = 1; i <= min; i++) { pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } cc = UCHAR21(eptr); if (cc >= 128 || (md->ctypes[cc] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); eptr++; /* No need to skip more bytes - we know it's a 1-byte character */ } break; case OP_NOT_WORDCHAR: for (i = 1; i <= min; i++) { pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } cc = UCHAR21(eptr); if (cc < 128 && (md->ctypes[cc] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); eptr++; ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++); } break; case OP_WORDCHAR: for (i = 1; i <= min; i++) { pcre_uint32 cc; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } cc = UCHAR21(eptr); if (cc >= 128 || (md->ctypes[cc] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); eptr++; /* No need to skip more bytes - we know it's a 1-byte character */ } break; default: RRETURN(PCRE_ERROR_INTERNAL); } /* End switch(ctype) */ else #endif /* SUPPORT_UTF */ /* Code for the non-UTF-8 case for minimum matching of operators other than OP_PROP and OP_NOTPROP. */ switch(ctype) { case OP_ANY: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); if (md->partial != 0 && eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && *eptr == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } eptr++; } break; case OP_ALLANY: if (eptr > md->end_subject - min) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } eptr += min; break; case OP_ANYBYTE: if (eptr > md->end_subject - min) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } eptr += min; break; case OP_ANYNL: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } switch(*eptr++) { default: RRETURN(MATCH_NOMATCH); case CHAR_CR: if (eptr < md->end_subject && *eptr == CHAR_LF) eptr++; break; case CHAR_LF: break; case CHAR_VT: case CHAR_FF: case CHAR_NEL: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case 0x2028: case 0x2029: #endif if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } } break; case OP_NOT_HSPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } switch(*eptr++) { default: break; HSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 HSPACE_MULTIBYTE_CASES: #endif RRETURN(MATCH_NOMATCH); } } break; case OP_HSPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } switch(*eptr++) { default: RRETURN(MATCH_NOMATCH); HSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 HSPACE_MULTIBYTE_CASES: #endif break; } } break; case OP_NOT_VSPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } switch(*eptr++) { VSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 VSPACE_MULTIBYTE_CASES: #endif RRETURN(MATCH_NOMATCH); default: break; } } break; case OP_VSPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } switch(*eptr++) { default: RRETURN(MATCH_NOMATCH); VSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 VSPACE_MULTIBYTE_CASES: #endif break; } } break; case OP_NOT_DIGIT: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); eptr++; } break; case OP_DIGIT: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); eptr++; } break; case OP_NOT_WHITESPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); eptr++; } break; case OP_WHITESPACE: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); eptr++; } break; case OP_NOT_WORDCHAR: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); eptr++; } break; case OP_WORDCHAR: for (i = 1; i <= min; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); eptr++; } break; default: RRETURN(PCRE_ERROR_INTERNAL); } } /* If min = max, continue at the same level without recursing */ if (min == max) continue; /* If minimizing, we have to test the rest of the pattern before each subsequent match. Again, separate the UTF-8 case for speed, and also separate the UCP cases. */ if (minimize) { #ifdef SUPPORT_UCP if (prop_type >= 0) { switch(prop_type) { case PT_ANY: for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM36); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if (prop_fail_result) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ case PT_LAMP: for (fi = min;; fi++) { int chartype; RMATCH(eptr, ecode, offset_top, md, eptrb, RM37); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); chartype = UCD_CHARTYPE(c); if ((chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt) == prop_fail_result) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ case PT_GC: for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM38); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ((UCD_CATEGORY(c) == prop_value) == prop_fail_result) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ case PT_PC: for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM39); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ((UCD_CHARTYPE(c) == prop_value) == prop_fail_result) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ case PT_SC: for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM40); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ((UCD_SCRIPT(c) == prop_value) == prop_fail_result) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ case PT_ALNUM: for (fi = min;; fi++) { int category; RMATCH(eptr, ecode, offset_top, md, eptrb, RM59); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); category = UCD_CATEGORY(c); if ((category == ucp_L || category == ucp_N) == prop_fail_result) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM61); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); switch(c) { HSPACE_CASES: VSPACE_CASES: if (prop_fail_result) RRETURN(MATCH_NOMATCH); break; default: if ((UCD_CATEGORY(c) == ucp_Z) == prop_fail_result) RRETURN(MATCH_NOMATCH); break; } } /* Control never gets here */ case PT_WORD: for (fi = min;; fi++) { int category; RMATCH(eptr, ecode, offset_top, md, eptrb, RM62); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); category = UCD_CATEGORY(c); if ((category == ucp_L || category == ucp_N || c == CHAR_UNDERSCORE) == prop_fail_result) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ case PT_CLIST: for (fi = min;; fi++) { const pcre_uint32 *cp; RMATCH(eptr, ecode, offset_top, md, eptrb, RM67); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); cp = PRIV(ucd_caseless_sets) + prop_value; for (;;) { if (c < *cp) { if (prop_fail_result) break; else { RRETURN(MATCH_NOMATCH); } } if (c == *cp++) { if (prop_fail_result) { RRETURN(MATCH_NOMATCH); } else break; } } } /* Control never gets here */ case PT_UCNC: for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM60); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } GETCHARINCTEST(c, eptr); if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || c >= 0xe000) == prop_fail_result) RRETURN(MATCH_NOMATCH); } /* Control never gets here */ /* This should never occur */ default: RRETURN(PCRE_ERROR_INTERNAL); } } /* Match extended Unicode sequences. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ else if (ctype == OP_EXTUNI) { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM41); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } else { int lgb, rgb; GETCHARINCTEST(c, eptr); lgb = UCD_GRAPHBREAK(c); while (eptr < md->end_subject) { int len = 1; if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } rgb = UCD_GRAPHBREAK(c); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; lgb = rgb; eptr += len; } } CHECK_PARTIAL(); } } else #endif /* SUPPORT_UCP */ #ifdef SUPPORT_UTF if (utf) { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM42); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (ctype == OP_ANY && IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); GETCHARINC(c, eptr); switch(ctype) { case OP_ANY: /* This is the non-NL case */ if (md->partial != 0 && /* Take care with CRLF partial */ eptr >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } break; case OP_ALLANY: case OP_ANYBYTE: break; case OP_ANYNL: switch(c) { default: RRETURN(MATCH_NOMATCH); case CHAR_CR: if (eptr < md->end_subject && UCHAR21(eptr) == CHAR_LF) eptr++; break; case CHAR_LF: break; case CHAR_VT: case CHAR_FF: case CHAR_NEL: #ifndef EBCDIC case 0x2028: case 0x2029: #endif /* Not EBCDIC */ if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } break; case OP_NOT_HSPACE: switch(c) { HSPACE_CASES: RRETURN(MATCH_NOMATCH); default: break; } break; case OP_HSPACE: switch(c) { HSPACE_CASES: break; default: RRETURN(MATCH_NOMATCH); } break; case OP_NOT_VSPACE: switch(c) { VSPACE_CASES: RRETURN(MATCH_NOMATCH); default: break; } break; case OP_VSPACE: switch(c) { VSPACE_CASES: break; default: RRETURN(MATCH_NOMATCH); } break; case OP_NOT_DIGIT: if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); break; case OP_DIGIT: if (c >= 256 || (md->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); break; case OP_NOT_WHITESPACE: if (c < 256 && (md->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); break; case OP_WHITESPACE: if (c >= 256 || (md->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); break; case OP_NOT_WORDCHAR: if (c < 256 && (md->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); break; case OP_WORDCHAR: if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); break; default: RRETURN(PCRE_ERROR_INTERNAL); } } } else #endif /* Not UTF mode */ { for (fi = min;; fi++) { RMATCH(eptr, ecode, offset_top, md, eptrb, RM43); if (rrc != MATCH_NOMATCH) RRETURN(rrc); if (fi >= max) RRETURN(MATCH_NOMATCH); if (eptr >= md->end_subject) { SCHECK_PARTIAL(); RRETURN(MATCH_NOMATCH); } if (ctype == OP_ANY && IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH); c = *eptr++; switch(ctype) { case OP_ANY: /* This is the non-NL case */ if (md->partial != 0 && /* Take care with CRLF partial */ eptr >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } break; case OP_ALLANY: case OP_ANYBYTE: break; case OP_ANYNL: switch(c) { default: RRETURN(MATCH_NOMATCH); case CHAR_CR: if (eptr < md->end_subject && *eptr == CHAR_LF) eptr++; break; case CHAR_LF: break; case CHAR_VT: case CHAR_FF: case CHAR_NEL: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case 0x2028: case 0x2029: #endif if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH); break; } break; case OP_NOT_HSPACE: switch(c) { default: break; HSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 HSPACE_MULTIBYTE_CASES: #endif RRETURN(MATCH_NOMATCH); } break; case OP_HSPACE: switch(c) { default: RRETURN(MATCH_NOMATCH); HSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 HSPACE_MULTIBYTE_CASES: #endif break; } break; case OP_NOT_VSPACE: switch(c) { default: break; VSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 VSPACE_MULTIBYTE_CASES: #endif RRETURN(MATCH_NOMATCH); } break; case OP_VSPACE: switch(c) { default: RRETURN(MATCH_NOMATCH); VSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 VSPACE_MULTIBYTE_CASES: #endif break; } break; case OP_NOT_DIGIT: if (MAX_255(c) && (md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH); break; case OP_DIGIT: if (!MAX_255(c) || (md->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH); break; case OP_NOT_WHITESPACE: if (MAX_255(c) && (md->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH); break; case OP_WHITESPACE: if (!MAX_255(c) || (md->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH); break; case OP_NOT_WORDCHAR: if (MAX_255(c) && (md->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH); break; case OP_WORDCHAR: if (!MAX_255(c) || (md->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH); break; default: RRETURN(PCRE_ERROR_INTERNAL); } } } /* Control never gets here */ } /* If maximizing, it is worth using inline code for speed, doing the type test once at the start (i.e. keep it out of the loop). Again, keep the UTF-8 and UCP stuff separate. */ else { pp = eptr; /* Remember where we started */ #ifdef SUPPORT_UCP if (prop_type >= 0) { switch(prop_type) { case PT_ANY: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); if (prop_fail_result) break; eptr+= len; } break; case PT_LAMP: for (i = min; i < max; i++) { int chartype; int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); chartype = UCD_CHARTYPE(c); if ((chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt) == prop_fail_result) break; eptr+= len; } break; case PT_GC: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); if ((UCD_CATEGORY(c) == prop_value) == prop_fail_result) break; eptr+= len; } break; case PT_PC: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); if ((UCD_CHARTYPE(c) == prop_value) == prop_fail_result) break; eptr+= len; } break; case PT_SC: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); if ((UCD_SCRIPT(c) == prop_value) == prop_fail_result) break; eptr+= len; } break; case PT_ALNUM: for (i = min; i < max; i++) { int category; int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); category = UCD_CATEGORY(c); if ((category == ucp_L || category == ucp_N) == prop_fail_result) break; eptr+= len; } break; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); switch(c) { HSPACE_CASES: VSPACE_CASES: if (prop_fail_result) goto ENDLOOP99; /* Break the loop */ break; default: if ((UCD_CATEGORY(c) == ucp_Z) == prop_fail_result) goto ENDLOOP99; /* Break the loop */ break; } eptr+= len; } ENDLOOP99: break; case PT_WORD: for (i = min; i < max; i++) { int category; int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); category = UCD_CATEGORY(c); if ((category == ucp_L || category == ucp_N || c == CHAR_UNDERSCORE) == prop_fail_result) break; eptr+= len; } break; case PT_CLIST: for (i = min; i < max; i++) { const pcre_uint32 *cp; int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); cp = PRIV(ucd_caseless_sets) + prop_value; for (;;) { if (c < *cp) { if (prop_fail_result) break; else goto GOT_MAX; } if (c == *cp++) { if (prop_fail_result) goto GOT_MAX; else break; } } eptr += len; } GOT_MAX: break; case PT_UCNC: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLENTEST(c, eptr, len); if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || c >= 0xe000) == prop_fail_result) break; eptr += len; } break; default: RRETURN(PCRE_ERROR_INTERNAL); } /* eptr is now past the end of the maximum run */ if (possessive) continue; /* No backtracking */ for(;;) { if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM44); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; if (utf) BACKCHAR(eptr); } } /* Match extended Unicode grapheme clusters. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ else if (ctype == OP_EXTUNI) { for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } else { int lgb, rgb; GETCHARINCTEST(c, eptr); lgb = UCD_GRAPHBREAK(c); while (eptr < md->end_subject) { int len = 1; if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); } rgb = UCD_GRAPHBREAK(c); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; lgb = rgb; eptr += len; } } CHECK_PARTIAL(); } /* eptr is now past the end of the maximum run */ if (possessive) continue; /* No backtracking */ /* We use <= pp rather than == pp to detect the start of the run while backtracking because the use of \C in UTF mode can cause BACKCHAR to move back past pp. This is just palliative; the use of \C in UTF mode is fraught with danger. */ for(;;) { int lgb, rgb; PCRE_PUCHAR fptr; if (eptr <= pp) goto TAIL_RECURSE; /* At start of char run */ RMATCH(eptr, ecode, offset_top, md, eptrb, RM45); if (rrc != MATCH_NOMATCH) RRETURN(rrc); /* Backtracking over an extended grapheme cluster involves inspecting the previous two characters (if present) to see if a break is permitted between them. */ eptr--; if (!utf) c = *eptr; else { BACKCHAR(eptr); GETCHAR(c, eptr); } rgb = UCD_GRAPHBREAK(c); for (;;) { if (eptr <= pp) goto TAIL_RECURSE; /* At start of char run */ fptr = eptr - 1; if (!utf) c = *fptr; else { BACKCHAR(fptr); GETCHAR(c, fptr); } lgb = UCD_GRAPHBREAK(c); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; eptr = fptr; rgb = lgb; } } } else #endif /* SUPPORT_UCP */ #ifdef SUPPORT_UTF if (utf) { switch(ctype) { case OP_ANY: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (IS_NEWLINE(eptr)) break; if (md->partial != 0 && /* Take care with CRLF partial */ eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && UCHAR21(eptr) == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } eptr++; ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++); } break; case OP_ALLANY: if (max < INT_MAX) { for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } eptr++; ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++); } } else { eptr = md->end_subject; /* Unlimited UTF-8 repeat */ SCHECK_PARTIAL(); } break; /* The byte case is the same as non-UTF8 */ case OP_ANYBYTE: c = max - min; if (c > (unsigned int)(md->end_subject - eptr)) { eptr = md->end_subject; SCHECK_PARTIAL(); } else eptr += c; break; case OP_ANYNL: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); if (c == CHAR_CR) { if (++eptr >= md->end_subject) break; if (UCHAR21(eptr) == CHAR_LF) eptr++; } else { if (c != CHAR_LF && (md->bsr_anycrlf || (c != CHAR_VT && c != CHAR_FF && c != CHAR_NEL #ifndef EBCDIC && c != 0x2028 && c != 0x2029 #endif /* Not EBCDIC */ ))) break; eptr += len; } } break; case OP_NOT_HSPACE: case OP_HSPACE: for (i = min; i < max; i++) { BOOL gotspace; int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); switch(c) { HSPACE_CASES: gotspace = TRUE; break; default: gotspace = FALSE; break; } if (gotspace == (ctype == OP_NOT_HSPACE)) break; eptr += len; } break; case OP_NOT_VSPACE: case OP_VSPACE: for (i = min; i < max; i++) { BOOL gotspace; int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); switch(c) { VSPACE_CASES: gotspace = TRUE; break; default: gotspace = FALSE; break; } if (gotspace == (ctype == OP_NOT_VSPACE)) break; eptr += len; } break; case OP_NOT_DIGIT: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) break; eptr+= len; } break; case OP_DIGIT: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); if (c >= 256 ||(md->ctypes[c] & ctype_digit) == 0) break; eptr+= len; } break; case OP_NOT_WHITESPACE: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); if (c < 256 && (md->ctypes[c] & ctype_space) != 0) break; eptr+= len; } break; case OP_WHITESPACE: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); if (c >= 256 ||(md->ctypes[c] & ctype_space) == 0) break; eptr+= len; } break; case OP_NOT_WORDCHAR: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); if (c < 256 && (md->ctypes[c] & ctype_word) != 0) break; eptr+= len; } break; case OP_WORDCHAR: for (i = min; i < max; i++) { int len = 1; if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } GETCHARLEN(c, eptr, len); if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) break; eptr+= len; } break; default: RRETURN(PCRE_ERROR_INTERNAL); } if (possessive) continue; /* No backtracking */ for(;;) { if (eptr <= pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM46); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; BACKCHAR(eptr); if (ctype == OP_ANYNL && eptr > pp && UCHAR21(eptr) == CHAR_NL && UCHAR21(eptr - 1) == CHAR_CR) eptr--; } } else #endif /* SUPPORT_UTF */ /* Not UTF mode */ { switch(ctype) { case OP_ANY: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (IS_NEWLINE(eptr)) break; if (md->partial != 0 && /* Take care with CRLF partial */ eptr + 1 >= md->end_subject && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && *eptr == NLBLOCK->nl[0]) { md->hitend = TRUE; if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); } eptr++; } break; case OP_ALLANY: case OP_ANYBYTE: c = max - min; if (c > (unsigned int)(md->end_subject - eptr)) { eptr = md->end_subject; SCHECK_PARTIAL(); } else eptr += c; break; case OP_ANYNL: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } c = *eptr; if (c == CHAR_CR) { if (++eptr >= md->end_subject) break; if (*eptr == CHAR_LF) eptr++; } else { if (c != CHAR_LF && (md->bsr_anycrlf || (c != CHAR_VT && c != CHAR_FF && c != CHAR_NEL #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 && c != 0x2028 && c != 0x2029 #endif ))) break; eptr++; } } break; case OP_NOT_HSPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } switch(*eptr) { default: eptr++; break; HSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 HSPACE_MULTIBYTE_CASES: #endif goto ENDLOOP00; } } ENDLOOP00: break; case OP_HSPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } switch(*eptr) { default: goto ENDLOOP01; HSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 HSPACE_MULTIBYTE_CASES: #endif eptr++; break; } } ENDLOOP01: break; case OP_NOT_VSPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } switch(*eptr) { default: eptr++; break; VSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 VSPACE_MULTIBYTE_CASES: #endif goto ENDLOOP02; } } ENDLOOP02: break; case OP_VSPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } switch(*eptr) { default: goto ENDLOOP03; VSPACE_BYTE_CASES: #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 VSPACE_MULTIBYTE_CASES: #endif eptr++; break; } } ENDLOOP03: break; case OP_NOT_DIGIT: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_digit) != 0) break; eptr++; } break; case OP_DIGIT: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_digit) == 0) break; eptr++; } break; case OP_NOT_WHITESPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_space) != 0) break; eptr++; } break; case OP_WHITESPACE: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_space) == 0) break; eptr++; } break; case OP_NOT_WORDCHAR: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_word) != 0) break; eptr++; } break; case OP_WORDCHAR: for (i = min; i < max; i++) { if (eptr >= md->end_subject) { SCHECK_PARTIAL(); break; } if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_word) == 0) break; eptr++; } break; default: RRETURN(PCRE_ERROR_INTERNAL); } if (possessive) continue; /* No backtracking */ for (;;) { if (eptr == pp) goto TAIL_RECURSE; RMATCH(eptr, ecode, offset_top, md, eptrb, RM47); if (rrc != MATCH_NOMATCH) RRETURN(rrc); eptr--; if (ctype == OP_ANYNL && eptr > pp && *eptr == CHAR_LF && eptr[-1] == CHAR_CR) eptr--; } } /* Control never gets here */ } /* There's been some horrible disaster. Arrival here can only mean there is something seriously wrong in the code above or the OP_xxx definitions. */ default: DPRINTF(("Unknown opcode %d\n", *ecode)); RRETURN(PCRE_ERROR_UNKNOWN_OPCODE); } /* Do not stick any code in here without much thought; it is assumed that "continue" in the code above comes out to here to repeat the main loop. */ } /* End of main loop */ /* Control never reaches here */ /* When compiling to use the heap rather than the stack for recursive calls to match(), the RRETURN() macro jumps here. The number that is saved in frame->Xwhere indicates which label we actually want to return to. */ #ifdef NO_RECURSE #define LBL(val) case val: goto L_RM##val; HEAP_RETURN: switch (frame->Xwhere) { LBL( 1) LBL( 2) LBL( 3) LBL( 4) LBL( 5) LBL( 6) LBL( 7) LBL( 8) LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(17) LBL(19) LBL(24) LBL(25) LBL(26) LBL(27) LBL(29) LBL(31) LBL(33) LBL(35) LBL(43) LBL(47) LBL(48) LBL(49) LBL(50) LBL(51) LBL(52) LBL(53) LBL(54) LBL(55) LBL(56) LBL(57) LBL(58) LBL(63) LBL(64) LBL(65) LBL(66) #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 LBL(20) LBL(21) #endif #ifdef SUPPORT_UTF LBL(16) LBL(18) LBL(22) LBL(23) LBL(28) LBL(30) LBL(32) LBL(34) LBL(42) LBL(46) #ifdef SUPPORT_UCP LBL(36) LBL(37) LBL(38) LBL(39) LBL(40) LBL(41) LBL(44) LBL(45) LBL(59) LBL(60) LBL(61) LBL(62) LBL(67) #endif /* SUPPORT_UCP */ #endif /* SUPPORT_UTF */ default: DPRINTF(("jump error in pcre match: label %d non-existent\n", frame->Xwhere)); return PCRE_ERROR_INTERNAL; } #undef LBL #endif /* NO_RECURSE */ } /*************************************************************************** **************************************************************************** RECURSION IN THE match() FUNCTION Undefine all the macros that were defined above to handle this. */ #ifdef NO_RECURSE #undef eptr #undef ecode #undef mstart #undef offset_top #undef eptrb #undef flags #undef callpat #undef charptr #undef data #undef next #undef pp #undef prev #undef saved_eptr #undef new_recursive #undef cur_is_word #undef condition #undef prev_is_word #undef ctype #undef length #undef max #undef min #undef number #undef offset #undef op #undef save_capture_last #undef save_offset1 #undef save_offset2 #undef save_offset3 #undef stacksave #undef newptrb #endif /* These two are defined as macros in both cases */ #undef fc #undef fi /*************************************************************************** ***************************************************************************/ #ifdef NO_RECURSE /************************************************* * Release allocated heap frames * *************************************************/ /* This function releases all the allocated frames. The base frame is on the machine stack, and so must not be freed. Argument: the address of the base frame Returns: nothing */ static void release_match_heapframes (heapframe *frame_base) { heapframe *nextframe = frame_base->Xnextframe; while (nextframe != NULL) { heapframe *oldframe = nextframe; nextframe = nextframe->Xnextframe; (PUBL(stack_free))(oldframe); } } #endif /************************************************* * Execute a Regular Expression * *************************************************/ /* This function applies a compiled re to a subject string and picks out portions of the string if it matches. Two elements in the vector are set for each substring: the offsets to the start and end of the substring. Arguments: argument_re points to the compiled expression extra_data points to extra data or is NULL subject points to the subject string length length of subject string (may contain binary zeros) start_offset where to start in the subject string options option bits offsets points to a vector of ints to be filled in with offsets offsetcount the number of elements in the vector Returns: > 0 => success; value is the number of elements filled in = 0 => success, but offsets is not big enough -1 => failed to match < -1 => some kind of unexpected problem */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_exec(const pcre *argument_re, const pcre_extra *extra_data, PCRE_SPTR subject, int length, int start_offset, int options, int *offsets, int offsetcount) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_exec(const pcre16 *argument_re, const pcre16_extra *extra_data, PCRE_SPTR16 subject, int length, int start_offset, int options, int *offsets, int offsetcount) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_exec(const pcre32 *argument_re, const pcre32_extra *extra_data, PCRE_SPTR32 subject, int length, int start_offset, int options, int *offsets, int offsetcount) #endif { int rc, ocount, arg_offset_max; int newline; BOOL using_temporary_offsets = FALSE; BOOL anchored; BOOL startline; BOOL firstline; BOOL utf; BOOL has_first_char = FALSE; BOOL has_req_char = FALSE; pcre_uchar first_char = 0; pcre_uchar first_char2 = 0; pcre_uchar req_char = 0; pcre_uchar req_char2 = 0; match_data match_block; match_data *md = &match_block; const pcre_uint8 *tables; const pcre_uint8 *start_bits = NULL; PCRE_PUCHAR start_match = (PCRE_PUCHAR)subject + start_offset; PCRE_PUCHAR end_subject; PCRE_PUCHAR start_partial = NULL; PCRE_PUCHAR match_partial = NULL; PCRE_PUCHAR req_char_ptr = start_match - 1; const pcre_study_data *study; const REAL_PCRE *re = (const REAL_PCRE *)argument_re; #ifdef NO_RECURSE heapframe frame_zero; frame_zero.Xprevframe = NULL; /* Marks the top level */ frame_zero.Xnextframe = NULL; /* None are allocated yet */ md->match_frames_base = &frame_zero; #endif /* Check for the special magic call that measures the size of the stack used per recursive call of match(). Without the funny casting for sizeof, a Windows compiler gave this error: "unary minus operator applied to unsigned type, result still unsigned". Hopefully the cast fixes that. */ if (re == NULL && extra_data == NULL && subject == NULL && length == -999 && start_offset == -999) #ifdef NO_RECURSE return -((int)sizeof(heapframe)); #else return match(NULL, NULL, NULL, 0, NULL, NULL, 0); #endif /* Plausibility checks */ if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; if (re == NULL || subject == NULL || (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; if (offsetcount < 0) return PCRE_ERROR_BADCOUNT; if (length < 0) return PCRE_ERROR_BADLENGTH; if (start_offset < 0 || start_offset > length) return PCRE_ERROR_BADOFFSET; /* Check that the first field in the block is the magic number. If it is not, return with PCRE_ERROR_BADMAGIC. However, if the magic number is equal to REVERSED_MAGIC_NUMBER we return with PCRE_ERROR_BADENDIANNESS, which means that the pattern is likely compiled with different endianness. */ if (re->magic_number != MAGIC_NUMBER) return re->magic_number == REVERSED_MAGIC_NUMBER? PCRE_ERROR_BADENDIANNESS:PCRE_ERROR_BADMAGIC; if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE; /* These two settings are used in the code for checking a UTF-8 string that follows immediately afterwards. Other values in the md block are used only during "normal" pcre_exec() processing, not when the JIT support is in use, so they are set up later. */ /* PCRE_UTF16 has the same value as PCRE_UTF8. */ utf = md->utf = (re->options & PCRE_UTF8) != 0; md->partial = ((options & PCRE_PARTIAL_HARD) != 0)? 2 : ((options & PCRE_PARTIAL_SOFT) != 0)? 1 : 0; /* Check a UTF-8 string if required. Pass back the character offset and error code for an invalid string if a results vector is available. */ #ifdef SUPPORT_UTF if (utf && (options & PCRE_NO_UTF8_CHECK) == 0) { int erroroffset; int errorcode = PRIV(valid_utf)((PCRE_PUCHAR)subject, length, &erroroffset); if (errorcode != 0) { if (offsetcount >= 2) { offsets[0] = erroroffset; offsets[1] = errorcode; } #if defined COMPILE_PCRE8 return (errorcode <= PCRE_UTF8_ERR5 && md->partial > 1)? PCRE_ERROR_SHORTUTF8 : PCRE_ERROR_BADUTF8; #elif defined COMPILE_PCRE16 return (errorcode <= PCRE_UTF16_ERR1 && md->partial > 1)? PCRE_ERROR_SHORTUTF16 : PCRE_ERROR_BADUTF16; #elif defined COMPILE_PCRE32 return PCRE_ERROR_BADUTF32; #endif } #if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 /* Check that a start_offset points to the start of a UTF character. */ if (start_offset > 0 && start_offset < length && NOT_FIRSTCHAR(((PCRE_PUCHAR)subject)[start_offset])) return PCRE_ERROR_BADUTF8_OFFSET; #endif } #endif /* If the pattern was successfully studied with JIT support, run the JIT executable instead of the rest of this function. Most options must be set at compile time for the JIT code to be usable. Fallback to the normal code path if an unsupported flag is set. */ #ifdef SUPPORT_JIT if (extra_data != NULL && (extra_data->flags & (PCRE_EXTRA_EXECUTABLE_JIT | PCRE_EXTRA_TABLES)) == PCRE_EXTRA_EXECUTABLE_JIT && extra_data->executable_jit != NULL && (options & ~PUBLIC_JIT_EXEC_OPTIONS) == 0) { rc = PRIV(jit_exec)(extra_data, (const pcre_uchar *)subject, length, start_offset, options, offsets, offsetcount); /* PCRE_ERROR_NULL means that the selected normal or partial matching mode is not compiled. In this case we simply fallback to interpreter. */ if (rc != PCRE_ERROR_JIT_BADOPTION) return rc; } #endif /* Carry on with non-JIT matching. This information is for finding all the numbers associated with a given name, for condition testing. */ md->name_table = (pcre_uchar *)re + re->name_table_offset; md->name_count = re->name_count; md->name_entry_size = re->name_entry_size; /* Fish out the optional data from the extra_data structure, first setting the default values. */ study = NULL; md->match_limit = MATCH_LIMIT; md->match_limit_recursion = MATCH_LIMIT_RECURSION; md->callout_data = NULL; /* The table pointer is always in native byte order. */ tables = re->tables; /* The two limit values override the defaults, whatever their value. */ if (extra_data != NULL) { unsigned long int flags = extra_data->flags; if ((flags & PCRE_EXTRA_STUDY_DATA) != 0) study = (const pcre_study_data *)extra_data->study_data; if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0) md->match_limit = extra_data->match_limit; if ((flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) != 0) md->match_limit_recursion = extra_data->match_limit_recursion; if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0) md->callout_data = extra_data->callout_data; if ((flags & PCRE_EXTRA_TABLES) != 0) tables = extra_data->tables; } /* Limits in the regex override only if they are smaller. */ if ((re->flags & PCRE_MLSET) != 0 && re->limit_match < md->match_limit) md->match_limit = re->limit_match; if ((re->flags & PCRE_RLSET) != 0 && re->limit_recursion < md->match_limit_recursion) md->match_limit_recursion = re->limit_recursion; /* If the exec call supplied NULL for tables, use the inbuilt ones. This is a feature that makes it possible to save compiled regex and re-use them in other programs later. */ if (tables == NULL) tables = PRIV(default_tables); /* Set up other data */ anchored = ((re->options | options) & PCRE_ANCHORED) != 0; startline = (re->flags & PCRE_STARTLINE) != 0; firstline = (re->options & PCRE_FIRSTLINE) != 0; /* The code starts after the real_pcre block and the capture name table. */ md->start_code = (const pcre_uchar *)re + re->name_table_offset + re->name_count * re->name_entry_size; md->start_subject = (PCRE_PUCHAR)subject; md->start_offset = start_offset; md->end_subject = md->start_subject + length; end_subject = md->end_subject; md->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; md->use_ucp = (re->options & PCRE_UCP) != 0; md->jscript_compat = (re->options & PCRE_JAVASCRIPT_COMPAT) != 0; md->ignore_skip_arg = 0; /* Some options are unpacked into BOOL variables in the hope that testing them will be faster than individual option bits. */ md->notbol = (options & PCRE_NOTBOL) != 0; md->noteol = (options & PCRE_NOTEOL) != 0; md->notempty = (options & PCRE_NOTEMPTY) != 0; md->notempty_atstart = (options & PCRE_NOTEMPTY_ATSTART) != 0; md->hitend = FALSE; md->mark = md->nomatch_mark = NULL; /* In case never set */ md->recursive = NULL; /* No recursion at top level */ md->hasthen = (re->flags & PCRE_HASTHEN) != 0; md->lcc = tables + lcc_offset; md->fcc = tables + fcc_offset; md->ctypes = tables + ctypes_offset; /* Handle different \R options. */ switch (options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) { case 0: if ((re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) != 0) md->bsr_anycrlf = (re->options & PCRE_BSR_ANYCRLF) != 0; else #ifdef BSR_ANYCRLF md->bsr_anycrlf = TRUE; #else md->bsr_anycrlf = FALSE; #endif break; case PCRE_BSR_ANYCRLF: md->bsr_anycrlf = TRUE; break; case PCRE_BSR_UNICODE: md->bsr_anycrlf = FALSE; break; default: return PCRE_ERROR_BADNEWLINE; } /* Handle different types of newline. The three bits give eight cases. If nothing is set at run time, whatever was used at compile time applies. */ switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : (pcre_uint32)options) & PCRE_NEWLINE_BITS) { case 0: newline = NEWLINE; break; /* Compile-time default */ case PCRE_NEWLINE_CR: newline = CHAR_CR; break; case PCRE_NEWLINE_LF: newline = CHAR_NL; break; case PCRE_NEWLINE_CR+ PCRE_NEWLINE_LF: newline = (CHAR_CR << 8) | CHAR_NL; break; case PCRE_NEWLINE_ANY: newline = -1; break; case PCRE_NEWLINE_ANYCRLF: newline = -2; break; default: return PCRE_ERROR_BADNEWLINE; } if (newline == -2) { md->nltype = NLTYPE_ANYCRLF; } else if (newline < 0) { md->nltype = NLTYPE_ANY; } else { md->nltype = NLTYPE_FIXED; if (newline > 255) { md->nllen = 2; md->nl[0] = (newline >> 8) & 255; md->nl[1] = newline & 255; } else { md->nllen = 1; md->nl[0] = newline; } } /* Partial matching was originally supported only for a restricted set of regexes; from release 8.00 there are no restrictions, but the bits are still defined (though never set). So there's no harm in leaving this code. */ if (md->partial && (re->flags & PCRE_NOPARTIAL) != 0) return PCRE_ERROR_BADPARTIAL; /* If the expression has got more back references than the offsets supplied can hold, we get a temporary chunk of working store to use during the matching. Otherwise, we can use the vector supplied, rounding down its size to a multiple of 3. */ ocount = offsetcount - (offsetcount % 3); arg_offset_max = (2*ocount)/3; if (re->top_backref > 0 && re->top_backref >= ocount/3) { ocount = re->top_backref * 3 + 3; md->offset_vector = (int *)(PUBL(malloc))(ocount * sizeof(int)); if (md->offset_vector == NULL) return PCRE_ERROR_NOMEMORY; using_temporary_offsets = TRUE; DPRINTF(("Got memory to hold back references\n")); } else md->offset_vector = offsets; md->offset_end = ocount; md->offset_max = (2*ocount)/3; md->capture_last = 0; /* Reset the working variable associated with each extraction. These should never be used unless previously set, but they get saved and restored, and so we initialize them to avoid reading uninitialized locations. Also, unset the offsets for the matched string. This is really just for tidiness with callouts, in case they inspect these fields. */ if (md->offset_vector != NULL) { register int *iptr = md->offset_vector + ocount; register int *iend = iptr - re->top_bracket; if (iend < md->offset_vector + 2) iend = md->offset_vector + 2; while (--iptr >= iend) *iptr = -1; if (offsetcount > 0) md->offset_vector[0] = -1; if (offsetcount > 1) md->offset_vector[1] = -1; } /* Set up the first character to match, if available. The first_char value is never set for an anchored regular expression, but the anchoring may be forced at run time, so we have to test for anchoring. The first char may be unset for an unanchored pattern, of course. If there's no first char and the pattern was studied, there may be a bitmap of possible first characters. */ if (!anchored) { if ((re->flags & PCRE_FIRSTSET) != 0) { has_first_char = TRUE; first_char = first_char2 = (pcre_uchar)(re->first_char); if ((re->flags & PCRE_FCH_CASELESS) != 0) { first_char2 = TABLE_GET(first_char, md->fcc, first_char); #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8) if (utf && first_char > 127) first_char2 = UCD_OTHERCASE(first_char); #endif } } else if (!startline && study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0) start_bits = study->start_bits; } /* For anchored or unanchored matches, there may be a "last known required character" set. */ if ((re->flags & PCRE_REQCHSET) != 0) { has_req_char = TRUE; req_char = req_char2 = (pcre_uchar)(re->req_char); if ((re->flags & PCRE_RCH_CASELESS) != 0) { req_char2 = TABLE_GET(req_char, md->fcc, req_char); #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8) if (utf && req_char > 127) req_char2 = UCD_OTHERCASE(req_char); #endif } } /* ==========================================================================*/ /* Loop for handling unanchored repeated matching attempts; for anchored regexs the loop runs just once. */ for(;;) { PCRE_PUCHAR save_end_subject = end_subject; PCRE_PUCHAR new_start_match; /* If firstline is TRUE, the start of the match is constrained to the first line of a multiline string. That is, the match must be before or at the first newline. Implement this by temporarily adjusting end_subject so that we stop scanning at a newline. If the match fails at the newline, later code breaks this loop. */ if (firstline) { PCRE_PUCHAR t = start_match; #ifdef SUPPORT_UTF if (utf) { while (t < md->end_subject && !IS_NEWLINE(t)) { t++; ACROSSCHAR(t < end_subject, *t, t++); } } else #endif while (t < md->end_subject && !IS_NEWLINE(t)) t++; end_subject = t; } /* There are some optimizations that avoid running the match if a known starting point is not found, or if a known later character is not present. However, there is an option that disables these, for testing and for ensuring that all callouts do actually occur. The option can be set in the regex by (*NO_START_OPT) or passed in match-time options. */ if (((options | re->options) & PCRE_NO_START_OPTIMIZE) == 0) { /* Advance to a unique first char if there is one. */ if (has_first_char) { pcre_uchar smc; if (first_char != first_char2) while (start_match < end_subject && (smc = UCHAR21TEST(start_match)) != first_char && smc != first_char2) start_match++; else while (start_match < end_subject && UCHAR21TEST(start_match) != first_char) start_match++; } /* Or to just after a linebreak for a multiline match */ else if (startline) { if (start_match > md->start_subject + start_offset) { #ifdef SUPPORT_UTF if (utf) { while (start_match < end_subject && !WAS_NEWLINE(start_match)) { start_match++; ACROSSCHAR(start_match < end_subject, *start_match, start_match++); } } else #endif while (start_match < end_subject && !WAS_NEWLINE(start_match)) start_match++; /* If we have just passed a CR and the newline option is ANY or ANYCRLF, and we are now at a LF, advance the match position by one more character. */ if (start_match[-1] == CHAR_CR && (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) && start_match < end_subject && UCHAR21TEST(start_match) == CHAR_NL) start_match++; } } /* Or to a non-unique first byte after study */ else if (start_bits != NULL) { while (start_match < end_subject) { register pcre_uint32 c = UCHAR21TEST(start_match); #ifndef COMPILE_PCRE8 if (c > 255) c = 255; #endif if ((start_bits[c/8] & (1 << (c&7))) != 0) break; start_match++; } } } /* Starting optimizations */ /* Restore fudged end_subject */ end_subject = save_end_subject; /* The following two optimizations are disabled for partial matching or if disabling is explicitly requested. */ if (((options | re->options) & PCRE_NO_START_OPTIMIZE) == 0 && !md->partial) { /* If the pattern was studied, a minimum subject length may be set. This is a lower bound; no actual string of that length may actually match the pattern. Although the value is, strictly, in characters, we treat it as bytes to avoid spending too much time in this optimization. */ if (study != NULL && (study->flags & PCRE_STUDY_MINLEN) != 0 && (pcre_uint32)(end_subject - start_match) < study->minlength) { rc = MATCH_NOMATCH; break; } /* If req_char is set, we know that that character must appear in the subject for the match to succeed. If the first character is set, req_char must be later in the subject; otherwise the test starts at the match point. This optimization can save a huge amount of backtracking in patterns with nested unlimited repeats that aren't going to match. Writing separate code for cased/caseless versions makes it go faster, as does using an autoincrement and backing off on a match. HOWEVER: when the subject string is very, very long, searching to its end can take a long time, and give bad performance on quite ordinary patterns. This showed up when somebody was matching something like /^\d+C/ on a 32-megabyte string... so we don't do this when the string is sufficiently long. */ if (has_req_char && end_subject - start_match < REQ_BYTE_MAX) { register PCRE_PUCHAR p = start_match + (has_first_char? 1:0); /* We don't need to repeat the search if we haven't yet reached the place we found it at last time. */ if (p > req_char_ptr) { if (req_char != req_char2) { while (p < end_subject) { register pcre_uint32 pp = UCHAR21INCTEST(p); if (pp == req_char || pp == req_char2) { p--; break; } } } else { while (p < end_subject) { if (UCHAR21INCTEST(p) == req_char) { p--; break; } } } /* If we can't find the required character, break the matching loop, forcing a match failure. */ if (p >= end_subject) { rc = MATCH_NOMATCH; break; } /* If we have found the required character, save the point where we found it, so that we don't search again next time round the loop if the start hasn't passed this character yet. */ req_char_ptr = p; } } } #ifdef PCRE_DEBUG /* Sigh. Some compilers never learn. */ printf(">>>> Match against: "); pchars(start_match, end_subject - start_match, TRUE, md); printf("\n"); #endif /* OK, we can now run the match. If "hitend" is set afterwards, remember the first starting point for which a partial match was found. */ md->start_match_ptr = start_match; md->start_used_ptr = start_match; md->match_call_count = 0; md->match_function_type = 0; md->end_offset_top = 0; md->skip_arg_count = 0; rc = match(start_match, md->start_code, start_match, 2, md, NULL, 0); if (md->hitend && start_partial == NULL) { start_partial = md->start_used_ptr; match_partial = start_match; } switch(rc) { /* If MATCH_SKIP_ARG reaches this level it means that a MARK that matched the SKIP's arg was not found. In this circumstance, Perl ignores the SKIP entirely. The only way we can do that is to re-do the match at the same point, with a flag to force SKIP with an argument to be ignored. Just treating this case as NOMATCH does not work because it does not check other alternatives in patterns such as A(*SKIP:A)B|AC when the subject is AC. */ case MATCH_SKIP_ARG: new_start_match = start_match; md->ignore_skip_arg = md->skip_arg_count; break; /* SKIP passes back the next starting point explicitly, but if it is no greater than the match we have just done, treat it as NOMATCH. */ case MATCH_SKIP: if (md->start_match_ptr > start_match) { new_start_match = md->start_match_ptr; break; } /* Fall through */ /* NOMATCH and PRUNE advance by one character. THEN at this level acts exactly like PRUNE. Unset ignore SKIP-with-argument. */ case MATCH_NOMATCH: case MATCH_PRUNE: case MATCH_THEN: md->ignore_skip_arg = 0; new_start_match = start_match + 1; #ifdef SUPPORT_UTF if (utf) ACROSSCHAR(new_start_match < end_subject, *new_start_match, new_start_match++); #endif break; /* COMMIT disables the bumpalong, but otherwise behaves as NOMATCH. */ case MATCH_COMMIT: rc = MATCH_NOMATCH; goto ENDLOOP; /* Any other return is either a match, or some kind of error. */ default: goto ENDLOOP; } /* Control reaches here for the various types of "no match at this point" result. Reset the code to MATCH_NOMATCH for subsequent checking. */ rc = MATCH_NOMATCH; /* If PCRE_FIRSTLINE is set, the match must happen before or at the first newline in the subject (though it may continue over the newline). Therefore, if we have just failed to match, starting at a newline, do not continue. */ if (firstline && IS_NEWLINE(start_match)) break; /* Advance to new matching position */ start_match = new_start_match; /* Break the loop if the pattern is anchored or if we have passed the end of the subject. */ if (anchored || start_match > end_subject) break; /* If we have just passed a CR and we are now at a LF, and the pattern does not contain any explicit matches for \r or \n, and the newline option is CRLF or ANY or ANYCRLF, advance the match position by one more character. In normal matching start_match will aways be greater than the first position at this stage, but a failed *SKIP can cause a return at the same point, which is why the first test exists. */ if (start_match > (PCRE_PUCHAR)subject + start_offset && start_match[-1] == CHAR_CR && start_match < end_subject && *start_match == CHAR_NL && (re->flags & PCRE_HASCRORLF) == 0 && (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF || md->nllen == 2)) start_match++; md->mark = NULL; /* Reset for start of next match attempt */ } /* End of for(;;) "bumpalong" loop */ /* ==========================================================================*/ /* We reach here when rc is not MATCH_NOMATCH, or if one of the stopping conditions is true: (1) The pattern is anchored or the match was failed by (*COMMIT); (2) We are past the end of the subject; (3) PCRE_FIRSTLINE is set and we have failed to match at a newline, because this option requests that a match occur at or before the first newline in the subject. When we have a match and the offset vector is big enough to deal with any backreferences, captured substring offsets will already be set up. In the case where we had to get some local store to hold offsets for backreference processing, copy those that we can. In this case there need not be overflow if certain parts of the pattern were not used, even though there are more capturing parentheses than vector slots. */ ENDLOOP: if (rc == MATCH_MATCH || rc == MATCH_ACCEPT) { if (using_temporary_offsets) { if (arg_offset_max >= 4) { memcpy(offsets + 2, md->offset_vector + 2, (arg_offset_max - 2) * sizeof(int)); DPRINTF(("Copied offsets from temporary memory\n")); } if (md->end_offset_top > arg_offset_max) md->capture_last |= OVFLBIT; DPRINTF(("Freeing temporary memory\n")); (PUBL(free))(md->offset_vector); } /* Set the return code to the number of captured strings, or 0 if there were too many to fit into the vector. */ rc = ((md->capture_last & OVFLBIT) != 0 && md->end_offset_top >= arg_offset_max)? 0 : md->end_offset_top/2; /* If there is space in the offset vector, set any unused pairs at the end of the pattern to -1 for backwards compatibility. It is documented that this happens. In earlier versions, the whole set of potential capturing offsets was set to -1 each time round the loop, but this is handled differently now. "Gaps" are set to -1 dynamically instead (this fixes a bug). Thus, it is only those at the end that need unsetting here. We can't just unset them all at the start of the whole thing because they may get set in one branch that is not the final matching branch. */ if (md->end_offset_top/2 <= re->top_bracket && offsets != NULL) { register int *iptr, *iend; int resetcount = 2 + re->top_bracket * 2; if (resetcount > offsetcount) resetcount = offsetcount; iptr = offsets + md->end_offset_top; iend = offsets + resetcount; while (iptr < iend) *iptr++ = -1; } /* If there is space, set up the whole thing as substring 0. The value of md->start_match_ptr might be modified if \K was encountered on the success matching path. */ if (offsetcount < 2) rc = 0; else { offsets[0] = (int)(md->start_match_ptr - md->start_subject); offsets[1] = (int)(md->end_match_ptr - md->start_subject); } /* Return MARK data if requested */ if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_MARK) != 0) *(extra_data->mark) = (pcre_uchar *)md->mark; DPRINTF((">>>> returning %d\n", rc)); #ifdef NO_RECURSE release_match_heapframes(&frame_zero); #endif return rc; } /* Control gets here if there has been an error, or if the overall match attempt has failed at all permitted starting positions. */ if (using_temporary_offsets) { DPRINTF(("Freeing temporary memory\n")); (PUBL(free))(md->offset_vector); } /* For anything other than nomatch or partial match, just return the code. */ if (rc != MATCH_NOMATCH && rc != PCRE_ERROR_PARTIAL) { DPRINTF((">>>> error: returning %d\n", rc)); #ifdef NO_RECURSE release_match_heapframes(&frame_zero); #endif return rc; } /* Handle partial matches - disable any mark data */ if (match_partial != NULL) { DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n")); md->mark = NULL; if (offsetcount > 1) { offsets[0] = (int)(start_partial - (PCRE_PUCHAR)subject); offsets[1] = (int)(end_subject - (PCRE_PUCHAR)subject); if (offsetcount > 2) offsets[2] = (int)(match_partial - (PCRE_PUCHAR)subject); } rc = PCRE_ERROR_PARTIAL; } /* This is the classic nomatch case */ else { DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n")); rc = PCRE_ERROR_NOMATCH; } /* Return the MARK data if it has been requested. */ if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_MARK) != 0) *(extra_data->mark) = (pcre_uchar *)md->nomatch_mark; #ifdef NO_RECURSE release_match_heapframes(&frame_zero); #endif return rc; } /* End of pcre_exec.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcrecpp_internal.h0000644000000000000020000000546714655113617023044 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* Copyright (c) 2005, Google Inc. All rights reserved. ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ #ifndef PCRECPP_INTERNAL_H #define PCRECPP_INTERNAL_H /* When compiling a DLL for Windows, the exported symbols have to be declared using some MS magic. I found some useful information on this web page: http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the information there, using __declspec(dllexport) without "extern" we have a definition; with "extern" we have a declaration. The settings here override the setting in pcre.h. We use: PCRECPP_EXP_DECL for declarations PCRECPP_EXP_DEFN for definitions of exported functions */ #ifndef PCRECPP_EXP_DECL # ifdef _WIN32 # ifndef PCRE_STATIC # define PCRECPP_EXP_DECL extern __declspec(dllexport) # define PCRECPP_EXP_DEFN __declspec(dllexport) # else # define PCRECPP_EXP_DECL extern # define PCRECPP_EXP_DEFN # endif # else # define PCRECPP_EXP_DECL extern # define PCRECPP_EXP_DEFN # endif #endif #endif /* PCRECPP_INTERNAL_H */ /* End of pcrecpp_internal.h */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_globals.c0000644000000000000020000000737414655113617022142 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2014 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains global variables that are exported by the PCRE library. PCRE is thread-clean and doesn't use any global variables in the normal sense. However, it calls memory allocation and freeing functions via the four indirections below, and it can optionally do callouts, using the fifth indirection. These values can be changed by the caller, but are shared between all threads. For MS Visual Studio and Symbian OS, there are problems in initializing these variables to non-local functions. In these cases, therefore, an indirection via a local function is used. Also, when compiling for Virtual Pascal, things are done differently, and global variables are not used. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" #if defined _MSC_VER || defined __SYMBIAN32__ static void* LocalPcreMalloc(size_t aSize) { return malloc(aSize); } static void LocalPcreFree(void* aPtr) { free(aPtr); } PCRE_EXP_DATA_DEFN void *(*PUBL(malloc))(size_t) = LocalPcreMalloc; PCRE_EXP_DATA_DEFN void (*PUBL(free))(void *) = LocalPcreFree; PCRE_EXP_DATA_DEFN void *(*PUBL(stack_malloc))(size_t) = LocalPcreMalloc; PCRE_EXP_DATA_DEFN void (*PUBL(stack_free))(void *) = LocalPcreFree; PCRE_EXP_DATA_DEFN int (*PUBL(callout))(PUBL(callout_block) *) = NULL; PCRE_EXP_DATA_DEFN int (*PUBL(stack_guard))(void) = NULL; #elif !defined VPCOMPAT PCRE_EXP_DATA_DEFN void *(*PUBL(malloc))(size_t) = malloc; PCRE_EXP_DATA_DEFN void (*PUBL(free))(void *) = free; PCRE_EXP_DATA_DEFN void *(*PUBL(stack_malloc))(size_t) = malloc; PCRE_EXP_DATA_DEFN void (*PUBL(stack_free))(void *) = free; PCRE_EXP_DATA_DEFN int (*PUBL(callout))(PUBL(callout_block) *) = NULL; PCRE_EXP_DATA_DEFN int (*PUBL(stack_guard))(void) = NULL; #endif /* End of pcre_globals.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/Makefile.vc0000644000000000000020000000454014655113617021401 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # PROJECT = pcre # Tools CC = cl.exe LINK = link.exe RC = rc.exe MT = mt.exe !IF !DEFINED(BUILD_CPU) || "$(BUILD_CPU)" == "" !ERROR Must specify BUILD_CPU matching compiler x86 or x64 !ENDIF WORKDIR = $(BUILD_CPU)_RELEASE BUILDLIB = $(WORKDIR)\$(PROJECT).lib CLEANTARGET = rd /s /q $(WORKDIR) MAKEWORKDIR = md $(WORKDIR) CFLAGS = $(CFLAGS) -DNDEBUG -DWIN32 -D_WINNT -DWINNT -D_WIN32_WINNT=$(WINVER) -DWINVER=$(WINVER) CFLAGS = $(CFLAGS) -DPCRE_STATIC -DHAVE_CONFIG_H $(CPUFLAGS) $(EXTRA_CFLAGS) CLOPTS = /c /nologo -MD -W3 -O2 -Ob2 -Zi -EHsc PDBFLAGS = -Fo$(WORKDIR)\ -Fd$(WORKDIR)\$(PROJECT) LFLAGS = -lib /nologo $(EXTRA_LFLAGS) OBJECTS = \ $(WORKDIR)\pcre_byte_order.obj \ $(WORKDIR)\pcre_chartables.obj \ $(WORKDIR)\pcre_compile.obj \ $(WORKDIR)\pcre_config.obj \ $(WORKDIR)\pcre_dfa_exec.obj \ $(WORKDIR)\pcre_exec.obj \ $(WORKDIR)\pcre_fullinfo.obj \ $(WORKDIR)\pcre_get.obj \ $(WORKDIR)\pcre_globals.obj \ $(WORKDIR)\pcre_jit_compile.obj \ $(WORKDIR)\pcre_maketables.obj \ $(WORKDIR)\pcre_newline.obj \ $(WORKDIR)\pcre_ord2utf8.obj \ $(WORKDIR)\pcre_refcount.obj \ $(WORKDIR)\pcre_string_utils.obj \ $(WORKDIR)\pcre_study.obj \ $(WORKDIR)\pcre_tables.obj \ $(WORKDIR)\pcre_ucd.obj \ $(WORKDIR)\pcre_valid_utf8.obj \ $(WORKDIR)\pcre_version.obj \ $(WORKDIR)\pcre_xclass.obj all : $(WORKDIR) $(BUILDLIB) $(WORKDIR) : @$(MAKEWORKDIR) .c{$(WORKDIR)}.obj: $(CC) $(CLOPTS) $(CFLAGS) $(PDBFLAGS) $< $(BUILDLIB): $(WORKDIR) $(OBJECTS) $(LINK) $(LFLAGS) $(OBJECTS) /out:$(BUILDLIB) clean: @-$(CLEANTARGET) 2>NUL tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_internal.h0000644000000000000020000033676714655113617022353 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2016 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This header contains definitions that are shared between the different modules, but which are not relevant to the exported API. This includes some functions whose names all begin with "_pcre_", "_pcre16_" or "_pcre32_" depending on the PRIV macro. */ #ifndef PCRE_INTERNAL_H #define PCRE_INTERNAL_H /* Define PCRE_DEBUG to get debugging output on stdout. */ #if 0 #define PCRE_DEBUG #endif /* PCRE is compiled as an 8 bit library if it is not requested otherwise. */ #if !defined COMPILE_PCRE16 && !defined COMPILE_PCRE32 #define COMPILE_PCRE8 #endif /* If SUPPORT_UCP is defined, SUPPORT_UTF must also be defined. The "configure" script ensures this, but not everybody uses "configure". */ #if defined SUPPORT_UCP && !(defined SUPPORT_UTF) #define SUPPORT_UTF 1 #endif /* We define SUPPORT_UTF if SUPPORT_UTF8 is enabled for compatibility reasons with existing code. */ #if defined SUPPORT_UTF8 && !(defined SUPPORT_UTF) #define SUPPORT_UTF 1 #endif /* Fixme: SUPPORT_UTF8 should be eventually disappear from the code. Until then we define it if SUPPORT_UTF is defined. */ #if defined SUPPORT_UTF && !(defined SUPPORT_UTF8) #define SUPPORT_UTF8 1 #endif /* We do not support both EBCDIC and UTF-8/16/32 at the same time. The "configure" script prevents both being selected, but not everybody uses "configure". */ #if defined EBCDIC && defined SUPPORT_UTF #error The use of both EBCDIC and SUPPORT_UTF is not supported. #endif /* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef inline, and there are *still* stupid compilers about that don't like indented pre-processor statements, or at least there were when I first wrote this. After all, it had only been about 10 years then... It turns out that the Mac Debugging.h header also defines the macro DPRINTF, so be absolutely sure we get our version. */ #undef DPRINTF #ifdef PCRE_DEBUG #define DPRINTF(p) printf p #else #define DPRINTF(p) /* Nothing */ #endif /* Standard C headers plus the external interface definition. The only time setjmp and stdarg are used is when NO_RECURSE is set. */ #include #include #include #include #include #include /* Valgrind (memcheck) support */ #ifdef SUPPORT_VALGRIND #include #endif /* When compiling a DLL for Windows, the exported symbols have to be declared using some MS magic. I found some useful information on this web page: http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the information there, using __declspec(dllexport) without "extern" we have a definition; with "extern" we have a declaration. The settings here override the setting in pcre.h (which is included below); it defines only PCRE_EXP_DECL, which is all that is needed for applications (they just import the symbols). We use: PCRE_EXP_DECL for declarations PCRE_EXP_DEFN for definitions of exported functions PCRE_EXP_DATA_DEFN for definitions of exported variables The reason for the two DEFN macros is that in non-Windows environments, one does not want to have "extern" before variable definitions because it leads to compiler warnings. So we distinguish between functions and variables. In Windows, the two should always be the same. The reason for wrapping this in #ifndef PCRE_EXP_DECL is so that pcretest, which is an application, but needs to import this file in order to "peek" at internals, can #include pcre.h first to get an application's-eye view. In principle, people compiling for non-Windows, non-Unix-like (i.e. uncommon, special-purpose environments) might want to stick other stuff in front of exported symbols. That's why, in the non-Windows case, we set PCRE_EXP_DEFN and PCRE_EXP_DATA_DEFN only if they are not already set. */ #ifndef PCRE_EXP_DECL # ifdef _WIN32 # ifndef PCRE_STATIC # define PCRE_EXP_DECL extern __declspec(dllexport) # define PCRE_EXP_DEFN __declspec(dllexport) # define PCRE_EXP_DATA_DEFN __declspec(dllexport) # else # define PCRE_EXP_DECL extern # define PCRE_EXP_DEFN # define PCRE_EXP_DATA_DEFN # endif # else # ifdef __cplusplus # define PCRE_EXP_DECL extern "C" # else # define PCRE_EXP_DECL extern # endif # ifndef PCRE_EXP_DEFN # define PCRE_EXP_DEFN PCRE_EXP_DECL # endif # ifndef PCRE_EXP_DATA_DEFN # define PCRE_EXP_DATA_DEFN # endif # endif #endif /* When compiling with the MSVC compiler, it is sometimes necessary to include a "calling convention" before exported function names. (This is secondhand information; I know nothing about MSVC myself). For example, something like void __cdecl function(....) might be needed. In order so make this easy, all the exported functions have PCRE_CALL_CONVENTION just before their names. It is rarely needed; if not set, we ensure here that it has no effect. */ #ifndef PCRE_CALL_CONVENTION #define PCRE_CALL_CONVENTION #endif /* We need to have types that specify unsigned 8, 16 and 32-bit integers. We cannot determine these outside the compilation (e.g. by running a program as part of "configure") because PCRE is often cross-compiled for use on other systems. Instead we make use of the maximum sizes that are available at preprocessor time in standard C environments. */ typedef unsigned char pcre_uint8; #if USHRT_MAX == 65535 typedef unsigned short pcre_uint16; typedef short pcre_int16; #define PCRE_UINT16_MAX USHRT_MAX #define PCRE_INT16_MAX SHRT_MAX #elif UINT_MAX == 65535 typedef unsigned int pcre_uint16; typedef int pcre_int16; #define PCRE_UINT16_MAX UINT_MAX #define PCRE_INT16_MAX INT_MAX #else #error Cannot determine a type for 16-bit integers #endif #if UINT_MAX == 4294967295U typedef unsigned int pcre_uint32; typedef int pcre_int32; #define PCRE_UINT32_MAX UINT_MAX #define PCRE_INT32_MAX INT_MAX #elif ULONG_MAX == 4294967295UL typedef unsigned long int pcre_uint32; typedef long int pcre_int32; #define PCRE_UINT32_MAX ULONG_MAX #define PCRE_INT32_MAX LONG_MAX #else #error Cannot determine a type for 32-bit integers #endif /* When checking for integer overflow in pcre_compile(), we need to handle large integers. If a 64-bit integer type is available, we can use that. Otherwise we have to cast to double, which of course requires floating point arithmetic. Handle this by defining a macro for the appropriate type. If stdint.h is available, include it; it may define INT64_MAX. Systems that do not have stdint.h (e.g. Solaris) may have inttypes.h. The macro int64_t may be set by "configure". */ #if defined HAVE_STDINT_H #include #elif defined HAVE_INTTYPES_H #include #endif #if defined INT64_MAX || defined int64_t #define INT64_OR_DOUBLE int64_t #else #define INT64_OR_DOUBLE double #endif /* All character handling must be done as unsigned characters. Otherwise there are problems with top-bit-set characters and functions such as isspace(). However, we leave the interface to the outside world as char * or short *, because that should make things easier for callers. This character type is called pcre_uchar. The IN_UCHARS macro multiply its argument with the byte size of the current pcre_uchar type. Useful for memcpy and such operations, whose require the byte size of their input/output buffers. The MAX_255 macro checks whether its pcre_uchar input is less than 256. The TABLE_GET macro is designed for accessing elements of tables whose contain exactly 256 items. When the character is able to contain more than 256 items, some check is needed before accessing these tables. */ #if defined COMPILE_PCRE8 typedef unsigned char pcre_uchar; #define IN_UCHARS(x) (x) #define MAX_255(c) 1 #define TABLE_GET(c, table, default) ((table)[c]) #elif defined COMPILE_PCRE16 #if USHRT_MAX != 65535 /* This is a warning message. Change PCRE_UCHAR16 to a 16 bit data type in pcre.h(.in) and disable (comment out) this message. */ #error Warning: PCRE_UCHAR16 is not a 16 bit data type. #endif typedef pcre_uint16 pcre_uchar; #define UCHAR_SHIFT (1) #define IN_UCHARS(x) ((x) * 2) #define MAX_255(c) ((c) <= 255u) #define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default)) #elif defined COMPILE_PCRE32 typedef pcre_uint32 pcre_uchar; #define UCHAR_SHIFT (2) #define IN_UCHARS(x) ((x) * 4) #define MAX_255(c) ((c) <= 255u) #define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default)) #else #error Unsupported compiling mode #endif /* COMPILE_PCRE[8|16|32] */ /* This is an unsigned int value that no character can ever have. UTF-8 characters only go up to 0x7fffffff (though Unicode doesn't go beyond 0x0010ffff). */ #define NOTACHAR 0xffffffff /* PCRE is able to support several different kinds of newline (CR, LF, CRLF, "any" and "anycrlf" at present). The following macros are used to package up testing for newlines. NLBLOCK, PSSTART, and PSEND are defined in the various modules to indicate in which datablock the parameters exist, and what the start/end of string field names are. */ #define NLTYPE_FIXED 0 /* Newline is a fixed length string */ #define NLTYPE_ANY 1 /* Newline is any Unicode line ending */ #define NLTYPE_ANYCRLF 2 /* Newline is CR, LF, or CRLF */ /* This macro checks for a newline at the given position */ #define IS_NEWLINE(p) \ ((NLBLOCK->nltype != NLTYPE_FIXED)? \ ((p) < NLBLOCK->PSEND && \ PRIV(is_newline)((p), NLBLOCK->nltype, NLBLOCK->PSEND, \ &(NLBLOCK->nllen), utf)) \ : \ ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \ UCHAR21TEST(p) == NLBLOCK->nl[0] && \ (NLBLOCK->nllen == 1 || UCHAR21TEST(p+1) == NLBLOCK->nl[1]) \ ) \ ) /* This macro checks for a newline immediately preceding the given position */ #define WAS_NEWLINE(p) \ ((NLBLOCK->nltype != NLTYPE_FIXED)? \ ((p) > NLBLOCK->PSSTART && \ PRIV(was_newline)((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \ &(NLBLOCK->nllen), utf)) \ : \ ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \ UCHAR21TEST(p - NLBLOCK->nllen) == NLBLOCK->nl[0] && \ (NLBLOCK->nllen == 1 || UCHAR21TEST(p - NLBLOCK->nllen + 1) == NLBLOCK->nl[1]) \ ) \ ) /* When PCRE is compiled as a C++ library, the subject pointer can be replaced with a custom type. This makes it possible, for example, to allow pcre_exec() to process subject strings that are discontinuous by using a smart pointer class. It must always be possible to inspect all of the subject string in pcre_exec() because of the way it backtracks. Two macros are required in the normal case, for sign-unspecified and unsigned char pointers. The former is used for the external interface and appears in pcre.h, which is why its name must begin with PCRE_. */ #ifdef CUSTOM_SUBJECT_PTR #define PCRE_PUCHAR CUSTOM_SUBJECT_PTR #else #define PCRE_PUCHAR const pcre_uchar * #endif /* Include the public PCRE header and the definitions of UCP character property values. */ #include "pcre.h" #include "ucp.h" #ifdef COMPILE_PCRE32 /* Assert that the public PCRE_UCHAR32 is a 32-bit type */ typedef int __assert_pcre_uchar32_size[sizeof(PCRE_UCHAR32) == 4 ? 1 : -1]; #endif /* When compiling for use with the Virtual Pascal compiler, these functions need to have their names changed. PCRE must be compiled with the -DVPCOMPAT option on the command line. */ #ifdef VPCOMPAT #define strlen(s) _strlen(s) #define strncmp(s1,s2,m) _strncmp(s1,s2,m) #define memcmp(s,c,n) _memcmp(s,c,n) #define memcpy(d,s,n) _memcpy(d,s,n) #define memmove(d,s,n) _memmove(d,s,n) #define memset(s,c,n) _memset(s,c,n) #else /* VPCOMPAT */ /* To cope with SunOS4 and other systems that lack memmove() but have bcopy(), define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY is set. Otherwise, include an emulating function for those systems that have neither (there some non-Unix environments where this is the case). */ #ifndef HAVE_MEMMOVE #undef memmove /* some systems may have a macro */ #ifdef HAVE_BCOPY #define memmove(a, b, c) bcopy(b, a, c) #else /* HAVE_BCOPY */ static void * pcre_memmove(void *d, const void *s, size_t n) { size_t i; unsigned char *dest = (unsigned char *)d; const unsigned char *src = (const unsigned char *)s; if (dest > src) { dest += n; src += n; for (i = 0; i < n; ++i) *(--dest) = *(--src); return (void *)dest; } else { for (i = 0; i < n; ++i) *dest++ = *src++; return (void *)(dest - n); } } #define memmove(a, b, c) pcre_memmove(a, b, c) #endif /* not HAVE_BCOPY */ #endif /* not HAVE_MEMMOVE */ #endif /* not VPCOMPAT */ /* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored in big-endian order) by default. These are used, for example, to link from the start of a subpattern to its alternatives and its end. The use of 2 bytes per offset limits the size of the compiled regex to around 64K, which is big enough for almost everybody. However, I received a request for an even bigger limit. For this reason, and also to make the code easier to maintain, the storing and loading of offsets from the byte string is now handled by the macros that are defined here. The macros are controlled by the value of LINK_SIZE. This defaults to 2 in the config.h file, but can be overridden by using -D on the command line. This is automated on Unix systems via the "configure" command. */ #if defined COMPILE_PCRE8 #if LINK_SIZE == 2 #define PUT(a,n,d) \ (a[n] = (d) >> 8), \ (a[(n)+1] = (d) & 255) #define GET(a,n) \ (((a)[n] << 8) | (a)[(n)+1]) #define MAX_PATTERN_SIZE (1 << 16) #elif LINK_SIZE == 3 #define PUT(a,n,d) \ (a[n] = (d) >> 16), \ (a[(n)+1] = (d) >> 8), \ (a[(n)+2] = (d) & 255) #define GET(a,n) \ (((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2]) #define MAX_PATTERN_SIZE (1 << 24) #elif LINK_SIZE == 4 #define PUT(a,n,d) \ (a[n] = (d) >> 24), \ (a[(n)+1] = (d) >> 16), \ (a[(n)+2] = (d) >> 8), \ (a[(n)+3] = (d) & 255) #define GET(a,n) \ (((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3]) /* Keep it positive */ #define MAX_PATTERN_SIZE (1 << 30) #else #error LINK_SIZE must be either 2, 3, or 4 #endif #elif defined COMPILE_PCRE16 #if LINK_SIZE == 2 /* Redefine LINK_SIZE as a multiple of sizeof(pcre_uchar) */ #undef LINK_SIZE #define LINK_SIZE 1 #define PUT(a,n,d) \ (a[n] = (d)) #define GET(a,n) \ (a[n]) #define MAX_PATTERN_SIZE (1 << 16) #elif LINK_SIZE == 3 || LINK_SIZE == 4 /* Redefine LINK_SIZE as a multiple of sizeof(pcre_uchar) */ #undef LINK_SIZE #define LINK_SIZE 2 #define PUT(a,n,d) \ (a[n] = (d) >> 16), \ (a[(n)+1] = (d) & 65535) #define GET(a,n) \ (((a)[n] << 16) | (a)[(n)+1]) /* Keep it positive */ #define MAX_PATTERN_SIZE (1 << 30) #else #error LINK_SIZE must be either 2, 3, or 4 #endif #elif defined COMPILE_PCRE32 /* Only supported LINK_SIZE is 4 */ /* Redefine LINK_SIZE as a multiple of sizeof(pcre_uchar) */ #undef LINK_SIZE #define LINK_SIZE 1 #define PUT(a,n,d) \ (a[n] = (d)) #define GET(a,n) \ (a[n]) /* Keep it positive */ #define MAX_PATTERN_SIZE (1 << 30) #else #error Unsupported compiling mode #endif /* COMPILE_PCRE[8|16|32] */ /* Convenience macro defined in terms of the others */ #define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE /* PCRE uses some other 2-byte quantities that do not change when the size of offsets changes. There are used for repeat counts and for other things such as capturing parenthesis numbers in back references. */ #if defined COMPILE_PCRE8 #define IMM2_SIZE 2 #define PUT2(a,n,d) \ a[n] = (d) >> 8; \ a[(n)+1] = (d) & 255 /* For reasons that I do not understand, the expression in this GET2 macro is treated by gcc as a signed expression, even when a is declared as unsigned. It seems that any kind of arithmetic results in a signed value. */ #define GET2(a,n) \ (unsigned int)(((a)[n] << 8) | (a)[(n)+1]) #elif defined COMPILE_PCRE16 #define IMM2_SIZE 1 #define PUT2(a,n,d) \ a[n] = d #define GET2(a,n) \ a[n] #elif defined COMPILE_PCRE32 #define IMM2_SIZE 1 #define PUT2(a,n,d) \ a[n] = d #define GET2(a,n) \ a[n] #else #error Unsupported compiling mode #endif /* COMPILE_PCRE[8|16|32] */ #define PUT2INC(a,n,d) PUT2(a,n,d), a += IMM2_SIZE /* The maximum length of a MARK name is currently one data unit; it may be changed in future to be a fixed number of bytes or to depend on LINK_SIZE. */ #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 #define MAX_MARK ((1u << 16) - 1) #else #define MAX_MARK ((1u << 8) - 1) #endif /* There is a proposed future special "UTF-21" mode, in which only the lowest 21 bits of a 32-bit character are interpreted as UTF, with the remaining 11 high-order bits available to the application for other uses. In preparation for the future implementation of this mode, there are macros that load a data item and, if in this special mode, mask it to 21 bits. These macros all have names starting with UCHAR21. In all other modes, including the normal 32-bit library, the macros all have the same simple definitions. When the new mode is implemented, it is expected that these definitions will be varied appropriately using #ifdef when compiling the library that supports the special mode. */ #define UCHAR21(eptr) (*(eptr)) #define UCHAR21TEST(eptr) (*(eptr)) #define UCHAR21INC(eptr) (*(eptr)++) #define UCHAR21INCTEST(eptr) (*(eptr)++) /* When UTF encoding is being used, a character is no longer just a single byte in 8-bit mode or a single short in 16-bit mode. The macros for character handling generate simple sequences when used in the basic mode, and more complicated ones for UTF characters. GETCHARLENTEST and other macros are not used when UTF is not supported. To make sure they can never even appear when UTF support is omitted, we don't even define them. */ #ifndef SUPPORT_UTF /* #define MAX_VALUE_FOR_SINGLE_CHAR */ /* #define HAS_EXTRALEN(c) */ /* #define GET_EXTRALEN(c) */ /* #define NOT_FIRSTCHAR(c) */ #define GETCHAR(c, eptr) c = *eptr; #define GETCHARTEST(c, eptr) c = *eptr; #define GETCHARINC(c, eptr) c = *eptr++; #define GETCHARINCTEST(c, eptr) c = *eptr++; #define GETCHARLEN(c, eptr, len) c = *eptr; /* #define GETCHARLENTEST(c, eptr, len) */ /* #define BACKCHAR(eptr) */ /* #define FORWARDCHAR(eptr) */ /* #define ACROSSCHAR(condition, eptr, action) */ #else /* SUPPORT_UTF */ /* Tests whether the code point needs extra characters to decode. */ #define HASUTF8EXTRALEN(c) ((c) >= 0xc0) /* Base macro to pick up the remaining bytes of a UTF-8 character, not advancing the pointer. */ #define GETUTF8(c, eptr) \ { \ if ((c & 0x20) == 0) \ c = ((c & 0x1f) << 6) | (eptr[1] & 0x3f); \ else if ((c & 0x10) == 0) \ c = ((c & 0x0f) << 12) | ((eptr[1] & 0x3f) << 6) | (eptr[2] & 0x3f); \ else if ((c & 0x08) == 0) \ c = ((c & 0x07) << 18) | ((eptr[1] & 0x3f) << 12) | \ ((eptr[2] & 0x3f) << 6) | (eptr[3] & 0x3f); \ else if ((c & 0x04) == 0) \ c = ((c & 0x03) << 24) | ((eptr[1] & 0x3f) << 18) | \ ((eptr[2] & 0x3f) << 12) | ((eptr[3] & 0x3f) << 6) | \ (eptr[4] & 0x3f); \ else \ c = ((c & 0x01) << 30) | ((eptr[1] & 0x3f) << 24) | \ ((eptr[2] & 0x3f) << 18) | ((eptr[3] & 0x3f) << 12) | \ ((eptr[4] & 0x3f) << 6) | (eptr[5] & 0x3f); \ } /* Base macro to pick up the remaining bytes of a UTF-8 character, advancing the pointer. */ #define GETUTF8INC(c, eptr) \ { \ if ((c & 0x20) == 0) \ c = ((c & 0x1f) << 6) | (*eptr++ & 0x3f); \ else if ((c & 0x10) == 0) \ { \ c = ((c & 0x0f) << 12) | ((*eptr & 0x3f) << 6) | (eptr[1] & 0x3f); \ eptr += 2; \ } \ else if ((c & 0x08) == 0) \ { \ c = ((c & 0x07) << 18) | ((*eptr & 0x3f) << 12) | \ ((eptr[1] & 0x3f) << 6) | (eptr[2] & 0x3f); \ eptr += 3; \ } \ else if ((c & 0x04) == 0) \ { \ c = ((c & 0x03) << 24) | ((*eptr & 0x3f) << 18) | \ ((eptr[1] & 0x3f) << 12) | ((eptr[2] & 0x3f) << 6) | \ (eptr[3] & 0x3f); \ eptr += 4; \ } \ else \ { \ c = ((c & 0x01) << 30) | ((*eptr & 0x3f) << 24) | \ ((eptr[1] & 0x3f) << 18) | ((eptr[2] & 0x3f) << 12) | \ ((eptr[3] & 0x3f) << 6) | (eptr[4] & 0x3f); \ eptr += 5; \ } \ } #if defined COMPILE_PCRE8 /* These macros were originally written in the form of loops that used data from the tables whose names start with PRIV(utf8_table). They were rewritten by a user so as not to use loops, because in some environments this gives a significant performance advantage, and it seems never to do any harm. */ /* Tells the biggest code point which can be encoded as a single character. */ #define MAX_VALUE_FOR_SINGLE_CHAR 127 /* Tests whether the code point needs extra characters to decode. */ #define HAS_EXTRALEN(c) ((c) >= 0xc0) /* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE. Otherwise it has an undefined behaviour. */ #define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3f]) /* Returns TRUE, if the given character is not the first character of a UTF sequence. */ #define NOT_FIRSTCHAR(c) (((c) & 0xc0) == 0x80) /* Get the next UTF-8 character, not advancing the pointer. This is called when we know we are in UTF-8 mode. */ #define GETCHAR(c, eptr) \ c = *eptr; \ if (c >= 0xc0) GETUTF8(c, eptr); /* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the pointer. */ #define GETCHARTEST(c, eptr) \ c = *eptr; \ if (utf && c >= 0xc0) GETUTF8(c, eptr); /* Get the next UTF-8 character, advancing the pointer. This is called when we know we are in UTF-8 mode. */ #define GETCHARINC(c, eptr) \ c = *eptr++; \ if (c >= 0xc0) GETUTF8INC(c, eptr); /* Get the next character, testing for UTF-8 mode, and advancing the pointer. This is called when we don't know if we are in UTF-8 mode. */ #define GETCHARINCTEST(c, eptr) \ c = *eptr++; \ if (utf && c >= 0xc0) GETUTF8INC(c, eptr); /* Base macro to pick up the remaining bytes of a UTF-8 character, not advancing the pointer, incrementing the length. */ #define GETUTF8LEN(c, eptr, len) \ { \ if ((c & 0x20) == 0) \ { \ c = ((c & 0x1f) << 6) | (eptr[1] & 0x3f); \ len++; \ } \ else if ((c & 0x10) == 0) \ { \ c = ((c & 0x0f) << 12) | ((eptr[1] & 0x3f) << 6) | (eptr[2] & 0x3f); \ len += 2; \ } \ else if ((c & 0x08) == 0) \ {\ c = ((c & 0x07) << 18) | ((eptr[1] & 0x3f) << 12) | \ ((eptr[2] & 0x3f) << 6) | (eptr[3] & 0x3f); \ len += 3; \ } \ else if ((c & 0x04) == 0) \ { \ c = ((c & 0x03) << 24) | ((eptr[1] & 0x3f) << 18) | \ ((eptr[2] & 0x3f) << 12) | ((eptr[3] & 0x3f) << 6) | \ (eptr[4] & 0x3f); \ len += 4; \ } \ else \ {\ c = ((c & 0x01) << 30) | ((eptr[1] & 0x3f) << 24) | \ ((eptr[2] & 0x3f) << 18) | ((eptr[3] & 0x3f) << 12) | \ ((eptr[4] & 0x3f) << 6) | (eptr[5] & 0x3f); \ len += 5; \ } \ } /* Get the next UTF-8 character, not advancing the pointer, incrementing length if there are extra bytes. This is called when we know we are in UTF-8 mode. */ #define GETCHARLEN(c, eptr, len) \ c = *eptr; \ if (c >= 0xc0) GETUTF8LEN(c, eptr, len); /* Get the next UTF-8 character, testing for UTF-8 mode, not advancing the pointer, incrementing length if there are extra bytes. This is called when we do not know if we are in UTF-8 mode. */ #define GETCHARLENTEST(c, eptr, len) \ c = *eptr; \ if (utf && c >= 0xc0) GETUTF8LEN(c, eptr, len); /* If the pointer is not at the start of a character, move it back until it is. This is called only in UTF-8 mode - we don't put a test within the macro because almost all calls are already within a block of UTF-8 only code. */ #define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr-- /* Same as above, just in the other direction. */ #define FORWARDCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr++ /* Same as above, but it allows a fully customizable form. */ #define ACROSSCHAR(condition, eptr, action) \ while((condition) && ((eptr) & 0xc0) == 0x80) action #elif defined COMPILE_PCRE16 /* Tells the biggest code point which can be encoded as a single character. */ #define MAX_VALUE_FOR_SINGLE_CHAR 65535 /* Tests whether the code point needs extra characters to decode. */ #define HAS_EXTRALEN(c) (((c) & 0xfc00) == 0xd800) /* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE. Otherwise it has an undefined behaviour. */ #define GET_EXTRALEN(c) 1 /* Returns TRUE, if the given character is not the first character of a UTF sequence. */ #define NOT_FIRSTCHAR(c) (((c) & 0xfc00) == 0xdc00) /* Base macro to pick up the low surrogate of a UTF-16 character, not advancing the pointer. */ #define GETUTF16(c, eptr) \ { c = (((c & 0x3ff) << 10) | (eptr[1] & 0x3ff)) + 0x10000; } /* Get the next UTF-16 character, not advancing the pointer. This is called when we know we are in UTF-16 mode. */ #define GETCHAR(c, eptr) \ c = *eptr; \ if ((c & 0xfc00) == 0xd800) GETUTF16(c, eptr); /* Get the next UTF-16 character, testing for UTF-16 mode, and not advancing the pointer. */ #define GETCHARTEST(c, eptr) \ c = *eptr; \ if (utf && (c & 0xfc00) == 0xd800) GETUTF16(c, eptr); /* Base macro to pick up the low surrogate of a UTF-16 character, advancing the pointer. */ #define GETUTF16INC(c, eptr) \ { c = (((c & 0x3ff) << 10) | (*eptr++ & 0x3ff)) + 0x10000; } /* Get the next UTF-16 character, advancing the pointer. This is called when we know we are in UTF-16 mode. */ #define GETCHARINC(c, eptr) \ c = *eptr++; \ if ((c & 0xfc00) == 0xd800) GETUTF16INC(c, eptr); /* Get the next character, testing for UTF-16 mode, and advancing the pointer. This is called when we don't know if we are in UTF-16 mode. */ #define GETCHARINCTEST(c, eptr) \ c = *eptr++; \ if (utf && (c & 0xfc00) == 0xd800) GETUTF16INC(c, eptr); /* Base macro to pick up the low surrogate of a UTF-16 character, not advancing the pointer, incrementing the length. */ #define GETUTF16LEN(c, eptr, len) \ { c = (((c & 0x3ff) << 10) | (eptr[1] & 0x3ff)) + 0x10000; len++; } /* Get the next UTF-16 character, not advancing the pointer, incrementing length if there is a low surrogate. This is called when we know we are in UTF-16 mode. */ #define GETCHARLEN(c, eptr, len) \ c = *eptr; \ if ((c & 0xfc00) == 0xd800) GETUTF16LEN(c, eptr, len); /* Get the next UTF-816character, testing for UTF-16 mode, not advancing the pointer, incrementing length if there is a low surrogate. This is called when we do not know if we are in UTF-16 mode. */ #define GETCHARLENTEST(c, eptr, len) \ c = *eptr; \ if (utf && (c & 0xfc00) == 0xd800) GETUTF16LEN(c, eptr, len); /* If the pointer is not at the start of a character, move it back until it is. This is called only in UTF-16 mode - we don't put a test within the macro because almost all calls are already within a block of UTF-16 only code. */ #define BACKCHAR(eptr) if ((*eptr & 0xfc00) == 0xdc00) eptr-- /* Same as above, just in the other direction. */ #define FORWARDCHAR(eptr) if ((*eptr & 0xfc00) == 0xdc00) eptr++ /* Same as above, but it allows a fully customizable form. */ #define ACROSSCHAR(condition, eptr, action) \ if ((condition) && ((eptr) & 0xfc00) == 0xdc00) action #elif defined COMPILE_PCRE32 /* These are trivial for the 32-bit library, since all UTF-32 characters fit into one pcre_uchar unit. */ #define MAX_VALUE_FOR_SINGLE_CHAR (0x10ffffu) #define HAS_EXTRALEN(c) (0) #define GET_EXTRALEN(c) (0) #define NOT_FIRSTCHAR(c) (0) /* Get the next UTF-32 character, not advancing the pointer. This is called when we know we are in UTF-32 mode. */ #define GETCHAR(c, eptr) \ c = *(eptr); /* Get the next UTF-32 character, testing for UTF-32 mode, and not advancing the pointer. */ #define GETCHARTEST(c, eptr) \ c = *(eptr); /* Get the next UTF-32 character, advancing the pointer. This is called when we know we are in UTF-32 mode. */ #define GETCHARINC(c, eptr) \ c = *((eptr)++); /* Get the next character, testing for UTF-32 mode, and advancing the pointer. This is called when we don't know if we are in UTF-32 mode. */ #define GETCHARINCTEST(c, eptr) \ c = *((eptr)++); /* Get the next UTF-32 character, not advancing the pointer, not incrementing length (since all UTF-32 is of length 1). This is called when we know we are in UTF-32 mode. */ #define GETCHARLEN(c, eptr, len) \ GETCHAR(c, eptr) /* Get the next UTF-32character, testing for UTF-32 mode, not advancing the pointer, not incrementing the length (since all UTF-32 is of length 1). This is called when we do not know if we are in UTF-32 mode. */ #define GETCHARLENTEST(c, eptr, len) \ GETCHARTEST(c, eptr) /* If the pointer is not at the start of a character, move it back until it is. This is called only in UTF-32 mode - we don't put a test within the macro because almost all calls are already within a block of UTF-32 only code. These are all no-ops since all UTF-32 characters fit into one pcre_uchar. */ #define BACKCHAR(eptr) do { } while (0) /* Same as above, just in the other direction. */ #define FORWARDCHAR(eptr) do { } while (0) /* Same as above, but it allows a fully customizable form. */ #define ACROSSCHAR(condition, eptr, action) do { } while (0) #else #error Unsupported compiling mode #endif /* COMPILE_PCRE[8|16|32] */ #endif /* SUPPORT_UTF */ /* Tests for Unicode horizontal and vertical whitespace characters must check a number of different values. Using a switch statement for this generates the fastest code (no loop, no memory access), and there are several places in the interpreter code where this happens. In order to ensure that all the case lists remain in step, we use macros so that there is only one place where the lists are defined. These values are also required as lists in pcre_compile.c when processing \h, \H, \v and \V in a character class. The lists are defined in pcre_tables.c, but macros that define the values are here so that all the definitions are together. The lists must be in ascending character order, terminated by NOTACHAR (which is 0xffffffff). Any changes should ensure that the various macros are kept in step with each other. NOTE: The values also appear in pcre_jit_compile.c. */ /* ------ ASCII/Unicode environments ------ */ #ifndef EBCDIC #define HSPACE_LIST \ CHAR_HT, CHAR_SPACE, CHAR_NBSP, \ 0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, \ 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202f, 0x205f, 0x3000, \ NOTACHAR #define HSPACE_MULTIBYTE_CASES \ case 0x1680: /* OGHAM SPACE MARK */ \ case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ \ case 0x2000: /* EN QUAD */ \ case 0x2001: /* EM QUAD */ \ case 0x2002: /* EN SPACE */ \ case 0x2003: /* EM SPACE */ \ case 0x2004: /* THREE-PER-EM SPACE */ \ case 0x2005: /* FOUR-PER-EM SPACE */ \ case 0x2006: /* SIX-PER-EM SPACE */ \ case 0x2007: /* FIGURE SPACE */ \ case 0x2008: /* PUNCTUATION SPACE */ \ case 0x2009: /* THIN SPACE */ \ case 0x200A: /* HAIR SPACE */ \ case 0x202f: /* NARROW NO-BREAK SPACE */ \ case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ \ case 0x3000 /* IDEOGRAPHIC SPACE */ #define HSPACE_BYTE_CASES \ case CHAR_HT: \ case CHAR_SPACE: \ case CHAR_NBSP #define HSPACE_CASES \ HSPACE_BYTE_CASES: \ HSPACE_MULTIBYTE_CASES #define VSPACE_LIST \ CHAR_LF, CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, 0x2028, 0x2029, NOTACHAR #define VSPACE_MULTIBYTE_CASES \ case 0x2028: /* LINE SEPARATOR */ \ case 0x2029 /* PARAGRAPH SEPARATOR */ #define VSPACE_BYTE_CASES \ case CHAR_LF: \ case CHAR_VT: \ case CHAR_FF: \ case CHAR_CR: \ case CHAR_NEL #define VSPACE_CASES \ VSPACE_BYTE_CASES: \ VSPACE_MULTIBYTE_CASES /* ------ EBCDIC environments ------ */ #else #define HSPACE_LIST CHAR_HT, CHAR_SPACE, CHAR_NBSP, NOTACHAR #define HSPACE_BYTE_CASES \ case CHAR_HT: \ case CHAR_SPACE: \ case CHAR_NBSP #define HSPACE_CASES HSPACE_BYTE_CASES #ifdef EBCDIC_NL25 #define VSPACE_LIST \ CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, CHAR_LF, NOTACHAR #else #define VSPACE_LIST \ CHAR_VT, CHAR_FF, CHAR_CR, CHAR_LF, CHAR_NEL, NOTACHAR #endif #define VSPACE_BYTE_CASES \ case CHAR_LF: \ case CHAR_VT: \ case CHAR_FF: \ case CHAR_CR: \ case CHAR_NEL #define VSPACE_CASES VSPACE_BYTE_CASES #endif /* EBCDIC */ /* ------ End of whitespace macros ------ */ /* Private flags containing information about the compiled regex. They used to live at the top end of the options word, but that got almost full, so they were moved to a 16-bit flags word - which got almost full, so now they are in a 32-bit flags word. From release 8.00, PCRE_NOPARTIAL is unused, as the restrictions on partial matching have been lifted. It remains for backwards compatibility. */ #define PCRE_MODE8 0x00000001 /* compiled in 8 bit mode */ #define PCRE_MODE16 0x00000002 /* compiled in 16 bit mode */ #define PCRE_MODE32 0x00000004 /* compiled in 32 bit mode */ #define PCRE_FIRSTSET 0x00000010 /* first_char is set */ #define PCRE_FCH_CASELESS 0x00000020 /* caseless first char */ #define PCRE_REQCHSET 0x00000040 /* req_byte is set */ #define PCRE_RCH_CASELESS 0x00000080 /* caseless requested char */ #define PCRE_STARTLINE 0x00000100 /* start after \n for multiline */ #define PCRE_NOPARTIAL 0x00000200 /* can't use partial with this regex */ #define PCRE_JCHANGED 0x00000400 /* j option used in regex */ #define PCRE_HASCRORLF 0x00000800 /* explicit \r or \n in pattern */ #define PCRE_HASTHEN 0x00001000 /* pattern contains (*THEN) */ #define PCRE_MLSET 0x00002000 /* match limit set by regex */ #define PCRE_RLSET 0x00004000 /* recursion limit set by regex */ #define PCRE_MATCH_EMPTY 0x00008000 /* pattern can match empty string */ #if defined COMPILE_PCRE8 #define PCRE_MODE PCRE_MODE8 #elif defined COMPILE_PCRE16 #define PCRE_MODE PCRE_MODE16 #elif defined COMPILE_PCRE32 #define PCRE_MODE PCRE_MODE32 #endif #define PCRE_MODE_MASK (PCRE_MODE8 | PCRE_MODE16 | PCRE_MODE32) /* Flags for the "extra" block produced by pcre_study(). */ #define PCRE_STUDY_MAPPED 0x0001 /* a map of starting chars exists */ #define PCRE_STUDY_MINLEN 0x0002 /* a minimum length field exists */ /* Masks for identifying the public options that are permitted at compile time, run time, or study time, respectively. */ #define PCRE_NEWLINE_BITS (PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|PCRE_NEWLINE_ANY| \ PCRE_NEWLINE_ANYCRLF) #define PUBLIC_COMPILE_OPTIONS \ (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \ PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \ PCRE_NO_AUTO_CAPTURE|PCRE_NO_AUTO_POSSESS| \ PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE| \ PCRE_DUPNAMES|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE| \ PCRE_JAVASCRIPT_COMPAT|PCRE_UCP|PCRE_NO_START_OPTIMIZE|PCRE_NEVER_UTF) #define PUBLIC_EXEC_OPTIONS \ (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NOTEMPTY_ATSTART| \ PCRE_NO_UTF8_CHECK|PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT|PCRE_NEWLINE_BITS| \ PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE|PCRE_NO_START_OPTIMIZE) #define PUBLIC_DFA_EXEC_OPTIONS \ (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NOTEMPTY_ATSTART| \ PCRE_NO_UTF8_CHECK|PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT|PCRE_DFA_SHORTEST| \ PCRE_DFA_RESTART|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE| \ PCRE_NO_START_OPTIMIZE) #define PUBLIC_STUDY_OPTIONS \ (PCRE_STUDY_JIT_COMPILE|PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE| \ PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE|PCRE_STUDY_EXTRA_NEEDED) #define PUBLIC_JIT_EXEC_OPTIONS \ (PCRE_NO_UTF8_CHECK|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|\ PCRE_NOTEMPTY_ATSTART|PCRE_PARTIAL_SOFT|PCRE_PARTIAL_HARD) /* Magic number to provide a small check against being handed junk. */ #define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */ /* This variable is used to detect a loaded regular expression in different endianness. */ #define REVERSED_MAGIC_NUMBER 0x45524350UL /* 'ERCP' */ /* The maximum remaining length of subject we are prepared to search for a req_byte match. */ #define REQ_BYTE_MAX 1000 /* Miscellaneous definitions. The #ifndef is to pacify compiler warnings in environments where these macros are defined elsewhere. Unfortunately, there is no way to do the same for the typedef. */ typedef int BOOL; #ifndef FALSE #define FALSE 0 #define TRUE 1 #endif /* If PCRE is to support UTF-8 on EBCDIC platforms, we cannot use normal character constants like '*' because the compiler would emit their EBCDIC code, which is different from their ASCII/UTF-8 code. Instead we define macros for the characters so that they always use the ASCII/UTF-8 code when UTF-8 support is enabled. When UTF-8 support is not enabled, the definitions use character literals. Both character and string versions of each character are needed, and there are some longer strings as well. This means that, on EBCDIC platforms, the PCRE library can handle either EBCDIC, or UTF-8, but not both. To support both in the same compiled library would need different lookups depending on whether PCRE_UTF8 was set or not. This would make it impossible to use characters in switch/case statements, which would reduce performance. For a theoretical use (which nobody has asked for) in a minority area (EBCDIC platforms), this is not sensible. Any application that did need both could compile two versions of the library, using macros to give the functions distinct names. */ #ifndef SUPPORT_UTF /* UTF-8 support is not enabled; use the platform-dependent character literals so that PCRE works in both ASCII and EBCDIC environments, but only in non-UTF mode. Newline characters are problematic in EBCDIC. Though it has CR and LF characters, a common practice has been to use its NL (0x15) character as the line terminator in C-like processing environments. However, sometimes the LF (0x25) character is used instead, according to this Unicode document: http://unicode.org/standard/reports/tr13/tr13-5.html PCRE defaults EBCDIC NL to 0x15, but has a build-time option to select 0x25 instead. Whichever is *not* chosen is defined as NEL. In both ASCII and EBCDIC environments, CHAR_NL and CHAR_LF are synonyms for the same code point. */ #ifdef EBCDIC #ifndef EBCDIC_NL25 #define CHAR_NL '\x15' #define CHAR_NEL '\x25' #define STR_NL "\x15" #define STR_NEL "\x25" #else #define CHAR_NL '\x25' #define CHAR_NEL '\x15' #define STR_NL "\x25" #define STR_NEL "\x15" #endif #define CHAR_LF CHAR_NL #define STR_LF STR_NL #define CHAR_ESC '\047' #define CHAR_DEL '\007' #define CHAR_NBSP '\x41' #define STR_ESC "\047" #define STR_DEL "\007" #else /* Not EBCDIC */ /* In ASCII/Unicode, linefeed is '\n' and we equate this to NL for compatibility. NEL is the Unicode newline character; make sure it is a positive value. */ #define CHAR_LF '\n' #define CHAR_NL CHAR_LF #define CHAR_NEL ((unsigned char)'\x85') #define CHAR_ESC '\033' #define CHAR_DEL '\177' #define CHAR_NBSP ((unsigned char)'\xa0') #define STR_LF "\n" #define STR_NL STR_LF #define STR_NEL "\x85" #define STR_ESC "\033" #define STR_DEL "\177" #endif /* EBCDIC */ /* The remaining definitions work in both environments. */ #define CHAR_NULL '\0' #define CHAR_HT '\t' #define CHAR_VT '\v' #define CHAR_FF '\f' #define CHAR_CR '\r' #define CHAR_BS '\b' #define CHAR_BEL '\a' #define CHAR_SPACE ' ' #define CHAR_EXCLAMATION_MARK '!' #define CHAR_QUOTATION_MARK '"' #define CHAR_NUMBER_SIGN '#' #define CHAR_DOLLAR_SIGN '$' #define CHAR_PERCENT_SIGN '%' #define CHAR_AMPERSAND '&' #define CHAR_APOSTROPHE '\'' #define CHAR_LEFT_PARENTHESIS '(' #define CHAR_RIGHT_PARENTHESIS ')' #define CHAR_ASTERISK '*' #define CHAR_PLUS '+' #define CHAR_COMMA ',' #define CHAR_MINUS '-' #define CHAR_DOT '.' #define CHAR_SLASH '/' #define CHAR_0 '0' #define CHAR_1 '1' #define CHAR_2 '2' #define CHAR_3 '3' #define CHAR_4 '4' #define CHAR_5 '5' #define CHAR_6 '6' #define CHAR_7 '7' #define CHAR_8 '8' #define CHAR_9 '9' #define CHAR_COLON ':' #define CHAR_SEMICOLON ';' #define CHAR_LESS_THAN_SIGN '<' #define CHAR_EQUALS_SIGN '=' #define CHAR_GREATER_THAN_SIGN '>' #define CHAR_QUESTION_MARK '?' #define CHAR_COMMERCIAL_AT '@' #define CHAR_A 'A' #define CHAR_B 'B' #define CHAR_C 'C' #define CHAR_D 'D' #define CHAR_E 'E' #define CHAR_F 'F' #define CHAR_G 'G' #define CHAR_H 'H' #define CHAR_I 'I' #define CHAR_J 'J' #define CHAR_K 'K' #define CHAR_L 'L' #define CHAR_M 'M' #define CHAR_N 'N' #define CHAR_O 'O' #define CHAR_P 'P' #define CHAR_Q 'Q' #define CHAR_R 'R' #define CHAR_S 'S' #define CHAR_T 'T' #define CHAR_U 'U' #define CHAR_V 'V' #define CHAR_W 'W' #define CHAR_X 'X' #define CHAR_Y 'Y' #define CHAR_Z 'Z' #define CHAR_LEFT_SQUARE_BRACKET '[' #define CHAR_BACKSLASH '\\' #define CHAR_RIGHT_SQUARE_BRACKET ']' #define CHAR_CIRCUMFLEX_ACCENT '^' #define CHAR_UNDERSCORE '_' #define CHAR_GRAVE_ACCENT '`' #define CHAR_a 'a' #define CHAR_b 'b' #define CHAR_c 'c' #define CHAR_d 'd' #define CHAR_e 'e' #define CHAR_f 'f' #define CHAR_g 'g' #define CHAR_h 'h' #define CHAR_i 'i' #define CHAR_j 'j' #define CHAR_k 'k' #define CHAR_l 'l' #define CHAR_m 'm' #define CHAR_n 'n' #define CHAR_o 'o' #define CHAR_p 'p' #define CHAR_q 'q' #define CHAR_r 'r' #define CHAR_s 's' #define CHAR_t 't' #define CHAR_u 'u' #define CHAR_v 'v' #define CHAR_w 'w' #define CHAR_x 'x' #define CHAR_y 'y' #define CHAR_z 'z' #define CHAR_LEFT_CURLY_BRACKET '{' #define CHAR_VERTICAL_LINE '|' #define CHAR_RIGHT_CURLY_BRACKET '}' #define CHAR_TILDE '~' #define STR_HT "\t" #define STR_VT "\v" #define STR_FF "\f" #define STR_CR "\r" #define STR_BS "\b" #define STR_BEL "\a" #define STR_SPACE " " #define STR_EXCLAMATION_MARK "!" #define STR_QUOTATION_MARK "\"" #define STR_NUMBER_SIGN "#" #define STR_DOLLAR_SIGN "$" #define STR_PERCENT_SIGN "%" #define STR_AMPERSAND "&" #define STR_APOSTROPHE "'" #define STR_LEFT_PARENTHESIS "(" #define STR_RIGHT_PARENTHESIS ")" #define STR_ASTERISK "*" #define STR_PLUS "+" #define STR_COMMA "," #define STR_MINUS "-" #define STR_DOT "." #define STR_SLASH "/" #define STR_0 "0" #define STR_1 "1" #define STR_2 "2" #define STR_3 "3" #define STR_4 "4" #define STR_5 "5" #define STR_6 "6" #define STR_7 "7" #define STR_8 "8" #define STR_9 "9" #define STR_COLON ":" #define STR_SEMICOLON ";" #define STR_LESS_THAN_SIGN "<" #define STR_EQUALS_SIGN "=" #define STR_GREATER_THAN_SIGN ">" #define STR_QUESTION_MARK "?" #define STR_COMMERCIAL_AT "@" #define STR_A "A" #define STR_B "B" #define STR_C "C" #define STR_D "D" #define STR_E "E" #define STR_F "F" #define STR_G "G" #define STR_H "H" #define STR_I "I" #define STR_J "J" #define STR_K "K" #define STR_L "L" #define STR_M "M" #define STR_N "N" #define STR_O "O" #define STR_P "P" #define STR_Q "Q" #define STR_R "R" #define STR_S "S" #define STR_T "T" #define STR_U "U" #define STR_V "V" #define STR_W "W" #define STR_X "X" #define STR_Y "Y" #define STR_Z "Z" #define STR_LEFT_SQUARE_BRACKET "[" #define STR_BACKSLASH "\\" #define STR_RIGHT_SQUARE_BRACKET "]" #define STR_CIRCUMFLEX_ACCENT "^" #define STR_UNDERSCORE "_" #define STR_GRAVE_ACCENT "`" #define STR_a "a" #define STR_b "b" #define STR_c "c" #define STR_d "d" #define STR_e "e" #define STR_f "f" #define STR_g "g" #define STR_h "h" #define STR_i "i" #define STR_j "j" #define STR_k "k" #define STR_l "l" #define STR_m "m" #define STR_n "n" #define STR_o "o" #define STR_p "p" #define STR_q "q" #define STR_r "r" #define STR_s "s" #define STR_t "t" #define STR_u "u" #define STR_v "v" #define STR_w "w" #define STR_x "x" #define STR_y "y" #define STR_z "z" #define STR_LEFT_CURLY_BRACKET "{" #define STR_VERTICAL_LINE "|" #define STR_RIGHT_CURLY_BRACKET "}" #define STR_TILDE "~" #define STRING_ACCEPT0 "ACCEPT\0" #define STRING_COMMIT0 "COMMIT\0" #define STRING_F0 "F\0" #define STRING_FAIL0 "FAIL\0" #define STRING_MARK0 "MARK\0" #define STRING_PRUNE0 "PRUNE\0" #define STRING_SKIP0 "SKIP\0" #define STRING_THEN "THEN" #define STRING_alpha0 "alpha\0" #define STRING_lower0 "lower\0" #define STRING_upper0 "upper\0" #define STRING_alnum0 "alnum\0" #define STRING_ascii0 "ascii\0" #define STRING_blank0 "blank\0" #define STRING_cntrl0 "cntrl\0" #define STRING_digit0 "digit\0" #define STRING_graph0 "graph\0" #define STRING_print0 "print\0" #define STRING_punct0 "punct\0" #define STRING_space0 "space\0" #define STRING_word0 "word\0" #define STRING_xdigit "xdigit" #define STRING_DEFINE "DEFINE" #define STRING_WEIRD_STARTWORD "[:<:]]" #define STRING_WEIRD_ENDWORD "[:>:]]" #define STRING_CR_RIGHTPAR "CR)" #define STRING_LF_RIGHTPAR "LF)" #define STRING_CRLF_RIGHTPAR "CRLF)" #define STRING_ANY_RIGHTPAR "ANY)" #define STRING_ANYCRLF_RIGHTPAR "ANYCRLF)" #define STRING_BSR_ANYCRLF_RIGHTPAR "BSR_ANYCRLF)" #define STRING_BSR_UNICODE_RIGHTPAR "BSR_UNICODE)" #define STRING_UTF8_RIGHTPAR "UTF8)" #define STRING_UTF16_RIGHTPAR "UTF16)" #define STRING_UTF32_RIGHTPAR "UTF32)" #define STRING_UTF_RIGHTPAR "UTF)" #define STRING_UCP_RIGHTPAR "UCP)" #define STRING_NO_AUTO_POSSESS_RIGHTPAR "NO_AUTO_POSSESS)" #define STRING_NO_START_OPT_RIGHTPAR "NO_START_OPT)" #define STRING_LIMIT_MATCH_EQ "LIMIT_MATCH=" #define STRING_LIMIT_RECURSION_EQ "LIMIT_RECURSION=" #else /* SUPPORT_UTF */ /* UTF-8 support is enabled; always use UTF-8 (=ASCII) character codes. This works in both modes non-EBCDIC platforms, and on EBCDIC platforms in UTF-8 mode only. */ #define CHAR_HT '\011' #define CHAR_VT '\013' #define CHAR_FF '\014' #define CHAR_CR '\015' #define CHAR_LF '\012' #define CHAR_NL CHAR_LF #define CHAR_NEL ((unsigned char)'\x85') #define CHAR_BS '\010' #define CHAR_BEL '\007' #define CHAR_ESC '\033' #define CHAR_DEL '\177' #define CHAR_NULL '\0' #define CHAR_SPACE '\040' #define CHAR_EXCLAMATION_MARK '\041' #define CHAR_QUOTATION_MARK '\042' #define CHAR_NUMBER_SIGN '\043' #define CHAR_DOLLAR_SIGN '\044' #define CHAR_PERCENT_SIGN '\045' #define CHAR_AMPERSAND '\046' #define CHAR_APOSTROPHE '\047' #define CHAR_LEFT_PARENTHESIS '\050' #define CHAR_RIGHT_PARENTHESIS '\051' #define CHAR_ASTERISK '\052' #define CHAR_PLUS '\053' #define CHAR_COMMA '\054' #define CHAR_MINUS '\055' #define CHAR_DOT '\056' #define CHAR_SLASH '\057' #define CHAR_0 '\060' #define CHAR_1 '\061' #define CHAR_2 '\062' #define CHAR_3 '\063' #define CHAR_4 '\064' #define CHAR_5 '\065' #define CHAR_6 '\066' #define CHAR_7 '\067' #define CHAR_8 '\070' #define CHAR_9 '\071' #define CHAR_COLON '\072' #define CHAR_SEMICOLON '\073' #define CHAR_LESS_THAN_SIGN '\074' #define CHAR_EQUALS_SIGN '\075' #define CHAR_GREATER_THAN_SIGN '\076' #define CHAR_QUESTION_MARK '\077' #define CHAR_COMMERCIAL_AT '\100' #define CHAR_A '\101' #define CHAR_B '\102' #define CHAR_C '\103' #define CHAR_D '\104' #define CHAR_E '\105' #define CHAR_F '\106' #define CHAR_G '\107' #define CHAR_H '\110' #define CHAR_I '\111' #define CHAR_J '\112' #define CHAR_K '\113' #define CHAR_L '\114' #define CHAR_M '\115' #define CHAR_N '\116' #define CHAR_O '\117' #define CHAR_P '\120' #define CHAR_Q '\121' #define CHAR_R '\122' #define CHAR_S '\123' #define CHAR_T '\124' #define CHAR_U '\125' #define CHAR_V '\126' #define CHAR_W '\127' #define CHAR_X '\130' #define CHAR_Y '\131' #define CHAR_Z '\132' #define CHAR_LEFT_SQUARE_BRACKET '\133' #define CHAR_BACKSLASH '\134' #define CHAR_RIGHT_SQUARE_BRACKET '\135' #define CHAR_CIRCUMFLEX_ACCENT '\136' #define CHAR_UNDERSCORE '\137' #define CHAR_GRAVE_ACCENT '\140' #define CHAR_a '\141' #define CHAR_b '\142' #define CHAR_c '\143' #define CHAR_d '\144' #define CHAR_e '\145' #define CHAR_f '\146' #define CHAR_g '\147' #define CHAR_h '\150' #define CHAR_i '\151' #define CHAR_j '\152' #define CHAR_k '\153' #define CHAR_l '\154' #define CHAR_m '\155' #define CHAR_n '\156' #define CHAR_o '\157' #define CHAR_p '\160' #define CHAR_q '\161' #define CHAR_r '\162' #define CHAR_s '\163' #define CHAR_t '\164' #define CHAR_u '\165' #define CHAR_v '\166' #define CHAR_w '\167' #define CHAR_x '\170' #define CHAR_y '\171' #define CHAR_z '\172' #define CHAR_LEFT_CURLY_BRACKET '\173' #define CHAR_VERTICAL_LINE '\174' #define CHAR_RIGHT_CURLY_BRACKET '\175' #define CHAR_TILDE '\176' #define CHAR_NBSP ((unsigned char)'\xa0') #define STR_HT "\011" #define STR_VT "\013" #define STR_FF "\014" #define STR_CR "\015" #define STR_NL "\012" #define STR_BS "\010" #define STR_BEL "\007" #define STR_ESC "\033" #define STR_DEL "\177" #define STR_SPACE "\040" #define STR_EXCLAMATION_MARK "\041" #define STR_QUOTATION_MARK "\042" #define STR_NUMBER_SIGN "\043" #define STR_DOLLAR_SIGN "\044" #define STR_PERCENT_SIGN "\045" #define STR_AMPERSAND "\046" #define STR_APOSTROPHE "\047" #define STR_LEFT_PARENTHESIS "\050" #define STR_RIGHT_PARENTHESIS "\051" #define STR_ASTERISK "\052" #define STR_PLUS "\053" #define STR_COMMA "\054" #define STR_MINUS "\055" #define STR_DOT "\056" #define STR_SLASH "\057" #define STR_0 "\060" #define STR_1 "\061" #define STR_2 "\062" #define STR_3 "\063" #define STR_4 "\064" #define STR_5 "\065" #define STR_6 "\066" #define STR_7 "\067" #define STR_8 "\070" #define STR_9 "\071" #define STR_COLON "\072" #define STR_SEMICOLON "\073" #define STR_LESS_THAN_SIGN "\074" #define STR_EQUALS_SIGN "\075" #define STR_GREATER_THAN_SIGN "\076" #define STR_QUESTION_MARK "\077" #define STR_COMMERCIAL_AT "\100" #define STR_A "\101" #define STR_B "\102" #define STR_C "\103" #define STR_D "\104" #define STR_E "\105" #define STR_F "\106" #define STR_G "\107" #define STR_H "\110" #define STR_I "\111" #define STR_J "\112" #define STR_K "\113" #define STR_L "\114" #define STR_M "\115" #define STR_N "\116" #define STR_O "\117" #define STR_P "\120" #define STR_Q "\121" #define STR_R "\122" #define STR_S "\123" #define STR_T "\124" #define STR_U "\125" #define STR_V "\126" #define STR_W "\127" #define STR_X "\130" #define STR_Y "\131" #define STR_Z "\132" #define STR_LEFT_SQUARE_BRACKET "\133" #define STR_BACKSLASH "\134" #define STR_RIGHT_SQUARE_BRACKET "\135" #define STR_CIRCUMFLEX_ACCENT "\136" #define STR_UNDERSCORE "\137" #define STR_GRAVE_ACCENT "\140" #define STR_a "\141" #define STR_b "\142" #define STR_c "\143" #define STR_d "\144" #define STR_e "\145" #define STR_f "\146" #define STR_g "\147" #define STR_h "\150" #define STR_i "\151" #define STR_j "\152" #define STR_k "\153" #define STR_l "\154" #define STR_m "\155" #define STR_n "\156" #define STR_o "\157" #define STR_p "\160" #define STR_q "\161" #define STR_r "\162" #define STR_s "\163" #define STR_t "\164" #define STR_u "\165" #define STR_v "\166" #define STR_w "\167" #define STR_x "\170" #define STR_y "\171" #define STR_z "\172" #define STR_LEFT_CURLY_BRACKET "\173" #define STR_VERTICAL_LINE "\174" #define STR_RIGHT_CURLY_BRACKET "\175" #define STR_TILDE "\176" #define STRING_ACCEPT0 STR_A STR_C STR_C STR_E STR_P STR_T "\0" #define STRING_COMMIT0 STR_C STR_O STR_M STR_M STR_I STR_T "\0" #define STRING_F0 STR_F "\0" #define STRING_FAIL0 STR_F STR_A STR_I STR_L "\0" #define STRING_MARK0 STR_M STR_A STR_R STR_K "\0" #define STRING_PRUNE0 STR_P STR_R STR_U STR_N STR_E "\0" #define STRING_SKIP0 STR_S STR_K STR_I STR_P "\0" #define STRING_THEN STR_T STR_H STR_E STR_N #define STRING_alpha0 STR_a STR_l STR_p STR_h STR_a "\0" #define STRING_lower0 STR_l STR_o STR_w STR_e STR_r "\0" #define STRING_upper0 STR_u STR_p STR_p STR_e STR_r "\0" #define STRING_alnum0 STR_a STR_l STR_n STR_u STR_m "\0" #define STRING_ascii0 STR_a STR_s STR_c STR_i STR_i "\0" #define STRING_blank0 STR_b STR_l STR_a STR_n STR_k "\0" #define STRING_cntrl0 STR_c STR_n STR_t STR_r STR_l "\0" #define STRING_digit0 STR_d STR_i STR_g STR_i STR_t "\0" #define STRING_graph0 STR_g STR_r STR_a STR_p STR_h "\0" #define STRING_print0 STR_p STR_r STR_i STR_n STR_t "\0" #define STRING_punct0 STR_p STR_u STR_n STR_c STR_t "\0" #define STRING_space0 STR_s STR_p STR_a STR_c STR_e "\0" #define STRING_word0 STR_w STR_o STR_r STR_d "\0" #define STRING_xdigit STR_x STR_d STR_i STR_g STR_i STR_t #define STRING_DEFINE STR_D STR_E STR_F STR_I STR_N STR_E #define STRING_WEIRD_STARTWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_LESS_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET #define STRING_WEIRD_ENDWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_GREATER_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET #define STRING_CR_RIGHTPAR STR_C STR_R STR_RIGHT_PARENTHESIS #define STRING_LF_RIGHTPAR STR_L STR_F STR_RIGHT_PARENTHESIS #define STRING_CRLF_RIGHTPAR STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS #define STRING_ANY_RIGHTPAR STR_A STR_N STR_Y STR_RIGHT_PARENTHESIS #define STRING_ANYCRLF_RIGHTPAR STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS #define STRING_BSR_ANYCRLF_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS #define STRING_BSR_UNICODE_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS #define STRING_UTF8_RIGHTPAR STR_U STR_T STR_F STR_8 STR_RIGHT_PARENTHESIS #define STRING_UTF16_RIGHTPAR STR_U STR_T STR_F STR_1 STR_6 STR_RIGHT_PARENTHESIS #define STRING_UTF32_RIGHTPAR STR_U STR_T STR_F STR_3 STR_2 STR_RIGHT_PARENTHESIS #define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_RIGHT_PARENTHESIS #define STRING_UCP_RIGHTPAR STR_U STR_C STR_P STR_RIGHT_PARENTHESIS #define STRING_NO_AUTO_POSSESS_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_A STR_U STR_T STR_O STR_UNDERSCORE STR_P STR_O STR_S STR_S STR_E STR_S STR_S STR_RIGHT_PARENTHESIS #define STRING_NO_START_OPT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_S STR_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS #define STRING_LIMIT_MATCH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_M STR_A STR_T STR_C STR_H STR_EQUALS_SIGN #define STRING_LIMIT_RECURSION_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_R STR_E STR_C STR_U STR_R STR_S STR_I STR_O STR_N STR_EQUALS_SIGN #endif /* SUPPORT_UTF */ /* Escape items that are just an encoding of a particular data value. */ #ifndef ESC_a #define ESC_a CHAR_BEL #endif #ifndef ESC_e #define ESC_e CHAR_ESC #endif #ifndef ESC_f #define ESC_f CHAR_FF #endif #ifndef ESC_n #define ESC_n CHAR_LF #endif #ifndef ESC_r #define ESC_r CHAR_CR #endif /* We can't officially use ESC_t because it is a POSIX reserved identifier (presumably because of all the others like size_t). */ #ifndef ESC_tee #define ESC_tee CHAR_HT #endif /* Codes for different types of Unicode property */ #define PT_ANY 0 /* Any property - matches all chars */ #define PT_LAMP 1 /* L& - the union of Lu, Ll, Lt */ #define PT_GC 2 /* Specified general characteristic (e.g. L) */ #define PT_PC 3 /* Specified particular characteristic (e.g. Lu) */ #define PT_SC 4 /* Script (e.g. Han) */ #define PT_ALNUM 5 /* Alphanumeric - the union of L and N */ #define PT_SPACE 6 /* Perl space - Z plus 9,10,12,13 */ #define PT_PXSPACE 7 /* POSIX space - Z plus 9,10,11,12,13 */ #define PT_WORD 8 /* Word - L plus N plus underscore */ #define PT_CLIST 9 /* Pseudo-property: match character list */ #define PT_UCNC 10 /* Universal Character nameable character */ #define PT_TABSIZE 11 /* Size of square table for autopossessify tests */ /* The following special properties are used only in XCLASS items, when POSIX classes are specified and PCRE_UCP is set - in other words, for Unicode handling of these classes. They are not available via the \p or \P escapes like those in the above list, and so they do not take part in the autopossessifying table. */ #define PT_PXGRAPH 11 /* [:graph:] - characters that mark the paper */ #define PT_PXPRINT 12 /* [:print:] - [:graph:] plus non-control spaces */ #define PT_PXPUNCT 13 /* [:punct:] - punctuation characters */ /* Flag bits and data types for the extended class (OP_XCLASS) for classes that contain characters with values greater than 255. */ #define XCL_NOT 0x01 /* Flag: this is a negative class */ #define XCL_MAP 0x02 /* Flag: a 32-byte map is present */ #define XCL_HASPROP 0x04 /* Flag: property checks are present. */ #define XCL_END 0 /* Marks end of individual items */ #define XCL_SINGLE 1 /* Single item (one multibyte char) follows */ #define XCL_RANGE 2 /* A range (two multibyte chars) follows */ #define XCL_PROP 3 /* Unicode property (2-byte property code follows) */ #define XCL_NOTPROP 4 /* Unicode inverted property (ditto) */ /* These are escaped items that aren't just an encoding of a particular data value such as \n. They must have non-zero values, as check_escape() returns 0 for a data character. Also, they must appear in the same order as in the opcode definitions below, up to ESC_z. There's a dummy for OP_ALLANY because it corresponds to "." in DOTALL mode rather than an escape sequence. It is also used for [^] in JavaScript compatibility mode, and for \C in non-utf mode. In non-DOTALL mode, "." behaves like \N. The special values ESC_DU, ESC_du, etc. are used instead of ESC_D, ESC_d, etc. when PCRE_UCP is set and replacement of \d etc by \p sequences is required. They must be contiguous, and remain in order so that the replacements can be looked up from a table. Negative numbers are used to encode a backreference (\1, \2, \3, etc.) in check_escape(). There are two tests in the code for an escape greater than ESC_b and less than ESC_Z to detect the types that may be repeated. These are the types that consume characters. If any new escapes are put in between that don't consume a character, that code will have to change. */ enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H, ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z, ESC_E, ESC_Q, ESC_g, ESC_k, ESC_DU, ESC_du, ESC_SU, ESC_su, ESC_WU, ESC_wu }; /********************** Opcode definitions ******************/ /****** NOTE NOTE NOTE ****** Starting from 1 (i.e. after OP_END), the values up to OP_EOD must correspond in order to the list of escapes immediately above. Furthermore, values up to OP_DOLLM must not be changed without adjusting the table called autoposstab in pcre_compile.c Whenever this list is updated, the two macro definitions that follow must be updated to match. The possessification table called "opcode_possessify" in pcre_compile.c must also be updated, and also the tables called "coptable" and "poptable" in pcre_dfa_exec.c. ****** NOTE NOTE NOTE ******/ /* The values between FIRST_AUTOTAB_OP and LAST_AUTOTAB_RIGHT_OP, inclusive, are used in a table for deciding whether a repeated character type can be auto-possessified. */ #define FIRST_AUTOTAB_OP OP_NOT_DIGIT #define LAST_AUTOTAB_LEFT_OP OP_EXTUNI #define LAST_AUTOTAB_RIGHT_OP OP_DOLLM enum { OP_END, /* 0 End of pattern */ /* Values corresponding to backslashed metacharacters */ OP_SOD, /* 1 Start of data: \A */ OP_SOM, /* 2 Start of match (subject + offset): \G */ OP_SET_SOM, /* 3 Set start of match (\K) */ OP_NOT_WORD_BOUNDARY, /* 4 \B */ OP_WORD_BOUNDARY, /* 5 \b */ OP_NOT_DIGIT, /* 6 \D */ OP_DIGIT, /* 7 \d */ OP_NOT_WHITESPACE, /* 8 \S */ OP_WHITESPACE, /* 9 \s */ OP_NOT_WORDCHAR, /* 10 \W */ OP_WORDCHAR, /* 11 \w */ OP_ANY, /* 12 Match any character except newline (\N) */ OP_ALLANY, /* 13 Match any character */ OP_ANYBYTE, /* 14 Match any byte (\C); different to OP_ANY for UTF-8 */ OP_NOTPROP, /* 15 \P (not Unicode property) */ OP_PROP, /* 16 \p (Unicode property) */ OP_ANYNL, /* 17 \R (any newline sequence) */ OP_NOT_HSPACE, /* 18 \H (not horizontal whitespace) */ OP_HSPACE, /* 19 \h (horizontal whitespace) */ OP_NOT_VSPACE, /* 20 \V (not vertical whitespace) */ OP_VSPACE, /* 21 \v (vertical whitespace) */ OP_EXTUNI, /* 22 \X (extended Unicode sequence */ OP_EODN, /* 23 End of data or \n at end of data (\Z) */ OP_EOD, /* 24 End of data (\z) */ /* Line end assertions */ OP_DOLL, /* 25 End of line - not multiline */ OP_DOLLM, /* 26 End of line - multiline */ OP_CIRC, /* 27 Start of line - not multiline */ OP_CIRCM, /* 28 Start of line - multiline */ /* Single characters; caseful must precede the caseless ones */ OP_CHAR, /* 29 Match one character, casefully */ OP_CHARI, /* 30 Match one character, caselessly */ OP_NOT, /* 31 Match one character, not the given one, casefully */ OP_NOTI, /* 32 Match one character, not the given one, caselessly */ /* The following sets of 13 opcodes must always be kept in step because the offset from the first one is used to generate the others. */ /* Repeated characters; caseful must precede the caseless ones */ OP_STAR, /* 33 The maximizing and minimizing versions of */ OP_MINSTAR, /* 34 these six opcodes must come in pairs, with */ OP_PLUS, /* 35 the minimizing one second. */ OP_MINPLUS, /* 36 */ OP_QUERY, /* 37 */ OP_MINQUERY, /* 38 */ OP_UPTO, /* 39 From 0 to n matches of one character, caseful*/ OP_MINUPTO, /* 40 */ OP_EXACT, /* 41 Exactly n matches */ OP_POSSTAR, /* 42 Possessified star, caseful */ OP_POSPLUS, /* 43 Possessified plus, caseful */ OP_POSQUERY, /* 44 Posesssified query, caseful */ OP_POSUPTO, /* 45 Possessified upto, caseful */ /* Repeated characters; caseless must follow the caseful ones */ OP_STARI, /* 46 */ OP_MINSTARI, /* 47 */ OP_PLUSI, /* 48 */ OP_MINPLUSI, /* 49 */ OP_QUERYI, /* 50 */ OP_MINQUERYI, /* 51 */ OP_UPTOI, /* 52 From 0 to n matches of one character, caseless */ OP_MINUPTOI, /* 53 */ OP_EXACTI, /* 54 */ OP_POSSTARI, /* 55 Possessified star, caseless */ OP_POSPLUSI, /* 56 Possessified plus, caseless */ OP_POSQUERYI, /* 57 Posesssified query, caseless */ OP_POSUPTOI, /* 58 Possessified upto, caseless */ /* The negated ones must follow the non-negated ones, and match them */ /* Negated repeated character, caseful; must precede the caseless ones */ OP_NOTSTAR, /* 59 The maximizing and minimizing versions of */ OP_NOTMINSTAR, /* 60 these six opcodes must come in pairs, with */ OP_NOTPLUS, /* 61 the minimizing one second. They must be in */ OP_NOTMINPLUS, /* 62 exactly the same order as those above. */ OP_NOTQUERY, /* 63 */ OP_NOTMINQUERY, /* 64 */ OP_NOTUPTO, /* 65 From 0 to n matches, caseful */ OP_NOTMINUPTO, /* 66 */ OP_NOTEXACT, /* 67 Exactly n matches */ OP_NOTPOSSTAR, /* 68 Possessified versions, caseful */ OP_NOTPOSPLUS, /* 69 */ OP_NOTPOSQUERY, /* 70 */ OP_NOTPOSUPTO, /* 71 */ /* Negated repeated character, caseless; must follow the caseful ones */ OP_NOTSTARI, /* 72 */ OP_NOTMINSTARI, /* 73 */ OP_NOTPLUSI, /* 74 */ OP_NOTMINPLUSI, /* 75 */ OP_NOTQUERYI, /* 76 */ OP_NOTMINQUERYI, /* 77 */ OP_NOTUPTOI, /* 78 From 0 to n matches, caseless */ OP_NOTMINUPTOI, /* 79 */ OP_NOTEXACTI, /* 80 Exactly n matches */ OP_NOTPOSSTARI, /* 81 Possessified versions, caseless */ OP_NOTPOSPLUSI, /* 82 */ OP_NOTPOSQUERYI, /* 83 */ OP_NOTPOSUPTOI, /* 84 */ /* Character types */ OP_TYPESTAR, /* 85 The maximizing and minimizing versions of */ OP_TYPEMINSTAR, /* 86 these six opcodes must come in pairs, with */ OP_TYPEPLUS, /* 87 the minimizing one second. These codes must */ OP_TYPEMINPLUS, /* 88 be in exactly the same order as those above. */ OP_TYPEQUERY, /* 89 */ OP_TYPEMINQUERY, /* 90 */ OP_TYPEUPTO, /* 91 From 0 to n matches */ OP_TYPEMINUPTO, /* 92 */ OP_TYPEEXACT, /* 93 Exactly n matches */ OP_TYPEPOSSTAR, /* 94 Possessified versions */ OP_TYPEPOSPLUS, /* 95 */ OP_TYPEPOSQUERY, /* 96 */ OP_TYPEPOSUPTO, /* 97 */ /* These are used for character classes and back references; only the first six are the same as the sets above. */ OP_CRSTAR, /* 98 The maximizing and minimizing versions of */ OP_CRMINSTAR, /* 99 all these opcodes must come in pairs, with */ OP_CRPLUS, /* 100 the minimizing one second. These codes must */ OP_CRMINPLUS, /* 101 be in exactly the same order as those above. */ OP_CRQUERY, /* 102 */ OP_CRMINQUERY, /* 103 */ OP_CRRANGE, /* 104 These are different to the three sets above. */ OP_CRMINRANGE, /* 105 */ OP_CRPOSSTAR, /* 106 Possessified versions */ OP_CRPOSPLUS, /* 107 */ OP_CRPOSQUERY, /* 108 */ OP_CRPOSRANGE, /* 109 */ /* End of quantifier opcodes */ OP_CLASS, /* 110 Match a character class, chars < 256 only */ OP_NCLASS, /* 111 Same, but the bitmap was created from a negative class - the difference is relevant only when a character > 255 is encountered. */ OP_XCLASS, /* 112 Extended class for handling > 255 chars within the class. This does both positive and negative. */ OP_REF, /* 113 Match a back reference, casefully */ OP_REFI, /* 114 Match a back reference, caselessly */ OP_DNREF, /* 115 Match a duplicate name backref, casefully */ OP_DNREFI, /* 116 Match a duplicate name backref, caselessly */ OP_RECURSE, /* 117 Match a numbered subpattern (possibly recursive) */ OP_CALLOUT, /* 118 Call out to external function if provided */ OP_ALT, /* 119 Start of alternation */ OP_KET, /* 120 End of group that doesn't have an unbounded repeat */ OP_KETRMAX, /* 121 These two must remain together and in this */ OP_KETRMIN, /* 122 order. They are for groups the repeat for ever. */ OP_KETRPOS, /* 123 Possessive unlimited repeat. */ /* The assertions must come before BRA, CBRA, ONCE, and COND, and the four asserts must remain in order. */ OP_REVERSE, /* 124 Move pointer back - used in lookbehind assertions */ OP_ASSERT, /* 125 Positive lookahead */ OP_ASSERT_NOT, /* 126 Negative lookahead */ OP_ASSERTBACK, /* 127 Positive lookbehind */ OP_ASSERTBACK_NOT, /* 128 Negative lookbehind */ /* ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come immediately after the assertions, with ONCE first, as there's a test for >= ONCE for a subpattern that isn't an assertion. The POS versions must immediately follow the non-POS versions in each case. */ OP_ONCE, /* 129 Atomic group, contains captures */ OP_ONCE_NC, /* 130 Atomic group containing no captures */ OP_BRA, /* 131 Start of non-capturing bracket */ OP_BRAPOS, /* 132 Ditto, with unlimited, possessive repeat */ OP_CBRA, /* 133 Start of capturing bracket */ OP_CBRAPOS, /* 134 Ditto, with unlimited, possessive repeat */ OP_COND, /* 135 Conditional group */ /* These five must follow the previous five, in the same order. There's a check for >= SBRA to distinguish the two sets. */ OP_SBRA, /* 136 Start of non-capturing bracket, check empty */ OP_SBRAPOS, /* 137 Ditto, with unlimited, possessive repeat */ OP_SCBRA, /* 138 Start of capturing bracket, check empty */ OP_SCBRAPOS, /* 139 Ditto, with unlimited, possessive repeat */ OP_SCOND, /* 140 Conditional group, check empty */ /* The next two pairs must (respectively) be kept together. */ OP_CREF, /* 141 Used to hold a capture number as condition */ OP_DNCREF, /* 142 Used to point to duplicate names as a condition */ OP_RREF, /* 143 Used to hold a recursion number as condition */ OP_DNRREF, /* 144 Used to point to duplicate names as a condition */ OP_DEF, /* 145 The DEFINE condition */ OP_BRAZERO, /* 146 These two must remain together and in this */ OP_BRAMINZERO, /* 147 order. */ OP_BRAPOSZERO, /* 148 */ /* These are backtracking control verbs */ OP_MARK, /* 149 always has an argument */ OP_PRUNE, /* 150 */ OP_PRUNE_ARG, /* 151 same, but with argument */ OP_SKIP, /* 152 */ OP_SKIP_ARG, /* 153 same, but with argument */ OP_THEN, /* 154 */ OP_THEN_ARG, /* 155 same, but with argument */ OP_COMMIT, /* 156 */ /* These are forced failure and success verbs */ OP_FAIL, /* 157 */ OP_ACCEPT, /* 158 */ OP_ASSERT_ACCEPT, /* 159 Used inside assertions */ OP_CLOSE, /* 160 Used before OP_ACCEPT to close open captures */ /* This is used to skip a subpattern with a {0} quantifier */ OP_SKIPZERO, /* 161 */ /* This is not an opcode, but is used to check that tables indexed by opcode are the correct length, in order to catch updating errors - there have been some in the past. */ OP_TABLE_LENGTH }; /* *** NOTE NOTE NOTE *** Whenever the list above is updated, the two macro definitions that follow must also be updated to match. There are also tables called "opcode_possessify" in pcre_compile.c and "coptable" and "poptable" in pcre_dfa_exec.c that must be updated. */ /* This macro defines textual names for all the opcodes. These are used only for debugging, and some of them are only partial names. The macro is referenced only in pcre_printint.c, which fills out the full names in many cases (and in some cases doesn't actually use these names at all). */ #define OP_NAME_LIST \ "End", "\\A", "\\G", "\\K", "\\B", "\\b", "\\D", "\\d", \ "\\S", "\\s", "\\W", "\\w", "Any", "AllAny", "Anybyte", \ "notprop", "prop", "\\R", "\\H", "\\h", "\\V", "\\v", \ "extuni", "\\Z", "\\z", \ "$", "$", "^", "^", "char", "chari", "not", "noti", \ "*", "*?", "+", "+?", "?", "??", \ "{", "{", "{", \ "*+","++", "?+", "{", \ "*", "*?", "+", "+?", "?", "??", \ "{", "{", "{", \ "*+","++", "?+", "{", \ "*", "*?", "+", "+?", "?", "??", \ "{", "{", "{", \ "*+","++", "?+", "{", \ "*", "*?", "+", "+?", "?", "??", \ "{", "{", "{", \ "*+","++", "?+", "{", \ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \ "*+","++", "?+", "{", \ "*", "*?", "+", "+?", "?", "??", "{", "{", \ "*+","++", "?+", "{", \ "class", "nclass", "xclass", "Ref", "Refi", "DnRef", "DnRefi", \ "Recurse", "Callout", \ "Alt", "Ket", "KetRmax", "KetRmin", "KetRpos", \ "Reverse", "Assert", "Assert not", "AssertB", "AssertB not", \ "Once", "Once_NC", \ "Bra", "BraPos", "CBra", "CBraPos", \ "Cond", \ "SBra", "SBraPos", "SCBra", "SCBraPos", \ "SCond", \ "Cond ref", "Cond dnref", "Cond rec", "Cond dnrec", "Cond def", \ "Brazero", "Braminzero", "Braposzero", \ "*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP", \ "*THEN", "*THEN", "*COMMIT", "*FAIL", \ "*ACCEPT", "*ASSERT_ACCEPT", \ "Close", "Skip zero" /* This macro defines the length of fixed length operations in the compiled regex. The lengths are used when searching for specific things, and also in the debugging printing of a compiled regex. We use a macro so that it can be defined close to the definitions of the opcodes themselves. As things have been extended, some of these are no longer fixed lenths, but are minima instead. For example, the length of a single-character repeat may vary in UTF-8 mode. The code that uses this table must know about such things. */ #define OP_LENGTHS \ 1, /* End */ \ 1, 1, 1, 1, 1, /* \A, \G, \K, \B, \b */ \ 1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */ \ 1, 1, 1, /* Any, AllAny, Anybyte */ \ 3, 3, /* \P, \p */ \ 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ \ 1, /* \X */ \ 1, 1, 1, 1, 1, 1, /* \Z, \z, $, $M ^, ^M */ \ 2, /* Char - the minimum length */ \ 2, /* Chari - the minimum length */ \ 2, /* not */ \ 2, /* noti */ \ /* Positive single-char repeats ** These are */ \ 2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** minima in */ \ 2+IMM2_SIZE, 2+IMM2_SIZE, /* upto, minupto ** mode */ \ 2+IMM2_SIZE, /* exact */ \ 2, 2, 2, 2+IMM2_SIZE, /* *+, ++, ?+, upto+ */ \ 2, 2, 2, 2, 2, 2, /* *I, *?I, +I, +?I, ?I, ??I ** UTF-8 */ \ 2+IMM2_SIZE, 2+IMM2_SIZE, /* upto I, minupto I */ \ 2+IMM2_SIZE, /* exact I */ \ 2, 2, 2, 2+IMM2_SIZE, /* *+I, ++I, ?+I, upto+I */ \ /* Negative single-char repeats - only for chars < 256 */ \ 2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \ 2+IMM2_SIZE, 2+IMM2_SIZE, /* NOT upto, minupto */ \ 2+IMM2_SIZE, /* NOT exact */ \ 2, 2, 2, 2+IMM2_SIZE, /* Possessive NOT *, +, ?, upto */ \ 2, 2, 2, 2, 2, 2, /* NOT *I, *?I, +I, +?I, ?I, ??I */ \ 2+IMM2_SIZE, 2+IMM2_SIZE, /* NOT upto I, minupto I */ \ 2+IMM2_SIZE, /* NOT exact I */ \ 2, 2, 2, 2+IMM2_SIZE, /* Possessive NOT *I, +I, ?I, upto I */ \ /* Positive type repeats */ \ 2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \ 2+IMM2_SIZE, 2+IMM2_SIZE, /* Type upto, minupto */ \ 2+IMM2_SIZE, /* Type exact */ \ 2, 2, 2, 2+IMM2_SIZE, /* Possessive *+, ++, ?+, upto+ */ \ /* Character class & ref repeats */ \ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \ 1+2*IMM2_SIZE, 1+2*IMM2_SIZE, /* CRRANGE, CRMINRANGE */ \ 1, 1, 1, 1+2*IMM2_SIZE, /* Possessive *+, ++, ?+, CRPOSRANGE */ \ 1+(32/sizeof(pcre_uchar)), /* CLASS */ \ 1+(32/sizeof(pcre_uchar)), /* NCLASS */ \ 0, /* XCLASS - variable length */ \ 1+IMM2_SIZE, /* REF */ \ 1+IMM2_SIZE, /* REFI */ \ 1+2*IMM2_SIZE, /* DNREF */ \ 1+2*IMM2_SIZE, /* DNREFI */ \ 1+LINK_SIZE, /* RECURSE */ \ 2+2*LINK_SIZE, /* CALLOUT */ \ 1+LINK_SIZE, /* Alt */ \ 1+LINK_SIZE, /* Ket */ \ 1+LINK_SIZE, /* KetRmax */ \ 1+LINK_SIZE, /* KetRmin */ \ 1+LINK_SIZE, /* KetRpos */ \ 1+LINK_SIZE, /* Reverse */ \ 1+LINK_SIZE, /* Assert */ \ 1+LINK_SIZE, /* Assert not */ \ 1+LINK_SIZE, /* Assert behind */ \ 1+LINK_SIZE, /* Assert behind not */ \ 1+LINK_SIZE, /* ONCE */ \ 1+LINK_SIZE, /* ONCE_NC */ \ 1+LINK_SIZE, /* BRA */ \ 1+LINK_SIZE, /* BRAPOS */ \ 1+LINK_SIZE+IMM2_SIZE, /* CBRA */ \ 1+LINK_SIZE+IMM2_SIZE, /* CBRAPOS */ \ 1+LINK_SIZE, /* COND */ \ 1+LINK_SIZE, /* SBRA */ \ 1+LINK_SIZE, /* SBRAPOS */ \ 1+LINK_SIZE+IMM2_SIZE, /* SCBRA */ \ 1+LINK_SIZE+IMM2_SIZE, /* SCBRAPOS */ \ 1+LINK_SIZE, /* SCOND */ \ 1+IMM2_SIZE, 1+2*IMM2_SIZE, /* CREF, DNCREF */ \ 1+IMM2_SIZE, 1+2*IMM2_SIZE, /* RREF, DNRREF */ \ 1, /* DEF */ \ 1, 1, 1, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ \ 3, 1, 3, /* MARK, PRUNE, PRUNE_ARG */ \ 1, 3, /* SKIP, SKIP_ARG */ \ 1, 3, /* THEN, THEN_ARG */ \ 1, 1, 1, 1, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */ \ 1+IMM2_SIZE, 1 /* CLOSE, SKIPZERO */ /* A magic value for OP_RREF to indicate the "any recursion" condition. */ #define RREF_ANY 0xffff /* Compile time error code numbers. They are given names so that they can more easily be tracked. When a new number is added, the table called eint in pcreposix.c must be updated. */ enum { ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, ERR30, ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80, ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERRCOUNT }; /* JIT compiling modes. The function list is indexed by them. */ enum { JIT_COMPILE, JIT_PARTIAL_SOFT_COMPILE, JIT_PARTIAL_HARD_COMPILE, JIT_NUMBER_OF_COMPILE_MODES }; /* The real format of the start of the pcre block; the index of names and the code vector run on as long as necessary after the end. We store an explicit offset to the name table so that if a regex is compiled on one host, saved, and then run on another where the size of pointers is different, all might still be well. The size of the structure must be a multiple of 8 bytes. For the case of compiled-on-4 and run-on-8, we include an extra pointer that is always NULL so that there are an even number of pointers which therefore are a multiple of 8 bytes. It is necessary to fork the struct for the 32 bit library, since it needs to use pcre_uint32 for first_char and req_char. We can't put an ifdef inside the typedef because pcretest needs access to the struct of the 8-, 16- and 32-bit variants. *** WARNING *** When new fields are added to these structures, remember to adjust the code in pcre_byte_order.c that is concerned with swapping the byte order of the fields when a compiled regex is reloaded on a host with different endianness. *** WARNING *** There is also similar byte-flipping code in pcretest.c, which is used for testing the byte-flipping features. It must also be kept in step. *** WARNING *** */ typedef struct real_pcre8_or_16 { pcre_uint32 magic_number; pcre_uint32 size; /* Total that was malloced */ pcre_uint32 options; /* Public options */ pcre_uint32 flags; /* Private flags */ pcre_uint32 limit_match; /* Limit set from regex */ pcre_uint32 limit_recursion; /* Limit set from regex */ pcre_uint16 first_char; /* Starting character */ pcre_uint16 req_char; /* This character must be seen */ pcre_uint16 max_lookbehind; /* Longest lookbehind (characters) */ pcre_uint16 top_bracket; /* Highest numbered group */ pcre_uint16 top_backref; /* Highest numbered back reference */ pcre_uint16 name_table_offset; /* Offset to name table that follows */ pcre_uint16 name_entry_size; /* Size of any name items */ pcre_uint16 name_count; /* Number of name items */ pcre_uint16 ref_count; /* Reference count */ pcre_uint16 dummy1; /* To ensure size is a multiple of 8 */ pcre_uint16 dummy2; /* To ensure size is a multiple of 8 */ pcre_uint16 dummy3; /* To ensure size is a multiple of 8 */ const pcre_uint8 *tables; /* Pointer to tables or NULL for std */ void *nullpad; /* NULL padding */ } real_pcre8_or_16; typedef struct real_pcre8_or_16 real_pcre; typedef struct real_pcre8_or_16 real_pcre16; typedef struct real_pcre32 { pcre_uint32 magic_number; pcre_uint32 size; /* Total that was malloced */ pcre_uint32 options; /* Public options */ pcre_uint32 flags; /* Private flags */ pcre_uint32 limit_match; /* Limit set from regex */ pcre_uint32 limit_recursion; /* Limit set from regex */ pcre_uint32 first_char; /* Starting character */ pcre_uint32 req_char; /* This character must be seen */ pcre_uint16 max_lookbehind; /* Longest lookbehind (characters) */ pcre_uint16 top_bracket; /* Highest numbered group */ pcre_uint16 top_backref; /* Highest numbered back reference */ pcre_uint16 name_table_offset; /* Offset to name table that follows */ pcre_uint16 name_entry_size; /* Size of any name items */ pcre_uint16 name_count; /* Number of name items */ pcre_uint16 ref_count; /* Reference count */ pcre_uint16 dummy; /* To ensure size is a multiple of 8 */ const pcre_uint8 *tables; /* Pointer to tables or NULL for std */ void *nullpad; /* NULL padding */ } real_pcre32; #if defined COMPILE_PCRE8 #define REAL_PCRE real_pcre #elif defined COMPILE_PCRE16 #define REAL_PCRE real_pcre16 #elif defined COMPILE_PCRE32 #define REAL_PCRE real_pcre32 #endif /* Assert that the size of REAL_PCRE is divisible by 8 */ typedef int __assert_real_pcre_size_divisible_8[(sizeof(REAL_PCRE) % 8) == 0 ? 1 : -1]; /* Needed in pcretest to access some fields in the real_pcre* structures * directly. They're unified for 8/16/32 bits since the structs only differ * after these fields; if that ever changes, need to fork those defines into * 8/16 and 32 bit versions. */ #define REAL_PCRE_MAGIC(re) (((REAL_PCRE*)re)->magic_number) #define REAL_PCRE_SIZE(re) (((REAL_PCRE*)re)->size) #define REAL_PCRE_OPTIONS(re) (((REAL_PCRE*)re)->options) #define REAL_PCRE_FLAGS(re) (((REAL_PCRE*)re)->flags) /* The format of the block used to store data from pcre_study(). The same remark (see NOTE above) about extending this structure applies. */ typedef struct pcre_study_data { pcre_uint32 size; /* Total that was malloced */ pcre_uint32 flags; /* Private flags */ pcre_uint8 start_bits[32]; /* Starting char bits */ pcre_uint32 minlength; /* Minimum subject length */ } pcre_study_data; /* Structure for building a chain of open capturing subpatterns during compiling, so that instructions to close them can be compiled when (*ACCEPT) is encountered. This is also used to identify subpatterns that contain recursive back references to themselves, so that they can be made atomic. */ typedef struct open_capitem { struct open_capitem *next; /* Chain link */ pcre_uint16 number; /* Capture number */ pcre_uint16 flag; /* Set TRUE if recursive back ref */ } open_capitem; /* Structure for building a list of named groups during the first pass of compiling. */ typedef struct named_group { const pcre_uchar *name; /* Points to the name in the pattern */ int length; /* Length of the name */ pcre_uint32 number; /* Group number */ } named_group; /* Structure for passing "static" information around between the functions doing the compiling, so that they are thread-safe. */ typedef struct compile_data { const pcre_uint8 *lcc; /* Points to lower casing table */ const pcre_uint8 *fcc; /* Points to case-flipping table */ const pcre_uint8 *cbits; /* Points to character type table */ const pcre_uint8 *ctypes; /* Points to table of type maps */ const pcre_uchar *start_workspace;/* The start of working space */ const pcre_uchar *start_code; /* The start of the compiled code */ const pcre_uchar *start_pattern; /* The start of the pattern */ const pcre_uchar *end_pattern; /* The end of the pattern */ pcre_uchar *hwm; /* High watermark of workspace */ open_capitem *open_caps; /* Chain of open capture items */ named_group *named_groups; /* Points to vector in pre-compile */ pcre_uchar *name_table; /* The name/number table */ int names_found; /* Number of entries so far */ int name_entry_size; /* Size of each entry */ int named_group_list_size; /* Number of entries in the list */ int workspace_size; /* Size of workspace */ unsigned int bracount; /* Count of capturing parens as we compile */ int final_bracount; /* Saved value after first pass */ int max_lookbehind; /* Maximum lookbehind (characters) */ int top_backref; /* Maximum back reference */ unsigned int backref_map; /* Bitmap of low back refs */ unsigned int namedrefcount; /* Number of backreferences by name */ int parens_depth; /* Depth of nested parentheses */ int assert_depth; /* Depth of nested assertions */ pcre_uint32 external_options; /* External (initial) options */ pcre_uint32 external_flags; /* External flag bits to be set */ int req_varyopt; /* "After variable item" flag for reqbyte */ BOOL had_accept; /* (*ACCEPT) encountered */ BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ BOOL check_lookbehind; /* Lookbehinds need later checking */ BOOL dupnames; /* Duplicate names exist */ BOOL dupgroups; /* Duplicate groups exist: (?| found */ BOOL iscondassert; /* Next assert is a condition */ int nltype; /* Newline type */ int nllen; /* Newline string length */ pcre_uchar nl[4]; /* Newline string when fixed length */ } compile_data; /* Structure for maintaining a chain of pointers to the currently incomplete branches, for testing for left recursion while compiling. */ typedef struct branch_chain { struct branch_chain *outer; pcre_uchar *current_branch; } branch_chain; /* Structure for mutual recursion detection. */ typedef struct recurse_check { struct recurse_check *prev; const pcre_uchar *group; } recurse_check; /* Structure for items in a linked list that represents an explicit recursive call within the pattern; used by pcre_exec(). */ typedef struct recursion_info { struct recursion_info *prevrec; /* Previous recursion record (or NULL) */ unsigned int group_num; /* Number of group that was called */ int *offset_save; /* Pointer to start of saved offsets */ int saved_max; /* Number of saved offsets */ int saved_capture_last; /* Last capture number */ PCRE_PUCHAR subject_position; /* Position at start of recursion */ } recursion_info; /* A similar structure for pcre_dfa_exec(). */ typedef struct dfa_recursion_info { struct dfa_recursion_info *prevrec; int group_num; PCRE_PUCHAR subject_position; } dfa_recursion_info; /* Structure for building a chain of data for holding the values of the subject pointer at the start of each subpattern, so as to detect when an empty string has been matched by a subpattern - to break infinite loops; used by pcre_exec(). */ typedef struct eptrblock { struct eptrblock *epb_prev; PCRE_PUCHAR epb_saved_eptr; } eptrblock; /* Structure for passing "static" information around between the functions doing traditional NFA matching, so that they are thread-safe. */ typedef struct match_data { unsigned long int match_call_count; /* As it says */ unsigned long int match_limit; /* As it says */ unsigned long int match_limit_recursion; /* As it says */ int *offset_vector; /* Offset vector */ int offset_end; /* One past the end */ int offset_max; /* The maximum usable for return data */ int nltype; /* Newline type */ int nllen; /* Newline string length */ int name_count; /* Number of names in name table */ int name_entry_size; /* Size of entry in names table */ unsigned int skip_arg_count; /* For counting SKIP_ARGs */ unsigned int ignore_skip_arg; /* For re-run when SKIP arg name not found */ pcre_uchar *name_table; /* Table of names */ pcre_uchar nl[4]; /* Newline string when fixed */ const pcre_uint8 *lcc; /* Points to lower casing table */ const pcre_uint8 *fcc; /* Points to case-flipping table */ const pcre_uint8 *ctypes; /* Points to table of type maps */ BOOL notbol; /* NOTBOL flag */ BOOL noteol; /* NOTEOL flag */ BOOL utf; /* UTF-8 / UTF-16 flag */ BOOL jscript_compat; /* JAVASCRIPT_COMPAT flag */ BOOL use_ucp; /* PCRE_UCP flag */ BOOL endonly; /* Dollar not before final \n */ BOOL notempty; /* Empty string match not wanted */ BOOL notempty_atstart; /* Empty string match at start not wanted */ BOOL hitend; /* Hit the end of the subject at some point */ BOOL bsr_anycrlf; /* \R is just any CRLF, not full Unicode */ BOOL hasthen; /* Pattern contains (*THEN) */ const pcre_uchar *start_code; /* For use when recursing */ PCRE_PUCHAR start_subject; /* Start of the subject string */ PCRE_PUCHAR end_subject; /* End of the subject string */ PCRE_PUCHAR start_match_ptr; /* Start of matched string */ PCRE_PUCHAR end_match_ptr; /* Subject position at end match */ PCRE_PUCHAR start_used_ptr; /* Earliest consulted character */ int partial; /* PARTIAL options */ int end_offset_top; /* Highwater mark at end of match */ pcre_int32 capture_last; /* Most recent capture number + overflow flag */ int start_offset; /* The start offset value */ int match_function_type; /* Set for certain special calls of MATCH() */ eptrblock *eptrchain; /* Chain of eptrblocks for tail recursions */ int eptrn; /* Next free eptrblock */ recursion_info *recursive; /* Linked list of recursion data */ void *callout_data; /* To pass back to callouts */ const pcre_uchar *mark; /* Mark pointer to pass back on success */ const pcre_uchar *nomatch_mark;/* Mark pointer to pass back on failure */ const pcre_uchar *once_target; /* Where to back up to for atomic groups */ #ifdef NO_RECURSE void *match_frames_base; /* For remembering malloc'd frames */ #endif } match_data; /* A similar structure is used for the same purpose by the DFA matching functions. */ typedef struct dfa_match_data { const pcre_uchar *start_code; /* Start of the compiled pattern */ const pcre_uchar *start_subject ; /* Start of the subject string */ const pcre_uchar *end_subject; /* End of subject string */ const pcre_uchar *start_used_ptr; /* Earliest consulted character */ const pcre_uint8 *tables; /* Character tables */ int start_offset; /* The start offset value */ int moptions; /* Match options */ int poptions; /* Pattern options */ int nltype; /* Newline type */ int nllen; /* Newline string length */ pcre_uchar nl[4]; /* Newline string when fixed */ void *callout_data; /* To pass back to callouts */ dfa_recursion_info *recursive; /* Linked list of recursion data */ } dfa_match_data; /* Bit definitions for entries in the pcre_ctypes table. */ #define ctype_space 0x01 #define ctype_letter 0x02 #define ctype_digit 0x04 #define ctype_xdigit 0x08 #define ctype_word 0x10 /* alphanumeric or '_' */ #define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */ /* Offsets for the bitmap tables in pcre_cbits. Each table contains a set of bits for a class map. Some classes are built by combining these tables. */ #define cbit_space 0 /* [:space:] or \s */ #define cbit_xdigit 32 /* [:xdigit:] */ #define cbit_digit 64 /* [:digit:] or \d */ #define cbit_upper 96 /* [:upper:] */ #define cbit_lower 128 /* [:lower:] */ #define cbit_word 160 /* [:word:] or \w */ #define cbit_graph 192 /* [:graph:] */ #define cbit_print 224 /* [:print:] */ #define cbit_punct 256 /* [:punct:] */ #define cbit_cntrl 288 /* [:cntrl:] */ #define cbit_length 320 /* Length of the cbits table */ /* Offsets of the various tables from the base tables pointer, and total length. */ #define lcc_offset 0 #define fcc_offset 256 #define cbits_offset 512 #define ctypes_offset (cbits_offset + cbit_length) #define tables_length (ctypes_offset + 256) /* Internal function and data prefixes. */ #if defined COMPILE_PCRE8 #ifndef PUBL #define PUBL(name) pcre_##name #endif #ifndef PRIV #define PRIV(name) _pcre_##name #endif #elif defined COMPILE_PCRE16 #ifndef PUBL #define PUBL(name) pcre16_##name #endif #ifndef PRIV #define PRIV(name) _pcre16_##name #endif #elif defined COMPILE_PCRE32 #ifndef PUBL #define PUBL(name) pcre32_##name #endif #ifndef PRIV #define PRIV(name) _pcre32_##name #endif #else #error Unsupported compiling mode #endif /* COMPILE_PCRE[8|16|32] */ /* Layout of the UCP type table that translates property names into types and codes. Each entry used to point directly to a name, but to reduce the number of relocations in shared libraries, it now has an offset into a single string instead. */ typedef struct { pcre_uint16 name_offset; pcre_uint16 type; pcre_uint16 value; } ucp_type_table; /* Internal shared data tables. These are tables that are used by more than one of the exported public functions. They have to be "external" in the C sense, but are not part of the PCRE public API. The data for these tables is in the pcre_tables.c module. */ #ifdef COMPILE_PCRE8 extern const int PRIV(utf8_table1)[]; extern const int PRIV(utf8_table1_size); extern const int PRIV(utf8_table2)[]; extern const int PRIV(utf8_table3)[]; extern const pcre_uint8 PRIV(utf8_table4)[]; #endif /* COMPILE_PCRE8 */ extern const char PRIV(utt_names)[]; extern const ucp_type_table PRIV(utt)[]; extern const int PRIV(utt_size); extern const pcre_uint8 PRIV(OP_lengths)[]; extern const pcre_uint8 PRIV(default_tables)[]; extern const pcre_uint32 PRIV(hspace_list)[]; extern const pcre_uint32 PRIV(vspace_list)[]; /* Internal shared functions. These are functions that are used by more than one of the exported public functions. They have to be "external" in the C sense, but are not part of the PCRE public API. */ /* String comparison functions. */ #if defined COMPILE_PCRE8 #define STRCMP_UC_UC(str1, str2) \ strcmp((char *)(str1), (char *)(str2)) #define STRCMP_UC_C8(str1, str2) \ strcmp((char *)(str1), (str2)) #define STRNCMP_UC_UC(str1, str2, num) \ strncmp((char *)(str1), (char *)(str2), (num)) #define STRNCMP_UC_C8(str1, str2, num) \ strncmp((char *)(str1), (str2), (num)) #define STRLEN_UC(str) strlen((const char *)str) #elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 extern int PRIV(strcmp_uc_uc)(const pcre_uchar *, const pcre_uchar *); extern int PRIV(strcmp_uc_c8)(const pcre_uchar *, const char *); extern int PRIV(strncmp_uc_uc)(const pcre_uchar *, const pcre_uchar *, unsigned int num); extern int PRIV(strncmp_uc_c8)(const pcre_uchar *, const char *, unsigned int num); extern unsigned int PRIV(strlen_uc)(const pcre_uchar *str); #define STRCMP_UC_UC(str1, str2) \ PRIV(strcmp_uc_uc)((str1), (str2)) #define STRCMP_UC_C8(str1, str2) \ PRIV(strcmp_uc_c8)((str1), (str2)) #define STRNCMP_UC_UC(str1, str2, num) \ PRIV(strncmp_uc_uc)((str1), (str2), (num)) #define STRNCMP_UC_C8(str1, str2, num) \ PRIV(strncmp_uc_c8)((str1), (str2), (num)) #define STRLEN_UC(str) PRIV(strlen_uc)(str) #endif /* COMPILE_PCRE[8|16|32] */ #if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 #define STRCMP_UC_UC_TEST(str1, str2) STRCMP_UC_UC(str1, str2) #define STRCMP_UC_C8_TEST(str1, str2) STRCMP_UC_C8(str1, str2) #elif defined COMPILE_PCRE32 extern int PRIV(strcmp_uc_uc_utf)(const pcre_uchar *, const pcre_uchar *); extern int PRIV(strcmp_uc_c8_utf)(const pcre_uchar *, const char *); #define STRCMP_UC_UC_TEST(str1, str2) \ (utf ? PRIV(strcmp_uc_uc_utf)((str1), (str2)) : PRIV(strcmp_uc_uc)((str1), (str2))) #define STRCMP_UC_C8_TEST(str1, str2) \ (utf ? PRIV(strcmp_uc_c8_utf)((str1), (str2)) : PRIV(strcmp_uc_c8)((str1), (str2))) #endif /* COMPILE_PCRE[8|16|32] */ extern const pcre_uchar *PRIV(find_bracket)(const pcre_uchar *, BOOL, int); extern BOOL PRIV(is_newline)(PCRE_PUCHAR, int, PCRE_PUCHAR, int *, BOOL); extern unsigned int PRIV(ord2utf)(pcre_uint32, pcre_uchar *); extern int PRIV(valid_utf)(PCRE_PUCHAR, int, int *); extern BOOL PRIV(was_newline)(PCRE_PUCHAR, int, PCRE_PUCHAR, int *, BOOL); extern BOOL PRIV(xclass)(pcre_uint32, const pcre_uchar *, BOOL); #ifdef SUPPORT_JIT extern void PRIV(jit_compile)(const REAL_PCRE *, PUBL(extra) *, int); extern int PRIV(jit_exec)(const PUBL(extra) *, const pcre_uchar *, int, int, int, int *, int); extern void PRIV(jit_free)(void *); extern int PRIV(jit_get_size)(void *); extern const char* PRIV(jit_get_target)(void); #endif /* Unicode character database (UCD) */ typedef struct { pcre_uint8 script; /* ucp_Arabic, etc. */ pcre_uint8 chartype; /* ucp_Cc, etc. (general categories) */ pcre_uint8 gbprop; /* ucp_gbControl, etc. (grapheme break property) */ pcre_uint8 caseset; /* offset to multichar other cases or zero */ pcre_int32 other_case; /* offset to other case, or zero if none */ } ucd_record; extern const pcre_uint32 PRIV(ucd_caseless_sets)[]; extern const ucd_record PRIV(ucd_records)[]; extern const pcre_uint8 PRIV(ucd_stage1)[]; extern const pcre_uint16 PRIV(ucd_stage2)[]; extern const pcre_uint32 PRIV(ucp_gentype)[]; extern const pcre_uint32 PRIV(ucp_gbtable)[]; #ifdef COMPILE_PCRE32 extern const ucd_record PRIV(dummy_ucd_record)[]; #endif #ifdef SUPPORT_JIT extern const int PRIV(ucp_typerange)[]; #endif #ifdef SUPPORT_UCP /* UCD access macros */ #define UCD_BLOCK_SIZE 128 #define REAL_GET_UCD(ch) (PRIV(ucd_records) + \ PRIV(ucd_stage2)[PRIV(ucd_stage1)[(int)(ch) / UCD_BLOCK_SIZE] * \ UCD_BLOCK_SIZE + (int)(ch) % UCD_BLOCK_SIZE]) #ifdef COMPILE_PCRE32 #define GET_UCD(ch) ((ch > 0x10ffff)? PRIV(dummy_ucd_record) : REAL_GET_UCD(ch)) #else #define GET_UCD(ch) REAL_GET_UCD(ch) #endif #define UCD_CHARTYPE(ch) GET_UCD(ch)->chartype #define UCD_SCRIPT(ch) GET_UCD(ch)->script #define UCD_CATEGORY(ch) PRIV(ucp_gentype)[UCD_CHARTYPE(ch)] #define UCD_GRAPHBREAK(ch) GET_UCD(ch)->gbprop #define UCD_CASESET(ch) GET_UCD(ch)->caseset #define UCD_OTHERCASE(ch) ((pcre_uint32)((int)ch + (int)(GET_UCD(ch)->other_case))) #endif /* SUPPORT_UCP */ #endif /* End of pcre_internal.h */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_dfa_exec.c0000644000000000000020000036746014655113617022262 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language (but see below for why this module is different). Written by Philip Hazel Copyright (c) 1997-2017 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains the external function pcre_dfa_exec(), which is an alternative matching function that uses a sort of DFA algorithm (not a true FSM). This is NOT Perl-compatible, but it has advantages in certain applications. */ /* NOTE ABOUT PERFORMANCE: A user of this function sent some code that improved the performance of his patterns greatly. I could not use it as it stood, as it was not thread safe, and made assumptions about pattern sizes. Also, it caused test 7 to loop, and test 9 to crash with a segfault. The issue is the check for duplicate states, which is done by a simple linear search up the state list. (Grep for "duplicate" below to find the code.) For many patterns, there will never be many states active at one time, so a simple linear search is fine. In patterns that have many active states, it might be a bottleneck. The suggested code used an indexing scheme to remember which states had previously been used for each character, and avoided the linear search when it knew there was no chance of a duplicate. This was implemented when adding states to the state lists. I wrote some thread-safe, not-limited code to try something similar at the time of checking for duplicates (instead of when adding states), using index vectors on the stack. It did give a 13% improvement with one specially constructed pattern for certain subject strings, but on other strings and on many of the simpler patterns in the test suite it did worse. The major problem, I think, was the extra time to initialize the index. This had to be done for each call of internal_dfa_exec(). (The supplied patch used a static vector, initialized only once - I suspect this was the cause of the problems with the tests.) Overall, I concluded that the gains in some cases did not outweigh the losses in others, so I abandoned this code. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define NLBLOCK md /* Block containing newline information */ #define PSSTART start_subject /* Field containing processed string start */ #define PSEND end_subject /* Field containing processed string end */ #include "pcre_internal.h" /* For use to indent debugging output */ #define SP " " /************************************************* * Code parameters and static tables * *************************************************/ /* These are offsets that are used to turn the OP_TYPESTAR and friends opcodes into others, under special conditions. A gap of 20 between the blocks should be enough. The resulting opcodes don't have to be less than 256 because they are never stored, so we push them well clear of the normal opcodes. */ #define OP_PROP_EXTRA 300 #define OP_EXTUNI_EXTRA 320 #define OP_ANYNL_EXTRA 340 #define OP_HSPACE_EXTRA 360 #define OP_VSPACE_EXTRA 380 /* This table identifies those opcodes that are followed immediately by a character that is to be tested in some way. This makes it possible to centralize the loading of these characters. In the case of Type * etc, the "character" is the opcode for \D, \d, \S, \s, \W, or \w, which will always be a small value. Non-zero values in the table are the offsets from the opcode where the character is to be found. ***NOTE*** If the start of this table is modified, the three tables that follow must also be modified. */ static const pcre_uint8 coptable[] = { 0, /* End */ 0, 0, 0, 0, 0, /* \A, \G, \K, \B, \b */ 0, 0, 0, 0, 0, 0, /* \D, \d, \S, \s, \W, \w */ 0, 0, 0, /* Any, AllAny, Anybyte */ 0, 0, /* \P, \p */ 0, 0, 0, 0, 0, /* \R, \H, \h, \V, \v */ 0, /* \X */ 0, 0, 0, 0, 0, 0, /* \Z, \z, $, $M, ^, ^M */ 1, /* Char */ 1, /* Chari */ 1, /* not */ 1, /* noti */ /* Positive single-char repeats */ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ 1+IMM2_SIZE, 1+IMM2_SIZE, /* upto, minupto */ 1+IMM2_SIZE, /* exact */ 1, 1, 1, 1+IMM2_SIZE, /* *+, ++, ?+, upto+ */ 1, 1, 1, 1, 1, 1, /* *I, *?I, +I, +?I, ?I, ??I */ 1+IMM2_SIZE, 1+IMM2_SIZE, /* upto I, minupto I */ 1+IMM2_SIZE, /* exact I */ 1, 1, 1, 1+IMM2_SIZE, /* *+I, ++I, ?+I, upto+I */ /* Negative single-char repeats - only for chars < 256 */ 1, 1, 1, 1, 1, 1, /* NOT *, *?, +, +?, ?, ?? */ 1+IMM2_SIZE, 1+IMM2_SIZE, /* NOT upto, minupto */ 1+IMM2_SIZE, /* NOT exact */ 1, 1, 1, 1+IMM2_SIZE, /* NOT *+, ++, ?+, upto+ */ 1, 1, 1, 1, 1, 1, /* NOT *I, *?I, +I, +?I, ?I, ??I */ 1+IMM2_SIZE, 1+IMM2_SIZE, /* NOT upto I, minupto I */ 1+IMM2_SIZE, /* NOT exact I */ 1, 1, 1, 1+IMM2_SIZE, /* NOT *+I, ++I, ?+I, upto+I */ /* Positive type repeats */ 1, 1, 1, 1, 1, 1, /* Type *, *?, +, +?, ?, ?? */ 1+IMM2_SIZE, 1+IMM2_SIZE, /* Type upto, minupto */ 1+IMM2_SIZE, /* Type exact */ 1, 1, 1, 1+IMM2_SIZE, /* Type *+, ++, ?+, upto+ */ /* Character class & ref repeats */ 0, 0, 0, 0, 0, 0, /* *, *?, +, +?, ?, ?? */ 0, 0, /* CRRANGE, CRMINRANGE */ 0, 0, 0, 0, /* Possessive *+, ++, ?+, CRPOSRANGE */ 0, /* CLASS */ 0, /* NCLASS */ 0, /* XCLASS - variable length */ 0, /* REF */ 0, /* REFI */ 0, /* DNREF */ 0, /* DNREFI */ 0, /* RECURSE */ 0, /* CALLOUT */ 0, /* Alt */ 0, /* Ket */ 0, /* KetRmax */ 0, /* KetRmin */ 0, /* KetRpos */ 0, /* Reverse */ 0, /* Assert */ 0, /* Assert not */ 0, /* Assert behind */ 0, /* Assert behind not */ 0, 0, /* ONCE, ONCE_NC */ 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */ 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */ 0, 0, /* CREF, DNCREF */ 0, 0, /* RREF, DNRREF */ 0, /* DEF */ 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */ 0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */ 0, 0, 0, 0, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */ 0, 0 /* CLOSE, SKIPZERO */ }; /* This table identifies those opcodes that inspect a character. It is used to remember the fact that a character could have been inspected when the end of the subject is reached. ***NOTE*** If the start of this table is modified, the two tables that follow must also be modified. */ static const pcre_uint8 poptable[] = { 0, /* End */ 0, 0, 0, 1, 1, /* \A, \G, \K, \B, \b */ 1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */ 1, 1, 1, /* Any, AllAny, Anybyte */ 1, 1, /* \P, \p */ 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ 1, /* \X */ 0, 0, 0, 0, 0, 0, /* \Z, \z, $, $M, ^, ^M */ 1, /* Char */ 1, /* Chari */ 1, /* not */ 1, /* noti */ /* Positive single-char repeats */ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ 1, 1, 1, /* upto, minupto, exact */ 1, 1, 1, 1, /* *+, ++, ?+, upto+ */ 1, 1, 1, 1, 1, 1, /* *I, *?I, +I, +?I, ?I, ??I */ 1, 1, 1, /* upto I, minupto I, exact I */ 1, 1, 1, 1, /* *+I, ++I, ?+I, upto+I */ /* Negative single-char repeats - only for chars < 256 */ 1, 1, 1, 1, 1, 1, /* NOT *, *?, +, +?, ?, ?? */ 1, 1, 1, /* NOT upto, minupto, exact */ 1, 1, 1, 1, /* NOT *+, ++, ?+, upto+ */ 1, 1, 1, 1, 1, 1, /* NOT *I, *?I, +I, +?I, ?I, ??I */ 1, 1, 1, /* NOT upto I, minupto I, exact I */ 1, 1, 1, 1, /* NOT *+I, ++I, ?+I, upto+I */ /* Positive type repeats */ 1, 1, 1, 1, 1, 1, /* Type *, *?, +, +?, ?, ?? */ 1, 1, 1, /* Type upto, minupto, exact */ 1, 1, 1, 1, /* Type *+, ++, ?+, upto+ */ /* Character class & ref repeats */ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ 1, 1, /* CRRANGE, CRMINRANGE */ 1, 1, 1, 1, /* Possessive *+, ++, ?+, CRPOSRANGE */ 1, /* CLASS */ 1, /* NCLASS */ 1, /* XCLASS - variable length */ 0, /* REF */ 0, /* REFI */ 0, /* DNREF */ 0, /* DNREFI */ 0, /* RECURSE */ 0, /* CALLOUT */ 0, /* Alt */ 0, /* Ket */ 0, /* KetRmax */ 0, /* KetRmin */ 0, /* KetRpos */ 0, /* Reverse */ 0, /* Assert */ 0, /* Assert not */ 0, /* Assert behind */ 0, /* Assert behind not */ 0, 0, /* ONCE, ONCE_NC */ 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */ 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */ 0, 0, /* CREF, DNCREF */ 0, 0, /* RREF, DNRREF */ 0, /* DEF */ 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */ 0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */ 0, 0, 0, 0, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */ 0, 0 /* CLOSE, SKIPZERO */ }; /* These 2 tables allow for compact code for testing for \D, \d, \S, \s, \W, and \w */ static const pcre_uint8 toptable1[] = { 0, 0, 0, 0, 0, 0, ctype_digit, ctype_digit, ctype_space, ctype_space, ctype_word, ctype_word, 0, 0 /* OP_ANY, OP_ALLANY */ }; static const pcre_uint8 toptable2[] = { 0, 0, 0, 0, 0, 0, ctype_digit, 0, ctype_space, 0, ctype_word, 0, 1, 1 /* OP_ANY, OP_ALLANY */ }; /* Structure for holding data about a particular state, which is in effect the current data for an active path through the match tree. It must consist entirely of ints because the working vector we are passed, and which we put these structures in, is a vector of ints. */ typedef struct stateblock { int offset; /* Offset to opcode */ int count; /* Count for repeats */ int data; /* Some use extra data */ } stateblock; #define INTS_PER_STATEBLOCK (int)(sizeof(stateblock)/sizeof(int)) #ifdef PCRE_DEBUG /************************************************* * Print character string * *************************************************/ /* Character string printing function for debugging. Arguments: p points to string length number of bytes f where to print Returns: nothing */ static void pchars(const pcre_uchar *p, int length, FILE *f) { pcre_uint32 c; while (length-- > 0) { if (isprint(c = *(p++))) fprintf(f, "%c", c); else fprintf(f, "\\x{%02x}", c); } } #endif /************************************************* * Execute a Regular Expression - DFA engine * *************************************************/ /* This internal function applies a compiled pattern to a subject string, starting at a given point, using a DFA engine. This function is called from the external one, possibly multiple times if the pattern is not anchored. The function calls itself recursively for some kinds of subpattern. Arguments: md the match_data block with fixed information this_start_code the opening bracket of this subexpression's code current_subject where we currently are in the subject string start_offset start offset in the subject string offsets vector to contain the matching string offsets offsetcount size of same workspace vector of workspace wscount size of same rlevel function call recursion level Returns: > 0 => number of match offset pairs placed in offsets = 0 => offsets overflowed; longest matches are present -1 => failed to match < -1 => some kind of unexpected problem The following macros are used for adding states to the two state vectors (one for the current character, one for the following character). */ #define ADD_ACTIVE(x,y) \ if (active_count++ < wscount) \ { \ next_active_state->offset = (x); \ next_active_state->count = (y); \ next_active_state++; \ DPRINTF(("%.*sADD_ACTIVE(%d,%d)\n", rlevel*2-2, SP, (x), (y))); \ } \ else return PCRE_ERROR_DFA_WSSIZE #define ADD_ACTIVE_DATA(x,y,z) \ if (active_count++ < wscount) \ { \ next_active_state->offset = (x); \ next_active_state->count = (y); \ next_active_state->data = (z); \ next_active_state++; \ DPRINTF(("%.*sADD_ACTIVE_DATA(%d,%d,%d)\n", rlevel*2-2, SP, (x), (y), (z))); \ } \ else return PCRE_ERROR_DFA_WSSIZE #define ADD_NEW(x,y) \ if (new_count++ < wscount) \ { \ next_new_state->offset = (x); \ next_new_state->count = (y); \ next_new_state++; \ DPRINTF(("%.*sADD_NEW(%d,%d)\n", rlevel*2-2, SP, (x), (y))); \ } \ else return PCRE_ERROR_DFA_WSSIZE #define ADD_NEW_DATA(x,y,z) \ if (new_count++ < wscount) \ { \ next_new_state->offset = (x); \ next_new_state->count = (y); \ next_new_state->data = (z); \ next_new_state++; \ DPRINTF(("%.*sADD_NEW_DATA(%d,%d,%d) line %d\n", rlevel*2-2, SP, \ (x), (y), (z), __LINE__)); \ } \ else return PCRE_ERROR_DFA_WSSIZE /* And now, here is the code */ static int internal_dfa_exec( dfa_match_data *md, const pcre_uchar *this_start_code, const pcre_uchar *current_subject, int start_offset, int *offsets, int offsetcount, int *workspace, int wscount, int rlevel) { stateblock *active_states, *new_states, *temp_states; stateblock *next_active_state, *next_new_state; const pcre_uint8 *ctypes, *lcc, *fcc; const pcre_uchar *ptr; const pcre_uchar *end_code, *first_op; dfa_recursion_info new_recursive; int active_count, new_count, match_count; /* Some fields in the md block are frequently referenced, so we load them into independent variables in the hope that this will perform better. */ const pcre_uchar *start_subject = md->start_subject; const pcre_uchar *end_subject = md->end_subject; const pcre_uchar *start_code = md->start_code; #ifdef SUPPORT_UTF BOOL utf = (md->poptions & PCRE_UTF8) != 0; #else BOOL utf = FALSE; #endif BOOL reset_could_continue = FALSE; rlevel++; offsetcount &= (-2); wscount -= 2; wscount = (wscount - (wscount % (INTS_PER_STATEBLOCK * 2))) / (2 * INTS_PER_STATEBLOCK); DPRINTF(("\n%.*s---------------------\n" "%.*sCall to internal_dfa_exec f=%d\n", rlevel*2-2, SP, rlevel*2-2, SP, rlevel)); ctypes = md->tables + ctypes_offset; lcc = md->tables + lcc_offset; fcc = md->tables + fcc_offset; match_count = PCRE_ERROR_NOMATCH; /* A negative number */ active_states = (stateblock *)(workspace + 2); next_new_state = new_states = active_states + wscount; new_count = 0; first_op = this_start_code + 1 + LINK_SIZE + ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA || *this_start_code == OP_CBRAPOS || *this_start_code == OP_SCBRAPOS) ? IMM2_SIZE:0); /* The first thing in any (sub) pattern is a bracket of some sort. Push all the alternative states onto the list, and find out where the end is. This makes is possible to use this function recursively, when we want to stop at a matching internal ket rather than at the end. If the first opcode in the first alternative is OP_REVERSE, we are dealing with a backward assertion. In that case, we have to find out the maximum amount to move back, and set up each alternative appropriately. */ if (*first_op == OP_REVERSE) { int max_back = 0; int gone_back; end_code = this_start_code; do { int back = GET(end_code, 2+LINK_SIZE); if (back > max_back) max_back = back; end_code += GET(end_code, 1); } while (*end_code == OP_ALT); /* If we can't go back the amount required for the longest lookbehind pattern, go back as far as we can; some alternatives may still be viable. */ #ifdef SUPPORT_UTF /* In character mode we have to step back character by character */ if (utf) { for (gone_back = 0; gone_back < max_back; gone_back++) { if (current_subject <= start_subject) break; current_subject--; ACROSSCHAR(current_subject > start_subject, *current_subject, current_subject--); } } else #endif /* In byte-mode we can do this quickly. */ { gone_back = (current_subject - max_back < start_subject)? (int)(current_subject - start_subject) : max_back; current_subject -= gone_back; } /* Save the earliest consulted character */ if (current_subject < md->start_used_ptr) md->start_used_ptr = current_subject; /* Now we can process the individual branches. */ end_code = this_start_code; do { int back = GET(end_code, 2+LINK_SIZE); if (back <= gone_back) { int bstate = (int)(end_code - start_code + 2 + 2*LINK_SIZE); ADD_NEW_DATA(-bstate, 0, gone_back - back); } end_code += GET(end_code, 1); } while (*end_code == OP_ALT); } /* This is the code for a "normal" subpattern (not a backward assertion). The start of a whole pattern is always one of these. If we are at the top level, we may be asked to restart matching from the same point that we reached for a previous partial match. We still have to scan through the top-level branches to find the end state. */ else { end_code = this_start_code; /* Restarting */ if (rlevel == 1 && (md->moptions & PCRE_DFA_RESTART) != 0) { do { end_code += GET(end_code, 1); } while (*end_code == OP_ALT); new_count = workspace[1]; if (!workspace[0]) memcpy(new_states, active_states, new_count * sizeof(stateblock)); } /* Not restarting */ else { int length = 1 + LINK_SIZE + ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA || *this_start_code == OP_CBRAPOS || *this_start_code == OP_SCBRAPOS) ? IMM2_SIZE:0); do { ADD_NEW((int)(end_code - start_code + length), 0); end_code += GET(end_code, 1); length = 1 + LINK_SIZE; } while (*end_code == OP_ALT); } } workspace[0] = 0; /* Bit indicating which vector is current */ DPRINTF(("%.*sEnd state = %d\n", rlevel*2-2, SP, (int)(end_code - start_code))); /* Loop for scanning the subject */ ptr = current_subject; for (;;) { int i, j; int clen, dlen; pcre_uint32 c, d; int forced_fail = 0; BOOL partial_newline = FALSE; BOOL could_continue = reset_could_continue; reset_could_continue = FALSE; /* Make the new state list into the active state list and empty the new state list. */ temp_states = active_states; active_states = new_states; new_states = temp_states; active_count = new_count; new_count = 0; workspace[0] ^= 1; /* Remember for the restarting feature */ workspace[1] = active_count; #ifdef PCRE_DEBUG printf("%.*sNext character: rest of subject = \"", rlevel*2-2, SP); pchars(ptr, STRLEN_UC(ptr), stdout); printf("\"\n"); printf("%.*sActive states: ", rlevel*2-2, SP); for (i = 0; i < active_count; i++) printf("%d/%d ", active_states[i].offset, active_states[i].count); printf("\n"); #endif /* Set the pointers for adding new states */ next_active_state = active_states + active_count; next_new_state = new_states; /* Load the current character from the subject outside the loop, as many different states may want to look at it, and we assume that at least one will. */ if (ptr < end_subject) { clen = 1; /* Number of data items in the character */ #ifdef SUPPORT_UTF GETCHARLENTEST(c, ptr, clen); #else c = *ptr; #endif /* SUPPORT_UTF */ } else { clen = 0; /* This indicates the end of the subject */ c = NOTACHAR; /* This value should never actually be used */ } /* Scan up the active states and act on each one. The result of an action may be to add more states to the currently active list (e.g. on hitting a parenthesis) or it may be to put states on the new list, for considering when we move the character pointer on. */ for (i = 0; i < active_count; i++) { stateblock *current_state = active_states + i; BOOL caseless = FALSE; const pcre_uchar *code; int state_offset = current_state->offset; int codevalue, rrc; int count; #ifdef PCRE_DEBUG printf ("%.*sProcessing state %d c=", rlevel*2-2, SP, state_offset); if (clen == 0) printf("EOL\n"); else if (c > 32 && c < 127) printf("'%c'\n", c); else printf("0x%02x\n", c); #endif /* A negative offset is a special case meaning "hold off going to this (negated) state until the number of characters in the data field have been skipped". If the could_continue flag was passed over from a previous state, arrange for it to passed on. */ if (state_offset < 0) { if (current_state->data > 0) { DPRINTF(("%.*sSkipping this character\n", rlevel*2-2, SP)); ADD_NEW_DATA(state_offset, current_state->count, current_state->data - 1); if (could_continue) reset_could_continue = TRUE; continue; } else { current_state->offset = state_offset = -state_offset; } } /* Check for a duplicate state with the same count, and skip if found. See the note at the head of this module about the possibility of improving performance here. */ for (j = 0; j < i; j++) { if (active_states[j].offset == state_offset && active_states[j].count == current_state->count) { DPRINTF(("%.*sDuplicate state: skipped\n", rlevel*2-2, SP)); goto NEXT_ACTIVE_STATE; } } /* The state offset is the offset to the opcode */ code = start_code + state_offset; codevalue = *code; /* If this opcode inspects a character, but we are at the end of the subject, remember the fact for use when testing for a partial match. */ if (clen == 0 && poptable[codevalue] != 0) could_continue = TRUE; /* If this opcode is followed by an inline character, load it. It is tempting to test for the presence of a subject character here, but that is wrong, because sometimes zero repetitions of the subject are permitted. We also use this mechanism for opcodes such as OP_TYPEPLUS that take an argument that is not a data character - but is always one byte long because the values are small. We have to take special action to deal with \P, \p, \H, \h, \V, \v and \X in this case. To keep the other cases fast, convert these ones to new opcodes. */ if (coptable[codevalue] > 0) { dlen = 1; #ifdef SUPPORT_UTF if (utf) { GETCHARLEN(d, (code + coptable[codevalue]), dlen); } else #endif /* SUPPORT_UTF */ d = code[coptable[codevalue]]; if (codevalue >= OP_TYPESTAR) { switch(d) { case OP_ANYBYTE: return PCRE_ERROR_DFA_UITEM; case OP_NOTPROP: case OP_PROP: codevalue += OP_PROP_EXTRA; break; case OP_ANYNL: codevalue += OP_ANYNL_EXTRA; break; case OP_EXTUNI: codevalue += OP_EXTUNI_EXTRA; break; case OP_NOT_HSPACE: case OP_HSPACE: codevalue += OP_HSPACE_EXTRA; break; case OP_NOT_VSPACE: case OP_VSPACE: codevalue += OP_VSPACE_EXTRA; break; default: break; } } } else { dlen = 0; /* Not strictly necessary, but compilers moan */ d = NOTACHAR; /* if these variables are not set. */ } /* Now process the individual opcodes */ switch (codevalue) { /* ========================================================================== */ /* These cases are never obeyed. This is a fudge that causes a compile- time error if the vectors coptable or poptable, which are indexed by opcode, are not the correct length. It seems to be the only way to do such a check at compile time, as the sizeof() operator does not work in the C preprocessor. */ case OP_TABLE_LENGTH: case OP_TABLE_LENGTH + ((sizeof(coptable) == OP_TABLE_LENGTH) && (sizeof(poptable) == OP_TABLE_LENGTH)): break; /* ========================================================================== */ /* Reached a closing bracket. If not at the end of the pattern, carry on with the next opcode. For repeating opcodes, also add the repeat state. Note that KETRPOS will always be encountered at the end of the subpattern, because the possessive subpattern repeats are always handled using recursive calls. Thus, it never adds any new states. At the end of the (sub)pattern, unless we have an empty string and PCRE_NOTEMPTY is set, or PCRE_NOTEMPTY_ATSTART is set and we are at the start of the subject, save the match data, shifting up all previous matches so we always have the longest first. */ case OP_KET: case OP_KETRMIN: case OP_KETRMAX: case OP_KETRPOS: if (code != end_code) { ADD_ACTIVE(state_offset + 1 + LINK_SIZE, 0); if (codevalue != OP_KET) { ADD_ACTIVE(state_offset - GET(code, 1), 0); } } else { if (ptr > current_subject || ((md->moptions & PCRE_NOTEMPTY) == 0 && ((md->moptions & PCRE_NOTEMPTY_ATSTART) == 0 || current_subject > start_subject + md->start_offset))) { if (match_count < 0) match_count = (offsetcount >= 2)? 1 : 0; else if (match_count > 0 && ++match_count * 2 > offsetcount) match_count = 0; count = ((match_count == 0)? offsetcount : match_count * 2) - 2; if (count > 0) memmove(offsets + 2, offsets, count * sizeof(int)); if (offsetcount >= 2) { offsets[0] = (int)(current_subject - start_subject); offsets[1] = (int)(ptr - start_subject); DPRINTF(("%.*sSet matched string = \"%.*s\"\n", rlevel*2-2, SP, offsets[1] - offsets[0], (char *)current_subject)); } if ((md->moptions & PCRE_DFA_SHORTEST) != 0) { DPRINTF(("%.*sEnd of internal_dfa_exec %d: returning %d\n" "%.*s---------------------\n\n", rlevel*2-2, SP, rlevel, match_count, rlevel*2-2, SP)); return match_count; } } } break; /* ========================================================================== */ /* These opcodes add to the current list of states without looking at the current character. */ /*-----------------------------------------------------------------*/ case OP_ALT: do { code += GET(code, 1); } while (*code == OP_ALT); ADD_ACTIVE((int)(code - start_code), 0); break; /*-----------------------------------------------------------------*/ case OP_BRA: case OP_SBRA: do { ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0); code += GET(code, 1); } while (*code == OP_ALT); break; /*-----------------------------------------------------------------*/ case OP_CBRA: case OP_SCBRA: ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE + IMM2_SIZE), 0); code += GET(code, 1); while (*code == OP_ALT) { ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0); code += GET(code, 1); } break; /*-----------------------------------------------------------------*/ case OP_BRAZERO: case OP_BRAMINZERO: ADD_ACTIVE(state_offset + 1, 0); code += 1 + GET(code, 2); while (*code == OP_ALT) code += GET(code, 1); ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0); break; /*-----------------------------------------------------------------*/ case OP_SKIPZERO: code += 1 + GET(code, 2); while (*code == OP_ALT) code += GET(code, 1); ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0); break; /*-----------------------------------------------------------------*/ case OP_CIRC: if (ptr == start_subject && (md->moptions & PCRE_NOTBOL) == 0) { ADD_ACTIVE(state_offset + 1, 0); } break; /*-----------------------------------------------------------------*/ case OP_CIRCM: if ((ptr == start_subject && (md->moptions & PCRE_NOTBOL) == 0) || (ptr != end_subject && WAS_NEWLINE(ptr))) { ADD_ACTIVE(state_offset + 1, 0); } break; /*-----------------------------------------------------------------*/ case OP_EOD: if (ptr >= end_subject) { if ((md->moptions & PCRE_PARTIAL_HARD) != 0) could_continue = TRUE; else { ADD_ACTIVE(state_offset + 1, 0); } } break; /*-----------------------------------------------------------------*/ case OP_SOD: if (ptr == start_subject) { ADD_ACTIVE(state_offset + 1, 0); } break; /*-----------------------------------------------------------------*/ case OP_SOM: if (ptr == start_subject + start_offset) { ADD_ACTIVE(state_offset + 1, 0); } break; /* ========================================================================== */ /* These opcodes inspect the next subject character, and sometimes the previous one as well, but do not have an argument. The variable clen contains the length of the current character and is zero if we are at the end of the subject. */ /*-----------------------------------------------------------------*/ case OP_ANY: if (clen > 0 && !IS_NEWLINE(ptr)) { if (ptr + 1 >= md->end_subject && (md->moptions & (PCRE_PARTIAL_HARD)) != 0 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { could_continue = partial_newline = TRUE; } else { ADD_NEW(state_offset + 1, 0); } } break; /*-----------------------------------------------------------------*/ case OP_ALLANY: if (clen > 0) { ADD_NEW(state_offset + 1, 0); } break; /*-----------------------------------------------------------------*/ case OP_EODN: if (clen == 0 && (md->moptions & PCRE_PARTIAL_HARD) != 0) could_continue = TRUE; else if (clen == 0 || (IS_NEWLINE(ptr) && ptr == end_subject - md->nllen)) { ADD_ACTIVE(state_offset + 1, 0); } break; /*-----------------------------------------------------------------*/ case OP_DOLL: if ((md->moptions & PCRE_NOTEOL) == 0) { if (clen == 0 && (md->moptions & PCRE_PARTIAL_HARD) != 0) could_continue = TRUE; else if (clen == 0 || ((md->poptions & PCRE_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr) && (ptr == end_subject - md->nllen) )) { ADD_ACTIVE(state_offset + 1, 0); } else if (ptr + 1 >= md->end_subject && (md->moptions & (PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT)) != 0 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { if ((md->moptions & PCRE_PARTIAL_HARD) != 0) { reset_could_continue = TRUE; ADD_NEW_DATA(-(state_offset + 1), 0, 1); } else could_continue = partial_newline = TRUE; } } break; /*-----------------------------------------------------------------*/ case OP_DOLLM: if ((md->moptions & PCRE_NOTEOL) == 0) { if (clen == 0 && (md->moptions & PCRE_PARTIAL_HARD) != 0) could_continue = TRUE; else if (clen == 0 || ((md->poptions & PCRE_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr))) { ADD_ACTIVE(state_offset + 1, 0); } else if (ptr + 1 >= md->end_subject && (md->moptions & (PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT)) != 0 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { if ((md->moptions & PCRE_PARTIAL_HARD) != 0) { reset_could_continue = TRUE; ADD_NEW_DATA(-(state_offset + 1), 0, 1); } else could_continue = partial_newline = TRUE; } } else if (IS_NEWLINE(ptr)) { ADD_ACTIVE(state_offset + 1, 0); } break; /*-----------------------------------------------------------------*/ case OP_DIGIT: case OP_WHITESPACE: case OP_WORDCHAR: if (clen > 0 && c < 256 && ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0) { ADD_NEW(state_offset + 1, 0); } break; /*-----------------------------------------------------------------*/ case OP_NOT_DIGIT: case OP_NOT_WHITESPACE: case OP_NOT_WORDCHAR: if (clen > 0 && (c >= 256 || ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0)) { ADD_NEW(state_offset + 1, 0); } break; /*-----------------------------------------------------------------*/ case OP_WORD_BOUNDARY: case OP_NOT_WORD_BOUNDARY: { int left_word, right_word; if (ptr > start_subject) { const pcre_uchar *temp = ptr - 1; if (temp < md->start_used_ptr) md->start_used_ptr = temp; #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) { BACKCHAR(temp); } #endif GETCHARTEST(d, temp); #ifdef SUPPORT_UCP if ((md->poptions & PCRE_UCP) != 0) { if (d == '_') left_word = TRUE; else { int cat = UCD_CATEGORY(d); left_word = (cat == ucp_L || cat == ucp_N); } } else #endif left_word = d < 256 && (ctypes[d] & ctype_word) != 0; } else left_word = FALSE; if (clen > 0) { #ifdef SUPPORT_UCP if ((md->poptions & PCRE_UCP) != 0) { if (c == '_') right_word = TRUE; else { int cat = UCD_CATEGORY(c); right_word = (cat == ucp_L || cat == ucp_N); } } else #endif right_word = c < 256 && (ctypes[c] & ctype_word) != 0; } else right_word = FALSE; if ((left_word == right_word) == (codevalue == OP_NOT_WORD_BOUNDARY)) { ADD_ACTIVE(state_offset + 1, 0); } } break; /*-----------------------------------------------------------------*/ /* Check the next character by Unicode property. We will get here only if the support is in the binary; otherwise a compile-time error occurs. */ #ifdef SUPPORT_UCP case OP_PROP: case OP_NOTPROP: if (clen > 0) { BOOL OK; const pcre_uint32 *cp; const ucd_record * prop = GET_UCD(c); switch(code[1]) { case PT_ANY: OK = TRUE; break; case PT_LAMP: OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt; break; case PT_GC: OK = PRIV(ucp_gentype)[prop->chartype] == code[2]; break; case PT_PC: OK = prop->chartype == code[2]; break; case PT_SC: OK = prop->script == code[2]; break; /* These are specials for combination cases. */ case PT_ALNUM: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N; break; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ switch(c) { HSPACE_CASES: VSPACE_CASES: OK = TRUE; break; default: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; break; } break; case PT_WORD: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE; break; case PT_CLIST: cp = PRIV(ucd_caseless_sets) + code[2]; for (;;) { if (c < *cp) { OK = FALSE; break; } if (c == *cp++) { OK = TRUE; break; } } break; case PT_UCNC: OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || c >= 0xe000; break; /* Should never occur, but keep compilers from grumbling. */ default: OK = codevalue != OP_PROP; break; } if (OK == (codevalue == OP_PROP)) { ADD_NEW(state_offset + 3, 0); } } break; #endif /* ========================================================================== */ /* These opcodes likewise inspect the subject character, but have an argument that is not a data character. It is one of these opcodes: OP_ANY, OP_ALLANY, OP_DIGIT, OP_NOT_DIGIT, OP_WHITESPACE, OP_NOT_SPACE, OP_WORDCHAR, OP_NOT_WORDCHAR. The value is loaded into d. */ case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } if (clen > 0) { if (d == OP_ANY && ptr + 1 >= md->end_subject && (md->moptions & (PCRE_PARTIAL_HARD)) != 0 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { could_continue = partial_newline = TRUE; } else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || (c < 256 && (d != OP_ANY || !IS_NEWLINE(ptr)) && ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) { if (count > 0 && codevalue == OP_TYPEPOSPLUS) { active_count--; /* Remove non-match possibility */ next_active_state--; } count++; ADD_NEW(state_offset, count); } } break; /*-----------------------------------------------------------------*/ case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEPOSQUERY: ADD_ACTIVE(state_offset + 2, 0); if (clen > 0) { if (d == OP_ANY && ptr + 1 >= md->end_subject && (md->moptions & (PCRE_PARTIAL_HARD)) != 0 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { could_continue = partial_newline = TRUE; } else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || (c < 256 && (d != OP_ANY || !IS_NEWLINE(ptr)) && ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) { if (codevalue == OP_TYPEPOSQUERY) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW(state_offset + 2, 0); } } break; /*-----------------------------------------------------------------*/ case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPOSSTAR: ADD_ACTIVE(state_offset + 2, 0); if (clen > 0) { if (d == OP_ANY && ptr + 1 >= md->end_subject && (md->moptions & (PCRE_PARTIAL_HARD)) != 0 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { could_continue = partial_newline = TRUE; } else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || (c < 256 && (d != OP_ANY || !IS_NEWLINE(ptr)) && ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) { if (codevalue == OP_TYPEPOSSTAR) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW(state_offset, 0); } } break; /*-----------------------------------------------------------------*/ case OP_TYPEEXACT: count = current_state->count; /* Number already matched */ if (clen > 0) { if (d == OP_ANY && ptr + 1 >= md->end_subject && (md->moptions & (PCRE_PARTIAL_HARD)) != 0 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { could_continue = partial_newline = TRUE; } else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || (c < 256 && (d != OP_ANY || !IS_NEWLINE(ptr)) && ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) { if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + 1 + IMM2_SIZE + 1, 0); } else { ADD_NEW(state_offset, count); } } } break; /*-----------------------------------------------------------------*/ case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEPOSUPTO: ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); count = current_state->count; /* Number already matched */ if (clen > 0) { if (d == OP_ANY && ptr + 1 >= md->end_subject && (md->moptions & (PCRE_PARTIAL_HARD)) != 0 && NLBLOCK->nltype == NLTYPE_FIXED && NLBLOCK->nllen == 2 && c == NLBLOCK->nl[0]) { could_continue = partial_newline = TRUE; } else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) || (c < 256 && (d != OP_ANY || !IS_NEWLINE(ptr)) && ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0)) { if (codevalue == OP_TYPEPOSUPTO) { active_count--; /* Remove non-match possibility */ next_active_state--; } if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + 2 + IMM2_SIZE, 0); } else { ADD_NEW(state_offset, count); } } } break; /* ========================================================================== */ /* These are virtual opcodes that are used when something like OP_TYPEPLUS has OP_PROP, OP_NOTPROP, OP_ANYNL, or OP_EXTUNI as its argument. It keeps the code above fast for the other cases. The argument is in the d variable. */ #ifdef SUPPORT_UCP case OP_PROP_EXTRA + OP_TYPEPLUS: case OP_PROP_EXTRA + OP_TYPEMINPLUS: case OP_PROP_EXTRA + OP_TYPEPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(state_offset + 4, 0); } if (clen > 0) { BOOL OK; const pcre_uint32 *cp; const ucd_record * prop = GET_UCD(c); switch(code[2]) { case PT_ANY: OK = TRUE; break; case PT_LAMP: OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt; break; case PT_GC: OK = PRIV(ucp_gentype)[prop->chartype] == code[3]; break; case PT_PC: OK = prop->chartype == code[3]; break; case PT_SC: OK = prop->script == code[3]; break; /* These are specials for combination cases. */ case PT_ALNUM: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N; break; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ switch(c) { HSPACE_CASES: VSPACE_CASES: OK = TRUE; break; default: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; break; } break; case PT_WORD: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE; break; case PT_CLIST: cp = PRIV(ucd_caseless_sets) + code[3]; for (;;) { if (c < *cp) { OK = FALSE; break; } if (c == *cp++) { OK = TRUE; break; } } break; case PT_UCNC: OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || c >= 0xe000; break; /* Should never occur, but keep compilers from grumbling. */ default: OK = codevalue != OP_PROP; break; } if (OK == (d == OP_PROP)) { if (count > 0 && codevalue == OP_PROP_EXTRA + OP_TYPEPOSPLUS) { active_count--; /* Remove non-match possibility */ next_active_state--; } count++; ADD_NEW(state_offset, count); } } break; /*-----------------------------------------------------------------*/ case OP_EXTUNI_EXTRA + OP_TYPEPLUS: case OP_EXTUNI_EXTRA + OP_TYPEMINPLUS: case OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } if (clen > 0) { int lgb, rgb; const pcre_uchar *nptr = ptr + clen; int ncount = 0; if (count > 0 && codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS) { active_count--; /* Remove non-match possibility */ next_active_state--; } lgb = UCD_GRAPHBREAK(c); while (nptr < end_subject) { dlen = 1; if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } rgb = UCD_GRAPHBREAK(d); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; ncount++; lgb = rgb; nptr += dlen; } count++; ADD_NEW_DATA(-state_offset, count, ncount); } break; #endif /*-----------------------------------------------------------------*/ case OP_ANYNL_EXTRA + OP_TYPEPLUS: case OP_ANYNL_EXTRA + OP_TYPEMINPLUS: case OP_ANYNL_EXTRA + OP_TYPEPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } if (clen > 0) { int ncount = 0; switch (c) { case CHAR_VT: case CHAR_FF: case CHAR_NEL: #ifndef EBCDIC case 0x2028: case 0x2029: #endif /* Not EBCDIC */ if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; goto ANYNL01; case CHAR_CR: if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1; /* Fall through */ ANYNL01: case CHAR_LF: if (count > 0 && codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSPLUS) { active_count--; /* Remove non-match possibility */ next_active_state--; } count++; ADD_NEW_DATA(-state_offset, count, ncount); break; default: break; } } break; /*-----------------------------------------------------------------*/ case OP_VSPACE_EXTRA + OP_TYPEPLUS: case OP_VSPACE_EXTRA + OP_TYPEMINPLUS: case OP_VSPACE_EXTRA + OP_TYPEPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } if (clen > 0) { BOOL OK; switch (c) { VSPACE_CASES: OK = TRUE; break; default: OK = FALSE; break; } if (OK == (d == OP_VSPACE)) { if (count > 0 && codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSPLUS) { active_count--; /* Remove non-match possibility */ next_active_state--; } count++; ADD_NEW_DATA(-state_offset, count, 0); } } break; /*-----------------------------------------------------------------*/ case OP_HSPACE_EXTRA + OP_TYPEPLUS: case OP_HSPACE_EXTRA + OP_TYPEMINPLUS: case OP_HSPACE_EXTRA + OP_TYPEPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); } if (clen > 0) { BOOL OK; switch (c) { HSPACE_CASES: OK = TRUE; break; default: OK = FALSE; break; } if (OK == (d == OP_HSPACE)) { if (count > 0 && codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSPLUS) { active_count--; /* Remove non-match possibility */ next_active_state--; } count++; ADD_NEW_DATA(-state_offset, count, 0); } } break; /*-----------------------------------------------------------------*/ #ifdef SUPPORT_UCP case OP_PROP_EXTRA + OP_TYPEQUERY: case OP_PROP_EXTRA + OP_TYPEMINQUERY: case OP_PROP_EXTRA + OP_TYPEPOSQUERY: count = 4; goto QS1; case OP_PROP_EXTRA + OP_TYPESTAR: case OP_PROP_EXTRA + OP_TYPEMINSTAR: case OP_PROP_EXTRA + OP_TYPEPOSSTAR: count = 0; QS1: ADD_ACTIVE(state_offset + 4, 0); if (clen > 0) { BOOL OK; const pcre_uint32 *cp; const ucd_record * prop = GET_UCD(c); switch(code[2]) { case PT_ANY: OK = TRUE; break; case PT_LAMP: OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt; break; case PT_GC: OK = PRIV(ucp_gentype)[prop->chartype] == code[3]; break; case PT_PC: OK = prop->chartype == code[3]; break; case PT_SC: OK = prop->script == code[3]; break; /* These are specials for combination cases. */ case PT_ALNUM: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N; break; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ switch(c) { HSPACE_CASES: VSPACE_CASES: OK = TRUE; break; default: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; break; } break; case PT_WORD: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE; break; case PT_CLIST: cp = PRIV(ucd_caseless_sets) + code[3]; for (;;) { if (c < *cp) { OK = FALSE; break; } if (c == *cp++) { OK = TRUE; break; } } break; case PT_UCNC: OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || c >= 0xe000; break; /* Should never occur, but keep compilers from grumbling. */ default: OK = codevalue != OP_PROP; break; } if (OK == (d == OP_PROP)) { if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSSTAR || codevalue == OP_PROP_EXTRA + OP_TYPEPOSQUERY) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW(state_offset + count, 0); } } break; /*-----------------------------------------------------------------*/ case OP_EXTUNI_EXTRA + OP_TYPEQUERY: case OP_EXTUNI_EXTRA + OP_TYPEMINQUERY: case OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY: count = 2; goto QS2; case OP_EXTUNI_EXTRA + OP_TYPESTAR: case OP_EXTUNI_EXTRA + OP_TYPEMINSTAR: case OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR: count = 0; QS2: ADD_ACTIVE(state_offset + 2, 0); if (clen > 0) { int lgb, rgb; const pcre_uchar *nptr = ptr + clen; int ncount = 0; if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR || codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY) { active_count--; /* Remove non-match possibility */ next_active_state--; } lgb = UCD_GRAPHBREAK(c); while (nptr < end_subject) { dlen = 1; if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } rgb = UCD_GRAPHBREAK(d); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; ncount++; lgb = rgb; nptr += dlen; } ADD_NEW_DATA(-(state_offset + count), 0, ncount); } break; #endif /*-----------------------------------------------------------------*/ case OP_ANYNL_EXTRA + OP_TYPEQUERY: case OP_ANYNL_EXTRA + OP_TYPEMINQUERY: case OP_ANYNL_EXTRA + OP_TYPEPOSQUERY: count = 2; goto QS3; case OP_ANYNL_EXTRA + OP_TYPESTAR: case OP_ANYNL_EXTRA + OP_TYPEMINSTAR: case OP_ANYNL_EXTRA + OP_TYPEPOSSTAR: count = 0; QS3: ADD_ACTIVE(state_offset + 2, 0); if (clen > 0) { int ncount = 0; switch (c) { case CHAR_VT: case CHAR_FF: case CHAR_NEL: #ifndef EBCDIC case 0x2028: case 0x2029: #endif /* Not EBCDIC */ if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; goto ANYNL02; case CHAR_CR: if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1; /* Fall through */ ANYNL02: case CHAR_LF: if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSSTAR || codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSQUERY) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW_DATA(-(state_offset + (int)count), 0, ncount); break; default: break; } } break; /*-----------------------------------------------------------------*/ case OP_VSPACE_EXTRA + OP_TYPEQUERY: case OP_VSPACE_EXTRA + OP_TYPEMINQUERY: case OP_VSPACE_EXTRA + OP_TYPEPOSQUERY: count = 2; goto QS4; case OP_VSPACE_EXTRA + OP_TYPESTAR: case OP_VSPACE_EXTRA + OP_TYPEMINSTAR: case OP_VSPACE_EXTRA + OP_TYPEPOSSTAR: count = 0; QS4: ADD_ACTIVE(state_offset + 2, 0); if (clen > 0) { BOOL OK; switch (c) { VSPACE_CASES: OK = TRUE; break; default: OK = FALSE; break; } if (OK == (d == OP_VSPACE)) { if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSSTAR || codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSQUERY) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW_DATA(-(state_offset + (int)count), 0, 0); } } break; /*-----------------------------------------------------------------*/ case OP_HSPACE_EXTRA + OP_TYPEQUERY: case OP_HSPACE_EXTRA + OP_TYPEMINQUERY: case OP_HSPACE_EXTRA + OP_TYPEPOSQUERY: count = 2; goto QS5; case OP_HSPACE_EXTRA + OP_TYPESTAR: case OP_HSPACE_EXTRA + OP_TYPEMINSTAR: case OP_HSPACE_EXTRA + OP_TYPEPOSSTAR: count = 0; QS5: ADD_ACTIVE(state_offset + 2, 0); if (clen > 0) { BOOL OK; switch (c) { HSPACE_CASES: OK = TRUE; break; default: OK = FALSE; break; } if (OK == (d == OP_HSPACE)) { if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSSTAR || codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSQUERY) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW_DATA(-(state_offset + (int)count), 0, 0); } } break; /*-----------------------------------------------------------------*/ #ifdef SUPPORT_UCP case OP_PROP_EXTRA + OP_TYPEEXACT: case OP_PROP_EXTRA + OP_TYPEUPTO: case OP_PROP_EXTRA + OP_TYPEMINUPTO: case OP_PROP_EXTRA + OP_TYPEPOSUPTO: if (codevalue != OP_PROP_EXTRA + OP_TYPEEXACT) { ADD_ACTIVE(state_offset + 1 + IMM2_SIZE + 3, 0); } count = current_state->count; /* Number already matched */ if (clen > 0) { BOOL OK; const pcre_uint32 *cp; const ucd_record * prop = GET_UCD(c); switch(code[1 + IMM2_SIZE + 1]) { case PT_ANY: OK = TRUE; break; case PT_LAMP: OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt; break; case PT_GC: OK = PRIV(ucp_gentype)[prop->chartype] == code[1 + IMM2_SIZE + 2]; break; case PT_PC: OK = prop->chartype == code[1 + IMM2_SIZE + 2]; break; case PT_SC: OK = prop->script == code[1 + IMM2_SIZE + 2]; break; /* These are specials for combination cases. */ case PT_ALNUM: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N; break; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ switch(c) { HSPACE_CASES: VSPACE_CASES: OK = TRUE; break; default: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z; break; } break; case PT_WORD: OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE; break; case PT_CLIST: cp = PRIV(ucd_caseless_sets) + code[1 + IMM2_SIZE + 2]; for (;;) { if (c < *cp) { OK = FALSE; break; } if (c == *cp++) { OK = TRUE; break; } } break; case PT_UCNC: OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) || c >= 0xe000; break; /* Should never occur, but keep compilers from grumbling. */ default: OK = codevalue != OP_PROP; break; } if (OK == (d == OP_PROP)) { if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSUPTO) { active_count--; /* Remove non-match possibility */ next_active_state--; } if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + 1 + IMM2_SIZE + 3, 0); } else { ADD_NEW(state_offset, count); } } } break; /*-----------------------------------------------------------------*/ case OP_EXTUNI_EXTRA + OP_TYPEEXACT: case OP_EXTUNI_EXTRA + OP_TYPEUPTO: case OP_EXTUNI_EXTRA + OP_TYPEMINUPTO: case OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO: if (codevalue != OP_EXTUNI_EXTRA + OP_TYPEEXACT) { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); } count = current_state->count; /* Number already matched */ if (clen > 0) { int lgb, rgb; const pcre_uchar *nptr = ptr + clen; int ncount = 0; if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO) { active_count--; /* Remove non-match possibility */ next_active_state--; } lgb = UCD_GRAPHBREAK(c); while (nptr < end_subject) { dlen = 1; if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } rgb = UCD_GRAPHBREAK(d); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; ncount++; lgb = rgb; nptr += dlen; } if (nptr >= end_subject && (md->moptions & PCRE_PARTIAL_HARD) != 0) reset_could_continue = TRUE; if (++count >= (int)GET2(code, 1)) { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); } else { ADD_NEW_DATA(-state_offset, count, ncount); } } break; #endif /*-----------------------------------------------------------------*/ case OP_ANYNL_EXTRA + OP_TYPEEXACT: case OP_ANYNL_EXTRA + OP_TYPEUPTO: case OP_ANYNL_EXTRA + OP_TYPEMINUPTO: case OP_ANYNL_EXTRA + OP_TYPEPOSUPTO: if (codevalue != OP_ANYNL_EXTRA + OP_TYPEEXACT) { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); } count = current_state->count; /* Number already matched */ if (clen > 0) { int ncount = 0; switch (c) { case CHAR_VT: case CHAR_FF: case CHAR_NEL: #ifndef EBCDIC case 0x2028: case 0x2029: #endif /* Not EBCDIC */ if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; goto ANYNL03; case CHAR_CR: if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1; /* Fall through */ ANYNL03: case CHAR_LF: if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSUPTO) { active_count--; /* Remove non-match possibility */ next_active_state--; } if (++count >= (int)GET2(code, 1)) { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); } else { ADD_NEW_DATA(-state_offset, count, ncount); } break; default: break; } } break; /*-----------------------------------------------------------------*/ case OP_VSPACE_EXTRA + OP_TYPEEXACT: case OP_VSPACE_EXTRA + OP_TYPEUPTO: case OP_VSPACE_EXTRA + OP_TYPEMINUPTO: case OP_VSPACE_EXTRA + OP_TYPEPOSUPTO: if (codevalue != OP_VSPACE_EXTRA + OP_TYPEEXACT) { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); } count = current_state->count; /* Number already matched */ if (clen > 0) { BOOL OK; switch (c) { VSPACE_CASES: OK = TRUE; break; default: OK = FALSE; } if (OK == (d == OP_VSPACE)) { if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSUPTO) { active_count--; /* Remove non-match possibility */ next_active_state--; } if (++count >= (int)GET2(code, 1)) { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); } else { ADD_NEW_DATA(-state_offset, count, 0); } } } break; /*-----------------------------------------------------------------*/ case OP_HSPACE_EXTRA + OP_TYPEEXACT: case OP_HSPACE_EXTRA + OP_TYPEUPTO: case OP_HSPACE_EXTRA + OP_TYPEMINUPTO: case OP_HSPACE_EXTRA + OP_TYPEPOSUPTO: if (codevalue != OP_HSPACE_EXTRA + OP_TYPEEXACT) { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); } count = current_state->count; /* Number already matched */ if (clen > 0) { BOOL OK; switch (c) { HSPACE_CASES: OK = TRUE; break; default: OK = FALSE; break; } if (OK == (d == OP_HSPACE)) { if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSUPTO) { active_count--; /* Remove non-match possibility */ next_active_state--; } if (++count >= (int)GET2(code, 1)) { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); } else { ADD_NEW_DATA(-state_offset, count, 0); } } } break; /* ========================================================================== */ /* These opcodes are followed by a character that is usually compared to the current subject character; it is loaded into d. We still get here even if there is no subject character, because in some cases zero repetitions are permitted. */ /*-----------------------------------------------------------------*/ case OP_CHAR: if (clen > 0 && c == d) { ADD_NEW(state_offset + dlen + 1, 0); } break; /*-----------------------------------------------------------------*/ case OP_CHARI: if (clen == 0) break; #ifdef SUPPORT_UTF if (utf) { if (c == d) { ADD_NEW(state_offset + dlen + 1, 0); } else { unsigned int othercase; if (c < 128) othercase = fcc[c]; else /* If we have Unicode property support, we can use it to test the other case of the character. */ #ifdef SUPPORT_UCP othercase = UCD_OTHERCASE(c); #else othercase = NOTACHAR; #endif if (d == othercase) { ADD_NEW(state_offset + dlen + 1, 0); } } } else #endif /* SUPPORT_UTF */ /* Not UTF mode */ { if (TABLE_GET(c, lcc, c) == TABLE_GET(d, lcc, d)) { ADD_NEW(state_offset + 2, 0); } } break; #ifdef SUPPORT_UCP /*-----------------------------------------------------------------*/ /* This is a tricky one because it can match more than one character. Find out how many characters to skip, and then set up a negative state to wait for them to pass before continuing. */ case OP_EXTUNI: if (clen > 0) { int lgb, rgb; const pcre_uchar *nptr = ptr + clen; int ncount = 0; lgb = UCD_GRAPHBREAK(c); while (nptr < end_subject) { dlen = 1; if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); } rgb = UCD_GRAPHBREAK(d); if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break; ncount++; lgb = rgb; nptr += dlen; } if (nptr >= end_subject && (md->moptions & PCRE_PARTIAL_HARD) != 0) reset_could_continue = TRUE; ADD_NEW_DATA(-(state_offset + 1), 0, ncount); } break; #endif /*-----------------------------------------------------------------*/ /* This is a tricky like EXTUNI because it too can match more than one character (when CR is followed by LF). In this case, set up a negative state to wait for one character to pass before continuing. */ case OP_ANYNL: if (clen > 0) switch(c) { case CHAR_VT: case CHAR_FF: case CHAR_NEL: #ifndef EBCDIC case 0x2028: case 0x2029: #endif /* Not EBCDIC */ if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break; case CHAR_LF: ADD_NEW(state_offset + 1, 0); break; case CHAR_CR: if (ptr + 1 >= end_subject) { ADD_NEW(state_offset + 1, 0); if ((md->moptions & PCRE_PARTIAL_HARD) != 0) reset_could_continue = TRUE; } else if (UCHAR21TEST(ptr + 1) == CHAR_LF) { ADD_NEW_DATA(-(state_offset + 1), 0, 1); } else { ADD_NEW(state_offset + 1, 0); } break; } break; /*-----------------------------------------------------------------*/ case OP_NOT_VSPACE: if (clen > 0) switch(c) { VSPACE_CASES: break; default: ADD_NEW(state_offset + 1, 0); break; } break; /*-----------------------------------------------------------------*/ case OP_VSPACE: if (clen > 0) switch(c) { VSPACE_CASES: ADD_NEW(state_offset + 1, 0); break; default: break; } break; /*-----------------------------------------------------------------*/ case OP_NOT_HSPACE: if (clen > 0) switch(c) { HSPACE_CASES: break; default: ADD_NEW(state_offset + 1, 0); break; } break; /*-----------------------------------------------------------------*/ case OP_HSPACE: if (clen > 0) switch(c) { HSPACE_CASES: ADD_NEW(state_offset + 1, 0); break; default: break; } break; /*-----------------------------------------------------------------*/ /* Match a negated single character casefully. */ case OP_NOT: if (clen > 0 && c != d) { ADD_NEW(state_offset + dlen + 1, 0); } break; /*-----------------------------------------------------------------*/ /* Match a negated single character caselessly. */ case OP_NOTI: if (clen > 0) { pcre_uint32 otherd; #ifdef SUPPORT_UTF if (utf && d >= 128) { #ifdef SUPPORT_UCP otherd = UCD_OTHERCASE(d); #else otherd = d; #endif /* SUPPORT_UCP */ } else #endif /* SUPPORT_UTF */ otherd = TABLE_GET(d, fcc, d); if (c != d && c != otherd) { ADD_NEW(state_offset + dlen + 1, 0); } } break; /*-----------------------------------------------------------------*/ case OP_PLUSI: case OP_MINPLUSI: case OP_POSPLUSI: case OP_NOTPLUSI: case OP_NOTMINPLUSI: case OP_NOTPOSPLUSI: caseless = TRUE; codevalue -= OP_STARI - OP_STAR; /* Fall through */ case OP_PLUS: case OP_MINPLUS: case OP_POSPLUS: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(state_offset + dlen + 1, 0); } if (clen > 0) { pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF if (utf && d >= 128) { #ifdef SUPPORT_UCP otherd = UCD_OTHERCASE(d); #endif /* SUPPORT_UCP */ } else #endif /* SUPPORT_UTF */ otherd = TABLE_GET(d, fcc, d); } if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) { if (count > 0 && (codevalue == OP_POSPLUS || codevalue == OP_NOTPOSPLUS)) { active_count--; /* Remove non-match possibility */ next_active_state--; } count++; ADD_NEW(state_offset, count); } } break; /*-----------------------------------------------------------------*/ case OP_QUERYI: case OP_MINQUERYI: case OP_POSQUERYI: case OP_NOTQUERYI: case OP_NOTMINQUERYI: case OP_NOTPOSQUERYI: caseless = TRUE; codevalue -= OP_STARI - OP_STAR; /* Fall through */ case OP_QUERY: case OP_MINQUERY: case OP_POSQUERY: case OP_NOTQUERY: case OP_NOTMINQUERY: case OP_NOTPOSQUERY: ADD_ACTIVE(state_offset + dlen + 1, 0); if (clen > 0) { pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF if (utf && d >= 128) { #ifdef SUPPORT_UCP otherd = UCD_OTHERCASE(d); #endif /* SUPPORT_UCP */ } else #endif /* SUPPORT_UTF */ otherd = TABLE_GET(d, fcc, d); } if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) { if (codevalue == OP_POSQUERY || codevalue == OP_NOTPOSQUERY) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW(state_offset + dlen + 1, 0); } } break; /*-----------------------------------------------------------------*/ case OP_STARI: case OP_MINSTARI: case OP_POSSTARI: case OP_NOTSTARI: case OP_NOTMINSTARI: case OP_NOTPOSSTARI: caseless = TRUE; codevalue -= OP_STARI - OP_STAR; /* Fall through */ case OP_STAR: case OP_MINSTAR: case OP_POSSTAR: case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPOSSTAR: ADD_ACTIVE(state_offset + dlen + 1, 0); if (clen > 0) { pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF if (utf && d >= 128) { #ifdef SUPPORT_UCP otherd = UCD_OTHERCASE(d); #endif /* SUPPORT_UCP */ } else #endif /* SUPPORT_UTF */ otherd = TABLE_GET(d, fcc, d); } if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) { if (codevalue == OP_POSSTAR || codevalue == OP_NOTPOSSTAR) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW(state_offset, 0); } } break; /*-----------------------------------------------------------------*/ case OP_EXACTI: case OP_NOTEXACTI: caseless = TRUE; codevalue -= OP_STARI - OP_STAR; /* Fall through */ case OP_EXACT: case OP_NOTEXACT: count = current_state->count; /* Number already matched */ if (clen > 0) { pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF if (utf && d >= 128) { #ifdef SUPPORT_UCP otherd = UCD_OTHERCASE(d); #endif /* SUPPORT_UCP */ } else #endif /* SUPPORT_UTF */ otherd = TABLE_GET(d, fcc, d); } if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) { if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); } else { ADD_NEW(state_offset, count); } } } break; /*-----------------------------------------------------------------*/ case OP_UPTOI: case OP_MINUPTOI: case OP_POSUPTOI: case OP_NOTUPTOI: case OP_NOTMINUPTOI: case OP_NOTPOSUPTOI: caseless = TRUE; codevalue -= OP_STARI - OP_STAR; /* Fall through */ case OP_UPTO: case OP_MINUPTO: case OP_POSUPTO: case OP_NOTUPTO: case OP_NOTMINUPTO: case OP_NOTPOSUPTO: ADD_ACTIVE(state_offset + dlen + 1 + IMM2_SIZE, 0); count = current_state->count; /* Number already matched */ if (clen > 0) { pcre_uint32 otherd = NOTACHAR; if (caseless) { #ifdef SUPPORT_UTF if (utf && d >= 128) { #ifdef SUPPORT_UCP otherd = UCD_OTHERCASE(d); #endif /* SUPPORT_UCP */ } else #endif /* SUPPORT_UTF */ otherd = TABLE_GET(d, fcc, d); } if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR)) { if (codevalue == OP_POSUPTO || codevalue == OP_NOTPOSUPTO) { active_count--; /* Remove non-match possibility */ next_active_state--; } if (++count >= (int)GET2(code, 1)) { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); } else { ADD_NEW(state_offset, count); } } } break; /* ========================================================================== */ /* These are the class-handling opcodes */ case OP_CLASS: case OP_NCLASS: case OP_XCLASS: { BOOL isinclass = FALSE; int next_state_offset; const pcre_uchar *ecode; /* For a simple class, there is always just a 32-byte table, and we can set isinclass from it. */ if (codevalue != OP_XCLASS) { ecode = code + 1 + (32 / sizeof(pcre_uchar)); if (clen > 0) { isinclass = (c > 255)? (codevalue == OP_NCLASS) : ((((pcre_uint8 *)(code + 1))[c/8] & (1 << (c&7))) != 0); } } /* An extended class may have a table or a list of single characters, ranges, or both, and it may be positive or negative. There's a function that sorts all this out. */ else { ecode = code + GET(code, 1); if (clen > 0) isinclass = PRIV(xclass)(c, code + 1 + LINK_SIZE, utf); } /* At this point, isinclass is set for all kinds of class, and ecode points to the byte after the end of the class. If there is a quantifier, this is where it will be. */ next_state_offset = (int)(ecode - start_code); switch (*ecode) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPOSSTAR: ADD_ACTIVE(next_state_offset + 1, 0); if (isinclass) { if (*ecode == OP_CRPOSSTAR) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW(state_offset, 0); } break; case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRPOSPLUS: count = current_state->count; /* Already matched */ if (count > 0) { ADD_ACTIVE(next_state_offset + 1, 0); } if (isinclass) { if (count > 0 && *ecode == OP_CRPOSPLUS) { active_count--; /* Remove non-match possibility */ next_active_state--; } count++; ADD_NEW(state_offset, count); } break; case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSQUERY: ADD_ACTIVE(next_state_offset + 1, 0); if (isinclass) { if (*ecode == OP_CRPOSQUERY) { active_count--; /* Remove non-match possibility */ next_active_state--; } ADD_NEW(next_state_offset + 1, 0); } break; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: count = current_state->count; /* Already matched */ if (count >= (int)GET2(ecode, 1)) { ADD_ACTIVE(next_state_offset + 1 + 2 * IMM2_SIZE, 0); } if (isinclass) { int max = (int)GET2(ecode, 1 + IMM2_SIZE); if (*ecode == OP_CRPOSRANGE && count >= (int)GET2(ecode, 1)) { active_count--; /* Remove non-match possibility */ next_active_state--; } if (++count >= max && max != 0) /* Max 0 => no limit */ { ADD_NEW(next_state_offset + 1 + 2 * IMM2_SIZE, 0); } else { ADD_NEW(state_offset, count); } } break; default: if (isinclass) { ADD_NEW(next_state_offset, 0); } break; } } break; /* ========================================================================== */ /* These are the opcodes for fancy brackets of various kinds. We have to use recursion in order to handle them. The "always failing" assertion (?!) is optimised to OP_FAIL when compiling, so we have to support that, though the other "backtracking verbs" are not supported. */ case OP_FAIL: forced_fail++; /* Count FAILs for multiple states */ break; case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: { int rc; int local_offsets[2]; int local_workspace[1000]; const pcre_uchar *endasscode = code + GET(code, 1); while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); rc = internal_dfa_exec( md, /* static match data */ code, /* this subexpression's code */ ptr, /* where we currently are */ (int)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ sizeof(local_offsets)/sizeof(int), /* size of same */ local_workspace, /* workspace vector */ sizeof(local_workspace)/sizeof(int), /* size of same */ rlevel); /* function recursion level */ if (rc == PCRE_ERROR_DFA_UITEM) return rc; if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK)) { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); } } break; /*-----------------------------------------------------------------*/ case OP_COND: case OP_SCOND: { int local_offsets[1000]; int local_workspace[1000]; int codelink = GET(code, 1); int condcode; /* Because of the way auto-callout works during compile, a callout item is inserted between OP_COND and an assertion condition. This does not happen for the other conditions. */ if (code[LINK_SIZE+1] == OP_CALLOUT) { rrc = 0; if (PUBL(callout) != NULL) { PUBL(callout_block) cb; cb.version = 1; /* Version 1 of the callout block */ cb.callout_number = code[LINK_SIZE+2]; cb.offset_vector = offsets; #if defined COMPILE_PCRE8 cb.subject = (PCRE_SPTR)start_subject; #elif defined COMPILE_PCRE16 cb.subject = (PCRE_SPTR16)start_subject; #elif defined COMPILE_PCRE32 cb.subject = (PCRE_SPTR32)start_subject; #endif cb.subject_length = (int)(end_subject - start_subject); cb.start_match = (int)(current_subject - start_subject); cb.current_position = (int)(ptr - start_subject); cb.pattern_position = GET(code, LINK_SIZE + 3); cb.next_item_length = GET(code, 3 + 2*LINK_SIZE); cb.capture_top = 1; cb.capture_last = -1; cb.callout_data = md->callout_data; cb.mark = NULL; /* No (*MARK) support */ if ((rrc = (*PUBL(callout))(&cb)) < 0) return rrc; /* Abandon */ } if (rrc > 0) break; /* Fail this thread */ code += PRIV(OP_lengths)[OP_CALLOUT]; /* Skip callout data */ } condcode = code[LINK_SIZE+1]; /* Back reference conditions and duplicate named recursion conditions are not supported */ if (condcode == OP_CREF || condcode == OP_DNCREF || condcode == OP_DNRREF) return PCRE_ERROR_DFA_UCOND; /* The DEFINE condition is always false, and the assertion (?!) is converted to OP_FAIL. */ if (condcode == OP_DEF || condcode == OP_FAIL) { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); } /* The only supported version of OP_RREF is for the value RREF_ANY, which means "test if in any recursion". We can't test for specifically recursed groups. */ else if (condcode == OP_RREF) { int value = GET2(code, LINK_SIZE + 2); if (value != RREF_ANY) return PCRE_ERROR_DFA_UCOND; if (md->recursive != NULL) { ADD_ACTIVE(state_offset + LINK_SIZE + 2 + IMM2_SIZE, 0); } else { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); } } /* Otherwise, the condition is an assertion */ else { int rc; const pcre_uchar *asscode = code + LINK_SIZE + 1; const pcre_uchar *endasscode = asscode + GET(asscode, 1); while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1); rc = internal_dfa_exec( md, /* fixed match data */ asscode, /* this subexpression's code */ ptr, /* where we currently are */ (int)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ sizeof(local_offsets)/sizeof(int), /* size of same */ local_workspace, /* workspace vector */ sizeof(local_workspace)/sizeof(int), /* size of same */ rlevel); /* function recursion level */ if (rc == PCRE_ERROR_DFA_UITEM) return rc; if ((rc >= 0) == (condcode == OP_ASSERT || condcode == OP_ASSERTBACK)) { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); } else { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); } } } break; /*-----------------------------------------------------------------*/ case OP_RECURSE: { dfa_recursion_info *ri; int local_offsets[1000]; int local_workspace[1000]; const pcre_uchar *callpat = start_code + GET(code, 1); int recno = (callpat == md->start_code)? 0 : GET2(callpat, 1 + LINK_SIZE); int rc; DPRINTF(("%.*sStarting regex recursion\n", rlevel*2-2, SP)); /* Check for repeating a recursion without advancing the subject pointer. This should catch convoluted mutual recursions. (Some simple cases are caught at compile time.) */ for (ri = md->recursive; ri != NULL; ri = ri->prevrec) if (recno == ri->group_num && ptr == ri->subject_position) return PCRE_ERROR_RECURSELOOP; /* Remember this recursion and where we started it so as to catch infinite loops. */ new_recursive.group_num = recno; new_recursive.subject_position = ptr; new_recursive.prevrec = md->recursive; md->recursive = &new_recursive; rc = internal_dfa_exec( md, /* fixed match data */ callpat, /* this subexpression's code */ ptr, /* where we currently are */ (int)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ sizeof(local_offsets)/sizeof(int), /* size of same */ local_workspace, /* workspace vector */ sizeof(local_workspace)/sizeof(int), /* size of same */ rlevel); /* function recursion level */ md->recursive = new_recursive.prevrec; /* Done this recursion */ DPRINTF(("%.*sReturn from regex recursion: rc=%d\n", rlevel*2-2, SP, rc)); /* Ran out of internal offsets */ if (rc == 0) return PCRE_ERROR_DFA_RECURSE; /* For each successful matched substring, set up the next state with a count of characters to skip before trying it. Note that the count is in characters, not bytes. */ if (rc > 0) { for (rc = rc*2 - 2; rc >= 0; rc -= 2) { int charcount = local_offsets[rc+1] - local_offsets[rc]; #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) { const pcre_uchar *p = start_subject + local_offsets[rc]; const pcre_uchar *pp = start_subject + local_offsets[rc+1]; while (p < pp) if (NOT_FIRSTCHAR(*p++)) charcount--; } #endif if (charcount > 0) { ADD_NEW_DATA(-(state_offset + LINK_SIZE + 1), 0, (charcount - 1)); } else { ADD_ACTIVE(state_offset + LINK_SIZE + 1, 0); } } } else if (rc != PCRE_ERROR_NOMATCH) return rc; } break; /*-----------------------------------------------------------------*/ case OP_BRAPOS: case OP_SBRAPOS: case OP_CBRAPOS: case OP_SCBRAPOS: case OP_BRAPOSZERO: { int charcount, matched_count; const pcre_uchar *local_ptr = ptr; BOOL allow_zero; if (codevalue == OP_BRAPOSZERO) { allow_zero = TRUE; codevalue = *(++code); /* Codevalue will be one of above BRAs */ } else allow_zero = FALSE; /* Loop to match the subpattern as many times as possible as if it were a complete pattern. */ for (matched_count = 0;; matched_count++) { int local_offsets[2]; int local_workspace[1000]; int rc = internal_dfa_exec( md, /* fixed match data */ code, /* this subexpression's code */ local_ptr, /* where we currently are */ (int)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ sizeof(local_offsets)/sizeof(int), /* size of same */ local_workspace, /* workspace vector */ sizeof(local_workspace)/sizeof(int), /* size of same */ rlevel); /* function recursion level */ /* Failed to match */ if (rc < 0) { if (rc != PCRE_ERROR_NOMATCH) return rc; break; } /* Matched: break the loop if zero characters matched. */ charcount = local_offsets[1] - local_offsets[0]; if (charcount == 0) break; local_ptr += charcount; /* Advance temporary position ptr */ } /* At this point we have matched the subpattern matched_count times, and local_ptr is pointing to the character after the end of the last match. */ if (matched_count > 0 || allow_zero) { const pcre_uchar *end_subpattern = code; int next_state_offset; do { end_subpattern += GET(end_subpattern, 1); } while (*end_subpattern == OP_ALT); next_state_offset = (int)(end_subpattern - start_code + LINK_SIZE + 1); /* Optimization: if there are no more active states, and there are no new states yet set up, then skip over the subject string right here, to save looping. Otherwise, set up the new state to swing into action when the end of the matched substring is reached. */ if (i + 1 >= active_count && new_count == 0) { ptr = local_ptr; clen = 0; ADD_NEW(next_state_offset, 0); } else { const pcre_uchar *p = ptr; const pcre_uchar *pp = local_ptr; charcount = (int)(pp - p); #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) while (p < pp) if (NOT_FIRSTCHAR(*p++)) charcount--; #endif ADD_NEW_DATA(-next_state_offset, 0, (charcount - 1)); } } } break; /*-----------------------------------------------------------------*/ case OP_ONCE: case OP_ONCE_NC: { int local_offsets[2]; int local_workspace[1000]; int rc = internal_dfa_exec( md, /* fixed match data */ code, /* this subexpression's code */ ptr, /* where we currently are */ (int)(ptr - start_subject), /* start offset */ local_offsets, /* offset vector */ sizeof(local_offsets)/sizeof(int), /* size of same */ local_workspace, /* workspace vector */ sizeof(local_workspace)/sizeof(int), /* size of same */ rlevel); /* function recursion level */ if (rc >= 0) { const pcre_uchar *end_subpattern = code; int charcount = local_offsets[1] - local_offsets[0]; int next_state_offset, repeat_state_offset; do { end_subpattern += GET(end_subpattern, 1); } while (*end_subpattern == OP_ALT); next_state_offset = (int)(end_subpattern - start_code + LINK_SIZE + 1); /* If the end of this subpattern is KETRMAX or KETRMIN, we must arrange for the repeat state also to be added to the relevant list. Calculate the offset, or set -1 for no repeat. */ repeat_state_offset = (*end_subpattern == OP_KETRMAX || *end_subpattern == OP_KETRMIN)? (int)(end_subpattern - start_code - GET(end_subpattern, 1)) : -1; /* If we have matched an empty string, add the next state at the current character pointer. This is important so that the duplicate checking kicks in, which is what breaks infinite loops that match an empty string. */ if (charcount == 0) { ADD_ACTIVE(next_state_offset, 0); } /* Optimization: if there are no more active states, and there are no new states yet set up, then skip over the subject string right here, to save looping. Otherwise, set up the new state to swing into action when the end of the matched substring is reached. */ else if (i + 1 >= active_count && new_count == 0) { ptr += charcount; clen = 0; ADD_NEW(next_state_offset, 0); /* If we are adding a repeat state at the new character position, we must fudge things so that it is the only current state. Otherwise, it might be a duplicate of one we processed before, and that would cause it to be skipped. */ if (repeat_state_offset >= 0) { next_active_state = active_states; active_count = 0; i = -1; ADD_ACTIVE(repeat_state_offset, 0); } } else { #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) { const pcre_uchar *p = start_subject + local_offsets[0]; const pcre_uchar *pp = start_subject + local_offsets[1]; while (p < pp) if (NOT_FIRSTCHAR(*p++)) charcount--; } #endif ADD_NEW_DATA(-next_state_offset, 0, (charcount - 1)); if (repeat_state_offset >= 0) { ADD_NEW_DATA(-repeat_state_offset, 0, (charcount - 1)); } } } else if (rc != PCRE_ERROR_NOMATCH) return rc; } break; /* ========================================================================== */ /* Handle callouts */ case OP_CALLOUT: rrc = 0; if (PUBL(callout) != NULL) { PUBL(callout_block) cb; cb.version = 1; /* Version 1 of the callout block */ cb.callout_number = code[1]; cb.offset_vector = offsets; #if defined COMPILE_PCRE8 cb.subject = (PCRE_SPTR)start_subject; #elif defined COMPILE_PCRE16 cb.subject = (PCRE_SPTR16)start_subject; #elif defined COMPILE_PCRE32 cb.subject = (PCRE_SPTR32)start_subject; #endif cb.subject_length = (int)(end_subject - start_subject); cb.start_match = (int)(current_subject - start_subject); cb.current_position = (int)(ptr - start_subject); cb.pattern_position = GET(code, 2); cb.next_item_length = GET(code, 2 + LINK_SIZE); cb.capture_top = 1; cb.capture_last = -1; cb.callout_data = md->callout_data; cb.mark = NULL; /* No (*MARK) support */ if ((rrc = (*PUBL(callout))(&cb)) < 0) return rrc; /* Abandon */ } if (rrc == 0) { ADD_ACTIVE(state_offset + PRIV(OP_lengths)[OP_CALLOUT], 0); } break; /* ========================================================================== */ default: /* Unsupported opcode */ return PCRE_ERROR_DFA_UITEM; } NEXT_ACTIVE_STATE: continue; } /* End of loop scanning active states */ /* We have finished the processing at the current subject character. If no new states have been set for the next character, we have found all the matches that we are going to find. If we are at the top level and partial matching has been requested, check for appropriate conditions. The "forced_ fail" variable counts the number of (*F) encountered for the character. If it is equal to the original active_count (saved in workspace[1]) it means that (*F) was found on every active state. In this case we don't want to give a partial match. The "could_continue" variable is true if a state could have continued but for the fact that the end of the subject was reached. */ if (new_count <= 0) { if (rlevel == 1 && /* Top level, and */ could_continue && /* Some could go on, and */ forced_fail != workspace[1] && /* Not all forced fail & */ ( /* either... */ (md->moptions & PCRE_PARTIAL_HARD) != 0 /* Hard partial */ || /* or... */ ((md->moptions & PCRE_PARTIAL_SOFT) != 0 && /* Soft partial and */ match_count < 0) /* no matches */ ) && /* And... */ ( partial_newline || /* Either partial NL */ ( /* or ... */ ptr >= end_subject && /* End of subject and */ ptr > md->start_used_ptr) /* Inspected non-empty string */ ) ) match_count = PCRE_ERROR_PARTIAL; DPRINTF(("%.*sEnd of internal_dfa_exec %d: returning %d\n" "%.*s---------------------\n\n", rlevel*2-2, SP, rlevel, match_count, rlevel*2-2, SP)); break; /* In effect, "return", but see the comment below */ } /* One or more states are active for the next character. */ ptr += clen; /* Advance to next subject character */ } /* Loop to move along the subject string */ /* Control gets here from "break" a few lines above. We do it this way because if we use "return" above, we have compiler trouble. Some compilers warn if there's nothing here because they think the function doesn't return a value. On the other hand, if we put a dummy statement here, some more clever compilers complain that it can't be reached. Sigh. */ return match_count; } /************************************************* * Execute a Regular Expression - DFA engine * *************************************************/ /* This external function applies a compiled re to a subject string using a DFA engine. This function calls the internal function multiple times if the pattern is not anchored. Arguments: argument_re points to the compiled expression extra_data points to extra data or is NULL subject points to the subject string length length of subject string (may contain binary zeros) start_offset where to start in the subject string options option bits offsets vector of match offsets offsetcount size of same workspace workspace vector wscount size of same Returns: > 0 => number of match offset pairs placed in offsets = 0 => offsets overflowed; longest matches are present -1 => failed to match < -1 => some kind of unexpected problem */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_dfa_exec(const pcre *argument_re, const pcre_extra *extra_data, const char *subject, int length, int start_offset, int options, int *offsets, int offsetcount, int *workspace, int wscount) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_dfa_exec(const pcre16 *argument_re, const pcre16_extra *extra_data, PCRE_SPTR16 subject, int length, int start_offset, int options, int *offsets, int offsetcount, int *workspace, int wscount) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_dfa_exec(const pcre32 *argument_re, const pcre32_extra *extra_data, PCRE_SPTR32 subject, int length, int start_offset, int options, int *offsets, int offsetcount, int *workspace, int wscount) #endif { REAL_PCRE *re = (REAL_PCRE *)argument_re; dfa_match_data match_block; dfa_match_data *md = &match_block; BOOL utf, anchored, startline, firstline; const pcre_uchar *current_subject, *end_subject; const pcre_study_data *study = NULL; const pcre_uchar *req_char_ptr; const pcre_uint8 *start_bits = NULL; BOOL has_first_char = FALSE; BOOL has_req_char = FALSE; pcre_uchar first_char = 0; pcre_uchar first_char2 = 0; pcre_uchar req_char = 0; pcre_uchar req_char2 = 0; int newline; /* Plausibility checks */ if ((options & ~PUBLIC_DFA_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION; if (re == NULL || subject == NULL || workspace == NULL || (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL; if (offsetcount < 0) return PCRE_ERROR_BADCOUNT; if (wscount < 20) return PCRE_ERROR_DFA_WSSIZE; if (length < 0) return PCRE_ERROR_BADLENGTH; if (start_offset < 0 || start_offset > length) return PCRE_ERROR_BADOFFSET; /* Check that the first field in the block is the magic number. If it is not, return with PCRE_ERROR_BADMAGIC. However, if the magic number is equal to REVERSED_MAGIC_NUMBER we return with PCRE_ERROR_BADENDIANNESS, which means that the pattern is likely compiled with different endianness. */ if (re->magic_number != MAGIC_NUMBER) return re->magic_number == REVERSED_MAGIC_NUMBER? PCRE_ERROR_BADENDIANNESS:PCRE_ERROR_BADMAGIC; if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE; /* If restarting after a partial match, do some sanity checks on the contents of the workspace. */ if ((options & PCRE_DFA_RESTART) != 0) { if ((workspace[0] & (-2)) != 0 || workspace[1] < 1 || workspace[1] > (wscount - 2)/INTS_PER_STATEBLOCK) return PCRE_ERROR_DFA_BADRESTART; } /* Set up study, callout, and table data */ md->tables = re->tables; md->callout_data = NULL; if (extra_data != NULL) { unsigned long int flags = extra_data->flags; if ((flags & PCRE_EXTRA_STUDY_DATA) != 0) study = (const pcre_study_data *)extra_data->study_data; if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0) return PCRE_ERROR_DFA_UMLIMIT; if ((flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) != 0) return PCRE_ERROR_DFA_UMLIMIT; if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0) md->callout_data = extra_data->callout_data; if ((flags & PCRE_EXTRA_TABLES) != 0) md->tables = extra_data->tables; } /* Set some local values */ current_subject = (const pcre_uchar *)subject + start_offset; end_subject = (const pcre_uchar *)subject + length; req_char_ptr = current_subject - 1; #ifdef SUPPORT_UTF /* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */ utf = (re->options & PCRE_UTF8) != 0; #else utf = FALSE; #endif anchored = (options & (PCRE_ANCHORED|PCRE_DFA_RESTART)) != 0 || (re->options & PCRE_ANCHORED) != 0; /* The remaining fixed data for passing around. */ md->start_code = (const pcre_uchar *)argument_re + re->name_table_offset + re->name_count * re->name_entry_size; md->start_subject = (const pcre_uchar *)subject; md->end_subject = end_subject; md->start_offset = start_offset; md->moptions = options; md->poptions = re->options; /* If the BSR option is not set at match time, copy what was set at compile time. */ if ((md->moptions & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) == 0) { if ((re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) != 0) md->moptions |= re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE); #ifdef BSR_ANYCRLF else md->moptions |= PCRE_BSR_ANYCRLF; #endif } /* Handle different types of newline. The three bits give eight cases. If nothing is set at run time, whatever was used at compile time applies. */ switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : (pcre_uint32)options) & PCRE_NEWLINE_BITS) { case 0: newline = NEWLINE; break; /* Compile-time default */ case PCRE_NEWLINE_CR: newline = CHAR_CR; break; case PCRE_NEWLINE_LF: newline = CHAR_NL; break; case PCRE_NEWLINE_CR+ PCRE_NEWLINE_LF: newline = (CHAR_CR << 8) | CHAR_NL; break; case PCRE_NEWLINE_ANY: newline = -1; break; case PCRE_NEWLINE_ANYCRLF: newline = -2; break; default: return PCRE_ERROR_BADNEWLINE; } if (newline == -2) { md->nltype = NLTYPE_ANYCRLF; } else if (newline < 0) { md->nltype = NLTYPE_ANY; } else { md->nltype = NLTYPE_FIXED; if (newline > 255) { md->nllen = 2; md->nl[0] = (newline >> 8) & 255; md->nl[1] = newline & 255; } else { md->nllen = 1; md->nl[0] = newline; } } /* Check a UTF-8 string if required. Unfortunately there's no way of passing back the character offset. */ #ifdef SUPPORT_UTF if (utf && (options & PCRE_NO_UTF8_CHECK) == 0) { int erroroffset; int errorcode = PRIV(valid_utf)((pcre_uchar *)subject, length, &erroroffset); if (errorcode != 0) { if (offsetcount >= 2) { offsets[0] = erroroffset; offsets[1] = errorcode; } #if defined COMPILE_PCRE8 return (errorcode <= PCRE_UTF8_ERR5 && (options & PCRE_PARTIAL_HARD) != 0) ? PCRE_ERROR_SHORTUTF8 : PCRE_ERROR_BADUTF8; #elif defined COMPILE_PCRE16 return (errorcode <= PCRE_UTF16_ERR1 && (options & PCRE_PARTIAL_HARD) != 0) ? PCRE_ERROR_SHORTUTF16 : PCRE_ERROR_BADUTF16; #elif defined COMPILE_PCRE32 return PCRE_ERROR_BADUTF32; #endif } #if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 if (start_offset > 0 && start_offset < length && NOT_FIRSTCHAR(((PCRE_PUCHAR)subject)[start_offset])) return PCRE_ERROR_BADUTF8_OFFSET; #endif } #endif /* If the exec call supplied NULL for tables, use the inbuilt ones. This is a feature that makes it possible to save compiled regex and re-use them in other programs later. */ if (md->tables == NULL) md->tables = PRIV(default_tables); /* The "must be at the start of a line" flags are used in a loop when finding where to start. */ startline = (re->flags & PCRE_STARTLINE) != 0; firstline = (re->options & PCRE_FIRSTLINE) != 0; /* Set up the first character to match, if available. The first_byte value is never set for an anchored regular expression, but the anchoring may be forced at run time, so we have to test for anchoring. The first char may be unset for an unanchored pattern, of course. If there's no first char and the pattern was studied, there may be a bitmap of possible first characters. */ if (!anchored) { if ((re->flags & PCRE_FIRSTSET) != 0) { has_first_char = TRUE; first_char = first_char2 = (pcre_uchar)(re->first_char); if ((re->flags & PCRE_FCH_CASELESS) != 0) { first_char2 = TABLE_GET(first_char, md->tables + fcc_offset, first_char); #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8) if (utf && first_char > 127) first_char2 = UCD_OTHERCASE(first_char); #endif } } else { if (!startline && study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0) start_bits = study->start_bits; } } /* For anchored or unanchored matches, there may be a "last known required character" set. */ if ((re->flags & PCRE_REQCHSET) != 0) { has_req_char = TRUE; req_char = req_char2 = (pcre_uchar)(re->req_char); if ((re->flags & PCRE_RCH_CASELESS) != 0) { req_char2 = TABLE_GET(req_char, md->tables + fcc_offset, req_char); #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8) if (utf && req_char > 127) req_char2 = UCD_OTHERCASE(req_char); #endif } } /* Call the main matching function, looping for a non-anchored regex after a failed match. If not restarting, perform certain optimizations at the start of a match. */ for (;;) { int rc; if ((options & PCRE_DFA_RESTART) == 0) { const pcre_uchar *save_end_subject = end_subject; /* If firstline is TRUE, the start of the match is constrained to the first line of a multiline string. Implement this by temporarily adjusting end_subject so that we stop scanning at a newline. If the match fails at the newline, later code breaks this loop. */ if (firstline) { PCRE_PUCHAR t = current_subject; #ifdef SUPPORT_UTF if (utf) { while (t < md->end_subject && !IS_NEWLINE(t)) { t++; ACROSSCHAR(t < end_subject, *t, t++); } } else #endif while (t < md->end_subject && !IS_NEWLINE(t)) t++; end_subject = t; } /* There are some optimizations that avoid running the match if a known starting point is not found. However, there is an option that disables these, for testing and for ensuring that all callouts do actually occur. The option can be set in the regex by (*NO_START_OPT) or passed in match-time options. */ if (((options | re->options) & PCRE_NO_START_OPTIMIZE) == 0) { /* Advance to a known first pcre_uchar (i.e. data item) */ if (has_first_char) { if (first_char != first_char2) { pcre_uchar csc; while (current_subject < end_subject && (csc = UCHAR21TEST(current_subject)) != first_char && csc != first_char2) current_subject++; } else while (current_subject < end_subject && UCHAR21TEST(current_subject) != first_char) current_subject++; } /* Or to just after a linebreak for a multiline match if possible */ else if (startline) { if (current_subject > md->start_subject + start_offset) { #ifdef SUPPORT_UTF if (utf) { while (current_subject < end_subject && !WAS_NEWLINE(current_subject)) { current_subject++; ACROSSCHAR(current_subject < end_subject, *current_subject, current_subject++); } } else #endif while (current_subject < end_subject && !WAS_NEWLINE(current_subject)) current_subject++; /* If we have just passed a CR and the newline option is ANY or ANYCRLF, and we are now at a LF, advance the match position by one more character. */ if (UCHAR21TEST(current_subject - 1) == CHAR_CR && (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) && current_subject < end_subject && UCHAR21TEST(current_subject) == CHAR_NL) current_subject++; } } /* Advance to a non-unique first pcre_uchar after study */ else if (start_bits != NULL) { while (current_subject < end_subject) { register pcre_uint32 c = UCHAR21TEST(current_subject); #ifndef COMPILE_PCRE8 if (c > 255) c = 255; #endif if ((start_bits[c/8] & (1 << (c&7))) != 0) break; current_subject++; } } } /* Restore fudged end_subject */ end_subject = save_end_subject; /* The following two optimizations are disabled for partial matching or if disabling is explicitly requested (and of course, by the test above, this code is not obeyed when restarting after a partial match). */ if (((options | re->options) & PCRE_NO_START_OPTIMIZE) == 0 && (options & (PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT)) == 0) { /* If the pattern was studied, a minimum subject length may be set. This is a lower bound; no actual string of that length may actually match the pattern. Although the value is, strictly, in characters, we treat it as in pcre_uchar units to avoid spending too much time in this optimization. */ if (study != NULL && (study->flags & PCRE_STUDY_MINLEN) != 0 && (pcre_uint32)(end_subject - current_subject) < study->minlength) return PCRE_ERROR_NOMATCH; /* If req_char is set, we know that that pcre_uchar must appear in the subject for the match to succeed. If the first pcre_uchar is set, req_char must be later in the subject; otherwise the test starts at the match point. This optimization can save a huge amount of work in patterns with nested unlimited repeats that aren't going to match. Writing separate code for cased/caseless versions makes it go faster, as does using an autoincrement and backing off on a match. HOWEVER: when the subject string is very, very long, searching to its end can take a long time, and give bad performance on quite ordinary patterns. This showed up when somebody was matching /^C/ on a 32-megabyte string... so we don't do this when the string is sufficiently long. */ if (has_req_char && end_subject - current_subject < REQ_BYTE_MAX) { register PCRE_PUCHAR p = current_subject + (has_first_char? 1:0); /* We don't need to repeat the search if we haven't yet reached the place we found it at last time. */ if (p > req_char_ptr) { if (req_char != req_char2) { while (p < end_subject) { register pcre_uint32 pp = UCHAR21INCTEST(p); if (pp == req_char || pp == req_char2) { p--; break; } } } else { while (p < end_subject) { if (UCHAR21INCTEST(p) == req_char) { p--; break; } } } /* If we can't find the required pcre_uchar, break the matching loop, which will cause a return or PCRE_ERROR_NOMATCH. */ if (p >= end_subject) break; /* If we have found the required pcre_uchar, save the point where we found it, so that we don't search again next time round the loop if the start hasn't passed this point yet. */ req_char_ptr = p; } } } } /* End of optimizations that are done when not restarting */ /* OK, now we can do the business */ md->start_used_ptr = current_subject; md->recursive = NULL; rc = internal_dfa_exec( md, /* fixed match data */ md->start_code, /* this subexpression's code */ current_subject, /* where we currently are */ start_offset, /* start offset in subject */ offsets, /* offset vector */ offsetcount, /* size of same */ workspace, /* workspace vector */ wscount, /* size of same */ 0); /* function recurse level */ /* Anything other than "no match" means we are done, always; otherwise, carry on only if not anchored. */ if (rc != PCRE_ERROR_NOMATCH || anchored) { if (rc == PCRE_ERROR_PARTIAL && offsetcount >= 2) { offsets[0] = (int)(md->start_used_ptr - (PCRE_PUCHAR)subject); offsets[1] = (int)(end_subject - (PCRE_PUCHAR)subject); if (offsetcount > 2) offsets[2] = (int)(current_subject - (PCRE_PUCHAR)subject); } return rc; } /* Advance to the next subject character unless we are at the end of a line and firstline is set. */ if (firstline && IS_NEWLINE(current_subject)) break; current_subject++; #ifdef SUPPORT_UTF if (utf) { ACROSSCHAR(current_subject < end_subject, *current_subject, current_subject++); } #endif if (current_subject > end_subject) break; /* If we have just passed a CR and we are now at a LF, and the pattern does not contain any explicit matches for \r or \n, and the newline option is CRLF or ANY or ANYCRLF, advance the match position by one more character. */ if (UCHAR21TEST(current_subject - 1) == CHAR_CR && current_subject < end_subject && UCHAR21TEST(current_subject) == CHAR_NL && (re->flags & PCRE_HASCRORLF) == 0 && (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF || md->nllen == 2)) current_subject++; } /* "Bumpalong" loop */ return PCRE_ERROR_NOMATCH; } /* End of pcre_dfa_exec.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_xclass.c0000644000000000000020000002004714655113617022004 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains an internal function that is used to match an extended class. It is used by both pcre_exec() and pcre_def_exec(). */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" /************************************************* * Match character against an XCLASS * *************************************************/ /* This function is called to match a character against an extended class that might contain values > 255 and/or Unicode properties. Arguments: c the character data points to the flag byte of the XCLASS data Returns: TRUE if character matches, else FALSE */ BOOL PRIV(xclass)(pcre_uint32 c, const pcre_uchar *data, BOOL utf) { pcre_uchar t; BOOL negated = (*data & XCL_NOT) != 0; (void)utf; #ifdef COMPILE_PCRE8 /* In 8 bit mode, this must always be TRUE. Help the compiler to know that. */ utf = TRUE; #endif /* Character values < 256 are matched against a bitmap, if one is present. If not, we still carry on, because there may be ranges that start below 256 in the additional data. */ if (c < 256) { if ((*data & XCL_HASPROP) == 0) { if ((*data & XCL_MAP) == 0) return negated; return (((pcre_uint8 *)(data + 1))[c/8] & (1 << (c&7))) != 0; } if ((*data & XCL_MAP) != 0 && (((pcre_uint8 *)(data + 1))[c/8] & (1 << (c&7))) != 0) return !negated; /* char found */ } /* First skip the bit map if present. Then match against the list of Unicode properties or large chars or ranges that end with a large char. We won't ever encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */ if ((*data++ & XCL_MAP) != 0) data += 32 / sizeof(pcre_uchar); while ((t = *data++) != XCL_END) { pcre_uint32 x, y; if (t == XCL_SINGLE) { #ifdef SUPPORT_UTF if (utf) { GETCHARINC(x, data); /* macro generates multiple statements */ } else #endif x = *data++; if (c == x) return !negated; } else if (t == XCL_RANGE) { #ifdef SUPPORT_UTF if (utf) { GETCHARINC(x, data); /* macro generates multiple statements */ GETCHARINC(y, data); /* macro generates multiple statements */ } else #endif { x = *data++; y = *data++; } if (c >= x && c <= y) return !negated; } #ifdef SUPPORT_UCP else /* XCL_PROP & XCL_NOTPROP */ { const ucd_record *prop = GET_UCD(c); BOOL isprop = t == XCL_PROP; switch(*data) { case PT_ANY: if (isprop) return !negated; break; case PT_LAMP: if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt) == isprop) return !negated; break; case PT_GC: if ((data[1] == PRIV(ucp_gentype)[prop->chartype]) == isprop) return !negated; break; case PT_PC: if ((data[1] == prop->chartype) == isprop) return !negated; break; case PT_SC: if ((data[1] == prop->script) == isprop) return !negated; break; case PT_ALNUM: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N) == isprop) return !negated; break; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ switch(c) { HSPACE_CASES: VSPACE_CASES: if (isprop) return !negated; break; default: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == isprop) return !negated; break; } break; case PT_WORD: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE) == isprop) return !negated; break; case PT_UCNC: if (c < 0xa0) { if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT || c == CHAR_GRAVE_ACCENT) == isprop) return !negated; } else { if ((c < 0xd800 || c > 0xdfff) == isprop) return !negated; } break; /* The following three properties can occur only in an XCLASS, as there is no \p or \P coding for them. */ /* Graphic character. Implement this as not Z (space or separator) and not C (other), except for Cf (format) with a few exceptions. This seems to be what Perl does. The exceptional characters are: U+061C Arabic Letter Mark U+180E Mongolian Vowel Separator U+2066 - U+2069 Various "isolate"s */ case PT_PXGRAPH: if ((PRIV(ucp_gentype)[prop->chartype] != ucp_Z && (PRIV(ucp_gentype)[prop->chartype] != ucp_C || (prop->chartype == ucp_Cf && c != 0x061c && c != 0x180e && (c < 0x2066 || c > 0x2069)) )) == isprop) return !negated; break; /* Printable character: same as graphic, with the addition of Zs, i.e. not Zl and not Zp, and U+180E. */ case PT_PXPRINT: if ((prop->chartype != ucp_Zl && prop->chartype != ucp_Zp && (PRIV(ucp_gentype)[prop->chartype] != ucp_C || (prop->chartype == ucp_Cf && c != 0x061c && (c < 0x2066 || c > 0x2069)) )) == isprop) return !negated; break; /* Punctuation: all Unicode punctuation, plus ASCII characters that Unicode treats as symbols rather than punctuation, for Perl compatibility (these are $+<=>^`|~). */ case PT_PXPUNCT: if ((PRIV(ucp_gentype)[prop->chartype] == ucp_P || (c < 128 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop) return !negated; break; /* This should never occur, but compilers may mutter if there is no default. */ default: return FALSE; } data += 2; } #endif /* SUPPORT_UCP */ } return negated; /* char did not match */ } /* End of pcre_xclass.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_version.c0000644000000000000020000001015214655113617022170 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2012 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains the external function pcre_version(), which returns a string that identifies the PCRE version that is in use. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" /************************************************* * Return version string * *************************************************/ /* These macros are the standard way of turning unquoted text into C strings. They allow macros like PCRE_MAJOR to be defined without quotes, which is convenient for user programs that want to test its value. */ #define STRING(a) # a #define XSTRING(s) STRING(s) /* A problem turned up with PCRE_PRERELEASE, which is defined empty for production releases. Originally, it was used naively in this code: return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) XSTRING(PCRE_PRERELEASE) " " XSTRING(PCRE_DATE); However, when PCRE_PRERELEASE is empty, this leads to an attempted expansion of STRING(). The C standard states: "If (before argument substitution) any argument consists of no preprocessing tokens, the behavior is undefined." It turns out the gcc treats this case as a single empty string - which is what we really want - but Visual C grumbles about the lack of an argument for the macro. Unfortunately, both are within their rights. To cope with both ways of handling this, I had resort to some messy hackery that does a test at run time. I could find no way of detecting that a macro is defined as an empty string at pre-processor time. This hack uses a standard trick for avoiding calling the STRING macro with an empty argument when doing the test. */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION pcre_version(void) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION pcre16_version(void) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION pcre32_version(void) #endif { return (XSTRING(Z PCRE_PRERELEASE)[1] == 0)? XSTRING(PCRE_MAJOR.PCRE_MINOR PCRE_DATE) : XSTRING(PCRE_MAJOR.PCRE_MINOR) XSTRING(PCRE_PRERELEASE PCRE_DATE); } /* End of pcre_version.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_ord2utf8.c0000644000000000000020000000627414655113617022172 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2012 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This file contains a private PCRE function that converts an ordinal character value into a UTF8 string. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define COMPILE_PCRE8 #include "pcre_internal.h" /************************************************* * Convert character value to UTF-8 * *************************************************/ /* This function takes an integer value in the range 0 - 0x10ffff and encodes it as a UTF-8 character in 1 to 4 pcre_uchars. Arguments: cvalue the character value buffer pointer to buffer for result - at least 6 pcre_uchars long Returns: number of characters placed in the buffer */ unsigned int PRIV(ord2utf)(pcre_uint32 cvalue, pcre_uchar *buffer) { #ifdef SUPPORT_UTF register int i, j; for (i = 0; i < PRIV(utf8_table1_size); i++) if ((int)cvalue <= PRIV(utf8_table1)[i]) break; buffer += i; for (j = i; j > 0; j--) { *buffer-- = 0x80 | (cvalue & 0x3f); cvalue >>= 6; } *buffer = PRIV(utf8_table2)[i] | cvalue; return i + 1; #else (void)(cvalue); /* Keep compiler happy; this function won't ever be */ (void)(buffer); /* called when SUPPORT_UTF is not defined. */ return 0; #endif } /* End of pcre_ord2utf8.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_compile.c0000644000000000000020000116621114655113617022144 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2021 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains the external function pcre_compile(), along with supporting internal functions that are not used by other modules. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define NLBLOCK cd /* Block containing newline information */ #define PSSTART start_pattern /* Field containing pattern start */ #define PSEND end_pattern /* Field containing pattern end */ #include "pcre_internal.h" /* When PCRE_DEBUG is defined, we need the pcre(16|32)_printint() function, which is also used by pcretest. PCRE_DEBUG is not defined when building a production library. We do not need to select pcre16_printint.c specially, because the COMPILE_PCREx macro will already be appropriately set. */ #ifdef PCRE_DEBUG /* pcre_printint.c should not include any headers */ #define PCRE_INCLUDED #include "pcre_printint.c" #undef PCRE_INCLUDED #endif /* Macro for setting individual bits in class bitmaps. */ #define SETBIT(a,b) a[(b)/8] |= (1U << ((b)&7)) /* Maximum length value to check against when making sure that the integer that holds the compiled pattern length does not overflow. We make it a bit less than INT_MAX to allow for adding in group terminating bytes, so that we don't have to check them every time. */ #define OFLOW_MAX (INT_MAX - 20) /* Definitions to allow mutual recursion */ static int add_list_to_class(pcre_uint8 *, pcre_uchar **, int, compile_data *, const pcre_uint32 *, unsigned int); static BOOL compile_regex(int, pcre_uchar **, const pcre_uchar **, int *, BOOL, BOOL, int, int, pcre_uint32 *, pcre_int32 *, pcre_uint32 *, pcre_int32 *, branch_chain *, compile_data *, int *); /************************************************* * Code parameters and static tables * *************************************************/ /* This value specifies the size of stack workspace that is used during the first pre-compile phase that determines how much memory is required. The regex is partly compiled into this space, but the compiled parts are discarded as soon as they can be, so that hopefully there will never be an overrun. The code does, however, check for an overrun. The largest amount I've seen used is 218, so this number is very generous. The same workspace is used during the second, actual compile phase for remembering forward references to groups so that they can be filled in at the end. Each entry in this list occupies LINK_SIZE bytes, so even when LINK_SIZE is 4 there is plenty of room for most patterns. However, the memory can get filled up by repetitions of forward references, for example patterns like /(?1){0,1999}(b)/, and one user did hit the limit. The code has been changed so that the workspace is expanded using malloc() in this situation. The value below is therefore a minimum, and we put a maximum on it for safety. The minimum is now also defined in terms of LINK_SIZE so that the use of malloc() kicks in at the same number of forward references in all cases. */ #define COMPILE_WORK_SIZE (2048*LINK_SIZE) #define COMPILE_WORK_SIZE_MAX (100*COMPILE_WORK_SIZE) /* This value determines the size of the initial vector that is used for remembering named groups during the pre-compile. It is allocated on the stack, but if it is too small, it is expanded using malloc(), in a similar way to the workspace. The value is the number of slots in the list. */ #define NAMED_GROUP_LIST_SIZE 20 /* The overrun tests check for a slightly smaller size so that they detect the overrun before it actually does run off the end of the data block. */ #define WORK_SIZE_SAFETY_MARGIN (100) /* Private flags added to firstchar and reqchar. */ #define REQ_CASELESS (1U << 0) /* Indicates caselessness */ #define REQ_VARY (1U << 1) /* Reqchar followed non-literal item */ /* Negative values for the firstchar and reqchar flags */ #define REQ_UNSET (-2) #define REQ_NONE (-1) /* Repeated character flags. */ #define UTF_LENGTH 0x10000000l /* The char contains its length. */ /* Table for handling escaped characters in the range '0'-'z'. Positive returns are simple data values; negative values are for special things like \d and so on. Zero means further processing is needed (for things like \x), or the escape is invalid. */ #ifndef EBCDIC /* This is the "normal" table for ASCII systems or for EBCDIC systems running in UTF-8 mode. */ static const short int escapes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CHAR_COLON, CHAR_SEMICOLON, CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, CHAR_GREATER_THAN_SIGN, CHAR_QUESTION_MARK, CHAR_COMMERCIAL_AT, -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E, 0, -ESC_G, -ESC_H, 0, 0, -ESC_K, 0, 0, -ESC_N, 0, -ESC_P, -ESC_Q, -ESC_R, -ESC_S, 0, 0, -ESC_V, -ESC_W, -ESC_X, 0, -ESC_Z, CHAR_LEFT_SQUARE_BRACKET, CHAR_BACKSLASH, CHAR_RIGHT_SQUARE_BRACKET, CHAR_CIRCUMFLEX_ACCENT, CHAR_UNDERSCORE, CHAR_GRAVE_ACCENT, ESC_a, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, -ESC_h, 0, 0, -ESC_k, 0, 0, ESC_n, 0, -ESC_p, 0, ESC_r, -ESC_s, ESC_tee, 0, -ESC_v, -ESC_w, 0, 0, -ESC_z }; #else /* This is the "abnormal" table for EBCDIC systems without UTF-8 support. */ static const short int escapes[] = { /* 48 */ 0, 0, 0, '.', '<', '(', '+', '|', /* 50 */ '&', 0, 0, 0, 0, 0, 0, 0, /* 58 */ 0, 0, '!', '$', '*', ')', ';', '~', /* 60 */ '-', '/', 0, 0, 0, 0, 0, 0, /* 68 */ 0, 0, '|', ',', '%', '_', '>', '?', /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 78 */ 0, '`', ':', '#', '@', '\'', '=', '"', /* 80 */ 0, ESC_a, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0, /* 88 */-ESC_h, 0, 0, '{', 0, 0, 0, 0, /* 90 */ 0, 0, -ESC_k, 0, 0, ESC_n, 0, -ESC_p, /* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0, /* A0 */ 0, '~', -ESC_s, ESC_tee, 0,-ESC_v, -ESC_w, 0, /* A8 */ 0,-ESC_z, 0, 0, 0, '[', 0, 0, /* B0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* B8 */ 0, 0, 0, 0, 0, ']', '=', '-', /* C0 */ '{',-ESC_A, -ESC_B, -ESC_C, -ESC_D,-ESC_E, 0, -ESC_G, /* C8 */-ESC_H, 0, 0, 0, 0, 0, 0, 0, /* D0 */ '}', 0, -ESC_K, 0, 0,-ESC_N, 0, -ESC_P, /* D8 */-ESC_Q,-ESC_R, 0, 0, 0, 0, 0, 0, /* E0 */ '\\', 0, -ESC_S, 0, 0,-ESC_V, -ESC_W, -ESC_X, /* E8 */ 0,-ESC_Z, 0, 0, 0, 0, 0, 0, /* F0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* F8 */ 0, 0, 0, 0, 0, 0, 0, 0 }; /* We also need a table of characters that may follow \c in an EBCDIC environment for characters 0-31. */ static unsigned char ebcdic_escape_c[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"; #endif /* Table of special "verbs" like (*PRUNE). This is a short table, so it is searched linearly. Put all the names into a single string, in order to reduce the number of relocations when a shared library is dynamically linked. The string is built from string macros so that it works in UTF-8 mode on EBCDIC platforms. */ typedef struct verbitem { int len; /* Length of verb name */ int op; /* Op when no arg, or -1 if arg mandatory */ int op_arg; /* Op when arg present, or -1 if not allowed */ } verbitem; static const char verbnames[] = "\0" /* Empty name is a shorthand for MARK */ STRING_MARK0 STRING_ACCEPT0 STRING_COMMIT0 STRING_F0 STRING_FAIL0 STRING_PRUNE0 STRING_SKIP0 STRING_THEN; static const verbitem verbs[] = { { 0, -1, OP_MARK }, { 4, -1, OP_MARK }, { 6, OP_ACCEPT, -1 }, { 6, OP_COMMIT, -1 }, { 1, OP_FAIL, -1 }, { 4, OP_FAIL, -1 }, { 5, OP_PRUNE, OP_PRUNE_ARG }, { 4, OP_SKIP, OP_SKIP_ARG }, { 4, OP_THEN, OP_THEN_ARG } }; static const int verbcount = sizeof(verbs)/sizeof(verbitem); /* Substitutes for [[:<:]] and [[:>:]], which mean start and end of word in another regex library. */ static const pcre_uchar sub_start_of_word[] = { CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, CHAR_RIGHT_PARENTHESIS, '\0' }; static const pcre_uchar sub_end_of_word[] = { CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK, CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, CHAR_RIGHT_PARENTHESIS, '\0' }; /* Tables of names of POSIX character classes and their lengths. The names are now all in a single string, to reduce the number of relocations when a shared library is dynamically loaded. The list of lengths is terminated by a zero length entry. The first three must be alpha, lower, upper, as this is assumed for handling case independence. The indices for graph, print, and punct are needed, so identify them. */ static const char posix_names[] = STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0 STRING_ascii0 STRING_blank0 STRING_cntrl0 STRING_digit0 STRING_graph0 STRING_print0 STRING_punct0 STRING_space0 STRING_word0 STRING_xdigit; static const pcre_uint8 posix_name_lengths[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 }; #define PC_GRAPH 8 #define PC_PRINT 9 #define PC_PUNCT 10 /* Table of class bit maps for each POSIX class. Each class is formed from a base map, with an optional addition or removal of another map. Then, for some classes, there is some additional tweaking: for [:blank:] the vertical space characters are removed, and for [:alpha:] and [:alnum:] the underscore character is removed. The triples in the table consist of the base map offset, second map offset or -1 if no second map, and a non-negative value for map addition or a negative value for map subtraction (if there are two maps). The absolute value of the third field has these meanings: 0 => no tweaking, 1 => remove vertical space characters, 2 => remove underscore. */ static const int posix_class_maps[] = { cbit_word, cbit_digit, -2, /* alpha */ cbit_lower, -1, 0, /* lower */ cbit_upper, -1, 0, /* upper */ cbit_word, -1, 2, /* alnum - word without underscore */ cbit_print, cbit_cntrl, 0, /* ascii */ cbit_space, -1, 1, /* blank - a GNU extension */ cbit_cntrl, -1, 0, /* cntrl */ cbit_digit, -1, 0, /* digit */ cbit_graph, -1, 0, /* graph */ cbit_print, -1, 0, /* print */ cbit_punct, -1, 0, /* punct */ cbit_space, -1, 0, /* space */ cbit_word, -1, 0, /* word - a Perl extension */ cbit_xdigit,-1, 0 /* xdigit */ }; /* Table of substitutes for \d etc when PCRE_UCP is set. They are replaced by Unicode property escapes. */ #ifdef SUPPORT_UCP static const pcre_uchar string_PNd[] = { CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_pNd[] = { CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_PXsp[] = { CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_pXsp[] = { CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_PXwd[] = { CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_pXwd[] = { CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar *substitutes[] = { string_PNd, /* \D */ string_pNd, /* \d */ string_PXsp, /* \S */ /* Xsp is Perl space, but from 8.34, Perl */ string_pXsp, /* \s */ /* space and POSIX space are the same. */ string_PXwd, /* \W */ string_pXwd /* \w */ }; /* The POSIX class substitutes must be in the order of the POSIX class names, defined above, and there are both positive and negative cases. NULL means no general substitute of a Unicode property escape (\p or \P). However, for some POSIX classes (e.g. graph, print, punct) a special property code is compiled directly. */ static const pcre_uchar string_pL[] = { CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_pLl[] = { CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_pLu[] = { CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_pXan[] = { CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_h[] = { CHAR_BACKSLASH, CHAR_h, '\0' }; static const pcre_uchar string_pXps[] = { CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET, CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_PL[] = { CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_PLl[] = { CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_PLu[] = { CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_PXan[] = { CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar string_H[] = { CHAR_BACKSLASH, CHAR_H, '\0' }; static const pcre_uchar string_PXps[] = { CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET, CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' }; static const pcre_uchar *posix_substitutes[] = { string_pL, /* alpha */ string_pLl, /* lower */ string_pLu, /* upper */ string_pXan, /* alnum */ NULL, /* ascii */ string_h, /* blank */ NULL, /* cntrl */ string_pNd, /* digit */ NULL, /* graph */ NULL, /* print */ NULL, /* punct */ string_pXps, /* space */ /* Xps is POSIX space, but from 8.34 */ string_pXwd, /* word */ /* Perl and POSIX space are the same */ NULL, /* xdigit */ /* Negated cases */ string_PL, /* ^alpha */ string_PLl, /* ^lower */ string_PLu, /* ^upper */ string_PXan, /* ^alnum */ NULL, /* ^ascii */ string_H, /* ^blank */ NULL, /* ^cntrl */ string_PNd, /* ^digit */ NULL, /* ^graph */ NULL, /* ^print */ NULL, /* ^punct */ string_PXps, /* ^space */ /* Xps is POSIX space, but from 8.34 */ string_PXwd, /* ^word */ /* Perl and POSIX space are the same */ NULL /* ^xdigit */ }; #define POSIX_SUBSIZE (sizeof(posix_substitutes) / sizeof(pcre_uchar *)) #endif #define STRING(a) # a #define XSTRING(s) STRING(s) /* The texts of compile-time error messages. These are "char *" because they are passed to the outside world. Do not ever re-use any error number, because they are documented. Always add a new error instead. Messages marked DEAD below are no longer used. This used to be a table of strings, but in order to reduce the number of relocations needed when a shared library is loaded dynamically, it is now one long string. We cannot use a table of offsets, because the lengths of inserts such as XSTRING(MAX_NAME_SIZE) are not known. Instead, we simply count through to the one we want - this isn't a performance issue because these strings are used only when there is a compilation error. Each substring ends with \0 to insert a null character. This includes the final substring, so that the whole string ends with \0\0, which can be detected when counting through. */ static const char error_texts[] = "no error\0" "\\ at end of pattern\0" "\\c at end of pattern\0" "unrecognized character follows \\\0" "numbers out of order in {} quantifier\0" /* 5 */ "number too big in {} quantifier\0" "missing terminating ] for character class\0" "invalid escape sequence in character class\0" "range out of order in character class\0" "nothing to repeat\0" /* 10 */ "internal error: invalid forward reference offset\0" "internal error: unexpected repeat\0" "unrecognized character after (? or (?-\0" "POSIX named classes are supported only within a class\0" "missing )\0" /* 15 */ "reference to non-existent subpattern\0" "erroffset passed as NULL\0" "unknown option bit(s) set\0" "missing ) after comment\0" "parentheses nested too deeply\0" /** DEAD **/ /* 20 */ "regular expression is too large\0" "failed to get memory\0" "unmatched parentheses\0" "internal error: code overflow\0" "unrecognized character after (?<\0" /* 25 */ "lookbehind assertion is not fixed length\0" "malformed number or name after (?(\0" "conditional group contains more than two branches\0" "assertion expected after (?( or (?(?C)\0" "(?R or (?[+-]digits must be followed by )\0" /* 30 */ "unknown POSIX class name\0" "POSIX collating elements are not supported\0" "this version of PCRE is compiled without UTF support\0" "spare error\0" /** DEAD **/ "character value in \\x{} or \\o{} is too large\0" /* 35 */ "invalid condition (?(0)\0" "\\C not allowed in lookbehind assertion\0" "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u\0" "number after (?C is > 255\0" "closing ) for (?C expected\0" /* 40 */ "recursive call could loop indefinitely\0" "unrecognized character after (?P\0" "syntax error in subpattern name (missing terminator)\0" "two named subpatterns have the same name\0" "invalid UTF-8 string\0" /* 45 */ "support for \\P, \\p, and \\X has not been compiled\0" "malformed \\P or \\p sequence\0" "unknown property name after \\P or \\p\0" "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)\0" "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0" /* 50 */ "repeated subpattern is too long\0" /** DEAD **/ "octal value is greater than \\377 in 8-bit non-UTF-8 mode\0" "internal error: overran compiling workspace\0" "internal error: previously-checked referenced subpattern not found\0" "DEFINE group contains more than one branch\0" /* 55 */ "repeating a DEFINE group is not allowed\0" /** DEAD **/ "inconsistent NEWLINE options\0" "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0" "a numbered reference must not be zero\0" "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0" /* 60 */ "(*VERB) not recognized or malformed\0" "number is too big\0" "subpattern name expected\0" "digit expected after (?+\0" "] is an invalid data character in JavaScript compatibility mode\0" /* 65 */ "different names for subpatterns of the same number are not allowed\0" "(*MARK) must have an argument\0" "this version of PCRE is not compiled with Unicode property support\0" #ifndef EBCDIC "\\c must be followed by an ASCII character\0" #else "\\c must be followed by a letter or one of [\\]^_?\0" #endif "\\k is not followed by a braced, angle-bracketed, or quoted name\0" /* 70 */ "internal error: unknown opcode in find_fixedlength()\0" "\\N is not supported in a class\0" "too many forward references\0" "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)\0" "invalid UTF-16 string\0" /* 75 */ "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0" "character value in \\u.... sequence is too large\0" "invalid UTF-32 string\0" "setting UTF is disabled by the application\0" "non-hex character in \\x{} (closing brace missing?)\0" /* 80 */ "non-octal character in \\o{} (closing brace missing?)\0" "missing opening brace after \\o\0" "parentheses are too deeply nested\0" "invalid range in character class\0" "group name must start with a non-digit\0" /* 85 */ "parentheses are too deeply nested (stack check)\0" "digits missing in \\x{} or \\o{}\0" "regular expression is too complicated\0" ; /* Table to identify digits and hex digits. This is used when compiling patterns. Note that the tables in chartables are dependent on the locale, and may mark arbitrary characters as digits - but the PCRE compiling code expects to handle only 0-9, a-z, and A-Z as digits when compiling. That is why we have a private table here. It costs 256 bytes, but it is a lot faster than doing character value tests (at least in some simple cases I timed), and in some applications one wants PCRE to compile efficiently as well as match efficiently. For convenience, we use the same bit definitions as in chartables: 0x04 decimal digit 0x08 hexadecimal digit Then we can use ctype_digit and ctype_xdigit in the code. */ /* Using a simple comparison for decimal numbers rather than a memory read is much faster, and the resulting code is simpler (the compiler turns it into a subtraction and unsigned comparison). */ #define IS_DIGIT(x) ((x) >= CHAR_0 && (x) <= CHAR_9) #ifndef EBCDIC /* This is the "normal" case, for ASCII systems, and EBCDIC systems running in UTF-8 mode. */ static const pcre_uint8 digitab[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */ 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 */ 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* @ - G */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H - O */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* P - W */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* X - _ */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* ` - g */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h - o */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p - w */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x -127 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */ #else /* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */ static const pcre_uint8 digitab[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 10 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32- 39 20 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 30 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 40 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 72- | */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 50 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 88- 95 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 60 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 104- ? */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 70 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* 128- g 80 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144- p 90 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160- x A0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 B0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* { - G C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* } - P D0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* \ - X E0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */ 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 F0 */ 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */ static const pcre_uint8 ebcdic_chartab[] = { /* chartable partial dup */ 0x80,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 0- 7 */ 0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */ 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 16- 23 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */ 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 32- 39 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 */ 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80, /* 72- | */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 */ 0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00, /* 88- 95 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 */ 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x80, /* 104- ? */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* 128- g */ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */ 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* 144- p */ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */ 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* 160- x */ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 */ 0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00, /* 184-191 */ 0x80,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* { - G */ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */ 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* } - P */ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */ 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* \ - X */ 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */ 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */ #endif /* This table is used to check whether auto-possessification is possible between adjacent character-type opcodes. The left-hand (repeated) opcode is used to select the row, and the right-hand opcode is use to select the column. A value of 1 means that auto-possessification is OK. For example, the second value in the first row means that \D+\d can be turned into \D++\d. The Unicode property types (\P and \p) have to be present to fill out the table because of what their opcode values are, but the table values should always be zero because property types are handled separately in the code. The last four columns apply to items that cannot be repeated, so there is no need to have rows for them. Note that OP_DIGIT etc. are generated only when PCRE_UCP is *not* set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */ #define APTROWS (LAST_AUTOTAB_LEFT_OP - FIRST_AUTOTAB_OP + 1) #define APTCOLS (LAST_AUTOTAB_RIGHT_OP - FIRST_AUTOTAB_OP + 1) static const pcre_uint8 autoposstab[APTROWS][APTCOLS] = { /* \D \d \S \s \W \w . .+ \C \P \p \R \H \h \V \v \X \Z \z $ $M */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \D */ { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \d */ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \S */ { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \s */ { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \W */ { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \w */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* . */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* .+ */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \C */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \P */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \p */ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \R */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \H */ { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \h */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \V */ { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, /* \v */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 } /* \X */ }; /* This table is used to check whether auto-possessification is possible between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP). The left-hand (repeated) opcode is used to select the row, and the right-hand opcode is used to select the column. The values are as follows: 0 Always return FALSE (never auto-possessify) 1 Character groups are distinct (possessify if both are OP_PROP) 2 Check character categories in the same group (general or particular) 3 TRUE if the two opcodes are not the same (PROP vs NOTPROP) 4 Check left general category vs right particular category 5 Check right general category vs left particular category 6 Left alphanum vs right general category 7 Left space vs right general category 8 Left word vs right general category 9 Right alphanum vs left general category 10 Right space vs left general category 11 Right word vs left general category 12 Left alphanum vs right particular category 13 Left space vs right particular category 14 Left word vs right particular category 15 Right alphanum vs left particular category 16 Right space vs left particular category 17 Right word vs left particular category */ static const pcre_uint8 propposstab[PT_TABSIZE][PT_TABSIZE] = { /* ANY LAMP GC PC SC ALNUM SPACE PXSPACE WORD CLIST UCNC */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_ANY */ { 0, 3, 0, 0, 0, 3, 1, 1, 0, 0, 0 }, /* PT_LAMP */ { 0, 0, 2, 4, 0, 9, 10, 10, 11, 0, 0 }, /* PT_GC */ { 0, 0, 5, 2, 0, 15, 16, 16, 17, 0, 0 }, /* PT_PC */ { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, /* PT_SC */ { 0, 3, 6, 12, 0, 3, 1, 1, 0, 0, 0 }, /* PT_ALNUM */ { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_SPACE */ { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_PXSPACE */ { 0, 0, 8, 14, 0, 0, 1, 1, 3, 0, 0 }, /* PT_WORD */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_CLIST */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 } /* PT_UCNC */ }; /* This table is used to check whether auto-possessification is possible between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP) when one specifies a general category and the other specifies a particular category. The row is selected by the general category and the column by the particular category. The value is 1 if the particular category is not part of the general category. */ static const pcre_uint8 catposstab[7][30] = { /* Cc Cf Cn Co Cs Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc Pd Pe Pf Pi Po Ps Sc Sk Sm So Zl Zp Zs */ { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* C */ { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* L */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* M */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* N */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }, /* P */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1 }, /* S */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 } /* Z */ }; /* This table is used when checking ALNUM, (PX)SPACE, SPACE, and WORD against a general or particular category. The properties in each row are those that apply to the character set in question. Duplication means that a little unnecessary work is done when checking, but this keeps things much simpler because they can all use the same code. For more details see the comment where this table is used. Note: SPACE and PXSPACE used to be different because Perl excluded VT from "space", but from Perl 5.18 it's included, so both categories are treated the same here. */ static const pcre_uint8 posspropstab[3][4] = { { ucp_L, ucp_N, ucp_N, ucp_Nl }, /* ALNUM, 3rd and 4th values redundant */ { ucp_Z, ucp_Z, ucp_C, ucp_Cc }, /* SPACE and PXSPACE, 2nd value redundant */ { ucp_L, ucp_N, ucp_P, ucp_Po } /* WORD */ }; /* This table is used when converting repeating opcodes into possessified versions as a result of an explicit possessive quantifier such as ++. A zero value means there is no possessified version - in those cases the item in question must be wrapped in ONCE brackets. The table is truncated at OP_CALLOUT because all relevant opcodes are less than that. */ static const pcre_uint8 opcode_possessify[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */ 0, /* NOTI */ OP_POSSTAR, 0, /* STAR, MINSTAR */ OP_POSPLUS, 0, /* PLUS, MINPLUS */ OP_POSQUERY, 0, /* QUERY, MINQUERY */ OP_POSUPTO, 0, /* UPTO, MINUPTO */ 0, /* EXACT */ 0, 0, 0, 0, /* POS{STAR,PLUS,QUERY,UPTO} */ OP_POSSTARI, 0, /* STARI, MINSTARI */ OP_POSPLUSI, 0, /* PLUSI, MINPLUSI */ OP_POSQUERYI, 0, /* QUERYI, MINQUERYI */ OP_POSUPTOI, 0, /* UPTOI, MINUPTOI */ 0, /* EXACTI */ 0, 0, 0, 0, /* POS{STARI,PLUSI,QUERYI,UPTOI} */ OP_NOTPOSSTAR, 0, /* NOTSTAR, NOTMINSTAR */ OP_NOTPOSPLUS, 0, /* NOTPLUS, NOTMINPLUS */ OP_NOTPOSQUERY, 0, /* NOTQUERY, NOTMINQUERY */ OP_NOTPOSUPTO, 0, /* NOTUPTO, NOTMINUPTO */ 0, /* NOTEXACT */ 0, 0, 0, 0, /* NOTPOS{STAR,PLUS,QUERY,UPTO} */ OP_NOTPOSSTARI, 0, /* NOTSTARI, NOTMINSTARI */ OP_NOTPOSPLUSI, 0, /* NOTPLUSI, NOTMINPLUSI */ OP_NOTPOSQUERYI, 0, /* NOTQUERYI, NOTMINQUERYI */ OP_NOTPOSUPTOI, 0, /* NOTUPTOI, NOTMINUPTOI */ 0, /* NOTEXACTI */ 0, 0, 0, 0, /* NOTPOS{STARI,PLUSI,QUERYI,UPTOI} */ OP_TYPEPOSSTAR, 0, /* TYPESTAR, TYPEMINSTAR */ OP_TYPEPOSPLUS, 0, /* TYPEPLUS, TYPEMINPLUS */ OP_TYPEPOSQUERY, 0, /* TYPEQUERY, TYPEMINQUERY */ OP_TYPEPOSUPTO, 0, /* TYPEUPTO, TYPEMINUPTO */ 0, /* TYPEEXACT */ 0, 0, 0, 0, /* TYPEPOS{STAR,PLUS,QUERY,UPTO} */ OP_CRPOSSTAR, 0, /* CRSTAR, CRMINSTAR */ OP_CRPOSPLUS, 0, /* CRPLUS, CRMINPLUS */ OP_CRPOSQUERY, 0, /* CRQUERY, CRMINQUERY */ OP_CRPOSRANGE, 0, /* CRRANGE, CRMINRANGE */ 0, 0, 0, 0, /* CRPOS{STAR,PLUS,QUERY,RANGE} */ 0, 0, 0, /* CLASS, NCLASS, XCLASS */ 0, 0, /* REF, REFI */ 0, 0, /* DNREF, DNREFI */ 0, 0 /* RECURSE, CALLOUT */ }; /************************************************* * Find an error text * *************************************************/ /* The error texts are now all in one long string, to save on relocations. As some of the text is of unknown length, we can't use a table of offsets. Instead, just count through the strings. This is not a performance issue because it happens only when there has been a compilation error. Argument: the error number Returns: pointer to the error string */ static const char * find_error_text(int n) { const char *s = error_texts; for (; n > 0; n--) { while (*s++ != CHAR_NULL) {}; if (*s == CHAR_NULL) return "Error text not found (please report)"; } return s; } /************************************************* * Expand the workspace * *************************************************/ /* This function is called during the second compiling phase, if the number of forward references fills the existing workspace, which is originally a block on the stack. A larger block is obtained from malloc() unless the ultimate limit has been reached or the increase will be rather small. Argument: pointer to the compile data block Returns: 0 if all went well, else an error number */ static int expand_workspace(compile_data *cd) { pcre_uchar *newspace; int newsize = cd->workspace_size * 2; if (newsize > COMPILE_WORK_SIZE_MAX) newsize = COMPILE_WORK_SIZE_MAX; if (cd->workspace_size >= COMPILE_WORK_SIZE_MAX || newsize - cd->workspace_size < WORK_SIZE_SAFETY_MARGIN) return ERR72; newspace = (PUBL(malloc))(IN_UCHARS(newsize)); if (newspace == NULL) return ERR21; memcpy(newspace, cd->start_workspace, cd->workspace_size * sizeof(pcre_uchar)); cd->hwm = (pcre_uchar *)newspace + (cd->hwm - cd->start_workspace); if (cd->workspace_size > COMPILE_WORK_SIZE) (PUBL(free))((void *)cd->start_workspace); cd->start_workspace = newspace; cd->workspace_size = newsize; return 0; } /************************************************* * Check for counted repeat * *************************************************/ /* This function is called when a '{' is encountered in a place where it might start a quantifier. It looks ahead to see if it really is a quantifier or not. It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} where the ddds are digits. Arguments: p pointer to the first char after '{' Returns: TRUE or FALSE */ static BOOL is_counted_repeat(const pcre_uchar *p) { if (!IS_DIGIT(*p)) return FALSE; p++; while (IS_DIGIT(*p)) p++; if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE; if (*p++ != CHAR_COMMA) return FALSE; if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE; if (!IS_DIGIT(*p)) return FALSE; p++; while (IS_DIGIT(*p)) p++; return (*p == CHAR_RIGHT_CURLY_BRACKET); } /************************************************* * Handle escapes * *************************************************/ /* This function is called when a \ has been encountered. It either returns a positive value for a simple escape such as \n, or 0 for a data character which will be placed in chptr. A backreference to group n is returned as negative n. When UTF-8 is enabled, a positive value greater than 255 may be returned in chptr. On entry, ptr is pointing at the \. On exit, it is on the final character of the escape sequence. Arguments: ptrptr points to the pattern position pointer chptr points to a returned data character errorcodeptr points to the errorcode variable bracount number of previous extracting brackets options the options bits isclass TRUE if inside a character class Returns: zero => a data character positive => a special escape sequence negative => a back reference on error, errorcodeptr is set */ static int check_escape(const pcre_uchar **ptrptr, pcre_uint32 *chptr, int *errorcodeptr, int bracount, int options, BOOL isclass) { /* PCRE_UTF16 has the same value as PCRE_UTF8. */ BOOL utf = (options & PCRE_UTF8) != 0; const pcre_uchar *ptr = *ptrptr + 1; pcre_uint32 c; int escape = 0; int i; GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */ ptr--; /* Set pointer back to the last byte */ /* If backslash is at the end of the pattern, it's an error. */ if (c == CHAR_NULL) *errorcodeptr = ERR1; /* Non-alphanumerics are literals. For digits or letters, do an initial lookup in a table. A non-zero result is something that can be returned immediately. Otherwise further processing may be required. */ #ifndef EBCDIC /* ASCII/UTF-8 coding */ /* Not alphanumeric */ else if (c < CHAR_0 || c > CHAR_z) {} else if ((i = escapes[c - CHAR_0]) != 0) { if (i > 0) c = (pcre_uint32)i; else escape = -i; } #else /* EBCDIC coding */ /* Not alphanumeric */ else if (c < CHAR_a || (!MAX_255(c) || (ebcdic_chartab[c] & 0x0E) == 0)) {} else if ((i = escapes[c - 0x48]) != 0) { if (i > 0) c = (pcre_uint32)i; else escape = -i; } #endif /* Escapes that need further processing, or are illegal. */ else { const pcre_uchar *oldptr; BOOL braced, negated, overflow; int s; switch (c) { /* A number of Perl escapes are not handled by PCRE. We give an explicit error. */ case CHAR_l: case CHAR_L: *errorcodeptr = ERR37; break; case CHAR_u: if ((options & PCRE_JAVASCRIPT_COMPAT) != 0) { /* In JavaScript, \u must be followed by four hexadecimal numbers. Otherwise it is a lowercase u letter. */ if (MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0 && MAX_255(ptr[2]) && (digitab[ptr[2]] & ctype_xdigit) != 0 && MAX_255(ptr[3]) && (digitab[ptr[3]] & ctype_xdigit) != 0 && MAX_255(ptr[4]) && (digitab[ptr[4]] & ctype_xdigit) != 0) { c = 0; for (i = 0; i < 4; ++i) { register pcre_uint32 cc = *(++ptr); #ifndef EBCDIC /* ASCII/UTF-8 coding */ if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); #else /* EBCDIC coding */ if (cc >= CHAR_a && cc <= CHAR_z) cc += 64; /* Convert to upper case */ c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10)); #endif } #if defined COMPILE_PCRE8 if (c > (utf ? 0x10ffffU : 0xffU)) #elif defined COMPILE_PCRE16 if (c > (utf ? 0x10ffffU : 0xffffU)) #elif defined COMPILE_PCRE32 if (utf && c > 0x10ffffU) #endif { *errorcodeptr = ERR76; } else if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; } } else *errorcodeptr = ERR37; break; case CHAR_U: /* In JavaScript, \U is an uppercase U letter. */ if ((options & PCRE_JAVASCRIPT_COMPAT) == 0) *errorcodeptr = ERR37; break; /* In a character class, \g is just a literal "g". Outside a character class, \g must be followed by one of a number of specific things: (1) A number, either plain or braced. If positive, it is an absolute backreference. If negative, it is a relative backreference. This is a Perl 5.10 feature. (2) Perl 5.10 also supports \g{name} as a reference to a named group. This is part of Perl's movement towards a unified syntax for back references. As this is synonymous with \k{name}, we fudge it up by pretending it really was \k. (3) For Oniguruma compatibility we also support \g followed by a name or a number either in angle brackets or in single quotes. However, these are (possibly recursive) subroutine calls, _not_ backreferences. Just return the ESC_g code (cf \k). */ case CHAR_g: if (isclass) break; if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE) { escape = ESC_g; break; } /* Handle the Perl-compatible cases */ if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) { const pcre_uchar *p; for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++) if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break; if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET) { escape = ESC_k; break; } braced = TRUE; ptr++; } else braced = FALSE; if (ptr[1] == CHAR_MINUS) { negated = TRUE; ptr++; } else negated = FALSE; /* The integer range is limited by the machine's int representation. */ s = 0; overflow = FALSE; while (IS_DIGIT(ptr[1])) { if (s > INT_MAX / 10 - 1) /* Integer overflow */ { overflow = TRUE; break; } s = s * 10 + (int)(*(++ptr) - CHAR_0); } if (overflow) /* Integer overflow */ { while (IS_DIGIT(ptr[1])) ptr++; *errorcodeptr = ERR61; break; } if (braced && *(++ptr) != CHAR_RIGHT_CURLY_BRACKET) { *errorcodeptr = ERR57; break; } if (s == 0) { *errorcodeptr = ERR58; break; } if (negated) { if (s > bracount) { *errorcodeptr = ERR15; break; } s = bracount - (s - 1); } escape = -s; break; /* The handling of escape sequences consisting of a string of digits starting with one that is not zero is not straightforward. Perl has changed over the years. Nowadays \g{} for backreferences and \o{} for octal are recommended to avoid the ambiguities in the old syntax. Outside a character class, the digits are read as a decimal number. If the number is less than 8 (used to be 10), or if there are that many previous extracting left brackets, then it is a back reference. Otherwise, up to three octal digits are read to form an escaped byte. Thus \123 is likely to be octal 123 (cf \0123, which is octal 012 followed by the literal 3). If the octal value is greater than 377, the least significant 8 bits are taken. \8 and \9 are treated as the literal characters 8 and 9. Inside a character class, \ followed by a digit is always either a literal 8 or 9 or an octal number. */ case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: if (!isclass) { oldptr = ptr; /* The integer range is limited by the machine's int representation. */ s = (int)(c -CHAR_0); overflow = FALSE; while (IS_DIGIT(ptr[1])) { if (s > INT_MAX / 10 - 1) /* Integer overflow */ { overflow = TRUE; break; } s = s * 10 + (int)(*(++ptr) - CHAR_0); } if (overflow) /* Integer overflow */ { while (IS_DIGIT(ptr[1])) ptr++; *errorcodeptr = ERR61; break; } if (s < 8 || s <= bracount) /* Check for back reference */ { escape = -s; break; } ptr = oldptr; /* Put the pointer back and fall through */ } /* Handle a digit following \ when the number is not a back reference. If the first digit is 8 or 9, Perl used to generate a binary zero byte and then treat the digit as a following literal. At least by Perl 5.18 this changed so as not to insert the binary zero. */ if ((c = *ptr) >= CHAR_8) break; /* Fall through with a digit less than 8 */ /* \0 always starts an octal number, but we may drop through to here with a larger first octal digit. The original code used just to take the least significant 8 bits of octal numbers (I think this is what early Perls used to do). Nowadays we allow for larger numbers in UTF-8 mode and 16-bit mode, but no more than 3 octal digits. */ case CHAR_0: c -= CHAR_0; while(i++ < 2 && ptr[1] >= CHAR_0 && ptr[1] <= CHAR_7) c = c * 8 + *(++ptr) - CHAR_0; #ifdef COMPILE_PCRE8 if (!utf && c > 0xff) *errorcodeptr = ERR51; #endif break; /* \o is a relatively new Perl feature, supporting a more general way of specifying character codes in octal. The only supported form is \o{ddd}. */ case CHAR_o: if (ptr[1] != CHAR_LEFT_CURLY_BRACKET) *errorcodeptr = ERR81; else if (ptr[2] == CHAR_RIGHT_CURLY_BRACKET) *errorcodeptr = ERR86; else { ptr += 2; c = 0; overflow = FALSE; while (*ptr >= CHAR_0 && *ptr <= CHAR_7) { register pcre_uint32 cc = *ptr++; if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */ #ifdef COMPILE_PCRE32 if (c >= 0x20000000l) { overflow = TRUE; break; } #endif c = (c << 3) + cc - CHAR_0 ; #if defined COMPILE_PCRE8 if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; } #elif defined COMPILE_PCRE16 if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; } #elif defined COMPILE_PCRE32 if (utf && c > 0x10ffffU) { overflow = TRUE; break; } #endif } if (overflow) { while (*ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++; *errorcodeptr = ERR34; } else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) { if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; } else *errorcodeptr = ERR80; } break; /* \x is complicated. In JavaScript, \x must be followed by two hexadecimal numbers. Otherwise it is a lowercase x letter. */ case CHAR_x: if ((options & PCRE_JAVASCRIPT_COMPAT) != 0) { if (MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0 && MAX_255(ptr[2]) && (digitab[ptr[2]] & ctype_xdigit) != 0) { c = 0; for (i = 0; i < 2; ++i) { register pcre_uint32 cc = *(++ptr); #ifndef EBCDIC /* ASCII/UTF-8 coding */ if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); #else /* EBCDIC coding */ if (cc >= CHAR_a && cc <= CHAR_z) cc += 64; /* Convert to upper case */ c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10)); #endif } } } /* End JavaScript handling */ /* Handle \x in Perl's style. \x{ddd} is a character number which can be greater than 0xff in utf or non-8bit mode, but only if the ddd are hex digits. If not, { used to be treated as a data character. However, Perl seems to read hex digits up to the first non-such, and ignore the rest, so that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE now gives an error. */ else { if (ptr[1] == CHAR_LEFT_CURLY_BRACKET) { ptr += 2; if (*ptr == CHAR_RIGHT_CURLY_BRACKET) { *errorcodeptr = ERR86; break; } c = 0; overflow = FALSE; while (MAX_255(*ptr) && (digitab[*ptr] & ctype_xdigit) != 0) { register pcre_uint32 cc = *ptr++; if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */ #ifdef COMPILE_PCRE32 if (c >= 0x10000000l) { overflow = TRUE; break; } #endif #ifndef EBCDIC /* ASCII/UTF-8 coding */ if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); #else /* EBCDIC coding */ if (cc >= CHAR_a && cc <= CHAR_z) cc += 64; /* Convert to upper case */ c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10)); #endif #if defined COMPILE_PCRE8 if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; } #elif defined COMPILE_PCRE16 if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; } #elif defined COMPILE_PCRE32 if (utf && c > 0x10ffffU) { overflow = TRUE; break; } #endif } if (overflow) { while (MAX_255(*ptr) && (digitab[*ptr] & ctype_xdigit) != 0) ptr++; *errorcodeptr = ERR34; } else if (*ptr == CHAR_RIGHT_CURLY_BRACKET) { if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73; } /* If the sequence of hex digits does not end with '}', give an error. We used just to recognize this construct and fall through to the normal \x handling, but nowadays Perl gives an error, which seems much more sensible, so we do too. */ else *errorcodeptr = ERR79; } /* End of \x{} processing */ /* Read a single-byte hex-defined char (up to two hex digits after \x) */ else { c = 0; while (i++ < 2 && MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0) { pcre_uint32 cc; /* Some compilers don't like */ cc = *(++ptr); /* ++ in initializers */ #ifndef EBCDIC /* ASCII/UTF-8 coding */ if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */ c = c * 16 + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10)); #else /* EBCDIC coding */ if (cc <= CHAR_z) cc += 64; /* Convert to upper case */ c = c * 16 + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10)); #endif } } /* End of \xdd handling */ } /* End of Perl-style \x handling */ break; /* For \c, a following letter is upper-cased; then the 0x40 bit is flipped. An error is given if the byte following \c is not an ASCII character. This coding is ASCII-specific, but then the whole concept of \cx is ASCII-specific. (However, an EBCDIC equivalent has now been added.) */ case CHAR_c: c = *(++ptr); if (c == CHAR_NULL) { *errorcodeptr = ERR2; break; } #ifndef EBCDIC /* ASCII/UTF-8 coding */ if (c > 127) /* Excludes all non-ASCII in either mode */ { *errorcodeptr = ERR68; break; } if (c >= CHAR_a && c <= CHAR_z) c -= 32; c ^= 0x40; #else /* EBCDIC coding */ if (c >= CHAR_a && c <= CHAR_z) c += 64; if (c == CHAR_QUESTION_MARK) c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff; else { for (i = 0; i < 32; i++) { if (c == ebcdic_escape_c[i]) break; } if (i < 32) c = i; else *errorcodeptr = ERR68; } #endif break; /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any other alphanumeric following \ is an error if PCRE_EXTRA was set; otherwise, for Perl compatibility, it is a literal. This code looks a bit odd, but there used to be some cases other than the default, and there may be again in future, so I haven't "optimized" it. */ default: if ((options & PCRE_EXTRA) != 0) switch(c) { default: *errorcodeptr = ERR3; break; } break; } } /* Perl supports \N{name} for character names, as well as plain \N for "not newline". PCRE does not support \N{name}. However, it does support quantification such as \N{2,3}. */ if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET && !is_counted_repeat(ptr+2)) *errorcodeptr = ERR37; /* If PCRE_UCP is set, we change the values for \d etc. */ if ((options & PCRE_UCP) != 0 && escape >= ESC_D && escape <= ESC_w) escape += (ESC_DU - ESC_D); /* Set the pointer to the final character before returning. */ *ptrptr = ptr; *chptr = c; return escape; } #ifdef SUPPORT_UCP /************************************************* * Handle \P and \p * *************************************************/ /* This function is called after \P or \p has been encountered, provided that PCRE is compiled with support for Unicode properties. On entry, ptrptr is pointing at the P or p. On exit, it is pointing at the final character of the escape sequence. Argument: ptrptr points to the pattern position pointer negptr points to a boolean that is set TRUE for negation else FALSE ptypeptr points to an unsigned int that is set to the type value pdataptr points to an unsigned int that is set to the detailed property value errorcodeptr points to the error code variable Returns: TRUE if the type value was found, or FALSE for an invalid type */ static BOOL get_ucp(const pcre_uchar **ptrptr, BOOL *negptr, unsigned int *ptypeptr, unsigned int *pdataptr, int *errorcodeptr) { pcre_uchar c; int i, bot, top; const pcre_uchar *ptr = *ptrptr; pcre_uchar name[32]; c = *(++ptr); if (c == CHAR_NULL) goto ERROR_RETURN; *negptr = FALSE; /* \P or \p can be followed by a name in {}, optionally preceded by ^ for negation. */ if (c == CHAR_LEFT_CURLY_BRACKET) { if (ptr[1] == CHAR_CIRCUMFLEX_ACCENT) { *negptr = TRUE; ptr++; } for (i = 0; i < (int)(sizeof(name) / sizeof(pcre_uchar)) - 1; i++) { c = *(++ptr); if (c == CHAR_NULL) goto ERROR_RETURN; if (c == CHAR_RIGHT_CURLY_BRACKET) break; name[i] = c; } if (c != CHAR_RIGHT_CURLY_BRACKET) goto ERROR_RETURN; name[i] = 0; } /* Otherwise there is just one following character */ else { name[0] = c; name[1] = 0; } *ptrptr = ptr; /* Search for a recognized property name using binary chop */ bot = 0; top = PRIV(utt_size); while (bot < top) { int r; i = (bot + top) >> 1; r = STRCMP_UC_C8(name, PRIV(utt_names) + PRIV(utt)[i].name_offset); if (r == 0) { *ptypeptr = PRIV(utt)[i].type; *pdataptr = PRIV(utt)[i].value; return TRUE; } if (r > 0) bot = i + 1; else top = i; } *errorcodeptr = ERR47; *ptrptr = ptr; return FALSE; ERROR_RETURN: *errorcodeptr = ERR46; *ptrptr = ptr; return FALSE; } #endif /************************************************* * Read repeat counts * *************************************************/ /* Read an item of the form {n,m} and return the values. This is called only after is_counted_repeat() has confirmed that a repeat-count quantifier exists, so the syntax is guaranteed to be correct, but we need to check the values. Arguments: p pointer to first char after '{' minp pointer to int for min maxp pointer to int for max returned as -1 if no max errorcodeptr points to error code variable Returns: pointer to '}' on success; current ptr on error, with errorcodeptr set non-zero */ static const pcre_uchar * read_repeat_counts(const pcre_uchar *p, int *minp, int *maxp, int *errorcodeptr) { int min = 0; int max = -1; while (IS_DIGIT(*p)) { min = min * 10 + (int)(*p++ - CHAR_0); if (min > 65535) { *errorcodeptr = ERR5; return p; } } if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else { if (*(++p) != CHAR_RIGHT_CURLY_BRACKET) { max = 0; while(IS_DIGIT(*p)) { max = max * 10 + (int)(*p++ - CHAR_0); if (max > 65535) { *errorcodeptr = ERR5; return p; } } if (max < min) { *errorcodeptr = ERR4; return p; } } } *minp = min; *maxp = max; return p; } /************************************************* * Find first significant op code * *************************************************/ /* This is called by several functions that scan a compiled expression looking for a fixed first character, or an anchoring op code etc. It skips over things that do not influence this. For some calls, it makes sense to skip negative forward and all backward assertions, and also the \b assertion; for others it does not. Arguments: code pointer to the start of the group skipassert TRUE if certain assertions are to be skipped Returns: pointer to the first significant opcode */ static const pcre_uchar* first_significant_code(const pcre_uchar *code, BOOL skipassert) { for (;;) { switch ((int)*code) { case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: if (!skipassert) return code; do code += GET(code, 1); while (*code == OP_ALT); code += PRIV(OP_lengths)[*code]; break; case OP_WORD_BOUNDARY: case OP_NOT_WORD_BOUNDARY: if (!skipassert) return code; /* Fall through */ case OP_CALLOUT: case OP_CREF: case OP_DNCREF: case OP_RREF: case OP_DNRREF: case OP_DEF: code += PRIV(OP_lengths)[*code]; break; default: return code; } } /* Control never reaches here */ } /************************************************* * Find the fixed length of a branch * *************************************************/ /* Scan a branch and compute the fixed length of subject that will match it, if the length is fixed. This is needed for dealing with backward assertions. In UTF8 mode, the result is in characters rather than bytes. The branch is temporarily terminated with OP_END when this function is called. This function is called when a backward assertion is encountered, so that if it fails, the error message can point to the correct place in the pattern. However, we cannot do this when the assertion contains subroutine calls, because they can be forward references. We solve this by remembering this case and doing the check at the end; a flag specifies which mode we are running in. Arguments: code points to the start of the pattern (the bracket) utf TRUE in UTF-8 / UTF-16 / UTF-32 mode atend TRUE if called when the pattern is complete cd the "compile data" structure recurses chain of recurse_check to catch mutual recursion Returns: the fixed length, or -1 if there is no fixed length, or -2 if \C was encountered (in UTF-8 mode only) or -3 if an OP_RECURSE item was encountered and atend is FALSE or -4 if an unknown opcode was encountered (internal error) */ static int find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd, recurse_check *recurses) { int length = -1; recurse_check this_recurse; register int branchlength = 0; register pcre_uchar *cc = code + 1 + LINK_SIZE; /* Scan along the opcodes for this branch. If we get to the end of the branch, check the length against that of the other branches. */ for (;;) { int d; pcre_uchar *ce, *cs; register pcre_uchar op = *cc; switch (op) { /* We only need to continue for OP_CBRA (normal capturing bracket) and OP_BRA (normal non-capturing bracket) because the other variants of these opcodes are all concerned with unlimited repeated groups, which of course are not of fixed length. */ case OP_CBRA: case OP_BRA: case OP_ONCE: case OP_ONCE_NC: case OP_COND: d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd, recurses); if (d < 0) return d; branchlength += d; do cc += GET(cc, 1); while (*cc == OP_ALT); cc += 1 + LINK_SIZE; break; /* Reached end of a branch; if it's a ket it is the end of a nested call. If it's ALT it is an alternation in a nested call. An ACCEPT is effectively an ALT. If it is END it's the end of the outer call. All can be handled by the same code. Note that we must not include the OP_KETRxxx opcodes here, because they all imply an unlimited repeat. */ case OP_ALT: case OP_KET: case OP_END: case OP_ACCEPT: case OP_ASSERT_ACCEPT: if (length < 0) length = branchlength; else if (length != branchlength) return -1; if (*cc != OP_ALT) return length; cc += 1 + LINK_SIZE; branchlength = 0; break; /* A true recursion implies not fixed length, but a subroutine call may be OK. If the subroutine is a forward reference, we can't deal with it until the end of the pattern, so return -3. */ case OP_RECURSE: if (!atend) return -3; cs = ce = (pcre_uchar *)cd->start_code + GET(cc, 1); /* Start subpattern */ do ce += GET(ce, 1); while (*ce == OP_ALT); /* End subpattern */ if (cc > cs && cc < ce) return -1; /* Recursion */ else /* Check for mutual recursion */ { recurse_check *r = recurses; for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; if (r != NULL) return -1; /* Mutual recursion */ } this_recurse.prev = recurses; this_recurse.group = cs; d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd, &this_recurse); if (d < 0) return d; branchlength += d; cc += 1 + LINK_SIZE; break; /* Skip over assertive subpatterns */ case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: do cc += GET(cc, 1); while (*cc == OP_ALT); cc += 1 + LINK_SIZE; break; /* Skip over things that don't match chars */ case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: cc += cc[1] + PRIV(OP_lengths)[*cc]; break; case OP_CALLOUT: case OP_CIRC: case OP_CIRCM: case OP_CLOSE: case OP_COMMIT: case OP_CREF: case OP_DEF: case OP_DNCREF: case OP_DNRREF: case OP_DOLL: case OP_DOLLM: case OP_EOD: case OP_EODN: case OP_FAIL: case OP_NOT_WORD_BOUNDARY: case OP_PRUNE: case OP_REVERSE: case OP_RREF: case OP_SET_SOM: case OP_SKIP: case OP_SOD: case OP_SOM: case OP_THEN: case OP_WORD_BOUNDARY: cc += PRIV(OP_lengths)[*cc]; break; /* Handle literal characters */ case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: branchlength++; cc += 2; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; /* Handle exact repetitions. The count is already in characters, but we need to skip over a multibyte character in UTF8 mode. */ case OP_EXACT: case OP_EXACTI: case OP_NOTEXACT: case OP_NOTEXACTI: branchlength += (int)GET2(cc,1); cc += 2 + IMM2_SIZE; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; case OP_TYPEEXACT: branchlength += GET2(cc,1); if (cc[1 + IMM2_SIZE] == OP_PROP || cc[1 + IMM2_SIZE] == OP_NOTPROP) cc += 2; cc += 1 + IMM2_SIZE + 1; break; /* Handle single-char matchers */ case OP_PROP: case OP_NOTPROP: cc += 2; /* Fall through */ case OP_HSPACE: case OP_VSPACE: case OP_NOT_HSPACE: case OP_NOT_VSPACE: case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: case OP_ALLANY: branchlength++; cc++; break; /* The single-byte matcher isn't allowed. This only happens in UTF-8 mode; otherwise \C is coded as OP_ALLANY. */ case OP_ANYBYTE: return -2; /* Check a class for variable quantification */ case OP_CLASS: case OP_NCLASS: #if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case OP_XCLASS: /* The original code caused an unsigned overflow in 64 bit systems, so now we use a conditional statement. */ if (op == OP_XCLASS) cc += GET(cc, 1); else cc += PRIV(OP_lengths)[OP_CLASS]; #else cc += PRIV(OP_lengths)[OP_CLASS]; #endif switch (*cc) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSSTAR: case OP_CRPOSPLUS: case OP_CRPOSQUERY: return -1; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) return -1; branchlength += (int)GET2(cc,1); cc += 1 + 2 * IMM2_SIZE; break; default: branchlength++; } break; /* Anything else is variable length */ case OP_ANYNL: case OP_BRAMINZERO: case OP_BRAPOS: case OP_BRAPOSZERO: case OP_BRAZERO: case OP_CBRAPOS: case OP_EXTUNI: case OP_KETRMAX: case OP_KETRMIN: case OP_KETRPOS: case OP_MINPLUS: case OP_MINPLUSI: case OP_MINQUERY: case OP_MINQUERYI: case OP_MINSTAR: case OP_MINSTARI: case OP_MINUPTO: case OP_MINUPTOI: case OP_NOTMINPLUS: case OP_NOTMINPLUSI: case OP_NOTMINQUERY: case OP_NOTMINQUERYI: case OP_NOTMINSTAR: case OP_NOTMINSTARI: case OP_NOTMINUPTO: case OP_NOTMINUPTOI: case OP_NOTPLUS: case OP_NOTPLUSI: case OP_NOTPOSPLUS: case OP_NOTPOSPLUSI: case OP_NOTPOSQUERY: case OP_NOTPOSQUERYI: case OP_NOTPOSSTAR: case OP_NOTPOSSTARI: case OP_NOTPOSUPTO: case OP_NOTPOSUPTOI: case OP_NOTQUERY: case OP_NOTQUERYI: case OP_NOTSTAR: case OP_NOTSTARI: case OP_NOTUPTO: case OP_NOTUPTOI: case OP_PLUS: case OP_PLUSI: case OP_POSPLUS: case OP_POSPLUSI: case OP_POSQUERY: case OP_POSQUERYI: case OP_POSSTAR: case OP_POSSTARI: case OP_POSUPTO: case OP_POSUPTOI: case OP_QUERY: case OP_QUERYI: case OP_REF: case OP_REFI: case OP_DNREF: case OP_DNREFI: case OP_SBRA: case OP_SBRAPOS: case OP_SCBRA: case OP_SCBRAPOS: case OP_SCOND: case OP_SKIPZERO: case OP_STAR: case OP_STARI: case OP_TYPEMINPLUS: case OP_TYPEMINQUERY: case OP_TYPEMINSTAR: case OP_TYPEMINUPTO: case OP_TYPEPLUS: case OP_TYPEPOSPLUS: case OP_TYPEPOSQUERY: case OP_TYPEPOSSTAR: case OP_TYPEPOSUPTO: case OP_TYPEQUERY: case OP_TYPESTAR: case OP_TYPEUPTO: case OP_UPTO: case OP_UPTOI: return -1; /* Catch unrecognized opcodes so that when new ones are added they are not forgotten, as has happened in the past. */ default: return -4; } } /* Control never gets here */ } /************************************************* * Scan compiled regex for specific bracket * *************************************************/ /* This little function scans through a compiled pattern until it finds a capturing bracket with the given number, or, if the number is negative, an instance of OP_REVERSE for a lookbehind. The function is global in the C sense so that it can be called from pcre_study() when finding the minimum matching length. Arguments: code points to start of expression utf TRUE in UTF-8 / UTF-16 / UTF-32 mode number the required bracket number or negative to find a lookbehind Returns: pointer to the opcode for the bracket, or NULL if not found */ const pcre_uchar * PRIV(find_bracket)(const pcre_uchar *code, BOOL utf, int number) { for (;;) { register pcre_uchar c = *code; if (c == OP_END) return NULL; /* XCLASS is used for classes that cannot be represented just by a bit map. This includes negated single high-valued characters. The length in the table is zero; the actual length is stored in the compiled code. */ if (c == OP_XCLASS) code += GET(code, 1); /* Handle recursion */ else if (c == OP_REVERSE) { if (number < 0) return (pcre_uchar *)code; code += PRIV(OP_lengths)[c]; } /* Handle capturing bracket */ else if (c == OP_CBRA || c == OP_SCBRA || c == OP_CBRAPOS || c == OP_SCBRAPOS) { int n = (int)GET2(code, 1+LINK_SIZE); if (n == number) return (pcre_uchar *)code; code += PRIV(OP_lengths)[c]; } /* Otherwise, we can get the item's length from the table, except that for repeated character types, we have to test for \p and \P, which have an extra two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we must add in its length. */ else { switch(c) { case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEPOSSTAR: case OP_TYPEPOSPLUS: case OP_TYPEPOSQUERY: if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; break; case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEEXACT: case OP_TYPEPOSUPTO: if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2; break; case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: code += code[1]; break; } /* Add in the fixed length from the table */ code += PRIV(OP_lengths)[c]; /* In UTF-8 mode, opcodes that are followed by a character may be followed by a multi-byte character. The length in the table is a minimum, so we have to arrange to skip the extra bytes. */ #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) switch(c) { case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: case OP_EXACT: case OP_EXACTI: case OP_NOTEXACT: case OP_NOTEXACTI: case OP_UPTO: case OP_UPTOI: case OP_NOTUPTO: case OP_NOTUPTOI: case OP_MINUPTO: case OP_MINUPTOI: case OP_NOTMINUPTO: case OP_NOTMINUPTOI: case OP_POSUPTO: case OP_POSUPTOI: case OP_NOTPOSUPTO: case OP_NOTPOSUPTOI: case OP_STAR: case OP_STARI: case OP_NOTSTAR: case OP_NOTSTARI: case OP_MINSTAR: case OP_MINSTARI: case OP_NOTMINSTAR: case OP_NOTMINSTARI: case OP_POSSTAR: case OP_POSSTARI: case OP_NOTPOSSTAR: case OP_NOTPOSSTARI: case OP_PLUS: case OP_PLUSI: case OP_NOTPLUS: case OP_NOTPLUSI: case OP_MINPLUS: case OP_MINPLUSI: case OP_NOTMINPLUS: case OP_NOTMINPLUSI: case OP_POSPLUS: case OP_POSPLUSI: case OP_NOTPOSPLUS: case OP_NOTPOSPLUSI: case OP_QUERY: case OP_QUERYI: case OP_NOTQUERY: case OP_NOTQUERYI: case OP_MINQUERY: case OP_MINQUERYI: case OP_NOTMINQUERY: case OP_NOTMINQUERYI: case OP_POSQUERY: case OP_POSQUERYI: case OP_NOTPOSQUERY: case OP_NOTPOSQUERYI: if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); break; } #else (void)(utf); /* Keep compiler happy by referencing function argument */ #endif } } } /************************************************* * Scan compiled regex for recursion reference * *************************************************/ /* This little function scans through a compiled pattern until it finds an instance of OP_RECURSE. Arguments: code points to start of expression utf TRUE in UTF-8 / UTF-16 / UTF-32 mode Returns: pointer to the opcode for OP_RECURSE, or NULL if not found */ static const pcre_uchar * find_recurse(const pcre_uchar *code, BOOL utf) { for (;;) { register pcre_uchar c = *code; if (c == OP_END) return NULL; if (c == OP_RECURSE) return code; /* XCLASS is used for classes that cannot be represented just by a bit map. This includes negated single high-valued characters. The length in the table is zero; the actual length is stored in the compiled code. */ if (c == OP_XCLASS) code += GET(code, 1); /* Otherwise, we can get the item's length from the table, except that for repeated character types, we have to test for \p and \P, which have an extra two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we must add in its length. */ else { switch(c) { case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEPOSSTAR: case OP_TYPEPOSPLUS: case OP_TYPEPOSQUERY: if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; break; case OP_TYPEPOSUPTO: case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEEXACT: if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2; break; case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: code += code[1]; break; } /* Add in the fixed length from the table */ code += PRIV(OP_lengths)[c]; /* In UTF-8 mode, opcodes that are followed by a character may be followed by a multi-byte character. The length in the table is a minimum, so we have to arrange to skip the extra bytes. */ #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) switch(c) { case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: case OP_EXACT: case OP_EXACTI: case OP_NOTEXACT: case OP_NOTEXACTI: case OP_UPTO: case OP_UPTOI: case OP_NOTUPTO: case OP_NOTUPTOI: case OP_MINUPTO: case OP_MINUPTOI: case OP_NOTMINUPTO: case OP_NOTMINUPTOI: case OP_POSUPTO: case OP_POSUPTOI: case OP_NOTPOSUPTO: case OP_NOTPOSUPTOI: case OP_STAR: case OP_STARI: case OP_NOTSTAR: case OP_NOTSTARI: case OP_MINSTAR: case OP_MINSTARI: case OP_NOTMINSTAR: case OP_NOTMINSTARI: case OP_POSSTAR: case OP_POSSTARI: case OP_NOTPOSSTAR: case OP_NOTPOSSTARI: case OP_PLUS: case OP_PLUSI: case OP_NOTPLUS: case OP_NOTPLUSI: case OP_MINPLUS: case OP_MINPLUSI: case OP_NOTMINPLUS: case OP_NOTMINPLUSI: case OP_POSPLUS: case OP_POSPLUSI: case OP_NOTPOSPLUS: case OP_NOTPOSPLUSI: case OP_QUERY: case OP_QUERYI: case OP_NOTQUERY: case OP_NOTQUERYI: case OP_MINQUERY: case OP_MINQUERYI: case OP_NOTMINQUERY: case OP_NOTMINQUERYI: case OP_POSQUERY: case OP_POSQUERYI: case OP_NOTPOSQUERY: case OP_NOTPOSQUERYI: if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); break; } #else (void)(utf); /* Keep compiler happy by referencing function argument */ #endif } } } /************************************************* * Scan compiled branch for non-emptiness * *************************************************/ /* This function scans through a branch of a compiled pattern to see whether it can match the empty string or not. It is called from could_be_empty() below and from compile_branch() when checking for an unlimited repeat of a group that can match nothing. Note that first_significant_code() skips over backward and negative forward assertions when its final argument is TRUE. If we hit an unclosed bracket, we return "empty" - this means we've struck an inner bracket whose current branch will already have been scanned. Arguments: code points to start of search endcode points to where to stop utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode cd contains pointers to tables etc. recurses chain of recurse_check to catch mutual recursion Returns: TRUE if what is matched could be empty */ static BOOL could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode, BOOL utf, compile_data *cd, recurse_check *recurses) { register pcre_uchar c; recurse_check this_recurse; for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE); code < endcode; code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE)) { const pcre_uchar *ccode; c = *code; /* Skip over forward assertions; the other assertions are skipped by first_significant_code() with a TRUE final argument. */ if (c == OP_ASSERT) { do code += GET(code, 1); while (*code == OP_ALT); c = *code; continue; } /* For a recursion/subroutine call, if its end has been reached, which implies a backward reference subroutine call, we can scan it. If it's a forward reference subroutine call, we can't. To detect forward reference we have to scan up the list that is kept in the workspace. This function is called only when doing the real compile, not during the pre-compile that measures the size of the compiled pattern. */ if (c == OP_RECURSE) { const pcre_uchar *scode = cd->start_code + GET(code, 1); const pcre_uchar *endgroup = scode; BOOL empty_branch; /* Test for forward reference or uncompleted reference. This is disabled when called to scan a completed pattern by setting cd->start_workspace to NULL. */ if (cd->start_workspace != NULL) { const pcre_uchar *tcode; for (tcode = cd->start_workspace; tcode < cd->hwm; tcode += LINK_SIZE) if ((int)GET(tcode, 0) == (int)(code + 1 - cd->start_code)) return TRUE; if (GET(scode, 1) == 0) return TRUE; /* Unclosed */ } /* If the reference is to a completed group, we need to detect whether this is a recursive call, as otherwise there will be an infinite loop. If it is a recursion, just skip over it. Simple recursions are easily detected. For mutual recursions we keep a chain on the stack. */ do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT); if (code >= scode && code <= endgroup) continue; /* Simple recursion */ else { recurse_check *r = recurses; for (r = recurses; r != NULL; r = r->prev) if (r->group == scode) break; if (r != NULL) continue; /* Mutual recursion */ } /* Completed reference; scan the referenced group, remembering it on the stack chain to detect mutual recursions. */ empty_branch = FALSE; this_recurse.prev = recurses; this_recurse.group = scode; do { if (could_be_empty_branch(scode, endcode, utf, cd, &this_recurse)) { empty_branch = TRUE; break; } scode += GET(scode, 1); } while (*scode == OP_ALT); if (!empty_branch) return FALSE; /* All branches are non-empty */ continue; } /* Groups with zero repeats can of course be empty; skip them. */ if (c == OP_BRAZERO || c == OP_BRAMINZERO || c == OP_SKIPZERO || c == OP_BRAPOSZERO) { code += PRIV(OP_lengths)[c]; do code += GET(code, 1); while (*code == OP_ALT); c = *code; continue; } /* A nested group that is already marked as "could be empty" can just be skipped. */ if (c == OP_SBRA || c == OP_SBRAPOS || c == OP_SCBRA || c == OP_SCBRAPOS) { do code += GET(code, 1); while (*code == OP_ALT); c = *code; continue; } /* For other groups, scan the branches. */ if (c == OP_BRA || c == OP_BRAPOS || c == OP_CBRA || c == OP_CBRAPOS || c == OP_ONCE || c == OP_ONCE_NC || c == OP_COND || c == OP_SCOND) { BOOL empty_branch; if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */ /* If a conditional group has only one branch, there is a second, implied, empty branch, so just skip over the conditional, because it could be empty. Otherwise, scan the individual branches of the group. */ if (c == OP_COND && code[GET(code, 1)] != OP_ALT) code += GET(code, 1); else { empty_branch = FALSE; do { if (!empty_branch && could_be_empty_branch(code, endcode, utf, cd, recurses)) empty_branch = TRUE; code += GET(code, 1); } while (*code == OP_ALT); if (!empty_branch) return FALSE; /* All branches are non-empty */ } c = *code; continue; } /* Handle the other opcodes */ switch (c) { /* Check for quantifiers after a class. XCLASS is used for classes that cannot be represented just by a bit map. This includes negated single high-valued characters. The length in PRIV(OP_lengths)[] is zero; the actual length is stored in the compiled code, so we must update "code" here. */ #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: ccode = code += GET(code, 1); goto CHECK_CLASS_REPEAT; #endif case OP_CLASS: case OP_NCLASS: ccode = code + PRIV(OP_lengths)[OP_CLASS]; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 CHECK_CLASS_REPEAT: #endif switch (*ccode) { case OP_CRSTAR: /* These could be empty; continue */ case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSSTAR: case OP_CRPOSQUERY: break; default: /* Non-repeat => class must match */ case OP_CRPLUS: /* These repeats aren't empty */ case OP_CRMINPLUS: case OP_CRPOSPLUS: return FALSE; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: if (GET2(ccode, 1) > 0) return FALSE; /* Minimum > 0 */ break; } break; /* Opcodes that must match a character */ case OP_ANY: case OP_ALLANY: case OP_ANYBYTE: case OP_PROP: case OP_NOTPROP: case OP_ANYNL: case OP_NOT_HSPACE: case OP_HSPACE: case OP_NOT_VSPACE: case OP_VSPACE: case OP_EXTUNI: case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: case OP_PLUS: case OP_PLUSI: case OP_MINPLUS: case OP_MINPLUSI: case OP_NOTPLUS: case OP_NOTPLUSI: case OP_NOTMINPLUS: case OP_NOTMINPLUSI: case OP_POSPLUS: case OP_POSPLUSI: case OP_NOTPOSPLUS: case OP_NOTPOSPLUSI: case OP_EXACT: case OP_EXACTI: case OP_NOTEXACT: case OP_NOTEXACTI: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEPOSPLUS: case OP_TYPEEXACT: return FALSE; /* These are going to continue, as they may be empty, but we have to fudge the length for the \p and \P cases. */ case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPOSSTAR: case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEPOSQUERY: if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; break; /* Same for these */ case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEPOSUPTO: if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2; break; /* End of branch */ case OP_KET: case OP_KETRMAX: case OP_KETRMIN: case OP_KETRPOS: case OP_ALT: return TRUE; /* In UTF-8 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, POSQUERY, UPTO, MINUPTO, and POSUPTO and their caseless and negative versions may be followed by a multibyte character. */ #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 case OP_STAR: case OP_STARI: case OP_NOTSTAR: case OP_NOTSTARI: case OP_MINSTAR: case OP_MINSTARI: case OP_NOTMINSTAR: case OP_NOTMINSTARI: case OP_POSSTAR: case OP_POSSTARI: case OP_NOTPOSSTAR: case OP_NOTPOSSTARI: case OP_QUERY: case OP_QUERYI: case OP_NOTQUERY: case OP_NOTQUERYI: case OP_MINQUERY: case OP_MINQUERYI: case OP_NOTMINQUERY: case OP_NOTMINQUERYI: case OP_POSQUERY: case OP_POSQUERYI: case OP_NOTPOSQUERY: case OP_NOTPOSQUERYI: if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]); break; case OP_UPTO: case OP_UPTOI: case OP_NOTUPTO: case OP_NOTUPTOI: case OP_MINUPTO: case OP_MINUPTOI: case OP_NOTMINUPTO: case OP_NOTMINUPTOI: case OP_POSUPTO: case OP_POSUPTOI: case OP_NOTPOSUPTO: case OP_NOTPOSUPTOI: if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]); break; #endif /* MARK, and PRUNE/SKIP/THEN with an argument must skip over the argument string. */ case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: code += code[1]; break; /* None of the remaining opcodes are required to match a character. */ default: break; } } return TRUE; } /************************************************* * Scan compiled regex for non-emptiness * *************************************************/ /* This function is called to check for left recursive calls. We want to check the current branch of the current pattern to see if it could match the empty string. If it could, we must look outwards for branches at other levels, stopping when we pass beyond the bracket which is the subject of the recursion. This function is called only during the real compile, not during the pre-compile. Arguments: code points to start of the recursion endcode points to where to stop (current RECURSE item) bcptr points to the chain of current (unclosed) branch starts utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode cd pointers to tables etc Returns: TRUE if what is matched could be empty */ static BOOL could_be_empty(const pcre_uchar *code, const pcre_uchar *endcode, branch_chain *bcptr, BOOL utf, compile_data *cd) { while (bcptr != NULL && bcptr->current_branch >= code) { if (!could_be_empty_branch(bcptr->current_branch, endcode, utf, cd, NULL)) return FALSE; bcptr = bcptr->outer; } return TRUE; } /************************************************* * Base opcode of repeated opcodes * *************************************************/ /* Returns the base opcode for repeated single character type opcodes. If the opcode is not a repeated character type, it returns with the original value. Arguments: c opcode Returns: base opcode for the type */ static pcre_uchar get_repeat_base(pcre_uchar c) { return (c > OP_TYPEPOSUPTO)? c : (c >= OP_TYPESTAR)? OP_TYPESTAR : (c >= OP_NOTSTARI)? OP_NOTSTARI : (c >= OP_NOTSTAR)? OP_NOTSTAR : (c >= OP_STARI)? OP_STARI : OP_STAR; } #ifdef SUPPORT_UCP /************************************************* * Check a character and a property * *************************************************/ /* This function is called by check_auto_possessive() when a property item is adjacent to a fixed character. Arguments: c the character ptype the property type pdata the data for the type negated TRUE if it's a negated property (\P or \p{^) Returns: TRUE if auto-possessifying is OK */ static BOOL check_char_prop(pcre_uint32 c, unsigned int ptype, unsigned int pdata, BOOL negated) { const pcre_uint32 *p; const ucd_record *prop = GET_UCD(c); switch(ptype) { case PT_LAMP: return (prop->chartype == ucp_Lu || prop->chartype == ucp_Ll || prop->chartype == ucp_Lt) == negated; case PT_GC: return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated; case PT_PC: return (pdata == prop->chartype) == negated; case PT_SC: return (pdata == prop->script) == negated; /* These are specials */ case PT_ALNUM: return (PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated; /* Perl space used to exclude VT, but from Perl 5.18 it is included, which means that Perl space and POSIX space are now identical. PCRE was changed at release 8.34. */ case PT_SPACE: /* Perl space */ case PT_PXSPACE: /* POSIX space */ switch(c) { HSPACE_CASES: VSPACE_CASES: return negated; default: return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == negated; } break; /* Control never reaches here */ case PT_WORD: return (PRIV(ucp_gentype)[prop->chartype] == ucp_L || PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE) == negated; case PT_CLIST: p = PRIV(ucd_caseless_sets) + prop->caseset; for (;;) { if (c < *p) return !negated; if (c == *p++) return negated; } break; /* Control never reaches here */ } return FALSE; } #endif /* SUPPORT_UCP */ /************************************************* * Fill the character property list * *************************************************/ /* Checks whether the code points to an opcode that can take part in auto- possessification, and if so, fills a list with its properties. Arguments: code points to start of expression utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode fcc points to case-flipping table list points to output list list[0] will be filled with the opcode list[1] will be non-zero if this opcode can match an empty character string list[2..7] depends on the opcode Returns: points to the start of the next opcode if *code is accepted NULL if *code is not accepted */ static const pcre_uchar * get_chr_property_list(const pcre_uchar *code, BOOL utf, const pcre_uint8 *fcc, pcre_uint32 *list) { pcre_uchar c = *code; pcre_uchar base; const pcre_uchar *end; pcre_uint32 chr; #ifdef SUPPORT_UCP pcre_uint32 *clist_dest; const pcre_uint32 *clist_src; #else utf = utf; /* Suppress "unused parameter" compiler warning */ #endif list[0] = c; list[1] = FALSE; code++; if (c >= OP_STAR && c <= OP_TYPEPOSUPTO) { base = get_repeat_base(c); c -= (base - OP_STAR); if (c == OP_UPTO || c == OP_MINUPTO || c == OP_EXACT || c == OP_POSUPTO) code += IMM2_SIZE; list[1] = (c != OP_PLUS && c != OP_MINPLUS && c != OP_EXACT && c != OP_POSPLUS); switch(base) { case OP_STAR: list[0] = OP_CHAR; break; case OP_STARI: list[0] = OP_CHARI; break; case OP_NOTSTAR: list[0] = OP_NOT; break; case OP_NOTSTARI: list[0] = OP_NOTI; break; case OP_TYPESTAR: list[0] = *code; code++; break; } c = list[0]; } switch(c) { case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: case OP_ALLANY: case OP_ANYNL: case OP_NOT_HSPACE: case OP_HSPACE: case OP_NOT_VSPACE: case OP_VSPACE: case OP_EXTUNI: case OP_EODN: case OP_EOD: case OP_DOLL: case OP_DOLLM: return code; case OP_CHAR: case OP_NOT: GETCHARINCTEST(chr, code); list[2] = chr; list[3] = NOTACHAR; return code; case OP_CHARI: case OP_NOTI: list[0] = (c == OP_CHARI) ? OP_CHAR : OP_NOT; GETCHARINCTEST(chr, code); list[2] = chr; #ifdef SUPPORT_UCP if (chr < 128 || (chr < 256 && !utf)) list[3] = fcc[chr]; else list[3] = UCD_OTHERCASE(chr); #elif defined SUPPORT_UTF || !defined COMPILE_PCRE8 list[3] = (chr < 256) ? fcc[chr] : chr; #else list[3] = fcc[chr]; #endif /* The othercase might be the same value. */ if (chr == list[3]) list[3] = NOTACHAR; else list[4] = NOTACHAR; return code; #ifdef SUPPORT_UCP case OP_PROP: case OP_NOTPROP: if (code[0] != PT_CLIST) { list[2] = code[0]; list[3] = code[1]; return code + 2; } /* Convert only if we have enough space. */ clist_src = PRIV(ucd_caseless_sets) + code[1]; clist_dest = list + 2; code += 2; do { if (clist_dest >= list + 8) { /* Early return if there is not enough space. This should never happen, since all clists are shorter than 5 character now. */ list[2] = code[0]; list[3] = code[1]; return code; } *clist_dest++ = *clist_src; } while(*clist_src++ != NOTACHAR); /* All characters are stored. The terminating NOTACHAR is copied form the clist itself. */ list[0] = (c == OP_PROP) ? OP_CHAR : OP_NOT; return code; #endif case OP_NCLASS: case OP_CLASS: #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: if (c == OP_XCLASS) end = code + GET(code, 0) - 1; else #endif end = code + 32 / sizeof(pcre_uchar); switch(*end) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSSTAR: case OP_CRPOSQUERY: list[1] = TRUE; end++; break; case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRPOSPLUS: end++; break; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: list[1] = (GET2(end, 1) == 0); end += 1 + 2 * IMM2_SIZE; break; } list[2] = (pcre_uint32)(end - code); return end; } return NULL; /* Opcode not accepted */ } /************************************************* * Scan further character sets for match * *************************************************/ /* Checks whether the base and the current opcode have a common character, in which case the base cannot be possessified. Arguments: code points to the byte code utf TRUE in UTF-8 / UTF-16 / UTF-32 mode cd static compile data base_list the data list of the base opcode Returns: TRUE if the auto-possessification is possible */ static BOOL compare_opcodes(const pcre_uchar *code, BOOL utf, const compile_data *cd, const pcre_uint32 *base_list, const pcre_uchar *base_end, int *rec_limit) { pcre_uchar c; pcre_uint32 list[8]; const pcre_uint32 *chr_ptr; const pcre_uint32 *ochr_ptr; const pcre_uint32 *list_ptr; const pcre_uchar *next_code; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 const pcre_uchar *xclass_flags; #endif const pcre_uint8 *class_bitset; const pcre_uint8 *set1, *set2, *set_end; pcre_uint32 chr; BOOL accepted, invert_bits; BOOL entered_a_group = FALSE; if (*rec_limit == 0) return FALSE; --(*rec_limit); /* Note: the base_list[1] contains whether the current opcode has greedy (represented by a non-zero value) quantifier. This is a different from other character type lists, which stores here that the character iterator matches to an empty string (also represented by a non-zero value). */ for(;;) { /* All operations move the code pointer forward. Therefore infinite recursions are not possible. */ c = *code; /* Skip over callouts */ if (c == OP_CALLOUT) { code += PRIV(OP_lengths)[c]; continue; } if (c == OP_ALT) { do code += GET(code, 1); while (*code == OP_ALT); c = *code; } switch(c) { case OP_END: case OP_KETRPOS: /* TRUE only in greedy case. The non-greedy case could be replaced by an OP_EXACT, but it is probably not worth it. (And note that OP_EXACT uses more memory, which we cannot get at this stage.) */ return base_list[1] != 0; case OP_KET: /* If the bracket is capturing, and referenced by an OP_RECURSE, or it is an atomic sub-pattern (assert, once, etc.) the non-greedy case cannot be converted to a possessive form. */ if (base_list[1] == 0) return FALSE; switch(*(code - GET(code, 1))) { case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: case OP_ONCE_NC: /* Atomic sub-patterns and assertions can always auto-possessify their last iterator. However, if the group was entered as a result of checking a previous iterator, this is not possible. */ return !entered_a_group; } code += PRIV(OP_lengths)[c]; continue; case OP_ONCE: case OP_ONCE_NC: case OP_BRA: case OP_CBRA: next_code = code + GET(code, 1); code += PRIV(OP_lengths)[c]; while (*next_code == OP_ALT) { if (!compare_opcodes(code, utf, cd, base_list, base_end, rec_limit)) return FALSE; code = next_code + 1 + LINK_SIZE; next_code += GET(next_code, 1); } entered_a_group = TRUE; continue; case OP_BRAZERO: case OP_BRAMINZERO: next_code = code + 1; if (*next_code != OP_BRA && *next_code != OP_CBRA && *next_code != OP_ONCE && *next_code != OP_ONCE_NC) return FALSE; do next_code += GET(next_code, 1); while (*next_code == OP_ALT); /* The bracket content will be checked by the OP_BRA/OP_CBRA case above. */ next_code += 1 + LINK_SIZE; if (!compare_opcodes(next_code, utf, cd, base_list, base_end, rec_limit)) return FALSE; code += PRIV(OP_lengths)[c]; continue; default: break; } /* Check for a supported opcode, and load its properties. */ code = get_chr_property_list(code, utf, cd->fcc, list); if (code == NULL) return FALSE; /* Unsupported */ /* If either opcode is a small character list, set pointers for comparing characters from that list with another list, or with a property. */ if (base_list[0] == OP_CHAR) { chr_ptr = base_list + 2; list_ptr = list; } else if (list[0] == OP_CHAR) { chr_ptr = list + 2; list_ptr = base_list; } /* Character bitsets can also be compared to certain opcodes. */ else if (base_list[0] == OP_CLASS || list[0] == OP_CLASS #ifdef COMPILE_PCRE8 /* In 8 bit, non-UTF mode, OP_CLASS and OP_NCLASS are the same. */ || (!utf && (base_list[0] == OP_NCLASS || list[0] == OP_NCLASS)) #endif ) { #ifdef COMPILE_PCRE8 if (base_list[0] == OP_CLASS || (!utf && base_list[0] == OP_NCLASS)) #else if (base_list[0] == OP_CLASS) #endif { set1 = (pcre_uint8 *)(base_end - base_list[2]); list_ptr = list; } else { set1 = (pcre_uint8 *)(code - list[2]); list_ptr = base_list; } invert_bits = FALSE; switch(list_ptr[0]) { case OP_CLASS: case OP_NCLASS: set2 = (pcre_uint8 *) ((list_ptr == list ? code : base_end) - list_ptr[2]); break; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: xclass_flags = (list_ptr == list ? code : base_end) - list_ptr[2] + LINK_SIZE; if ((*xclass_flags & XCL_HASPROP) != 0) return FALSE; if ((*xclass_flags & XCL_MAP) == 0) { /* No bits are set for characters < 256. */ if (list[1] == 0) return (*xclass_flags & XCL_NOT) == 0; /* Might be an empty repeat. */ continue; } set2 = (pcre_uint8 *)(xclass_flags + 1); break; #endif case OP_NOT_DIGIT: invert_bits = TRUE; /* Fall through */ case OP_DIGIT: set2 = (pcre_uint8 *)(cd->cbits + cbit_digit); break; case OP_NOT_WHITESPACE: invert_bits = TRUE; /* Fall through */ case OP_WHITESPACE: set2 = (pcre_uint8 *)(cd->cbits + cbit_space); break; case OP_NOT_WORDCHAR: invert_bits = TRUE; /* Fall through */ case OP_WORDCHAR: set2 = (pcre_uint8 *)(cd->cbits + cbit_word); break; default: return FALSE; } /* Because the sets are unaligned, we need to perform byte comparison here. */ set_end = set1 + 32; if (invert_bits) { do { if ((*set1++ & ~(*set2++)) != 0) return FALSE; } while (set1 < set_end); } else { do { if ((*set1++ & *set2++) != 0) return FALSE; } while (set1 < set_end); } if (list[1] == 0) return TRUE; /* Might be an empty repeat. */ continue; } /* Some property combinations also acceptable. Unicode property opcodes are processed specially; the rest can be handled with a lookup table. */ else { pcre_uint32 leftop, rightop; leftop = base_list[0]; rightop = list[0]; #ifdef SUPPORT_UCP accepted = FALSE; /* Always set in non-unicode case. */ if (leftop == OP_PROP || leftop == OP_NOTPROP) { if (rightop == OP_EOD) accepted = TRUE; else if (rightop == OP_PROP || rightop == OP_NOTPROP) { int n; const pcre_uint8 *p; BOOL same = leftop == rightop; BOOL lisprop = leftop == OP_PROP; BOOL risprop = rightop == OP_PROP; BOOL bothprop = lisprop && risprop; /* There's a table that specifies how each combination is to be processed: 0 Always return FALSE (never auto-possessify) 1 Character groups are distinct (possessify if both are OP_PROP) 2 Check character categories in the same group (general or particular) 3 Return TRUE if the two opcodes are not the same ... see comments below */ n = propposstab[base_list[2]][list[2]]; switch(n) { case 0: break; case 1: accepted = bothprop; break; case 2: accepted = (base_list[3] == list[3]) != same; break; case 3: accepted = !same; break; case 4: /* Left general category, right particular category */ accepted = risprop && catposstab[base_list[3]][list[3]] == same; break; case 5: /* Right general category, left particular category */ accepted = lisprop && catposstab[list[3]][base_list[3]] == same; break; /* This code is logically tricky. Think hard before fiddling with it. The posspropstab table has four entries per row. Each row relates to one of PCRE's special properties such as ALNUM or SPACE or WORD. Only WORD actually needs all four entries, but using repeats for the others means they can all use the same code below. The first two entries in each row are Unicode general categories, and apply always, because all the characters they include are part of the PCRE character set. The third and fourth entries are a general and a particular category, respectively, that include one or more relevant characters. One or the other is used, depending on whether the check is for a general or a particular category. However, in both cases the category contains more characters than the specials that are defined for the property being tested against. Therefore, it cannot be used in a NOTPROP case. Example: the row for WORD contains ucp_L, ucp_N, ucp_P, ucp_Po. Underscore is covered by ucp_P or ucp_Po. */ case 6: /* Left alphanum vs right general category */ case 7: /* Left space vs right general category */ case 8: /* Left word vs right general category */ p = posspropstab[n-6]; accepted = risprop && lisprop == (list[3] != p[0] && list[3] != p[1] && (list[3] != p[2] || !lisprop)); break; case 9: /* Right alphanum vs left general category */ case 10: /* Right space vs left general category */ case 11: /* Right word vs left general category */ p = posspropstab[n-9]; accepted = lisprop && risprop == (base_list[3] != p[0] && base_list[3] != p[1] && (base_list[3] != p[2] || !risprop)); break; case 12: /* Left alphanum vs right particular category */ case 13: /* Left space vs right particular category */ case 14: /* Left word vs right particular category */ p = posspropstab[n-12]; accepted = risprop && lisprop == (catposstab[p[0]][list[3]] && catposstab[p[1]][list[3]] && (list[3] != p[3] || !lisprop)); break; case 15: /* Right alphanum vs left particular category */ case 16: /* Right space vs left particular category */ case 17: /* Right word vs left particular category */ p = posspropstab[n-15]; accepted = lisprop && risprop == (catposstab[p[0]][base_list[3]] && catposstab[p[1]][base_list[3]] && (base_list[3] != p[3] || !risprop)); break; } } } else #endif /* SUPPORT_UCP */ accepted = leftop >= FIRST_AUTOTAB_OP && leftop <= LAST_AUTOTAB_LEFT_OP && rightop >= FIRST_AUTOTAB_OP && rightop <= LAST_AUTOTAB_RIGHT_OP && autoposstab[leftop - FIRST_AUTOTAB_OP][rightop - FIRST_AUTOTAB_OP]; if (!accepted) return FALSE; if (list[1] == 0) return TRUE; /* Might be an empty repeat. */ continue; } /* Control reaches here only if one of the items is a small character list. All characters are checked against the other side. */ do { chr = *chr_ptr; switch(list_ptr[0]) { case OP_CHAR: ochr_ptr = list_ptr + 2; do { if (chr == *ochr_ptr) return FALSE; ochr_ptr++; } while(*ochr_ptr != NOTACHAR); break; case OP_NOT: ochr_ptr = list_ptr + 2; do { if (chr == *ochr_ptr) break; ochr_ptr++; } while(*ochr_ptr != NOTACHAR); if (*ochr_ptr == NOTACHAR) return FALSE; /* Not found */ break; /* Note that OP_DIGIT etc. are generated only when PCRE_UCP is *not* set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */ case OP_DIGIT: if (chr < 256 && (cd->ctypes[chr] & ctype_digit) != 0) return FALSE; break; case OP_NOT_DIGIT: if (chr > 255 || (cd->ctypes[chr] & ctype_digit) == 0) return FALSE; break; case OP_WHITESPACE: if (chr < 256 && (cd->ctypes[chr] & ctype_space) != 0) return FALSE; break; case OP_NOT_WHITESPACE: if (chr > 255 || (cd->ctypes[chr] & ctype_space) == 0) return FALSE; break; case OP_WORDCHAR: if (chr < 255 && (cd->ctypes[chr] & ctype_word) != 0) return FALSE; break; case OP_NOT_WORDCHAR: if (chr > 255 || (cd->ctypes[chr] & ctype_word) == 0) return FALSE; break; case OP_HSPACE: switch(chr) { HSPACE_CASES: return FALSE; default: break; } break; case OP_NOT_HSPACE: switch(chr) { HSPACE_CASES: break; default: return FALSE; } break; case OP_ANYNL: case OP_VSPACE: switch(chr) { VSPACE_CASES: return FALSE; default: break; } break; case OP_NOT_VSPACE: switch(chr) { VSPACE_CASES: break; default: return FALSE; } break; case OP_DOLL: case OP_EODN: switch (chr) { case CHAR_CR: case CHAR_LF: case CHAR_VT: case CHAR_FF: case CHAR_NEL: #ifndef EBCDIC case 0x2028: case 0x2029: #endif /* Not EBCDIC */ return FALSE; } break; case OP_EOD: /* Can always possessify before \z */ break; #ifdef SUPPORT_UCP case OP_PROP: case OP_NOTPROP: if (!check_char_prop(chr, list_ptr[2], list_ptr[3], list_ptr[0] == OP_NOTPROP)) return FALSE; break; #endif case OP_NCLASS: if (chr > 255) return FALSE; /* Fall through */ case OP_CLASS: if (chr > 255) break; class_bitset = (pcre_uint8 *) ((list_ptr == list ? code : base_end) - list_ptr[2]); if ((class_bitset[chr >> 3] & (1U << (chr & 7))) != 0) return FALSE; break; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: if (PRIV(xclass)(chr, (list_ptr == list ? code : base_end) - list_ptr[2] + LINK_SIZE, utf)) return FALSE; break; #endif default: return FALSE; } chr_ptr++; } while(*chr_ptr != NOTACHAR); /* At least one character must be matched from this opcode. */ if (list[1] == 0) return TRUE; } /* Control never reaches here. There used to be a fail-save return FALSE; here, but some compilers complain about an unreachable statement. */ } /************************************************* * Scan compiled regex for auto-possession * *************************************************/ /* Replaces single character iterations with their possessive alternatives if appropriate. This function modifies the compiled opcode! Arguments: code points to start of the byte code utf TRUE in UTF-8 / UTF-16 / UTF-32 mode cd static compile data Returns: nothing */ static void auto_possessify(pcre_uchar *code, BOOL utf, const compile_data *cd) { register pcre_uchar c; const pcre_uchar *end; pcre_uchar *repeat_opcode; pcre_uint32 list[8]; int rec_limit; for (;;) { c = *code; /* When a pattern with bad UTF-8 encoding is compiled with NO_UTF_CHECK, it may compile without complaining, but may get into a loop here if the code pointer points to a bad value. This is, of course a documentated possibility, when NO_UTF_CHECK is set, so it isn't a bug, but we can detect this case and just give up on this optimization. */ if (c >= OP_TABLE_LENGTH) return; if (c >= OP_STAR && c <= OP_TYPEPOSUPTO) { c -= get_repeat_base(c) - OP_STAR; end = (c <= OP_MINUPTO) ? get_chr_property_list(code, utf, cd->fcc, list) : NULL; list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO; rec_limit = 1000; if (end != NULL && compare_opcodes(end, utf, cd, list, end, &rec_limit)) { switch(c) { case OP_STAR: *code += OP_POSSTAR - OP_STAR; break; case OP_MINSTAR: *code += OP_POSSTAR - OP_MINSTAR; break; case OP_PLUS: *code += OP_POSPLUS - OP_PLUS; break; case OP_MINPLUS: *code += OP_POSPLUS - OP_MINPLUS; break; case OP_QUERY: *code += OP_POSQUERY - OP_QUERY; break; case OP_MINQUERY: *code += OP_POSQUERY - OP_MINQUERY; break; case OP_UPTO: *code += OP_POSUPTO - OP_UPTO; break; case OP_MINUPTO: *code += OP_POSUPTO - OP_MINUPTO; break; } } c = *code; } else if (c == OP_CLASS || c == OP_NCLASS || c == OP_XCLASS) { #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 if (c == OP_XCLASS) repeat_opcode = code + GET(code, 1); else #endif repeat_opcode = code + 1 + (32 / sizeof(pcre_uchar)); c = *repeat_opcode; if (c >= OP_CRSTAR && c <= OP_CRMINRANGE) { /* end must not be NULL. */ end = get_chr_property_list(code, utf, cd->fcc, list); list[1] = (c & 1) == 0; rec_limit = 1000; if (compare_opcodes(end, utf, cd, list, end, &rec_limit)) { switch (c) { case OP_CRSTAR: case OP_CRMINSTAR: *repeat_opcode = OP_CRPOSSTAR; break; case OP_CRPLUS: case OP_CRMINPLUS: *repeat_opcode = OP_CRPOSPLUS; break; case OP_CRQUERY: case OP_CRMINQUERY: *repeat_opcode = OP_CRPOSQUERY; break; case OP_CRRANGE: case OP_CRMINRANGE: *repeat_opcode = OP_CRPOSRANGE; break; } } } c = *code; } switch(c) { case OP_END: return; case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEPOSSTAR: case OP_TYPEPOSPLUS: case OP_TYPEPOSQUERY: if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2; break; case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEEXACT: case OP_TYPEPOSUPTO: if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP) code += 2; break; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: code += GET(code, 1); break; #endif case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: code += code[1]; break; } /* Add in the fixed length from the table */ code += PRIV(OP_lengths)[c]; /* In UTF-8 mode, opcodes that are followed by a character may be followed by a multi-byte character. The length in the table is a minimum, so we have to arrange to skip the extra bytes. */ #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf) switch(c) { case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: case OP_UPTO: case OP_MINUPTO: case OP_EXACT: case OP_POSSTAR: case OP_POSPLUS: case OP_POSQUERY: case OP_POSUPTO: case OP_STARI: case OP_MINSTARI: case OP_PLUSI: case OP_MINPLUSI: case OP_QUERYI: case OP_MINQUERYI: case OP_UPTOI: case OP_MINUPTOI: case OP_EXACTI: case OP_POSSTARI: case OP_POSPLUSI: case OP_POSQUERYI: case OP_POSUPTOI: case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: case OP_NOTUPTO: case OP_NOTMINUPTO: case OP_NOTEXACT: case OP_NOTPOSSTAR: case OP_NOTPOSPLUS: case OP_NOTPOSQUERY: case OP_NOTPOSUPTO: case OP_NOTSTARI: case OP_NOTMINSTARI: case OP_NOTPLUSI: case OP_NOTMINPLUSI: case OP_NOTQUERYI: case OP_NOTMINQUERYI: case OP_NOTUPTOI: case OP_NOTMINUPTOI: case OP_NOTEXACTI: case OP_NOTPOSSTARI: case OP_NOTPOSPLUSI: case OP_NOTPOSQUERYI: case OP_NOTPOSUPTOI: if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]); break; } #else (void)(utf); /* Keep compiler happy by referencing function argument */ #endif } } /************************************************* * Check for POSIX class syntax * *************************************************/ /* This function is called when the sequence "[:" or "[." or "[=" is encountered in a character class. It checks whether this is followed by a sequence of characters terminated by a matching ":]" or ".]" or "=]". If we reach an unescaped ']' without the special preceding character, return FALSE. Originally, this function only recognized a sequence of letters between the terminators, but it seems that Perl recognizes any sequence of characters, though of course unknown POSIX names are subsequently rejected. Perl gives an "Unknown POSIX class" error for [:f\oo:] for example, where previously PCRE didn't consider this to be a POSIX class. Likewise for [:1234:]. The problem in trying to be exactly like Perl is in the handling of escapes. We have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code below handles the special cases \\ and \], but does not try to do any other escape processing. This makes it different from Perl for cases such as [:l\ower:] where Perl recognizes it as the POSIX class "lower" but PCRE does not recognize "l\ower". This is a lesser evil than not diagnosing bad classes when Perl does, I think. A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not. It seems that the appearance of a nested POSIX class supersedes an apparent external class. For example, [:a[:digit:]b:] matches "a", "b", ":", or a digit. In Perl, unescaped square brackets may also appear as part of class names. For example, [:a[:abc]b:] gives unknown POSIX class "[:abc]b:]". However, for [:a[:abc]b][b:] it gives unknown POSIX class "[:abc]b][b:]", which does not seem right at all. PCRE does not allow closing square brackets in POSIX class names. Arguments: ptr pointer to the initial [ endptr where to return the end pointer Returns: TRUE or FALSE */ static BOOL check_posix_syntax(const pcre_uchar *ptr, const pcre_uchar **endptr) { pcre_uchar terminator; /* Don't combine these lines; the Solaris cc */ terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ for (++ptr; *ptr != CHAR_NULL; ptr++) { if (*ptr == CHAR_BACKSLASH && (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ptr[1] == CHAR_BACKSLASH)) ptr++; else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) || *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE; else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) { *endptr = ptr; return TRUE; } } return FALSE; } /************************************************* * Check POSIX class name * *************************************************/ /* This function is called to check the name given in a POSIX-style class entry such as [:alnum:]. Arguments: ptr points to the first letter len the length of the name Returns: a value representing the name, or -1 if unknown */ static int check_posix_name(const pcre_uchar *ptr, int len) { const char *pn = posix_names; register int yield = 0; while (posix_name_lengths[yield] != 0) { if (len == posix_name_lengths[yield] && STRNCMP_UC_C8(ptr, pn, (unsigned int)len) == 0) return yield; pn += posix_name_lengths[yield] + 1; yield++; } return -1; } /************************************************* * Adjust OP_RECURSE items in repeated group * *************************************************/ /* OP_RECURSE items contain an offset from the start of the regex to the group that is referenced. This means that groups can be replicated for fixed repetition simply by copying (because the recursion is allowed to refer to earlier groups that are outside the current group). However, when a group is optional (i.e. the minimum quantifier is zero), OP_BRAZERO or OP_SKIPZERO is inserted before it, after it has been compiled. This means that any OP_RECURSE items within it that refer to the group itself or any contained groups have to have their offsets adjusted. That one of the jobs of this function. Before it is called, the partially compiled regex must be temporarily terminated with OP_END. This function has been extended to cope with forward references for recursions and subroutine calls. It must check the list of such references for the group we are dealing with. If it finds that one of the recursions in the current group is on this list, it does not adjust the value in the reference (which is a group number). After the group has been scanned, all the offsets in the forward reference list for the group are adjusted. Arguments: group points to the start of the group adjust the amount by which the group is to be moved utf TRUE in UTF-8 / UTF-16 / UTF-32 mode cd contains pointers to tables etc. save_hwm_offset the hwm forward reference offset at the start of the group Returns: nothing */ static void adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd, size_t save_hwm_offset) { int offset; pcre_uchar *hc; pcre_uchar *ptr = group; while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL) { for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm; hc += LINK_SIZE) { offset = (int)GET(hc, 0); if (cd->start_code + offset == ptr + 1) break; } /* If we have not found this recursion on the forward reference list, adjust the recursion's offset if it's after the start of this group. */ if (hc >= cd->hwm) { offset = (int)GET(ptr, 1); if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust); } ptr += 1 + LINK_SIZE; } /* Now adjust all forward reference offsets for the group. */ for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm; hc += LINK_SIZE) { offset = (int)GET(hc, 0); PUT(hc, 0, offset + adjust); } } /************************************************* * Insert an automatic callout point * *************************************************/ /* This function is called when the PCRE_AUTO_CALLOUT option is set, to insert callout points before each pattern item. Arguments: code current code pointer ptr current pattern pointer cd pointers to tables etc Returns: new code pointer */ static pcre_uchar * auto_callout(pcre_uchar *code, const pcre_uchar *ptr, compile_data *cd) { *code++ = OP_CALLOUT; *code++ = 255; PUT(code, 0, (int)(ptr - cd->start_pattern)); /* Pattern offset */ PUT(code, LINK_SIZE, 0); /* Default length */ return code + 2 * LINK_SIZE; } /************************************************* * Complete a callout item * *************************************************/ /* A callout item contains the length of the next item in the pattern, which we can't fill in till after we have reached the relevant point. This is used for both automatic and manual callouts. Arguments: previous_callout points to previous callout item ptr current pattern pointer cd pointers to tables etc Returns: nothing */ static void complete_callout(pcre_uchar *previous_callout, const pcre_uchar *ptr, compile_data *cd) { int length = (int)(ptr - cd->start_pattern - GET(previous_callout, 2)); PUT(previous_callout, 2 + LINK_SIZE, length); } #ifdef SUPPORT_UCP /************************************************* * Get othercase range * *************************************************/ /* This function is passed the start and end of a class range, in UTF-8 mode with UCP support. It searches up the characters, looking for ranges of characters in the "other" case. Each call returns the next one, updating the start address. A character with multiple other cases is returned on its own with a special return value. Arguments: cptr points to starting character value; updated d end value ocptr where to put start of othercase range odptr where to put end of othercase range Yield: -1 when no more 0 when a range is returned >0 the CASESET offset for char with multiple other cases in this case, ocptr contains the original */ static int get_othercase_range(pcre_uint32 *cptr, pcre_uint32 d, pcre_uint32 *ocptr, pcre_uint32 *odptr) { pcre_uint32 c, othercase, next; unsigned int co; /* Find the first character that has an other case. If it has multiple other cases, return its case offset value. */ for (c = *cptr; c <= d; c++) { if ((co = UCD_CASESET(c)) != 0) { *ocptr = c++; /* Character that has the set */ *cptr = c; /* Rest of input range */ return (int)co; } if ((othercase = UCD_OTHERCASE(c)) != c) break; } if (c > d) return -1; /* Reached end of range */ /* Found a character that has a single other case. Search for the end of the range, which is either the end of the input range, or a character that has zero or more than one other cases. */ *ocptr = othercase; next = othercase + 1; for (++c; c <= d; c++) { if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break; next++; } *odptr = next - 1; /* End of othercase range */ *cptr = c; /* Rest of input range */ return 0; } #endif /* SUPPORT_UCP */ /************************************************* * Add a character or range to a class * *************************************************/ /* This function packages up the logic of adding a character or range of characters to a class. The character values in the arguments will be within the valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is mutually recursive with the function immediately below. Arguments: classbits the bit map for characters < 256 uchardptr points to the pointer for extra data options the options word cd contains pointers to tables etc. start start of range character end end of range character Returns: the number of < 256 characters added the pointer to extra data is updated */ static int add_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options, compile_data *cd, pcre_uint32 start, pcre_uint32 end) { pcre_uint32 c; pcre_uint32 classbits_end = (end <= 0xff ? end : 0xff); int n8 = 0; /* If caseless matching is required, scan the range and process alternate cases. In Unicode, there are 8-bit characters that have alternate cases that are greater than 255 and vice-versa. Sometimes we can just extend the original range. */ if ((options & PCRE_CASELESS) != 0) { #ifdef SUPPORT_UCP if ((options & PCRE_UTF8) != 0) { int rc; pcre_uint32 oc, od; options &= ~PCRE_CASELESS; /* Remove for recursive calls */ c = start; while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0) { /* Handle a single character that has more than one other case. */ if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cd, PRIV(ucd_caseless_sets) + rc, oc); /* Do nothing if the other case range is within the original range. */ else if (oc >= start && od <= end) continue; /* Extend the original range if there is overlap, noting that if oc < c, we can't have od > end because a subrange is always shorter than the basic range. Otherwise, use a recursive call to add the additional range. */ else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */ else if (od > end && oc <= end + 1) { end = od; /* Extend upwards */ if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff); } else n8 += add_to_class(classbits, uchardptr, options, cd, oc, od); } } else #endif /* SUPPORT_UCP */ /* Not UTF-mode, or no UCP */ for (c = start; c <= classbits_end; c++) { SETBIT(classbits, cd->fcc[c]); n8++; } } /* Now handle the original range. Adjust the final value according to the bit length - this means that the same lists of (e.g.) horizontal spaces can be used in all cases. */ #if defined COMPILE_PCRE8 #ifdef SUPPORT_UTF if ((options & PCRE_UTF8) == 0) #endif if (end > 0xff) end = 0xff; #elif defined COMPILE_PCRE16 #ifdef SUPPORT_UTF if ((options & PCRE_UTF16) == 0) #endif if (end > 0xffff) end = 0xffff; #endif /* COMPILE_PCRE[8|16] */ /* Use the bitmap for characters < 256. Otherwise use extra data.*/ for (c = start; c <= classbits_end; c++) { /* Regardless of start, c will always be <= 255. */ SETBIT(classbits, c); n8++; } #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 if (start <= 0xff) start = 0xff + 1; if (end >= start) { pcre_uchar *uchardata = *uchardptr; #ifdef SUPPORT_UTF if ((options & PCRE_UTF8) != 0) /* All UTFs use the same flag bit */ { if (start < end) { *uchardata++ = XCL_RANGE; uchardata += PRIV(ord2utf)(start, uchardata); uchardata += PRIV(ord2utf)(end, uchardata); } else if (start == end) { *uchardata++ = XCL_SINGLE; uchardata += PRIV(ord2utf)(start, uchardata); } } else #endif /* SUPPORT_UTF */ /* Without UTF support, character values are constrained by the bit length, and can only be > 256 for 16-bit and 32-bit libraries. */ #ifdef COMPILE_PCRE8 {} #else if (start < end) { *uchardata++ = XCL_RANGE; *uchardata++ = start; *uchardata++ = end; } else if (start == end) { *uchardata++ = XCL_SINGLE; *uchardata++ = start; } #endif *uchardptr = uchardata; /* Updata extra data pointer */ } #endif /* SUPPORT_UTF || !COMPILE_PCRE8 */ return n8; /* Number of 8-bit characters */ } /************************************************* * Add a list of characters to a class * *************************************************/ /* This function is used for adding a list of case-equivalent characters to a class, and also for adding a list of horizontal or vertical whitespace. If the list is in order (which it should be), ranges of characters are detected and handled appropriately. This function is mutually recursive with the function above. Arguments: classbits the bit map for characters < 256 uchardptr points to the pointer for extra data options the options word cd contains pointers to tables etc. p points to row of 32-bit values, terminated by NOTACHAR except character to omit; this is used when adding lists of case-equivalent characters to avoid including the one we already know about Returns: the number of < 256 characters added the pointer to extra data is updated */ static int add_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options, compile_data *cd, const pcre_uint32 *p, unsigned int except) { int n8 = 0; while (p[0] < NOTACHAR) { int n = 0; if (p[0] != except) { while(p[n+1] == p[0] + n + 1) n++; n8 += add_to_class(classbits, uchardptr, options, cd, p[0], p[n]); } p += n + 1; } return n8; } /************************************************* * Add characters not in a list to a class * *************************************************/ /* This function is used for adding the complement of a list of horizontal or vertical whitespace to a class. The list must be in order. Arguments: classbits the bit map for characters < 256 uchardptr points to the pointer for extra data options the options word cd contains pointers to tables etc. p points to row of 32-bit values, terminated by NOTACHAR Returns: the number of < 256 characters added the pointer to extra data is updated */ static int add_not_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options, compile_data *cd, const pcre_uint32 *p) { BOOL utf = (options & PCRE_UTF8) != 0; int n8 = 0; if (p[0] > 0) n8 += add_to_class(classbits, uchardptr, options, cd, 0, p[0] - 1); while (p[0] < NOTACHAR) { while (p[1] == p[0] + 1) p++; n8 += add_to_class(classbits, uchardptr, options, cd, p[0] + 1, (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1); p++; } return n8; } /************************************************* * Compile one branch * *************************************************/ /* Scan the pattern, compiling it into the a vector. If the options are changed during the branch, the pointer is used to change the external options bits. This function is used during the pre-compile phase when we are trying to find out the amount of memory needed, as well as during the real compile phase. The value of lengthptr distinguishes the two phases. Arguments: optionsptr pointer to the option bits codeptr points to the pointer to the current code point ptrptr points to the current pattern pointer errorcodeptr points to error code variable firstcharptr place to put the first required character firstcharflagsptr place to put the first character flags, or a negative number reqcharptr place to put the last required character reqcharflagsptr place to put the last required character flags, or a negative number bcptr points to current branch chain cond_depth conditional nesting depth cd contains pointers to tables etc. lengthptr NULL during the real compile phase points to length accumulator during pre-compile phase Returns: TRUE on success FALSE, with *errorcodeptr set non-zero on error */ static BOOL compile_branch(int *optionsptr, pcre_uchar **codeptr, const pcre_uchar **ptrptr, int *errorcodeptr, pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr, pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr, branch_chain *bcptr, int cond_depth, compile_data *cd, int *lengthptr) { int repeat_type, op_type; int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ int bravalue = 0; int greedy_default, greedy_non_default; pcre_uint32 firstchar, reqchar; pcre_int32 firstcharflags, reqcharflags; pcre_uint32 zeroreqchar, zerofirstchar; pcre_int32 zeroreqcharflags, zerofirstcharflags; pcre_int32 req_caseopt, reqvary, tempreqvary; int options = *optionsptr; /* May change dynamically */ int after_manual_callout = 0; int length_prevgroup = 0; register pcre_uint32 c; int escape; register pcre_uchar *code = *codeptr; pcre_uchar *last_code = code; pcre_uchar *orig_code = code; pcre_uchar *tempcode; BOOL inescq = FALSE; BOOL groupsetfirstchar = FALSE; const pcre_uchar *ptr = *ptrptr; const pcre_uchar *tempptr; const pcre_uchar *nestptr = NULL; pcre_uchar *previous = NULL; pcre_uchar *previous_callout = NULL; size_t item_hwm_offset = 0; pcre_uint8 classbits[32]; /* We can fish out the UTF-8 setting once and for all into a BOOL, but we must not do this for other options (e.g. PCRE_EXTENDED) because they may change dynamically as we process the pattern. */ #ifdef SUPPORT_UTF /* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */ BOOL utf = (options & PCRE_UTF8) != 0; #ifndef COMPILE_PCRE32 pcre_uchar utf_chars[6]; #endif #else BOOL utf = FALSE; #endif /* Helper variables for OP_XCLASS opcode (for characters > 255). We define class_uchardata always so that it can be passed to add_to_class() always, though it will not be used in non-UTF 8-bit cases. This avoids having to supply alternative calls for the different cases. */ pcre_uchar *class_uchardata; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 BOOL xclass; pcre_uchar *class_uchardata_base; #endif #ifdef PCRE_DEBUG if (lengthptr != NULL) DPRINTF((">> start branch\n")); #endif /* Set up the default and non-default settings for greediness */ greedy_default = ((options & PCRE_UNGREEDY) != 0); greedy_non_default = greedy_default ^ 1; /* Initialize no first byte, no required byte. REQ_UNSET means "no char matching encountered yet". It gets changed to REQ_NONE if we hit something that matches a non-fixed char first char; reqchar just remains unset if we never find one. When we hit a repeat whose minimum is zero, we may have to adjust these values to take the zero repeat into account. This is implemented by setting them to zerofirstbyte and zeroreqchar when such a repeat is encountered. The individual item types that can be repeated set these backoff variables appropriately. */ firstchar = reqchar = zerofirstchar = zeroreqchar = 0; firstcharflags = reqcharflags = zerofirstcharflags = zeroreqcharflags = REQ_UNSET; /* The variable req_caseopt contains either the REQ_CASELESS value or zero, according to the current setting of the caseless flag. The REQ_CASELESS leaves the lower 28 bit empty. It is added into the firstchar or reqchar variables to record the case status of the value. This is used only for ASCII characters. */ req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS:0; /* Switch on next character until the end of the branch */ for (;; ptr++) { BOOL negate_class; BOOL should_flip_negation; BOOL possessive_quantifier; BOOL is_quantifier; BOOL is_recurse; BOOL reset_bracount; int class_has_8bitchar; int class_one_char; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 BOOL xclass_has_prop; #endif int newoptions; int recno; int refsign; int skipbytes; pcre_uint32 subreqchar, subfirstchar; pcre_int32 subreqcharflags, subfirstcharflags; int terminator; unsigned int mclength; unsigned int tempbracount; pcre_uint32 ec; pcre_uchar mcbuffer[8]; /* Come here to restart the loop without advancing the pointer. */ REDO_LOOP: /* Get next character in the pattern */ c = *ptr; /* If we are at the end of a nested substitution, revert to the outer level string. Nesting only happens one level deep. */ if (c == CHAR_NULL && nestptr != NULL) { ptr = nestptr; nestptr = NULL; c = *ptr; } /* If we are in the pre-compile phase, accumulate the length used for the previous cycle of this loop. */ if (lengthptr != NULL) { #ifdef PCRE_DEBUG if (code > cd->hwm) cd->hwm = code; /* High water info */ #endif if (code > cd->start_workspace + cd->workspace_size - WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */ { *errorcodeptr = (code >= cd->start_workspace + cd->workspace_size)? ERR52 : ERR87; goto FAILED; } /* There is at least one situation where code goes backwards: this is the case of a zero quantifier after a class (e.g. [ab]{0}). At compile time, the class is simply eliminated. However, it is created first, so we have to allow memory for it. Therefore, don't ever reduce the length at this point. */ if (code < last_code) code = last_code; /* Paranoid check for integer overflow */ if (OFLOW_MAX - *lengthptr < code - last_code) { *errorcodeptr = ERR20; goto FAILED; } *lengthptr += (int)(code - last_code); DPRINTF(("length=%d added %d c=%c (0x%x)\n", *lengthptr, (int)(code - last_code), c, c)); /* If "previous" is set and it is not at the start of the work space, move it back to there, in order to avoid filling up the work space. Otherwise, if "previous" is NULL, reset the current code pointer to the start. */ if (previous != NULL) { if (previous > orig_code) { memmove(orig_code, previous, IN_UCHARS(code - previous)); code -= previous - orig_code; previous = orig_code; } } else code = orig_code; /* Remember where this code item starts so we can pick up the length next time round. */ last_code = code; } /* In the real compile phase, just check the workspace used by the forward reference list. */ else if (cd->hwm > cd->start_workspace + cd->workspace_size) { *errorcodeptr = ERR52; goto FAILED; } /* If in \Q...\E, check for the end; if not, we have a literal. Otherwise an isolated \E is ignored. */ if (c != CHAR_NULL) { if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) { inescq = FALSE; ptr++; continue; } else if (inescq) { if (previous_callout != NULL) { if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ complete_callout(previous_callout, ptr, cd); previous_callout = NULL; } if ((options & PCRE_AUTO_CALLOUT) != 0) { previous_callout = code; code = auto_callout(code, ptr, cd); } goto NORMAL_CHAR; } /* Check for the start of a \Q...\E sequence. We must do this here rather than later in case it is immediately followed by \E, which turns it into a "do nothing" sequence. */ if (c == CHAR_BACKSLASH && ptr[1] == CHAR_Q) { inescq = TRUE; ptr++; continue; } } /* In extended mode, skip white space and comments. */ if ((options & PCRE_EXTENDED) != 0) { const pcre_uchar *wscptr = ptr; while (MAX_255(c) && (cd->ctypes[c] & ctype_space) != 0) c = *(++ptr); if (c == CHAR_NUMBER_SIGN) { ptr++; while (*ptr != CHAR_NULL) { if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */ { /* IS_NEWLINE sets cd->nllen. */ ptr += cd->nllen; break; } ptr++; #ifdef SUPPORT_UTF if (utf) FORWARDCHAR(ptr); #endif } } /* If we skipped any characters, restart the loop. Otherwise, we didn't see a comment. */ if (ptr > wscptr) goto REDO_LOOP; } /* Skip over (?# comments. We need to do this here because we want to know if the next thing is a quantifier, and these comments may come between an item and its quantifier. */ if (c == CHAR_LEFT_PARENTHESIS && ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_NUMBER_SIGN) { ptr += 3; while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; if (*ptr == CHAR_NULL) { *errorcodeptr = ERR18; goto FAILED; } continue; } /* See if the next thing is a quantifier. */ is_quantifier = c == CHAR_ASTERISK || c == CHAR_PLUS || c == CHAR_QUESTION_MARK || (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1)); /* Fill in length of a previous callout, except when the next thing is a quantifier or when processing a property substitution string in UCP mode. */ if (!is_quantifier && previous_callout != NULL && nestptr == NULL && after_manual_callout-- <= 0) { if (lengthptr == NULL) /* Don't attempt in pre-compile phase */ complete_callout(previous_callout, ptr, cd); previous_callout = NULL; } /* Create auto callout, except for quantifiers, or while processing property strings that are substituted for \w etc in UCP mode. */ if ((options & PCRE_AUTO_CALLOUT) != 0 && !is_quantifier && nestptr == NULL) { previous_callout = code; code = auto_callout(code, ptr, cd); } /* Process the next pattern item. */ switch(c) { /* ===================================================================*/ case CHAR_NULL: /* The branch terminates at string end */ case CHAR_VERTICAL_LINE: /* or | or ) */ case CHAR_RIGHT_PARENTHESIS: *firstcharptr = firstchar; *firstcharflagsptr = firstcharflags; *reqcharptr = reqchar; *reqcharflagsptr = reqcharflags; *codeptr = code; *ptrptr = ptr; if (lengthptr != NULL) { if (OFLOW_MAX - *lengthptr < code - last_code) { *errorcodeptr = ERR20; goto FAILED; } *lengthptr += (int)(code - last_code); /* To include callout length */ DPRINTF((">> end branch\n")); } return TRUE; /* ===================================================================*/ /* Handle single-character metacharacters. In multiline mode, ^ disables the setting of any following char as a first character. */ case CHAR_CIRCUMFLEX_ACCENT: previous = NULL; if ((options & PCRE_MULTILINE) != 0) { if (firstcharflags == REQ_UNSET) zerofirstcharflags = firstcharflags = REQ_NONE; *code++ = OP_CIRCM; } else *code++ = OP_CIRC; break; case CHAR_DOLLAR_SIGN: previous = NULL; *code++ = ((options & PCRE_MULTILINE) != 0)? OP_DOLLM : OP_DOLL; break; /* There can never be a first char if '.' is first, whatever happens about repeats. The value of reqchar doesn't change either. */ case CHAR_DOT: if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; zerofirstchar = firstchar; zerofirstcharflags = firstcharflags; zeroreqchar = reqchar; zeroreqcharflags = reqcharflags; previous = code; item_hwm_offset = cd->hwm - cd->start_workspace; *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY; break; /* ===================================================================*/ /* Character classes. If the included characters are all < 256, we build a 32-byte bitmap of the permitted characters, except in the special case where there is only one such character. For negated classes, we build the map as usual, then invert it at the end. However, we use a different opcode so that data characters > 255 can be handled correctly. If the class contains characters outside the 0-255 range, a different opcode is compiled. It may optionally have a bit map for characters < 256, but those above are are explicitly listed afterwards. A flag byte tells whether the bitmap is present, and whether this is a negated class or not. In JavaScript compatibility mode, an isolated ']' causes an error. In default (Perl) mode, it is treated as a data character. */ case CHAR_RIGHT_SQUARE_BRACKET: if ((cd->external_options & PCRE_JAVASCRIPT_COMPAT) != 0) { *errorcodeptr = ERR64; goto FAILED; } goto NORMAL_CHAR; /* In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is used for "start of word" and "end of word". As these are otherwise illegal sequences, we don't break anything by recognizing them. They are replaced by \b(?=\w) and \b(?<=\w) respectively. Sequences like [a[:<:]] are erroneous and are handled by the normal code below. */ case CHAR_LEFT_SQUARE_BRACKET: if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0) { nestptr = ptr + 7; ptr = sub_start_of_word; goto REDO_LOOP; } if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0) { nestptr = ptr + 7; ptr = sub_end_of_word; goto REDO_LOOP; } /* Handle a real character class. */ previous = code; item_hwm_offset = cd->hwm - cd->start_workspace; /* PCRE supports POSIX class stuff inside a class. Perl gives an error if they are encountered at the top level, so we'll do that too. */ if ((ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr)) { *errorcodeptr = (ptr[1] == CHAR_COLON)? ERR13 : ERR31; goto FAILED; } /* If the first character is '^', set the negation flag and skip it. Also, if the first few characters (either before or after ^) are \Q\E or \E we skip them too. This makes for compatibility with Perl. */ negate_class = FALSE; for (;;) { c = *(++ptr); if (c == CHAR_BACKSLASH) { if (ptr[1] == CHAR_E) ptr++; else if (STRNCMP_UC_C8(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0) ptr += 3; else break; } else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT) negate_class = TRUE; else break; } /* Empty classes are allowed in JavaScript compatibility mode. Otherwise, an initial ']' is taken as a data character -- the code below handles that. In JS mode, [] must always fail, so generate OP_FAIL, whereas [^] must match any character, so generate OP_ALLANY. */ if (c == CHAR_RIGHT_SQUARE_BRACKET && (cd->external_options & PCRE_JAVASCRIPT_COMPAT) != 0) { *code++ = negate_class? OP_ALLANY : OP_FAIL; if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; zerofirstchar = firstchar; zerofirstcharflags = firstcharflags; break; } /* If a class contains a negative special such as \S, we need to flip the negation flag at the end, so that support for characters > 255 works correctly (they are all included in the class). */ should_flip_negation = FALSE; /* Extended class (xclass) will be used when characters > 255 might match. */ #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 xclass = FALSE; class_uchardata = code + LINK_SIZE + 2; /* For XCLASS items */ class_uchardata_base = class_uchardata; /* Save the start */ #endif /* For optimization purposes, we track some properties of the class: class_has_8bitchar will be non-zero if the class contains at least one < 256 character; class_one_char will be 1 if the class contains just one character; xclass_has_prop will be TRUE if unicode property checks are present in the class. */ class_has_8bitchar = 0; class_one_char = 0; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 xclass_has_prop = FALSE; #endif /* Initialize the 32-char bit map to all zeros. We build the map in a temporary bit of memory, in case the class contains fewer than two 8-bit characters because in that case the compiled code doesn't use the bit map. */ memset(classbits, 0, 32 * sizeof(pcre_uint8)); /* Process characters until ] is reached. By writing this as a "do" it means that an initial ] is taken as a data character. At the start of the loop, c contains the first byte of the character. */ if (c != CHAR_NULL) do { const pcre_uchar *oldptr; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(c)) { /* Braces are required because the */ GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */ } #endif #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 /* In the pre-compile phase, accumulate the length of any extra data and reset the pointer. This is so that very large classes that contain a zillion > 255 characters no longer overwrite the work space (which is on the stack). We have to remember that there was XCLASS data, however. */ if (class_uchardata > class_uchardata_base) xclass = TRUE; if (lengthptr != NULL && class_uchardata > class_uchardata_base) { *lengthptr += (int)(class_uchardata - class_uchardata_base); class_uchardata = class_uchardata_base; } #endif /* Inside \Q...\E everything is literal except \E */ if (inescq) { if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) /* If we are at \E */ { inescq = FALSE; /* Reset literal state */ ptr++; /* Skip the 'E' */ continue; /* Carry on with next */ } goto CHECK_RANGE; /* Could be range if \E follows */ } /* Handle POSIX class names. Perl allows a negation extension of the form [:^name:]. A square bracket that doesn't match the syntax is treated as a literal. We also recognize the POSIX constructions [.ch.] and [=ch=] ("collating elements") and fault them, as Perl 5.6 and 5.8 do. */ if (c == CHAR_LEFT_SQUARE_BRACKET && (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr)) { BOOL local_negate = FALSE; int posix_class, taboffset, tabopt; register const pcre_uint8 *cbits = cd->cbits; pcre_uint8 pbits[32]; if (ptr[1] != CHAR_COLON) { *errorcodeptr = ERR31; goto FAILED; } ptr += 2; if (*ptr == CHAR_CIRCUMFLEX_ACCENT) { local_negate = TRUE; should_flip_negation = TRUE; /* Note negative special */ ptr++; } posix_class = check_posix_name(ptr, (int)(tempptr - ptr)); if (posix_class < 0) { *errorcodeptr = ERR30; goto FAILED; } /* If matching is caseless, upper and lower are converted to alpha. This relies on the fact that the class table starts with alpha, lower, upper as the first 3 entries. */ if ((options & PCRE_CASELESS) != 0 && posix_class <= 2) posix_class = 0; /* When PCRE_UCP is set, some of the POSIX classes are converted to different escape sequences that use Unicode properties \p or \P. Others that are not available via \p or \P generate XCL_PROP/XCL_NOTPROP directly. */ #ifdef SUPPORT_UCP if ((options & PCRE_UCP) != 0) { unsigned int ptype = 0; int pc = posix_class + ((local_negate)? POSIX_SUBSIZE/2 : 0); /* The posix_substitutes table specifies which POSIX classes can be converted to \p or \P items. */ if (posix_substitutes[pc] != NULL) { nestptr = tempptr + 1; ptr = posix_substitutes[pc] - 1; continue; } /* There are three other classes that generate special property calls that are recognized only in an XCLASS. */ else switch(posix_class) { case PC_GRAPH: ptype = PT_PXGRAPH; /* Fall through */ case PC_PRINT: if (ptype == 0) ptype = PT_PXPRINT; /* Fall through */ case PC_PUNCT: if (ptype == 0) ptype = PT_PXPUNCT; *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP; *class_uchardata++ = ptype; *class_uchardata++ = 0; xclass_has_prop = TRUE; ptr = tempptr + 1; continue; /* For the other POSIX classes (ascii, cntrl, xdigit) we are going to fall through to the non-UCP case and build a bit map for characters with code points less than 256. If we are in a negated POSIX class, characters with code points greater than 255 must either all match or all not match. In the special case where we have not yet generated any xclass data, and this is the final item in the overall class, we need do nothing: later on, the opcode OP_NCLASS will be used to indicate that characters greater than 255 are acceptable. If we have already seen an xclass item or one may follow (we have to assume that it might if this is not the end of the class), explicitly list all wide codepoints, which will then either not match or match, depending on whether the class is or is not negated. */ default: if (local_negate && (xclass || tempptr[2] != CHAR_RIGHT_SQUARE_BRACKET)) { *class_uchardata++ = XCL_RANGE; class_uchardata += PRIV(ord2utf)(0x100, class_uchardata); class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata); } break; } } #endif /* In the non-UCP case, or when UCP makes no difference, we build the bit map for the POSIX class in a chunk of local store because we may be adding and subtracting from it, and we don't want to subtract bits that may be in the main map already. At the end we or the result into the bit map that is being built. */ posix_class *= 3; /* Copy in the first table (always present) */ memcpy(pbits, cbits + posix_class_maps[posix_class], 32 * sizeof(pcre_uint8)); /* If there is a second table, add or remove it as required. */ taboffset = posix_class_maps[posix_class + 1]; tabopt = posix_class_maps[posix_class + 2]; if (taboffset >= 0) { if (tabopt >= 0) for (c = 0; c < 32; c++) pbits[c] |= cbits[c + taboffset]; else for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset]; } /* Now see if we need to remove any special characters. An option value of 1 removes vertical space and 2 removes underscore. */ if (tabopt < 0) tabopt = -tabopt; if (tabopt == 1) pbits[1] &= ~0x3c; else if (tabopt == 2) pbits[11] &= 0x7f; /* Add the POSIX table or its complement into the main table that is being built and we are done. */ if (local_negate) for (c = 0; c < 32; c++) classbits[c] |= ~pbits[c]; else for (c = 0; c < 32; c++) classbits[c] |= pbits[c]; ptr = tempptr + 1; /* Every class contains at least one < 256 character. */ class_has_8bitchar = 1; /* Every class contains at least two characters. */ class_one_char = 2; continue; /* End of POSIX syntax handling */ } /* Backslash may introduce a single character, or it may introduce one of the specials, which just set a flag. The sequence \b is a special case. Inside a class (and only there) it is treated as backspace. We assume that other escapes have more than one character in them, so speculatively set both class_has_8bitchar and class_one_char bigger than one. Unrecognized escapes fall through and are either treated as literal characters (by default), or are faulted if PCRE_EXTRA is set. */ if (c == CHAR_BACKSLASH) { escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options, TRUE); if (*errorcodeptr != 0) goto FAILED; if (escape == 0) c = ec; else if (escape == ESC_b) c = CHAR_BS; /* \b is backspace in a class */ else if (escape == ESC_N) /* \N is not supported in a class */ { *errorcodeptr = ERR71; goto FAILED; } else if (escape == ESC_Q) /* Handle start of quoted string */ { if (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) { ptr += 2; /* avoid empty string */ } else inescq = TRUE; continue; } else if (escape == ESC_E) continue; /* Ignore orphan \E */ else { register const pcre_uint8 *cbits = cd->cbits; /* Every class contains at least two < 256 characters. */ class_has_8bitchar++; /* Every class contains at least two characters. */ class_one_char += 2; switch (escape) { #ifdef SUPPORT_UCP case ESC_du: /* These are the values given for \d etc */ case ESC_DU: /* when PCRE_UCP is set. We replace the */ case ESC_wu: /* escape sequence with an appropriate \p */ case ESC_WU: /* or \P to test Unicode properties instead */ case ESC_su: /* of the default ASCII testing. */ case ESC_SU: nestptr = ptr; ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ class_has_8bitchar--; /* Undo! */ continue; #endif case ESC_d: for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit]; continue; case ESC_D: should_flip_negation = TRUE; for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit]; continue; case ESC_w: for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_word]; continue; case ESC_W: should_flip_negation = TRUE; for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word]; continue; /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl 5.18. Before PCRE 8.34, we had to preserve the VT bit if it was previously set by something earlier in the character class. Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so we could just adjust the appropriate bit. From PCRE 8.34 we no longer treat \s and \S specially. */ case ESC_s: for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space]; continue; case ESC_S: should_flip_negation = TRUE; for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space]; continue; /* The rest apply in both UCP and non-UCP cases. */ case ESC_h: (void)add_list_to_class(classbits, &class_uchardata, options, cd, PRIV(hspace_list), NOTACHAR); continue; case ESC_H: (void)add_not_list_to_class(classbits, &class_uchardata, options, cd, PRIV(hspace_list)); continue; case ESC_v: (void)add_list_to_class(classbits, &class_uchardata, options, cd, PRIV(vspace_list), NOTACHAR); continue; case ESC_V: (void)add_not_list_to_class(classbits, &class_uchardata, options, cd, PRIV(vspace_list)); continue; case ESC_p: case ESC_P: #ifdef SUPPORT_UCP { BOOL negated; unsigned int ptype = 0, pdata = 0; if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr)) goto FAILED; *class_uchardata++ = ((escape == ESC_p) != negated)? XCL_PROP : XCL_NOTPROP; *class_uchardata++ = ptype; *class_uchardata++ = pdata; xclass_has_prop = TRUE; class_has_8bitchar--; /* Undo! */ continue; } #else *errorcodeptr = ERR45; goto FAILED; #endif /* Unrecognized escapes are faulted if PCRE is running in its strict mode. By default, for compatibility with Perl, they are treated as literals. */ default: if ((options & PCRE_EXTRA) != 0) { *errorcodeptr = ERR7; goto FAILED; } class_has_8bitchar--; /* Undo the speculative increase. */ class_one_char -= 2; /* Undo the speculative increase. */ c = *ptr; /* Get the final character and fall through */ break; } } /* Fall through if the escape just defined a single character (c >= 0). This may be greater than 256. */ escape = 0; } /* End of backslash handling */ /* A character may be followed by '-' to form a range. However, Perl does not permit ']' to be the end of the range. A '-' character at the end is treated as a literal. Perl ignores orphaned \E sequences entirely. The code for handling \Q and \E is messy. */ CHECK_RANGE: while (ptr[1] == CHAR_BACKSLASH && ptr[2] == CHAR_E) { inescq = FALSE; ptr += 2; } oldptr = ptr; /* Remember if \r or \n were explicitly used */ if (c == CHAR_CR || c == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF; /* Check for range */ if (!inescq && ptr[1] == CHAR_MINUS) { pcre_uint32 d; ptr += 2; while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2; /* If we hit \Q (not followed by \E) at this point, go into escaped mode. */ while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_Q) { ptr += 2; if (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) { ptr += 2; continue; } inescq = TRUE; break; } /* Minus (hyphen) at the end of a class is treated as a literal, so put back the pointer and jump to handle the character that preceded it. */ if (*ptr == CHAR_NULL || (!inescq && *ptr == CHAR_RIGHT_SQUARE_BRACKET)) { ptr = oldptr; goto CLASS_SINGLE_CHARACTER; } /* Otherwise, we have a potential range; pick up the next character */ #ifdef SUPPORT_UTF if (utf) { /* Braces are required because the */ GETCHARLEN(d, ptr, ptr); /* macro generates multiple statements */ } else #endif d = *ptr; /* Not UTF-8 mode */ /* The second part of a range can be a single-character escape sequence, but not any of the other escapes. Perl treats a hyphen as a literal in such circumstances. However, in Perl's warning mode, a warning is given, so PCRE now faults it as it is almost certainly a mistake on the user's part. */ if (!inescq) { if (d == CHAR_BACKSLASH) { int descape; descape = check_escape(&ptr, &d, errorcodeptr, cd->bracount, options, TRUE); if (*errorcodeptr != 0) goto FAILED; /* 0 means a character was put into d; \b is backspace; any other special causes an error. */ if (descape != 0) { if (descape == ESC_b) d = CHAR_BS; else { *errorcodeptr = ERR83; goto FAILED; } } } /* A hyphen followed by a POSIX class is treated in the same way. */ else if (d == CHAR_LEFT_SQUARE_BRACKET && (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT || ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr)) { *errorcodeptr = ERR83; goto FAILED; } } /* Check that the two values are in the correct order. Optimize one-character ranges. */ if (d < c) { *errorcodeptr = ERR8; goto FAILED; } if (d == c) goto CLASS_SINGLE_CHARACTER; /* A few lines below */ /* We have found a character range, so single character optimizations cannot be done anymore. Any value greater than 1 indicates that there is more than one character. */ class_one_char = 2; /* Remember an explicit \r or \n, and add the range to the class. */ if (d == CHAR_CR || d == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF; class_has_8bitchar += add_to_class(classbits, &class_uchardata, options, cd, c, d); continue; /* Go get the next char in the class */ } /* Handle a single character - we can get here for a normal non-escape char, or after \ that introduces a single character or for an apparent range that isn't. Only the value 1 matters for class_one_char, so don't increase it if it is already 2 or more ... just in case there's a class with a zillion characters in it. */ CLASS_SINGLE_CHARACTER: if (class_one_char < 2) class_one_char++; /* If xclass_has_prop is false and class_one_char is 1, we have the first single character in the class, and there have been no prior ranges, or XCLASS items generated by escapes. If this is the final character in the class, we can optimize by turning the item into a 1-character OP_CHAR[I] if it's positive, or OP_NOT[I] if it's negative. In the positive case, it can cause firstchar to be set. Otherwise, there can be no first char if this item is first, whatever repeat count may follow. In the case of reqchar, save the previous value for reinstating. */ if (!inescq && #ifdef SUPPORT_UCP !xclass_has_prop && #endif class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET) { ptr++; zeroreqchar = reqchar; zeroreqcharflags = reqcharflags; if (negate_class) { #ifdef SUPPORT_UCP int d; #endif if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; zerofirstchar = firstchar; zerofirstcharflags = firstcharflags; /* For caseless UTF-8 mode when UCP support is available, check whether this character has more than one other case. If so, generate a special OP_NOTPROP item instead of OP_NOTI. */ #ifdef SUPPORT_UCP if (utf && (options & PCRE_CASELESS) != 0 && (d = UCD_CASESET(c)) != 0) { *code++ = OP_NOTPROP; *code++ = PT_CLIST; *code++ = d; } else #endif /* Char has only one other case, or UCP not available */ { *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT; #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR) code += PRIV(ord2utf)(c, code); else #endif *code++ = c; } /* We are finished with this character class */ goto END_CLASS; } /* For a single, positive character, get the value into mcbuffer, and then we can handle this with the normal one-character code. */ #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR) mclength = PRIV(ord2utf)(c, mcbuffer); else #endif { mcbuffer[0] = c; mclength = 1; } goto ONE_CHAR; } /* End of 1-char optimization */ /* There is more than one character in the class, or an XCLASS item has been generated. Add this character to the class. */ class_has_8bitchar += add_to_class(classbits, &class_uchardata, options, cd, c, c); } /* Loop until ']' reached. This "while" is the end of the "do" far above. If we are at the end of an internal nested string, revert to the outer string. */ while (((c = *(++ptr)) != CHAR_NULL || (nestptr != NULL && (ptr = nestptr, nestptr = NULL, c = *(++ptr)) != CHAR_NULL)) && (c != CHAR_RIGHT_SQUARE_BRACKET || inescq)); /* Check for missing terminating ']' */ if (c == CHAR_NULL) { *errorcodeptr = ERR6; goto FAILED; } /* We will need an XCLASS if data has been placed in class_uchardata. In the second phase this is a sufficient test. However, in the pre-compile phase, class_uchardata gets emptied to prevent workspace overflow, so it only if the very last character in the class needs XCLASS will it contain anything at this point. For this reason, xclass gets set TRUE above when uchar_classdata is emptied, and that's why this code is the way it is here instead of just doing a test on class_uchardata below. */ #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 if (class_uchardata > class_uchardata_base) xclass = TRUE; #endif /* If this is the first thing in the branch, there can be no first char setting, whatever the repeat count. Any reqchar setting must remain unchanged after any kind of repeat. */ if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; zerofirstchar = firstchar; zerofirstcharflags = firstcharflags; zeroreqchar = reqchar; zeroreqcharflags = reqcharflags; /* If there are characters with values > 255, we have to compile an extended class, with its own opcode, unless there was a negated special such as \S in the class, and PCRE_UCP is not set, because in that case all characters > 255 are in the class, so any that were explicitly given as well can be ignored. If (when there are explicit characters > 255 that must be listed) there are no characters < 256, we can omit the bitmap in the actual compiled code. */ #ifdef SUPPORT_UTF if (xclass && (xclass_has_prop || !should_flip_negation || (options & PCRE_UCP) != 0)) #elif !defined COMPILE_PCRE8 if (xclass && (xclass_has_prop || !should_flip_negation)) #endif #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 { /* For non-UCP wide characters, in a non-negative class containing \S or similar (should_flip_negation is set), all characters greater than 255 must be in the class. */ if ( #if defined COMPILE_PCRE8 utf && #endif should_flip_negation && !negate_class && (options & PCRE_UCP) == 0) { *class_uchardata++ = XCL_RANGE; if (utf) /* Will always be utf in the 8-bit library */ { class_uchardata += PRIV(ord2utf)(0x100, class_uchardata); class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata); } else /* Can only happen for the 16-bit & 32-bit libraries */ { #if defined COMPILE_PCRE16 *class_uchardata++ = 0x100; *class_uchardata++ = 0xffffu; #elif defined COMPILE_PCRE32 *class_uchardata++ = 0x100; *class_uchardata++ = 0xffffffffu; #endif } } *class_uchardata++ = XCL_END; /* Marks the end of extra data */ *code++ = OP_XCLASS; code += LINK_SIZE; *code = negate_class? XCL_NOT:0; if (xclass_has_prop) *code |= XCL_HASPROP; /* If the map is required, move up the extra data to make room for it; otherwise just move the code pointer to the end of the extra data. */ if (class_has_8bitchar > 0) { *code++ |= XCL_MAP; memmove(code + (32 / sizeof(pcre_uchar)), code, IN_UCHARS(class_uchardata - code)); if (negate_class && !xclass_has_prop) for (c = 0; c < 32; c++) classbits[c] = ~classbits[c]; memcpy(code, classbits, 32); code = class_uchardata + (32 / sizeof(pcre_uchar)); } else code = class_uchardata; /* Now fill in the complete length of the item */ PUT(previous, 1, (int)(code - previous)); break; /* End of class handling */ } /* Even though any XCLASS list is now discarded, we must allow for its memory. */ if (lengthptr != NULL) *lengthptr += (int)(class_uchardata - class_uchardata_base); #endif /* If there are no characters > 255, or they are all to be included or excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the whole class was negated and whether there were negative specials such as \S (non-UCP) in the class. Then copy the 32-byte map into the code vector, negating it if necessary. */ *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS; if (lengthptr == NULL) /* Save time in the pre-compile phase */ { if (negate_class) for (c = 0; c < 32; c++) classbits[c] = ~classbits[c]; memcpy(code, classbits, 32); } code += 32 / sizeof(pcre_uchar); END_CLASS: break; /* ===================================================================*/ /* Various kinds of repeat; '{' is not necessarily a quantifier, but this has been tested above. */ case CHAR_LEFT_CURLY_BRACKET: if (!is_quantifier) goto NORMAL_CHAR; ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorcodeptr); if (*errorcodeptr != 0) goto FAILED; goto REPEAT; case CHAR_ASTERISK: repeat_min = 0; repeat_max = -1; goto REPEAT; case CHAR_PLUS: repeat_min = 1; repeat_max = -1; goto REPEAT; case CHAR_QUESTION_MARK: repeat_min = 0; repeat_max = 1; REPEAT: if (previous == NULL) { *errorcodeptr = ERR9; goto FAILED; } if (repeat_min == 0) { firstchar = zerofirstchar; /* Adjust for zero repeat */ firstcharflags = zerofirstcharflags; reqchar = zeroreqchar; /* Ditto */ reqcharflags = zeroreqcharflags; } /* Remember whether this is a variable length repeat */ reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY; op_type = 0; /* Default single-char op codes */ possessive_quantifier = FALSE; /* Default not possessive quantifier */ /* Save start of previous item, in case we have to move it up in order to insert something before it. */ tempcode = previous; /* Before checking for a possessive quantifier, we must skip over whitespace and comments in extended mode because Perl allows white space at this point. */ if ((options & PCRE_EXTENDED) != 0) { const pcre_uchar *p = ptr + 1; for (;;) { while (MAX_255(*p) && (cd->ctypes[*p] & ctype_space) != 0) p++; if (*p != CHAR_NUMBER_SIGN) break; p++; while (*p != CHAR_NULL) { if (IS_NEWLINE(p)) /* For non-fixed-length newline cases, */ { /* IS_NEWLINE sets cd->nllen. */ p += cd->nllen; break; } p++; #ifdef SUPPORT_UTF if (utf) FORWARDCHAR(p); #endif } /* Loop for comment characters */ } /* Loop for multiple comments */ ptr = p - 1; /* Character before the next significant one. */ } /* We also need to skip over (?# comments, which are not dependent on extended mode. */ if (ptr[1] == CHAR_LEFT_PARENTHESIS && ptr[2] == CHAR_QUESTION_MARK && ptr[3] == CHAR_NUMBER_SIGN) { ptr += 4; while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; if (*ptr == CHAR_NULL) { *errorcodeptr = ERR18; goto FAILED; } } /* If the next character is '+', we have a possessive quantifier. This implies greediness, whatever the setting of the PCRE_UNGREEDY option. If the next character is '?' this is a minimizing repeat, by default, but if PCRE_UNGREEDY is set, it works the other way round. We change the repeat type to the non-default. */ if (ptr[1] == CHAR_PLUS) { repeat_type = 0; /* Force greedy */ possessive_quantifier = TRUE; ptr++; } else if (ptr[1] == CHAR_QUESTION_MARK) { repeat_type = greedy_non_default; ptr++; } else repeat_type = greedy_default; /* If previous was a recursion call, wrap it in atomic brackets so that previous becomes the atomic group. All recursions were so wrapped in the past, but it no longer happens for non-repeated recursions. In fact, the repeated ones could be re-implemented independently so as not to need this, but for the moment we rely on the code for repeating groups. */ if (*previous == OP_RECURSE) { memmove(previous + 1 + LINK_SIZE, previous, IN_UCHARS(1 + LINK_SIZE)); *previous = OP_ONCE; PUT(previous, 1, 2 + 2*LINK_SIZE); previous[2 + 2*LINK_SIZE] = OP_KET; PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE); code += 2 + 2 * LINK_SIZE; length_prevgroup = 3 + 3*LINK_SIZE; /* When actually compiling, we need to check whether this was a forward reference, and if so, adjust the offset. */ if (lengthptr == NULL && cd->hwm >= cd->start_workspace + LINK_SIZE) { int offset = GET(cd->hwm, -LINK_SIZE); if (offset == previous + 1 - cd->start_code) PUT(cd->hwm, -LINK_SIZE, offset + 1 + LINK_SIZE); } } /* Now handle repetition for the different types of item. */ /* If previous was a character or negated character match, abolish the item and generate a repeat item instead. If a char item has a minimum of more than one, ensure that it is set in reqchar - it might not be if a sequence such as x{3} is the first thing in a branch because the x will have gone into firstchar instead. */ if (*previous == OP_CHAR || *previous == OP_CHARI || *previous == OP_NOT || *previous == OP_NOTI) { switch (*previous) { default: /* Make compiler happy. */ case OP_CHAR: op_type = OP_STAR - OP_STAR; break; case OP_CHARI: op_type = OP_STARI - OP_STAR; break; case OP_NOT: op_type = OP_NOTSTAR - OP_STAR; break; case OP_NOTI: op_type = OP_NOTSTARI - OP_STAR; break; } /* Deal with UTF characters that take up more than one character. It's easier to write this out separately than try to macrify it. Use c to hold the length of the character in bytes, plus UTF_LENGTH to flag that it's a length rather than a small character. */ #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && NOT_FIRSTCHAR(code[-1])) { pcre_uchar *lastchar = code - 1; BACKCHAR(lastchar); c = (int)(code - lastchar); /* Length of UTF-8 character */ memcpy(utf_chars, lastchar, IN_UCHARS(c)); /* Save the char */ c |= UTF_LENGTH; /* Flag c as a length */ } else #endif /* SUPPORT_UTF */ /* Handle the case of a single charater - either with no UTF support, or with UTF disabled, or for a single character UTF character. */ { c = code[-1]; if (*previous <= OP_CHARI && repeat_min > 1) { reqchar = c; reqcharflags = req_caseopt | cd->req_varyopt; } } goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ } /* If previous was a character type match (\d or similar), abolish it and create a suitable repeat item. The code is shared with single-character repeats by setting op_type to add a suitable offset into repeat_type. Note the the Unicode property types will be present only when SUPPORT_UCP is defined, but we don't wrap the little bits of code here because it just makes it horribly messy. */ else if (*previous < OP_EODN) { pcre_uchar *oldcode; int prop_type, prop_value; op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ c = *previous; OUTPUT_SINGLE_REPEAT: if (*previous == OP_PROP || *previous == OP_NOTPROP) { prop_type = previous[1]; prop_value = previous[2]; } else prop_type = prop_value = -1; oldcode = code; code = previous; /* Usually overwrite previous item */ /* If the maximum is zero then the minimum must also be zero; Perl allows this case, so we do too - by simply omitting the item altogether. */ if (repeat_max == 0) goto END_REPEAT; /* Combine the op_type with the repeat_type */ repeat_type += op_type; /* A minimum of zero is handled either as the special case * or ?, or as an UPTO, with the maximum given. */ if (repeat_min == 0) { if (repeat_max == -1) *code++ = OP_STAR + repeat_type; else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type; else { *code++ = OP_UPTO + repeat_type; PUT2INC(code, 0, repeat_max); } } /* A repeat minimum of 1 is optimized into some special cases. If the maximum is unlimited, we use OP_PLUS. Otherwise, the original item is left in place and, if the maximum is greater than 1, we use OP_UPTO with one less than the maximum. */ else if (repeat_min == 1) { if (repeat_max == -1) *code++ = OP_PLUS + repeat_type; else { code = oldcode; /* leave previous item in place */ if (repeat_max == 1) goto END_REPEAT; *code++ = OP_UPTO + repeat_type; PUT2INC(code, 0, repeat_max - 1); } } /* The case {n,n} is just an EXACT, while the general case {n,m} is handled as an EXACT followed by an UPTO. */ else { *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */ PUT2INC(code, 0, repeat_min); /* If the maximum is unlimited, insert an OP_STAR. Before doing so, we have to insert the character for the previous code. For a repeated Unicode property match, there are two extra bytes that define the required property. In UTF-8 mode, long characters have their length in c, with the UTF_LENGTH bit as a flag. */ if (repeat_max < 0) { #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && (c & UTF_LENGTH) != 0) { memcpy(code, utf_chars, IN_UCHARS(c & 7)); code += c & 7; } else #endif { *code++ = c; if (prop_type >= 0) { *code++ = prop_type; *code++ = prop_value; } } *code++ = OP_STAR + repeat_type; } /* Else insert an UPTO if the max is greater than the min, again preceded by the character, for the previously inserted code. If the UPTO is just for 1 instance, we can use QUERY instead. */ else if (repeat_max != repeat_min) { #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && (c & UTF_LENGTH) != 0) { memcpy(code, utf_chars, IN_UCHARS(c & 7)); code += c & 7; } else #endif *code++ = c; if (prop_type >= 0) { *code++ = prop_type; *code++ = prop_value; } repeat_max -= repeat_min; if (repeat_max == 1) { *code++ = OP_QUERY + repeat_type; } else { *code++ = OP_UPTO + repeat_type; PUT2INC(code, 0, repeat_max); } } } /* The character or character type itself comes last in all cases. */ #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && (c & UTF_LENGTH) != 0) { memcpy(code, utf_chars, IN_UCHARS(c & 7)); code += c & 7; } else #endif *code++ = c; /* For a repeated Unicode property match, there are two extra bytes that define the required property. */ #ifdef SUPPORT_UCP if (prop_type >= 0) { *code++ = prop_type; *code++ = prop_value; } #endif } /* If previous was a character class or a back reference, we put the repeat stuff after it, but just skip the item if the repeat was {0,0}. */ else if (*previous == OP_CLASS || *previous == OP_NCLASS || #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 *previous == OP_XCLASS || #endif *previous == OP_REF || *previous == OP_REFI || *previous == OP_DNREF || *previous == OP_DNREFI) { if (repeat_max == 0) { code = previous; goto END_REPEAT; } if (repeat_min == 0 && repeat_max == -1) *code++ = OP_CRSTAR + repeat_type; else if (repeat_min == 1 && repeat_max == -1) *code++ = OP_CRPLUS + repeat_type; else if (repeat_min == 0 && repeat_max == 1) *code++ = OP_CRQUERY + repeat_type; else { *code++ = OP_CRRANGE + repeat_type; PUT2INC(code, 0, repeat_min); if (repeat_max == -1) repeat_max = 0; /* 2-byte encoding for max */ PUT2INC(code, 0, repeat_max); } } /* If previous was a bracket group, we may have to replicate it in certain cases. Note that at this point we can encounter only the "basic" bracket opcodes such as BRA and CBRA, as this is the place where they get converted into the more special varieties such as BRAPOS and SBRA. A test for >= OP_ASSERT and <= OP_COND includes ASSERT, ASSERT_NOT, ASSERTBACK, ASSERTBACK_NOT, ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND. Originally, PCRE did not allow repetition of assertions, but now it does, for Perl compatibility. */ else if (*previous >= OP_ASSERT && *previous <= OP_COND) { register int i; int len = (int)(code - previous); size_t base_hwm_offset = item_hwm_offset; pcre_uchar *bralink = NULL; pcre_uchar *brazeroptr = NULL; /* Repeating a DEFINE group is pointless, but Perl allows the syntax, so we just ignore the repeat. */ if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_DEF) goto END_REPEAT; /* There is no sense in actually repeating assertions. The only potential use of repetition is in cases when the assertion is optional. Therefore, if the minimum is greater than zero, just ignore the repeat. If the maximum is not zero or one, set it to 1. */ if (*previous < OP_ONCE) /* Assertion */ { if (repeat_min > 0) goto END_REPEAT; if (repeat_max < 0 || repeat_max > 1) repeat_max = 1; } /* The case of a zero minimum is special because of the need to stick OP_BRAZERO in front of it, and because the group appears once in the data, whereas in other cases it appears the minimum number of times. For this reason, it is simplest to treat this case separately, as otherwise the code gets far too messy. There are several special subcases when the minimum is zero. */ if (repeat_min == 0) { /* If the maximum is also zero, we used to just omit the group from the output altogether, like this: ** if (repeat_max == 0) ** { ** code = previous; ** goto END_REPEAT; ** } However, that fails when a group or a subgroup within it is referenced as a subroutine from elsewhere in the pattern, so now we stick in OP_SKIPZERO in front of it so that it is skipped on execution. As we don't have a list of which groups are referenced, we cannot do this selectively. If the maximum is 1 or unlimited, we just have to stick in the BRAZERO and do no more at this point. However, we do need to adjust any OP_RECURSE calls inside the group that refer to the group itself or any internal or forward referenced group, because the offset is from the start of the whole regex. Temporarily terminate the pattern while doing this. */ if (repeat_max <= 1) /* Covers 0, 1, and unlimited */ { *code = OP_END; adjust_recurse(previous, 1, utf, cd, item_hwm_offset); memmove(previous + 1, previous, IN_UCHARS(len)); code++; if (repeat_max == 0) { *previous++ = OP_SKIPZERO; goto END_REPEAT; } brazeroptr = previous; /* Save for possessive optimizing */ *previous++ = OP_BRAZERO + repeat_type; } /* If the maximum is greater than 1 and limited, we have to replicate in a nested fashion, sticking OP_BRAZERO before each set of brackets. The first one has to be handled carefully because it's the original copy, which has to be moved up. The remainder can be handled by code that is common with the non-zero minimum case below. We have to adjust the value or repeat_max, since one less copy is required. Once again, we may have to adjust any OP_RECURSE calls inside the group. */ else { int offset; *code = OP_END; adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, item_hwm_offset); memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len)); code += 2 + LINK_SIZE; *previous++ = OP_BRAZERO + repeat_type; *previous++ = OP_BRA; /* We chain together the bracket offset fields that have to be filled in later when the ends of the brackets are reached. */ offset = (bralink == NULL)? 0 : (int)(previous - bralink); bralink = previous; PUTINC(previous, 0, offset); } repeat_max--; } /* If the minimum is greater than zero, replicate the group as many times as necessary, and adjust the maximum to the number of subsequent copies that we need. If we set a first char from the group, and didn't set a required char, copy the latter from the former. If there are any forward reference subroutine calls in the group, there will be entries on the workspace list; replicate these with an appropriate increment. */ else { if (repeat_min > 1) { /* In the pre-compile phase, we don't actually do the replication. We just adjust the length as if we had. Do some paranoid checks for potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit integer type when available, otherwise double. */ if (lengthptr != NULL) { int delta = (repeat_min - 1)*length_prevgroup; if ((INT64_OR_DOUBLE)(repeat_min - 1)* (INT64_OR_DOUBLE)length_prevgroup > (INT64_OR_DOUBLE)INT_MAX || OFLOW_MAX - *lengthptr < delta) { *errorcodeptr = ERR20; goto FAILED; } *lengthptr += delta; } /* This is compiling for real. If there is a set first byte for the group, and we have not yet set a "required byte", set it. Make sure there is enough workspace for copying forward references before doing the copy. */ else { if (groupsetfirstchar && reqcharflags < 0) { reqchar = firstchar; reqcharflags = firstcharflags; } for (i = 1; i < repeat_min; i++) { pcre_uchar *hc; size_t this_hwm_offset = cd->hwm - cd->start_workspace; memcpy(code, previous, IN_UCHARS(len)); while (cd->hwm > cd->start_workspace + cd->workspace_size - WORK_SIZE_SAFETY_MARGIN - (this_hwm_offset - base_hwm_offset)) { *errorcodeptr = expand_workspace(cd); if (*errorcodeptr != 0) goto FAILED; } for (hc = (pcre_uchar *)cd->start_workspace + base_hwm_offset; hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset; hc += LINK_SIZE) { PUT(cd->hwm, 0, GET(hc, 0) + len); cd->hwm += LINK_SIZE; } base_hwm_offset = this_hwm_offset; code += len; } } } if (repeat_max > 0) repeat_max -= repeat_min; } /* This code is common to both the zero and non-zero minimum cases. If the maximum is limited, it replicates the group in a nested fashion, remembering the bracket starts on a stack. In the case of a zero minimum, the first one was set up above. In all cases the repeat_max now specifies the number of additional copies needed. Again, we must remember to replicate entries on the forward reference list. */ if (repeat_max >= 0) { /* In the pre-compile phase, we don't actually do the replication. We just adjust the length as if we had. For each repetition we must add 1 to the length for BRAZERO and for all but the last repetition we must add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type is a 64-bit integer type when available, otherwise double. */ if (lengthptr != NULL && repeat_max > 0) { int delta = repeat_max * (length_prevgroup + 1 + 2 + 2*LINK_SIZE) - 2 - 2*LINK_SIZE; /* Last one doesn't nest */ if ((INT64_OR_DOUBLE)repeat_max * (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE) > (INT64_OR_DOUBLE)INT_MAX || OFLOW_MAX - *lengthptr < delta) { *errorcodeptr = ERR20; goto FAILED; } *lengthptr += delta; } /* This is compiling for real */ else for (i = repeat_max - 1; i >= 0; i--) { pcre_uchar *hc; size_t this_hwm_offset = cd->hwm - cd->start_workspace; *code++ = OP_BRAZERO + repeat_type; /* All but the final copy start a new nesting, maintaining the chain of brackets outstanding. */ if (i != 0) { int offset; *code++ = OP_BRA; offset = (bralink == NULL)? 0 : (int)(code - bralink); bralink = code; PUTINC(code, 0, offset); } memcpy(code, previous, IN_UCHARS(len)); /* Ensure there is enough workspace for forward references before copying them. */ while (cd->hwm > cd->start_workspace + cd->workspace_size - WORK_SIZE_SAFETY_MARGIN - (this_hwm_offset - base_hwm_offset)) { *errorcodeptr = expand_workspace(cd); if (*errorcodeptr != 0) goto FAILED; } for (hc = (pcre_uchar *)cd->start_workspace + base_hwm_offset; hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset; hc += LINK_SIZE) { PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1)); cd->hwm += LINK_SIZE; } base_hwm_offset = this_hwm_offset; code += len; } /* Now chain through the pending brackets, and fill in their length fields (which are holding the chain links pro tem). */ while (bralink != NULL) { int oldlinkoffset; int offset = (int)(code - bralink + 1); pcre_uchar *bra = code - offset; oldlinkoffset = GET(bra, 1); bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset; *code++ = OP_KET; PUTINC(code, 0, offset); PUT(bra, 1, offset); } } /* If the maximum is unlimited, set a repeater in the final copy. For ONCE brackets, that's all we need to do. However, possessively repeated ONCE brackets can be converted into non-capturing brackets, as the behaviour of (?:xx)++ is the same as (?>xx)++ and this saves having to deal with possessive ONCEs specially. Otherwise, when we are doing the actual compile phase, check to see whether this group is one that could match an empty string. If so, convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so that runtime checking can be done. [This check is also applied to ONCE groups at runtime, but in a different way.] Then, if the quantifier was possessive and the bracket is not a conditional, we convert the BRA code to the POS form, and the KET code to KETRPOS. (It turns out to be convenient at runtime to detect this kind of subpattern at both the start and at the end.) The use of special opcodes makes it possible to reduce greatly the stack usage in pcre_exec(). If the group is preceded by OP_BRAZERO, convert this to OP_BRAPOSZERO. Then, if the minimum number of matches is 1 or 0, cancel the possessive flag so that the default action below, of wrapping everything inside atomic brackets, does not happen. When the minimum is greater than 1, there will be earlier copies of the group, and so we still have to wrap the whole thing. */ else { pcre_uchar *ketcode = code - 1 - LINK_SIZE; pcre_uchar *bracode = ketcode - GET(ketcode, 1); /* Convert possessive ONCE brackets to non-capturing */ if ((*bracode == OP_ONCE || *bracode == OP_ONCE_NC) && possessive_quantifier) *bracode = OP_BRA; /* For non-possessive ONCE brackets, all we need to do is to set the KET. */ if (*bracode == OP_ONCE || *bracode == OP_ONCE_NC) *ketcode = OP_KETRMAX + repeat_type; /* Handle non-ONCE brackets and possessive ONCEs (which have been converted to non-capturing above). */ else { /* In the compile phase, check for empty string matching. */ if (lengthptr == NULL) { pcre_uchar *scode = bracode; do { if (could_be_empty_branch(scode, ketcode, utf, cd, NULL)) { *bracode += OP_SBRA - OP_BRA; break; } scode += GET(scode, 1); } while (*scode == OP_ALT); } /* A conditional group with only one branch has an implicit empty alternative branch. */ if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT) *bracode = OP_SCOND; /* Handle possessive quantifiers. */ if (possessive_quantifier) { /* For COND brackets, we wrap the whole thing in a possessively repeated non-capturing bracket, because we have not invented POS versions of the COND opcodes. Because we are moving code along, we must ensure that any pending recursive references are updated. */ if (*bracode == OP_COND || *bracode == OP_SCOND) { int nlen = (int)(code - bracode); *code = OP_END; adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, item_hwm_offset); memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen)); code += 1 + LINK_SIZE; nlen += 1 + LINK_SIZE; *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS; *code++ = OP_KETRPOS; PUTINC(code, 0, nlen); PUT(bracode, 1, nlen); } /* For non-COND brackets, we modify the BRA code and use KETRPOS. */ else { *bracode += 1; /* Switch to xxxPOS opcodes */ *ketcode = OP_KETRPOS; } /* If the minimum is zero, mark it as possessive, then unset the possessive flag when the minimum is 0 or 1. */ if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO; if (repeat_min < 2) possessive_quantifier = FALSE; } /* Non-possessive quantifier */ else *ketcode = OP_KETRMAX + repeat_type; } } } /* If previous is OP_FAIL, it was generated by an empty class [] in JavaScript mode. The other ways in which OP_FAIL can be generated, that is by (*FAIL) or (?!) set previous to NULL, which gives a "nothing to repeat" error above. We can just ignore the repeat in JS case. */ else if (*previous == OP_FAIL) goto END_REPEAT; /* Else there's some kind of shambles */ else { *errorcodeptr = ERR11; goto FAILED; } /* If the character following a repeat is '+', possessive_quantifier is TRUE. For some opcodes, there are special alternative opcodes for this case. For anything else, we wrap the entire repeated item inside OP_ONCE brackets. Logically, the '+' notation is just syntactic sugar, taken from Sun's Java package, but the special opcodes can optimize it. Some (but not all) possessively repeated subpatterns have already been completely handled in the code just above. For them, possessive_quantifier is always FALSE at this stage. Note that the repeated item starts at tempcode, not at previous, which might be the first part of a string whose (former) last char we repeated. */ if (possessive_quantifier) { int len; /* Possessifying an EXACT quantifier has no effect, so we can ignore it. However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6}, {5,}, or {5,10}). We skip over an EXACT item; if the length of what remains is greater than zero, there's a further opcode that can be handled. If not, do nothing, leaving the EXACT alone. */ switch(*tempcode) { case OP_TYPEEXACT: tempcode += PRIV(OP_lengths)[*tempcode] + ((tempcode[1 + IMM2_SIZE] == OP_PROP || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0); break; /* CHAR opcodes are used for exacts whose count is 1. */ case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: case OP_EXACT: case OP_EXACTI: case OP_NOTEXACT: case OP_NOTEXACTI: tempcode += PRIV(OP_lengths)[*tempcode]; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(tempcode[-1])) tempcode += GET_EXTRALEN(tempcode[-1]); #endif break; /* For the class opcodes, the repeat operator appears at the end; adjust tempcode to point to it. */ case OP_CLASS: case OP_NCLASS: tempcode += 1 + 32/sizeof(pcre_uchar); break; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: tempcode += GET(tempcode, 1); break; #endif } /* If tempcode is equal to code (which points to the end of the repeated item), it means we have skipped an EXACT item but there is no following QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In all other cases, tempcode will be pointing to the repeat opcode, and will be less than code, so the value of len will be greater than 0. */ len = (int)(code - tempcode); if (len > 0) { unsigned int repcode = *tempcode; /* There is a table for possessifying opcodes, all of which are less than OP_CALLOUT. A zero entry means there is no possessified version. */ if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0) *tempcode = opcode_possessify[repcode]; /* For opcode without a special possessified version, wrap the item in ONCE brackets. Because we are moving code along, we must ensure that any pending recursive references are updated. */ else { *code = OP_END; adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset); memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len)); code += 1 + LINK_SIZE; len += 1 + LINK_SIZE; tempcode[0] = OP_ONCE; *code++ = OP_KET; PUTINC(code, 0, len); PUT(tempcode, 1, len); } } #ifdef NEVER if (len > 0) switch (*tempcode) { case OP_STAR: *tempcode = OP_POSSTAR; break; case OP_PLUS: *tempcode = OP_POSPLUS; break; case OP_QUERY: *tempcode = OP_POSQUERY; break; case OP_UPTO: *tempcode = OP_POSUPTO; break; case OP_STARI: *tempcode = OP_POSSTARI; break; case OP_PLUSI: *tempcode = OP_POSPLUSI; break; case OP_QUERYI: *tempcode = OP_POSQUERYI; break; case OP_UPTOI: *tempcode = OP_POSUPTOI; break; case OP_NOTSTAR: *tempcode = OP_NOTPOSSTAR; break; case OP_NOTPLUS: *tempcode = OP_NOTPOSPLUS; break; case OP_NOTQUERY: *tempcode = OP_NOTPOSQUERY; break; case OP_NOTUPTO: *tempcode = OP_NOTPOSUPTO; break; case OP_NOTSTARI: *tempcode = OP_NOTPOSSTARI; break; case OP_NOTPLUSI: *tempcode = OP_NOTPOSPLUSI; break; case OP_NOTQUERYI: *tempcode = OP_NOTPOSQUERYI; break; case OP_NOTUPTOI: *tempcode = OP_NOTPOSUPTOI; break; case OP_TYPESTAR: *tempcode = OP_TYPEPOSSTAR; break; case OP_TYPEPLUS: *tempcode = OP_TYPEPOSPLUS; break; case OP_TYPEQUERY: *tempcode = OP_TYPEPOSQUERY; break; case OP_TYPEUPTO: *tempcode = OP_TYPEPOSUPTO; break; case OP_CRSTAR: *tempcode = OP_CRPOSSTAR; break; case OP_CRPLUS: *tempcode = OP_CRPOSPLUS; break; case OP_CRQUERY: *tempcode = OP_CRPOSQUERY; break; case OP_CRRANGE: *tempcode = OP_CRPOSRANGE; break; /* Because we are moving code along, we must ensure that any pending recursive references are updated. */ default: *code = OP_END; adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset); memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len)); code += 1 + LINK_SIZE; len += 1 + LINK_SIZE; tempcode[0] = OP_ONCE; *code++ = OP_KET; PUTINC(code, 0, len); PUT(tempcode, 1, len); break; } #endif } /* In all case we no longer have a previous item. We also set the "follows varying string" flag for subsequently encountered reqchars if it isn't already set and we have just passed a varying length item. */ END_REPEAT: previous = NULL; cd->req_varyopt |= reqvary; break; /* ===================================================================*/ /* Start of nested parenthesized sub-expression, or comment or lookahead or lookbehind or option setting or condition or all the other extended parenthesis forms. */ case CHAR_LEFT_PARENTHESIS: ptr++; /* Now deal with various "verbs" that can be introduced by '*'. */ if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':' || (MAX_255(ptr[1]) && ((cd->ctypes[ptr[1]] & ctype_letter) != 0)))) { int i, namelen; int arglen = 0; const char *vn = verbnames; const pcre_uchar *name = ptr + 1; const pcre_uchar *arg = NULL; previous = NULL; ptr++; while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_letter) != 0) ptr++; namelen = (int)(ptr - name); /* It appears that Perl allows any characters whatsoever, other than a closing parenthesis, to appear in arguments, so we no longer insist on letters, digits, and underscores. */ if (*ptr == CHAR_COLON) { arg = ++ptr; while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++; arglen = (int)(ptr - arg); if ((unsigned int)arglen > MAX_MARK) { *errorcodeptr = ERR75; goto FAILED; } } if (*ptr != CHAR_RIGHT_PARENTHESIS) { *errorcodeptr = ERR60; goto FAILED; } /* Scan the table of verb names */ for (i = 0; i < verbcount; i++) { if (namelen == verbs[i].len && STRNCMP_UC_C8(name, vn, namelen) == 0) { int setverb; /* Check for open captures before ACCEPT and convert it to ASSERT_ACCEPT if in an assertion. */ if (verbs[i].op == OP_ACCEPT) { open_capitem *oc; if (arglen != 0) { *errorcodeptr = ERR59; goto FAILED; } cd->had_accept = TRUE; for (oc = cd->open_caps; oc != NULL; oc = oc->next) { if (lengthptr != NULL) { #ifdef COMPILE_PCRE8 *lengthptr += 1 + IMM2_SIZE; #elif defined COMPILE_PCRE16 *lengthptr += 2 + IMM2_SIZE; #elif defined COMPILE_PCRE32 *lengthptr += 4 + IMM2_SIZE; #endif } else { *code++ = OP_CLOSE; PUT2INC(code, 0, oc->number); } } setverb = *code++ = (cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT; /* Do not set firstchar after *ACCEPT */ if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; } /* Handle other cases with/without an argument */ else if (arglen == 0) { if (verbs[i].op < 0) /* Argument is mandatory */ { *errorcodeptr = ERR66; goto FAILED; } setverb = *code++ = verbs[i].op; } else { if (verbs[i].op_arg < 0) /* Argument is forbidden */ { *errorcodeptr = ERR59; goto FAILED; } setverb = *code++ = verbs[i].op_arg; if (lengthptr != NULL) /* In pass 1 just add in the length */ { /* to avoid potential workspace */ *lengthptr += arglen; /* overflow. */ *code++ = 0; } else { *code++ = arglen; memcpy(code, arg, IN_UCHARS(arglen)); code += arglen; } *code++ = 0; } switch (setverb) { case OP_THEN: case OP_THEN_ARG: cd->external_flags |= PCRE_HASTHEN; break; case OP_PRUNE: case OP_PRUNE_ARG: case OP_SKIP: case OP_SKIP_ARG: cd->had_pruneorskip = TRUE; break; } break; /* Found verb, exit loop */ } vn += verbs[i].len + 1; } if (i < verbcount) continue; /* Successfully handled a verb */ *errorcodeptr = ERR60; /* Verb not recognized */ goto FAILED; } /* Initialize for "real" parentheses */ newoptions = options; skipbytes = 0; bravalue = OP_CBRA; item_hwm_offset = cd->hwm - cd->start_workspace; reset_bracount = FALSE; /* Deal with the extended parentheses; all are introduced by '?', and the appearance of any of them means that this is not a capturing group. */ if (*ptr == CHAR_QUESTION_MARK) { int i, set, unset, namelen; int *optset; const pcre_uchar *name; pcre_uchar *slot; switch (*(++ptr)) { /* ------------------------------------------------------------ */ case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */ reset_bracount = TRUE; cd->dupgroups = TRUE; /* Record (?| encountered */ /* Fall through */ /* ------------------------------------------------------------ */ case CHAR_COLON: /* Non-capturing bracket */ bravalue = OP_BRA; ptr++; break; /* ------------------------------------------------------------ */ case CHAR_LEFT_PARENTHESIS: bravalue = OP_COND; /* Conditional group */ tempptr = ptr; /* A condition can be an assertion, a number (referring to a numbered group's having been set), a name (referring to a named group), or 'R', referring to recursion. R and R&name are also permitted for recursion tests. There are ways of testing a named group: (?(name)) is used by Python; Perl 5.10 onwards uses (?() or (?('name')). There is one unfortunate ambiguity, caused by history. 'R' can be the recursive thing or the name 'R' (and similarly for 'R' followed by digits). We look for a name first; if not found, we try the other case. For compatibility with auto-callouts, we allow a callout to be specified before a condition that is an assertion. First, check for the syntax of a callout; if found, adjust the temporary pointer that is used to check for an assertion condition. That's all that is needed! */ if (ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_C) { for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break; if (ptr[i] == CHAR_RIGHT_PARENTHESIS) tempptr += i + 1; /* tempptr should now be pointing to the opening parenthesis of the assertion condition. */ if (*tempptr != CHAR_LEFT_PARENTHESIS) { *errorcodeptr = ERR28; goto FAILED; } } /* For conditions that are assertions, check the syntax, and then exit the switch. This will take control down to where bracketed groups, including assertions, are processed. */ if (tempptr[1] == CHAR_QUESTION_MARK && (tempptr[2] == CHAR_EQUALS_SIGN || tempptr[2] == CHAR_EXCLAMATION_MARK || (tempptr[2] == CHAR_LESS_THAN_SIGN && (tempptr[3] == CHAR_EQUALS_SIGN || tempptr[3] == CHAR_EXCLAMATION_MARK)))) { cd->iscondassert = TRUE; break; } /* Other conditions use OP_CREF/OP_DNCREF/OP_RREF/OP_DNRREF, and all need to skip at least 1+IMM2_SIZE bytes at the start of the group. */ code[1+LINK_SIZE] = OP_CREF; skipbytes = 1+IMM2_SIZE; refsign = -1; /* => not a number */ namelen = -1; /* => not a name; must set to avoid warning */ name = NULL; /* Always set to avoid warning */ recno = 0; /* Always set to avoid warning */ /* Check for a test for recursion in a named group. */ ptr++; if (*ptr == CHAR_R && ptr[1] == CHAR_AMPERSAND) { terminator = -1; ptr += 2; code[1+LINK_SIZE] = OP_RREF; /* Change the type of test */ } /* Check for a test for a named group's having been set, using the Perl syntax (?() or (?('name'), and also allow for the original PCRE syntax of (?(name) or for (?(+n), (?(-n), and just (?(n). */ else if (*ptr == CHAR_LESS_THAN_SIGN) { terminator = CHAR_GREATER_THAN_SIGN; ptr++; } else if (*ptr == CHAR_APOSTROPHE) { terminator = CHAR_APOSTROPHE; ptr++; } else { terminator = CHAR_NULL; if (*ptr == CHAR_MINUS || *ptr == CHAR_PLUS) refsign = *ptr++; else if (IS_DIGIT(*ptr)) refsign = 0; } /* Handle a number */ if (refsign >= 0) { while (IS_DIGIT(*ptr)) { if (recno > INT_MAX / 10 - 1) /* Integer overflow */ { while (IS_DIGIT(*ptr)) ptr++; *errorcodeptr = ERR61; goto FAILED; } recno = recno * 10 + (int)(*ptr - CHAR_0); ptr++; } } /* Otherwise we expect to read a name; anything else is an error. When a name is one of a number of duplicates, a different opcode is used and it needs more memory. Unfortunately we cannot tell whether a name is a duplicate in the first pass, so we have to allow for more memory. */ else { if (IS_DIGIT(*ptr)) { *errorcodeptr = ERR84; goto FAILED; } if (!MAX_255(*ptr) || (cd->ctypes[*ptr] & ctype_word) == 0) { *errorcodeptr = ERR28; /* Assertion expected */ goto FAILED; } name = ptr++; while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) { ptr++; } namelen = (int)(ptr - name); if (lengthptr != NULL) skipbytes += IMM2_SIZE; } /* Check the terminator */ if ((terminator > 0 && *ptr++ != (pcre_uchar)terminator) || *ptr++ != CHAR_RIGHT_PARENTHESIS) { ptr--; /* Error offset */ *errorcodeptr = ERR26; /* Malformed number or name */ goto FAILED; } /* Do no further checking in the pre-compile phase. */ if (lengthptr != NULL) break; /* In the real compile we do the work of looking for the actual reference. If refsign is not negative, it means we have a number in recno. */ if (refsign >= 0) { if (recno <= 0) { *errorcodeptr = ERR35; goto FAILED; } if (refsign != 0) recno = (refsign == CHAR_MINUS)? cd->bracount - recno + 1 : recno + cd->bracount; if (recno <= 0 || recno > cd->final_bracount) { *errorcodeptr = ERR15; goto FAILED; } PUT2(code, 2+LINK_SIZE, recno); if (recno > cd->top_backref) cd->top_backref = recno; break; } /* Otherwise look for the name. */ slot = cd->name_table; for (i = 0; i < cd->names_found; i++) { if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) == 0 && slot[IMM2_SIZE+namelen] == 0) break; slot += cd->name_entry_size; } /* Found the named subpattern. If the name is duplicated, add one to the opcode to change CREF/RREF into DNCREF/DNRREF and insert appropriate data values. Otherwise, just insert the unique subpattern number. */ if (i < cd->names_found) { int offset = i++; int count = 1; recno = GET2(slot, 0); /* Number from first found */ if (recno > cd->top_backref) cd->top_backref = recno; for (; i < cd->names_found; i++) { slot += cd->name_entry_size; if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) != 0 || (slot+IMM2_SIZE)[namelen] != 0) break; count++; } if (count > 1) { PUT2(code, 2+LINK_SIZE, offset); PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count); skipbytes += IMM2_SIZE; code[1+LINK_SIZE]++; } else /* Not a duplicated name */ { PUT2(code, 2+LINK_SIZE, recno); } } /* If terminator == CHAR_NULL it means that the name followed directly after the opening parenthesis [e.g. (?(abc)...] and in this case there are some further alternatives to try. For the cases where terminator != CHAR_NULL [things like (?(... or (?('name')... or (?(R&name)... ] we have now checked all the possibilities, so give an error. */ else if (terminator != CHAR_NULL) { *errorcodeptr = ERR15; goto FAILED; } /* Check for (?(R) for recursion. Allow digits after R to specify a specific group number. */ else if (*name == CHAR_R) { recno = 0; for (i = 1; i < namelen; i++) { if (!IS_DIGIT(name[i])) { *errorcodeptr = ERR15; goto FAILED; } if (recno > INT_MAX / 10 - 1) /* Integer overflow */ { *errorcodeptr = ERR61; goto FAILED; } recno = recno * 10 + name[i] - CHAR_0; } if (recno == 0) recno = RREF_ANY; code[1+LINK_SIZE] = OP_RREF; /* Change test type */ PUT2(code, 2+LINK_SIZE, recno); } /* Similarly, check for the (?(DEFINE) "condition", which is always false. */ else if (namelen == 6 && STRNCMP_UC_C8(name, STRING_DEFINE, 6) == 0) { code[1+LINK_SIZE] = OP_DEF; skipbytes = 1; } /* Reference to an unidentified subpattern. */ else { *errorcodeptr = ERR15; goto FAILED; } break; /* ------------------------------------------------------------ */ case CHAR_EQUALS_SIGN: /* Positive lookahead */ bravalue = OP_ASSERT; cd->assert_depth += 1; ptr++; break; /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird thing to do, but Perl allows all assertions to be quantified, and when they contain capturing parentheses there may be a potential use for this feature. Not that that applies to a quantified (?!) but we allow it for uniformity. */ /* ------------------------------------------------------------ */ case CHAR_EXCLAMATION_MARK: /* Negative lookahead */ ptr++; if (*ptr == CHAR_RIGHT_PARENTHESIS && ptr[1] != CHAR_ASTERISK && ptr[1] != CHAR_PLUS && ptr[1] != CHAR_QUESTION_MARK && (ptr[1] != CHAR_LEFT_CURLY_BRACKET || !is_counted_repeat(ptr+2))) { *code++ = OP_FAIL; previous = NULL; continue; } bravalue = OP_ASSERT_NOT; cd->assert_depth += 1; break; /* ------------------------------------------------------------ */ case CHAR_LESS_THAN_SIGN: /* Lookbehind or named define */ switch (ptr[1]) { case CHAR_EQUALS_SIGN: /* Positive lookbehind */ bravalue = OP_ASSERTBACK; cd->assert_depth += 1; ptr += 2; break; case CHAR_EXCLAMATION_MARK: /* Negative lookbehind */ bravalue = OP_ASSERTBACK_NOT; cd->assert_depth += 1; ptr += 2; break; default: /* Could be name define, else bad */ if (MAX_255(ptr[1]) && (cd->ctypes[ptr[1]] & ctype_word) != 0) goto DEFINE_NAME; ptr++; /* Correct offset for error */ *errorcodeptr = ERR24; goto FAILED; } break; /* ------------------------------------------------------------ */ case CHAR_GREATER_THAN_SIGN: /* One-time brackets */ bravalue = OP_ONCE; ptr++; break; /* ------------------------------------------------------------ */ case CHAR_C: /* Callout - may be followed by digits; */ previous_callout = code; /* Save for later completion */ after_manual_callout = 1; /* Skip one item before completing */ *code++ = OP_CALLOUT; { int n = 0; ptr++; while(IS_DIGIT(*ptr)) { n = n * 10 + *ptr++ - CHAR_0; if (n > 255) { *errorcodeptr = ERR38; goto FAILED; } } if (*ptr != CHAR_RIGHT_PARENTHESIS) { *errorcodeptr = ERR39; goto FAILED; } *code++ = n; PUT(code, 0, (int)(ptr - cd->start_pattern + 1)); /* Pattern offset */ PUT(code, LINK_SIZE, 0); /* Default length */ code += 2 * LINK_SIZE; } previous = NULL; continue; /* ------------------------------------------------------------ */ case CHAR_P: /* Python-style named subpattern handling */ if (*(++ptr) == CHAR_EQUALS_SIGN || *ptr == CHAR_GREATER_THAN_SIGN) /* Reference or recursion */ { is_recurse = *ptr == CHAR_GREATER_THAN_SIGN; terminator = CHAR_RIGHT_PARENTHESIS; goto NAMED_REF_OR_RECURSE; } else if (*ptr != CHAR_LESS_THAN_SIGN) /* Test for Python-style defn */ { *errorcodeptr = ERR41; goto FAILED; } /* Fall through to handle (?P< as (?< is handled */ /* ------------------------------------------------------------ */ DEFINE_NAME: /* Come here from (?< handling */ case CHAR_APOSTROPHE: terminator = (*ptr == CHAR_LESS_THAN_SIGN)? CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; name = ++ptr; if (IS_DIGIT(*ptr)) { *errorcodeptr = ERR84; /* Group name must start with non-digit */ goto FAILED; } while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++; namelen = (int)(ptr - name); /* In the pre-compile phase, do a syntax check, remember the longest name, and then remember the group in a vector, expanding it if necessary. Duplicates for the same number are skipped; other duplicates are checked for validity. In the actual compile, there is nothing to do. */ if (lengthptr != NULL) { named_group *ng; pcre_uint32 number = cd->bracount + 1; if (*ptr != (pcre_uchar)terminator) { *errorcodeptr = ERR42; goto FAILED; } if (cd->names_found >= MAX_NAME_COUNT) { *errorcodeptr = ERR49; goto FAILED; } if (namelen + IMM2_SIZE + 1 > cd->name_entry_size) { cd->name_entry_size = namelen + IMM2_SIZE + 1; if (namelen > MAX_NAME_SIZE) { *errorcodeptr = ERR48; goto FAILED; } } /* Scan the list to check for duplicates. For duplicate names, if the number is the same, break the loop, which causes the name to be discarded; otherwise, if DUPNAMES is not set, give an error. If it is set, allow the name with a different number, but continue scanning in case this is a duplicate with the same number. For non-duplicate names, give an error if the number is duplicated. */ ng = cd->named_groups; for (i = 0; i < cd->names_found; i++, ng++) { if (namelen == ng->length && STRNCMP_UC_UC(name, ng->name, namelen) == 0) { if (ng->number == number) break; if ((options & PCRE_DUPNAMES) == 0) { *errorcodeptr = ERR43; goto FAILED; } cd->dupnames = TRUE; /* Duplicate names exist */ } else if (ng->number == number) { *errorcodeptr = ERR65; goto FAILED; } } if (i >= cd->names_found) /* Not a duplicate with same number */ { /* Increase the list size if necessary */ if (cd->names_found >= cd->named_group_list_size) { int newsize = cd->named_group_list_size * 2; named_group *newspace = (PUBL(malloc)) (newsize * sizeof(named_group)); if (newspace == NULL) { *errorcodeptr = ERR21; goto FAILED; } memcpy(newspace, cd->named_groups, cd->named_group_list_size * sizeof(named_group)); if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE) (PUBL(free))((void *)cd->named_groups); cd->named_groups = newspace; cd->named_group_list_size = newsize; } cd->named_groups[cd->names_found].name = name; cd->named_groups[cd->names_found].length = namelen; cd->named_groups[cd->names_found].number = number; cd->names_found++; } } ptr++; /* Move past > or ' in both passes. */ goto NUMBERED_GROUP; /* ------------------------------------------------------------ */ case CHAR_AMPERSAND: /* Perl recursion/subroutine syntax */ terminator = CHAR_RIGHT_PARENTHESIS; is_recurse = TRUE; /* Fall through */ /* We come here from the Python syntax above that handles both references (?P=name) and recursion (?P>name), as well as falling through from the Perl recursion syntax (?&name). We also come here from the Perl \k or \k'name' back reference syntax and the \k{name} .NET syntax, and the Oniguruma \g<...> and \g'...' subroutine syntax. */ NAMED_REF_OR_RECURSE: name = ++ptr; if (IS_DIGIT(*ptr)) { *errorcodeptr = ERR84; /* Group name must start with non-digit */ goto FAILED; } while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++; namelen = (int)(ptr - name); /* In the pre-compile phase, do a syntax check. We used to just set a dummy reference number, because it was not used in the first pass. However, with the change of recursive back references to be atomic, we have to look for the number so that this state can be identified, as otherwise the incorrect length is computed. If it's not a backwards reference, the dummy number will do. */ if (lengthptr != NULL) { named_group *ng; recno = 0; if (namelen == 0) { *errorcodeptr = ERR62; goto FAILED; } if (*ptr != (pcre_uchar)terminator) { *errorcodeptr = ERR42; goto FAILED; } if (namelen > MAX_NAME_SIZE) { *errorcodeptr = ERR48; goto FAILED; } /* Count named back references. */ if (!is_recurse) cd->namedrefcount++; /* We have to allow for a named reference to a duplicated name (this cannot be determined until the second pass). This needs an extra 16-bit data item. */ *lengthptr += IMM2_SIZE; /* If this is a forward reference and we are within a (?|...) group, the reference may end up as the number of a group which we are currently inside, that is, it could be a recursive reference. In the real compile this will be picked up and the reference wrapped with OP_ONCE to make it atomic, so we must space in case this occurs. */ /* In fact, this can happen for a non-forward reference because another group with the same number might be created later. This issue is fixed "properly" in PCRE2. As PCRE1 is now in maintenance only mode, we finesse the bug by allowing more memory always. */ *lengthptr += 4 + 4*LINK_SIZE; /* It is even worse than that. The current reference may be to an existing named group with a different number (so apparently not recursive) but which later on is also attached to a group with the current number. This can only happen if $(| has been previous encountered. In that case, we allow yet more memory, just in case. (Again, this is fixed "properly" in PCRE2. */ if (cd->dupgroups) *lengthptr += 4 + 4*LINK_SIZE; /* Otherwise, check for recursion here. The name table does not exist in the first pass; instead we must scan the list of names encountered so far in order to get the number. If the name is not found, leave the value of recno as 0 for a forward reference. */ /* This patch (removing "else") fixes a problem when a reference is to multiple identically named nested groups from within the nest. Once again, it is not the "proper" fix, and it results in an over-allocation of memory. */ /* else */ { ng = cd->named_groups; for (i = 0; i < cd->names_found; i++, ng++) { if (namelen == ng->length && STRNCMP_UC_UC(name, ng->name, namelen) == 0) { open_capitem *oc; recno = ng->number; if (is_recurse) break; for (oc = cd->open_caps; oc != NULL; oc = oc->next) { if (oc->number == recno) { oc->flag = TRUE; break; } } } } } } /* In the real compile, search the name table. We check the name first, and then check that we have reached the end of the name in the table. That way, if the name is longer than any in the table, the comparison will fail without reading beyond the table entry. */ else { slot = cd->name_table; for (i = 0; i < cd->names_found; i++) { if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) == 0 && slot[IMM2_SIZE+namelen] == 0) break; slot += cd->name_entry_size; } if (i < cd->names_found) { recno = GET2(slot, 0); } else { *errorcodeptr = ERR15; goto FAILED; } } /* In both phases, for recursions, we can now go to the code than handles numerical recursion. */ if (is_recurse) goto HANDLE_RECURSION; /* In the second pass we must see if the name is duplicated. If so, we generate a different opcode. */ if (lengthptr == NULL && cd->dupnames) { int count = 1; unsigned int index = i; pcre_uchar *cslot = slot + cd->name_entry_size; for (i++; i < cd->names_found; i++) { if (STRCMP_UC_UC(slot + IMM2_SIZE, cslot + IMM2_SIZE) != 0) break; count++; cslot += cd->name_entry_size; } if (count > 1) { if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; previous = code; item_hwm_offset = cd->hwm - cd->start_workspace; *code++ = ((options & PCRE_CASELESS) != 0)? OP_DNREFI : OP_DNREF; PUT2INC(code, 0, index); PUT2INC(code, 0, count); /* Process each potentially referenced group. */ for (; slot < cslot; slot += cd->name_entry_size) { open_capitem *oc; recno = GET2(slot, 0); cd->backref_map |= (recno < 32)? (1U << recno) : 1; if (recno > cd->top_backref) cd->top_backref = recno; /* Check to see if this back reference is recursive, that it, it is inside the group that it references. A flag is set so that the group can be made atomic. */ for (oc = cd->open_caps; oc != NULL; oc = oc->next) { if (oc->number == recno) { oc->flag = TRUE; break; } } } continue; /* End of back ref handling */ } } /* First pass, or a non-duplicated name. */ goto HANDLE_REFERENCE; /* ------------------------------------------------------------ */ case CHAR_R: /* Recursion, same as (?0) */ recno = 0; if (*(++ptr) != CHAR_RIGHT_PARENTHESIS) { *errorcodeptr = ERR29; goto FAILED; } goto HANDLE_RECURSION; /* ------------------------------------------------------------ */ case CHAR_MINUS: case CHAR_PLUS: /* Recursion or subroutine */ case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9: { const pcre_uchar *called; terminator = CHAR_RIGHT_PARENTHESIS; /* Come here from the \g<...> and \g'...' code (Oniguruma compatibility). However, the syntax has been checked to ensure that the ... are a (signed) number, so that neither ERR63 nor ERR29 will be called on this path, nor with the jump to OTHER_CHAR_AFTER_QUERY ever be taken. */ HANDLE_NUMERICAL_RECURSION: if ((refsign = *ptr) == CHAR_PLUS) { ptr++; if (!IS_DIGIT(*ptr)) { *errorcodeptr = ERR63; goto FAILED; } } else if (refsign == CHAR_MINUS) { if (!IS_DIGIT(ptr[1])) goto OTHER_CHAR_AFTER_QUERY; ptr++; } recno = 0; while(IS_DIGIT(*ptr)) { if (recno > INT_MAX / 10 - 1) /* Integer overflow */ { while (IS_DIGIT(*ptr)) ptr++; *errorcodeptr = ERR61; goto FAILED; } recno = recno * 10 + *ptr++ - CHAR_0; } if (*ptr != (pcre_uchar)terminator) { *errorcodeptr = ERR29; goto FAILED; } if (refsign == CHAR_MINUS) { if (recno == 0) { *errorcodeptr = ERR58; goto FAILED; } recno = cd->bracount - recno + 1; if (recno <= 0) { *errorcodeptr = ERR15; goto FAILED; } } else if (refsign == CHAR_PLUS) { if (recno == 0) { *errorcodeptr = ERR58; goto FAILED; } recno += cd->bracount; } /* Come here from code above that handles a named recursion */ HANDLE_RECURSION: previous = code; item_hwm_offset = cd->hwm - cd->start_workspace; called = cd->start_code; /* When we are actually compiling, find the bracket that is being referenced. Temporarily end the regex in case it doesn't exist before this point. If we end up with a forward reference, first check that the bracket does occur later so we can give the error (and position) now. Then remember this forward reference in the workspace so it can be filled in at the end. */ if (lengthptr == NULL) { *code = OP_END; if (recno != 0) called = PRIV(find_bracket)(cd->start_code, utf, recno); /* Forward reference */ if (called == NULL) { if (recno > cd->final_bracount) { *errorcodeptr = ERR15; goto FAILED; } /* Fudge the value of "called" so that when it is inserted as an offset below, what it actually inserted is the reference number of the group. Then remember the forward reference. */ called = cd->start_code + recno; if (cd->hwm >= cd->start_workspace + cd->workspace_size - WORK_SIZE_SAFETY_MARGIN) { *errorcodeptr = expand_workspace(cd); if (*errorcodeptr != 0) goto FAILED; } PUTINC(cd->hwm, 0, (int)(code + 1 - cd->start_code)); } /* If not a forward reference, and the subpattern is still open, this is a recursive call. We check to see if this is a left recursion that could loop for ever, and diagnose that case. We must not, however, do this check if we are in a conditional subpattern because the condition might be testing for recursion in a pattern such as /(?(R)a+|(?R)b)/, which is perfectly valid. Forever loops are also detected at runtime, so those that occur in conditional subpatterns will be picked up then. */ else if (GET(called, 1) == 0 && cond_depth <= 0 && could_be_empty(called, code, bcptr, utf, cd)) { *errorcodeptr = ERR40; goto FAILED; } } /* Insert the recursion/subroutine item. It does not have a set first character (relevant if it is repeated, because it will then be wrapped with ONCE brackets). */ *code = OP_RECURSE; PUT(code, 1, (int)(called - cd->start_code)); code += 1 + LINK_SIZE; groupsetfirstchar = FALSE; } /* Can't determine a first byte now */ if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE; zerofirstchar = firstchar; zerofirstcharflags = firstcharflags; continue; /* ------------------------------------------------------------ */ default: /* Other characters: check option setting */ OTHER_CHAR_AFTER_QUERY: set = unset = 0; optset = &set; while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON) { switch (*ptr++) { case CHAR_MINUS: optset = &unset; break; case CHAR_J: /* Record that it changed in the external options */ *optset |= PCRE_DUPNAMES; cd->external_flags |= PCRE_JCHANGED; break; case CHAR_i: *optset |= PCRE_CASELESS; break; case CHAR_m: *optset |= PCRE_MULTILINE; break; case CHAR_s: *optset |= PCRE_DOTALL; break; case CHAR_x: *optset |= PCRE_EXTENDED; break; case CHAR_U: *optset |= PCRE_UNGREEDY; break; case CHAR_X: *optset |= PCRE_EXTRA; break; default: *errorcodeptr = ERR12; ptr--; /* Correct the offset */ goto FAILED; } } /* Set up the changed option bits, but don't change anything yet. */ newoptions = (options | set) & (~unset); /* If the options ended with ')' this is not the start of a nested group with option changes, so the options change at this level. If we are not at the pattern start, reset the greedy defaults and the case value for firstchar and reqchar. */ if (*ptr == CHAR_RIGHT_PARENTHESIS) { greedy_default = ((newoptions & PCRE_UNGREEDY) != 0); greedy_non_default = greedy_default ^ 1; req_caseopt = ((newoptions & PCRE_CASELESS) != 0)? REQ_CASELESS:0; /* Change options at this level, and pass them back for use in subsequent branches. */ *optionsptr = options = newoptions; previous = NULL; /* This item can't be repeated */ continue; /* It is complete */ } /* If the options ended with ':' we are heading into a nested group with possible change of options. Such groups are non-capturing and are not assertions of any kind. All we need to do is skip over the ':'; the newoptions value is handled below. */ bravalue = OP_BRA; ptr++; } /* End of switch for character following (? */ } /* End of (? handling */ /* Opening parenthesis not followed by '*' or '?'. If PCRE_NO_AUTO_CAPTURE is set, all unadorned brackets become non-capturing and behave like (?:...) brackets. */ else if ((options & PCRE_NO_AUTO_CAPTURE) != 0) { bravalue = OP_BRA; } /* Else we have a capturing group. */ else { NUMBERED_GROUP: cd->bracount += 1; PUT2(code, 1+LINK_SIZE, cd->bracount); skipbytes = IMM2_SIZE; } /* Process nested bracketed regex. First check for parentheses nested too deeply. */ if ((cd->parens_depth += 1) > PARENS_NEST_LIMIT) { *errorcodeptr = ERR82; goto FAILED; } /* All assertions used not to be repeatable, but this was changed for Perl compatibility. All kinds can now be repeated except for assertions that are conditions (Perl also forbids these to be repeated). We copy code into a non-register variable (tempcode) in order to be able to pass its address because some compilers complain otherwise. At the start of a conditional group whose condition is an assertion, cd->iscondassert is set. We unset it here so as to allow assertions later in the group to be quantified. */ if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT && cd->iscondassert) { previous = NULL; cd->iscondassert = FALSE; } else { previous = code; item_hwm_offset = cd->hwm - cd->start_workspace; } *code = bravalue; tempcode = code; tempreqvary = cd->req_varyopt; /* Save value before bracket */ tempbracount = cd->bracount; /* Save value before bracket */ length_prevgroup = 0; /* Initialize for pre-compile phase */ if (!compile_regex( newoptions, /* The complete new option state */ &tempcode, /* Where to put code (updated) */ &ptr, /* Input pointer (updated) */ errorcodeptr, /* Where to put an error message */ (bravalue == OP_ASSERTBACK || bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */ reset_bracount, /* True if (?| group */ skipbytes, /* Skip over bracket number */ cond_depth + ((bravalue == OP_COND)?1:0), /* Depth of condition subpatterns */ &subfirstchar, /* For possible first char */ &subfirstcharflags, &subreqchar, /* For possible last char */ &subreqcharflags, bcptr, /* Current branch chain */ cd, /* Tables block */ (lengthptr == NULL)? NULL : /* Actual compile phase */ &length_prevgroup /* Pre-compile phase */ )) goto FAILED; cd->parens_depth -= 1; /* If this was an atomic group and there are no capturing groups within it, generate OP_ONCE_NC instead of OP_ONCE. */ if (bravalue == OP_ONCE && cd->bracount <= tempbracount) *code = OP_ONCE_NC; if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT) cd->assert_depth -= 1; /* At the end of compiling, code is still pointing to the start of the group, while tempcode has been updated to point past the end of the group. The pattern pointer (ptr) is on the bracket. If this is a conditional bracket, check that there are no more than two branches in the group, or just one if it's a DEFINE group. We do this in the real compile phase, not in the pre-pass, where the whole group may not be available. */ if (bravalue == OP_COND && lengthptr == NULL) { pcre_uchar *tc = code; int condcount = 0; do { condcount++; tc += GET(tc,1); } while (*tc != OP_KET); /* A DEFINE group is never obeyed inline (the "condition" is always false). It must have only one branch. */ if (code[LINK_SIZE+1] == OP_DEF) { if (condcount > 1) { *errorcodeptr = ERR54; goto FAILED; } bravalue = OP_DEF; /* Just a flag to suppress char handling below */ } /* A "normal" conditional group. If there is just one branch, we must not make use of its firstchar or reqchar, because this is equivalent to an empty second branch. */ else { if (condcount > 2) { *errorcodeptr = ERR27; goto FAILED; } if (condcount == 1) subfirstcharflags = subreqcharflags = REQ_NONE; } } /* Error if hit end of pattern */ if (*ptr != CHAR_RIGHT_PARENTHESIS) { *errorcodeptr = ERR14; goto FAILED; } /* In the pre-compile phase, update the length by the length of the group, less the brackets at either end. Then reduce the compiled code to just a set of non-capturing brackets so that it doesn't use much memory if it is duplicated by a quantifier.*/ if (lengthptr != NULL) { if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE) { *errorcodeptr = ERR20; goto FAILED; } *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE; code++; /* This already contains bravalue */ PUTINC(code, 0, 1 + LINK_SIZE); *code++ = OP_KET; PUTINC(code, 0, 1 + LINK_SIZE); break; /* No need to waste time with special character handling */ } /* Otherwise update the main code pointer to the end of the group. */ code = tempcode; /* For a DEFINE group, required and first character settings are not relevant. */ if (bravalue == OP_DEF) break; /* Handle updating of the required and first characters for other types of group. Update for normal brackets of all kinds, and conditions with two branches (see code above). If the bracket is followed by a quantifier with zero repeat, we have to back off. Hence the definition of zeroreqchar and zerofirstchar outside the main loop so that they can be accessed for the back off. */ zeroreqchar = reqchar; zeroreqcharflags = reqcharflags; zerofirstchar = firstchar; zerofirstcharflags = firstcharflags; groupsetfirstchar = FALSE; if (bravalue >= OP_ONCE) { /* If we have not yet set a firstchar in this branch, take it from the subpattern, remembering that it was set here so that a repeat of more than one can replicate it as reqchar if necessary. If the subpattern has no firstchar, set "none" for the whole branch. In both cases, a zero repeat forces firstchar to "none". */ if (firstcharflags == REQ_UNSET) { if (subfirstcharflags >= 0) { firstchar = subfirstchar; firstcharflags = subfirstcharflags; groupsetfirstchar = TRUE; } else firstcharflags = REQ_NONE; zerofirstcharflags = REQ_NONE; } /* If firstchar was previously set, convert the subpattern's firstchar into reqchar if there wasn't one, using the vary flag that was in existence beforehand. */ else if (subfirstcharflags >= 0 && subreqcharflags < 0) { subreqchar = subfirstchar; subreqcharflags = subfirstcharflags | tempreqvary; } /* If the subpattern set a required byte (or set a first byte that isn't really the first byte - see above), set it. */ if (subreqcharflags >= 0) { reqchar = subreqchar; reqcharflags = subreqcharflags; } } /* For a forward assertion, we take the reqchar, if set, provided that the group has also set a first char. This can be helpful if the pattern that follows the assertion doesn't set a different char. For example, it's useful for /(?=abcde).+/. We can't set firstchar for an assertion, however because it leads to incorrect effect for patterns such as /(?=a)a.+/ when the "real" "a" would then become a reqchar instead of a firstchar. This is overcome by a scan at the end if there's no firstchar, looking for an asserted first char. */ else if (bravalue == OP_ASSERT && subreqcharflags >= 0 && subfirstcharflags >= 0) { reqchar = subreqchar; reqcharflags = subreqcharflags; } break; /* End of processing '(' */ /* ===================================================================*/ /* Handle metasequences introduced by \. For ones like \d, the ESC_ values are arranged to be the negation of the corresponding OP_values in the default case when PCRE_UCP is not set. For the back references, the values are negative the reference number. Only back references and those types that consume a character may be repeated. We can test for values between ESC_b and ESC_Z for the latter; this may have to change if any new ones are ever created. */ case CHAR_BACKSLASH: tempptr = ptr; escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options, FALSE); if (*errorcodeptr != 0) goto FAILED; if (escape == 0) /* The escape coded a single character */ c = ec; else { /* For metasequences that actually match a character, we disable the setting of a first character if it hasn't already been set. */ if (firstcharflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z) firstcharflags = REQ_NONE; /* Set values to reset to if this is followed by a zero repeat. */ zerofirstchar = firstchar; zerofirstcharflags = firstcharflags; zeroreqchar = reqchar; zeroreqcharflags = reqcharflags; /* \g or \g'name' is a subroutine call by name and \g or \g'n' is a subroutine call by number (Oniguruma syntax). In fact, the value ESC_g is returned only for these cases. So we don't need to check for < or ' if the value is ESC_g. For the Perl syntax \g{n} the value is -n, and for the Perl syntax \g{name} the result is ESC_k (as that is a synonym for a named back reference). */ if (escape == ESC_g) { const pcre_uchar *p; pcre_uint32 cf; item_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */ terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE; /* These two statements stop the compiler for warning about possibly unset variables caused by the jump to HANDLE_NUMERICAL_RECURSION. In fact, because we do the check for a number below, the paths that would actually be in error are never taken. */ skipbytes = 0; reset_bracount = FALSE; /* If it's not a signed or unsigned number, treat it as a name. */ cf = ptr[1]; if (cf != CHAR_PLUS && cf != CHAR_MINUS && !IS_DIGIT(cf)) { is_recurse = TRUE; goto NAMED_REF_OR_RECURSE; } /* Signed or unsigned number (cf = ptr[1]) is known to be plus or minus or a digit. */ p = ptr + 2; while (IS_DIGIT(*p)) p++; if (*p != (pcre_uchar)terminator) { *errorcodeptr = ERR57; goto FAILED; } ptr++; goto HANDLE_NUMERICAL_RECURSION; } /* \k or \k'name' is a back reference by name (Perl syntax). We also support \k{name} (.NET syntax). */ if (escape == ESC_k) { if ((ptr[1] != CHAR_LESS_THAN_SIGN && ptr[1] != CHAR_APOSTROPHE && ptr[1] != CHAR_LEFT_CURLY_BRACKET)) { *errorcodeptr = ERR69; goto FAILED; } is_recurse = FALSE; terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)? CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)? CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET; goto NAMED_REF_OR_RECURSE; } /* Back references are handled specially; must disable firstchar if not set to cope with cases like (?=(\w+))\1: which would otherwise set ':' later. */ if (escape < 0) { open_capitem *oc; recno = -escape; /* Come here from named backref handling when the reference is to a single group (i.e. not to a duplicated name. */ HANDLE_REFERENCE: if (firstcharflags == REQ_UNSET) zerofirstcharflags = firstcharflags = REQ_NONE; previous = code; item_hwm_offset = cd->hwm - cd->start_workspace; *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF; PUT2INC(code, 0, recno); cd->backref_map |= (recno < 32)? (1U << recno) : 1; if (recno > cd->top_backref) cd->top_backref = recno; /* Check to see if this back reference is recursive, that it, it is inside the group that it references. A flag is set so that the group can be made atomic. */ for (oc = cd->open_caps; oc != NULL; oc = oc->next) { if (oc->number == recno) { oc->flag = TRUE; break; } } } /* So are Unicode property matches, if supported. */ #ifdef SUPPORT_UCP else if (escape == ESC_P || escape == ESC_p) { BOOL negated; unsigned int ptype = 0, pdata = 0; if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr)) goto FAILED; previous = code; item_hwm_offset = cd->hwm - cd->start_workspace; *code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP; *code++ = ptype; *code++ = pdata; } #else /* If Unicode properties are not supported, \X, \P, and \p are not allowed. */ else if (escape == ESC_X || escape == ESC_P || escape == ESC_p) { *errorcodeptr = ERR45; goto FAILED; } #endif /* For the rest (including \X when Unicode properties are supported), we can obtain the OP value by negating the escape value in the default situation when PCRE_UCP is not set. When it *is* set, we substitute Unicode property tests. Note that \b and \B do a one-character lookbehind, and \A also behaves as if it does. */ else { if ((escape == ESC_b || escape == ESC_B || escape == ESC_A) && cd->max_lookbehind == 0) cd->max_lookbehind = 1; #ifdef SUPPORT_UCP if (escape >= ESC_DU && escape <= ESC_wu) { nestptr = ptr + 1; /* Where to resume */ ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */ } else #endif /* In non-UTF-8 mode, we turn \C into OP_ALLANY instead of OP_ANYBYTE so that it works in DFA mode and in lookbehinds. */ { previous = (escape > ESC_b && escape < ESC_Z)? code : NULL; item_hwm_offset = cd->hwm - cd->start_workspace; *code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape; } } continue; } /* We have a data character whose value is in c. In UTF-8 mode it may have a value > 127. We set its representation in the length/buffer, and then handle it as a data character. */ #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR) mclength = PRIV(ord2utf)(c, mcbuffer); else #endif { mcbuffer[0] = c; mclength = 1; } goto ONE_CHAR; /* ===================================================================*/ /* Handle a literal character. It is guaranteed not to be whitespace or # when the extended flag is set. If we are in a UTF mode, it may be a multi-unit literal character. */ default: NORMAL_CHAR: mclength = 1; mcbuffer[0] = c; #ifdef SUPPORT_UTF if (utf && HAS_EXTRALEN(c)) ACROSSCHAR(TRUE, ptr[1], mcbuffer[mclength++] = *(++ptr)); #endif /* At this point we have the character's bytes in mcbuffer, and the length in mclength. When not in UTF-8 mode, the length is always 1. */ ONE_CHAR: previous = code; item_hwm_offset = cd->hwm - cd->start_workspace; /* For caseless UTF-8 mode when UCP support is available, check whether this character has more than one other case. If so, generate a special OP_PROP item instead of OP_CHARI. */ #ifdef SUPPORT_UCP if (utf && (options & PCRE_CASELESS) != 0) { GETCHAR(c, mcbuffer); if ((c = UCD_CASESET(c)) != 0) { *code++ = OP_PROP; *code++ = PT_CLIST; *code++ = c; if (firstcharflags == REQ_UNSET) firstcharflags = zerofirstcharflags = REQ_NONE; break; } } #endif /* Caseful matches, or not one of the multicase characters. */ *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARI : OP_CHAR; for (c = 0; c < mclength; c++) *code++ = mcbuffer[c]; /* Remember if \r or \n were seen */ if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF; /* Set the first and required bytes appropriately. If no previous first byte, set it from this character, but revert to none on a zero repeat. Otherwise, leave the firstchar value alone, and don't change it on a zero repeat. */ if (firstcharflags == REQ_UNSET) { zerofirstcharflags = REQ_NONE; zeroreqchar = reqchar; zeroreqcharflags = reqcharflags; /* If the character is more than one byte long, we can set firstchar only if it is not to be matched caselessly. */ if (mclength == 1 || req_caseopt == 0) { firstchar = mcbuffer[0]; firstcharflags = req_caseopt; if (mclength != 1) { reqchar = code[-1]; reqcharflags = cd->req_varyopt; } } else firstcharflags = reqcharflags = REQ_NONE; } /* firstchar was previously set; we can set reqchar only if the length is 1 or the matching is caseful. */ else { zerofirstchar = firstchar; zerofirstcharflags = firstcharflags; zeroreqchar = reqchar; zeroreqcharflags = reqcharflags; if (mclength == 1 || req_caseopt == 0) { reqchar = code[-1]; reqcharflags = req_caseopt | cd->req_varyopt; } } break; /* End of literal character handling */ } } /* end of big loop */ /* Control never reaches here by falling through, only by a goto for all the error states. Pass back the position in the pattern so that it can be displayed to the user for diagnosing the error. */ FAILED: *ptrptr = ptr; return FALSE; } /************************************************* * Compile sequence of alternatives * *************************************************/ /* On entry, ptr is pointing past the bracket character, but on return it points to the closing bracket, or vertical bar, or end of string. The code variable is pointing at the byte into which the BRA operator has been stored. This function is used during the pre-compile phase when we are trying to find out the amount of memory needed, as well as during the real compile phase. The value of lengthptr distinguishes the two phases. Arguments: options option bits, including any changes for this subpattern codeptr -> the address of the current code pointer ptrptr -> the address of the current pattern pointer errorcodeptr -> pointer to error code variable lookbehind TRUE if this is a lookbehind assertion reset_bracount TRUE to reset the count for each branch skipbytes skip this many bytes at start (for brackets and OP_COND) cond_depth depth of nesting for conditional subpatterns firstcharptr place to put the first required character firstcharflagsptr place to put the first character flags, or a negative number reqcharptr place to put the last required character reqcharflagsptr place to put the last required character flags, or a negative number bcptr pointer to the chain of currently open branches cd points to the data block with tables pointers etc. lengthptr NULL during the real compile phase points to length accumulator during pre-compile phase Returns: TRUE on success */ static BOOL compile_regex(int options, pcre_uchar **codeptr, const pcre_uchar **ptrptr, int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, int skipbytes, int cond_depth, pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr, pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr, branch_chain *bcptr, compile_data *cd, int *lengthptr) { const pcre_uchar *ptr = *ptrptr; pcre_uchar *code = *codeptr; pcre_uchar *last_branch = code; pcre_uchar *start_bracket = code; pcre_uchar *reverse_count = NULL; open_capitem capitem; int capnumber = 0; pcre_uint32 firstchar, reqchar; pcre_int32 firstcharflags, reqcharflags; pcre_uint32 branchfirstchar, branchreqchar; pcre_int32 branchfirstcharflags, branchreqcharflags; int length; unsigned int orig_bracount; unsigned int max_bracount; branch_chain bc; size_t save_hwm_offset; /* If set, call the external function that checks for stack availability. */ if (PUBL(stack_guard) != NULL && PUBL(stack_guard)()) { *errorcodeptr= ERR85; return FALSE; } /* Miscellaneous initialization */ bc.outer = bcptr; bc.current_branch = code; firstchar = reqchar = 0; firstcharflags = reqcharflags = REQ_UNSET; save_hwm_offset = cd->hwm - cd->start_workspace; /* Accumulate the length for use in the pre-compile phase. Start with the length of the BRA and KET and any extra bytes that are required at the beginning. We accumulate in a local variable to save frequent testing of lenthptr for NULL. We cannot do this by looking at the value of code at the start and end of each alternative, because compiled items are discarded during the pre-compile phase so that the work space is not exceeded. */ length = 2 + 2*LINK_SIZE + skipbytes; /* WARNING: If the above line is changed for any reason, you must also change the code that abstracts option settings at the start of the pattern and makes them global. It tests the value of length for (2 + 2*LINK_SIZE) in the pre-compile phase to find out whether anything has yet been compiled or not. */ /* If this is a capturing subpattern, add to the chain of open capturing items so that we can detect them if (*ACCEPT) is encountered. This is also used to detect groups that contain recursive back references to themselves. Note that only OP_CBRA need be tested here; changing this opcode to one of its variants, e.g. OP_SCBRAPOS, happens later, after the group has been compiled. */ if (*code == OP_CBRA) { capnumber = GET2(code, 1 + LINK_SIZE); capitem.number = capnumber; capitem.next = cd->open_caps; capitem.flag = FALSE; cd->open_caps = &capitem; } /* Offset is set zero to mark that this bracket is still open */ PUT(code, 1, 0); code += 1 + LINK_SIZE + skipbytes; /* Loop for each alternative branch */ orig_bracount = max_bracount = cd->bracount; for (;;) { /* For a (?| group, reset the capturing bracket count so that each branch uses the same numbers. */ if (reset_bracount) cd->bracount = orig_bracount; /* Set up dummy OP_REVERSE if lookbehind assertion */ if (lookbehind) { *code++ = OP_REVERSE; reverse_count = code; PUTINC(code, 0, 0); length += 1 + LINK_SIZE; } /* Now compile the branch; in the pre-compile phase its length gets added into the length. */ if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstchar, &branchfirstcharflags, &branchreqchar, &branchreqcharflags, &bc, cond_depth, cd, (lengthptr == NULL)? NULL : &length)) { *ptrptr = ptr; return FALSE; } /* Keep the highest bracket count in case (?| was used and some branch has fewer than the rest. */ if (cd->bracount > max_bracount) max_bracount = cd->bracount; /* In the real compile phase, there is some post-processing to be done. */ if (lengthptr == NULL) { /* If this is the first branch, the firstchar and reqchar values for the branch become the values for the regex. */ if (*last_branch != OP_ALT) { firstchar = branchfirstchar; firstcharflags = branchfirstcharflags; reqchar = branchreqchar; reqcharflags = branchreqcharflags; } /* If this is not the first branch, the first char and reqchar have to match the values from all the previous branches, except that if the previous value for reqchar didn't have REQ_VARY set, it can still match, and we set REQ_VARY for the regex. */ else { /* If we previously had a firstchar, but it doesn't match the new branch, we have to abandon the firstchar for the regex, but if there was previously no reqchar, it takes on the value of the old firstchar. */ if (firstcharflags >= 0 && (firstcharflags != branchfirstcharflags || firstchar != branchfirstchar)) { if (reqcharflags < 0) { reqchar = firstchar; reqcharflags = firstcharflags; } firstcharflags = REQ_NONE; } /* If we (now or from before) have no firstchar, a firstchar from the branch becomes a reqchar if there isn't a branch reqchar. */ if (firstcharflags < 0 && branchfirstcharflags >= 0 && branchreqcharflags < 0) { branchreqchar = branchfirstchar; branchreqcharflags = branchfirstcharflags; } /* Now ensure that the reqchars match */ if (((reqcharflags & ~REQ_VARY) != (branchreqcharflags & ~REQ_VARY)) || reqchar != branchreqchar) reqcharflags = REQ_NONE; else { reqchar = branchreqchar; reqcharflags |= branchreqcharflags; /* To "or" REQ_VARY */ } } /* If lookbehind, check that this branch matches a fixed-length string, and put the length into the OP_REVERSE item. Temporarily mark the end of the branch with OP_END. If the branch contains OP_RECURSE, the result is -3 because there may be forward references that we can't check here. Set a flag to cause another lookbehind check at the end. Why not do it all at the end? Because common, erroneous checks are picked up here and the offset of the problem can be shown. */ if (lookbehind) { int fixed_length; *code = OP_END; fixed_length = find_fixedlength(last_branch, (options & PCRE_UTF8) != 0, FALSE, cd, NULL); DPRINTF(("fixed length = %d\n", fixed_length)); if (fixed_length == -3) { cd->check_lookbehind = TRUE; } else if (fixed_length < 0) { *errorcodeptr = (fixed_length == -2)? ERR36 : (fixed_length == -4)? ERR70: ERR25; *ptrptr = ptr; return FALSE; } else { if (fixed_length > cd->max_lookbehind) cd->max_lookbehind = fixed_length; PUT(reverse_count, 0, fixed_length); } } } /* Reached end of expression, either ')' or end of pattern. In the real compile phase, go back through the alternative branches and reverse the chain of offsets, with the field in the BRA item now becoming an offset to the first alternative. If there are no alternatives, it points to the end of the group. The length in the terminating ket is always the length of the whole bracketed item. Return leaving the pointer at the terminating char. */ if (*ptr != CHAR_VERTICAL_LINE) { if (lengthptr == NULL) { int branch_length = (int)(code - last_branch); do { int prev_length = GET(last_branch, 1); PUT(last_branch, 1, branch_length); branch_length = prev_length; last_branch -= branch_length; } while (branch_length > 0); } /* Fill in the ket */ *code = OP_KET; PUT(code, 1, (int)(code - start_bracket)); code += 1 + LINK_SIZE; /* If it was a capturing subpattern, check to see if it contained any recursive back references. If so, we must wrap it in atomic brackets. Because we are moving code along, we must ensure that any pending recursive references are updated. In any event, remove the block from the chain. */ if (capnumber > 0) { if (cd->open_caps->flag) { *code = OP_END; adjust_recurse(start_bracket, 1 + LINK_SIZE, (options & PCRE_UTF8) != 0, cd, save_hwm_offset); memmove(start_bracket + 1 + LINK_SIZE, start_bracket, IN_UCHARS(code - start_bracket)); *start_bracket = OP_ONCE; code += 1 + LINK_SIZE; PUT(start_bracket, 1, (int)(code - start_bracket)); *code = OP_KET; PUT(code, 1, (int)(code - start_bracket)); code += 1 + LINK_SIZE; length += 2 + 2*LINK_SIZE; } cd->open_caps = cd->open_caps->next; } /* Retain the highest bracket number, in case resetting was used. */ cd->bracount = max_bracount; /* Set values to pass back */ *codeptr = code; *ptrptr = ptr; *firstcharptr = firstchar; *firstcharflagsptr = firstcharflags; *reqcharptr = reqchar; *reqcharflagsptr = reqcharflags; if (lengthptr != NULL) { if (OFLOW_MAX - *lengthptr < length) { *errorcodeptr = ERR20; return FALSE; } *lengthptr += length; } return TRUE; } /* Another branch follows. In the pre-compile phase, we can move the code pointer back to where it was for the start of the first branch. (That is, pretend that each branch is the only one.) In the real compile phase, insert an ALT node. Its length field points back to the previous branch while the bracket remains open. At the end the chain is reversed. It's done like this so that the start of the bracket has a zero offset until it is closed, making it possible to detect recursion. */ if (lengthptr != NULL) { code = *codeptr + 1 + LINK_SIZE + skipbytes; length += 1 + LINK_SIZE; } else { *code = OP_ALT; PUT(code, 1, (int)(code - last_branch)); bc.current_branch = last_branch = code; code += 1 + LINK_SIZE; } ptr++; } /* Control never reaches here */ } /************************************************* * Check for anchored expression * *************************************************/ /* Try to find out if this is an anchored regular expression. Consider each alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then it's anchored. However, if this is a multiline pattern, then only OP_SOD will be found, because ^ generates OP_CIRCM in that mode. We can also consider a regex to be anchored if OP_SOM starts all its branches. This is the code for \G, which means "match at start of match position, taking into account the match offset". A branch is also implicitly anchored if it starts with .* and DOTALL is set, because that will try the rest of the pattern at all possible matching points, so there is no point trying again.... er .... .... except when the .* appears inside capturing parentheses, and there is a subsequent back reference to those parentheses. We haven't enough information to catch that case precisely. At first, the best we could do was to detect when .* was in capturing brackets and the highest back reference was greater than or equal to that level. However, by keeping a bitmap of the first 31 back references, we can catch some of the more common cases more precisely. ... A second exception is when the .* appears inside an atomic group, because this prevents the number of characters it matches from being adjusted. Arguments: code points to start of expression (the bracket) bracket_map a bitmap of which brackets we are inside while testing; this handles up to substring 31; after that we just have to take the less precise approach cd points to the compile data block atomcount atomic group level Returns: TRUE or FALSE */ static BOOL is_anchored(register const pcre_uchar *code, unsigned int bracket_map, compile_data *cd, int atomcount) { do { const pcre_uchar *scode = first_significant_code( code + PRIV(OP_lengths)[*code], FALSE); register int op = *scode; /* Non-capturing brackets */ if (op == OP_BRA || op == OP_BRAPOS || op == OP_SBRA || op == OP_SBRAPOS) { if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE; } /* Capturing brackets */ else if (op == OP_CBRA || op == OP_CBRAPOS || op == OP_SCBRA || op == OP_SCBRAPOS) { int n = GET2(scode, 1+LINK_SIZE); int new_map = bracket_map | ((n < 32)? (1U << n) : 1); if (!is_anchored(scode, new_map, cd, atomcount)) return FALSE; } /* Positive forward assertion */ else if (op == OP_ASSERT) { if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE; } /* Condition; not anchored if no second branch */ else if (op == OP_COND) { if (scode[GET(scode,1)] != OP_ALT) return FALSE; if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE; } /* Atomic groups */ else if (op == OP_ONCE || op == OP_ONCE_NC) { if (!is_anchored(scode, bracket_map, cd, atomcount + 1)) return FALSE; } /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and it isn't in brackets that are or may be referenced or inside an atomic group. */ else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)) { if (scode[1] != OP_ALLANY || (bracket_map & cd->backref_map) != 0 || atomcount > 0 || cd->had_pruneorskip) return FALSE; } /* Check for explicit anchoring */ else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE; code += GET(code, 1); } while (*code == OP_ALT); /* Loop for each alternative */ return TRUE; } /************************************************* * Check for starting with ^ or .* * *************************************************/ /* This is called to find out if every branch starts with ^ or .* so that "first char" processing can be done to speed things up in multiline matching and for non-DOTALL patterns that start with .* (which must start at the beginning or after \n). As in the case of is_anchored() (see above), we have to take account of back references to capturing brackets that contain .* because in that case we can't make the assumption. Also, the appearance of .* inside atomic brackets or in an assertion, or in a pattern that contains *PRUNE or *SKIP does not count, because once again the assumption no longer holds. Arguments: code points to start of expression (the bracket) bracket_map a bitmap of which brackets we are inside while testing; this handles up to substring 31; after that we just have to take the less precise approach cd points to the compile data atomcount atomic group level inassert TRUE if in an assertion Returns: TRUE or FALSE */ static BOOL is_startline(const pcre_uchar *code, unsigned int bracket_map, compile_data *cd, int atomcount, BOOL inassert) { do { const pcre_uchar *scode = first_significant_code( code + PRIV(OP_lengths)[*code], FALSE); register int op = *scode; /* If we are at the start of a conditional assertion group, *both* the conditional assertion *and* what follows the condition must satisfy the test for start of line. Other kinds of condition fail. Note that there may be an auto-callout at the start of a condition. */ if (op == OP_COND) { scode += 1 + LINK_SIZE; if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT]; switch (*scode) { case OP_CREF: case OP_DNCREF: case OP_RREF: case OP_DNRREF: case OP_DEF: case OP_FAIL: return FALSE; default: /* Assertion */ if (!is_startline(scode, bracket_map, cd, atomcount, TRUE)) return FALSE; do scode += GET(scode, 1); while (*scode == OP_ALT); scode += 1 + LINK_SIZE; break; } scode = first_significant_code(scode, FALSE); op = *scode; } /* Non-capturing brackets */ if (op == OP_BRA || op == OP_BRAPOS || op == OP_SBRA || op == OP_SBRAPOS) { if (!is_startline(scode, bracket_map, cd, atomcount, inassert)) return FALSE; } /* Capturing brackets */ else if (op == OP_CBRA || op == OP_CBRAPOS || op == OP_SCBRA || op == OP_SCBRAPOS) { int n = GET2(scode, 1+LINK_SIZE); int new_map = bracket_map | ((n < 32)? (1U << n) : 1); if (!is_startline(scode, new_map, cd, atomcount, inassert)) return FALSE; } /* Positive forward assertions */ else if (op == OP_ASSERT) { if (!is_startline(scode, bracket_map, cd, atomcount, TRUE)) return FALSE; } /* Atomic brackets */ else if (op == OP_ONCE || op == OP_ONCE_NC) { if (!is_startline(scode, bracket_map, cd, atomcount + 1, inassert)) return FALSE; } /* .* means "start at start or after \n" if it isn't in atomic brackets or brackets that may be referenced or an assertion, as long as the pattern does not contain *PRUNE or *SKIP, because these break the feature. Consider, for example, /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e. not at the start of a line. */ else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR) { if (scode[1] != OP_ANY || (bracket_map & cd->backref_map) != 0 || atomcount > 0 || cd->had_pruneorskip || inassert) return FALSE; } /* Check for explicit circumflex; anything else gives a FALSE result. Note in particular that this includes atomic brackets OP_ONCE and OP_ONCE_NC because the number of characters matched by .* cannot be adjusted inside them. */ else if (op != OP_CIRC && op != OP_CIRCM) return FALSE; /* Move on to the next alternative */ code += GET(code, 1); } while (*code == OP_ALT); /* Loop for each alternative */ return TRUE; } /************************************************* * Check for asserted fixed first char * *************************************************/ /* During compilation, the "first char" settings from forward assertions are discarded, because they can cause conflicts with actual literals that follow. However, if we end up without a first char setting for an unanchored pattern, it is worth scanning the regex to see if there is an initial asserted first char. If all branches start with the same asserted char, or with a non-conditional bracket all of whose alternatives start with the same asserted char (recurse ad lib), then we return that char, with the flags set to zero or REQ_CASELESS; otherwise return zero with REQ_NONE in the flags. Arguments: code points to start of expression (the bracket) flags points to the first char flags, or to REQ_NONE inassert TRUE if in an assertion Returns: the fixed first char, or 0 with REQ_NONE in flags */ static pcre_uint32 find_firstassertedchar(const pcre_uchar *code, pcre_int32 *flags, BOOL inassert) { register pcre_uint32 c = 0; int cflags = REQ_NONE; *flags = REQ_NONE; do { pcre_uint32 d; int dflags; int xl = (*code == OP_CBRA || *code == OP_SCBRA || *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0; const pcre_uchar *scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE); register pcre_uchar op = *scode; switch(op) { default: return 0; case OP_BRA: case OP_BRAPOS: case OP_CBRA: case OP_SCBRA: case OP_CBRAPOS: case OP_SCBRAPOS: case OP_ASSERT: case OP_ONCE: case OP_ONCE_NC: d = find_firstassertedchar(scode, &dflags, op == OP_ASSERT); if (dflags < 0) return 0; if (cflags < 0) { c = d; cflags = dflags; } else if (c != d || cflags != dflags) return 0; break; case OP_EXACT: scode += IMM2_SIZE; /* Fall through */ case OP_CHAR: case OP_PLUS: case OP_MINPLUS: case OP_POSPLUS: if (!inassert) return 0; if (cflags < 0) { c = scode[1]; cflags = 0; } else if (c != scode[1]) return 0; break; case OP_EXACTI: scode += IMM2_SIZE; /* Fall through */ case OP_CHARI: case OP_PLUSI: case OP_MINPLUSI: case OP_POSPLUSI: if (!inassert) return 0; if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; } else if (c != scode[1]) return 0; break; } code += GET(code, 1); } while (*code == OP_ALT); *flags = cflags; return c; } /************************************************* * Add an entry to the name/number table * *************************************************/ /* This function is called between compiling passes to add an entry to the name/number table, maintaining alphabetical order. Checking for permitted and forbidden duplicates has already been done. Arguments: cd the compile data block name the name to add length the length of the name groupno the group number Returns: nothing */ static void add_name(compile_data *cd, const pcre_uchar *name, int length, unsigned int groupno) { int i; pcre_uchar *slot = cd->name_table; for (i = 0; i < cd->names_found; i++) { int crc = memcmp(name, slot+IMM2_SIZE, IN_UCHARS(length)); if (crc == 0 && slot[IMM2_SIZE+length] != 0) crc = -1; /* Current name is a substring */ /* Make space in the table and break the loop for an earlier name. For a duplicate or later name, carry on. We do this for duplicates so that in the simple case (when ?(| is not used) they are in order of their numbers. In all cases they are in the order in which they appear in the pattern. */ if (crc < 0) { memmove(slot + cd->name_entry_size, slot, IN_UCHARS((cd->names_found - i) * cd->name_entry_size)); break; } /* Continue the loop for a later or duplicate name */ slot += cd->name_entry_size; } PUT2(slot, 0, groupno); memcpy(slot + IMM2_SIZE, name, IN_UCHARS(length)); slot[IMM2_SIZE + length] = 0; cd->names_found++; } /************************************************* * Compile a Regular Expression * *************************************************/ /* This function takes a string and returns a pointer to a block of store holding a compiled version of the expression. The original API for this function had no error code return variable; it is retained for backwards compatibility. The new function is given a new name. Arguments: pattern the regular expression options various option bits errorcodeptr pointer to error code variable (pcre_compile2() only) can be NULL if you don't want a code value errorptr pointer to pointer to error text erroroffset ptr offset in pattern where error was detected tables pointer to character tables or NULL Returns: pointer to compiled data block, or NULL on error, with errorptr and erroroffset set */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION pcre_compile(const char *pattern, int options, const char **errorptr, int *erroroffset, const unsigned char *tables) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION pcre16_compile(PCRE_SPTR16 pattern, int options, const char **errorptr, int *erroroffset, const unsigned char *tables) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION pcre32_compile(PCRE_SPTR32 pattern, int options, const char **errorptr, int *erroroffset, const unsigned char *tables) #endif { #if defined COMPILE_PCRE8 return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables); #elif defined COMPILE_PCRE16 return pcre16_compile2(pattern, options, NULL, errorptr, erroroffset, tables); #elif defined COMPILE_PCRE32 return pcre32_compile2(pattern, options, NULL, errorptr, erroroffset, tables); #endif } #if defined COMPILE_PCRE8 PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION pcre_compile2(const char *pattern, int options, int *errorcodeptr, const char **errorptr, int *erroroffset, const unsigned char *tables) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION pcre16_compile2(PCRE_SPTR16 pattern, int options, int *errorcodeptr, const char **errorptr, int *erroroffset, const unsigned char *tables) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION pcre32_compile2(PCRE_SPTR32 pattern, int options, int *errorcodeptr, const char **errorptr, int *erroroffset, const unsigned char *tables) #endif { REAL_PCRE *re; int length = 1; /* For final END opcode */ pcre_int32 firstcharflags, reqcharflags; pcre_uint32 firstchar, reqchar; pcre_uint32 limit_match = PCRE_UINT32_MAX; pcre_uint32 limit_recursion = PCRE_UINT32_MAX; int newline; int errorcode = 0; int skipatstart = 0; BOOL utf; BOOL never_utf = FALSE; size_t size; pcre_uchar *code; const pcre_uchar *codestart; const pcre_uchar *ptr; compile_data compile_block; compile_data *cd = &compile_block; /* This space is used for "compiling" into during the first phase, when we are computing the amount of memory that is needed. Compiled items are thrown away as soon as possible, so that a fairly large buffer should be sufficient for this purpose. The same space is used in the second phase for remembering where to fill in forward references to subpatterns. That may overflow, in which case new memory is obtained from malloc(). */ pcre_uchar cworkspace[COMPILE_WORK_SIZE]; /* This vector is used for remembering name groups during the pre-compile. In a similar way to cworkspace, it can be expanded using malloc() if necessary. */ named_group named_groups[NAMED_GROUP_LIST_SIZE]; cd->named_groups = named_groups; cd->named_group_list_size = NAMED_GROUP_LIST_SIZE; /* Set this early so that early errors get offset 0. */ ptr = (const pcre_uchar *)pattern; /* We can't pass back an error message if errorptr is NULL; I guess the best we can do is just return NULL, but we can set a code value if there is a code pointer. */ if (errorptr == NULL) { if (errorcodeptr != NULL) *errorcodeptr = 99; return NULL; } *errorptr = NULL; if (errorcodeptr != NULL) *errorcodeptr = ERR0; /* However, we can give a message for this error */ if (erroroffset == NULL) { errorcode = ERR16; goto PCRE_EARLY_ERROR_RETURN2; } *erroroffset = 0; /* Set up pointers to the individual character tables */ if (tables == NULL) tables = PRIV(default_tables); cd->lcc = tables + lcc_offset; cd->fcc = tables + fcc_offset; cd->cbits = tables + cbits_offset; cd->ctypes = tables + ctypes_offset; /* Check that all undefined public option bits are zero */ if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0) { errorcode = ERR17; goto PCRE_EARLY_ERROR_RETURN; } /* If PCRE_NEVER_UTF is set, remember it. */ if ((options & PCRE_NEVER_UTF) != 0) never_utf = TRUE; /* Check for global one-time settings at the start of the pattern, and remember the offset for later. */ cd->external_flags = 0; /* Initialize here for LIMIT_MATCH/RECURSION */ while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS && ptr[skipatstart+1] == CHAR_ASTERISK) { int newnl = 0; int newbsr = 0; /* For completeness and backward compatibility, (*UTFn) is supported in the relevant libraries, but (*UTF) is generic and always supported. Note that PCRE_UTF8 == PCRE_UTF16 == PCRE_UTF32. */ #ifdef COMPILE_PCRE8 if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF8_RIGHTPAR, 5) == 0) { skipatstart += 7; options |= PCRE_UTF8; continue; } #endif #ifdef COMPILE_PCRE16 if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF16_RIGHTPAR, 6) == 0) { skipatstart += 8; options |= PCRE_UTF16; continue; } #endif #ifdef COMPILE_PCRE32 if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF32_RIGHTPAR, 6) == 0) { skipatstart += 8; options |= PCRE_UTF32; continue; } #endif else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_RIGHTPAR, 4) == 0) { skipatstart += 6; options |= PCRE_UTF8; continue; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UCP_RIGHTPAR, 4) == 0) { skipatstart += 6; options |= PCRE_UCP; continue; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_NO_AUTO_POSSESS_RIGHTPAR, 16) == 0) { skipatstart += 18; options |= PCRE_NO_AUTO_POSSESS; continue; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_NO_START_OPT_RIGHTPAR, 13) == 0) { skipatstart += 15; options |= PCRE_NO_START_OPTIMIZE; continue; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_MATCH_EQ, 12) == 0) { pcre_uint32 c = 0; int p = skipatstart + 14; while (isdigit(ptr[p])) { if (c > PCRE_UINT32_MAX / 10 - 1) break; /* Integer overflow */ c = c*10 + ptr[p++] - CHAR_0; } if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break; if (c < limit_match) { limit_match = c; cd->external_flags |= PCRE_MLSET; } skipatstart = p; continue; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_RECURSION_EQ, 16) == 0) { pcre_uint32 c = 0; int p = skipatstart + 18; while (isdigit(ptr[p])) { if (c > PCRE_UINT32_MAX / 10 - 1) break; /* Integer overflow check */ c = c*10 + ptr[p++] - CHAR_0; } if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break; if (c < limit_recursion) { limit_recursion = c; cd->external_flags |= PCRE_RLSET; } skipatstart = p; continue; } if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_CR_RIGHTPAR, 3) == 0) { skipatstart += 5; newnl = PCRE_NEWLINE_CR; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LF_RIGHTPAR, 3) == 0) { skipatstart += 5; newnl = PCRE_NEWLINE_LF; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_CRLF_RIGHTPAR, 5) == 0) { skipatstart += 7; newnl = PCRE_NEWLINE_CR + PCRE_NEWLINE_LF; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_ANY_RIGHTPAR, 4) == 0) { skipatstart += 6; newnl = PCRE_NEWLINE_ANY; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_ANYCRLF_RIGHTPAR, 8) == 0) { skipatstart += 10; newnl = PCRE_NEWLINE_ANYCRLF; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_BSR_ANYCRLF_RIGHTPAR, 12) == 0) { skipatstart += 14; newbsr = PCRE_BSR_ANYCRLF; } else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_BSR_UNICODE_RIGHTPAR, 12) == 0) { skipatstart += 14; newbsr = PCRE_BSR_UNICODE; } if (newnl != 0) options = (options & ~PCRE_NEWLINE_BITS) | newnl; else if (newbsr != 0) options = (options & ~(PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) | newbsr; else break; } /* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */ utf = (options & PCRE_UTF8) != 0; if (utf && never_utf) { errorcode = ERR78; goto PCRE_EARLY_ERROR_RETURN2; } /* Can't support UTF unless PCRE has been compiled to include the code. The return of an error code from PRIV(valid_utf)() is a new feature, introduced in release 8.13. It is passed back from pcre_[dfa_]exec(), but at the moment is not used here. */ #ifdef SUPPORT_UTF if (utf && (options & PCRE_NO_UTF8_CHECK) == 0 && (errorcode = PRIV(valid_utf)((PCRE_PUCHAR)pattern, -1, erroroffset)) != 0) { #if defined COMPILE_PCRE8 errorcode = ERR44; #elif defined COMPILE_PCRE16 errorcode = ERR74; #elif defined COMPILE_PCRE32 errorcode = ERR77; #endif goto PCRE_EARLY_ERROR_RETURN2; } #else if (utf) { errorcode = ERR32; goto PCRE_EARLY_ERROR_RETURN; } #endif /* Can't support UCP unless PCRE has been compiled to include the code. */ #ifndef SUPPORT_UCP if ((options & PCRE_UCP) != 0) { errorcode = ERR67; goto PCRE_EARLY_ERROR_RETURN; } #endif /* Check validity of \R options. */ if ((options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) == (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) { errorcode = ERR56; goto PCRE_EARLY_ERROR_RETURN; } /* Handle different types of newline. The three bits give seven cases. The current code allows for fixed one- or two-byte sequences, plus "any" and "anycrlf". */ switch (options & PCRE_NEWLINE_BITS) { case 0: newline = NEWLINE; break; /* Build-time default */ case PCRE_NEWLINE_CR: newline = CHAR_CR; break; case PCRE_NEWLINE_LF: newline = CHAR_NL; break; case PCRE_NEWLINE_CR+ PCRE_NEWLINE_LF: newline = (CHAR_CR << 8) | CHAR_NL; break; case PCRE_NEWLINE_ANY: newline = -1; break; case PCRE_NEWLINE_ANYCRLF: newline = -2; break; default: errorcode = ERR56; goto PCRE_EARLY_ERROR_RETURN; } if (newline == -2) { cd->nltype = NLTYPE_ANYCRLF; } else if (newline < 0) { cd->nltype = NLTYPE_ANY; } else { cd->nltype = NLTYPE_FIXED; if (newline > 255) { cd->nllen = 2; cd->nl[0] = (newline >> 8) & 255; cd->nl[1] = newline & 255; } else { cd->nllen = 1; cd->nl[0] = newline; } } /* Maximum back reference and backref bitmap. The bitmap records up to 31 back references to help in deciding whether (.*) can be treated as anchored or not. */ cd->top_backref = 0; cd->backref_map = 0; /* Reflect pattern for debugging output */ DPRINTF(("------------------------------------------------------------------\n")); #ifdef PCRE_DEBUG print_puchar(stdout, (PCRE_PUCHAR)pattern); #endif DPRINTF(("\n")); /* Pretend to compile the pattern while actually just accumulating the length of memory required. This behaviour is triggered by passing a non-NULL final argument to compile_regex(). We pass a block of workspace (cworkspace) for it to compile parts of the pattern into; the compiled code is discarded when it is no longer needed, so hopefully this workspace will never overflow, though there is a test for its doing so. */ cd->bracount = cd->final_bracount = 0; cd->names_found = 0; cd->name_entry_size = 0; cd->name_table = NULL; cd->dupnames = FALSE; cd->dupgroups = FALSE; cd->namedrefcount = 0; cd->start_code = cworkspace; cd->hwm = cworkspace; cd->iscondassert = FALSE; cd->start_workspace = cworkspace; cd->workspace_size = COMPILE_WORK_SIZE; cd->start_pattern = (const pcre_uchar *)pattern; cd->end_pattern = (const pcre_uchar *)(pattern + STRLEN_UC((const pcre_uchar *)pattern)); cd->req_varyopt = 0; cd->parens_depth = 0; cd->assert_depth = 0; cd->max_lookbehind = 0; cd->external_options = options; cd->open_caps = NULL; /* Now do the pre-compile. On error, errorcode will be set non-zero, so we don't need to look at the result of the function here. The initial options have been put into the cd block so that they can be changed if an option setting is found within the regex right at the beginning. Bringing initial option settings outside can help speed up starting point checks. */ ptr += skipatstart; code = cworkspace; *code = OP_BRA; (void)compile_regex(cd->external_options, &code, &ptr, &errorcode, FALSE, FALSE, 0, 0, &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL, cd, &length); if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN; DPRINTF(("end pre-compile: length=%d workspace=%d\n", length, (int)(cd->hwm - cworkspace))); if (length > MAX_PATTERN_SIZE) { errorcode = ERR20; goto PCRE_EARLY_ERROR_RETURN; } /* Compute the size of the data block for storing the compiled pattern. Integer overflow should no longer be possible because nowadays we limit the maximum value of cd->names_found and cd->name_entry_size. */ size = sizeof(REAL_PCRE) + (length + cd->names_found * cd->name_entry_size) * sizeof(pcre_uchar); /* Get the memory. */ re = (REAL_PCRE *)(PUBL(malloc))(size); if (re == NULL) { errorcode = ERR21; goto PCRE_EARLY_ERROR_RETURN; } /* Put in the magic number, and save the sizes, initial options, internal flags, and character table pointer. NULL is used for the default character tables. The nullpad field is at the end; it's there to help in the case when a regex compiled on a system with 4-byte pointers is run on another with 8-byte pointers. */ re->magic_number = MAGIC_NUMBER; re->size = (int)size; re->options = cd->external_options; re->flags = cd->external_flags; re->limit_match = limit_match; re->limit_recursion = limit_recursion; re->first_char = 0; re->req_char = 0; re->name_table_offset = sizeof(REAL_PCRE) / sizeof(pcre_uchar); re->name_entry_size = cd->name_entry_size; re->name_count = cd->names_found; re->ref_count = 0; re->tables = (tables == PRIV(default_tables))? NULL : tables; re->nullpad = NULL; #ifdef COMPILE_PCRE32 re->dummy = 0; #else re->dummy1 = re->dummy2 = re->dummy3 = 0; #endif /* The starting points of the name/number translation table and of the code are passed around in the compile data block. The start/end pattern and initial options are already set from the pre-compile phase, as is the name_entry_size field. Reset the bracket count and the names_found field. Also reset the hwm field; this time it's used for remembering forward references to subpatterns. */ cd->final_bracount = cd->bracount; /* Save for checking forward references */ cd->parens_depth = 0; cd->assert_depth = 0; cd->bracount = 0; cd->max_lookbehind = 0; cd->name_table = (pcre_uchar *)re + re->name_table_offset; codestart = cd->name_table + re->name_entry_size * re->name_count; cd->start_code = codestart; cd->hwm = (pcre_uchar *)(cd->start_workspace); cd->iscondassert = FALSE; cd->req_varyopt = 0; cd->had_accept = FALSE; cd->had_pruneorskip = FALSE; cd->check_lookbehind = FALSE; cd->open_caps = NULL; /* If any named groups were found, create the name/number table from the list created in the first pass. */ if (cd->names_found > 0) { int i = cd->names_found; named_group *ng = cd->named_groups; cd->names_found = 0; for (; i > 0; i--, ng++) add_name(cd, ng->name, ng->length, ng->number); if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE) (PUBL(free))((void *)cd->named_groups); cd->named_group_list_size = 0; /* So we don't free it twice */ } /* Set up a starting, non-extracting bracket, then compile the expression. On error, errorcode will be set non-zero, so we don't need to look at the result of the function here. */ ptr = (const pcre_uchar *)pattern + skipatstart; code = (pcre_uchar *)codestart; *code = OP_BRA; (void)compile_regex(re->options, &code, &ptr, &errorcode, FALSE, FALSE, 0, 0, &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL, cd, NULL); re->top_bracket = cd->bracount; re->top_backref = cd->top_backref; re->max_lookbehind = cd->max_lookbehind; re->flags = cd->external_flags | PCRE_MODE; if (cd->had_accept) { reqchar = 0; /* Must disable after (*ACCEPT) */ reqcharflags = REQ_NONE; } /* If not reached end of pattern on success, there's an excess bracket. */ if (errorcode == 0 && *ptr != CHAR_NULL) errorcode = ERR22; /* Fill in the terminating state and check for disastrous overflow, but if debugging, leave the test till after things are printed out. */ *code++ = OP_END; #ifndef PCRE_DEBUG if (code - codestart > length) errorcode = ERR23; #endif #ifdef SUPPORT_VALGRIND /* If the estimated length exceeds the really used length, mark the extra allocated memory as unaddressable, so that any out-of-bound reads can be detected. */ VALGRIND_MAKE_MEM_NOACCESS(code, (length - (code - codestart)) * sizeof(pcre_uchar)); #endif /* Fill in any forward references that are required. There may be repeated references; optimize for them, as searching a large regex takes time. */ if (cd->hwm > cd->start_workspace) { int prev_recno = -1; const pcre_uchar *groupptr = NULL; while (errorcode == 0 && cd->hwm > cd->start_workspace) { int offset, recno; cd->hwm -= LINK_SIZE; offset = GET(cd->hwm, 0); /* Check that the hwm handling hasn't gone wrong. This whole area is rewritten in PCRE2 because there are some obscure cases. */ if (offset == 0 || codestart[offset-1] != OP_RECURSE) { errorcode = ERR10; break; } recno = GET(codestart, offset); if (recno != prev_recno) { groupptr = PRIV(find_bracket)(codestart, utf, recno); prev_recno = recno; } if (groupptr == NULL) errorcode = ERR53; else PUT(((pcre_uchar *)codestart), offset, (int)(groupptr - codestart)); } } /* If the workspace had to be expanded, free the new memory. Set the pointer to NULL to indicate that forward references have been filled in. */ if (cd->workspace_size > COMPILE_WORK_SIZE) (PUBL(free))((void *)cd->start_workspace); cd->start_workspace = NULL; /* Give an error if there's back reference to a non-existent capturing subpattern. */ if (errorcode == 0 && re->top_backref > re->top_bracket) errorcode = ERR15; /* Unless disabled, check whether any single character iterators can be auto-possessified. The function overwrites the appropriate opcode values, so the type of the pointer must be cast. NOTE: the intermediate variable "temp" is used in this code because at least one compiler gives a warning about loss of "const" attribute if the cast (pcre_uchar *)codestart is used directly in the function call. */ if (errorcode == 0 && (options & PCRE_NO_AUTO_POSSESS) == 0) { pcre_uchar *temp = (pcre_uchar *)codestart; auto_possessify(temp, utf, cd); } /* If there were any lookbehind assertions that contained OP_RECURSE (recursions or subroutine calls), a flag is set for them to be checked here, because they may contain forward references. Actual recursions cannot be fixed length, but subroutine calls can. It is done like this so that those without OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The exceptional ones forgo this. We scan the pattern to check that they are fixed length, and set their lengths. */ if (errorcode == 0 && cd->check_lookbehind) { pcre_uchar *cc = (pcre_uchar *)codestart; /* Loop, searching for OP_REVERSE items, and process those that do not have their length set. (Actually, it will also re-process any that have a length of zero, but that is a pathological case, and it does no harm.) When we find one, we temporarily terminate the branch it is in while we scan it. */ for (cc = (pcre_uchar *)PRIV(find_bracket)(codestart, utf, -1); cc != NULL; cc = (pcre_uchar *)PRIV(find_bracket)(cc, utf, -1)) { if (GET(cc, 1) == 0) { int fixed_length; pcre_uchar *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE); int end_op = *be; *be = OP_END; fixed_length = find_fixedlength(cc, (re->options & PCRE_UTF8) != 0, TRUE, cd, NULL); *be = end_op; DPRINTF(("fixed length = %d\n", fixed_length)); if (fixed_length < 0) { errorcode = (fixed_length == -2)? ERR36 : (fixed_length == -4)? ERR70 : ERR25; break; } if (fixed_length > cd->max_lookbehind) cd->max_lookbehind = fixed_length; PUT(cc, 1, fixed_length); } cc += 1 + LINK_SIZE; } } /* Failed to compile, or error while post-processing */ if (errorcode != 0) { (PUBL(free))(re); PCRE_EARLY_ERROR_RETURN: if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE) (PUBL(free))((void *)cd->named_groups); *erroroffset = (int)(ptr - (const pcre_uchar *)pattern); PCRE_EARLY_ERROR_RETURN2: *errorptr = find_error_text(errorcode); if (errorcodeptr != NULL) *errorcodeptr = errorcode; return NULL; } /* If the anchored option was not passed, set the flag if we can determine that the pattern is anchored by virtue of ^ characters or \A or anything else, such as starting with non-atomic .* when DOTALL is set and there are no occurrences of *PRUNE or *SKIP. Otherwise, if we know what the first byte has to be, save it, because that speeds up unanchored matches no end. If not, see if we can set the PCRE_STARTLINE flag. This is helpful for multiline matches when all branches start with ^. and also when all branches start with non-atomic .* for non-DOTALL matches when *PRUNE and SKIP are not present. */ if ((re->options & PCRE_ANCHORED) == 0) { if (is_anchored(codestart, 0, cd, 0)) re->options |= PCRE_ANCHORED; else { if (firstcharflags < 0) firstchar = find_firstassertedchar(codestart, &firstcharflags, FALSE); if (firstcharflags >= 0) /* Remove caseless flag for non-caseable chars */ { #if defined COMPILE_PCRE8 re->first_char = firstchar & 0xff; #elif defined COMPILE_PCRE16 re->first_char = firstchar & 0xffff; #elif defined COMPILE_PCRE32 re->first_char = firstchar; #endif if ((firstcharflags & REQ_CASELESS) != 0) { #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8) /* We ignore non-ASCII first chars in 8 bit mode. */ if (utf) { if (re->first_char < 128) { if (cd->fcc[re->first_char] != re->first_char) re->flags |= PCRE_FCH_CASELESS; } else if (UCD_OTHERCASE(re->first_char) != re->first_char) re->flags |= PCRE_FCH_CASELESS; } else #endif if (MAX_255(re->first_char) && cd->fcc[re->first_char] != re->first_char) re->flags |= PCRE_FCH_CASELESS; } re->flags |= PCRE_FIRSTSET; } else if (is_startline(codestart, 0, cd, 0, FALSE)) re->flags |= PCRE_STARTLINE; } } /* For an anchored pattern, we use the "required byte" only if it follows a variable length item in the regex. Remove the caseless flag for non-caseable bytes. */ if (reqcharflags >= 0 && ((re->options & PCRE_ANCHORED) == 0 || (reqcharflags & REQ_VARY) != 0)) { #if defined COMPILE_PCRE8 re->req_char = reqchar & 0xff; #elif defined COMPILE_PCRE16 re->req_char = reqchar & 0xffff; #elif defined COMPILE_PCRE32 re->req_char = reqchar; #endif if ((reqcharflags & REQ_CASELESS) != 0) { #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8) /* We ignore non-ASCII first chars in 8 bit mode. */ if (utf) { if (re->req_char < 128) { if (cd->fcc[re->req_char] != re->req_char) re->flags |= PCRE_RCH_CASELESS; } else if (UCD_OTHERCASE(re->req_char) != re->req_char) re->flags |= PCRE_RCH_CASELESS; } else #endif if (MAX_255(re->req_char) && cd->fcc[re->req_char] != re->req_char) re->flags |= PCRE_RCH_CASELESS; } re->flags |= PCRE_REQCHSET; } /* Print out the compiled data if debugging is enabled. This is never the case when building a production library. */ #ifdef PCRE_DEBUG printf("Length = %d top_bracket = %d top_backref = %d\n", length, re->top_bracket, re->top_backref); printf("Options=%08x\n", re->options); if ((re->flags & PCRE_FIRSTSET) != 0) { pcre_uchar ch = re->first_char; const char *caseless = ((re->flags & PCRE_FCH_CASELESS) == 0)? "" : " (caseless)"; if (PRINTABLE(ch)) printf("First char = %c%s\n", ch, caseless); else printf("First char = \\x%02x%s\n", ch, caseless); } if ((re->flags & PCRE_REQCHSET) != 0) { pcre_uchar ch = re->req_char; const char *caseless = ((re->flags & PCRE_RCH_CASELESS) == 0)? "" : " (caseless)"; if (PRINTABLE(ch)) printf("Req char = %c%s\n", ch, caseless); else printf("Req char = \\x%02x%s\n", ch, caseless); } #if defined COMPILE_PCRE8 pcre_printint((pcre *)re, stdout, TRUE); #elif defined COMPILE_PCRE16 pcre16_printint((pcre *)re, stdout, TRUE); #elif defined COMPILE_PCRE32 pcre32_printint((pcre *)re, stdout, TRUE); #endif /* This check is done here in the debugging case so that the code that was compiled can be seen. */ if (code - codestart > length) { (PUBL(free))(re); *errorptr = find_error_text(ERR23); *erroroffset = ptr - (pcre_uchar *)pattern; if (errorcodeptr != NULL) *errorcodeptr = ERR23; return NULL; } #endif /* PCRE_DEBUG */ /* Check for a pattern than can match an empty string, so that this information can be provided to applications. */ do { if (could_be_empty_branch(codestart, code, utf, cd, NULL)) { re->flags |= PCRE_MATCH_EMPTY; break; } codestart += GET(codestart, 1); } while (*codestart == OP_ALT); #if defined COMPILE_PCRE8 return (pcre *)re; #elif defined COMPILE_PCRE16 return (pcre16 *)re; #elif defined COMPILE_PCRE32 return (pcre32 *)re; #endif } /* End of pcre_compile.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_fullinfo.c0000644000000000000020000001721314655113617022326 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2013 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains the external function pcre_fullinfo(), which returns information about a compiled pattern. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" /************************************************* * Return info about compiled pattern * *************************************************/ /* This is a newer "info" function which has an extensible interface so that additional items can be added compatibly. Arguments: argument_re points to compiled code extra_data points extra data, or NULL what what information is required where where to put the information Returns: 0 if data returned, negative on error */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_fullinfo(const pcre *argument_re, const pcre_extra *extra_data, int what, void *where) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_fullinfo(const pcre16 *argument_re, const pcre16_extra *extra_data, int what, void *where) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_fullinfo(const pcre32 *argument_re, const pcre32_extra *extra_data, int what, void *where) #endif { const REAL_PCRE *re = (const REAL_PCRE *)argument_re; const pcre_study_data *study = NULL; if (re == NULL || where == NULL) return PCRE_ERROR_NULL; if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0) study = (const pcre_study_data *)extra_data->study_data; /* Check that the first field in the block is the magic number. If it is not, return with PCRE_ERROR_BADMAGIC. However, if the magic number is equal to REVERSED_MAGIC_NUMBER we return with PCRE_ERROR_BADENDIANNESS, which means that the pattern is likely compiled with different endianness. */ if (re->magic_number != MAGIC_NUMBER) return re->magic_number == REVERSED_MAGIC_NUMBER? PCRE_ERROR_BADENDIANNESS:PCRE_ERROR_BADMAGIC; /* Check that this pattern was compiled in the correct bit mode */ if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE; switch (what) { case PCRE_INFO_OPTIONS: *((unsigned long int *)where) = re->options & PUBLIC_COMPILE_OPTIONS; break; case PCRE_INFO_SIZE: *((size_t *)where) = re->size; break; case PCRE_INFO_STUDYSIZE: *((size_t *)where) = (study == NULL)? 0 : study->size; break; case PCRE_INFO_JITSIZE: #ifdef SUPPORT_JIT *((size_t *)where) = (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 && extra_data->executable_jit != NULL)? PRIV(jit_get_size)(extra_data->executable_jit) : 0; #else *((size_t *)where) = 0; #endif break; case PCRE_INFO_CAPTURECOUNT: *((int *)where) = re->top_bracket; break; case PCRE_INFO_BACKREFMAX: *((int *)where) = re->top_backref; break; case PCRE_INFO_FIRSTBYTE: *((int *)where) = ((re->flags & PCRE_FIRSTSET) != 0)? (int)re->first_char : ((re->flags & PCRE_STARTLINE) != 0)? -1 : -2; break; case PCRE_INFO_FIRSTCHARACTER: *((pcre_uint32 *)where) = (re->flags & PCRE_FIRSTSET) != 0 ? re->first_char : 0; break; case PCRE_INFO_FIRSTCHARACTERFLAGS: *((int *)where) = ((re->flags & PCRE_FIRSTSET) != 0) ? 1 : ((re->flags & PCRE_STARTLINE) != 0) ? 2 : 0; break; /* Make sure we pass back the pointer to the bit vector in the external block, not the internal copy (with flipped integer fields). */ case PCRE_INFO_FIRSTTABLE: *((const pcre_uint8 **)where) = (study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0)? ((const pcre_study_data *)extra_data->study_data)->start_bits : NULL; break; case PCRE_INFO_MINLENGTH: *((int *)where) = (study != NULL && (study->flags & PCRE_STUDY_MINLEN) != 0)? (int)(study->minlength) : -1; break; case PCRE_INFO_JIT: *((int *)where) = extra_data != NULL && (extra_data->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 && extra_data->executable_jit != NULL; break; case PCRE_INFO_LASTLITERAL: *((int *)where) = ((re->flags & PCRE_REQCHSET) != 0)? (int)re->req_char : -1; break; case PCRE_INFO_REQUIREDCHAR: *((pcre_uint32 *)where) = ((re->flags & PCRE_REQCHSET) != 0) ? re->req_char : 0; break; case PCRE_INFO_REQUIREDCHARFLAGS: *((int *)where) = ((re->flags & PCRE_REQCHSET) != 0); break; case PCRE_INFO_NAMEENTRYSIZE: *((int *)where) = re->name_entry_size; break; case PCRE_INFO_NAMECOUNT: *((int *)where) = re->name_count; break; case PCRE_INFO_NAMETABLE: *((const pcre_uchar **)where) = (const pcre_uchar *)re + re->name_table_offset; break; case PCRE_INFO_DEFAULT_TABLES: *((const pcre_uint8 **)where) = (const pcre_uint8 *)(PRIV(default_tables)); break; /* From release 8.00 this will always return TRUE because NOPARTIAL is no longer ever set (the restrictions have been removed). */ case PCRE_INFO_OKPARTIAL: *((int *)where) = (re->flags & PCRE_NOPARTIAL) == 0; break; case PCRE_INFO_JCHANGED: *((int *)where) = (re->flags & PCRE_JCHANGED) != 0; break; case PCRE_INFO_HASCRORLF: *((int *)where) = (re->flags & PCRE_HASCRORLF) != 0; break; case PCRE_INFO_MAXLOOKBEHIND: *((int *)where) = re->max_lookbehind; break; case PCRE_INFO_MATCHLIMIT: if ((re->flags & PCRE_MLSET) == 0) return PCRE_ERROR_UNSET; *((pcre_uint32 *)where) = re->limit_match; break; case PCRE_INFO_RECURSIONLIMIT: if ((re->flags & PCRE_RLSET) == 0) return PCRE_ERROR_UNSET; *((pcre_uint32 *)where) = re->limit_recursion; break; case PCRE_INFO_MATCH_EMPTY: *((int *)where) = (re->flags & PCRE_MATCH_EMPTY) != 0; break; default: return PCRE_ERROR_BADOPTION; } return 0; } /* End of pcre_fullinfo.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcreposix.h0000644000000000000020000001251414655113617021517 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ #ifndef _PCREPOSIX_H #define _PCREPOSIX_H /* This is the header for the POSIX wrapper interface to the PCRE Perl- Compatible Regular Expression library. It defines the things POSIX says should be there. I hope. Copyright (c) 1997-2012 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* Have to include stdlib.h in order to ensure that size_t is defined. */ #include /* Allow for C++ users */ #ifdef __cplusplus extern "C" { #endif /* Options, mostly defined by POSIX, but with some extras. */ #define REG_ICASE 0x0001 /* Maps to PCRE_CASELESS */ #define REG_NEWLINE 0x0002 /* Maps to PCRE_MULTILINE */ #define REG_NOTBOL 0x0004 /* Maps to PCRE_NOTBOL */ #define REG_NOTEOL 0x0008 /* Maps to PCRE_NOTEOL */ #define REG_DOTALL 0x0010 /* NOT defined by POSIX; maps to PCRE_DOTALL */ #define REG_NOSUB 0x0020 /* Maps to PCRE_NO_AUTO_CAPTURE */ #define REG_UTF8 0x0040 /* NOT defined by POSIX; maps to PCRE_UTF8 */ #define REG_STARTEND 0x0080 /* BSD feature: pass subject string by so,eo */ #define REG_NOTEMPTY 0x0100 /* NOT defined by POSIX; maps to PCRE_NOTEMPTY */ #define REG_UNGREEDY 0x0200 /* NOT defined by POSIX; maps to PCRE_UNGREEDY */ #define REG_UCP 0x0400 /* NOT defined by POSIX; maps to PCRE_UCP */ /* This is not used by PCRE, but by defining it we make it easier to slot PCRE into existing programs that make POSIX calls. */ #define REG_EXTENDED 0 /* Error values. Not all these are relevant or used by the wrapper. */ enum { REG_ASSERT = 1, /* internal error ? */ REG_BADBR, /* invalid repeat counts in {} */ REG_BADPAT, /* pattern error */ REG_BADRPT, /* ? * + invalid */ REG_EBRACE, /* unbalanced {} */ REG_EBRACK, /* unbalanced [] */ REG_ECOLLATE, /* collation error - not relevant */ REG_ECTYPE, /* bad class */ REG_EESCAPE, /* bad escape sequence */ REG_EMPTY, /* empty expression */ REG_EPAREN, /* unbalanced () */ REG_ERANGE, /* bad range inside [] */ REG_ESIZE, /* expression too big */ REG_ESPACE, /* failed to get memory */ REG_ESUBREG, /* bad back reference */ REG_INVARG, /* bad argument */ REG_NOMATCH /* match failed */ }; /* The structure representing a compiled regular expression. */ typedef struct { void *re_pcre; size_t re_nsub; size_t re_erroffset; } regex_t; /* The structure in which a captured offset is returned. */ typedef int regoff_t; typedef struct { regoff_t rm_so; regoff_t rm_eo; } regmatch_t; /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE, the appropriate export settings are needed, and are set in pcreposix.c before including this file. */ #if defined(_WIN32) && !defined(PCRE_STATIC) && !defined(PCREPOSIX_EXP_DECL) # define PCREPOSIX_EXP_DECL extern __declspec(dllimport) # define PCREPOSIX_EXP_DEFN __declspec(dllimport) #endif /* By default, we use the standard "extern" declarations. */ #ifndef PCREPOSIX_EXP_DECL # ifdef __cplusplus # define PCREPOSIX_EXP_DECL extern "C" # define PCREPOSIX_EXP_DEFN extern "C" # else # define PCREPOSIX_EXP_DECL extern # define PCREPOSIX_EXP_DEFN extern # endif #endif /* The functions */ PCREPOSIX_EXP_DECL int regcomp(regex_t *, const char *, int); PCREPOSIX_EXP_DECL int regexec(const regex_t *, const char *, size_t, regmatch_t *, int); PCREPOSIX_EXP_DECL size_t regerror(int, const regex_t *, char *, size_t); PCREPOSIX_EXP_DECL void regfree(regex_t *); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* End of pcreposix.h */ tomcat-connectors-1.2.50-src/native/iis/pcre/ucp.h0000644000000000000020000001213714655113617020273 0ustar rootbin/************************************************* * Unicode Property Table handler * *************************************************/ #ifndef _UCP_H #define _UCP_H /* This file contains definitions of the property values that are returned by the UCD access macros. New values that are added for new releases of Unicode should always be at the end of each enum, for backwards compatibility. IMPORTANT: Note also that the specific numeric values of the enums have to be the same as the values that are generated by the maint/MultiStage2.py script, where the equivalent property descriptive names are listed in vectors. ALSO: The specific values of the first two enums are assumed for the table called catposstab in pcre_compile.c. */ /* These are the general character categories. */ enum { ucp_C, /* Other */ ucp_L, /* Letter */ ucp_M, /* Mark */ ucp_N, /* Number */ ucp_P, /* Punctuation */ ucp_S, /* Symbol */ ucp_Z /* Separator */ }; /* These are the particular character categories. */ enum { ucp_Cc, /* Control */ ucp_Cf, /* Format */ ucp_Cn, /* Unassigned */ ucp_Co, /* Private use */ ucp_Cs, /* Surrogate */ ucp_Ll, /* Lower case letter */ ucp_Lm, /* Modifier letter */ ucp_Lo, /* Other letter */ ucp_Lt, /* Title case letter */ ucp_Lu, /* Upper case letter */ ucp_Mc, /* Spacing mark */ ucp_Me, /* Enclosing mark */ ucp_Mn, /* Non-spacing mark */ ucp_Nd, /* Decimal number */ ucp_Nl, /* Letter number */ ucp_No, /* Other number */ ucp_Pc, /* Connector punctuation */ ucp_Pd, /* Dash punctuation */ ucp_Pe, /* Close punctuation */ ucp_Pf, /* Final punctuation */ ucp_Pi, /* Initial punctuation */ ucp_Po, /* Other punctuation */ ucp_Ps, /* Open punctuation */ ucp_Sc, /* Currency symbol */ ucp_Sk, /* Modifier symbol */ ucp_Sm, /* Mathematical symbol */ ucp_So, /* Other symbol */ ucp_Zl, /* Line separator */ ucp_Zp, /* Paragraph separator */ ucp_Zs /* Space separator */ }; /* These are grapheme break properties. Note that the code for processing them assumes that the values are less than 16. If more values are added that take the number to 16 or more, the code will have to be rewritten. */ enum { ucp_gbCR, /* 0 */ ucp_gbLF, /* 1 */ ucp_gbControl, /* 2 */ ucp_gbExtend, /* 3 */ ucp_gbPrepend, /* 4 */ ucp_gbSpacingMark, /* 5 */ ucp_gbL, /* 6 Hangul syllable type L */ ucp_gbV, /* 7 Hangul syllable type V */ ucp_gbT, /* 8 Hangul syllable type T */ ucp_gbLV, /* 9 Hangul syllable type LV */ ucp_gbLVT, /* 10 Hangul syllable type LVT */ ucp_gbRegionalIndicator, /* 11 */ ucp_gbOther /* 12 */ }; /* These are the script identifications. */ enum { ucp_Arabic, ucp_Armenian, ucp_Bengali, ucp_Bopomofo, ucp_Braille, ucp_Buginese, ucp_Buhid, ucp_Canadian_Aboriginal, ucp_Cherokee, ucp_Common, ucp_Coptic, ucp_Cypriot, ucp_Cyrillic, ucp_Deseret, ucp_Devanagari, ucp_Ethiopic, ucp_Georgian, ucp_Glagolitic, ucp_Gothic, ucp_Greek, ucp_Gujarati, ucp_Gurmukhi, ucp_Han, ucp_Hangul, ucp_Hanunoo, ucp_Hebrew, ucp_Hiragana, ucp_Inherited, ucp_Kannada, ucp_Katakana, ucp_Kharoshthi, ucp_Khmer, ucp_Lao, ucp_Latin, ucp_Limbu, ucp_Linear_B, ucp_Malayalam, ucp_Mongolian, ucp_Myanmar, ucp_New_Tai_Lue, ucp_Ogham, ucp_Old_Italic, ucp_Old_Persian, ucp_Oriya, ucp_Osmanya, ucp_Runic, ucp_Shavian, ucp_Sinhala, ucp_Syloti_Nagri, ucp_Syriac, ucp_Tagalog, ucp_Tagbanwa, ucp_Tai_Le, ucp_Tamil, ucp_Telugu, ucp_Thaana, ucp_Thai, ucp_Tibetan, ucp_Tifinagh, ucp_Ugaritic, ucp_Yi, /* New for Unicode 5.0: */ ucp_Balinese, ucp_Cuneiform, ucp_Nko, ucp_Phags_Pa, ucp_Phoenician, /* New for Unicode 5.1: */ ucp_Carian, ucp_Cham, ucp_Kayah_Li, ucp_Lepcha, ucp_Lycian, ucp_Lydian, ucp_Ol_Chiki, ucp_Rejang, ucp_Saurashtra, ucp_Sundanese, ucp_Vai, /* New for Unicode 5.2: */ ucp_Avestan, ucp_Bamum, ucp_Egyptian_Hieroglyphs, ucp_Imperial_Aramaic, ucp_Inscriptional_Pahlavi, ucp_Inscriptional_Parthian, ucp_Javanese, ucp_Kaithi, ucp_Lisu, ucp_Meetei_Mayek, ucp_Old_South_Arabian, ucp_Old_Turkic, ucp_Samaritan, ucp_Tai_Tham, ucp_Tai_Viet, /* New for Unicode 6.0.0: */ ucp_Batak, ucp_Brahmi, ucp_Mandaic, /* New for Unicode 6.1.0: */ ucp_Chakma, ucp_Meroitic_Cursive, ucp_Meroitic_Hieroglyphs, ucp_Miao, ucp_Sharada, ucp_Sora_Sompeng, ucp_Takri, /* New for Unicode 7.0.0: */ ucp_Bassa_Vah, ucp_Caucasian_Albanian, ucp_Duployan, ucp_Elbasan, ucp_Grantha, ucp_Khojki, ucp_Khudawadi, ucp_Linear_A, ucp_Mahajani, ucp_Manichaean, ucp_Mende_Kikakui, ucp_Modi, ucp_Mro, ucp_Nabataean, ucp_Old_North_Arabian, ucp_Old_Permic, ucp_Pahawh_Hmong, ucp_Palmyrene, ucp_Psalter_Pahlavi, ucp_Pau_Cin_Hau, ucp_Siddham, ucp_Tirhuta, ucp_Warang_Citi }; #endif /* End of ucp.h */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_refcount.c0000644000000000000020000000730214655113617022333 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2012 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains the external function pcre_refcount(), which is an auxiliary function that can be used to maintain a reference count in a compiled pattern data block. This might be helpful in applications where the block is shared by different users. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" /************************************************* * Maintain reference count * *************************************************/ /* The reference count is a 16-bit field, initialized to zero. It is not possible to transfer a non-zero count from one host to a different host that has a different byte order - though I can't see why anyone in their right mind would ever want to do that! Arguments: argument_re points to compiled code adjust value to add to the count Returns: the (possibly updated) count value (a non-negative number), or a negative error number */ #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_refcount(pcre *argument_re, int adjust) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_refcount(pcre16 *argument_re, int adjust) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_refcount(pcre32 *argument_re, int adjust) #endif { REAL_PCRE *re = (REAL_PCRE *)argument_re; if (re == NULL) return PCRE_ERROR_NULL; if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC; if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE; re->ref_count = (-adjust > re->ref_count)? 0 : (adjust + re->ref_count > 65535)? 65535 : re->ref_count + adjust; return re->ref_count; } /* End of pcre_refcount.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_maketables.c0000644000000000000020000001334714655113617022624 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2012 University of Cambridge ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* This module contains the external function pcre_maketables(), which builds character tables for PCRE in the current locale. The file is compiled on its own as part of the PCRE library. However, it is also included in the compilation of dftables.c, in which case the macro DFTABLES is defined. */ #ifndef DFTABLES # ifdef HAVE_CONFIG_H # include "config.h" # endif # include "pcre_internal.h" #endif /************************************************* * Create PCRE character tables * *************************************************/ /* This function builds a set of character tables for use by PCRE and returns a pointer to them. They are build using the ctype functions, and consequently their contents will depend upon the current locale setting. When compiled as part of the library, the store is obtained via PUBL(malloc)(), but when compiled inside dftables, use malloc(). Arguments: none Returns: pointer to the contiguous block of data */ #if defined COMPILE_PCRE8 const unsigned char * pcre_maketables(void) #elif defined COMPILE_PCRE16 const unsigned char * pcre16_maketables(void) #elif defined COMPILE_PCRE32 const unsigned char * pcre32_maketables(void) #endif { unsigned char *yield, *p; int i; #ifndef DFTABLES yield = (unsigned char*)(PUBL(malloc))(tables_length); #else yield = (unsigned char*)malloc(tables_length); #endif if (yield == NULL) return NULL; p = yield; /* First comes the lower casing table */ for (i = 0; i < 256; i++) *p++ = tolower(i); /* Next the case-flipping table */ for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i); /* Then the character class tables. Don't try to be clever and save effort on exclusive ones - in some locales things may be different. Note that the table for "space" includes everything "isspace" gives, including VT in the default locale. This makes it work for the POSIX class [:space:]. From release 8.34 is is also correct for Perl space, because Perl added VT at release 5.18. Note also that it is possible for a character to be alnum or alpha without being lower or upper, such as "male and female ordinals" (\xAA and \xBA) in the fr_FR locale (at least under Debian Linux's locales as of 12/2005). So we must test for alnum specially. */ memset(p, 0, cbit_length); for (i = 0; i < 256; i++) { if (isdigit(i)) p[cbit_digit + i/8] |= 1 << (i&7); if (isupper(i)) p[cbit_upper + i/8] |= 1 << (i&7); if (islower(i)) p[cbit_lower + i/8] |= 1 << (i&7); if (isalnum(i)) p[cbit_word + i/8] |= 1 << (i&7); if (i == '_') p[cbit_word + i/8] |= 1 << (i&7); if (isspace(i)) p[cbit_space + i/8] |= 1 << (i&7); if (isxdigit(i))p[cbit_xdigit + i/8] |= 1 << (i&7); if (isgraph(i)) p[cbit_graph + i/8] |= 1 << (i&7); if (isprint(i)) p[cbit_print + i/8] |= 1 << (i&7); if (ispunct(i)) p[cbit_punct + i/8] |= 1 << (i&7); if (iscntrl(i)) p[cbit_cntrl + i/8] |= 1 << (i&7); } p += cbit_length; /* Finally, the character type table. In this, we used to exclude VT from the white space chars, because Perl didn't recognize it as such for \s and for comments within regexes. However, Perl changed at release 5.18, so PCRE changed at release 8.34. */ for (i = 0; i < 256; i++) { int x = 0; if (isspace(i)) x += ctype_space; if (isalpha(i)) x += ctype_letter; if (isdigit(i)) x += ctype_digit; if (isxdigit(i)) x += ctype_xdigit; if (isalnum(i) || i == '_') x += ctype_word; /* Note: strchr includes the terminating zero in the characters it considers. In this instance, that is ok because we want binary zero to be flagged as a meta-character, which in this sense is any character that terminates a run of data characters. */ if (strchr("\\*+?{^.$|()[", i) != 0) x += ctype_meta; *p++ = x; } return yield; } /* End of pcre_maketables.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_jit_compile.c0000644000000000000020000130773414655113617023021 0ustar rootbin/************************************************* * Perl-Compatible Regular Expressions * *************************************************/ /* PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Written by Philip Hazel Copyright (c) 1997-2013 University of Cambridge The machine code generator part (this module) was written by Zoltan Herczeg Copyright (c) 2010-2013 ----------------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" #if defined SUPPORT_JIT /* All-in-one: Since we use the JIT compiler only from here, we just include it. This way we don't need to touch the build system files. */ #define SLJIT_MALLOC(size, allocator_data) (PUBL(malloc))(size) #define SLJIT_FREE(ptr, allocator_data) (PUBL(free))(ptr) #define SLJIT_CONFIG_AUTO 1 #define SLJIT_CONFIG_STATIC 1 #define SLJIT_VERBOSE 0 #define SLJIT_DEBUG 0 #include "sljit/sljitLir.c" #if defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED #error Unsupported architecture #endif /* Defines for debugging purposes. */ /* 1 - Use unoptimized capturing brackets. 2 - Enable capture_last_ptr (includes option 1). */ /* #define DEBUG_FORCE_UNOPTIMIZED_CBRAS 2 */ /* 1 - Always have a control head. */ /* #define DEBUG_FORCE_CONTROL_HEAD 1 */ /* Allocate memory for the regex stack on the real machine stack. Fast, but limited size. */ #define MACHINE_STACK_SIZE 32768 /* Growth rate for stack allocated by the OS. Should be the multiply of page size. */ #define STACK_GROWTH_RATE 8192 /* Enable to check that the allocation could destroy temporaries. */ #if defined SLJIT_DEBUG && SLJIT_DEBUG #define DESTROY_REGISTERS 1 #endif /* Short summary about the backtracking mechanism empolyed by the jit code generator: The code generator follows the recursive nature of the PERL compatible regular expressions. The basic blocks of regular expressions are condition checkers whose execute different commands depending on the result of the condition check. The relationship between the operators can be horizontal (concatenation) and vertical (sub-expression) (See struct backtrack_common for more details). 'ab' - 'a' and 'b' regexps are concatenated 'a+' - 'a' is the sub-expression of the '+' operator The condition checkers are boolean (true/false) checkers. Machine code is generated for the checker itself and for the actions depending on the result of the checker. The 'true' case is called as the matching path (expected path), and the other is called as the 'backtrack' path. Branch instructions are expesive for all CPUs, so we avoid taken branches on the matching path. Greedy star operator (*) : Matching path: match happens. Backtrack path: match failed. Non-greedy star operator (*?) : Matching path: no need to perform a match. Backtrack path: match is required. The following example shows how the code generated for a capturing bracket with two alternatives. Let A, B, C, D are arbirary regular expressions, and we have the following regular expression: A(B|C)D The generated code will be the following: A matching path '(' matching path (pushing arguments to the stack) B matching path ')' matching path (pushing arguments to the stack) D matching path return with successful match D backtrack path ')' backtrack path (If we arrived from "C" jump to the backtrack of "C") B backtrack path C expected path jump to D matching path C backtrack path A backtrack path Notice, that the order of backtrack code paths are the opposite of the fast code paths. In this way the topmost value on the stack is always belong to the current backtrack code path. The backtrack path must check whether there is a next alternative. If so, it needs to jump back to the matching path eventually. Otherwise it needs to clear out its own stack frame and continue the execution on the backtrack code paths. */ /* Saved stack frames: Atomic blocks and asserts require reloading the values of private data when the backtrack mechanism performed. Because of OP_RECURSE, the data are not necessarly known in compile time, thus we need a dynamic restore mechanism. The stack frames are stored in a chain list, and have the following format: ([ capturing bracket offset ][ start value ][ end value ])+ ... [ 0 ] [ previous head ] Thus we can restore the private data to a particular point in the stack. */ typedef struct jit_arguments { /* Pointers first. */ struct sljit_stack *stack; const pcre_uchar *str; const pcre_uchar *begin; const pcre_uchar *end; int *offsets; pcre_uchar *mark_ptr; void *callout_data; /* Everything else after. */ sljit_u32 limit_match; int real_offset_count; int offset_count; sljit_u8 notbol; sljit_u8 noteol; sljit_u8 notempty; sljit_u8 notempty_atstart; } jit_arguments; typedef struct executable_functions { void *executable_funcs[JIT_NUMBER_OF_COMPILE_MODES]; void *read_only_data_heads[JIT_NUMBER_OF_COMPILE_MODES]; sljit_uw executable_sizes[JIT_NUMBER_OF_COMPILE_MODES]; PUBL(jit_callback) callback; void *userdata; sljit_u32 top_bracket; sljit_u32 limit_match; } executable_functions; typedef struct jump_list { struct sljit_jump *jump; struct jump_list *next; } jump_list; typedef struct stub_list { struct sljit_jump *start; struct sljit_label *quit; struct stub_list *next; } stub_list; typedef struct label_addr_list { struct sljit_label *label; sljit_uw *update_addr; struct label_addr_list *next; } label_addr_list; enum frame_types { no_frame = -1, no_stack = -2 }; enum control_types { type_mark = 0, type_then_trap = 1 }; typedef int (SLJIT_FUNC *jit_function)(jit_arguments *args); /* The following structure is the key data type for the recursive code generator. It is allocated by compile_matchingpath, and contains the arguments for compile_backtrackingpath. Must be the first member of its descendants. */ typedef struct backtrack_common { /* Concatenation stack. */ struct backtrack_common *prev; jump_list *nextbacktracks; /* Internal stack (for component operators). */ struct backtrack_common *top; jump_list *topbacktracks; /* Opcode pointer. */ pcre_uchar *cc; } backtrack_common; typedef struct assert_backtrack { backtrack_common common; jump_list *condfailed; /* Less than 0 if a frame is not needed. */ int framesize; /* Points to our private memory word on the stack. */ int private_data_ptr; /* For iterators. */ struct sljit_label *matchingpath; } assert_backtrack; typedef struct bracket_backtrack { backtrack_common common; /* Where to coninue if an alternative is successfully matched. */ struct sljit_label *alternative_matchingpath; /* For rmin and rmax iterators. */ struct sljit_label *recursive_matchingpath; /* For greedy ? operator. */ struct sljit_label *zero_matchingpath; /* Contains the branches of a failed condition. */ union { /* Both for OP_COND, OP_SCOND. */ jump_list *condfailed; assert_backtrack *assert; /* For OP_ONCE. Less than 0 if not needed. */ int framesize; } u; /* Points to our private memory word on the stack. */ int private_data_ptr; } bracket_backtrack; typedef struct bracketpos_backtrack { backtrack_common common; /* Points to our private memory word on the stack. */ int private_data_ptr; /* Reverting stack is needed. */ int framesize; /* Allocated stack size. */ int stacksize; } bracketpos_backtrack; typedef struct braminzero_backtrack { backtrack_common common; struct sljit_label *matchingpath; } braminzero_backtrack; typedef struct char_iterator_backtrack { backtrack_common common; /* Next iteration. */ struct sljit_label *matchingpath; union { jump_list *backtracks; struct { unsigned int othercasebit; pcre_uchar chr; BOOL enabled; } charpos; } u; } char_iterator_backtrack; typedef struct ref_iterator_backtrack { backtrack_common common; /* Next iteration. */ struct sljit_label *matchingpath; } ref_iterator_backtrack; typedef struct recurse_entry { struct recurse_entry *next; /* Contains the function entry. */ struct sljit_label *entry; /* Collects the calls until the function is not created. */ jump_list *calls; /* Points to the starting opcode. */ sljit_sw start; } recurse_entry; typedef struct recurse_backtrack { backtrack_common common; BOOL inlined_pattern; } recurse_backtrack; #define OP_THEN_TRAP OP_TABLE_LENGTH typedef struct then_trap_backtrack { backtrack_common common; /* If then_trap is not NULL, this structure contains the real then_trap for the backtracking path. */ struct then_trap_backtrack *then_trap; /* Points to the starting opcode. */ sljit_sw start; /* Exit point for the then opcodes of this alternative. */ jump_list *quit; /* Frame size of the current alternative. */ int framesize; } then_trap_backtrack; #define MAX_RANGE_SIZE 4 typedef struct compiler_common { /* The sljit ceneric compiler. */ struct sljit_compiler *compiler; /* First byte code. */ pcre_uchar *start; /* Maps private data offset to each opcode. */ sljit_s32 *private_data_ptrs; /* Chain list of read-only data ptrs. */ void *read_only_data_head; /* Tells whether the capturing bracket is optimized. */ sljit_u8 *optimized_cbracket; /* Tells whether the starting offset is a target of then. */ sljit_u8 *then_offsets; /* Current position where a THEN must jump. */ then_trap_backtrack *then_trap; /* Starting offset of private data for capturing brackets. */ sljit_s32 cbra_ptr; /* Output vector starting point. Must be divisible by 2. */ sljit_s32 ovector_start; /* Points to the starting character of the current match. */ sljit_s32 start_ptr; /* Last known position of the requested byte. */ sljit_s32 req_char_ptr; /* Head of the last recursion. */ sljit_s32 recursive_head_ptr; /* First inspected character for partial matching. (Needed for avoiding zero length partial matches.) */ sljit_s32 start_used_ptr; /* Starting pointer for partial soft matches. */ sljit_s32 hit_start; /* Pointer of the match end position. */ sljit_s32 match_end_ptr; /* Points to the marked string. */ sljit_s32 mark_ptr; /* Recursive control verb management chain. */ sljit_s32 control_head_ptr; /* Points to the last matched capture block index. */ sljit_s32 capture_last_ptr; /* Fast forward skipping byte code pointer. */ pcre_uchar *fast_forward_bc_ptr; /* Locals used by fast fail optimization. */ sljit_s32 fast_fail_start_ptr; sljit_s32 fast_fail_end_ptr; /* Flipped and lower case tables. */ const sljit_u8 *fcc; sljit_sw lcc; /* Mode can be PCRE_STUDY_JIT_COMPILE and others. */ int mode; /* TRUE, when minlength is greater than 0. */ BOOL might_be_empty; /* \K is found in the pattern. */ BOOL has_set_som; /* (*SKIP:arg) is found in the pattern. */ BOOL has_skip_arg; /* (*THEN) is found in the pattern. */ BOOL has_then; /* (*SKIP) or (*SKIP:arg) is found in lookbehind assertion. */ BOOL has_skip_in_assert_back; /* Currently in recurse or negative assert. */ BOOL local_exit; /* Currently in a positive assert. */ BOOL positive_assert; /* Newline control. */ int nltype; sljit_u32 nlmax; sljit_u32 nlmin; int newline; int bsr_nltype; sljit_u32 bsr_nlmax; sljit_u32 bsr_nlmin; /* Dollar endonly. */ int endonly; /* Tables. */ sljit_sw ctypes; /* Named capturing brackets. */ pcre_uchar *name_table; sljit_sw name_count; sljit_sw name_entry_size; /* Labels and jump lists. */ struct sljit_label *partialmatchlabel; struct sljit_label *quit_label; struct sljit_label *forced_quit_label; struct sljit_label *accept_label; struct sljit_label *ff_newline_shortcut; stub_list *stubs; label_addr_list *label_addrs; recurse_entry *entries; recurse_entry *currententry; jump_list *partialmatch; jump_list *quit; jump_list *positive_assert_quit; jump_list *forced_quit; jump_list *accept; jump_list *calllimit; jump_list *stackalloc; jump_list *revertframes; jump_list *wordboundary; jump_list *anynewline; jump_list *hspace; jump_list *vspace; jump_list *casefulcmp; jump_list *caselesscmp; jump_list *reset_match; BOOL jscript_compat; #ifdef SUPPORT_UTF BOOL utf; #ifdef SUPPORT_UCP BOOL use_ucp; jump_list *getucd; #endif #ifdef COMPILE_PCRE8 jump_list *utfreadchar; jump_list *utfreadchar16; jump_list *utfreadtype8; #endif #endif /* SUPPORT_UTF */ } compiler_common; /* For byte_sequence_compare. */ typedef struct compare_context { int length; int sourcereg; #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED int ucharptr; union { sljit_s32 asint; sljit_u16 asushort; #if defined COMPILE_PCRE8 sljit_u8 asbyte; sljit_u8 asuchars[4]; #elif defined COMPILE_PCRE16 sljit_u16 asuchars[2]; #elif defined COMPILE_PCRE32 sljit_u32 asuchars[1]; #endif } c; union { sljit_s32 asint; sljit_u16 asushort; #if defined COMPILE_PCRE8 sljit_u8 asbyte; sljit_u8 asuchars[4]; #elif defined COMPILE_PCRE16 sljit_u16 asuchars[2]; #elif defined COMPILE_PCRE32 sljit_u32 asuchars[1]; #endif } oc; #endif } compare_context; /* Undefine sljit macros. */ #undef CMP /* Used for accessing the elements of the stack. */ #define STACK(i) ((i) * (int)sizeof(sljit_sw)) #ifdef SLJIT_PREF_SHIFT_REG #if SLJIT_PREF_SHIFT_REG == SLJIT_R2 /* Nothing. */ #elif SLJIT_PREF_SHIFT_REG == SLJIT_R3 #define SHIFT_REG_IS_R3 #else #error "Unsupported shift register" #endif #endif #define TMP1 SLJIT_R0 #ifdef SHIFT_REG_IS_R3 #define TMP2 SLJIT_R3 #define TMP3 SLJIT_R2 #else #define TMP2 SLJIT_R2 #define TMP3 SLJIT_R3 #endif #define STR_PTR SLJIT_S0 #define STR_END SLJIT_S1 #define STACK_TOP SLJIT_R1 #define STACK_LIMIT SLJIT_S2 #define COUNT_MATCH SLJIT_S3 #define ARGUMENTS SLJIT_S4 #define RETURN_ADDR SLJIT_R4 /* Local space layout. */ /* These two locals can be used by the current opcode. */ #define LOCALS0 (0 * sizeof(sljit_sw)) #define LOCALS1 (1 * sizeof(sljit_sw)) /* Two local variables for possessive quantifiers (char1 cannot use them). */ #define POSSESSIVE0 (2 * sizeof(sljit_sw)) #define POSSESSIVE1 (3 * sizeof(sljit_sw)) /* Max limit of recursions. */ #define LIMIT_MATCH (4 * sizeof(sljit_sw)) /* The output vector is stored on the stack, and contains pointers to characters. The vector data is divided into two groups: the first group contains the start / end character pointers, and the second is the start pointers when the end of the capturing group has not yet reached. */ #define OVECTOR_START (common->ovector_start) #define OVECTOR(i) (OVECTOR_START + (i) * (sljit_sw)sizeof(sljit_sw)) #define OVECTOR_PRIV(i) (common->cbra_ptr + (i) * (sljit_sw)sizeof(sljit_sw)) #define PRIVATE_DATA(cc) (common->private_data_ptrs[(cc) - common->start]) #if defined COMPILE_PCRE8 #define MOV_UCHAR SLJIT_MOV_U8 #elif defined COMPILE_PCRE16 #define MOV_UCHAR SLJIT_MOV_U16 #elif defined COMPILE_PCRE32 #define MOV_UCHAR SLJIT_MOV_U32 #else #error Unsupported compiling mode #endif /* Shortcuts. */ #define DEFINE_COMPILER \ struct sljit_compiler *compiler = common->compiler #define OP1(op, dst, dstw, src, srcw) \ sljit_emit_op1(compiler, (op), (dst), (dstw), (src), (srcw)) #define OP2(op, dst, dstw, src1, src1w, src2, src2w) \ sljit_emit_op2(compiler, (op), (dst), (dstw), (src1), (src1w), (src2), (src2w)) #define LABEL() \ sljit_emit_label(compiler) #define JUMP(type) \ sljit_emit_jump(compiler, (type)) #define JUMPTO(type, label) \ sljit_set_label(sljit_emit_jump(compiler, (type)), (label)) #define JUMPHERE(jump) \ sljit_set_label((jump), sljit_emit_label(compiler)) #define SET_LABEL(jump, label) \ sljit_set_label((jump), (label)) #define CMP(type, src1, src1w, src2, src2w) \ sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)) #define CMPTO(type, src1, src1w, src2, src2w, label) \ sljit_set_label(sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)), (label)) #define OP_FLAGS(op, dst, dstw, type) \ sljit_emit_op_flags(compiler, (op), (dst), (dstw), (type)) #define GET_LOCAL_BASE(dst, dstw, offset) \ sljit_get_local_base(compiler, (dst), (dstw), (offset)) #define READ_CHAR_MAX 0x7fffffff #define INVALID_UTF_CHAR 888 static pcre_uchar *bracketend(pcre_uchar *cc) { SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND)); do cc += GET(cc, 1); while (*cc == OP_ALT); SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS); cc += 1 + LINK_SIZE; return cc; } static int no_alternatives(pcre_uchar *cc) { int count = 0; SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND)); do { cc += GET(cc, 1); count++; } while (*cc == OP_ALT); SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS); return count; } /* Functions whose might need modification for all new supported opcodes: next_opcode check_opcode_types set_private_data_ptrs get_framesize init_frame get_private_data_copy_length copy_private_data compile_matchingpath compile_backtrackingpath */ static pcre_uchar *next_opcode(compiler_common *common, pcre_uchar *cc) { SLJIT_UNUSED_ARG(common); switch(*cc) { case OP_SOD: case OP_SOM: case OP_SET_SOM: case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: case OP_ALLANY: case OP_NOTPROP: case OP_PROP: case OP_ANYNL: case OP_NOT_HSPACE: case OP_HSPACE: case OP_NOT_VSPACE: case OP_VSPACE: case OP_EXTUNI: case OP_EODN: case OP_EOD: case OP_CIRC: case OP_CIRCM: case OP_DOLL: case OP_DOLLM: case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSSTAR: case OP_CRPOSPLUS: case OP_CRPOSQUERY: case OP_CRPOSRANGE: case OP_CLASS: case OP_NCLASS: case OP_REF: case OP_REFI: case OP_DNREF: case OP_DNREFI: case OP_RECURSE: case OP_CALLOUT: case OP_ALT: case OP_KET: case OP_KETRMAX: case OP_KETRMIN: case OP_KETRPOS: case OP_REVERSE: case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: case OP_ONCE_NC: case OP_BRA: case OP_BRAPOS: case OP_CBRA: case OP_CBRAPOS: case OP_COND: case OP_SBRA: case OP_SBRAPOS: case OP_SCBRA: case OP_SCBRAPOS: case OP_SCOND: case OP_CREF: case OP_DNCREF: case OP_RREF: case OP_DNRREF: case OP_DEF: case OP_BRAZERO: case OP_BRAMINZERO: case OP_BRAPOSZERO: case OP_PRUNE: case OP_SKIP: case OP_THEN: case OP_COMMIT: case OP_FAIL: case OP_ACCEPT: case OP_ASSERT_ACCEPT: case OP_CLOSE: case OP_SKIPZERO: return cc + PRIV(OP_lengths)[*cc]; case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: case OP_UPTO: case OP_MINUPTO: case OP_EXACT: case OP_POSSTAR: case OP_POSPLUS: case OP_POSQUERY: case OP_POSUPTO: case OP_STARI: case OP_MINSTARI: case OP_PLUSI: case OP_MINPLUSI: case OP_QUERYI: case OP_MINQUERYI: case OP_UPTOI: case OP_MINUPTOI: case OP_EXACTI: case OP_POSSTARI: case OP_POSPLUSI: case OP_POSQUERYI: case OP_POSUPTOI: case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: case OP_NOTUPTO: case OP_NOTMINUPTO: case OP_NOTEXACT: case OP_NOTPOSSTAR: case OP_NOTPOSPLUS: case OP_NOTPOSQUERY: case OP_NOTPOSUPTO: case OP_NOTSTARI: case OP_NOTMINSTARI: case OP_NOTPLUSI: case OP_NOTMINPLUSI: case OP_NOTQUERYI: case OP_NOTMINQUERYI: case OP_NOTUPTOI: case OP_NOTMINUPTOI: case OP_NOTEXACTI: case OP_NOTPOSSTARI: case OP_NOTPOSPLUSI: case OP_NOTPOSQUERYI: case OP_NOTPOSUPTOI: cc += PRIV(OP_lengths)[*cc]; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif return cc; /* Special cases. */ case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEEXACT: case OP_TYPEPOSSTAR: case OP_TYPEPOSPLUS: case OP_TYPEPOSQUERY: case OP_TYPEPOSUPTO: return cc + PRIV(OP_lengths)[*cc] - 1; case OP_ANYBYTE: #ifdef SUPPORT_UTF if (common->utf) return NULL; #endif return cc + 1; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: return cc + GET(cc, 1); #endif case OP_MARK: case OP_PRUNE_ARG: case OP_SKIP_ARG: case OP_THEN_ARG: return cc + 1 + 2 + cc[1]; default: /* All opcodes are supported now! */ SLJIT_UNREACHABLE(); return NULL; } } static BOOL check_opcode_types(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend) { int count; pcre_uchar *slot; pcre_uchar *assert_back_end = cc - 1; /* Calculate important variables (like stack size) and checks whether all opcodes are supported. */ while (cc < ccend) { switch(*cc) { case OP_SET_SOM: common->has_set_som = TRUE; common->might_be_empty = TRUE; cc += 1; break; case OP_REF: case OP_REFI: common->optimized_cbracket[GET2(cc, 1)] = 0; cc += 1 + IMM2_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] = 0; cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_COND: case OP_SCOND: /* Only AUTO_CALLOUT can insert this opcode. We do not intend to support this case. */ if (cc[1 + LINK_SIZE] == OP_CALLOUT) return FALSE; cc += 1 + LINK_SIZE; break; case OP_CREF: common->optimized_cbracket[GET2(cc, 1)] = 0; cc += 1 + IMM2_SIZE; break; case OP_DNREF: case OP_DNREFI: case OP_DNCREF: count = GET2(cc, 1 + IMM2_SIZE); slot = common->name_table + GET2(cc, 1) * common->name_entry_size; while (count-- > 0) { common->optimized_cbracket[GET2(slot, 0)] = 0; slot += common->name_entry_size; } cc += 1 + 2 * IMM2_SIZE; break; case OP_RECURSE: /* Set its value only once. */ if (common->recursive_head_ptr == 0) { common->recursive_head_ptr = common->ovector_start; common->ovector_start += sizeof(sljit_sw); } cc += 1 + LINK_SIZE; break; case OP_CALLOUT: if (common->capture_last_ptr == 0) { common->capture_last_ptr = common->ovector_start; common->ovector_start += sizeof(sljit_sw); } cc += 2 + 2 * LINK_SIZE; break; case OP_ASSERTBACK: slot = bracketend(cc); if (slot > assert_back_end) assert_back_end = slot; cc += 1 + LINK_SIZE; break; case OP_THEN_ARG: common->has_then = TRUE; common->control_head_ptr = 1; /* Fall through. */ case OP_PRUNE_ARG: case OP_MARK: if (common->mark_ptr == 0) { common->mark_ptr = common->ovector_start; common->ovector_start += sizeof(sljit_sw); } cc += 1 + 2 + cc[1]; break; case OP_THEN: common->has_then = TRUE; common->control_head_ptr = 1; cc += 1; break; case OP_SKIP: if (cc < assert_back_end) common->has_skip_in_assert_back = TRUE; cc += 1; break; case OP_SKIP_ARG: common->control_head_ptr = 1; common->has_skip_arg = TRUE; if (cc < assert_back_end) common->has_skip_in_assert_back = TRUE; cc += 1 + 2 + cc[1]; break; default: cc = next_opcode(common, cc); if (cc == NULL) return FALSE; break; } } return TRUE; } static BOOL is_accelerated_repeat(pcre_uchar *cc) { switch(*cc) { case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEPOSSTAR: case OP_TYPEPOSPLUS: return (cc[1] != OP_ANYNL && cc[1] != OP_EXTUNI); case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_POSSTAR: case OP_POSPLUS: case OP_STARI: case OP_MINSTARI: case OP_PLUSI: case OP_MINPLUSI: case OP_POSSTARI: case OP_POSPLUSI: case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTPOSSTAR: case OP_NOTPOSPLUS: case OP_NOTSTARI: case OP_NOTMINSTARI: case OP_NOTPLUSI: case OP_NOTMINPLUSI: case OP_NOTPOSSTARI: case OP_NOTPOSPLUSI: return TRUE; case OP_CLASS: case OP_NCLASS: #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: cc += (*cc == OP_XCLASS) ? GET(cc, 1) : (int)(1 + (32 / sizeof(pcre_uchar))); #else cc += (1 + (32 / sizeof(pcre_uchar))); #endif switch(*cc) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRPOSSTAR: case OP_CRPOSPLUS: return TRUE; } break; } return FALSE; } static SLJIT_INLINE BOOL detect_fast_forward_skip(compiler_common *common, int *private_data_start) { pcre_uchar *cc = common->start; pcre_uchar *end; /* Skip not repeated brackets. */ while (TRUE) { switch(*cc) { case OP_SOD: case OP_SOM: case OP_SET_SOM: case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: case OP_EODN: case OP_EOD: case OP_CIRC: case OP_CIRCM: case OP_DOLL: case OP_DOLLM: /* Zero width assertions. */ cc++; continue; } if (*cc != OP_BRA && *cc != OP_CBRA) break; end = cc + GET(cc, 1); if (*end != OP_KET || PRIVATE_DATA(end) != 0) return FALSE; if (*cc == OP_CBRA) { if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) return FALSE; cc += IMM2_SIZE; } cc += 1 + LINK_SIZE; } if (is_accelerated_repeat(cc)) { common->fast_forward_bc_ptr = cc; common->private_data_ptrs[(cc + 1) - common->start] = *private_data_start; *private_data_start += sizeof(sljit_sw); return TRUE; } return FALSE; } static SLJIT_INLINE void detect_fast_fail(compiler_common *common, pcre_uchar *cc, int *private_data_start, sljit_s32 depth) { pcre_uchar *next_alt; SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA); if (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) return; next_alt = bracketend(cc) - (1 + LINK_SIZE); if (*next_alt != OP_KET || PRIVATE_DATA(next_alt) != 0) return; do { next_alt = cc + GET(cc, 1); cc += 1 + LINK_SIZE + ((*cc == OP_CBRA) ? IMM2_SIZE : 0); while (TRUE) { switch(*cc) { case OP_SOD: case OP_SOM: case OP_SET_SOM: case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: case OP_EODN: case OP_EOD: case OP_CIRC: case OP_CIRCM: case OP_DOLL: case OP_DOLLM: /* Zero width assertions. */ cc++; continue; } break; } if (depth > 0 && (*cc == OP_BRA || *cc == OP_CBRA)) detect_fast_fail(common, cc, private_data_start, depth - 1); if (is_accelerated_repeat(cc)) { common->private_data_ptrs[(cc + 1) - common->start] = *private_data_start; if (common->fast_fail_start_ptr == 0) common->fast_fail_start_ptr = *private_data_start; *private_data_start += sizeof(sljit_sw); common->fast_fail_end_ptr = *private_data_start; if (*private_data_start > SLJIT_MAX_LOCAL_SIZE) return; } cc = next_alt; } while (*cc == OP_ALT); } static int get_class_iterator_size(pcre_uchar *cc) { sljit_u32 min; sljit_u32 max; switch(*cc) { case OP_CRSTAR: case OP_CRPLUS: return 2; case OP_CRMINSTAR: case OP_CRMINPLUS: case OP_CRQUERY: case OP_CRMINQUERY: return 1; case OP_CRRANGE: case OP_CRMINRANGE: min = GET2(cc, 1); max = GET2(cc, 1 + IMM2_SIZE); if (max == 0) return (*cc == OP_CRRANGE) ? 2 : 1; max -= min; if (max > 2) max = 2; return max; default: return 0; } } static BOOL detect_repeat(compiler_common *common, pcre_uchar *begin) { pcre_uchar *end = bracketend(begin); pcre_uchar *next; pcre_uchar *next_end; pcre_uchar *max_end; pcre_uchar type; sljit_sw length = end - begin; int min, max, i; /* Detect fixed iterations first. */ if (end[-(1 + LINK_SIZE)] != OP_KET) return FALSE; /* Already detected repeat. */ if (common->private_data_ptrs[end - common->start - LINK_SIZE] != 0) return TRUE; next = end; min = 1; while (1) { if (*next != *begin) break; next_end = bracketend(next); if (next_end - next != length || memcmp(begin, next, IN_UCHARS(length)) != 0) break; next = next_end; min++; } if (min == 2) return FALSE; max = 0; max_end = next; if (*next == OP_BRAZERO || *next == OP_BRAMINZERO) { type = *next; while (1) { if (next[0] != type || next[1] != OP_BRA || next[2 + LINK_SIZE] != *begin) break; next_end = bracketend(next + 2 + LINK_SIZE); if (next_end - next != (length + 2 + LINK_SIZE) || memcmp(begin, next + 2 + LINK_SIZE, IN_UCHARS(length)) != 0) break; next = next_end; max++; } if (next[0] == type && next[1] == *begin && max >= 1) { next_end = bracketend(next + 1); if (next_end - next == (length + 1) && memcmp(begin, next + 1, IN_UCHARS(length)) == 0) { for (i = 0; i < max; i++, next_end += 1 + LINK_SIZE) if (*next_end != OP_KET) break; if (i == max) { common->private_data_ptrs[max_end - common->start - LINK_SIZE] = next_end - max_end; common->private_data_ptrs[max_end - common->start - LINK_SIZE + 1] = (type == OP_BRAZERO) ? OP_UPTO : OP_MINUPTO; /* +2 the original and the last. */ common->private_data_ptrs[max_end - common->start - LINK_SIZE + 2] = max + 2; if (min == 1) return TRUE; min--; max_end -= (1 + LINK_SIZE) + GET(max_end, -LINK_SIZE); } } } } if (min >= 3) { common->private_data_ptrs[end - common->start - LINK_SIZE] = max_end - end; common->private_data_ptrs[end - common->start - LINK_SIZE + 1] = OP_EXACT; common->private_data_ptrs[end - common->start - LINK_SIZE + 2] = min; return TRUE; } return FALSE; } #define CASE_ITERATOR_PRIVATE_DATA_1 \ case OP_MINSTAR: \ case OP_MINPLUS: \ case OP_QUERY: \ case OP_MINQUERY: \ case OP_MINSTARI: \ case OP_MINPLUSI: \ case OP_QUERYI: \ case OP_MINQUERYI: \ case OP_NOTMINSTAR: \ case OP_NOTMINPLUS: \ case OP_NOTQUERY: \ case OP_NOTMINQUERY: \ case OP_NOTMINSTARI: \ case OP_NOTMINPLUSI: \ case OP_NOTQUERYI: \ case OP_NOTMINQUERYI: #define CASE_ITERATOR_PRIVATE_DATA_2A \ case OP_STAR: \ case OP_PLUS: \ case OP_STARI: \ case OP_PLUSI: \ case OP_NOTSTAR: \ case OP_NOTPLUS: \ case OP_NOTSTARI: \ case OP_NOTPLUSI: #define CASE_ITERATOR_PRIVATE_DATA_2B \ case OP_UPTO: \ case OP_MINUPTO: \ case OP_UPTOI: \ case OP_MINUPTOI: \ case OP_NOTUPTO: \ case OP_NOTMINUPTO: \ case OP_NOTUPTOI: \ case OP_NOTMINUPTOI: #define CASE_ITERATOR_TYPE_PRIVATE_DATA_1 \ case OP_TYPEMINSTAR: \ case OP_TYPEMINPLUS: \ case OP_TYPEQUERY: \ case OP_TYPEMINQUERY: #define CASE_ITERATOR_TYPE_PRIVATE_DATA_2A \ case OP_TYPESTAR: \ case OP_TYPEPLUS: #define CASE_ITERATOR_TYPE_PRIVATE_DATA_2B \ case OP_TYPEUPTO: \ case OP_TYPEMINUPTO: static void set_private_data_ptrs(compiler_common *common, int *private_data_start, pcre_uchar *ccend) { pcre_uchar *cc = common->start; pcre_uchar *alternative; pcre_uchar *end = NULL; int private_data_ptr = *private_data_start; int space, size, bracketlen; BOOL repeat_check = TRUE; while (cc < ccend) { space = 0; size = 0; bracketlen = 0; if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE) break; if (repeat_check && (*cc == OP_ONCE || *cc == OP_ONCE_NC || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND)) { if (detect_repeat(common, cc)) { /* These brackets are converted to repeats, so no global based single character repeat is allowed. */ if (cc >= end) end = bracketend(cc); } } repeat_check = TRUE; switch(*cc) { case OP_KET: if (common->private_data_ptrs[cc + 1 - common->start] != 0) { common->private_data_ptrs[cc - common->start] = private_data_ptr; private_data_ptr += sizeof(sljit_sw); cc += common->private_data_ptrs[cc + 1 - common->start]; } cc += 1 + LINK_SIZE; break; case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: case OP_ONCE_NC: case OP_BRAPOS: case OP_SBRA: case OP_SBRAPOS: case OP_SCOND: common->private_data_ptrs[cc - common->start] = private_data_ptr; private_data_ptr += sizeof(sljit_sw); bracketlen = 1 + LINK_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: common->private_data_ptrs[cc - common->start] = private_data_ptr; private_data_ptr += sizeof(sljit_sw); bracketlen = 1 + LINK_SIZE + IMM2_SIZE; break; case OP_COND: /* Might be a hidden SCOND. */ alternative = cc + GET(cc, 1); if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) { common->private_data_ptrs[cc - common->start] = private_data_ptr; private_data_ptr += sizeof(sljit_sw); } bracketlen = 1 + LINK_SIZE; break; case OP_BRA: bracketlen = 1 + LINK_SIZE; break; case OP_CBRA: case OP_SCBRA: bracketlen = 1 + LINK_SIZE + IMM2_SIZE; break; case OP_BRAZERO: case OP_BRAMINZERO: case OP_BRAPOSZERO: repeat_check = FALSE; size = 1; break; CASE_ITERATOR_PRIVATE_DATA_1 space = 1; size = -2; break; CASE_ITERATOR_PRIVATE_DATA_2A space = 2; size = -2; break; CASE_ITERATOR_PRIVATE_DATA_2B space = 2; size = -(2 + IMM2_SIZE); break; CASE_ITERATOR_TYPE_PRIVATE_DATA_1 space = 1; size = 1; break; CASE_ITERATOR_TYPE_PRIVATE_DATA_2A if (cc[1] != OP_ANYNL && cc[1] != OP_EXTUNI) space = 2; size = 1; break; case OP_TYPEUPTO: if (cc[1 + IMM2_SIZE] != OP_ANYNL && cc[1 + IMM2_SIZE] != OP_EXTUNI) space = 2; size = 1 + IMM2_SIZE; break; case OP_TYPEMINUPTO: space = 2; size = 1 + IMM2_SIZE; break; case OP_CLASS: case OP_NCLASS: space = get_class_iterator_size(cc + size); size = 1 + 32 / sizeof(pcre_uchar); break; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: space = get_class_iterator_size(cc + size); size = GET(cc, 1); break; #endif default: cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); break; } /* Character iterators, which are not inside a repeated bracket, gets a private slot instead of allocating it on the stack. */ if (space > 0 && cc >= end) { common->private_data_ptrs[cc - common->start] = private_data_ptr; private_data_ptr += sizeof(sljit_sw) * space; } if (size != 0) { if (size < 0) { cc += -size; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif } else cc += size; } if (bracketlen > 0) { if (cc >= end) { end = bracketend(cc); if (end[-1 - LINK_SIZE] == OP_KET) end = NULL; } cc += bracketlen; } } *private_data_start = private_data_ptr; } /* Returns with a frame_types (always < 0) if no need for frame. */ static int get_framesize(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, BOOL recursive, BOOL *needs_control_head) { int length = 0; int possessive = 0; BOOL stack_restore = FALSE; BOOL setsom_found = recursive; BOOL setmark_found = recursive; /* The last capture is a local variable even for recursions. */ BOOL capture_last_found = FALSE; #if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD SLJIT_ASSERT(common->control_head_ptr != 0); *needs_control_head = TRUE; #else *needs_control_head = FALSE; #endif if (ccend == NULL) { ccend = bracketend(cc) - (1 + LINK_SIZE); if (!recursive && (*cc == OP_CBRAPOS || *cc == OP_SCBRAPOS)) { possessive = length = (common->capture_last_ptr != 0) ? 5 : 3; /* This is correct regardless of common->capture_last_ptr. */ capture_last_found = TRUE; } cc = next_opcode(common, cc); } SLJIT_ASSERT(cc != NULL); while (cc < ccend) switch(*cc) { case OP_SET_SOM: SLJIT_ASSERT(common->has_set_som); stack_restore = TRUE; if (!setsom_found) { length += 2; setsom_found = TRUE; } cc += 1; break; case OP_MARK: case OP_PRUNE_ARG: case OP_THEN_ARG: SLJIT_ASSERT(common->mark_ptr != 0); stack_restore = TRUE; if (!setmark_found) { length += 2; setmark_found = TRUE; } if (common->control_head_ptr != 0) *needs_control_head = TRUE; cc += 1 + 2 + cc[1]; break; case OP_RECURSE: stack_restore = TRUE; if (common->has_set_som && !setsom_found) { length += 2; setsom_found = TRUE; } if (common->mark_ptr != 0 && !setmark_found) { length += 2; setmark_found = TRUE; } if (common->capture_last_ptr != 0 && !capture_last_found) { length += 2; capture_last_found = TRUE; } cc += 1 + LINK_SIZE; break; case OP_CBRA: case OP_CBRAPOS: case OP_SCBRA: case OP_SCBRAPOS: stack_restore = TRUE; if (common->capture_last_ptr != 0 && !capture_last_found) { length += 2; capture_last_found = TRUE; } length += 3; cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_THEN: stack_restore = TRUE; if (common->control_head_ptr != 0) *needs_control_head = TRUE; cc ++; break; default: stack_restore = TRUE; /* Fall through. */ case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: case OP_ALLANY: case OP_ANYBYTE: case OP_NOTPROP: case OP_PROP: case OP_ANYNL: case OP_NOT_HSPACE: case OP_HSPACE: case OP_NOT_VSPACE: case OP_VSPACE: case OP_EXTUNI: case OP_EODN: case OP_EOD: case OP_CIRC: case OP_CIRCM: case OP_DOLL: case OP_DOLLM: case OP_CHAR: case OP_CHARI: case OP_NOT: case OP_NOTI: case OP_EXACT: case OP_POSSTAR: case OP_POSPLUS: case OP_POSQUERY: case OP_POSUPTO: case OP_EXACTI: case OP_POSSTARI: case OP_POSPLUSI: case OP_POSQUERYI: case OP_POSUPTOI: case OP_NOTEXACT: case OP_NOTPOSSTAR: case OP_NOTPOSPLUS: case OP_NOTPOSQUERY: case OP_NOTPOSUPTO: case OP_NOTEXACTI: case OP_NOTPOSSTARI: case OP_NOTPOSPLUSI: case OP_NOTPOSQUERYI: case OP_NOTPOSUPTOI: case OP_TYPEEXACT: case OP_TYPEPOSSTAR: case OP_TYPEPOSPLUS: case OP_TYPEPOSQUERY: case OP_TYPEPOSUPTO: case OP_CLASS: case OP_NCLASS: case OP_XCLASS: case OP_CALLOUT: cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); break; } /* Possessive quantifiers can use a special case. */ if (SLJIT_UNLIKELY(possessive == length)) return stack_restore ? no_frame : no_stack; if (length > 0) return length + 1; return stack_restore ? no_frame : no_stack; } static void init_frame(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, int stackpos, int stacktop, BOOL recursive) { DEFINE_COMPILER; BOOL setsom_found = recursive; BOOL setmark_found = recursive; /* The last capture is a local variable even for recursions. */ BOOL capture_last_found = FALSE; int offset; /* >= 1 + shortest item size (2) */ SLJIT_UNUSED_ARG(stacktop); SLJIT_ASSERT(stackpos >= stacktop + 2); stackpos = STACK(stackpos); if (ccend == NULL) { ccend = bracketend(cc) - (1 + LINK_SIZE); if (recursive || (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS)) cc = next_opcode(common, cc); } SLJIT_ASSERT(cc != NULL); while (cc < ccend) switch(*cc) { case OP_SET_SOM: SLJIT_ASSERT(common->has_set_som); if (!setsom_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0)); stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); stackpos -= (int)sizeof(sljit_sw); setsom_found = TRUE; } cc += 1; break; case OP_MARK: case OP_PRUNE_ARG: case OP_THEN_ARG: SLJIT_ASSERT(common->mark_ptr != 0); if (!setmark_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr); stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); stackpos -= (int)sizeof(sljit_sw); setmark_found = TRUE; } cc += 1 + 2 + cc[1]; break; case OP_RECURSE: if (common->has_set_som && !setsom_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0)); stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); stackpos -= (int)sizeof(sljit_sw); setsom_found = TRUE; } if (common->mark_ptr != 0 && !setmark_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr); stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); stackpos -= (int)sizeof(sljit_sw); setmark_found = TRUE; } if (common->capture_last_ptr != 0 && !capture_last_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr); stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); stackpos -= (int)sizeof(sljit_sw); capture_last_found = TRUE; } cc += 1 + LINK_SIZE; break; case OP_CBRA: case OP_CBRAPOS: case OP_SCBRA: case OP_SCBRAPOS: if (common->capture_last_ptr != 0 && !capture_last_found) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr); stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); stackpos -= (int)sizeof(sljit_sw); capture_last_found = TRUE; } offset = (GET2(cc, 1 + LINK_SIZE)) << 1; OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset)); stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0); stackpos -= (int)sizeof(sljit_sw); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0); stackpos -= (int)sizeof(sljit_sw); cc += 1 + LINK_SIZE + IMM2_SIZE; break; default: cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); break; } OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, 0); SLJIT_ASSERT(stackpos == STACK(stacktop)); } static SLJIT_INLINE int get_private_data_copy_length(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, BOOL needs_control_head) { int private_data_length = needs_control_head ? 3 : 2; int size; pcre_uchar *alternative; /* Calculate the sum of the private machine words. */ while (cc < ccend) { size = 0; switch(*cc) { case OP_KET: if (PRIVATE_DATA(cc) != 0) { private_data_length++; SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0); cc += PRIVATE_DATA(cc + 1); } cc += 1 + LINK_SIZE; break; case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: case OP_ONCE_NC: case OP_BRAPOS: case OP_SBRA: case OP_SBRAPOS: case OP_SCOND: private_data_length++; SLJIT_ASSERT(PRIVATE_DATA(cc) != 0); cc += 1 + LINK_SIZE; break; case OP_CBRA: case OP_SCBRA: if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) private_data_length++; cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: private_data_length += 2; cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_COND: /* Might be a hidden SCOND. */ alternative = cc + GET(cc, 1); if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) private_data_length++; cc += 1 + LINK_SIZE; break; CASE_ITERATOR_PRIVATE_DATA_1 if (PRIVATE_DATA(cc)) private_data_length++; cc += 2; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; CASE_ITERATOR_PRIVATE_DATA_2A if (PRIVATE_DATA(cc)) private_data_length += 2; cc += 2; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; CASE_ITERATOR_PRIVATE_DATA_2B if (PRIVATE_DATA(cc)) private_data_length += 2; cc += 2 + IMM2_SIZE; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; CASE_ITERATOR_TYPE_PRIVATE_DATA_1 if (PRIVATE_DATA(cc)) private_data_length++; cc += 1; break; CASE_ITERATOR_TYPE_PRIVATE_DATA_2A if (PRIVATE_DATA(cc)) private_data_length += 2; cc += 1; break; CASE_ITERATOR_TYPE_PRIVATE_DATA_2B if (PRIVATE_DATA(cc)) private_data_length += 2; cc += 1 + IMM2_SIZE; break; case OP_CLASS: case OP_NCLASS: #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(pcre_uchar); #else size = 1 + 32 / (int)sizeof(pcre_uchar); #endif if (PRIVATE_DATA(cc)) private_data_length += get_class_iterator_size(cc + size); cc += size; break; default: cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); break; } } SLJIT_ASSERT(cc == ccend); return private_data_length; } static void copy_private_data(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, BOOL save, int stackptr, int stacktop, BOOL needs_control_head) { DEFINE_COMPILER; int srcw[2]; int count, size; BOOL tmp1next = TRUE; BOOL tmp1empty = TRUE; BOOL tmp2empty = TRUE; pcre_uchar *alternative; enum { loop, end } status; status = loop; stackptr = STACK(stackptr); stacktop = STACK(stacktop - 1); if (!save) { stacktop -= (needs_control_head ? 2 : 1) * sizeof(sljit_sw); if (stackptr < stacktop) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), stackptr); stackptr += sizeof(sljit_sw); tmp1empty = FALSE; } if (stackptr < stacktop) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), stackptr); stackptr += sizeof(sljit_sw); tmp2empty = FALSE; } /* The tmp1next must be TRUE in either way. */ } SLJIT_ASSERT(common->recursive_head_ptr != 0); do { count = 0; if (cc >= ccend) { if (!save) break; count = 1; srcw[0] = common->recursive_head_ptr; if (needs_control_head) { SLJIT_ASSERT(common->control_head_ptr != 0); count = 2; srcw[0] = common->control_head_ptr; srcw[1] = common->recursive_head_ptr; } status = end; } else switch(*cc) { case OP_KET: if (PRIVATE_DATA(cc) != 0) { count = 1; srcw[0] = PRIVATE_DATA(cc); SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0); cc += PRIVATE_DATA(cc + 1); } cc += 1 + LINK_SIZE; break; case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: case OP_ONCE: case OP_ONCE_NC: case OP_BRAPOS: case OP_SBRA: case OP_SBRAPOS: case OP_SCOND: count = 1; srcw[0] = PRIVATE_DATA(cc); SLJIT_ASSERT(srcw[0] != 0); cc += 1 + LINK_SIZE; break; case OP_CBRA: case OP_SCBRA: if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0) { count = 1; srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE)); } cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: count = 2; srcw[0] = PRIVATE_DATA(cc); srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE)); SLJIT_ASSERT(srcw[0] != 0 && srcw[1] != 0); cc += 1 + LINK_SIZE + IMM2_SIZE; break; case OP_COND: /* Might be a hidden SCOND. */ alternative = cc + GET(cc, 1); if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN) { count = 1; srcw[0] = PRIVATE_DATA(cc); SLJIT_ASSERT(srcw[0] != 0); } cc += 1 + LINK_SIZE; break; CASE_ITERATOR_PRIVATE_DATA_1 if (PRIVATE_DATA(cc)) { count = 1; srcw[0] = PRIVATE_DATA(cc); } cc += 2; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; CASE_ITERATOR_PRIVATE_DATA_2A if (PRIVATE_DATA(cc)) { count = 2; srcw[0] = PRIVATE_DATA(cc); srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw); } cc += 2; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; CASE_ITERATOR_PRIVATE_DATA_2B if (PRIVATE_DATA(cc)) { count = 2; srcw[0] = PRIVATE_DATA(cc); srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw); } cc += 2 + IMM2_SIZE; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]); #endif break; CASE_ITERATOR_TYPE_PRIVATE_DATA_1 if (PRIVATE_DATA(cc)) { count = 1; srcw[0] = PRIVATE_DATA(cc); } cc += 1; break; CASE_ITERATOR_TYPE_PRIVATE_DATA_2A if (PRIVATE_DATA(cc)) { count = 2; srcw[0] = PRIVATE_DATA(cc); srcw[1] = srcw[0] + sizeof(sljit_sw); } cc += 1; break; CASE_ITERATOR_TYPE_PRIVATE_DATA_2B if (PRIVATE_DATA(cc)) { count = 2; srcw[0] = PRIVATE_DATA(cc); srcw[1] = srcw[0] + sizeof(sljit_sw); } cc += 1 + IMM2_SIZE; break; case OP_CLASS: case OP_NCLASS: #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(pcre_uchar); #else size = 1 + 32 / (int)sizeof(pcre_uchar); #endif if (PRIVATE_DATA(cc)) switch(get_class_iterator_size(cc + size)) { case 1: count = 1; srcw[0] = PRIVATE_DATA(cc); break; case 2: count = 2; srcw[0] = PRIVATE_DATA(cc); srcw[1] = srcw[0] + sizeof(sljit_sw); break; default: SLJIT_UNREACHABLE(); break; } cc += size; break; default: cc = next_opcode(common, cc); SLJIT_ASSERT(cc != NULL); break; } while (count > 0) { count--; if (save) { if (tmp1next) { if (!tmp1empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0); stackptr += sizeof(sljit_sw); } OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), srcw[count]); tmp1empty = FALSE; tmp1next = FALSE; } else { if (!tmp2empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0); stackptr += sizeof(sljit_sw); } OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), srcw[count]); tmp2empty = FALSE; tmp1next = TRUE; } } else { if (tmp1next) { SLJIT_ASSERT(!tmp1empty); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), srcw[count], TMP1, 0); tmp1empty = stackptr >= stacktop; if (!tmp1empty) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), stackptr); stackptr += sizeof(sljit_sw); } tmp1next = FALSE; } else { SLJIT_ASSERT(!tmp2empty); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), srcw[count], TMP2, 0); tmp2empty = stackptr >= stacktop; if (!tmp2empty) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), stackptr); stackptr += sizeof(sljit_sw); } tmp1next = TRUE; } } } } while (status != end); if (save) { if (tmp1next) { if (!tmp1empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0); stackptr += sizeof(sljit_sw); } if (!tmp2empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0); stackptr += sizeof(sljit_sw); } } else { if (!tmp2empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP2, 0); stackptr += sizeof(sljit_sw); } if (!tmp1empty) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackptr, TMP1, 0); stackptr += sizeof(sljit_sw); } } } SLJIT_ASSERT(cc == ccend && stackptr == stacktop && (save || (tmp1empty && tmp2empty))); } static SLJIT_INLINE pcre_uchar *set_then_offsets(compiler_common *common, pcre_uchar *cc, sljit_u8 *current_offset) { pcre_uchar *end = bracketend(cc); BOOL has_alternatives = cc[GET(cc, 1)] == OP_ALT; /* Assert captures then. */ if (*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) current_offset = NULL; /* Conditional block does not. */ if (*cc == OP_COND || *cc == OP_SCOND) has_alternatives = FALSE; cc = next_opcode(common, cc); if (has_alternatives) current_offset = common->then_offsets + (cc - common->start); while (cc < end) { if ((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND)) cc = set_then_offsets(common, cc, current_offset); else { if (*cc == OP_ALT && has_alternatives) current_offset = common->then_offsets + (cc + 1 + LINK_SIZE - common->start); if (*cc >= OP_THEN && *cc <= OP_THEN_ARG && current_offset != NULL) *current_offset = 1; cc = next_opcode(common, cc); } } return end; } #undef CASE_ITERATOR_PRIVATE_DATA_1 #undef CASE_ITERATOR_PRIVATE_DATA_2A #undef CASE_ITERATOR_PRIVATE_DATA_2B #undef CASE_ITERATOR_TYPE_PRIVATE_DATA_1 #undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2A #undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2B static SLJIT_INLINE BOOL is_powerof2(unsigned int value) { return (value & (value - 1)) == 0; } static SLJIT_INLINE void set_jumps(jump_list *list, struct sljit_label *label) { while (list) { /* sljit_set_label is clever enough to do nothing if either the jump or the label is NULL. */ SET_LABEL(list->jump, label); list = list->next; } } static SLJIT_INLINE void add_jump(struct sljit_compiler *compiler, jump_list **list, struct sljit_jump *jump) { jump_list *list_item = sljit_alloc_memory(compiler, sizeof(jump_list)); if (list_item) { list_item->next = *list; list_item->jump = jump; *list = list_item; } } static void add_stub(compiler_common *common, struct sljit_jump *start) { DEFINE_COMPILER; stub_list *list_item = sljit_alloc_memory(compiler, sizeof(stub_list)); if (list_item) { list_item->start = start; list_item->quit = LABEL(); list_item->next = common->stubs; common->stubs = list_item; } } static void flush_stubs(compiler_common *common) { DEFINE_COMPILER; stub_list *list_item = common->stubs; while (list_item) { JUMPHERE(list_item->start); add_jump(compiler, &common->stackalloc, JUMP(SLJIT_FAST_CALL)); JUMPTO(SLJIT_JUMP, list_item->quit); list_item = list_item->next; } common->stubs = NULL; } static void add_label_addr(compiler_common *common, sljit_uw *update_addr) { DEFINE_COMPILER; label_addr_list *label_addr; label_addr = sljit_alloc_memory(compiler, sizeof(label_addr_list)); if (label_addr == NULL) return; label_addr->label = LABEL(); label_addr->update_addr = update_addr; label_addr->next = common->label_addrs; common->label_addrs = label_addr; } static SLJIT_INLINE void count_match(compiler_common *common) { DEFINE_COMPILER; OP2(SLJIT_SUB | SLJIT_SET_Z, COUNT_MATCH, 0, COUNT_MATCH, 0, SLJIT_IMM, 1); add_jump(compiler, &common->calllimit, JUMP(SLJIT_ZERO)); } static SLJIT_INLINE void allocate_stack(compiler_common *common, int size) { /* May destroy all locals and registers except TMP2. */ DEFINE_COMPILER; SLJIT_ASSERT(size > 0); OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); #ifdef DESTROY_REGISTERS OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345); OP1(SLJIT_MOV, TMP3, 0, TMP1, 0); OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0); #endif add_stub(common, CMP(SLJIT_LESS, STACK_TOP, 0, STACK_LIMIT, 0)); } static SLJIT_INLINE void free_stack(compiler_common *common, int size) { DEFINE_COMPILER; SLJIT_ASSERT(size > 0); OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw)); } static sljit_uw * allocate_read_only_data(compiler_common *common, sljit_uw size) { DEFINE_COMPILER; sljit_uw *result; if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; result = (sljit_uw *)SLJIT_MALLOC(size + sizeof(sljit_uw), compiler->allocator_data); if (SLJIT_UNLIKELY(result == NULL)) { sljit_set_compiler_memory_error(compiler); return NULL; } *(void**)result = common->read_only_data_head; common->read_only_data_head = (void *)result; return result + 1; } static void free_read_only_data(void *current, void *allocator_data) { void *next; SLJIT_UNUSED_ARG(allocator_data); while (current != NULL) { next = *(void**)current; SLJIT_FREE(current, allocator_data); current = next; } } static SLJIT_INLINE void reset_ovector(compiler_common *common, int length) { DEFINE_COMPILER; struct sljit_label *loop; int i; /* At this point we can freely use all temporary registers. */ SLJIT_ASSERT(length > 1); /* TMP1 returns with begin - 1. */ OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(jit_arguments, begin), SLJIT_IMM, IN_UCHARS(1)); if (length < 8) { for (i = 1; i < length; i++) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(i), SLJIT_R0, 0); } else { if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw)) == SLJIT_SUCCESS) { GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START); OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1); loop = LABEL(); sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw)); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, loop); } else { GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START + sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1); loop = LABEL(); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R0, 0); OP2(SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, sizeof(sljit_sw)); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, loop); } } } static SLJIT_INLINE void reset_fast_fail(compiler_common *common) { DEFINE_COMPILER; sljit_s32 i; SLJIT_ASSERT(common->fast_fail_start_ptr < common->fast_fail_end_ptr); OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); for (i = common->fast_fail_start_ptr; i < common->fast_fail_end_ptr; i += sizeof(sljit_sw)) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), i, TMP1, 0); } static SLJIT_INLINE void do_reset_match(compiler_common *common, int length) { DEFINE_COMPILER; struct sljit_label *loop; int i; SLJIT_ASSERT(length > 1); /* OVECTOR(1) contains the "string begin - 1" constant. */ if (length > 2) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); if (length < 8) { for (i = 2; i < length; i++) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(i), TMP1, 0); } else { if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw)) == SLJIT_SUCCESS) { GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + sizeof(sljit_sw)); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2); loop = LABEL(); sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, loop); } else { GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + 2 * sizeof(sljit_sw)); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2); loop = LABEL(); OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0); OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, sizeof(sljit_sw)); OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, loop); } } OP1(SLJIT_MOV, STACK_TOP, 0, ARGUMENTS, 0); if (common->mark_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, SLJIT_IMM, 0); if (common->control_head_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(jit_arguments, stack)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, end)); } static sljit_sw SLJIT_FUNC do_search_mark(sljit_sw *current, const pcre_uchar *skip_arg) { while (current != NULL) { switch (current[1]) { case type_then_trap: break; case type_mark: if (STRCMP_UC_UC(skip_arg, (pcre_uchar *)current[2]) == 0) return current[3]; break; default: SLJIT_UNREACHABLE(); break; } SLJIT_ASSERT(current[0] == 0 || current < (sljit_sw*)current[0]); current = (sljit_sw*)current[0]; } return 0; } static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket) { DEFINE_COMPILER; struct sljit_label *loop; struct sljit_jump *early_quit; BOOL has_pre; /* At this point we can freely use all registers. */ OP1(SLJIT_MOV, SLJIT_S2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(1), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0); if (common->mark_ptr != 0) OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); OP1(SLJIT_MOV_S32, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, offset_count)); if (common->mark_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_R2, 0); OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, offsets), SLJIT_IMM, sizeof(int)); OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, begin)); has_pre = sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw)) == SLJIT_SUCCESS; GET_LOCAL_BASE(SLJIT_S0, 0, OVECTOR_START - (has_pre ? sizeof(sljit_sw) : 0)); /* Unlikely, but possible */ early_quit = CMP(SLJIT_EQUAL, SLJIT_R1, 0, SLJIT_IMM, 0); loop = LABEL(); if (has_pre) sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw)); else { OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_S0), 0); OP2(SLJIT_ADD, SLJIT_S0, 0, SLJIT_S0, 0, SLJIT_IMM, sizeof(sljit_sw)); } OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, sizeof(int)); OP2(SLJIT_SUB, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_R0, 0); /* Copy the integer value to the output buffer */ #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R2), 0, SLJIT_S1, 0); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, loop); JUMPHERE(early_quit); /* Calculate the return value, which is the maximum ovector value. */ if (topbracket > 1) { if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw))) == SLJIT_SUCCESS) { GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1); /* OVECTOR(0) is never equal to SLJIT_S2. */ loop = LABEL(); sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw))); OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop); } else { GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + (topbracket - 1) * 2 * sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1); /* OVECTOR(0) is never equal to SLJIT_S2. */ loop = LABEL(); OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), 0); OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 2 * (sljit_sw)sizeof(sljit_sw)); OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1); CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop); } OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0); } else OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1); } static SLJIT_INLINE void return_with_partial_match(compiler_common *common, struct sljit_label *quit) { DEFINE_COMPILER; struct sljit_jump *jump; SLJIT_COMPILE_ASSERT(STR_END == SLJIT_S1, str_end_must_be_saved_reg2); SLJIT_ASSERT(common->start_used_ptr != 0 && common->start_ptr != 0 && (common->mode == JIT_PARTIAL_SOFT_COMPILE ? common->hit_start != 0 : common->hit_start == 0)); OP1(SLJIT_MOV, SLJIT_R1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_PARTIAL); OP1(SLJIT_MOV_S32, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, real_offset_count)); CMPTO(SLJIT_SIG_LESS, SLJIT_R2, 0, SLJIT_IMM, 2, quit); /* Store match begin and end. */ OP1(SLJIT_MOV, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, begin)); OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, offsets)); jump = CMP(SLJIT_SIG_LESS, SLJIT_R2, 0, SLJIT_IMM, 3); OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mode == JIT_PARTIAL_HARD_COMPILE ? common->start_ptr : (common->hit_start + (int)sizeof(sljit_sw)), SLJIT_S0, 0); #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R1), 2 * sizeof(int), SLJIT_R2, 0); JUMPHERE(jump); OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mode == JIT_PARTIAL_HARD_COMPILE ? common->start_used_ptr : common->hit_start); OP2(SLJIT_SUB, SLJIT_S1, 0, STR_END, 0, SLJIT_S0, 0); #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R1), sizeof(int), SLJIT_S1, 0); OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_S0, 0); #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R2, 0); JUMPTO(SLJIT_JUMP, quit); } static SLJIT_INLINE void check_start_used_ptr(compiler_common *common) { /* May destroy TMP1. */ DEFINE_COMPILER; struct sljit_jump *jump; if (common->mode == JIT_PARTIAL_SOFT_COMPILE) { /* The value of -1 must be kept for start_used_ptr! */ OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, 1); /* Jumps if start_used_ptr < STR_PTR, or start_used_ptr == -1. Although overwriting is not necessary if start_used_ptr == STR_PTR, it does not hurt as well. */ jump = CMP(SLJIT_LESS_EQUAL, TMP1, 0, STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); JUMPHERE(jump); } else if (common->mode == JIT_PARTIAL_HARD_COMPILE) { jump = CMP(SLJIT_LESS_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); JUMPHERE(jump); } } static SLJIT_INLINE BOOL char_has_othercase(compiler_common *common, pcre_uchar *cc) { /* Detects if the character has an othercase. */ unsigned int c; #ifdef SUPPORT_UTF if (common->utf) { GETCHAR(c, cc); if (c > 127) { #ifdef SUPPORT_UCP return c != UCD_OTHERCASE(c); #else return FALSE; #endif } #ifndef COMPILE_PCRE8 return common->fcc[c] != c; #endif } else #endif c = *cc; return MAX_255(c) ? common->fcc[c] != c : FALSE; } static SLJIT_INLINE unsigned int char_othercase(compiler_common *common, unsigned int c) { /* Returns with the othercase. */ #ifdef SUPPORT_UTF if (common->utf && c > 127) { #ifdef SUPPORT_UCP return UCD_OTHERCASE(c); #else return c; #endif } #endif return TABLE_GET(c, common->fcc, c); } static unsigned int char_get_othercase_bit(compiler_common *common, pcre_uchar *cc) { /* Detects if the character and its othercase has only 1 bit difference. */ unsigned int c, oc, bit; #if defined SUPPORT_UTF && defined COMPILE_PCRE8 int n; #endif #ifdef SUPPORT_UTF if (common->utf) { GETCHAR(c, cc); if (c <= 127) oc = common->fcc[c]; else { #ifdef SUPPORT_UCP oc = UCD_OTHERCASE(c); #else oc = c; #endif } } else { c = *cc; oc = TABLE_GET(c, common->fcc, c); } #else c = *cc; oc = TABLE_GET(c, common->fcc, c); #endif SLJIT_ASSERT(c != oc); bit = c ^ oc; /* Optimized for English alphabet. */ if (c <= 127 && bit == 0x20) return (0 << 8) | 0x20; /* Since c != oc, they must have at least 1 bit difference. */ if (!is_powerof2(bit)) return 0; #if defined COMPILE_PCRE8 #ifdef SUPPORT_UTF if (common->utf && c > 127) { n = GET_EXTRALEN(*cc); while ((bit & 0x3f) == 0) { n--; bit >>= 6; } return (n << 8) | bit; } #endif /* SUPPORT_UTF */ return (0 << 8) | bit; #elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 #ifdef SUPPORT_UTF if (common->utf && c > 65535) { if (bit >= (1 << 10)) bit >>= 10; else return (bit < 256) ? ((2 << 8) | bit) : ((3 << 8) | (bit >> 8)); } #endif /* SUPPORT_UTF */ return (bit < 256) ? ((0 << 8) | bit) : ((1 << 8) | (bit >> 8)); #endif /* COMPILE_PCRE[8|16|32] */ } static void check_partial(compiler_common *common, BOOL force) { /* Checks whether a partial matching is occurred. Does not modify registers. */ DEFINE_COMPILER; struct sljit_jump *jump = NULL; SLJIT_ASSERT(!force || common->mode != JIT_COMPILE); if (common->mode == JIT_COMPILE) return; if (!force) jump = CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); else if (common->mode == JIT_PARTIAL_SOFT_COMPILE) jump = CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1); if (common->mode == JIT_PARTIAL_SOFT_COMPILE) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); else { if (common->partialmatchlabel != NULL) JUMPTO(SLJIT_JUMP, common->partialmatchlabel); else add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP)); } if (jump != NULL) JUMPHERE(jump); } static void check_str_end(compiler_common *common, jump_list **end_reached) { /* Does not affect registers. Usually used in a tight spot. */ DEFINE_COMPILER; struct sljit_jump *jump; if (common->mode == JIT_COMPILE) { add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); return; } jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); if (common->mode == JIT_PARTIAL_SOFT_COMPILE) { add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); add_jump(compiler, end_reached, JUMP(SLJIT_JUMP)); } else { add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0)); if (common->partialmatchlabel != NULL) JUMPTO(SLJIT_JUMP, common->partialmatchlabel); else add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP)); } JUMPHERE(jump); } static void detect_partial_match(compiler_common *common, jump_list **backtracks) { DEFINE_COMPILER; struct sljit_jump *jump; if (common->mode == JIT_COMPILE) { add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); return; } /* Partial matching mode. */ jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0)); if (common->mode == JIT_PARTIAL_SOFT_COMPILE) { OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); } else { if (common->partialmatchlabel != NULL) JUMPTO(SLJIT_JUMP, common->partialmatchlabel); else add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP)); } JUMPHERE(jump); } static void peek_char(compiler_common *common, sljit_u32 max) { /* Reads the character into TMP1, keeps STR_PTR. Does not check STR_END. TMP2 Destroyed. */ DEFINE_COMPILER; #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 struct sljit_jump *jump; #endif SLJIT_UNUSED_ARG(max); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf) { if (max < 128) return; jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); add_jump(compiler, &common->utfreadchar, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); JUMPHERE(jump); } #endif /* SUPPORT_UTF && !COMPILE_PCRE32 */ #if defined SUPPORT_UTF && defined COMPILE_PCRE16 if (common->utf) { if (max < 0xd800) return; OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800 - 1); /* TMP2 contains the high surrogate. */ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x40); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3ff); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); JUMPHERE(jump); } #endif } #if defined SUPPORT_UTF && defined COMPILE_PCRE8 static BOOL is_char7_bitset(const sljit_u8 *bitset, BOOL nclass) { /* Tells whether the character codes below 128 are enough to determine a match. */ const sljit_u8 value = nclass ? 0xff : 0; const sljit_u8 *end = bitset + 32; bitset += 16; do { if (*bitset++ != value) return FALSE; } while (bitset < end); return TRUE; } static void read_char7_type(compiler_common *common, BOOL full_read) { /* Reads the precise character type of a character into TMP1, if the character is less than 128. Otherwise it returns with zero. Does not check STR_END. The full_read argument tells whether characters above max are accepted or not. */ DEFINE_COMPILER; struct sljit_jump *jump; SLJIT_ASSERT(common->utf); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); if (full_read) { jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xc0); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); JUMPHERE(jump); } } #endif /* SUPPORT_UTF && COMPILE_PCRE8 */ static void read_char_range(compiler_common *common, sljit_u32 min, sljit_u32 max, BOOL update_str_ptr) { /* Reads the precise value of a character into TMP1, if the character is between min and max (c >= min && c <= max). Otherwise it returns with a value outside the range. Does not check STR_END. */ DEFINE_COMPILER; #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 struct sljit_jump *jump; #endif #if defined SUPPORT_UTF && defined COMPILE_PCRE8 struct sljit_jump *jump2; #endif SLJIT_UNUSED_ARG(update_str_ptr); SLJIT_UNUSED_ARG(min); SLJIT_UNUSED_ARG(max); SLJIT_ASSERT(min <= max); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf) { if (max < 128 && !update_str_ptr) return; jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0); if (min >= 0x10000) { OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xf0); if (update_str_ptr) OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0x7); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2)); if (!update_str_ptr) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3)); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); JUMPHERE(jump2); if (update_str_ptr) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0); } else if (min >= 0x800 && max <= 0xffff) { OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xe0); if (update_str_ptr) OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xf); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); if (!update_str_ptr) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); JUMPHERE(jump2); if (update_str_ptr) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0); } else if (max >= 0x800) add_jump(compiler, (max < 0x10000) ? &common->utfreadchar16 : &common->utfreadchar, JUMP(SLJIT_FAST_CALL)); else if (max < 128) { OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); } else { OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); if (!update_str_ptr) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); else OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); if (update_str_ptr) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0); } JUMPHERE(jump); } #endif #if defined SUPPORT_UTF && defined COMPILE_PCRE16 if (common->utf) { if (max >= 0x10000) { OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800 - 1); /* TMP2 contains the high surrogate. */ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x40); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3ff); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); JUMPHERE(jump); return; } if (max < 0xd800 && !update_str_ptr) return; /* Skip low surrogate if necessary. */ OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800); jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800 - 1); if (update_str_ptr) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); if (max >= 0xd800) OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0x10000); JUMPHERE(jump); } #endif } static SLJIT_INLINE void read_char(compiler_common *common) { read_char_range(common, 0, READ_CHAR_MAX, TRUE); } static void read_char8_type(compiler_common *common, BOOL update_str_ptr) { /* Reads the character type into TMP1, updates STR_PTR. Does not check STR_END. */ DEFINE_COMPILER; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 struct sljit_jump *jump; #endif #if defined SUPPORT_UTF && defined COMPILE_PCRE8 struct sljit_jump *jump2; #endif SLJIT_UNUSED_ARG(update_str_ptr); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf) { /* This can be an extra read in some situations, but hopefully it is needed in most cases. */ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xc0); if (!update_str_ptr) { OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP2, 0, TMP2, 0, TMP1, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); JUMPHERE(jump2); } else add_jump(compiler, &common->utfreadtype8, JUMP(SLJIT_FAST_CALL)); JUMPHERE(jump); return; } #endif /* SUPPORT_UTF && COMPILE_PCRE8 */ #if !defined COMPILE_PCRE8 /* The ctypes array contains only 256 values. */ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255); #endif OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); #if !defined COMPILE_PCRE8 JUMPHERE(jump); #endif #if defined SUPPORT_UTF && defined COMPILE_PCRE16 if (common->utf && update_str_ptr) { /* Skip low surrogate if necessary. */ OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xd800); jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800 - 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPHERE(jump); } #endif /* SUPPORT_UTF && COMPILE_PCRE16 */ } static void skip_char_back(compiler_common *common) { /* Goes one character back. Affects STR_PTR and TMP1. Does not check begin. */ DEFINE_COMPILER; #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 #if defined COMPILE_PCRE8 struct sljit_label *label; if (common->utf) { label = LABEL(); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1)); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, label); return; } #elif defined COMPILE_PCRE16 if (common->utf) { OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1)); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); /* Skip low surrogate if necessary. */ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xdc00); OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0); return; } #endif /* COMPILE_PCRE[8|16] */ #endif /* SUPPORT_UTF && !COMPILE_PCRE32 */ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } static void check_newlinechar(compiler_common *common, int nltype, jump_list **backtracks, BOOL jumpifmatch) { /* Character comes in TMP1. Checks if it is a newline. TMP2 may be destroyed. */ DEFINE_COMPILER; struct sljit_jump *jump; if (nltype == NLTYPE_ANY) { add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL)); sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(jumpifmatch ? SLJIT_NOT_ZERO : SLJIT_ZERO)); } else if (nltype == NLTYPE_ANYCRLF) { if (jumpifmatch) { add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR)); add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL)); } else { jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL)); JUMPHERE(jump); } } else { SLJIT_ASSERT(nltype == NLTYPE_FIXED && common->newline < 256); add_jump(compiler, backtracks, CMP(jumpifmatch ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline)); } } #ifdef SUPPORT_UTF #if defined COMPILE_PCRE8 static void do_utfreadchar(compiler_common *common) { /* Fast decoding a UTF-8 character. TMP1 contains the first byte of the character (>= 0xc0). Return char value in TMP1, length in TMP2. */ DEFINE_COMPILER; struct sljit_jump *jump; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); /* Searching for the first zero. */ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800); jump = JUMP(SLJIT_NOT_ZERO); /* Two byte sequence. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, IN_UCHARS(2)); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); JUMPHERE(jump); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x800); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x10000); jump = JUMP(SLJIT_NOT_ZERO); /* Three byte sequence. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, IN_UCHARS(3)); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); /* Four byte sequence. */ JUMPHERE(jump); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2)); OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3)); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, IN_UCHARS(4)); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } static void do_utfreadchar16(compiler_common *common) { /* Fast decoding a UTF-8 character. TMP1 contains the first byte of the character (>= 0xc0). Return value in TMP1. */ DEFINE_COMPILER; struct sljit_jump *jump; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); /* Searching for the first zero. */ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800); jump = JUMP(SLJIT_NOT_ZERO); /* Two byte sequence. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); JUMPHERE(jump); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x400); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_NOT_ZERO); /* This code runs only in 8 bit mode. No need to shift the value. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x800); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); /* Three byte sequence. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } static void do_utfreadtype8(compiler_common *common) { /* Fast decoding a UTF-8 character type. TMP2 contains the first byte of the character (>= 0xc0). Return value in TMP1. */ DEFINE_COMPILER; struct sljit_jump *jump; struct sljit_jump *compare; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x20); jump = JUMP(SLJIT_NOT_ZERO); /* Two byte sequence. */ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x1f); /* The upper 5 bits are known at this point. */ compare = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0x3); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f); OP2(SLJIT_OR, TMP2, 0, TMP2, 0, TMP1, 0); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); JUMPHERE(compare); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); /* We only have types for characters less than 256. */ JUMPHERE(jump); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } #endif /* COMPILE_PCRE8 */ #endif /* SUPPORT_UTF */ #ifdef SUPPORT_UCP /* UCD_BLOCK_SIZE must be 128 (see the assert below). */ #define UCD_BLOCK_MASK 127 #define UCD_BLOCK_SHIFT 7 static void do_getucd(compiler_common *common) { /* Search the UCD record for the character comes in TMP1. Returns chartype in TMP1 and UCD offset in TMP2. */ DEFINE_COMPILER; #ifdef COMPILE_PCRE32 struct sljit_jump *jump; #endif #if defined SLJIT_DEBUG && SLJIT_DEBUG /* dummy_ucd_record */ const ucd_record *record = GET_UCD(INVALID_UTF_CHAR); SLJIT_ASSERT(record->script == ucp_Common && record->chartype == ucp_Cn && record->gbprop == ucp_gbOther); SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0); #endif SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 8); sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); #ifdef COMPILE_PCRE32 if (!common->utf) { jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x10ffff + 1); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); JUMPHERE(jump); } #endif OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2)); OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype)); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } #endif static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common, BOOL hascrorlf) { DEFINE_COMPILER; struct sljit_label *mainloop; struct sljit_label *newlinelabel = NULL; struct sljit_jump *start; struct sljit_jump *end = NULL; struct sljit_jump *end2 = NULL; #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 struct sljit_jump *singlechar; #endif jump_list *newline = NULL; BOOL newlinecheck = FALSE; BOOL readuchar = FALSE; if (!(hascrorlf || (common->match_end_ptr != 0)) && (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF || common->newline > 255)) newlinecheck = TRUE; if (common->match_end_ptr != 0) { /* Search for the end of the first line. */ OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); if (common->nltype == NLTYPE_FIXED && common->newline > 255) { mainloop = LABEL(); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, mainloop); CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, mainloop); JUMPHERE(end); OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } else { end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); mainloop = LABEL(); /* Continual stores does not cause data dependency. */ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0); read_char_range(common, common->nlmin, common->nlmax, TRUE); check_newlinechar(common, common->nltype, &newline, TRUE); CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, mainloop); JUMPHERE(end); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0); set_jumps(newline, LABEL()); } OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); } start = JUMP(SLJIT_JUMP); if (newlinecheck) { newlinelabel = LABEL(); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff); OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); end2 = JUMP(SLJIT_JUMP); } mainloop = LABEL(); /* Increasing the STR_PTR here requires one less jump in the most common case. */ #ifdef SUPPORT_UTF if (common->utf) readuchar = TRUE; #endif if (newlinecheck) readuchar = TRUE; if (readuchar) OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); if (newlinecheck) CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, newlinelabel); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 #if defined COMPILE_PCRE8 if (common->utf) { singlechar = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); JUMPHERE(singlechar); } #elif defined COMPILE_PCRE16 if (common->utf) { singlechar = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); JUMPHERE(singlechar); } #endif /* COMPILE_PCRE[8|16] */ #endif /* SUPPORT_UTF && !COMPILE_PCRE32 */ JUMPHERE(start); if (newlinecheck) { JUMPHERE(end); JUMPHERE(end2); } return mainloop; } #define MAX_N_CHARS 16 #define MAX_DIFF_CHARS 6 static SLJIT_INLINE void add_prefix_char(pcre_uchar chr, pcre_uchar *chars) { pcre_uchar i, len; len = chars[0]; if (len == 255) return; if (len == 0) { chars[0] = 1; chars[1] = chr; return; } for (i = len; i > 0; i--) if (chars[i] == chr) return; if (len >= MAX_DIFF_CHARS - 1) { chars[0] = 255; return; } len++; chars[len] = chr; chars[0] = len; } static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uchar *chars, int max_chars, sljit_u32 *rec_count) { /* Recursive function, which scans prefix literals. */ BOOL last, any, class, caseless; int len, repeat, len_save, consumed = 0; sljit_u32 chr; /* Any unicode character. */ sljit_u8 *bytes, *bytes_end, byte; pcre_uchar *alternative, *cc_save, *oc; #if defined SUPPORT_UTF && defined COMPILE_PCRE8 pcre_uchar othercase[8]; #elif defined SUPPORT_UTF && defined COMPILE_PCRE16 pcre_uchar othercase[2]; #else pcre_uchar othercase[1]; #endif repeat = 1; while (TRUE) { if (*rec_count == 0) return 0; (*rec_count)--; last = TRUE; any = FALSE; class = FALSE; caseless = FALSE; switch (*cc) { case OP_CHARI: caseless = TRUE; case OP_CHAR: last = FALSE; cc++; break; case OP_SOD: case OP_SOM: case OP_SET_SOM: case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: case OP_EODN: case OP_EOD: case OP_CIRC: case OP_CIRCM: case OP_DOLL: case OP_DOLLM: /* Zero width assertions. */ cc++; continue; case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: cc = bracketend(cc); continue; case OP_PLUSI: case OP_MINPLUSI: case OP_POSPLUSI: caseless = TRUE; case OP_PLUS: case OP_MINPLUS: case OP_POSPLUS: cc++; break; case OP_EXACTI: caseless = TRUE; case OP_EXACT: repeat = GET2(cc, 1); last = FALSE; cc += 1 + IMM2_SIZE; break; case OP_QUERYI: case OP_MINQUERYI: case OP_POSQUERYI: caseless = TRUE; case OP_QUERY: case OP_MINQUERY: case OP_POSQUERY: len = 1; cc++; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc); #endif max_chars = scan_prefix(common, cc + len, chars, max_chars, rec_count); if (max_chars == 0) return consumed; last = FALSE; break; case OP_KET: cc += 1 + LINK_SIZE; continue; case OP_ALT: cc += GET(cc, 1); continue; case OP_ONCE: case OP_ONCE_NC: case OP_BRA: case OP_BRAPOS: case OP_CBRA: case OP_CBRAPOS: alternative = cc + GET(cc, 1); while (*alternative == OP_ALT) { max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, max_chars, rec_count); if (max_chars == 0) return consumed; alternative += GET(alternative, 1); } if (*cc == OP_CBRA || *cc == OP_CBRAPOS) cc += IMM2_SIZE; cc += 1 + LINK_SIZE; continue; case OP_CLASS: #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf && !is_char7_bitset((const sljit_u8 *)(cc + 1), FALSE)) return consumed; #endif class = TRUE; break; case OP_NCLASS: #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf) return consumed; #endif class = TRUE; break; #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf) return consumed; #endif any = TRUE; cc += GET(cc, 1); break; #endif case OP_DIGIT: #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_digit, FALSE)) return consumed; #endif any = TRUE; cc++; break; case OP_WHITESPACE: #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_space, FALSE)) return consumed; #endif any = TRUE; cc++; break; case OP_WORDCHAR: #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_word, FALSE)) return consumed; #endif any = TRUE; cc++; break; case OP_NOT: case OP_NOTI: cc++; /* Fall through. */ case OP_NOT_DIGIT: case OP_NOT_WHITESPACE: case OP_NOT_WORDCHAR: case OP_ANY: case OP_ALLANY: #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf) return consumed; #endif any = TRUE; cc++; break; #ifdef SUPPORT_UTF case OP_NOTPROP: case OP_PROP: #ifndef COMPILE_PCRE32 if (common->utf) return consumed; #endif any = TRUE; cc += 1 + 2; break; #endif case OP_TYPEEXACT: repeat = GET2(cc, 1); cc += 1 + IMM2_SIZE; continue; case OP_NOTEXACT: case OP_NOTEXACTI: #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf) return consumed; #endif any = TRUE; repeat = GET2(cc, 1); cc += 1 + IMM2_SIZE + 1; break; default: return consumed; } if (any) { do { chars[0] = 255; consumed++; if (--max_chars == 0) return consumed; chars += MAX_DIFF_CHARS; } while (--repeat > 0); repeat = 1; continue; } if (class) { bytes = (sljit_u8*) (cc + 1); cc += 1 + 32 / sizeof(pcre_uchar); switch (*cc) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPOSSTAR: case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSQUERY: max_chars = scan_prefix(common, cc + 1, chars, max_chars, rec_count); if (max_chars == 0) return consumed; break; default: case OP_CRPLUS: case OP_CRMINPLUS: case OP_CRPOSPLUS: break; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: repeat = GET2(cc, 1); if (repeat <= 0) return consumed; break; } do { if (bytes[31] & 0x80) chars[0] = 255; else if (chars[0] != 255) { bytes_end = bytes + 32; chr = 0; do { byte = *bytes++; SLJIT_ASSERT((chr & 0x7) == 0); if (byte == 0) chr += 8; else { do { if ((byte & 0x1) != 0) add_prefix_char(chr, chars); byte >>= 1; chr++; } while (byte != 0); chr = (chr + 7) & ~7; } } while (chars[0] != 255 && bytes < bytes_end); bytes = bytes_end - 32; } consumed++; if (--max_chars == 0) return consumed; chars += MAX_DIFF_CHARS; } while (--repeat > 0); switch (*cc) { case OP_CRSTAR: case OP_CRMINSTAR: case OP_CRPOSSTAR: return consumed; case OP_CRQUERY: case OP_CRMINQUERY: case OP_CRPOSQUERY: cc++; break; case OP_CRRANGE: case OP_CRMINRANGE: case OP_CRPOSRANGE: if (GET2(cc, 1) != GET2(cc, 1 + IMM2_SIZE)) return consumed; cc += 1 + 2 * IMM2_SIZE; break; } repeat = 1; continue; } len = 1; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc); #endif if (caseless && char_has_othercase(common, cc)) { #ifdef SUPPORT_UTF if (common->utf) { GETCHAR(chr, cc); if ((int)PRIV(ord2utf)(char_othercase(common, chr), othercase) != len) return consumed; } else #endif { chr = *cc; othercase[0] = TABLE_GET(chr, common->fcc, chr); } } else { caseless = FALSE; othercase[0] = 0; /* Stops compiler warning - PH */ } len_save = len; cc_save = cc; while (TRUE) { oc = othercase; do { chr = *cc; add_prefix_char(*cc, chars); if (caseless) add_prefix_char(*oc, chars); len--; consumed++; if (--max_chars == 0) return consumed; chars += MAX_DIFF_CHARS; cc++; oc++; } while (len > 0); if (--repeat == 0) break; len = len_save; cc = cc_save; } repeat = 1; if (last) return consumed; } } #if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND) static sljit_s32 character_to_int32(pcre_uchar chr) { sljit_s32 value = (sljit_s32)chr; #if defined COMPILE_PCRE8 #define SSE2_COMPARE_TYPE_INDEX 0 return ((unsigned int)value << 24) | ((unsigned int)value << 16) | ((unsigned int)value << 8) | (unsigned int)value; #elif defined COMPILE_PCRE16 #define SSE2_COMPARE_TYPE_INDEX 1 return ((unsigned int)value << 16) | value; #elif defined COMPILE_PCRE32 #define SSE2_COMPARE_TYPE_INDEX 2 return value; #else #error "Unsupported unit width" #endif } static SLJIT_INLINE void fast_forward_first_char2_sse2(compiler_common *common, pcre_uchar char1, pcre_uchar char2) { DEFINE_COMPILER; struct sljit_label *start; struct sljit_jump *quit[3]; struct sljit_jump *nomatch; sljit_u8 instruction[8]; sljit_s32 tmp1_ind = sljit_get_register_index(TMP1); sljit_s32 tmp2_ind = sljit_get_register_index(TMP2); sljit_s32 str_ptr_ind = sljit_get_register_index(STR_PTR); BOOL load_twice = FALSE; pcre_uchar bit; bit = char1 ^ char2; if (!is_powerof2(bit)) bit = 0; if ((char1 != char2) && bit == 0) load_twice = TRUE; quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); /* First part (unaligned start) */ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit)); SLJIT_ASSERT(tmp1_ind < 8 && tmp2_ind == 1); /* MOVD xmm, r/m32 */ instruction[0] = 0x66; instruction[1] = 0x0f; instruction[2] = 0x6e; instruction[3] = 0xc0 | (2 << 3) | tmp1_ind; sljit_emit_op_custom(compiler, instruction, 4); if (char1 != char2) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2)); /* MOVD xmm, r/m32 */ instruction[3] = 0xc0 | (3 << 3) | tmp1_ind; sljit_emit_op_custom(compiler, instruction, 4); } /* PSHUFD xmm1, xmm2/m128, imm8 */ instruction[2] = 0x70; instruction[3] = 0xc0 | (2 << 3) | 2; instruction[4] = 0; sljit_emit_op_custom(compiler, instruction, 5); if (char1 != char2) { /* PSHUFD xmm1, xmm2/m128, imm8 */ instruction[3] = 0xc0 | (3 << 3) | 3; instruction[4] = 0; sljit_emit_op_custom(compiler, instruction, 5); } OP2(SLJIT_AND, TMP2, 0, STR_PTR, 0, SLJIT_IMM, 0xf); OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf); /* MOVDQA xmm1, xmm2/m128 */ #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if (str_ptr_ind < 8) { instruction[2] = 0x6f; instruction[3] = (0 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 4); if (load_twice) { instruction[3] = (1 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 4); } } else { instruction[1] = 0x41; instruction[2] = 0x0f; instruction[3] = 0x6f; instruction[4] = (0 << 3) | (str_ptr_ind & 0x7); sljit_emit_op_custom(compiler, instruction, 5); if (load_twice) { instruction[4] = (1 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 5); } instruction[1] = 0x0f; } #else instruction[2] = 0x6f; instruction[3] = (0 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 4); if (load_twice) { instruction[3] = (1 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 4); } #endif if (bit != 0) { /* POR xmm1, xmm2/m128 */ instruction[2] = 0xeb; instruction[3] = 0xc0 | (0 << 3) | 3; sljit_emit_op_custom(compiler, instruction, 4); } /* PCMPEQB/W/D xmm1, xmm2/m128 */ instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX; instruction[3] = 0xc0 | (0 << 3) | 2; sljit_emit_op_custom(compiler, instruction, 4); if (load_twice) { instruction[3] = 0xc0 | (1 << 3) | 3; sljit_emit_op_custom(compiler, instruction, 4); } /* PMOVMSKB reg, xmm */ instruction[2] = 0xd7; instruction[3] = 0xc0 | (tmp1_ind << 3) | 0; sljit_emit_op_custom(compiler, instruction, 4); if (load_twice) { OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP2, 0); instruction[3] = 0xc0 | (tmp2_ind << 3) | 1; sljit_emit_op_custom(compiler, instruction, 4); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); OP1(SLJIT_MOV, TMP2, 0, RETURN_ADDR, 0); } OP2(SLJIT_ASHR, TMP1, 0, TMP1, 0, TMP2, 0); /* BSF r32, r/m32 */ instruction[0] = 0x0f; instruction[1] = 0xbc; instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind; sljit_emit_op_custom(compiler, instruction, 3); sljit_set_current_flags(compiler, SLJIT_SET_Z); nomatch = JUMP(SLJIT_ZERO); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); quit[1] = JUMP(SLJIT_JUMP); JUMPHERE(nomatch); start = LABEL(); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16); quit[2] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); /* Second part (aligned) */ instruction[0] = 0x66; instruction[1] = 0x0f; /* MOVDQA xmm1, xmm2/m128 */ #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if (str_ptr_ind < 8) { instruction[2] = 0x6f; instruction[3] = (0 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 4); if (load_twice) { instruction[3] = (1 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 4); } } else { instruction[1] = 0x41; instruction[2] = 0x0f; instruction[3] = 0x6f; instruction[4] = (0 << 3) | (str_ptr_ind & 0x7); sljit_emit_op_custom(compiler, instruction, 5); if (load_twice) { instruction[4] = (1 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 5); } instruction[1] = 0x0f; } #else instruction[2] = 0x6f; instruction[3] = (0 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 4); if (load_twice) { instruction[3] = (1 << 3) | str_ptr_ind; sljit_emit_op_custom(compiler, instruction, 4); } #endif if (bit != 0) { /* POR xmm1, xmm2/m128 */ instruction[2] = 0xeb; instruction[3] = 0xc0 | (0 << 3) | 3; sljit_emit_op_custom(compiler, instruction, 4); } /* PCMPEQB/W/D xmm1, xmm2/m128 */ instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX; instruction[3] = 0xc0 | (0 << 3) | 2; sljit_emit_op_custom(compiler, instruction, 4); if (load_twice) { instruction[3] = 0xc0 | (1 << 3) | 3; sljit_emit_op_custom(compiler, instruction, 4); } /* PMOVMSKB reg, xmm */ instruction[2] = 0xd7; instruction[3] = 0xc0 | (tmp1_ind << 3) | 0; sljit_emit_op_custom(compiler, instruction, 4); if (load_twice) { instruction[3] = 0xc0 | (tmp2_ind << 3) | 1; sljit_emit_op_custom(compiler, instruction, 4); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0); } /* BSF r32, r/m32 */ instruction[0] = 0x0f; instruction[1] = 0xbc; instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind; sljit_emit_op_custom(compiler, instruction, 3); sljit_set_current_flags(compiler, SLJIT_SET_Z); JUMPTO(SLJIT_ZERO, start); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); start = LABEL(); SET_LABEL(quit[0], start); SET_LABEL(quit[1], start); SET_LABEL(quit[2], start); } #undef SSE2_COMPARE_TYPE_INDEX #endif static void fast_forward_first_char2(compiler_common *common, pcre_uchar char1, pcre_uchar char2, sljit_s32 offset) { DEFINE_COMPILER; struct sljit_label *start; struct sljit_jump *quit; struct sljit_jump *found; pcre_uchar mask; #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 struct sljit_label *utf_start = NULL; struct sljit_jump *utf_quit = NULL; #endif BOOL has_match_end = (common->match_end_ptr != 0); if (offset > 0) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); if (has_match_end) { OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); OP2(SLJIT_ADD, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, SLJIT_IMM, IN_UCHARS(offset + 1)); OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP3, 0); sljit_emit_cmov(compiler, SLJIT_GREATER, STR_END, TMP3, 0); } #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf && offset > 0) utf_start = LABEL(); #endif #if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND) /* SSE2 accelerated first character search. */ if (sljit_has_cpu_feature(SLJIT_HAS_SSE2)) { fast_forward_first_char2_sse2(common, char1, char2); SLJIT_ASSERT(common->mode == JIT_COMPILE || offset == 0); if (common->mode == JIT_COMPILE) { /* In complete mode, we don't need to run a match when STR_PTR == STR_END. */ SLJIT_ASSERT(common->forced_quit_label == NULL); OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH); add_jump(compiler, &common->forced_quit, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf && offset > 0) { SLJIT_ASSERT(common->mode == JIT_COMPILE); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset)); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); #if defined COMPILE_PCRE8 OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, utf_start); #elif defined COMPILE_PCRE16 OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, utf_start); #else #error "Unknown code width" #endif OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } #endif if (offset > 0) OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); } else { OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0); if (has_match_end) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); sljit_emit_cmov(compiler, SLJIT_GREATER_EQUAL, STR_PTR, TMP1, 0); } else sljit_emit_cmov(compiler, SLJIT_GREATER_EQUAL, STR_PTR, STR_END, 0); } if (has_match_end) OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); return; } #endif quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); start = LABEL(); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); if (char1 == char2) found = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1); else { mask = char1 ^ char2; if (is_powerof2(mask)) { OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask); found = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1 | mask); } else { OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char1); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char2); OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); found = JUMP(SLJIT_NOT_ZERO); } } OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, start); #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf && offset > 0) utf_quit = JUMP(SLJIT_JUMP); #endif JUMPHERE(found); #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf && offset > 0) { OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset)); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); #if defined COMPILE_PCRE8 OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, utf_start); #elif defined COMPILE_PCRE16 OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, utf_start); #else #error "Unknown code width" #endif OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPHERE(utf_quit); } #endif JUMPHERE(quit); if (has_match_end) { quit = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); if (offset > 0) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); JUMPHERE(quit); OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); } if (offset > 0) OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset)); } static SLJIT_INLINE BOOL fast_forward_first_n_chars(compiler_common *common) { DEFINE_COMPILER; struct sljit_label *start; struct sljit_jump *quit; struct sljit_jump *match; /* bytes[0] represent the number of characters between 0 and MAX_N_BYTES - 1, 255 represents any character. */ pcre_uchar chars[MAX_N_CHARS * MAX_DIFF_CHARS]; sljit_s32 offset; pcre_uchar mask; pcre_uchar *char_set, *char_set_end; int i, max, from; int range_right = -1, range_len; sljit_u8 *update_table = NULL; BOOL in_range; sljit_u32 rec_count; for (i = 0; i < MAX_N_CHARS; i++) chars[i * MAX_DIFF_CHARS] = 0; rec_count = 10000; max = scan_prefix(common, common->start, chars, MAX_N_CHARS, &rec_count); if (max < 1) return FALSE; in_range = FALSE; /* Prevent compiler "uninitialized" warning */ from = 0; range_len = 4 /* minimum length */ - 1; for (i = 0; i <= max; i++) { if (in_range && (i - from) > range_len && (chars[(i - 1) * MAX_DIFF_CHARS] < 255)) { range_len = i - from; range_right = i - 1; } if (i < max && chars[i * MAX_DIFF_CHARS] < 255) { SLJIT_ASSERT(chars[i * MAX_DIFF_CHARS] > 0); if (!in_range) { in_range = TRUE; from = i; } } else in_range = FALSE; } if (range_right >= 0) { update_table = (sljit_u8 *)allocate_read_only_data(common, 256); if (update_table == NULL) return TRUE; memset(update_table, IN_UCHARS(range_len), 256); for (i = 0; i < range_len; i++) { char_set = chars + ((range_right - i) * MAX_DIFF_CHARS); SLJIT_ASSERT(char_set[0] > 0 && char_set[0] < 255); char_set_end = char_set + char_set[0]; char_set++; while (char_set <= char_set_end) { if (update_table[(*char_set) & 0xff] > IN_UCHARS(i)) update_table[(*char_set) & 0xff] = IN_UCHARS(i); char_set++; } } } offset = -1; /* Scan forward. */ for (i = 0; i < max; i++) { if (offset == -1) { if (chars[i * MAX_DIFF_CHARS] <= 2) offset = i; } else if (chars[offset * MAX_DIFF_CHARS] == 2 && chars[i * MAX_DIFF_CHARS] <= 2) { if (chars[i * MAX_DIFF_CHARS] == 1) offset = i; else { mask = chars[offset * MAX_DIFF_CHARS + 1] ^ chars[offset * MAX_DIFF_CHARS + 2]; if (!is_powerof2(mask)) { mask = chars[i * MAX_DIFF_CHARS + 1] ^ chars[i * MAX_DIFF_CHARS + 2]; if (is_powerof2(mask)) offset = i; } } } } if (range_right < 0) { if (offset < 0) return FALSE; SLJIT_ASSERT(chars[offset * MAX_DIFF_CHARS] >= 1 && chars[offset * MAX_DIFF_CHARS] <= 2); /* Works regardless the value is 1 or 2. */ mask = chars[offset * MAX_DIFF_CHARS + chars[offset * MAX_DIFF_CHARS]]; fast_forward_first_char2(common, chars[offset * MAX_DIFF_CHARS + 1], mask, offset); return TRUE; } if (range_right == offset) offset = -1; SLJIT_ASSERT(offset == -1 || (chars[offset * MAX_DIFF_CHARS] >= 1 && chars[offset * MAX_DIFF_CHARS] <= 2)); max -= 1; SLJIT_ASSERT(max > 0); if (common->match_end_ptr != 0) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max)); quit = CMP(SLJIT_LESS_EQUAL, STR_END, 0, TMP1, 0); OP1(SLJIT_MOV, STR_END, 0, TMP1, 0); JUMPHERE(quit); } else OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max)); SLJIT_ASSERT(range_right >= 0); #if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) OP1(SLJIT_MOV, RETURN_ADDR, 0, SLJIT_IMM, (sljit_sw)update_table); #endif start = LABEL(); quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); #if defined COMPILE_PCRE8 || (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN) OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right)); #else OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right + 1) - 1); #endif #if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(RETURN_ADDR, TMP1), 0); #else OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)update_table); #endif OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, start); if (offset >= 0) { OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offset)); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); if (chars[offset * MAX_DIFF_CHARS] == 1) CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 1], start); else { mask = chars[offset * MAX_DIFF_CHARS + 1] ^ chars[offset * MAX_DIFF_CHARS + 2]; if (is_powerof2(mask)) { OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask); CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 1] | mask, start); } else { match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 1]); CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset * MAX_DIFF_CHARS + 2], start); JUMPHERE(match); } } } #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf && offset != 0) { if (offset < 0) { OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } else OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); #if defined COMPILE_PCRE8 OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0); CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, start); #elif defined COMPILE_PCRE16 OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, start); #else #error "Unknown code width" #endif if (offset < 0) OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } #endif if (offset >= 0) OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPHERE(quit); if (common->match_end_ptr != 0) { if (range_right >= 0) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); if (range_right >= 0) { quit = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP1, 0); OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0); JUMPHERE(quit); } } else OP2(SLJIT_ADD, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max)); return TRUE; } #undef MAX_N_CHARS #undef MAX_DIFF_CHARS static SLJIT_INLINE void fast_forward_first_char(compiler_common *common, pcre_uchar first_char, BOOL caseless) { pcre_uchar oc; oc = first_char; if (caseless) { oc = TABLE_GET(first_char, common->fcc, first_char); #if defined SUPPORT_UCP && !defined COMPILE_PCRE8 if (first_char > 127 && common->utf) oc = UCD_OTHERCASE(first_char); #endif } fast_forward_first_char2(common, first_char, oc, 0); } static SLJIT_INLINE void fast_forward_newline(compiler_common *common) { DEFINE_COMPILER; struct sljit_label *loop; struct sljit_jump *lastchar; struct sljit_jump *firstchar; struct sljit_jump *quit; struct sljit_jump *foundcr = NULL; struct sljit_jump *notfoundnl; jump_list *newline = NULL; if (common->match_end_ptr != 0) { OP1(SLJIT_MOV, TMP3, 0, STR_END, 0); OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); } if (common->nltype == NLTYPE_FIXED && common->newline > 255) { lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(2)); OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER_EQUAL); #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); loop = LABEL(); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, loop); CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, loop); JUMPHERE(quit); JUMPHERE(firstchar); JUMPHERE(lastchar); if (common->match_end_ptr != 0) OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); return; } OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0); skip_char_back(common); loop = LABEL(); common->ff_newline_shortcut = loop; read_char_range(common, common->nlmin, common->nlmax, TRUE); lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF) foundcr = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); check_newlinechar(common, common->nltype, &newline, FALSE); set_jumps(newline, loop); if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF) { quit = JUMP(SLJIT_JUMP); JUMPHERE(foundcr); notfoundnl = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL); OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); #if defined COMPILE_PCRE16 || defined COMPILE_PCRE32 OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT); #endif OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); JUMPHERE(notfoundnl); JUMPHERE(quit); } JUMPHERE(lastchar); JUMPHERE(firstchar); if (common->match_end_ptr != 0) OP1(SLJIT_MOV, STR_END, 0, TMP3, 0); } static BOOL check_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks); static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common, const sljit_u8 *start_bits) { DEFINE_COMPILER; struct sljit_label *start; struct sljit_jump *quit; struct sljit_jump *found = NULL; jump_list *matches = NULL; #ifndef COMPILE_PCRE8 struct sljit_jump *jump; #endif if (common->match_end_ptr != 0) { OP1(SLJIT_MOV, RETURN_ADDR, 0, STR_END, 0); OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); } start = LABEL(); quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); #ifdef SUPPORT_UTF if (common->utf) OP1(SLJIT_MOV, TMP3, 0, TMP1, 0); #endif if (!check_class_ranges(common, start_bits, (start_bits[31] & 0x80) != 0, TRUE, &matches)) { #ifndef COMPILE_PCRE8 jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 255); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 255); JUMPHERE(jump); #endif OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)start_bits); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); found = JUMP(SLJIT_NOT_ZERO); } #ifdef SUPPORT_UTF if (common->utf) OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); #endif OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); #ifdef SUPPORT_UTF #if defined COMPILE_PCRE8 if (common->utf) { CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0, start); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); } #elif defined COMPILE_PCRE16 if (common->utf) { CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800, start); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); } #endif /* COMPILE_PCRE[8|16] */ #endif /* SUPPORT_UTF */ JUMPTO(SLJIT_JUMP, start); if (found != NULL) JUMPHERE(found); if (matches != NULL) set_jumps(matches, LABEL()); JUMPHERE(quit); if (common->match_end_ptr != 0) OP1(SLJIT_MOV, STR_END, 0, RETURN_ADDR, 0); } static SLJIT_INLINE struct sljit_jump *search_requested_char(compiler_common *common, pcre_uchar req_char, BOOL caseless, BOOL has_firstchar) { DEFINE_COMPILER; struct sljit_label *loop; struct sljit_jump *toolong; struct sljit_jump *alreadyfound; struct sljit_jump *found; struct sljit_jump *foundoc = NULL; struct sljit_jump *notfound; sljit_u32 oc, bit; SLJIT_ASSERT(common->req_char_ptr != 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr); OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, REQ_BYTE_MAX); toolong = CMP(SLJIT_LESS, TMP1, 0, STR_END, 0); alreadyfound = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0); if (has_firstchar) OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); else OP1(SLJIT_MOV, TMP1, 0, STR_PTR, 0); loop = LABEL(); notfound = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(TMP1), 0); oc = req_char; if (caseless) { oc = TABLE_GET(req_char, common->fcc, req_char); #if defined SUPPORT_UCP && !(defined COMPILE_PCRE8) if (req_char > 127 && common->utf) oc = UCD_OTHERCASE(req_char); #endif } if (req_char == oc) found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char); else { bit = req_char ^ oc; if (is_powerof2(bit)) { OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, bit); found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char | bit); } else { found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char); foundoc = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, oc); } } OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPTO(SLJIT_JUMP, loop); JUMPHERE(found); if (foundoc) JUMPHERE(foundoc); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr, TMP1, 0); JUMPHERE(alreadyfound); JUMPHERE(toolong); return notfound; } static void do_revertframes(compiler_common *common) { DEFINE_COMPILER; struct sljit_jump *jump; struct sljit_label *mainloop; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP1(SLJIT_MOV, TMP3, 0, STACK_TOP, 0); GET_LOCAL_BASE(TMP1, 0, 0); /* Drop frames until we reach STACK_TOP. */ mainloop = LABEL(); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), -sizeof(sljit_sw)); jump = CMP(SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0); OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -2 * sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), SLJIT_MEM1(STACK_TOP), -3 * sizeof(sljit_sw)); OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * sizeof(sljit_sw)); JUMPTO(SLJIT_JUMP, mainloop); JUMPHERE(jump); jump = CMP(SLJIT_NOT_ZERO /* SIG_LESS */, TMP2, 0, SLJIT_IMM, 0); /* End of reverting values. */ OP1(SLJIT_MOV, STACK_TOP, 0, TMP3, 0); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); JUMPHERE(jump); OP1(SLJIT_NEG, TMP2, 0, TMP2, 0); OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -2 * sizeof(sljit_sw)); OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * sizeof(sljit_sw)); JUMPTO(SLJIT_JUMP, mainloop); } static void check_wordboundary(compiler_common *common) { DEFINE_COMPILER; struct sljit_jump *skipread; jump_list *skipread_list = NULL; #if !(defined COMPILE_PCRE8) || defined SUPPORT_UTF struct sljit_jump *jump; #endif SLJIT_COMPILE_ASSERT(ctype_word == 0x10, ctype_word_must_be_16); sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); /* Get type of the previous char, and put it to LOCALS1. */ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, SLJIT_IMM, 0); skipread = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP1, 0); skip_char_back(common); check_start_used_ptr(common); read_char(common); /* Testing char type. */ #ifdef SUPPORT_UCP if (common->use_ucp) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1); jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE); add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); JUMPHERE(jump); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP2, 0); } else #endif { #ifndef COMPILE_PCRE8 jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); #elif defined SUPPORT_UTF /* Here LOCALS1 has already been zeroed. */ jump = NULL; if (common->utf) jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); #endif /* COMPILE_PCRE8 */ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), common->ctypes); OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 4 /* ctype_word */); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0); #ifndef COMPILE_PCRE8 JUMPHERE(jump); #elif defined SUPPORT_UTF if (jump != NULL) JUMPHERE(jump); #endif /* COMPILE_PCRE8 */ } JUMPHERE(skipread); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); check_str_end(common, &skipread_list); peek_char(common, READ_CHAR_MAX); /* Testing char type. This is a code duplication. */ #ifdef SUPPORT_UCP if (common->use_ucp) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1); jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE); add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); JUMPHERE(jump); } else #endif { #ifndef COMPILE_PCRE8 /* TMP2 may be destroyed by peek_char. */ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); #elif defined SUPPORT_UTF OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0); jump = NULL; if (common->utf) jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); #endif OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), common->ctypes); OP2(SLJIT_LSHR, TMP2, 0, TMP2, 0, SLJIT_IMM, 4 /* ctype_word */); OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); #ifndef COMPILE_PCRE8 JUMPHERE(jump); #elif defined SUPPORT_UTF if (jump != NULL) JUMPHERE(jump); #endif /* COMPILE_PCRE8 */ } set_jumps(skipread_list, LABEL()); OP2(SLJIT_XOR | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); } static BOOL check_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks) { /* May destroy TMP1. */ DEFINE_COMPILER; int ranges[MAX_RANGE_SIZE]; sljit_u8 bit, cbit, all; int i, byte, length = 0; bit = bits[0] & 0x1; /* All bits will be zero or one (since bit is zero or one). */ all = -bit; for (i = 0; i < 256; ) { byte = i >> 3; if ((i & 0x7) == 0 && bits[byte] == all) i += 8; else { cbit = (bits[byte] >> (i & 0x7)) & 0x1; if (cbit != bit) { if (length >= MAX_RANGE_SIZE) return FALSE; ranges[length] = i; length++; bit = cbit; all = -cbit; } i++; } } if (((bit == 0) && nclass) || ((bit == 1) && !nclass)) { if (length >= MAX_RANGE_SIZE) return FALSE; ranges[length] = 256; length++; } if (length < 0 || length > 4) return FALSE; bit = bits[0] & 0x1; if (invert) bit ^= 0x1; /* No character is accepted. */ if (length == 0 && bit == 0) add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); switch(length) { case 0: /* When bit != 0, all characters are accepted. */ return TRUE; case 1: add_jump(compiler, backtracks, CMP(bit == 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0])); return TRUE; case 2: if (ranges[0] + 1 != ranges[1]) { OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]); add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0])); } else add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0])); return TRUE; case 3: if (bit != 0) { add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2])); if (ranges[0] + 1 != ranges[1]) { OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]); add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0])); } else add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0])); return TRUE; } add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[0])); if (ranges[1] + 1 != ranges[2]) { OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[1]); add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[1])); } else add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1])); return TRUE; case 4: if ((ranges[1] - ranges[0]) == (ranges[3] - ranges[2]) && (ranges[0] | (ranges[2] - ranges[0])) == ranges[2] && (ranges[1] & (ranges[2] - ranges[0])) == 0 && is_powerof2(ranges[2] - ranges[0])) { SLJIT_ASSERT((ranges[0] & (ranges[2] - ranges[0])) == 0 && (ranges[2] & ranges[3] & (ranges[2] - ranges[0])) != 0); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[0]); if (ranges[2] + 1 != ranges[3]) { OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2]); add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[2])); } else add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2])); return TRUE; } if (bit != 0) { i = 0; if (ranges[0] + 1 != ranges[1]) { OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]); add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0])); i = ranges[0]; } else add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0])); if (ranges[2] + 1 != ranges[3]) { OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2] - i); add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[2])); } else add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2] - i)); return TRUE; } OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]); add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[0])); if (ranges[1] + 1 != ranges[2]) { OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]); add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[1])); } else add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0])); return TRUE; default: SLJIT_UNREACHABLE(); return FALSE; } } static void check_anynewline(compiler_common *common) { /* Check whether TMP1 contains a newline character. TMP2 destroyed. */ DEFINE_COMPILER; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); #if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 #ifdef COMPILE_PCRE8 if (common->utf) { #endif OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); #ifdef COMPILE_PCRE8 } #endif #endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } static void check_hspace(compiler_common *common) { /* Check whether TMP1 contains a newline character. TMP2 destroyed. */ DEFINE_COMPILER; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x09); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0); #if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 #ifdef COMPILE_PCRE8 if (common->utf) { #endif OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x1680); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2000); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000); #ifdef COMPILE_PCRE8 } #endif #endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } static void check_vspace(compiler_common *common) { /* Check whether TMP1 contains a newline character. TMP2 destroyed. */ DEFINE_COMPILER; sljit_emit_fast_enter(compiler, RETURN_ADDR, 0); OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a); #if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 #ifdef COMPILE_PCRE8 if (common->utf) { #endif OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a); #ifdef COMPILE_PCRE8 } #endif #endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); sljit_emit_fast_return(compiler, RETURN_ADDR, 0); } static void do_casefulcmp(compiler_common *common) { DEFINE_COMPILER; struct sljit_jump *jump; struct sljit_label *label; int char1_reg; int char2_reg; if (sljit_get_register_index(TMP3) < 0) { char1_reg = STR_END; char2_reg = STACK_TOP; } else { char1_reg = TMP3; char2_reg = RETURN_ADDR; } sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); if (char1_reg == STR_END) { OP1(SLJIT_MOV, TMP3, 0, char1_reg, 0); OP1(SLJIT_MOV, RETURN_ADDR, 0, char2_reg, 0); } if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) { label = LABEL(); sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPTO(SLJIT_NOT_ZERO, label); JUMPHERE(jump); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); } else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) { OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); label = LABEL(); sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPTO(SLJIT_NOT_ZERO, label); JUMPHERE(jump); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } else { label = LABEL(); OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0); OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPTO(SLJIT_NOT_ZERO, label); JUMPHERE(jump); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); } if (char1_reg == STR_END) { OP1(SLJIT_MOV, char1_reg, 0, TMP3, 0); OP1(SLJIT_MOV, char2_reg, 0, RETURN_ADDR, 0); } sljit_emit_fast_return(compiler, TMP1, 0); } static void do_caselesscmp(compiler_common *common) { DEFINE_COMPILER; struct sljit_jump *jump; struct sljit_label *label; int char1_reg = STR_END; int char2_reg; int lcc_table; int opt_type = 0; if (sljit_get_register_index(TMP3) < 0) { char2_reg = STACK_TOP; lcc_table = STACK_LIMIT; } else { char2_reg = RETURN_ADDR; lcc_table = TMP3; } if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) opt_type = 1; else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS) opt_type = 2; sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, char1_reg, 0); if (char2_reg == STACK_TOP) { OP1(SLJIT_MOV, TMP3, 0, char2_reg, 0); OP1(SLJIT_MOV, RETURN_ADDR, 0, lcc_table, 0); } OP1(SLJIT_MOV, lcc_table, 0, SLJIT_IMM, common->lcc); if (opt_type == 1) { label = LABEL(); sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); } else if (opt_type == 2) { OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); label = LABEL(); sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)); sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); } else { label = LABEL(); OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0); OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1)); } #ifndef COMPILE_PCRE8 jump = CMP(SLJIT_GREATER, char1_reg, 0, SLJIT_IMM, 255); #endif OP1(SLJIT_MOV_U8, char1_reg, 0, SLJIT_MEM2(lcc_table, char1_reg), 0); #ifndef COMPILE_PCRE8 JUMPHERE(jump); jump = CMP(SLJIT_GREATER, char2_reg, 0, SLJIT_IMM, 255); #endif OP1(SLJIT_MOV_U8, char2_reg, 0, SLJIT_MEM2(lcc_table, char2_reg), 0); #ifndef COMPILE_PCRE8 JUMPHERE(jump); #endif if (opt_type == 0) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0); OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1)); JUMPTO(SLJIT_NOT_ZERO, label); JUMPHERE(jump); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); if (opt_type == 2) OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); if (char2_reg == STACK_TOP) { OP1(SLJIT_MOV, char2_reg, 0, TMP3, 0); OP1(SLJIT_MOV, lcc_table, 0, RETURN_ADDR, 0); } OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); sljit_emit_fast_return(compiler, TMP1, 0); } #if defined SUPPORT_UTF && defined SUPPORT_UCP static const pcre_uchar * SLJIT_FUNC do_utf_caselesscmp(pcre_uchar *src1, pcre_uchar *src2, pcre_uchar *end1, pcre_uchar *end2) { /* This function would be ineffective to do in JIT level. */ sljit_u32 c1, c2; const ucd_record *ur; const sljit_u32 *pp; while (src1 < end1) { if (src2 >= end2) return (pcre_uchar*)1; GETCHARINC(c1, src1); GETCHARINC(c2, src2); ur = GET_UCD(c2); if (c1 != c2 && c1 != c2 + ur->other_case) { pp = PRIV(ucd_caseless_sets) + ur->caseset; for (;;) { if (c1 < *pp) return NULL; if (c1 == *pp++) break; } } } return src2; } #endif /* SUPPORT_UTF && SUPPORT_UCP */ static pcre_uchar *byte_sequence_compare(compiler_common *common, BOOL caseless, pcre_uchar *cc, compare_context *context, jump_list **backtracks) { DEFINE_COMPILER; unsigned int othercasebit = 0; pcre_uchar *othercasechar = NULL; #ifdef SUPPORT_UTF int utflength; #endif if (caseless && char_has_othercase(common, cc)) { othercasebit = char_get_othercase_bit(common, cc); SLJIT_ASSERT(othercasebit); /* Extracting bit difference info. */ #if defined COMPILE_PCRE8 othercasechar = cc + (othercasebit >> 8); othercasebit &= 0xff; #elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 /* Note that this code only handles characters in the BMP. If there ever are characters outside the BMP whose othercase differs in only one bit from itself (there currently are none), this code will need to be revised for COMPILE_PCRE32. */ othercasechar = cc + (othercasebit >> 9); if ((othercasebit & 0x100) != 0) othercasebit = (othercasebit & 0xff) << 8; else othercasebit &= 0xff; #endif /* COMPILE_PCRE[8|16|32] */ } if (context->sourcereg == -1) { #if defined COMPILE_PCRE8 #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED if (context->length >= 4) OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); else if (context->length >= 2) OP1(SLJIT_MOV_U16, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); else #endif OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); #elif defined COMPILE_PCRE16 #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED if (context->length >= 4) OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); else #endif OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); #elif defined COMPILE_PCRE32 OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length); #endif /* COMPILE_PCRE[8|16|32] */ context->sourcereg = TMP2; } #ifdef SUPPORT_UTF utflength = 1; if (common->utf && HAS_EXTRALEN(*cc)) utflength += GET_EXTRALEN(*cc); do { #endif context->length -= IN_UCHARS(1); #if (defined SLJIT_UNALIGNED && SLJIT_UNALIGNED) && (defined COMPILE_PCRE8 || defined COMPILE_PCRE16) /* Unaligned read is supported. */ if (othercasebit != 0 && othercasechar == cc) { context->c.asuchars[context->ucharptr] = *cc | othercasebit; context->oc.asuchars[context->ucharptr] = othercasebit; } else { context->c.asuchars[context->ucharptr] = *cc; context->oc.asuchars[context->ucharptr] = 0; } context->ucharptr++; #if defined COMPILE_PCRE8 if (context->ucharptr >= 4 || context->length == 0 || (context->ucharptr == 2 && context->length == 1)) #else if (context->ucharptr >= 2 || context->length == 0) #endif { if (context->length >= 4) OP1(SLJIT_MOV_S32, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); else if (context->length >= 2) OP1(SLJIT_MOV_U16, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); #if defined COMPILE_PCRE8 else if (context->length >= 1) OP1(SLJIT_MOV_U8, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); #endif /* COMPILE_PCRE8 */ context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1; switch(context->ucharptr) { case 4 / sizeof(pcre_uchar): if (context->oc.asint != 0) OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asint); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asint | context->oc.asint)); break; case 2 / sizeof(pcre_uchar): if (context->oc.asushort != 0) OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asushort); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asushort | context->oc.asushort)); break; #ifdef COMPILE_PCRE8 case 1: if (context->oc.asbyte != 0) OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asbyte); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asbyte | context->oc.asbyte)); break; #endif default: SLJIT_UNREACHABLE(); break; } context->ucharptr = 0; } #else /* Unaligned read is unsupported or in 32 bit mode. */ if (context->length >= 1) OP1(MOV_UCHAR, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length); context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1; if (othercasebit != 0 && othercasechar == cc) { OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, othercasebit); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc | othercasebit)); } else add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc)); #endif cc++; #ifdef SUPPORT_UTF utflength--; } while (utflength > 0); #endif return cc; } #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 #define SET_TYPE_OFFSET(value) \ if ((value) != typeoffset) \ { \ if ((value) < typeoffset) \ OP2(SLJIT_ADD, typereg, 0, typereg, 0, SLJIT_IMM, typeoffset - (value)); \ else \ OP2(SLJIT_SUB, typereg, 0, typereg, 0, SLJIT_IMM, (value) - typeoffset); \ } \ typeoffset = (value); #define SET_CHAR_OFFSET(value) \ if ((value) != charoffset) \ { \ if ((value) < charoffset) \ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(charoffset - (value))); \ else \ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)((value) - charoffset)); \ } \ charoffset = (value); static pcre_uchar *compile_char1_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks, BOOL check_str_ptr); static void compile_xclass_matchingpath(compiler_common *common, pcre_uchar *cc, jump_list **backtracks) { DEFINE_COMPILER; jump_list *found = NULL; jump_list **list = (cc[0] & XCL_NOT) == 0 ? &found : backtracks; sljit_uw c, charoffset, max = 256, min = READ_CHAR_MAX; struct sljit_jump *jump = NULL; pcre_uchar *ccbegin; int compares, invertcmp, numberofcmps; #if defined SUPPORT_UTF && (defined COMPILE_PCRE8 || defined COMPILE_PCRE16) BOOL utf = common->utf; #endif #ifdef SUPPORT_UCP BOOL needstype = FALSE, needsscript = FALSE, needschar = FALSE; BOOL charsaved = FALSE; int typereg = TMP1; const sljit_u32 *other_cases; sljit_uw typeoffset; #endif /* Scanning the necessary info. */ cc++; ccbegin = cc; compares = 0; if (cc[-1] & XCL_MAP) { min = 0; cc += 32 / sizeof(pcre_uchar); } while (*cc != XCL_END) { compares++; if (*cc == XCL_SINGLE) { cc ++; GETCHARINCTEST(c, cc); if (c > max) max = c; if (c < min) min = c; #ifdef SUPPORT_UCP needschar = TRUE; #endif } else if (*cc == XCL_RANGE) { cc ++; GETCHARINCTEST(c, cc); if (c < min) min = c; GETCHARINCTEST(c, cc); if (c > max) max = c; #ifdef SUPPORT_UCP needschar = TRUE; #endif } #ifdef SUPPORT_UCP else { SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP); cc++; if (*cc == PT_CLIST) { other_cases = PRIV(ucd_caseless_sets) + cc[1]; while (*other_cases != NOTACHAR) { if (*other_cases > max) max = *other_cases; if (*other_cases < min) min = *other_cases; other_cases++; } } else { max = READ_CHAR_MAX; min = 0; } switch(*cc) { case PT_ANY: /* Any either accepts everything or ignored. */ if (cc[-1] == XCL_PROP) { compile_char1_matchingpath(common, OP_ALLANY, cc, backtracks, FALSE); if (list == backtracks) add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); return; } break; case PT_LAMP: case PT_GC: case PT_PC: case PT_ALNUM: needstype = TRUE; break; case PT_SC: needsscript = TRUE; break; case PT_SPACE: case PT_PXSPACE: case PT_WORD: case PT_PXGRAPH: case PT_PXPRINT: case PT_PXPUNCT: needstype = TRUE; needschar = TRUE; break; case PT_CLIST: case PT_UCNC: needschar = TRUE; break; default: SLJIT_UNREACHABLE(); break; } cc += 2; } #endif } SLJIT_ASSERT(compares > 0); /* We are not necessary in utf mode even in 8 bit mode. */ cc = ccbegin; read_char_range(common, min, max, (cc[-1] & XCL_NOT) != 0); if ((cc[-1] & XCL_HASPROP) == 0) { if ((cc[-1] & XCL_MAP) != 0) { jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); if (!check_class_ranges(common, (const sljit_u8 *)cc, (((const sljit_u8 *)cc)[31] & 0x80) != 0, TRUE, &found)) { OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); add_jump(compiler, &found, JUMP(SLJIT_NOT_ZERO)); } add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); JUMPHERE(jump); cc += 32 / sizeof(pcre_uchar); } else { OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, min); add_jump(compiler, (cc[-1] & XCL_NOT) == 0 ? backtracks : &found, CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, max - min)); } } else if ((cc[-1] & XCL_MAP) != 0) { OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); #ifdef SUPPORT_UCP charsaved = TRUE; #endif if (!check_class_ranges(common, (const sljit_u8 *)cc, FALSE, TRUE, list)) { #ifdef COMPILE_PCRE8 jump = NULL; if (common->utf) #endif jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); add_jump(compiler, list, JUMP(SLJIT_NOT_ZERO)); #ifdef COMPILE_PCRE8 if (common->utf) #endif JUMPHERE(jump); } OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0); cc += 32 / sizeof(pcre_uchar); } #ifdef SUPPORT_UCP if (needstype || needsscript) { if (needschar && !charsaved) OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0); #ifdef COMPILE_PCRE32 if (!common->utf) { jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x10ffff + 1); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR); JUMPHERE(jump); } #endif OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1)); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK); OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2)); OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1); /* Before anything else, we deal with scripts. */ if (needsscript) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script)); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3); ccbegin = cc; while (*cc != XCL_END) { if (*cc == XCL_SINGLE) { cc ++; GETCHARINCTEST(c, cc); } else if (*cc == XCL_RANGE) { cc ++; GETCHARINCTEST(c, cc); GETCHARINCTEST(c, cc); } else { SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP); cc++; if (*cc == PT_SC) { compares--; invertcmp = (compares == 0 && list != backtracks); if (cc[-1] == XCL_NOTPROP) invertcmp ^= 0x1; jump = CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (int)cc[1]); add_jump(compiler, compares > 0 ? list : backtracks, jump); } cc += 2; } } cc = ccbegin; } if (needschar) { OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0); } if (needstype) { if (!needschar) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype)); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3); } else { OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 3); OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype)); typereg = RETURN_ADDR; } } } #endif /* Generating code. */ charoffset = 0; numberofcmps = 0; #ifdef SUPPORT_UCP typeoffset = 0; #endif while (*cc != XCL_END) { compares--; invertcmp = (compares == 0 && list != backtracks); jump = NULL; if (*cc == XCL_SINGLE) { cc ++; GETCHARINCTEST(c, cc); if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE)) { OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_EQUAL); numberofcmps++; } else if (numberofcmps > 0) { OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); numberofcmps = 0; } else { jump = CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); numberofcmps = 0; } } else if (*cc == XCL_RANGE) { cc ++; GETCHARINCTEST(c, cc); SET_CHAR_OFFSET(c); GETCHARINCTEST(c, cc); if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE)) { OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); numberofcmps++; } else if (numberofcmps > 0) { OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); numberofcmps = 0; } else { jump = CMP(SLJIT_LESS_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset)); numberofcmps = 0; } } #ifdef SUPPORT_UCP else { SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP); if (*cc == XCL_NOTPROP) invertcmp ^= 0x1; cc++; switch(*cc) { case PT_ANY: if (!invertcmp) jump = JUMP(SLJIT_JUMP); break; case PT_LAMP: OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset); OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; case PT_GC: c = PRIV(ucp_typerange)[(int)cc[1] * 2]; SET_TYPE_OFFSET(c); jump = CMP(SLJIT_LESS_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, PRIV(ucp_typerange)[(int)cc[1] * 2 + 1] - c); break; case PT_PC: jump = CMP(SLJIT_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, (int)cc[1] - typeoffset); break; case PT_SC: compares++; /* Do nothing. */ break; case PT_SPACE: case PT_PXSPACE: SET_CHAR_OFFSET(9); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd - 0x9); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x9); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x9); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); SET_TYPE_OFFSET(ucp_Zl); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl); OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; case PT_WORD: OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_UNDERSCORE - charoffset)); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); /* Fall through. */ case PT_ALNUM: SET_TYPE_OFFSET(ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll); OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); SET_TYPE_OFFSET(ucp_Nd); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd); OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; case PT_CLIST: other_cases = PRIV(ucd_caseless_sets) + cc[1]; /* At least three characters are required. Otherwise this case would be handled by the normal code path. */ SLJIT_ASSERT(other_cases[0] != NOTACHAR && other_cases[1] != NOTACHAR && other_cases[2] != NOTACHAR); SLJIT_ASSERT(other_cases[0] < other_cases[1] && other_cases[1] < other_cases[2]); /* Optimizing character pairs, if their difference is power of 2. */ if (is_powerof2(other_cases[1] ^ other_cases[0])) { if (charoffset == 0) OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); else { OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset); OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); } OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[1]); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); other_cases += 2; } else if (is_powerof2(other_cases[2] ^ other_cases[1])) { if (charoffset == 0) OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[2] ^ other_cases[1]); else { OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset); OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]); } OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[2]); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(other_cases[0] - charoffset)); OP_FLAGS(SLJIT_OR | ((other_cases[3] == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL); other_cases += 3; } else { OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset)); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); } while (*other_cases != NOTACHAR) { OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset)); OP_FLAGS(SLJIT_OR | ((*other_cases == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL); } jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; case PT_UCNC: OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_DOLLAR_SIGN - charoffset)); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_COMMERCIAL_AT - charoffset)); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_GRAVE_ACCENT - charoffset)); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); SET_CHAR_OFFSET(0xa0); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(0xd7ff - charoffset)); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL); SET_CHAR_OFFSET(0); OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xe000 - 0); OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_GREATER_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; case PT_PXGRAPH: /* C and Z groups are the farthest two groups. */ SET_TYPE_OFFSET(ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER); jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll); /* In case of ucp_Cf, we overwrite the result. */ SET_CHAR_OFFSET(0x2066); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); JUMPHERE(jump); jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0); break; case PT_PXPRINT: /* C and Z groups are the farthest two groups. */ SET_TYPE_OFFSET(ucp_Ll); OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll); OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_NOT_EQUAL); jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll); /* In case of ucp_Cf, we overwrite the result. */ SET_CHAR_OFFSET(0x2066); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066); OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL); JUMPHERE(jump); jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0); break; case PT_PXPUNCT: SET_TYPE_OFFSET(ucp_Sc); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL); SET_CHAR_OFFSET(0); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x7f); OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_LESS_EQUAL); SET_TYPE_OFFSET(ucp_Pc); OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc); OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL); jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp); break; default: SLJIT_UNREACHABLE(); break; } cc += 2; } #endif if (jump != NULL) add_jump(compiler, compares > 0 ? list : backtracks, jump); } if (found != NULL) set_jumps(found, LABEL()); } #undef SET_TYPE_OFFSET #undef SET_CHAR_OFFSET #endif static pcre_uchar *compile_simple_assertion_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks) { DEFINE_COMPILER; int length; struct sljit_jump *jump[4]; #ifdef SUPPORT_UTF struct sljit_label *label; #endif /* SUPPORT_UTF */ switch(type) { case OP_SOD: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0)); return cc; case OP_SOM: OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0)); return cc; case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: add_jump(compiler, &common->wordboundary, JUMP(SLJIT_FAST_CALL)); sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(type == OP_NOT_WORD_BOUNDARY ? SLJIT_NOT_ZERO : SLJIT_ZERO)); return cc; case OP_EODN: /* Requires rather complex checks. */ jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); if (common->nltype == NLTYPE_FIXED && common->newline > 255) { OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); if (common->mode == JIT_COMPILE) add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0)); else { jump[1] = CMP(SLJIT_EQUAL, TMP2, 0, STR_END, 0); OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0); OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff); OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_NOT_EQUAL); add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL)); check_partial(common, TRUE); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); JUMPHERE(jump[1]); } OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff)); } else if (common->nltype == NLTYPE_FIXED) { OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline)); } else { OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0); jump[2] = JUMP(SLJIT_GREATER); add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL) /* LESS */); /* Equal. */ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); jump[3] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); JUMPHERE(jump[1]); if (common->nltype == NLTYPE_ANYCRLF) { OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, STR_END, 0)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL)); } else { OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STR_PTR, 0); read_char_range(common, common->nlmin, common->nlmax, TRUE); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0)); add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL)); sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(SLJIT_ZERO)); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); } JUMPHERE(jump[2]); JUMPHERE(jump[3]); } JUMPHERE(jump[0]); check_partial(common, FALSE); return cc; case OP_EOD: add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0)); check_partial(common, FALSE); return cc; case OP_DOLL: OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); if (!common->endonly) compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks); else { add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0)); check_partial(common, FALSE); } return cc; case OP_DOLLM: jump[1] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); check_partial(common, FALSE); jump[0] = JUMP(SLJIT_JUMP); JUMPHERE(jump[1]); if (common->nltype == NLTYPE_FIXED && common->newline > 255) { OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); if (common->mode == JIT_COMPILE) add_jump(compiler, backtracks, CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0)); else { jump[1] = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0); /* STR_PTR = STR_END - IN_UCHARS(1) */ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff)); check_partial(common, TRUE); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); JUMPHERE(jump[1]); } OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff)); } else { peek_char(common, common->nlmax); check_newlinechar(common, common->nltype, backtracks, FALSE); } JUMPHERE(jump[0]); return cc; case OP_CIRC: OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin)); add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0)); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); return cc; case OP_CIRCM: OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin)); jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); jump[0] = JUMP(SLJIT_JUMP); JUMPHERE(jump[1]); add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); if (common->nltype == NLTYPE_FIXED && common->newline > 255) { OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2)); add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, TMP1, 0)); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2)); OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff)); } else { skip_char_back(common); read_char_range(common, common->nlmin, common->nlmax, TRUE); check_newlinechar(common, common->nltype, backtracks, FALSE); } JUMPHERE(jump[0]); return cc; case OP_REVERSE: length = GET(cc, 0); if (length == 0) return cc + LINK_SIZE; OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); #ifdef SUPPORT_UTF if (common->utf) { OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, length); label = LABEL(); add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP3, 0)); skip_char_back(common); OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } else #endif { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin)); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length)); add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, TMP1, 0)); } check_start_used_ptr(common); return cc + LINK_SIZE; } SLJIT_UNREACHABLE(); return cc; } static pcre_uchar *compile_char1_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks, BOOL check_str_ptr) { DEFINE_COMPILER; int length; unsigned int c, oc, bit; compare_context context; struct sljit_jump *jump[3]; jump_list *end_list; #ifdef SUPPORT_UTF struct sljit_label *label; #ifdef SUPPORT_UCP pcre_uchar propdata[5]; #endif #endif /* SUPPORT_UTF */ switch(type) { case OP_NOT_DIGIT: case OP_DIGIT: /* Digits are usually 0-9, so it is worth to optimize them. */ if (check_str_ptr) detect_partial_match(common, backtracks); #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf && is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_digit, FALSE)) read_char7_type(common, type == OP_NOT_DIGIT); else #endif read_char8_type(common, type == OP_NOT_DIGIT); /* Flip the starting bit in the negative case. */ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit); add_jump(compiler, backtracks, JUMP(type == OP_DIGIT ? SLJIT_ZERO : SLJIT_NOT_ZERO)); return cc; case OP_NOT_WHITESPACE: case OP_WHITESPACE: if (check_str_ptr) detect_partial_match(common, backtracks); #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf && is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_space, FALSE)) read_char7_type(common, type == OP_NOT_WHITESPACE); else #endif read_char8_type(common, type == OP_NOT_WHITESPACE); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_space); add_jump(compiler, backtracks, JUMP(type == OP_WHITESPACE ? SLJIT_ZERO : SLJIT_NOT_ZERO)); return cc; case OP_NOT_WORDCHAR: case OP_WORDCHAR: if (check_str_ptr) detect_partial_match(common, backtracks); #if defined SUPPORT_UTF && defined COMPILE_PCRE8 if (common->utf && is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_word, FALSE)) read_char7_type(common, type == OP_NOT_WORDCHAR); else #endif read_char8_type(common, type == OP_NOT_WORDCHAR); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_word); add_jump(compiler, backtracks, JUMP(type == OP_WORDCHAR ? SLJIT_ZERO : SLJIT_NOT_ZERO)); return cc; case OP_ANY: if (check_str_ptr) detect_partial_match(common, backtracks); read_char_range(common, common->nlmin, common->nlmax, TRUE); if (common->nltype == NLTYPE_FIXED && common->newline > 255) { jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff); end_list = NULL; if (common->mode != JIT_PARTIAL_HARD_COMPILE) add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); else check_str_end(common, &end_list); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline & 0xff)); set_jumps(end_list, LABEL()); JUMPHERE(jump[0]); } else check_newlinechar(common, common->nltype, backtracks, TRUE); return cc; case OP_ALLANY: if (check_str_ptr) detect_partial_match(common, backtracks); #ifdef SUPPORT_UTF if (common->utf) { OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); #if defined COMPILE_PCRE8 || defined COMPILE_PCRE16 #if defined COMPILE_PCRE8 jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); #elif defined COMPILE_PCRE16 jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800); OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800); OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL); OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); #endif JUMPHERE(jump[0]); #endif /* COMPILE_PCRE[8|16] */ return cc; } #endif OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); return cc; case OP_ANYBYTE: if (check_str_ptr) detect_partial_match(common, backtracks); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); return cc; #ifdef SUPPORT_UTF #ifdef SUPPORT_UCP case OP_NOTPROP: case OP_PROP: propdata[0] = XCL_HASPROP; propdata[1] = type == OP_NOTPROP ? XCL_NOTPROP : XCL_PROP; propdata[2] = cc[0]; propdata[3] = cc[1]; propdata[4] = XCL_END; if (check_str_ptr) detect_partial_match(common, backtracks); compile_xclass_matchingpath(common, propdata, backtracks); return cc + 2; #endif #endif case OP_ANYNL: if (check_str_ptr) detect_partial_match(common, backtracks); read_char_range(common, common->bsr_nlmin, common->bsr_nlmax, FALSE); jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR); /* We don't need to handle soft partial matching case. */ end_list = NULL; if (common->mode != JIT_PARTIAL_HARD_COMPILE) add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0)); else check_str_end(common, &end_list); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); jump[2] = JUMP(SLJIT_JUMP); JUMPHERE(jump[0]); check_newlinechar(common, common->bsr_nltype, backtracks, FALSE); set_jumps(end_list, LABEL()); JUMPHERE(jump[1]); JUMPHERE(jump[2]); return cc; case OP_NOT_HSPACE: case OP_HSPACE: if (check_str_ptr) detect_partial_match(common, backtracks); read_char_range(common, 0x9, 0x3000, type == OP_NOT_HSPACE); add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL)); sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(type == OP_NOT_HSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO)); return cc; case OP_NOT_VSPACE: case OP_VSPACE: if (check_str_ptr) detect_partial_match(common, backtracks); read_char_range(common, 0xa, 0x2029, type == OP_NOT_VSPACE); add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL)); sljit_set_current_flags(compiler, SLJIT_SET_Z); add_jump(compiler, backtracks, JUMP(type == OP_NOT_VSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO)); return cc; #ifdef SUPPORT_UCP case OP_EXTUNI: if (check_str_ptr) detect_partial_match(common, backtracks); read_char(common); add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop)); /* Optimize register allocation: use a real register. */ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0); OP1(SLJIT_MOV_U8, STACK_TOP, 0, SLJIT_MEM2(TMP1, TMP2), 3); label = LABEL(); jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0); OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); read_char(common); add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, gbprop)); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM2(TMP1, TMP2), 3); OP2(SLJIT_SHL, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2); OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(STACK_TOP), (sljit_sw)PRIV(ucp_gbtable)); OP1(SLJIT_MOV, STACK_TOP, 0, TMP2, 0); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); JUMPTO(SLJIT_NOT_ZERO, label); OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); JUMPHERE(jump[0]); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); if (common->mode == JIT_PARTIAL_HARD_COMPILE) { jump[0] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0); /* Since we successfully read a char above, partial matching must occure. */ check_partial(common, TRUE); JUMPHERE(jump[0]); } return cc; #endif case OP_CHAR: case OP_CHARI: length = 1; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(*cc)) length += GET_EXTRALEN(*cc); #endif if (common->mode == JIT_COMPILE && check_str_ptr && (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0)) { OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length)); add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0)); context.length = IN_UCHARS(length); context.sourcereg = -1; #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED context.ucharptr = 0; #endif return byte_sequence_compare(common, type == OP_CHARI, cc, &context, backtracks); } if (check_str_ptr) detect_partial_match(common, backtracks); #ifdef SUPPORT_UTF if (common->utf) { GETCHAR(c, cc); } else #endif c = *cc; if (type == OP_CHAR || !char_has_othercase(common, cc)) { read_char_range(common, c, c, FALSE); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, c)); return cc + length; } oc = char_othercase(common, c); read_char_range(common, c < oc ? c : oc, c > oc ? c : oc, FALSE); bit = c ^ oc; if (is_powerof2(bit)) { OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, c | bit)); return cc + length; } jump[0] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, oc)); JUMPHERE(jump[0]); return cc + length; case OP_NOT: case OP_NOTI: if (check_str_ptr) detect_partial_match(common, backtracks); length = 1; #ifdef SUPPORT_UTF if (common->utf) { #ifdef COMPILE_PCRE8 c = *cc; if (c < 128) { OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), 0); if (type == OP_NOT || !char_has_othercase(common, cc)) add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c)); else { /* Since UTF8 code page is fixed, we know that c is in [a-z] or [A-Z] range. */ OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x20); add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, c | 0x20)); } /* Skip the variable-length character. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0); JUMPHERE(jump[0]); return cc + 1; } else #endif /* COMPILE_PCRE8 */ { GETCHARLEN(c, cc, length); } } else #endif /* SUPPORT_UTF */ c = *cc; if (type == OP_NOT || !char_has_othercase(common, cc)) { read_char_range(common, c, c, TRUE); add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c)); } else { oc = char_othercase(common, c); read_char_range(common, c < oc ? c : oc, c > oc ? c : oc, TRUE); bit = c ^ oc; if (is_powerof2(bit)) { OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit); add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c | bit)); } else { add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c)); add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, oc)); } } return cc + length; case OP_CLASS: case OP_NCLASS: if (check_str_ptr) detect_partial_match(common, backtracks); #if defined SUPPORT_UTF && defined COMPILE_PCRE8 bit = (common->utf && is_char7_bitset((const sljit_u8 *)cc, type == OP_NCLASS)) ? 127 : 255; read_char_range(common, 0, bit, type == OP_NCLASS); #else read_char_range(common, 0, 255, type == OP_NCLASS); #endif if (check_class_ranges(common, (const sljit_u8 *)cc, type == OP_NCLASS, FALSE, backtracks)) return cc + 32 / sizeof(pcre_uchar); #if defined SUPPORT_UTF && defined COMPILE_PCRE8 jump[0] = NULL; if (common->utf) { jump[0] = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, bit); if (type == OP_CLASS) { add_jump(compiler, backtracks, jump[0]); jump[0] = NULL; } } #elif !defined COMPILE_PCRE8 jump[0] = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255); if (type == OP_CLASS) { add_jump(compiler, backtracks, jump[0]); jump[0] = NULL; } #endif /* SUPPORT_UTF && COMPILE_PCRE8 */ OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7); OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3); OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc); OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0); OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0); add_jump(compiler, backtracks, JUMP(SLJIT_ZERO)); #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 if (jump[0] != NULL) JUMPHERE(jump[0]); #endif return cc + 32 / sizeof(pcre_uchar); #if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case OP_XCLASS: if (check_str_ptr) detect_partial_match(common, backtracks); compile_xclass_matchingpath(common, cc + LINK_SIZE, backtracks); return cc + GET(cc, 0) - 1; #endif } SLJIT_UNREACHABLE(); return cc; } static SLJIT_INLINE pcre_uchar *compile_charn_matchingpath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, jump_list **backtracks) { /* This function consumes at least one input character. */ /* To decrease the number of length checks, we try to concatenate the fixed length character sequences. */ DEFINE_COMPILER; pcre_uchar *ccbegin = cc; compare_context context; int size; context.length = 0; do { if (cc >= ccend) break; if (*cc == OP_CHAR) { size = 1; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(cc[1])) size += GET_EXTRALEN(cc[1]); #endif } else if (*cc == OP_CHARI) { size = 1; #ifdef SUPPORT_UTF if (common->utf) { if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0) size = 0; else if (HAS_EXTRALEN(cc[1])) size += GET_EXTRALEN(cc[1]); } else #endif if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0) size = 0; } else size = 0; cc += 1 + size; context.length += IN_UCHARS(size); } while (size > 0 && context.length <= 128); cc = ccbegin; if (context.length > 0) { /* We have a fixed-length byte sequence. */ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, context.length); add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0)); context.sourcereg = -1; #if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED context.ucharptr = 0; #endif do cc = byte_sequence_compare(common, *cc == OP_CHARI, cc + 1, &context, backtracks); while (context.length > 0); return cc; } /* A non-fixed length character will be checked if length == 0. */ return compile_char1_matchingpath(common, *cc, cc + 1, backtracks, TRUE); } /* Forward definitions. */ static void compile_matchingpath(compiler_common *, pcre_uchar *, pcre_uchar *, backtrack_common *); static void compile_backtrackingpath(compiler_common *, struct backtrack_common *); #define PUSH_BACKTRACK(size, ccstart, error) \ do \ { \ backtrack = sljit_alloc_memory(compiler, (size)); \ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \ return error; \ memset(backtrack, 0, size); \ backtrack->prev = parent->top; \ backtrack->cc = (ccstart); \ parent->top = backtrack; \ } \ while (0) #define PUSH_BACKTRACK_NOVALUE(size, ccstart) \ do \ { \ backtrack = sljit_alloc_memory(compiler, (size)); \ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \ return; \ memset(backtrack, 0, size); \ backtrack->prev = parent->top; \ backtrack->cc = (ccstart); \ parent->top = backtrack; \ } \ while (0) #define BACKTRACK_AS(type) ((type *)backtrack) static void compile_dnref_search(compiler_common *common, pcre_uchar *cc, jump_list **backtracks) { /* The OVECTOR offset goes to TMP2. */ DEFINE_COMPILER; int count = GET2(cc, 1 + IMM2_SIZE); pcre_uchar *slot = common->name_table + GET2(cc, 1) * common->name_entry_size; unsigned int offset; jump_list *found = NULL; SLJIT_ASSERT(*cc == OP_DNREF || *cc == OP_DNREFI); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); count--; while (count-- > 0) { offset = GET2(slot, 0) << 1; GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset)); add_jump(compiler, &found, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0)); slot += common->name_entry_size; } offset = GET2(slot, 0) << 1; GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset)); if (backtracks != NULL && !common->jscript_compat) add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0)); set_jumps(found, LABEL()); } static void compile_ref_matchingpath(compiler_common *common, pcre_uchar *cc, jump_list **backtracks, BOOL withchecks, BOOL emptyfail) { DEFINE_COMPILER; BOOL ref = (*cc == OP_REF || *cc == OP_REFI); int offset = 0; struct sljit_jump *jump = NULL; struct sljit_jump *partial; struct sljit_jump *nopartial; if (ref) { offset = GET2(cc, 1) << 1; OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); /* OVECTOR(1) contains the "string begin - 1" constant. */ if (withchecks && !common->jscript_compat) add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1))); } else OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); #if defined SUPPORT_UTF && defined SUPPORT_UCP if (common->utf && *cc == OP_REFI) { SLJIT_ASSERT(TMP1 == SLJIT_R0 && STACK_TOP == SLJIT_R1); if (ref) OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); else OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); if (withchecks) jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_R2, 0); /* No free saved registers so save data on stack. */ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0); OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_R3, 0, STR_END, 0); sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_utf_caselesscmp)); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0); if (common->mode == JIT_COMPILE) add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1)); else { OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_LESS, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1); add_jump(compiler, backtracks, JUMP(SLJIT_LESS)); nopartial = JUMP(SLJIT_NOT_EQUAL); OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0); check_partial(common, FALSE); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); JUMPHERE(nopartial); } } else #endif /* SUPPORT_UTF && SUPPORT_UCP */ { if (ref) OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0); else OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0); if (withchecks) jump = JUMP(SLJIT_ZERO); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0); partial = CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0); if (common->mode == JIT_COMPILE) add_jump(compiler, backtracks, partial); add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); if (common->mode != JIT_COMPILE) { nopartial = JUMP(SLJIT_JUMP); JUMPHERE(partial); /* TMP2 -= STR_END - STR_PTR */ OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, STR_PTR, 0); OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, STR_END, 0); partial = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0); OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0); add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL)); add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); JUMPHERE(partial); check_partial(common, FALSE); add_jump(compiler, backtracks, JUMP(SLJIT_JUMP)); JUMPHERE(nopartial); } } if (jump != NULL) { if (emptyfail) add_jump(compiler, backtracks, jump); else JUMPHERE(jump); } } static SLJIT_INLINE pcre_uchar *compile_ref_iterator_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; BOOL ref = (*cc == OP_REF || *cc == OP_REFI); backtrack_common *backtrack; pcre_uchar type; int offset = 0; struct sljit_label *label; struct sljit_jump *zerolength; struct sljit_jump *jump = NULL; pcre_uchar *ccbegin = cc; int min = 0, max = 0; BOOL minimize; PUSH_BACKTRACK(sizeof(ref_iterator_backtrack), cc, NULL); if (ref) offset = GET2(cc, 1) << 1; else cc += IMM2_SIZE; type = cc[1 + IMM2_SIZE]; SLJIT_COMPILE_ASSERT((OP_CRSTAR & 0x1) == 0, crstar_opcode_must_be_even); minimize = (type & 0x1) != 0; switch(type) { case OP_CRSTAR: case OP_CRMINSTAR: min = 0; max = 0; cc += 1 + IMM2_SIZE + 1; break; case OP_CRPLUS: case OP_CRMINPLUS: min = 1; max = 0; cc += 1 + IMM2_SIZE + 1; break; case OP_CRQUERY: case OP_CRMINQUERY: min = 0; max = 1; cc += 1 + IMM2_SIZE + 1; break; case OP_CRRANGE: case OP_CRMINRANGE: min = GET2(cc, 1 + IMM2_SIZE + 1); max = GET2(cc, 1 + IMM2_SIZE + 1 + IMM2_SIZE); cc += 1 + IMM2_SIZE + 1 + 2 * IMM2_SIZE; break; default: SLJIT_UNREACHABLE(); break; } if (!minimize) { if (min == 0) { allocate_stack(common, 2); if (ref) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0); /* Temporary release of STR_PTR. */ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); /* Handles both invalid and empty cases. Since the minimum repeat, is zero the invalid case is basically the same as an empty case. */ if (ref) zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); else { compile_dnref_search(common, ccbegin, NULL); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0); zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); } /* Restore if not zero length. */ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); } else { allocate_stack(common, 1); if (ref) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); if (ref) { add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1))); zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); } else { compile_dnref_search(common, ccbegin, &backtrack->topbacktracks); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0); zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); } } if (min > 1 || max > 1) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, 0); label = LABEL(); if (!ref) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1); compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, FALSE, FALSE); if (min > 1 || max > 1) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0); if (min > 1) CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, label); if (max > 1) { jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, max); allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); JUMPTO(SLJIT_JUMP, label); JUMPHERE(jump); } } if (max == 0) { /* Includes min > 1 case as well. */ allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); JUMPTO(SLJIT_JUMP, label); } JUMPHERE(zerolength); BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL(); count_match(common); return cc; } allocate_stack(common, ref ? 2 : 3); if (ref) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); if (type != OP_CRMINSTAR) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0); if (min == 0) { /* Handles both invalid and empty cases. Since the minimum repeat, is zero the invalid case is basically the same as an empty case. */ if (ref) zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); else { compile_dnref_search(common, ccbegin, NULL); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0); zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); } /* Length is non-zero, we can match real repeats. */ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); jump = JUMP(SLJIT_JUMP); } else { if (ref) { add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1))); zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); } else { compile_dnref_search(common, ccbegin, &backtrack->topbacktracks); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0); zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw)); } } BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL(); if (max > 0) add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, max)); if (!ref) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(2)); compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, TRUE, TRUE); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); if (min > 1) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, BACKTRACK_AS(ref_iterator_backtrack)->matchingpath); } else if (max > 0) OP2(SLJIT_ADD, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1); if (jump != NULL) JUMPHERE(jump); JUMPHERE(zerolength); count_match(common); return cc; } static SLJIT_INLINE pcre_uchar *compile_recurse_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; recurse_entry *entry = common->entries; recurse_entry *prev = NULL; sljit_sw start = GET(cc, 1); pcre_uchar *start_cc; BOOL needs_control_head; PUSH_BACKTRACK(sizeof(recurse_backtrack), cc, NULL); /* Inlining simple patterns. */ if (get_framesize(common, common->start + start, NULL, TRUE, &needs_control_head) == no_stack) { start_cc = common->start + start; compile_matchingpath(common, next_opcode(common, start_cc), bracketend(start_cc) - (1 + LINK_SIZE), backtrack); BACKTRACK_AS(recurse_backtrack)->inlined_pattern = TRUE; return cc + 1 + LINK_SIZE; } while (entry != NULL) { if (entry->start == start) break; prev = entry; entry = entry->next; } if (entry == NULL) { entry = sljit_alloc_memory(compiler, sizeof(recurse_entry)); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; entry->next = NULL; entry->entry = NULL; entry->calls = NULL; entry->start = start; if (prev != NULL) prev->next = entry; else common->entries = entry; } if (common->has_set_som && common->mark_ptr != 0) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); allocate_stack(common, 2); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); } else if (common->has_set_som || common->mark_ptr != 0) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->has_set_som ? (int)(OVECTOR(0)) : common->mark_ptr); allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); } if (entry->entry == NULL) add_jump(compiler, &entry->calls, JUMP(SLJIT_FAST_CALL)); else JUMPTO(SLJIT_FAST_CALL, entry->entry); /* Leave if the match is failed. */ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0)); return cc + 1 + LINK_SIZE; } static sljit_s32 SLJIT_FUNC do_callout(struct jit_arguments *arguments, PUBL(callout_block) *callout_block, pcre_uchar **jit_ovector) { const pcre_uchar *begin = arguments->begin; int *offset_vector = arguments->offsets; int offset_count = arguments->offset_count; int i; if (PUBL(callout) == NULL) return 0; callout_block->version = 2; callout_block->callout_data = arguments->callout_data; /* Offsets in subject. */ callout_block->subject_length = arguments->end - arguments->begin; callout_block->start_match = (pcre_uchar*)callout_block->subject - arguments->begin; callout_block->current_position = (pcre_uchar*)callout_block->offset_vector - arguments->begin; #if defined COMPILE_PCRE8 callout_block->subject = (PCRE_SPTR)begin; #elif defined COMPILE_PCRE16 callout_block->subject = (PCRE_SPTR16)begin; #elif defined COMPILE_PCRE32 callout_block->subject = (PCRE_SPTR32)begin; #endif /* Convert and copy the JIT offset vector to the offset_vector array. */ callout_block->capture_top = 0; callout_block->offset_vector = offset_vector; for (i = 2; i < offset_count; i += 2) { offset_vector[i] = jit_ovector[i] - begin; offset_vector[i + 1] = jit_ovector[i + 1] - begin; if (jit_ovector[i] >= begin) callout_block->capture_top = i; } callout_block->capture_top = (callout_block->capture_top >> 1) + 1; if (offset_count > 0) offset_vector[0] = -1; if (offset_count > 1) offset_vector[1] = -1; return (*PUBL(callout))(callout_block); } /* Aligning to 8 byte. */ #define CALLOUT_ARG_SIZE \ (((int)sizeof(PUBL(callout_block)) + 7) & ~7) #define CALLOUT_ARG_OFFSET(arg) \ SLJIT_OFFSETOF(PUBL(callout_block), arg) static SLJIT_INLINE pcre_uchar *compile_callout_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); allocate_stack(common, CALLOUT_ARG_SIZE / sizeof(sljit_sw)); SLJIT_ASSERT(common->capture_last_ptr != 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, cc[1]); OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0); /* These pointer sized fields temporarly stores internal variables. */ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(offset_vector), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(subject), TMP2, 0); if (common->mark_ptr != 0) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr)); OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(pattern_position), SLJIT_IMM, GET(cc, 2)); OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(next_item_length), SLJIT_IMM, GET(cc, 2 + LINK_SIZE)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_ptr != 0) ? TMP2 : SLJIT_IMM, 0); /* Needed to save important temporary registers. */ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0); /* SLJIT_R0 = arguments */ OP1(SLJIT_MOV, SLJIT_R1, 0, STACK_TOP, 0); GET_LOCAL_BASE(SLJIT_R2, 0, OVECTOR_START); sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(S32) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout)); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); free_stack(common, CALLOUT_ARG_SIZE / sizeof(sljit_sw)); /* Check return value. */ OP2(SLJIT_SUB32 | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER32)); if (common->forced_quit_label == NULL) add_jump(compiler, &common->forced_quit, JUMP(SLJIT_NOT_EQUAL32) /* SIG_LESS */); else JUMPTO(SLJIT_NOT_EQUAL32 /* SIG_LESS */, common->forced_quit_label); return cc + 2 + 2 * LINK_SIZE; } #undef CALLOUT_ARG_SIZE #undef CALLOUT_ARG_OFFSET static SLJIT_INLINE BOOL assert_needs_str_ptr_saving(pcre_uchar *cc) { while (TRUE) { switch (*cc) { case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: case OP_CIRC: case OP_CIRCM: case OP_DOLL: case OP_DOLLM: case OP_CALLOUT: case OP_ALT: cc += PRIV(OP_lengths)[*cc]; break; case OP_KET: return FALSE; default: return TRUE; } } } static pcre_uchar *compile_assert_matchingpath(compiler_common *common, pcre_uchar *cc, assert_backtrack *backtrack, BOOL conditional) { DEFINE_COMPILER; int framesize; int extrasize; BOOL needs_control_head; int private_data_ptr; backtrack_common altbacktrack; pcre_uchar *ccbegin; pcre_uchar opcode; pcre_uchar bra = OP_BRA; jump_list *tmp = NULL; jump_list **target = (conditional) ? &backtrack->condfailed : &backtrack->common.topbacktracks; jump_list **found; /* Saving previous accept variables. */ BOOL save_local_exit = common->local_exit; BOOL save_positive_assert = common->positive_assert; then_trap_backtrack *save_then_trap = common->then_trap; struct sljit_label *save_quit_label = common->quit_label; struct sljit_label *save_accept_label = common->accept_label; jump_list *save_quit = common->quit; jump_list *save_positive_assert_quit = common->positive_assert_quit; jump_list *save_accept = common->accept; struct sljit_jump *jump; struct sljit_jump *brajump = NULL; /* Assert captures then. */ common->then_trap = NULL; if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) { SLJIT_ASSERT(!conditional); bra = *cc; cc++; } private_data_ptr = PRIVATE_DATA(cc); SLJIT_ASSERT(private_data_ptr != 0); framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head); backtrack->framesize = framesize; backtrack->private_data_ptr = private_data_ptr; opcode = *cc; SLJIT_ASSERT(opcode >= OP_ASSERT && opcode <= OP_ASSERTBACK_NOT); found = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) ? &tmp : target; ccbegin = cc; cc += GET(cc, 1); if (bra == OP_BRAMINZERO) { /* This is a braminzero backtrack path. */ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); brajump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); } if (framesize < 0) { extrasize = 1; if (bra == OP_BRA && !assert_needs_str_ptr_saving(ccbegin + 1 + LINK_SIZE)) extrasize = 0; if (needs_control_head) extrasize++; if (framesize == no_frame) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0); if (extrasize > 0) allocate_stack(common, extrasize); if (needs_control_head) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); if (extrasize > 0) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); if (needs_control_head) { SLJIT_ASSERT(extrasize == 2); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); } } else { extrasize = needs_control_head ? 3 : 2; allocate_stack(common, framesize + extrasize); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); if (needs_control_head) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); if (needs_control_head) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); } else OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0); init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize, FALSE); } memset(&altbacktrack, 0, sizeof(backtrack_common)); if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) { /* Negative assert is stronger than positive assert. */ common->local_exit = TRUE; common->quit_label = NULL; common->quit = NULL; common->positive_assert = FALSE; } else common->positive_assert = TRUE; common->positive_assert_quit = NULL; while (1) { common->accept_label = NULL; common->accept = NULL; altbacktrack.top = NULL; altbacktrack.topbacktracks = NULL; if (*ccbegin == OP_ALT && extrasize > 0) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); altbacktrack.cc = ccbegin; compile_matchingpath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) { common->local_exit = save_local_exit; common->quit_label = save_quit_label; common->quit = save_quit; } common->positive_assert = save_positive_assert; common->then_trap = save_then_trap; common->accept_label = save_accept_label; common->positive_assert_quit = save_positive_assert_quit; common->accept = save_accept; return NULL; } common->accept_label = LABEL(); if (common->accept != NULL) set_jumps(common->accept, common->accept_label); /* Reset stack. */ if (framesize < 0) { if (framesize == no_frame) OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); else if (extrasize > 0) free_stack(common, extrasize); if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1)); } else { if ((opcode != OP_ASSERT_NOT && opcode != OP_ASSERTBACK_NOT) || conditional) { /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1)); } else { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 2)); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); } } if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) { /* We know that STR_PTR was stored on the top of the stack. */ if (conditional) { if (extrasize > 0) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? STACK(-2) : STACK(-1)); } else if (bra == OP_BRAZERO) { if (framesize < 0) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize)); else { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1)); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - extrasize)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); } OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else if (framesize >= 0) { /* For OP_BRA and OP_BRAMINZERO. */ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1)); } } add_jump(compiler, found, JUMP(SLJIT_JUMP)); compile_backtrackingpath(common, altbacktrack.top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) { common->local_exit = save_local_exit; common->quit_label = save_quit_label; common->quit = save_quit; } common->positive_assert = save_positive_assert; common->then_trap = save_then_trap; common->accept_label = save_accept_label; common->positive_assert_quit = save_positive_assert_quit; common->accept = save_accept; return NULL; } set_jumps(altbacktrack.topbacktracks, LABEL()); if (*cc != OP_ALT) break; ccbegin = cc; cc += GET(cc, 1); } if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) { SLJIT_ASSERT(common->positive_assert_quit == NULL); /* Makes the check less complicated below. */ common->positive_assert_quit = common->quit; } /* None of them matched. */ if (common->positive_assert_quit != NULL) { jump = JUMP(SLJIT_JUMP); set_jumps(common->positive_assert_quit, LABEL()); SLJIT_ASSERT(framesize != no_stack); if (framesize < 0) OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw)); else { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw)); } JUMPHERE(jump); } if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(1)); if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) { /* Assert is failed. */ if ((conditional && extrasize > 0) || bra == OP_BRAZERO) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); if (framesize < 0) { /* The topmost item should be 0. */ if (bra == OP_BRAZERO) { if (extrasize == 2) free_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else if (extrasize > 0) free_stack(common, extrasize); } else { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1)); /* The topmost item should be 0. */ if (bra == OP_BRAZERO) { free_stack(common, framesize + extrasize - 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else free_stack(common, framesize + extrasize); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); } jump = JUMP(SLJIT_JUMP); if (bra != OP_BRAZERO) add_jump(compiler, target, jump); /* Assert is successful. */ set_jumps(tmp, LABEL()); if (framesize < 0) { /* We know that STR_PTR was stored on the top of the stack. */ if (extrasize > 0) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize)); /* Keep the STR_PTR on the top of the stack. */ if (bra == OP_BRAZERO) { OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); if (extrasize == 2) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); } else if (bra == OP_BRAMINZERO) { OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } } else { if (bra == OP_BRA) { /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw)); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize + 1)); } else { /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw)); if (extrasize == 2) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); if (bra == OP_BRAMINZERO) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), bra == OP_BRAZERO ? STR_PTR : SLJIT_IMM, 0); } } } if (bra == OP_BRAZERO) { backtrack->matchingpath = LABEL(); SET_LABEL(jump, backtrack->matchingpath); } else if (bra == OP_BRAMINZERO) { JUMPTO(SLJIT_JUMP, backtrack->matchingpath); JUMPHERE(brajump); if (framesize >= 0) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1)); } set_jumps(backtrack->common.topbacktracks, LABEL()); } } else { /* AssertNot is successful. */ if (framesize < 0) { if (extrasize > 0) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); if (bra != OP_BRA) { if (extrasize == 2) free_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else if (extrasize > 0) free_stack(common, extrasize); } else { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1)); /* The topmost item should be 0. */ if (bra != OP_BRA) { free_stack(common, framesize + extrasize - 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } else free_stack(common, framesize + extrasize); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); } if (bra == OP_BRAZERO) backtrack->matchingpath = LABEL(); else if (bra == OP_BRAMINZERO) { JUMPTO(SLJIT_JUMP, backtrack->matchingpath); JUMPHERE(brajump); } if (bra != OP_BRA) { SLJIT_ASSERT(found == &backtrack->common.topbacktracks); set_jumps(backtrack->common.topbacktracks, LABEL()); backtrack->common.topbacktracks = NULL; } } if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT) { common->local_exit = save_local_exit; common->quit_label = save_quit_label; common->quit = save_quit; } common->positive_assert = save_positive_assert; common->then_trap = save_then_trap; common->accept_label = save_accept_label; common->positive_assert_quit = save_positive_assert_quit; common->accept = save_accept; return cc + 1 + LINK_SIZE; } static SLJIT_INLINE void match_once_common(compiler_common *common, pcre_uchar ket, int framesize, int private_data_ptr, BOOL has_alternatives, BOOL needs_control_head) { DEFINE_COMPILER; int stacksize; if (framesize < 0) { if (framesize == no_frame) OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); else { stacksize = needs_control_head ? 1 : 0; if (ket != OP_KET || has_alternatives) stacksize++; if (stacksize > 0) free_stack(common, stacksize); } if (needs_control_head) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), (ket != OP_KET || has_alternatives) ? STACK(-2) : STACK(-1)); /* TMP2 which is set here used by OP_KETRMAX below. */ if (ket == OP_KETRMAX) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-1)); else if (ket == OP_KETRMIN) { /* Move the STR_PTR to the private_data_ptr. */ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1)); } } else { stacksize = (ket != OP_KET || has_alternatives) ? 2 : 1; OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + stacksize) * sizeof(sljit_sw)); if (needs_control_head) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-1)); if (ket == OP_KETRMAX) { /* TMP2 which is set here used by OP_KETRMAX below. */ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); } } if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0); } static SLJIT_INLINE int match_capture_common(compiler_common *common, int stacksize, int offset, int private_data_ptr) { DEFINE_COMPILER; if (common->capture_last_ptr != 0) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); stacksize++; } if (common->optimized_cbracket[offset >> 1] == 0) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); stacksize += 2; } return stacksize; } /* Handling bracketed expressions is probably the most complex part. Stack layout naming characters: S - Push the current STR_PTR 0 - Push a 0 (NULL) A - Push the current STR_PTR. Needed for restoring the STR_PTR before the next alternative. Not pushed if there are no alternatives. M - Any values pushed by the current alternative. Can be empty, or anything. C - Push the previous OVECTOR(i), OVECTOR(i+1) and OVECTOR_PRIV(i) to the stack. L - Push the previous local (pointed by localptr) to the stack () - opional values stored on the stack ()* - optonal, can be stored multiple times The following list shows the regular expression templates, their PCRE byte codes and stack layout supported by pcre-sljit. (?:) OP_BRA | OP_KET A M () OP_CBRA | OP_KET C M (?:)+ OP_BRA | OP_KETRMAX 0 A M S ( A M S )* OP_SBRA | OP_KETRMAX 0 L M S ( L M S )* (?:)+? OP_BRA | OP_KETRMIN 0 A M S ( A M S )* OP_SBRA | OP_KETRMIN 0 L M S ( L M S )* ()+ OP_CBRA | OP_KETRMAX 0 C M S ( C M S )* OP_SCBRA | OP_KETRMAX 0 C M S ( C M S )* ()+? OP_CBRA | OP_KETRMIN 0 C M S ( C M S )* OP_SCBRA | OP_KETRMIN 0 C M S ( C M S )* (?:)? OP_BRAZERO | OP_BRA | OP_KET S ( A M 0 ) (?:)?? OP_BRAMINZERO | OP_BRA | OP_KET S ( A M 0 ) ()? OP_BRAZERO | OP_CBRA | OP_KET S ( C M 0 ) ()?? OP_BRAMINZERO | OP_CBRA | OP_KET S ( C M 0 ) (?:)* OP_BRAZERO | OP_BRA | OP_KETRMAX S 0 ( A M S )* OP_BRAZERO | OP_SBRA | OP_KETRMAX S 0 ( L M S )* (?:)*? OP_BRAMINZERO | OP_BRA | OP_KETRMIN S 0 ( A M S )* OP_BRAMINZERO | OP_SBRA | OP_KETRMIN S 0 ( L M S )* ()* OP_BRAZERO | OP_CBRA | OP_KETRMAX S 0 ( C M S )* OP_BRAZERO | OP_SCBRA | OP_KETRMAX S 0 ( C M S )* ()*? OP_BRAMINZERO | OP_CBRA | OP_KETRMIN S 0 ( C M S )* OP_BRAMINZERO | OP_SCBRA | OP_KETRMIN S 0 ( C M S )* Stack layout naming characters: A - Push the alternative index (starting from 0) on the stack. Not pushed if there is no alternatives. M - Any values pushed by the current alternative. Can be empty, or anything. The next list shows the possible content of a bracket: (|) OP_*BRA | OP_ALT ... M A (?()|) OP_*COND | OP_ALT M A (?>|) OP_ONCE | OP_ALT ... [stack trace] M A (?>|) OP_ONCE_NC | OP_ALT ... [stack trace] M A Or nothing, if trace is unnecessary */ static pcre_uchar *compile_bracket_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; pcre_uchar opcode; int private_data_ptr = 0; int offset = 0; int i, stacksize; int repeat_ptr = 0, repeat_length = 0; int repeat_type = 0, repeat_count = 0; pcre_uchar *ccbegin; pcre_uchar *matchingpath; pcre_uchar *slot; pcre_uchar bra = OP_BRA; pcre_uchar ket; assert_backtrack *assert; BOOL has_alternatives; BOOL needs_control_head = FALSE; struct sljit_jump *jump; struct sljit_jump *skip; struct sljit_label *rmax_label = NULL; struct sljit_jump *braminzero = NULL; PUSH_BACKTRACK(sizeof(bracket_backtrack), cc, NULL); if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) { bra = *cc; cc++; opcode = *cc; } opcode = *cc; ccbegin = cc; matchingpath = bracketend(cc) - 1 - LINK_SIZE; ket = *matchingpath; if (ket == OP_KET && PRIVATE_DATA(matchingpath) != 0) { repeat_ptr = PRIVATE_DATA(matchingpath); repeat_length = PRIVATE_DATA(matchingpath + 1); repeat_type = PRIVATE_DATA(matchingpath + 2); repeat_count = PRIVATE_DATA(matchingpath + 3); SLJIT_ASSERT(repeat_length != 0 && repeat_type != 0 && repeat_count != 0); if (repeat_type == OP_UPTO) ket = OP_KETRMAX; if (repeat_type == OP_MINUPTO) ket = OP_KETRMIN; } if ((opcode == OP_COND || opcode == OP_SCOND) && cc[1 + LINK_SIZE] == OP_DEF) { /* Drop this bracket_backtrack. */ parent->top = backtrack->prev; return matchingpath + 1 + LINK_SIZE + repeat_length; } matchingpath = ccbegin + 1 + LINK_SIZE; SLJIT_ASSERT(ket == OP_KET || ket == OP_KETRMAX || ket == OP_KETRMIN); SLJIT_ASSERT(!((bra == OP_BRAZERO && ket == OP_KETRMIN) || (bra == OP_BRAMINZERO && ket == OP_KETRMAX))); cc += GET(cc, 1); has_alternatives = *cc == OP_ALT; if (SLJIT_UNLIKELY(opcode == OP_COND || opcode == OP_SCOND)) has_alternatives = (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF || *matchingpath == OP_FAIL) ? FALSE : TRUE; if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN)) opcode = OP_SCOND; if (SLJIT_UNLIKELY(opcode == OP_ONCE_NC)) opcode = OP_ONCE; if (opcode == OP_CBRA || opcode == OP_SCBRA) { /* Capturing brackets has a pre-allocated space. */ offset = GET2(ccbegin, 1 + LINK_SIZE); if (common->optimized_cbracket[offset] == 0) { private_data_ptr = OVECTOR_PRIV(offset); offset <<= 1; } else { offset <<= 1; private_data_ptr = OVECTOR(offset); } BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr; matchingpath += IMM2_SIZE; } else if (opcode == OP_ONCE || opcode == OP_SBRA || opcode == OP_SCOND) { /* Other brackets simply allocate the next entry. */ private_data_ptr = PRIVATE_DATA(ccbegin); SLJIT_ASSERT(private_data_ptr != 0); BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr; if (opcode == OP_ONCE) BACKTRACK_AS(bracket_backtrack)->u.framesize = get_framesize(common, ccbegin, NULL, FALSE, &needs_control_head); } /* Instructions before the first alternative. */ stacksize = 0; if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO)) stacksize++; if (bra == OP_BRAZERO) stacksize++; if (stacksize > 0) allocate_stack(common, stacksize); stacksize = 0; if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO)) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); stacksize++; } if (bra == OP_BRAZERO) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); if (bra == OP_BRAMINZERO) { /* This is a backtrack path! (Since the try-path of OP_BRAMINZERO matches to the empty string) */ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); if (ket != OP_KETRMIN) { free_stack(common, 1); braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); } else { if (opcode == OP_ONCE || opcode >= OP_SBRA) { jump = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); /* Nothing stored during the first run. */ skip = JUMP(SLJIT_JUMP); JUMPHERE(jump); /* Checking zero-length iteration. */ if (opcode != OP_ONCE || BACKTRACK_AS(bracket_backtrack)->u.framesize < 0) { /* When we come from outside, private_data_ptr contains the previous STR_PTR. */ braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); } else { /* Except when the whole stack frame must be saved. */ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-BACKTRACK_AS(bracket_backtrack)->u.framesize - 2)); } JUMPHERE(skip); } else { jump = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); JUMPHERE(jump); } } } if (repeat_type != 0) { OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, repeat_count); if (repeat_type == OP_EXACT) rmax_label = LABEL(); } if (ket == OP_KETRMIN) BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL(); if (ket == OP_KETRMAX) { rmax_label = LABEL(); if (has_alternatives && opcode != OP_ONCE && opcode < OP_SBRA && repeat_type == 0) BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = rmax_label; } /* Handling capturing brackets and alternatives. */ if (opcode == OP_ONCE) { stacksize = 0; if (needs_control_head) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); stacksize++; } if (BACKTRACK_AS(bracket_backtrack)->u.framesize < 0) { /* Neither capturing brackets nor recursions are found in the block. */ if (ket == OP_KETRMIN) { stacksize += 2; if (!needs_control_head) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); } else { if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0); if (ket == OP_KETRMAX || has_alternatives) stacksize++; } if (stacksize > 0) allocate_stack(common, stacksize); stacksize = 0; if (needs_control_head) { stacksize++; OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); } if (ket == OP_KETRMIN) { if (needs_control_head) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame) OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, needs_control_head ? (2 * sizeof(sljit_sw)) : sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0); } else if (ket == OP_KETRMAX || has_alternatives) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); } else { if (ket != OP_KET || has_alternatives) stacksize++; stacksize += BACKTRACK_AS(bracket_backtrack)->u.framesize + 1; allocate_stack(common, stacksize); if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); stacksize = needs_control_head ? 1 : 0; if (ket != OP_KET || has_alternatives) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); stacksize++; OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); } else { OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0); } init_frame(common, ccbegin, NULL, BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize, stacksize + 1, FALSE); } } else if (opcode == OP_CBRA || opcode == OP_SCBRA) { /* Saving the previous values. */ if (common->optimized_cbracket[offset >> 1] != 0) { SLJIT_ASSERT(private_data_ptr == OVECTOR(offset)); allocate_stack(common, 2); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); } else { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); } } else if (opcode == OP_SBRA || opcode == OP_SCOND) { /* Saving the previous value. */ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); } else if (has_alternatives) { /* Pushing the starting string pointer. */ allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); } /* Generating code for the first alternative. */ if (opcode == OP_COND || opcode == OP_SCOND) { if (*matchingpath == OP_CREF) { SLJIT_ASSERT(has_alternatives); add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(matchingpath, 1) << 1), SLJIT_MEM1(SLJIT_SP), OVECTOR(1))); matchingpath += 1 + IMM2_SIZE; } else if (*matchingpath == OP_DNCREF) { SLJIT_ASSERT(has_alternatives); i = GET2(matchingpath, 1 + IMM2_SIZE); slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size; OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)); OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0); slot += common->name_entry_size; i--; while (i-- > 0) { OP2(SLJIT_SUB, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0); OP2(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, TMP2, 0, STR_PTR, 0); slot += common->name_entry_size; } OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0); add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), JUMP(SLJIT_ZERO)); matchingpath += 1 + 2 * IMM2_SIZE; } else if (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF || *matchingpath == OP_FAIL) { /* Never has other case. */ BACKTRACK_AS(bracket_backtrack)->u.condfailed = NULL; SLJIT_ASSERT(!has_alternatives); if (*matchingpath == OP_FAIL) stacksize = 0; else if (*matchingpath == OP_RREF) { stacksize = GET2(matchingpath, 1); if (common->currententry == NULL) stacksize = 0; else if (stacksize == RREF_ANY) stacksize = 1; else if (common->currententry->start == 0) stacksize = stacksize == 0; else stacksize = stacksize == (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE); if (stacksize != 0) matchingpath += 1 + IMM2_SIZE; } else { if (common->currententry == NULL || common->currententry->start == 0) stacksize = 0; else { stacksize = GET2(matchingpath, 1 + IMM2_SIZE); slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size; i = (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE); while (stacksize > 0) { if ((int)GET2(slot, 0) == i) break; slot += common->name_entry_size; stacksize--; } } if (stacksize != 0) matchingpath += 1 + 2 * IMM2_SIZE; } /* The stacksize == 0 is a common "else" case. */ if (stacksize == 0) { if (*cc == OP_ALT) { matchingpath = cc + 1 + LINK_SIZE; cc += GET(cc, 1); } else matchingpath = cc; } } else { SLJIT_ASSERT(has_alternatives && *matchingpath >= OP_ASSERT && *matchingpath <= OP_ASSERTBACK_NOT); /* Similar code as PUSH_BACKTRACK macro. */ assert = sljit_alloc_memory(compiler, sizeof(assert_backtrack)); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; memset(assert, 0, sizeof(assert_backtrack)); assert->common.cc = matchingpath; BACKTRACK_AS(bracket_backtrack)->u.assert = assert; matchingpath = compile_assert_matchingpath(common, matchingpath, assert, TRUE); } } compile_matchingpath(common, matchingpath, cc, backtrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; if (opcode == OP_ONCE) match_once_common(common, ket, BACKTRACK_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head); stacksize = 0; if (repeat_type == OP_MINUPTO) { /* We need to preserve the counter. TMP2 will be used below. */ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr); stacksize++; } if (ket != OP_KET || bra != OP_BRA) stacksize++; if (offset != 0) { if (common->capture_last_ptr != 0) stacksize++; if (common->optimized_cbracket[offset >> 1] == 0) stacksize += 2; } if (has_alternatives && opcode != OP_ONCE) stacksize++; if (stacksize > 0) allocate_stack(common, stacksize); stacksize = 0; if (repeat_type == OP_MINUPTO) { /* TMP2 was set above. */ OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1); stacksize++; } if (ket != OP_KET || bra != OP_BRA) { if (ket != OP_KET) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); else OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); stacksize++; } if (offset != 0) stacksize = match_capture_common(common, stacksize, offset, private_data_ptr); if (has_alternatives) { if (opcode != OP_ONCE) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); if (ket != OP_KETRMAX) BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); } /* Must be after the matchingpath label. */ if (offset != 0 && common->optimized_cbracket[offset >> 1] != 0) { SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); } if (ket == OP_KETRMAX) { if (repeat_type != 0) { if (has_alternatives) BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, rmax_label); /* Drop STR_PTR for greedy plus quantifier. */ if (opcode != OP_ONCE) free_stack(common, 1); } else if (opcode == OP_ONCE || opcode >= OP_SBRA) { if (has_alternatives) BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL(); /* Checking zero-length iteration. */ if (opcode != OP_ONCE) { CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0, rmax_label); /* Drop STR_PTR for greedy plus quantifier. */ if (bra != OP_BRAZERO) free_stack(common, 1); } else /* TMP2 must contain the starting STR_PTR. */ CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, rmax_label); } else JUMPTO(SLJIT_JUMP, rmax_label); BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL(); } if (repeat_type == OP_EXACT) { count_match(common); OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, rmax_label); } else if (repeat_type == OP_UPTO) { /* We need to preserve the counter. */ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr); allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); } if (bra == OP_BRAZERO) BACKTRACK_AS(bracket_backtrack)->zero_matchingpath = LABEL(); if (bra == OP_BRAMINZERO) { /* This is a backtrack path! (From the viewpoint of OP_BRAMINZERO) */ JUMPTO(SLJIT_JUMP, ((braminzero_backtrack *)parent)->matchingpath); if (braminzero != NULL) { JUMPHERE(braminzero); /* We need to release the end pointer to perform the backtrack for the zero-length iteration. When framesize is < 0, OP_ONCE will do the release itself. */ if (opcode == OP_ONCE && BACKTRACK_AS(bracket_backtrack)->u.framesize >= 0) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); } else if (ket == OP_KETRMIN && opcode != OP_ONCE) free_stack(common, 1); } /* Continue to the normal backtrack. */ } if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO) count_match(common); /* Skip the other alternatives. */ while (*cc == OP_ALT) cc += GET(cc, 1); cc += 1 + LINK_SIZE; if (opcode == OP_ONCE) { /* We temporarily encode the needs_control_head in the lowest bit. Note: on the target architectures of SLJIT the ((x << 1) >> 1) returns the same value for small signed numbers (including negative numbers). */ BACKTRACK_AS(bracket_backtrack)->u.framesize = ((unsigned int)BACKTRACK_AS(bracket_backtrack)->u.framesize << 1) | (needs_control_head ? 1 : 0); } return cc + repeat_length; } static pcre_uchar *compile_bracketpos_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; pcre_uchar opcode; int private_data_ptr; int cbraprivptr = 0; BOOL needs_control_head; int framesize; int stacksize; int offset = 0; BOOL zero = FALSE; pcre_uchar *ccbegin = NULL; int stack; /* Also contains the offset of control head. */ struct sljit_label *loop = NULL; struct jump_list *emptymatch = NULL; PUSH_BACKTRACK(sizeof(bracketpos_backtrack), cc, NULL); if (*cc == OP_BRAPOSZERO) { zero = TRUE; cc++; } opcode = *cc; private_data_ptr = PRIVATE_DATA(cc); SLJIT_ASSERT(private_data_ptr != 0); BACKTRACK_AS(bracketpos_backtrack)->private_data_ptr = private_data_ptr; switch(opcode) { case OP_BRAPOS: case OP_SBRAPOS: ccbegin = cc + 1 + LINK_SIZE; break; case OP_CBRAPOS: case OP_SCBRAPOS: offset = GET2(cc, 1 + LINK_SIZE); /* This case cannot be optimized in the same was as normal capturing brackets. */ SLJIT_ASSERT(common->optimized_cbracket[offset] == 0); cbraprivptr = OVECTOR_PRIV(offset); offset <<= 1; ccbegin = cc + 1 + LINK_SIZE + IMM2_SIZE; break; default: SLJIT_UNREACHABLE(); break; } framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head); BACKTRACK_AS(bracketpos_backtrack)->framesize = framesize; if (framesize < 0) { if (offset != 0) { stacksize = 2; if (common->capture_last_ptr != 0) stacksize++; } else stacksize = 1; if (needs_control_head) stacksize++; if (!zero) stacksize++; BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize; allocate_stack(common, stacksize); if (framesize == no_frame) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0); stack = 0; if (offset != 0) { stack = 2; OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); if (common->capture_last_ptr != 0) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0); if (needs_control_head) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); if (common->capture_last_ptr != 0) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0); stack = 3; } } else { if (needs_control_head) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); stack = 1; } if (needs_control_head) stack++; if (!zero) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), SLJIT_IMM, 1); if (needs_control_head) { stack--; OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0); } } else { stacksize = framesize + 1; if (!zero) stacksize++; if (needs_control_head) stacksize++; if (offset == 0) stacksize++; BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize; allocate_stack(common, stacksize); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); if (needs_control_head) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); stack = 0; if (!zero) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 1); stack = 1; } if (needs_control_head) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0); stack++; } if (offset == 0) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), STR_PTR, 0); stack++; } OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP1, 0); init_frame(common, cc, NULL, stacksize - 1, stacksize - framesize, FALSE); stack -= 1 + (offset == 0); } if (offset != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0); loop = LABEL(); while (*cc != OP_KETRPOS) { backtrack->top = NULL; backtrack->topbacktracks = NULL; cc += GET(cc, 1); compile_matchingpath(common, ccbegin, cc, backtrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; if (framesize < 0) { if (framesize == no_frame) OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); if (offset != 0) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0); if (common->capture_last_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); } else { if (opcode == OP_SBRAPOS) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); } /* Even if the match is empty, we need to reset the control head. */ if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack)); if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS) add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0)); if (!zero) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0); } else { if (offset != 0) { OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, stacksize * sizeof(sljit_sw)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0); if (common->capture_last_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); } else { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP2(SLJIT_SUB, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw)); if (opcode == OP_SBRAPOS) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2)); OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(-framesize - 2), STR_PTR, 0); } /* Even if the match is empty, we need to reset the control head. */ if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack)); if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS) add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0)); if (!zero) { if (framesize < 0) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0); else OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); } } JUMPTO(SLJIT_JUMP, loop); flush_stubs(common); compile_backtrackingpath(common, backtrack->top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return NULL; set_jumps(backtrack->topbacktracks, LABEL()); if (framesize < 0) { if (offset != 0) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr); else OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); } else { if (offset != 0) { /* Last alternative. */ if (*cc == OP_KETRPOS) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr); } else { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2)); } } if (*cc == OP_KETRPOS) break; ccbegin = cc + 1 + LINK_SIZE; } /* We don't have to restore the control head in case of a failed match. */ backtrack->topbacktracks = NULL; if (!zero) { if (framesize < 0) add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0)); else /* TMP2 is set to [private_data_ptr] above. */ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), STACK(-stacksize), SLJIT_IMM, 0)); } /* None of them matched. */ set_jumps(emptymatch, LABEL()); count_match(common); return cc + 1 + LINK_SIZE; } static SLJIT_INLINE pcre_uchar *get_iterator_parameters(compiler_common *common, pcre_uchar *cc, pcre_uchar *opcode, pcre_uchar *type, sljit_u32 *max, sljit_u32 *exact, pcre_uchar **end) { int class_len; *opcode = *cc; *exact = 0; if (*opcode >= OP_STAR && *opcode <= OP_POSUPTO) { cc++; *type = OP_CHAR; } else if (*opcode >= OP_STARI && *opcode <= OP_POSUPTOI) { cc++; *type = OP_CHARI; *opcode -= OP_STARI - OP_STAR; } else if (*opcode >= OP_NOTSTAR && *opcode <= OP_NOTPOSUPTO) { cc++; *type = OP_NOT; *opcode -= OP_NOTSTAR - OP_STAR; } else if (*opcode >= OP_NOTSTARI && *opcode <= OP_NOTPOSUPTOI) { cc++; *type = OP_NOTI; *opcode -= OP_NOTSTARI - OP_STAR; } else if (*opcode >= OP_TYPESTAR && *opcode <= OP_TYPEPOSUPTO) { cc++; *opcode -= OP_TYPESTAR - OP_STAR; *type = OP_END; } else { SLJIT_ASSERT(*opcode == OP_CLASS || *opcode == OP_NCLASS || *opcode == OP_XCLASS); *type = *opcode; cc++; class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(pcre_uchar))) : GET(cc, 0); *opcode = cc[class_len - 1]; if (*opcode >= OP_CRSTAR && *opcode <= OP_CRMINQUERY) { *opcode -= OP_CRSTAR - OP_STAR; *end = cc + class_len; if (*opcode == OP_PLUS || *opcode == OP_MINPLUS) { *exact = 1; *opcode -= OP_PLUS - OP_STAR; } } else if (*opcode >= OP_CRPOSSTAR && *opcode <= OP_CRPOSQUERY) { *opcode -= OP_CRPOSSTAR - OP_POSSTAR; *end = cc + class_len; if (*opcode == OP_POSPLUS) { *exact = 1; *opcode = OP_POSSTAR; } } else { SLJIT_ASSERT(*opcode == OP_CRRANGE || *opcode == OP_CRMINRANGE || *opcode == OP_CRPOSRANGE); *max = GET2(cc, (class_len + IMM2_SIZE)); *exact = GET2(cc, class_len); if (*max == 0) { if (*opcode == OP_CRPOSRANGE) *opcode = OP_POSSTAR; else *opcode -= OP_CRRANGE - OP_STAR; } else { *max -= *exact; if (*max == 0) *opcode = OP_EXACT; else if (*max == 1) { if (*opcode == OP_CRPOSRANGE) *opcode = OP_POSQUERY; else *opcode -= OP_CRRANGE - OP_QUERY; } else { if (*opcode == OP_CRPOSRANGE) *opcode = OP_POSUPTO; else *opcode -= OP_CRRANGE - OP_UPTO; } } *end = cc + class_len + 2 * IMM2_SIZE; } return cc; } switch(*opcode) { case OP_EXACT: *exact = GET2(cc, 0); cc += IMM2_SIZE; break; case OP_PLUS: case OP_MINPLUS: *exact = 1; *opcode -= OP_PLUS - OP_STAR; break; case OP_POSPLUS: *exact = 1; *opcode = OP_POSSTAR; break; case OP_UPTO: case OP_MINUPTO: case OP_POSUPTO: *max = GET2(cc, 0); cc += IMM2_SIZE; break; } if (*type == OP_END) { *type = *cc; *end = next_opcode(common, cc); cc++; return cc; } *end = cc + 1; #ifdef SUPPORT_UTF if (common->utf && HAS_EXTRALEN(*cc)) *end += GET_EXTRALEN(*cc); #endif return cc; } static pcre_uchar *compile_iterator_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; pcre_uchar opcode; pcre_uchar type; sljit_u32 max = 0, exact; BOOL fast_fail; sljit_s32 fast_str_ptr; BOOL charpos_enabled; pcre_uchar charpos_char; unsigned int charpos_othercasebit; pcre_uchar *end; jump_list *no_match = NULL; jump_list *no_char1_match = NULL; struct sljit_jump *jump = NULL; struct sljit_label *label; int private_data_ptr = PRIVATE_DATA(cc); int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP); int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr; int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw); int tmp_base, tmp_offset; PUSH_BACKTRACK(sizeof(char_iterator_backtrack), cc, NULL); fast_str_ptr = PRIVATE_DATA(cc + 1); fast_fail = TRUE; SLJIT_ASSERT(common->fast_forward_bc_ptr == NULL || fast_str_ptr == 0 || cc == common->fast_forward_bc_ptr); if (cc == common->fast_forward_bc_ptr) fast_fail = FALSE; else if (common->fast_fail_start_ptr == 0) fast_str_ptr = 0; SLJIT_ASSERT(common->fast_forward_bc_ptr != NULL || fast_str_ptr == 0 || (fast_str_ptr >= common->fast_fail_start_ptr && fast_str_ptr <= common->fast_fail_end_ptr)); cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end); if (type != OP_EXTUNI) { tmp_base = TMP3; tmp_offset = 0; } else { tmp_base = SLJIT_MEM1(SLJIT_SP); tmp_offset = POSSESSIVE0; } if (fast_fail && fast_str_ptr != 0) add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), fast_str_ptr)); /* Handle fixed part first. */ if (exact > 1) { SLJIT_ASSERT(fast_str_ptr == 0); if (common->mode == JIT_COMPILE #ifdef SUPPORT_UTF && !common->utf #endif && type != OP_ANYNL && type != OP_EXTUNI) { OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(exact)); add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER, TMP1, 0, STR_END, 0)); OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact); label = LABEL(); compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE); OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } else { OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact); label = LABEL(); compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE); OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } } else if (exact == 1) compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE); switch(opcode) { case OP_STAR: case OP_UPTO: SLJIT_ASSERT(fast_str_ptr == 0 || opcode == OP_STAR); if (type == OP_ANYNL || type == OP_EXTUNI) { SLJIT_ASSERT(private_data_ptr == 0); SLJIT_ASSERT(fast_str_ptr == 0); allocate_stack(common, 2); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0); if (opcode == OP_UPTO) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, max); label = LABEL(); compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE); if (opcode == OP_UPTO) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0); OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); jump = JUMP(SLJIT_ZERO); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0); } /* We cannot use TMP3 because of this allocate_stack. */ allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); JUMPTO(SLJIT_JUMP, label); if (jump != NULL) JUMPHERE(jump); } else { charpos_enabled = FALSE; charpos_char = 0; charpos_othercasebit = 0; if ((type != OP_CHAR && type != OP_CHARI) && (*end == OP_CHAR || *end == OP_CHARI)) { charpos_enabled = TRUE; #ifdef SUPPORT_UTF charpos_enabled = !common->utf || !HAS_EXTRALEN(end[1]); #endif if (charpos_enabled && *end == OP_CHARI && char_has_othercase(common, end + 1)) { charpos_othercasebit = char_get_othercase_bit(common, end + 1); if (charpos_othercasebit == 0) charpos_enabled = FALSE; } if (charpos_enabled) { charpos_char = end[1]; /* Consumpe the OP_CHAR opcode. */ end += 2; #if defined COMPILE_PCRE8 SLJIT_ASSERT((charpos_othercasebit >> 8) == 0); #elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32 SLJIT_ASSERT((charpos_othercasebit >> 9) == 0); if ((charpos_othercasebit & 0x100) != 0) charpos_othercasebit = (charpos_othercasebit & 0xff) << 8; #endif if (charpos_othercasebit != 0) charpos_char |= charpos_othercasebit; BACKTRACK_AS(char_iterator_backtrack)->u.charpos.enabled = TRUE; BACKTRACK_AS(char_iterator_backtrack)->u.charpos.chr = charpos_char; BACKTRACK_AS(char_iterator_backtrack)->u.charpos.othercasebit = charpos_othercasebit; } } if (charpos_enabled) { if (opcode == OP_UPTO) OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max + 1); /* Search the first instance of charpos_char. */ jump = JUMP(SLJIT_JUMP); label = LABEL(); if (opcode == OP_UPTO) { OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_ZERO)); } compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE); if (fast_str_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0); JUMPHERE(jump); detect_partial_match(common, &backtrack->topbacktracks); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); if (charpos_othercasebit != 0) OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit); CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label); if (private_data_ptr == 0) allocate_stack(common, 2); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); OP1(SLJIT_MOV, base, offset1, STR_PTR, 0); if (opcode == OP_UPTO) { OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); add_jump(compiler, &no_match, JUMP(SLJIT_ZERO)); } /* Search the last instance of charpos_char. */ label = LABEL(); compile_char1_matchingpath(common, type, cc, &no_match, FALSE); if (fast_str_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0); detect_partial_match(common, &no_match); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0)); if (charpos_othercasebit != 0) OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit); if (opcode == OP_STAR) { CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); } else { jump = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); JUMPHERE(jump); } if (opcode == OP_UPTO) { OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } else JUMPTO(SLJIT_JUMP, label); set_jumps(no_match, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); } #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 else if (common->utf) { if (private_data_ptr == 0) allocate_stack(common, 2); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); OP1(SLJIT_MOV, base, offset1, STR_PTR, 0); if (opcode == OP_UPTO) OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max); label = LABEL(); compile_char1_matchingpath(common, type, cc, &no_match, TRUE); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); if (opcode == OP_UPTO) { OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); } else JUMPTO(SLJIT_JUMP, label); set_jumps(no_match, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); if (fast_str_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0); } #endif else { if (private_data_ptr == 0) allocate_stack(common, 2); OP1(SLJIT_MOV, base, offset1, STR_PTR, 0); if (opcode == OP_UPTO) OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max); label = LABEL(); detect_partial_match(common, &no_match); compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE); if (opcode == OP_UPTO) { OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); } else JUMPTO(SLJIT_JUMP, label); set_jumps(no_char1_match, LABEL()); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); set_jumps(no_match, LABEL()); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); if (fast_str_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0); } } BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); break; case OP_MINSTAR: if (private_data_ptr == 0) allocate_stack(common, 1); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); if (fast_str_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0); break; case OP_MINUPTO: SLJIT_ASSERT(fast_str_ptr == 0); if (private_data_ptr == 0) allocate_stack(common, 2); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); OP1(SLJIT_MOV, base, offset1, SLJIT_IMM, max + 1); BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); break; case OP_QUERY: case OP_MINQUERY: SLJIT_ASSERT(fast_str_ptr == 0); if (private_data_ptr == 0) allocate_stack(common, 1); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); if (opcode == OP_QUERY) compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE); BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL(); break; case OP_EXACT: break; case OP_POSSTAR: #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf) { OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); label = LABEL(); compile_char1_matchingpath(common, type, cc, &no_match, TRUE); OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); JUMPTO(SLJIT_JUMP, label); set_jumps(no_match, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset); if (fast_str_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0); break; } #endif label = LABEL(); detect_partial_match(common, &no_match); compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE); JUMPTO(SLJIT_JUMP, label); set_jumps(no_char1_match, LABEL()); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); set_jumps(no_match, LABEL()); if (fast_str_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0); break; case OP_POSUPTO: SLJIT_ASSERT(fast_str_ptr == 0); #if defined SUPPORT_UTF && !defined COMPILE_PCRE32 if (common->utf) { OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0); OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max); label = LABEL(); compile_char1_matchingpath(common, type, cc, &no_match, TRUE); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0); OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); set_jumps(no_match, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1); break; } #endif OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max); label = LABEL(); detect_partial_match(common, &no_match); compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE); OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1); JUMPTO(SLJIT_NOT_ZERO, label); OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); set_jumps(no_char1_match, LABEL()); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); set_jumps(no_match, LABEL()); break; case OP_POSQUERY: SLJIT_ASSERT(fast_str_ptr == 0); OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); compile_char1_matchingpath(common, type, cc, &no_match, TRUE); OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0); set_jumps(no_match, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset); break; default: SLJIT_UNREACHABLE(); break; } count_match(common); return end; } static SLJIT_INLINE pcre_uchar *compile_fail_accept_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); if (*cc == OP_FAIL) { add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP)); return cc + 1; } if (*cc == OP_ASSERT_ACCEPT || common->currententry != NULL || !common->might_be_empty) { /* No need to check notempty conditions. */ if (common->accept_label == NULL) add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP)); else JUMPTO(SLJIT_JUMP, common->accept_label); return cc + 1; } if (common->accept_label == NULL) add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0))); else CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), common->accept_label); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty)); add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart)); if (common->accept_label == NULL) add_jump(compiler, &common->accept, CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0)); else CMPTO(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0, common->accept_label); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); if (common->accept_label == NULL) add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0)); else CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, common->accept_label); add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP)); return cc + 1; } static SLJIT_INLINE pcre_uchar *compile_close_matchingpath(compiler_common *common, pcre_uchar *cc) { DEFINE_COMPILER; int offset = GET2(cc, 1); BOOL optimized_cbracket = common->optimized_cbracket[offset] != 0; /* Data will be discarded anyway... */ if (common->currententry != NULL) return cc + 1 + IMM2_SIZE; if (!optimized_cbracket) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR_PRIV(offset)); offset <<= 1; OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); if (!optimized_cbracket) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); return cc + 1 + IMM2_SIZE; } static SLJIT_INLINE pcre_uchar *compile_control_verb_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; pcre_uchar opcode = *cc; pcre_uchar *ccend = cc + 1; if (opcode == OP_PRUNE_ARG || opcode == OP_SKIP_ARG || opcode == OP_THEN_ARG) ccend += 2 + cc[1]; PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL); if (opcode == OP_SKIP) { allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); return ccend; } if (opcode == OP_PRUNE_ARG || opcode == OP_THEN_ARG) { OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0); } return ccend; } static pcre_uchar then_trap_opcode[1] = { OP_THEN_TRAP }; static SLJIT_INLINE void compile_then_trap_matchingpath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; BOOL needs_control_head; int size; PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc); common->then_trap = BACKTRACK_AS(then_trap_backtrack); BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode; BACKTRACK_AS(then_trap_backtrack)->start = (sljit_sw)(cc - common->start); BACKTRACK_AS(then_trap_backtrack)->framesize = get_framesize(common, cc, ccend, FALSE, &needs_control_head); size = BACKTRACK_AS(then_trap_backtrack)->framesize; size = 3 + (size < 0 ? 0 : size); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); allocate_stack(common, size); if (size > 3) OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0, SLJIT_IMM, (size - 3) * sizeof(sljit_sw)); else OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 1), SLJIT_IMM, BACKTRACK_AS(then_trap_backtrack)->start); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 2), SLJIT_IMM, type_then_trap); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 3), TMP2, 0); size = BACKTRACK_AS(then_trap_backtrack)->framesize; if (size >= 0) init_frame(common, cc, ccend, size - 1, 0, FALSE); } static void compile_matchingpath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, backtrack_common *parent) { DEFINE_COMPILER; backtrack_common *backtrack; BOOL has_then_trap = FALSE; then_trap_backtrack *save_then_trap = NULL; SLJIT_ASSERT(*ccend == OP_END || (*ccend >= OP_ALT && *ccend <= OP_KETRPOS)); if (common->has_then && common->then_offsets[cc - common->start] != 0) { SLJIT_ASSERT(*ccend != OP_END && common->control_head_ptr != 0); has_then_trap = TRUE; save_then_trap = common->then_trap; /* Tail item on backtrack. */ compile_then_trap_matchingpath(common, cc, ccend, parent); } while (cc < ccend) { switch(*cc) { case OP_SOD: case OP_SOM: case OP_NOT_WORD_BOUNDARY: case OP_WORD_BOUNDARY: case OP_EODN: case OP_EOD: case OP_DOLL: case OP_DOLLM: case OP_CIRC: case OP_CIRCM: case OP_REVERSE: cc = compile_simple_assertion_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); break; case OP_NOT_DIGIT: case OP_DIGIT: case OP_NOT_WHITESPACE: case OP_WHITESPACE: case OP_NOT_WORDCHAR: case OP_WORDCHAR: case OP_ANY: case OP_ALLANY: case OP_ANYBYTE: case OP_NOTPROP: case OP_PROP: case OP_ANYNL: case OP_NOT_HSPACE: case OP_HSPACE: case OP_NOT_VSPACE: case OP_VSPACE: case OP_EXTUNI: case OP_NOT: case OP_NOTI: cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE); break; case OP_SET_SOM: PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0); cc++; break; case OP_CHAR: case OP_CHARI: if (common->mode == JIT_COMPILE) cc = compile_charn_matchingpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); else cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE); break; case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: case OP_UPTO: case OP_MINUPTO: case OP_EXACT: case OP_POSSTAR: case OP_POSPLUS: case OP_POSQUERY: case OP_POSUPTO: case OP_STARI: case OP_MINSTARI: case OP_PLUSI: case OP_MINPLUSI: case OP_QUERYI: case OP_MINQUERYI: case OP_UPTOI: case OP_MINUPTOI: case OP_EXACTI: case OP_POSSTARI: case OP_POSPLUSI: case OP_POSQUERYI: case OP_POSUPTOI: case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: case OP_NOTUPTO: case OP_NOTMINUPTO: case OP_NOTEXACT: case OP_NOTPOSSTAR: case OP_NOTPOSPLUS: case OP_NOTPOSQUERY: case OP_NOTPOSUPTO: case OP_NOTSTARI: case OP_NOTMINSTARI: case OP_NOTPLUSI: case OP_NOTMINPLUSI: case OP_NOTQUERYI: case OP_NOTMINQUERYI: case OP_NOTUPTOI: case OP_NOTMINUPTOI: case OP_NOTEXACTI: case OP_NOTPOSSTARI: case OP_NOTPOSPLUSI: case OP_NOTPOSQUERYI: case OP_NOTPOSUPTOI: case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEEXACT: case OP_TYPEPOSSTAR: case OP_TYPEPOSPLUS: case OP_TYPEPOSQUERY: case OP_TYPEPOSUPTO: cc = compile_iterator_matchingpath(common, cc, parent); break; case OP_CLASS: case OP_NCLASS: if (cc[1 + (32 / sizeof(pcre_uchar))] >= OP_CRSTAR && cc[1 + (32 / sizeof(pcre_uchar))] <= OP_CRPOSRANGE) cc = compile_iterator_matchingpath(common, cc, parent); else cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE); break; #if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32 case OP_XCLASS: if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= OP_CRPOSRANGE) cc = compile_iterator_matchingpath(common, cc, parent); else cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE); break; #endif case OP_REF: case OP_REFI: if (cc[1 + IMM2_SIZE] >= OP_CRSTAR && cc[1 + IMM2_SIZE] <= OP_CRPOSRANGE) cc = compile_ref_iterator_matchingpath(common, cc, parent); else { compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE); cc += 1 + IMM2_SIZE; } break; case OP_DNREF: case OP_DNREFI: if (cc[1 + 2 * IMM2_SIZE] >= OP_CRSTAR && cc[1 + 2 * IMM2_SIZE] <= OP_CRPOSRANGE) cc = compile_ref_iterator_matchingpath(common, cc, parent); else { compile_dnref_search(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks); compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE); cc += 1 + 2 * IMM2_SIZE; } break; case OP_RECURSE: cc = compile_recurse_matchingpath(common, cc, parent); break; case OP_CALLOUT: cc = compile_callout_matchingpath(common, cc, parent); break; case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc); cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE); break; case OP_BRAMINZERO: PUSH_BACKTRACK_NOVALUE(sizeof(braminzero_backtrack), cc); cc = bracketend(cc + 1); if (*(cc - 1 - LINK_SIZE) != OP_KETRMIN) { allocate_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); } else { allocate_stack(common, 2); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_PTR, 0); } BACKTRACK_AS(braminzero_backtrack)->matchingpath = LABEL(); count_match(common); break; case OP_ONCE: case OP_ONCE_NC: case OP_BRA: case OP_CBRA: case OP_COND: case OP_SBRA: case OP_SCBRA: case OP_SCOND: cc = compile_bracket_matchingpath(common, cc, parent); break; case OP_BRAZERO: if (cc[1] > OP_ASSERTBACK_NOT) cc = compile_bracket_matchingpath(common, cc, parent); else { PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc); cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE); } break; case OP_BRAPOS: case OP_CBRAPOS: case OP_SBRAPOS: case OP_SCBRAPOS: case OP_BRAPOSZERO: cc = compile_bracketpos_matchingpath(common, cc, parent); break; case OP_MARK: PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc); SLJIT_ASSERT(common->mark_ptr != 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr); allocate_stack(common, common->has_skip_arg ? 5 : 1); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0), TMP2, 0); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0); if (common->has_skip_arg) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, type_mark); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), SLJIT_IMM, (sljit_sw)(cc + 2)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(3), STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0); } cc += 1 + 2 + cc[1]; break; case OP_PRUNE: case OP_PRUNE_ARG: case OP_SKIP: case OP_SKIP_ARG: case OP_THEN: case OP_THEN_ARG: case OP_COMMIT: cc = compile_control_verb_matchingpath(common, cc, parent); break; case OP_FAIL: case OP_ACCEPT: case OP_ASSERT_ACCEPT: cc = compile_fail_accept_matchingpath(common, cc, parent); break; case OP_CLOSE: cc = compile_close_matchingpath(common, cc); break; case OP_SKIPZERO: cc = bracketend(cc + 1); break; default: SLJIT_UNREACHABLE(); return; } if (cc == NULL) return; } if (has_then_trap) { /* Head item on backtrack. */ PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc); BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode; BACKTRACK_AS(then_trap_backtrack)->then_trap = common->then_trap; common->then_trap = save_then_trap; } SLJIT_ASSERT(cc == ccend); } #undef PUSH_BACKTRACK #undef PUSH_BACKTRACK_NOVALUE #undef BACKTRACK_AS #define COMPILE_BACKTRACKINGPATH(current) \ do \ { \ compile_backtrackingpath(common, (current)); \ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \ return; \ } \ while (0) #define CURRENT_AS(type) ((type *)current) static void compile_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; pcre_uchar *cc = current->cc; pcre_uchar opcode; pcre_uchar type; sljit_u32 max = 0, exact; struct sljit_label *label = NULL; struct sljit_jump *jump = NULL; jump_list *jumplist = NULL; pcre_uchar *end; int private_data_ptr = PRIVATE_DATA(cc); int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP); int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr; int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw); cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end); switch(opcode) { case OP_STAR: case OP_UPTO: if (type == OP_ANYNL || type == OP_EXTUNI) { SLJIT_ASSERT(private_data_ptr == 0); set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath); } else { if (CURRENT_AS(char_iterator_backtrack)->u.charpos.enabled) { OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); OP1(SLJIT_MOV, TMP2, 0, base, offset1); OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1)); jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0); label = LABEL(); OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1)); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); if (CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit != 0) OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit); CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.chr, CURRENT_AS(char_iterator_backtrack)->matchingpath); skip_char_back(common); CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP2, 0, label); } else { OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, base, offset1); skip_char_back(common); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); } JUMPHERE(jump); if (private_data_ptr == 0) free_stack(common, 2); } break; case OP_MINSTAR: OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); compile_char1_matchingpath(common, type, cc, &jumplist, TRUE); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); set_jumps(jumplist, LABEL()); if (private_data_ptr == 0) free_stack(common, 1); break; case OP_MINUPTO: OP1(SLJIT_MOV, TMP1, 0, base, offset1); OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); add_jump(compiler, &jumplist, JUMP(SLJIT_ZERO)); OP1(SLJIT_MOV, base, offset1, TMP1, 0); compile_char1_matchingpath(common, type, cc, &jumplist, TRUE); OP1(SLJIT_MOV, base, offset0, STR_PTR, 0); JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); set_jumps(jumplist, LABEL()); if (private_data_ptr == 0) free_stack(common, 2); break; case OP_QUERY: OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0); CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath); jump = JUMP(SLJIT_JUMP); set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0); JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); JUMPHERE(jump); if (private_data_ptr == 0) free_stack(common, 1); break; case OP_MINQUERY: OP1(SLJIT_MOV, STR_PTR, 0, base, offset0); OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0); jump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); compile_char1_matchingpath(common, type, cc, &jumplist, TRUE); JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath); set_jumps(jumplist, LABEL()); JUMPHERE(jump); if (private_data_ptr == 0) free_stack(common, 1); break; case OP_EXACT: case OP_POSSTAR: case OP_POSQUERY: case OP_POSUPTO: break; default: SLJIT_UNREACHABLE(); break; } set_jumps(current->topbacktracks, LABEL()); } static SLJIT_INLINE void compile_ref_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; pcre_uchar *cc = current->cc; BOOL ref = (*cc == OP_REF || *cc == OP_REFI); pcre_uchar type; type = cc[ref ? 1 + IMM2_SIZE : 1 + 2 * IMM2_SIZE]; if ((type & 0x1) == 0) { /* Maximize case. */ set_jumps(current->topbacktracks, LABEL()); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath); return; } OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath); set_jumps(current->topbacktracks, LABEL()); free_stack(common, ref ? 2 : 3); } static SLJIT_INLINE void compile_recurse_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; if (CURRENT_AS(recurse_backtrack)->inlined_pattern) compile_backtrackingpath(common, current->top); set_jumps(current->topbacktracks, LABEL()); if (CURRENT_AS(recurse_backtrack)->inlined_pattern) return; if (common->has_set_som && common->mark_ptr != 0) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); free_stack(common, 2); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP1, 0); } else if (common->has_set_som || common->mark_ptr != 0) { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->has_set_som ? (int)(OVECTOR(0)) : common->mark_ptr, TMP2, 0); } } static void compile_assert_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; pcre_uchar *cc = current->cc; pcre_uchar bra = OP_BRA; struct sljit_jump *brajump = NULL; SLJIT_ASSERT(*cc != OP_BRAMINZERO); if (*cc == OP_BRAZERO) { bra = *cc; cc++; } if (bra == OP_BRAZERO) { SLJIT_ASSERT(current->topbacktracks == NULL); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); } if (CURRENT_AS(assert_backtrack)->framesize < 0) { set_jumps(current->topbacktracks, LABEL()); if (bra == OP_BRAZERO) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath); free_stack(common, 1); } return; } if (bra == OP_BRAZERO) { if (*cc == OP_ASSERT_NOT || *cc == OP_ASSERTBACK_NOT) { OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath); free_stack(common, 1); return; } free_stack(common, 1); brajump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0); } if (*cc == OP_ASSERT || *cc == OP_ASSERTBACK) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(assert_backtrack)->framesize - 1)); set_jumps(current->topbacktracks, LABEL()); } else set_jumps(current->topbacktracks, LABEL()); if (bra == OP_BRAZERO) { /* We know there is enough place on the stack. */ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw)); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0); JUMPTO(SLJIT_JUMP, CURRENT_AS(assert_backtrack)->matchingpath); JUMPHERE(brajump); } } static void compile_bracket_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; int opcode, stacksize, alt_count, alt_max; int offset = 0; int private_data_ptr = CURRENT_AS(bracket_backtrack)->private_data_ptr; int repeat_ptr = 0, repeat_type = 0, repeat_count = 0; pcre_uchar *cc = current->cc; pcre_uchar *ccbegin; pcre_uchar *ccprev; pcre_uchar bra = OP_BRA; pcre_uchar ket; assert_backtrack *assert; sljit_uw *next_update_addr = NULL; BOOL has_alternatives; BOOL needs_control_head = FALSE; struct sljit_jump *brazero = NULL; struct sljit_jump *alt1 = NULL; struct sljit_jump *alt2 = NULL; struct sljit_jump *once = NULL; struct sljit_jump *cond = NULL; struct sljit_label *rmin_label = NULL; struct sljit_label *exact_label = NULL; if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO) { bra = *cc; cc++; } opcode = *cc; ccbegin = bracketend(cc) - 1 - LINK_SIZE; ket = *ccbegin; if (ket == OP_KET && PRIVATE_DATA(ccbegin) != 0) { repeat_ptr = PRIVATE_DATA(ccbegin); repeat_type = PRIVATE_DATA(ccbegin + 2); repeat_count = PRIVATE_DATA(ccbegin + 3); SLJIT_ASSERT(repeat_type != 0 && repeat_count != 0); if (repeat_type == OP_UPTO) ket = OP_KETRMAX; if (repeat_type == OP_MINUPTO) ket = OP_KETRMIN; } ccbegin = cc; cc += GET(cc, 1); has_alternatives = *cc == OP_ALT; if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) has_alternatives = (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT) || CURRENT_AS(bracket_backtrack)->u.condfailed != NULL; if (opcode == OP_CBRA || opcode == OP_SCBRA) offset = (GET2(ccbegin, 1 + LINK_SIZE)) << 1; if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN)) opcode = OP_SCOND; if (SLJIT_UNLIKELY(opcode == OP_ONCE_NC)) opcode = OP_ONCE; alt_max = has_alternatives ? no_alternatives(ccbegin) : 0; /* Decoding the needs_control_head in framesize. */ if (opcode == OP_ONCE) { needs_control_head = (CURRENT_AS(bracket_backtrack)->u.framesize & 0x1) != 0; CURRENT_AS(bracket_backtrack)->u.framesize >>= 1; } if (ket != OP_KET && repeat_type != 0) { /* TMP1 is used in OP_KETRMIN below. */ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); if (repeat_type == OP_UPTO) OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0, SLJIT_IMM, 1); else OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0); } if (ket == OP_KETRMAX) { if (bra == OP_BRAZERO) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); brazero = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0); } } else if (ket == OP_KETRMIN) { if (bra != OP_BRAMINZERO) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); if (repeat_type != 0) { /* TMP1 was set a few lines above. */ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); /* Drop STR_PTR for non-greedy plus quantifier. */ if (opcode != OP_ONCE) free_stack(common, 1); } else if (opcode >= OP_SBRA || opcode == OP_ONCE) { /* Checking zero-length iteration. */ if (opcode != OP_ONCE || CURRENT_AS(bracket_backtrack)->u.framesize < 0) CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); else { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 2), CURRENT_AS(bracket_backtrack)->recursive_matchingpath); } /* Drop STR_PTR for non-greedy plus quantifier. */ if (opcode != OP_ONCE) free_stack(common, 1); } else JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); } rmin_label = LABEL(); if (repeat_type != 0) OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); } else if (bra == OP_BRAZERO) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); brazero = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0); } else if (repeat_type == OP_EXACT) { OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); exact_label = LABEL(); } if (offset != 0) { if (common->capture_last_ptr != 0) { SLJIT_ASSERT(common->optimized_cbracket[offset >> 1] == 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2)); free_stack(common, 3); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP2, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0); } else if (common->optimized_cbracket[offset >> 1] == 0) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); free_stack(common, 2); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0); } } if (SLJIT_UNLIKELY(opcode == OP_ONCE)) { if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); } once = JUMP(SLJIT_JUMP); } else if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) { if (has_alternatives) { /* Always exactly one alternative. */ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); alt_max = 2; alt1 = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, sizeof(sljit_uw)); } } else if (has_alternatives) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); if (alt_max > 4) { /* Table jump if alt_max is greater than 4. */ next_update_addr = allocate_read_only_data(common, alt_max * sizeof(sljit_uw)); if (SLJIT_UNLIKELY(next_update_addr == NULL)) return; sljit_emit_ijump(compiler, SLJIT_JUMP, SLJIT_MEM1(TMP1), (sljit_sw)next_update_addr); add_label_addr(common, next_update_addr++); } else { if (alt_max == 4) alt2 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_uw)); alt1 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, sizeof(sljit_uw)); } } COMPILE_BACKTRACKINGPATH(current->top); if (current->topbacktracks) set_jumps(current->topbacktracks, LABEL()); if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND)) { /* Conditional block always has at most one alternative. */ if (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT) { SLJIT_ASSERT(has_alternatives); assert = CURRENT_AS(bracket_backtrack)->u.assert; if (assert->framesize >= 0 && (ccbegin[1 + LINK_SIZE] == OP_ASSERT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK)) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-assert->framesize - 1)); } cond = JUMP(SLJIT_JUMP); set_jumps(CURRENT_AS(bracket_backtrack)->u.assert->condfailed, LABEL()); } else if (CURRENT_AS(bracket_backtrack)->u.condfailed != NULL) { SLJIT_ASSERT(has_alternatives); cond = JUMP(SLJIT_JUMP); set_jumps(CURRENT_AS(bracket_backtrack)->u.condfailed, LABEL()); } else SLJIT_ASSERT(!has_alternatives); } if (has_alternatives) { alt_count = sizeof(sljit_uw); do { current->top = NULL; current->topbacktracks = NULL; current->nextbacktracks = NULL; /* Conditional blocks always have an additional alternative, even if it is empty. */ if (*cc == OP_ALT) { ccprev = cc + 1 + LINK_SIZE; cc += GET(cc, 1); if (opcode != OP_COND && opcode != OP_SCOND) { if (opcode != OP_ONCE) { if (private_data_ptr != 0) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr); else OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); } else OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(needs_control_head ? 1 : 0)); } compile_matchingpath(common, ccprev, cc, current); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return; } /* Instructions after the current alternative is successfully matched. */ /* There is a similar code in compile_bracket_matchingpath. */ if (opcode == OP_ONCE) match_once_common(common, ket, CURRENT_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head); stacksize = 0; if (repeat_type == OP_MINUPTO) { /* We need to preserve the counter. TMP2 will be used below. */ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr); stacksize++; } if (ket != OP_KET || bra != OP_BRA) stacksize++; if (offset != 0) { if (common->capture_last_ptr != 0) stacksize++; if (common->optimized_cbracket[offset >> 1] == 0) stacksize += 2; } if (opcode != OP_ONCE) stacksize++; if (stacksize > 0) allocate_stack(common, stacksize); stacksize = 0; if (repeat_type == OP_MINUPTO) { /* TMP2 was set above. */ OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1); stacksize++; } if (ket != OP_KET || bra != OP_BRA) { if (ket != OP_KET) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0); else OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0); stacksize++; } if (offset != 0) stacksize = match_capture_common(common, stacksize, offset, private_data_ptr); if (opcode != OP_ONCE) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, alt_count); if (offset != 0 && ket == OP_KETRMAX && common->optimized_cbracket[offset >> 1] != 0) { /* If ket is not OP_KETRMAX, this code path is executed after the jump to alternative_matchingpath. */ SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0); } JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->alternative_matchingpath); if (opcode != OP_ONCE) { if (alt_max > 4) add_label_addr(common, next_update_addr++); else { if (alt_count != 2 * sizeof(sljit_uw)) { JUMPHERE(alt1); if (alt_max == 3 && alt_count == sizeof(sljit_uw)) alt2 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_uw)); } else { JUMPHERE(alt2); if (alt_max == 4) alt1 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_uw)); } } alt_count += sizeof(sljit_uw); } COMPILE_BACKTRACKINGPATH(current->top); if (current->topbacktracks) set_jumps(current->topbacktracks, LABEL()); SLJIT_ASSERT(!current->nextbacktracks); } while (*cc == OP_ALT); if (cond != NULL) { SLJIT_ASSERT(opcode == OP_COND || opcode == OP_SCOND); assert = CURRENT_AS(bracket_backtrack)->u.assert; if ((ccbegin[1 + LINK_SIZE] == OP_ASSERT_NOT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK_NOT) && assert->framesize >= 0) { OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-assert->framesize - 1)); } JUMPHERE(cond); } /* Free the STR_PTR. */ if (private_data_ptr == 0) free_stack(common, 1); } if (offset != 0) { /* Using both tmp register is better for instruction scheduling. */ if (common->optimized_cbracket[offset >> 1] != 0) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); free_stack(common, 2); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0); } else { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); } } else if (opcode == OP_SBRA || opcode == OP_SCOND) { OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); } else if (opcode == OP_ONCE) { cc = ccbegin + GET(ccbegin, 1); stacksize = needs_control_head ? 1 : 0; if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) { /* Reset head and drop saved frame. */ stacksize += CURRENT_AS(bracket_backtrack)->u.framesize + ((ket != OP_KET || *cc == OP_ALT) ? 2 : 1); } else if (ket == OP_KETRMAX || (*cc == OP_ALT && ket != OP_KETRMIN)) { /* The STR_PTR must be released. */ stacksize++; } if (stacksize > 0) free_stack(common, stacksize); JUMPHERE(once); /* Restore previous private_data_ptr */ if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 1)); else if (ket == OP_KETRMIN) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); /* See the comment below. */ free_stack(common, 2); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0); } } if (repeat_type == OP_EXACT) { OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0); CMPTO(SLJIT_LESS_EQUAL, TMP1, 0, SLJIT_IMM, repeat_count, exact_label); } else if (ket == OP_KETRMAX) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); if (bra != OP_BRAZERO) free_stack(common, 1); CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath); if (bra == OP_BRAZERO) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath); JUMPHERE(brazero); free_stack(common, 1); } } else if (ket == OP_KETRMIN) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); /* OP_ONCE removes everything in case of a backtrack, so we don't need to explicitly release the STR_PTR. The extra release would affect badly the free_stack(2) above. */ if (opcode != OP_ONCE) free_stack(common, 1); CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, rmin_label); if (opcode == OP_ONCE) free_stack(common, bra == OP_BRAMINZERO ? 2 : 1); else if (bra == OP_BRAMINZERO) free_stack(common, 1); } else if (bra == OP_BRAZERO) { OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath); JUMPHERE(brazero); } } static SLJIT_INLINE void compile_bracketpos_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; int offset; struct sljit_jump *jump; if (CURRENT_AS(bracketpos_backtrack)->framesize < 0) { if (*current->cc == OP_CBRAPOS || *current->cc == OP_SCBRAPOS) { offset = (GET2(current->cc, 1 + LINK_SIZE)) << 1; OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0); if (common->capture_last_ptr != 0) OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0); if (common->capture_last_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0); } set_jumps(current->topbacktracks, LABEL()); free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize); return; } OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); if (current->topbacktracks) { jump = JUMP(SLJIT_JUMP); set_jumps(current->topbacktracks, LABEL()); /* Drop the stack frame. */ free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize); JUMPHERE(jump); } OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracketpos_backtrack)->framesize - 1)); } static SLJIT_INLINE void compile_braminzero_backtrackingpath(compiler_common *common, struct backtrack_common *current) { assert_backtrack backtrack; current->top = NULL; current->topbacktracks = NULL; current->nextbacktracks = NULL; if (current->cc[1] > OP_ASSERTBACK_NOT) { /* Manual call of compile_bracket_matchingpath and compile_bracket_backtrackingpath. */ compile_bracket_matchingpath(common, current->cc, current); compile_bracket_backtrackingpath(common, current->top); } else { memset(&backtrack, 0, sizeof(backtrack)); backtrack.common.cc = current->cc; backtrack.matchingpath = CURRENT_AS(braminzero_backtrack)->matchingpath; /* Manual call of compile_assert_matchingpath. */ compile_assert_matchingpath(common, current->cc, &backtrack, FALSE); } SLJIT_ASSERT(!current->nextbacktracks && !current->topbacktracks); } static SLJIT_INLINE void compile_control_verb_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; pcre_uchar opcode = *current->cc; struct sljit_label *loop; struct sljit_jump *jump; if (opcode == OP_THEN || opcode == OP_THEN_ARG) { if (common->then_trap != NULL) { SLJIT_ASSERT(common->control_head_ptr != 0); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, type_then_trap); OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, common->then_trap->start); jump = JUMP(SLJIT_JUMP); loop = LABEL(); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); JUMPHERE(jump); CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0, loop); CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0, loop); add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP)); return; } else if (common->positive_assert) { add_jump(compiler, &common->positive_assert_quit, JUMP(SLJIT_JUMP)); return; } } if (common->local_exit) { if (common->quit_label == NULL) add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); else JUMPTO(SLJIT_JUMP, common->quit_label); return; } if (opcode == OP_SKIP_ARG) { SLJIT_ASSERT(common->control_head_ptr != 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, (sljit_sw)(current->cc + 2)); sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_search_mark)); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0); add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0)); return; } if (opcode == OP_SKIP) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); else OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_IMM, 0); add_jump(compiler, &common->reset_match, JUMP(SLJIT_JUMP)); } static SLJIT_INLINE void compile_then_trap_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; struct sljit_jump *jump; int size; if (CURRENT_AS(then_trap_backtrack)->then_trap) { common->then_trap = CURRENT_AS(then_trap_backtrack)->then_trap; return; } size = CURRENT_AS(then_trap_backtrack)->framesize; size = 3 + (size < 0 ? 0 : size); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(size - 3)); free_stack(common, size); jump = JUMP(SLJIT_JUMP); set_jumps(CURRENT_AS(then_trap_backtrack)->quit, LABEL()); /* STACK_TOP is set by THEN. */ if (CURRENT_AS(then_trap_backtrack)->framesize >= 0) add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 3); JUMPHERE(jump); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0); } static void compile_backtrackingpath(compiler_common *common, struct backtrack_common *current) { DEFINE_COMPILER; then_trap_backtrack *save_then_trap = common->then_trap; while (current) { if (current->nextbacktracks != NULL) set_jumps(current->nextbacktracks, LABEL()); switch(*current->cc) { case OP_SET_SOM: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), TMP1, 0); break; case OP_STAR: case OP_MINSTAR: case OP_PLUS: case OP_MINPLUS: case OP_QUERY: case OP_MINQUERY: case OP_UPTO: case OP_MINUPTO: case OP_EXACT: case OP_POSSTAR: case OP_POSPLUS: case OP_POSQUERY: case OP_POSUPTO: case OP_STARI: case OP_MINSTARI: case OP_PLUSI: case OP_MINPLUSI: case OP_QUERYI: case OP_MINQUERYI: case OP_UPTOI: case OP_MINUPTOI: case OP_EXACTI: case OP_POSSTARI: case OP_POSPLUSI: case OP_POSQUERYI: case OP_POSUPTOI: case OP_NOTSTAR: case OP_NOTMINSTAR: case OP_NOTPLUS: case OP_NOTMINPLUS: case OP_NOTQUERY: case OP_NOTMINQUERY: case OP_NOTUPTO: case OP_NOTMINUPTO: case OP_NOTEXACT: case OP_NOTPOSSTAR: case OP_NOTPOSPLUS: case OP_NOTPOSQUERY: case OP_NOTPOSUPTO: case OP_NOTSTARI: case OP_NOTMINSTARI: case OP_NOTPLUSI: case OP_NOTMINPLUSI: case OP_NOTQUERYI: case OP_NOTMINQUERYI: case OP_NOTUPTOI: case OP_NOTMINUPTOI: case OP_NOTEXACTI: case OP_NOTPOSSTARI: case OP_NOTPOSPLUSI: case OP_NOTPOSQUERYI: case OP_NOTPOSUPTOI: case OP_TYPESTAR: case OP_TYPEMINSTAR: case OP_TYPEPLUS: case OP_TYPEMINPLUS: case OP_TYPEQUERY: case OP_TYPEMINQUERY: case OP_TYPEUPTO: case OP_TYPEMINUPTO: case OP_TYPEEXACT: case OP_TYPEPOSSTAR: case OP_TYPEPOSPLUS: case OP_TYPEPOSQUERY: case OP_TYPEPOSUPTO: case OP_CLASS: case OP_NCLASS: #if defined SUPPORT_UTF || !defined COMPILE_PCRE8 case OP_XCLASS: #endif compile_iterator_backtrackingpath(common, current); break; case OP_REF: case OP_REFI: case OP_DNREF: case OP_DNREFI: compile_ref_iterator_backtrackingpath(common, current); break; case OP_RECURSE: compile_recurse_backtrackingpath(common, current); break; case OP_ASSERT: case OP_ASSERT_NOT: case OP_ASSERTBACK: case OP_ASSERTBACK_NOT: compile_assert_backtrackingpath(common, current); break; case OP_ONCE: case OP_ONCE_NC: case OP_BRA: case OP_CBRA: case OP_COND: case OP_SBRA: case OP_SCBRA: case OP_SCOND: compile_bracket_backtrackingpath(common, current); break; case OP_BRAZERO: if (current->cc[1] > OP_ASSERTBACK_NOT) compile_bracket_backtrackingpath(common, current); else compile_assert_backtrackingpath(common, current); break; case OP_BRAPOS: case OP_CBRAPOS: case OP_SBRAPOS: case OP_SCBRAPOS: case OP_BRAPOSZERO: compile_bracketpos_backtrackingpath(common, current); break; case OP_BRAMINZERO: compile_braminzero_backtrackingpath(common, current); break; case OP_MARK: OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0)); if (common->has_skip_arg) OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); free_stack(common, common->has_skip_arg ? 5 : 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP1, 0); if (common->has_skip_arg) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP2, 0); break; case OP_THEN: case OP_THEN_ARG: case OP_PRUNE: case OP_PRUNE_ARG: case OP_SKIP: case OP_SKIP_ARG: compile_control_verb_backtrackingpath(common, current); break; case OP_COMMIT: if (!common->local_exit) OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH); if (common->quit_label == NULL) add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); else JUMPTO(SLJIT_JUMP, common->quit_label); break; case OP_CALLOUT: case OP_FAIL: case OP_ACCEPT: case OP_ASSERT_ACCEPT: set_jumps(current->topbacktracks, LABEL()); break; case OP_THEN_TRAP: /* A virtual opcode for then traps. */ compile_then_trap_backtrackingpath(common, current); break; default: SLJIT_UNREACHABLE(); break; } current = current->prev; } common->then_trap = save_then_trap; } static SLJIT_INLINE void compile_recurse(compiler_common *common) { DEFINE_COMPILER; pcre_uchar *cc = common->start + common->currententry->start; pcre_uchar *ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : IMM2_SIZE); pcre_uchar *ccend = bracketend(cc) - (1 + LINK_SIZE); BOOL needs_control_head; int framesize = get_framesize(common, cc, NULL, TRUE, &needs_control_head); int private_data_size = get_private_data_copy_length(common, ccbegin, ccend, needs_control_head); int alternativesize; BOOL needs_frame; backtrack_common altbacktrack; struct sljit_jump *jump; /* Recurse captures then. */ common->then_trap = NULL; SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA || *cc == OP_CBRAPOS || *cc == OP_SCBRA || *cc == OP_SCBRAPOS); needs_frame = framesize >= 0; if (!needs_frame) framesize = 0; alternativesize = *(cc + GET(cc, 1)) == OP_ALT ? 1 : 0; SLJIT_ASSERT(common->currententry->entry == NULL && common->recursive_head_ptr != 0); common->currententry->entry = LABEL(); set_jumps(common->currententry->calls, common->currententry->entry); sljit_emit_fast_enter(compiler, TMP2, 0); count_match(common); allocate_stack(common, private_data_size + framesize + alternativesize); OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(private_data_size + framesize + alternativesize - 1), TMP2, 0); copy_private_data(common, ccbegin, ccend, TRUE, framesize + alternativesize, private_data_size + framesize + alternativesize, needs_control_head); if (needs_control_head) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, STACK_TOP, 0); if (needs_frame) init_frame(common, cc, NULL, framesize + alternativesize - 1, alternativesize, TRUE); if (alternativesize > 0) OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0); memset(&altbacktrack, 0, sizeof(backtrack_common)); common->quit_label = NULL; common->accept_label = NULL; common->quit = NULL; common->accept = NULL; altbacktrack.cc = ccbegin; cc += GET(cc, 1); while (1) { altbacktrack.top = NULL; altbacktrack.topbacktracks = NULL; if (altbacktrack.cc != ccbegin) OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0)); compile_matchingpath(common, altbacktrack.cc, cc, &altbacktrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return; add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP)); compile_backtrackingpath(common, altbacktrack.top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) return; set_jumps(altbacktrack.topbacktracks, LABEL()); if (*cc != OP_ALT) break; altbacktrack.cc = cc + 1 + LINK_SIZE; cc += GET(cc, 1); } /* None of them matched. */ OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0); jump = JUMP(SLJIT_JUMP); if (common->quit != NULL) { set_jumps(common->quit, LABEL()); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr); if (needs_frame) { OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); } OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0); common->quit = NULL; add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP)); } set_jumps(common->accept, LABEL()); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr); if (needs_frame) { OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL)); OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + alternativesize) * sizeof(sljit_sw)); } OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 1); JUMPHERE(jump); if (common->quit != NULL) set_jumps(common->quit, LABEL()); copy_private_data(common, ccbegin, ccend, FALSE, framesize + alternativesize, private_data_size + framesize + alternativesize, needs_control_head); free_stack(common, private_data_size + framesize + alternativesize); if (needs_control_head) { OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-3)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, TMP1, 0); OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP2, 0); } else { OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-2)); OP1(SLJIT_MOV, TMP1, 0, TMP3, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, TMP2, 0); } sljit_emit_fast_return(compiler, SLJIT_MEM1(STACK_TOP), STACK(-1)); } #undef COMPILE_BACKTRACKINGPATH #undef CURRENT_AS void PRIV(jit_compile)(const REAL_PCRE *re, PUBL(extra) *extra, int mode) { struct sljit_compiler *compiler; backtrack_common rootbacktrack; compiler_common common_data; compiler_common *common = &common_data; const sljit_u8 *tables = re->tables; pcre_study_data *study; int private_data_size; pcre_uchar *ccend; executable_functions *functions; void *executable_func; sljit_uw executable_size; sljit_uw total_length; label_addr_list *label_addr; struct sljit_label *mainloop_label = NULL; struct sljit_label *continue_match_label; struct sljit_label *empty_match_found_label = NULL; struct sljit_label *empty_match_backtrack_label = NULL; struct sljit_label *reset_match_label; struct sljit_label *quit_label; struct sljit_jump *jump; struct sljit_jump *minlength_check_failed = NULL; struct sljit_jump *reqbyte_notfound = NULL; struct sljit_jump *empty_match = NULL; SLJIT_ASSERT((extra->flags & PCRE_EXTRA_STUDY_DATA) != 0); study = extra->study_data; if (!tables) tables = PRIV(default_tables); memset(&rootbacktrack, 0, sizeof(backtrack_common)); memset(common, 0, sizeof(compiler_common)); rootbacktrack.cc = (pcre_uchar *)re + re->name_table_offset + re->name_count * re->name_entry_size; common->start = rootbacktrack.cc; common->read_only_data_head = NULL; common->fcc = tables + fcc_offset; common->lcc = (sljit_sw)(tables + lcc_offset); common->mode = mode; common->might_be_empty = study->minlength == 0; common->nltype = NLTYPE_FIXED; switch(re->options & PCRE_NEWLINE_BITS) { case 0: /* Compile-time default */ switch(NEWLINE) { case -1: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break; case -2: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break; default: common->newline = NEWLINE; break; } break; case PCRE_NEWLINE_CR: common->newline = CHAR_CR; break; case PCRE_NEWLINE_LF: common->newline = CHAR_NL; break; case PCRE_NEWLINE_CR+ PCRE_NEWLINE_LF: common->newline = (CHAR_CR << 8) | CHAR_NL; break; case PCRE_NEWLINE_ANY: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break; case PCRE_NEWLINE_ANYCRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break; default: return; } common->nlmax = READ_CHAR_MAX; common->nlmin = 0; if ((re->options & PCRE_BSR_ANYCRLF) != 0) common->bsr_nltype = NLTYPE_ANYCRLF; else if ((re->options & PCRE_BSR_UNICODE) != 0) common->bsr_nltype = NLTYPE_ANY; else { #ifdef BSR_ANYCRLF common->bsr_nltype = NLTYPE_ANYCRLF; #else common->bsr_nltype = NLTYPE_ANY; #endif } common->bsr_nlmax = READ_CHAR_MAX; common->bsr_nlmin = 0; common->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0; common->ctypes = (sljit_sw)(tables + ctypes_offset); common->name_table = ((pcre_uchar *)re) + re->name_table_offset; common->name_count = re->name_count; common->name_entry_size = re->name_entry_size; common->jscript_compat = (re->options & PCRE_JAVASCRIPT_COMPAT) != 0; #ifdef SUPPORT_UTF /* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */ common->utf = (re->options & PCRE_UTF8) != 0; #ifdef SUPPORT_UCP common->use_ucp = (re->options & PCRE_UCP) != 0; #endif if (common->utf) { if (common->nltype == NLTYPE_ANY) common->nlmax = 0x2029; else if (common->nltype == NLTYPE_ANYCRLF) common->nlmax = (CHAR_CR > CHAR_NL) ? CHAR_CR : CHAR_NL; else { /* We only care about the first newline character. */ common->nlmax = common->newline & 0xff; } if (common->nltype == NLTYPE_FIXED) common->nlmin = common->newline & 0xff; else common->nlmin = (CHAR_CR < CHAR_NL) ? CHAR_CR : CHAR_NL; if (common->bsr_nltype == NLTYPE_ANY) common->bsr_nlmax = 0x2029; else common->bsr_nlmax = (CHAR_CR > CHAR_NL) ? CHAR_CR : CHAR_NL; common->bsr_nlmin = (CHAR_CR < CHAR_NL) ? CHAR_CR : CHAR_NL; } #endif /* SUPPORT_UTF */ ccend = bracketend(common->start); /* Calculate the local space size on the stack. */ common->ovector_start = LIMIT_MATCH + sizeof(sljit_sw); common->optimized_cbracket = (sljit_u8 *)SLJIT_MALLOC(re->top_bracket + 1, compiler->allocator_data); if (!common->optimized_cbracket) return; #if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 1 memset(common->optimized_cbracket, 0, re->top_bracket + 1); #else memset(common->optimized_cbracket, 1, re->top_bracket + 1); #endif SLJIT_ASSERT(*common->start == OP_BRA && ccend[-(1 + LINK_SIZE)] == OP_KET); #if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 2 common->capture_last_ptr = common->ovector_start; common->ovector_start += sizeof(sljit_sw); #endif if (!check_opcode_types(common, common->start, ccend)) { SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data); return; } /* Checking flags and updating ovector_start. */ if (mode == JIT_COMPILE && (re->flags & PCRE_REQCHSET) != 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0) { common->req_char_ptr = common->ovector_start; common->ovector_start += sizeof(sljit_sw); } if (mode != JIT_COMPILE) { common->start_used_ptr = common->ovector_start; common->ovector_start += sizeof(sljit_sw); if (mode == JIT_PARTIAL_SOFT_COMPILE) { common->hit_start = common->ovector_start; common->ovector_start += 2 * sizeof(sljit_sw); } } if ((re->options & PCRE_FIRSTLINE) != 0) { common->match_end_ptr = common->ovector_start; common->ovector_start += sizeof(sljit_sw); } #if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD common->control_head_ptr = 1; #endif if (common->control_head_ptr != 0) { common->control_head_ptr = common->ovector_start; common->ovector_start += sizeof(sljit_sw); } if (common->has_set_som) { /* Saving the real start pointer is necessary. */ common->start_ptr = common->ovector_start; common->ovector_start += sizeof(sljit_sw); } /* Aligning ovector to even number of sljit words. */ if ((common->ovector_start & sizeof(sljit_sw)) != 0) common->ovector_start += sizeof(sljit_sw); if (common->start_ptr == 0) common->start_ptr = OVECTOR(0); /* Capturing brackets cannot be optimized if callouts are allowed. */ if (common->capture_last_ptr != 0) memset(common->optimized_cbracket, 0, re->top_bracket + 1); SLJIT_ASSERT(!(common->req_char_ptr != 0 && common->start_used_ptr != 0)); common->cbra_ptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_sw); total_length = ccend - common->start; common->private_data_ptrs = (sljit_s32 *)SLJIT_MALLOC(total_length * (sizeof(sljit_s32) + (common->has_then ? 1 : 0)), compiler->allocator_data); if (!common->private_data_ptrs) { SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data); return; } memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32)); private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw); set_private_data_ptrs(common, &private_data_size, ccend); if ((re->options & PCRE_ANCHORED) == 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0) { if (!detect_fast_forward_skip(common, &private_data_size) && !common->has_skip_in_assert_back) detect_fast_fail(common, common->start, &private_data_size, 4); } SLJIT_ASSERT(common->fast_fail_start_ptr <= common->fast_fail_end_ptr); if (private_data_size > SLJIT_MAX_LOCAL_SIZE) { SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data); SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data); return; } if (common->has_then) { common->then_offsets = (sljit_u8 *)(common->private_data_ptrs + total_length); memset(common->then_offsets, 0, total_length); set_then_offsets(common, common->start, NULL); } compiler = sljit_create_compiler(NULL); if (!compiler) { SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data); SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data); return; } common->compiler = compiler; /* Main pcre_jit_exec entry. */ sljit_emit_enter(compiler, 0, SLJIT_ARG1(SW), 5, 5, 0, 0, private_data_size); /* Register init. */ reset_ovector(common, (re->top_bracket + 1) * 2); if (common->req_char_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr, SLJIT_R0, 0); OP1(SLJIT_MOV, ARGUMENTS, 0, SLJIT_S0, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_S0, 0); OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, end)); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack)); OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match)); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, end)); OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, start)); OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0); if (common->fast_fail_start_ptr < common->fast_fail_end_ptr) reset_fast_fail(common); if (mode == JIT_PARTIAL_SOFT_COMPILE) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1); if (common->mark_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, SLJIT_IMM, 0); if (common->control_head_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0); /* Main part of the matching */ if ((re->options & PCRE_ANCHORED) == 0) { mainloop_label = mainloop_entry(common, (re->flags & PCRE_HASCRORLF) != 0); continue_match_label = LABEL(); /* Forward search if possible. */ if ((re->options & PCRE_NO_START_OPTIMIZE) == 0) { if (mode == JIT_COMPILE && fast_forward_first_n_chars(common)) ; else if ((re->flags & PCRE_FIRSTSET) != 0) fast_forward_first_char(common, (pcre_uchar)re->first_char, (re->flags & PCRE_FCH_CASELESS) != 0); else if ((re->flags & PCRE_STARTLINE) != 0) fast_forward_newline(common); else if (study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0) fast_forward_start_bits(common, study->start_bits); } } else continue_match_label = LABEL(); if (mode == JIT_COMPILE && study->minlength > 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0) { OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH); OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(study->minlength)); minlength_check_failed = CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0); } if (common->req_char_ptr != 0) reqbyte_notfound = search_requested_char(common, (pcre_uchar)re->req_char, (re->flags & PCRE_RCH_CASELESS) != 0, (re->flags & PCRE_FIRSTSET) != 0); /* Store the current STR_PTR in OVECTOR(0). */ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), STR_PTR, 0); /* Copy the limit of allowed recursions. */ OP1(SLJIT_MOV, COUNT_MATCH, 0, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH); if (common->capture_last_ptr != 0) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, -1); if (common->fast_forward_bc_ptr != NULL) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), PRIVATE_DATA(common->fast_forward_bc_ptr + 1), STR_PTR, 0); if (common->start_ptr != OVECTOR(0)) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_ptr, STR_PTR, 0); /* Copy the beginning of the string. */ if (mode == JIT_PARTIAL_SOFT_COMPILE) { jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start + sizeof(sljit_sw), STR_PTR, 0); JUMPHERE(jump); } else if (mode == JIT_PARTIAL_HARD_COMPILE) OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0); compile_matchingpath(common, common->start, ccend, &rootbacktrack); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { sljit_free_compiler(compiler); SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data); SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data); free_read_only_data(common->read_only_data_head, compiler->allocator_data); return; } if (common->might_be_empty) { empty_match = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)); empty_match_found_label = LABEL(); } common->accept_label = LABEL(); if (common->accept != NULL) set_jumps(common->accept, common->accept_label); /* This means we have a match. Update the ovector. */ copy_ovector(common, re->top_bracket + 1); common->quit_label = common->forced_quit_label = LABEL(); if (common->quit != NULL) set_jumps(common->quit, common->quit_label); if (common->forced_quit != NULL) set_jumps(common->forced_quit, common->forced_quit_label); if (minlength_check_failed != NULL) SET_LABEL(minlength_check_failed, common->forced_quit_label); sljit_emit_return(compiler, SLJIT_MOV, SLJIT_RETURN_REG, 0); if (mode != JIT_COMPILE) { common->partialmatchlabel = LABEL(); set_jumps(common->partialmatch, common->partialmatchlabel); return_with_partial_match(common, common->quit_label); } if (common->might_be_empty) empty_match_backtrack_label = LABEL(); compile_backtrackingpath(common, rootbacktrack.top); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { sljit_free_compiler(compiler); SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data); SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data); free_read_only_data(common->read_only_data_head, compiler->allocator_data); return; } SLJIT_ASSERT(rootbacktrack.prev == NULL); reset_match_label = LABEL(); if (mode == JIT_PARTIAL_SOFT_COMPILE) { /* Update hit_start only in the first time. */ jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, TMP1, 0); JUMPHERE(jump); } /* Check we have remaining characters. */ if ((re->options & PCRE_ANCHORED) == 0 && (re->options & PCRE_FIRSTLINE) != 0) { SLJIT_ASSERT(common->match_end_ptr != 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr); } OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), (common->fast_forward_bc_ptr != NULL) ? (PRIVATE_DATA(common->fast_forward_bc_ptr + 1)) : common->start_ptr); if ((re->options & PCRE_ANCHORED) == 0) { if (common->ff_newline_shortcut != NULL) { if ((re->options & PCRE_FIRSTLINE) == 0) CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, common->ff_newline_shortcut); /* There cannot be more newlines here. */ } else CMPTO(SLJIT_LESS, STR_PTR, 0, ((re->options & PCRE_FIRSTLINE) == 0) ? STR_END : TMP1, 0, mainloop_label); } /* No more remaining characters. */ if (reqbyte_notfound != NULL) JUMPHERE(reqbyte_notfound); if (mode == JIT_PARTIAL_SOFT_COMPILE) CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1, common->partialmatchlabel); OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH); JUMPTO(SLJIT_JUMP, common->quit_label); flush_stubs(common); if (common->might_be_empty) { JUMPHERE(empty_match); OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty)); CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_backtrack_label); OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart)); CMPTO(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_found_label); OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str)); CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found_label); JUMPTO(SLJIT_JUMP, empty_match_backtrack_label); } common->fast_forward_bc_ptr = NULL; common->fast_fail_start_ptr = 0; common->fast_fail_end_ptr = 0; common->currententry = common->entries; common->local_exit = TRUE; quit_label = common->quit_label; while (common->currententry != NULL) { /* Might add new entries. */ compile_recurse(common); if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) { sljit_free_compiler(compiler); SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data); SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data); free_read_only_data(common->read_only_data_head, compiler->allocator_data); return; } flush_stubs(common); common->currententry = common->currententry->next; } common->local_exit = FALSE; common->quit_label = quit_label; /* Allocating stack, returns with PCRE_ERROR_JIT_STACKLIMIT if fails. */ /* This is a (really) rare case. */ set_jumps(common->stackalloc, LABEL()); /* RETURN_ADDR is not a saved register. */ sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0); SLJIT_ASSERT(TMP1 == SLJIT_R0 && STACK_TOP == SLJIT_R1); OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STACK_TOP, 0); OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0); OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_LIMIT, 0, SLJIT_IMM, STACK_GROWTH_RATE); OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, stack)); OP1(SLJIT_MOV, STACK_LIMIT, 0, TMP2, 0); sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize)); jump = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0); OP1(SLJIT_MOV, TMP2, 0, STACK_LIMIT, 0); OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_RETURN_REG, 0); OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0); OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1); sljit_emit_fast_return(compiler, TMP1, 0); /* Allocation failed. */ JUMPHERE(jump); /* We break the return address cache here, but this is a really rare case. */ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_JIT_STACKLIMIT); JUMPTO(SLJIT_JUMP, common->quit_label); /* Call limit reached. */ set_jumps(common->calllimit, LABEL()); OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_MATCHLIMIT); JUMPTO(SLJIT_JUMP, common->quit_label); if (common->revertframes != NULL) { set_jumps(common->revertframes, LABEL()); do_revertframes(common); } if (common->wordboundary != NULL) { set_jumps(common->wordboundary, LABEL()); check_wordboundary(common); } if (common->anynewline != NULL) { set_jumps(common->anynewline, LABEL()); check_anynewline(common); } if (common->hspace != NULL) { set_jumps(common->hspace, LABEL()); check_hspace(common); } if (common->vspace != NULL) { set_jumps(common->vspace, LABEL()); check_vspace(common); } if (common->casefulcmp != NULL) { set_jumps(common->casefulcmp, LABEL()); do_casefulcmp(common); } if (common->caselesscmp != NULL) { set_jumps(common->caselesscmp, LABEL()); do_caselesscmp(common); } if (common->reset_match != NULL) { set_jumps(common->reset_match, LABEL()); do_reset_match(common, (re->top_bracket + 1) * 2); CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP1, 0, continue_match_label); OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0); JUMPTO(SLJIT_JUMP, reset_match_label); } #ifdef SUPPORT_UTF #ifdef COMPILE_PCRE8 if (common->utfreadchar != NULL) { set_jumps(common->utfreadchar, LABEL()); do_utfreadchar(common); } if (common->utfreadchar16 != NULL) { set_jumps(common->utfreadchar16, LABEL()); do_utfreadchar16(common); } if (common->utfreadtype8 != NULL) { set_jumps(common->utfreadtype8, LABEL()); do_utfreadtype8(common); } #endif /* COMPILE_PCRE8 */ #endif /* SUPPORT_UTF */ #ifdef SUPPORT_UCP if (common->getucd != NULL) { set_jumps(common->getucd, LABEL()); do_getucd(common); } #endif SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data); SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data); executable_func = sljit_generate_code(compiler); executable_size = sljit_get_generated_code_size(compiler); label_addr = common->label_addrs; while (label_addr != NULL) { *label_addr->update_addr = sljit_get_label_addr(label_addr->label); label_addr = label_addr->next; } sljit_free_compiler(compiler); if (executable_func == NULL) { free_read_only_data(common->read_only_data_head, compiler->allocator_data); return; } /* Reuse the function descriptor if possible. */ if ((extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 && extra->executable_jit != NULL) functions = (executable_functions *)extra->executable_jit; else { /* Note: If your memory-checker has flagged the allocation below as a * memory leak, it is probably because you either forgot to call * pcre_free_study() (or pcre16_free_study()) on the pcre_extra (or * pcre16_extra) object, or you called said function after having * cleared the PCRE_EXTRA_EXECUTABLE_JIT bit from the "flags" field * of the object. (The function will only free the JIT data if the * bit remains set, as the bit indicates that the pointer to the data * is valid.) */ functions = SLJIT_MALLOC(sizeof(executable_functions), compiler->allocator_data); if (functions == NULL) { /* This case is highly unlikely since we just recently freed a lot of memory. Not impossible though. */ sljit_free_code(executable_func); free_read_only_data(common->read_only_data_head, compiler->allocator_data); return; } memset(functions, 0, sizeof(executable_functions)); functions->top_bracket = (re->top_bracket + 1) * 2; functions->limit_match = (re->flags & PCRE_MLSET) != 0 ? re->limit_match : 0; extra->executable_jit = functions; extra->flags |= PCRE_EXTRA_EXECUTABLE_JIT; } functions->executable_funcs[mode] = executable_func; functions->read_only_data_heads[mode] = common->read_only_data_head; functions->executable_sizes[mode] = executable_size; } static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, void *executable_func) { union { void *executable_func; jit_function call_executable_func; } convert_executable_func; sljit_u8 local_space[MACHINE_STACK_SIZE]; struct sljit_stack local_stack; local_stack.min_start = local_space; local_stack.start = local_space; local_stack.end = local_space + MACHINE_STACK_SIZE; local_stack.top = local_space + MACHINE_STACK_SIZE; arguments->stack = &local_stack; convert_executable_func.executable_func = executable_func; return convert_executable_func.call_executable_func(arguments); } int PRIV(jit_exec)(const PUBL(extra) *extra_data, const pcre_uchar *subject, int length, int start_offset, int options, int *offsets, int offset_count) { executable_functions *functions = (executable_functions *)extra_data->executable_jit; union { void *executable_func; jit_function call_executable_func; } convert_executable_func; jit_arguments arguments; int max_offset_count; int retval; int mode = JIT_COMPILE; if ((options & PCRE_PARTIAL_HARD) != 0) mode = JIT_PARTIAL_HARD_COMPILE; else if ((options & PCRE_PARTIAL_SOFT) != 0) mode = JIT_PARTIAL_SOFT_COMPILE; if (functions->executable_funcs[mode] == NULL) return PCRE_ERROR_JIT_BADOPTION; /* Sanity checks should be handled by pcre_exec. */ arguments.str = subject + start_offset; arguments.begin = subject; arguments.end = subject + length; arguments.mark_ptr = NULL; /* JIT decreases this value less frequently than the interpreter. */ arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (sljit_u32)(extra_data->match_limit); if (functions->limit_match != 0 && functions->limit_match < arguments.limit_match) arguments.limit_match = functions->limit_match; arguments.notbol = (options & PCRE_NOTBOL) != 0; arguments.noteol = (options & PCRE_NOTEOL) != 0; arguments.notempty = (options & PCRE_NOTEMPTY) != 0; arguments.notempty_atstart = (options & PCRE_NOTEMPTY_ATSTART) != 0; arguments.offsets = offsets; arguments.callout_data = (extra_data->flags & PCRE_EXTRA_CALLOUT_DATA) != 0 ? extra_data->callout_data : NULL; arguments.real_offset_count = offset_count; /* pcre_exec() rounds offset_count to a multiple of 3, and then uses only 2/3 of the output vector for storing captured strings, with the remainder used as workspace. We don't need the workspace here. For compatibility, we limit the number of captured strings in the same way as pcre_exec(), so that the user gets the same result with and without JIT. */ if (offset_count != 2) offset_count = ((offset_count - (offset_count % 3)) * 2) / 3; max_offset_count = functions->top_bracket; if (offset_count > max_offset_count) offset_count = max_offset_count; arguments.offset_count = offset_count; if (functions->callback) arguments.stack = (struct sljit_stack *)functions->callback(functions->userdata); else arguments.stack = (struct sljit_stack *)functions->userdata; if (arguments.stack == NULL) retval = jit_machine_stack_exec(&arguments, functions->executable_funcs[mode]); else { convert_executable_func.executable_func = functions->executable_funcs[mode]; retval = convert_executable_func.call_executable_func(&arguments); } if (retval * 2 > offset_count) retval = 0; if ((extra_data->flags & PCRE_EXTRA_MARK) != 0) *(extra_data->mark) = arguments.mark_ptr; return retval; } #if defined COMPILE_PCRE8 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre_jit_exec(const pcre *argument_re, const pcre_extra *extra_data, PCRE_SPTR subject, int length, int start_offset, int options, int *offsets, int offset_count, pcre_jit_stack *stack) #elif defined COMPILE_PCRE16 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre16_jit_exec(const pcre16 *argument_re, const pcre16_extra *extra_data, PCRE_SPTR16 subject, int length, int start_offset, int options, int *offsets, int offset_count, pcre16_jit_stack *stack) #elif defined COMPILE_PCRE32 PCRE_EXP_DEFN int PCRE_CALL_CONVENTION pcre32_jit_exec(const pcre32 *argument_re, const pcre32_extra *extra_data, PCRE_SPTR32 subject, int length, int start_offset, int options, int *offsets, int offset_count, pcre32_jit_stack *stack) #endif { pcre_uchar *subject_ptr = (pcre_uchar *)subject; executable_functions *functions = (executable_functions *)extra_data->executable_jit; union { void *executable_func; jit_function call_executable_func; } convert_executable_func; jit_arguments arguments; int max_offset_count; int retval; int mode = JIT_COMPILE; SLJIT_UNUSED_ARG(argument_re); /* Plausibility checks */ if ((options & ~PUBLIC_JIT_EXEC_OPTIONS) != 0) return PCRE_ERROR_JIT_BADOPTION; if ((options & PCRE_PARTIAL_HARD) != 0) mode = JIT_PARTIAL_HARD_COMPILE; else if ((options & PCRE_PARTIAL_SOFT) != 0) mode = JIT_PARTIAL_SOFT_COMPILE; if (functions == NULL || functions->executable_funcs[mode] == NULL) return PCRE_ERROR_JIT_BADOPTION; /* Sanity checks should be handled by pcre_exec. */ arguments.stack = (struct sljit_stack *)stack; arguments.str = subject_ptr + start_offset; arguments.begin = subject_ptr; arguments.end = subject_ptr + length; arguments.mark_ptr = NULL; /* JIT decreases this value less frequently than the interpreter. */ arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (sljit_u32)(extra_data->match_limit); if (functions->limit_match != 0 && functions->limit_match < arguments.limit_match) arguments.limit_match = functions->limit_match; arguments.notbol = (options & PCRE_NOTBOL) != 0; arguments.noteol = (options & PCRE_NOTEOL) != 0; arguments.notempty = (options & PCRE_NOTEMPTY) != 0; arguments.notempty_atstart = (options & PCRE_NOTEMPTY_ATSTART) != 0; arguments.offsets = offsets; arguments.callout_data = (extra_data->flags & PCRE_EXTRA_CALLOUT_DATA) != 0 ? extra_data->callout_data : NULL; arguments.real_offset_count = offset_count; /* pcre_exec() rounds offset_count to a multiple of 3, and then uses only 2/3 of the output vector for storing captured strings, with the remainder used as workspace. We don't need the workspace here. For compatibility, we limit the number of captured strings in the same way as pcre_exec(), so that the user gets the same result with and without JIT. */ if (offset_count != 2) offset_count = ((offset_count - (offset_count % 3)) * 2) / 3; max_offset_count = functions->top_bracket; if (offset_count > max_offset_count) offset_count = max_offset_count; arguments.offset_count = offset_count; convert_executable_func.executable_func = functions->executable_funcs[mode]; retval = convert_executable_func.call_executable_func(&arguments); if (retval * 2 > offset_count) retval = 0; if ((extra_data->flags & PCRE_EXTRA_MARK) != 0) *(extra_data->mark) = arguments.mark_ptr; return retval; } void PRIV(jit_free)(void *executable_funcs) { int i; executable_functions *functions = (executable_functions *)executable_funcs; for (i = 0; i < JIT_NUMBER_OF_COMPILE_MODES; i++) { if (functions->executable_funcs[i] != NULL) sljit_free_code(functions->executable_funcs[i]); free_read_only_data(functions->read_only_data_heads[i], NULL); } SLJIT_FREE(functions, compiler->allocator_data); } int PRIV(jit_get_size)(void *executable_funcs) { int i; sljit_uw size = 0; sljit_uw *executable_sizes = ((executable_functions *)executable_funcs)->executable_sizes; for (i = 0; i < JIT_NUMBER_OF_COMPILE_MODES; i++) size += executable_sizes[i]; return (int)size; } const char* PRIV(jit_get_target)(void) { return sljit_get_platform_name(); } #if defined COMPILE_PCRE8 PCRE_EXP_DECL pcre_jit_stack * pcre_jit_stack_alloc(int startsize, int maxsize) #elif defined COMPILE_PCRE16 PCRE_EXP_DECL pcre16_jit_stack * pcre16_jit_stack_alloc(int startsize, int maxsize) #elif defined COMPILE_PCRE32 PCRE_EXP_DECL pcre32_jit_stack * pcre32_jit_stack_alloc(int startsize, int maxsize) #endif { if (startsize < 1 || maxsize < 1) return NULL; if (startsize > maxsize) startsize = maxsize; startsize = (startsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1); maxsize = (maxsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1); return (PUBL(jit_stack)*)sljit_allocate_stack(startsize, maxsize, NULL); } #if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *stack) #elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *stack) #elif defined COMPILE_PCRE32 PCRE_EXP_DECL void pcre32_jit_stack_free(pcre32_jit_stack *stack) #endif { sljit_free_stack((struct sljit_stack *)stack, NULL); } #if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *extra, pcre_jit_callback callback, void *userdata) #elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *extra, pcre16_jit_callback callback, void *userdata) #elif defined COMPILE_PCRE32 PCRE_EXP_DECL void pcre32_assign_jit_stack(pcre32_extra *extra, pcre32_jit_callback callback, void *userdata) #endif { executable_functions *functions; if (extra != NULL && (extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 && extra->executable_jit != NULL) { functions = (executable_functions *)extra->executable_jit; functions->callback = callback; functions->userdata = userdata; } } #if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_jit_free_unused_memory(void) #elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_jit_free_unused_memory(void) #elif defined COMPILE_PCRE32 PCRE_EXP_DECL void pcre32_jit_free_unused_memory(void) #endif { sljit_free_unused_memory_exec(); } #else /* SUPPORT_JIT */ /* These are dummy functions to avoid linking errors when JIT support is not being compiled. */ #if defined COMPILE_PCRE8 PCRE_EXP_DECL pcre_jit_stack * pcre_jit_stack_alloc(int startsize, int maxsize) #elif defined COMPILE_PCRE16 PCRE_EXP_DECL pcre16_jit_stack * pcre16_jit_stack_alloc(int startsize, int maxsize) #elif defined COMPILE_PCRE32 PCRE_EXP_DECL pcre32_jit_stack * pcre32_jit_stack_alloc(int startsize, int maxsize) #endif { (void)startsize; (void)maxsize; return NULL; } #if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *stack) #elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *stack) #elif defined COMPILE_PCRE32 PCRE_EXP_DECL void pcre32_jit_stack_free(pcre32_jit_stack *stack) #endif { (void)stack; } #if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *extra, pcre_jit_callback callback, void *userdata) #elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *extra, pcre16_jit_callback callback, void *userdata) #elif defined COMPILE_PCRE32 PCRE_EXP_DECL void pcre32_assign_jit_stack(pcre32_extra *extra, pcre32_jit_callback callback, void *userdata) #endif { (void)extra; (void)callback; (void)userdata; } #if defined COMPILE_PCRE8 PCRE_EXP_DECL void pcre_jit_free_unused_memory(void) #elif defined COMPILE_PCRE16 PCRE_EXP_DECL void pcre16_jit_free_unused_memory(void) #elif defined COMPILE_PCRE32 PCRE_EXP_DECL void pcre32_jit_free_unused_memory(void) #endif { } #endif /* End of pcre_jit_compile.c */ tomcat-connectors-1.2.50-src/native/iis/pcre/pcre_ucd.c0000644000000000000020000062726614655113617021302 0ustar rootbin/* This module is generated by the maint/MultiStage2.py script. Do not modify it by hand. Instead modify the script and run it to regenerate this code. As well as being part of the PCRE library, this module is #included by the pcretest program, which redefines the PRIV macro to change table names from _pcre_xxx to xxxx, thereby avoiding name clashes with the library. At present, just one of these tables is actually needed. */ #ifndef PCRE_INCLUDED #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pcre_internal.h" #endif /* PCRE_INCLUDED */ /* Unicode character database. */ /* This file was autogenerated by the MultiStage2.py script. */ /* Total size: 72576 bytes, block size: 128. */ /* The tables herein are needed only when UCP support is built into PCRE. This module should not be referenced otherwise, so it should not matter whether it is compiled or not. However a comment was received about space saving - maybe the guy linked all the modules rather than using a library - so we include a condition to cut out the tables when not needed. But don't leave a totally empty module because some compilers barf at that. Instead, just supply small dummy tables. */ #ifndef SUPPORT_UCP const ucd_record PRIV(ucd_records)[] = {{0,0,0,0,0 }}; const pcre_uint8 PRIV(ucd_stage1)[] = {0}; const pcre_uint16 PRIV(ucd_stage2)[] = {0}; const pcre_uint32 PRIV(ucd_caseless_sets)[] = {0}; #else /* If the 32-bit library is run in non-32-bit mode, character values greater than 0x10ffff may be encountered. For these we set up a special record. */ #ifdef COMPILE_PCRE32 const ucd_record PRIV(dummy_ucd_record)[] = {{ ucp_Common, /* script */ ucp_Cn, /* type unassigned */ ucp_gbOther, /* grapheme break property */ 0, /* case set */ 0, /* other case */ }}; #endif /* When recompiling tables with a new Unicode version, please check the types in this structure definition from pcre_internal.h (the actual field names will be different): typedef struct { pcre_uint8 property_0; pcre_uint8 property_1; pcre_uint8 property_2; pcre_uint8 property_3; pcre_int32 property_4; } ucd_record; */ const pcre_uint32 PRIV(ucd_caseless_sets)[] = { NOTACHAR, 0x0053, 0x0073, 0x017f, NOTACHAR, 0x01c4, 0x01c5, 0x01c6, NOTACHAR, 0x01c7, 0x01c8, 0x01c9, NOTACHAR, 0x01ca, 0x01cb, 0x01cc, NOTACHAR, 0x01f1, 0x01f2, 0x01f3, NOTACHAR, 0x0345, 0x0399, 0x03b9, 0x1fbe, NOTACHAR, 0x00b5, 0x039c, 0x03bc, NOTACHAR, 0x03a3, 0x03c2, 0x03c3, NOTACHAR, 0x0392, 0x03b2, 0x03d0, NOTACHAR, 0x0398, 0x03b8, 0x03d1, 0x03f4, NOTACHAR, 0x03a6, 0x03c6, 0x03d5, NOTACHAR, 0x03a0, 0x03c0, 0x03d6, NOTACHAR, 0x039a, 0x03ba, 0x03f0, NOTACHAR, 0x03a1, 0x03c1, 0x03f1, NOTACHAR, 0x0395, 0x03b5, 0x03f5, NOTACHAR, 0x1e60, 0x1e61, 0x1e9b, NOTACHAR, 0x03a9, 0x03c9, 0x2126, NOTACHAR, 0x004b, 0x006b, 0x212a, NOTACHAR, 0x00c5, 0x00e5, 0x212b, NOTACHAR, }; /* When #included in pcretest, we don't need this large table. */ #ifndef PCRE_INCLUDED const ucd_record PRIV(ucd_records)[] = { /* 5760 bytes, record size 8 */ { 9, 0, 2, 0, 0, }, /* 0 */ { 9, 0, 1, 0, 0, }, /* 1 */ { 9, 0, 0, 0, 0, }, /* 2 */ { 9, 29, 12, 0, 0, }, /* 3 */ { 9, 21, 12, 0, 0, }, /* 4 */ { 9, 23, 12, 0, 0, }, /* 5 */ { 9, 22, 12, 0, 0, }, /* 6 */ { 9, 18, 12, 0, 0, }, /* 7 */ { 9, 25, 12, 0, 0, }, /* 8 */ { 9, 17, 12, 0, 0, }, /* 9 */ { 9, 13, 12, 0, 0, }, /* 10 */ { 33, 9, 12, 0, 32, }, /* 11 */ { 33, 9, 12, 71, 32, }, /* 12 */ { 33, 9, 12, 1, 32, }, /* 13 */ { 9, 24, 12, 0, 0, }, /* 14 */ { 9, 16, 12, 0, 0, }, /* 15 */ { 33, 5, 12, 0, -32, }, /* 16 */ { 33, 5, 12, 71, -32, }, /* 17 */ { 33, 5, 12, 1, -32, }, /* 18 */ { 9, 26, 12, 0, 0, }, /* 19 */ { 33, 7, 12, 0, 0, }, /* 20 */ { 9, 20, 12, 0, 0, }, /* 21 */ { 9, 1, 2, 0, 0, }, /* 22 */ { 9, 15, 12, 0, 0, }, /* 23 */ { 9, 5, 12, 26, 775, }, /* 24 */ { 9, 19, 12, 0, 0, }, /* 25 */ { 33, 9, 12, 75, 32, }, /* 26 */ { 33, 5, 12, 0, 7615, }, /* 27 */ { 33, 5, 12, 75, -32, }, /* 28 */ { 33, 5, 12, 0, 121, }, /* 29 */ { 33, 9, 12, 0, 1, }, /* 30 */ { 33, 5, 12, 0, -1, }, /* 31 */ { 33, 9, 12, 0, 0, }, /* 32 */ { 33, 5, 12, 0, 0, }, /* 33 */ { 33, 9, 12, 0, -121, }, /* 34 */ { 33, 5, 12, 1, -268, }, /* 35 */ { 33, 5, 12, 0, 195, }, /* 36 */ { 33, 9, 12, 0, 210, }, /* 37 */ { 33, 9, 12, 0, 206, }, /* 38 */ { 33, 9, 12, 0, 205, }, /* 39 */ { 33, 9, 12, 0, 79, }, /* 40 */ { 33, 9, 12, 0, 202, }, /* 41 */ { 33, 9, 12, 0, 203, }, /* 42 */ { 33, 9, 12, 0, 207, }, /* 43 */ { 33, 5, 12, 0, 97, }, /* 44 */ { 33, 9, 12, 0, 211, }, /* 45 */ { 33, 9, 12, 0, 209, }, /* 46 */ { 33, 5, 12, 0, 163, }, /* 47 */ { 33, 9, 12, 0, 213, }, /* 48 */ { 33, 5, 12, 0, 130, }, /* 49 */ { 33, 9, 12, 0, 214, }, /* 50 */ { 33, 9, 12, 0, 218, }, /* 51 */ { 33, 9, 12, 0, 217, }, /* 52 */ { 33, 9, 12, 0, 219, }, /* 53 */ { 33, 5, 12, 0, 56, }, /* 54 */ { 33, 9, 12, 5, 2, }, /* 55 */ { 33, 8, 12, 5, 1, }, /* 56 */ { 33, 5, 12, 5, -2, }, /* 57 */ { 33, 9, 12, 9, 2, }, /* 58 */ { 33, 8, 12, 9, 1, }, /* 59 */ { 33, 5, 12, 9, -2, }, /* 60 */ { 33, 9, 12, 13, 2, }, /* 61 */ { 33, 8, 12, 13, 1, }, /* 62 */ { 33, 5, 12, 13, -2, }, /* 63 */ { 33, 5, 12, 0, -79, }, /* 64 */ { 33, 9, 12, 17, 2, }, /* 65 */ { 33, 8, 12, 17, 1, }, /* 66 */ { 33, 5, 12, 17, -2, }, /* 67 */ { 33, 9, 12, 0, -97, }, /* 68 */ { 33, 9, 12, 0, -56, }, /* 69 */ { 33, 9, 12, 0, -130, }, /* 70 */ { 33, 9, 12, 0, 10795, }, /* 71 */ { 33, 9, 12, 0, -163, }, /* 72 */ { 33, 9, 12, 0, 10792, }, /* 73 */ { 33, 5, 12, 0, 10815, }, /* 74 */ { 33, 9, 12, 0, -195, }, /* 75 */ { 33, 9, 12, 0, 69, }, /* 76 */ { 33, 9, 12, 0, 71, }, /* 77 */ { 33, 5, 12, 0, 10783, }, /* 78 */ { 33, 5, 12, 0, 10780, }, /* 79 */ { 33, 5, 12, 0, 10782, }, /* 80 */ { 33, 5, 12, 0, -210, }, /* 81 */ { 33, 5, 12, 0, -206, }, /* 82 */ { 33, 5, 12, 0, -205, }, /* 83 */ { 33, 5, 12, 0, -202, }, /* 84 */ { 33, 5, 12, 0, -203, }, /* 85 */ { 33, 5, 12, 0, 42319, }, /* 86 */ { 33, 5, 12, 0, 42315, }, /* 87 */ { 33, 5, 12, 0, -207, }, /* 88 */ { 33, 5, 12, 0, 42280, }, /* 89 */ { 33, 5, 12, 0, 42308, }, /* 90 */ { 33, 5, 12, 0, -209, }, /* 91 */ { 33, 5, 12, 0, -211, }, /* 92 */ { 33, 5, 12, 0, 10743, }, /* 93 */ { 33, 5, 12, 0, 42305, }, /* 94 */ { 33, 5, 12, 0, 10749, }, /* 95 */ { 33, 5, 12, 0, -213, }, /* 96 */ { 33, 5, 12, 0, -214, }, /* 97 */ { 33, 5, 12, 0, 10727, }, /* 98 */ { 33, 5, 12, 0, -218, }, /* 99 */ { 33, 5, 12, 0, 42282, }, /* 100 */ { 33, 5, 12, 0, -69, }, /* 101 */ { 33, 5, 12, 0, -217, }, /* 102 */ { 33, 5, 12, 0, -71, }, /* 103 */ { 33, 5, 12, 0, -219, }, /* 104 */ { 33, 5, 12, 0, 42258, }, /* 105 */ { 33, 6, 12, 0, 0, }, /* 106 */ { 9, 6, 12, 0, 0, }, /* 107 */ { 3, 24, 12, 0, 0, }, /* 108 */ { 27, 12, 3, 0, 0, }, /* 109 */ { 27, 12, 3, 21, 116, }, /* 110 */ { 19, 9, 12, 0, 1, }, /* 111 */ { 19, 5, 12, 0, -1, }, /* 112 */ { 19, 24, 12, 0, 0, }, /* 113 */ { 9, 2, 12, 0, 0, }, /* 114 */ { 19, 6, 12, 0, 0, }, /* 115 */ { 19, 5, 12, 0, 130, }, /* 116 */ { 19, 9, 12, 0, 116, }, /* 117 */ { 19, 9, 12, 0, 38, }, /* 118 */ { 19, 9, 12, 0, 37, }, /* 119 */ { 19, 9, 12, 0, 64, }, /* 120 */ { 19, 9, 12, 0, 63, }, /* 121 */ { 19, 5, 12, 0, 0, }, /* 122 */ { 19, 9, 12, 0, 32, }, /* 123 */ { 19, 9, 12, 34, 32, }, /* 124 */ { 19, 9, 12, 59, 32, }, /* 125 */ { 19, 9, 12, 38, 32, }, /* 126 */ { 19, 9, 12, 21, 32, }, /* 127 */ { 19, 9, 12, 51, 32, }, /* 128 */ { 19, 9, 12, 26, 32, }, /* 129 */ { 19, 9, 12, 47, 32, }, /* 130 */ { 19, 9, 12, 55, 32, }, /* 131 */ { 19, 9, 12, 30, 32, }, /* 132 */ { 19, 9, 12, 43, 32, }, /* 133 */ { 19, 9, 12, 67, 32, }, /* 134 */ { 19, 5, 12, 0, -38, }, /* 135 */ { 19, 5, 12, 0, -37, }, /* 136 */ { 19, 5, 12, 0, -32, }, /* 137 */ { 19, 5, 12, 34, -32, }, /* 138 */ { 19, 5, 12, 59, -32, }, /* 139 */ { 19, 5, 12, 38, -32, }, /* 140 */ { 19, 5, 12, 21, -116, }, /* 141 */ { 19, 5, 12, 51, -32, }, /* 142 */ { 19, 5, 12, 26, -775, }, /* 143 */ { 19, 5, 12, 47, -32, }, /* 144 */ { 19, 5, 12, 55, -32, }, /* 145 */ { 19, 5, 12, 30, 1, }, /* 146 */ { 19, 5, 12, 30, -32, }, /* 147 */ { 19, 5, 12, 43, -32, }, /* 148 */ { 19, 5, 12, 67, -32, }, /* 149 */ { 19, 5, 12, 0, -64, }, /* 150 */ { 19, 5, 12, 0, -63, }, /* 151 */ { 19, 9, 12, 0, 8, }, /* 152 */ { 19, 5, 12, 34, -30, }, /* 153 */ { 19, 5, 12, 38, -25, }, /* 154 */ { 19, 9, 12, 0, 0, }, /* 155 */ { 19, 5, 12, 43, -15, }, /* 156 */ { 19, 5, 12, 47, -22, }, /* 157 */ { 19, 5, 12, 0, -8, }, /* 158 */ { 10, 9, 12, 0, 1, }, /* 159 */ { 10, 5, 12, 0, -1, }, /* 160 */ { 19, 5, 12, 51, -54, }, /* 161 */ { 19, 5, 12, 55, -48, }, /* 162 */ { 19, 5, 12, 0, 7, }, /* 163 */ { 19, 5, 12, 0, -116, }, /* 164 */ { 19, 9, 12, 38, -60, }, /* 165 */ { 19, 5, 12, 59, -64, }, /* 166 */ { 19, 25, 12, 0, 0, }, /* 167 */ { 19, 9, 12, 0, -7, }, /* 168 */ { 19, 9, 12, 0, -130, }, /* 169 */ { 12, 9, 12, 0, 80, }, /* 170 */ { 12, 9, 12, 0, 32, }, /* 171 */ { 12, 5, 12, 0, -32, }, /* 172 */ { 12, 5, 12, 0, -80, }, /* 173 */ { 12, 9, 12, 0, 1, }, /* 174 */ { 12, 5, 12, 0, -1, }, /* 175 */ { 12, 26, 12, 0, 0, }, /* 176 */ { 12, 12, 3, 0, 0, }, /* 177 */ { 12, 11, 3, 0, 0, }, /* 178 */ { 12, 9, 12, 0, 15, }, /* 179 */ { 12, 5, 12, 0, -15, }, /* 180 */ { 1, 9, 12, 0, 48, }, /* 181 */ { 1, 6, 12, 0, 0, }, /* 182 */ { 1, 21, 12, 0, 0, }, /* 183 */ { 1, 5, 12, 0, -48, }, /* 184 */ { 1, 5, 12, 0, 0, }, /* 185 */ { 1, 17, 12, 0, 0, }, /* 186 */ { 1, 26, 12, 0, 0, }, /* 187 */ { 1, 23, 12, 0, 0, }, /* 188 */ { 25, 12, 3, 0, 0, }, /* 189 */ { 25, 17, 12, 0, 0, }, /* 190 */ { 25, 21, 12, 0, 0, }, /* 191 */ { 25, 7, 12, 0, 0, }, /* 192 */ { 0, 1, 2, 0, 0, }, /* 193 */ { 0, 25, 12, 0, 0, }, /* 194 */ { 0, 21, 12, 0, 0, }, /* 195 */ { 0, 23, 12, 0, 0, }, /* 196 */ { 0, 26, 12, 0, 0, }, /* 197 */ { 0, 12, 3, 0, 0, }, /* 198 */ { 0, 7, 12, 0, 0, }, /* 199 */ { 0, 6, 12, 0, 0, }, /* 200 */ { 0, 13, 12, 0, 0, }, /* 201 */ { 49, 21, 12, 0, 0, }, /* 202 */ { 49, 1, 2, 0, 0, }, /* 203 */ { 49, 7, 12, 0, 0, }, /* 204 */ { 49, 12, 3, 0, 0, }, /* 205 */ { 55, 7, 12, 0, 0, }, /* 206 */ { 55, 12, 3, 0, 0, }, /* 207 */ { 63, 13, 12, 0, 0, }, /* 208 */ { 63, 7, 12, 0, 0, }, /* 209 */ { 63, 12, 3, 0, 0, }, /* 210 */ { 63, 6, 12, 0, 0, }, /* 211 */ { 63, 26, 12, 0, 0, }, /* 212 */ { 63, 21, 12, 0, 0, }, /* 213 */ { 89, 7, 12, 0, 0, }, /* 214 */ { 89, 12, 3, 0, 0, }, /* 215 */ { 89, 6, 12, 0, 0, }, /* 216 */ { 89, 21, 12, 0, 0, }, /* 217 */ { 94, 7, 12, 0, 0, }, /* 218 */ { 94, 12, 3, 0, 0, }, /* 219 */ { 94, 21, 12, 0, 0, }, /* 220 */ { 14, 12, 3, 0, 0, }, /* 221 */ { 14, 10, 5, 0, 0, }, /* 222 */ { 14, 7, 12, 0, 0, }, /* 223 */ { 14, 13, 12, 0, 0, }, /* 224 */ { 14, 21, 12, 0, 0, }, /* 225 */ { 14, 6, 12, 0, 0, }, /* 226 */ { 2, 7, 12, 0, 0, }, /* 227 */ { 2, 12, 3, 0, 0, }, /* 228 */ { 2, 10, 5, 0, 0, }, /* 229 */ { 2, 10, 3, 0, 0, }, /* 230 */ { 2, 13, 12, 0, 0, }, /* 231 */ { 2, 23, 12, 0, 0, }, /* 232 */ { 2, 15, 12, 0, 0, }, /* 233 */ { 2, 26, 12, 0, 0, }, /* 234 */ { 21, 12, 3, 0, 0, }, /* 235 */ { 21, 10, 5, 0, 0, }, /* 236 */ { 21, 7, 12, 0, 0, }, /* 237 */ { 21, 13, 12, 0, 0, }, /* 238 */ { 20, 12, 3, 0, 0, }, /* 239 */ { 20, 10, 5, 0, 0, }, /* 240 */ { 20, 7, 12, 0, 0, }, /* 241 */ { 20, 13, 12, 0, 0, }, /* 242 */ { 20, 21, 12, 0, 0, }, /* 243 */ { 20, 23, 12, 0, 0, }, /* 244 */ { 43, 12, 3, 0, 0, }, /* 245 */ { 43, 10, 5, 0, 0, }, /* 246 */ { 43, 7, 12, 0, 0, }, /* 247 */ { 43, 10, 3, 0, 0, }, /* 248 */ { 43, 13, 12, 0, 0, }, /* 249 */ { 43, 26, 12, 0, 0, }, /* 250 */ { 43, 15, 12, 0, 0, }, /* 251 */ { 53, 12, 3, 0, 0, }, /* 252 */ { 53, 7, 12, 0, 0, }, /* 253 */ { 53, 10, 3, 0, 0, }, /* 254 */ { 53, 10, 5, 0, 0, }, /* 255 */ { 53, 13, 12, 0, 0, }, /* 256 */ { 53, 15, 12, 0, 0, }, /* 257 */ { 53, 26, 12, 0, 0, }, /* 258 */ { 53, 23, 12, 0, 0, }, /* 259 */ { 54, 12, 3, 0, 0, }, /* 260 */ { 54, 10, 5, 0, 0, }, /* 261 */ { 54, 7, 12, 0, 0, }, /* 262 */ { 54, 13, 12, 0, 0, }, /* 263 */ { 54, 15, 12, 0, 0, }, /* 264 */ { 54, 26, 12, 0, 0, }, /* 265 */ { 28, 12, 3, 0, 0, }, /* 266 */ { 28, 10, 5, 0, 0, }, /* 267 */ { 28, 7, 12, 0, 0, }, /* 268 */ { 28, 10, 3, 0, 0, }, /* 269 */ { 28, 13, 12, 0, 0, }, /* 270 */ { 36, 12, 3, 0, 0, }, /* 271 */ { 36, 10, 5, 0, 0, }, /* 272 */ { 36, 7, 12, 0, 0, }, /* 273 */ { 36, 10, 3, 0, 0, }, /* 274 */ { 36, 13, 12, 0, 0, }, /* 275 */ { 36, 15, 12, 0, 0, }, /* 276 */ { 36, 26, 12, 0, 0, }, /* 277 */ { 47, 10, 5, 0, 0, }, /* 278 */ { 47, 7, 12, 0, 0, }, /* 279 */ { 47, 12, 3, 0, 0, }, /* 280 */ { 47, 10, 3, 0, 0, }, /* 281 */ { 47, 13, 12, 0, 0, }, /* 282 */ { 47, 21, 12, 0, 0, }, /* 283 */ { 56, 7, 12, 0, 0, }, /* 284 */ { 56, 12, 3, 0, 0, }, /* 285 */ { 56, 7, 5, 0, 0, }, /* 286 */ { 56, 6, 12, 0, 0, }, /* 287 */ { 56, 21, 12, 0, 0, }, /* 288 */ { 56, 13, 12, 0, 0, }, /* 289 */ { 32, 7, 12, 0, 0, }, /* 290 */ { 32, 12, 3, 0, 0, }, /* 291 */ { 32, 7, 5, 0, 0, }, /* 292 */ { 32, 6, 12, 0, 0, }, /* 293 */ { 32, 13, 12, 0, 0, }, /* 294 */ { 57, 7, 12, 0, 0, }, /* 295 */ { 57, 26, 12, 0, 0, }, /* 296 */ { 57, 21, 12, 0, 0, }, /* 297 */ { 57, 12, 3, 0, 0, }, /* 298 */ { 57, 13, 12, 0, 0, }, /* 299 */ { 57, 15, 12, 0, 0, }, /* 300 */ { 57, 22, 12, 0, 0, }, /* 301 */ { 57, 18, 12, 0, 0, }, /* 302 */ { 57, 10, 5, 0, 0, }, /* 303 */ { 38, 7, 12, 0, 0, }, /* 304 */ { 38, 10, 12, 0, 0, }, /* 305 */ { 38, 12, 3, 0, 0, }, /* 306 */ { 38, 10, 5, 0, 0, }, /* 307 */ { 38, 13, 12, 0, 0, }, /* 308 */ { 38, 21, 12, 0, 0, }, /* 309 */ { 38, 26, 12, 0, 0, }, /* 310 */ { 16, 9, 12, 0, 7264, }, /* 311 */ { 16, 7, 12, 0, 0, }, /* 312 */ { 16, 6, 12, 0, 0, }, /* 313 */ { 23, 7, 6, 0, 0, }, /* 314 */ { 23, 7, 7, 0, 0, }, /* 315 */ { 23, 7, 8, 0, 0, }, /* 316 */ { 15, 7, 12, 0, 0, }, /* 317 */ { 15, 12, 3, 0, 0, }, /* 318 */ { 15, 21, 12, 0, 0, }, /* 319 */ { 15, 15, 12, 0, 0, }, /* 320 */ { 15, 26, 12, 0, 0, }, /* 321 */ { 8, 7, 12, 0, 0, }, /* 322 */ { 7, 17, 12, 0, 0, }, /* 323 */ { 7, 7, 12, 0, 0, }, /* 324 */ { 7, 21, 12, 0, 0, }, /* 325 */ { 40, 29, 12, 0, 0, }, /* 326 */ { 40, 7, 12, 0, 0, }, /* 327 */ { 40, 22, 12, 0, 0, }, /* 328 */ { 40, 18, 12, 0, 0, }, /* 329 */ { 45, 7, 12, 0, 0, }, /* 330 */ { 45, 14, 12, 0, 0, }, /* 331 */ { 50, 7, 12, 0, 0, }, /* 332 */ { 50, 12, 3, 0, 0, }, /* 333 */ { 24, 7, 12, 0, 0, }, /* 334 */ { 24, 12, 3, 0, 0, }, /* 335 */ { 6, 7, 12, 0, 0, }, /* 336 */ { 6, 12, 3, 0, 0, }, /* 337 */ { 51, 7, 12, 0, 0, }, /* 338 */ { 51, 12, 3, 0, 0, }, /* 339 */ { 31, 7, 12, 0, 0, }, /* 340 */ { 31, 12, 3, 0, 0, }, /* 341 */ { 31, 10, 5, 0, 0, }, /* 342 */ { 31, 21, 12, 0, 0, }, /* 343 */ { 31, 6, 12, 0, 0, }, /* 344 */ { 31, 23, 12, 0, 0, }, /* 345 */ { 31, 13, 12, 0, 0, }, /* 346 */ { 31, 15, 12, 0, 0, }, /* 347 */ { 37, 21, 12, 0, 0, }, /* 348 */ { 37, 17, 12, 0, 0, }, /* 349 */ { 37, 12, 3, 0, 0, }, /* 350 */ { 37, 1, 2, 0, 0, }, /* 351 */ { 37, 13, 12, 0, 0, }, /* 352 */ { 37, 7, 12, 0, 0, }, /* 353 */ { 37, 6, 12, 0, 0, }, /* 354 */ { 34, 7, 12, 0, 0, }, /* 355 */ { 34, 12, 3, 0, 0, }, /* 356 */ { 34, 10, 5, 0, 0, }, /* 357 */ { 34, 26, 12, 0, 0, }, /* 358 */ { 34, 21, 12, 0, 0, }, /* 359 */ { 34, 13, 12, 0, 0, }, /* 360 */ { 52, 7, 12, 0, 0, }, /* 361 */ { 39, 7, 12, 0, 0, }, /* 362 */ { 39, 10, 12, 0, 0, }, /* 363 */ { 39, 10, 5, 0, 0, }, /* 364 */ { 39, 13, 12, 0, 0, }, /* 365 */ { 39, 15, 12, 0, 0, }, /* 366 */ { 39, 26, 12, 0, 0, }, /* 367 */ { 31, 26, 12, 0, 0, }, /* 368 */ { 5, 7, 12, 0, 0, }, /* 369 */ { 5, 12, 3, 0, 0, }, /* 370 */ { 5, 10, 5, 0, 0, }, /* 371 */ { 5, 21, 12, 0, 0, }, /* 372 */ { 90, 7, 12, 0, 0, }, /* 373 */ { 90, 10, 5, 0, 0, }, /* 374 */ { 90, 12, 3, 0, 0, }, /* 375 */ { 90, 10, 12, 0, 0, }, /* 376 */ { 90, 13, 12, 0, 0, }, /* 377 */ { 90, 21, 12, 0, 0, }, /* 378 */ { 90, 6, 12, 0, 0, }, /* 379 */ { 27, 11, 3, 0, 0, }, /* 380 */ { 61, 12, 3, 0, 0, }, /* 381 */ { 61, 10, 5, 0, 0, }, /* 382 */ { 61, 7, 12, 0, 0, }, /* 383 */ { 61, 13, 12, 0, 0, }, /* 384 */ { 61, 21, 12, 0, 0, }, /* 385 */ { 61, 26, 12, 0, 0, }, /* 386 */ { 75, 12, 3, 0, 0, }, /* 387 */ { 75, 10, 5, 0, 0, }, /* 388 */ { 75, 7, 12, 0, 0, }, /* 389 */ { 75, 13, 12, 0, 0, }, /* 390 */ { 92, 7, 12, 0, 0, }, /* 391 */ { 92, 12, 3, 0, 0, }, /* 392 */ { 92, 10, 5, 0, 0, }, /* 393 */ { 92, 21, 12, 0, 0, }, /* 394 */ { 69, 7, 12, 0, 0, }, /* 395 */ { 69, 10, 5, 0, 0, }, /* 396 */ { 69, 12, 3, 0, 0, }, /* 397 */ { 69, 21, 12, 0, 0, }, /* 398 */ { 69, 13, 12, 0, 0, }, /* 399 */ { 72, 13, 12, 0, 0, }, /* 400 */ { 72, 7, 12, 0, 0, }, /* 401 */ { 72, 6, 12, 0, 0, }, /* 402 */ { 72, 21, 12, 0, 0, }, /* 403 */ { 75, 21, 12, 0, 0, }, /* 404 */ { 9, 10, 5, 0, 0, }, /* 405 */ { 9, 7, 12, 0, 0, }, /* 406 */ { 12, 5, 12, 0, 0, }, /* 407 */ { 12, 6, 12, 0, 0, }, /* 408 */ { 33, 5, 12, 0, 35332, }, /* 409 */ { 33, 5, 12, 0, 3814, }, /* 410 */ { 33, 9, 12, 63, 1, }, /* 411 */ { 33, 5, 12, 63, -1, }, /* 412 */ { 33, 5, 12, 63, -58, }, /* 413 */ { 33, 9, 12, 0, -7615, }, /* 414 */ { 19, 5, 12, 0, 8, }, /* 415 */ { 19, 9, 12, 0, -8, }, /* 416 */ { 19, 5, 12, 0, 74, }, /* 417 */ { 19, 5, 12, 0, 86, }, /* 418 */ { 19, 5, 12, 0, 100, }, /* 419 */ { 19, 5, 12, 0, 128, }, /* 420 */ { 19, 5, 12, 0, 112, }, /* 421 */ { 19, 5, 12, 0, 126, }, /* 422 */ { 19, 8, 12, 0, -8, }, /* 423 */ { 19, 5, 12, 0, 9, }, /* 424 */ { 19, 9, 12, 0, -74, }, /* 425 */ { 19, 8, 12, 0, -9, }, /* 426 */ { 19, 5, 12, 21, -7173, }, /* 427 */ { 19, 9, 12, 0, -86, }, /* 428 */ { 19, 9, 12, 0, -100, }, /* 429 */ { 19, 9, 12, 0, -112, }, /* 430 */ { 19, 9, 12, 0, -128, }, /* 431 */ { 19, 9, 12, 0, -126, }, /* 432 */ { 27, 1, 3, 0, 0, }, /* 433 */ { 9, 27, 2, 0, 0, }, /* 434 */ { 9, 28, 2, 0, 0, }, /* 435 */ { 9, 2, 2, 0, 0, }, /* 436 */ { 9, 9, 12, 0, 0, }, /* 437 */ { 9, 5, 12, 0, 0, }, /* 438 */ { 19, 9, 12, 67, -7517, }, /* 439 */ { 33, 9, 12, 71, -8383, }, /* 440 */ { 33, 9, 12, 75, -8262, }, /* 441 */ { 33, 9, 12, 0, 28, }, /* 442 */ { 33, 5, 12, 0, -28, }, /* 443 */ { 33, 14, 12, 0, 16, }, /* 444 */ { 33, 14, 12, 0, -16, }, /* 445 */ { 33, 14, 12, 0, 0, }, /* 446 */ { 9, 26, 12, 0, 26, }, /* 447 */ { 9, 26, 12, 0, -26, }, /* 448 */ { 4, 26, 12, 0, 0, }, /* 449 */ { 17, 9, 12, 0, 48, }, /* 450 */ { 17, 5, 12, 0, -48, }, /* 451 */ { 33, 9, 12, 0, -10743, }, /* 452 */ { 33, 9, 12, 0, -3814, }, /* 453 */ { 33, 9, 12, 0, -10727, }, /* 454 */ { 33, 5, 12, 0, -10795, }, /* 455 */ { 33, 5, 12, 0, -10792, }, /* 456 */ { 33, 9, 12, 0, -10780, }, /* 457 */ { 33, 9, 12, 0, -10749, }, /* 458 */ { 33, 9, 12, 0, -10783, }, /* 459 */ { 33, 9, 12, 0, -10782, }, /* 460 */ { 33, 9, 12, 0, -10815, }, /* 461 */ { 10, 5, 12, 0, 0, }, /* 462 */ { 10, 26, 12, 0, 0, }, /* 463 */ { 10, 12, 3, 0, 0, }, /* 464 */ { 10, 21, 12, 0, 0, }, /* 465 */ { 10, 15, 12, 0, 0, }, /* 466 */ { 16, 5, 12, 0, -7264, }, /* 467 */ { 58, 7, 12, 0, 0, }, /* 468 */ { 58, 6, 12, 0, 0, }, /* 469 */ { 58, 21, 12, 0, 0, }, /* 470 */ { 58, 12, 3, 0, 0, }, /* 471 */ { 22, 26, 12, 0, 0, }, /* 472 */ { 22, 6, 12, 0, 0, }, /* 473 */ { 22, 14, 12, 0, 0, }, /* 474 */ { 23, 10, 3, 0, 0, }, /* 475 */ { 26, 7, 12, 0, 0, }, /* 476 */ { 26, 6, 12, 0, 0, }, /* 477 */ { 29, 7, 12, 0, 0, }, /* 478 */ { 29, 6, 12, 0, 0, }, /* 479 */ { 3, 7, 12, 0, 0, }, /* 480 */ { 23, 7, 12, 0, 0, }, /* 481 */ { 23, 26, 12, 0, 0, }, /* 482 */ { 29, 26, 12, 0, 0, }, /* 483 */ { 22, 7, 12, 0, 0, }, /* 484 */ { 60, 7, 12, 0, 0, }, /* 485 */ { 60, 6, 12, 0, 0, }, /* 486 */ { 60, 26, 12, 0, 0, }, /* 487 */ { 85, 7, 12, 0, 0, }, /* 488 */ { 85, 6, 12, 0, 0, }, /* 489 */ { 85, 21, 12, 0, 0, }, /* 490 */ { 76, 7, 12, 0, 0, }, /* 491 */ { 76, 6, 12, 0, 0, }, /* 492 */ { 76, 21, 12, 0, 0, }, /* 493 */ { 76, 13, 12, 0, 0, }, /* 494 */ { 12, 7, 12, 0, 0, }, /* 495 */ { 12, 21, 12, 0, 0, }, /* 496 */ { 78, 7, 12, 0, 0, }, /* 497 */ { 78, 14, 12, 0, 0, }, /* 498 */ { 78, 12, 3, 0, 0, }, /* 499 */ { 78, 21, 12, 0, 0, }, /* 500 */ { 33, 9, 12, 0, -35332, }, /* 501 */ { 33, 9, 12, 0, -42280, }, /* 502 */ { 33, 9, 12, 0, -42308, }, /* 503 */ { 33, 9, 12, 0, -42319, }, /* 504 */ { 33, 9, 12, 0, -42315, }, /* 505 */ { 33, 9, 12, 0, -42305, }, /* 506 */ { 33, 9, 12, 0, -42258, }, /* 507 */ { 33, 9, 12, 0, -42282, }, /* 508 */ { 48, 7, 12, 0, 0, }, /* 509 */ { 48, 12, 3, 0, 0, }, /* 510 */ { 48, 10, 5, 0, 0, }, /* 511 */ { 48, 26, 12, 0, 0, }, /* 512 */ { 64, 7, 12, 0, 0, }, /* 513 */ { 64, 21, 12, 0, 0, }, /* 514 */ { 74, 10, 5, 0, 0, }, /* 515 */ { 74, 7, 12, 0, 0, }, /* 516 */ { 74, 12, 3, 0, 0, }, /* 517 */ { 74, 21, 12, 0, 0, }, /* 518 */ { 74, 13, 12, 0, 0, }, /* 519 */ { 68, 13, 12, 0, 0, }, /* 520 */ { 68, 7, 12, 0, 0, }, /* 521 */ { 68, 12, 3, 0, 0, }, /* 522 */ { 68, 21, 12, 0, 0, }, /* 523 */ { 73, 7, 12, 0, 0, }, /* 524 */ { 73, 12, 3, 0, 0, }, /* 525 */ { 73, 10, 5, 0, 0, }, /* 526 */ { 73, 21, 12, 0, 0, }, /* 527 */ { 83, 12, 3, 0, 0, }, /* 528 */ { 83, 10, 5, 0, 0, }, /* 529 */ { 83, 7, 12, 0, 0, }, /* 530 */ { 83, 21, 12, 0, 0, }, /* 531 */ { 83, 13, 12, 0, 0, }, /* 532 */ { 38, 6, 12, 0, 0, }, /* 533 */ { 67, 7, 12, 0, 0, }, /* 534 */ { 67, 12, 3, 0, 0, }, /* 535 */ { 67, 10, 5, 0, 0, }, /* 536 */ { 67, 13, 12, 0, 0, }, /* 537 */ { 67, 21, 12, 0, 0, }, /* 538 */ { 91, 7, 12, 0, 0, }, /* 539 */ { 91, 12, 3, 0, 0, }, /* 540 */ { 91, 6, 12, 0, 0, }, /* 541 */ { 91, 21, 12, 0, 0, }, /* 542 */ { 86, 7, 12, 0, 0, }, /* 543 */ { 86, 10, 5, 0, 0, }, /* 544 */ { 86, 12, 3, 0, 0, }, /* 545 */ { 86, 21, 12, 0, 0, }, /* 546 */ { 86, 6, 12, 0, 0, }, /* 547 */ { 86, 13, 12, 0, 0, }, /* 548 */ { 23, 7, 9, 0, 0, }, /* 549 */ { 23, 7, 10, 0, 0, }, /* 550 */ { 9, 4, 2, 0, 0, }, /* 551 */ { 9, 3, 12, 0, 0, }, /* 552 */ { 25, 25, 12, 0, 0, }, /* 553 */ { 0, 24, 12, 0, 0, }, /* 554 */ { 9, 6, 3, 0, 0, }, /* 555 */ { 35, 7, 12, 0, 0, }, /* 556 */ { 19, 14, 12, 0, 0, }, /* 557 */ { 19, 15, 12, 0, 0, }, /* 558 */ { 19, 26, 12, 0, 0, }, /* 559 */ { 70, 7, 12, 0, 0, }, /* 560 */ { 66, 7, 12, 0, 0, }, /* 561 */ { 41, 7, 12, 0, 0, }, /* 562 */ { 41, 15, 12, 0, 0, }, /* 563 */ { 18, 7, 12, 0, 0, }, /* 564 */ { 18, 14, 12, 0, 0, }, /* 565 */ { 117, 7, 12, 0, 0, }, /* 566 */ { 117, 12, 3, 0, 0, }, /* 567 */ { 59, 7, 12, 0, 0, }, /* 568 */ { 59, 21, 12, 0, 0, }, /* 569 */ { 42, 7, 12, 0, 0, }, /* 570 */ { 42, 21, 12, 0, 0, }, /* 571 */ { 42, 14, 12, 0, 0, }, /* 572 */ { 13, 9, 12, 0, 40, }, /* 573 */ { 13, 5, 12, 0, -40, }, /* 574 */ { 46, 7, 12, 0, 0, }, /* 575 */ { 44, 7, 12, 0, 0, }, /* 576 */ { 44, 13, 12, 0, 0, }, /* 577 */ { 105, 7, 12, 0, 0, }, /* 578 */ { 103, 7, 12, 0, 0, }, /* 579 */ { 103, 21, 12, 0, 0, }, /* 580 */ { 109, 7, 12, 0, 0, }, /* 581 */ { 11, 7, 12, 0, 0, }, /* 582 */ { 80, 7, 12, 0, 0, }, /* 583 */ { 80, 21, 12, 0, 0, }, /* 584 */ { 80, 15, 12, 0, 0, }, /* 585 */ { 119, 7, 12, 0, 0, }, /* 586 */ { 119, 26, 12, 0, 0, }, /* 587 */ { 119, 15, 12, 0, 0, }, /* 588 */ { 115, 7, 12, 0, 0, }, /* 589 */ { 115, 15, 12, 0, 0, }, /* 590 */ { 65, 7, 12, 0, 0, }, /* 591 */ { 65, 15, 12, 0, 0, }, /* 592 */ { 65, 21, 12, 0, 0, }, /* 593 */ { 71, 7, 12, 0, 0, }, /* 594 */ { 71, 21, 12, 0, 0, }, /* 595 */ { 97, 7, 12, 0, 0, }, /* 596 */ { 96, 7, 12, 0, 0, }, /* 597 */ { 30, 7, 12, 0, 0, }, /* 598 */ { 30, 12, 3, 0, 0, }, /* 599 */ { 30, 15, 12, 0, 0, }, /* 600 */ { 30, 21, 12, 0, 0, }, /* 601 */ { 87, 7, 12, 0, 0, }, /* 602 */ { 87, 15, 12, 0, 0, }, /* 603 */ { 87, 21, 12, 0, 0, }, /* 604 */ { 116, 7, 12, 0, 0, }, /* 605 */ { 116, 15, 12, 0, 0, }, /* 606 */ { 111, 7, 12, 0, 0, }, /* 607 */ { 111, 26, 12, 0, 0, }, /* 608 */ { 111, 12, 3, 0, 0, }, /* 609 */ { 111, 15, 12, 0, 0, }, /* 610 */ { 111, 21, 12, 0, 0, }, /* 611 */ { 77, 7, 12, 0, 0, }, /* 612 */ { 77, 21, 12, 0, 0, }, /* 613 */ { 82, 7, 12, 0, 0, }, /* 614 */ { 82, 15, 12, 0, 0, }, /* 615 */ { 81, 7, 12, 0, 0, }, /* 616 */ { 81, 15, 12, 0, 0, }, /* 617 */ { 120, 7, 12, 0, 0, }, /* 618 */ { 120, 21, 12, 0, 0, }, /* 619 */ { 120, 15, 12, 0, 0, }, /* 620 */ { 88, 7, 12, 0, 0, }, /* 621 */ { 0, 15, 12, 0, 0, }, /* 622 */ { 93, 10, 5, 0, 0, }, /* 623 */ { 93, 12, 3, 0, 0, }, /* 624 */ { 93, 7, 12, 0, 0, }, /* 625 */ { 93, 21, 12, 0, 0, }, /* 626 */ { 93, 15, 12, 0, 0, }, /* 627 */ { 93, 13, 12, 0, 0, }, /* 628 */ { 84, 12, 3, 0, 0, }, /* 629 */ { 84, 10, 5, 0, 0, }, /* 630 */ { 84, 7, 12, 0, 0, }, /* 631 */ { 84, 21, 12, 0, 0, }, /* 632 */ { 84, 1, 2, 0, 0, }, /* 633 */ { 100, 7, 12, 0, 0, }, /* 634 */ { 100, 13, 12, 0, 0, }, /* 635 */ { 95, 12, 3, 0, 0, }, /* 636 */ { 95, 7, 12, 0, 0, }, /* 637 */ { 95, 10, 5, 0, 0, }, /* 638 */ { 95, 13, 12, 0, 0, }, /* 639 */ { 95, 21, 12, 0, 0, }, /* 640 */ { 110, 7, 12, 0, 0, }, /* 641 */ { 110, 12, 3, 0, 0, }, /* 642 */ { 110, 21, 12, 0, 0, }, /* 643 */ { 99, 12, 3, 0, 0, }, /* 644 */ { 99, 10, 5, 0, 0, }, /* 645 */ { 99, 7, 12, 0, 0, }, /* 646 */ { 99, 21, 12, 0, 0, }, /* 647 */ { 99, 13, 12, 0, 0, }, /* 648 */ { 47, 15, 12, 0, 0, }, /* 649 */ { 107, 7, 12, 0, 0, }, /* 650 */ { 107, 10, 5, 0, 0, }, /* 651 */ { 107, 12, 3, 0, 0, }, /* 652 */ { 107, 21, 12, 0, 0, }, /* 653 */ { 108, 7, 12, 0, 0, }, /* 654 */ { 108, 12, 3, 0, 0, }, /* 655 */ { 108, 10, 5, 0, 0, }, /* 656 */ { 108, 13, 12, 0, 0, }, /* 657 */ { 106, 12, 3, 0, 0, }, /* 658 */ { 106, 10, 5, 0, 0, }, /* 659 */ { 106, 7, 12, 0, 0, }, /* 660 */ { 106, 10, 3, 0, 0, }, /* 661 */ { 123, 7, 12, 0, 0, }, /* 662 */ { 123, 10, 3, 0, 0, }, /* 663 */ { 123, 10, 5, 0, 0, }, /* 664 */ { 123, 12, 3, 0, 0, }, /* 665 */ { 123, 21, 12, 0, 0, }, /* 666 */ { 123, 13, 12, 0, 0, }, /* 667 */ { 122, 7, 12, 0, 0, }, /* 668 */ { 122, 10, 3, 0, 0, }, /* 669 */ { 122, 10, 5, 0, 0, }, /* 670 */ { 122, 12, 3, 0, 0, }, /* 671 */ { 122, 21, 12, 0, 0, }, /* 672 */ { 113, 7, 12, 0, 0, }, /* 673 */ { 113, 10, 5, 0, 0, }, /* 674 */ { 113, 12, 3, 0, 0, }, /* 675 */ { 113, 21, 12, 0, 0, }, /* 676 */ { 113, 13, 12, 0, 0, }, /* 677 */ { 101, 7, 12, 0, 0, }, /* 678 */ { 101, 12, 3, 0, 0, }, /* 679 */ { 101, 10, 5, 0, 0, }, /* 680 */ { 101, 13, 12, 0, 0, }, /* 681 */ { 124, 9, 12, 0, 32, }, /* 682 */ { 124, 5, 12, 0, -32, }, /* 683 */ { 124, 13, 12, 0, 0, }, /* 684 */ { 124, 15, 12, 0, 0, }, /* 685 */ { 124, 7, 12, 0, 0, }, /* 686 */ { 121, 7, 12, 0, 0, }, /* 687 */ { 62, 7, 12, 0, 0, }, /* 688 */ { 62, 14, 12, 0, 0, }, /* 689 */ { 62, 21, 12, 0, 0, }, /* 690 */ { 79, 7, 12, 0, 0, }, /* 691 */ { 114, 7, 12, 0, 0, }, /* 692 */ { 114, 13, 12, 0, 0, }, /* 693 */ { 114, 21, 12, 0, 0, }, /* 694 */ { 102, 7, 12, 0, 0, }, /* 695 */ { 102, 12, 3, 0, 0, }, /* 696 */ { 102, 21, 12, 0, 0, }, /* 697 */ { 118, 7, 12, 0, 0, }, /* 698 */ { 118, 12, 3, 0, 0, }, /* 699 */ { 118, 21, 12, 0, 0, }, /* 700 */ { 118, 26, 12, 0, 0, }, /* 701 */ { 118, 6, 12, 0, 0, }, /* 702 */ { 118, 13, 12, 0, 0, }, /* 703 */ { 118, 15, 12, 0, 0, }, /* 704 */ { 98, 7, 12, 0, 0, }, /* 705 */ { 98, 10, 5, 0, 0, }, /* 706 */ { 98, 12, 3, 0, 0, }, /* 707 */ { 98, 6, 12, 0, 0, }, /* 708 */ { 104, 7, 12, 0, 0, }, /* 709 */ { 104, 26, 12, 0, 0, }, /* 710 */ { 104, 12, 3, 0, 0, }, /* 711 */ { 104, 21, 12, 0, 0, }, /* 712 */ { 9, 10, 3, 0, 0, }, /* 713 */ { 19, 12, 3, 0, 0, }, /* 714 */ { 112, 7, 12, 0, 0, }, /* 715 */ { 112, 15, 12, 0, 0, }, /* 716 */ { 112, 12, 3, 0, 0, }, /* 717 */ { 9, 26, 11, 0, 0, }, /* 718 */ { 26, 26, 12, 0, 0, }, /* 719 */ }; const pcre_uint8 PRIV(ucd_stage1)[] = { /* 8704 bytes */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* U+0000 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* U+0800 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 41, 41, 42, 43, 44, 45, /* U+1000 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, /* U+1800 */ 62, 63, 64, 65, 66, 66, 67, 68, 69, 70, 71, 72, 73, 71, 74, 75, /* U+2000 */ 76, 76, 66, 77, 66, 66, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, /* U+2800 */ 88, 89, 90, 91, 92, 93, 94, 71, 95, 95, 95, 95, 95, 95, 95, 95, /* U+3000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+3800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+4000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 95, 95, 95, 95, /* U+4800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+5000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+5800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+6000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+6800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+7000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+7800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+8000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+8800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+9000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 97, /* U+9800 */ 98, 99, 99, 99, 99, 99, 99, 99, 99,100,101,101,102,103,104,105, /* U+A000 */ 106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,114, /* U+A800 */ 115,116,117,118,119,120,114,115,116,117,118,119,120,114,115,116, /* U+B000 */ 117,118,119,120,114,115,116,117,118,119,120,114,115,116,117,118, /* U+B800 */ 119,120,114,115,116,117,118,119,120,114,115,116,117,118,119,120, /* U+C000 */ 114,115,116,117,118,119,120,114,115,116,117,118,119,120,114,115, /* U+C800 */ 116,117,118,119,120,114,115,116,117,118,119,120,114,115,116,121, /* U+D000 */ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, /* U+D800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+E000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+E800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F000 */ 123,123, 95, 95,124,125,126,127,128,128,129,130,131,132,133,134, /* U+F800 */ 135,136,137,138,139,140,141,142,143,144,145,139,146,146,147,139, /* U+10000 */ 148,149,150,151,152,153,154,155,156,139,139,139,157,139,139,139, /* U+10800 */ 158,159,160,161,162,163,164,139,139,165,139,166,167,168,139,139, /* U+11000 */ 139,169,139,139,139,170,139,139,139,139,139,139,139,139,139,139, /* U+11800 */ 171,171,171,171,171,171,171,172,173,139,139,139,139,139,139,139, /* U+12000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+12800 */ 174,174,174,174,174,174,174,174,175,139,139,139,139,139,139,139, /* U+13000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+13800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+14000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+14800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+15000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+15800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+16000 */ 176,176,176,176,177,178,179,180,139,139,139,139,139,139,181,182, /* U+16800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+17000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+17800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+18000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+18800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+19000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+19800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1A000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1A800 */ 183,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1B000 */ 139,139,139,139,139,139,139,139,184,185,139,139,139,139,139,139, /* U+1B800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1C000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1C800 */ 71,186,187,188,189,139,190,139,191,192,193,194,195,196,197,198, /* U+1D000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1D800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1E000 */ 199,200,139,139,139,139,139,139,139,139,139,139,201,202,139,139, /* U+1E800 */ 203,204,205,206,207,139,208,209, 71,210,211,212,213,214,215,216, /* U+1F000 */ 217,218,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1F800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+20000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+20800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+21000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+21800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+22000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+22800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+23000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+23800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+24000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+24800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+25000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+25800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+26000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+26800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+27000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+27800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+28000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+28800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+29000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+29800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,219, 95, 95, /* U+2A000 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+2A800 */ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,220, 95, /* U+2B000 */ 221,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2B800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2C000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2C800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2D000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2D800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2E000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2E800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2F000 */ 95, 95, 95, 95,221,139,139,139,139,139,139,139,139,139,139,139, /* U+2F800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+30000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+30800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+31000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+31800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+32000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+32800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+33000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+33800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+34000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+34800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+35000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+35800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+36000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+36800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+37000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+37800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+38000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+38800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+39000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+39800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3A000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3A800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3B000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3B800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3C000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3C800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3D000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3D800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3E000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3E800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3F000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+3F800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+40000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+40800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+41000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+41800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+42000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+42800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+43000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+43800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+44000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+44800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+45000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+45800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+46000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+46800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+47000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+47800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+48000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+48800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+49000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+49800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4A000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4A800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4B000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4B800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4C000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4C800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4D000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4D800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4E000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4E800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4F000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+4F800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+50000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+50800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+51000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+51800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+52000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+52800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+53000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+53800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+54000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+54800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+55000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+55800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+56000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+56800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+57000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+57800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+58000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+58800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+59000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+59800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5A000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5A800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5B000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5B800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5C000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5C800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5D000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5D800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5E000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5E800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5F000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+5F800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+60000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+60800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+61000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+61800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+62000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+62800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+63000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+63800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+64000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+64800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+65000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+65800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+66000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+66800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+67000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+67800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+68000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+68800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+69000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+69800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6A000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6A800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6B000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6B800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6C000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6C800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6D000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6D800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6E000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6E800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6F000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+6F800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+70000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+70800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+71000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+71800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+72000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+72800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+73000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+73800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+74000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+74800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+75000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+75800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+76000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+76800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+77000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+77800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+78000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+78800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+79000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+79800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7A000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7A800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7B000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7B800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7C000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7C800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7D000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7D800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7E000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7E800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7F000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+7F800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+80000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+80800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+81000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+81800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+82000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+82800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+83000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+83800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+84000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+84800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+85000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+85800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+86000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+86800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+87000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+87800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+88000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+88800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+89000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+89800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8A000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8A800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8B000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8B800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8C000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8C800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8D000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8D800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8E000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8E800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8F000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+8F800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+90000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+90800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+91000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+91800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+92000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+92800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+93000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+93800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+94000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+94800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+95000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+95800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+96000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+96800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+97000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+97800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+98000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+98800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+99000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+99800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9A000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9A800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9B000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9B800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9C000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9C800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9D000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9D800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9E000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9E800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9F000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+9F800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A0000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A0800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A1000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A1800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A2000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A2800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A3000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A3800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A4000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A4800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A5000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A5800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A6000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A6800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A7000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A7800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A8000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A8800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A9000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+A9800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AA000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AA800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AB000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AB800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AC000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AC800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AD000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AD800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AE000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AE800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AF000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+AF800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B0000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B0800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B1000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B1800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B2000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B2800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B3000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B3800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B4000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B4800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B5000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B5800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B6000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B6800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B7000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B7800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B8000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B8800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B9000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+B9800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BA000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BA800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BB000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BB800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BC000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BC800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BD000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BD800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BE000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BE800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BF000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+BF800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C0000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C0800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C1000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C1800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C2000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C2800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C3000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C3800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C4000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C4800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C5000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C5800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C6000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C6800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C7000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C7800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C8000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C8800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C9000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+C9800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CA000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CA800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CB000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CB800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CC000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CC800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CD000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CD800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CE000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CE800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CF000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+CF800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D0000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D0800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D1000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D1800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D2000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D2800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D3000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D3800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D4000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D4800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D5000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D5800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D6000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D6800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D7000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D7800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D8000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D8800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D9000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+D9800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DA000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DA800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DB000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DB800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DC000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DC800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DD000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DD800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DE000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DE800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DF000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DF800 */ 222,223,224,225,223,223,223,223,223,223,223,223,223,223,223,223, /* U+E0000 */ 223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, /* U+E0800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E1000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E1800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E2000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E2800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E3000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E3800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E4000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E4800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E5000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E5800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E6000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E6800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E7000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E7800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E8000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E8800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E9000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E9800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EA000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EA800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EB000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EB800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EC000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EC800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+ED000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+ED800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EE000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EE800 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EF000 */ 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+EF800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F0000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F0800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F1000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F1800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F2000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F2800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F3000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F3800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F4000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F4800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F5000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F5800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F6000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F6800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F7000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F7800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F8000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F8800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F9000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F9800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FA000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FA800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FB000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FB800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FC000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FC800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FD000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FD800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FE000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FE800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FF000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,226, /* U+FF800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+100000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+100800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+101000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+101800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+102000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+102800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+103000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+103800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+104000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+104800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+105000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+105800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+106000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+106800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+107000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+107800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+108000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+108800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+109000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+109800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10A000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10A800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10B000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10B800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10C000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10C800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10D000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10D800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10E000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10E800 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10F000 */ 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,226, /* U+10F800 */ }; const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */ /* block 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 4, 4, 5, 4, 4, 4, 6, 7, 4, 8, 4, 9, 4, 4, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 4, 8, 8, 8, 4, 4, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 11, 11, 11, 11, 11, 11, 11, 13, 11, 11, 11, 11, 11, 11, 11, 6, 4, 7, 14, 15, 14, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 16, 16, 16, 16, 16, 16, 18, 16, 16, 16, 16, 16, 16, 16, 6, 8, 7, 8, 0, /* block 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 5, 5, 5, 19, 4, 14, 19, 20, 21, 8, 22, 19, 14, 19, 8, 23, 23, 14, 24, 4, 4, 14, 23, 20, 25, 23, 23, 23, 4, 11, 11, 11, 11, 11, 26, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 8, 11, 11, 11, 11, 11, 11, 11, 27, 16, 16, 16, 16, 16, 28, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 29, /* block 2 */ 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 32, 33, 30, 31, 30, 31, 30, 31, 33, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 33, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 34, 30, 31, 30, 31, 30, 31, 35, /* block 3 */ 36, 37, 30, 31, 30, 31, 38, 30, 31, 39, 39, 30, 31, 33, 40, 41, 42, 30, 31, 39, 43, 44, 45, 46, 30, 31, 47, 33, 45, 48, 49, 50, 30, 31, 30, 31, 30, 31, 51, 30, 31, 51, 33, 33, 30, 31, 51, 30, 31, 52, 52, 30, 31, 30, 31, 53, 30, 31, 33, 20, 30, 31, 33, 54, 20, 20, 20, 20, 55, 56, 57, 58, 59, 60, 61, 62, 63, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 64, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 33, 65, 66, 67, 30, 31, 68, 69, 30, 31, 30, 31, 30, 31, 30, 31, /* block 4 */ 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 70, 33, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 33, 33, 33, 33, 33, 33, 71, 30, 31, 72, 73, 74, 74, 30, 31, 75, 76, 77, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 78, 79, 80, 81, 82, 33, 83, 83, 33, 84, 33, 85, 86, 33, 33, 33, 83, 87, 33, 88, 33, 89, 90, 33, 91, 92, 33, 93, 94, 33, 33, 92, 33, 95, 96, 33, 33, 97, 33, 33, 33, 33, 33, 33, 33, 98, 33, 33, /* block 5 */ 99, 33, 33, 99, 33, 33, 33,100, 99,101,102,102,103, 33, 33, 33, 33, 33,104, 33, 20, 33, 33, 33, 33, 33, 33, 33, 33, 33,105, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 106,106,106,106,106,106,106,106,106,107,107,107,107,107,107,107, 107,107, 14, 14, 14, 14,107,107,107,107,107,107,107,107,107,107, 107,107, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 106,106,106,106,106, 14, 14, 14, 14, 14,108,108,107, 14,107, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, /* block 6 */ 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,110,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 111,112,111,112,107,113,111,112,114,114,115,116,116,116, 4,117, /* block 7 */ 114,114,114,114,113, 14,118, 4,119,119,119,114,120,114,121,121, 122,123,124,123,123,125,123,123,126,127,128,123,129,123,123,123, 130,131,114,132,123,123,133,123,123,134,123,123,135,136,136,136, 122,137,138,137,137,139,137,137,140,141,142,137,143,137,137,137, 144,145,146,147,137,137,148,137,137,149,137,137,150,151,151,152, 153,154,155,155,155,156,157,158,111,112,111,112,111,112,111,112, 111,112,159,160,159,160,159,160,159,160,159,160,159,160,159,160, 161,162,163,164,165,166,167,111,112,168,111,112,122,169,169,169, /* block 8 */ 170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, 171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, 172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, 173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, /* block 9 */ 174,175,176,177,177,109,109,177,178,178,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 179,174,175,174,175,174,175,174,175,174,175,174,175,174,175,180, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, /* block 10 */ 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 114,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, 181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, 181,181,181,181,181,181,181,114,114,182,183,183,183,183,183,183, 114,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, 184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, /* block 11 */ 184,184,184,184,184,184,184,185,114, 4,186,114,114,187,187,188, 114,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, 189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, 189,189,189,189,189,189,189,189,189,189,189,189,189,189,190,189, 191,189,189,191,189,189,191,189,114,114,114,114,114,114,114,114, 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, 192,192,192,192,192,192,192,192,192,192,192,114,114,114,114,114, 192,192,192,191,191,114,114,114,114,114,114,114,114,114,114,114, /* block 12 */ 193,193,193,193,193, 22,194,194,194,195,195,196, 4,195,197,197, 198,198,198,198,198,198,198,198,198,198,198, 4, 22,114,195, 4, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 107,199,199,199,199,199,199,199,199,199,199,109,109,109,109,109, 109,109,109,109,109,109,198,198,198,198,198,198,198,198,198,198, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,195,195,195,195,199,199, 109,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, /* block 13 */ 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,195,199,198,198,198,198,198,198,198, 22,197,198, 198,198,198,198,198,200,200,198,198,197,198,198,198,198,199,199, 201,201,201,201,201,201,201,201,201,201,199,199,199,197,197,199, /* block 14 */ 202,202,202,202,202,202,202,202,202,202,202,202,202,202,114,203, 204,205,204,204,204,204,204,204,204,204,204,204,204,204,204,204, 204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, 205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, 205,205,205,205,205,205,205,205,205,205,205,114,114,204,204,204, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, /* block 15 */ 206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, 206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, 206,206,206,206,206,206,207,207,207,207,207,207,207,207,207,207, 207,206,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 208,208,208,208,208,208,208,208,208,208,209,209,209,209,209,209, 209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, 209,209,209,209,209,209,209,209,209,209,209,210,210,210,210,210, 210,210,210,210,211,211,212,213,213,213,211,114,114,114,114,114, /* block 16 */ 214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, 214,214,214,214,214,214,215,215,215,215,216,215,215,215,215,215, 215,215,215,215,216,215,215,215,216,215,215,215,215,215,114,114, 217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,114, 218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, 218,218,218,218,218,218,218,218,218,219,219,219,114,114,220,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 17 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,198,198,198,198,198,198,198,198,198,198,198,198, 198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, /* block 18 */ 221,221,221,222,223,223,223,223,223,223,223,223,223,223,223,223, 223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, 223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, 223,223,223,223,223,223,223,223,223,223,221,222,221,223,222,222, 222,221,221,221,221,221,221,221,221,222,222,222,222,221,222,222, 223,109,109,221,221,221,221,221,223,223,223,223,223,223,223,223, 223,223,221,221, 4, 4,224,224,224,224,224,224,224,224,224,224, 225,226,223,223,223,223,223,223,223,223,223,223,223,223,223,223, /* block 19 */ 227,228,229,229,114,227,227,227,227,227,227,227,227,114,114,227, 227,114,114,227,227,227,227,227,227,227,227,227,227,227,227,227, 227,227,227,227,227,227,227,227,227,114,227,227,227,227,227,227, 227,114,227,114,114,114,227,227,227,227,114,114,228,227,230,229, 229,228,228,228,228,114,114,229,229,114,114,229,229,228,227,114, 114,114,114,114,114,114,114,230,114,114,114,114,227,227,114,227, 227,227,228,228,114,114,231,231,231,231,231,231,231,231,231,231, 227,227,232,232,233,233,233,233,233,233,234,232,114,114,114,114, /* block 20 */ 114,235,235,236,114,237,237,237,237,237,237,114,114,114,114,237, 237,114,114,237,237,237,237,237,237,237,237,237,237,237,237,237, 237,237,237,237,237,237,237,237,237,114,237,237,237,237,237,237, 237,114,237,237,114,237,237,114,237,237,114,114,235,114,236,236, 236,235,235,114,114,114,114,235,235,114,114,235,235,235,114,114, 114,235,114,114,114,114,114,114,114,237,237,237,237,114,237,114, 114,114,114,114,114,114,238,238,238,238,238,238,238,238,238,238, 235,235,237,237,237,235,114,114,114,114,114,114,114,114,114,114, /* block 21 */ 114,239,239,240,114,241,241,241,241,241,241,241,241,241,114,241, 241,241,114,241,241,241,241,241,241,241,241,241,241,241,241,241, 241,241,241,241,241,241,241,241,241,114,241,241,241,241,241,241, 241,114,241,241,114,241,241,241,241,241,114,114,239,241,240,240, 240,239,239,239,239,239,114,239,239,240,114,240,240,239,114,114, 241,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 241,241,239,239,114,114,242,242,242,242,242,242,242,242,242,242, 243,244,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 22 */ 114,245,246,246,114,247,247,247,247,247,247,247,247,114,114,247, 247,114,114,247,247,247,247,247,247,247,247,247,247,247,247,247, 247,247,247,247,247,247,247,247,247,114,247,247,247,247,247,247, 247,114,247,247,114,247,247,247,247,247,114,114,245,247,248,245, 246,245,245,245,245,114,114,246,246,114,114,246,246,245,114,114, 114,114,114,114,114,114,245,248,114,114,114,114,247,247,114,247, 247,247,245,245,114,114,249,249,249,249,249,249,249,249,249,249, 250,247,251,251,251,251,251,251,114,114,114,114,114,114,114,114, /* block 23 */ 114,114,252,253,114,253,253,253,253,253,253,114,114,114,253,253, 253,114,253,253,253,253,114,114,114,253,253,114,253,114,253,253, 114,114,114,253,253,114,114,114,253,253,253,114,114,114,253,253, 253,253,253,253,253,253,253,253,253,253,114,114,114,114,254,255, 252,255,255,114,114,114,255,255,255,114,255,255,255,252,114,114, 253,114,114,114,114,114,114,254,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,256,256,256,256,256,256,256,256,256,256, 257,257,257,258,258,258,258,258,258,259,258,114,114,114,114,114, /* block 24 */ 260,261,261,261,114,262,262,262,262,262,262,262,262,114,262,262, 262,114,262,262,262,262,262,262,262,262,262,262,262,262,262,262, 262,262,262,262,262,262,262,262,262,114,262,262,262,262,262,262, 262,262,262,262,262,262,262,262,262,262,114,114,114,262,260,260, 260,261,261,261,261,114,260,260,260,114,260,260,260,260,114,114, 114,114,114,114,114,260,260,114,262,262,114,114,114,114,114,114, 262,262,260,260,114,114,263,263,263,263,263,263,263,263,263,263, 114,114,114,114,114,114,114,114,264,264,264,264,264,264,264,265, /* block 25 */ 114,266,267,267,114,268,268,268,268,268,268,268,268,114,268,268, 268,114,268,268,268,268,268,268,268,268,268,268,268,268,268,268, 268,268,268,268,268,268,268,268,268,114,268,268,268,268,268,268, 268,268,268,268,114,268,268,268,268,268,114,114,266,268,267,266, 267,267,269,267,267,114,266,267,267,114,267,267,266,266,114,114, 114,114,114,114,114,269,269,114,114,114,114,114,114,114,268,114, 268,268,266,266,114,114,270,270,270,270,270,270,270,270,270,270, 114,268,268,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 26 */ 114,271,272,272,114,273,273,273,273,273,273,273,273,114,273,273, 273,114,273,273,273,273,273,273,273,273,273,273,273,273,273,273, 273,273,273,273,273,273,273,273,273,273,273,273,273,273,273,273, 273,273,273,273,273,273,273,273,273,273,273,114,114,273,274,272, 272,271,271,271,271,114,272,272,272,114,272,272,272,271,273,114, 114,114,114,114,114,114,114,274,114,114,114,114,114,114,114,114, 273,273,271,271,114,114,275,275,275,275,275,275,275,275,275,275, 276,276,276,276,276,276,114,114,114,277,273,273,273,273,273,273, /* block 27 */ 114,114,278,278,114,279,279,279,279,279,279,279,279,279,279,279, 279,279,279,279,279,279,279,114,114,114,279,279,279,279,279,279, 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279, 279,279,114,279,279,279,279,279,279,279,279,279,114,279,114,114, 279,279,279,279,279,279,279,114,114,114,280,114,114,114,114,281, 278,278,280,280,280,114,280,114,278,278,278,278,278,278,278,281, 114,114,114,114,114,114,282,282,282,282,282,282,282,282,282,282, 114,114,278,278,283,114,114,114,114,114,114,114,114,114,114,114, /* block 28 */ 114,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284, 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284, 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284, 284,285,284,286,285,285,285,285,285,285,285,114,114,114,114, 5, 284,284,284,284,284,284,287,285,285,285,285,285,285,285,285,288, 289,289,289,289,289,289,289,289,289,289,288,288,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 29 */ 114,290,290,114,290,114,114,290,290,114,290,114,114,290,114,114, 114,114,114,114,290,290,290,290,114,290,290,290,290,290,290,290, 114,290,290,290,114,290,114,290,114,114,290,290,114,290,290,290, 290,291,290,292,291,291,291,291,291,291,114,291,291,290,114,114, 290,290,290,290,290,114,293,114,291,291,291,291,291,291,114,114, 294,294,294,294,294,294,294,294,294,294,114,114,290,290,290,290, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 30 */ 295,296,296,296,297,297,297,297,297,297,297,297,297,297,297,297, 297,297,297,296,297,296,296,296,298,298,296,296,296,296,296,296, 299,299,299,299,299,299,299,299,299,299,300,300,300,300,300,300, 300,300,300,300,296,298,296,298,296,298,301,302,301,302,303,303, 295,295,295,295,295,295,295,295,114,295,295,295,295,295,295,295, 295,295,295,295,295,295,295,295,295,295,295,295,295,295,295,295, 295,295,295,295,295,295,295,295,295,295,295,295,295,114,114,114, 114,298,298,298,298,298,298,298,298,298,298,298,298,298,298,303, /* block 31 */ 298,298,298,298,298,297,298,298,295,295,295,295,295,298,298,298, 298,298,298,298,298,298,298,298,114,298,298,298,298,298,298,298, 298,298,298,298,298,298,298,298,298,298,298,298,298,298,298,298, 298,298,298,298,298,298,298,298,298,298,298,298,298,114,296,296, 296,296,296,296,296,296,298,296,296,296,296,296,296,114,296,296, 297,297,297,297,297, 19, 19, 19, 19,297,297,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 32 */ 304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,304, 304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,304, 304,304,304,304,304,304,304,304,304,304,304,305,305,306,306,306, 306,307,306,306,306,306,306,306,305,306,306,307,307,306,306,304, 308,308,308,308,308,308,308,308,308,308,309,309,309,309,309,309, 304,304,304,304,304,304,307,307,306,306,304,304,304,304,306,306, 306,304,305,305,305,304,304,305,305,305,305,305,305,305,304,304, 304,306,306,306,306,304,304,304,304,304,304,304,304,304,304,304, /* block 33 */ 304,304,306,305,307,306,306,305,305,305,305,305,305,306,304,305, 308,308,308,308,308,308,308,308,308,308,305,305,305,306,310,310, 311,311,311,311,311,311,311,311,311,311,311,311,311,311,311,311, 311,311,311,311,311,311,311,311,311,311,311,311,311,311,311,311, 311,311,311,311,311,311,114,311,114,114,114,114,114,311,114,114, 312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,312, 312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,312, 312,312,312,312,312,312,312,312,312,312,312, 4,313,312,312,312, /* block 34 */ 314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314, 314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314, 314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314, 314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314, 314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314, 314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314, 315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315, 315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315, /* block 35 */ 315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315, 315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315, 315,315,315,315,315,315,315,315,316,316,316,316,316,316,316,316, 316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316, 316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316, 316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316, 316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316, 316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316, /* block 36 */ 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,114,317,317,317,317,114,114, 317,317,317,317,317,317,317,114,317,114,317,317,317,317,114,114, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, /* block 37 */ 317,317,317,317,317,317,317,317,317,114,317,317,317,317,114,114, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,114,317,317,317,317,114,114,317,317,317,317,317,317,317,114, 317,114,317,317,317,317,114,114,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, /* block 38 */ 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,114,317,317,317,317,114,114,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,317,317,317,317,114,114,318,318,318, 319,319,319,319,319,319,319,319,319,320,320,320,320,320,320,320, 320,320,320,320,320,320,320,320,320,320,320,320,320,114,114,114, /* block 39 */ 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 321,321,321,321,321,321,321,321,321,321,114,114,114,114,114,114, 322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322, 322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322, 322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322, 322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322, 322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322, 322,322,322,322,322,114,114,114,114,114,114,114,114,114,114,114, /* block 40 */ 323,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, /* block 41 */ 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, /* block 42 */ 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,325,325,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, /* block 43 */ 326,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327, 327,327,327,327,327,327,327,327,327,327,327,328,329,114,114,114, 330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330, 330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330, 330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330, 330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330, 330,330,330,330,330,330,330,330,330,330,330, 4, 4, 4,331,331, 331,330,330,330,330,330,330,330,330,114,114,114,114,114,114,114, /* block 44 */ 332,332,332,332,332,332,332,332,332,332,332,332,332,114,332,332, 332,332,333,333,333,114,114,114,114,114,114,114,114,114,114,114, 334,334,334,334,334,334,334,334,334,334,334,334,334,334,334,334, 334,334,335,335,335, 4, 4,114,114,114,114,114,114,114,114,114, 336,336,336,336,336,336,336,336,336,336,336,336,336,336,336,336, 336,336,337,337,114,114,114,114,114,114,114,114,114,114,114,114, 338,338,338,338,338,338,338,338,338,338,338,338,338,114,338,338, 338,114,339,339,114,114,114,114,114,114,114,114,114,114,114,114, /* block 45 */ 340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340, 340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340, 340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340, 340,340,340,340,341,341,342,341,341,341,341,341,341,341,342,342, 342,342,342,342,342,342,341,342,342,341,341,341,341,341,341,341, 341,341,341,341,343,343,343,344,343,343,343,345,340,341,114,114, 346,346,346,346,346,346,346,346,346,346,114,114,114,114,114,114, 347,347,347,347,347,347,347,347,347,347,114,114,114,114,114,114, /* block 46 */ 348,348, 4, 4,348, 4,349,348,348,348,348,350,350,350,351,114, 352,352,352,352,352,352,352,352,352,352,114,114,114,114,114,114, 353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353, 353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353, 353,353,353,354,353,353,353,353,353,353,353,353,353,353,353,353, 353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353, 353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353, 353,353,353,353,353,353,353,353,114,114,114,114,114,114,114,114, /* block 47 */ 353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353, 353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353, 353,353,353,353,353,353,353,353,353,350,353,114,114,114,114,114, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324, 324,324,324,324,324,324,114,114,114,114,114,114,114,114,114,114, /* block 48 */ 355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,355, 355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,114, 356,356,356,357,357,357,357,356,356,357,357,357,114,114,114,114, 357,357,356,357,357,357,357,357,357,356,356,356,114,114,114,114, 358,114,114,114,359,359,360,360,360,360,360,360,360,360,360,360, 361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361, 361,361,361,361,361,361,361,361,361,361,361,361,361,361,114,114, 361,361,361,361,361,114,114,114,114,114,114,114,114,114,114,114, /* block 49 */ 362,362,362,362,362,362,362,362,362,362,362,362,362,362,362,362, 362,362,362,362,362,362,362,362,362,362,362,362,362,362,362,362, 362,362,362,362,362,362,362,362,362,362,362,362,114,114,114,114, 363,363,363,363,363,364,364,364,363,363,364,363,363,363,363,363, 363,362,362,362,362,362,362,362,363,363,114,114,114,114,114,114, 365,365,365,365,365,365,365,365,365,365,366,114,114,114,367,367, 368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368, 368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368, /* block 50 */ 369,369,369,369,369,369,369,369,369,369,369,369,369,369,369,369, 369,369,369,369,369,369,369,370,370,371,371,370,114,114,372,372, 373,373,373,373,373,373,373,373,373,373,373,373,373,373,373,373, 373,373,373,373,373,373,373,373,373,373,373,373,373,373,373,373, 373,373,373,373,373,373,373,373,373,373,373,373,373,373,373,373, 373,373,373,373,373,374,375,374,375,375,375,375,375,375,375,114, 375,376,375,376,376,375,375,375,375,375,375,375,375,374,374,374, 374,374,374,375,375,375,375,375,375,375,375,375,375,114,114,375, /* block 51 */ 377,377,377,377,377,377,377,377,377,377,114,114,114,114,114,114, 377,377,377,377,377,377,377,377,377,377,114,114,114,114,114,114, 378,378,378,378,378,378,378,379,378,378,378,378,378,378,114,114, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,380,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 52 */ 381,381,381,381,382,383,383,383,383,383,383,383,383,383,383,383, 383,383,383,383,383,383,383,383,383,383,383,383,383,383,383,383, 383,383,383,383,383,383,383,383,383,383,383,383,383,383,383,383, 383,383,383,383,381,382,381,381,381,381,381,382,381,382,382,382, 382,382,381,382,382,383,383,383,383,383,383,383,114,114,114,114, 384,384,384,384,384,384,384,384,384,384,385,385,385,385,385,385, 385,386,386,386,386,386,386,386,386,386,386,381,381,381,381,381, 381,381,381,381,386,386,386,386,386,386,386,386,386,114,114,114, /* block 53 */ 387,387,388,389,389,389,389,389,389,389,389,389,389,389,389,389, 389,389,389,389,389,389,389,389,389,389,389,389,389,389,389,389, 389,388,387,387,387,387,388,388,387,387,388,387,387,387,389,389, 390,390,390,390,390,390,390,390,390,390,389,389,389,389,389,389, 391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,391, 391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,391, 391,391,391,391,391,391,392,393,392,392,393,393,393,392,393,392, 392,392,393,393,114,114,114,114,114,114,114,114,394,394,394,394, /* block 54 */ 395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,395, 395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,395, 395,395,395,395,396,396,396,396,396,396,396,396,397,397,397,397, 397,397,397,397,396,396,397,397,114,114,114,398,398,398,398,398, 399,399,399,399,399,399,399,399,399,399,114,114,114,395,395,395, 400,400,400,400,400,400,400,400,400,400,401,401,401,401,401,401, 401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401, 401,401,401,401,401,401,401,401,402,402,402,402,402,402,403,403, /* block 55 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 404,404,404,404,404,404,404,404,114,114,114,114,114,114,114,114, 109,109,109, 4,109,109,109,109,109,109,109,109,109,109,109,109, 109,405,109,109,109,109,109,109,109,406,406,406,406,109,406,406, 406,406,405,405,109,406,406,114,109,109,114,114,114,114,114,114, /* block 56 */ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,122,122,122,122,122,407,106,106,106,106, 106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, 106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, 106,106,106,106,106,106,106,106,106,106,106,106,106,115,115,115, 115,115,106,106,106,106,115,115,115,115,115, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,408,409, 33, 33, 33,410, 33, 33, /* block 57 */ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,106,106,106,106,106, 106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, 106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,115, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,114,114,114,114,114,114,109,109,109,109, /* block 58 */ 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 411,412, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, /* block 59 */ 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 33, 33, 33, 33, 33,413, 33, 33,414, 33, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, /* block 60 */ 415,415,415,415,415,415,415,415,416,416,416,416,416,416,416,416, 415,415,415,415,415,415,114,114,416,416,416,416,416,416,114,114, 415,415,415,415,415,415,415,415,416,416,416,416,416,416,416,416, 415,415,415,415,415,415,415,415,416,416,416,416,416,416,416,416, 415,415,415,415,415,415,114,114,416,416,416,416,416,416,114,114, 122,415,122,415,122,415,122,415,114,416,114,416,114,416,114,416, 415,415,415,415,415,415,415,415,416,416,416,416,416,416,416,416, 417,417,418,418,418,418,419,419,420,420,421,421,422,422,114,114, /* block 61 */ 415,415,415,415,415,415,415,415,423,423,423,423,423,423,423,423, 415,415,415,415,415,415,415,415,423,423,423,423,423,423,423,423, 415,415,415,415,415,415,415,415,423,423,423,423,423,423,423,423, 415,415,122,424,122,114,122,122,416,416,425,425,426,113,427,113, 113,113,122,424,122,114,122,122,428,428,428,428,426,113,113,113, 415,415,122,122,114,114,122,122,416,416,429,429,114,113,113,113, 415,415,122,122,122,163,122,122,416,416,430,430,168,113,113,113, 114,114,122,424,122,114,122,122,431,431,432,432,426,113,113,114, /* block 62 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 22,433,433, 22, 22, 9, 9, 9, 9, 9, 9, 4, 4, 21, 25, 6, 21, 21, 25, 6, 21, 4, 4, 4, 4, 4, 4, 4, 4,434,435, 22, 22, 22, 22, 22, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 21, 25, 4, 4, 4, 4, 15, 15, 4, 4, 4, 8, 6, 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 15, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 22, 22, 22, 22, 22,436, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,106,114,114, 23, 23, 23, 23, 23, 23, 8, 8, 8, 6, 7,106, /* block 63 */ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 8, 8, 8, 6, 7,114, 106,106,106,106,106,106,106,106,106,106,106,106,106,114,114,114, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 109,109,109,109,109,109,109,109,109,109,109,109,109,380,380,380, 380,109,380,380,380,109,109,109,109,109,109,109,109,109,109,109, 109,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 64 */ 19, 19,437, 19, 19, 19, 19,437, 19, 19,438,437,437,437,438,438, 437,437,437,438, 19,437, 19, 19, 8,437,437,437,437,437, 19, 19, 19, 19, 19, 19,437, 19,439, 19,437, 19,440,441,437,437, 19,438, 437,437,442,437,438,406,406,406,406,438, 19, 19,438,438,437,437, 8, 8, 8, 8, 8,437,438,438,438,438, 19, 8, 19, 19,443, 19, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 444,444,444,444,444,444,444,444,444,444,444,444,444,444,444,444, 445,445,445,445,445,445,445,445,445,445,445,445,445,445,445,445, /* block 65 */ 446,446,446, 30, 31,446,446,446,446, 23,114,114,114,114,114,114, 8, 8, 8, 8, 8, 19, 19, 19, 19, 19, 8, 8, 19, 19, 19, 19, 8, 19, 19, 8, 19, 19, 8, 19, 19, 19, 19, 19, 19, 19, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 19, 19, 8, 19, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* block 66 */ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* block 67 */ 19, 19, 19, 19, 19, 19, 19, 19, 6, 7, 6, 7, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 19, 19, 19, 19, 19, 19, 19, 6, 7, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 19, 19, 19, /* block 68 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8, 8, 8, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114, /* block 69 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, /* block 70 */ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,447,447,447,447,447,447,447,447,447,447, 447,447,447,447,447,447,447,447,447,447,447,447,447,447,447,447, 448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448, 448,448,448,448,448,448,448,448,448,448, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, /* block 71 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 72 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8, 8, 8, 8, 8, 8, /* block 73 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 74 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, /* block 75 */ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8, 8, 8, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, /* block 76 */ 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, 449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449, /* block 77 */ 8, 8, 8, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 7, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 7, 8, 8, /* block 78 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 19, 19, 8, 8, 8, 8, 8, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 79 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 80 */ 450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450, 450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450, 450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,114, 451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,451, 451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,451, 451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,114, 30, 31,452,453,454,455,456, 30, 31, 30, 31, 30, 31,457,458,459, 460, 33, 30, 31, 33, 30, 31, 33, 33, 33, 33, 33,106,106,461,461, /* block 81 */ 159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160, 159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160, 159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160, 159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160, 159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160, 159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160, 159,160,159,160,462,463,463,463,463,463,463,159,160,159,160,464, 464,464,159,160,114,114,114,114,114,465,465,465,465,466,465,465, /* block 82 */ 467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467, 467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467, 467,467,467,467,467,467,114,467,114,114,114,114,114,467,114,114, 468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,468, 468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,468, 468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,468, 468,468,468,468,468,468,468,468,114,114,114,114,114,114,114,469, 470,114,114,114,114,114,114,114,114,114,114,114,114,114,114,471, /* block 83 */ 317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317, 317,317,317,317,317,317,317,114,114,114,114,114,114,114,114,114, 317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114, 317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114, 317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114, 317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114, 177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, 177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, /* block 84 */ 4, 4, 21, 25, 21, 25, 4, 4, 4, 21, 25, 4, 21, 25, 4, 4, 4, 4, 4, 4, 4, 4, 4, 9, 4, 4, 9, 4, 21, 25, 4, 4, 21, 25, 6, 7, 6, 7, 6, 7, 6, 7, 4, 4, 4, 4, 4,107, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 9, 9, 4, 4, 4, 4, 9, 4, 6,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 85 */ 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,114,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,114,114,114,114,114,114,114,114,114,114,114,114, /* block 86 */ 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, /* block 87 */ 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 472,472,472,472,472,472,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114, /* block 88 */ 3, 4, 4, 4, 19,473,406,474, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 19, 19, 6, 7, 6, 7, 6, 7, 6, 7, 9, 6, 7, 7, 19,474,474,474,474,474,474,474,474,474,109,109,109,109,475,475, 9,107,107,107,107,107, 19, 19,474,474,474,473,406, 4, 19, 19, 114,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476, 476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476, 476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476, 476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476, /* block 89 */ 476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476, 476,476,476,476,476,476,476,114,114,109,109, 14, 14,477,477,476, 9,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478, 478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478, 478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478, 478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478, 478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478, 478,478,478,478,478,478,478,478,478,478,478, 4,107,479,479,478, /* block 90 */ 114,114,114,114,114,480,480,480,480,480,480,480,480,480,480,480, 480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,480, 480,480,480,480,480,480,480,480,480,480,480,480,480,480,114,114, 114,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481, 481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481, 481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481, 481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481, 481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481, /* block 91 */ 481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,114, 19, 19, 23, 23, 23, 23, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,480, 480,480,480,480,480,480,480,480,480,480,480,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114, 478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478, /* block 92 */ 482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482, 482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,114, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 23, 23, 23, 23, 23, 23, 23, 23, 19, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482, 482,482,482,482,482,482,482,482,482,482,482,482,482,482,482, 19, /* block 93 */ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483, 483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483, 483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,114, /* block 94 */ 483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483, 483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483, 483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483, 483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483, 483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483, 483,483,483,483,483,483,483,483, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 95 */ 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, /* block 96 */ 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,114,114,114,114,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 97 */ 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 98 */ 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,486,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, /* block 99 */ 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, 485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485, /* block 100 */ 485,485,485,485,485,485,485,485,485,485,485,485,485,114,114,114, 487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487, 487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487, 487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487, 487,487,487,487,487,487,487,114,114,114,114,114,114,114,114,114, 488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,488, 488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,488, 488,488,488,488,488,488,488,488,489,489,489,489,489,489,490,490, /* block 101 */ 491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491, 491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491, 491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491, 491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491, 491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491, 491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491, 491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491, 491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491, /* block 102 */ 491,491,491,491,491,491,491,491,491,491,491,491,492,493,493,493, 491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491, 494,494,494,494,494,494,494,494,494,494,491,491,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,174,175,495,177, 178,178,178,496,177,177,177,177,177,177,177,177,177,177,496,408, /* block 103 */ 174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175, 174,175,174,175,174,175,174,175,174,175,174,175,408,408,114,177, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,498,498,498,498,498,498,498,498,498,498, 499,499,500,500,500,500,500,500,114,114,114,114,114,114,114,114, /* block 104 */ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,107,107,107,107,107,107,107,107,107, 14, 14, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 33, 33, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 106, 33, 33, 33, 33, 33, 33, 33, 33, 30, 31, 30, 31,501, 30, 31, /* block 105 */ 30, 31, 30, 31, 30, 31, 30, 31,107, 14, 14, 30, 31,502, 33,114, 30, 31, 30, 31, 33, 33, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,503,504,505,506,114,114, 507,508,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114, 20,106,106, 33, 20, 20, 20, 20, 20, /* block 106 */ 509,509,510,509,509,509,510,509,509,509,509,510,509,509,509,509, 509,509,509,509,509,509,509,509,509,509,509,509,509,509,509,509, 509,509,509,511,511,510,510,511,512,512,512,512,114,114,114,114, 23, 23, 23, 23, 23, 23, 19, 19, 5, 19,114,114,114,114,114,114, 513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513, 513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513, 513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513, 513,513,513,513,514,514,514,514,114,114,114,114,114,114,114,114, /* block 107 */ 515,515,516,516,516,516,516,516,516,516,516,516,516,516,516,516, 516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516, 516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516, 516,516,516,516,515,515,515,515,515,515,515,515,515,515,515,515, 515,515,515,515,517,114,114,114,114,114,114,114,114,114,518,518, 519,519,519,519,519,519,519,519,519,519,114,114,114,114,114,114, 221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, 221,221,223,223,223,223,223,223,225,225,225,223,114,114,114,114, /* block 108 */ 520,520,520,520,520,520,520,520,520,520,521,521,521,521,521,521, 521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,521, 521,521,521,521,521,521,522,522,522,522,522,522,522,522, 4,523, 524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524, 524,524,524,524,524,524,524,525,525,525,525,525,525,525,525,525, 525,525,526,526,114,114,114,114,114,114,114,114,114,114,114,527, 314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314, 314,314,314,314,314,314,314,314,314,314,314,314,314,114,114,114, /* block 109 */ 528,528,528,529,530,530,530,530,530,530,530,530,530,530,530,530, 530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530, 530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530, 530,530,530,528,529,529,528,528,528,528,529,529,528,529,529,529, 529,531,531,531,531,531,531,531,531,531,531,531,531,531,114,107, 532,532,532,532,532,532,532,532,532,532,114,114,114,114,531,531, 304,304,304,304,304,306,533,304,304,304,304,304,304,304,304,304, 308,308,308,308,308,308,308,308,308,308,304,304,304,304,304,114, /* block 110 */ 534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534, 534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534, 534,534,534,534,534,534,534,534,534,535,535,535,535,535,535,536, 536,535,535,536,536,535,535,114,114,114,114,114,114,114,114,114, 534,534,534,535,534,534,534,534,534,534,534,534,535,536,114,114, 537,537,537,537,537,537,537,537,537,537,114,114,538,538,538,538, 304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,304, 533,304,304,304,304,304,304,310,310,310,304,305,306,305,304,304, /* block 111 */ 539,539,539,539,539,539,539,539,539,539,539,539,539,539,539,539, 539,539,539,539,539,539,539,539,539,539,539,539,539,539,539,539, 539,539,539,539,539,539,539,539,539,539,539,539,539,539,539,539, 540,539,540,540,540,539,539,540,540,539,539,539,539,539,540,540, 539,540,539,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,539,539,541,542,542, 543,543,543,543,543,543,543,543,543,543,543,544,545,545,544,544, 546,546,543,547,547,544,545,114,114,114,114,114,114,114,114,114, /* block 112 */ 114,317,317,317,317,317,317,114,114,317,317,317,317,317,317,114, 114,317,317,317,317,317,317,114,114,114,114,114,114,114,114,114, 317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 14,106,106,106,106, 114,114,114,114, 33,122,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 113 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 543,543,543,543,543,543,543,543,543,543,543,543,543,543,543,543, 543,543,543,543,543,543,543,543,543,543,543,543,543,543,543,543, 543,543,543,544,544,545,544,544,545,544,544,546,544,545,114,114, 548,548,548,548,548,548,548,548,548,548,114,114,114,114,114,114, /* block 114 */ 549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, /* block 115 */ 550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550, /* block 116 */ 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, /* block 117 */ 550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550, /* block 118 */ 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, /* block 119 */ 550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550, /* block 120 */ 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, /* block 121 */ 550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550, 550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550, 550,550,550,550,114,114,114,114,114,114,114,114,114,114,114,114, 315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315, 315,315,315,315,315,315,315,114,114,114,114,316,316,316,316,316, 316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316, 316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316, 316,316,316,316,316,316,316,316,316,316,316,316,114,114,114,114, /* block 122 */ 551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551, 551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551, 551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551, 551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551, 551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551, 551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551, 551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551, 551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551, /* block 123 */ 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, /* block 124 */ 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,114,114, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, /* block 125 */ 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 126 */ 33, 33, 33, 33, 33, 33, 33,114,114,114,114,114,114,114,114,114, 114,114,114,185,185,185,185,185,114,114,114,114,114,192,189,192, 192,192,192,192,192,192,192,192,192,553,192,192,192,192,192,192, 192,192,192,192,192,192,192,114,192,192,192,192,192,114,192,114, 192,192,114,192,192,114,192,192,192,192,192,192,192,192,192,192, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, /* block 127 */ 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,554,554,554,554,554,554,554,554,554,554,554,554,554,554, 554,554,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, /* block 128 */ 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, /* block 129 */ 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199, 7, 6, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, /* block 130 */ 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 114,114,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 199,199,199,199,199,199,199,199,199,199,199,199,196,197,114,114, /* block 131 */ 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 4, 4, 4, 4, 4, 4, 4, 6, 7, 4,114,114,114,114,114,114, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,114,114, 4, 9, 9, 15, 15, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 4, 4, 6, 7, 4, 4, 4, 4, 15, 15, 15, 4, 4, 4,114, 4, 4, 4, 4, 9, 6, 7, 6, 7, 6, 7, 4, 4, 4, 8, 9, 8, 8, 8,114, 4, 5, 4, 4,114,114,114,114, 199,199,199,199,199,114,199,199,199,199,199,199,199,199,199,199, /* block 132 */ 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,114,114, 22, /* block 133 */ 114, 4, 4, 4, 5, 4, 4, 4, 6, 7, 4, 8, 4, 9, 4, 4, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 4, 8, 8, 8, 4, 4, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6, 4, 7, 14, 15, 14, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 6, 8, 7, 8, 6, 7, 4, 6, 7, 4, 4,478,478,478,478,478,478,478,478,478,478, 107,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478, /* block 134 */ 478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478, 478,478,478,478,478,478,478,478,478,478,478,478,478,478,555,555, 481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481, 481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,114, 114,114,481,481,481,481,481,481,114,114,481,481,481,481,481,481, 114,114,481,481,481,481,481,481,114,114,481,481,481,114,114,114, 5, 5, 8, 14, 19, 5, 5,114, 19, 8, 8, 8, 8, 19, 19,114, 436,436,436,436,436,436,436,436,436, 22, 22, 22, 19, 19,114,114, /* block 135 */ 556,556,556,556,556,556,556,556,556,556,556,556,114,556,556,556, 556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556, 556,556,556,556,556,556,556,114,556,556,556,556,556,556,556,556, 556,556,556,556,556,556,556,556,556,556,556,114,556,556,114,556, 556,556,556,556,556,556,556,556,556,556,556,556,556,556,114,114, 556,556,556,556,556,556,556,556,556,556,556,556,556,556,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 136 */ 556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556, 556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556, 556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556, 556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556, 556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556, 556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556, 556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556, 556,556,556,556,556,556,556,556,556,556,556,114,114,114,114,114, /* block 137 */ 4, 4, 4,114,114,114,114, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557, 557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557, 557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557, 557,557,557,557,557,558,558,558,558,559,559,559,559,559,559,559, /* block 138 */ 559,559,559,559,559,559,559,559,559,559,558,558,559,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114, 559,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,109,114,114, /* block 139 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 140 */ 560,560,560,560,560,560,560,560,560,560,560,560,560,560,560,560, 560,560,560,560,560,560,560,560,560,560,560,560,560,114,114,114, 561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561, 561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561, 561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561, 561,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 109, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,114,114,114,114, /* block 141 */ 562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,562, 562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,562, 563,563,563,563,114,114,114,114,114,114,114,114,114,114,114,114, 564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,564, 564,565,564,564,564,564,564,564,564,564,565,114,114,114,114,114, 566,566,566,566,566,566,566,566,566,566,566,566,566,566,566,566, 566,566,566,566,566,566,566,566,566,566,566,566,566,566,566,566, 566,566,566,566,566,566,567,567,567,567,567,114,114,114,114,114, /* block 142 */ 568,568,568,568,568,568,568,568,568,568,568,568,568,568,568,568, 568,568,568,568,568,568,568,568,568,568,568,568,568,568,114,569, 570,570,570,570,570,570,570,570,570,570,570,570,570,570,570,570, 570,570,570,570,570,570,570,570,570,570,570,570,570,570,570,570, 570,570,570,570,114,114,114,114,570,570,570,570,570,570,570,570, 571,572,572,572,572,572,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 143 */ 573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573, 573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573, 573,573,573,573,573,573,573,573,574,574,574,574,574,574,574,574, 574,574,574,574,574,574,574,574,574,574,574,574,574,574,574,574, 574,574,574,574,574,574,574,574,574,574,574,574,574,574,574,574, 575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575, 575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575, 575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575, /* block 144 */ 576,576,576,576,576,576,576,576,576,576,576,576,576,576,576,576, 576,576,576,576,576,576,576,576,576,576,576,576,576,576,114,114, 577,577,577,577,577,577,577,577,577,577,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 145 */ 578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578, 578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578, 578,578,578,578,578,578,578,578,114,114,114,114,114,114,114,114, 579,579,579,579,579,579,579,579,579,579,579,579,579,579,579,579, 579,579,579,579,579,579,579,579,579,579,579,579,579,579,579,579, 579,579,579,579,579,579,579,579,579,579,579,579,579,579,579,579, 579,579,579,579,114,114,114,114,114,114,114,114,114,114,114,580, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 146 */ 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, /* block 147 */ 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,581,114,114,114,114,114,114,114,114,114, 581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581, 581,581,581,581,581,581,114,114,114,114,114,114,114,114,114,114, 581,581,581,581,581,581,581,581,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 148 */ 582,582,582,582,582,582,114,114,582,114,582,582,582,582,582,582, 582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,582, 582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,582, 582,582,582,582,582,582,114,582,582,114,114,114,582,114,114,582, 583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583, 583,583,583,583,583,583,114,584,585,585,585,585,585,585,585,585, 586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586, 586,586,586,586,586,586,586,587,587,588,588,588,588,588,588,588, /* block 149 */ 589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,589, 589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,114, 114,114,114,114,114,114,114,590,590,590,590,590,590,590,590,590, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 150 */ 591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,591, 591,591,591,591,591,591,592,592,592,592,592,592,114,114,114,593, 594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,594, 594,594,594,594,594,594,594,594,594,594,114,114,114,114,114,595, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 151 */ 596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596, 596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596, 597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597, 597,597,597,597,597,597,597,597,114,114,114,114,114,114,597,597, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 152 */ 598,599,599,599,114,599,599,114,114,114,114,114,599,599,599,599, 598,598,598,598,114,598,598,598,114,598,598,598,598,598,598,598, 598,598,598,598,598,598,598,598,598,598,598,598,598,598,598,598, 598,598,598,598,114,114,114,114,599,599,599,114,114,114,114,599, 600,600,600,600,600,600,600,600,114,114,114,114,114,114,114,114, 601,601,601,601,601,601,601,601,601,114,114,114,114,114,114,114, 602,602,602,602,602,602,602,602,602,602,602,602,602,602,602,602, 602,602,602,602,602,602,602,602,602,602,602,602,602,603,603,604, /* block 153 */ 605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,605, 605,605,605,605,605,605,605,605,605,605,605,605,605,606,606,606, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 607,607,607,607,607,607,607,607,608,607,607,607,607,607,607,607, 607,607,607,607,607,607,607,607,607,607,607,607,607,607,607,607, 607,607,607,607,607,609,609,114,114,114,114,610,610,610,610,610, 611,611,611,611,611,611,611,114,114,114,114,114,114,114,114,114, /* block 154 */ 612,612,612,612,612,612,612,612,612,612,612,612,612,612,612,612, 612,612,612,612,612,612,612,612,612,612,612,612,612,612,612,612, 612,612,612,612,612,612,612,612,612,612,612,612,612,612,612,612, 612,612,612,612,612,612,114,114,114,613,613,613,613,613,613,613, 614,614,614,614,614,614,614,614,614,614,614,614,614,614,614,614, 614,614,614,614,614,614,114,114,615,615,615,615,615,615,615,615, 616,616,616,616,616,616,616,616,616,616,616,616,616,616,616,616, 616,616,616,114,114,114,114,114,617,617,617,617,617,617,617,617, /* block 155 */ 618,618,618,618,618,618,618,618,618,618,618,618,618,618,618,618, 618,618,114,114,114,114,114,114,114,619,619,619,619,114,114,114, 114,114,114,114,114,114,114,114,114,620,620,620,620,620,620,620, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 156 */ 621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,621, 621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,621, 621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,621, 621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,621, 621,621,621,621,621,621,621,621,621,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 157 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 622,622,622,622,622,622,622,622,622,622,622,622,622,622,622,622, 622,622,622,622,622,622,622,622,622,622,622,622,622,622,622,114, /* block 158 */ 623,624,623,625,625,625,625,625,625,625,625,625,625,625,625,625, 625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,625, 625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,625, 625,625,625,625,625,625,625,625,624,624,624,624,624,624,624,624, 624,624,624,624,624,624,624,626,626,626,626,626,626,626,114,114, 114,114,627,627,627,627,627,627,627,627,627,627,627,627,627,627, 627,627,627,627,627,627,628,628,628,628,628,628,628,628,628,628, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,624, /* block 159 */ 629,629,630,631,631,631,631,631,631,631,631,631,631,631,631,631, 631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631, 631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631, 630,630,630,629,629,629,629,630,630,629,629,632,632,633,632,632, 632,632,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 634,634,634,634,634,634,634,634,634,634,634,634,634,634,634,634, 634,634,634,634,634,634,634,634,634,114,114,114,114,114,114,114, 635,635,635,635,635,635,635,635,635,635,114,114,114,114,114,114, /* block 160 */ 636,636,636,637,637,637,637,637,637,637,637,637,637,637,637,637, 637,637,637,637,637,637,637,637,637,637,637,637,637,637,637,637, 637,637,637,637,637,637,637,636,636,636,636,636,638,636,636,636, 636,636,636,636,636,114,639,639,639,639,639,639,639,639,639,639, 640,640,640,640,114,114,114,114,114,114,114,114,114,114,114,114, 641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641, 641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641, 641,641,641,642,643,643,641,114,114,114,114,114,114,114,114,114, /* block 161 */ 644,644,645,646,646,646,646,646,646,646,646,646,646,646,646,646, 646,646,646,646,646,646,646,646,646,646,646,646,646,646,646,646, 646,646,646,646,646,646,646,646,646,646,646,646,646,646,646,646, 646,646,646,645,645,645,644,644,644,644,644,644,644,644,644,645, 645,646,646,646,646,647,647,647,647,114,114,114,114,647,114,114, 648,648,648,648,648,648,648,648,648,648,646,114,114,114,114,114, 114,649,649,649,649,649,649,649,649,649,649,649,649,649,649,649, 649,649,649,649,649,114,114,114,114,114,114,114,114,114,114,114, /* block 162 */ 650,650,650,650,650,650,650,650,650,650,650,650,650,650,650,650, 650,650,114,650,650,650,650,650,650,650,650,650,650,650,650,650, 650,650,650,650,650,650,650,650,650,650,650,650,651,651,651,652, 652,652,651,651,652,651,652,652,653,653,653,653,653,653,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 163 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 654,654,654,654,654,654,654,654,654,654,654,654,654,654,654,654, 654,654,654,654,654,654,654,654,654,654,654,654,654,654,654,654, 654,654,654,654,654,654,654,654,654,654,654,654,654,654,654,655, 656,656,656,655,655,655,655,655,655,655,655,114,114,114,114,114, 657,657,657,657,657,657,657,657,657,657,114,114,114,114,114,114, /* block 164 */ 114,658,659,659,114,660,660,660,660,660,660,660,660,114,114,660, 660,114,114,660,660,660,660,660,660,660,660,660,660,660,660,660, 660,660,660,660,660,660,660,660,660,114,660,660,660,660,660,660, 660,114,660,660,114,660,660,660,660,660,114,114,658,660,661,659, 658,659,659,659,659,114,114,659,659,114,114,659,659,659,114,114, 114,114,114,114,114,114,114,661,114,114,114,114,114,660,660,660, 660,660,659,659,114,114,658,658,658,658,658,658,658,114,114,114, 658,658,658,658,658,114,114,114,114,114,114,114,114,114,114,114, /* block 165 */ 662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662, 662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662, 662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662, 663,664,664,665,665,665,665,665,665,664,665,664,664,663,664,665, 665,664,665,665,662,662,666,662,114,114,114,114,114,114,114,114, 667,667,667,667,667,667,667,667,667,667,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 166 */ 668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668, 668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668, 668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,669, 670,670,671,671,671,671,114,114,670,670,670,670,671,671,670,671, 671,672,672,672,672,672,672,672,672,672,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 167 */ 673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673, 673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673, 673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673, 674,674,674,675,675,675,675,675,675,675,675,674,674,675,674,675, 675,676,676,676,673,114,114,114,114,114,114,114,114,114,114,114, 677,677,677,677,677,677,677,677,677,677,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 168 */ 678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678, 678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678, 678,678,678,678,678,678,678,678,678,678,678,679,680,679,680,680, 679,679,679,679,679,679,680,679,114,114,114,114,114,114,114,114, 681,681,681,681,681,681,681,681,681,681,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 169 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 682,682,682,682,682,682,682,682,682,682,682,682,682,682,682,682, 682,682,682,682,682,682,682,682,682,682,682,682,682,682,682,682, 683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683, 683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683, 684,684,684,684,684,684,684,684,684,684,685,685,685,685,685,685, 685,685,685,114,114,114,114,114,114,114,114,114,114,114,114,686, /* block 170 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687, 687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687, 687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687, 687,687,687,687,687,687,687,687,687,114,114,114,114,114,114,114, /* block 171 */ 688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688, 688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688, 688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688, 688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688, 688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688, 688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688, 688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688, 688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688, /* block 172 */ 688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688, 688,688,688,688,688,688,688,688,688,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 173 */ 689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689, 689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689, 689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689, 689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689, 689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689, 689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689, 689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,114, 690,690,690,690,690,114,114,114,114,114,114,114,114,114,114,114, /* block 174 */ 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, /* block 175 */ 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691, 691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 176 */ 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, /* block 177 */ 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497, 497,497,497,497,497,497,497,497,497,114,114,114,114,114,114,114, 692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,692, 692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,114, 693,693,693,693,693,693,693,693,693,693,114,114,114,114,694,694, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 178 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 695,695,695,695,695,695,695,695,695,695,695,695,695,695,695,695, 695,695,695,695,695,695,695,695,695,695,695,695,695,695,114,114, 696,696,696,696,696,697,114,114,114,114,114,114,114,114,114,114, /* block 179 */ 698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698, 698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698, 698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698, 699,699,699,699,699,699,699,700,700,700,700,700,701,701,701,701, 702,702,702,702,700,701,114,114,114,114,114,114,114,114,114,114, 703,703,703,703,703,703,703,703,703,703,114,704,704,704,704,704, 704,704,114,698,698,698,698,698,698,698,698,698,698,698,698,698, 698,698,698,698,698,698,698,698,114,114,114,114,114,698,698,698, /* block 180 */ 698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 181 */ 705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705, 705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705, 705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705, 705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705, 705,705,705,705,705,114,114,114,114,114,114,114,114,114,114,114, 705,706,706,706,706,706,706,706,706,706,706,706,706,706,706,706, 706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,706, 706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,114, /* block 182 */ 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,707, 707,707,707,708,708,708,708,708,708,708,708,708,708,708,708,708, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 183 */ 478,476,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 184 */ 709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709, 709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709, 709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709, 709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709, 709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709, 709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709, 709,709,709,709,709,709,709,709,709,709,709,114,114,114,114,114, 709,709,709,709,709,709,709,709,709,709,709,709,709,114,114,114, /* block 185 */ 709,709,709,709,709,709,709,709,709,114,114,114,114,114,114,114, 709,709,709,709,709,709,709,709,709,709,114,114,710,711,711,712, 22, 22, 22, 22,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 186 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114, /* block 187 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,713,405,109,109,109, 19, 19, 19,405,713,713, 713,713,713, 22, 22, 22, 22, 22, 22, 22, 22,109,109,109,109,109, /* block 188 */ 109,109,109, 19, 19,109,109,109,109,109,109,109, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,109,109,109,109, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 189 */ 559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559, 559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559, 559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559, 559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559, 559,559,714,714,714,559,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 190 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 191 */ 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,438,438, 438,438,438,438,438,114,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, /* block 192 */ 437,437,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,437,114,437,437, 114,114,437,114,114,437,437,114,114,437,437,437,437,114,437,437, 437,437,437,437,437,437,438,438,438,438,114,438,114,438,438,438, 438,438,438,438,114,438,438,438,438,438,438,438,438,438,438,438, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, /* block 193 */ 438,438,438,438,437,437,114,437,437,437,437,114,114,437,437,437, 437,437,437,437,437,114,437,437,437,437,437,437,437,114,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,437,437,114,437,437,437,437,114, 437,437,437,437,437,114,437,114,114,114,437,437,437,437,437,437, 437,114,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, /* block 194 */ 437,437,437,437,437,437,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, /* block 195 */ 438,438,438,438,438,438,438,438,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, /* block 196 */ 437,437,437,437,437,437,437,437,437,437,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,114,114,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 437, 8,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438, 8,438,438,438,438, 438,438,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437, 8,438,438,438,438, /* block 197 */ 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438, 8,438,438,438,438,438,438,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437, 8,438,438,438,438,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 8, 438,438,438,438,438,438,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 8, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, /* block 198 */ 438,438,438,438,438,438,438,438,438, 8,438,438,438,438,438,438, 437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 437,437,437,437,437,437,437,437,437, 8,438,438,438,438,438,438, 438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 438,438,438, 8,438,438,438,438,438,438,437,438,114,114, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, /* block 199 */ 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, /* block 200 */ 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715, 715,715,715,715,715,114,114,716,716,716,716,716,716,716,716,716, 717,717,717,717,717,717,717,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 201 */ 199,199,199,199,114,199,199,199,199,199,199,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, 114,199,199,114,199,114,114,199,114,199,199,199,199,199,199,199, 199,199,199,114,199,199,199,199,114,199,114,199,114,114,114,114, 114,114,199,114,114,114,114,199,114,199,114,199,114,199,199,199, 114,199,199,114,199,114,114,199,114,199,114,199,114,199,114,199, 114,199,199,114,199,114,114,199,199,199,199,114,199,199,199,199, 199,199,199,114,199,199,199,199,114,199,199,199,199,114,199,114, /* block 202 */ 199,199,199,199,199,199,199,199,199,199,114,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,114,114,114,114, 114,199,199,199,114,199,199,199,199,199,114,199,199,199,199,199, 199,199,199,199,199,199,199,199,199,199,199,199,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 194,194,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 203 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 204 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114, 114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114, /* block 205 */ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 206 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,718,718,718,718,718,718,718,718,718,718, 718,718,718,718,718,718,718,718,718,718,718,718,718,718,718,718, /* block 207 */ 719, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 208 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114, /* block 209 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114, 114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114, /* block 210 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114, /* block 211 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114, 19, 19, 19, 19, 19, /* block 212 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 213 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 214 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114, /* block 215 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114, /* block 216 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 217 */ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, /* block 218 */ 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 219 */ 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 220 */ 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,114,114,114,114,114,114,114,114,114,114,114, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, /* block 221 */ 484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484, 484,484,484,484,484,484,484,484,484,484,484,484,484,484,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, /* block 222 */ 436, 22,436,436,436,436,436,436,436,436,436,436,436,436,436,436, 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, /* block 223 */ 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, /* block 224 */ 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, /* block 225 */ 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, 436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436, /* block 226 */ 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552, 552,552,552,552,552,552,552,552,552,552,552,552,552,552,114,114, }; #if UCD_BLOCK_SIZE != 128 #error Please correct UCD_BLOCK_SIZE in pcre_internal.h #endif #endif /* SUPPORT_UCP */ #endif /* PCRE_INCLUDED */ tomcat-connectors-1.2.50-src/native/iis/README0000644000000000000020000000553714655113617017270 0ustar rootbinABOUT ----- This is the ISAPI redirector (IIS plug-in) that enables IIS to pass selected requests to Tomcat over the AJP protocol. REQUIREMENT ----------- To build the ISAPI redirector you will need to create the following build environment: - Git client - Mladen's Custom Microsoft Compiler Toolkit Compilation https://github.com/mturk/cmsc/releases/tag/v15.0.47 download cmsc-15.0_47-win7-x86_x64.zip and unzip in C: BUILDING -------- Obtain the source code: git clone https://github.com/apache/tomcat-connectors.git cd tomcat-connectors\native\iis Build isapi_redirector.dll: c:\cmsc-15.0_47\setenv.bat x86 nmake -f Makefile.vc open new cmd.exe c:\cmsc-15.0_47\setenv.bat x64 nmake -f Makefile.vc Tomcat isapi_redirect DLLs may then be found in tomcat-connectors\native\iis\[x86|x64]_RELEASE RELEASING --------- Construct the binary distributions set VER=1.2.50 mkdir tomcat-connectors-%VER%-windows-i386-iis copy ..\LICENSE tomcat-connectors-%VER%-windows-i386-iis\ copy ..\NOTICE tomcat-connectors-%VER%-windows-i386-iis\ copy README tomcat-connectors-%VER%-windows-i386-iis\ copy x86_RELEASE\isapi_redirect.dll tomcat-connectors-%VER%-windows-i386-iis\ mkdir tomcat-connectors-%VER%-windows-x86_64-iis copy ..\LICENSE tomcat-connectors-%VER%-windows-x86_64-iis\ copy ..\NOTICE tomcat-connectors-%VER%-windows-x86_64-iis\ copy README tomcat-connectors-%VER%-windows-x86_64-iis\ copy x64_RELEASE\isapi_redirect.dll tomcat-connectors-%VER%-windows-x86_64-iis\ mkdir tomcat-connectors-%VER%-windows-i386-symbols copy ..\LICENSE tomcat-connectors-%VER%-windows-i386-symbols copy ..\NOTICE tomcat-connectors-%VER%-windows-i386-symbols copy README tomcat-connectors-%VER%-windows-i386-symbols\ copy x86_RELEASE\isapi_redirect.pdb tomcat-connectors-%VER%-windows-i386-symbols\ mkdir tomcat-connectors-%VER%-windows-x86_64-symbols copy ..\LICENSE tomcat-connectors-%VER%-windows-x86_64-symbols copy ..\NOTICE tomcat-connectors-%VER%-windows-x86_64-symbols copy README tomcat-connectors-%VER%-windows-x86_64-symbols\ copy x64_RELEASE\isapi_redirect.pdb tomcat-connectors-%VER%-windows-x86_64-symbols\ SET JAVA_HOME=C:\Program Files\Java\jdk1.7.0_71 set PATH=%PATH%;%JAVA_HOME%\bin cd tomcat-connectors-%VER%-windows-i386-iis jar -cMf ..\tomcat-connectors-%VER%-windows-i386-iis.zip * cd ..\tomcat-connectors-%VER%-windows-x86_64-iis jar -cMf ..\tomcat-connectors-%VER%-windows-x86_64-iis.zip * cd ..\tomcat-connectors-%VER%-windows-i386-symbols jar -cMf ..\tomcat-connectors-%VER%-windows-i386-symbols.zip * cd ..\tomcat-connectors-%VER%-windows-x86_64-symbols jar -cMf ..\tomcat-connectors-%VER%-windows-x86_64-symbols.zip * The Windows binary distributions may then be found in C:\tomcat-jk-1.2.x\native\iis These need to be signed and hashed before uploading for the release vote. tomcat-connectors-1.2.50-src/native/iis/isapi_redirect.reg0000644000000000000020000000067614655113617022074 0ustar rootbinREGEDIT4 [HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0] "extension_uri"="/jakarta/isapi_redirect.dll" "log_file"="C:\\tomcat\\logs\\isapi_redirect.%Y-%m-%d.log" "log_level"="info" "worker_file"="C:\\tomcat\\conf\\workers.properties" "worker_mount_file"="C:\\tomcat\\conf\\uriworkermap.properties" "log_rotationtime"="86400" "strip_session"="false" "reject_unsafe"="false" "enable_chunked_encoding"="false" tomcat-connectors-1.2.50-src/native/README.txt0000644000000000000020000000332514655113617017313 0ustar rootbin Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. README for tomcat-connectors (mod_jk) ===================================== What is tomcat-connector? ------------------------- tomcat-connectors is a project that provides web server connectors for the Tomcat servlet engine. The supported web servers are the Apache HTTP Server 2.x and Microsoft IIS. The AJP protocol used by the connector is supported in all Tomcat versions starting with Tomcat 3.2. Some other back end servers also support the AJP protocol. Main features of the tomcat-connectors are fault tolerance, load balancing, dynamic configuration, flexibility and robustness. The project was based on the original mod_jk code and keeps maintaining it. Originally the project also provided the Java parts of the connectors used inside Tomcat. These parts have since then been moved directly into the Tomcat source. How do i build it? ------------------ Just take a look at BUILDING.txt Where are the docs? ------------------- In the docs directory. tomcat-connectors-1.2.50-src/native/Makefile.in0000644000000000000020000007120314655113623017657 0ustar rootbin# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/scripts/build/jk_common.m4 \ $(top_srcdir)/../support/os_apache.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/common/config.h CONFIG_CLEAN_FILES = apache-2.0/Makefile apache-2.0/Makefile.apxs \ common/Makefile common/list.mk common/jk_types.h CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir distdir-am dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/apache-2.0/Makefile.apxs.in \ $(top_srcdir)/apache-2.0/Makefile.in \ $(top_srcdir)/common/Makefile.in \ $(top_srcdir)/common/config.h.in \ $(top_srcdir)/common/jk_types.h.in \ $(top_srcdir)/common/list.mk.in \ $(top_srcdir)/scripts/build/unix/compile \ $(top_srcdir)/scripts/build/unix/config.guess \ $(top_srcdir)/scripts/build/unix/config.sub \ $(top_srcdir)/scripts/build/unix/install-sh \ $(top_srcdir)/scripts/build/unix/ltmain.sh \ $(top_srcdir)/scripts/build/unix/missing NEWS \ scripts/build/unix/compile scripts/build/unix/config.guess \ scripts/build/unix/config.sub scripts/build/unix/install-sh \ scripts/build/unix/ltmain.sh scripts/build/unix/missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ APACHE20_OEXT = @APACHE20_OEXT@ APACHE_CONFIG_VARS = @APACHE_CONFIG_VARS@ APACHE_DIR = @APACHE_DIR@ APXS = @APXS@ APXSCFLAGS = @APXSCFLAGS@ APXSCPPFLAGS = @APXSCPPFLAGS@ APXSLDFLAGS = @APXSLDFLAGS@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CP = @CP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_TYPE = @INSTALL_TYPE@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_JK_TYPE = @LIB_JK_TYPE@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR = @MKDIR@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TEST = @TEST@ VERSION = @VERSION@ WEBSERVER = @WEBSERVER@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ apache_include = @apache_include@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ int32_t_fmt = @int32_t_fmt@ int32_value = @int32_value@ int64_t_fmt = @int64_t_fmt@ int64_value = @int64_value@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pid_t_fmt = @pid_t_fmt@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pthread_t_fmt = @pthread_t_fmt@ pthread_t_value = @pthread_t_value@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ uint32_t_fmt = @uint32_t_fmt@ uint32_t_hex_fmt = @uint32_t_hex_fmt@ uint64_t_fmt = @uint64_t_fmt@ uint64_t_hex_fmt = @uint64_t_hex_fmt@ # # Tell automake what it should do AUTOMAKE_OPTIONS = foreign MAINTAINERCLEANFILES = config.cache config.status config.log \ config.nice Makefile.in configure common/config.h.in \ common/config.h aclocal.m4 SUBDIRS = @WEBSERVER@ all: all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): common/config.h: common/stamp-h1 @test -f $@ || rm -f common/stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) common/stamp-h1 common/stamp-h1: $(top_srcdir)/common/config.h.in $(top_builddir)/config.status @rm -f common/stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status common/config.h $(top_srcdir)/common/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f common/stamp-h1 touch $@ distclean-hdr: -rm -f common/config.h common/stamp-h1 apache-2.0/Makefile: $(top_builddir)/config.status $(top_srcdir)/apache-2.0/Makefile.in cd $(top_builddir) && $(SHELL) ./config.status $@ apache-2.0/Makefile.apxs: $(top_builddir)/config.status $(top_srcdir)/apache-2.0/Makefile.apxs.in cd $(top_builddir) && $(SHELL) ./config.status $@ common/Makefile: $(top_builddir)/config.status $(top_srcdir)/common/Makefile.in cd $(top_builddir) && $(SHELL) ./config.status $@ common/list.mk: $(top_builddir)/config.status $(top_srcdir)/common/list.mk.in cd $(top_builddir) && $(SHELL) ./config.status $@ common/jk_types.h: $(top_builddir)/config.status $(top_srcdir)/common/jk_types.h.in cd $(top_builddir) && $(SHELL) ./config.status $@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool cscope cscopelist-am ctags ctags-am dist \ dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ dist-xz dist-zip dist-zstd distcheck distclean \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am .PRECIOUS: Makefile all: target="all"; \ list='$(SUBDIRS)'; \ for i in $$list; do \ echo "Making $$target in $$i"; \ if test "$$i" != "."; then \ (cd $$i && $(MAKE) $$target) || exit 1; \ fi; \ done; apidocs: common/*.h ../../scandoc/scandoc.pl -i ../../scandoc/template.pl -p \ ./docs/api/ -dproject="mod_jk Library" common/*.h common/*.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tomcat-connectors-1.2.50-src/native/configure.ac0000644000000000000020000005176514655113617020116 0ustar rootbindnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl Process this file with autoconf to produce a configure script dnl dnl Minimum autoconf version AC_PREREQ(2.59) dnl package and version. dnl synchronization with common/jk_version.h ? AC_INIT([mod_jk], [1.2.50]) AC_CONFIG_SRCDIR([common/jk_worker.h]) AC_CONFIG_HEADER(common/config.h) AC_CONFIG_AUX_DIR(scripts/build/unix) AC_CANONICAL_SYSTEM AM_INIT_AUTOMAKE dnl dnl Include our own M4 macros dnl sinclude(scripts/build/jk_common.m4) dnl Generate ./config.nice for reproducing runs of configure dnl JK_CONFIG_NICE(config.nice) AC_PATH_PROG(TEST,test,$PATH)dnl AC_SUBST(TEST) AC_PATH_PROG(GREP,grep,$PATH)dnl AC_SUBST(GREP) AC_PATH_PROG(ECHO,echo,echo,$PATH)dnl AC_SUBST(ECHO) AC_PATH_PROG(SED,sed,$PATH)dnl AC_SUBST(SED) AC_PATH_PROG(CP,cp,$PATH)dnl AC_SUBST(CP) AC_PATH_PROG(MKDIR,mkdir,$PATH)dnl AC_SUBST(MKDIR) dnl Mark that we have generated config.h CFLAGS="${CFLAGS} -DHAVE_CONFIG_H" AC_SUBST(CFLAGS) configure_dir=`dirname $0` configure_dir=`cd $configure_dir; pwd` APACHE_CONFIG_VARS=$configure_dir/scripts/build/config_vars.mk WEBSERVER="" apache_dir="" apache_include="" APXS="apxs" AC_ARG_WITH(apxs, [[ --with-apxs[=FILE] Build shared Apache module. FILE is the optional pathname to the apxs tool; defaults to finding apxs in your PATH.]], [ case "${withval}" in y | yes | true) find_apxs=true ;; n | no | false) find_apxs= ;; *) find_apxs=${withval} ;; esac if ${TEST} ${find_apxs} ; then AC_MSG_RESULT([need to check for Perl first, apxs depends on it...]) AC_PATH_PROG(PERL,perl,$PATH)dnl if ${TEST} ${find_apxs} = true ; then AC_PATH_PROG(APXS,apxs,$PATH)dnl else APXS=${find_apxs} fi if ${TEST} -n "${APXS}" ; then dnl Seems that we have it, but have to check if it is OK first if ${TEST} ! -x "${APXS}" ; then AC_MSG_ERROR(Invalid location for apxs: '${APXS}') fi ${APXS} -q PREFIX >/dev/null 2>/dev/null || apxs_support=false if ${TEST} "${apxs_support}" = "false" ; then AC_MSG_RESULT(could not find ${APXS}) AC_MSG_ERROR(You must specify a valid --with-apxs path) fi dnl apache_dir and apache_include are also needed. apache_dir=`$APXS -q PREFIX` apache_include="-I`$APXS -q INCLUDEDIR`" dnl test apache version APA=`${GREP} STANDARD20 ${APXS}` if ${TEST} -z "$APA" ; then AC_MSG_ERROR(No Apache 2.x found) fi WEBSERVER="apache-2.0" APRINCLUDEDIR="" INCTEMP="`$APXS -q APR_INCLUDEDIR` `$APXS -q APU_INCLUDEDIR`" for INC in ${INCTEMP}; do APRINCLUDEDIR="${APRINCLUDEDIR} -I${INC}" done AC_MSG_RESULT([APRINCLUDEDIR is $APRINCLUDEDIR]) APXSCC="`$APXS -q CC`" APXSCFLAGS="`${APXS} -q CFLAGS` `${APXS} -q EXTRA_CFLAGS` -DHAVE_APR ${APRINCLUDEDIR}" APXSCPPFLAGS="`${APXS} -q EXTRA_CPPFLAGS`" APXSLDFLAGS="`$APXS -q LDFLAGS`" APACHE_CONFIG_VARS="`${APXS} -q exp_installbuilddir`/config_vars.mk" LIBTOOL=`$APXS -q LIBTOOL` AC_MSG_RESULT([building connector for \"$WEBSERVER\"]) if ${TEST} -z "${CC}" ; then CC="${APXSCC}" else if ${TEST} "${CC}" != "$APXSCC" ; then WARN_CC=1 fi fi AC_SUBST(APXS) fi fi ], [ AC_MSG_RESULT(no apxs given) ]) AC_SUBST(APACHE_CONFIG_VARS) AC_PROG_CC AC_PROG_LD SAVE_LIBTOOL="$LIBTOOL" dnl Not sure what it does, but the libtool manual seems to require this dnl It should use the native platform dlopen ( if available ) AC_LIBTOOL_DLOPEN dnl AM_PROG_LIBTOOL often causes problems. dnl I have solved them once using aclocal --acdir=/usr/local/share/aclocal/ AM_PROG_LIBTOOL if ${TEST} -n "${SAVE_LIBTOOL}" ; then LIBTOOL="$SAVE_LIBTOOL" fi AC_MSG_RESULT([LIBTOOL="$LIBTOOL"]) AC_SUBST(LIBTOOL) dnl ----------------------------- Checks for standard typedefs dnl Checks for integer size AC_CHECK_SIZEOF(char, 1) AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(long, 4) AC_CHECK_SIZEOF(short, 2) AC_CHECK_SIZEOF(long double, 12) AC_CHECK_SIZEOF(long long, 8) AC_CHECK_SIZEOF(longlong, 8) # Now we need to find what jk_uint32_t (sizeof == 4) will be. # The first match is our preference. if test "$ac_cv_sizeof_int" = "4"; then int32_t_fmt='#define JK_INT32_T_FMT "d"' uint32_t_fmt='#define JK_UINT32_T_FMT "u"' uint32_t_hex_fmt='#define JK_UINT32_T_HEX_FMT "x"' int32_value="int" elif test "$ac_cv_sizeof_long" = "4"; then int32_t_fmt='#define JK_INT32_T_FMT "ld"' uint32_t_fmt='#define JK_UINT32_T_FMT "lu"' uint32_t_hex_fmt='#define JK_UINT32_T_HEX_FMT "lx"' int32_value="long" else int32_t_fmt='#error could not detect a 32-bit integer type' uint32_t_fmt='#error could not detect a 32-bit integer type' uint32_t_hex_fmt='#error could not detect a 32-bit integer type' AC_ERROR([could not detect a 32-bit integer type]) fi # Now we need to find what jk_uint64_t (sizeof == 8) will be. # The first match is our preference. if test "$ac_cv_sizeof_int" = "8"; then int64_t_fmt='#define JK_INT64_T_FMT "d"' uint64_t_fmt='#define JK_UINT64_T_FMT "u"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "x"' int64_value="int" elif test "$ac_cv_sizeof_long" = "8"; then int64_t_fmt='#define JK_INT64_T_FMT "ld"' uint64_t_fmt='#define JK_UINT64_T_FMT "lu"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "lx"' int64_value="long" elif test "$ac_cv_sizeof_long_long" = "8"; then # Linux, Solaris, FreeBSD all support ll with printf. # BSD 4.4 originated 'q'. Solaris is more popular and # doesn't support 'q'. Solaris wins. Exceptions can # go to the OS-dependent section. int64_t_fmt='#define JK_INT64_T_FMT "lld"' uint64_t_fmt='#define JK_UINT64_T_FMT "llu"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "llx"' int64_value="long long" elif test "$ac_cv_sizeof_long_double" = "8"; then int64_t_fmt='#define JK_INT64_T_FMT "Ld"' uint64_t_fmt='#define JK_UINT64_T_FMT "Lu"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "Lx"' int64_value="long double" elif test "$ac_cv_sizeof_longlong" = "8"; then int64_t_fmt='#define JK_INT64_T_FMT "qd"' uint64_t_fmt='#define JK_UINT64_T_FMT "qu"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "qx"' int64_value="__int64" else int64_t_fmt='#error could not detect a 64-bit integer type' uint64_t_fmt='#error could not detect a 64-bit integer type' uint64_t_hex_fmt='#error could not detect a 64-bit integer type' AC_ERROR([could not detect a 64-bit integer type]) fi JK_CHECK_SIZEOF_EXTENDED([#include ], pid_t, 8) if test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_short"; then pid_t_fmt='#define JK_PID_T_FMT "hd"' elif test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_int"; then pid_t_fmt='#define JK_PID_T_FMT "d"' elif test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_long"; then pid_t_fmt='#define JK_PID_T_FMT "ld"' elif test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_long_long"; then pid_t_fmt='#define JK_PID_T_FMT JK_INT64_T_FMT' else pid_t_fmt='#error Can not determine the proper size for pid_t' fi JK_CHECK_SIZEOF_EXTENDED([#include ], pthread_t, 8) if test "$ac_cv_sizeof_pthread_t" = "$ac_cv_sizeof_short"; then pthread_t_fmt='#define JK_PTHREAD_T_FMT "hu"' pthread_t_value="short" elif test "$ac_cv_sizeof_pthread_t" = "$ac_cv_sizeof_int"; then pthread_t_fmt='#define JK_PTHREAD_T_FMT "u"' pthread_t_value="int" elif test "$ac_cv_sizeof_pthread_t" = "$ac_cv_sizeof_long"; then pthread_t_fmt='#define JK_PTHREAD_T_FMT "lu"' pthread_t_value="long" elif test "$ac_cv_sizeof_pthread_t" = "$ac_cv_sizeof_long_long"; then pthread_t_fmt='#define JK_PTHREAD_T_FMT "llu"' pthread_t_value="long long" else pthread_t_fmt='#error Can not determine the proper size for pthread_t' fi # Basically, we have tried to figure out the correct format strings # for pid_t which varies between platforms, but we don't always get # it right. If you find that we don't get it right for your platform, # you can override our decision below. case $host in *-solaris*) if test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_long"; then pid_t_fmt='#define JK_PID_T_FMT "ld"' fi ;; esac AC_SUBST(int32_value) AC_SUBST(int32_t_fmt) AC_SUBST(uint32_t_fmt) AC_SUBST(uint32_t_hex_fmt) AC_SUBST(int64_value) AC_SUBST(int64_t_fmt) AC_SUBST(uint64_t_fmt) AC_SUBST(uint64_t_hex_fmt) AC_SUBST(pid_t_fmt) AC_SUBST(pthread_t_fmt) AC_SUBST(pthread_t_value) dnl check for snprintf and vsnprintf. AC_CHECK_FUNC(snprintf, AC_DEFINE(HAVE_SNPRINTF,1,[Have snprintf()])) AC_CHECK_FUNC(vsnprintf, AC_DEFINE(HAVE_VSNPRINTF,1,[Have vsnprintf()])) dnl check for flock function. AC_CHECK_FUNC(flock, AC_DEFINE(HAVE_FLOCK,1,[Have flock()])) dnl check for -lsocket library AC_CHECK_LIB(socket, setsockopt, [LIBS="$LIBS -lsocket"]) dnl check for filio.h used on Solaris to define FIONREAD ioctl. AC_CHECK_HEADERS(sys/filio.h) AC_DEFUN([JK_CHECK_SETSOCKOPT], [ AC_MSG_CHECKING(whether to use $1 with setsockopt()) AC_TRY_RUN([ #include #include #include #include int main(void) { int s; struct timeval tv; tv.tv_sec = 3; tv.tv_usec = 0; #ifndef $1 exit(3); #else if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) exit(2); /* fails on Solaris 2.6,8,9,10 and some Linuxes because SO_RCVTIMEO|SO_SNDTIMEO are defined but not implemented */ if (setsockopt(s, SOL_SOCKET, $1, (const void *)&tv, sizeof(tv)) == -1) exit(1); exit(0); #endif } ] , [ AC_MSG_RESULT([yes]) AC_DEFINE(USE_$1, 1, [Define to use $1 with setsockopt()]) ] , [ AC_MSG_RESULT([no]) ] ) ])dnl dnl check for SO_RCVTIMEO and SO_SNDTIMEO JK_CHECK_SETSOCKOPT(SO_RCVTIMEO) JK_CHECK_SETSOCKOPT(SO_SNDTIMEO) AC_DEFUN([JK_CHECK_SOCKOPT], [ AC_MSG_CHECKING(whether to use $1 with socket()) AC_TRY_RUN([ #include #include #include #include int main(void) { int s; #ifndef $1 exit(3); #else if ((s = socket(AF_INET, SOCK_STREAM | $1, 0)) == -1) exit(2); exit(0); #endif } ] , [ AC_MSG_RESULT([yes]) AC_DEFINE(USE_$1, 1, [Define to use $1 with socket()]) ] , [ AC_MSG_RESULT([no]) ] ) ])dnl AC_ARG_ENABLE(sock-cloexec, [AS_HELP_STRING([--disable-sock-cloexec],[Disable use of SOCK_CLOEXEC. This ensures the built module can be used on systems that do not support SOCK_CLOEXEC])], [ case "${enableval}" in y | Y | YES | yes | TRUE | true ) dnl check for SOCK_CLOEXEC JK_CHECK_SOCKOPT(SOCK_CLOEXEC) ;; esac ], [ dnl check for SOCK_CLOEXEC JK_CHECK_SOCKOPT(SOCK_CLOEXEC) ]) dnl check for poll.h header AC_CHECK_HEADERS(poll.h) dnl check for poll function AC_CHECK_FUNC(poll, AC_DEFINE(HAVE_POLL,1,[Have poll()])) dnl check for netinet/in.h header AC_CHECK_HEADERS(netinet/in.h) dnl check for netdb.h header AC_CHECK_HEADERS(netdb.h) AC_DEFUN([JK_HAVE_IPV6], [ AC_MSG_CHECKING(for IPv6 with socket()) AC_TRY_RUN([ #include #include #include #include int main(void) { int s; if ((s = socket(AF_INET6, SOCK_STREAM, 0)) == -1) exit(2); exit(0); } ] , [ AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_AF_INET6, 1, [Define to 1 if you have IPv6 support]) ] , [ AC_MSG_RESULT([no]) ] ) ])dnl AC_DEFUN([JK_CHECK_SASTORAGE], [ AC_MSG_CHECKING(for struct sockaddr_storage) AC_TRY_RUN([ #include #include #include #include int main(void) { struct sockaddr_storage sa; exit(sizeof(sa) == 0); } ] , [ AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, [Define to 1 if you have struct sockaddr_storage]) ] , [ AC_MSG_RESULT([no]) ] ) ])dnl JK_HAVE_IPV6 JK_CHECK_SASTORAGE AC_CHECK_FUNC(getaddrinfo, AC_DEFINE(HAVE_GETADDRINFO,1,[Have getaddrinfo()])) AC_CHECK_FUNC(gethostbyname_r, AC_DEFINE(HAVE_GETHOSTBYNAME_R,1,[Have gethostbyname_r()])) AC_DEFUN([JK_CHECK_ATOMICS], [ AC_MSG_CHECKING(whether the compiler provides atomic builtins) AC_TRY_RUN([ int main() { unsigned long val = 1010; if (__sync_add_and_fetch(&val, 1010) != 2020 || val != 2020) return 1; if (__sync_sub_and_fetch(&val, 1010) != 1010 || val != 1010) return 1; return 0; } ] , [ AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_ATOMIC_BUILTINS, 1, [Define to 1 if the compiler provides atomic builtins]) ] , [ AC_MSG_RESULT([no]) ] ) ])dnl JK_CHECK_ATOMICS dnl Apache-2.0 needs the os subdirectory to include os.h dnl this include is copy from os/config.m4 sinclude(../support/os_apache.m4) dnl it is copied from the configure of JServ ;=) dnl and adapted. apache_dir_is_src="false" AC_ARG_WITH(apache, [AS_HELP_STRING([--with-apache=DIR], [Build static Apache module. DIR is the pathname to the Apache source directory.])], [ if ${TEST} ! -z "$WEBSERVER" ; then AC_MSG_ERROR([Sorry cannot use --with-apxs=${APXS} and --with-apache=${withval} together, please choose one of both]) fi AC_MSG_CHECKING([for Apache source directory (assume static build)]) if ${TEST} -n "${withval}" && ${TEST} -d "${withval}" ; then if ${TEST} -d "${withval}/src" ; then # handle the case where people use relative paths to # the apache source directory by pre-pending the current # build directory to the path. there are probably # errors with this if configure is run while in a # different directory than what you are in at the time if ${TEST} -n "`${ECHO} ${withval}|${GREP} \"^\.\.\"`" ; then withval=`pwd`/${withval} fi apache_dir=${withval} apache_dir_is_src="true" AC_MSG_RESULT(${apache_dir}) AC_MSG_CHECKING(for Apache include directory) if ${TEST} -d "${withval}/src/include" ; then # read osdir from the existing apache. osdir=`${GREP} '^OSDIR=' ${withval}/src/Makefile.config | ${SED} -e 's:^OSDIR=.*/os:os:'` if ${TEST} -z "${osdir}" ; then osdir=os/unix fi apache_include="-I${withval}/src/include \ -I${withval}/src/${osdir}" WEBSERVER="apache-1.3" LIB_JK_TYPE=mod_jk.a CFLAGS="${CFLAGS} -DJK_PREFORK" AC_MSG_RESULT([${apache_include}, version 1.3]) else AC_MSG_ERROR([Sorry Apache 1.2.x is no longer supported.]) fi else if ${TEST} -d "${withval}/include" ; then # osdir for Apache20. WEBSERVER="apache-2.0" apache_dir=${withval} apache_dir_is_src="true" LIB_JK_TYPE=lib_jk.la apache_include="-I${withval}/include -I${withval}/srclib/apr/include -I${withval}/os/${OS_APACHE_DIR} -I${withval}/srclib/apr-util/include" AC_MSG_RESULT(${apache_dir}) fi fi fi dnl Make sure we have a result. if ${TEST} -z "$WEBSERVER" ; then AC_MSG_ERROR([Directory $apache_dir is not a valid Apache source distribution]) fi # VT: Now, which one I'm supposed to use? Let's figure it out later configure_apache=true configure_src=true AC_MSG_RESULT([building connector for \"$WEBSERVER\"]) ], [ AC_MSG_RESULT(no apache given) ]) AC_SUBST(apache_include) APACHE_DIR=${apache_dir} AC_SUBST(APACHE_DIR) dnl CFLAGS for EAPI mod_ssl (Apache 1.3) dnl it also allows the CFLAGS environment variable. CFLAGS="${CFLAGS}" AC_ARG_ENABLE(EAPI, [AS_HELP_STRING([--enable-EAPI],[Enable EAPI support (mod_ssl, Apache 1.3)])], [ case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DEAPI" AC_MSG_RESULT([...Enabling EAPI Support...]) ;; esac ]) AC_SUBST(CFLAGS) dnl CFLAGS for maintainer mode dnl it also allows the CFLAGS environment variable. CFLAGS="${CFLAGS}" AC_ARG_ENABLE(maintainer-mode, [AS_HELP_STRING([--enable-maintainer-mode],[Turn on debugging and compile time warnings])], [ case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DDEBUG -Wall" AC_MSG_RESULT([...Enabling Maintainer mode...]) ;; esac ]) AC_SUBST(CFLAGS) dnl CFLAGS for prefork mode dnl it also allows the CFLAGS environment variable. CFLAGS="${CFLAGS}" AC_ARG_ENABLE(prefork, [AS_HELP_STRING([--enable-prefork],[Turn on prefork web server mode (single-threaded)])], [ case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DJK_PREFORK" AC_MSG_RESULT([...Enabling Prefork mode...]) ;; esac ]) AC_SUBST(CFLAGS) dnl CFLAGS for stripping TRACE logs dnl it also allows the CFLAGS environment variable. CFLAGS="${CFLAGS}" AC_ARG_ENABLE(trace, [AS_HELP_STRING([--disable-trace],[Exclude trace log code from compilation])], [ case "${enableval}" in no ) CFLAGS="${CFLAGS} -DJK_PRODUCTION" AC_MSG_RESULT([...Exclude trace log code...]) ;; esac ]) AC_SUBST(CFLAGS) dnl CFLAGS for building against recent httpd but without dnl using httpd API functions, which didn't exist in the first dnl production releases. This ensures, that the resulting dnl module binary is compatible with older httpd releases. dnl Until now only relevant for httpd 2.2.x with x >= 4. CFLAGS="${CFLAGS}" AC_ARG_ENABLE(api-compatibility, [AS_HELP_STRING([--enable-api-compatibility], [Only use httpd API functions available in all production releases. This improves binary compatibility of module builds with httpd releases older than the release against we build (only between minor versions).])], [ case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DAPI_COMPATIBILITY" AC_MSG_RESULT([...Only using compatible httpd API...]) ;; esac ]) AC_SUBST(CFLAGS) dnl CFLAGS for shared memory lock mode dnl it also allows the CFLAGS environment variable. CFLAGS="${CFLAGS}" AC_ARG_ENABLE(flock, [AS_HELP_STRING([--enable-flock],[Turn on flock for shared locking if present])], [ case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DJK_USE_FLOCK" AC_MSG_RESULT([...Enabling flock() shared memory locking...]) ;; esac ]) AC_SUBST(CFLAGS) dnl the APXSCFLAGS is given by apxs to the C compiler if ${TEST} -n "${CFLAGS}" ; then APXSCFLAGS="${APXSCFLAGS} ${CFLAGS}" fi AC_SUBST(APXSCFLAGS) AC_SUBST(APXSCPPFLAGS) dnl the APXSLDFLAGS is given to the linker (for APRVARS). if ${TEST} -n "${LDFLAGS}" ; then APXSLDFLAGS="${APXSLDFLAGS} ${LDFLAGS}" fi dnl Prefix all LDFLAGS with "-Wl,", dnl because we pass them to libtool JK_PREFIX_IF_MISSING(APXSLDFLAGS, [-Wl,]) AC_SUBST(APXSLDFLAGS) dnl Check that a WEBSERVER has been given if ${TEST} -z "$WEBSERVER" ; then AC_MSG_ERROR(Cannot find the WebServer) fi dnl Add common to subdir list WEBSERVER="common ${WEBSERVER}" AC_SUBST(WEBSERVER) AM_CONDITIONAL(MAKE_DYNAMIC_APACHE, ${TEST} "${apache_dir_is_src}" = "false") if ${TEST} "${apache_dir_is_src}" = "false" ; then dnl normal apxs handling APACHE20_OEXT=.c LIB_JK_TYPE=mod_jk.so INSTALL_TYPE=install_dynamic else dnl install static library in apache sources. APACHE20_OEXT=.lo INSTALL_TYPE=install_static fi AC_SUBST(APACHE20_OEXT) AC_SUBST(LIB_JK_TYPE) AC_SUBST(INSTALL_TYPE) dnl automake needs the path it does not work with $WEBSERVER dnl that why useless Makefiles are build. AC_OUTPUT([ Makefile apache-2.0/Makefile apache-2.0/Makefile.apxs common/Makefile common/list.mk common/jk_types.h ]) if ${TEST} -n "${WARN_CC}" ; then AC_MSG_WARN([===========================================]) AC_MSG_WARN([Using CC from environment:]) AC_MSG_WARN([ CC="$CC"]) AC_MSG_WARN([instead of CC from apxs:]) AC_MSG_WARN([ CC="$APXSCC"]) AC_MSG_WARN([If "make" throws an error of the form]) AC_MSG_WARN([ "libtool: compile: unable to infer tagged configuration"]) AC_MSG_WARN([ "libtool: compile: specify a tag with `--tag'"]) AC_MSG_WARN([try running configure without setting CC,]) AC_MSG_WARN([or at least CC should start with "$APXSCC"]) AC_MSG_WARN([===========================================]) fi tomcat-connectors-1.2.50-src/native/scripts/0000755000000000000020000000000014655113617017301 5ustar rootbintomcat-connectors-1.2.50-src/native/scripts/build/0000755000000000000020000000000014655113617020400 5ustar rootbintomcat-connectors-1.2.50-src/native/scripts/build/config_vars.mk0000644000000000000020000000157214655113617023236 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # libtool is given by Apache-2.0 when installed otherwise we provide it. LIBTOOL = $(SHELL) ../libtool tomcat-connectors-1.2.50-src/native/scripts/build/rules.mk0000644000000000000020000000222514655113617022064 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # That an extract of what is in APR. # # Compile commands #VPATH=.:../common COMPILE = $(CC) $(CFLAGS) LT_COMPILE = $(LIBTOOL) --mode=compile $(COMPILE) -c $< -o $@ # Implicit rules for creating outputs from input files .SUFFIXES: .SUFFIXES: .c .lo .o .slo .s .c.o: $(COMPILE) -c $< .s.o: $(COMPILE) -c $< .c.lo: $(LT_COMPILE) .s.lo: $(LT_COMPILE) .c.slo: $(SH_COMPILE) tomcat-connectors-1.2.50-src/native/scripts/build/instdso.sh0000755000000000000020000000534414655113617022430 0ustar rootbin#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # # instdso.sh - install Apache DSO modules # # we use this instead of libtool --install because: # 1) on a few platforms libtool doesn't install DSOs exactly like we'd # want (weird names, doesn't remove DSO first) # 2) we never want the .la files copied, so we might as well copy # the .so files ourselves if test "$#" != "3"; then echo "wrong number of arguments to instdso.sh" echo "Usage: instdso.sh SH_LIBTOOL-value dso-name path-to-modules" exit 1 fi SH_LIBTOOL=`echo $1 | sed -e 's/^SH_LIBTOOL=//'` DSOARCHIVE=$2 DSOARCHIVE_BASENAME=`basename $2` TARGETDIR=$3 DSOBASE=`echo $DSOARCHIVE_BASENAME | sed -e 's/\.la$//'` TARGET_NAME="$DSOBASE.so" SYS=`uname -s` if test "$SYS" = "AIX" then # on AIX, shared libraries remain in storage even when # all processes using them have exited; standard practice # prior to installing a shared library is to rm -f first CMD="rm -f $TARGETDIR/$TARGET_NAME" echo $CMD $CMD || exit $? fi CMD="$SH_LIBTOOL --mode=install cp $DSOARCHIVE $TARGETDIR/" echo $CMD $CMD || exit $? if test "$SYS" = "OS/2" then # on OS/2, aplibtool --install doesn't copy the .la files & we can't # rename DLLs to have a .so extension or they won't load so none of the # steps below make sense. exit 0 fi if test -s "$TARGETDIR/$DSOARCHIVE_BASENAME" then DLNAME=`sed -n "/^dlname=/{s/.*='\([^']*\)'/\1/;p;}" $TARGETDIR/$DSOARCHIVE_BASENAME` LIBRARY_NAMES=`sed -n "/^library_names/{s/library_names='\([^']*\)'/\1/;p;}" $TARGETDIR/$DSOARCHIVE_BASENAME` LIBRARY_NAMES=`echo $LIBRARY_NAMES | sed -e "s/ *$DLNAME//g"` fi if test -z "$DLNAME" then echo "Warning! dlname not found in $TARGETDIR/$DSOARCHIVE_BASENAME." echo "Assuming installing a .so rather than a libtool archive." exit 0 fi if test -n "$LIBRARY_NAMES" then for f in $LIBRARY_NAMES do rm -f $TARGETDIR/$f done fi if test "$DLNAME" != "$TARGET_NAME" then mv $TARGETDIR/$DLNAME $TARGETDIR/$TARGET_NAME fi exit 0 tomcat-connectors-1.2.50-src/native/scripts/build/unix/0000755000000000000020000000000014655113623021360 5ustar rootbintomcat-connectors-1.2.50-src/native/scripts/build/unix/ltmain.sh0000755000000000000020000117720314655113621023214 0ustar rootbin#! /bin/sh ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in ## by inline-source v2014-01-03.01 # libtool (GNU libtool) 2.4.6 # Provide generalized library-building support services. # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.6 Debian-2.4.6-15build2" package_revision=2.4.6 ## ------ ## ## Usage. ## ## ------ ## # Run './libtool --help' for help with using this script from the # command line. ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # After configure completes, it has a better idea of some of the # shell tools we need than the defaults used by the functions shared # with bootstrap, so set those here where they can still be over- # ridden by the user, but otherwise take precedence. : ${AUTOCONF="autoconf"} : ${AUTOMAKE="automake"} ## -------------------------- ## ## Source external libraries. ## ## -------------------------- ## # Much of our low-level functionality needs to be sourced from external # libraries, which are installed to $pkgauxdir. # Set a version string for this script. scriptversion=2015-01-20.17; # UTC # General shell script boiler plate, and helper functions. # Written by Gary V. Vaughan, 2004 # Copyright (C) 2004-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # 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. # As a special exception to the GNU General Public License, if you distribute # this file as part of a program or library that is built using GNU Libtool, # you may include this file under the same distribution terms that you use # for the rest of that program. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNES 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 . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # Evaluate this file near the top of your script to gain access to # the functions and variables defined here: # # . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh # # If you need to override any of the default environment variable # settings, do that before evaluating this file. ## -------------------- ## ## Shell normalisation. ## ## -------------------- ## # Some shells need a little help to be as Bourne compatible as possible. # Before doing anything else, make sure all that help has been provided! DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # NLS nuisances: We save the old values in case they are required later. _G_user_locale= _G_safe_locale= for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test set = \"\${$_G_var+set}\"; then save_$_G_var=\$$_G_var $_G_var=C export $_G_var _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" fi" done # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Make sure IFS has a sensible default sp=' ' nl=' ' IFS="$sp $nl" # There are apparently some retarded systems that use ';' as a PATH separator! if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi ## ------------------------- ## ## Locate command utilities. ## ## ------------------------- ## # func_executable_p FILE # ---------------------- # Check that FILE is an executable regular file. func_executable_p () { test -f "$1" && test -x "$1" } # func_path_progs PROGS_LIST CHECK_FUNC [PATH] # -------------------------------------------- # Search for either a program that responds to --version with output # containing "GNU", or else returned by CHECK_FUNC otherwise, by # trying all the directories in PATH with each of the elements of # PROGS_LIST. # # CHECK_FUNC should accept the path to a candidate program, and # set $func_check_prog_result if it truncates its output less than # $_G_path_prog_max characters. func_path_progs () { _G_progs_list=$1 _G_check_func=$2 _G_PATH=${3-"$PATH"} _G_path_prog_max=0 _G_path_prog_found=false _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} for _G_dir in $_G_PATH; do IFS=$_G_save_IFS test -z "$_G_dir" && _G_dir=. for _G_prog_name in $_G_progs_list; do for _exeext in '' .EXE; do _G_path_prog=$_G_dir/$_G_prog_name$_exeext func_executable_p "$_G_path_prog" || continue case `"$_G_path_prog" --version 2>&1` in *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; *) $_G_check_func $_G_path_prog func_path_progs_result=$func_check_prog_result ;; esac $_G_path_prog_found && break 3 done done done IFS=$_G_save_IFS test -z "$func_path_progs_result" && { echo "no acceptable sed could be found in \$PATH" >&2 exit 1 } } # We want to be able to use the functions in this file before configure # has figured out where the best binaries are kept, which means we have # to search for them ourselves - except when the results are already set # where we skip the searches. # Unless the user overrides by setting SED, search the path for either GNU # sed, or the sed that truncates its output the least. test -z "$SED" && { _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for _G_i in 1 2 3 4 5 6 7; do _G_sed_script=$_G_sed_script$nl$_G_sed_script done echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed _G_sed_script= func_check_prog_sed () { _G_path_prog=$1 _G_count=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo '' >> conftest.nl "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin rm -f conftest.sed SED=$func_path_progs_result } # Unless the user overrides by setting GREP, search the path for either GNU # grep, or the grep that truncates its output the least. test -z "$GREP" && { func_check_prog_grep () { _G_path_prog=$1 _G_count=0 _G_path_prog_max=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo 'GREP' >> conftest.nl "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin GREP=$func_path_progs_result } ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # All uppercase variable names are used for environment variables. These # variables can be overridden by the user before calling a script that # uses them if a suitable command of that name is not already available # in the command search PATH. : ${CP="cp -f"} : ${ECHO="printf %s\n"} : ${EGREP="$GREP -E"} : ${FGREP="$GREP -F"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} ## -------------------- ## ## Useful sed snippets. ## ## -------------------- ## sed_dirname='s|/[^/]*$||' sed_basename='s|^.*/||' # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s|\([`"$\\]\)|\\\1|g' # Same as above, but do not quote variable references. sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' # Sed substitution that converts a w32 file name or path # that contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-'\' parameter expansions in output of sed_double_quote_subst that # were '\'-ed in input to the same. If an odd number of '\' preceded a # '$' in input to sed_double_quote_subst, that '$' was protected from # expansion. Since each input '\' is now two '\'s, look for any number # of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. _G_bs='\\' _G_bs2='\\\\' _G_bs4='\\\\\\\\' _G_dollar='\$' sed_double_backslash="\ s/$_G_bs4/&\\ /g s/^$_G_bs2$_G_dollar/$_G_bs&/ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g s/\n//g" ## ----------------- ## ## Global variables. ## ## ----------------- ## # Except for the global variables explicitly listed below, the following # functions in the '^func_' namespace, and the '^require_' namespace # variables initialised in the 'Resource management' section, sourcing # this file will not pollute your global namespace with anything # else. There's no portable way to scope variables in Bourne shell # though, so actually running these functions will sometimes place # results into a variable named after the function, and often use # temporary variables in the '^_G_' namespace. If you are careful to # avoid using those namespaces casually in your sourcing script, things # should continue to work as you expect. And, of course, you can freely # overwrite any of the functions or variables defined here before # calling anything to customize them. EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. # Allow overriding, eg assuming that you follow the convention of # putting '$debug_cmd' at the start of all your functions, you can get # bash to show function call trace with: # # debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name debug_cmd=${debug_cmd-":"} exit_cmd=: # By convention, finish your script with: # # exit $exit_status # # so that you can set exit_status to non-zero if you want to indicate # something went wrong during execution without actually bailing out at # the point of failure. exit_status=$EXIT_SUCCESS # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath=$0 # The name of this program. progname=`$ECHO "$progpath" |$SED "$sed_basename"` # Make sure we have an absolute progpath for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` progdir=`cd "$progdir" && pwd` progpath=$progdir/$progname ;; *) _G_IFS=$IFS IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS=$_G_IFS test -x "$progdir/$progname" && break done IFS=$_G_IFS test -n "$progdir" || progdir=`pwd` progpath=$progdir/$progname ;; esac ## ----------------- ## ## Standard options. ## ## ----------------- ## # The following options affect the operation of the functions defined # below, and should be set appropriately depending on run-time para- # meters passed on the command line. opt_dry_run=false opt_quiet=false opt_verbose=false # Categories 'all' and 'none' are always available. Append any others # you will pass as the first argument to func_warning from your own # code. warning_categories= # By default, display warnings according to 'opt_warning_types'. Set # 'warning_func' to ':' to elide all warnings, or func_fatal_error to # treat the next displayed warning as a fatal error. warning_func=func_warn_and_continue # Set to 'all' to display all warnings, 'none' to suppress all # warnings, or a space delimited list of some subset of # 'warning_categories' to display only the listed warnings. opt_warning_types=all ## -------------------- ## ## Resource management. ## ## -------------------- ## # This section contains definitions for functions that each ensure a # particular resource (a file, or a non-empty configuration variable for # example) is available, and if appropriate to extract default values # from pertinent package files. Call them using their associated # 'require_*' variable to ensure that they are executed, at most, once. # # It's entirely deliberate that calling these functions can set # variables that don't obey the namespace limitations obeyed by the rest # of this file, in order that that they be as useful as possible to # callers. # require_term_colors # ------------------- # Allow display of bold text on terminals that support it. require_term_colors=func_require_term_colors func_require_term_colors () { $debug_cmd test -t 1 && { # COLORTERM and USE_ANSI_COLORS environment variables take # precedence, because most terminfo databases neglect to describe # whether color sequences are supported. test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} if test 1 = "$USE_ANSI_COLORS"; then # Standard ANSI escape sequences tc_reset='' tc_bold=''; tc_standout='' tc_red=''; tc_green='' tc_blue=''; tc_cyan='' else # Otherwise trust the terminfo database after all. test -n "`tput sgr0 2>/dev/null`" && { tc_reset=`tput sgr0` test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` tc_standout=$tc_bold test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` } fi } require_term_colors=: } ## ----------------- ## ## Function library. ## ## ----------------- ## # This section contains a variety of useful functions to call in your # scripts. Take note of the portable wrappers for features provided by # some modern shells, which will fall back to slower equivalents on # less featureful shells. # func_append VAR VALUE # --------------------- # Append VALUE onto the existing contents of VAR. # We should try to minimise forks, especially on Windows where they are # unreasonably slow, so skip the feature probes when bash or zsh are # being used: if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then : ${_G_HAVE_ARITH_OP="yes"} : ${_G_HAVE_XSI_OPS="yes"} # The += operator was introduced in bash 3.1 case $BASH_VERSION in [12].* | 3.0 | 3.0*) ;; *) : ${_G_HAVE_PLUSEQ_OP="yes"} ;; esac fi # _G_HAVE_PLUSEQ_OP # Can be empty, in which case the shell is probed, "yes" if += is # useable or anything else if it does not work. test -z "$_G_HAVE_PLUSEQ_OP" \ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ && _G_HAVE_PLUSEQ_OP=yes if test yes = "$_G_HAVE_PLUSEQ_OP" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_append () { $debug_cmd eval "$1+=\$2" }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_append () { $debug_cmd eval "$1=\$$1\$2" } fi # func_append_quoted VAR VALUE # ---------------------------- # Quote VALUE and append to the end of shell variable VAR, separated # by a space. if test yes = "$_G_HAVE_PLUSEQ_OP"; then eval 'func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1+=\\ \$func_quote_for_eval_result" }' else func_append_quoted () { $debug_cmd func_quote_for_eval "$2" eval "$1=\$$1\\ \$func_quote_for_eval_result" } fi # func_append_uniq VAR VALUE # -------------------------- # Append unique VALUE onto the existing contents of VAR, assuming # entries are delimited by the first character of VALUE. For example: # # func_append_uniq options " --another-option option-argument" # # will only append to $options if " --another-option option-argument " # is not already present somewhere in $options already (note spaces at # each end implied by leading space in second argument). func_append_uniq () { $debug_cmd eval _G_current_value='`$ECHO $'$1'`' _G_delim=`expr "$2" : '\(.\)'` case $_G_delim$_G_current_value$_G_delim in *"$2$_G_delim"*) ;; *) func_append "$@" ;; esac } # func_arith TERM... # ------------------ # Set func_arith_result to the result of evaluating TERMs. test -z "$_G_HAVE_ARITH_OP" \ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ && _G_HAVE_ARITH_OP=yes if test yes = "$_G_HAVE_ARITH_OP"; then eval 'func_arith () { $debug_cmd func_arith_result=$(( $* )) }' else func_arith () { $debug_cmd func_arith_result=`expr "$@"` } fi # func_basename FILE # ------------------ # Set func_basename_result to FILE with everything up to and including # the last / stripped. if test yes = "$_G_HAVE_XSI_OPS"; then # If this shell supports suffix pattern removal, then use it to avoid # forking. Hide the definitions single quotes in case the shell chokes # on unsupported syntax... _b='func_basename_result=${1##*/}' _d='case $1 in */*) func_dirname_result=${1%/*}$2 ;; * ) func_dirname_result=$3 ;; esac' else # ...otherwise fall back to using sed. _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` if test "X$func_dirname_result" = "X$1"; then func_dirname_result=$3 else func_append func_dirname_result "$2" fi' fi eval 'func_basename () { $debug_cmd '"$_b"' }' # func_dirname FILE APPEND NONDIR_REPLACEMENT # ------------------------------------------- # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. eval 'func_dirname () { $debug_cmd '"$_d"' }' # func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT # -------------------------------------------------------- # Perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # For efficiency, we do not delegate to the functions above but instead # duplicate the functionality here. eval 'func_dirname_and_basename () { $debug_cmd '"$_b"' '"$_d"' }' # func_echo ARG... # ---------------- # Echo program name prefixed message. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname: $_G_line" done IFS=$func_echo_IFS } # func_echo_all ARG... # -------------------- # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_echo_infix_1 INFIX ARG... # ------------------------------ # Echo program name, followed by INFIX on the first line, with any # additional lines not showing INFIX. func_echo_infix_1 () { $debug_cmd $require_term_colors _G_infix=$1; shift _G_indent=$_G_infix _G_prefix="$progname: $_G_infix: " _G_message=$* # Strip color escape sequences before counting printable length for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" do test -n "$_G_tc" && { _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` } done _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes func_echo_infix_1_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_infix_1_IFS $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 _G_prefix=$_G_indent done IFS=$func_echo_infix_1_IFS } # func_error ARG... # ----------------- # Echo program name prefixed message to standard error. func_error () { $debug_cmd $require_term_colors func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 } # func_fatal_error ARG... # ----------------------- # Echo program name prefixed message to standard error, and exit. func_fatal_error () { $debug_cmd func_error "$*" exit $EXIT_FAILURE } # func_grep EXPRESSION FILENAME # ----------------------------- # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $debug_cmd $GREP "$1" "$2" >/dev/null 2>&1 } # func_len STRING # --------------- # Set func_len_result to the length of STRING. STRING may not # start with a hyphen. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_len () { $debug_cmd func_len_result=${#1} }' else func_len () { $debug_cmd func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } fi # func_mkdir_p DIRECTORY-PATH # --------------------------- # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { $debug_cmd _G_directory_path=$1 _G_dir_list= if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then # Protect directory names starting with '-' case $_G_directory_path in -*) _G_directory_path=./$_G_directory_path ;; esac # While some portion of DIR does not yet exist... while test ! -d "$_G_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. _G_dir_list=$_G_directory_path:$_G_dir_list # If the last portion added has no slash in it, the list is done case $_G_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` done _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` func_mkdir_p_IFS=$IFS; IFS=: for _G_dir in $_G_dir_list; do IFS=$func_mkdir_p_IFS # mkdir can fail with a 'File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$_G_dir" 2>/dev/null || : done IFS=$func_mkdir_p_IFS # Bail out if we (or some other process) failed to create a directory. test -d "$_G_directory_path" || \ func_fatal_error "Failed to create '$1'" fi } # func_mktempdir [BASENAME] # ------------------------- # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, BASENAME is the basename for that directory. func_mktempdir () { $debug_cmd _G_template=${TMPDIR-/tmp}/${1-$progname} if test : = "$opt_dry_run"; then # Return a directory name, but don't create it in dry-run mode _G_tmpdir=$_G_template-$$ else # If mktemp works, use that first and foremost _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` if test ! -d "$_G_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race _G_tmpdir=$_G_template-${RANDOM-0}$$ func_mktempdir_umask=`umask` umask 0077 $MKDIR "$_G_tmpdir" umask $func_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$_G_tmpdir" || \ func_fatal_error "cannot create temporary directory '$_G_tmpdir'" fi $ECHO "$_G_tmpdir" } # func_normal_abspath PATH # ------------------------ # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. func_normal_abspath () { $debug_cmd # These SED scripts presuppose an absolute path with a trailing slash. _G_pathcar='s|^/\([^/]*\).*$|\1|' _G_pathcdr='s|^/[^/]*||' _G_removedotparts=':dotsl s|/\./|/|g t dotsl s|/\.$|/|' _G_collapseslashes='s|/\{1,\}|/|g' _G_finalslash='s|/*$|/|' # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` while :; do # Processed it all yet? if test / = "$func_normal_abspath_tpath"; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result"; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_notquiet ARG... # -------------------- # Echo program name prefixed message only when not in quiet mode. func_notquiet () { $debug_cmd $opt_quiet || func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_relative_path SRCDIR DSTDIR # -------------------------------- # Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. func_relative_path () { $debug_cmd func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=$func_dirname_result if test -z "$func_relative_path_tlibdir"; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test -n "$func_stripname_result"; then func_append func_relative_path_result "/$func_stripname_result" fi # Normalisation. If bindir is libdir, return '.' else relative path. if test -n "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result" func_relative_path_result=$func_stripname_result fi test -n "$func_relative_path_result" || func_relative_path_result=. : } # func_quote_for_eval ARG... # -------------------------- # Aesthetically quote ARGs to be evaled later. # This function returns two values: # i) func_quote_for_eval_result # double-quoted, suitable for a subsequent eval # ii) func_quote_for_eval_unquoted_result # has all characters that are still active within double # quotes backslashified. func_quote_for_eval () { $debug_cmd func_quote_for_eval_unquoted_result= func_quote_for_eval_result= while test 0 -lt $#; do case $1 in *[\\\`\"\$]*) _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; *) _G_unquoted_arg=$1 ;; esac if test -n "$func_quote_for_eval_unquoted_result"; then func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" else func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" fi case $_G_unquoted_arg in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and variable expansion # for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_quoted_arg=\"$_G_unquoted_arg\" ;; *) _G_quoted_arg=$_G_unquoted_arg ;; esac if test -n "$func_quote_for_eval_result"; then func_append func_quote_for_eval_result " $_G_quoted_arg" else func_append func_quote_for_eval_result "$_G_quoted_arg" fi shift done } # func_quote_for_expand ARG # ------------------------- # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { $debug_cmd case $1 in *[\\\`\"]*) _G_arg=`$ECHO "$1" | $SED \ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; *) _G_arg=$1 ;; esac case $_G_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") _G_arg=\"$_G_arg\" ;; esac func_quote_for_expand_result=$_G_arg } # func_stripname PREFIX SUFFIX NAME # --------------------------------- # strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_stripname () { $debug_cmd # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary variable first. func_stripname_result=$3 func_stripname_result=${func_stripname_result#"$1"} func_stripname_result=${func_stripname_result%"$2"} }' else func_stripname () { $debug_cmd case $2 in .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; esac } fi # func_show_eval CMD [FAIL_EXP] # ----------------------------- # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} func_quote_for_expand "$_G_cmd" eval "func_notquiet $func_quote_for_expand_result" $opt_dry_run || { eval "$_G_cmd" _G_status=$? if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_show_eval_locale CMD [FAIL_EXP] # ------------------------------------ # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} $opt_quiet || { func_quote_for_expand "$_G_cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || { eval "$_G_user_locale $_G_cmd" _G_status=$? eval "$_G_safe_locale" if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_tr_sh # ---------- # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { $debug_cmd case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_verbose ARG... # ------------------- # Echo program name prefixed message in verbose mode only. func_verbose () { $debug_cmd $opt_verbose && func_echo "$*" : } # func_warn_and_continue ARG... # ----------------------------- # Echo program name prefixed warning message to standard error. func_warn_and_continue () { $debug_cmd $require_term_colors func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 } # func_warning CATEGORY ARG... # ---------------------------- # Echo program name prefixed warning message to standard error. Warning # messages can be filtered according to CATEGORY, where this function # elides messages where CATEGORY is not listed in the global variable # 'opt_warning_types'. func_warning () { $debug_cmd # CATEGORY must be in the warning_categories list! case " $warning_categories " in *" $1 "*) ;; *) func_internal_error "invalid warning category '$1'" ;; esac _G_category=$1 shift case " $opt_warning_types " in *" $_G_category "*) $warning_func ${1+"$@"} ;; esac } # func_sort_ver VER1 VER2 # ----------------------- # 'sort -V' is not generally available. # Note this deviates from the version comparison in automake # in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a # but this should suffice as we won't be specifying old # version formats or redundant trailing .0 in bootstrap.conf. # If we did want full compatibility then we should probably # use m4_version_compare from autoconf. func_sort_ver () { $debug_cmd printf '%s\n%s\n' "$1" "$2" \ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n } # func_lt_ver PREV CURR # --------------------- # Return true if PREV and CURR are in the correct order according to # func_sort_ver, otherwise false. Use it like this: # # func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." func_lt_ver () { $debug_cmd test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: #! /bin/sh # Set a version string for this script. scriptversion=2015-10-07.11; # UTC # A portable, pluggable option parser for Bourne shell. # Written by Gary V. Vaughan, 2010 # Copyright (C) 2010-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # 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 . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # This file is a library for parsing options in your shell scripts along # with assorted other useful supporting features that you can make use # of too. # # For the simplest scripts you might need only: # # #!/bin/sh # . relative/path/to/funclib.sh # . relative/path/to/options-parser # scriptversion=1.0 # func_options ${1+"$@"} # eval set dummy "$func_options_result"; shift # ...rest of your script... # # In order for the '--version' option to work, you will need to have a # suitably formatted comment like the one at the top of this file # starting with '# Written by ' and ending with '# warranty; '. # # For '-h' and '--help' to work, you will also need a one line # description of your script's purpose in a comment directly above the # '# Written by ' line, like the one at the top of this file. # # The default options also support '--debug', which will turn on shell # execution tracing (see the comment above debug_cmd below for another # use), and '--verbose' and the func_verbose function to allow your script # to display verbose messages only when your user has specified # '--verbose'. # # After sourcing this file, you can plug processing for additional # options by amending the variables from the 'Configuration' section # below, and following the instructions in the 'Option parsing' # section further down. ## -------------- ## ## Configuration. ## ## -------------- ## # You should override these variables in your script after sourcing this # file so that they reflect the customisations you have added to the # option parser. # The usage line for option parsing errors and the start of '-h' and # '--help' output messages. You can embed shell variables for delayed # expansion at the time the message is displayed, but you will need to # quote other shell meta-characters carefully to prevent them being # expanded when the contents are evaled. usage='$progpath [OPTION]...' # Short help message in response to '-h' and '--help'. Add to this or # override it after sourcing this library to reflect the full set of # options your script accepts. usage_message="\ --debug enable verbose shell tracing -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -v, --verbose verbosely report processing --version print version information and exit -h, --help print short or long help message and exit " # Additional text appended to 'usage_message' in response to '--help'. long_help_message=" Warning categories include: 'all' show all warnings 'none' turn off all the warnings 'error' warnings are treated as fatal errors" # Help message printed before fatal option parsing errors. fatal_help="Try '\$progname --help' for more information." ## ------------------------- ## ## Hook function management. ## ## ------------------------- ## # This section contains functions for adding, removing, and running hooks # to the main code. A hook is just a named list of of function, that can # be run in order later on. # func_hookable FUNC_NAME # ----------------------- # Declare that FUNC_NAME will run hooks added with # 'func_add_hook FUNC_NAME ...'. func_hookable () { $debug_cmd func_append hookable_fns " $1" } # func_add_hook FUNC_NAME HOOK_FUNC # --------------------------------- # Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must # first have been declared "hookable" by a call to 'func_hookable'. func_add_hook () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not accept hook functions." ;; esac eval func_append ${1}_hooks '" $2"' } # func_remove_hook FUNC_NAME HOOK_FUNC # ------------------------------------ # Remove HOOK_FUNC from the list of functions called by FUNC_NAME. func_remove_hook () { $debug_cmd eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' } # func_run_hooks FUNC_NAME [ARG]... # --------------------------------- # Run all hook functions registered to FUNC_NAME. # It is assumed that the list of hook functions contains nothing more # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. func_run_hooks () { $debug_cmd _G_rc_run_hooks=false case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook funcions.n" ;; esac eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do if eval $_G_hook '"$@"'; then # store returned options list back into positional # parameters for next 'cmd' execution. eval _G_hook_result=\$${_G_hook}_result eval set dummy "$_G_hook_result"; shift _G_rc_run_hooks=: fi done $_G_rc_run_hooks && func_run_hooks_result=$_G_hook_result } ## --------------- ## ## Option parsing. ## ## --------------- ## # In order to add your own option parsing hooks, you must accept the # full positional parameter list in your hook function, you may remove/edit # any options that you action, and then pass back the remaining unprocessed # options in '_result', escaped suitably for # 'eval'. In this case you also must return $EXIT_SUCCESS to let the # hook's caller know that it should pay attention to # '_result'. Returning $EXIT_FAILURE signalizes that # arguments are left untouched by the hook and therefore caller will ignore the # result variable. # # Like this: # # my_options_prep () # { # $debug_cmd # # # Extend the existing usage message. # usage_message=$usage_message' # -s, --silent don'\''t print informational messages # ' # # No change in '$@' (ignored completely by this hook). There is # # no need to do the equivalent (but slower) action: # # func_quote_for_eval ${1+"$@"} # # my_options_prep_result=$func_quote_for_eval_result # false # } # func_add_hook func_options_prep my_options_prep # # # my_silent_option () # { # $debug_cmd # # args_changed=false # # # Note that for efficiency, we parse as many options as we can # # recognise in a loop before passing the remainder back to the # # caller on the first unrecognised argument we encounter. # while test $# -gt 0; do # opt=$1; shift # case $opt in # --silent|-s) opt_silent=: # args_changed=: # ;; # # Separate non-argument short options: # -s*) func_split_short_opt "$_G_opt" # set dummy "$func_split_short_opt_name" \ # "-$func_split_short_opt_arg" ${1+"$@"} # shift # args_changed=: # ;; # *) # Make sure the first unrecognised option "$_G_opt" # # is added back to "$@", we could need that later # # if $args_changed is true. # set dummy "$_G_opt" ${1+"$@"}; shift; break ;; # esac # done # # if $args_changed; then # func_quote_for_eval ${1+"$@"} # my_silent_option_result=$func_quote_for_eval_result # fi # # $args_changed # } # func_add_hook func_parse_options my_silent_option # # # my_option_validation () # { # $debug_cmd # # $opt_silent && $opt_verbose && func_fatal_help "\ # '--silent' and '--verbose' options are mutually exclusive." # # false # } # func_add_hook func_validate_options my_option_validation # # You'll also need to manually amend $usage_message to reflect the extra # options you parse. It's preferable to append if you can, so that # multiple option parsing hooks can be added safely. # func_options_finish [ARG]... # ---------------------------- # Finishing the option parse loop (call 'func_options' hooks ATM). func_options_finish () { $debug_cmd _G_func_options_finish_exit=false if func_run_hooks func_options ${1+"$@"}; then func_options_finish_result=$func_run_hooks_result _G_func_options_finish_exit=: fi $_G_func_options_finish_exit } # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the # individual implementations for details. func_hookable func_options func_options () { $debug_cmd _G_rc_options=false for my_func in options_prep parse_options validate_options options_finish do if eval func_$my_func '${1+"$@"}'; then eval _G_res_var='$'"func_${my_func}_result" eval set dummy "$_G_res_var" ; shift _G_rc_options=: fi done # Save modified positional parameters for caller. As a top-level # options-parser function we always need to set the 'func_options_result' # variable (regardless the $_G_rc_options value). if $_G_rc_options; then func_options_result=$_G_res_var else func_quote_for_eval ${1+"$@"} func_options_result=$func_quote_for_eval_result fi $_G_rc_options } # func_options_prep [ARG]... # -------------------------- # All initialisations required before starting the option parse loop. # Note that when calling hook functions, we pass through the list of # positional parameters. If a hook function modifies that list, and # needs to propagate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before # returning $EXIT_SUCCESS (otherwise $EXIT_FAILURE is returned). func_hookable func_options_prep func_options_prep () { $debug_cmd # Option defaults: opt_verbose=false opt_warning_types= _G_rc_options_prep=false if func_run_hooks func_options_prep ${1+"$@"}; then _G_rc_options_prep=: # save modified positional parameters for caller func_options_prep_result=$func_run_hooks_result fi $_G_rc_options_prep } # func_parse_options [ARG]... # --------------------------- # The main option parsing loop. func_hookable func_parse_options func_parse_options () { $debug_cmd func_parse_options_result= _G_rc_parse_options=false # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. if func_run_hooks func_parse_options ${1+"$@"}; then eval set dummy "$func_run_hooks_result"; shift _G_rc_parse_options=: fi # Break out of the loop if we already parsed every option. test $# -gt 0 || break _G_match_parse_options=: _G_opt=$1 shift case $_G_opt in --debug|-x) debug_cmd='set -x' func_echo "enabling shell trace mode" $debug_cmd ;; --no-warnings|--no-warning|--no-warn) set dummy --warnings none ${1+"$@"} shift ;; --warnings|--warning|-W) if test $# = 0 && func_missing_arg $_G_opt; then _G_rc_parse_options=: break fi case " $warning_categories $1" in *" $1 "*) # trailing space prevents matching last $1 above func_append_uniq opt_warning_types " $1" ;; *all) opt_warning_types=$warning_categories ;; *none) opt_warning_types=none warning_func=: ;; *error) opt_warning_types=$warning_categories warning_func=func_fatal_error ;; *) func_fatal_error \ "unsupported warning category: '$1'" ;; esac shift ;; --verbose|-v) opt_verbose=: ;; --version) func_version ;; -\?|-h) func_usage ;; --help) func_help ;; # Separate optargs to long options (plugins may need this): --*=*) func_split_equals "$_G_opt" set dummy "$func_split_equals_lhs" \ "$func_split_equals_rhs" ${1+"$@"} shift ;; # Separate optargs to short options: -W*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "$func_split_short_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-v*|-x*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) _G_rc_parse_options=: ; break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; *) set dummy "$_G_opt" ${1+"$@"}; shift _G_match_parse_options=false break ;; esac $_G_match_parse_options && _G_rc_parse_options=: done if $_G_rc_parse_options; then # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} func_parse_options_result=$func_quote_for_eval_result fi $_G_rc_parse_options } # func_validate_options [ARG]... # ------------------------------ # Perform any sanity checks on option settings and/or unconsumed # arguments. func_hookable func_validate_options func_validate_options () { $debug_cmd _G_rc_validate_options=false # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" if func_run_hooks func_validate_options ${1+"$@"}; then # save modified positional parameters for caller func_validate_options_result=$func_run_hooks_result _G_rc_validate_options=: fi # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE $_G_rc_validate_options } ## ----------------- ## ## Helper functions. ## ## ----------------- ## # This section contains the helper functions used by the rest of the # hookable option parser framework in ascii-betical order. # func_fatal_help ARG... # ---------------------- # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { $debug_cmd eval \$ECHO \""Usage: $usage"\" eval \$ECHO \""$fatal_help"\" func_error ${1+"$@"} exit $EXIT_FAILURE } # func_help # --------- # Echo long help message to standard output and exit. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message" exit 0 } # func_missing_arg ARGNAME # ------------------------ # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $debug_cmd func_error "Missing argument for '$1'." exit_cmd=exit } # func_split_equals STRING # ------------------------ # Set func_split_equals_lhs and func_split_equals_rhs shell variables after # splitting STRING at the '=' sign. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_equals () { $debug_cmd func_split_equals_lhs=${1%%=*} func_split_equals_rhs=${1#*=} test "x$func_split_equals_lhs" = "x$1" \ && func_split_equals_rhs= }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_equals () { $debug_cmd func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` func_split_equals_rhs= test "x$func_split_equals_lhs" = "x$1" \ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` } fi #func_split_equals # func_split_short_opt SHORTOPT # ----------------------------- # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_short_opt () { $debug_cmd func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"} }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_short_opt () { $debug_cmd func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` } fi #func_split_short_opt # func_usage # ---------- # Echo short help message to standard output and exit. func_usage () { $debug_cmd func_usage_message $ECHO "Run '$progname --help |${PAGER-more}' for full usage" exit 0 } # func_usage_message # ------------------ # Echo short help message to standard output. func_usage_message () { $debug_cmd eval \$ECHO \""Usage: $usage"\" echo $SED -n 's|^# || /^Written by/{ x;p;x } h /^Written by/q' < "$progpath" echo eval \$ECHO \""$usage_message"\" } # func_version # ------------ # Echo version message to standard output and exit. func_version () { $debug_cmd printf '%s\n' "$progname $scriptversion" $SED -n ' /(C)/!b go :more /\./!{ N s|\n# | | b more } :go /^# Written by /,/# warranty; / { s|^# || s|^# *$|| s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| p } /^# Written by / { s|^# || p } /^warranty; /q' < "$progpath" exit $? } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: # Set a version string. scriptversion='(GNU libtool) 2.4.6' # func_echo ARG... # ---------------- # Libtool also displays the current mode in messages, so override # funclib.sh func_echo with this custom definition. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" done IFS=$func_echo_IFS } # func_warning ARG... # ------------------- # Libtool warnings are not categorized, so override funclib.sh # func_warning with this simpler definition. func_warning () { $debug_cmd $warning_func ${1+"$@"} } ## ---------------- ## ## Options parsing. ## ## ---------------- ## # Hook in the functions to make sure our own options are parsed during # the option parsing loop. usage='$progpath [OPTION]... [MODE-ARG]...' # Short help message in response to '-h'. usage_message="Options: --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 --mode=MODE use operation mode MODE --no-warnings equivalent to '-Wnone' --preserve-dup-deps don't remove duplicate dependency libraries --quiet, --silent don't print informational messages --tag=TAG use configuration variables from tag TAG -v, --verbose print more informational messages than default --version print version information -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -h, --help, --help-all print short, long, or detailed help message " # Additional text appended to 'usage_message' in response to '--help'. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message 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. When passed as first option, '--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. Try '$progname --help --mode=MODE' for a more detailed description of MODE. When reporting a bug, please describe a test case to reproduce it and include the following information: host-triplet: $host shell: $SHELL compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) version: $progname $scriptversion Debian-2.4.6-15build2 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . GNU libtool home page: . General help using GNU software: ." exit 0 } # func_lo2o OBJECT-NAME # --------------------- # Transform OBJECT-NAME from a '.lo' suffix to the platform specific # object suffix. lo2o=s/\\.lo\$/.$objext/ o2lo=s/\\.$objext\$/.lo/ if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_lo2o () { case $1 in *.lo) func_lo2o_result=${1%.lo}.$objext ;; * ) func_lo2o_result=$1 ;; esac }' # func_xform LIBOBJ-OR-SOURCE # --------------------------- # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) # suffix to a '.lo' libtool-object suffix. eval 'func_xform () { func_xform_result=${1%.*}.lo }' else # ...otherwise fall back to using sed. func_lo2o () { func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` } func_xform () { func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` } fi # func_fatal_configuration ARG... # ------------------------------- # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func__fatal_error ${1+"$@"} \ "See the $PACKAGE documentation for more information." \ "Fatal configuration error." } # func_config # ----------- # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # ------------- # Display the features supported by this script. func_features () { echo "host: $host" if test yes = "$build_libtool_libs"; then echo "enable shared libraries" else echo "disable shared libraries" fi if test yes = "$build_old_libs"; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag TAGNAME # ----------------------- # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname=$1 re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf=/$re_begincf/,/$re_endcf/p # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # ------------------------ # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # libtool_options_prep [ARG]... # ----------------------------- # Preparation for options parsed by libtool. libtool_options_prep () { $debug_mode # Option defaults: opt_config=false opt_dlopen= opt_dry_run=false opt_help=false opt_mode= opt_preserve_dup_deps=false opt_quiet=false nonopt= preserve_args= _G_rc_lt_options_prep=: # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; *) _G_rc_lt_options_prep=false ;; esac if $_G_rc_lt_options_prep; then # Pass back the list of options. func_quote_for_eval ${1+"$@"} libtool_options_prep_result=$func_quote_for_eval_result fi $_G_rc_lt_options_prep } func_add_hook func_options_prep libtool_options_prep # libtool_parse_options [ARG]... # --------------------------------- # Provide handling for libtool specific options. libtool_parse_options () { $debug_cmd _G_rc_lt_parse_options=false # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do _G_match_lt_parse_options=: _G_opt=$1 shift case $_G_opt in --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) func_config ;; --dlopen|-dlopen) opt_dlopen="${opt_dlopen+$opt_dlopen }$1" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) func_features ;; --finish) set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $_G_opt && break opt_mode=$1 case $1 in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $_G_opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_quiet=false func_append preserve_args " $_G_opt" ;; --no-warnings|--no-warning|--no-warn) opt_warning=false func_append preserve_args " $_G_opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $_G_opt" ;; --silent|--quiet) opt_quiet=: opt_verbose=false func_append preserve_args " $_G_opt" ;; --tag) test $# = 0 && func_missing_arg $_G_opt && break opt_tag=$1 func_append preserve_args " $_G_opt $1" func_enable_tag "$1" shift ;; --verbose|-v) opt_quiet=false opt_verbose=: func_append preserve_args " $_G_opt" ;; # An option not handled by this hook function: *) set dummy "$_G_opt" ${1+"$@"} ; shift _G_match_lt_parse_options=false break ;; esac $_G_match_lt_parse_options && _G_rc_lt_parse_options=: done if $_G_rc_lt_parse_options; then # save modified positional parameters for caller func_quote_for_eval ${1+"$@"} libtool_parse_options_result=$func_quote_for_eval_result fi $_G_rc_lt_parse_options } func_add_hook func_parse_options libtool_parse_options # libtool_validate_options [ARG]... # --------------------------------- # Perform any sanity checks on option settings and/or unconsumed # arguments. libtool_validate_options () { # save first non-option argument if test 0 -lt $#; then nonopt=$1 shift fi # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" case $host in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match test yes != "$build_libtool_libs" \ && test yes != "$build_old_libs" \ && func_fatal_configuration "not configured to build any kind of library" # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test execute != "$opt_mode"; then func_error "unrecognized option '-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help=$help help="Try '$progname --help --mode=$opt_mode' for more information." } # Pass back the unparsed argument list func_quote_for_eval ${1+"$@"} libtool_validate_options_result=$func_quote_for_eval_result } func_add_hook func_validate_options libtool_validate_options # Process options as early as possible so that --help and --version # can return quickly. func_options ${1+"$@"} eval set dummy "$func_options_result"; shift ## ----------- ## ## Main. ## ## ----------- ## magic='%%%MAGIC variable%%%' magic_exe='%%%MAGIC EXE variable%%%' # Global variables. extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # func_generated_by_libtool # True iff stdin has been generated by Libtool. This function is only # a basic sanity check; it will hardly flush out determined imposters. func_generated_by_libtool_p () { $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p } # func_lalib_unsafe_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if 'file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case $lalib_p_line in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test yes = "$lalib_p" } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { test -f "$1" && $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $debug_cmd save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # 'FILE.' does not work on cygwin managed mounts. func_source () { $debug_cmd case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case $lt_sysroot:$1 in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result='='$func_stripname_result ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $debug_cmd if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with '--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=$1 if test yes = "$build_libtool_libs"; then write_lobj=\'$2\' else write_lobj=none fi if test yes = "$build_old_libs"; then write_oldobj=\'$3\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $debug_cmd # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result= if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result"; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $debug_cmd if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $debug_cmd # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $debug_cmd if test -z "$2" && test -n "$1"; then func_error "Could not determine host file name corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result=$1 fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $debug_cmd if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " '$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result=$3 fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $debug_cmd case $4 in $1 ) func_to_host_path_result=$3$func_to_host_path_result ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via '$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $debug_cmd $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $debug_cmd case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result=$1 } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result=$func_convert_core_msys_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result=$func_convert_core_file_wine_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via '$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $debug_cmd if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd=func_convert_path_$func_stripname_result fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $debug_cmd func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result=$1 } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_msys_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_path_wine_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_dll_def_p FILE # True iff FILE is a Windows DLL '.def' file. # Keep in sync with _LT_DLL_DEF_P in libtool.m4 func_dll_def_p () { $debug_cmd func_dll_def_p_tmp=`$SED -n \ -e 's/^[ ]*//' \ -e '/^\(;.*\)*$/d' \ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ -e q \ "$1"` test DEF = "$func_dll_def_p_tmp" } # func_mode_compile arg... func_mode_compile () { $debug_cmd # Get the compilation command and the source file. base_compile= srcfile=$nonopt # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg=$arg arg_mode=normal ;; target ) libobj=$arg arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify '-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs=$IFS; IFS=, for arg in $args; do IFS=$save_ifs func_append_quoted lastarg "$arg" done IFS=$save_ifs func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg=$srcfile srcfile=$arg ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with '-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj=$func_basename_result } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from '$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test yes = "$build_libtool_libs" \ || func_fatal_configuration "cannot build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name '$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname=$func_basename_result xdir=$func_dirname_result lobj=$xdir$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test yes = "$build_old_libs"; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; 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 no = "$compiler_c_o"; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext lockfile=$output_obj.lock else output_obj= 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 yes = "$need_locks"; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test warn = "$need_locks"; 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." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test yes = "$build_libtool_libs"; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test no != "$pic_mode"; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && 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." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test yes = "$suppress_opt"; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test yes = "$build_old_libs"; then if test yes != "$pic_mode"; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test yes = "$compiler_c_o"; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && 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." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test no != "$need_locks"; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test compile = "$opt_mode" && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [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: $progname [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 -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a '.o' file suitable for static linking -static only build a '.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler 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: $progname [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: $progname [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: $progname [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 following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [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 -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -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 -objectlist FILE use a list of object files found in FILE to specify objects -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) -precious-files-regex REGEX don't remove output files matching REGEX -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 -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) 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: $progname [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." ;; *) func_fatal_help "invalid operation mode '$opt_mode'" ;; esac echo $ECHO "Try '$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test : = "$opt_help"; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | $SED -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | $SED '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $debug_cmd # The first argument is the command name. cmd=$nonopt test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "'$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "'$file' was not linked with '-export-dynamic'" continue fi func_dirname "$file" "" "." dir=$func_dirname_result if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir=$func_dirname_result ;; *) func_warning "'-dlopen' is ignored for non-libtool libraries and objects" 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 -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file=$progdir/$program elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file=$progdir/$program fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if $opt_dry_run; then # 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 $EXIT_SUCCESS else if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd=\$cmd$args fi } test execute = "$opt_mode" && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $debug_cmd libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "'$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument '$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and '=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_quiet && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then 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" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test finish = "$opt_mode" && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $debug_cmd # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=false stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=: ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test X-m = "X$prev" && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the '$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=: if $isdir; then destdir=$dest destname= else func_dirname_and_basename "$dest" "" "." destdir=$func_dirname_result destname=$func_basename_result # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "'$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "'$destdir' must be an absolute directory name" ;; 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. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir=$func_dirname_result func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking '$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname=$1 shift srcname=$realname test -n "$relink_command" && srcname=${realname}T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme=$stripme case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme= ;; esac ;; os2*) case $realname in *_dll.a) tstripme= ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try 'ln -sf' first, because the 'ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib=$destdir/$realname func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name=$func_basename_result instname=$dir/${name}i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append 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 func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest=$destfile destfile= ;; *) func_fatal_help "cannot copy a libtool object to '$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test yes = "$build_old_libs"; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext= case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=.exe fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script '$wrapper'" finalize=: for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` if test -n "$libdir" && test ! -f "$libfile"; then func_warning "'$lib' has not been installed in '$libdir'" finalize=false fi done relink_command= func_source "$wrapper" outputname= if test no = "$fast_install" && test -n "$relink_command"; then $opt_dry_run || { if $finalize; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file=$func_basename_result outputname=$tmpdir/$file # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_quiet || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink '$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file=$outputname else func_warning "cannot relink '$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name=$func_basename_result # Set up the ranlib parameters. oldlib=$destdir/$name func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run '$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test install = "$opt_mode" && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $debug_cmd my_outputname=$1 my_originator=$2 my_pic_p=${3-false} my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms=${my_outputname}S.c else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist=$output_objdir/$my_outputname.nm func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* External symbol declarations for the compiler. */\ " if test yes = "$dlself"; then func_verbose "generating symbol list for '$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from '$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols=$output_objdir/$outputname.exp $opt_dry_run || { $RM $export_symbols eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from '$dlprefile'" func_basename "$dlprefile" name=$func_basename_result case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename= if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname"; then func_basename "$dlprefile_dlname" dlprefile_dlbasename=$func_basename_result else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename"; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # 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" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | 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/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi func_show_eval '$RM "${nlist}I"' if test -n "$global_symbol_to_import"; then eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[];\ " if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ static void lt_syminit(void) { LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; for (; symbol->name; ++symbol) {" $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" echo >> "$output_objdir/$my_dlsyms" "\ } }" fi echo >> "$output_objdir/$my_dlsyms" "\ LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = { {\"$my_originator\", (void *) 0}," if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ {\"@INIT@\", (void *) <_syminit}," fi case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) 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*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) $my_pic_p && pic_flag_for_symtable=" $pic_flag" ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for '$my_dlsyms'" ;; 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 "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $debug_cmd win32_libid_type=unknown win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then case $nm_interface in "MS dumpbin") if func_cygming_ms_implib_p "$1" || func_cygming_gnu_implib_p "$1" then win32_nmres=import else win32_nmres= fi ;; *) func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s|.*|import| p q } }'` ;; esac case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $debug_cmd sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $debug_cmd match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive that possess that section. Heuristic: eliminate # all those that have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $debug_cmd if func_cygming_gnu_implib_p "$1"; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1"; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result= fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $debug_cmd f_ex_an_ar_dir=$1; shift f_ex_an_ar_oldlib=$1 if test yes = "$lock_old_archive_extraction"; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test yes = "$lock_old_archive_extraction"; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $debug_cmd my_gentop=$1; shift my_oldlibs=${1+"$@"} my_oldobjs= my_xlib= my_xabs= my_xdir= for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib=$func_basename_result my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir=$my_gentop/$my_xlib_u func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` func_basename "$darwin_archive" darwin_base_archive=$func_basename_result darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches; do func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" cd "unfat-$$/$darwin_base_archive-$darwin_arch" func_extract_an_archive "`pwd`" "$darwin_base_archive" cd "$darwin_curdir" $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result=$my_oldobjs } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory where it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # 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. sed_quote_subst='$sed_quote_subst' # 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+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' 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 file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ that is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options that match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED '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 \"\$file\" | $SED '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 \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test yes = "$fast_install"; then $ECHO "\ 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 "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else \$ECHO \"\$relink_command_output\" >&2 $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 "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # 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 \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${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\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* declarations of non-ANSI functions */ #if defined __MINGW32__ # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined __CYGWIN__ # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined other_platform || defined ... */ #endif /* portability defines, excluding path handling macros */ #if defined _MSC_VER # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC #elif defined __MINGW32__ # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined __CYGWIN__ # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined other platforms ... */ #endif #if defined PATH_MAX # define LT_PATHMAX PATH_MAX #elif defined MAXPATHLEN # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ defined __OS2__ # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free (stale); stale = 0; } \ } while (0) #if defined LT_DEBUGWRAPPER static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; size_t tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined HAVE_DOS_BASED_FILE_SYSTEM if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined HAVE_DOS_BASED_FILE_SYSTEM } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = (size_t) (q - p); p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (STREQ (str, pat)) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else size_t len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { size_t orig_value_len = strlen (orig_value); size_t add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ size_t len = strlen (new_value); while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[--len] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $debug_cmd case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_suncc_cstd_abi # !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! # Several compiler flags select an ABI that is incompatible with the # Cstd library. Avoid specifying it if any are in CXXFLAGS. func_suncc_cstd_abi () { $debug_cmd case " $compile_command " in *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) suncc_use_cstd_abi=no ;; *) suncc_use_cstd_abi=yes ;; esac } # func_mode_link arg... func_mode_link () { $debug_cmd case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # what system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll that 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 base_compile="$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` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= os2dllname= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=false prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module=$wl-single_module func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test yes != "$build_libtool_libs" \ && func_fatal_configuration "cannot build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_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 func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir=$arg prev= continue ;; dlfiles|dlprefiles) $preload || { # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=: } case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test no = "$dlself"; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test dlprefiles = "$prev"; then dlself=yes elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test dlfiles = "$prev"; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols=$arg test -f "$arg" \ || func_fatal_error "symbol file '$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex=$arg prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir=$arg prev= continue ;; mllvm) # Clang does not use LLVM to link, so we can simply discard any # '-mllvm $arg' options when doing the link step. prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result if test none != "$pic_object"; then # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object fi # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file '$arg' does not exist" fi arg=$save_arg prev= continue ;; os2dllname) os2dllname=$arg prev= continue ;; precious_regex) precious_files_regex=$arg prev= continue ;; release) release=-$arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test rpath = "$prev"; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds=$arg prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append 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 # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "'-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir 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 func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test X-export-symbols = "X$arg"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix 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* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between '-L' and '$1'" else func_fatal_error "need path for '-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of '$dir'" dir=$absdir ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test X-lc = "X$arg" || test X-lm = "X$arg"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test X-lc = "X$arg" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test X-lc = "X$arg" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test X-lc = "X$arg" && continue ;; esac elif test X-lc_r = "X$arg"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -mllvm) prev=mllvm continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module=$wl-multi_module continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "'-no-install' is ignored for $host" func_warning "assuming '-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -os2dllname) prev=os2dllname continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # 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 ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # -fstack-protector* stack protector flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -specs=* GCC specs files # -stdlib=* select c++ std lib with clang # -fsanitize=* Clang/GCC memory and address sanitizer # -fuse-ld=* Linker select flags for GCC # -static-* direct GCC to link specific libraries statically # -fcilkplus Cilk Plus language extension features for C/C++ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; -Z*) if test os2 = "`expr $host : '.*\(os2\)'`"; then # OS/2 uses -Zxxx to specify OS/2-specific options compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case $arg in -Zlinker | -Zstack) prev=xcompiler ;; esac continue else # Otherwise treat like 'Some other compiler flag' below func_quote_for_eval "$arg" arg=$func_quote_for_eval_result fi ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result test none = "$pic_object" || { # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object } # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test dlfiles = "$prev"; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test dlprefiles = "$prev"; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" 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. func_quote_for_eval "$arg" arg=$func_quote_for_eval_result ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the '$prevarg' option requires an argument" if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname=$func_basename_result libobjs_save=$libobjs if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'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\" # Definition is injected by LT_CONFIG during libtool generation. func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" func_dirname "$output" "/" "" output_objdir=$func_dirname_result$objdir func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$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 if $opt_preserve_dup_deps; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test lib = "$linkmode"; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi 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 dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=false newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test lib,link = "$linkmode,$pass"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs=$tmp_deplibs fi if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass"; then libs=$deplibs deplibs= fi if test prog = "$linkmode"; then case $pass in dlopen) libs=$dlfiles ;; dlpreopen) libs=$dlprefiles ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test lib,dlpreopen = "$linkmode,$pass"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs=$dlprefiles fi if test dlopen = "$pass"; then # Collect dlpreopened libraries save_deplibs=$deplibs deplibs= fi for deplib in $libs; do lib= found=false case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test lib != "$linkmode" && test prog != "$linkmode"; then func_warning "'-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test lib = "$linkmode"; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib=$searchdir/lib$name$search_ext if test -f "$lib"; then if test .la = "$search_ext"; then found=: else found=false fi break 2 fi done done if $found; then # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll=$l done if test "X$ll" = "X$old_library"; then # only static version available found=false func_dirname "$lib" "" "." ladir=$func_dirname_result lib=$ladir/$old_library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi else # deplib doesn't seem to be a libtool library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi ;; # -l *.ltframework) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test conv = "$pass" && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi if test scan = "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "'-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test link = "$pass"; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=false case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=: fi ;; pass_all) valid_a_lib=: ;; esac if $valid_a_lib; then echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" else echo $ECHO "*** Warning: Trying to link with static lib archive $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" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." fi ;; esac continue ;; prog) if test link != "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test conv = "$pass"; then deplibs="$deplib $deplibs" elif test prog = "$linkmode"; then if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=: continue ;; esac # case $deplib $found || test -f "$lib" \ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "'$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir=$func_dirname_result dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass" || { test prog != "$linkmode" && test lib != "$linkmode"; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test conv = "$pass"; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for '$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test prog != "$linkmode" && test lib != "$linkmode"; then func_fatal_error "'$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test yes = "$prefer_static_libs" || test built,no = "$prefer_static_libs,$installed"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib=$l done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for '$lib'" fi # This library was specified with -dlopen. if test dlopen = "$pass"; then test -z "$libdir" \ && func_fatal_error "cannot -dlopen a convenience library: '$lib'" if test -z "$dlname" || test yes != "$dlopen_support" || test no = "$build_libtool_libs" then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append 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 func_warning "cannot determine absolute directory name of '$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir=$ladir fi ;; esac func_basename "$lib" laname=$func_basename_result # Find the relevant object directory and library name. if test yes = "$installed"; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library '$lib' was moved." dir=$ladir absdir=$abs_ladir libdir=$abs_ladir else dir=$lt_sysroot$libdir absdir=$lt_sysroot$libdir fi test yes = "$hardcode_automatic" && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir=$ladir absdir=$abs_ladir # Remove this search path later func_append notinst_path " $abs_ladir" else dir=$ladir/$objdir absdir=$abs_ladir/$objdir # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test dlpreopen = "$pass"; then if test -z "$libdir" && test prog = "$linkmode"; then func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" fi case $host in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test lib = "$linkmode"; then deplibs="$dir/$old_library $deplibs" elif test prog,link = "$linkmode,$pass"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test prog = "$linkmode" && test link != "$pass"; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=false if test no != "$link_all_deplibs" || test -z "$library_names" || test no = "$build_libtool_libs"; then linkalldeplibs=: fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if $linkalldeplibs; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test prog,link = "$linkmode,$pass"; then if test -n "$library_names" && { { test no = "$prefer_static_libs" || test built,yes = "$prefer_static_libs,$installed"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then # Make sure the rpath contains only unique directories. case $temp_rpath: in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # 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 "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if $alldeplibs && { test pass_all = "$deplibs_check_method" || { test yes = "$build_libtool_libs" && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test built = "$use_static_libs" && test yes = "$installed"; then use_static_libs=no fi if test -n "$library_names" && { test no = "$use_static_libs" || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc* | *os2*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test no = "$installed"; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule= for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule=$dlpremoduletest break fi done if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then echo if test prog = "$linkmode"; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test lib = "$linkmode" && test yes = "$hardcode_into_libs"; 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 "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname=$1 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* | mingw* | *cegcc* | *os2*) func_arith $current - $age major=$func_arith_result versuffix=-$major ;; esac eval soname=\"$soname_spec\" else soname=$realname fi # Make a new name for the extract_expsyms_cmds to use soroot=$soname func_basename "$soroot" soname=$func_basename_result func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from '$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for '$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' 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 prog = "$linkmode" || test relink != "$opt_mode"; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test no = "$hardcode_direct"; then add=$dir/$linklib case $host in *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; *-*-sysv4*uw2*) add_dir=-L$dir ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir=-L$dir ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we cannot # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library"; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add=$dir/$old_library fi elif test -n "$old_library"; then add=$dir/$old_library fi fi esac elif test no = "$hardcode_minus_L"; then case $host in *-*-sunos*) add_shlibpath=$dir ;; esac add_dir=-L$dir add=-l$name elif test no = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; relink) if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$dir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$absdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name elif test yes = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; *) lib_linked=no ;; esac if test yes != "$lib_linked"; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test prog = "$linkmode"; 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 yes != "$hardcode_direct" && test yes != "$hardcode_minus_L" && test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test prog = "$linkmode" || test relink = "$opt_mode"; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$libdir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$libdir add=-l$name elif test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add=-l$name elif test yes = "$hardcode_automatic"; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib"; then add=$inst_prefix_dir$libdir/$linklib else add=$libdir/$linklib fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir=-L$libdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name fi if test prog = "$linkmode"; 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 prog = "$linkmode"; then # 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 unsupported != "$hardcode_direct"; 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 yes = "$build_libtool_libs"; then # Not a shared library if test pass_all != "$deplibs_check_method"; 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 system cannot link to static lib archive $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 yes = "$module"; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." 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 no = "$build_old_libs"; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test lib = "$linkmode"; then if test -n "$dependency_libs" && { test yes != "$hardcode_into_libs" || test yes = "$build_old_libs" || test yes = "$link_static"; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs=$temp_deplibs fi func_append newlib_search_path " $absdir" # Link against this library test no = "$link_static" && 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 $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test no != "$link_all_deplibs"; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path=$deplib ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of '$dir'" absdir=$dir fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names"; then for tmp in $deplibrary_names; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl"; then depdepl=$absdir/$objdir/$depdepl darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" path= fi fi ;; *) path=-L$absdir/$objdir ;; esac else eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "'$deplib' seems to be moved" path=-L$absdir fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test link = "$pass"; then if test prog = "$linkmode"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs=$newdependency_libs if test dlpreopen = "$pass"; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test dlopen != "$pass"; then test conv = "$pass" || { # 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 "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= } if test prog,link = "$linkmode,$pass"; then vars="compile_deplibs finalize_deplibs" else vars=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 # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. 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 "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Add Sun CC postdeps if required: test CXX = "$tagname" && { case $host_os in linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; solaris*) func_cc_basename "$CC" case $func_cc_basename_result in CC* | sunCC*) func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; esac } # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i= ;; esac if test -n "$i"; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test prog = "$linkmode"; then dlfiles=$newdlfiles fi if test prog = "$linkmode" || test lib = "$linkmode"; then dlprefiles=$newdlprefiles fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "'-R' is ignored for archives" test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "'-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "'-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs=$output func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form 'libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test no = "$module" \ && func_fatal_help "libtool library '$output' must begin with 'lib'" if test no != "$need_lib_prefix"; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test pass_all != "$deplibs_check_method"; then func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test no = "$dlself" \ || func_warning "'-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test 1 -lt "$#" \ && func_warning "ignoring multiple '-rpath's for a libtool library" install_libdir=$1 oldlibs= if test -z "$rpath"; then if test yes = "$build_libtool_libs"; then # Building a libtool convenience library. # Some compilers have problems with a '.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "'-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs=$IFS; IFS=: set dummy $vinfo 0 0 0 shift IFS=$save_ifs test -n "$7" && \ func_fatal_help "too many parameters to '-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major=$1 number_minor=$2 number_revision=$3 # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # that has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|freebsd-elf|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_revision ;; freebsd-aout|qnx|sunos) current=$number_major revision=$number_minor age=0 ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_minor lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type '$version_type'" ;; esac ;; no) current=$1 revision=$2 age=$3 ;; esac # 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]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT '$current' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION '$revision' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE '$age' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE '$age' is greater than the current interface number '$current'" func_fatal_error "'$vinfo' is not valid version information" 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 func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" # On Darwin other compilers case $CC in nagfor*) verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" ;; *) verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; esac ;; freebsd-aout) major=.$current versuffix=.$current.$revision ;; freebsd-elf) func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; irix | nonstopux) if test no = "$lt_irix_increment"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring=$verstring_prefix$major.$revision # Add in all the interfaces that we are compatible with. loop=$revision while test 0 -ne "$loop"; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring_prefix$major.$iface:$verstring done # Before this point, $major must not contain '.'. major=.$major versuffix=$major.$revision ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=.$current.$age.$revision verstring=$current.$age.$revision # Add in all the interfaces that we are compatible with. loop=$age while test 0 -ne "$loop"; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring:$iface.0 done # Make executables depend on our current version. func_append verstring ":$current.0" ;; qnx) major=.$current versuffix=.$current ;; sco) major=.$current versuffix=.$current ;; sunos) major=.$current versuffix=.$current.$revision ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 file systems. func_arith $current - $age major=$func_arith_result versuffix=-$major ;; *) func_fatal_configuration "unknown library version type '$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring=0.0 ;; esac if test no = "$need_version"; then versuffix= else versuffix=.0.0 fi fi # Remove version info from name if versioning should be avoided if test yes,no = "$avoid_version,$need_version"; then major= versuffix= verstring= fi # Check to see if the archive will have undefined symbols. if test yes = "$allow_undefined"; then if test unsupported = "$allow_undefined_flag"; then if test yes = "$build_old_libs"; then func_warning "undefined symbols not allowed in $host shared libraries; building static only" build_libtool_libs=no else func_fatal_error "can't build $host shared library unless -no-undefined is specified" fi fi else # Don't allow undefined symbols. allow_undefined_flag=$no_undefined_flag fi fi func_generate_dlsyms "$libname" "$libname" : func_append libobjs " $symfileobj" test " " = "$libobjs" && libobjs= if test relink != "$opt_mode"; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) if test -n "$precious_files_regex"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "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 func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; 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 "*) ;; *) func_append 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 "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test yes = "$build_libtool_libs"; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test yes = "$build_libtool_need_lc"; then func_append 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 behavior. 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. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi 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 "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $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" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib= ;; esac fi if test -n "$a_deplib"; 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 potlib=$potent_lib # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $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" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs= tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test yes = "$allow_libtool_libs_with_static_runtimes"; then for i in $predeps $postdeps; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test none = "$deplibs_check_method"; 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 ;; esac ;; 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 with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test yes = "$droppeddeps"; then if test yes = "$module"; 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 no = "$build_old_libs"; 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 no = "$allow_undefined"; 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 no = "$build_old_libs"; 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 # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs=$new_libs # 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 yes = "$build_libtool_libs"; then # Remove $wl instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test yes = "$hardcode_into_libs"; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath=$finalize_rpath test relink = "$opt_mode" || rpath=$compile_rpath$rpath for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result 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"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append 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 func_append 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 relink = "$opt_mode" || 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 shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname=$1 shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname=$realname fi if test -z "$dlname"; then dlname=$soname fi lib=$output_objdir/$realname linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols=$output_objdir/$libname.uexp func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile func_dll_def_p "$export_symbols" || { # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols=$export_symbols export_symbols= always_export_symbols=yes } fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs=$IFS; IFS='~' for cmd1 in $cmds; do IFS=$save_ifs # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test yes = "$try_normal_branch" \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=$output_objdir/$output_la.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS=$save_ifs if test -n "$export_symbols_regex" && test : != "$skipped_export"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test : != "$skipped_export" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs=$tmp_deplibs if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test yes = "$compiler_needs_object" && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test : != "$skipped_export" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then output=$output_objdir/$output_la.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then output=$output_objdir/$output_la.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test yes = "$compiler_needs_object"; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-$k.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test -z "$objlist" || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test 1 -eq "$k"; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-$k.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-$k.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi ${skipped_export-false} && { func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi } test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs=$IFS; IFS='~' for cmd in $concat_cmds; do IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi ${skipped_export-false} && { if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi } libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs=$IFS; IFS='~' for cmd in $cmds; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs $opt_quiet || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs # Restore the uninstalled library and exit if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_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 yes = "$module" || test yes = "$export_dynamic"; then # On all known operating systems, these are identical. dlname=$soname fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "'-R' is ignored for objects" test -n "$vinfo" && \ func_warning "'-version-info' is ignored for objects" test -n "$release" && \ func_warning "'-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object '$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj=$output ;; esac # Delete the old objects. $opt_dry_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= # if reload_cmds runs $LD directly, get rid of -Wl from # whole_archive_flag_spec and hope we can get by with turning comma # into space. case $reload_cmds in *\$LD[\ \$]*) wl= ;; esac if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags else gentop=$output_objdir/${obj}x func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test yes = "$build_libtool_libs" || libobjs=$non_pic_objects # Create the old-style object. reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs output=$obj func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi test yes = "$build_libtool_libs" || { if test -n "$gentop"; then func_show_eval '${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" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS } if test -n "$pic_flag" || test default != "$pic_mode"; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output=$libobj func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "'-version-info' is ignored for programs" test -n "$release" && \ func_warning "'-release' is ignored for programs" $preload \ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test CXX = "$tagname"; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " $wl-bind_at_load" func_append finalize_command " $wl-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs=$new_libs func_append compile_command " $compile_deplibs" func_append 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 "*) ;; *) func_append 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"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; 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"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append 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 yes = "$build_old_libs"; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" false # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=: case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=false ;; *cygwin* | *mingw* ) test yes = "$build_libtool_libs" || wrappers_required=false ;; *) if test no = "$need_relink" || test yes != "$build_libtool_libs"; then wrappers_required=false fi ;; esac $wrappers_required || { # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command=$compile_command$compile_rpath # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.$objext"; then func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' fi exit $exit_status } 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 func_append 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 func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test yes = "$no_install"; 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 "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi case $hardcode_action,$fast_install in relink,*) # Fast installation is not supported link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath func_warning "this platform does not like uninstalled shared libraries" func_warning "'$output' will be relinked during installation" ;; *,yes) link_command=$finalize_var$compile_command$finalize_rpath relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` ;; *,no) link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath ;; *,needless) link_command=$finalize_var$compile_command$finalize_rpath relink_command= ;; esac # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "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}\" || $lt_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 func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource=$output_path/$objdir/lt-$output_name.c cwrapper=$output_path/$output_name.exe $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host"; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do case $build_libtool_libs in convenience) oldobjs="$libobjs_save $symfileobj" addlibs=$convenience build_libtool_libs=no ;; module) oldobjs=$libobjs_save addlibs=$old_convenience build_libtool_libs=no ;; *) oldobjs="$old_deplibs $non_pic_objects" $preload && test -f "$symfileobj" \ && func_append oldobjs " $symfileobj" addlibs=$old_convenience ;; esac if test -n "$addlibs"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase=$func_basename_result case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj"; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test -z "$oldobjs"; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test yes = "$build_old_libs" && old_library=$libname.$libext func_verbose "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}\" || $lt_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 func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test yes = "$hardcode_automatic"; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test yes = "$installed"; 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) func_basename "$deplib" name=$func_basename_result func_resolve_sysroot "$deplib" eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs=$newdependency_libs newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles=$newdlprefiles else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles=$newdlprefiles fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test -n "$bindir"; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result/$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # 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' # Linker flags that cannot go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test no,yes = "$installed,$need_relink"; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } if test link = "$opt_mode" || test relink = "$opt_mode"; then func_mode_link ${1+"$@"} fi # func_mode_uninstall arg... func_mode_uninstall () { $debug_cmd RM=$nonopt files= rmforce=false 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) func_append RM " $arg"; rmforce=: ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir=$func_dirname_result if test . = "$dir"; then odir=$objdir else odir=$dir/$objdir fi func_basename "$file" name=$func_basename_result test uninstall = "$opt_mode" && odir=$dir # Remember odir for removal later, being careful to avoid duplicates if test clean = "$opt_mode"; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; 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 $rmforce; then continue fi rmfiles=$file case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case $opt_mode in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test none != "$pic_object"; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test none != "$non_pic_object"; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test clean = "$opt_mode"; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.$objext" if test yes = "$fast_install" && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name"; then func_append rmfiles " $odir/lt-$noexename.c" fi fi fi ;; esac func_show_eval "$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 func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then func_mode_uninstall ${1+"$@"} fi test -z "$opt_mode" && { help=$generic_help func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode '$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # where we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: tomcat-connectors-1.2.50-src/native/scripts/build/unix/config.guess0000755000000000000020000014306714655113617023716 0ustar rootbin#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2024-07-27' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 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 . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still # use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c17 c99 c89 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #if defined(__ANDROID__) LIBC=android #else #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #elif defined(__LLVM_LIBC__) LIBC=llvm #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like '4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-pc-managarm-mlibc" ;; *:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __ARM_EABI__ #ifdef __ARM_PCS_VFP ABI=eabihf #else ABI=eabi #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; esac fi GUESS=$CPU-unknown-linux-$LIBCABI ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:cos:*:*) GUESS=$UNAME_MACHINE-unknown-cos ;; kvx:mbr:*:*) GUESS=$UNAME_MACHINE-unknown-mbr ;; loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; *:Ironclad:*:*) GUESS=$UNAME_MACHINE-unknown-ironclad ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif int main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: tomcat-connectors-1.2.50-src/native/scripts/build/unix/install-sh0000755000000000000020000003577614655113623023406 0ustar rootbin#!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: tomcat-connectors-1.2.50-src/native/scripts/build/unix/.gitignore0000644000000000000020000000004514655113617023352 0ustar rootbincompile install-sh ltmain.sh missing tomcat-connectors-1.2.50-src/native/scripts/build/unix/buildcheck.sh0000755000000000000020000000414314655113617024021 0ustar rootbin#! /bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. echo "buildconf: checking installation..." # autoconf 2.59 or newer ac_version=`${AUTOCONF:-autoconf} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[a-z]* *$//;q'` if test -z "$ac_version"; then echo "buildconf: autoconf not found." echo " You need autoconf version 2.59 or newer installed" echo " to build mod_jk from version control." exit 1 fi IFS=.; set $ac_version; IFS=' ' if test "$1" = "2" -a "$2" -lt "59" || test "$1" -lt "2"; then echo "buildconf: autoconf version $ac_version found." echo " You need autoconf version 2.59 or newer installed" echo " to build mod_jk from version control." exit 1 else echo "buildconf: autoconf version $ac_version (ok)" fi ac_version=`${LIBTOOL:-libtool} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[a-z]* *$//;s/(.*//;q'` if test -z "$ac_version"; then echo "buildconf: libtool not found." echo " You need libtool version 1.4 or newer installed" echo " to build mod_jk from version control." exit 1 fi IFS=.; set $ac_version; IFS=' ' if test "$1" = "1" -a "$2" -lt "4" || test "$1" -lt "1"; then echo "buildconf: libtool version $ac_version found." echo " You need libtool version 1.4 or newer installed" echo " to build mod_jk from version control." exit 1 else echo "buildconf: libtool version $ac_version (ok)" fi exit 0 tomcat-connectors-1.2.50-src/native/scripts/build/unix/config.sub0000755000000000000020000011544114655113617023354 0ustar rootbin#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale timestamp='2024-05-27' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 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 . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in cloudabi*-eabi* \ | kfreebsd*-gnu* \ | knetbsd*-gnu* \ | kopensolaris*-gnu* \ | linux-* \ | managarm-* \ | netbsd*-eabi* \ | netbsd*-gnu* \ | nto-qnx* \ | os2-emx* \ | rtmk-nova* \ | storm-chaos* \ | uclinux-gnu* \ | uclinux-uclibc* \ | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) case $field1-$field2 in # Shorthands that happen to contain a single dash convex-c[12] | convex-c3[248]) basic_machine=$field2-convex basic_os= ;; decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Do not treat sunos as a manufacturer sun*os*) basic_machine=$field1 basic_os=$field2 ;; # Manufacturers 3100* \ | 32* \ | 3300* \ | 3600* \ | 7300* \ | acorn \ | altos* \ | apollo \ | apple \ | atari \ | att* \ | axis \ | be \ | bull \ | cbm \ | ccur \ | cisco \ | commodore \ | convergent* \ | convex* \ | cray \ | crds \ | dec* \ | delta* \ | dg \ | digital \ | dolphin \ | encore* \ | gould \ | harris \ | highlevel \ | hitachi* \ | hp \ | ibm* \ | intergraph \ | isi* \ | knuth \ | masscomp \ | microblaze* \ | mips* \ | motorola* \ | ncr* \ | news \ | next \ | ns \ | oki \ | omron* \ | pc533* \ | rebel \ | rom68k \ | rombug \ | semi \ | sequent* \ | siemens \ | sgi* \ | siemens \ | sim \ | sni \ | sony* \ | stratus \ | sun \ | sun[234]* \ | tektronix \ | tti* \ | ultra \ | unicom* \ | wec \ | winbond \ | wrs) basic_machine=$field1-$field2 basic_os= ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300) cpu=m68k vendor=motorola ;; # This used to be dpx2*, but that gets the RS6000-based # DPX/20 and the x86-based DPX/2-100 wrong. See # https://oldskool.silicium.org/stations/bull_dpx20.htm # https://www.feb-patrimoine.com/english/bull_dpx2.htm # https://www.feb-patrimoine.com/english/unix_and_bull.htm dpx2 | dpx2[23]00 | dpx2[23]xx) cpu=m68k vendor=bull ;; dpx2100 | dpx21xx) cpu=i386 vendor=bull ;; dpx20) cpu=rs6000 vendor=bull ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x"$basic_os" != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. obj= case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) saved_IFS=$IFS IFS="-" read kernel os <&2 fi ;; *) echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 exit 1 ;; esac case $obj in aout* | coff* | elf* | pe*) ;; '') # empty is fine ;; *) echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 exit 1 ;; esac # Here we handle the constraint that a (synthetic) cpu and os are # valid only in combination with each other and nowhere else. case $cpu-$os in # The "javascript-unknown-ghcjs" triple is used by GHC; we # accept it here in order to tolerate that, but reject any # variations. javascript-ghcjs) ;; javascript-* | *-ghcjs) echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os-$obj in linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ | linux-mlibc*- | linux-musl*- | linux-newlib*- \ | linux-relibc*- | linux-uclibc*- | linux-ohos*- ) ;; uclinux-uclibc*- | uclinux-gnu*- ) ;; managarm-mlibc*- | managarm-kernel*- ) ;; windows*-msvc*-) ;; -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ | -uclibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; -kernel*- ) echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 exit 1 ;; *-kernel*- ) echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 exit 1 ;; *-msvc*- ) echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 exit 1 ;; kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-) ;; vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) ;; nto-qnx*-) ;; os2-emx-) ;; rtmk-nova-) ;; *-eabi*- | *-gnueabi*-) ;; none--*) # None (no kernel, i.e. freestanding / bare metal), # can be paired with an machine code file format ;; -*-) # Blank kernel with real OS is always fine. ;; --*) # Blank kernel and OS with real machine code file format is always fine. ;; *-*-*) echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos* | *-solaris*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: tomcat-connectors-1.2.50-src/native/scripts/build/unix/missing0000755000000000000020000001533614655113623022767 0ustar rootbin#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2021 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # 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. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: tomcat-connectors-1.2.50-src/native/scripts/build/unix/compile0000755000000000000020000001635014655113623022743 0ustar rootbin#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2021 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # 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. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: tomcat-connectors-1.2.50-src/native/scripts/build/jk_common.m40000644000000000000020000001032414655113617022616 0ustar rootbindnl -------------------------------------------------------- -*- autoconf -*- dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. dnl dnl jk_common.m4: JK's general-purpose autoconf macros dnl Mostly taken from APR. dnl dnl dnl JK_CHECK_SIZEOF_EXTENDED(INCLUDES, TYPE [, CROSS_SIZE]) dnl dnl A variant of AC_CHECK_SIZEOF which allows the checking of dnl sizes of non-builtin types dnl AC_DEFUN([JK_CHECK_SIZEOF_EXTENDED], [changequote(<<,>>)dnl dnl The name to #define define(<>, translit(sizeof_$2, [a-z *], [A-Z_P]))dnl dnl The cache variable define(<>, translit(ac_cv_sizeof_$2, [ *],[

]))dnl changequote([, ])dnl AC_MSG_CHECKING(size of $2) AC_CACHE_VAL(AC_CV_NAME, [AC_TRY_RUN([#include #include $1 int main() { FILE *f=fopen("conftestval","w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof($2)); exit(0); }], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, ifelse([$3],,, AC_CV_NAME=$3))])dnl AC_MSG_RESULT($AC_CV_NAME) AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The size of ]$2) undefine([AC_TYPE_NAME])dnl undefine([AC_CV_NAME])dnl ]) dnl dnl JK_PREFIX_IF_MISSING(variable, prefix) dnl dnl Prefix all tokens in a variable with "prefix" unless dnl it is already there. dnl AC_DEFUN([JK_PREFIX_IF_MISSING], [ jk_new_val="" jk_val_changed=0 for i in $$1; do case $i in $2*) jk_new_val="$jk_new_val $i" ;; *) jk_new_val="$jk_new_val $2$i" jk_val_changed=1 ;; esac done if test $jk_val_changed = "1"; then AC_MSG_NOTICE(tokens in $1 have been prefixed with '[$2]') $1=$jk_new_val fi ]) dnl dnl Iteratively interpolate the contents of the second argument dnl until interpolation offers no new result. Then assign the dnl final result to $1. dnl dnl Example: dnl dnl foo=1 dnl bar='${foo}/2' dnl baz='${bar}/3' dnl JK_EXPAND_VAR(fraz, $baz) dnl $fraz is now "1/2/3" dnl AC_DEFUN([JK_EXPAND_VAR], [ jk_last= jk_cur="$2" while test "x${jk_cur}" != "x${jk_last}"; do jk_last="${jk_cur}" jk_cur=`eval "echo ${jk_cur}"` done $1="${jk_cur}" ]) dnl dnl JK_CONFIG_NICE(filename) dnl dnl Saves a snapshot of the configure command-line for later reuse dnl AC_DEFUN([JK_CONFIG_NICE], [ rm -f $1 cat >$1<> $1 fi if test -n "$CFLAGS"; then echo "CFLAGS=\"$CFLAGS\"; export CFLAGS" >> $1 fi if test -n "$CPPFLAGS"; then echo "CPPFLAGS=\"$CPPFLAGS\"; export CPPFLAGS" >> $1 fi if test -n "$LDFLAGS"; then echo "LDFLAGS=\"$LDFLAGS\"; export LDFLAGS" >> $1 fi if test -n "$LTFLAGS"; then echo "LTFLAGS=\"$LTFLAGS\"; export LTFLAGS" >> $1 fi if test -n "$LIBS"; then echo "LIBS=\"$LIBS\"; export LIBS" >> $1 fi if test -n "$INCLUDES"; then echo "INCLUDES=\"$INCLUDES\"; export INCLUDES" >> $1 fi if test -n "$NOTEST_CFLAGS"; then echo "NOTEST_CFLAGS=\"$NOTEST_CFLAGS\"; export NOTEST_CFLAGS" >> $1 fi if test -n "$NOTEST_CPPFLAGS"; then echo "NOTEST_CPPFLAGS=\"$NOTEST_CPPFLAGS\"; export NOTEST_CPPFLAGS" >> $1 fi if test -n "$NOTEST_LDFLAGS"; then echo "NOTEST_LDFLAGS=\"$NOTEST_LDFLAGS\"; export NOTEST_LDFLAGS" >> $1 fi if test -n "$NOTEST_LIBS"; then echo "NOTEST_LIBS=\"$NOTEST_LIBS\"; export NOTEST_LIBS" >> $1 fi # Retrieve command-line arguments. eval "set x $[0] $ac_configure_args" shift for arg do JK_EXPAND_VAR(arg, $arg) echo "\"[$]arg\" \\" >> $1 done echo '"[$]@"' >> $1 chmod +x $1 ])dnl tomcat-connectors-1.2.50-src/native/.gitignore0000644000000000000020000000020414655113617017576 0ustar rootbinMakefile Makefile.in aclocal.m4 configure config.log config.cache libtool config.status build.properties config.nice autom4te.cache tomcat-connectors-1.2.50-src/native/common/0000755000000000000020000000000014655113623017077 5ustar rootbintomcat-connectors-1.2.50-src/native/common/jk_sockbuf.c0000644000000000000020000001203314655113617021365 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Simple buffer object to handle buffered socket IO * * Author: Gal Shachor * ***************************************************************************/ #include "jk_global.h" #include "jk_sockbuf.h" static int fill_buffer(jk_sockbuf_t *sb); int jk_sb_open(jk_sockbuf_t *sb, jk_sock_t sd) { if (sb && sd >= 0) { sb->end = 0; sb->start = 0; sb->sd = sd; return JK_TRUE; } return JK_FALSE; } int jk_sb_write(jk_sockbuf_t *sb, const void *buf, unsigned sz) { if (sb && buf && sz) { if ((SOCKBUF_SIZE - sb->end) >= sz) { memcpy(sb->buf + sb->end, buf, sz); sb->end += sz; } else { if (!jk_sb_flush(sb)) { return JK_FALSE; } if (sz > SOCKBUF_SIZE) { return (send(sb->sd, (char *)buf, sz, 0) == (int)sz); } memcpy(sb->buf + sb->end, buf, sz); sb->end += sz; } return JK_TRUE; } return JK_FALSE; } int jk_sb_flush(jk_sockbuf_t *sb) { if (sb) { int save_out = sb->end; sb->end = sb->start = 0; if (save_out) { return send(sb->sd, sb->buf, save_out, 0) == save_out; } return JK_TRUE; } return JK_FALSE; } int jk_sb_read(jk_sockbuf_t *sb, char **buf, unsigned sz, unsigned *ac) { if (sb && buf && ac) { unsigned avail; *ac = 0; *buf = NULL; if (sb->end == sb->start) { sb->end = sb->start = 0; if (fill_buffer(sb) < 0) { return JK_FALSE; } } *buf = sb->buf + sb->start; avail = sb->end - sb->start; if (avail > sz) { *ac = sz; } else { *ac = avail; } sb->start += *ac; return JK_TRUE; } return JK_FALSE; } int jk_sb_gets(jk_sockbuf_t *sb, char **ps) { int ret; if (sb) { while (1) { unsigned i; for (i = sb->start; i < sb->end; i++) { if (JK_LF == sb->buf[i]) { if (i > sb->start && JK_CR == sb->buf[i - 1]) { sb->buf[i - 1] = '\0'; } else { sb->buf[i] = '\0'; } *ps = sb->buf + sb->start; sb->start = (i + 1); return JK_TRUE; } } if ((ret = fill_buffer(sb)) < 0) { return JK_FALSE; } else if (ret == 0) { *ps = sb->buf + sb->start; if ((SOCKBUF_SIZE - sb->end) > 0) { sb->buf[sb->end] = '\0'; } else { sb->buf[sb->end - 1] = '\0'; } return JK_TRUE; } } } return JK_FALSE; } /* * Read data from the socket into the associated buffer, and update the * start and end indices. May move the data currently in the buffer. If * new data is read into the buffer (or if it is already full), returns 1. * If EOF is received on the socket, returns 0. In case of error returns * -1. */ static int fill_buffer(jk_sockbuf_t *sb) { int ret; /* * First move the current data to the beginning of the buffer */ if (sb->start < sb->end) { if (sb->start > 0) { unsigned to_copy = sb->end - sb->start; memmove(sb->buf, sb->buf + sb->start, to_copy); sb->start = 0; sb->end = to_copy; } } else { sb->start = sb->end = 0; } /* * In the unlikely case where the buffer is already full, we won't be * reading anything and we'd be calling recv with a 0 count. */ if ((SOCKBUF_SIZE - sb->end) > 0) { /* * Now, read more data */ ret = recv(sb->sd, sb->buf + sb->end, SOCKBUF_SIZE - sb->end, 0); /* 0 is EOF/SHUTDOWN, -1 is SOCK_ERROR */ if (ret <= 0) { return ret; } sb->end += ret; } return 1; } tomcat-connectors-1.2.50-src/native/common/jk_status.h0000644000000000000020000000314614655113617021266 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Status worker header file * * Author: Mladen Turk * ***************************************************************************/ #ifndef JK_STATUS_H #define JK_STATUS_H #include "jk_logger.h" #include "jk_service.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define JK_STATUS_WORKER_NAME ("status") #define JK_STATUS_WORKER_TYPE (6) int JK_METHOD status_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_STATUS_H */ tomcat-connectors-1.2.50-src/native/common/Makefile.in0000644000000000000020000000251714655113617021154 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #### XXXX DO we need this Makefile ???? srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ APXSLDFLAGS=@APXSLDFLAGS@ APXSCFLAGS=@APXSCFLAGS@ APXSCPPFLAGS=@APXSCPPFLAGS@ SHELL=@SHELL@ top_builddir = .. LIBTOOL = @LIBTOOL@ CC = @CC@ OEXT=.lo include list.mk CFLAGS=-I. @apache_include@ @CFLAGS@ ${APXSCFLAGS} ${APXSCPPFLAGS} include @top_srcdir@/scripts/build/rules.mk JK=./ all: ${APACHE_OBJECTS} install: clean: rm -f *.o *.lo *.a *.la *.so *.so.* *.slo rm -rf .libs maintainer-clean: clean distclean: clean tomcat-connectors-1.2.50-src/native/common/jk_ajp14.h0000644000000000000020000002046214655113617020662 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Next generation bi-directional protocol handler. * * Author: Henri Gomez * ***************************************************************************/ #ifndef JK_AJP14_H #define JK_AJP14_H #include "jk_ajp_common.h" #include "jk_context.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define AJP14_PROTO 14 #define AJP14_WS_HEADER 0x1235 #define AJP14_SW_HEADER 0x1235 /* AJP14 use now the same header in both directions */ #define AJP14_DEF_HOST ("localhost") #define AJP14_DEF_PORT (8011) #define AJP14_DEF_RETRY_ATTEMPTS (1) #define AJP14_DEF_CACHE_SZ (1) #define AJP14_HEADER_LEN (4) #define AJP14_HEADER_SZ_LEN (2) /* * Initial Login Phase (web server -> servlet engine) */ #define AJP14_LOGINIT_CMD (unsigned char)0x10 /* * Second Login Phase (servlet engine -> web server), md5 seed is received */ #define AJP14_LOGSEED_CMD (unsigned char)0x11 /* * Third Login Phase (web server -> servlet engine), md5 of seed + secret is sent */ #define AJP14_LOGCOMP_CMD (unsigned char)0x12 /* * Login Accepted (servlet engine -> web server) */ #define AJP14_LOGOK_CMD (unsigned char)0x13 /* * Login Rejected (servlet engine -> web server), will be logged */ #define AJP14_LOGNOK_CMD (unsigned char)0x14 /* * Context Query (web server -> servlet engine), which URI are handled by servlet engine ? */ #define AJP14_CONTEXT_QRY_CMD (unsigned char)0x15 /* * Context Info (servlet engine -> web server), URI handled response */ #define AJP14_CONTEXT_INFO_CMD (unsigned char)0x16 /* * Context Update (servlet engine -> web server), status of context changed */ #define AJP14_CONTEXT_UPDATE_CMD (unsigned char)0x17 /* * Servlet Engine Status (web server -> servlet engine), what's the status of the servlet engine ? */ #define AJP14_STATUS_CMD (unsigned char)0x18 /* * Secure Shutdown command (web server -> servlet engine), please servlet stop yourself. */ #define AJP14_SHUTDOWN_CMD (unsigned char)0x19 /* * Secure Shutdown command Accepted (servlet engine -> web server) */ #define AJP14_SHUTOK_CMD (unsigned char)0x1A /* * Secure Shutdown Rejected (servlet engine -> web server) */ #define AJP14_SHUTNOK_CMD (unsigned char)0x1B /* * Context Status (web server -> servlet engine), what's the status of the context ? */ #define AJP14_CONTEXT_STATE_CMD (unsigned char)0x1C /* * Context Status Reply (servlet engine -> web server), status of context */ #define AJP14_CONTEXT_STATE_REP_CMD (unsigned char)0x1D /* * Unknown Packet Reply (web server <-> servlet engine), when a packet couldn't be decoded */ #define AJP14_UNKNOW_PACKET_CMD (unsigned char)0x1E /* * Negotiation flags */ /* * web-server want context info after login */ #define AJP14_CONTEXT_INFO_NEG 0x80000000 /* * web-server want context updates */ #define AJP14_CONTEXT_UPDATE_NEG 0x40000000 /* * web-server want compressed stream */ #define AJP14_GZIP_STREAM_NEG 0x20000000 /* * web-server want crypted DES56 stream with secret key */ #define AJP14_DES56_STREAM_NEG 0x10000000 /* * Extended info on server SSL vars */ #define AJP14_SSL_VSERVER_NEG 0x08000000 /* *Extended info on client SSL vars */ #define AJP14_SSL_VCLIENT_NEG 0x04000000 /* * Extended info on crypto SSL vars */ #define AJP14_SSL_VCRYPTO_NEG 0x02000000 /* * Extended info on misc SSL vars */ #define AJP14_SSL_VMISC_NEG 0x01000000 /* * mask of protocol supported */ #define AJP14_PROTO_SUPPORT_AJPXX_NEG 0x00FF0000 /* * communication could use AJP14 */ #define AJP14_PROTO_SUPPORT_AJP14_NEG 0x00010000 /* * communication could use AJP15 */ #define AJP14_PROTO_SUPPORT_AJP15_NEG 0x00020000 /* * communication could use AJP16 */ #define AJP14_PROTO_SUPPORT_AJP16_NEG 0x00040000 /* * Some failure codes */ #define AJP14_BAD_KEY_ERR 0xFFFFFFFF #define AJP14_ENGINE_DOWN_ERR 0xFFFFFFFE #define AJP14_RETRY_LATER_ERR 0xFFFFFFFD #define AJP14_SHUT_AUTHOR_FAILED_ERR 0xFFFFFFFC /* * Some status codes */ #define AJP14_CONTEXT_DOWN 0x01 #define AJP14_CONTEXT_UP 0x02 #define AJP14_CONTEXT_OK 0x03 /* * Misc defines */ #define AJP14_ENTROPY_SEED_LEN 32 /* we're using MD5 => 32 chars */ #define AJP14_COMPUTED_KEY_LEN 32 /* we're using MD5 also */ /* * The login structure */ typedef struct jk_login_service jk_login_service_t; struct jk_login_service { /* * Pointer to web-server name */ const char *web_server_name; /* * Pointer to servlet-engine name */ char *servlet_engine_name; /* * Pointer to secret key */ const char *secret_key; /* * Received entropy seed */ char entropy[AJP14_ENTROPY_SEED_LEN + 1]; /* * Computed key */ char computed_key[AJP14_COMPUTED_KEY_LEN + 1]; /* * What we want to negociate */ unsigned long negotiation; /* * What we received from servlet engine */ unsigned long negociated; }; /* * functions defined here */ void ajp14_compute_md5(jk_login_service_t *s, jk_log_context_t *log_ctx); int ajp14_marshal_login_init_into_msgb(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *log_ctx); int ajp14_unmarshal_login_seed(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *log_ctx); int ajp14_marshal_login_comp_into_msgb(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *log_ctx); int ajp14_unmarshal_log_ok(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *log_ctx); int ajp14_unmarshal_log_nok(jk_msg_buf_t *msg, jk_log_context_t *log_ctx); int ajp14_marshal_shutdown_into_msgb(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *log_ctx); int ajp14_unmarshal_shutdown_nok(jk_msg_buf_t *msg, jk_log_context_t *log_ctx); int ajp14_marshal_unknown_packet_into_msgb(jk_msg_buf_t *msg, jk_msg_buf_t *unk, jk_log_context_t *log_ctx); int ajp14_marshal_context_query_into_msgb(jk_msg_buf_t *msg, char *virtual, jk_log_context_t *log_ctx); int ajp14_unmarshal_context_info(jk_msg_buf_t *msg, jk_context_t *context, jk_log_context_t *log_ctx); int ajp14_marshal_context_state_into_msgb(jk_msg_buf_t *msg, jk_context_t *context, char *cname, jk_log_context_t *log_ctx); int ajp14_unmarshal_context_state_reply(jk_msg_buf_t *msg, jk_context_t *context, jk_log_context_t *log_ctx); int ajp14_unmarshal_context_update_cmd(jk_msg_buf_t *msg, jk_context_t *context, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_AJP14_H */ tomcat-connectors-1.2.50-src/native/common/jk_pool.h0000644000000000000020000000711714655113617020716 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Memory Pool object header file * * Author: Gal Shachor * ***************************************************************************/ #ifndef _JK_POOL_H #define _JK_POOL_H #include "jk_global.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * @file jk_pool.h * @brief Jk memory allocation * * Similar with apr_pools, but completely unsynchronized. * XXX use same names * */ /* * The pool atom (basic pool alocation unit) is an 8 byte long. * Each allocation (even for 1 byte) will return a round up to the * number of atoms. * * This is to help in alignment of 32/64 bit machines ... * G.S */ #ifdef WIN32 typedef __int64 jk_pool_atom_t; #elif defined(AIX) typedef long long jk_pool_atom_t; #elif defined(SOLARIS) typedef long long jk_pool_atom_t; #elif defined(LINUX) typedef long long jk_pool_atom_t; #elif defined(FREEBSD) typedef long long jk_pool_atom_t; #elif defined(OS2) typedef long long jk_pool_atom_t; #elif defined(HPUX11) typedef long long jk_pool_atom_t; #elif defined(IRIX) typedef long long jk_pool_atom_t; #elif defined(AS400) typedef void *jk_pool_atom_t; #else typedef long long jk_pool_atom_t; #endif /** * Alignment macros */ /* JK_ALIGN() is only to be used to align on a power of 2 boundary */ #define JK_ALIGN(size, boundary) \ (((size) + ((boundary) - 1)) & ~((boundary) - 1)) /** Default alignment */ #ifdef AS400 #define JK_ALIGN_DEFAULT(size) JK_ALIGN(size, 16) #else #define JK_ALIGN_DEFAULT(size) JK_ALIGN(size, 8) #endif /* * Pool size in number of pool atoms. */ #define TINY_POOL_SIZE 256 /* Tiny 1/4K atom pool. */ #define SMALL_POOL_SIZE 512 /* Small 1/2K atom pool. */ #define BIG_POOL_SIZE 2*SMALL_POOL_SIZE /* Bigger 1K atom pool. */ #define HUGE_POOL_SIZE 2*BIG_POOL_SIZE /* Huge 2K atom pool. */ /** jk pool structure */ struct jk_pool { size_t size; size_t pos; char *buf; size_t dyn_size; size_t dyn_pos; void **dynamic; }; typedef struct jk_pool jk_pool_t; void jk_open_pool(jk_pool_t *p, jk_pool_atom_t *buf, size_t size); void jk_close_pool(jk_pool_t *p); void jk_reset_pool(jk_pool_t *p); void *jk_pool_alloc(jk_pool_t *p, size_t sz); void *jk_pool_calloc(jk_pool_t *p, size_t sz); void *jk_pool_realloc(jk_pool_t *p, size_t sz, const void *old, size_t old_sz); char *jk_pool_strdup(jk_pool_t *p, const char *s); char *jk_pool_strcat(jk_pool_t *p, const char *s, const char *a); char *jk_pool_strcatv(jk_pool_t *p, ...); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _JK_POOL_H */ tomcat-connectors-1.2.50-src/native/common/jk_connect.h0000644000000000000020000000521414655113617021372 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Socket connections header file * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_CONNECT_H #define JK_CONNECT_H #include "jk_logger.h" #include "jk_global.h" #if !defined(WIN32) #define closesocket close #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define JK_SOCKET_EOF (-2) void jk_clone_sockaddr(jk_sockaddr_t *out, jk_sockaddr_t *in); int jk_resolve(const char *host, int port, jk_sockaddr_t *rc, void *pool, int prefer_ipv6, jk_log_context_t *log_ctx); jk_sock_t jk_open_socket(jk_sockaddr_t *addr, jk_sockaddr_t *source, int keepalive, int timeout, int connect_timeout, int sock_buf, jk_log_context_t *log_ctx); int jk_close_socket(jk_sock_t sd, jk_log_context_t *log_ctx); int jk_shutdown_socket(jk_sock_t sd, jk_log_context_t *log_ctx); int jk_tcp_socket_sendfull(jk_sock_t sd, const unsigned char *b, int len, jk_log_context_t *log_ctx); int jk_tcp_socket_recvfull(jk_sock_t sd, unsigned char *b, int len, jk_log_context_t *log_ctx); char *jk_dump_hinfo(jk_sockaddr_t *saddr, char *buf, size_t size); char *jk_dump_sinfo(jk_sock_t sd, char *buf, size_t size); int jk_is_input_event(jk_sock_t sd, int timeout, jk_log_context_t *log_ctx); int jk_is_socket_connected(jk_sock_t sd, jk_log_context_t *log_ctx); /*** * i5/OS V5R4 need ASCII<->EBCDIC translation for inet_addr() call */ #if !defined(AS400_UTF8) #define jk_inet_addr inet_addr #endif #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_CONNECT_H */ tomcat-connectors-1.2.50-src/native/common/jk_msg_buff.h0000644000000000000020000001015414655113617021530 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Data marshaling. XDR like * * Author: Costin * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_MSG_BUF_H #define JK_MSG_BUF_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* XXX replace all return values with error codes */ #define ERR_BAD_PACKET -5 /* RPC details: - one parameter - use a structure for more. The method is encoded as part of the request - one or no result - */ typedef struct jk_msg_buf_t jk_msg_buf_t; struct jk_msg_buf_t { jk_pool_t *pool; unsigned char *buf; int pos; int len; int maxlen; }; /* -------------------- Setup routines -------------------- */ /** Allocate a buffer. */ jk_msg_buf_t *jk_b_new(jk_pool_t *p); /** Set up a buffer with an existing buffer */ int jk_b_set_buffer(jk_msg_buf_t *msg, unsigned char *data, int buffSize); /* * Set up a buffer with a new buffer of buffSize */ int jk_b_set_buffer_size(jk_msg_buf_t *msg, int buffSize); /* * Finalize the buffer before sending - set length fields, etc */ void jk_b_end(jk_msg_buf_t *msg, int protoh); /* * Recycle the buffer - z for a new invocation */ void jk_b_reset(jk_msg_buf_t *msg); /* -------------------- Real encoding -------------------- */ int jk_b_append_byte(jk_msg_buf_t *msg, unsigned char val); int jk_b_append_bytes(jk_msg_buf_t *msg, const unsigned char *param, int len); int jk_b_append_int(jk_msg_buf_t *msg, unsigned short val); int jk_b_append_long(jk_msg_buf_t *msg, unsigned long val); int jk_b_append_string(jk_msg_buf_t *msg, const char *param); #if defined(AS400) && !defined(AS400_UTF8) int jk_b_append_asciistring(jk_msg_buf_t *msg, const char *param); #endif int jk_b_append_bytes(jk_msg_buf_t *msg, const unsigned char *param, int len); /* -------------------- Decoding -------------------- */ /** Get a byte from the current position */ unsigned char jk_b_get_byte(jk_msg_buf_t *msg); /** Get an int from the current position */ unsigned short jk_b_get_int(jk_msg_buf_t *msg); /** Get a long from the current position */ unsigned long jk_b_get_long(jk_msg_buf_t *msg); /** Get a String from the current position */ char *jk_b_get_string(jk_msg_buf_t *msg); /** Get Bytes from the current position */ int jk_b_get_bytes(jk_msg_buf_t *msg, unsigned char *buf, int len); /** Get a byte from an arbitrary position */ unsigned char jk_b_pget_byte(jk_msg_buf_t *msg, int pos); /** Get an int from an arbitrary position */ unsigned short jk_b_pget_int(jk_msg_buf_t *msg, int pos); /** Get a long from an arbitrary position */ unsigned long jk_b_pget_long(jk_msg_buf_t *msg, int pos); /* --------------------- Help ------------------------ */ void jk_dump_buff(jk_log_context_t *log_ctx, const char *file, int line, const char *funcname, int level, char *what, jk_msg_buf_t *msg); /** Copy a msg buf into another one */ int jk_b_copy(jk_msg_buf_t *smsg, jk_msg_buf_t *dmsg); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_MSG_BUF_H */ tomcat-connectors-1.2.50-src/native/common/jk.rc0000644000000000000020000000547114655113617020043 0ustar rootbin/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "jk_version.h" #define ASF_COPYRIGHT "Licensed to the Apache Software Foundation " \ "(ASF) under one or more contributor license " \ "agreements. See the NOTICE file distributed " \ "with this work for additional information " \ "regarding copyright ownership." #define ASF_LICENSE "The ASF licenses this file to You under the " \ "Apache License, Version 2.0 (the ""License""); " \ "you may not use this file except in compliance " \ "with the License. You may obtain a copy of " \ "the License at\r\n\r\n" \ "http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n" \ "Unless required by applicable law or agreed to in " \ "writing, software distributed under the License is " \ "distributed on an ""AS IS"" BASIS, WITHOUT " \ "WARRANTIES OR CONDITIONS OF ANY KIND, either " \ "express or implied. See the License for the " \ "specific language governing permissions and " \ "limitations under the License." 1 VERSIONINFO FILEVERSION JK_VERSIONCSV,0 PRODUCTVERSION JK_VERSIONCSV,0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0x0L FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_APP FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", ASF_LICENSE VALUE "CompanyName", "Apache Software Foundation" VALUE "FileDescription", "Apache Tomcat Connector" VALUE "FileVersion", JK_VERSTRING VALUE "InternalName", JK_DISTNAME VALUE "LegalCopyright", ASF_COPYRIGHT VALUE "OriginalFilename", JK_DISTNAME "." JK_DLL_SUFFIX VALUE "ProductName", "Apache Tomcat " JK_DISTNAME " Connector" VALUE "ProductVersion", JK_EXPOSED_VERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END tomcat-connectors-1.2.50-src/native/common/jk_util.h0000644000000000000020000002421614655113617020721 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Various utility functions * * Author: Gal Shachor * * Author: Henri Gomez * * Author: Rainer Jung * ***************************************************************************/ #ifndef _JK_UTIL_H #define _JK_UTIL_H #include "jk_global.h" #include "jk_logger.h" #include "jk_map.h" #include "jk_pool.h" #include "jk_service.h" #define JK_SLEEP_DEF (100) #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ const char *jk_get_bool(int v); int jk_get_bool_code(const char *v, int def); void jk_sleep(int ms); void jk_set_time_fmt(jk_logger_t *l, const char *jk_log_fmt); int jk_parse_log_level(const char *level); int jk_open_file_logger(jk_logger_t **l, const char *file, int level); int jk_attach_file_logger(jk_logger_t **l, int fd, int level); int jk_close_file_logger(jk_logger_t **l); int jk_log(jk_log_context_t *log_ctx, const char *file, int line, const char *funcname, int level, const char *fmt, ...); const char *jk_get_worker_host(jk_map_t *m, const char *wname, const char *def); const char *jk_get_worker_source(jk_map_t *m, const char *wname, const char *def); const char *jk_get_worker_type(jk_map_t *m, const char *wname); int jk_get_worker_port(jk_map_t *m, const char *wname, int def); int jk_get_worker_prefer_ipv6(jk_map_t *m, const char *wname, int def); int jk_get_worker_cache_size(jk_map_t *m, const char *wname, int def); int jk_get_worker_cache_size_min(jk_map_t *m, const char *wname, int def); int jk_get_worker_cache_acquire_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_socket_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_socket_connect_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_socket_buffer(jk_map_t *m, const char *wname, int def); int jk_get_worker_socket_keepalive(jk_map_t *m, const char *wname, int def); int jk_get_worker_conn_ping_interval(jk_map_t *m, const char *wname, int def); int jk_get_worker_cache_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_recovery_opts(jk_map_t *m, const char *wname, int def); int jk_get_worker_connect_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_reply_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_prepost_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_ping_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_ping_mode(jk_map_t *m, const char *wname, int def); int jk_get_worker_recycle_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_recover_timeout(jk_map_t *m, const char *wname, int def); int jk_get_worker_error_escalation_time(jk_map_t *m, const char *wname, int def); int jk_get_worker_max_reply_timeouts(jk_map_t *m, const char *wname, int def); int jk_get_worker_retry_interval(jk_map_t *m, const char *wname, int def); int jk_get_worker_busy_limit(jk_map_t *m, const char *wname, int def); const char *jk_get_worker_route(jk_map_t *m, const char *wname, const char *def); const char *jk_get_worker_domain(jk_map_t *m, const char *wname, const char *def); const char *jk_get_worker_redirect(jk_map_t *m, const char *wname, const char *def); const char *jk_get_worker_secret_key(jk_map_t *m, const char *wname); const char *jk_get_lb_session_cookie(jk_map_t *m, const char *wname, const char *def); const char *jk_get_lb_session_path(jk_map_t *m, const char *wname, const char *def); int jk_get_lb_set_session_cookie(jk_map_t *m, const char *wname, int def); const char *jk_get_lb_session_cookie_path(jk_map_t *m, const char *wname, const char *def); int jk_get_worker_retries(jk_map_t *m, const char *wname, int def); int jk_get_worker_lb_retries(jk_map_t *m, const char *wname, int def); int jk_get_is_worker_disabled(jk_map_t *m, const char *wname); int jk_get_is_worker_stopped(jk_map_t *m, const char *wname); int jk_get_worker_activation(jk_map_t *m, const char *wname); int jk_get_worker_list(jk_map_t *m, char ***list, unsigned *num_of_workers); int jk_get_lb_factor(jk_map_t *m, const char *wname); int jk_get_distance(jk_map_t *m, const char *wname); int jk_get_is_sticky_session(jk_map_t *m, const char *wname); int jk_get_is_sticky_session_force(jk_map_t *m, const char *wname); int jk_get_lb_method(jk_map_t *m, const char *wname); int jk_get_lb_lock(jk_map_t *m, const char *wname); int jk_get_lb_worker_list(jk_map_t *m, const char *lb_wname, char ***list, unsigned int *num_of_workers); int jk_get_worker_mount_list(jk_map_t *m, const char *wname, char ***list, unsigned int *num_of_maps); const char *jk_get_worker_secret(jk_map_t *m, const char *wname); int jk_get_worker_mx(jk_map_t *m, const char *wname, unsigned *mx); int jk_get_worker_ms(jk_map_t *m, const char *wname, unsigned *ms); int jk_get_worker_classpath(jk_map_t *m, const char *wname, const char **cp); int jk_get_worker_bridge_type(jk_map_t *m, const char *wname, unsigned *bt); int jk_get_worker_jvm_path(jk_map_t *m, const char *wname, const char **vm_path); int jk_get_worker_callback_dll(jk_map_t *m, const char *wname, const char **cb_path); int jk_get_worker_cmd_line(jk_map_t *m, const char *wname, const char **cmd_line); int jk_file_exists(const char *f); int jk_is_list_property(const char *prp_name); int jk_is_path_property(const char *prp_name); int jk_is_cmd_line_property(const char *prp_name); int jk_is_unique_property(const char *prp_name); int jk_is_deprecated_property(const char *prp_name); int jk_check_buffer_size(); int jk_is_valid_property(const char *prp_name); int jk_get_worker_stdout(jk_map_t *m, const char *wname, const char **stdout_name); int jk_get_worker_stderr(jk_map_t *m, const char *wname, const char **stderr_name); int jk_get_worker_sysprops(jk_map_t *m, const char *wname, const char **sysprops); int jk_get_worker_libpath(jk_map_t *m, const char *wname, const char **libpath); char **jk_parse_sysprops(jk_pool_t *p, const char *sysprops); void jk_append_libpath(jk_pool_t *p, const char *libpath); void jk_set_worker_def_cache_size(int sz); int jk_get_worker_def_cache_size(int protocol); int jk_get_worker_maintain_time(jk_map_t *m); int jk_get_max_packet_size(jk_map_t *m, const char *wname); const char *jk_get_worker_style_sheet(jk_map_t *m, const char *wname, const char *def); int jk_get_is_read_only(jk_map_t *m, const char *wname); int jk_get_worker_user_list(jk_map_t *m, const char *wname, char ***list, unsigned int *num); int jk_get_worker_good_rating(jk_map_t *m, const char *wname, char ***list, unsigned int *num); int jk_get_worker_bad_rating(jk_map_t *m, const char *wname, char ***list, unsigned int *num); const char *jk_get_worker_name_space(jk_map_t *m, const char *wname, const char *def); const char *jk_get_worker_xmlns(jk_map_t *m, const char *wname, const char *def); const char *jk_get_worker_xml_doctype(jk_map_t *m, const char *wname, const char *def); const char *jk_get_worker_prop_prefix(jk_map_t *m, const char *wname, const char *def); int jk_get_worker_fail_on_status(jk_map_t *m, const char *wname, int **list, unsigned int *list_size); int jk_get_worker_user_case_insensitive(jk_map_t *m, const char *wname); int is_http_status_fail(unsigned int http_status_fail_num, int *http_status_fail, int status); int jk_wildchar_match(const char *str, const char *exp, int icase); int jk_servlet_normalize(char *path, jk_log_context_t *log_ctx); int jk_strip_session_id(char* path, char* session_name, jk_log_context_t *log_ctx); #define JK_NORMALIZE_BAD_PATH -1 #define JK_NORMALIZE_TRAVERSAL -2 #define TC32_BRIDGE_TYPE 32 #define TC33_BRIDGE_TYPE 33 #define TC40_BRIDGE_TYPE 40 #define TC41_BRIDGE_TYPE 41 #define TC50_BRIDGE_TYPE 50 #ifdef AS400 #define S_IFREG _S_IFREG #ifdef AS400_UTF8 void jk_ascii2ebcdic(char *src, char *dst); void jk_ebcdic2ascii(char *src, char *dst); #endif /* AS400_UTF8 */ #endif /* i5/OS V5R4 need ASCII-EBCDIC conversion before stat() call */ /* added a stat() mapper function, jk_stat, for such purpose */ int jk_stat(const char *f, struct stat * statbuf); #if defined (WIN32) PSECURITY_ATTRIBUTES jk_get_sa_with_null_dacl(void); #endif #define jk_isspace(c) (isspace(((unsigned char)(c)))) #define jk_isalnum(c) (isalnum(((unsigned char)(c)))) #define jk_isdigit(c) (isdigit(((unsigned char)(c)))) #define jk_isalpha(c) (isalpha(((unsigned char)(c)))) #define jk_islower(c) (islower(((unsigned char)(c)))) #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _JK_UTIL_H */ tomcat-connectors-1.2.50-src/native/common/jk_shm.c0000644000000000000020000007247314655113617020536 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Shared Memory support * * Author: Mladen Turk * * Author: Rainer Jung * ***************************************************************************/ #include "jk_global.h" #include "jk_pool.h" #include "jk_util.h" #include "jk_mt.h" #include "jk_lb_worker.h" #include "jk_ajp13_worker.h" #include "jk_ajp14_worker.h" #include "jk_shm.h" /** jk shm header core data structure * This is always the first slot in shared memory. */ struct jk_shm_header_data { /* Shared memory magic JK_SHM_MAGIC */ char magic[JK_SHM_MAGIC_SIZ]; unsigned int size; unsigned int pos; unsigned int childs; unsigned int workers; unsigned int maintain_checking; volatile time_t maintain_time; }; typedef struct jk_shm_header_data jk_shm_header_data_t; /** jk shm header record structure */ struct jk_shm_header { union { jk_shm_header_data_t data; char alignbuf[JK_SHM_SLOT_SIZE]; } h; char buf[1]; }; typedef struct jk_shm_header jk_shm_header_t; /** jk shm in memory structure. */ struct jk_shm { unsigned int size; unsigned int ajp_workers; unsigned int lb_sub_workers; unsigned int lb_workers; char *filename; char *lockname; int fd; int fd_lock; int attached; jk_shm_header_t *hdr; JK_CRIT_SEC cs; }; typedef struct jk_shm jk_shm_t; static const char shm_signature[] = { JK_SHM_MAGIC }; static jk_shm_t jk_shmem = { 0, 0, 0, 0, NULL, NULL, -1, -1, 0, NULL}; #if defined (WIN32) static HANDLE jk_shm_map = NULL; static HANDLE jk_shm_hlock = NULL; #endif static int jk_shm_inited_cs = 0; static size_t jk_shm_calculate_slot_size() { int align = 64; size_t slot_size = 0; size_t this_size = 0; this_size = sizeof(jk_shm_header_data_t); if (this_size > slot_size) slot_size = this_size; this_size = sizeof(jk_shm_worker_header_t); if (this_size > slot_size) slot_size = this_size; this_size = sizeof(jk_shm_ajp_worker_t); if (this_size > slot_size) slot_size = this_size; this_size = sizeof(jk_shm_lb_sub_worker_t); if (this_size > slot_size) slot_size = this_size; this_size = sizeof(jk_shm_lb_worker_t); if (this_size > slot_size) slot_size = this_size; slot_size = JK_ALIGN(slot_size, align); return slot_size; } /* Calculate needed shm size */ int jk_shm_calculate_size(jk_map_t *init_data, jk_log_context_t *l) { char **worker_list; size_t needed_slot_size = 0; unsigned int i; unsigned int num_of_workers; int num_of_ajp_workers = 0; int num_of_lb_sub_workers = 0; int num_of_lb_workers = 0; JK_TRACE_ENTER(l); if (jk_get_worker_list(init_data, &worker_list, &num_of_workers) == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "Could not get worker list from map"); JK_TRACE_EXIT(l); return 0; } needed_slot_size = jk_shm_calculate_slot_size(); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "JK_SHM_SLOT_SIZE defined as %d, need at least %d", JK_SHM_SLOT_SIZE , needed_slot_size); if (needed_slot_size > JK_SHM_SLOT_SIZE) { jk_log(l, JK_LOG_ERROR, "JK_SHM_SLOT_SIZE %d is too small, need at least %d", JK_SHM_SLOT_SIZE, needed_slot_size); JK_TRACE_EXIT(l); return 0; } for (i = 0; i < num_of_workers; i++) { const char *type = jk_get_worker_type(init_data, worker_list[i]); if (!strcmp(type, JK_AJP13_WORKER_NAME) || !strcmp(type, JK_AJP14_WORKER_NAME)) { num_of_ajp_workers++; } else if (!strcmp(type, JK_LB_WORKER_NAME)) { char **member_list; unsigned int num_of_members; num_of_lb_workers++; if (jk_get_lb_worker_list(init_data, worker_list[i], &member_list, &num_of_members) == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "Could not get member list for lb worker from map"); } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s of type %s has %u members", worker_list[i], JK_LB_WORKER_NAME, num_of_members); num_of_lb_sub_workers += num_of_members; } } } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "shared memory will contain %d ajp workers and %d lb workers with %d members", num_of_ajp_workers, num_of_lb_workers, num_of_lb_sub_workers); jk_shmem.ajp_workers = num_of_ajp_workers; jk_shmem.lb_sub_workers = num_of_lb_sub_workers; jk_shmem.lb_workers = num_of_lb_workers; JK_TRACE_EXIT(l); return (JK_SHM_SLOT_SIZE * (jk_shmem.ajp_workers + jk_shmem.lb_sub_workers * 2 + jk_shmem.lb_workers)); } #if defined (WIN32) /* Use plain memory */ int jk_shm_open(const char *fname, int sz, jk_log_context_t *l) { int rc = -1; int attached = 0; char lkname[MAX_PATH]; char shname[MAX_PATH] = ""; JK_TRACE_ENTER(l); if (!jk_shm_inited_cs) { jk_shm_inited_cs = 1; JK_INIT_CS(&jk_shmem.cs, rc); } JK_ENTER_CS(&jk_shmem.cs); if (jk_shmem.hdr) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Shared memory is already opened"); JK_TRACE_EXIT(l); JK_LEAVE_CS(&jk_shmem.cs); return 0; } if (sz < 0) { jk_log(l, JK_LOG_ERROR, "Invalid shared memory size (%d)", sz); JK_TRACE_EXIT(l); return EINVAL; } jk_shmem.size = JK_SHM_ALIGN(JK_SHM_SLOT_SIZE + sz); jk_shm_map = NULL; jk_shm_hlock = NULL; if (fname) { int i; SIZE_T shmsz = 0; strcpy(shname, "Local\\"); strncat(shname, fname, MAX_PATH - 8); for(i = 7; i < (int)strlen(shname); i++) { if (!jk_isalnum(shname[i])) shname[i] = '_'; else shname[i] = toupper(shname[i]); } strcpy(lkname, shname); strncat(lkname, "_MUTEX", MAX_PATH - 1); jk_shm_hlock = CreateMutex(jk_get_sa_with_null_dacl(), TRUE, lkname); if (jk_shm_hlock == NULL) { if (GetLastError() == ERROR_ALREADY_EXISTS) { attached = 1; jk_shm_hlock = OpenMutex(MUTEX_ALL_ACCESS, FALSE, lkname); } } else if (GetLastError() == ERROR_ALREADY_EXISTS) attached = 1; if (jk_shm_hlock == NULL) { rc = GetLastError(); jk_log(l, JK_LOG_ERROR, "Failed to open shared memory mutex %s with errno=%d", lkname, rc); JK_LEAVE_CS(&jk_shmem.cs); JK_TRACE_EXIT(l); return rc; } if (attached) { DWORD ws = WaitForSingleObject(jk_shm_hlock, INFINITE); if (ws == WAIT_FAILED) { rc = GetLastError(); CloseHandle(jk_shm_hlock); jk_shm_hlock = NULL; JK_LEAVE_CS(&jk_shmem.cs); JK_TRACE_EXIT(l); return rc; } jk_shm_map = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, shname); if (jk_shm_map == NULL) { rc = GetLastError(); jk_log(l, JK_LOG_ERROR, "Failed to open shared memory %s with errno=%d", shname, rc); } } if (jk_shm_map == NULL) { shmsz = jk_shmem.size; jk_shm_map = CreateFileMapping(INVALID_HANDLE_VALUE, jk_get_sa_with_null_dacl(), PAGE_READWRITE, 0, (DWORD)shmsz, shname); } if (jk_shm_map == NULL || jk_shm_map == INVALID_HANDLE_VALUE) { rc = GetLastError(); jk_log(l, JK_LOG_ERROR, "Failed to map shared memory %s with errno=%d", fname, rc); CloseHandle(jk_shm_hlock); jk_shm_hlock = NULL; jk_shm_map = NULL; JK_LEAVE_CS(&jk_shmem.cs); JK_TRACE_EXIT(l); return rc; } jk_shmem.hdr = (jk_shm_header_t *)MapViewOfFile(jk_shm_map, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, shmsz); } else jk_shmem.hdr = (jk_shm_header_t *)calloc(1, jk_shmem.size); if (!jk_shmem.hdr) { rc = GetLastError(); if (jk_shm_map) { CloseHandle(jk_shm_map); jk_shm_map = NULL; } if (jk_shm_hlock) { CloseHandle(jk_shm_hlock); jk_shm_hlock = NULL; } JK_LEAVE_CS(&jk_shmem.cs); JK_TRACE_EXIT(l); return rc; } if (!jk_shmem.filename) { if (shname[0]) jk_shmem.filename = strdup(shname); else jk_shmem.filename = strdup("memory"); } jk_shmem.fd = 0; jk_shmem.attached = attached; if (!attached) { memset(jk_shmem.hdr, 0, jk_shmem.size); memcpy(jk_shmem.hdr->h.data.magic, shm_signature, JK_SHM_MAGIC_SIZ); jk_shmem.hdr->h.data.size = sz; jk_shmem.hdr->h.data.childs = 1; jk_shmem.hdr->h.data.maintain_checking = 0; jk_shmem.hdr->h.data.maintain_time = time(NULL); } else { jk_shmem.hdr->h.data.childs++; /* * Reset the shared memory so that * alloc works even for attached memory. * XXX: This might break already used memory * if the number of workers change between * open and attach or between two attach operations. */ #if 0 if (jk_shmem.hdr->h.data.childs > 1) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Resetting the shared memory for child %d", jk_shmem.hdr->h.data.childs); } } jk_shmem.hdr->h.data.pos = 0; jk_shmem.hdr->h.data.workers = 0; #endif } if (jk_shm_hlock != NULL) { /* Unlock shared memory */ ReleaseMutex(jk_shm_hlock); } JK_LEAVE_CS(&jk_shmem.cs); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "%s shared memory %s [%d] size=%u workers=%d free=%u addr=%#lx", attached ? "Attached" : "Initialized", jk_shm_name(), jk_shmem.hdr->h.data.childs, jk_shmem.size, jk_shmem.hdr->h.data.workers - 1, jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, jk_shmem.hdr); JK_TRACE_EXIT(l); return 0; } int jk_shm_attach(const char *fname, int sz, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (!jk_shm_open(fname, sz, l)) { if (!jk_shmem.attached) { jk_shmem.attached = 1; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Attached shared memory %s [%d] size=%u free=%u addr=%#lx", jk_shm_name(), jk_shmem.hdr->h.data.childs, jk_shmem.size, jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, jk_shmem.hdr); } } JK_TRACE_EXIT(l); return 0; } else { JK_TRACE_EXIT(l); return -1; } } void jk_shm_close(jk_log_context_t *l) { if (jk_shm_inited_cs) { JK_ENTER_CS(&jk_shmem.cs); } if (jk_shmem.hdr) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Closed shared memory %s childs=%u", jk_shm_name(), jk_shmem.hdr->h.data.childs); } if (jk_shm_hlock) { WaitForSingleObject(jk_shm_hlock, 60000); ReleaseMutex(jk_shm_hlock); CloseHandle(jk_shm_hlock); jk_shm_hlock = NULL; } if (jk_shm_map) { --jk_shmem.hdr->h.data.childs; UnmapViewOfFile(jk_shmem.hdr); CloseHandle(jk_shm_map); jk_shm_map = NULL; } else free(jk_shmem.hdr); } jk_shmem.hdr = NULL; if (jk_shmem.filename) { free(jk_shmem.filename); jk_shmem.filename = NULL; } if (jk_shm_inited_cs) { JK_LEAVE_CS(&jk_shmem.cs); } } #else #include #include #include #include #include #include #ifndef MAP_FAILED #define MAP_FAILED (-1) #endif #ifndef MAP_FILE #define MAP_FILE (0) #endif static int do_shm_open_lock(const char *fname, int attached, jk_log_context_t *l) { int rc; char flkname[256]; #ifdef AS400_UTF8 char *wptr; #endif JK_TRACE_ENTER(l); if (attached && jk_shmem.lockname) { #ifdef JK_SHM_LOCK_REOPEN jk_shmem.fd_lock = open(jk_shmem.lockname, O_RDWR, 0600); #else errno = EINVAL; #endif if (jk_shmem.fd_lock == -1) { rc = errno; JK_TRACE_EXIT(l); return rc; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Duplicated shared memory lock %s", jk_shmem.lockname); JK_TRACE_EXIT(l); return 0; } if (!jk_shmem.lockname) { #ifdef JK_SHM_LOCK_REOPEN int i; jk_shmem.fd_lock = -1; mode_t mask = umask(0); for (i = 0; i < 8; i++) { strcpy(flkname, "/tmp/jkshmlock.XXXXXX"); if (mktemp(flkname)) { jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0600); if (jk_shmem.fd_lock >= 0) break; } } umask(mask); #else strcpy(flkname, fname); strcat(flkname, ".lock"); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(flkname) + 1); jk_ascii2ebcdic((char *)flkname, wptr); jk_shmem.fd_lock = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0600); free(wptr); #else jk_shmem.fd_lock = open(flkname, O_RDWR|O_CREAT|O_TRUNC, 0600); #endif #endif if (jk_shmem.fd_lock == -1) { rc = errno; JK_TRACE_EXIT(l); return rc; } jk_shmem.lockname = strdup(flkname); } else { /* Nothing to do */ JK_TRACE_EXIT(l); return 0; } if (ftruncate(jk_shmem.fd_lock, 1)) { rc = errno; close(jk_shmem.fd_lock); jk_shmem.fd_lock = -1; JK_TRACE_EXIT(l); return rc; } if (lseek(jk_shmem.fd_lock, 0, SEEK_SET) != 0) { rc = errno; close(jk_shmem.fd_lock); jk_shmem.fd_lock = -1; return rc; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Opened shared memory lock %s", jk_shmem.lockname); JK_TRACE_EXIT(l); return 0; } static int do_shm_open(const char *fname, int attached, int sz, jk_log_context_t *l) { int rc; int fd; void *base; #ifdef AS400_UTF8 char *wptr; #endif JK_TRACE_ENTER(l); if (!jk_shm_inited_cs) { jk_shm_inited_cs = 1; JK_INIT_CS(&jk_shmem.cs, rc); } if (jk_shmem.hdr) { /* Probably a call from vhost */ if (!attached) attached = 1; } else if (attached) { /* We should already have a header * Use memory if we don't */ JK_TRACE_EXIT(l); return 0; } if (sz < 0) { jk_log(l, JK_LOG_ERROR, "Invalid shared memory size (%d)", sz); JK_TRACE_EXIT(l); return EINVAL; } jk_shmem.size = JK_SHM_ALIGN(JK_SHM_SLOT_SIZE + sz); if (!fname) { /* Use plain memory in case there is no file name */ if (!jk_shmem.filename) jk_shmem.filename = strdup("memory"); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Using process memory as shared memory"); JK_TRACE_EXIT(l); return 0; } if (!jk_shmem.filename) { jk_shmem.filename = (char *)malloc(strlen(fname) + 32); sprintf(jk_shmem.filename, "%s.%" JK_PID_T_FMT, fname, getpid()); } if (!attached) { size_t size; jk_shmem.attached = 0; #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); fd = open(wptr, O_RDWR|O_CREAT|O_TRUNC, 0600); free(wptr); #else fd = open(jk_shmem.filename, O_RDWR|O_CREAT|O_TRUNC, 0600); #endif if (fd == -1) { jk_shmem.size = 0; JK_TRACE_EXIT(l); return errno; } size = lseek(fd, 0, SEEK_END); if (size < jk_shmem.size) { size = jk_shmem.size; if (ftruncate(fd, jk_shmem.size)) { rc = errno; close(fd); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif jk_shmem.size = 0; JK_TRACE_EXIT(l); return rc; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Truncated shared memory to %u", size); } if (lseek(fd, 0, SEEK_SET) != 0) { rc = errno; close(fd); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif jk_shmem.size = 0; JK_TRACE_EXIT(l); return rc; } base = mmap((caddr_t)0, jk_shmem.size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0); if (base == (caddr_t)MAP_FAILED || base == (caddr_t)0) { rc = errno; close(fd); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif jk_shmem.size = 0; JK_TRACE_EXIT(l); return rc; } jk_shmem.hdr = base; jk_shmem.fd = fd; memset(jk_shmem.hdr, 0, jk_shmem.size); memcpy(jk_shmem.hdr->h.data.magic, shm_signature, JK_SHM_MAGIC_SIZ); jk_shmem.hdr->h.data.size = sz; jk_shmem.hdr->h.data.childs = 1; jk_shmem.hdr->h.data.maintain_checking = 0; jk_shmem.hdr->h.data.maintain_time = time(NULL); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Initialized shared memory %s size=%u free=%u addr=%#lx", jk_shm_name(), jk_shmem.size, jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, jk_shmem.hdr); } else { jk_shmem.hdr->h.data.childs++; jk_shmem.attached = (int)getpid(); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Attached shared memory %s [%d] size=%u workers=%u free=%u addr=%#lx", jk_shm_name(), jk_shmem.hdr->h.data.childs, jk_shmem.size, jk_shmem.hdr->h.data.workers - 1, jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos, jk_shmem.hdr); #if 0 /* * Reset the shared memory so that * alloc works even for attached memory. * XXX: This might break already used memory * if the number of workers change between * open and attach or between two attach operations. */ if (nchild > 1) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Resetting the shared memory for child %d", nchild); } } jk_shmem.hdr->h.data.pos = 0; jk_shmem.hdr->h.data.workers = 0; #endif } if ((rc = do_shm_open_lock(jk_shmem.filename, attached, l))) { if (!attached) { munmap((void *)jk_shmem.hdr, jk_shmem.size); close(jk_shmem.fd); #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif } jk_shmem.hdr = NULL; jk_shmem.fd = -1; JK_TRACE_EXIT(l); return rc; } JK_TRACE_EXIT(l); return 0; } int jk_shm_open(const char *fname, int sz, jk_log_context_t *l) { return do_shm_open(fname, 0, sz, l); } int jk_shm_attach(const char *fname, int sz, jk_log_context_t *l) { return do_shm_open(fname, 1, sz, l); } void jk_shm_close(jk_log_context_t *l) { #ifdef AS400_UTF8 char *wptr; #endif if (jk_shmem.hdr) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Closed shared memory %s childs=%u", jk_shm_name(), jk_shmem.hdr->h.data.childs); } --jk_shmem.hdr->h.data.childs; #ifdef JK_SHM_LOCK_REOPEN if (jk_shmem.fd_lock >= 0) { close(jk_shmem.fd_lock); jk_shmem.fd_lock = -1; } #endif if (jk_shmem.attached) { int p = (int)getpid(); if (p == jk_shmem.attached) { /* In case this is a forked child * do not close the shared memory. * It will be closed by the parent. */ jk_shmem.size = 0; jk_shmem.hdr = NULL; jk_shmem.fd = -1; return; } } if (jk_shmem.fd >= 0) { munmap((void *)jk_shmem.hdr, jk_shmem.size); close(jk_shmem.fd); } if (jk_shmem.fd_lock >= 0) close(jk_shmem.fd_lock); if (jk_shmem.lockname) { #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.lockname) + 1); jk_ascii2ebcdic((char *)jk_shmem.lockname, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.lockname); #endif free(jk_shmem.lockname); jk_shmem.lockname = NULL; } if (jk_shmem.filename) { #ifdef AS400_UTF8 wptr = (char *)malloc(strlen(jk_shmem.filename) + 1); jk_ascii2ebcdic((char *)jk_shmem.filename, wptr); unlink(wptr); free(wptr); #else unlink(jk_shmem.filename); #endif free(jk_shmem.filename); jk_shmem.filename = NULL; } } jk_shmem.size = 0; jk_shmem.hdr = NULL; jk_shmem.fd = -1; jk_shmem.fd_lock = -1; } #endif static int jk_shm_check_str_length(const char *name, const char *value, jk_log_context_t *l) { size_t len = strlen(value); if (len >= JK_SHM_STR_SIZ) { jk_log(l, JK_LOG_ERROR, "Worker %s '%s' is %d bytes too long, " "a maximum of %d bytes is supported", name, value, len - (JK_SHM_STR_SIZ - 1), JK_SHM_STR_SIZ - 1); return JK_FALSE; } return JK_TRUE; } int jk_shm_str_init(shm_str dst, const char *src, const char *name, jk_log_context_t *l) { if (jk_shm_check_str_length(name, src, l) == JK_FALSE) { return JK_FALSE; } strncpy(dst, src, JK_SHM_STR_SIZ - 1); dst[JK_SHM_STR_SIZ - 1] = '\0'; return JK_TRUE; } int jk_shm_str_init_ne(shm_str dst, const char *src, const char *name, jk_log_context_t *l) { if (jk_shm_check_str_length(name, src, l) == JK_FALSE) { return -1; } if (!strncmp(dst, src, JK_SHM_STR_SIZ)) { return 0; } strncpy(dst, src, JK_SHM_STR_SIZ - 1); dst[JK_SHM_STR_SIZ - 1] = '\0'; return 1; } void jk_shm_str_copy(shm_str dst, shm_str src, jk_log_context_t *l) { memcpy((dst), (src), JK_SHM_STR_SIZ); } jk_shm_worker_header_t *jk_shm_alloc_worker(jk_pool_t *p, int type, int parent_id, const char *name, jk_log_context_t *l) { unsigned int i; jk_shm_worker_header_t *w = 0; shm_str str; if (jk_shm_str_init(str, name, "name", l) == JK_FALSE) { return NULL; } if (jk_shmem.hdr) { jk_shm_lock(); for (i = 0; i < jk_shmem.hdr->h.data.pos; i += JK_SHM_SLOT_SIZE) { w = (jk_shm_worker_header_t *)(jk_shmem.hdr->buf + i); if (w->type == type && w-> parent_id == parent_id && strcmp(w->name, name) == 0) { /* We have found already created worker */ jk_shm_unlock(); return w; } } /* Allocate new worker */ if ((jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos) >= JK_SHM_SLOT_SIZE) { w = (jk_shm_worker_header_t *)(jk_shmem.hdr->buf + jk_shmem.hdr->h.data.pos); memset(w, 0, JK_SHM_SLOT_SIZE); jk_shm_str_copy(w->name, str, l); jk_shmem.hdr->h.data.workers++; w->id = jk_shmem.hdr->h.data.workers; w->type = type; w->parent_id = parent_id; jk_shmem.hdr->h.data.pos += JK_SHM_SLOT_SIZE; } else { /* No more free memory left. */ jk_log(l, JK_LOG_ERROR, "Could not allocate shared memory for worker %s", name); w = NULL; } jk_shm_unlock(); } else if (p) { w = (jk_shm_worker_header_t *)jk_pool_alloc(p, JK_SHM_SLOT_SIZE); if (w) { memset(w, 0, JK_SHM_SLOT_SIZE); jk_shm_str_copy(w->name, str, l); w->id = 0; w->type = type; w->parent_id = parent_id; } } return w; } const char *jk_shm_name() { return jk_shmem.filename; } int jk_shm_check_maintain(time_t trigger) { int rv = JK_FALSE; int maintain_checking = JK_ATOMIC_INCREMENT(&(jk_shmem.hdr->h.data.maintain_checking)); /* Another process (or thread) is already checking */ if (maintain_checking > 1) { JK_ATOMIC_DECREMENT(&(jk_shmem.hdr->h.data.maintain_checking)); return rv; } if (jk_shmem.hdr->h.data.maintain_time <= trigger) { jk_shmem.hdr->h.data.maintain_time = time(NULL); rv = JK_TRUE; } JK_ATOMIC_DECREMENT(&(jk_shmem.hdr->h.data.maintain_checking)); return rv; } int jk_shm_lock() { int rc = JK_TRUE; if (!jk_shm_inited_cs) return JK_FALSE; JK_ENTER_CS(&jk_shmem.cs); #if defined (WIN32) if (jk_shm_hlock != NULL) { if (WaitForSingleObject(jk_shm_hlock, INFINITE) == WAIT_FAILED) rc = JK_FALSE; } #else if (jk_shmem.fd_lock != -1) { JK_ENTER_LOCK(jk_shmem.fd_lock, rc); } #endif return rc; } int jk_shm_unlock() { int rc = JK_TRUE; if (!jk_shm_inited_cs) return JK_FALSE; #if defined (WIN32) if (jk_shm_hlock != NULL) { ReleaseMutex(jk_shm_hlock); } #else if (jk_shmem.fd_lock != -1) { JK_LEAVE_LOCK(jk_shmem.fd_lock, rc); } #endif JK_LEAVE_CS(&jk_shmem.cs); return rc; } jk_shm_ajp_worker_t *jk_shm_alloc_ajp_worker(jk_pool_t *p, const char *name, jk_log_context_t *l) { return (jk_shm_ajp_worker_t *)jk_shm_alloc_worker(p, JK_AJP13_WORKER_TYPE, 0, name, l); } jk_shm_lb_sub_worker_t *jk_shm_alloc_lb_sub_worker(jk_pool_t *p, int lb_id, const char *name, jk_log_context_t *l) { return (jk_shm_lb_sub_worker_t *)jk_shm_alloc_worker(p, JK_LB_SUB_WORKER_TYPE, lb_id, name, l); } jk_shm_lb_worker_t *jk_shm_alloc_lb_worker(jk_pool_t *p, const char *name, jk_log_context_t *l) { return (jk_shm_lb_worker_t *)jk_shm_alloc_worker(p, JK_LB_WORKER_TYPE, 0, name, l); } tomcat-connectors-1.2.50-src/native/common/list.mk.in0000644000000000000020000000271114655113617021014 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ## Object needed for mod_jk for Apache-1.3 APACHE_OBJECTS= ${JK}jk_ajp12_worker${OEXT} ${JK}jk_connect${OEXT} \ ${JK}jk_msg_buff${OEXT} ${JK}jk_util${OEXT} \ ${JK}jk_ajp13${OEXT} ${JK}jk_pool${OEXT} \ ${JK}jk_worker${OEXT} ${JK}jk_ajp13_worker${OEXT} \ ${JK}jk_lb_worker${OEXT} ${JK}jk_sockbuf${OEXT} \ ${JK}jk_map${OEXT} ${JK}jk_uri_worker_map${OEXT} \ ${JK}jk_ajp14${OEXT} ${JK}jk_ajp14_worker${OEXT} \ ${JK}jk_md5${OEXT} ${JK}jk_shm${OEXT} \ ${JK}jk_ajp_common${OEXT} ${JK}jk_context${OEXT} \ ${JK}jk_url${OEXT} \ ${JK}jk_status${OEXT} tomcat-connectors-1.2.50-src/native/common/ap_snprintf.h0000644000000000000020000001356014655113617021603 0ustar rootbin/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * The ap_vsnprintf/ap_snprintf functions are based on, and used with the * permission of, the SIO stdio-replacement strx_* functions by Panos * Tsirigotis for xinetd. */ #ifndef APACHE_AP_SNPRINTF_H #define APACHE_AP_SNPRINTF_H #include #include #include #ifdef __cplusplus extern "C" { #endif /* stuff marked API_EXPORT is part of the API, and intended for use * by modules */ #ifndef API_EXPORT #define API_EXPORT(type) type #endif /* Stuff marked API_EXPORT_NONSTD is part of the API, and intended for * use by modules. The difference between API_EXPORT and * API_EXPORT_NONSTD is that the latter is required for any functions * which use varargs or are used via indirect function call. This * is to accomodate the two calling conventions in windows dlls. */ #ifndef API_EXPORT_NONSTD #define API_EXPORT_NONSTD(type) type #endif #if !defined(__GNUC__) || __GNUC__ < 2 || \ (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ||\ defined(NEXT) #define __attribute__(__x) #endif /* These macros allow correct support of 8-bit characters on systems which * support 8-bit characters. Pretty dumb how the cast is required, but * that's legacy libc for ya. These new macros do not support EOF like * the standard macros do. Tough. */ #define ap_isalpha(c) (isalpha(((unsigned char)(c)))) #define ap_isdigit(c) (isdigit(((unsigned char)(c)))) #define ap_islower(c) (islower(((unsigned char)(c)))) /* ap_vformatter() is a generic printf-style formatting routine * with some extensions. The extensions are: * * %pA takes a struct in_addr *, and prints it as a.b.c.d * %pI takes a struct sockaddr_in * and prints it as a.b.c.d:port * %pp takes a void * and outputs it in hex * * The %p hacks are to force gcc's printf warning code to skip * over a pointer argument without complaining. This does * mean that the ANSI-style %p (output a void * in hex format) won't * work as expected at all, but that seems to be a fair trade-off * for the increased robustness of having printf-warnings work. * * Additionally, ap_vformatter allows for arbitrary output methods * using the ap_vformatter_buff and flush_func. * * The ap_vformatter_buff has two elements curpos and endpos. * curpos is where ap_vformatter will write the next byte of output. * It proceeds writing output to curpos, and updating curpos, until * either the end of output is reached, or curpos == endpos (i.e. the * buffer is full). * * If the end of output is reached, ap_vformatter returns the * number of bytes written. * * When the buffer is full, the flush_func is called. The flush_func * can return -1 to indicate that no further output should be attempted, * and ap_vformatter will return immediately with -1. Otherwise * the flush_func should flush the buffer in whatever manner is * appropriate, re-initialize curpos and endpos, and return 0. * * Note that flush_func is only invoked as a result of attempting to * write another byte at curpos when curpos >= endpos. So for * example, it's possible when the output exactly matches the buffer * space available that curpos == endpos will be true when * ap_vformatter returns. * * ap_vformatter does not call out to any other code, it is entirely * self-contained. This allows the callers to do things which are * otherwise "unsafe". For example, ap_psprintf uses the "scratch" * space at the unallocated end of a block, and doesn't actually * complete the allocation until ap_vformatter returns. ap_psprintf * would be completely broken if ap_vformatter were to call anything * that used a pool. Similarly http_bprintf() uses the "scratch" * space at the end of its output buffer, and doesn't actually note * that the space is in use until it either has to flush the buffer * or until ap_vformatter returns. */ typedef struct { char *curpos; char *endpos; } ap_vformatter_buff; API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *), ap_vformatter_buff *, const char *fmt, va_list ap); /* These are snprintf implementations based on ap_vformatter(). * * Note that various standards and implementations disagree on the return * value of snprintf, and side-effects due to %n in the formatting string. * ap_snprintf behaves as follows: * * Process the format string until the entire string is exhausted, or * the buffer fills. If the buffer fills then stop processing immediately * (so no further %n arguments are processed), and return the buffer * length. In all cases the buffer is NUL terminated. The return value * is the number of characters placed in the buffer, excluding the * terminating NUL. All this implies that, at most, (len-1) characters * will be copied over; if the return value is >= len, then truncation * occured. * * In no event does ap_snprintf return a negative number. */ API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...) __attribute__((format(printf,3,4))); API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap); #ifdef __cplusplus } #endif #endif /* !APACHE_AP_SNPRINTF_H */ tomcat-connectors-1.2.50-src/native/common/jk_global.h0000644000000000000020000003230314655113617021200 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Global definitions and include files that should exist * * anywhere * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_GLOBAL_H #define JK_GLOBAL_H #if defined(HAVE_CONFIG_H) /* Undefine autoconf defines also existing * in Apache web server includes, and which * will be redefined in our config.h */ #undef PACKAGE #undef PACKAGE_NAME #undef PACKAGE_STRING #undef PACKAGE_TARNAME #undef PACKAGE_VERSION #undef PACKAGE_BUGREPORT #undef PACKAGE_URL #include "config.h" #endif #if defined(WIN32) /* Ignore most warnings (back down to /W3) for poorly constructed headers */ #if defined(_MSC_VER) && _MSC_VER >= 1200 #pragma warning(push, 3) #endif /* disable or reduce the frequency of... * C4057: indirection to slightly different base types * C4075: slight indirection changes (unsigned short* vs short[]) * C4100: unreferenced formal parameter * C4127: conditional expression is constant * C4163: '_rotl64' : not available as an intrinsic function * C4201: nonstandard extension nameless struct/unions * C4244: int to char/short - precision loss * C4514: unreferenced inline function removed */ #pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244) /* Ignore Microsoft's interpretation of secure development * and the POSIX string handling API */ #if defined(_MSC_VER) && _MSC_VER >= 1400 #ifndef _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE #endif #pragma warning(disable: 4996) #endif /* defined(_MSC_VER) && _MSC_VER >= 1400 */ #endif /* defined(WIN32) */ #include "jk_version.h" #ifdef HAVE_APR #include "apr_lib.h" #include "apr_strings.h" #include "apr_atomic.h" #endif #include #include #include #include #include #include #include #include #ifdef _OSD_POSIX #include "ap_config.h" #endif #ifdef AS400 #include "ap_config.h" extern char *strdup(const char *str); #endif #include #include #ifdef WIN32 #ifndef _WINDOWS_ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #ifndef _WIN32_WINNT /* Restrict the server to a subset of Windows NT 4.0 header files by default */ #define _WIN32_WINNT 0x0500 #endif #ifndef NOUSER #define NOUSER #endif #ifndef NOMCX #define NOMCX #endif #ifndef NOIME #define NOIME #endif #include /* * Add a _very_few_ declarations missing from the restricted set of headers * (If this list becomes extensive, re-enable the required headers above!) * winsock headers were excluded by WIN32_LEAN_AND_MEAN, so include them now */ #include #include #include #endif /* _WINDOWS_ */ #ifdef _WINDOWS_ #ifndef SIO_RCVALL #include #endif #endif #include #include #include #include #else /* WIN32 */ #include #include #include #include #include #include #include #include #if !defined(_OSD_POSIX) && !defined(AS400) && !defined(__CYGWIN__) && !defined(HPUX11) && !defined(PLATFORM_LINUX) #include #endif #if !defined(HPUX11) && !defined(AS400) #include #endif #include #include #endif /* WIN32 */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define JK_WORKER_FILE_TAG ("worker_file") #define JK_MOUNT_FILE_TAG ("worker_mount_file") #define JK_LOG_LEVEL_TAG ("log_level") #define JK_LOG_FILE_TAG ("log_file") #define JK_SHM_FILE_TAG ("shm_file") #define JK_WORKER_NAME_TAG ("worker") #define JK_WORKER_FILE_DEF ("workers.properties") /* Urimap reload check time. Use 60 seconds by default. */ #define JK_URIMAP_DEF_RELOAD (60) #define JK_TRUE (1) #define JK_FALSE (0) #define JK_UNSET (-1) #define JK_LF (10) #define JK_CR (13) #define JK_MAX_NAME_LEN (60) #define JK_SESSION_IDENTIFIER "JSESSIONID" #define JK_PATH_SESSION_IDENTIFIER ";jsessionid" #if defined(WIN32) #ifdef __GNUC__ #define JK_METHOD #define C_LEVEL_TRY_START #define C_LEVEL_TRY_END #define C_LEVEL_FINALLY_START #define C_LEVEL_FINALLY_END #else #define JK_METHOD __stdcall #define C_LEVEL_TRY_START __try { #define C_LEVEL_TRY_END } #define C_LEVEL_FINALLY_START __finally { #define C_LEVEL_FINALLY_END } #endif #define PATH_SEPERATOR (';') #define FILE_SEPERATOR ('\\') #define PATH_ENV_VARIABLE ("PATH") /* incompatible names... */ #ifndef strcasecmp #define strcasecmp stricmp #endif #else /* defined(WIN32) */ #define JK_METHOD #define C_LEVEL_TRY_START #define C_LEVEL_TRY_END #define C_LEVEL_FINALLY_START #define C_LEVEL_FINALLY_END #define PATH_SEPERATOR (':') #define FILE_SEPERATOR ('/') #define PATH_ENV_VARIABLE ("LD_LIBRARY_PATH") #endif /* defined(WIN32) */ /* HTTP Error codes */ #define JK_HTTP_OK 200 #define JK_HTTP_BAD_REQUEST 400 #define JK_HTTP_UNAUTHORIZED 401 #define JK_HTTP_REQUEST_TOO_LARGE 413 #define JK_HTTP_SERVER_ERROR 500 #define JK_HTTP_NOT_IMPLEMENTED 501 #define JK_HTTP_BAD_GATEWAY 502 #define JK_HTTP_SERVER_BUSY 503 #define JK_HTTP_GATEWAY_TIME_OUT 504 /* * RECO STATUS */ #define RECO_NONE 0x00 #define RECO_INITED 0x01 #define RECO_FILLED 0x02 /* * JK options */ #define JK_OPT_FWDURIMASK 0x0007 #define JK_OPT_FWDADDRMASK 0x0810 #define JK_OPT_FWDURICOMPAT 0x0001 #define JK_OPT_FWDURICOMPATUNPARSED 0x0002 #define JK_OPT_FWDURIESCAPED 0x0003 #define JK_OPT_FWDURIPROXY 0x0004 #define JK_OPT_FWDURIDEFAULT JK_OPT_FWDURIPROXY #define JK_OPT_FWDDIRS 0x0008 /* Forward local instead remote address */ #define JK_OPT_FWDLOCAL 0x0010 #define JK_OPT_FLUSHPACKETS 0x0020 #define JK_OPT_FLUSHEADER 0x0040 #define JK_OPT_DISABLEREUSE 0x0080 #define JK_OPT_FWDCERTCHAIN 0x0100 #define JK_OPT_FWDKEYSIZE 0x0200 #define JK_OPT_REJECTUNSAFE 0x0400 /* Forward physical tcp peer address instead of * client address as provided e.g. by httpd mod_remoteip. */ #define JK_OPT_FWDPHYSICAL 0x0800 #define JK_OPT_COLLAPSEMASK 0x7000 #define JK_OPT_COLLAPSEALL 0x1000 #define JK_OPT_COLLAPSENONE 0x2000 #define JK_OPT_COLLAPSEUNMOUNT 0x4000 #define JK_OPT_DEFAULT (JK_OPT_FWDURIDEFAULT | JK_OPT_FWDKEYSIZE) /* Check for EBCDIC systems */ /* Check for Apache 2.0 running on an EBCDIC system */ #if APR_CHARSET_EBCDIC #include #define USE_CHARSET_EBCDIC #define jk_xlate_to_ascii(b, l) ap_xlate_proto_to_ascii(b, l) #define jk_xlate_from_ascii(b, l) ap_xlate_proto_from_ascii(b, l) #else /* APR_CHARSET_EBCDIC */ /* Check for Apache 1.3 running on an EBCDIC system */ #ifdef CHARSET_EBCDIC #define USE_CHARSET_EBCDIC #define jk_xlate_to_ascii(b, l) ebcdic2ascii(b, b, l) #define jk_xlate_from_ascii(b, l) ascii2ebcdic(b, b, l) #else /* CHARSET_EBCDIC */ /* We're in on an ASCII system */ #define jk_xlate_to_ascii(b, l) /* NOOP */ #define jk_xlate_from_ascii(b, l) /* NOOP */ #endif /* CHARSET_EBCDIC */ #endif /* APR_CHARSET_EBCDIC */ /* on i5/OS V5R4 HTTP/APR APIs and Datas are in UTF */ #if defined(AS400_UTF8) #undef USE_CHARSET_EBCDIC #define jk_xlate_to_ascii(b, l) /* NOOP */ #define jk_xlate_from_ascii(b, l) /* NOOP */ #endif /* jk_uint32_t defines a four byte word */ /* jk_uint64_t defines a eight byte word */ #if defined (WIN32) typedef unsigned int jk_uint32_t; #define JK_UINT32_T_FMT "u" #define JK_UINT32_T_HEX_FMT "x" typedef unsigned __int64 jk_uint64_t; #define JK_UINT64_T_FMT "I64u" #define JK_UINT64_T_HEX_FMT "I64x" #define JK_PID_T_FMT "d" #define JK_PTHREAD_T_FMT "d" #elif defined(AS400) typedef unsigned int jk_uint32_t; #define JK_UINT32_T_FMT "u" #define JK_UINT32_T_HEX_FMT "x" typedef unsigned long long jk_uint64_t; #define JK_UINT64_T_FMT "llu" #define JK_UINT64_T_HEX_FMT "llx" #define JK_PID_T_FMT "d" #define JK_PTHREAD_T_FMT "d" #else #include "jk_types.h" #endif #define JK_UINT32_T_FMT_LEN (sizeof(JK_UINT32_T_FMT) - 1) #define JK_UINT32_T_HEX_FMT_LEN (sizeof(JK_UINT32_T_HEX_FMT) - 1) #define JK_UINT64_T_FMT_LEN (sizeof(JK_UINT64_T_FMT) - 1) #define JK_UINT64_T_HEX_FMT_LEN (sizeof(JK_UINT64_T_HEX_FMT) - 1) #ifdef WIN32 /* For WIN32, emulate gettimeofday() using _ftime() */ #define gettimeofday(tv, tz) { struct _timeb tb; _ftime(&tb); \ (tv)->tv_sec = (long)tb.time; \ (tv)->tv_usec = tb.millitm * 1000; } #define HAVE_VSNPRINTF #define HAVE_SNPRINTF #define HAVE_SOCKADDR_STORAGE #define HAVE_AF_INET6 #define HAVE_GETADDRINFO #ifdef HAVE_APR #define snprintf apr_snprintf #define vsnprintf apr_vsnprintf #else /* define snprint to match windows version */ #define snprintf _snprintf #define vsnprintf _vsnprintf #endif #endif /* WIN32" */ /* Use apr snprintf() and vsnprintf() when needed */ #if defined(HAVE_APR) #if !defined(HAVE_SNPRINTF) #define snprintf apr_snprintf #endif #if !defined(HAVE_VSNPRINTF) #define vsnprintf apr_vsnprintf #endif #endif /* Use ap snprintf() and vsnprintf() when needed */ #if !defined(HAVE_APR) #if !defined(HAVE_SNPRINTF) #define snprintf ap_snprintf #endif #if !defined(HAVE_VSNPRINTF) #define vsnprintf ap_vsnprintf #endif #endif #if defined(WIN32) typedef SOCKET jk_sock_t; #define IS_VALID_SOCKET(s) ((s) != INVALID_SOCKET) #define JK_INVALID_SOCKET INVALID_SOCKET #else typedef int jk_sock_t; #define IS_VALID_SOCKET(s) ((s) > 0) #define JK_INVALID_SOCKET (-1) #endif #if defined(_MSC_VER) && (_MSC_VER > 1200) #define stat _stat #endif #ifdef AS400_UTF8 #define strcasecmp(a,b) apr_strnatcasecmp(a,b) #endif /* Atomics */ #if defined(WIN32) #define JK_ATOMIC_INCREMENT(x) InterlockedIncrement(x) #define JK_ATOMIC_DECREMENT(x) \ do {\ if (InterlockedDecrement(x) < 0) InterlockedIncrement(x);\ } while (0) #elif defined(HAVE_ATOMIC_BUILTINS) #define JK_ATOMIC_INCREMENT(x) __sync_add_and_fetch(x, 1) #define JK_ATOMIC_DECREMENT(x) \ do {\ if (__sync_sub_and_fetch(x, 1) < 0) __sync_add_and_fetch(x, 1);\ } while (0) #elif defined(HAVE_APR) #define JK_ATOMIC_INCREMENT(x) ((int)apr_atomic_inc32((volatile apr_uint32_t *)x) + 1) #define JK_ATOMIC_DECREMENT(x) \ do {\ /* apr_atomic_add32 returns the *old* value */\ apr_uint32_t y;\ y = apr_atomic_add32((volatile apr_uint32_t *)x, -1);\ if (y == 0 || y > INT_MAX) apr_atomic_inc32((volatile apr_uint32_t *)x);\ } while (0) #else #define JK_ATOMIC_MISSING #define JK_ATOMIC_INCREMENT(x) (++(*x)) #define JK_ATOMIC_DECREMENT(x) \ do {\ if (--(*x) < 0) (++(*x));\ } while (0) #endif /* IPV6 support */ #if defined(HAVE_APR) #define JK_HAVE_IPV6 APR_HAVE_IPV6 #define JK_INET APR_INET #define JK_INET6 APR_INET6 #define JK_UNSPEC APR_UNSPEC #else #if defined(WIN32) || defined(HAVE_AF_INET6) #define JK_HAVE_IPV6 1 #define JK_INET6 AF_INET6 #else #define JK_HAVE_IPV6 0 #define JK_INET6 0 #endif #define JK_INET AF_INET #if defined(AF_UNSPEC) #define JK_UNSPEC AF_UNSPEC #else #define JK_UNSPEC 0 #endif #endif typedef struct jk_sockaddr_t jk_sockaddr_t; struct jk_sockaddr_t { int family; int port; int salen; int ipaddr_len; /** This points to the IP address structure within the appropriate * sockaddr structure. */ void *ipaddr_ptr; /** Union of either IPv4 or IPv6 sockaddr. */ union { /** IPv4 sockaddr structure */ struct sockaddr_in sin; #if JK_HAVE_IPV6 /** IPv6 sockaddr structure */ struct sockaddr_in6 sin6; #endif /** Placeholder to ensure that the size of this union is not * dependent on whether JK_HAVE_IPV6 is defined. */ #ifdef HAVE_SOCKADDR_STORAGE struct sockaddr_storage sas; #else char sas[128]; #endif } sa; }; #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_GLOBAL_H */ tomcat-connectors-1.2.50-src/native/common/jk_md5.c0000644000000000000020000003774414655113617020436 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * This is work is derived from material Copyright RSA Data Security, Inc. * * The RSA copyright statement and Licence for that original material is * included below. This is followed by the Apache copyright statement and * licence for the modifications made to that material. */ /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ /* * The ap_MD5Encode() routine uses much code obtained from the FreeBSD 3.0 * MD5 crypt() function, which is licenced as follows: * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- */ /*************************************************************************** * Description: MD5 encoding wrapper * * Author: Henri Gomez * ***************************************************************************/ /* * JK MD5 Encoding function (jk_MD5Encode) * * Jk delegate MD5 encoding to ap_MD5Encode when used in Apache Web-Server. * When another web-server is used like NES/IIS, we should use corresponding calls. * NES/IIS specialists will add the necessary code but until that, I reused the code * from Apache HTTP server. * * Nota: If you use an EBCDIC system without Apache, you'll have to use MD5 encoding * corresponding call or have a ebcdic2ascii() functions somewhere. * For example current AS/400 have MD5 encoding support APIs but olders not.... */ #include "jk_global.h" #include "jk_md5.h" char *JK_METHOD jk_hextocstr(unsigned char *org, char *dst, int n) { char *os = dst; unsigned char v; static unsigned char zitohex[] = "0123456789ABCDEF"; while (--n >= 0) { v = *org++; *dst++ = zitohex[v >> 4]; *dst++ = zitohex[v & 0x0f]; } *dst = 0; return (os); } #ifndef USE_APACHE_MD5 /* Constants for MD5Transform routine. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 static void MD5Transform(jk_uint32_t state[4], const unsigned char block[64]); static void Encode(unsigned char *output, const jk_uint32_t * input, size_t len); static void Decode(jk_uint32_t * output, const unsigned char *input, size_t len); static void jk_MD5Init(JK_MD5_CTX * context); static void jk_MD5Update(JK_MD5_CTX * context, const unsigned char *input, size_t inputLen); /*static void jk_MD5Final(unsigned char digest[JK_MD5_DIGESTSIZE], JK_MD5_CTX *context);*/ static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* F, G, H and I are basic MD5 functions. */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) /* ROTATE_LEFT rotates x left n bits. */ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ #define FF(a, b, c, d, x, s, ac) { \ (a) += F ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) { \ (a) += G ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) { \ (a) += H ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) { \ (a) += I ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } /* MD5 initialization. Begins an MD5 operation, writing a new context. */ static void jk_MD5Init(JK_MD5_CTX * context) { context->count[0] = context->count[1] = 0; /* Load magic initialization constants. */ context->state[0] = 0x67452301; context->state[1] = 0xefcdab89; context->state[2] = 0x98badcfe; context->state[3] = 0x10325476; } /* MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context. */ static void jk_MD5Update(JK_MD5_CTX * context, const unsigned char *input, size_t inputLen) { size_t i, idx, partLen; /* Compute number of bytes mod 64 */ idx = (size_t) ((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += ((jk_uint32_t) inputLen << 3)) < ((jk_uint32_t) inputLen << 3)) { context->count[1]++; } context->count[1] += (jk_uint32_t) inputLen >> 29; partLen = 64 - idx; /* Transform as many times as possible. */ #ifndef CHARSET_EBCDIC if (inputLen >= partLen) { memcpy(&context->buffer[idx], input, partLen); MD5Transform(context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) { MD5Transform(context->state, &input[i]); } idx = 0; } else { i = 0; } /* Buffer remaining input */ memcpy(&context->buffer[idx], &input[i], inputLen - i); #else /*CHARSET_EBCDIC */ if (inputLen >= partLen) { ebcdic2ascii(&context->buffer[idx], input, partLen); MD5Transform(context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) { unsigned char inp_tmp[64]; ebcdic2ascii(inp_tmp, &input[i], 64); MD5Transform(context->state, inp_tmp); } idx = 0; } else { i = 0; } /* Buffer remaining input */ ebcdic2ascii(&context->buffer[idx], &input[i], inputLen - i); #endif /*CHARSET_EBCDIC */ } /* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. */ static void JK_METHOD jk_MD5Final(unsigned char digest[16], JK_MD5_CTX * context) { unsigned char bits[8]; size_t idx, padLen; /* Save number of bits */ Encode(bits, context->count, 8); #ifdef CHARSET_EBCDIC /* XXX: @@@: In order to make this no more complex than necessary, * this kludge converts the bits[] array using the ascii-to-ebcdic * table, because the following jk_MD5Update() re-translates * its input (ebcdic-to-ascii). * Otherwise, we would have to pass a "conversion" flag to jk_MD5Update() */ ascii2ebcdic(bits, bits, 8); /* Since everything is converted to ascii within jk_MD5Update(), * the initial 0x80 (PADDING[0]) must be stored as 0x20 */ ascii2ebcdic(PADDING, PADDING, 1); #endif /*CHARSET_EBCDIC */ /* Pad out to 56 mod 64. */ idx = (size_t) ((context->count[0] >> 3) & 0x3f); padLen = (idx < 56) ? (56 - idx) : (120 - idx); jk_MD5Update(context, (const unsigned char *)PADDING, padLen); /* Append length (before padding) */ jk_MD5Update(context, (const unsigned char *)bits, 8); /* Store state in digest */ Encode(digest, context->state, 16); /* Zeroize sensitive information. */ memset(context, 0, sizeof(*context)); } /* MD5 basic transformation. Transforms state based on block. */ static void MD5Transform(jk_uint32_t state[4], const unsigned char block[64]) { jk_uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; Decode(x, block, 64); /* Round 1 */ FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ memset(x, 0, sizeof(x)); } /* Encodes input (jk_uint32_t) into output (unsigned char). Assumes len is a multiple of 4. */ static void Encode(unsigned char *output, const jk_uint32_t * input, size_t len) { size_t i, j; jk_uint32_t k; for (i = 0, j = 0; j < len; i++, j += 4) { k = input[i]; output[j] = (unsigned char)(k & 0xff); output[j + 1] = (unsigned char)((k >> 8) & 0xff); output[j + 2] = (unsigned char)((k >> 16) & 0xff); output[j + 3] = (unsigned char)((k >> 24) & 0xff); } } /* Decodes input (unsigned char) into output (jk_uint32_t). Assumes len is * a multiple of 4. */ static void Decode(jk_uint32_t * output, const unsigned char *input, size_t len) { size_t i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((jk_uint32_t) input[j]) | (((jk_uint32_t) input[j + 1]) << 8) | (((jk_uint32_t) input[j + 2]) << 16) | (((jk_uint32_t) input[j + 3]) << 24); } char *JK_METHOD jk_md5(const unsigned char *org, const unsigned char *org2, char *dst) { JK_MD5_CTX ctx; char buf[JK_MD5_DIGESTSIZE + 1]; jk_MD5Init(&ctx); jk_MD5Update(&ctx, org, strlen((const char *)org)); if (org2 != NULL) jk_MD5Update(&ctx, org2, strlen((const char *)org2)); jk_MD5Final((unsigned char *)buf, &ctx); return (jk_hextocstr((unsigned char *)buf, dst, JK_MD5_DIGESTSIZE)); } #else /* USE_APACHE_MD5 */ #include "httpd.h" #include "http_config.h" #ifdef STANDARD20_MODULE_STUFF #include "apr_md5.h" #define AP_MD5_CTX apr_md5_ctx_t #define ap_MD5Init apr_md5_init #define ap_MD5Update apr_md5_update #define ap_MD5Final apr_md5_final #else /* STANDARD20_MODULE_STUFF */ #include "ap_md5.h" #endif /* STANDARD20_MODULE_STUFF */ char *JK_METHOD jk_md5(const unsigned char *org, const unsigned char *org2, char *dst) { AP_MD5_CTX ctx; char buf[JK_MD5_DIGESTSIZE + 1]; ap_MD5Init(&ctx); ap_MD5Update(&ctx, org, strlen((const char *)org)); if (org2 != NULL) ap_MD5Update(&ctx, org2, strlen((const char *)org2)); ap_MD5Final((unsigned char *)buf, &ctx); return (jk_hextocstr((unsigned char *)buf, dst, JK_MD5_DIGESTSIZE)); } #endif /* USE_APACHE_MD5 */ /* Test values: * "" D4 1D 8C D9 8F 00 B2 04 E9 80 09 98 EC F8 42 7E * "a" 0C C1 75 B9 C0 F1 B6 A8 31 C3 99 E2 69 77 26 61 * "abc 90 01 50 98 3C D2 4F B0 D6 96 3F 7D 28 E1 7F 72 * "message digest" F9 6B 69 7D 7C B7 93 8D 52 5A 2F 31 AA F1 61 D0 * */ #ifdef TEST_JKMD5 main(int argc, char **argv) { char xxx[(2 * JK_MD5_DIGESTSIZE) + 1]; if (argc > 1) printf("%s => %s\n", argv[1], jk_md5(argv[1], NULL, xxx)); } #endif tomcat-connectors-1.2.50-src/native/common/jk_connect.c0000644000000000000020000013200414655113617021363 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Description: Socket/Naming manipulation functions * Based on: Various Jserv files */ /** * @package jk_connect * @author Gal Shachor * @author Mladen Turk */ #include "jk_connect.h" #include "jk_util.h" #ifdef HAVE_APR #include "apr_network_io.h" #include "apr_errno.h" #include "apr_general.h" #include "apr_pools.h" static apr_pool_t *jk_apr_pool = NULL; #endif #ifdef HAVE_SYS_FILIO_H /* FIONREAD on Solaris et al. */ #include #endif #ifdef HAVE_POLL_H /* Use poll instead select */ #include #endif #if defined(WIN32) #define JK_IS_SOCKET_ERROR(x) ((x) == SOCKET_ERROR) #define JK_GET_SOCKET_ERRNO() errno = WSAGetLastError() - WSABASEERR #else #define JK_IS_SOCKET_ERROR(x) ((x) == -1) #define JK_GET_SOCKET_ERRNO() ((void)0) #endif /* WIN32 */ #ifndef INET6_ADDRSTRLEN /* Maximum size of an IPv6 address in ASCII */ #define INET6_ADDRSTRLEN 46 #endif /* 2 IPv6 adresses of length (INET6_ADDRSTRLEN-1) * each suffixed with a ":" and a port (5 digits) * plus " -> " plus terminating "\0" */ #define DUMP_SINFO_BUF_SZ (2 * (INET6_ADDRSTRLEN - 1 + 1 + 5) + 4 + 1) #ifndef IN6ADDRSZ #define IN6ADDRSZ 16 #endif #ifndef INT16SZ #define INT16SZ sizeof(short) #endif #if !defined(EAFNOSUPPORT) && defined(WSAEAFNOSUPPORT) #define EAFNOSUPPORT WSAEAFNOSUPPORT #endif /** Set socket to blocking * @param sd socket to manipulate * @return errno: fcntl returns -1 (!WIN32) * pseudo errno: ioctlsocket returns SOCKET_ERROR (WIN32) * 0: success */ static int soblock(jk_sock_t sd) { /* BeOS uses setsockopt at present for non blocking... */ #if defined (WIN32) u_long on = 0; if (JK_IS_SOCKET_ERROR(ioctlsocket(sd, FIONBIO, &on))) { JK_GET_SOCKET_ERRNO(); return errno; } #else int fd_flags; fd_flags = fcntl(sd, F_GETFL, 0); #if defined(O_NONBLOCK) fd_flags &= ~O_NONBLOCK; #elif defined(O_NDELAY) fd_flags &= ~O_NDELAY; #elif defined(FNDELAY) fd_flags &= ~FNDELAY; #else #error Please teach JK how to make sockets blocking on your platform. #endif if (fcntl(sd, F_SETFL, fd_flags) == -1) { return errno; } #endif /* WIN32 */ return 0; } /** Set socket to non-blocking * @param sd socket to manipulate * @return errno: fcntl returns -1 (!WIN32) * pseudo errno: ioctlsocket returns SOCKET_ERROR (WIN32) * 0: success */ static int sononblock(jk_sock_t sd) { #if defined (WIN32) u_long on = 1; if (JK_IS_SOCKET_ERROR(ioctlsocket(sd, FIONBIO, &on))) { JK_GET_SOCKET_ERRNO(); return errno; } #else int fd_flags; fd_flags = fcntl(sd, F_GETFL, 0); #if defined(O_NONBLOCK) fd_flags |= O_NONBLOCK; #elif defined(O_NDELAY) fd_flags |= O_NDELAY; #elif defined(FNDELAY) fd_flags |= FNDELAY; #else #error Please teach JK how to make sockets non-blocking on your platform. #endif if (fcntl(sd, F_SETFL, fd_flags) == -1) { return errno; } #endif /* WIN32 */ return 0; } #if defined (WIN32) /* WIN32 implementation */ /** Non-blocking socket connect * @param sd socket to connect * @param addr address to connect to * @param source optional source address * @param timeout connect timeout in seconds * (<=0: no timeout=blocking) * @param l log context * @return -1: some kind of error occured * SOCKET_ERROR: no timeout given and error * during blocking connect * 0: success */ static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, jk_sockaddr_t *source, int timeout, jk_log_context_t *l) { int rc; char buf[64]; JK_TRACE_ENTER(l); if (source != NULL) { if (bind(sd, (const struct sockaddr *)&source->sa.sin, source->salen)) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "error during source bind on socket %d [%s] (errno=%d)", sd, jk_dump_hinfo(source, buf, sizeof(buf)), errno); } } if (timeout <= 0) { rc = connect(sd, (const struct sockaddr *)&addr->sa.sin, addr->salen); JK_TRACE_EXIT(l); return rc; } if ((rc = sononblock(sd))) { JK_TRACE_EXIT(l); return -1; } if (JK_IS_SOCKET_ERROR(connect(sd, (const struct sockaddr *)&addr->sa.sin, addr->salen))) { struct timeval tv; fd_set wfdset, efdset; if ((rc = WSAGetLastError()) != WSAEWOULDBLOCK) { soblock(sd); WSASetLastError(rc); JK_TRACE_EXIT(l); return -1; } /* wait for the connect to complete or timeout */ FD_ZERO(&wfdset); FD_SET(sd, &wfdset); FD_ZERO(&efdset); FD_SET(sd, &efdset); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; rc = select((int)sd + 1, NULL, &wfdset, &efdset, &tv); if (JK_IS_SOCKET_ERROR(rc) || rc == 0) { rc = WSAGetLastError(); soblock(sd); WSASetLastError(rc); JK_TRACE_EXIT(l); return -1; } /* Evaluate the efdset */ if (FD_ISSET(sd, &efdset)) { /* The connect failed. */ int rclen = (int)sizeof(rc); if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*) &rc, &rclen)) rc = 0; soblock(sd); if (rc) WSASetLastError(rc); JK_TRACE_EXIT(l); return -1; } } soblock(sd); JK_TRACE_EXIT(l); return 0; } #elif defined(HAVE_POLL_H) /* POSIX implementation using poll(2) */ /** Non-blocking socket connect * @param sd socket to connect * @param addr address to connect to * @param source optional source address * @param timeout connect timeout in seconds * (<=0: no timeout=blocking) * @param l log context * @return -1: some kind of error occured * 0: success */ static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, jk_sockaddr_t *source, int timeout, jk_log_context_t *l) { int rc = 0; char buf[64]; JK_TRACE_ENTER(l); if (source != NULL) { if (bind(sd, (const struct sockaddr *)&source->sa.sin, source->salen)) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "error during source bind on socket %d [%s] (errno=%d)", sd, jk_dump_hinfo(source, buf, sizeof(buf)), errno); } } if (timeout > 0) { if (sononblock(sd)) { JK_TRACE_EXIT(l); return -1; } } do { rc = connect(sd, (const struct sockaddr *)&addr->sa.sin, addr->salen); } while (rc == -1 && errno == EINTR); if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY) && (timeout > 0)) { struct pollfd pfd; socklen_t rclen = (socklen_t)sizeof(rc); pfd.fd = sd; pfd.events = POLLOUT; rc = poll(&pfd, 1, timeout); if (rc <= 0) { /* Save errno */ int err = errno; soblock(sd); errno = err; JK_TRACE_EXIT(l); return -1; } rc = 0; #ifdef SO_ERROR if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char *)&rc, &rclen) < 0 || rc) { if (rc) errno = rc; rc = -1; } #endif } soblock(sd); JK_TRACE_EXIT(l); return rc; } #else /* POSIX implementation using select(2) */ /** Non-blocking socket connect * @param sd socket to connect * @param addr address to connect to * @param source optional source address * @param timeout connect timeout in seconds * (<=0: no timeout=blocking) * @param l log context * @return -1: some kind of error occured * 0: success */ static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, jk_sockaddr_t *source, int timeout, jk_log_context_t *l) { int rc = 0; char buf[64]; JK_TRACE_ENTER(l); if (source != NULL) { if (bind(sd, (const struct sockaddr *)&source->sa.sin, source->salen)) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "error during source bind on socket %d [%s] (errno=%d)", sd, jk_dump_hinfo(source, buf, sizeof(buf)), errno); } } if (timeout > 0) { if (sononblock(sd)) { JK_TRACE_EXIT(l); return -1; } } do { rc = connect(sd, (const struct sockaddr *)&addr->sa.sin, addr->salen); } while (rc == -1 && errno == EINTR); if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY) && (timeout > 0)) { fd_set wfdset; struct timeval tv; socklen_t rclen = (socklen_t)sizeof(rc); FD_ZERO(&wfdset); FD_SET(sd, &wfdset); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; rc = select(sd + 1, NULL, &wfdset, NULL, &tv); if (rc <= 0) { /* Save errno */ int err = errno; soblock(sd); errno = err; JK_TRACE_EXIT(l); return -1; } rc = 0; #ifdef SO_ERROR if (!FD_ISSET(sd, &wfdset) || (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char *)&rc, &rclen) < 0) || rc) { if (rc) errno = rc; rc = -1; } #endif /* SO_ERROR */ } /* Not sure we can be already connected */ if (rc == -1 && errno == EISCONN) rc = 0; soblock(sd); JK_TRACE_EXIT(l); return rc; } #endif /** Clone a jk_sockaddr_t * @param out The source structure * @param in The target structure */ void jk_clone_sockaddr(jk_sockaddr_t *out, jk_sockaddr_t *in) { memcpy(out, in, sizeof(*in)); /* The ipaddr_ptr member points to memory inside the struct. * Do not copy the pointer but use the same offset relative * to the struct start */ out->ipaddr_ptr = (char *)out + ((char *)in->ipaddr_ptr - (char *)in); } /** Resolve the host IP * @param host host or ip address * @param port port * @param pool memory pool for allocation * @param prefer_ipv6 should IPv6 be preferred * @param l log context * @return JK_FALSE: some kind of error occured * JK_TRUE: success */ int jk_resolve(const char *host, int port, jk_sockaddr_t *saddr, void *pool, int prefer_ipv6, jk_log_context_t *l) { int family = JK_INET; struct in_addr iaddr; JK_TRACE_ENTER(l); memset(saddr, 0, sizeof(jk_sockaddr_t)); if (*host >= '0' && *host <= '9' && strspn(host, "0123456789.") == strlen(host)) { /* If we found only digits we use inet_addr() */ iaddr.s_addr = jk_inet_addr(host); memcpy(&(saddr->sa.sin.sin_addr), &iaddr, sizeof(struct in_addr)); } else { #ifdef HAVE_APR apr_sockaddr_t *remote_sa, *temp_sa; if (!jk_apr_pool) { if (apr_pool_create(&jk_apr_pool, (apr_pool_t *)pool) != APR_SUCCESS) { JK_TRACE_EXIT(l); return JK_FALSE; } } apr_pool_clear(jk_apr_pool); if (apr_sockaddr_info_get(&remote_sa, host, APR_UNSPEC, (apr_port_t)port, 0, jk_apr_pool) != APR_SUCCESS) { JK_TRACE_EXIT(l); return JK_FALSE; } /* Check if we have multiple address matches */ if (remote_sa->next) { /* Since we are only handling JK_INET (IPV4) address (in_addr_t) */ /* make sure we find one of those. */ temp_sa = remote_sa; #if APR_HAVE_IPV6 if (prefer_ipv6) { while ((NULL != temp_sa) && (APR_INET6 != temp_sa->family)) temp_sa = temp_sa->next; } #endif if (NULL != temp_sa) { remote_sa = temp_sa; } else { while ((NULL != temp_sa) && (APR_INET != temp_sa->family)) temp_sa = temp_sa->next; #if APR_HAVE_IPV6 if (NULL == temp_sa) { temp_sa = remote_sa; while ((NULL != temp_sa) && (APR_INET6 != temp_sa->family)) temp_sa = temp_sa->next; } #endif } /* if temp_sa is set, we have a valid address otherwise, just return */ if (NULL != temp_sa) { remote_sa = temp_sa; } else { JK_TRACE_EXIT(l); return JK_FALSE; } } if (remote_sa->family == APR_INET) { saddr->sa.sin = remote_sa->sa.sin; family = JK_INET; } #if APR_HAVE_IPV6 else { saddr->sa.sin6 = remote_sa->sa.sin6; family = JK_INET6; } #endif #else /* HAVE_APR */ /* Without APR go the classic way. */ #if defined(HAVE_GETADDRINFO) /* TODO: * 1. Check for numeric IPV6 addresses * 2. Do we need to set service name for getaddrinfo? */ struct addrinfo hints, *ai_list, *ai = NULL; int error; char pbuf[12]; char *pbufptr = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; #if JK_HAVE_IPV6 if (strchr(host, ':')) { /* If host name contains colon this must be IPV6 address. * Set prefer_ipv6 flag in this case if it wasn't set already */ prefer_ipv6 = 1; } if (prefer_ipv6) hints.ai_family = JK_INET6; else #endif hints.ai_family = JK_INET; if (port > 0) { snprintf(pbuf, sizeof(pbuf), "%d", port); pbufptr = pbuf; } error = getaddrinfo(host, pbufptr, &hints, &ai_list); #if JK_HAVE_IPV6 /* XXX: * Is the check for EAI_FAMILY/WSAEAFNOSUPPORT correct * way to retry the IPv4 address? */ if (error == EAI_FAMILY && prefer_ipv6) { hints.ai_family = JK_INET; error = getaddrinfo(host, pbufptr, &hints, &ai_list); } #endif if (error) { JK_TRACE_EXIT(l); errno = error; return JK_FALSE; } #if JK_HAVE_IPV6 if (prefer_ipv6) { ai = ai_list; while (ai) { if (ai->ai_family == JK_INET6) { /* ignore elements without required address info */ if((ai->ai_addr != NULL) && (ai->ai_addrlen > 0)) { family = JK_INET6; break; } } ai = ai->ai_next; } } #endif if (ai == NULL) { ai = ai_list; while (ai) { if (ai->ai_family == JK_INET) { /* ignore elements without required address info */ if((ai->ai_addr != NULL) && (ai->ai_addrlen > 0)) { family = JK_INET; break; } } ai = ai->ai_next; } } if (ai == NULL) { /* No address found * XXX: Use better error code? */ freeaddrinfo(ai_list); JK_TRACE_EXIT(l); errno = ENOENT; return JK_FALSE; } memcpy(&(saddr->sa), ai->ai_addr, ai->ai_addrlen); freeaddrinfo(ai_list); #else /* HAVE_GETADDRINFO */ struct hostent *hoste; /* XXX : WARNING : We should really use gethostbyname_r in multi-threaded env */ /* Fortunatly when APR is available, ie under Apache 2.0, we use it */ hoste = gethostbyname(host); if (!hoste) { JK_TRACE_EXIT(l); return JK_FALSE; } iaddr = *((struct in_addr *)hoste->h_addr_list[0]); memcpy(&(saddr->sa.sin.sin_addr), &iaddr, sizeof(struct in_addr)); #endif /* HAVE_GETADDRINFO */ #endif /* HAVE_APR */ } if (family == JK_INET) { saddr->ipaddr_ptr = &(saddr->sa.sin.sin_addr); saddr->ipaddr_len = (int)sizeof(struct in_addr); saddr->salen = (int)sizeof(struct sockaddr_in); } #if JK_HAVE_IPV6 else { saddr->ipaddr_ptr = &(saddr->sa.sin6.sin6_addr); saddr->ipaddr_len = (int)sizeof(struct in6_addr); saddr->salen = (int)sizeof(struct sockaddr_in6); } #endif saddr->sa.sin.sin_family = family; /* XXX IPv6: assumes sin_port and sin6_port at same offset */ saddr->sa.sin.sin_port = htons(port); saddr->port = port; saddr->family = family; JK_TRACE_EXIT(l); return JK_TRUE; } /** Connect to Tomcat * @param addr address to connect to * @param source source address to use * @param keepalive should we set SO_KEEPALIVE (if !=0) * @param timeout socket timeout in seconds * (<=0: no timeout=blocking) * @param connect_timeout connect timeout in seconds * @param sock_buf size of send and recv buffer * (<=0: use default) * @param l log context * @return JK_INVALID_SOCKET: some kind of error occured * created socket: success * @remark Cares about errno */ jk_sock_t jk_open_socket(jk_sockaddr_t *addr, jk_sockaddr_t *source, int keepalive, int timeout, int connect_timeout, int sock_buf, jk_log_context_t *l) { char buf[DUMP_SINFO_BUF_SZ]; jk_sock_t sd; int set = 1; int ret = 0; int flags = 0; #ifdef SO_LINGER struct linger li; #endif JK_TRACE_ENTER(l); errno = 0; #if defined(SOCK_CLOEXEC) && defined(USE_SOCK_CLOEXEC) flags |= SOCK_CLOEXEC; #endif sd = socket(addr->family, SOCK_STREAM | flags, 0); if (!IS_VALID_SOCKET(sd)) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "socket() failed (errno=%d)", errno); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } #if defined(FD_CLOEXEC) && !defined(USE_SOCK_CLOEXEC) if ((flags = fcntl(sd, F_GETFD)) == -1) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "fcntl() failed (errno=%d)", errno); jk_close_socket(sd, l); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } flags |= FD_CLOEXEC; if (fcntl(sd, F_SETFD, flags) == -1) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "fcntl() failed (errno=%d)", errno); jk_close_socket(sd, l); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } #endif /* Disable Nagle algorithm */ if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (const char*)&set, sizeof(set))) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "failed setting TCP_NODELAY (errno=%d)", errno); jk_close_socket(sd, l); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "socket TCP_NODELAY set to On"); if (keepalive) { #if defined(WIN32) DWORD dw; struct tcp_keepalive ka = { 0 }, ks = { 0 }; if (timeout) ka.keepalivetime = timeout * 10000; else ka.keepalivetime = 60 * 10000; /* 10 minutes */ ka.keepaliveinterval = 1000; ka.onoff = 1; if (WSAIoctl(sd, SIO_KEEPALIVE_VALS, &ka, sizeof(ka), &ks, sizeof(ks), &dw, NULL, NULL)) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "failed setting SIO_KEEPALIVE_VALS (errno=%d)", errno); jk_close_socket(sd, l); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "socket SO_KEEPALIVE set to %d seconds", ka.keepalivetime / 1000); #else set = 1; if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&set, sizeof(set))) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "failed setting SO_KEEPALIVE (errno=%d)", errno); jk_close_socket(sd, l); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "socket SO_KEEPALIVE set to On"); #endif } if (sock_buf > 0) { set = sock_buf; /* Set socket send buffer size */ if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (const char*)&set, sizeof(set))) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "failed setting SO_SNDBUF (errno=%d)", errno); jk_close_socket(sd, l); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } set = sock_buf; /* Set socket receive buffer size */ if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (const char*)&set, sizeof(set))) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "failed setting SO_RCVBUF (errno=%d)", errno); jk_close_socket(sd, l); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "socket SO_SNDBUF and SO_RCVBUF set to %d", sock_buf); } if (timeout > 0) { #if defined(WIN32) int tmout = timeout * 1000; setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (const char *) &tmout, sizeof(int)); setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, (const char *) &tmout, sizeof(int)); JK_GET_SOCKET_ERRNO(); #elif defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO) struct timeval tv; tv.tv_sec = timeout; tv.tv_usec = 0; setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (const void *) &tv, sizeof(tv)); setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, (const void *) &tv, sizeof(tv)); #endif if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "timeout %d set for socket=%d", timeout, sd); } #ifdef SO_NOSIGPIPE /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when * sending data to a dead peer. Possibly also existing and in use on other BSD * systems? */ set = 1; if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (const char *)&set, sizeof(int))) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "failed setting SO_NOSIGPIPE (errno=%d)", errno); jk_close_socket(sd, l); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } #endif #ifdef SO_LINGER /* Make hard closesocket by disabling lingering */ li.l_linger = li.l_onoff = 0; if (setsockopt(sd, SOL_SOCKET, SO_LINGER, (const char*)&li, sizeof(li))) { JK_GET_SOCKET_ERRNO(); jk_log(l, JK_LOG_ERROR, "failed setting SO_LINGER (errno=%d)", errno); jk_close_socket(sd, l); JK_TRACE_EXIT(l); return JK_INVALID_SOCKET; } #endif /* Tries to connect to Tomcat (continues trying while error is EINTR) */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "trying to connect socket %d to %s", sd, jk_dump_hinfo(addr, buf, sizeof(buf))); /* Need more infos for BSD 4.4 and Unix 98 defines, for now only iSeries when Unix98 is required at compile time */ #if (_XOPEN_SOURCE >= 520) && defined(AS400) ((struct sockaddr *)addr)->sa.sin.sa_len = sizeof(struct sockaddr_in); #endif ret = nb_connect(sd, addr, source, connect_timeout, l); #if defined(WIN32) if (JK_IS_SOCKET_ERROR(ret)) { JK_GET_SOCKET_ERRNO(); } #endif /* WIN32 */ /* Check if we are connected */ if (ret) { jk_log(l, JK_LOG_INFO, "connect to %s failed (errno=%d)", jk_dump_hinfo(addr, buf, sizeof(buf)), errno); jk_close_socket(sd, l); sd = JK_INVALID_SOCKET; } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "socket %d [%s] connected", sd, jk_dump_sinfo(sd, buf, sizeof(buf))); } JK_TRACE_EXIT(l); return sd; } /** Close the socket * @param sd socket to close * @param l log context * @return -1: some kind of error occured (!WIN32) * SOCKET_ERROR: some kind of error occured (WIN32) * 0: success * @remark Does not change errno */ int jk_close_socket(jk_sock_t sd, jk_log_context_t *l) { int rc; int save_errno; JK_TRACE_ENTER(l); if (!IS_VALID_SOCKET(sd)) { JK_TRACE_EXIT(l); return -1; } save_errno = errno; #if defined(WIN32) rc = closesocket(sd) ? -1 : 0; #else do { rc = close(sd); } while (JK_IS_SOCKET_ERROR(rc) && (errno == EINTR || errno == EAGAIN)); #endif JK_TRACE_EXIT(l); errno = save_errno; return rc; } #ifndef MAX_SECS_TO_LINGER #define MAX_SECS_TO_LINGER 2 #endif #ifndef MS_TO_LINGER #define MS_TO_LINGER 100 #endif #ifndef MS_TO_LINGER_LAST #define MS_TO_LINGER_LAST 20 #endif #ifndef MAX_READ_RETRY #define MAX_READ_RETRY 10 #endif #ifndef MAX_LINGER_BYTES #define MAX_LINGER_BYTES 32768 #endif #ifndef SHUT_WR #ifdef SD_SEND #define SHUT_WR SD_SEND #else #define SHUT_WR 0x01 #endif #endif #ifndef SHUT_RD #ifdef SD_RECEIVE #define SHUT_RD SD_RECEIVE #else #define SHUT_RD 0x00 #endif #endif /** Drain and close the socket * @param sd socket to close * @param l log context * @return -1: socket to close is invalid * -1: some kind of error occured (!WIN32) * SOCKET_ERROR: some kind of error occured (WIN32) * 0: success * @remark Does not change errno */ int jk_shutdown_socket(jk_sock_t sd, jk_log_context_t *l) { char dummy[512]; char buf[DUMP_SINFO_BUF_SZ]; char *sb = NULL; int rc = 0; size_t rd = 0; size_t rp = 0; int save_errno; int timeout = MS_TO_LINGER; time_t start = time(NULL); JK_TRACE_ENTER(l); if (!IS_VALID_SOCKET(sd)) { JK_TRACE_EXIT(l); return -1; } save_errno = errno; if (JK_IS_DEBUG_LEVEL(l)) { sb = jk_dump_sinfo(sd, buf, sizeof(buf)); jk_log(l, JK_LOG_DEBUG, "About to shutdown socket %d [%s]", sd, sb); } /* Shut down the socket for write, which will send a FIN * to the peer. */ if (shutdown(sd, SHUT_WR)) { rc = jk_close_socket(sd, l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Failed sending SHUT_WR for socket %d [%s]", sd, sb); errno = save_errno; JK_TRACE_EXIT(l); return rc; } do { rp = 0; if (jk_is_input_event(sd, timeout, l)) { /* Do a restartable read on the socket * draining out all the data currently in the socket buffer. */ int num = 0; do { num++; #if defined(WIN32) rc = recv(sd, &dummy[0], sizeof(dummy), 0); if (JK_IS_SOCKET_ERROR(rc)) JK_GET_SOCKET_ERRNO(); #else rc = read(sd, &dummy[0], sizeof(dummy)); #endif if (rc > 0) rp += rc; } while (JK_IS_SOCKET_ERROR(rc) && (errno == EINTR || errno == EAGAIN) && num < MAX_READ_RETRY); if (rc < 0) { /* Read failed. * Bail out from the loop. */ break; } } else { /* Error or timeout (reason is logged within jk_is_input_event) * Exit the drain loop */ break; } rd += rp; if (rp < sizeof(dummy)) { if (timeout > MS_TO_LINGER_LAST) { /* Try one last time with a short timeout */ timeout = MS_TO_LINGER_LAST; continue; } /* We have read less then size of buffer * It's a good chance there will be no more data * to read. */ if ((rc = sononblock(sd))) { rc = jk_close_socket(sd, l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "error setting socket %d [%s] to nonblocking", sd, sb); errno = save_errno; JK_TRACE_EXIT(l); return rc; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "shutting down the read side of socket %d [%s]", sd, sb); shutdown(sd, SHUT_RD); break; } timeout = MS_TO_LINGER; } while ((rd < MAX_LINGER_BYTES) && (difftime(time(NULL), start) < MAX_SECS_TO_LINGER)); rc = jk_close_socket(sd, l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Shutdown socket %d [%s] and read %d lingering bytes in %d sec.", sd, sb, rd, (int)difftime(time(NULL), start)); errno = save_errno; JK_TRACE_EXIT(l); return rc; } /** send a message * @param sd socket to use * @param b buffer containing the data * @param len length to send * @param l log context * @return negative errno: write returns a fatal -1 (!WIN32) * negative pseudo errno: send returns SOCKET_ERROR (WIN32) * JK_SOCKET_EOF: no bytes could be sent * >0: success, provided number of bytes send * @remark Always closes socket in case of error * @remark Cares about errno * @bug this fails on Unixes if len is too big for the underlying * protocol */ int jk_tcp_socket_sendfull(jk_sock_t sd, const unsigned char *b, int len, jk_log_context_t *l) { int sent = 0; int wr; JK_TRACE_ENTER(l); errno = 0; while (sent < len) { do { #if defined(WIN32) wr = send(sd, (const char*)(b + sent), len - sent, 0); if (JK_IS_SOCKET_ERROR(wr)) JK_GET_SOCKET_ERRNO(); #else wr = write(sd, b + sent, len - sent); #endif } while (JK_IS_SOCKET_ERROR(wr) && (errno == EINTR || errno == EAGAIN)); if (JK_IS_SOCKET_ERROR(wr)) { int err; jk_shutdown_socket(sd, l); err = (errno > 0) ? -errno : errno; JK_TRACE_EXIT(l); return err; } else if (wr == 0) { jk_shutdown_socket(sd, l); JK_TRACE_EXIT(l); return JK_SOCKET_EOF; } sent += wr; } JK_TRACE_EXIT(l); return sent; } /** receive a message * @param sd socket to use * @param b buffer to store the data * @param len length to receive * @param l log context * @return negative errno: read returns a fatal -1 (!WIN32) * negative pseudo errno: recv returns SOCKET_ERROR (WIN32) * JK_SOCKET_EOF: no bytes could be read * >0: success, requested number of bytes received * @remark Always closes socket in case of error * @remark Cares about errno */ int jk_tcp_socket_recvfull(jk_sock_t sd, unsigned char *b, int len, jk_log_context_t *l) { int rdlen = 0; int rd; JK_TRACE_ENTER(l); errno = 0; while (rdlen < len) { do { #if defined(WIN32) rd = recv(sd, (char *)b + rdlen, len - rdlen, 0); if (JK_IS_SOCKET_ERROR(rd)) JK_GET_SOCKET_ERRNO(); #else rd = read(sd, (char *)b + rdlen, len - rdlen); #endif } while (JK_IS_SOCKET_ERROR(rd) && errno == EINTR); if (JK_IS_SOCKET_ERROR(rd)) { int err = (errno > 0) ? -errno : errno; jk_shutdown_socket(sd, l); JK_TRACE_EXIT(l); return (err == 0) ? JK_SOCKET_EOF : err; } else if (rd == 0) { jk_shutdown_socket(sd, l); JK_TRACE_EXIT(l); return JK_SOCKET_EOF; } rdlen += rd; } JK_TRACE_EXIT(l); return rdlen; } /* const char * * inet_ntop4(src, dst, size) * format an IPv4 address, more or less like inet_ntoa() * return: * `dst' (as a const) * notes: * (1) uses no statics * (2) takes a u_char* not an in_addr as input * author: * Paul Vixie, 1996. */ static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size) { const size_t MIN_SIZE = 16; /* space for 255.255.255.255\0 */ int n = 0; char *next = dst; if (size < MIN_SIZE) { errno = ENOSPC; return NULL; } do { unsigned char u = *src++; if (u > 99) { *next++ = '0' + u/100; u %= 100; *next++ = '0' + u/10; u %= 10; } else if (u > 9) { *next++ = '0' + u/10; u %= 10; } *next++ = '0' + u; *next++ = '.'; n++; } while (n < 4); *--next = '\0'; return dst; } #if JK_HAVE_IPV6 /* const char * * inet_ntop6(src, dst, size) * convert IPv6 binary address into presentation (printable) format * author: * Paul Vixie, 1996. */ static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size) { /* * Note that int32_t and int16_t need only be "at least" large enough * to contain a value of the specified size. On some systems, like * Crays, there is no such thing as an integer variable with 16 bits. * Keep this in mind if you think this function should have been coded * to use pointer overlays. All the world's not a VAX. */ char tmp[INET6_ADDRSTRLEN], *tp; struct { int base, len; } best = {-1, 0}, cur = {-1, 0}; unsigned int words[IN6ADDRSZ / INT16SZ]; int i; const unsigned char *next_src, *src_end; unsigned int *next_dest; /* * Preprocess: * Copy the input (bytewise) array into a wordwise array. * Find the longest run of 0x00's in src[] for :: shorthanding. */ next_src = src; src_end = src + IN6ADDRSZ; next_dest = words; i = 0; do { unsigned int next_word = (unsigned int)*next_src++; next_word <<= 8; next_word |= (unsigned int)*next_src++; *next_dest++ = next_word; if (next_word == 0) { if (cur.base == -1) { cur.base = i; cur.len = 1; } else { cur.len++; } } else { if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) { best = cur; } cur.base = -1; } } i++; } while (next_src < src_end); if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) { best = cur; } } if (best.base != -1 && best.len < 2) { best.base = -1; } /* * Format the result. */ tp = tmp; for (i = 0; i < (IN6ADDRSZ / INT16SZ);) { /* Are we inside the best run of 0x00's? */ if (i == best.base) { *tp++ = ':'; i += best.len; continue; } /* Are we following an initial run of 0x00s or any real hex? */ if (i != 0) { *tp++ = ':'; } /* Is this address an encapsulated IPv4? */ if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) { return (NULL); } tp += strlen(tp); break; } tp += sprintf(tp, "%x", words[i]); i++; } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { *tp++ = ':'; } *tp++ = '\0'; /* * Check for overflow, copy, and we're done. */ if ((size_t)(tp - tmp) > size) { errno = ENOSPC; return NULL; } strcpy(dst, tmp); return dst; } #endif /** * dump a jk_sockaddr_t in A.B.C.D:P in ASCII buffer * */ char *jk_dump_hinfo(jk_sockaddr_t *saddr, char *buf, size_t size) { char pb[8]; if (saddr->ipaddr_ptr == NULL) { strcpy(buf, "UnresolvedIP"); } else { if (saddr->family == JK_INET) { inet_ntop4(saddr->ipaddr_ptr, buf, size); } #if JK_HAVE_IPV6 else { inet_ntop6(saddr->ipaddr_ptr, buf, size); } #endif } sprintf(pb, ":%d", saddr->port); strncat(buf, pb, size - strlen(buf) - 1); return buf; } char *jk_dump_sinfo(jk_sock_t sd, char *buf, size_t size) { struct sockaddr rsaddr; struct sockaddr lsaddr; socklen_t salen; salen = sizeof(struct sockaddr); if (getsockname(sd, &lsaddr, &salen) == 0) { salen = sizeof(struct sockaddr); if (getpeername(sd, &rsaddr, &salen) == 0) { char pb[8]; size_t ps; if (lsaddr.sa_family == JK_INET) { struct sockaddr_in *sa = (struct sockaddr_in *)&lsaddr; inet_ntop4((unsigned char *)&sa->sin_addr, buf, size); sprintf(pb, ":%d", (unsigned int)htons(sa->sin_port)); } #if JK_HAVE_IPV6 else { struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&lsaddr; inet_ntop6((unsigned char *)&sa->sin6_addr, buf, size); sprintf(pb, ":%d", (unsigned int)htons(sa->sin6_port)); } #endif ps = strlen(buf); strncat(buf, pb, size - ps - 1); ps = strlen(buf); strncat(buf, " -> ", size - ps - 1); ps = strlen(buf); if (rsaddr.sa_family == JK_INET) { struct sockaddr_in *sa = (struct sockaddr_in *)&rsaddr; inet_ntop4((unsigned char *)&sa->sin_addr, buf + ps, size - ps); sprintf(pb, ":%d", (unsigned int)htons(sa->sin_port)); } #if JK_HAVE_IPV6 else { struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&rsaddr; inet_ntop6((unsigned char *)&sa->sin6_addr, buf + ps, size - ps); sprintf(pb, ":%d", (unsigned int)htons(sa->sin6_port)); } #endif strncat(buf, pb, size - strlen(buf) - 1); return buf; } } snprintf(buf, size, "errno=%d", errno); return buf; } /** Wait for input event on socket until timeout * @param sd socket to use * @param timeout wait timeout in milliseconds * @param l log context * @return JK_FALSE: Timeout expired without something to read * JK_FALSE: Error during waiting * JK_TRUE: success * @remark Does not close socket in case of error * to allow for iterative waiting * @remark Cares about errno */ #ifdef HAVE_POLL int jk_is_input_event(jk_sock_t sd, int timeout, jk_log_context_t *l) { struct pollfd fds; int rc; int save_errno; char buf[DUMP_SINFO_BUF_SZ]; JK_TRACE_ENTER(l); errno = 0; fds.fd = sd; fds.events = POLLIN; fds.revents = 0; do { rc = poll(&fds, 1, timeout); } while (rc < 0 && errno == EINTR); if (rc == 0) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "timeout during poll on socket %d [%s] (timeout=%d)", sd, jk_dump_sinfo(sd, buf, sizeof(buf)), timeout); } /* Timeout. Set the errno to timeout */ errno = ETIMEDOUT; JK_TRACE_EXIT(l); return JK_FALSE; } else if (rc < 0) { save_errno = errno; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "error during poll on socket %d [%s] (errno=%d)", sd, jk_dump_sinfo(sd, buf, sizeof(buf)), errno); } errno = save_errno; JK_TRACE_EXIT(l); return JK_FALSE; } if ((fds.revents & (POLLERR | POLLHUP))) { save_errno = fds.revents & (POLLERR | POLLHUP); if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "error event during poll on socket %d [%s] (event=%d)", sd, jk_dump_sinfo(sd, buf, sizeof(buf)), save_errno); } errno = save_errno; JK_TRACE_EXIT(l); return JK_FALSE; } errno = 0; JK_TRACE_EXIT(l); return JK_TRUE; } #else int jk_is_input_event(jk_sock_t sd, int timeout, jk_log_context_t *l) { fd_set rset; struct timeval tv; int rc; int save_errno; char buf[DUMP_SINFO_BUF_SZ]; JK_TRACE_ENTER(l); errno = 0; FD_ZERO(&rset); FD_SET(sd, &rset); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; do { rc = select((int)sd + 1, &rset, NULL, NULL, &tv); } while (rc < 0 && errno == EINTR); if (rc == 0) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "timeout during select on socket %d [%s] (timeout=%d)", sd, jk_dump_sinfo(sd, buf, sizeof(buf)), timeout); } /* Timeout. Set the errno to timeout */ #if defined(WIN32) errno = WSAETIMEDOUT - WSABASEERR; #else errno = ETIMEDOUT; #endif JK_TRACE_EXIT(l); return JK_FALSE; } else if (rc < 0) { save_errno = errno; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "error during select on socket %d [%s] (errno=%d)", sd, jk_dump_sinfo(sd, buf, sizeof(buf)), errno); } errno = save_errno; JK_TRACE_EXIT(l); return JK_FALSE; } errno = 0; JK_TRACE_EXIT(l); return JK_TRUE; } #endif /** Test if a socket is still connected * @param sd socket to use * @param l log context * @return JK_FALSE: failure * JK_TRUE: success * @remark Always closes socket in case of error * @remark Cares about errno */ #ifdef HAVE_POLL int jk_is_socket_connected(jk_sock_t sd, jk_log_context_t *l) { struct pollfd fds; int rc; JK_TRACE_ENTER(l); errno = 0; fds.fd = sd; fds.events = POLLIN; do { rc = poll(&fds, 1, 0); } while (rc < 0 && errno == EINTR); if (rc == 0) { /* If we get a timeout, then we are still connected */ JK_TRACE_EXIT(l); return JK_TRUE; } else if (rc == 1 && fds.revents == POLLIN) { char buf; do { rc = (int)recvfrom(sd, &buf, 1, MSG_PEEK, NULL, NULL); } while (rc < 0 && errno == EINTR); if (rc == 1) { /* There is at least one byte to read. */ JK_TRACE_EXIT(l); return JK_TRUE; } } jk_shutdown_socket(sd, l); JK_TRACE_EXIT(l); return JK_FALSE; } #else int jk_is_socket_connected(jk_sock_t sd, jk_log_context_t *l) { fd_set fd; struct timeval tv; int rc; JK_TRACE_ENTER(l); errno = 0; FD_ZERO(&fd); FD_SET(sd, &fd); /* Initially test the socket without any blocking. */ tv.tv_sec = 0; tv.tv_usec = 0; do { rc = select((int)sd + 1, &fd, NULL, NULL, &tv); JK_GET_SOCKET_ERRNO(); /* Wait one microsecond on next select, if EINTR */ tv.tv_sec = 0; tv.tv_usec = 1; } while (JK_IS_SOCKET_ERROR(rc) && errno == EINTR); errno = 0; if (rc == 0) { /* If we get a timeout, then we are still connected */ JK_TRACE_EXIT(l); return JK_TRUE; } else if (rc == 1) { #if defined(WIN32) u_long nr; rc = ioctlsocket(sd, FIONREAD, &nr); if (rc == 0) { if (WSAGetLastError() == 0) errno = 0; else JK_GET_SOCKET_ERRNO(); } #else int nr; rc = ioctl(sd, FIONREAD, (void*)&nr); #endif if (rc == 0 && nr != 0) { JK_TRACE_EXIT(l); return JK_TRUE; } JK_GET_SOCKET_ERRNO(); } jk_shutdown_socket(sd, l); JK_TRACE_EXIT(l); return JK_FALSE; } #endif tomcat-connectors-1.2.50-src/native/common/jk_mt.h0000644000000000000020000001011614655113617020356 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Multi thread portability code for JK * * Author: Gal Shachor * ***************************************************************************/ #ifndef _JK_MT_H #define _JK_MT_H #include "jk_global.h" #if defined(WIN32) #define jk_gettid() ((jk_uint32_t)GetCurrentThreadId()) #endif #ifdef JK_PREFORK #define _MT_CODE 0 #else #define _MT_CODE 1 #endif /* * Marks execution under MT compilation */ #if _MT_CODE #ifdef WIN32 #include typedef CRITICAL_SECTION JK_CRIT_SEC; #define JK_INIT_CS(x, rc) InitializeCriticalSection(x); rc = JK_TRUE #define JK_DELETE_CS(x) DeleteCriticalSection(x) #define JK_ENTER_CS(x) EnterCriticalSection(x) #define JK_LEAVE_CS(x) LeaveCriticalSection(x) #else /* !WIN32 */ #define _MT_CODE_PTHREAD #include #include #include typedef pthread_mutex_t JK_CRIT_SEC; #define JK_INIT_CS(x, rc) \ if (pthread_mutex_init(x, NULL)) rc = JK_FALSE; else rc = JK_TRUE #define JK_DELETE_CS(x) pthread_mutex_destroy(x) #define JK_ENTER_CS(x) pthread_mutex_lock(x) #define JK_LEAVE_CS(x) pthread_mutex_unlock(x) #if defined(AS400) #define jk_pthread_t jk_uint32_t #endif /* AS400 */ jk_pthread_t jk_gettid(void); #endif /* WIN32 */ #else /* !_MT_CODE */ typedef void *JK_CRIT_SEC; #define JK_INIT_CS(x, rc) rc = JK_TRUE #define JK_DELETE_CS(x) (void)0 #define JK_ENTER_CS(x) (void)0 #define JK_LEAVE_CS(x) (void)0 #define jk_gettid() 0 #endif /* MT_CODE */ #if !defined(WIN32) #include #include #if HAVE_FLOCK #ifdef JK_USE_FLOCK #define USE_FLOCK_LK 1 #endif #endif #ifndef USE_FLOCK_LK #define USE_FLOCK_LK 0 #endif #if USE_FLOCK_LK #include #define JK_ENTER_LOCK(x, rc) \ do { \ while ((rc = flock((x), LOCK_EX) < 0) && (errno == EINTR)); \ rc = rc == 0 ? JK_TRUE : JK_FALSE; \ } while (0) #define JK_LEAVE_LOCK(x, rc) \ do { \ while ((rc = flock((x), LOCK_UN) < 0) && (errno == EINTR)); \ rc = rc == 0 ? JK_TRUE : JK_FALSE; \ } while (0) #else /* !USE_FLOCK_LK */ #define JK_ENTER_LOCK(x, rc) \ do { \ struct flock _fl; \ _fl.l_type = F_WRLCK; \ _fl.l_whence = SEEK_SET; \ _fl.l_start = 0; \ _fl.l_len = 1L; \ _fl.l_pid = 0; \ while ((rc = fcntl((x), F_SETLKW, &_fl) < 0) && (errno == EINTR)); \ rc = rc == 0 ? JK_TRUE : JK_FALSE; \ } while (0) #define JK_LEAVE_LOCK(x, rc) \ do { \ struct flock _fl; \ _fl.l_type = F_UNLCK; \ _fl.l_whence = SEEK_SET; \ _fl.l_start = 0; \ _fl.l_len = 1L; \ _fl.l_pid = 0; \ while ((rc = fcntl((x), F_SETLKW, &_fl) < 0) && (errno == EINTR)); \ rc = rc == 0 ? JK_TRUE : JK_FALSE; \ } while (0) #endif /* USE_FLOCK_LK */ #else /* WIN32 */ #define JK_ENTER_LOCK(x, rc) rc = JK_TRUE #define JK_LEAVE_LOCK(x, rc) rc = JK_TRUE #endif #endif /* _JK_MT_H */ tomcat-connectors-1.2.50-src/native/common/jk_map.c0000644000000000000020000006251014655113617020513 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: General purpose map object * * Author: Gal Shachor * * Author: Mladen Turk * ***************************************************************************/ #if defined(AS400) && !defined(AS400_UTF8) #include "apr_xlate.h" #endif #include "jk_global.h" #include "jk_pool.h" #include "jk_util.h" #include "jk_map.h" #define CAPACITY_INC_SIZE (50) #define LENGTH_OF_LINE (8192) #define JK_MAP_RECURSION (20) #define JK_MAP_REFERENCE (".reference") #define JK_MAP_REFERENCE_SZ (strlen(JK_MAP_REFERENCE)) /* Taken from APR tables/apr_hash.c */ /* * This is the popular `times 33' hash algorithm which is used by * perl and also appears in Berkeley DB. This is one of the best * known hash functions for strings because it is both computed * very fast and distributes very well. * * The originator may be Dan Bernstein but the code in Berkeley DB * cites Chris Torek as the source. The best citation I have found * is "Chris Torek, Hash function for text in C, Usenet message * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich * Salz's USENIX 1992 paper about INN which can be found at * . * * The magic of number 33, i.e. why it works better than many other * constants, prime or not, has never been adequately explained by * anyone. So I try an explanation: if one experimentally tests all * multipliers between 1 and 256 (as I did while writing a low-level * data structure library some time ago) one detects that even * numbers are not useable at all. The remaining 128 odd numbers * (except for the number 1) work more or less all equally well. * They all distribute in an acceptable way and this way fill a hash * table with an average percent of approx. 86%. * * If one compares the chi^2 values of the variants (see * Bob Jenkins ``Hashing Frequently Asked Questions'' at * http://burtleburtle.net/bob/hash/hashfaq.html for a description * of chi^2), the number 33 not even has the best value. But the * number 33 and a few other equally good numbers like 17, 31, 63, * 127 and 129 have nevertheless a great advantage to the remaining * numbers in the large set of possible multipliers: their multiply * operation can be replaced by a faster operation based on just one * shift plus either a single addition or subtraction operation. And * because a hash function has to both distribute good _and_ has to * be very fast to compute, those few numbers should be preferred. * * -- Ralf S. Engelschall */ #define COMPUTE_KEY_HASH(key, hash) \ { \ const unsigned char *p; \ hash = 0; \ for (p = (const unsigned char *)key; *p; p++) { \ hash = hash * 33 + *p; \ } \ } static volatile int global_map_id = 0; static void trim_prp_comment(char *prp); static size_t trim(char *s); static int map_realloc(jk_map_t *m); static char *jk_map_replace_properties(jk_map_t *m, jk_map_t *env, char *value); int jk_map_alloc(jk_map_t **m) { if (m) { *m = (jk_map_t *)calloc(1, sizeof(jk_map_t)); if (*m) return jk_map_open(*m); } return JK_FALSE; } int jk_map_free(jk_map_t **m) { int rc = JK_FALSE; if (m && *m) { jk_map_close(*m); free(*m); *m = NULL; } return rc; } int jk_map_open(jk_map_t *m) { int rc = JK_FALSE; if (m) { jk_open_pool(&m->p, m->buf, sizeof(jk_pool_atom_t) * SMALL_POOL_SIZE); m->id = ++global_map_id; m->capacity = 0; m->size = 0; m->keys = NULL; m->names = NULL; m->values = NULL; rc = JK_TRUE; } return rc; } int jk_map_close(jk_map_t *m) { int rc = JK_FALSE; if (m) { jk_close_pool(&m->p); rc = JK_TRUE; } return rc; } void *jk_map_get(jk_map_t *m, const char *name, const void *def) { const void *rc = (void *)def; if (m && name) { unsigned int i; unsigned int hash; COMPUTE_KEY_HASH(name, hash) for (i = 0; i < m->size; i++) { if (m->keys[i] == hash && strcmp(m->names[i], name) == 0) { rc = m->values[i]; break; } } } return (void *)rc; /* DIRTY */ } int jk_map_get_id(jk_map_t *m, const char *name) { int rc = -1; if (m && name) { unsigned int i; unsigned int hash; COMPUTE_KEY_HASH(name, hash) for (i = 0; i < m->size; i++) { if (m->keys[i] == hash && strcmp(m->names[i], name) == 0) { rc = i; break; } } } return rc; } const char *jk_map_get_string(jk_map_t *m, const char *name, const char *def) { const char *rc = def; if (m && name) { unsigned int i; unsigned int hash; COMPUTE_KEY_HASH(name, hash) for (i = 0; i < m->size; i++) { if (m->keys[i] == hash && strcmp(m->names[i], name) == 0) { rc = m->values[i]; break; } } } return rc; } int jk_map_get_int(jk_map_t *m, const char *name, int def) { char buf[100]; const char *rc; size_t len; int int_res; sprintf(buf, "%d", def); rc = jk_map_get_string(m, name, buf); len = strlen(rc); if (len) { const char *lastchar = &rc[0] + len - 1; int multit = 1; if ('m' == *lastchar || 'M' == *lastchar) { multit = 1024 * 1024; } else if ('k' == *lastchar || 'K' == *lastchar) { multit = 1024; } /* Safe because atoi() will stop at any non-numeric lastchar */ int_res = atoi(rc) * multit; } else int_res = def; return int_res; } double jk_map_get_double(jk_map_t *m, const char *name, double def) { char buf[100]; const char *rc; sprintf(buf, "%f", def); rc = jk_map_get_string(m, name, buf); return atof(rc); } int jk_map_get_bool(jk_map_t *m, const char *name, int def) { char buf[100]; const char *rc; sprintf(buf, "%d", def); rc = jk_map_get_string(m, name, buf); return jk_get_bool_code(rc, def); } char **jk_map_get_string_list(jk_map_t *m, const char *name, unsigned int *list_len, const char *def) { const char *l = jk_map_get_string(m, name, def); char **ar = NULL; #ifdef _MT_CODE_PTHREAD char *lasts; #endif *list_len = 0; if (l) { unsigned capacity = 0; unsigned idex = 0; char *p; char *v = jk_pool_strdup(&m->p, l); if (!v) { return NULL; } /* * GS, in addition to VG's patch, we now need to * strtok also by a "*" */ #ifdef _MT_CODE_PTHREAD for (p = strtok_r(v, " \t,", &lasts); p; p = strtok_r(NULL, " \t,", &lasts)) #else for (p = strtok(v, " \t,"); p; p = strtok(NULL, " \t,")) #endif { if (idex == capacity) { ar = jk_pool_realloc(&m->p, sizeof(char *) * (capacity + 5), ar, sizeof(char *) * capacity); if (!ar) { return NULL; } capacity += 5; } ar[idex] = jk_pool_strdup(&m->p, p); idex++; } *list_len = idex; } return ar; } int *jk_map_get_int_list(jk_map_t *m, const char *name, unsigned int *list_len, const char *def) { const char *l = jk_map_get_string(m, name, def); int *ar = NULL; #ifdef _MT_CODE_PTHREAD char *lasts; #endif if (l) { unsigned int capacity = 0; unsigned int idex = 0; char *p; char *v = jk_pool_strdup(&m->p, l); if (!v) { return NULL; } /* * GS, in addition to VG's patch, we now need to * strtok also by a "*" */ #ifdef _MT_CODE_PTHREAD for (p = strtok_r(v, " \t,", &lasts); p; p = strtok_r(NULL, " \t,", &lasts)) #else for (p = strtok(v, " \t,"); p; p = strtok(NULL, " \t,")) #endif { if (idex == capacity) { ar = jk_pool_realloc(&m->p, sizeof(int) * (capacity + 5), ar, sizeof(int) * capacity); if (!ar) { return NULL; } capacity += 5; } ar[idex] = atoi(p); idex++; } *list_len = idex; } return ar; } int jk_map_add(jk_map_t *m, const char *name, const void *value) { int rc = JK_FALSE; if (m && name) { unsigned int hash; COMPUTE_KEY_HASH(name, hash) map_realloc(m); if (m->size < m->capacity) { m->values[m->size] = value; m->names[m->size] = jk_pool_strdup(&m->p, name); m->keys[m->size] = hash; m->size++; rc = JK_TRUE; } } return rc; } int jk_map_put(jk_map_t *m, const char *name, const void *value, void **old) { int rc = JK_FALSE; if (m && name) { unsigned int i; unsigned int hash; COMPUTE_KEY_HASH(name, hash) for (i = 0; i < m->size; i++) { if (m->keys[i] == hash && strcmp(m->names[i], name) == 0) { break; } } if (i < m->size) { if (old) *old = (void *)m->values[i]; /* DIRTY */ m->values[i] = value; rc = JK_TRUE; } else { rc = jk_map_add(m, name, value); } } return rc; } static int jk_map_validate_property(char *prp, jk_log_context_t *l) { /* check the worker properties */ if (!jk_is_valid_property(prp)) { jk_log(l, JK_LOG_ERROR, "The attribute '%s' is not supported - please check" " the documentation for the supported attributes.", prp); return JK_FALSE; } if (jk_is_deprecated_property(prp)) { jk_log(l, JK_LOG_WARNING, "The attribute '%s' is deprecated - please check" " the documentation for the correct replacement.", prp); } return JK_TRUE; } static int jk_map_handle_duplicates(jk_map_t *m, const char *prp, char **v, int treatment, jk_log_context_t *l) { const char *oldv = jk_map_get_string(m, prp, NULL); if (oldv) { if ((treatment == JK_MAP_HANDLE_DUPLICATES) && jk_is_unique_property(prp) == JK_FALSE) { char *tmpv = jk_pool_alloc(&m->p, strlen(*v) + strlen(oldv) + 3); if (tmpv) { char sep = '*'; if (jk_is_path_property(prp)) sep = PATH_SEPERATOR; else if (jk_is_cmd_line_property(prp)) sep = ' '; else if (jk_is_list_property(prp)) sep = ','; sprintf(tmpv, "%s%c%s", oldv, sep, *v); } *v = tmpv; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Concatenated value is: %s -> %s", prp, *v); return JK_FALSE; } else { jk_log(l, JK_LOG_WARNING, "Duplicate key '%s' detected - previous value '%s'" " will be overwritten with '%s'.", prp, oldv ? oldv : "(null)", v ? *v : "(null)"); return JK_TRUE; } } else { return JK_TRUE; } } int jk_map_read_property(jk_map_t *m, jk_map_t *env, const char *str, int treatment, jk_log_context_t *l) { int rc = JK_TRUE; char buf[LENGTH_OF_LINE + 1]; char *prp = &buf[0]; if (strlen(str) > LENGTH_OF_LINE) { jk_log(l, JK_LOG_ERROR, "Line too long (%d > %d), ignoring entry", strlen(str), LENGTH_OF_LINE); return JK_FALSE; } strcpy(prp, str); if (trim(prp)) { char *v = strchr(prp, '='); if (v) { *v = '\0'; v++; if (trim(v) && trim(prp)) { if (treatment == JK_MAP_HANDLE_RAW) { v = jk_pool_strdup(&m->p, v); } else { if (jk_map_validate_property(prp, l) == JK_FALSE) return JK_FALSE; v = jk_map_replace_properties(m, env, v); if (jk_map_handle_duplicates(m, prp, &v, treatment, l) == JK_TRUE) v = jk_pool_strdup(&m->p, v); } if (v) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Adding property '%s' with value '%s' to map.", prp, v); jk_map_put(m, prp, v, NULL); } else { JK_LOG_NULL_PARAMS(l); rc = JK_FALSE; } } } } return rc; } int jk_map_read_properties(jk_map_t *m, jk_map_t *env, const char *f, time_t *modified, int treatment, jk_log_context_t *l) { int rc = JK_FALSE; if (m && f) { struct stat statbuf; FILE *fp; if (jk_stat(f, &statbuf) == -1) return JK_FALSE; #if defined(AS400) && !defined(AS400_UTF8) fp = fopen(f, "r, o_ccsid=0"); #else fp = fopen(f, "r"); #endif if (fp) { char buf[LENGTH_OF_LINE + 1]; char *prp; rc = JK_TRUE; while (NULL != (prp = fgets(buf, LENGTH_OF_LINE, fp))) { trim_prp_comment(prp); if (*prp) { if ((rc = jk_map_read_property(m, env, prp, treatment, l)) == JK_FALSE) break; } } fclose(fp); if (modified) *modified = statbuf.st_mtime; } } return rc; } int jk_map_size(jk_map_t *m) { if (m) { return m->size; } return -1; } const char *jk_map_name_at(jk_map_t *m, int idex) { if (m && idex >= 0) { return m->names[idex]; /* DIRTY */ } return NULL; } void *jk_map_value_at(jk_map_t *m, int idex) { if (m && idex >= 0) { return (void *)m->values[idex]; /* DIRTY */ } return NULL; } void jk_map_dump(jk_map_t *m, jk_log_context_t *l) { if (m) { int s = jk_map_size(m); int i; for (i=0;i '%s'", m->id, jk_map_name_at(m, i) ? jk_map_name_at(m, i) : "(null)", jk_map_value_at(m, i) ? jk_map_value_at(m, i) : "(null)"); } } } } int jk_map_copy(jk_map_t *src, jk_map_t *dst) { int sz = jk_map_size(src); int i; for (i = 0; i < sz; i++) { const char *name = jk_map_name_at(src, i); if (jk_map_get(dst, name, NULL) == NULL) { if (!jk_map_put(dst, name, jk_pool_strdup(&dst->p, jk_map_get_string(src, name, NULL)), NULL)) { return JK_FALSE; } } } return JK_TRUE; } static void trim_prp_comment(char *prp) { #if defined(AS400) && !defined(AS400_UTF8) char *comment; /* lots of lines that translate a '#' realtime deleted */ comment = strchr(prp, *APR_NUMBERSIGN); #else char *comment = strchr(prp, '#'); #endif if (comment) { *comment = '\0'; } } static size_t trim(char *s) { size_t first; size_t len; /* check for empty strings */ if (!(len = strlen(s))) return 0; for (len = len - 1; (len > 0) && jk_isspace(s[len]); len--); if ((len > 0) || !jk_isspace(s[len])) { len++; } s[len] = '\0'; len++; for (first = 0; (s[first] != '\0') && jk_isspace(s[first]); first++); if (first > 0) { memmove(s, s + first, len - first); } return len; } static int map_realloc(jk_map_t *m) { if (m->size == m->capacity) { const char **names; const void **values; unsigned int *keys; int capacity = m->capacity + CAPACITY_INC_SIZE; size_t old_sz = m->capacity * sizeof(void *); size_t new_sz = capacity * sizeof(void *); names = (const char **)jk_pool_realloc(&m->p, new_sz, m->names, old_sz); values = (const void **)jk_pool_realloc(&m->p, new_sz, m->values, old_sz); keys = (unsigned int *)jk_pool_realloc(&m->p, new_sz, m->keys, old_sz); if (values && names && keys) { m->names = names; m->values = values; m->keys = keys; m->capacity = capacity; return JK_TRUE; } } return JK_FALSE; } /** * Replace $(property) in value. * */ static char *jk_map_replace_properties(jk_map_t *m, jk_map_t *env, char *value) { char *rc = value; char *env_start = rc; int rec = 0; while ((env_start = strstr(env_start, "$(")) != NULL) { char *env_end = strstr(env_start, ")"); if (rec++ > 20) return rc; if (env_end) { char env_name[LENGTH_OF_LINE + 1] = ""; const char *env_value; #if defined(WIN32) char env_buf[LENGTH_OF_LINE + 1]; #endif *env_end = '\0'; strcpy(env_name, env_start + 2); *env_end = ')'; env_value = jk_map_get_string(m, env_name, NULL); if (!env_value) { env_value = getenv(env_name); } if (!env_value && env) { /* Search inside local environment table */ env_value = jk_map_get_string(env, env_name, NULL); } #if defined(WIN32) if (!env_value) { /* Try the env block from calling process */ if (GetEnvironmentVariable(env_name, env_buf, sizeof(env_buf))) env_value = &env_buf[0]; } #endif if (env_value) { size_t offset = 0; char *new_value = jk_pool_alloc(&m->p, (sizeof(char) * (strlen(rc) + strlen(env_value)))); if (!new_value) { break; } *env_start = '\0'; strcpy(new_value, rc); strcat(new_value, env_value); strcat(new_value, env_end + 1); offset = env_start - rc + strlen(env_value); rc = new_value; /* Avoid recursive subst */ env_start = rc + offset; } else { env_start = env_end; } } else { break; } } return rc; } /** * Resolve references * */ int jk_map_resolve_references(jk_map_t *m, const char *prefix, int wildcard, int depth, jk_log_context_t *l) { int rc = JK_FALSE; JK_TRACE_ENTER(l); if (m && prefix) { if (depth <= JK_MAP_RECURSION) { size_t prelen = strlen(prefix); unsigned int i; rc = JK_TRUE; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Checking for references with prefix %s with%s wildcard (recursion %d)", prefix, wildcard? "" : "out", depth); for (i = 0; i < m->size; i++) { char *v = (char *)m->values[i]; if (v && *v && !strncmp(m->names[i], prefix, prelen)) { size_t remain = strlen(m->names[i]) - prelen; if ((remain == JK_MAP_REFERENCE_SZ) || (wildcard && remain > JK_MAP_REFERENCE_SZ)) { remain = strlen(m->names[i]) - JK_MAP_REFERENCE_SZ; if (!strncmp(m->names[i] + remain, JK_MAP_REFERENCE, JK_MAP_REFERENCE_SZ)) { char *from = jk_pool_alloc(&m->p, (sizeof(char) * (strlen(v) + 2))); char *to = jk_pool_alloc(&m->p, (sizeof(char) * (remain + 2))); if (!from || !to) { jk_log(l, JK_LOG_ERROR, "Error in string allocation"); rc = JK_FALSE; break; } strcpy(from, v); *(from+strlen(v)) = '.'; *(from+strlen(v)+1) = '\0'; strncpy(to, m->names[i], remain); *(to+remain) = '.'; *(to+remain+1) = '\0'; rc = jk_map_resolve_references(m, v, 0, depth+1, l); if (rc == JK_FALSE) { break; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Copying values from %s to %s", from, to); rc = jk_map_inherit_properties(m, from, to, l); if (rc == JK_FALSE) { break; } } } } } } else { jk_log(l, JK_LOG_ERROR, "Recursion limit %d for worker references with prefix '%s' reached", JK_MAP_RECURSION, prefix); } } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return rc; } /** * Inherit properties * */ int jk_map_inherit_properties(jk_map_t *m, const char *from, const char *to, jk_log_context_t *l) { int rc = JK_FALSE; const char *prp; char *to_prp; if (m && from && to) { unsigned int i; for (i = 0; i < m->size; i++) { if (!strncmp(m->names[i], from, strlen(from))) { rc = JK_TRUE; prp = m->names[i] + strlen(from); to_prp = jk_pool_alloc(&m->p, (sizeof(char) * (strlen(to) + strlen(prp) + 1))); if (!to_prp) { jk_log(l, JK_LOG_ERROR, "Error in string allocation for attribute '%s.%s'", to, prp); rc = JK_FALSE; break; } strcpy(to_prp, to); strcat(to_prp, prp); if (jk_map_get_id(m, to_prp) < 0) { rc = jk_map_add(m, to_prp, m->values[i]); if (rc == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "Error when adding attribute '%s'", to_prp); break; } } } } if (rc == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "Reference '%s' not found", from); } } else { JK_LOG_NULL_PARAMS(l); } return rc; } tomcat-connectors-1.2.50-src/native/common/jk_ajp14.c0000644000000000000020000004434614655113617020664 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Next generation bi-directional protocol handler. * * Author: Henri Gomez * ***************************************************************************/ #include "jk_global.h" #include "jk_util.h" #include "jk_map.h" #include "jk_ajp_common.h" #include "jk_ajp14.h" #include "jk_md5.h" /* * Compute the MD5 with ENTROPY / SECRET KEY */ void ajp14_compute_md5(jk_login_service_t *s, jk_log_context_t *l) { JK_TRACE_ENTER(l); jk_md5((const unsigned char *)s->entropy, (const unsigned char *)s->secret_key, s->computed_key); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s/%s) -> (%s)", s->entropy, s->secret_key, s->computed_key); JK_TRACE_EXIT(l); } /* * Build the Login Init Command * * +-------------------------+---------------------------+---------------------------+ * | LOGIN INIT CMD (1 byte) | NEGOTIATION DATA (32bits) | WEB SERVER INFO (CString) | * +-------------------------+---------------------------+---------------------------+ * */ int ajp14_marshal_login_init_into_msgb(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *l) { JK_TRACE_ENTER(l); /* To be on the safe side */ jk_b_reset(msg); /* * LOGIN */ if (jk_b_append_byte(msg, AJP14_LOGINIT_CMD)) { JK_TRACE_EXIT(l); return JK_FALSE; } /* * NEGOTIATION FLAGS */ if (jk_b_append_long(msg, s->negotiation)) { JK_TRACE_EXIT(l); return JK_FALSE; } /* * WEB-SERVER NAME */ if (jk_b_append_string(msg, s->web_server_name)) { jk_log(l, JK_LOG_ERROR, "failed appending the web_server_name string"); JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Decode the Login Seed Command * * +-------------------------+---------------------------+ * | LOGIN SEED CMD (1 byte) | MD5 of entropy (32 chars) | * +-------------------------+---------------------------+ * */ int ajp14_unmarshal_login_seed(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (jk_b_get_bytes (msg, (unsigned char *)s->entropy, AJP14_ENTROPY_SEED_LEN) < 0) { jk_log(l, JK_LOG_ERROR, "can't get seed"); JK_TRACE_EXIT(l); return JK_FALSE; } s->entropy[AJP14_ENTROPY_SEED_LEN] = 0; /* Just to have a CString */ JK_TRACE_EXIT(l); return JK_TRUE; } /* * Build the Login Computed Command * * +-------------------------+---------------------------------------+ * | LOGIN COMP CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) | * +-------------------------+---------------------------------------+ * */ int ajp14_marshal_login_comp_into_msgb(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *l) { JK_TRACE_ENTER(l); /* To be on the safe side */ jk_b_reset(msg); /* * LOGIN */ if (jk_b_append_byte(msg, AJP14_LOGCOMP_CMD)) { JK_TRACE_EXIT(l); return JK_FALSE; } /* * COMPUTED-SEED */ if (jk_b_append_bytes (msg, (const unsigned char *)s->computed_key, AJP14_COMPUTED_KEY_LEN)) { jk_log(l, JK_LOG_ERROR, "failed appending the COMPUTED MD5 bytes"); JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Decode the LogOk Command * * +--------------------+------------------------+-------------------------------+ * | LOGOK CMD (1 byte) | NEGOCIED DATA (32bits) | SERVLET ENGINE INFO (CString) | * +--------------------+------------------------+-------------------------------+ * */ int ajp14_unmarshal_log_ok(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *l) { unsigned long nego; char *sname; JK_TRACE_ENTER(l); nego = jk_b_get_long(msg); if (nego == 0xFFFFFFFF) { jk_log(l, JK_LOG_ERROR, "can't get negociated data"); JK_TRACE_EXIT(l); return JK_FALSE; } sname = jk_b_get_string(msg); if (!sname) { jk_log(l, JK_LOG_ERROR, "can't get servlet engine name"); JK_TRACE_EXIT(l); return JK_FALSE; } /* take care of removing previously allocated data */ if (s->servlet_engine_name) free(s->servlet_engine_name); s->servlet_engine_name = strdup(sname); if (!s->servlet_engine_name) { jk_log(l, JK_LOG_ERROR, "can't malloc servlet engine name"); JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Decode the Log Nok Command * * +---------------------+-----------------------+ * | LOGNOK CMD (1 byte) | FAILURE CODE (32bits) | * +---------------------+-----------------------+ * */ int ajp14_unmarshal_log_nok(jk_msg_buf_t *msg, jk_log_context_t *l) { unsigned long status; JK_TRACE_ENTER(l); status = jk_b_get_long(msg); if (status == 0xFFFFFFFF) { jk_log(l, JK_LOG_ERROR, "can't get failure code"); JK_TRACE_EXIT(l); return JK_FALSE; } jk_log(l, JK_LOG_INFO, "Can't Log with servlet engine - code %08lx", status); JK_TRACE_EXIT(l); return JK_TRUE; } /* * Build the Shutdown Cmd * * +-----------------------+---------------------------------------+ * | SHUTDOWN CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) | * +-----------------------+---------------------------------------+ * */ int ajp14_marshal_shutdown_into_msgb(jk_msg_buf_t *msg, jk_login_service_t *s, jk_log_context_t *l) { JK_TRACE_ENTER(l); /* To be on the safe side */ jk_b_reset(msg); /* * SHUTDOWN CMD */ if (jk_b_append_byte(msg, AJP14_SHUTDOWN_CMD)) { JK_TRACE_EXIT(l); return JK_FALSE; } /* * COMPUTED-SEED */ if (jk_b_append_bytes (msg, (const unsigned char *)s->computed_key, AJP14_COMPUTED_KEY_LEN)) { jk_log(l, JK_LOG_ERROR, "failed appending the COMPUTED MD5 bytes"); JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Decode the Shutdown Nok Command * * +----------------------+-----------------------+ * | SHUTNOK CMD (1 byte) | FAILURE CODE (32bits) | * +----------------------+-----------------------+ * */ int ajp14_unmarshal_shutdown_nok(jk_msg_buf_t *msg, jk_log_context_t *l) { unsigned long status; JK_TRACE_ENTER(l); status = jk_b_get_long(msg); if (status == 0xFFFFFFFF) { jk_log(l, JK_LOG_ERROR, "can't get failure code"); JK_TRACE_EXIT(l); return JK_FALSE; } jk_log(l, JK_LOG_INFO, "Can't shutdown servlet engine - code %08lx", status); JK_TRACE_EXIT(l); return JK_TRUE; } /* * Build the Unknown Packet * * +-----------------------------+---------------------------------+------------------------------+ * | UNKNOWN PACKET CMD (1 byte) | UNHANDLED MESSAGE SIZE (16bits) | UNHANDLED MESSAGE (bytes...) | * +-----------------------------+---------------------------------+------------------------------+ * */ int ajp14_marshal_unknown_packet_into_msgb(jk_msg_buf_t *msg, jk_msg_buf_t *unk, jk_log_context_t *l) { JK_TRACE_ENTER(l); /* To be on the safe side */ jk_b_reset(msg); /* * UNKNOWN PACKET CMD */ if (jk_b_append_byte(msg, AJP14_UNKNOW_PACKET_CMD)) { JK_TRACE_EXIT(l); return JK_FALSE; } /* * UNHANDLED MESSAGE SIZE */ if (jk_b_append_int(msg, (unsigned short)unk->len)) { JK_TRACE_EXIT(l); return JK_FALSE; } /* * UNHANDLED MESSAGE (Question : Did we have to send all the message * or only part of) (ie: only 1k max) */ if (jk_b_append_bytes(msg, unk->buf, unk->len)) { jk_log(l, JK_LOG_ERROR, "failed appending the UNHANDLED MESSAGE"); JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Build the Context Query Cmd (autoconf) * * +--------------------------+---------------------------------+ * | CONTEXT QRY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | * +--------------------------+---------------------------------+ * */ int ajp14_marshal_context_query_into_msgb(jk_msg_buf_t *msg, char *virtual, jk_log_context_t *l) { JK_TRACE_ENTER(l); /* To be on the safe side */ jk_b_reset(msg); /* * CONTEXT QUERY CMD */ if (jk_b_append_byte(msg, AJP14_CONTEXT_QRY_CMD)) { JK_TRACE_EXIT(l); return JK_FALSE; } /* * VIRTUAL HOST CSTRING */ if (jk_b_append_string(msg, virtual)) { jk_log(l, JK_LOG_ERROR, "failed appending the virtual host string"); JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Decode the Context Info Cmd (Autoconf) * * The Autoconf feature of AJP14, let us know which URL/URI could * be handled by the servlet-engine * * +---------------------------+---------------------------------+----------------------------+-------------------------------+-----------+ * | CONTEXT INFO CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | URL1 [\n] URL2 [\n] URL3 [\n] | NEXT CTX. | * +---------------------------+---------------------------------+----------------------------+-------------------------------+-----------+ */ int ajp14_unmarshal_context_info(jk_msg_buf_t *msg, jk_context_t *c, jk_log_context_t *l) { char *vname; char *cname; char *uri; vname = jk_b_get_string(msg); JK_TRACE_ENTER(l); jk_log(l, JK_LOG_DEBUG, "get virtual %s for virtual %s", vname, c->virt); if (!vname) { jk_log(l, JK_LOG_ERROR, "can't get virtual hostname"); JK_TRACE_EXIT(l); return JK_FALSE; } /* Check if we get the correct virtual host */ if (c->virt != NULL && vname != NULL && strcmp(c->virt, vname)) { /* set the virtual name, better to add to a virtual list ? */ if (context_set_virtual(c, vname) == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "can't malloc virtual hostname"); JK_TRACE_EXIT(l); return JK_FALSE; } } for (;;) { cname = jk_b_get_string(msg); if (!cname) { jk_log(l, JK_LOG_ERROR, "can't get context"); JK_TRACE_EXIT(l); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "get context %s for virtual %s", cname, vname); /* grab all contexts up to empty one which indicate end of contexts */ if (!strlen(cname)) break; /* create new context base (if needed) */ if (context_add_base(c, cname) == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "can't add/set context %s", cname); JK_TRACE_EXIT(l); return JK_FALSE; } for (;;) { uri = jk_b_get_string(msg); if (!uri) { jk_log(l, JK_LOG_ERROR, "can't get URI"); JK_TRACE_EXIT(l); return JK_FALSE; } if (!strlen(uri)) { jk_log(l, JK_LOG_DEBUG, "No more URI for context %s", cname); break; } jk_log(l, JK_LOG_INFO, "Got URI (%s) for virtualhost %s and context %s", uri, vname, cname); if (context_add_uri(c, cname, uri) == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "can't add/set uri (%s) for context %s", uri, cname); JK_TRACE_EXIT(l); return JK_FALSE; } } } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Build the Context State Query Cmd * * We send the list of contexts where we want to know state, * empty string ends context list * If cname is set, only ask about THIS context * * +----------------------------+----------------------------------+----------------------------+----+ * | CONTEXT STATE CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | .. | * +----------------------------+----------------------------------+----------------------------+----+ * */ int ajp14_marshal_context_state_into_msgb(jk_msg_buf_t *msg, jk_context_t *c, char *cname, jk_log_context_t *l) { jk_context_item_t *ci; int i; JK_TRACE_ENTER(l); /* To be on the safe side */ jk_b_reset(msg); /* * CONTEXT STATE CMD */ if (jk_b_append_byte(msg, AJP14_CONTEXT_STATE_CMD)) { JK_TRACE_EXIT(l); return JK_FALSE; } /* * VIRTUAL HOST CSTRING */ if (jk_b_append_string(msg, c->virt)) { jk_log(l, JK_LOG_ERROR, "failed appending the virtual host string"); JK_TRACE_EXIT(l); return JK_FALSE; } if (cname) { ci = context_find_base(c, cname); if (!ci) { jk_log(l, JK_LOG_ERROR, "unknown context %s", cname); JK_TRACE_EXIT(l); return JK_FALSE; } /* * CONTEXT CSTRING */ if (jk_b_append_string(msg, cname)) { jk_log(l, JK_LOG_ERROR, "failed appending the context string %s", cname); JK_TRACE_EXIT(l); return JK_FALSE; } } else { /* Grab all contexts name */ for (i = 0; i < c->size; i++) { /* * CONTEXT CSTRING */ if (jk_b_append_string(msg, c->contexts[i]->cbase)) { jk_log(l, JK_LOG_ERROR, "failed appending the context string %s", c->contexts[i]->cbase); JK_TRACE_EXIT(l); return JK_FALSE; } } } /* End of context list, an empty string */ if (jk_b_append_string(msg, "")) { jk_log(l, JK_LOG_ERROR, "failed appending end of contexts"); JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Decode the Context State Reply Cmd * * We get update of contexts list, empty string end context list* * * +----------------------------------+---------------------------------+----------------------------+------------------+----+ * | CONTEXT STATE REPLY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | UP/DOWN (1 byte) | .. | * +----------------------------------+---------------------------------+----------------------------+------------------+----+ * */ int ajp14_unmarshal_context_state_reply(jk_msg_buf_t *msg, jk_context_t *c, jk_log_context_t *l) { char *vname; char *cname; jk_context_item_t *ci; JK_TRACE_ENTER(l); /* get virtual name */ vname = jk_b_get_string(msg); if (!vname) { jk_log(l, JK_LOG_ERROR, "can't get virtual hostname"); JK_TRACE_EXIT(l); return JK_FALSE; } /* Check if we speak about the correct virtual */ if (strcmp(c->virt, vname)) { jk_log(l, JK_LOG_ERROR, "incorrect virtual %s instead of %s", vname, c->virt); JK_TRACE_EXIT(l); return JK_FALSE; } for (;;) { /* get context name */ cname = jk_b_get_string(msg); if (!cname) { jk_log(l, JK_LOG_ERROR, "can't get context"); JK_TRACE_EXIT(l); return JK_FALSE; } if (!strlen(cname)) break; ci = context_find_base(c, cname); if (!ci) { jk_log(l, JK_LOG_ERROR, "unknow context %s for virtual %s", cname, vname); JK_TRACE_EXIT(l); return JK_FALSE; } ci->status = jk_b_get_int(msg); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "updated context %s to state %d", cname, ci->status); } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Decode the Context Update Cmd * * +-----------------------------+---------------------------------+----------------------------+------------------+ * | CONTEXT UPDATE CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | UP/DOWN (1 byte) | * +-----------------------------+---------------------------------+----------------------------+------------------+ * */ int ajp14_unmarshal_context_update_cmd(jk_msg_buf_t *msg, jk_context_t *c, jk_log_context_t *l) { int rc; JK_TRACE_ENTER(l); rc = ajp14_unmarshal_context_state_reply(msg, c, l); JK_TRACE_EXIT(l); return rc; } tomcat-connectors-1.2.50-src/native/common/jk_ajp_common.h0000644000000000000020000004065714655113617022075 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: common stuff for bi-directional protocol ajp13/ajp14. * * Author: Gal Shachor * * Author: Henri Gomez * ***************************************************************************/ #ifndef JK_AJP_COMMON_H #define JK_AJP_COMMON_H #include "jk_service.h" #include "jk_msg_buff.h" #include "jk_shm.h" #include "jk_mt.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define JK_AJP_STATE_IDLE (0) #define JK_AJP_STATE_OK (1) #define JK_AJP_STATE_ERROR (2) #define JK_AJP_STATE_PROBE (3) #define JK_AJP_STATE_DEF (JK_AJP_STATE_IDLE) #define JK_AJP_STATE_TEXT_IDLE ("OK/IDLE") #define JK_AJP_STATE_TEXT_OK ("OK") #define JK_AJP_STATE_TEXT_ERROR ("ERR") #define JK_AJP_STATE_TEXT_PROBE ("ERR/PRB") #define JK_AJP_STATE_TEXT_MAX (JK_AJP_STATE_PROBE) #define JK_AJP_STATE_TEXT_DEF (JK_AJP_STATE_TEXT_IDLE) /* * Conditional request attributes * */ #define SC_A_CONTEXT (unsigned char)1 #define SC_A_SERVLET_PATH (unsigned char)2 #define SC_A_REMOTE_USER (unsigned char)3 #define SC_A_AUTH_TYPE (unsigned char)4 #define SC_A_QUERY_STRING (unsigned char)5 #define SC_A_ROUTE (unsigned char)6 #define SC_A_SSL_CERT (unsigned char)7 #define SC_A_SSL_CIPHER (unsigned char)8 #define SC_A_SSL_SESSION (unsigned char)9 #define SC_A_REQ_ATTRIBUTE (unsigned char)10 #define SC_A_SSL_KEY_SIZE (unsigned char)11 /* only in if JkOptions +ForwardKeySize */ #define SC_A_SECRET (unsigned char)12 #define SC_A_STORED_METHOD (unsigned char)13 #define SC_A_ARE_DONE (unsigned char)0xFF /* * AJP private request attributes */ /* * The following request attribute is recognized by Tomcat * to contain the name of the ssl protocol used */ #define SC_A_SSL_PROTOCOL ("AJP_SSL_PROTOCOL") /* * The following request attribute is recognized by Tomcat * to contain the forwarded remote port. */ #define SC_A_REQ_REMOTE_PORT ("AJP_REMOTE_PORT") /* * The following request attribute is recognized by Tomcat * to contain the forwarded local ip address. */ #define SC_A_REQ_LOCAL_ADDR ("AJP_LOCAL_ADDR") /* * JK public request attributes * * Activation state of the worker in the load balancer. * Can be any of the JK_LB_ACTIVATION_TEXT_* strings * from jk_lb_worker.h. */ #define SC_A_JK_LB_ACTIVATION ("JK_LB_ACTIVATION") /* * Request methods, coded as numbers instead of strings. * The list of methods was taken from Section 5.1.1 of RFC 2616, * RFC 2518, the ACL IETF draft, and the DeltaV IESG Proposed Standard. * Method = "OPTIONS" * | "GET" * | "HEAD" * | "POST" * | "PUT" * | "DELETE" * | "TRACE" * | "PROPFIND" * | "PROPPATCH" * | "MKCOL" * | "COPY" * | "MOVE" * | "LOCK" * | "UNLOCK" * | "ACL" * | "REPORT" * | "VERSION-CONTROL" * | "CHECKIN" * | "CHECKOUT" * | "UNCHECKOUT" * | "SEARCH" * | "MKWORKSPACE" * | "UPDATE" * | "LABEL" * | "MERGE" * | "BASELINE-CONTROL" * | "MKACTIVITY" * */ #define SC_M_OPTIONS (unsigned char)1 #define SC_M_GET (unsigned char)2 #define SC_M_HEAD (unsigned char)3 #define SC_M_POST (unsigned char)4 #define SC_M_PUT (unsigned char)5 #define SC_M_DELETE (unsigned char)6 #define SC_M_TRACE (unsigned char)7 #define SC_M_PROPFIND (unsigned char)8 #define SC_M_PROPPATCH (unsigned char)9 #define SC_M_MKCOL (unsigned char)10 #define SC_M_COPY (unsigned char)11 #define SC_M_MOVE (unsigned char)12 #define SC_M_LOCK (unsigned char)13 #define SC_M_UNLOCK (unsigned char)14 #define SC_M_ACL (unsigned char)15 #define SC_M_REPORT (unsigned char)16 #define SC_M_VERSION_CONTROL (unsigned char)17 #define SC_M_CHECKIN (unsigned char)18 #define SC_M_CHECKOUT (unsigned char)19 #define SC_M_UNCHECKOUT (unsigned char)20 #define SC_M_SEARCH (unsigned char)21 #define SC_M_MKWORKSPACE (unsigned char)22 #define SC_M_UPDATE (unsigned char)23 #define SC_M_LABEL (unsigned char)24 #define SC_M_MERGE (unsigned char)25 #define SC_M_BASELINE_CONTROL (unsigned char)26 #define SC_M_MKACTIVITY (unsigned char)27 #define SC_M_JK_STORED (unsigned char)0xFF /* * Frequent request headers, these headers are coded as numbers * instead of strings. * * Accept * Accept-Charset * Accept-Encoding * Accept-Language * Authorization * Connection * Content-Type * Content-Length * Cookie * Cookie2 * Host * Pragma * Referer * User-Agent * */ #define SC_ACCEPT (unsigned short)0xA001 #define SC_ACCEPT_CHARSET (unsigned short)0xA002 #define SC_ACCEPT_ENCODING (unsigned short)0xA003 #define SC_ACCEPT_LANGUAGE (unsigned short)0xA004 #define SC_AUTHORIZATION (unsigned short)0xA005 #define SC_CONNECTION (unsigned short)0xA006 #define SC_CONTENT_TYPE (unsigned short)0xA007 #define SC_CONTENT_LENGTH (unsigned short)0xA008 #define SC_COOKIE (unsigned short)0xA009 #define SC_COOKIE2 (unsigned short)0xA00A #define SC_HOST (unsigned short)0xA00B #define SC_PRAGMA (unsigned short)0xA00C #define SC_REFERER (unsigned short)0xA00D #define SC_USER_AGENT (unsigned short)0xA00E /* * Frequent response headers, these headers are coded as numbers * instead of strings. * * Content-Type * Content-Language * Content-Length * Date * Last-Modified * Location * Set-Cookie * Servlet-Engine * Status * WWW-Authenticate * */ #define SC_RESP_CONTENT_TYPE (unsigned short)0xA001 #define SC_RESP_CONTENT_LANGUAGE (unsigned short)0xA002 #define SC_RESP_CONTENT_LENGTH (unsigned short)0xA003 #define SC_RESP_DATE (unsigned short)0xA004 #define SC_RESP_LAST_MODIFIED (unsigned short)0xA005 #define SC_RESP_LOCATION (unsigned short)0xA006 #define SC_RESP_SET_COOKIE (unsigned short)0xA007 #define SC_RESP_SET_COOKIE2 (unsigned short)0xA008 #define SC_RESP_SERVLET_ENGINE (unsigned short)0xA009 #define SC_RESP_STATUS (unsigned short)0xA00A #define SC_RESP_WWW_AUTHENTICATE (unsigned short)0xA00B #define SC_RES_HEADERS_NUM 11 /* * AJP13/AJP14 use same message structure */ #define AJP_DEF_RETRY_ATTEMPTS (1) #define AJP_HEADER_LEN (4) #define AJP_HEADER_SZ_LEN (2) #define CHUNK_BUFFER_PAD (12) #define AJP_DEF_CACHE_TIMEOUT (0) #define AJP_DEF_CONNECT_TIMEOUT (0) /* NO CONNECTION TIMEOUT => NO CPING/CPONG */ #define AJP_DEF_REPLY_TIMEOUT (0) /* NO REPLY TIMEOUT */ #define AJP_DEF_PREPOST_TIMEOUT (0) /* NO PREPOST TIMEOUT => NO CPING/CPONG */ #define AJP_DEF_RECOVERY_OPTS (0) /* NO RECOVERY / NO */ #define AJP_DEF_SOCKET_TIMEOUT (0) /* No timeout */ #define AJP_DEF_PING_TIMEOUT (10000) /* Default CPING/CPONG timeout (10 seconds) */ #define AJP_CPING_NONE (0) /* Do not send cping packets */ #define AJP_CPING_CONNECT (1) /* Send cping on fresh connection */ #define AJP_CPING_PREPOST (2) /* Send cping before sending request */ #define AJP_CPING_INTERVAL (4) /* Send cping on regular intervals */ #define AJP_CPING_MAX (AJP_CPING_INTERVAL) #define AJP_CPING_CONNECT_TEXT ('C') /* Send cping on fresh connection */ #define AJP_CPING_PREPOST_TEXT ('P') /* Send cping before sending request */ #define AJP_CPING_INTERVAL_TEXT ('I') /* Send cping on regular intervals */ #define AJP_CPING_ALL_TEXT ('A') /* Send cping on regular intervals */ #define RECOVER_ABORT_IF_TCGETREQUEST 0x0001 /* DON'T RECOVER IF TOMCAT FAILS AFTER RECEIVING REQUEST */ #define RECOVER_ABORT_IF_TCSENDHEADER 0x0002 /* DON'T RECOVER IF TOMCAT FAILS AFTER SENDING HEADERS */ #define RECOVER_ABORT_IF_CLIENTERROR 0x0004 /* CLOSE THE SOCKET IN CASE OF CLIENT ERROR */ #define RECOVER_ALWAYS_HTTP_HEAD 0x0008 /* RECOVER HTTP HEAD REQUESTS, EVEN IF ABORT OPTIONS ARE SET */ #define RECOVER_ALWAYS_HTTP_GET 0x0010 /* RECOVER HTTP GET REQUESTS, EVEN IF ABORT OPTIONS ARE SET */ struct jk_res_data { int status; #ifdef AS400 char *msg; #else const char *msg; #endif unsigned num_headers; char **header_names; char **header_values; }; typedef struct jk_res_data jk_res_data_t; #include "jk_ajp14.h" struct ajp_operation; typedef struct ajp_operation ajp_operation_t; struct ajp_endpoint; typedef struct ajp_endpoint ajp_endpoint_t; struct ajp_worker; typedef struct ajp_worker ajp_worker_t; struct ajp_worker { jk_worker_t worker; /* Shared memory worker data */ jk_shm_ajp_worker_t *s; shm_str name; /* Sequence counter starting at 0 and increasing * every time we change the config */ volatile unsigned int sequence; jk_pool_t p; jk_pool_atom_t buf[TINY_POOL_SIZE]; JK_CRIT_SEC cs; jk_sockaddr_t worker_inet_addr; /* Contains host and port */ jk_sockaddr_t worker_source_inet_addr; /* Contains source ip */ unsigned connect_retry_attempts; shm_str host; int port; shm_str source; int addr_sequence; /* Whether the address is resolved */ int maintain_time; int prefer_ipv6; /* * Open connections cache... * * 1. Critical section object to protect the cache. * 2. Cache size. * 3. An array of "open" endpoints. */ unsigned int ep_cache_sz; unsigned int ep_mincache_sz; unsigned int ep_maxcache_sz; int cache_acquire_timeout; ajp_endpoint_t **ep_cache; int proto; /* PROTOCOL USED AJP13/AJP14 */ jk_login_service_t *login; /* Weak secret similar with ajp12, used in ajp13 */ const char *secret; /* * Post physical connect handler. * AJP14 will set here its login handler */ int (*logon) (ajp_endpoint_t * ae, jk_log_context_t *log_ctx); /* * Handle Socket Timeouts */ int socket_timeout; int socket_connect_timeout; int keepalive; int socket_buf; /* * Handle Cache Timeouts */ int cache_timeout; /* * Handle Connection/Reply Timeouts */ int connect_timeout; /* connect cping/cpong delay in ms (0 means disabled) */ int reply_timeout; /* reply timeout delay in ms (0 means disabled) */ int prepost_timeout; /* before sending a request cping/cpong timeout delay in ms (0 means disabled) */ int conn_ping_interval; /* interval for sending keepalive cping packets on * unused connection */ int ping_timeout; /* generic cping/cpong timeout. Used for keepalive packets or * as default for boolean valued connect and prepost timeouts. */ unsigned int ping_mode; /* Ping mode flags (which types of cpings should be used) */ /* * Recovery options */ unsigned int recovery_opts; /* * Public property to enable the number of retry attempts * on this worker. */ int retries; /* * Public property used in load balancer workers, meaning * the maximum number of failover attempts between ajp * workers of cluster. */ int lb_retries; unsigned int max_packet_size; /* Maximum AJP Packet size */ int retry_interval; /* Number of milliseconds to sleep before doing a retry */ int busy_limit; /* Maximum allowed number of concurrent requests (if > 0) */ /* * HTTP status that will cause failover (0 means disabled) */ unsigned int http_status_fail_num; int *http_status_fail; }; /* * endpoint, the remote connector which does the work */ struct ajp_endpoint { ajp_worker_t *worker; jk_pool_t pool; jk_pool_atom_t buf[BIG_POOL_SIZE]; int proto; /* PROTOCOL USED AJP13/AJP14 */ jk_sock_t sd; int reuse; int avail; /* Set to non-zero if cache slot is available */ /* Used with RECOVER_ABORT_IF_CLIENTERROR to hard abort write of AJP response on client write errors */ int hard_close; jk_endpoint_t endpoint; jk_uint64_t left_bytes_to_send; /* time of the last request handled by this endpoint */ time_t last_access; int last_errno; /* Last operation performed via this endpoint */ int last_op; int addr_sequence; /* Whether the address is resolved */ }; /* * little struct to avoid multiples ptr passing * this struct is ready to hold upload file fd * to add upload persistant storage */ struct ajp_operation { jk_msg_buf_t *request; /* original request storage */ jk_msg_buf_t *reply; /* reply storage (chuncked by ajp13 */ jk_msg_buf_t *post; /* small post data storage area */ int uploadfd; /* future persistant storage id */ int recoverable; /* if exchange could be conducted on another TC */ }; /* * Functions */ const char *jk_ajp_get_state(ajp_worker_t *aw, jk_log_context_t *log_ctx); int jk_ajp_get_state_code(const char *v); int ajp_validate(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *log_ctx, int proto); int ajp_init(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *log_ctx, int proto); int JK_METHOD ajp_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *log_ctx); int ajp_destroy(jk_worker_t **pThis, jk_log_context_t *log_ctx, int proto); int JK_METHOD ajp_done(jk_endpoint_t **e, jk_log_context_t *log_ctx); int ajp_get_endpoint(jk_worker_t *pThis, jk_endpoint_t **pend, jk_log_context_t *log_ctx, int proto); int ajp_connect_to_endpoint(ajp_endpoint_t * ae, jk_log_context_t *log_ctx); void ajp_close_endpoint(ajp_endpoint_t * ae, jk_log_context_t *log_ctx); void jk_ajp_pull(ajp_worker_t * aw, int locked, jk_log_context_t *log_ctx); void jk_ajp_push(ajp_worker_t * aw, int locked, jk_log_context_t *log_ctx); int ajp_connection_tcp_send_message(ajp_endpoint_t * ae, jk_msg_buf_t *msg, jk_log_context_t *log_ctx); int ajp_connection_tcp_get_message(ajp_endpoint_t * ae, jk_msg_buf_t *msg, jk_log_context_t *log_ctx); int JK_METHOD ajp_maintain(jk_worker_t *pThis, time_t now, int global, jk_log_context_t *log_ctx); int JK_METHOD ajp_shutdown(jk_worker_t *pThis, jk_log_context_t *log_ctx); void jk_ajp_get_cping_text(int mode, char *buf); int jk_ajp_get_cping_mode(const char *m, int def); int ajp_has_endpoint(jk_worker_t *pThis, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_AJP_COMMON_H */ tomcat-connectors-1.2.50-src/native/common/jk_lb_worker.c0000644000000000000020000022624014655113617021726 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Load balancer worker, knows how to load balance among * * several workers. * * Author: Gal Shachor * * Author: Mladen Turk * * Author: Rainer Jung * ***************************************************************************/ #include "jk_pool.h" #include "jk_service.h" #include "jk_util.h" #include "jk_worker.h" #include "jk_lb_worker.h" #include "jk_ajp13_worker.h" #include "jk_ajp14_worker.h" #include "jk_mt.h" #include "jk_shm.h" /* * The load balancing code in this */ /* * The following two macros need to be kept in sync with * the existing values for state and activation. * Note: state <= JK_LB_STATE_FORCE is equivalent to * state is none of JK_LB_STATE_BUSY, JK_LB_STATE_ERROR, JK_LB_STATE_PROBE * Note: state <= JK_LB_STATE_BUSY is equivalent to * state is none of JK_LB_STATE_ERROR, JK_LB_STATE_PROBE * Note: activation == JK_LB_ACTIVATION_ACTIVE is equivalent to * activation is none of JK_LB_ACTIVATION_STOPPED, JK_LB_ACTIVATION_DISABLED */ #define JK_WORKER_USABLE(s, activation) ((s) <= JK_LB_STATE_FORCE && activation == JK_LB_ACTIVATION_ACTIVE) #define JK_WORKER_USABLE_STICKY(s, activation) ((s) <= JK_LB_STATE_FORCE && activation != JK_LB_ACTIVATION_STOPPED) static const char *lb_locking_type[] = { JK_LB_LOCK_TEXT_OPTIMISTIC, JK_LB_LOCK_TEXT_PESSIMISTIC, "unknown", NULL }; static const char *lb_method_type[] = { JK_LB_METHOD_TEXT_REQUESTS, JK_LB_METHOD_TEXT_TRAFFIC, JK_LB_METHOD_TEXT_BUSYNESS, JK_LB_METHOD_TEXT_SESSIONS, JK_LB_METHOD_TEXT_NEXT, "unknown", NULL }; static const char *lb_state_type[] = { JK_LB_STATE_TEXT_IDLE, JK_LB_STATE_TEXT_OK, JK_LB_STATE_TEXT_RECOVER, JK_LB_STATE_TEXT_FORCE, JK_LB_STATE_TEXT_BUSY, JK_LB_STATE_TEXT_ERROR, JK_LB_STATE_TEXT_PROBE, "unknown", NULL }; static const char *lb_activation_type[] = { JK_LB_ACTIVATION_TEXT_ACTIVE, JK_LB_ACTIVATION_TEXT_DISABLED, JK_LB_ACTIVATION_TEXT_STOPPED, "unknown", NULL }; static const char *lb_first_log_names[] = { JK_NOTE_LB_FIRST_NAME, JK_NOTE_LB_FIRST_VALUE, JK_NOTE_LB_FIRST_ACCESSED, JK_NOTE_LB_FIRST_SESSIONS, JK_NOTE_LB_FIRST_READ, JK_NOTE_LB_FIRST_TRANSFERRED, JK_NOTE_LB_FIRST_ERRORS, JK_NOTE_LB_FIRST_BUSY, JK_NOTE_LB_FIRST_ACTIVATION, JK_NOTE_LB_FIRST_STATE, NULL }; static const char *lb_last_log_names[] = { JK_NOTE_LB_LAST_NAME, JK_NOTE_LB_LAST_VALUE, JK_NOTE_LB_LAST_ACCESSED, JK_NOTE_LB_LAST_SESSIONS, JK_NOTE_LB_LAST_READ, JK_NOTE_LB_LAST_TRANSFERRED, JK_NOTE_LB_LAST_ERRORS, JK_NOTE_LB_LAST_BUSY, JK_NOTE_LB_LAST_ACTIVATION, JK_NOTE_LB_LAST_STATE, NULL }; struct lb_endpoint { lb_worker_t *worker; jk_endpoint_t endpoint; int *states; }; typedef struct lb_endpoint lb_endpoint_t; /* Calculate the greatest common divisor of two positive integers */ static jk_uint64_t gcd(jk_uint64_t a, jk_uint64_t b) { jk_uint64_t r; if (b > a) { r = a; a = b; b = r; } while (b > 0) { r = a % b; a = b; b = r; } return a; } /* Calculate the smallest common multiple of two positive integers */ static jk_uint64_t scm(jk_uint64_t a, jk_uint64_t b) { return a * b / gcd(a, b); } /* Return the string representation of the lb lock type */ /* based on the integer representation */ const char *jk_lb_get_lock_direct(int lblock, jk_log_context_t *l) { return lb_locking_type[lblock]; } /* Return the string representation of the lb lock type */ /* based on the lb worker struct */ const char *jk_lb_get_lock(lb_worker_t *p, jk_log_context_t *l) { return lb_locking_type[p->lblock]; } /* Return the int representation of the lb lock type */ int jk_lb_get_lock_code(const char *v) { if (!v) return JK_LB_LOCK_DEF; if (*v == 'o' || *v == 'O' || *v == '0') return JK_LB_LOCK_OPTIMISTIC; if (*v == 'p' || *v == 'P' || *v == '1') return JK_LB_LOCK_PESSIMISTIC; return JK_LB_LOCK_DEF; } /* Return the string representation of the lb method type */ /* based on the integer representation */ const char *jk_lb_get_method_direct(int lbmethod, jk_log_context_t *l) { return lb_method_type[lbmethod]; } /* Return the string representation of the lb method type */ /* based on the lb worker struct */ const char *jk_lb_get_method(lb_worker_t *p, jk_log_context_t *l) { return lb_method_type[p->lbmethod]; } /* Return the int representation of the lb method type */ int jk_lb_get_method_code(const char *v) { if (!v) return JK_LB_METHOD_DEF; if (*v == 'r' || *v == 'R' || *v == '0') return JK_LB_METHOD_REQUESTS; if (*v == 't' || *v == 'T' || *v == '1') return JK_LB_METHOD_TRAFFIC; if (*v == 'b' || *v == 'B' || *v == '2') return JK_LB_METHOD_BUSYNESS; if (*v == 's' || *v == 'S' || *v == '3') return JK_LB_METHOD_SESSIONS; if (*v == 'n' || *v == 'N' || *v == '4') return JK_LB_METHOD_NEXT; return JK_LB_METHOD_DEF; } /* Return the string representation of the balance worker state */ /* based on the integer representation */ const char *jk_lb_get_state_direct(int state, jk_log_context_t *l) { return lb_state_type[state]; } /* Return the string representation of the balance worker state */ /* based on the sub worker struct */ const char *jk_lb_get_state(lb_sub_worker_t *p, jk_log_context_t *l) { return lb_state_type[p->s->state]; } /* Return the int representation of the lb state */ int jk_lb_get_state_code(const char *v) { if (!v) return JK_LB_STATE_DEF; if (*v == 'i' || *v == 'I' || *v == 'n' || *v == 'N' || *v == '0') return JK_LB_STATE_IDLE; if (*v == 'o' || *v == 'O' || *v == '1') return JK_LB_STATE_OK; if (*v == 'r' || *v == 'R' || *v == '2') return JK_LB_STATE_RECOVER; if (*v == 'f' || *v == 'F' || *v == '3') return JK_LB_STATE_FORCE; if (*v == 'b' || *v == 'B' || *v == '4') return JK_LB_STATE_BUSY; if (*v == 'e' || *v == 'E' || *v == '5') return JK_LB_STATE_ERROR; if (*v == 'p' || *v == 'P' || *v == '6') return JK_LB_STATE_PROBE; return JK_LB_STATE_DEF; } /* Return the string representation of the balance worker activation */ /* based on the integer representation */ const char *jk_lb_get_activation_direct(int activation, jk_log_context_t *l) { return lb_activation_type[activation]; } /* Return the string representation of the balance worker activation */ /* based on the sub worker struct */ const char *jk_lb_get_activation(lb_sub_worker_t *p, jk_log_context_t *l) { return lb_activation_type[p->activation]; } int jk_lb_get_activation_code(const char *v) { if (!v) return JK_LB_ACTIVATION_DEF; if (*v == 'a' || *v == 'A' || *v == '0') return JK_LB_ACTIVATION_ACTIVE; if (*v == 'd' || *v == 'D' || *v == '1') return JK_LB_ACTIVATION_DISABLED; if (*v == 's' || *v == 'S' || *v == '2') return JK_LB_ACTIVATION_STOPPED; return JK_LB_ACTIVATION_DEF; } /* Update the load multipliers wrt. lb_factor */ void update_mult(lb_worker_t *p, jk_log_context_t *l) { unsigned int i = 0; jk_uint64_t s = 1; JK_TRACE_ENTER(l); for (i = 0; i < p->num_of_workers; i++) { s = scm(s, p->lb_workers[i].lb_factor); } for (i = 0; i < p->num_of_workers; i++) { p->lb_workers[i].lb_mult = s / p->lb_workers[i].lb_factor; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s gets multiplicity %" JK_UINT64_T_FMT, p->lb_workers[i].name, p->lb_workers[i].lb_mult); } JK_TRACE_EXIT(l); } /* Reset all lb values. */ void reset_lb_values(lb_worker_t *p, jk_log_context_t *l) { unsigned int i = 0; JK_TRACE_ENTER(l); if (p->lbmethod != JK_LB_METHOD_BUSYNESS) { for (i = 0; i < p->num_of_workers; i++) { p->lb_workers[i].s->lb_value = 0; } } JK_TRACE_EXIT(l); } static void jk_lb_pull_worker(lb_worker_t *p, int i, jk_log_context_t *l) { lb_sub_worker_t *w = &p->lb_workers[i]; if (w->sequence < w->s->h.sequence) { jk_worker_t *jw = w->worker; ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "syncing mem for member '%s' of lb '%s' from shm", w->name, p->name); jk_ajp_pull(aw, JK_TRUE, l); jk_shm_str_copy(w->route, w->s->route, l); jk_shm_str_copy(w->domain, w->s->domain, l); jk_shm_str_copy(w->redirect, w->s->redirect, l); w->distance = w->s->distance; w->activation = w->s->activation; w->lb_factor = w->s->lb_factor; w->lb_mult = w->s->lb_mult; w->sequence = w->s->h.sequence; } } /* Syncing config values from shm */ void jk_lb_pull(lb_worker_t *p, int locked, jk_log_context_t *l) { unsigned int i = 0; JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "syncing mem for lb '%s' from shm (%u->%u)", p->name, p->sequence, p->s->h.sequence); if (locked == JK_FALSE) jk_shm_lock(); if (p->sequence == p->s->h.sequence) { if (locked == JK_FALSE) jk_shm_unlock(); return; } p->sticky_session = p->s->sticky_session; p->sticky_session_force = p->s->sticky_session_force; p->recover_wait_time = p->s->recover_wait_time; p->error_escalation_time = p->s->error_escalation_time; p->max_reply_timeouts = p->s->max_reply_timeouts; p->retries = p->s->retries; p->retry_interval = p->s->retry_interval; p->lbmethod = p->s->lbmethod; p->lblock = p->s->lblock; p->max_packet_size = p->s->max_packet_size; for (i = 0; i < p->num_of_workers; i++) { jk_lb_pull_worker(p, i, l); } p->sequence = p->s->h.sequence; if (locked == JK_FALSE) jk_shm_unlock(); JK_TRACE_EXIT(l); } /* Syncing config values to shm */ void jk_lb_push(lb_worker_t *p, int locked, int push_all_members, jk_log_context_t *l) { unsigned int i = 0; JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "syncing shm for lb '%s' from mem (%u->%u)", p->name, p->s->h.sequence, p->sequence); if (locked == JK_FALSE) jk_shm_lock(); p->s->sticky_session = p->sticky_session; p->s->sticky_session_force = p->sticky_session_force; p->s->recover_wait_time = p->recover_wait_time; p->s->error_escalation_time = p->error_escalation_time; p->s->max_reply_timeouts = p->max_reply_timeouts; p->s->retries = p->retries; p->s->retry_interval = p->retry_interval; p->s->lbmethod = p->lbmethod; p->s->lblock = p->lblock; p->s->max_packet_size = p->max_packet_size; for (i = 0; i < p->num_of_workers; i++) { lb_sub_worker_t *w = &p->lb_workers[i]; if (push_all_members == JK_TRUE || w->sequence != w->s->h.sequence) { jk_worker_t *jw = w->worker; ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "syncing shm for member '%s' of lb '%s' from mem", w->name, p->name); jk_ajp_push(aw, JK_TRUE, l); jk_shm_str_copy(w->s->route, w->route, l); jk_shm_str_copy(w->s->domain, w->domain, l); jk_shm_str_copy(w->s->redirect, w->redirect, l); w->s->distance = w->distance; w->s->activation = w->activation; w->s->lb_factor = w->lb_factor; w->s->lb_mult = w->lb_mult; w->s->h.sequence++; w->sequence = w->s->h.sequence; } } /* Increment the shared memory sequence number. * Our number can be behind the actual value in * shared memory. */ p->s->h.sequence++; p->sequence = p->s->h.sequence; if (locked == JK_FALSE) jk_shm_unlock(); JK_TRACE_EXIT(l); } /* Retrieve the parameter with the given name */ static char *get_path_param(jk_ws_service_t *s, const char *name) { char *id_start = NULL; for (id_start = strstr(s->req_uri, name); id_start; id_start = strstr(id_start + 1, name)) { if (id_start[strlen(name)] == '=') { /* * Session path-cookie was found, get it's value */ id_start += (1 + strlen(name)); if (strlen(id_start)) { char *id_end; id_start = jk_pool_strdup(s->pool, id_start); /* * The query string is not part of req_uri, however * to be on the safe side lets remove the trailing query * string if appended... */ if ((id_end = strchr(id_start, '?')) != NULL) { *id_end = '\0'; } /* * Remove any trailing path element. */ if ((id_end = strchr(id_start, ';')) != NULL) { *id_end = '\0'; } /* * Remove any trailing URI segments. */ if ((id_end = strchr(id_start, '/')) != NULL) { *id_end = '\0'; } return id_start; } } } return NULL; } /* Retrieve the cookie with the given name */ static char *get_cookie(jk_ws_service_t *s, const char *name) { unsigned i; char *result = NULL; for (i = 0; i < s->num_headers; i++) { if (strcasecmp(s->headers_names[i], "cookie") == 0) { char *id_start; for (id_start = strstr(s->headers_values[i], name); id_start; id_start = strstr(id_start + 1, name)) { if (id_start == s->headers_values[i] || id_start[-1] == ';' || id_start[-1] == ',' || jk_isspace(id_start[-1])) { id_start += strlen(name); while (*id_start && jk_isspace(*id_start)) ++id_start; if (*id_start == '=' && id_start[1]) { /* * Session cookie was found, get it's value */ char *id_end; size_t sz; ++id_start; if ((id_end = strpbrk(id_start, ";,")) != NULL) sz = id_end - id_start; else { sz = strlen(id_start); id_end = id_start + sz; } /* Chop off surrounding '"' (quoted cookie) */ if (sz > 1 && *id_start == '"' && *(id_start + sz - 1) == '"') { id_start++; sz -= 2; } if (result == NULL) { result = jk_pool_alloc(s->pool, sz + 1); memcpy(result, id_start, sz); result[sz] = '\0'; } else { size_t osz = strlen(result) + 1; result = jk_pool_realloc(s->pool, osz + sz + 1, result, osz); strcat(result, ";"); strncat(result, id_start, sz); } id_start = id_end; } } } } } return result; } /* Retrieve session id from the cookie or the parameter * (parameter first) */ static char *get_sessionid(jk_ws_service_t *s, lb_worker_t *p, jk_log_context_t *l) { char *val; char *session_path; char *session_cookie; /* If the web server sets a route, ignore the real session id * and fake a new one for that route. */ if (s->route) { size_t sz = strlen(s->route) + 1; val = jk_pool_alloc(s->pool, sz + 1); val[0] = '.'; memcpy(val + 1, s->route, sz); return val; } /* set session_path */ session_path = (s->extension.session_path) ? s->extension.session_path : p->session_path; /* set session_cookie */ session_cookie = (s->extension.session_cookie) ? s->extension.session_cookie : p->session_cookie; val = get_path_param(s, session_path); if (!val) { val = get_cookie(s, session_cookie); } if (val && !*val) { /* TODO: For now only log the empty sessions. * However we should probably return 400 * (BAD_REQUEST) in this case */ jk_log(l, JK_LOG_INFO, "Detected empty session identifier."); return NULL; } return val; } static void close_workers(lb_worker_t *p, int num_of_workers, jk_log_context_t *l) { int i = 0; for (i = 0; i < num_of_workers; i++) { p->lb_workers[i].worker->destroy(&(p->lb_workers[i].worker), l); } } /* If the worker is in error state run * retry on that worker. It will be marked as * operational if the retry timeout is elapsed. * The worker might still be unusable, but we try * anyway. * If the worker is in ok state and got no requests * since the last global maintenance, we mark its * state as not available. * Return the number of workers not in error state. */ static int recover_workers(lb_worker_t *p, jk_uint64_t curmax, time_t now, jk_log_context_t *l) { unsigned int i; int non_error = 0; int elapsed; lb_sub_worker_t *w = NULL; ajp_worker_t *aw = NULL; JK_TRACE_ENTER(l); if (p->sequence < p->s->h.sequence) jk_lb_pull(p, JK_TRUE, l); for (i = 0; i < p->num_of_workers; i++) { w = &p->lb_workers[i]; aw = (ajp_worker_t *)w->worker->worker_private; if (w->s->state == JK_LB_STATE_ERROR) { elapsed = (int)difftime(now, w->s->last_error_time); if (elapsed <= p->recover_wait_time) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s will recover in %d seconds", w->name, p->recover_wait_time - elapsed); } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s is marked for recovery", w->name); if (p->lbmethod != JK_LB_METHOD_BUSYNESS) w->s->lb_value = curmax; aw->s->reply_timeouts = 0; w->s->state = JK_LB_STATE_RECOVER; non_error++; } } else if (w->s->first_error_time > 0 && (int)difftime(now, w->s->first_error_time) >= p->error_escalation_time && w->s->state != JK_LB_STATE_RECOVER) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s escalating local error to global error", w->name); w->s->state = JK_LB_STATE_ERROR; } else { non_error++; if (w->s->state == JK_LB_STATE_OK && aw->s->used == w->s->elected_snapshot) w->s->state = JK_LB_STATE_IDLE; } w->s->elected_snapshot = aw->s->used; } JK_TRACE_EXIT(l); return non_error; } static int force_recovery(lb_worker_t *p, int *states, jk_log_context_t *l) { unsigned int i; int forced = 0; lb_sub_worker_t *w = NULL; ajp_worker_t *aw = NULL; JK_TRACE_ENTER(l); for (i = 0; i < p->num_of_workers; i++) { w = &p->lb_workers[i]; if (w->s->state == JK_LB_STATE_ERROR) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_INFO, "worker %s is marked for forced recovery", w->name); aw = (ajp_worker_t *)w->worker->worker_private; aw->s->reply_timeouts = 0; w->s->state = JK_LB_STATE_FORCE; if (states != NULL) states[i] = JK_LB_STATE_FORCE; forced++; } } JK_TRACE_EXIT(l); return forced; } /* Divide old load values by the decay factor, * such that older values get less important * for the routing decisions. */ static jk_uint64_t decay_load(lb_worker_t *p, time_t exponent, jk_log_context_t *l) { unsigned int i; jk_uint64_t curmax = 0; jk_uint64_t curmin = 0; int no_curmin = JK_TRUE; lb_sub_worker_t *w; ajp_worker_t *aw; JK_TRACE_ENTER(l); for (i = 0; i < p->num_of_workers; i++) { w = &p->lb_workers[i]; if (p->lbmethod != JK_LB_METHOD_BUSYNESS) { if (p->lbmethod != JK_LB_METHOD_NEXT) { w->s->lb_value >>= exponent; } if (w->s->lb_value > curmax) { curmax = w->s->lb_value; } } aw = (ajp_worker_t *)w->worker->worker_private; aw->s->reply_timeouts >>= exponent; } if (p->lbmethod == JK_LB_METHOD_NEXT) { for (i = 0; i < p->num_of_workers; i++) { w = &p->lb_workers[i]; /* Take into account only the workers that are * not in error state, stopped, disabled or busy. * Unfortunately we can not respect activations * defined by mapping rules here. */ if (JK_WORKER_USABLE(w->s->state, w->activation)) { if (w->s->lb_value < curmin || no_curmin == JK_TRUE) { no_curmin = JK_FALSE; curmin = w->s->lb_value; } } } for (i = 0; i < p->num_of_workers; i++) { w = &p->lb_workers[i]; if (w->s->lb_value >= curmin) w->s->lb_value -= curmin; else w->s->lb_value = 0; } } JK_TRACE_EXIT(l); return curmax; } static int JK_METHOD maintain_workers(jk_worker_t *p, time_t now, int global, jk_log_context_t *l) { unsigned int i = 0; jk_uint64_t curmax = 0; JK_TRACE_ENTER(l); if (p && p->worker_private) { lb_worker_t *lb = (lb_worker_t *)p->worker_private; /* Now we check for global maintenance (once for all processes). * Checking workers for recovery and applying decay to the * load values should not be done by each process individually. * Therefore we globally sync and we use a global timestamp. * Since it's possible that we come here a few milliseconds * before the interval has passed, we allow a little tolerance. */ if (global == JK_TRUE) { time_t exponent = JK_LB_DECAY_MULT * ((long)difftime(now, lb->s->last_maintain_time)) / lb->maintain_time; lb->s->last_maintain_time = now; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "decay with 2^%d", exponent); jk_shm_lock(); curmax = decay_load(lb, exponent, l); if (!recover_workers(lb, curmax, now, l)) { force_recovery(lb, NULL, l); } /* * Checking workers for idleness. */ for (i = 0; i < lb->num_of_workers; i++) { ajp_worker_t *aw = lb->lb_workers[i].worker->worker_private; if (aw->s->state == JK_AJP_STATE_OK && aw->s->used == aw->s->used_snapshot) aw->s->state = JK_AJP_STATE_IDLE; aw->s->used_snapshot = aw->s->used; } jk_shm_unlock(); } for (i = 0; i < lb->num_of_workers; i++) { if (lb->lb_workers[i].worker->maintain) { lb->lb_workers[i].worker->maintain(lb->lb_workers[i].worker, now, global, l); } } } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return JK_TRUE; } static int JK_METHOD shutdown_workers(jk_worker_t *p, jk_log_context_t *l) { unsigned int i = 0; JK_TRACE_ENTER(l); if (p && p->worker_private) { lb_worker_t *lb = (lb_worker_t *)p->worker_private; for (i = 0; i < lb->num_of_workers; i++) { if (lb->lb_workers[i].worker->shutdown) { lb->lb_workers[i].worker->shutdown(lb->lb_workers[i].worker, l); } } } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return JK_TRUE; } static int find_by_session(jk_ws_service_t *s, lb_worker_t *p, const char *session_route, jk_log_context_t *l) { int rc = -1; unsigned int i; for (i = 0; i < p->num_of_workers; i++) { if (strcmp(p->lb_workers[i].route, session_route) == 0) { rc = i; break; } } return rc; } static int find_best_bydomain(jk_ws_service_t *s, lb_worker_t *p, const char *route_or_domain, int *states, jk_log_context_t *l) { unsigned int i; int d = 0; jk_uint64_t curmin = 0; int candidate = -1; int activation; lb_sub_worker_t wr; char *idpart = strchr(route_or_domain, '.'); size_t domain_len = 0; if (idpart) { domain_len = idpart - route_or_domain; } else { domain_len = strlen(route_or_domain); } /* First try to see if we have available candidate */ for (i = 0; i < p->num_of_workers; i++) { /* Skip all workers that are not member of domain */ wr = p->lb_workers[i]; if (strlen(wr.domain) == 0 || strlen(wr.domain) != domain_len || strncmp(wr.domain, route_or_domain, domain_len)) continue; /* Take into account only the workers that are * not in error state, stopped, disabled or busy. */ activation = s->extension.activation ? s->extension.activation[i] : JK_LB_ACTIVATION_UNSET; if (activation == JK_LB_ACTIVATION_UNSET) activation = wr.activation; if (JK_WORKER_USABLE(states[wr.i], activation)) { if (candidate < 0 || wr.distance < d || (wr.s->lb_value < curmin && wr.distance == d)) { candidate = i; curmin = wr.s->lb_value; d = wr.distance; } } } return candidate; } static int find_best_byvalue(jk_ws_service_t *s, lb_worker_t *p, int *states, jk_log_context_t *l) { unsigned int i; unsigned int j; unsigned int offset; int d = 0; jk_uint64_t curmin = 0; /* find the least busy worker */ int candidate = -1; int activation; lb_sub_worker_t wr; offset = p->next_offset; /* First try to see if we have available candidate */ for (j = offset; j < p->num_of_workers + offset; j++) { i = j % p->num_of_workers; wr = p->lb_workers[i]; activation = s->extension.activation ? s->extension.activation[i] : JK_LB_ACTIVATION_UNSET; if (activation == JK_LB_ACTIVATION_UNSET) activation = wr.activation; /* Take into account only the workers that are * not in error state, stopped, disabled or busy. */ if (JK_WORKER_USABLE(states[wr.i], activation)) { if (candidate < 0 || wr.distance < d || (s->extension.stateless != JK_TRUE && wr.s->lb_value < curmin && wr.distance == d)) { candidate = i; curmin = wr.s->lb_value; d = wr.distance; p->next_offset = i + 1; } } } return candidate; } static int find_bysession_route(jk_ws_service_t *s, lb_worker_t *p, const char *session_route, int *states, jk_log_context_t *l) { int uses_domain = 0; int candidate = -1; candidate = find_by_session(s, p, session_route, l); if (candidate < 0) { uses_domain = 1; candidate = find_best_bydomain(s, p, session_route, states, l); } else { s->sticky = JK_TRUE; } if (candidate >= 0) { lb_sub_worker_t wr = p->lb_workers[candidate]; int activation; if (uses_domain) s->route = wr.domain; activation = s->extension.activation ? s->extension.activation[candidate] : JK_LB_ACTIVATION_UNSET; if (activation == JK_LB_ACTIVATION_UNSET) activation = wr.activation; if (!JK_WORKER_USABLE_STICKY(states[wr.i], activation)) { /* We have a worker that is error state or stopped. * If it has a redirection set use that redirection worker. * This enables to safely remove the member from the * balancer. Of course you will need a some kind of * session replication between those two remote. */ s->sticky = JK_FALSE; if (p->sticky_session_force) candidate = -1; else if (*wr.redirect) { candidate = find_by_session(s, p, wr.redirect, l); s->route = NULL; } else if (*wr.domain && !uses_domain) { candidate = find_best_bydomain(s, p, wr.domain, states, l); if (candidate >= 0) { s->route = wr.domain; } else { s->route = NULL; } } if (candidate >= 0) { wr = p->lb_workers[candidate]; activation = s->extension.activation ? s->extension.activation[candidate] : JK_LB_ACTIVATION_UNSET; if (activation == JK_LB_ACTIVATION_UNSET) activation = wr.activation; if (!JK_WORKER_USABLE_STICKY(states[wr.i], activation)) candidate = -1; } } } return candidate; } static int find_failover_worker(jk_ws_service_t *s, lb_worker_t *p, int *states, jk_log_context_t *l) { int rc = -1; unsigned int i; char *redirect = NULL; for (i = 0; i < p->num_of_workers; i++) { if (strlen(p->lb_workers[i].redirect)) { redirect = p->lb_workers[i].redirect; break; } } if (redirect) { rc = find_bysession_route(s, p, redirect, states, l); s->sticky = JK_FALSE; } return rc; } static int find_best_worker(jk_ws_service_t *s, lb_worker_t *p, int *states, jk_log_context_t *l) { int rc = -1; rc = find_best_byvalue(s, p, states, l); /* By default use worker route as session route */ if (rc < 0) rc = find_failover_worker(s, p, states, l); return rc; } static int get_most_suitable_worker(jk_ws_service_t *s, lb_worker_t *p, char *sessionid, int *states, jk_log_context_t *l) { int rc = -1; JK_TRACE_ENTER(l); s->sticky = JK_FALSE; if (p->num_of_workers == 1) { /* No need to find the best worker * if there is a single one */ int activation = s->extension.activation ? s->extension.activation[0] : JK_LB_ACTIVATION_UNSET; if (activation == JK_LB_ACTIVATION_UNSET) activation = p->lb_workers[0].activation; if (JK_WORKER_USABLE_STICKY(states[0], activation)) { if (activation != JK_LB_ACTIVATION_DISABLED) { s->sticky = JK_TRUE; JK_TRACE_EXIT(l); return 0; } } else { JK_TRACE_EXIT(l); return -1; } } if (p->lblock == JK_LB_LOCK_PESSIMISTIC) { if (!jk_shm_lock()) { jk_log(l, JK_LOG_ERROR, "locking failed (errno=%d)", errno); JK_TRACE_EXIT(l); return -1; } } else { JK_ENTER_CS(&p->cs); } if (sessionid) { char *session = sessionid; while (sessionid) { char *next = strchr(sessionid, ';'); char *session_route = NULL; if (next) *next++ = '\0'; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "searching worker for partial sessionid %s", sessionid); session_route = strchr(sessionid, '.'); if (session_route) { ++session_route; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "searching worker for session route %s", session_route); /* We have a session route. Whow! */ rc = find_bysession_route(s, p, session_route, states, l); if (rc >= 0) { lb_sub_worker_t *wr = &(p->lb_workers[rc]); if (p->lblock == JK_LB_LOCK_PESSIMISTIC) { jk_shm_unlock(); } else { JK_LEAVE_CS(&p->cs); } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "found worker %s (%s) for route %s and partial sessionid %s", wr->name, wr->route, session_route, sessionid); JK_TRACE_EXIT(l); return rc; } } /* Try next partial sessionid if present */ sessionid = next; rc = -1; } if (rc < 0 && p->sticky_session_force) { if (p->lblock == JK_LB_LOCK_PESSIMISTIC) { jk_shm_unlock(); } else { JK_LEAVE_CS(&p->cs); } jk_log(l, JK_LOG_INFO, "all workers are in error state for session %s", session); JK_TRACE_EXIT(l); return -1; } } rc = find_best_worker(s, p, states, l); if (p->lblock == JK_LB_LOCK_PESSIMISTIC) { jk_shm_unlock(); } else { JK_LEAVE_CS(&p->cs); } if (rc >= 0) { lb_sub_worker_t *wr = &(p->lb_workers[rc]); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "found best worker %s (%s) using method '%s'", wr->name, wr->route, jk_lb_get_method(p, l)); JK_TRACE_EXIT(l); return rc; } JK_TRACE_EXIT(l); return -1; } static void lb_add_log_items(jk_ws_service_t *s, const char *const *log_names, lb_sub_worker_t *w, jk_log_context_t *l) { /* ADJUST JK_LB_NOTES_COUNT WHEN ADDING MORE NOTES HERE! */ ajp_worker_t *aw = (ajp_worker_t *)w->worker->worker_private; const char **log_values = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT); char *buf = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT * JK_LB_UINT64_STR_SZ); if (log_values && buf) { /* JK_NOTE_LB_FIRST/LAST_NAME */ log_values[0] = w->name; snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, w->s->lb_value); /* JK_NOTE_LB_FIRST/LAST_VALUE */ log_values[1] = buf; buf += JK_LB_UINT64_STR_SZ; snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, aw->s->used); /* JK_NOTE_LB_FIRST/LAST_ACCESSED */ log_values[2] = buf; buf += JK_LB_UINT64_STR_SZ; snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, w->s->sessions); /* JK_NOTE_LB_FIRST/LAST_SESSIONS */ log_values[3] = buf; buf += JK_LB_UINT64_STR_SZ; snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, aw->s->readed); /* JK_NOTE_LB_FIRST/LAST_READ */ log_values[4] = buf; buf += JK_LB_UINT64_STR_SZ; snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, aw->s->transferred); /* JK_NOTE_LB_FIRST/LAST_TRANSFERRED */ log_values[5] = buf; buf += JK_LB_UINT64_STR_SZ; snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT32_T_FMT, w->s->errors); /* JK_NOTE_LB_FIRST/LAST_ERRORS */ log_values[6] = buf; buf += JK_LB_UINT64_STR_SZ; snprintf(buf, JK_LB_UINT64_STR_SZ, "%d", aw->s->busy); /* JK_NOTE_LB_FIRST/LAST_BUSY */ log_values[7] = buf; /* JK_NOTE_LB_FIRST/LAST_ACTIVATION */ log_values[8] = jk_lb_get_activation(w, l); /* JK_NOTE_LB_FIRST/LAST_STATE */ log_values[9] = jk_lb_get_state(w, l); s->add_log_items(s, log_names, log_values, JK_LB_NOTES_COUNT); } } static int JK_METHOD service(jk_endpoint_t *e, jk_ws_service_t *s, jk_log_context_t *l, int *is_error) { lb_endpoint_t *p; int attempt = 0; lb_sub_worker_t *prec = NULL; int num_of_workers; int first = 1; int was_forced = 0; int recoverable = JK_TRUE; int rc = JK_UNSET; char *sessionid = NULL; int i; int retry = 0; JK_TRACE_ENTER(l); if (!e || !e->endpoint_private || !s || !is_error) { JK_LOG_NULL_PARAMS(l); if (is_error) *is_error = JK_HTTP_SERVER_ERROR; JK_TRACE_EXIT(l); return JK_FALSE; } p = e->endpoint_private; num_of_workers = p->worker->num_of_workers; /* Set returned error to OK */ *is_error = JK_HTTP_OK; if (p->worker->sequence < p->worker->s->h.sequence) jk_lb_pull(p->worker, JK_FALSE, l); for (i = 0; i < num_of_workers; i++) { lb_sub_worker_t *rec; ajp_worker_t *aw; jk_log(l, JK_LOG_DEBUG, "LB - num_of_workers: %d, retry: %d, lb_retries: %d", num_of_workers, i, p->worker->lb_retries); rec = &(p->worker->lb_workers[i]); aw = (ajp_worker_t *)rec->worker->worker_private; if (rec->s->state == JK_LB_STATE_BUSY) { if ((aw->busy_limit <= 0 || aw->s->busy < aw->busy_limit) && ajp_has_endpoint(rec->worker, l)) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s busy state ended", rec->name); rec->s->state = JK_LB_STATE_OK; } } /* Copy the shared state info */ p->states[i] = rec->s->state; } /* set the recovery post, for LB mode */ s->reco_buf = jk_b_new(s->pool); if (!s->reco_buf) { *is_error = JK_HTTP_SERVER_ERROR; jk_log(l, JK_LOG_ERROR, "Failed allocating AJP message"); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } if (jk_b_set_buffer_size(s->reco_buf, p->worker->max_packet_size)) { *is_error = JK_HTTP_SERVER_ERROR; jk_log(l, JK_LOG_ERROR, "Failed allocating AJP message buffer of %d bytes.", p->worker->max_packet_size); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } jk_b_reset(s->reco_buf); s->reco_status = RECO_INITED; if (p->worker->sticky_session && s->extension.sticky_ignore != JK_TRUE) { /* Use sessionid only if sticky_session is * defined and not overwritten for this load balancer */ sessionid = get_sessionid(s, p->worker, l); } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "service sticky_session=%d id='%s'", p->worker->sticky_session, sessionid ? sessionid : "empty"); while (recoverable == JK_TRUE) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "attempt %d, max attempts %d, worker count %d", attempt, p->worker->lb_retries, num_of_workers); if (attempt >= num_of_workers || attempt >= p->worker->lb_retries) { retry++; if (retry >= p->worker->retries) { /* Done with retrying */ break; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "retry %d, sleeping for %d ms before retrying", retry, p->worker->retry_interval); jk_sleep(p->worker->retry_interval); /* Pull shared memory if something changed during sleep */ if (p->worker->sequence < p->worker->s->h.sequence) jk_lb_pull(p->worker, JK_FALSE, l); for (i = 0; i < num_of_workers; i++) { /* Copy the shared state info */ p->states[i] = p->worker->lb_workers[i].s->state; } attempt = 0; } rc = JK_FALSE; *is_error = JK_HTTP_SERVER_BUSY; i = get_most_suitable_worker(s, p->worker, sessionid, p->states, l); if (i >= 0) { int r; int is_service_error = JK_HTTP_OK; lb_sub_worker_t *rec = &(p->worker->lb_workers[i]); ajp_worker_t *aw = (ajp_worker_t *)rec->worker->worker_private; jk_endpoint_t *end = NULL; int activation = s->extension.activation ? s->extension.activation[i] : JK_LB_ACTIVATION_UNSET; if (activation == JK_LB_ACTIVATION_UNSET) activation = rec->activation; if (!s->route) s->route = rec->route; s->activation = jk_lb_get_activation_direct(activation, l); prec = rec; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "service worker=%s route=%s failover=%s", rec->name, s->route, s->sticky ? "false" : "true"); if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) jk_shm_lock(); if (rec->s->state == JK_LB_STATE_RECOVER) { rec->s->state = JK_LB_STATE_PROBE; p->states[rec->i] = JK_LB_STATE_PROBE; } if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) jk_shm_unlock(); r = rec->worker->get_endpoint(rec->worker, &end, l); if (!r || !end) { /* If we can not get the endpoint * mark the worker as busy rather then * as in error if the retry number is * greater then the number of retries. */ if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) jk_shm_lock(); if (rec->s->state != JK_LB_STATE_ERROR) { rec->s->state = JK_LB_STATE_BUSY; p->states[rec->i] = JK_LB_STATE_BUSY; } if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) jk_shm_unlock(); jk_log(l, JK_LOG_INFO, "could not get free endpoint for worker %s (%d retries)", rec->name, retry); } else { int service_stat = JK_UNSET; jk_uint64_t rd = 0; jk_uint64_t wr = 0; int busy; if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) jk_shm_lock(); /* Increment the number of workers serving request */ busy = JK_ATOMIC_INCREMENT(&(p->worker->s->busy)); if (busy > p->worker->s->max_busy) p->worker->s->max_busy = busy; if (p->worker->lbmethod == JK_LB_METHOD_REQUESTS || p->worker->lbmethod == JK_LB_METHOD_BUSYNESS || (!sessionid && s->extension.stateless != JK_TRUE && (p->worker->lbmethod == JK_LB_METHOD_SESSIONS || p->worker->lbmethod == JK_LB_METHOD_NEXT))) rec->s->lb_value += rec->lb_mult; if (!sessionid && s->extension.stateless != JK_TRUE) { rec->s->sessions++; } if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) jk_shm_unlock(); if (!s->sticky && (s->extension.set_session_cookie || p->worker->set_session_cookie)) { char **old_names = s->resp_headers_names; char **old_values = s->resp_headers_values; s->resp_headers_names = jk_pool_alloc(s->pool, (s->num_resp_headers + 1) * sizeof(char *)); s->resp_headers_values = jk_pool_alloc(s->pool, (s->num_resp_headers + 1) * sizeof(char *)); if (!s->resp_headers_names || !s->resp_headers_values) { jk_log(l, JK_LOG_ERROR, "Failed allocating %d new response headers.", s->num_resp_headers + 1); s->resp_headers_names = old_names; s->resp_headers_values = old_values; } else if (s->num_resp_headers) { memcpy(s->resp_headers_names, old_names, s->num_resp_headers * sizeof(char *)); memcpy(s->resp_headers_values, old_values, s->num_resp_headers * sizeof(char *)); } s->resp_headers_names[s->num_resp_headers] = "Set-Cookie"; s->resp_headers_values[s->num_resp_headers] = jk_pool_strcatv(s->pool, p->worker->session_cookie, "=.", rec->route, NULL); if (p->worker->session_cookie_path && *p->worker->session_cookie_path) { s->resp_headers_values[s->num_resp_headers] = jk_pool_strcatv(s->pool, s->resp_headers_values[s->num_resp_headers], ";PATH=", p->worker->session_cookie_path, NULL); } s->resp_headers_values[s->num_resp_headers] = jk_pool_strcatv(s->pool, s->resp_headers_values[s->num_resp_headers], ";HttpOnly", (s->is_ssl ? ";Secure" : ""), NULL); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Added cookie header '%s' with value '%s' ", s->resp_headers_names[s->num_resp_headers], s->resp_headers_values[s->num_resp_headers]); s->num_resp_headers++; } service_stat = end->service(end, s, l, &is_service_error); rd = end->rd; wr = end->wr; recoverable = end->recoverable; *is_error = is_service_error; end->done(&end, l); if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) jk_shm_lock(); /* Update partial reads and writes if any */ if (p->worker->lbmethod == JK_LB_METHOD_TRAFFIC) { rec->s->lb_value += (rd+wr)*rec->lb_mult; } else if (p->worker->lbmethod == JK_LB_METHOD_BUSYNESS) { if (rec->s->lb_value >= rec->lb_mult) { rec->s->lb_value -= rec->lb_mult; } else { rec->s->lb_value = 0; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "worker %s has load value to low (%" JK_UINT64_T_FMT " < %" JK_UINT64_T_FMT ") ", "- correcting to 0", rec->name, rec->s->lb_value, rec->lb_mult); } } } /* When have an endpoint and we ran a request, assume * we are OK, unless we last were in error. * We will below explicitely set OK or ERROR according * to the returned service_stat. */ if (rec->s->state != JK_LB_STATE_ERROR) { rec->s->state = JK_LB_STATE_OK; p->states[rec->i] = JK_LB_STATE_OK; } /* Decrement the busy worker count. * Check if the busy was reset to zero by graceful * restart of the server. */ JK_ATOMIC_DECREMENT(&(p->worker->s->busy)); if (service_stat == JK_TRUE) { /* * Successful request. */ rec->s->state = JK_LB_STATE_OK; p->states[rec->i] = JK_LB_STATE_OK; rec->s->first_error_time = 0; rec->s->last_error_time = 0; rc = JK_TRUE; recoverable = JK_UNSET; } else if (service_stat == JK_CLIENT_ERROR) { /* * Client error !!! * Since this is bad request do not fail over. */ rec->s->state = JK_LB_STATE_OK; p->states[rec->i] = JK_LB_STATE_ERROR; rec->s->first_error_time = 0; rec->s->last_error_time = 0; rc = JK_CLIENT_ERROR; recoverable = JK_FALSE; } else if (service_stat == JK_SERVER_ERROR) { /* * Internal JK server error. * Keep previous global state. * Do not try to reuse the same node for the same request. * Failing over to another node could help. */ p->states[rec->i] = JK_LB_STATE_ERROR; rc = JK_FALSE; } else if (service_stat == JK_AJP_PROTOCOL_ERROR) { /* * We've received a bad AJP message from the backend. * Keep previous global state. * Do not try to reuse the same node for the same request. * Failing over to another node could help. */ p->states[rec->i] = JK_LB_STATE_ERROR; rc = JK_FALSE; } else if (service_stat == JK_STATUS_ERROR) { /* * Status code configured as service is down. * The node is fine. * Do not try to reuse the same node for the same request. * Failing over to another node could help. */ rec->s->state = JK_LB_STATE_OK; p->states[rec->i] = JK_LB_STATE_ERROR; rec->s->first_error_time = 0; rec->s->last_error_time = 0; rc = JK_FALSE; } else if (service_stat == JK_BUSY_ERROR) { /* * Node was busy. * Do not try to reuse the same node for the same request. * Failing over to another node could help. */ rec->s->state = JK_LB_STATE_BUSY; p->states[rec->i] = JK_LB_STATE_BUSY; rc = JK_FALSE; } else if (service_stat == JK_STATUS_FATAL_ERROR) { /* * Status code configured as service is down. * Mark the node as bad. * Do not try to reuse the same node for the same request. * Failing over to another node could help. */ rec->s->errors++; rec->s->state = JK_LB_STATE_ERROR; p->states[rec->i] = JK_LB_STATE_ERROR; rec->s->first_error_time = time(NULL); rec->s->last_error_time = rec->s->first_error_time; rc = JK_FALSE; } else if (service_stat == JK_REPLY_TIMEOUT) { if (aw->s->reply_timeouts > (unsigned)p->worker->max_reply_timeouts) { /* * Service failed - to many reply timeouts * Mark the node as bad. * Do not try to reuse the same node for the same request. * Failing over to another node could help. */ rec->s->errors++; rec->s->state = JK_LB_STATE_ERROR; p->states[rec->i] = JK_LB_STATE_ERROR; rec->s->first_error_time = time(NULL); rec->s->last_error_time = rec->s->first_error_time; } else { /* * Reply timeout, but not yet too many of them. * Keep previous global state. * Do not try to reuse the same node for the same request. * Failing over to another node could help. */ p->states[rec->i] = JK_LB_STATE_ERROR; } rc = JK_FALSE; } else { /* * Various unspecific error cases. * Keep previous global state, if we are not in local error since to long. * Do not try to reuse the same node for the same request. * Failing over to another node could help. */ time_t now = time(NULL); rec->s->errors++; if (aw->s->busy == 0 || p->worker->error_escalation_time == 0 || (rec->s->first_error_time > 0 && (int)difftime(now, rec->s->first_error_time) >= p->worker->error_escalation_time)) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s escalating local error to global error", rec->name); rec->s->state = JK_LB_STATE_ERROR; } p->states[rec->i] = JK_LB_STATE_ERROR; if (rec->s->first_error_time == 0) { rec->s->first_error_time = now; } rec->s->last_error_time = now; rc = JK_FALSE; } if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC) jk_shm_unlock(); if (p->states[rec->i] == JK_LB_STATE_ERROR) jk_log(l, JK_LOG_INFO, "service failed, worker %s is in %serror state", rec->name, rec->s->state == JK_LB_STATE_ERROR ? "" : "local "); } if (recoverable == JK_TRUE) { /* * Error is recoverable by submitting the request to * another worker... Lets try to do that. */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "recoverable error... will try to recover on other worker"); } else { /* * Error is not recoverable - break with an error. */ if (rc == JK_CLIENT_ERROR) jk_log(l, JK_LOG_INFO, "unrecoverable error %d, request failed." " Client failed in the middle of request," " we can't recover to another instance.", *is_error); else if (rc != JK_TRUE) jk_log(l, JK_LOG_ERROR, "unrecoverable error %d, request failed." " Tomcat failed in the middle of request," " we can't recover to another instance.", *is_error); } if (first == 1 && s->add_log_items) { first = 0; lb_add_log_items(s, lb_first_log_names, prec, l); } } else { /* No more workers left ... */ if (!was_forced) { int nf; /* Force recovery only once. * If it still fails, Tomcat is still disconnected. */ jk_shm_lock(); nf = force_recovery(p->worker, p->states, l); jk_shm_unlock(); was_forced = 1; if (nf) { /* We have forced recovery. * Reset the service loop and go again */ prec = NULL; jk_log(l, JK_LOG_INFO, "Forcing recovery once for %d workers", nf); continue; } else { /* No workers in error state. * Somebody set them all to disabled? */ jk_log(l, JK_LOG_INFO, "All tomcat instances failed, no more workers " "left for recovery (attempt=%d, retry=%d)", attempt + 1, retry); *is_error = JK_HTTP_SERVER_BUSY; rc = JK_FALSE; } } else { jk_log(l, JK_LOG_INFO, "All tomcat instances failed, no more workers " "left (attempt=%d, retry=%d)", attempt + 1, retry); *is_error = JK_HTTP_SERVER_BUSY; rc = JK_FALSE; } } attempt++; } if (recoverable == JK_TRUE) { jk_log(l, JK_LOG_INFO, "All tomcat instances are busy or in error state"); /* rc and http error must be set above */ } if (rc == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "All tomcat instances failed, no more workers left"); } if (prec && s->add_log_items) { lb_add_log_items(s, lb_last_log_names, prec, l); } JK_TRACE_EXIT(l); return rc; } static int JK_METHOD done(jk_endpoint_t **e, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (e && *e && (*e)->endpoint_private) { lb_endpoint_t *p = (*e)->endpoint_private; free(p->states); free(p); *e = NULL; JK_TRACE_EXIT(l); return JK_TRUE; } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } static int JK_METHOD validate(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && pThis->worker_private) { lb_worker_t *p = pThis->worker_private; char **worker_names; unsigned int num_of_workers; const char *secret; p->worker.we = we; p->sticky_session = jk_get_is_sticky_session(props, p->name); p->sticky_session_force = jk_get_is_sticky_session_force(props, p->name); secret = jk_get_worker_secret(props, p->name); if (jk_get_lb_worker_list(props, p->name, &worker_names, &num_of_workers) && num_of_workers) { unsigned int i = 0; unsigned int j = 0; p->lb_workers = jk_pool_alloc(&p->p, num_of_workers * sizeof(lb_sub_worker_t)); if (!p->lb_workers) { JK_TRACE_EXIT(l); return JK_FALSE; } memset(p->lb_workers, 0, num_of_workers * sizeof(lb_sub_worker_t)); for (i = 0; i < num_of_workers; i++) { if (jk_shm_str_init(p->lb_workers[i].name, worker_names[i], "name", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } jk_shm_str_copy(p->lb_workers[i].route, p->lb_workers[i].name, l); p->lb_workers[i].s = jk_shm_alloc_lb_sub_worker(&p->p, p->s->h.id, worker_names[i], l); if (p->lb_workers[i].s == NULL) { jk_log(l, JK_LOG_ERROR, "allocating lb sub worker record from shared memory"); JK_TRACE_EXIT(l); return JK_FALSE; } p->lb_workers[i].i = i; } for (i = 0; i < num_of_workers; i++) { const char *s; unsigned int ms; if (p->lb_workers[i].s->h.sequence != 0) { /* Somebody already setup this worker. * Just pull the data. */ if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Balanced worker %s already configured (sequence=%d)", p->lb_workers[i].name, p->lb_workers[i].s->h.sequence); } if (!wc_create_worker(p->lb_workers[i].name, 0, props, &(p->lb_workers[i].worker), we, l) || !p->lb_workers[i].worker) { break; } jk_lb_pull_worker(p, i, l); continue; } p->lb_workers[i].lb_factor = jk_get_lb_factor(props, worker_names[i]); if (p->lb_workers[i].lb_factor < 1) { p->lb_workers[i].lb_factor = 1; } /* Calculate the maximum packet size from all workers * for the recovery buffer. */ ms = jk_get_max_packet_size(props, worker_names[i]); if (ms > p->max_packet_size) p->max_packet_size = ms; p->lb_workers[i].distance = jk_get_distance(props, worker_names[i]); if ((s = jk_get_worker_route(props, worker_names[i], NULL))) { if (jk_shm_str_init(p->lb_workers[i].route, s, "route", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } } if ((s = jk_get_worker_domain(props, worker_names[i], NULL))) { if (jk_shm_str_init(p->lb_workers[i].domain, s, "domain", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } } if ((s = jk_get_worker_redirect(props, worker_names[i], NULL))) { if (jk_shm_str_init(p->lb_workers[i].redirect, s, "redirect", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } } p->lb_workers[i].s->lb_value = 0; p->lb_workers[i].s->state = JK_LB_STATE_IDLE; p->lb_workers[i].s->first_error_time = 0; p->lb_workers[i].s->last_error_time = 0; p->lb_workers[i].s->elected_snapshot = 0; p->lb_workers[i].s->sessions = 0; p->lb_workers[i].activation = jk_get_worker_activation(props, worker_names[i]); if (!wc_create_worker(p->lb_workers[i].name, 0, props, &(p->lb_workers[i].worker), we, l) || !p->lb_workers[i].worker) { break; } if (secret && (p->lb_workers[i].worker->type == JK_AJP13_WORKER_TYPE || p->lb_workers[i].worker->type == JK_AJP14_WORKER_TYPE)) { ajp_worker_t *aw = (ajp_worker_t *)p->lb_workers[i].worker->worker_private; if (!aw->secret) aw->secret = secret; } if (p->lb_workers[i].worker->type == JK_AJP13_WORKER_TYPE || p->lb_workers[i].worker->type == JK_AJP14_WORKER_TYPE) { ajp_worker_t *aw = (ajp_worker_t *)p->lb_workers[i].worker->worker_private; if (aw->port == 0) { p->lb_workers[i].activation = JK_LB_ACTIVATION_STOPPED; } } } if (i != num_of_workers) { jk_log(l, JK_LOG_ERROR, "Failed creating worker %s", p->lb_workers[i].name); close_workers(p, i, l); } else { /* Update domain names if route contains period '.' */ for (i = 0; i < num_of_workers; i++) { if (!p->lb_workers[i].domain[0]) { char *id_domain = strchr(p->lb_workers[i].route, '.'); if (id_domain) { *id_domain = '\0'; strcpy(p->lb_workers[i].domain, p->lb_workers[i].route); *id_domain = '.'; } } if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Balanced worker %d has name %s and route %s in domain %s", i, p->lb_workers[i].name, p->lb_workers[i].route, p->lb_workers[i].domain); } } p->num_of_workers = num_of_workers; update_mult(p, l); for (i = 0; i < num_of_workers; i++) { for (j = 0; j < i; j++) { if (strcmp(p->lb_workers[i].route, p->lb_workers[j].route) == 0) { jk_log(l, JK_LOG_ERROR, "Balanced workers number %d (%s) and %d (%s) share the same route %s - aborting configuration!", i, p->lb_workers[i].name, j, p->lb_workers[j].name, p->lb_workers[i].route); JK_TRACE_EXIT(l); return JK_FALSE; } } } JK_TRACE_EXIT(l); return JK_TRUE; } } } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } static int JK_METHOD init(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { int i; const char *s; lb_worker_t *p = (lb_worker_t *)pThis->worker_private; JK_TRACE_ENTER(l); p->worker.we = we; p->retries = jk_get_worker_retries(props, p->name, JK_RETRIES); p->lb_retries = jk_get_worker_lb_retries(props, p->name, JK_LB_RETRIES); p->retry_interval = jk_get_worker_retry_interval(props, p->name, JK_SLEEP_DEF); p->recover_wait_time = jk_get_worker_recover_timeout(props, p->name, WAIT_BEFORE_RECOVER); if (p->recover_wait_time < 1) p->recover_wait_time = 1; p->error_escalation_time = jk_get_worker_error_escalation_time(props, p->name, p->recover_wait_time / 2); p->max_reply_timeouts = jk_get_worker_max_reply_timeouts(props, p->name, 0); p->maintain_time = jk_get_worker_maintain_time(props); if(p->maintain_time < 0) p->maintain_time = 0; p->s->last_maintain_time = time(NULL); p->s->last_reset = p->s->last_maintain_time; p->lbmethod = jk_get_lb_method(props, p->name); #ifdef JK_ATOMIC_MISSING if (p->lbmethod == JK_LB_METHOD_BUSYNESS) { jk_log(l, JK_LOG_WARNING, "Missing support for atomics: " "LB method 'busyness' not recommended"); } #endif p->lblock = jk_get_lb_lock(props, p->name); s = jk_get_lb_session_cookie(props, p->name, JK_SESSION_IDENTIFIER); if (jk_shm_str_init(p->session_cookie, s, "session_cookie", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } s = jk_get_lb_session_path(props, p->name, JK_PATH_SESSION_IDENTIFIER); if (jk_shm_str_init(p->session_path, s, "session_path", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } p->set_session_cookie = jk_get_lb_set_session_cookie(props, p->name, JK_FALSE); s = jk_get_lb_session_cookie_path(props, p->name, "/"); if (jk_shm_str_init(p->session_cookie_path, s, "session_cookie_path", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } JK_INIT_CS(&(p->cs), i); if (i == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "creating thread lock (errno=%d)", errno); JK_TRACE_EXIT(l); return JK_FALSE; } if (p->s->h.sequence == 0) { /* Set configuration data to shared memory */ jk_lb_push(p, JK_TRUE, JK_FALSE, l); } else { /* Shared memory for this worker is already configured. * Update with runtime data */ jk_lb_pull(p, JK_TRUE, l); } JK_TRACE_EXIT(l); return JK_TRUE; } static int JK_METHOD get_endpoint(jk_worker_t *pThis, jk_endpoint_t **pend, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && pThis->worker_private && pend) { lb_endpoint_t *p = (lb_endpoint_t *) malloc(sizeof(lb_endpoint_t)); p->worker = pThis->worker_private; p->endpoint.endpoint_private = p; p->endpoint.service = service; p->endpoint.done = done; p->states = (int *)malloc((p->worker->num_of_workers + 1) * sizeof(int)); if (!p->states) { free(p); jk_log(l, JK_LOG_ERROR, "Failed allocating private worker state memory"); JK_TRACE_EXIT(l); return JK_FALSE; } *pend = &p->endpoint; JK_TRACE_EXIT(l); return JK_TRUE; } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return JK_FALSE; } static int JK_METHOD destroy(jk_worker_t **pThis, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && *pThis && (*pThis)->worker_private) { lb_worker_t *private_data = (*pThis)->worker_private; close_workers(private_data, private_data->num_of_workers, l); JK_DELETE_CS(&private_data->cs); jk_close_pool(&private_data->p); free(private_data); JK_TRACE_EXIT(l); return JK_TRUE; } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } int JK_METHOD lb_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (NULL != name && NULL != w) { lb_worker_t *private_data = (lb_worker_t *) calloc(1, sizeof(lb_worker_t)); jk_open_pool(&private_data->p, private_data->buf, sizeof(jk_pool_atom_t) * TINY_POOL_SIZE); private_data->s = jk_shm_alloc_lb_worker(&private_data->p, name, l); if (!private_data->s) { free(private_data); JK_TRACE_EXIT(l); return 0; } if (jk_shm_str_init(private_data->name, name, "name", l) == JK_FALSE) { JK_TRACE_EXIT(l); return 0; } private_data->lb_workers = NULL; private_data->num_of_workers = 0; private_data->worker.worker_private = private_data; private_data->worker.validate = validate; private_data->worker.init = init; private_data->worker.get_endpoint = get_endpoint; private_data->worker.destroy = destroy; private_data->worker.maintain = maintain_workers; private_data->worker.shutdown = shutdown_workers; private_data->recover_wait_time = WAIT_BEFORE_RECOVER; private_data->error_escalation_time = private_data->recover_wait_time / 2; private_data->max_reply_timeouts = 0; private_data->max_packet_size = AJP13_DEF_PACKET_SIZE; private_data->sequence = 0; private_data->next_offset = 0; *w = &private_data->worker; JK_TRACE_EXIT(l); return JK_LB_WORKER_TYPE; } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return 0; } tomcat-connectors-1.2.50-src/native/common/jk_status.c0000644000000000000020000070207714655113617021272 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Status worker, display and manages JK workers * * Author: Mladen Turk * * Author: Rainer Jung * ***************************************************************************/ #include "jk_pool.h" #include "jk_service.h" #include "jk_util.h" #include "jk_worker.h" #include "jk_status.h" #include "jk_mt.h" #include "jk_shm.h" #include "jk_ajp_common.h" #include "jk_lb_worker.h" #include "jk_ajp13_worker.h" #include "jk_ajp14_worker.h" #include "jk_connect.h" #include "jk_uri_worker_map.h" #include "jk_url.h" #define HUGE_BUFFER_SIZE (8*1024) /** * Command line reference: * cmd=list (default) display configuration * cmd=show display detailed configuration * cmd=edit form to change configuration * cmd=update commit update configuration * cmd=reset reset lb runtime states, or lb member runtime states * cmd=version show only software version * Query arguments: * re=n (refresh time in seconds, n=0: disabled) * w=worker (cmd should be executed for worker "worker") * sw=sub_worker (cmd should be executed for "sub_worker" of worker "worker") * from=lastcmd (the last viewing command was "lastcmd") * opt=option (changes meaning of edit and list/show) */ #define JK_STATUS_ARG_CMD "cmd" #define JK_STATUS_ARG_MIME "mime" #define JK_STATUS_ARG_FROM "from" #define JK_STATUS_ARG_REFRESH "re" #define JK_STATUS_ARG_WORKER "w" #define JK_STATUS_ARG_SUB_WORKER "sw" #define JK_STATUS_ARG_PREV_SUB_WORKER "psw" #define JK_STATUS_ARG_ATTRIBUTE "att" #define JK_STATUS_ARG_MULT_VALUE_BASE "val" #define JK_STATUS_ARG_OPTIONS "opt" #define JK_STATUS_ARG_OPTION_NO_MEMBERS 0x0001 #define JK_STATUS_ARG_OPTION_NO_MAPS 0x0002 #define JK_STATUS_ARG_OPTION_NO_LEGEND 0x0004 #define JK_STATUS_ARG_OPTION_NO_LB 0x0008 #define JK_STATUS_ARG_OPTION_NO_AJP 0x0010 #define JK_STATUS_ARG_OPTION_READ_ONLY 0x0020 #define JK_STATUS_ARG_OPTION_NO_LB_CONF 0x0040 #define JK_STATUS_ARG_OPTION_NO_LB_SUMMARY 0x0080 #define JK_STATUS_ARG_OPTION_NO_AJP_CONF 0x0100 #define JK_STATUS_ARG_LB_RETRIES ("vlr") #define JK_STATUS_ARG_LB_RETRY_INT ("vlri") #define JK_STATUS_ARG_LB_RECOVER_TIME ("vlt") #define JK_STATUS_ARG_LB_ERROR_ESCALATION_TIME ("vlee") #define JK_STATUS_ARG_LB_MAX_REPLY_TIMEOUTS ("vlx") #define JK_STATUS_ARG_LB_STICKY ("vls") #define JK_STATUS_ARG_LB_STICKY_FORCE ("vlf") #define JK_STATUS_ARG_LB_METHOD ("vlm") #define JK_STATUS_ARG_LB_LOCK ("vll") #define JK_STATUS_ARG_LB_TEXT_RETRIES "Retries" #define JK_STATUS_ARG_LB_TEXT_RETRY_INT "Retry Interval" #define JK_STATUS_ARG_LB_TEXT_RECOVER_TIME "Recover Wait Time" #define JK_STATUS_ARG_LB_TEXT_ERROR_ESCALATION_TIME "Error Escalation Time" #define JK_STATUS_ARG_LB_TEXT_MAX_REPLY_TIMEOUTS "Max Reply Timeouts" #define JK_STATUS_ARG_LB_TEXT_STICKY "Sticky Sessions" #define JK_STATUS_ARG_LB_TEXT_STICKY_FORCE "Force Sticky Sessions" #define JK_STATUS_ARG_LB_TEXT_METHOD "LB Method" #define JK_STATUS_ARG_LB_TEXT_LOCK "Locking" #define JK_STATUS_ARG_LB_HEAD_RETRIES "Retries" #define JK_STATUS_ARG_LB_HEAD_RETRY_INT "Retry
Interval" #define JK_STATUS_ARG_LB_HEAD_RECOVER_TIME "Recover
Wait Time" #define JK_STATUS_ARG_LB_HEAD_ERROR_ESCALATION_TIME "Error
Escalation Time" #define JK_STATUS_ARG_LB_HEAD_MAX_REPLY_TIMEOUTS "Max Reply
Timeouts" #define JK_STATUS_ARG_LB_HEAD_STICKY "Sticky
Sessions" #define JK_STATUS_ARG_LB_HEAD_STICKY_FORCE "Force Sticky
Sessions" #define JK_STATUS_ARG_LB_HEAD_METHOD "LB
Method" #define JK_STATUS_ARG_LB_HEAD_LOCK "Locking" #define JK_STATUS_ARG_LBM_ACTIVATION ("vwa") #define JK_STATUS_ARG_LBM_FACTOR ("vwf") #define JK_STATUS_ARG_LBM_ROUTE ("vwn") #define JK_STATUS_ARG_LBM_REDIRECT ("vwr") #define JK_STATUS_ARG_LBM_DOMAIN ("vwc") #define JK_STATUS_ARG_LBM_DISTANCE ("vwd") #define JK_STATUS_ARG_LBM_TEXT_ACTIVATION "Activation" #define JK_STATUS_ARG_LBM_TEXT_FACTOR "LB Factor" #define JK_STATUS_ARG_LBM_TEXT_ROUTE "Route" #define JK_STATUS_ARG_LBM_TEXT_REDIRECT "Redirect Route" #define JK_STATUS_ARG_LBM_TEXT_DOMAIN "Cluster Domain" #define JK_STATUS_ARG_LBM_TEXT_DISTANCE "Distance" #define JK_STATUS_ARG_LBM_HEAD_ACTIVATION "Activation" #define JK_STATUS_ARG_LBM_HEAD_FACTOR "LB
Factor" #define JK_STATUS_ARG_LBM_HEAD_ROUTE "Route" #define JK_STATUS_ARG_LBM_HEAD_REDIRECT "Redirect
Route" #define JK_STATUS_ARG_LBM_HEAD_DOMAIN "Cluster
Domain" #define JK_STATUS_ARG_LBM_HEAD_DISTANCE "Distance" #define JK_STATUS_ARG_AJP_CACHE_TO "vacpt" #define JK_STATUS_ARG_AJP_PING_TO "vapng" #define JK_STATUS_ARG_AJP_CONNECT_TO "vact" #define JK_STATUS_ARG_AJP_PREPOST_TO "vapt" #define JK_STATUS_ARG_AJP_REPLY_TO "vart" #define JK_STATUS_ARG_AJP_RETRIES "var" #define JK_STATUS_ARG_AJP_RETRY_INT "vari" #define JK_STATUS_ARG_AJP_REC_OPTS "varo" #define JK_STATUS_ARG_AJP_BUSY_LIMIT "vabl" #define JK_STATUS_ARG_AJP_MAX_PK_SZ "vamps" #define JK_STATUS_ARG_AJP_CPING_INT "vacpi" #define JK_STATUS_ARG_AJP_HOST_STR "vahst" #define JK_STATUS_ARG_AJP_PORT "vaprt" #define JK_STATUS_ARG_AJP_TEXT_CACHE_TO "Connection Pool Timeout" #define JK_STATUS_ARG_AJP_TEXT_PING_TO "Ping Timeout" #define JK_STATUS_ARG_AJP_TEXT_CONNECT_TO "Connect Timeout" #define JK_STATUS_ARG_AJP_TEXT_PREPOST_TO "Prepost Timeout" #define JK_STATUS_ARG_AJP_TEXT_REPLY_TO "Reply Timeout" #define JK_STATUS_ARG_AJP_TEXT_RETRIES "Retries" #define JK_STATUS_ARG_AJP_TEXT_RETRY_INT "Retry Interval" #define JK_STATUS_ARG_AJP_TEXT_REC_OPTS "Recovery Options" #define JK_STATUS_ARG_AJP_TEXT_BUSY_LIMIT "Busy Limit" #define JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ "Max Packet Size" #define JK_STATUS_ARG_AJP_TEXT_CPING_INT "Connection Ping Interval" #define JK_STATUS_ARG_AJP_TEXT_HOST_STR "Hostname" #define JK_STATUS_ARG_AJP_TEXT_PORT "Port" #define JK_STATUS_ARG_AJP_TEXT_ADDR_STR "Address:Port" #define JK_STATUS_ARG_AJP_TEXT_SOURCE_STR "Source" #define JK_STATUS_ARG_AJP_HEAD_CACHE_TO "Connection
Pool Timeout" #define JK_STATUS_ARG_AJP_HEAD_PING_TO "Ping
Timeout" #define JK_STATUS_ARG_AJP_HEAD_CONNECT_TO "Connect
Timeout" #define JK_STATUS_ARG_AJP_HEAD_PREPOST_TO "Prepost
Timeout" #define JK_STATUS_ARG_AJP_HEAD_REPLY_TO "Reply
Timeout" #define JK_STATUS_ARG_AJP_HEAD_RETRIES "Retries" #define JK_STATUS_ARG_AJP_HEAD_RETRY_INT "Retry
Interval" #define JK_STATUS_ARG_AJP_HEAD_REC_OPTS "Recovery
Options" #define JK_STATUS_ARG_AJP_HEAD_BUSY_LIMIT "Busy
Limit" #define JK_STATUS_ARG_AJP_HEAD_MAX_PK_SZ "Max Packet
Size" #define JK_STATUS_ARG_AJP_HEAD_CPING_INT "Connection
Ping Interval" #define JK_STATUS_ARG_AJP_HEAD_HOST_STR "Hostname" #define JK_STATUS_ARG_AJP_HEAD_PORT "Port" #define JK_STATUS_ARG_AJP_HEAD_ADDR_STR "Address:Port" #define JK_STATUS_ARG_AJP_HEAD_SOURCE_STR "Source" #define JK_STATUS_CMD_UNKNOWN (0) #define JK_STATUS_CMD_LIST (1) #define JK_STATUS_CMD_SHOW (2) #define JK_STATUS_CMD_EDIT (3) #define JK_STATUS_CMD_UPDATE (4) #define JK_STATUS_CMD_RESET (5) #define JK_STATUS_CMD_VERSION (6) #define JK_STATUS_CMD_RECOVER (7) #define JK_STATUS_CMD_DUMP (8) #define JK_STATUS_CMD_DEF (JK_STATUS_CMD_LIST) #define JK_STATUS_CMD_MAX (JK_STATUS_CMD_DUMP) #define JK_STATUS_CMD_TEXT_UNKNOWN ("unknown") #define JK_STATUS_CMD_TEXT_LIST ("list") #define JK_STATUS_CMD_TEXT_SHOW ("show") #define JK_STATUS_CMD_TEXT_EDIT ("edit") #define JK_STATUS_CMD_TEXT_UPDATE ("update") #define JK_STATUS_CMD_TEXT_RESET ("reset") #define JK_STATUS_CMD_TEXT_VERSION ("version") #define JK_STATUS_CMD_TEXT_RECOVER ("recover") #define JK_STATUS_CMD_TEXT_DUMP ("dump") #define JK_STATUS_CMD_TEXT_DEF (JK_STATUS_CMD_TEXT_LIST) #define JK_STATUS_CMD_PROP_CHECK_WORKER 0x00000001 #define JK_STATUS_CMD_PROP_READONLY 0x00000002 #define JK_STATUS_CMD_PROP_HEAD 0x00000004 #define JK_STATUS_CMD_PROP_REFRESH 0x00000008 #define JK_STATUS_CMD_PROP_BACK_LINK 0x00000010 #define JK_STATUS_CMD_PROP_BACK_LIST 0x00000020 #define JK_STATUS_CMD_PROP_FMT 0x00000040 #define JK_STATUS_CMD_PROP_SWITCH_RO 0x00000080 #define JK_STATUS_CMD_PROP_DUMP_LINK 0x00000100 #define JK_STATUS_CMD_PROP_LINK_HELP 0x00000200 #define JK_STATUS_CMD_PROP_LEGEND 0x00000400 #define JK_STATUS_CMD_PROP_WILDCARD 0x00000800 #define JK_STATUS_MIME_UNKNOWN (0) #define JK_STATUS_MIME_HTML (1) #define JK_STATUS_MIME_XML (2) #define JK_STATUS_MIME_TXT (3) #define JK_STATUS_MIME_PROP (4) #define JK_STATUS_MIME_DEF (JK_STATUS_MIME_HTML) #define JK_STATUS_MIME_MAX (JK_STATUS_MIME_PROP) #define JK_STATUS_MIME_TEXT_UNKNOWN ("unknown") #define JK_STATUS_MIME_TEXT_HTML ("html") #define JK_STATUS_MIME_TEXT_XML ("xml") #define JK_STATUS_MIME_TEXT_TXT ("txt") #define JK_STATUS_MIME_TEXT_PROP ("prop") #define JK_STATUS_MIME_TEXT_DEF (JK_STATUS_MIME_TEXT_HTML) #define JK_STATUS_MASK_ACTIVE 0x000000FF #define JK_STATUS_MASK_DISABLED 0x0000FF00 #define JK_STATUS_MASK_STOPPED 0x00FF0000 #define JK_STATUS_MASK_OK 0x00010101 #define JK_STATUS_MASK_IDLE 0x00020202 #define JK_STATUS_MASK_BUSY 0x00040404 #define JK_STATUS_MASK_RECOVER 0x00080808 #define JK_STATUS_MASK_ERROR 0x00101010 #define JK_STATUS_MASK_GOOD_DEF 0x0000000F #define JK_STATUS_MASK_BAD_DEF 0x00FF1010 #define JK_STATUS_NEEDS_PUSH 0x00000001 #define JK_STATUS_NEEDS_RESET_LB_VALUES 0x00000002 #define JK_STATUS_NEEDS_UPDATE_MULT 0x00000004 #define JK_STATUS_NEEDS_ADDR_PUSH 0x00000008 #define JK_STATUS_WAIT_AFTER_UPDATE "3" #define JK_STATUS_REFRESH_DEF "10" #define JK_STATUS_ESC_CHARS ("<>?\"") #ifdef WIN32 /* See also windows_strftime_preprocess() */ #define JK_WINDOWS_TIMEZONE_PLACEHOLDER "+????" #define JK_STATUS_TIME_FMT_HTML "%Y-%m-%d %H:%M:%S " JK_WINDOWS_TIMEZONE_PLACEHOLDER #define JK_STATUS_TIME_FMT_TZ JK_WINDOWS_TIMEZONE_PLACEHOLDER #else #define JK_STATUS_TIME_FMT_HTML "%Y-%m-%d %H:%M:%S %z" #define JK_STATUS_TIME_FMT_TZ "%z" #endif #define JK_STATUS_TIME_FMT_TEXT "%Y%m%d%H%M%S" #define JK_STATUS_TIME_BUF_SZ (30) #define JK_STATUS_HEAD "\n" \ "\n" \ "" \ "JK Status Manager" #define JK_STATUS_COPYRIGHT "Copyright © 1999-2020, The Apache Software Foundation
" \ "Licensed under the " \ "Apache License, Version 2.0." #define JK_STATUS_HEND "\n\n" #define JK_STATUS_BEND "\n\n" #define JK_STATUS_XMLH "\n" #define JK_STATUS_NS_DEF "jk:" #define JK_STATUS_XMLNS_DEF "xmlns:jk=\"http://tomcat.apache.org\"" #define JK_STATUS_PREFIX_DEF "worker" #define JK_STATUS_FORM_START "

\n" #define JK_STATUS_FORM_HIDDEN_INT "\n" #define JK_STATUS_FORM_HIDDEN_STRING "\n" #define JK_STATUS_URI_MAP_TABLE_HEAD "%s%s%s%s%s%s%s%s%s%s%s\n" #define JK_STATUS_URI_MAP_TABLE_ROW "%s%s%s%d%d%d%s%s%s%s%d\n" #define JK_STATUS_URI_MAP_TABLE_HEAD2 "%s%s%s%s%s%s%s%s%s%s%s%s\n" #define JK_STATUS_URI_MAP_TABLE_ROW2 "%s%s%s%s%d%d%d%s%s%s%s%d\n" #define JK_STATUS_SHOW_AJP_CONF_HEAD "" \ "Type" \ "" JK_STATUS_ARG_AJP_HEAD_HOST_STR "" \ "" JK_STATUS_ARG_AJP_HEAD_ADDR_STR "" \ "" JK_STATUS_ARG_AJP_HEAD_SOURCE_STR "" \ "" JK_STATUS_ARG_AJP_HEAD_CACHE_TO "" \ "" JK_STATUS_ARG_AJP_HEAD_CONNECT_TO "" \ "" JK_STATUS_ARG_AJP_HEAD_PREPOST_TO "" \ "" JK_STATUS_ARG_AJP_HEAD_REPLY_TO "" \ "" JK_STATUS_ARG_AJP_HEAD_RETRIES "" \ "" JK_STATUS_ARG_AJP_HEAD_REC_OPTS "" \ "" JK_STATUS_ARG_AJP_HEAD_BUSY_LIMIT "" \ "" JK_STATUS_ARG_AJP_HEAD_MAX_PK_SZ "" \ "\n" #define JK_STATUS_SHOW_AJP_CONF_ROW "" \ "%s" \ "%s" \ "%s" \ "%s" \ "%d" \ "%d" \ "%d" \ "%d" \ "%u" \ "%d" \ "%u" \ "" \ "\n" #define JK_STATUS_SHOW_AJP_HEAD "" \ "State" \ "Acc" \ "ErrCERE" \ "WrRdBusyMaxBusyConMaxConLRLE" \ "\n" #define JK_STATUS_SHOW_AJP_ROW "" \ "%s" \ "%" JK_UINT64_T_FMT " (%d/sec)" \ "%" JK_UINT32_T_FMT "" \ "%" JK_UINT32_T_FMT "" \ "%" JK_UINT32_T_FMT "" \ "%s (%s/sec)" \ "%s (%s/sec)" \ "%d" \ "%d" \ "%d" \ "%d" \ "%d" \ "%s" \ "\n" #define JK_STATUS_SHOW_LB_HEAD "" \ "Type" \ "" JK_STATUS_ARG_LB_HEAD_STICKY "" \ "" JK_STATUS_ARG_LB_HEAD_STICKY_FORCE "" \ "" JK_STATUS_ARG_LB_HEAD_RETRIES "" \ "" JK_STATUS_ARG_LB_HEAD_METHOD "" \ "" JK_STATUS_ARG_LB_HEAD_LOCK "" \ "" JK_STATUS_ARG_LB_HEAD_RECOVER_TIME "" \ "" JK_STATUS_ARG_LB_HEAD_ERROR_ESCALATION_TIME "" \ "" JK_STATUS_ARG_LB_HEAD_MAX_REPLY_TIMEOUTS "" \ "\n" #define JK_STATUS_SHOW_LB_ROW "" \ "%s" \ "%s" \ "%s" \ "%d" \ "%s" \ "%s" \ "%d" \ "%d" \ "%d" \ "" \ "\n" #define JK_STATUS_SHOW_MEMBER_HEAD "" \ " Name" \ "ActState" \ "DFM" \ "VAccSess" \ "ErrCERE" \ "WrRdBusyMaxBusyConMaxCon" \ "" JK_STATUS_ARG_LBM_HEAD_ROUTE "" \ "RRCdRsLRLE" \ "\n" #define JK_STATUS_SHOW_MEMBER_ROW "%s" \ "%s" \ "%s" \ "%d" \ "%d" \ "%" JK_UINT64_T_FMT "" \ "%" JK_UINT64_T_FMT "" \ "%" JK_UINT64_T_FMT " (%d/sec)" \ "%" JK_UINT64_T_FMT " (%d/sec)" \ "%" JK_UINT32_T_FMT "" \ "%" JK_UINT32_T_FMT "" \ "%" JK_UINT32_T_FMT "" \ "%s (%s/sec)" \ "%s (%s/sec)" \ "%d" \ "%d" \ "%d" \ "%d" \ "%s" \ "%s" \ "%s" \ "%d/%d" \ "%d" \ "%s" \ "\n" #define JK_STATUS_SHOW_MEMBER_CONF_HEAD "" \ "NameType" \ "" JK_STATUS_ARG_AJP_HEAD_HOST_STR "" \ "" JK_STATUS_ARG_AJP_HEAD_ADDR_STR "" \ "" JK_STATUS_ARG_AJP_HEAD_SOURCE_STR "" \ "" JK_STATUS_ARG_AJP_HEAD_CACHE_TO "" \ "" JK_STATUS_ARG_AJP_HEAD_CONNECT_TO "" \ "" JK_STATUS_ARG_AJP_HEAD_PREPOST_TO "" \ "" JK_STATUS_ARG_AJP_HEAD_REPLY_TO "" \ "" JK_STATUS_ARG_AJP_HEAD_RETRIES "" \ "" JK_STATUS_ARG_AJP_HEAD_REC_OPTS "" \ "" JK_STATUS_ARG_AJP_HEAD_BUSY_LIMIT "" \ "" JK_STATUS_ARG_AJP_HEAD_MAX_PK_SZ "" \ "\n" #define JK_STATUS_SHOW_MEMBER_CONF_ROW "" \ "%s" \ "%s" \ "%s" \ "%s" \ "%s" \ "%d" \ "%d" \ "%d" \ "%d" \ "%d" \ "%u" \ "%d" \ "%u" \ "" \ "\n" typedef struct status_worker status_worker_t; struct status_endpoint { status_worker_t *worker; char *req_uri; char *query_string; jk_map_t *req_params; char *msg; jk_endpoint_t endpoint; }; typedef struct status_endpoint status_endpoint_t; struct status_worker { jk_pool_t p; jk_pool_atom_t buf[TINY_POOL_SIZE]; const char *name; const char *css; const char *ns; const char *xmlns; const char *doctype; const char *prefix; int read_only; char **user_names; unsigned int num_of_users; int user_case_insensitive; jk_uint32_t good_mask; jk_uint32_t bad_mask; jk_worker_t worker; jk_worker_env_t *we; }; static const char *worker_type[] = { "unknown", "ajp12", "ajp13", "ajp14", "jni", "lb", "status", NULL }; static const char *headers_names[] = { "Content-Type", "Cache-Control", "Pragma", NULL }; static const char *cmd_type[] = { JK_STATUS_CMD_TEXT_UNKNOWN, JK_STATUS_CMD_TEXT_LIST, JK_STATUS_CMD_TEXT_SHOW, JK_STATUS_CMD_TEXT_EDIT, JK_STATUS_CMD_TEXT_UPDATE, JK_STATUS_CMD_TEXT_RESET, JK_STATUS_CMD_TEXT_VERSION, JK_STATUS_CMD_TEXT_RECOVER, JK_STATUS_CMD_TEXT_DUMP, NULL }; static const char *mime_type[] = { JK_STATUS_MIME_TEXT_UNKNOWN, JK_STATUS_MIME_TEXT_HTML, JK_STATUS_MIME_TEXT_XML, JK_STATUS_MIME_TEXT_TXT, JK_STATUS_MIME_TEXT_PROP, NULL }; #define HEADERS_NO_CACHE "no-cache", "no-cache", NULL static const char *headers_vhtml[] = { "text/html", HEADERS_NO_CACHE }; static const char *headers_vxml[] = { "text/xml", HEADERS_NO_CACHE }; static const char *headers_vtxt[] = { "text/plain", HEADERS_NO_CACHE }; static void jk_puts(jk_ws_service_t *s, const char *str) { if (str) s->write(s, str, (unsigned int)strlen(str)); else s->write(s, "(null)", 6); } static void jk_putv(jk_ws_service_t *s, ...) { va_list va; const char *str; va_start(va, s); while (1) { str = va_arg(va, const char *); if (str == NULL) break; s->write(s, str, (unsigned int)strlen(str)); } va_end(va); } static int jk_printf(jk_ws_service_t *s, jk_log_context_t *l, const char *fmt, ...) { int rc = 0; va_list args; char buf[HUGE_BUFFER_SIZE]; if (!s || !fmt) { return -1; } va_start(args, fmt); rc = vsnprintf(buf, HUGE_BUFFER_SIZE, fmt, args); va_end(args); if (rc > 0 && rc < HUGE_BUFFER_SIZE) s->write(s, buf, rc); else jk_log(l, JK_LOG_WARNING, "Insufficient buffer size %d in status worker, some output was dropped", HUGE_BUFFER_SIZE); return rc; } static void jk_print_xml_start_elt(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, int indentation, int close_tag, const char *name) { if (close_tag) { jk_printf(s, l, "%*s<%s%s>\n", indentation, "", w->ns, name); } else { jk_printf(s, l, "%*s<%s%s\n", indentation, "", w->ns, name); } } static void jk_print_xml_close_elt(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, int indentation, const char *name) { jk_printf(s, l, "%*s\n", indentation, "", w->ns, name); } static void jk_print_xml_stop_elt(jk_ws_service_t *s, jk_log_context_t *l, int indentation, int close_tag) { if (close_tag) { jk_printf(s, l, "%*s/>\n", indentation, ""); } else { jk_printf(s, l, "%*s>\n", indentation, ""); } } static void jk_print_xml_att_string(jk_ws_service_t *s, jk_log_context_t *l, int indentation, const char *key, const char *value) { jk_printf(s, l, "%*s%s=\"%s\"\n", indentation, "", key, value ? value : ""); } static void jk_print_xml_att_int(jk_ws_service_t *s, jk_log_context_t *l, int indentation, const char *key, int value) { jk_printf(s, l, "%*s%s=\"%d\"\n", indentation, "", key, value); } static void jk_print_xml_att_uint(jk_ws_service_t *s, jk_log_context_t *l, int indentation, const char *key, unsigned int value) { jk_printf(s, l, "%*s%s=\"%u\"\n", indentation, "", key, value); } static void jk_print_xml_att_long(jk_ws_service_t *s, jk_log_context_t *l, int indentation, const char *key, long value) { jk_printf(s, l, "%*s%s=\"%ld\"\n", indentation, "", key, value); } static void jk_print_xml_att_uint32(jk_ws_service_t *s, jk_log_context_t *l, int indentation, const char *key, jk_uint32_t value) { jk_printf(s, l, "%*s%s=\"%" JK_UINT32_T_FMT "\"\n", indentation, "", key, value); } static void jk_print_xml_att_uint64(jk_ws_service_t *s, jk_log_context_t *l, int indentation, const char *key, jk_uint64_t value) { jk_printf(s, l, "%*s%s=\"%" JK_UINT64_T_FMT "\"\n", indentation, "", key, value); } static void jk_print_prop_att_string(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, const char *name, const char *key, const char *value) { if (name) { jk_printf(s, l, "%s.%s.%s=%s\n", w->prefix, name, key, value ? value : ""); } else { jk_printf(s, l, "%s.%s=%s\n", w->prefix, key, value ? value : ""); } } static void jk_print_prop_att_int(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, const char *name, const char *key, int value) { if (name) { jk_printf(s, l, "%s.%s.%s=%d\n", w->prefix, name, key, value); } else { jk_printf(s, l, "%s.%s=%d\n", w->prefix, key, value); } } static void jk_print_prop_att_uint(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, const char *name, const char *key, unsigned int value) { if (name) { jk_printf(s, l, "%s.%s.%s=%u\n", w->prefix, name, key, value); } else { jk_printf(s, l, "%s.%s=%u\n", w->prefix, key, value); } } static void jk_print_prop_att_long(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, const char *name, const char *key, long value) { if (name) { jk_printf(s, l, "%s.%s.%s=%ld\n", w->prefix, name, key, value); } else { jk_printf(s, l, "%s.%s=%ld\n", w->prefix, key, value); } } static void jk_print_prop_att_uint32(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, const char *name, const char *key, jk_uint32_t value) { if (name) { jk_printf(s, l, "%s.%s.%s=%" JK_UINT32_T_FMT "\n", w->prefix, name, key, value); } else { jk_printf(s, l, "%s.%s=%" JK_UINT32_T_FMT "\n", w->prefix, key, value); } } static void jk_print_prop_att_uint64(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, const char *name, const char *key, jk_uint64_t value) { if (name) { jk_printf(s, l, "%s.%s.%s=%" JK_UINT64_T_FMT "\n", w->prefix, name, key, value); } else { jk_printf(s, l, "%s.%s=%" JK_UINT64_T_FMT "\n", w->prefix, key, value); } } static void jk_print_prop_item_int(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, const char *name, const char *list, int num, const char *key, int value) { if (name) { jk_printf(s, l, "%s.%s.%s.%d.%s=%d\n", w->prefix, name, list, num, key, value); } else { jk_printf(s, l, "%s.%s.%d.%s=%d\n", w->prefix, list, num, key, value); } } static void jk_print_prop_item_string(jk_ws_service_t *s, jk_log_context_t *l, status_worker_t *w, const char *name, const char *list, int num, const char *key, const char *value) { if (name) { jk_printf(s, l, "%s.%s.%s.%d.%s=%s\n", w->prefix, name, list, num, key, value ? value : ""); } else { jk_printf(s, l, "%s.%s.%d.%s=%s\n", w->prefix, list, num, key, value ? value : ""); } } /* Actually APR's apr_strfsize */ static char *status_strfsize(jk_uint64_t size, char *buf) { const char ord[] = "KMGTPE"; const char *o = ord; unsigned int remain, siz; if (size < 973) { if (sprintf(buf, "%d ", (int) size) < 0) return strcpy(buf, "****"); return buf; } do { remain = (unsigned int)(size & 0x03FF); size >>= 10; if (size >= 973) { ++o; continue; } siz = (unsigned int)(size & 0xFFFF); if (siz < 9 || (siz == 9 && remain < 973)) { if ((remain = ((remain * 5) + 256) / 512) >= 10) ++siz, remain = 0; if (sprintf(buf, "%d.%d%c", siz, remain, *o) < 0) return strcpy(buf, "****"); return buf; } if (remain >= 512) ++siz; if (sprintf(buf, "%d%c", siz, *o) < 0) return strcpy(buf, "****"); return buf; } while (1); } #ifdef WIN32 /* Handle time formatting aspects which are not implemented by strftime * on Windows. * Currently only handles numeric time zone formatting * which needs to be requested using JK_WINDOWS_TIMEZONE_PLACEHOLDER * in the pattern. */ static const char *windows_strftime_preprocess(const char *pattern, char *buf, size_t sz) { char *found = strstr(pattern, JK_WINDOWS_TIMEZONE_PLACEHOLDER); if (found != NULL && sz > strlen(pattern)) { TIME_ZONE_INFORMATION tz; DWORD rc; strcpy(buf, pattern); found = buf + (found - pattern); rc = GetTimeZoneInformation(&tz); if (rc != TIME_ZONE_ID_INVALID) { if (rc == TIME_ZONE_ID_STANDARD) { tz.Bias += tz.StandardBias; } else if (rc == TIME_ZONE_ID_DAYLIGHT) { tz.Bias += tz.DaylightBias; } tz.Bias *= -1; snprintf(found, strlen(JK_WINDOWS_TIMEZONE_PLACEHOLDER), "%c%02d%02d", (tz.Bias >= 0 ? '+' : '-'), tz.Bias / 60, tz.Bias % 60); } return buf; } else { return pattern; } } #else #define windows_strftime_preprocess(x, y, z) (x) #endif static int status_strftime(time_t clock, int mime, char *buf_time, char *buf_tz, jk_log_context_t *l) { size_t rc_time; #ifdef WIN32 char buf[JK_STATUS_TIME_BUF_SZ]; #endif #ifdef _MT_CODE_PTHREAD struct tm res; struct tm *tms = localtime_r(&clock, &res); #else struct tm *tms = localtime(&clock); #endif JK_TRACE_ENTER(l); if (mime == JK_STATUS_MIME_HTML) rc_time = strftime(buf_time, JK_STATUS_TIME_BUF_SZ, windows_strftime_preprocess(JK_STATUS_TIME_FMT_HTML, buf, JK_STATUS_TIME_BUF_SZ), tms); else { rc_time = strftime(buf_time, JK_STATUS_TIME_BUF_SZ, windows_strftime_preprocess(JK_STATUS_TIME_FMT_TEXT, buf, JK_STATUS_TIME_BUF_SZ), tms); } strftime(buf_tz, JK_STATUS_TIME_BUF_SZ, windows_strftime_preprocess(JK_STATUS_TIME_FMT_TZ, buf, JK_STATUS_TIME_BUF_SZ), tms); JK_TRACE_EXIT(l); return (int)rc_time; } static int status_rate(lb_sub_worker_t *wr, status_worker_t *w, jk_log_context_t *l) { jk_uint32_t mask = 0; int activation = wr->activation; int state = wr->s->state; jk_uint32_t good = w->good_mask; jk_uint32_t bad = w->bad_mask; int rv = 0; switch (activation) { case JK_LB_ACTIVATION_ACTIVE: mask = JK_STATUS_MASK_ACTIVE; break; case JK_LB_ACTIVATION_DISABLED: mask = JK_STATUS_MASK_DISABLED; break; case JK_LB_ACTIVATION_STOPPED: mask = JK_STATUS_MASK_STOPPED; break; default: jk_log(l, JK_LOG_WARNING, "Status worker '%s' unknown activation type '%d'", w->name, activation); } switch (state) { case JK_LB_STATE_IDLE: mask &= JK_STATUS_MASK_IDLE; break; case JK_LB_STATE_OK: mask &= JK_STATUS_MASK_OK; break; case JK_LB_STATE_RECOVER: mask &= JK_STATUS_MASK_RECOVER; break; case JK_LB_STATE_FORCE: mask &= JK_STATUS_MASK_RECOVER; break; case JK_LB_STATE_BUSY: mask &= JK_STATUS_MASK_BUSY; break; case JK_LB_STATE_ERROR: mask &= JK_STATUS_MASK_ERROR; break; case JK_LB_STATE_PROBE: mask &= JK_STATUS_MASK_RECOVER; break; default: jk_log(l, JK_LOG_WARNING, "Status worker '%s' unknown state type '%d'", w->name, state); } if (mask&bad) rv = -1; else if (mask&good) rv = 1; else rv = 0; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' rating of activation '%s' and state '%s' for good '%08" JK_UINT32_T_HEX_FMT "' and bad '%08" JK_UINT32_T_HEX_FMT "' is %d", w->name, jk_lb_get_activation(wr, l), jk_lb_get_state(wr, l), good, bad, rv); return rv; } static jk_uint32_t status_get_single_rating(const char rating, jk_log_context_t *l) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "rating retrieval for '%c'", rating); switch (rating) { case 'A': case 'a': return JK_STATUS_MASK_ACTIVE; case 'D': case 'd': return JK_STATUS_MASK_DISABLED; case 'S': case 's': return JK_STATUS_MASK_STOPPED; case 'O': case 'o': return JK_STATUS_MASK_OK; case 'I': case 'i': case 'N': case 'n': return JK_STATUS_MASK_IDLE; case 'B': case 'b': return JK_STATUS_MASK_BUSY; case 'R': case 'r': return JK_STATUS_MASK_RECOVER; case 'E': case 'e': return JK_STATUS_MASK_ERROR; default: jk_log(l, JK_LOG_WARNING, "Unknown rating type '%c'", rating); return 0; } } static jk_uint32_t status_get_rating(const char *rating, jk_log_context_t *l) { int off = 0; jk_uint32_t mask = 0; while (rating[off] == ' ' || rating[off] == '\t' || rating[off] == '.') { off++; } mask = status_get_single_rating(rating[off], l); while (rating[off] != '\0' && rating[off] != '.') { off++; } if (rating[off] == '.') { off++; } if (rating[off] != '\0') { mask &= status_get_single_rating(rating[off], l); } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "rating for '%s' is '%08" JK_UINT32_T_HEX_FMT "'", rating, mask); return mask; } static const char *status_worker_type(int t) { if (t < 0 || t > 6) t = 0; return worker_type[t]; } static int status_get_string(status_endpoint_t *p, const char *param, const char *def, const char **result, jk_log_context_t *l) { int rv; *result = jk_map_get_string(p->req_params, param, NULL); if (*result) { rv = JK_TRUE; } else { *result = def; rv = JK_FALSE; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "retrieved string arg '%s' as '%s'%s", param, *result ? *result : "(null)", rv == JK_FALSE ? " (default)" : ""); return rv; } static int status_get_int(status_endpoint_t *p, const char *param, int def, jk_log_context_t *l) { const char *arg; int rv = def; if (status_get_string(p, param, NULL, &arg, l) == JK_TRUE) { rv = atoi(arg); } return rv; } static int status_get_bool(status_endpoint_t *p, const char *param, int def, jk_log_context_t *l) { const char *arg; if (status_get_string(p, param, NULL, &arg, l) == JK_TRUE) { return jk_get_bool_code(arg, def); } return def; } static const char *status_cmd_text(int cmd) { return cmd_type[cmd]; } static int status_cmd_int(const char *cmd) { if (!cmd) return JK_STATUS_CMD_DEF; if (!strcmp(cmd, JK_STATUS_CMD_TEXT_LIST)) return JK_STATUS_CMD_LIST; else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_SHOW)) return JK_STATUS_CMD_SHOW; else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_EDIT)) return JK_STATUS_CMD_EDIT; else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_UPDATE)) return JK_STATUS_CMD_UPDATE; else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_RESET)) return JK_STATUS_CMD_RESET; else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_VERSION)) return JK_STATUS_CMD_VERSION; else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_RECOVER)) return JK_STATUS_CMD_RECOVER; else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_DUMP)) return JK_STATUS_CMD_DUMP; return JK_STATUS_CMD_UNKNOWN; } static const char *status_mime_text(int mime) { return mime_type[mime]; } static int status_mime_int(const char *mime) { if (!mime) return JK_STATUS_MIME_DEF; if (!strcmp(mime, JK_STATUS_MIME_TEXT_HTML)) return JK_STATUS_MIME_HTML; else if (!strcmp(mime, JK_STATUS_MIME_TEXT_XML)) return JK_STATUS_MIME_XML; else if (!strcmp(mime, JK_STATUS_MIME_TEXT_TXT)) return JK_STATUS_MIME_TXT; else if (!strcmp(mime, JK_STATUS_MIME_TEXT_PROP)) return JK_STATUS_MIME_PROP; return JK_STATUS_MIME_UNKNOWN; } static jk_uint32_t status_cmd_props(int cmd) { jk_uint32_t props = 0; if (cmd == JK_STATUS_CMD_LIST || cmd == JK_STATUS_CMD_SHOW) props |= JK_STATUS_CMD_PROP_REFRESH | JK_STATUS_CMD_PROP_SWITCH_RO | JK_STATUS_CMD_PROP_LINK_HELP | JK_STATUS_CMD_PROP_LEGEND; if (cmd == JK_STATUS_CMD_LIST || cmd == JK_STATUS_CMD_SHOW || cmd == JK_STATUS_CMD_VERSION) props |= JK_STATUS_CMD_PROP_DUMP_LINK; if (cmd == JK_STATUS_CMD_LIST || cmd == JK_STATUS_CMD_SHOW || cmd == JK_STATUS_CMD_VERSION || cmd == JK_STATUS_CMD_DUMP) props |= JK_STATUS_CMD_PROP_HEAD | JK_STATUS_CMD_PROP_FMT; if (cmd == JK_STATUS_CMD_SHOW || cmd == JK_STATUS_CMD_VERSION || cmd == JK_STATUS_CMD_DUMP) props |= JK_STATUS_CMD_PROP_BACK_LIST; if (cmd == JK_STATUS_CMD_SHOW || cmd == JK_STATUS_CMD_EDIT || cmd == JK_STATUS_CMD_VERSION || cmd == JK_STATUS_CMD_DUMP) props |= JK_STATUS_CMD_PROP_BACK_LINK; if (cmd == JK_STATUS_CMD_UPDATE) props |= JK_STATUS_CMD_PROP_WILDCARD; if (cmd != JK_STATUS_CMD_EDIT && cmd != JK_STATUS_CMD_UPDATE && cmd != JK_STATUS_CMD_RESET && cmd != JK_STATUS_CMD_RECOVER) props |= JK_STATUS_CMD_PROP_READONLY; if (cmd != JK_STATUS_CMD_LIST && cmd != JK_STATUS_CMD_VERSION && cmd != JK_STATUS_CMD_DUMP) props |= JK_STATUS_CMD_PROP_CHECK_WORKER; return props; } static void status_start_form(jk_ws_service_t *s, status_endpoint_t *p, const char *method, int cmd, const char *overwrite, jk_log_context_t *l) { int i; int sz; jk_map_t *m = p->req_params; if (method) jk_printf(s, l, JK_STATUS_FORM_START, method, p->req_uri); else return; if (cmd != JK_STATUS_CMD_UNKNOWN) { jk_printf(s, l, JK_STATUS_FORM_HIDDEN_STRING, JK_STATUS_ARG_CMD, status_cmd_text(cmd)); } sz = jk_map_size(m); for (i = 0; i < sz; i++) { const char *k = jk_map_name_at(m, i); const char *v = jk_map_value_at(m, i); if ((strcmp(k, JK_STATUS_ARG_CMD) || cmd == JK_STATUS_CMD_UNKNOWN) && (!overwrite || strcmp(k, overwrite))) { jk_printf(s, l, JK_STATUS_FORM_HIDDEN_STRING, k, v); } } } static void status_write_uri(jk_ws_service_t *s, status_endpoint_t *p, const char *text, int cmd, int mime, const char *worker, const char *sub_worker, unsigned int add_options, unsigned int rm_options, const char *attribute, jk_log_context_t *l) { int i; int sz; int started = 0; int from; int restore_sub_worker = JK_FALSE; int save_sub_worker = JK_FALSE; int prev; unsigned int opt = 0; const char *arg; jk_map_t *m = p->req_params; if (text) jk_puts(s, "req_uri); status_get_string(p, JK_STATUS_ARG_FROM, NULL, &arg, l); from = status_cmd_int(arg); status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); prev = status_cmd_int(arg); if (cmd == JK_STATUS_CMD_SHOW && prev == JK_STATUS_CMD_EDIT) { restore_sub_worker = JK_TRUE; } if (cmd == JK_STATUS_CMD_UNKNOWN) { if (prev == JK_STATUS_CMD_UPDATE || prev == JK_STATUS_CMD_RESET || prev == JK_STATUS_CMD_RECOVER) { cmd = from; restore_sub_worker = JK_TRUE; } } if (cmd != JK_STATUS_CMD_UNKNOWN) { jk_printf(s, l, "%s%s=%s", started ? "&" : "?", JK_STATUS_ARG_CMD, status_cmd_text(cmd)); if (cmd == JK_STATUS_CMD_EDIT || cmd == JK_STATUS_CMD_RESET || cmd == JK_STATUS_CMD_RECOVER) { jk_printf(s, l, "%s%s=%s", "&", JK_STATUS_ARG_FROM, status_cmd_text(prev)); save_sub_worker = JK_TRUE; } started=1; } if (mime != JK_STATUS_MIME_UNKNOWN) { jk_printf(s, l, "%s%s=%s", started ? "&" : "?", JK_STATUS_ARG_MIME, status_mime_text(mime)); started=1; } if (worker && worker[0]) { jk_printf(s, l, "%s%s=%s", started ? "&" : "?", JK_STATUS_ARG_WORKER, worker); started=1; } if (sub_worker && sub_worker[0] && cmd != JK_STATUS_CMD_LIST) { jk_printf(s, l, "%s%s=%s", started ? "&" : "?", JK_STATUS_ARG_SUB_WORKER, sub_worker); started=1; } if (attribute && attribute[0]) { jk_printf(s, l, "%s%s=%s", started ? "&" : "?", JK_STATUS_ARG_ATTRIBUTE, attribute); started=1; } sz = jk_map_size(m); for (i = 0; i < sz; i++) { const char *k = jk_map_name_at(m, i); const char *v = jk_map_value_at(m, i); if (!strcmp(k, JK_STATUS_ARG_CMD) && cmd != JK_STATUS_CMD_UNKNOWN) { continue; } if (!strcmp(k, JK_STATUS_ARG_MIME) && mime != JK_STATUS_MIME_UNKNOWN) { continue; } if (!strcmp(k, JK_STATUS_ARG_FROM)) { continue; } if (!strcmp(k, JK_STATUS_ARG_WORKER) && worker) { continue; } if (!strcmp(k, JK_STATUS_ARG_SUB_WORKER)) { if (save_sub_worker == JK_TRUE) { jk_printf(s, l, "%s%s=%s", started ? "&" : "?", JK_STATUS_ARG_PREV_SUB_WORKER, v); started=1; continue; } else if (sub_worker || cmd == JK_STATUS_CMD_LIST) { continue; } else if (restore_sub_worker == JK_TRUE) { continue; } } if (!strcmp(k, JK_STATUS_ARG_PREV_SUB_WORKER) && restore_sub_worker == JK_TRUE && cmd != JK_STATUS_CMD_LIST) { jk_printf(s, l, "%s%s=%s", started ? "&" : "?", JK_STATUS_ARG_SUB_WORKER, v); started=1; continue; } if (!strcmp(k, JK_STATUS_ARG_ATTRIBUTE) && attribute) { continue; } if (!strcmp(k, JK_STATUS_ARG_ATTRIBUTE) && cmd != JK_STATUS_CMD_UPDATE && cmd != JK_STATUS_CMD_EDIT) { continue; } if (!strncmp(k, JK_STATUS_ARG_MULT_VALUE_BASE, 3) && cmd != JK_STATUS_CMD_UPDATE) { continue; } if (k[0] == 'v' && cmd != JK_STATUS_CMD_UPDATE) { continue; } if (!strcmp(k, JK_STATUS_ARG_OPTIONS)) { opt = atoi(v); continue; } jk_printf(s, l, "%s%s=%s", started ? "&" : "?", k, v); started=1; } if (opt | add_options | rm_options) jk_printf(s, l, "%s%s=%u", started ? "&" : "?", JK_STATUS_ARG_OPTIONS, (opt | add_options) & ~rm_options); if (text) jk_putv(s, "\">", text, "", NULL); } static int status_unescape_uri(jk_ws_service_t *s, status_endpoint_t *p, jk_log_context_t *l) { status_worker_t *w = p->worker; char *req_uri; JK_TRACE_ENTER(l); req_uri = p->req_uri = jk_pool_strdup(s->pool, s->req_uri); /* percent decoding */ if (jk_unescape_url(req_uri, req_uri, -1, NULL, NULL, 1, NULL) != JK_TRUE) { jk_log(l, JK_LOG_ERROR, "Status worker '%s' could not decode request uri", w->name); JK_TRACE_EXIT(l); return JK_FALSE; } /* XXX We simply mask special chars in the request uri with '@' to prevent cross site scripting */ while ((req_uri = strpbrk(req_uri, JK_STATUS_ESC_CHARS))) req_uri[0] = '@'; JK_TRACE_EXIT(l); return JK_TRUE; } static int status_parse_uri(jk_ws_service_t *s, status_endpoint_t *p, jk_log_context_t *l) { jk_map_t *m; status_worker_t *w = p->worker; #ifdef _MT_CODE_PTHREAD char *lasts; #endif char *param; char *query; JK_TRACE_ENTER(l); if (!s->query_string) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' query string is empty", w->name); JK_TRACE_EXIT(l); return JK_TRUE; } p->query_string = jk_pool_strdup(s->pool, s->query_string); if (!p->query_string) { jk_log(l, JK_LOG_ERROR, "Status worker '%s' could not copy query string", w->name); JK_TRACE_EXIT(l); return JK_FALSE; } /* XXX We simply mask special chars in the query string with '@' to prevent cross site scripting */ query = p->query_string; while ((query = strpbrk(query, JK_STATUS_ESC_CHARS))) query[0] = '@'; if (!jk_map_alloc(&(p->req_params))) { jk_log(l, JK_LOG_ERROR, "Status worker '%s' could not alloc map for request parameters", w->name); JK_TRACE_EXIT(l); return JK_FALSE; } m = p->req_params; query = jk_pool_strdup(s->pool, p->query_string); if (!query) { jk_log(l, JK_LOG_ERROR, "Status worker '%s' could not copy query string", w->name); JK_TRACE_EXIT(l); return JK_FALSE; } #ifdef _MT_CODE_PTHREAD for (param = strtok_r(query, "&", &lasts); param; param = strtok_r(NULL, "&", &lasts)) { #else for (param = strtok(query, "&"); param; param = strtok(NULL, "&")) { #endif char *key = jk_pool_strdup(s->pool, param); char *value; char *tmp; if (!key) { jk_log(l, JK_LOG_ERROR, "Status worker '%s' could not copy string", w->name); JK_TRACE_EXIT(l); return JK_FALSE; } value = strchr(key, '='); if (value) { *value = '\0'; value++; if (strlen(key)) { /* percent decoding */ if (jk_unescape_url(value, value, -1, NULL, NULL, 1, NULL) != JK_TRUE) { jk_log(l, JK_LOG_ERROR, "Status worker '%s' could not decode query string " "param '%s' with value '%s'", w->name, key, value); JK_TRACE_EXIT(l); return JK_FALSE; } /* XXX We simply mask special chars in the query string with '@' * to prevent cross site scripting */ tmp = value; while ((tmp = strpbrk(tmp, JK_STATUS_ESC_CHARS))) tmp[0] = '@'; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' adding request param '%s' with value '%s'", w->name, key, value); /* XXX Depending on the params values, we might need to trim */ jk_map_put(m, key, value, NULL); } } } JK_TRACE_EXIT(l); return JK_TRUE; } static void write_html_refresh_response(jk_ws_service_t *s, status_endpoint_t *p, const char *err, jk_log_context_t *l) { if (!err) { jk_puts(s, "\n"); jk_putv(s, "

Result: OK - You will be redirected in " JK_STATUS_WAIT_AFTER_UPDATE " seconds.

", NULL); } } static int fetch_worker_and_sub_worker(status_endpoint_t *p, const char *operation, const char **worker, const char **sub_worker, jk_log_context_t *l) { status_worker_t *w = p->worker; JK_TRACE_ENTER(l); status_get_string(p, JK_STATUS_ARG_WORKER, NULL, worker, l); status_get_string(p, JK_STATUS_ARG_SUB_WORKER, NULL, sub_worker, l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s worker '%s' sub worker '%s'", w->name, operation, *worker ? *worker : "(null)", *sub_worker ? *sub_worker : "(null)"); if (!*worker || !(*worker)[0]) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' NULL or EMPTY worker param", w->name); p->msg = "NULL or EMPTY worker param"; JK_TRACE_EXIT(l); return JK_FALSE; } if (*sub_worker && !(*sub_worker)[0]) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' EMPTY sub worker param", w->name); p->msg = "EMPTY sub worker param"; JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } static int check_valid_lb(jk_ws_service_t *s, status_endpoint_t *p, jk_worker_t *jw, const char *worker, lb_worker_t **lbp, int implemented, jk_log_context_t *l) { status_worker_t *w = p->worker; JK_TRACE_ENTER(l); if (jw->type != JK_LB_WORKER_TYPE) { if (implemented) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' worker type of worker '%s' has no sub workers", w->name, worker); p->msg = "worker type has no sub workers"; } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' worker type of worker '%s' not implemented", w->name, worker); p->msg = "worker type not implemented"; } JK_TRACE_EXIT(l); return JK_FALSE; } *lbp = (lb_worker_t *)jw->worker_private; if (!*lbp) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' lb structure of worker '%s' is (null)", w->name, worker); p->msg = "lb structure is (null)"; JK_TRACE_EXIT(l); return JK_FALSE; } p->msg = "OK"; JK_TRACE_EXIT(l); return JK_TRUE; } static int search_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_worker_t **jwp, const char *worker, jk_log_context_t *l) { status_worker_t *w = p->worker; JK_TRACE_ENTER(l); *jwp = NULL; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' searching worker '%s'", w->name, worker ? worker : "(null)"); if (!worker || !worker[0]) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' NULL or EMPTY worker param", w->name); p->msg = "NULL or EMPTY worker param"; JK_TRACE_EXIT(l); return JK_FALSE; } *jwp = wc_get_worker_for_name(worker, l); if (!*jwp) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' could not find worker '%s'", w->name, worker); p->msg = "Could not find given worker"; JK_TRACE_EXIT(l); return JK_FALSE; } p->msg = "OK"; JK_TRACE_EXIT(l); return JK_TRUE; } static int search_sub_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_worker_t *jw, const char *worker, lb_sub_worker_t **wrp, const char *sub_worker, unsigned int *idx, jk_log_context_t *l) { lb_worker_t *lb = NULL; lb_sub_worker_t *wr = NULL; status_worker_t *w = p->worker; unsigned int i = 0; JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' searching sub worker '%s' of worker '%s'", w->name, sub_worker ? sub_worker : "(null)", worker ? worker : "(null)"); if (!sub_worker || !sub_worker[0]) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' NULL or EMPTY sub_worker param", w->name); p->msg = "NULL or EMPTY sub_worker param"; JK_TRACE_EXIT(l); return JK_FALSE; } if (check_valid_lb(s, p, jw, worker, &lb, 1, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (idx) i = *idx; for (; i < lb->num_of_workers; i++) { wr = &(lb->lb_workers[i]); if (idx) { if (jk_wildchar_match(wr->name, sub_worker, 0) == 0) { *idx = i + 1; break; } } else if (strcmp(sub_worker, wr->name) == 0) break; } *wrp = wr; if (!wr || i == lb->num_of_workers) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' could not find sub worker '%s' of worker '%s'", w->name, sub_worker, worker ? worker : "(null)"); p->msg = "could not find sub worker"; JK_TRACE_EXIT(l); return JK_FALSE; } p->msg = "OK"; JK_TRACE_EXIT(l); return JK_TRUE; } static int count_map(jk_uri_worker_map_t *uw_map, const char *worker, jk_log_context_t *l) { unsigned int i; int count=0; JK_TRACE_ENTER(l); if (uw_map) { for (i = 0; i < uw_map->size[uw_map->index]; i++) { uri_worker_record_t *uwr = uw_map->maps[uw_map->index][i]; if (strcmp(uwr->worker_name, worker) && strcmp(uwr->worker_name, "*")) { continue; } count++; } } JK_TRACE_EXIT(l); return count; } static int count_maps(jk_ws_service_t *s, const char *worker, jk_log_context_t *l) { int count=0; JK_TRACE_ENTER(l); if (s->next_vhost) { void *srv; for (srv = s->next_vhost(NULL); srv; srv = s->next_vhost(srv)) { count += count_map(s->vhost_to_uw_map(srv), worker, l); } } else if (s->uw_map) count = count_map(s->uw_map, worker, l); JK_TRACE_EXIT(l); return count; } static void display_map(jk_ws_service_t *s, status_endpoint_t *p, jk_uri_worker_map_t *uw_map, const char *worker, const char *server_name, int *count_ptr, int mime, jk_log_context_t *l) { char buf[64]; unsigned int i; int count; status_worker_t *w = p->worker; JK_TRACE_ENTER(l); if (uw_map->fname) { uri_worker_map_update(uw_map, 1, l); } for (i = 0; i < uw_map->size[uw_map->index]; i++) { uri_worker_record_t *uwr = uw_map->maps[uw_map->index][i]; if (strcmp(uwr->worker_name, worker) && strcmp(uwr->worker_name, "*")) { continue; } (*count_ptr)++; count = *count_ptr; if (mime == JK_STATUS_MIME_HTML) { if (server_name) jk_printf(s, l, JK_STATUS_URI_MAP_TABLE_ROW2, server_name, uwr->uri, uri_worker_map_get_match(uwr, buf), uri_worker_map_get_source(uwr), uwr->extensions.reply_timeout, uwr->extensions.sticky_ignore, uwr->extensions.stateless, uwr->extensions.fail_on_status_str ? uwr->extensions.fail_on_status_str : "-", uwr->extensions.active ? uwr->extensions.active : "-", uwr->extensions.disabled ? uwr->extensions.disabled : "-", uwr->extensions.stopped ? uwr->extensions.stopped : "-", uwr->extensions.use_server_error_pages); else jk_printf(s, l, JK_STATUS_URI_MAP_TABLE_ROW, uwr->uri, uri_worker_map_get_match(uwr, buf), uri_worker_map_get_source(uwr), uwr->extensions.reply_timeout, uwr->extensions.sticky_ignore, uwr->extensions.stateless, uwr->extensions.fail_on_status_str ? uwr->extensions.fail_on_status_str : "-", uwr->extensions.active ? uwr->extensions.active : "-", uwr->extensions.disabled ? uwr->extensions.disabled : "-", uwr->extensions.stopped ? uwr->extensions.stopped : "-", uwr->extensions.use_server_error_pages); } else if (mime == JK_STATUS_MIME_XML) { jk_print_xml_start_elt(s, l, w, 6, 0, "map"); jk_print_xml_att_int(s, l, 8, "id", count); if (server_name) jk_print_xml_att_string(s, l, 8, "server", server_name); jk_print_xml_att_string(s, l, 8, "uri", uwr->uri); jk_print_xml_att_string(s, l, 8, "type", uri_worker_map_get_match(uwr, buf)); jk_print_xml_att_string(s, l, 8, "source", uri_worker_map_get_source(uwr)); jk_print_xml_att_int(s, l, 8, "reply_timeout", uwr->extensions.reply_timeout); jk_print_xml_att_int(s, l, 8, "sticky_ignore", uwr->extensions.sticky_ignore); jk_print_xml_att_int(s, l, 8, "stateless", uwr->extensions.stateless); jk_print_xml_att_string(s, l, 8, "fail_on_status", uwr->extensions.fail_on_status_str); jk_print_xml_att_string(s, l, 8, "active", uwr->extensions.active); jk_print_xml_att_string(s, l, 8, "disabled", uwr->extensions.disabled); jk_print_xml_att_string(s, l, 8, "stopped", uwr->extensions.stopped); jk_print_xml_att_int(s, l, 8, "use_server_errors", uwr->extensions.use_server_error_pages); jk_print_xml_stop_elt(s, l, 6, 1); } else if (mime == JK_STATUS_MIME_TXT) { jk_puts(s, "Map:"); jk_printf(s, l, " id=%d", count); if (server_name) jk_printf(s, l, " server=\"%s\"", server_name); jk_printf(s, l, " uri=\"%s\"", uwr->uri); jk_printf(s, l, " type=\"%s\"", uri_worker_map_get_match(uwr, buf)); jk_printf(s, l, " source=\"%s\"", uri_worker_map_get_source(uwr)); jk_printf(s, l, " reply_timeout=\"%d\"", uwr->extensions.reply_timeout); jk_printf(s, l, " sticky_ignore=\"%d\"", uwr->extensions.sticky_ignore); jk_printf(s, l, " stateless=\"%d\"", uwr->extensions.stateless); jk_printf(s, l, " fail_on_status=\"%s\"", uwr->extensions.fail_on_status_str ? uwr->extensions.fail_on_status_str : ""); jk_printf(s, l, " active=\"%s\"", uwr->extensions.active ? uwr->extensions.active : ""); jk_printf(s, l, " disabled=\"%s\"", uwr->extensions.disabled ? uwr->extensions.disabled : ""); jk_printf(s, l, " stopped=\"%s\"", uwr->extensions.stopped ? uwr->extensions.stopped : ""); jk_printf(s, l, " use_server_errors=\"%d\"", uwr->extensions.use_server_error_pages); jk_puts(s, "\n"); } else if (mime == JK_STATUS_MIME_PROP) { if (server_name) jk_print_prop_item_string(s, l, w, worker, "map", count, "server", server_name); jk_print_prop_item_string(s, l, w, worker, "map", count, "uri", uwr->uri); jk_print_prop_item_string(s, l, w, worker, "map", count, "type", uri_worker_map_get_match(uwr, buf)); jk_print_prop_item_string(s, l, w, worker, "map", count, "source", uri_worker_map_get_source(uwr)); jk_print_prop_item_int(s, l, w, worker, "map", count, "reply_timeout", uwr->extensions.reply_timeout); jk_print_prop_item_int(s, l, w, worker, "map", count, "sticky_ignore", uwr->extensions.sticky_ignore); jk_print_prop_item_int(s, l, w, worker, "map", count, "stateless", uwr->extensions.stateless); jk_print_prop_item_string(s, l, w, worker, "map", count, "fail_on_status", uwr->extensions.fail_on_status_str); jk_print_prop_item_string(s, l, w, worker, "map", count, "active", uwr->extensions.active); jk_print_prop_item_string(s, l, w, worker, "map", count, "disabled", uwr->extensions.disabled); jk_print_prop_item_string(s, l, w, worker, "map", count, "stopped", uwr->extensions.stopped); jk_print_prop_item_int(s, l, w, worker, "map", count, "use_server_errors", uwr->extensions.use_server_error_pages); } } JK_TRACE_EXIT(l); } static void display_maps(jk_ws_service_t *s, status_endpoint_t *p, const char *worker, jk_log_context_t *l) { int mime; unsigned int hide; int has_server_iterator = 0; int count=0; const char *arg; status_worker_t *w = p->worker; jk_uri_worker_map_t *uw_map; char server_name[80]; void *srv; JK_TRACE_ENTER(l); status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); mime = status_mime_int(arg); hide = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_NO_MAPS; if (s->next_vhost) has_server_iterator = 1; count = count_maps(s, worker, l); if (hide) { if (count && mime == JK_STATUS_MIME_HTML) { jk_puts(s, "

\n"); status_write_uri(s, p, "Show URI Mappings", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_MAPS, NULL, l); jk_puts(s, "

\n"); } JK_TRACE_EXIT(l); return; } if (count) { if (mime == JK_STATUS_MIME_HTML) { jk_printf(s, l, "

URI Mappings for %s (%d maps) [", worker, count); status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_MAPS, 0, NULL, l); jk_puts(s, "]

\n"); if (has_server_iterator) jk_printf(s, l, JK_STATUS_URI_MAP_TABLE_HEAD2, "Server", "URI", "Match
Type", "Source", "Reply
Timeout", "Sticky
Ignore", "Stateless", "Fail on
Status", "Active", "Disabled", "Stopped", "Use Server
Errors"); else jk_printf(s, l, JK_STATUS_URI_MAP_TABLE_HEAD, "URI", "Match
Type", "Source", "Reply
Timeout", "Sticky
Ignore", "Stateless", "Fail on
Status", "Active", "Disabled", "Stopped", "Use Server
Errors"); } count = 0; if (has_server_iterator) { for (srv = s->next_vhost(NULL); srv; srv = s->next_vhost(srv)) { uw_map = s->vhost_to_uw_map(srv); if (uw_map) { s->vhost_to_text(srv, server_name, 80); display_map(s, p, uw_map, worker, server_name, &count, mime, l); } } } else { uw_map = s->uw_map; if (uw_map) { display_map(s, p, uw_map, worker, NULL, &count, mime, l); } } if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "
\n"); } } else { if (mime == JK_STATUS_MIME_HTML) { jk_putv(s, "

Warning: No URI Mappings defined for ", worker, " !

\n", NULL); } } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' displayed %d maps for worker '%s'", w->name, count, worker); JK_TRACE_EXIT(l); } static const char *dump_ajp_addr(ajp_worker_t *aw, char *buf, size_t size) { if (aw->port > 0) return jk_dump_hinfo(&aw->worker_inet_addr, buf, size); else { if (aw->addr_sequence != aw->s->addr_sequence) return "unresolved"; else return "invalid"; } } static void display_worker_ajp_conf_details(jk_ws_service_t *s, status_endpoint_t *p, ajp_worker_t *aw, int is_member, int type, jk_log_context_t *l) { char buf[64]; JK_TRACE_ENTER(l); if (is_member) jk_printf(s, l, JK_STATUS_SHOW_MEMBER_CONF_ROW, aw->name, status_worker_type(type), aw->host, dump_ajp_addr(aw, buf, sizeof(buf)), aw->source && *aw->source ? aw->source : "undefined", aw->cache_timeout, aw->connect_timeout, aw->prepost_timeout, aw->reply_timeout, aw->retries, aw->recovery_opts, aw->busy_limit, aw->max_packet_size); else jk_printf(s, l, JK_STATUS_SHOW_AJP_CONF_ROW, status_worker_type(type), aw->host, dump_ajp_addr(aw, buf, sizeof(buf)), aw->source && *aw->source ? aw->source : "undefined", aw->cache_timeout, aw->connect_timeout, aw->prepost_timeout, aw->reply_timeout, aw->retries, aw->recovery_opts, aw->busy_limit, aw->max_packet_size); JK_TRACE_EXIT(l); } static void display_worker_ajp_details(jk_ws_service_t *s, status_endpoint_t *p, ajp_worker_t *aw, lb_sub_worker_t *wr, lb_worker_t *lb, int ms_min, int ms_max, int map_count, jk_log_context_t *l) { char buf[64]; char buf_rd[32]; char buf_rd_sec[32]; char buf_wr[32]; char buf_wr_sec[32]; int mime; const char *arg; time_t now = time(NULL); const char *name = NULL; const char *sub_name = NULL; const char *ajp_name = NULL; status_worker_t *w = p->worker; int rs_min = 0; int rs_max = 0; int delta_reset = (int)difftime(now, aw->s->last_reset); int delta_error = -1; char buf_time[JK_STATUS_TIME_BUF_SZ]; char buf_tz[JK_STATUS_TIME_BUF_SZ]; time_t error_time = 0; int rc_time = -1; JK_TRACE_ENTER(l); status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); mime = status_mime_int(arg); if (lb) { name = lb->name; sub_name = wr->name; ajp_name = wr->name; error_time = wr->s->first_error_time; if (wr->s->state == JK_LB_STATE_ERROR) { rs_min = lb->recover_wait_time - (int)difftime(now, wr->s->last_error_time); if (rs_min < 0) { rs_min = 0; } rs_max = rs_min + lb->maintain_time; if (rs_min < ms_min) { rs_min = ms_min; } } } else { name = aw->name; sub_name = NULL; ajp_name = aw->name; error_time = aw->s->error_time; } if (error_time > 0) { delta_error = (int)difftime(now, error_time); rc_time = status_strftime(error_time, mime, buf_time, buf_tz, l); } if (mime == JK_STATUS_MIME_HTML) { if (lb) jk_printf(s, l, JK_STATUS_SHOW_MEMBER_ROW, sub_name, jk_lb_get_activation(wr, l), jk_lb_get_state(wr, l), wr->distance, wr->lb_factor, wr->lb_mult, wr->s->lb_value, aw->s->used, delta_reset > 0 ? (int)(aw->s->used / delta_reset) : -1, wr->s->sessions, delta_reset > 0 ? (int)(wr->s->sessions / delta_reset) : -1, wr->s->errors, aw->s->client_errors, aw->s->reply_timeouts, status_strfsize(aw->s->transferred, buf_wr), delta_reset > 0 ? status_strfsize(aw->s->transferred / delta_reset, buf_wr_sec) : "-", status_strfsize(aw->s->readed, buf_rd), delta_reset > 0 ? status_strfsize(aw->s->readed / delta_reset , buf_rd_sec) : "-", aw->s->busy, aw->s->max_busy, aw->s->connected, aw->s->max_connected, wr->route, wr->redirect ? (*wr->redirect ? wr->redirect : " ") : " ", wr->domain ? (*wr->domain ? wr->domain : " ") : " ", rs_min, rs_max, delta_reset, rc_time > 0 ? buf_time : " "); else { jk_printf(s, l, JK_STATUS_SHOW_AJP_ROW, jk_ajp_get_state(aw, l), aw->s->used, delta_reset > 0 ? (int)(aw->s->used / delta_reset) : -1, aw->s->errors, aw->s->client_errors, aw->s->reply_timeouts, status_strfsize(aw->s->transferred, buf_wr), delta_reset > 0 ? status_strfsize(aw->s->transferred / delta_reset, buf_wr_sec) : "-", status_strfsize(aw->s->readed, buf_rd), delta_reset > 0 ? status_strfsize(aw->s->readed / delta_reset , buf_rd_sec) : "-", aw->s->busy, aw->s->max_busy, aw->s->connected, aw->s->max_connected, delta_reset, rc_time > 0 ? buf_time : " "); } } else if (mime == JK_STATUS_MIME_XML) { int off = 2; if (lb) off = 6; if (lb) { jk_print_xml_start_elt(s, l, w, off, 0, "member"); jk_print_xml_att_string(s, l, off+2, "name", sub_name); jk_print_xml_att_string(s, l, off+2, "type", status_worker_type(wr->worker->type)); } else { jk_print_xml_start_elt(s, l, w, off, 0, "ajp"); jk_print_xml_att_string(s, l, off+2, "name", ajp_name); jk_print_xml_att_string(s, l, off+2, "type", status_worker_type(aw->worker.type)); } jk_print_xml_att_string(s, l, off+2, "host", aw->host); jk_print_xml_att_int(s, l, off+2, "port", aw->port); jk_print_xml_att_string(s, l, off+2, "address", dump_ajp_addr(aw, buf, sizeof(buf))); jk_print_xml_att_string(s, l, off+2, "source", aw->source && *aw->source ? aw->source : "undefined"); jk_print_xml_att_int(s, l, off+2, "connection_pool_timeout", aw->cache_timeout); jk_print_xml_att_int(s, l, off+2, "ping_timeout", aw->ping_timeout); jk_print_xml_att_int(s, l, off+2, "connect_timeout", aw->connect_timeout); jk_print_xml_att_int(s, l, off+2, "prepost_timeout", aw->prepost_timeout); jk_print_xml_att_int(s, l, off+2, "reply_timeout", aw->reply_timeout); jk_print_xml_att_int(s, l, off+2, "connection_ping_interval", aw->conn_ping_interval); jk_print_xml_att_int(s, l, off+2, "retries", aw->retries); jk_print_xml_att_uint(s, l, off+2, "recovery_options", aw->recovery_opts); jk_print_xml_att_int(s, l, off+2, "busy_limit", aw->busy_limit); jk_print_xml_att_uint(s, l, off+2, "max_packet_size", aw->max_packet_size); if (lb) { jk_print_xml_att_string(s, l, off+2, "activation", jk_lb_get_activation(wr, l)); jk_print_xml_att_int(s, l, off+2, "lbfactor", wr->lb_factor); jk_print_xml_att_string(s, l, off+2, "route", wr->route); jk_print_xml_att_string(s, l, off+2, "redirect", wr->redirect); jk_print_xml_att_string(s, l, off+2, "domain", wr->domain); jk_print_xml_att_int(s, l, off+2, "distance", wr->distance); jk_print_xml_att_string(s, l, off+2, "state", jk_lb_get_state(wr, l)); jk_print_xml_att_uint64(s, l, off+2, "lbmult", wr->lb_mult); jk_print_xml_att_uint64(s, l, off+2, "lbvalue", wr->s->lb_value); jk_print_xml_att_uint64(s, l, off+2, "elected", aw->s->used); jk_print_xml_att_uint64(s, l, off+2, "sessions", wr->s->sessions); jk_print_xml_att_uint32(s, l, off+2, "errors", wr->s->errors); } else { jk_print_xml_att_uint64(s, l, off+2, "used", aw->s->used); jk_print_xml_att_uint32(s, l, off+2, "errors", aw->s->errors); } jk_print_xml_att_uint32(s, l, off+2, "client_errors", aw->s->client_errors); jk_print_xml_att_uint32(s, l, off+2, "reply_timeouts", aw->s->reply_timeouts); jk_print_xml_att_uint64(s, l, off+2, "transferred", aw->s->transferred); jk_print_xml_att_uint64(s, l, off+2, "read", aw->s->readed); jk_print_xml_att_int(s, l, off+2, "busy", aw->s->busy); jk_print_xml_att_int(s, l, off+2, "max_busy", aw->s->max_busy); jk_print_xml_att_int(s, l, off+2, "connected", aw->s->connected); jk_print_xml_att_int(s, l, off+2, "max_connected", aw->s->max_connected); if (lb) { jk_print_xml_att_int(s, l, off+2, "time_to_recover_min", rs_min); jk_print_xml_att_int(s, l, off+2, "time_to_recover_max", rs_max); } else jk_print_xml_att_int(s, l, off+2, "map_count", map_count); jk_print_xml_att_long(s, l, off+2, "last_reset_at", (long)aw->s->last_reset); jk_print_xml_att_int(s, l, off+2, "last_reset_ago", delta_reset); if (rc_time > 0) { jk_print_xml_att_string(s, l, off+2, "error_time_datetime", buf_time); jk_print_xml_att_string(s, l, off+2, "error_time_tz", buf_tz); jk_print_xml_att_int(s, l, off+2, "error_time_unix_seconds", (int)error_time); jk_print_xml_att_int(s, l, off+2, "error_time_ago", delta_error); } /* Terminate the tag */ jk_print_xml_stop_elt(s, l, off, 1); } else if (mime == JK_STATUS_MIME_TXT) { if (lb) { jk_puts(s, "Member:"); jk_printf(s, l, " name=%s", sub_name); jk_printf(s, l, " type=%s", status_worker_type(wr->worker->type)); } else { jk_puts(s, "AJP Worker:"); jk_printf(s, l, " name=%s", ajp_name); jk_printf(s, l, " type=%s", status_worker_type(aw->worker.type)); } jk_printf(s, l, " host=%s", aw->host); jk_printf(s, l, " port=%d", aw->port); jk_printf(s, l, " address=%s", dump_ajp_addr(aw, buf, sizeof(buf))); jk_printf(s, l, " source=%s", aw->source && *aw->source ? aw->source : "undefined"); jk_printf(s, l, " connection_pool_timeout=%d", aw->cache_timeout); jk_printf(s, l, " ping_timeout=%d", aw->ping_timeout); jk_printf(s, l, " connect_timeout=%d", aw->connect_timeout); jk_printf(s, l, " prepost_timeout=%d", aw->prepost_timeout); jk_printf(s, l, " reply_timeout=%d", aw->reply_timeout); jk_printf(s, l, " retries=%d", aw->retries); jk_printf(s, l, " connection_ping_interval=%d", aw->conn_ping_interval); jk_printf(s, l, " recovery_options=%u", aw->recovery_opts); jk_printf(s, l, " busy_limit=%d", aw->busy_limit); jk_printf(s, l, " max_packet_size=%u", aw->max_packet_size); if (lb) { jk_printf(s, l, " activation=%s", jk_lb_get_activation(wr, l)); jk_printf(s, l, " lbfactor=%d", wr->lb_factor); jk_printf(s, l, " route=\"%s\"", wr->route ? wr->route : ""); jk_printf(s, l, " redirect=\"%s\"", wr->redirect ? wr->redirect : ""); jk_printf(s, l, " domain=\"%s\"", wr->domain ? wr->domain : ""); jk_printf(s, l, " distance=%d", wr->distance); jk_printf(s, l, " state=%s", jk_lb_get_state(wr, l)); jk_printf(s, l, " lbmult=%" JK_UINT64_T_FMT, wr->lb_mult); jk_printf(s, l, " lbvalue=%" JK_UINT64_T_FMT, wr->s->lb_value); jk_printf(s, l, " elected=%" JK_UINT64_T_FMT, aw->s->used); jk_printf(s, l, " sessions=%" JK_UINT64_T_FMT, wr->s->sessions); jk_printf(s, l, " errors=%" JK_UINT32_T_FMT, wr->s->errors); } else { jk_printf(s, l, " used=%" JK_UINT64_T_FMT, aw->s->used); jk_printf(s, l, " errors=%" JK_UINT32_T_FMT, aw->s->errors); } jk_printf(s, l, " client_errors=%" JK_UINT32_T_FMT, aw->s->client_errors); jk_printf(s, l, " reply_timeouts=%" JK_UINT32_T_FMT, aw->s->reply_timeouts); jk_printf(s, l, " transferred=%" JK_UINT64_T_FMT, aw->s->transferred); jk_printf(s, l, " read=%" JK_UINT64_T_FMT, aw->s->readed); jk_printf(s, l, " busy=%d", aw->s->busy); jk_printf(s, l, " max_busy=%d", aw->s->max_busy); jk_printf(s, l, " connected=%d", aw->s->connected); jk_printf(s, l, " max_connected=%d", aw->s->max_connected); if (lb) { jk_printf(s, l, " time_to_recover_min=%d", rs_min); jk_printf(s, l, " time_to_recover_max=%d", rs_max); } else jk_printf(s, l, " map_count=%d", map_count); jk_printf(s, l, " last_reset_at=%ld", (long)aw->s->last_reset); jk_printf(s, l, " last_reset_ago=%d", delta_reset); if (rc_time > 0) { jk_printf(s, l, " error_time_datetime=%s", buf_time); jk_printf(s, l, " error_time_tz=%s", buf_tz); jk_printf(s, l, " error_time_unix_seconds=%d", error_time); jk_printf(s, l, " error_time_ago=%d", delta_error); } jk_puts(s, "\n"); } else if (mime == JK_STATUS_MIME_PROP) { if (lb) { jk_print_prop_att_string(s, l, w, name, "balance_workers", sub_name); jk_print_prop_att_string(s, l, w, ajp_name, "type", status_worker_type(wr->worker->type)); } else { jk_print_prop_att_string(s, l, w, name, "list", ajp_name); jk_print_prop_att_string(s, l, w, ajp_name, "type", status_worker_type(aw->worker.type)); } jk_print_prop_att_string(s, l, w, ajp_name, "host", aw->host); jk_print_prop_att_int(s, l, w, ajp_name, "port", aw->port); jk_print_prop_att_string(s, l, w, ajp_name, "address", dump_ajp_addr(aw, buf, sizeof(buf))); jk_print_prop_att_string(s, l, w, ajp_name, "source", aw->source && *aw->source ? aw->source : "undefined"); jk_print_prop_att_int(s, l, w, ajp_name, "connection_pool_timeout", aw->cache_timeout); jk_print_prop_att_int(s, l, w, ajp_name, "ping_timeout", aw->ping_timeout); jk_print_prop_att_int(s, l, w, ajp_name, "connect_timeout", aw->connect_timeout); jk_print_prop_att_int(s, l, w, ajp_name, "prepost_timeout", aw->prepost_timeout); jk_print_prop_att_int(s, l, w, ajp_name, "reply_timeout", aw->reply_timeout); jk_print_prop_att_int(s, l, w, ajp_name, "retries", aw->retries); jk_print_prop_att_int(s, l, w, ajp_name, "connection_ping_interval", aw->conn_ping_interval); jk_print_prop_att_uint(s, l, w, ajp_name, "recovery_options", aw->recovery_opts); jk_print_prop_att_int(s, l, w, ajp_name, "busy_limit", aw->busy_limit); jk_print_prop_att_uint(s, l, w, ajp_name, "max_packet_size", aw->max_packet_size); if (lb) { jk_print_prop_att_string(s, l, w, ajp_name, "activation", jk_lb_get_activation(wr, l)); jk_print_prop_att_int(s, l, w, ajp_name, "lbfactor", wr->lb_factor); jk_print_prop_att_string(s, l, w, ajp_name, "route", wr->route); jk_print_prop_att_string(s, l, w, ajp_name, "redirect", wr->redirect); jk_print_prop_att_string(s, l, w, ajp_name, "domain", wr->domain); jk_print_prop_att_int(s, l, w, ajp_name, "distance", wr->distance); jk_print_prop_att_string(s, l, w, ajp_name, "state", jk_lb_get_state(wr, l)); jk_print_prop_att_uint64(s, l, w, ajp_name, "lbmult", wr->lb_mult); jk_print_prop_att_uint64(s, l, w, ajp_name, "lbvalue", wr->s->lb_value); jk_print_prop_att_uint64(s, l, w, ajp_name, "elected", aw->s->used); jk_print_prop_att_uint64(s, l, w, ajp_name, "sessions", wr->s->sessions); jk_print_prop_att_uint32(s, l, w, ajp_name, "errors", wr->s->errors); } else { jk_print_prop_att_uint64(s, l, w, ajp_name, "used", aw->s->used); jk_print_prop_att_uint32(s, l, w, ajp_name, "errors", aw->s->errors); } jk_print_prop_att_uint32(s, l, w, ajp_name, "client_errors", aw->s->client_errors); jk_print_prop_att_uint32(s, l, w, ajp_name, "reply_timeouts", aw->s->reply_timeouts); jk_print_prop_att_uint64(s, l, w, ajp_name, "transferred", aw->s->transferred); jk_print_prop_att_uint64(s, l, w, ajp_name, "read", aw->s->readed); jk_print_prop_att_int(s, l, w, ajp_name, "busy", aw->s->busy); jk_print_prop_att_int(s, l, w, ajp_name, "max_busy", aw->s->max_busy); jk_print_prop_att_int(s, l, w, ajp_name, "connected", aw->s->connected); jk_print_prop_att_int(s, l, w, ajp_name, "max_connected", aw->s->max_connected); if (lb) { jk_print_prop_att_int(s, l, w, ajp_name, "time_to_recover_min", rs_min); jk_print_prop_att_int(s, l, w, ajp_name, "time_to_recover_max", rs_max); } else jk_print_prop_att_int(s, l, w, name, "map_count", map_count); jk_print_prop_att_long(s, l, w, name, "last_reset_at", (long)aw->s->last_reset); jk_print_prop_att_int(s, l, w, name, "last_reset_ago", delta_reset); if (rc_time > 0) { jk_print_prop_att_string(s, l, w, name, "error_time_datetime", buf_time); jk_print_prop_att_string(s, l, w, name, "error_time_tz", buf_tz); jk_print_prop_att_int(s, l, w, name, "error_time_unix seconds", (int)error_time); jk_print_prop_att_int(s, l, w, name, "error_time_ago seconds", delta_error); } } JK_TRACE_EXIT(l); } static void display_worker_lb(jk_ws_service_t *s, status_endpoint_t *p, lb_worker_t *lb, lb_sub_worker_t *swr, jk_log_context_t *l) { int cmd; int mime; int read_only = 0; int single = 0; unsigned int hide_members; unsigned int hide_lb_conf; unsigned int hide_lb_summary; unsigned int hide_ajp_conf; const char *arg; time_t now = time(NULL); unsigned int good = 0; unsigned int degraded = 0; unsigned int bad = 0; int map_count; int ms_min; int ms_max; unsigned int j; int pstart = JK_FALSE; const char *name = lb->name; status_worker_t *w = p->worker; JK_TRACE_ENTER(l); status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); cmd = status_cmd_int(arg); status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); mime = status_mime_int(arg); hide_members = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_NO_MEMBERS; hide_lb_conf = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_NO_LB_CONF; hide_lb_summary = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_NO_LB_SUMMARY; hide_ajp_conf = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_NO_AJP_CONF; if (w->read_only) { read_only = 1; } else { read_only = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_READ_ONLY; } if (cmd == JK_STATUS_CMD_SHOW) { single = 1; } if (lb->sequence != lb->s->h.sequence) jk_lb_pull(lb, JK_FALSE, l); for (j = 0; j < lb->num_of_workers; j++) { lb_sub_worker_t *wr = &(lb->lb_workers[j]); int rate; rate = status_rate(wr, w, l); if (rate > 0) good++; else if (rate < 0) bad++; else degraded++; } map_count = count_maps(s, name, l); ms_min = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time); ms_max = ms_min + lb->maintain_time; if (ms_min < 0) { ms_min = 0; } if (ms_max < 0) { ms_max = 0; } if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "

["); if (single) { jk_puts(s, "S"); } else { status_write_uri(s, p, "S", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, name, "", 0, 0, "", l); } if (!read_only) { jk_puts(s, "|"); status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN, name, "", 0, 0, "", l); jk_puts(s, "|"); status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN, name, "", 0, 0, "", l); } jk_puts(s, "]  "); jk_putv(s, "Worker Status for ", name, "

\n", NULL); if (hide_lb_conf) { pstart = JK_TRUE; jk_puts(s, "

\n"); if (single) { status_write_uri(s, p, "Show LB Configuration", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_CONF, "", l); } else { status_write_uri(s, p, "Show LB Configuration", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_CONF, "", l); } } if (hide_lb_summary) { if (pstart == JK_FALSE) jk_puts(s, "

\n"); else jk_puts(s, "  |  "); pstart = JK_TRUE; if (single) { status_write_uri(s, p, "Show LB Summary", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_SUMMARY, "", l); } else { status_write_uri(s, p, "Show LB Summary", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_SUMMARY, "", l); } } if (!hide_members && hide_ajp_conf) { if (pstart == JK_FALSE) jk_puts(s, "

\n"); else jk_puts(s, "  |  "); pstart = JK_TRUE; if (single) { status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l); } else { status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l); } } if (hide_members) { if (pstart == JK_FALSE) jk_puts(s, "

\n"); else jk_puts(s, "  |  "); pstart = JK_TRUE; if (single) { status_write_uri(s, p, "Show Balancer Members", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_MEMBERS, "", l); } else { status_write_uri(s, p, "Show Balancer Members", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_MEMBERS, "", l); } } if (pstart == JK_TRUE) jk_puts(s, "

\n"); if (!hide_lb_conf) { jk_puts(s, "" JK_STATUS_SHOW_LB_HEAD); jk_puts(s, "["); status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_LB_CONF, 0, NULL, l); jk_puts(s, "]"); jk_printf(s, l, JK_STATUS_SHOW_LB_ROW, status_worker_type(JK_LB_WORKER_TYPE), jk_get_bool(lb->sticky_session), jk_get_bool(lb->sticky_session_force), lb->retries, jk_lb_get_method(lb, l), jk_lb_get_lock(lb, l), lb->recover_wait_time, lb->error_escalation_time, lb->max_reply_timeouts); jk_puts(s, "
\n
\n"); } if (!hide_lb_summary) { jk_puts(s, "" "\n"); jk_printf(s, l, "", good); jk_printf(s, l, "", degraded); jk_printf(s, l, "", bad); jk_printf(s, l, "", lb->s->busy); jk_printf(s, l, "", lb->s->max_busy); jk_printf(s, l, "", ms_min, ms_max); jk_printf(s, l, "", (int)difftime(now, lb->s->last_reset)); jk_puts(s, "\n
GoodDegradedBad/StoppedBusyMax BusyNext MaintenanceLast Reset["); status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_LB_SUMMARY, 0, NULL, l); jk_puts(s, "]
%d%d%d%d%d%d/%d%d
\n\n"); } } else if (mime == JK_STATUS_MIME_XML) { jk_print_xml_start_elt(s, l, w, 2, 0, "balancer"); jk_print_xml_att_string(s, l, 4, "name", name); jk_print_xml_att_string(s, l, 4, "type", status_worker_type(JK_LB_WORKER_TYPE)); jk_print_xml_att_string(s, l, 4, "sticky_session", jk_get_bool(lb->sticky_session)); jk_print_xml_att_string(s, l, 4, "sticky_session_force", jk_get_bool(lb->sticky_session_force)); jk_print_xml_att_int(s, l, 4, "retries", lb->retries); jk_print_xml_att_int(s, l, 4, "recover_time", lb->recover_wait_time); jk_print_xml_att_int(s, l, 4, "error_escalation_time", lb->error_escalation_time); jk_print_xml_att_int(s, l, 4, "max_reply_timeouts", lb->max_reply_timeouts); jk_print_xml_att_string(s, l, 4, "method", jk_lb_get_method(lb, l)); jk_print_xml_att_string(s, l, 4, "lock", jk_lb_get_lock(lb, l)); jk_print_xml_att_int(s, l, 4, "member_count", lb->num_of_workers); jk_print_xml_att_int(s, l, 4, "good", good); jk_print_xml_att_int(s, l, 4, "degraded", degraded); jk_print_xml_att_int(s, l, 4, "bad", bad); jk_print_xml_att_int(s, l, 4, "busy", lb->s->busy); jk_print_xml_att_int(s, l, 4, "max_busy", lb->s->max_busy); jk_print_xml_att_int(s, l, 4, "map_count", map_count); jk_print_xml_att_int(s, l, 4, "time_to_maintenance_min", ms_min); jk_print_xml_att_int(s, l, 4, "time_to_maintenance_max", ms_max); jk_print_xml_att_long(s, l, 4, "last_reset_at", (long)lb->s->last_reset); jk_print_xml_att_int(s, l, 4, "last_reset_ago", (int)difftime(now, lb->s->last_reset)); jk_print_xml_stop_elt(s, l, 2, 0); } else if (mime == JK_STATUS_MIME_TXT) { jk_puts(s, "Balancer Worker:"); jk_printf(s, l, " name=%s", name); jk_printf(s, l, " type=%s", status_worker_type(JK_LB_WORKER_TYPE)); jk_printf(s, l, " sticky_session=%s", jk_get_bool(lb->sticky_session)); jk_printf(s, l, " sticky_session_force=%s", jk_get_bool(lb->sticky_session_force)); jk_printf(s, l, " retries=%d", lb->retries); jk_printf(s, l, " recover_time=%d", lb->recover_wait_time); jk_printf(s, l, " error_escalation_time=%d", lb->error_escalation_time); jk_printf(s, l, " max_reply_timeouts=%d", lb->max_reply_timeouts); jk_printf(s, l, " method=%s", jk_lb_get_method(lb, l)); jk_printf(s, l, " lock=%s", jk_lb_get_lock(lb, l)); jk_printf(s, l, " member_count=%d", lb->num_of_workers); jk_printf(s, l, " good=%d", good); jk_printf(s, l, " degraded=%d", degraded); jk_printf(s, l, " bad=%d", bad); jk_printf(s, l, " busy=%d", lb->s->busy); jk_printf(s, l, " max_busy=%d", lb->s->max_busy); jk_printf(s, l, " map_count=%d", map_count); jk_printf(s, l, " time_to_maintenance_min=%d", ms_min); jk_printf(s, l, " time_to_maintenance_max=%d", ms_max); jk_printf(s, l, " last_reset_at=%ld", (long)lb->s->last_reset); jk_printf(s, l, " last_reset_ago=%d", (int)difftime(now, lb->s->last_reset)); jk_puts(s, "\n"); } else if (mime == JK_STATUS_MIME_PROP) { jk_print_prop_att_string(s, l, w, NULL, "list", name); jk_print_prop_att_string(s, l, w, name, "type", status_worker_type(JK_LB_WORKER_TYPE)); jk_print_prop_att_string(s, l, w, name, "sticky_session", jk_get_bool(lb->sticky_session)); jk_print_prop_att_string(s, l, w, name, "sticky_session_force", jk_get_bool(lb->sticky_session_force)); jk_print_prop_att_int(s, l, w, name, "retries", lb->retries); jk_print_prop_att_int(s, l, w, name, "recover_time", lb->recover_wait_time); jk_print_prop_att_int(s, l, w, name, "error_escalation_time", lb->error_escalation_time); jk_print_prop_att_int(s, l, w, name, "max_reply_timeouts", lb->max_reply_timeouts); jk_print_prop_att_string(s, l, w, name, "method", jk_lb_get_method(lb, l)); jk_print_prop_att_string(s, l, w, name, "lock", jk_lb_get_lock(lb, l)); jk_print_prop_att_int(s, l, w, name, "member_count", lb->num_of_workers); jk_print_prop_att_int(s, l, w, name, "good", good); jk_print_prop_att_int(s, l, w, name, "degraded", degraded); jk_print_prop_att_int(s, l, w, name, "bad", bad); jk_print_prop_att_int(s, l, w, name, "busy", lb->s->busy); jk_print_prop_att_int(s, l, w, name, "max_busy", lb->s->max_busy); jk_print_prop_att_int(s, l, w, name, "map_count", map_count); jk_print_prop_att_int(s, l, w, name, "time_to_maintenance_min", ms_min); jk_print_prop_att_int(s, l, w, name, "time_to_maintenance_max", ms_max); jk_print_prop_att_long(s, l, w, name, "last_reset_at", (long)lb->s->last_reset); jk_print_prop_att_int(s, l, w, name, "last_reset_ago", (int)difftime(now, lb->s->last_reset)); } if (!hide_members) { if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "

Balancer Members ["); if (swr) { status_write_uri(s, p, "Show All Members", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, name, "", 0, 0, "", l); jk_puts(s, "]  ["); } if (single) { status_write_uri(s, p, "Hide", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_MEMBERS, 0, "", l); } else { status_write_uri(s, p, "Hide", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_MEMBERS, 0, "", l); } jk_puts(s, "]

\n"); if (!hide_ajp_conf) { jk_puts(s, "" JK_STATUS_SHOW_MEMBER_CONF_HEAD); jk_puts(s, "["); status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_AJP_CONF, 0, NULL, l); jk_puts(s, "]"); if (swr) { jk_worker_t *jw = (jk_worker_t *)swr->worker; ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; display_worker_ajp_conf_details(s, p, aw, 1, jw->type, l); } else for (j = 0; j < lb->num_of_workers; j++) { lb_sub_worker_t *wr = &(lb->lb_workers[j]); jk_worker_t *jw = (jk_worker_t *)wr->worker; ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; display_worker_ajp_conf_details(s, p, aw, 1, jw->type, l); } jk_puts(s, "
\n
\n"); } jk_puts(s, "" JK_STATUS_SHOW_MEMBER_HEAD); } if (swr) { const char *sub_name = swr->name; ajp_worker_t *aw = (ajp_worker_t *)swr->worker->worker_private; if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "\n"); } display_worker_ajp_details(s, p, aw, swr, lb, ms_min, ms_max, 0, l); } else for (j = 0; j < lb->num_of_workers; j++) { lb_sub_worker_t *wr = &(lb->lb_workers[j]); const char *sub_name = wr->name; ajp_worker_t *aw = (ajp_worker_t *)wr->worker->worker_private; if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "\n"); } display_worker_ajp_details(s, p, aw, wr, lb, ms_min, ms_max, 0, l); } if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "
["); jk_puts(s, "S"); if (!read_only) { jk_puts(s, "|"); status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN, name, sub_name, 0, 0, "", l); jk_puts(s, "|"); status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN, name, sub_name, 0, 0, "", l); if (swr->s->state == JK_LB_STATE_ERROR) { jk_puts(s, "|"); status_write_uri(s, p, "T", JK_STATUS_CMD_RECOVER, JK_STATUS_MIME_UNKNOWN, name, sub_name, 0, 0, "", l); } } jk_puts(s, "]"); jk_puts(s, " 
["); status_write_uri(s, p, "S", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, name, sub_name, 0, 0, "", l); if (!read_only) { jk_puts(s, "|"); status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN, name, sub_name, 0, 0, "", l); jk_puts(s, "|"); status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN, name, sub_name, 0, 0, "", l); if (wr->s->state == JK_LB_STATE_ERROR) { jk_puts(s, "|"); status_write_uri(s, p, "T", JK_STATUS_CMD_RECOVER, JK_STATUS_MIME_UNKNOWN, name, sub_name, 0, 0, "", l); } } jk_puts(s, "]"); jk_puts(s, " 

\n"); if (!read_only) { const char *arg; status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); status_start_form(s, p, "get", JK_STATUS_CMD_EDIT, NULL, l); jk_printf(s, l, JK_STATUS_FORM_HIDDEN_STRING, JK_STATUS_ARG_WORKER, name); if (arg) jk_printf(s, l, JK_STATUS_FORM_HIDDEN_STRING, JK_STATUS_ARG_FROM, arg); jk_puts(s, "
Edit this attribute for all members:"); jk_putv(s, "
\n"); } } } if (name) display_maps(s, p, name, l); if (mime == JK_STATUS_MIME_XML) { jk_print_xml_close_elt(s, l, w, 2, "balancer"); } JK_TRACE_EXIT(l); } static void display_worker_ajp(jk_ws_service_t *s, status_endpoint_t *p, ajp_worker_t *aw, int type, jk_log_context_t *l) { int cmd; int mime; int read_only = 0; int single = 0; unsigned int hide_ajp_conf; const char *arg; int map_count; const char *name = aw->name; status_worker_t *w = p->worker; JK_TRACE_ENTER(l); status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); cmd = status_cmd_int(arg); status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); mime = status_mime_int(arg); hide_ajp_conf = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_NO_AJP_CONF; if (w->read_only) { read_only = 1; } else { read_only = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_READ_ONLY; } if (cmd == JK_STATUS_CMD_SHOW) { single = 1; } if (aw->sequence != aw->s->h.sequence) jk_ajp_pull(aw, JK_FALSE, l); map_count = count_maps(s, name, l); if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "

["); if (single) jk_puts(s, "S"); else status_write_uri(s, p, "S", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, name, "", 0, 0, "", l); if (!read_only) { jk_puts(s, "|"); status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN, name, "", 0, 0, "", l); jk_puts(s, "|"); status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN, name, "", 0, 0, "", l); } jk_puts(s, "]  "); jk_putv(s, "Worker Status for ", name, "

\n", NULL); if (!hide_ajp_conf) { jk_puts(s, "" JK_STATUS_SHOW_AJP_CONF_HEAD); jk_puts(s, "["); status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_AJP_CONF, 0, NULL, l); jk_puts(s, "]"); display_worker_ajp_conf_details(s, p, aw, 0, type, l); jk_puts(s, "
\n
\n"); } else { jk_puts(s, "

\n"); if (single) { status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l); } else { status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l); } jk_puts(s, "

\n"); } jk_puts(s, "" JK_STATUS_SHOW_AJP_HEAD); } display_worker_ajp_details(s, p, aw, NULL, NULL, 0, 0, map_count, l); if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "
\n"); } if (name) display_maps(s, p, name, l); JK_TRACE_EXIT(l); } static void display_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_worker_t *jw, lb_sub_worker_t *swr, jk_log_context_t *l) { status_worker_t *w = p->worker; JK_TRACE_ENTER(l); if (jw->type == JK_LB_WORKER_TYPE) { lb_worker_t *lb = (lb_worker_t *)jw->worker_private; if (lb) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s lb worker '%s'", w->name, "displaying", lb->name); display_worker_lb(s, p, lb, swr, l); } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' lb worker is (null)", w->name); } } else if (jw->type == JK_AJP13_WORKER_TYPE || jw->type == JK_AJP14_WORKER_TYPE) { ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; if (aw) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s ajp worker '%s'", w->name, "displaying", aw->name); display_worker_ajp(s, p, aw, jw->type, l); } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' aw worker is (null)", w->name); } } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' worker type not implemented", w->name); JK_TRACE_EXIT(l); return; } } static void form_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_worker_t *jw, jk_log_context_t *l) { const char *name = NULL; lb_worker_t *lb = NULL; status_worker_t *w = p->worker; JK_TRACE_ENTER(l); if (jw->type == JK_LB_WORKER_TYPE) { lb = (lb_worker_t *)jw->worker_private; name = lb->name; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' producing edit form for lb worker '%s'", w->name, name); } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' worker type not implemented", w->name); JK_TRACE_EXIT(l); return; } if (!lb) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' lb structure is (null)", w->name); JK_TRACE_EXIT(l); return; } jk_putv(s, "

Edit load balancer settings for ", name, "

\n", NULL); status_start_form(s, p, "get", JK_STATUS_CMD_UPDATE, NULL, l); jk_putv(s, "\n\n", lb->retries); jk_putv(s, "\n", lb->retry_interval); jk_putv(s, "\n", lb->recover_wait_time); jk_putv(s, "\n", lb->error_escalation_time); jk_putv(s, "\n", lb->max_reply_timeouts); jk_putv(s, "\n"); jk_putv(s, "\n"); jk_putv(s, "\n", NULL); jk_putv(s, "\n"); jk_putv(s, "\n"); jk_putv(s, "\n"); jk_putv(s, "\n"); jk_putv(s, "\n"); jk_putv(s, "\n", NULL); jk_putv(s, "\n"); jk_putv(s, "\n"); jk_puts(s, "
", JK_STATUS_ARG_LB_TEXT_RETRIES, ":
", JK_STATUS_ARG_LB_TEXT_RETRY_INT, ":
", JK_STATUS_ARG_LB_TEXT_RECOVER_TIME, ":
", JK_STATUS_ARG_LB_TEXT_ERROR_ESCALATION_TIME, ":
", JK_STATUS_ARG_LB_TEXT_MAX_REPLY_TIMEOUTS, ":
", JK_STATUS_ARG_LB_TEXT_STICKY, ":sticky_session) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
", JK_STATUS_ARG_LB_TEXT_STICKY_FORCE, ":sticky_session_force) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
", JK_STATUS_ARG_LB_TEXT_METHOD, ":
  Requestslbmethod == JK_LB_METHOD_REQUESTS) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
  Trafficlbmethod == JK_LB_METHOD_TRAFFIC) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
  Busynesslbmethod == JK_LB_METHOD_BUSYNESS) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
  Sessionslbmethod == JK_LB_METHOD_SESSIONS) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
  Nextlbmethod == JK_LB_METHOD_NEXT) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
", JK_STATUS_ARG_LB_TEXT_LOCK, ":
  Optimisticlblock == JK_LB_LOCK_OPTIMISTIC) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
  Pessimisticlblock == JK_LB_LOCK_PESSIMISTIC) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
\n"); jk_puts(s, "
\n"); JK_TRACE_EXIT(l); } static void form_member(jk_ws_service_t *s, status_endpoint_t *p, lb_sub_worker_t *wr, ajp_worker_t *aw, const char *lb_name, jk_log_context_t *l) { status_worker_t *w = p->worker; JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' producing edit form for sub worker '%s' of lb worker '%s'", w->name, wr? wr->name : aw->name, lb_name); jk_putv(s, "

Edit worker settings for ", wr? wr->name : aw->name, "

\n", NULL); status_start_form(s, p, "get", JK_STATUS_CMD_UPDATE, NULL, l); if (wr) { jk_puts(s, "\n"); jk_puts(s, "\n"); jk_puts(s, "\n"); jk_puts(s, "
Balancing related settings  AJP settings
\n"); jk_putv(s, "\n", NULL); jk_putv(s, "\n"); jk_putv(s, "\n"); jk_putv(s, "\n"); jk_putv(s, "\n", wr->lb_factor); jk_putv(s, "\n", JK_MAX_NAME_LEN); jk_putv(s, "\n", JK_MAX_NAME_LEN); jk_putv(s, "\n", JK_MAX_NAME_LEN); jk_putv(s, "\n", wr->distance); jk_puts(s, "
", JK_STATUS_ARG_LBM_TEXT_ACTIVATION, ":
  Activeactivation == JK_LB_ACTIVATION_ACTIVE) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
  Disabledactivation == JK_LB_ACTIVATION_DISABLED) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
  Stoppedactivation == JK_LB_ACTIVATION_STOPPED) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>
", JK_STATUS_ARG_LBM_TEXT_FACTOR, ":
", JK_STATUS_ARG_LBM_TEXT_ROUTE, ":route, NULL); jk_printf(s, l, "\" maxlength=\"%d\"/>
", JK_STATUS_ARG_LBM_TEXT_REDIRECT, ":redirect, NULL); jk_printf(s, l, "\" maxlength=\"%d\"/>
", JK_STATUS_ARG_LBM_TEXT_DOMAIN, ":domain, NULL); jk_printf(s, l, "\" maxlength=\"%d\"/>
", JK_STATUS_ARG_LBM_TEXT_DISTANCE, ":
\n"); jk_puts(s, "
\n"); } jk_puts(s, "\n"); jk_putv(s, "\n", JK_MAX_NAME_LEN); jk_putv(s, "\n", aw->port); jk_putv(s, "\n", aw->cache_timeout); jk_putv(s, "\n", aw->ping_timeout); jk_putv(s, "\n", aw->connect_timeout); jk_putv(s, "\n", aw->prepost_timeout); jk_putv(s, "\n", aw->reply_timeout); jk_putv(s, "\n", aw->retries); jk_putv(s, "\n", aw->retry_interval); jk_putv(s, "\n", aw->conn_ping_interval); jk_putv(s, "\n", aw->recovery_opts); jk_putv(s, "\n", aw->busy_limit); jk_putv(s, "\n", aw->max_packet_size); jk_puts(s, "
", JK_STATUS_ARG_AJP_TEXT_HOST_STR, ":host, NULL); jk_printf(s, l, "\" maxlength=\"%d\"/>
", JK_STATUS_ARG_AJP_TEXT_PORT, ":
", JK_STATUS_ARG_AJP_TEXT_CACHE_TO, ":
", JK_STATUS_ARG_AJP_TEXT_PING_TO, ":
", JK_STATUS_ARG_AJP_TEXT_CONNECT_TO, ":
", JK_STATUS_ARG_AJP_TEXT_PREPOST_TO, ":
", JK_STATUS_ARG_AJP_TEXT_REPLY_TO, ":
", JK_STATUS_ARG_AJP_TEXT_RETRIES, ":
", JK_STATUS_ARG_AJP_TEXT_RETRY_INT, ":
", JK_STATUS_ARG_AJP_TEXT_CPING_INT, ":
", JK_STATUS_ARG_AJP_TEXT_REC_OPTS, ":
", JK_STATUS_ARG_AJP_TEXT_BUSY_LIMIT, ":
", JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ, ":
\n"); if (wr) jk_puts(s, "
\n"); jk_puts(s, "
\n\n"); JK_TRACE_EXIT(l); } static void form_all_members(jk_ws_service_t *s, status_endpoint_t *p, jk_worker_t *jw, const char *attribute, jk_log_context_t *l) { const char *name = NULL; lb_worker_t *lb = NULL; status_worker_t *w = p->worker; const char *aname; unsigned int i; JK_TRACE_ENTER(l); if (!attribute) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' missing request parameter '%s'", w->name, JK_STATUS_ARG_ATTRIBUTE); JK_TRACE_EXIT(l); return; } else { if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) aname=JK_STATUS_ARG_LBM_TEXT_ACTIVATION; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) aname=JK_STATUS_ARG_LBM_TEXT_FACTOR; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) aname=JK_STATUS_ARG_LBM_TEXT_ROUTE; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) aname=JK_STATUS_ARG_LBM_TEXT_REDIRECT; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) aname=JK_STATUS_ARG_LBM_TEXT_DOMAIN; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) aname=JK_STATUS_ARG_LBM_TEXT_DISTANCE; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) aname=JK_STATUS_ARG_AJP_TEXT_CACHE_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) aname=JK_STATUS_ARG_AJP_TEXT_PING_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) aname=JK_STATUS_ARG_AJP_TEXT_CONNECT_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) aname=JK_STATUS_ARG_AJP_TEXT_PREPOST_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) aname=JK_STATUS_ARG_AJP_TEXT_REPLY_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) aname=JK_STATUS_ARG_AJP_TEXT_RETRIES; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) aname=JK_STATUS_ARG_AJP_TEXT_RETRY_INT; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) aname=JK_STATUS_ARG_AJP_TEXT_CPING_INT; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) aname=JK_STATUS_ARG_AJP_TEXT_REC_OPTS; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_BUSY_LIMIT)) aname=JK_STATUS_ARG_AJP_TEXT_BUSY_LIMIT; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) aname=JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ; else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' unknown attribute '%s'", w->name, attribute); JK_TRACE_EXIT(l); return; } } if (jw->type == JK_LB_WORKER_TYPE) { lb = (lb_worker_t *)jw->worker_private; name = lb->name; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' producing edit form for attribute '%s' [%s] of all members of lb worker '%s'", w->name, attribute, aname, name); } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' worker type not implemented", w->name); JK_TRACE_EXIT(l); return; } if (lb) { jk_putv(s, "

Edit attribute '", aname, "' for all members of load balancer ", name, "

\n", NULL); status_start_form(s, p, "get", JK_STATUS_CMD_UPDATE, NULL, l); jk_putv(s, "" "" "", NULL); for (i = 0; i < lb->num_of_workers; i++) { lb_sub_worker_t *wr = &(lb->lb_workers[i]); jk_worker_t *jw = wr->worker; ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;; jk_putv(s, ""); } jk_puts(s, "
Balanced Worker", aname, "
", wr->name, "\n", NULL); if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) { jk_printf(s, l, "Active: activation == JK_LB_ACTIVATION_ACTIVE) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/> | \n"); jk_printf(s, l, "Disabled: activation == JK_LB_ACTIVATION_DISABLED) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/> | \n"); jk_printf(s, l, "Stopped: activation == JK_LB_ACTIVATION_STOPPED) jk_puts(s, " checked=\"checked\""); jk_puts(s, "/>\n"); } else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) { jk_printf(s, l, "\n", wr->lb_factor); } else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) { jk_printf(s, l, "route, NULL); jk_printf(s, l, "\" maxlength=\"%d\"/>\n", JK_MAX_NAME_LEN); } else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) { jk_printf(s, l, "redirect, NULL); jk_printf(s, l, "\" maxlength=\"%d\"/>\n", JK_MAX_NAME_LEN); } else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) { jk_printf(s, l, "domain, NULL); jk_printf(s, l, "\" maxlength=\"%d\"/>\n", JK_MAX_NAME_LEN); } else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) { jk_printf(s, l, "\n", wr->distance); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) { jk_printf(s, l, "\n", aw->cache_timeout); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) { jk_printf(s, l, "\n", aw->ping_timeout); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) { jk_printf(s, l, "\n", aw->connect_timeout); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) { jk_printf(s, l, "\n", aw->prepost_timeout); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) { jk_printf(s, l, "\n", aw->reply_timeout); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) { jk_printf(s, l, "\n", aw->retries); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) { jk_printf(s, l, "\n", aw->retry_interval); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) { jk_printf(s, l, "\n", aw->conn_ping_interval); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) { jk_printf(s, l, "\n", aw->recovery_opts); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_BUSY_LIMIT)) { jk_printf(s, l, "\n", aw->busy_limit); } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) { jk_printf(s, l, "\n", aw->max_packet_size); } jk_puts(s, "
\n"); jk_puts(s, "
\n"); } JK_TRACE_EXIT(l); } static void commit_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_worker_t *jw, jk_log_context_t *l) { const char *name = NULL; lb_worker_t *lb = NULL; status_worker_t *w = p->worker; const char *arg; int sync_needed = JK_FALSE; int i; JK_TRACE_ENTER(l); if (jw->type == JK_LB_WORKER_TYPE) { lb = (lb_worker_t *)jw->worker_private; name = lb->name; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' committing changes for lb worker '%s'", w->name, name); } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' worker type not implemented", w->name); JK_TRACE_EXIT(l); return; } if (!lb) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' lb structure is (null)", w->name); JK_TRACE_EXIT(l); return; } i = status_get_int(p, JK_STATUS_ARG_LB_RETRIES, lb->retries, l); if (i != lb->retries && i > 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'retries' for lb worker '%s' from '%d' to '%d'", w->name, name, lb->retries, i); lb->retries = i; sync_needed = JK_TRUE; } i = status_get_int(p, JK_STATUS_ARG_LB_RETRY_INT, lb->retry_interval, l); if (i != lb->retry_interval && i > 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'retry_interval' for lb worker '%s' from '%d' to '%d'", w->name, name, lb->retry_interval, i); lb->retry_interval = i; sync_needed = JK_TRUE; } i = status_get_int(p, JK_STATUS_ARG_LB_RECOVER_TIME, lb->recover_wait_time, l); if (i != lb->recover_wait_time && i > 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'recover_time' for lb worker '%s' from '%d' to '%d'", w->name, name, lb->recover_wait_time, i); lb->recover_wait_time = i; sync_needed = JK_TRUE; } i = status_get_int(p, JK_STATUS_ARG_LB_ERROR_ESCALATION_TIME, lb->error_escalation_time, l); if (i != lb->error_escalation_time && i > 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'error_escalation_time' for lb worker '%s' from '%d' to '%d'", w->name, name, lb->error_escalation_time, i); lb->error_escalation_time = i; sync_needed = JK_TRUE; } i = status_get_int(p, JK_STATUS_ARG_LB_MAX_REPLY_TIMEOUTS, lb->max_reply_timeouts, l); if (i != lb->max_reply_timeouts && i >= 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'max_reply_timeouts' for lb worker '%s' from '%d' to '%d'", w->name, name, lb->max_reply_timeouts, i); lb->max_reply_timeouts = i; sync_needed = JK_TRUE; } i = status_get_bool(p, JK_STATUS_ARG_LB_STICKY, lb->sticky_session, l); if (i != lb->sticky_session) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'sticky_session' for lb worker '%s' from '%d' to '%d'", w->name, name, lb->sticky_session, i); lb->sticky_session = i; sync_needed = JK_TRUE; } i = status_get_bool(p, JK_STATUS_ARG_LB_STICKY_FORCE, lb->sticky_session_force, l); if (i != lb->sticky_session_force) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'sticky_session_force' for lb worker '%s' from '%d' to '%d'", w->name, name, lb->sticky_session_force, i); lb->sticky_session_force = i; sync_needed = JK_TRUE; } if (status_get_string(p, JK_STATUS_ARG_LB_METHOD, NULL, &arg, l) == JK_TRUE) { i = jk_lb_get_method_code(arg); if (i != lb->lbmethod && i >= 0 && i <= JK_LB_METHOD_MAX) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'method' for lb worker '%s' from '%s' to '%s'", w->name, name, jk_lb_get_method(lb, l), jk_lb_get_method_direct(i, l)); lb->lbmethod = i; sync_needed = JK_TRUE; } } if (status_get_string(p, JK_STATUS_ARG_LB_LOCK, NULL, &arg, l) == JK_TRUE) { i = jk_lb_get_lock_code(arg); if (i != lb->lblock && i >= 0 && i <= JK_LB_LOCK_MAX) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'lock' for lb worker '%s' from '%s' to '%s'", w->name, name, jk_lb_get_lock(lb, l), jk_lb_get_lock_direct(i, l)); lb->lblock = i; sync_needed = JK_TRUE; } } if (sync_needed == JK_TRUE) { lb->sequence = -1; jk_lb_push(lb, JK_TRUE, JK_FALSE, l); } } static int set_int_if_changed(status_endpoint_t *p, const char *name, const char *att, const char *arg, int min, int max, int *param, const char *lb_name, jk_log_context_t *l) { int i; status_worker_t *w = p->worker; i = status_get_int(p, arg, *param, l); if (i != *param && i >= min && i <= max) { if (lb_name) jk_log(l, JK_LOG_INFO, "Status worker '%s' changing '%s' for sub worker '%s' of lb worker '%s' from '%d' to '%d'", w->name, att, name, lb_name, *param, i); else jk_log(l, JK_LOG_INFO, "Status worker '%s' changing '%s' for ajp worker '%s' from '%d' to '%d'", w->name, att, name, *param, i); *param = i; return JK_TRUE; } return JK_FALSE; } static int set_uint_if_changed(status_endpoint_t *p, const char *name, const char *att, const char *arg, unsigned int min, unsigned int max, unsigned int align, unsigned int *param, const char *lb_name, jk_log_context_t *l) { unsigned i; status_worker_t *w = p->worker; i = (unsigned)status_get_int(p, arg, *param, l); if (align > 1) { i = JK_ALIGN(i, align); } if (i != *param && i >= min && i <= max) { if (lb_name) jk_log(l, JK_LOG_INFO, "Status worker '%s' changing '%s' for sub worker '%s' of lb worker '%s' from '%u' to '%u'", w->name, att, name, lb_name, *param, i); else jk_log(l, JK_LOG_INFO, "Status worker '%s' changing '%s' for ajp worker '%s' from '%u' to '%u'", w->name, att, name, *param, i); *param = i; return JK_TRUE; } return JK_FALSE; } static int commit_member(jk_ws_service_t *s, status_endpoint_t *p, lb_worker_t *lb, lb_sub_worker_t *wr, ajp_worker_t *aw, int *side_effect, jk_log_context_t *l) { const char *arg; const char *lb_name = NULL; status_worker_t *w = p->worker; int rc = JK_TRUE; int rv; int i; int old; int resolve = JK_FALSE; shm_str host; int port = 0; JK_TRACE_ENTER(l); if (lb) { lb_name = lb->name; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' committing changes for sub worker '%s' of lb worker '%s'", w->name, wr->name, lb_name); } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' committing changes for ajp worker '%s'", w->name, aw->name); } if (lb) { if (status_get_string(p, JK_STATUS_ARG_LBM_ACTIVATION, NULL, &arg, l) == JK_TRUE) { i = jk_lb_get_activation_code(arg); if (i != wr->activation && i >= 0 && i <= JK_LB_ACTIVATION_MAX) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'activation' for sub worker '%s' of lb worker '%s' from '%s' to '%s'", w->name, wr->name, lb_name, jk_lb_get_activation(wr, l), jk_lb_get_activation_direct(i, l)); wr->activation = i; *side_effect |= JK_STATUS_NEEDS_RESET_LB_VALUES | JK_STATUS_NEEDS_PUSH; } } if (set_int_if_changed(p, wr->name, "lbfactor", JK_STATUS_ARG_LBM_FACTOR, 1, INT_MAX, &wr->lb_factor, lb_name, l)) /* Recalculate the load multiplicators wrt. lb_factor */ *side_effect |= JK_STATUS_NEEDS_UPDATE_MULT | JK_STATUS_NEEDS_PUSH; if ((rv = status_get_string(p, JK_STATUS_ARG_LBM_ROUTE, NULL, &arg, l)) == JK_TRUE) { int ret = jk_shm_str_init_ne(wr->route, arg, "route", l); if (ret == -1) { const char *msg = "Update failed (at least partially): new route '%s' " "too long for sub worker '%s', see log file for details."; size_t size = strlen(msg) + strlen(arg) + strlen(wr->name) + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, arg, aw->name); rc = JK_FALSE; } else if (ret != 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'route' for sub worker '%s' of lb worker '%s' from '%s' to '%s'", w->name, wr->name, lb_name, wr->route, arg); *side_effect |= JK_STATUS_NEEDS_PUSH; if (!wr->domain[0]) { char * id_domain = strchr(wr->route, '.'); if (id_domain) { *id_domain = '\0'; strcpy(wr->domain, wr->route); *id_domain = '.'; } } } } if ((rv = status_get_string(p, JK_STATUS_ARG_LBM_REDIRECT, NULL, &arg, l)) == JK_TRUE) { int ret = jk_shm_str_init_ne(wr->redirect, arg, "redirect", l); if (ret == -1) { const char *msg = "Update failed (at least partially): new redirect '%s' " "too long for sub worker '%s', see log file for details."; size_t size = strlen(msg) + strlen(arg) + strlen(wr->name) + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, arg, aw->name); rc = JK_FALSE; } else if (ret != 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'redirect' for sub worker '%s' of lb worker '%s' from '%s' to '%s'", w->name, wr->name, lb_name, wr->redirect, arg); *side_effect |= JK_STATUS_NEEDS_PUSH; } } if ((rv = status_get_string(p, JK_STATUS_ARG_LBM_DOMAIN, NULL, &arg, l)) == JK_TRUE) { int ret = jk_shm_str_init_ne(wr->domain, arg, "domain", l); if (ret == -1) { const char *msg = "Update failed (at least partially): new domain '%s' " "too long for sub worker '%s', see log file for details."; size_t size = strlen(msg) + strlen(arg) + strlen(wr->name) + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, arg, aw->name); rc = JK_FALSE; } else if (ret != 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'domain' for sub worker '%s' of lb worker '%s' from '%s' to '%s'", w->name, wr->name, lb_name, wr->domain, arg); *side_effect |= JK_STATUS_NEEDS_PUSH; } } if (set_int_if_changed(p, wr->name, "distance", JK_STATUS_ARG_LBM_DISTANCE, 0, INT_MAX, &wr->distance, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; } old = aw->cache_timeout; if (set_int_if_changed(p, aw->name, "connection_pool_timeout", JK_STATUS_ARG_AJP_CACHE_TO, 0, INT_MAX, &aw->cache_timeout, lb_name, l)) { *side_effect |= JK_STATUS_NEEDS_PUSH; if (old == 0) { unsigned int i; for (i = 0; i < aw->ep_cache_sz; i++) { ajp_endpoint_t *ae = (ajp_endpoint_t *) aw->ep_cache[i]; if (ae) ae->last_access = time(NULL); } } } port = aw->port; if (set_int_if_changed(p, aw->name, "port", JK_STATUS_ARG_AJP_PORT, 0, INT_MAX, &port, lb_name, l)) { jk_shm_str_copy(host, aw->host, l); resolve = JK_TRUE; } if ((rv = status_get_string(p, JK_STATUS_ARG_AJP_HOST_STR, NULL, &arg, l)) == JK_TRUE) { int ret = jk_shm_str_init_ne(host, arg, "host name", l); if (ret == -1) { const char *msg = "Update failed (at least partially): new host name '%s' " "too long for sub worker '%s', see log file for details."; size_t size = strlen(msg) + strlen(arg) + strlen(aw->name) + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, arg, aw->name); rc = JK_FALSE; } else if (ret != 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'host' for sub worker '%s' from '%s' to '%s'", w->name, aw->name, aw->host, arg); resolve = JK_TRUE; } } if (resolve == JK_TRUE) { jk_sockaddr_t inet_addr; if (!jk_resolve(host, port, &inet_addr, aw->worker.we->pool, aw->prefer_ipv6, l)) { const char *msg = "Update failed (at least partially): could not resolve address '%s:%d' for sub worker '%s'."; size_t size = strlen(msg) + strlen(host) + strlen(aw->name) + 10 + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, host, port, aw->name); jk_log(l, JK_LOG_ERROR, "Status worker '%s' failed resolving address '%s:%d' for sub worker '%s'.", w->name, host, port, aw->name); rc = JK_FALSE; } else { /* This is not atomic and not thread safe */ aw->port = port; jk_shm_str_copy(aw->host, host, l); jk_clone_sockaddr(&(aw->worker_inet_addr), &inet_addr); *side_effect |= JK_STATUS_NEEDS_PUSH | JK_STATUS_NEEDS_ADDR_PUSH; } } if (set_int_if_changed(p, aw->name, "ping_timeout", JK_STATUS_ARG_AJP_PING_TO, 0, INT_MAX, &aw->ping_timeout, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; if (set_int_if_changed(p, aw->name, "connect_timeout", JK_STATUS_ARG_AJP_CONNECT_TO, 0, INT_MAX, &aw->connect_timeout, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; if (set_int_if_changed(p, aw->name, "prepost_timeout", JK_STATUS_ARG_AJP_PREPOST_TO, 0, INT_MAX, &aw->prepost_timeout, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; if (set_int_if_changed(p, aw->name, "reply_timeout", JK_STATUS_ARG_AJP_REPLY_TO, 0, INT_MAX, &aw->reply_timeout, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; if (set_int_if_changed(p, aw->name, "retries", JK_STATUS_ARG_AJP_RETRIES, 1, INT_MAX, &aw->retries, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; if (set_int_if_changed(p, aw->name, "retry_interval", JK_STATUS_ARG_AJP_RETRY_INT, 1, INT_MAX, &aw->retry_interval, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; if (set_int_if_changed(p, aw->name, "connection_ping_interval", JK_STATUS_ARG_AJP_CPING_INT, 1, INT_MAX, &aw->conn_ping_interval, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; if (set_uint_if_changed(p, aw->name, "recovery_options", JK_STATUS_ARG_AJP_REC_OPTS, 0, INT_MAX, 1, &aw->recovery_opts, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; if (set_int_if_changed(p, aw->name, "busy_limit", JK_STATUS_ARG_AJP_BUSY_LIMIT, 0, INT_MAX, &aw->busy_limit, lb_name, l)) *side_effect |= JK_STATUS_NEEDS_PUSH; if (set_uint_if_changed(p, aw->name, "max_packet_size", JK_STATUS_ARG_AJP_MAX_PK_SZ, AJP13_DEF_PACKET_SIZE, AJP13_MAX_PACKET_SIZE, AJP13_PACKET_SIZE_ALIGN, &aw->max_packet_size, lb_name, l)) { *side_effect |= JK_STATUS_NEEDS_PUSH; if (aw->max_packet_size > lb->max_packet_size) { lb->max_packet_size = aw->max_packet_size; } } return rc; } static void commit_all_members(jk_ws_service_t *s, status_endpoint_t *p, jk_worker_t *jw, const char *attribute, jk_log_context_t *l) { const char *arg; char vname[32]; const char *name = NULL; lb_worker_t *lb = NULL; status_worker_t *w = p->worker; const char *aname; int i; int rc = 0; unsigned int j; int push_all_members = JK_FALSE; JK_TRACE_ENTER(l); if (!attribute) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' missing request parameter '%s'", w->name, JK_STATUS_ARG_ATTRIBUTE); JK_TRACE_EXIT(l); return; } else { if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) aname=JK_STATUS_ARG_LBM_TEXT_ACTIVATION; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) aname=JK_STATUS_ARG_LBM_TEXT_FACTOR; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) aname=JK_STATUS_ARG_LBM_TEXT_ROUTE; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) aname=JK_STATUS_ARG_LBM_TEXT_REDIRECT; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) aname=JK_STATUS_ARG_LBM_TEXT_DOMAIN; else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) aname=JK_STATUS_ARG_LBM_TEXT_DISTANCE; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) aname=JK_STATUS_ARG_AJP_TEXT_CACHE_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) aname=JK_STATUS_ARG_AJP_TEXT_PING_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) aname=JK_STATUS_ARG_AJP_TEXT_CONNECT_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) aname=JK_STATUS_ARG_AJP_TEXT_PREPOST_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) aname=JK_STATUS_ARG_AJP_TEXT_REPLY_TO; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) aname=JK_STATUS_ARG_AJP_TEXT_RETRIES; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) aname=JK_STATUS_ARG_AJP_TEXT_RETRY_INT; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) aname=JK_STATUS_ARG_AJP_TEXT_CPING_INT; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) aname=JK_STATUS_ARG_AJP_TEXT_REC_OPTS; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_BUSY_LIMIT)) aname=JK_STATUS_ARG_AJP_TEXT_BUSY_LIMIT; else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) aname=JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ; else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' unknown attribute '%s'", w->name, attribute); JK_TRACE_EXIT(l); return; } } if (jw->type == JK_LB_WORKER_TYPE) { lb = (lb_worker_t *)jw->worker_private; name = lb->name; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' committing changes for attribute '%s' [%s] of all members of lb worker '%s'", w->name, attribute, aname, name); } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' worker type not implemented", w->name); JK_TRACE_EXIT(l); return; } if (lb) { for (j = 0; j < lb->num_of_workers; j++) { int sync_needed = JK_FALSE; lb_sub_worker_t *wr = &(lb->lb_workers[j]); jk_worker_t *jw = wr->worker; ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;; snprintf(vname, 32-1, "" JK_STATUS_ARG_MULT_VALUE_BASE "%d", j); if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) { if (set_int_if_changed(p, wr->name, "lbfactor", vname, 1, INT_MAX, &wr->lb_factor, name, l)) { rc = 2; sync_needed = JK_TRUE; } } else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) { if (set_int_if_changed(p, wr->name, "distance", vname, 0, INT_MAX, &wr->distance, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) { int old = aw->cache_timeout; if (set_int_if_changed(p, aw->name, "connection_pool_timeout", vname, 0, INT_MAX, &aw->cache_timeout, name, l)) { sync_needed = JK_TRUE; if (old == 0) { unsigned int i; for (i = 0; i < aw->ep_cache_sz; i++) { ajp_endpoint_t *ae = (ajp_endpoint_t *) aw->ep_cache[i]; if (ae) ae->last_access = time(NULL); } } } } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) { if (set_int_if_changed(p, aw->name, "ping_timeout", vname, 0, INT_MAX, &aw->ping_timeout, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) { if (set_int_if_changed(p, aw->name, "connect_timeout", vname, 0, INT_MAX, &aw->connect_timeout, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) { if (set_int_if_changed(p, aw->name, "prepost_timeout", vname, 0, INT_MAX, &aw->prepost_timeout, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) { if (set_int_if_changed(p, aw->name, "reply_timeout", vname, 0, INT_MAX, &aw->reply_timeout, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) { if (set_int_if_changed(p, aw->name, "retries", vname, 1, INT_MAX, &aw->retries, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) { if (set_int_if_changed(p, aw->name, "retry_interval", vname, 1, INT_MAX, &aw->retry_interval, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) { if (set_int_if_changed(p, aw->name, "connection_ping_interval", vname, 1, INT_MAX, &aw->conn_ping_interval, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) { if (set_uint_if_changed(p, aw->name, "recovery_options", vname, 0, INT_MAX, 1, &aw->recovery_opts, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_BUSY_LIMIT)) { if (set_int_if_changed(p, aw->name, "busy_limit", vname, 0, INT_MAX, &aw->busy_limit, name, l)) sync_needed = JK_TRUE; } else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) { if (set_uint_if_changed(p, aw->name, "max_packet_size", vname, AJP13_DEF_PACKET_SIZE, AJP13_MAX_PACKET_SIZE, AJP13_PACKET_SIZE_ALIGN, &aw->max_packet_size, name, l)) { sync_needed = JK_TRUE; if (aw->max_packet_size > lb->max_packet_size) { lb->max_packet_size = aw->max_packet_size; } } } else { int rv = status_get_string(p, vname, NULL, &arg, l); if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) { if (rv == JK_TRUE) { i = jk_lb_get_activation_code(arg); if (i != wr->activation && i >= 0 && i <= JK_LB_ACTIVATION_MAX) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'activation' for sub worker '%s' of lb worker '%s' from '%s' to '%s'", w->name, wr->name, name, jk_lb_get_activation(wr, l), jk_lb_get_activation_direct(i, l)); wr->activation = i; rc = 1; sync_needed = JK_TRUE; } } } else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) { if (rv == JK_TRUE) { int ret = jk_shm_str_init_ne(wr->route, arg, "route", l); if (ret == -1) { const char *msg = "Update failed (at least partially): new route '%s' " "too long for sub worker '%s', see log file for details."; size_t size = strlen(msg) + strlen(arg) + strlen(wr->name) + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, arg, aw->name); rc = JK_FALSE; } else if (ret != 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'route' for sub worker '%s' of lb worker '%s' from '%s' to '%s'", w->name, wr->name, name, wr->route, arg); sync_needed = JK_TRUE; if (!wr->domain[0]) { char * id_domain = strchr(wr->route, '.'); if (id_domain) { *id_domain = '\0'; strcpy(wr->domain, wr->route); *id_domain = '.'; } } } } } else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) { if (rv == JK_TRUE) { int ret = jk_shm_str_init_ne(wr->redirect, arg, "redirect", l); if (ret == -1) { const char *msg = "Update failed (at least partially): new redirect '%s' " "too long for sub worker '%s', see log file for details."; size_t size = strlen(msg) + strlen(arg) + strlen(wr->name) + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, arg, aw->name); rc = JK_FALSE; } else if (ret != 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'redirect' for sub worker '%s' of lb worker '%s' from '%s' to '%s'", w->name, wr->name, name, wr->redirect, arg); sync_needed = JK_TRUE; } } } else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) { if (rv == JK_TRUE) { int ret = jk_shm_str_init_ne(wr->domain, arg, "domain", l); if (ret == -1) { const char *msg = "Update failed (at least partially): new domain '%s' " "too long for sub worker '%s', see log file for details."; size_t size = strlen(msg) + strlen(arg) + strlen(wr->name) + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, arg, aw->name); rc = JK_FALSE; } else if (ret != 0) { jk_log(l, JK_LOG_INFO, "Status worker '%s' changing 'domain' for sub worker '%s' of lb worker '%s' from '%s' to '%s'", w->name, wr->name, name, wr->domain, arg); sync_needed = JK_TRUE; } } } } if (sync_needed == JK_TRUE) { wr->sequence = -1; if (!rc) rc = 3; } } if (rc == 1) reset_lb_values(lb, l); else if (rc == 2) { /* Recalculate the load multiplicators wrt. lb_factor */ update_mult(lb, l); push_all_members = JK_TRUE; } if (rc) { lb->sequence = -1; jk_lb_push(lb, JK_TRUE, push_all_members, l); } } JK_TRACE_EXIT(l); } static void display_legend(jk_ws_service_t *s, status_endpoint_t *p, jk_log_context_t *l) { int mime; const char *arg; unsigned int hide_legend; JK_TRACE_ENTER(l); status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); mime = status_mime_int(arg); if (mime != JK_STATUS_MIME_HTML) { JK_TRACE_EXIT(l); return; } hide_legend = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_NO_LEGEND; if (hide_legend) { jk_puts(s, "

\n"); status_write_uri(s, p, "Show Legend", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LEGEND, NULL, l); jk_puts(s, "

\n"); } else { jk_puts(s, "

Legend ["); status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_LEGEND, 0, NULL, l); jk_puts(s, "]

\n"); jk_puts(s, "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "
NameWorker name
TypeWorker type
RouteWorker route
ActWorker activation configuration
\n" "ACT=Active, DIS=Disabled, STP=Stopped
StateWorker error status
\n" "OK=OK, ERR=Error with substates
\n" "IDLE=No requests handled, BUSY=All connections busy,
\n" "REC=Recovering, PRB=Probing, FRC=Forced Recovery
DWorker distance
FLoad Balancer factor
MLoad Balancer multiplicity
VLoad Balancer value
AccNumber of requests
SessNumber of sessions created
ErrNumber of failed requests
CENumber of client errors
RENumber of reply timeouts (decayed)
WrNumber of bytes transferred
RdNumber of bytes read
BusyCurrent number of busy connections
MaxBusyMaximum number of busy connections
ConCurrent number of backend connections
MaxConMaximum number of backend connections
RRRoute redirect
CdCluster domain
RsRecovery scheduled in app. min/max seconds
LRSeconds since last reset of statistics counters
LETimestamp of the last error
\n"); } JK_TRACE_EXIT(l); } static int check_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_uint32_t allow_wildchars, jk_log_context_t *l) { const char *worker; const char *sub_worker; status_worker_t *w = p->worker; jk_worker_t *jw = NULL; lb_sub_worker_t *wr = NULL; JK_TRACE_ENTER(l); if (fetch_worker_and_sub_worker(p, "checking", &worker, &sub_worker, l) == JK_FALSE || search_worker(s, p, &jw, worker, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (sub_worker && sub_worker[0]) { unsigned int idx = 0; unsigned int *wi = NULL; if (strchr(sub_worker, '*') || strchr(sub_worker, '?')) { /* We have a wildchar matching rule */ if (!allow_wildchars) { jk_log(l, JK_LOG_ERROR, "Status worker '%s' wildcards in sub worker '%s' of worker '%s' not allowed for this command", w->name, sub_worker, worker ? worker : "(null)"); p->msg = "wildcard not allowed in sub worker for this command"; JK_TRACE_EXIT(l); return JK_FALSE; } else { wi = &idx; } } if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, wi, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } } JK_TRACE_EXIT(l); return JK_TRUE; } static void count_workers(jk_ws_service_t *s, status_endpoint_t *p, int *lb_cnt, int *ajp_cnt, jk_log_context_t *l) { unsigned int i; jk_worker_t *jw = NULL; status_worker_t *w = p->worker; JK_TRACE_ENTER(l); *lb_cnt = 0; *ajp_cnt = 0; for (i = 0; i < w->we->num_of_workers; i++) { jw = wc_get_worker_for_name(w->we->worker_list[i], l); if (!jw) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' could not find worker '%s'", w->name, w->we->worker_list[i]); continue; } if (jw->type == JK_LB_WORKER_TYPE) { (*lb_cnt)++; } else if (jw->type == JK_AJP13_WORKER_TYPE || jw->type == JK_AJP14_WORKER_TYPE) { (*ajp_cnt)++; } } JK_TRACE_EXIT(l); } static void list_workers_type(jk_ws_service_t *s, status_endpoint_t *p, int list_lb, int count, jk_log_context_t *l) { const char *arg; unsigned int i; int mime; unsigned int hide; jk_worker_t *jw = NULL; status_worker_t *w = p->worker; JK_TRACE_ENTER(l); status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); mime = status_mime_int(arg); if (list_lb) { hide = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_NO_LB; if (hide) { if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "

\n"); status_write_uri(s, p, "Show Load Balancing Workers", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB, NULL, l); jk_puts(s, "

\n"); } } else { if (mime == JK_STATUS_MIME_XML) { jk_print_xml_start_elt(s, l, w, 0, 0, "balancers"); jk_print_xml_att_int(s, l, 2, "count", count); jk_print_xml_stop_elt(s, l, 0, 0); } else if (mime == JK_STATUS_MIME_TXT) { jk_printf(s, l, "Balancer Workers: count=%d\n", count); } else if (mime == JK_STATUS_MIME_PROP) { jk_print_prop_att_int(s, l, w, NULL, "lb_count", count); } else { jk_printf(s, l, "

Listing Load Balancing Worker%s (%d Worker%s) [", count>1 ? "s" : "", count, count>1 ? "s" : ""); status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_LB, 0, NULL, l); jk_puts(s, "]

\n"); } } } else { hide = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_NO_AJP; if (hide) { if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "

\n"); status_write_uri(s, p, "Show AJP Workers", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP, NULL, l); jk_puts(s, "

\n"); } } else { if (mime == JK_STATUS_MIME_XML) { jk_print_xml_start_elt(s, l, w, 0, 0, "ajp_workers"); jk_print_xml_att_int(s, l, 2, "count", count); jk_print_xml_stop_elt(s, l, 0, 0); } else if (mime == JK_STATUS_MIME_TXT) { jk_printf(s, l, "AJP Workers: count=%d\n", count); } else if (mime == JK_STATUS_MIME_PROP) { jk_print_prop_att_int(s, l, w, NULL, "ajp_count", count); } else { jk_printf(s, l, "

Listing AJP Worker%s (%d Worker%s) [", count>1 ? "s" : "", count, count>1 ? "s" : ""); status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_NO_AJP, 0, NULL, l); jk_puts(s, "]

\n"); } } } if (hide) { JK_TRACE_EXIT(l); return; } for (i = 0; i < w->we->num_of_workers; i++) { jw = wc_get_worker_for_name(w->we->worker_list[i], l); if (!jw) { jk_log(l, JK_LOG_WARNING, "Status worker '%s' could not find worker '%s'", w->name, w->we->worker_list[i]); continue; } if ((list_lb && jw->type == JK_LB_WORKER_TYPE) || (!list_lb && jw->type != JK_LB_WORKER_TYPE)) { display_worker(s, p, jw, NULL, l); } } if (list_lb) { if (mime == JK_STATUS_MIME_XML) { jk_print_xml_close_elt(s, l, w, 0, "balancers"); } else if (mime == JK_STATUS_MIME_TXT) { } else if (mime == JK_STATUS_MIME_PROP) { } else if (mime == JK_STATUS_MIME_HTML) { } } else { if (mime == JK_STATUS_MIME_XML) { jk_print_xml_close_elt(s, l, w, 0, "ajp_workers"); } else if (mime == JK_STATUS_MIME_TXT) { } else if (mime == JK_STATUS_MIME_PROP) { } else if (mime == JK_STATUS_MIME_HTML) { } } JK_TRACE_EXIT(l); } static int list_workers(jk_ws_service_t *s, status_endpoint_t *p, jk_log_context_t *l) { int lb_cnt = 0; int ajp_cnt = 0; JK_TRACE_ENTER(l); count_workers(s, p, &lb_cnt, &ajp_cnt, l); if (lb_cnt) { list_workers_type(s, p, 1, lb_cnt, l); } if (ajp_cnt) { list_workers_type(s, p, 0, ajp_cnt, l); } JK_TRACE_EXIT(l); return JK_TRUE; } static int show_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_log_context_t *l) { const char *worker; const char *sub_worker; jk_worker_t *jw = NULL; lb_sub_worker_t *wr = NULL; JK_TRACE_ENTER(l); if (fetch_worker_and_sub_worker(p, "showing", &worker, &sub_worker, l) == JK_FALSE || search_worker(s, p, &jw, worker, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (sub_worker && sub_worker[0]) { if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, NULL, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } } display_worker(s, p, jw, wr, l); JK_TRACE_EXIT(l); return JK_TRUE; } static int edit_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_log_context_t *l) { const char *worker; const char *sub_worker; status_worker_t *w = p->worker; jk_worker_t *jw = NULL; lb_worker_t *lb = NULL; lb_sub_worker_t *wr = NULL; ajp_worker_t *aw = NULL; JK_TRACE_ENTER(l); if (fetch_worker_and_sub_worker(p, "editing", &worker, &sub_worker, l) == JK_FALSE || search_worker(s, p, &jw, worker, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (jw->type == JK_LB_WORKER_TYPE) { if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (lb->sequence != lb->s->h.sequence) jk_lb_pull(lb, JK_FALSE, l); if (!sub_worker || !sub_worker[0]) { const char *arg; if (status_get_string(p, JK_STATUS_ARG_ATTRIBUTE, NULL, &arg, l) == JK_TRUE) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s lb worker '%s' with all sub workers", w->name, "editing", lb->name); form_all_members(s, p, jw, arg, l); } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s lb worker '%s'", w->name, "editing", lb->name); form_worker(s, p, jw, l); } JK_TRACE_EXIT(l); return JK_TRUE; } else { if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, NULL, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s lb worker '%s' sub worker '%s'", w->name, "editing", lb->name, wr->name); aw = (ajp_worker_t *)wr->worker->worker_private; form_member(s, p, wr, aw, worker, l); JK_TRACE_EXIT(l); return JK_TRUE; } } else if (jw->type == JK_AJP13_WORKER_TYPE || jw->type == JK_AJP14_WORKER_TYPE) { ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; if (aw) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s ajp worker '%s'", w->name, "editing", aw->name); if (aw->sequence != aw->s->h.sequence) jk_ajp_pull(aw, JK_FALSE, l); form_member(s, p, NULL, aw, worker, l); JK_TRACE_EXIT(l); return JK_TRUE; } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' aw worker is (null)", w->name); } } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' worker type not implemented", w->name); } JK_TRACE_EXIT(l); return JK_FALSE; } static int update_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_log_context_t *l) { const char *worker; const char *sub_worker; status_worker_t *w = p->worker; jk_worker_t *jw = NULL; lb_worker_t *lb = NULL; lb_sub_worker_t *wr = NULL; ajp_worker_t *aw = NULL; int rc = JK_TRUE; int rv; JK_TRACE_ENTER(l); if (fetch_worker_and_sub_worker(p, "updating", &worker, &sub_worker, l) == JK_FALSE || search_worker(s, p, &jw, worker, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (jw->type == JK_LB_WORKER_TYPE) { if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (lb->sequence != lb->s->h.sequence) jk_lb_pull(lb, JK_TRUE, l); if (!sub_worker || !sub_worker[0]) { const char *arg; if (status_get_string(p, JK_STATUS_ARG_ATTRIBUTE, NULL, &arg, l) == JK_TRUE) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s lb worker '%s' with all sub workers", w->name, "updating", lb->name); commit_all_members(s, p, jw, arg, l); } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s lb worker '%s'", w->name, "updating", lb->name); commit_worker(s, p, jw, l); } JK_TRACE_EXIT(l); return JK_TRUE; } else { unsigned int idx = 0; unsigned int *wi = NULL; int is_wildchar = JK_FALSE; if (strchr(sub_worker, '*') || strchr(sub_worker, '?')) { /* We have a wildchar matching rule */ wi = &idx; is_wildchar = JK_TRUE; } for (;;) { if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, wi, l) == JK_FALSE) { if (!idx) { JK_TRACE_EXIT(l); return JK_FALSE; } else { /* We have found at least one match previously */ p->msg = "OK"; break; } } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s lb worker '%s' sub worker '%s'", w->name, "updating", lb->name, wr->name); aw = (ajp_worker_t *)wr->worker->worker_private; rv = 0; rc = commit_member(s, p, lb, wr, aw, &rv, l); if (rv & JK_STATUS_NEEDS_ADDR_PUSH) { aw->addr_sequence = -1; } if (rv & JK_STATUS_NEEDS_RESET_LB_VALUES) reset_lb_values(lb, l); if (rv & JK_STATUS_NEEDS_UPDATE_MULT) /* Recalculate the load multiplicators wrt. lb_factor */ update_mult(lb, l); if (rv & (JK_STATUS_NEEDS_PUSH | JK_STATUS_NEEDS_ADDR_PUSH)) { wr->sequence = -1; lb->sequence = -1; jk_lb_push(lb, JK_TRUE, rv & JK_STATUS_NEEDS_UPDATE_MULT ? JK_TRUE: JK_FALSE, l); } if (rc == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "Status worker '%s' failed updating sub worker '%s' (at least partially).%s", w->name, aw->name, (is_wildchar == JK_TRUE) ? " Aborting further wildcard updates." : ""); if (!strncmp("OK", p->msg, 3)) { const char *msg = "Update failed (at least partially) for sub worker '%s'"; size_t size = strlen(msg) + strlen(aw->name) + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, aw->name); } if (is_wildchar == JK_TRUE) { const char *msg = " Aborting further wildcard updates."; size_t size = strlen(msg) + strlen(p->msg) + 1; p->msg = jk_pool_realloc(s->pool, size, p->msg, strlen(p->msg) + 1); strcat(p->msg, msg); } break; } if (!wi) break; } JK_TRACE_EXIT(l); return rc; } } else if (jw->type == JK_AJP13_WORKER_TYPE || jw->type == JK_AJP14_WORKER_TYPE) { ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; if (aw) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s ajp worker '%s'", w->name, "updating", aw->name); if (aw->sequence != aw->s->h.sequence) jk_ajp_pull(aw, JK_TRUE, l); rv = 0; rc = commit_member(s, p, NULL, NULL, aw, &rv, l); if (rv & JK_STATUS_NEEDS_ADDR_PUSH) { aw->addr_sequence = -1; } if (rv & (JK_STATUS_NEEDS_PUSH | JK_STATUS_NEEDS_ADDR_PUSH)) { aw->sequence = -1; jk_ajp_push(aw, JK_TRUE, l); } if (rc == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "Status worker '%s' failed updating worker '%s' (at least partially).", w->name, aw->name); if (!strncmp("OK", p->msg, 3)) { const char *msg = "Update failed (at least partially) for worker '%s'"; size_t size = strlen(msg) + strlen(aw->name) + 1; p->msg = jk_pool_alloc(s->pool, size); snprintf(p->msg, size, msg, aw->name); } } JK_TRACE_EXIT(l); return rc; } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' aw worker is (null)", w->name); } } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' worker type not implemented", w->name); } JK_TRACE_EXIT(l); return JK_FALSE; } static int reset_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_log_context_t *l) { unsigned int i; const char *worker; const char *sub_worker; status_worker_t *w = p->worker; jk_worker_t *jw = NULL; lb_worker_t *lb = NULL; lb_sub_worker_t *wr = NULL; ajp_worker_t *aw = NULL; time_t now = 0; JK_TRACE_ENTER(l); if (fetch_worker_and_sub_worker(p, "resetting", &worker, &sub_worker, l) == JK_FALSE || search_worker(s, p, &jw, worker, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } now = time(NULL); if (jw->type == JK_LB_WORKER_TYPE) { if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (!sub_worker || !sub_worker[0]) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s lb worker '%s' with all sub workers", w->name, "resetting", lb->name); lb->s->max_busy = 0; lb->s->last_reset = now; for (i = 0; i < lb->num_of_workers; i++) { wr = &(lb->lb_workers[i]); aw = (ajp_worker_t *)wr->worker->worker_private; wr->s->state = JK_LB_STATE_IDLE; wr->s->elected_snapshot = 0; wr->s->sessions = 0; wr->s->first_error_time = 0; wr->s->last_error_time = 0; wr->s->errors = 0; wr->s->lb_value = 0; aw->s->used = 0; aw->s->client_errors = 0; aw->s->reply_timeouts = 0; aw->s->transferred = 0; aw->s->readed = 0; aw->s->max_busy = 0; aw->s->max_connected = 0; aw->s->last_reset = now; } JK_TRACE_EXIT(l); return JK_TRUE; } else { if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, NULL, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s lb worker '%s' sub worker '%s'", w->name, "resetting", lb->name, wr->name); aw = (ajp_worker_t *)wr->worker->worker_private; wr->s->state = JK_LB_STATE_IDLE; wr->s->elected_snapshot = 0; wr->s->sessions = 0; wr->s->first_error_time = 0; wr->s->last_error_time = 0; wr->s->errors = 0; wr->s->lb_value = 0; aw->s->used = 0; aw->s->client_errors = 0; aw->s->reply_timeouts = 0; aw->s->transferred = 0; aw->s->readed = 0; aw->s->max_busy = 0; aw->s->max_connected = 0; aw->s->last_reset = now; JK_TRACE_EXIT(l); return JK_TRUE; } } else if (jw->type == JK_AJP13_WORKER_TYPE || jw->type == JK_AJP14_WORKER_TYPE) { ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private; if (aw) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' %s ajp worker '%s'", w->name, "resetting", aw->name); aw->s->errors = 0; aw->s->used = 0; aw->s->client_errors = 0; aw->s->reply_timeouts = 0; aw->s->transferred = 0; aw->s->readed = 0; aw->s->max_busy = 0; aw->s->max_connected = 0; aw->s->last_reset = now; JK_TRACE_EXIT(l); return JK_TRUE; } else { jk_log(l, JK_LOG_WARNING, "Status worker '%s' aw worker is (null)", w->name); } } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' worker type not implemented", w->name); } JK_TRACE_EXIT(l); return JK_FALSE; } static int recover_worker(jk_ws_service_t *s, status_endpoint_t *p, jk_log_context_t *l) { const char *worker; const char *sub_worker; jk_worker_t *jw = NULL; lb_sub_worker_t *wr = NULL; ajp_worker_t *aw = NULL; status_worker_t *w = p->worker; JK_TRACE_ENTER(l); if (fetch_worker_and_sub_worker(p, "recovering", &worker, &sub_worker, l) == JK_FALSE || search_worker(s, p, &jw, worker, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (search_sub_worker(s, p, jw, worker, &wr, sub_worker, NULL, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } aw = (ajp_worker_t *)wr->worker->worker_private; if (wr->s->state == JK_LB_STATE_ERROR) { lb_worker_t *lb = NULL; /* We need an lb to correct the lb_value */ if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (lb->lbmethod != JK_LB_METHOD_BUSYNESS) { unsigned int i; jk_uint64_t curmax = 0; for (i = 0; i < lb->num_of_workers; i++) { if (lb->lb_workers[i].s->lb_value > curmax) { curmax = lb->lb_workers[i].s->lb_value; } } wr->s->lb_value = curmax; } aw->s->reply_timeouts = 0; wr->s->state = JK_LB_STATE_RECOVER; jk_log(l, JK_LOG_INFO, "Status worker '%s' marked worker '%s' sub worker '%s' for recovery", w->name, worker ? worker : "(null)", sub_worker ? sub_worker : "(null)"); JK_TRACE_EXIT(l); return JK_TRUE; } jk_log(l, JK_LOG_WARNING, "Status worker '%s' could not mark worker '%s' sub worker '%s' for recovery - state %s is not an error state", w->name, worker ? worker : "(null)", sub_worker ? sub_worker : "(null)", jk_lb_get_state(wr, l)); JK_TRACE_EXIT(l); return JK_FALSE; } static int dump_config(jk_ws_service_t *s, status_endpoint_t *p, int mime, jk_log_context_t *l) { status_worker_t *w = p->worker; jk_worker_env_t *we = w->we; jk_map_t *init_data = we->init_data; JK_TRACE_ENTER(l); if (init_data) { int n = jk_map_size(init_data); int i; if (mime == JK_STATUS_MIME_HTML) { jk_puts(s, "

Configuration Data


\n"); jk_puts(s, "This dump does not include any changes applied by the status worker\n"); jk_puts(s, "to the configuration after the initial startup\n"); jk_puts(s, "
\n");
        }
        else if (mime == JK_STATUS_MIME_XML) {
            jk_print_xml_start_elt(s, l, w, 2, 0, "configuration");
        }
        else if (mime == JK_STATUS_MIME_TXT) {
            jk_puts(s, "Configuration:\n");
        }
        for (i=0;i sizeof(".secret") &&
                    strcmp(name + nl - 7, ".secret") == 0) {
                    continue;
                }
                value = jk_map_value_at(init_data, i);
                if (!value)
                    value = "(null)";
                if (mime == JK_STATUS_MIME_HTML ||
                    mime == JK_STATUS_MIME_PROP ||
                    mime == JK_STATUS_MIME_TXT) {
                    jk_putv(s, name, "=", value, "\n", NULL);
                }
                else if (mime == JK_STATUS_MIME_XML) {
                     jk_print_xml_att_string(s, l, 4, name, value);
                }
            }
        }
        if (mime == JK_STATUS_MIME_HTML) {
            jk_puts(s, "
\n"); } else if (mime == JK_STATUS_MIME_XML) { jk_print_xml_stop_elt(s, l, 2, 1); } } else { JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Return values of service() method for status worker: * return value is_error reason * JK_FALSE JK_HTTP_SERVER_ERROR Invalid parameters (null values) * JK_TRUE JK_HTTP_OK All other cases */ static int JK_METHOD service(jk_endpoint_t *e, jk_ws_service_t *s, jk_log_context_t *l, int *is_error) { int cmd; jk_uint32_t cmd_props; int mime; int refresh; int read_only = 0; const char *arg; char *err = NULL; status_endpoint_t *p; status_worker_t *w; int denied = 0; JK_TRACE_ENTER(l); if (!e || !e->endpoint_private || !s || !is_error) { JK_LOG_NULL_PARAMS(l); if (is_error) *is_error = JK_HTTP_SERVER_ERROR; JK_TRACE_EXIT(l); return JK_FALSE; } p = e->endpoint_private; w = p->worker; /* Set returned error to OK */ *is_error = JK_HTTP_OK; if (w->num_of_users) { if (s->remote_user) { unsigned int i; denied = 1; for (i = 0; i < w->num_of_users; i++) { if (w->user_case_insensitive) { if (!strcasecmp(s->remote_user, w->user_names[i])) { denied = 0; break; } } else { if (!strcmp(s->remote_user, w->user_names[i])) { denied = 0; break; } } } } else { denied = 2; } } /* Step 0: Unescape request uri and make safe against XSS */ if (status_unescape_uri(s, p, l) != JK_TRUE) { if (is_error) *is_error = JK_HTTP_SERVER_ERROR; JK_TRACE_EXIT(l); return JK_FALSE; } /* Step 1: Process GET params and update configuration */ if (status_parse_uri(s, p, l) != JK_TRUE) { err = "Error during parsing of URI"; } status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l); cmd = status_cmd_int(arg); cmd_props = status_cmd_props(cmd); status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l); mime = status_mime_int(arg); refresh = status_get_int(p, JK_STATUS_ARG_REFRESH, 0, l); if (w->read_only) { read_only = 1; } else { read_only = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) & JK_STATUS_ARG_OPTION_READ_ONLY; } if (mime == JK_STATUS_MIME_HTML) { s->start_response(s, 200, "OK", headers_names, headers_vhtml, 3); jk_puts(s, JK_STATUS_HEAD); } else if (mime == JK_STATUS_MIME_XML) { s->start_response(s, 200, "OK", headers_names, headers_vxml, 3); jk_puts(s, JK_STATUS_XMLH); if (w->doctype) { jk_putv(s, w->doctype, "\n", NULL); } jk_print_xml_start_elt(s, l, w, 0, 0, "status"); if (w->xmlns && strlen(w->xmlns)) jk_putv(s, " ", w->xmlns, NULL); jk_print_xml_stop_elt(s, l, 0, 0); } else { s->start_response(s, 200, "OK", headers_names, headers_vtxt, 3); } if (denied == 0) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' service allowed for user '%s' [%s] from %s [%s]", w->name, s->remote_user ? s->remote_user : "(null)", s->auth_type ? s->auth_type : "(null)", s->remote_addr ? s->remote_addr : "(null)", s->remote_host ? s->remote_host : "(null)"); } else if (denied == 1) { err = "Access denied."; jk_log(l, JK_LOG_WARNING, "Status worker '%s' service denied for user '%s' [%s] from %s [%s]", w->name, s->remote_user ? s->remote_user : "(null)", s->auth_type ? s->auth_type : "(null)", s->remote_addr ? s->remote_addr : "(null)", s->remote_host ? s->remote_host : "(null)"); } else if (denied == 2) { err = "Access denied."; jk_log(l, JK_LOG_WARNING, "Status worker '%s' service denied (no user) [%s] from %s [%s]", w->name, s->remote_user ? s->remote_user : "(null)", s->auth_type ? s->auth_type : "(null)", s->remote_addr ? s->remote_addr : "(null)", s->remote_host ? s->remote_host : "(null)"); } else { err = "Access denied."; jk_log(l, JK_LOG_WARNING, "Status worker '%s' service denied (unknown reason) for user '%s' [%s] from %s [%s]", w->name, s->remote_user ? s->remote_user : "(null)", s->auth_type ? s->auth_type : "(null)", s->remote_addr ? s->remote_addr : "(null)", s->remote_host ? s->remote_host : "(null)"); } if (!err) { if (read_only && !(cmd_props & JK_STATUS_CMD_PROP_READONLY)) { err = "This command is not allowed in read only mode."; } } if (!err) { if (cmd == JK_STATUS_CMD_UNKNOWN) { err = "Invalid command."; } else if (mime == JK_STATUS_MIME_UNKNOWN) { err = "Invalid mime type."; } else if (cmd_props & JK_STATUS_CMD_PROP_CHECK_WORKER && (check_worker(s, p, cmd_props & JK_STATUS_CMD_PROP_WILDCARD, l) != JK_TRUE)) { err = p->msg; } } if (!err) { char buf_time[JK_STATUS_TIME_BUF_SZ]; char buf_tz[JK_STATUS_TIME_BUF_SZ]; time_t clock = time(NULL); long unix_seconds = (long)clock; int rc_time = status_strftime(clock, mime, buf_time, buf_tz, l); if (cmd == JK_STATUS_CMD_UPDATE) { /* lock shared memory */ jk_shm_lock(); if (update_worker(s, p, l) == JK_FALSE) { if (strncmp("OK", p->msg, 3)) err = p->msg; else err = "Update failed"; } /* unlock the shared memory */ jk_shm_unlock(); if (mime == JK_STATUS_MIME_HTML) { write_html_refresh_response(s, p, err, l); } } else if (cmd == JK_STATUS_CMD_RESET) { /* lock shared memory */ jk_shm_lock(); if (reset_worker(s, p, l) == JK_FALSE) { err = "Reset failed"; } /* unlock the shared memory */ jk_shm_unlock(); if (mime == JK_STATUS_MIME_HTML) { write_html_refresh_response(s, p, err, l); } } else if (cmd == JK_STATUS_CMD_RECOVER) { /* lock shared memory */ jk_shm_lock(); if (recover_worker(s, p, l) == JK_FALSE) { err = "Marking worker for recovery failed"; } /* unlock the shared memory */ jk_shm_unlock(); if (mime == JK_STATUS_MIME_HTML) { write_html_refresh_response(s, p, err, l); } } else { if (mime == JK_STATUS_MIME_XML) { jk_print_xml_start_elt(s, l, w, 0, 0, "server"); jk_print_xml_att_string(s, l, 2, "name", s->server_name); jk_print_xml_att_int(s, l, 2, "port", s->server_port); jk_print_xml_stop_elt(s, l, 0, 1); if (cmd_props & JK_STATUS_CMD_PROP_HEAD) { if (rc_time > 0) { jk_print_xml_start_elt(s, l, w, 0, 0, "time"); jk_print_xml_att_string(s, l, 2, "datetime", buf_time); jk_print_xml_att_string(s, l, 2, "tz", buf_tz); jk_print_xml_att_long(s, l, 2, "unix", unix_seconds); jk_print_xml_stop_elt(s, l, 0, 1); } jk_print_xml_start_elt(s, l, w, 0, 0, "software"); jk_print_xml_att_string(s, l, 2, "web_server", s->server_software); jk_print_xml_att_string(s, l, 2, "jk_version", JK_FULL_EXPOSED_VERSION); jk_print_xml_stop_elt(s, l, 0, 1); } if (cmd == JK_STATUS_CMD_LIST) { /* Step 2: Display configuration */ if (list_workers(s, p, l) != JK_TRUE) { err = "Error in listing the workers."; } } else if (cmd == JK_STATUS_CMD_SHOW) { /* Step 2: Display detailed configuration */ if (show_worker(s, p, l) != JK_TRUE) { err = "Error in showing this worker."; } } } else if (mime == JK_STATUS_MIME_TXT) { jk_puts(s, "Server:"); jk_printf(s, l, " name=%s", s->server_name); jk_printf(s, l, " port=%d", s->server_port); jk_puts(s, "\n"); if (cmd_props & JK_STATUS_CMD_PROP_HEAD) { if (rc_time > 0) { jk_puts(s, "Time:"); jk_printf(s, l, " datetime=%s", buf_time); jk_printf(s, l, " tz=%s", buf_tz); jk_printf(s, l, " unix=%ld", unix_seconds); jk_puts(s, "\n"); } jk_puts(s, "Software:"); jk_printf(s, l, " web_server=\"%s\"", s->server_software); jk_printf(s, l, " jk_version=%s", JK_FULL_EXPOSED_VERSION); jk_puts(s, "\n"); } if (cmd == JK_STATUS_CMD_LIST) { /* Step 2: Display configuration */ if (list_workers(s, p, l) != JK_TRUE) { err = "Error in listing the workers."; } } else if (cmd == JK_STATUS_CMD_SHOW) { /* Step 2: Display detailed configuration */ if (show_worker(s, p, l) != JK_TRUE) { err = "Error in showing this worker."; } } } else if (mime == JK_STATUS_MIME_PROP) { jk_print_prop_att_string(s, l, w, NULL, "server_name", s->server_name); jk_print_prop_att_int(s, l, w, NULL, "server_port", s->server_port); if (cmd_props & JK_STATUS_CMD_PROP_HEAD) { if (rc_time > 0) { jk_print_prop_att_string(s, l, w, NULL, "time_datetime", buf_time); jk_print_prop_att_string(s, l, w, NULL, "time_tz", buf_tz); jk_print_prop_att_long(s, l, w, NULL, "time_unix", unix_seconds); } jk_print_prop_att_string(s, l, w, NULL, "web_server", s->server_software); jk_print_prop_att_string(s, l, w, NULL, "jk_version", JK_FULL_EXPOSED_VERSION); } if (cmd == JK_STATUS_CMD_LIST) { /* Step 2: Display configuration */ if (list_workers(s, p, l) != JK_TRUE) { err = "Error in listing the workers."; } } else if (cmd == JK_STATUS_CMD_SHOW) { /* Step 2: Display detailed configuration */ if (show_worker(s, p, l) != JK_TRUE) { err = "Error in showing this worker."; } } } else if (mime == JK_STATUS_MIME_HTML) { if (cmd_props & JK_STATUS_CMD_PROP_REFRESH && refresh > 0) { jk_printf(s, l, "\n", refresh, p->req_uri, p->query_string); } if (w->css) { jk_putv(s, "\ncss, "\" />\n", NULL); } jk_puts(s, JK_STATUS_HEND); jk_puts(s, "

JK Status Manager for "); jk_puts(s, s->server_name); jk_printf(s, l, ":%d", s->server_port); if (read_only) { jk_puts(s, " (read only)"); } jk_puts(s, "

\n\n"); if (cmd_props & JK_STATUS_CMD_PROP_HEAD) { jk_putv(s, "\n"); jk_putv(s, "
Server Version:", s->server_software, "   ", NULL); if (rc_time > 0) { jk_putv(s, "Server Time:", buf_time, NULL); } jk_puts(s, "
JK Version:", JK_FULL_EXPOSED_VERSION, "", NULL); jk_printf(s, l, "Unix Seconds:%d", unix_seconds); jk_puts(s, "
\n
\n"); } jk_puts(s, "\n"); if (cmd_props & JK_STATUS_CMD_PROP_REFRESH) { jk_puts(s, "\n"); } if (cmd_props & JK_STATUS_CMD_PROP_FMT) { jk_puts(s, "\n"); } jk_puts(s, "
"); if (refresh > 0) { const char *str = p->query_string; char *buf = jk_pool_alloc(s->pool, sizeof(char *) * (strlen(str)+1)); int result = 0; size_t scan = 0; size_t len = strlen(JK_STATUS_ARG_REFRESH); while (str[scan] != '\0') { if (strncmp(&str[scan], JK_STATUS_ARG_REFRESH, len) == 0 && str[scan+len] == '=') { scan += len + 1; while (str[scan] != '\0' && str[scan] != '&') scan++; if (str[scan] == '&') scan++; } else { if (result > 0 && str[scan] != '\0' && str[scan] != '&') { buf[result] = '&'; result++; } while (str[scan] != '\0' && str[scan] != '&') { buf[result] = str[scan]; result++; scan++; } if (str[scan] == '&') scan++; } } buf[result] = '\0'; jk_putv(s, "[req_uri, NULL); if (buf && buf[0]) jk_putv(s, "?", buf, NULL); jk_puts(s, "\">Stop auto refresh]"); } else { status_start_form(s, p, "get", JK_STATUS_CMD_UNKNOWN, JK_STATUS_ARG_REFRESH, l); jk_puts(s, "\n"); jk_putv(s, "(every ", " ", "seconds)", NULL); jk_puts(s, "\n"); } jk_puts(s, "  |  \n"); status_start_form(s, p, "get", JK_STATUS_CMD_UNKNOWN, JK_STATUS_ARG_MIME, l); jk_puts(s, "\n"); jk_putv(s, "\n"); jk_puts(s, "
\n"); jk_puts(s, "\n"); if (cmd_props & JK_STATUS_CMD_PROP_BACK_LINK) { int from; jk_puts(s, "\n"); } if (cmd_props & JK_STATUS_CMD_PROP_SWITCH_RO) { jk_puts(s, "\n"); } if (cmd_props & JK_STATUS_CMD_PROP_DUMP_LINK) { jk_puts(s, "\n"); } if (cmd_props & JK_STATUS_CMD_PROP_LINK_HELP && (cmd == JK_STATUS_CMD_LIST || !read_only)) { jk_puts(s, "\n"); } jk_puts(s, "
\n"); status_get_string(p, JK_STATUS_ARG_FROM, NULL, &arg, l); from = status_cmd_int(arg); jk_puts(s, "["); if (cmd_props & JK_STATUS_CMD_PROP_BACK_LIST || from == JK_STATUS_CMD_LIST) { status_write_uri(s, p, "Back to worker list", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN, "", "", 0, 0, "", l); } else { status_write_uri(s, p, "Back to worker view", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, 0, "", l); } jk_puts(s, "]  "); jk_puts(s, "\n"); if (!w->read_only) { jk_puts(s, "["); if (read_only) { status_write_uri(s, p, "Read/Write", 0, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, JK_STATUS_ARG_OPTION_READ_ONLY, NULL, l); } else { status_write_uri(s, p, "Read Only", 0, JK_STATUS_MIME_UNKNOWN, NULL, NULL, JK_STATUS_ARG_OPTION_READ_ONLY, 0, NULL, l); } jk_puts(s, "]  \n"); } jk_puts(s, "\n"); jk_puts(s, "["); status_write_uri(s, p, "Dump", JK_STATUS_CMD_DUMP, JK_STATUS_MIME_UNKNOWN, NULL, NULL, 0, 0, NULL, l); jk_puts(s, "]  \n"); jk_puts(s, "\n"); jk_puts(s, "["); if (cmd == JK_STATUS_CMD_LIST) { jk_puts(s, "S=Show only this worker, "); } jk_puts(s, "E=Edit worker, R=Reset worker state, T=Try worker recovery"); jk_puts(s, "]
\n"); jk_puts(s, "
\n"); if (cmd == JK_STATUS_CMD_LIST) { /* Step 2: Display configuration */ if (list_workers(s, p, l) != JK_TRUE) { err = "Error in listing the workers."; } } else if (cmd == JK_STATUS_CMD_SHOW) { /* Step 2: Display detailed configuration */ if (show_worker(s, p, l) != JK_TRUE) { err = "Error in showing this worker."; } } else if (cmd == JK_STATUS_CMD_EDIT) { /* Step 2: Display edit form */ if (edit_worker(s, p, l) != JK_TRUE) { err = "Error in generating this worker's configuration form."; } } } if (cmd == JK_STATUS_CMD_DUMP) { if (dump_config(s, p, mime, l) == JK_FALSE) { err = "Dumping configuration failed"; } } if (cmd_props & JK_STATUS_CMD_PROP_LEGEND) { display_legend(s, p, l); } } } if (err) { jk_log(l, JK_LOG_WARNING, "Status worker '%s': %s", w->name, err); if (mime == JK_STATUS_MIME_HTML) { jk_putv(s, "

Result: ERROR - ", err, "
", NULL); jk_putv(s, "req_uri, "\">JK Status Manager Start Page

", NULL); } else if (mime == JK_STATUS_MIME_XML) { jk_print_xml_start_elt(s, l, w, 2, 0, "result"); jk_print_xml_att_string(s, l, 4, "type", "ERROR"); jk_print_xml_att_string(s, l, 4, "message", err); jk_print_xml_stop_elt(s, l, 2, 1); } else if (mime == JK_STATUS_MIME_TXT) { jk_puts(s, "Result:"); jk_printf(s, l, " type=%s", "ERROR"); jk_printf(s, l, " message=\"%s\"", err); jk_puts(s, "\n"); } else { jk_print_prop_att_string(s, l, w, "result", "type", "ERROR"); jk_print_prop_att_string(s, l, w, "result", "message", err); } } else { if (mime == JK_STATUS_MIME_HTML) { jk_putv(s, "

req_uri, "\">JK Status Manager Start Page

", NULL); } else if (mime == JK_STATUS_MIME_XML) { jk_print_xml_start_elt(s, l, w, 2, 0, "result"); jk_print_xml_att_string(s, l, 4, "type", "OK"); jk_print_xml_att_string(s, l, 4, "message", "Action finished"); jk_print_xml_stop_elt(s, l, 2, 1); } else if (mime == JK_STATUS_MIME_TXT) { jk_puts(s, "Result:"); jk_printf(s, l, " type=%s", "OK"); jk_printf(s, l, " message=\"%s\"", "Action finished"); jk_puts(s, "\n"); } else { jk_print_prop_att_string(s, l, w, "result", "type", "OK"); jk_print_prop_att_string(s, l, w, "result", "message", "Action finished"); } } if (mime == JK_STATUS_MIME_HTML) { if (w->css) { jk_putv(s, "
", JK_STATUS_COPYRIGHT, "
\n", NULL); } else { jk_putv(s, "

", JK_STATUS_COPYRIGHT, "

\n", NULL); } jk_puts(s, JK_STATUS_BEND); } else if (mime == JK_STATUS_MIME_XML) { jk_print_xml_close_elt(s, l, w, 0, "status"); } JK_TRACE_EXIT(l); return JK_TRUE; } static int JK_METHOD done(jk_endpoint_t **e, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (e && *e && (*e)->endpoint_private) { status_endpoint_t *p = (*e)->endpoint_private; jk_map_free(&(p->req_params)); free(p); *e = NULL; JK_TRACE_EXIT(l); return JK_TRUE; } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } static int JK_METHOD validate(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && pThis->worker_private) { JK_TRACE_EXIT(l); return JK_TRUE; } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } static int JK_METHOD init(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && pThis->worker_private) { status_worker_t *p = pThis->worker_private; char **good_rating; unsigned int num_of_good; char **bad_rating; unsigned int num_of_bad; unsigned int i; p->we = we; p->css = jk_get_worker_style_sheet(props, p->name, NULL); p->prefix = jk_get_worker_prop_prefix(props, p->name, JK_STATUS_PREFIX_DEF); p->ns = jk_get_worker_name_space(props, p->name, JK_STATUS_NS_DEF); p->xmlns = jk_get_worker_xmlns(props, p->name, JK_STATUS_XMLNS_DEF); p->doctype = jk_get_worker_xml_doctype(props, p->name, NULL); p->read_only = jk_get_is_read_only(props, p->name); p->user_case_insensitive = jk_get_worker_user_case_insensitive(props, p->name); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' is %s and has css '%s', prefix '%s', name space '%s', xml name space '%s', document type '%s'", p->name, p->read_only ? "read-only" : "read/write", p->css ? p->css : "(null)", p->prefix ? p->prefix : "(null)", p->ns ? p->ns : "(null)", p->xmlns ? p->xmlns : "(null)", p->doctype ? p->doctype : "(null)"); if (jk_get_worker_user_list(props, p->name, &(p->user_names), &(p->num_of_users)) && p->num_of_users) { for (i = 0; i < p->num_of_users; i++) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' restricting access to user '%s' case %s", p->name, p->user_names[i], p->user_case_insensitive ? "insensitive" : "sensitive"); } } if (jk_get_worker_good_rating(props, p->name, &good_rating, &num_of_good) && num_of_good) { p->good_mask = 0; for (i = 0; i < num_of_good; i++) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' rating as good: '%s'", p->name, good_rating[i]); p->good_mask |= status_get_rating(good_rating[i], l); } } else { p->good_mask = JK_STATUS_MASK_GOOD_DEF; } if (jk_get_worker_bad_rating(props, p->name, &bad_rating, &num_of_bad) && num_of_bad) { p->bad_mask = 0; for (i = 0; i < num_of_bad; i++) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' rating as bad: '%s'", p->name, bad_rating[i]); p->bad_mask |= status_get_rating(bad_rating[i], l); } } else { p->bad_mask = JK_STATUS_MASK_BAD_DEF; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Status worker '%s' has good rating for '%08" JK_UINT32_T_HEX_FMT "' and bad rating for '%08" JK_UINT32_T_HEX_FMT "'", p->name, p->good_mask, p->bad_mask); if (p->good_mask & p->bad_mask) jk_log(l, JK_LOG_WARNING, "Status worker '%s' has non empty intersection '%08" JK_UINT32_T_HEX_FMT "' between good rating for '%08" JK_UINT32_T_HEX_FMT "' and bad rating for '%08" JK_UINT32_T_HEX_FMT "'", p->name, p->good_mask & p->bad_mask, p->good_mask, p->bad_mask); } JK_TRACE_EXIT(l); return JK_TRUE; } static int JK_METHOD get_endpoint(jk_worker_t *pThis, jk_endpoint_t **pend, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && pThis->worker_private && pend) { status_endpoint_t *p = (status_endpoint_t *) malloc(sizeof(status_endpoint_t)); p->worker = pThis->worker_private; p->endpoint.endpoint_private = p; p->endpoint.service = service; p->endpoint.done = done; p->req_params = NULL; p->msg = NULL; *pend = &p->endpoint; JK_TRACE_EXIT(l); return JK_TRUE; } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return JK_FALSE; } static int JK_METHOD destroy(jk_worker_t **pThis, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && *pThis && (*pThis)->worker_private) { status_worker_t *private_data = (*pThis)->worker_private; jk_close_pool(&private_data->p); free(private_data); JK_TRACE_EXIT(l); return JK_TRUE; } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } int JK_METHOD status_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (NULL != name && NULL != w) { status_worker_t *private_data = (status_worker_t *) calloc(1, sizeof(status_worker_t)); jk_open_pool(&private_data->p, private_data->buf, sizeof(jk_pool_atom_t) * TINY_POOL_SIZE); private_data->name = name; private_data->worker.worker_private = private_data; private_data->worker.validate = validate; private_data->worker.init = init; private_data->worker.get_endpoint = get_endpoint; private_data->worker.destroy = destroy; *w = &private_data->worker; JK_TRACE_EXIT(l); return JK_STATUS_WORKER_TYPE; } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return 0; } tomcat-connectors-1.2.50-src/native/common/.gitignore0000644000000000000020000000014214655113617021067 0ustar rootbin*.o *.lo *.slo .libs Makefile stamp-h.in list.mk stamp-h config.h.in config.h stamp-h1 jk_types.h tomcat-connectors-1.2.50-src/native/common/jk_context.h0000644000000000000020000000556614655113617021437 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Context Stuff (Autoconf) * * Author: Henri Gomez * ***************************************************************************/ #ifndef JK_CONTEXT_H #define JK_CONTEXT_H #include "jk_pool.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define CBASE_INC_SIZE (8) /* Allocate memory by step of 8 URIs : ie 8 URI by context */ #define URI_INC_SIZE (8) /* Allocate memory by step of 8 CONTEXTs : ie 8 contexts by worker */ typedef struct { /* * Context base (ie examples) */ char *cbase; /* * Status (Up/Down) */ int status; /* * Num of URI handled */ int size; /* * Capacity */ int capacity; /* * URL/URIs (autoconf) */ char **uris; } jk_context_item_t; typedef struct { /* * Memory Pool */ jk_pool_t p; jk_pool_atom_t buf[SMALL_POOL_SIZE]; /* * Virtual Server (if use) */ char *virt; /* * Num of context handled (ie: examples, admin...) */ int size; /* * Capacity */ int capacity; /* * Context list, context / URIs */ jk_context_item_t **contexts; } jk_context_t; /* * functions defined here */ int context_set_virtual(jk_context_t *c, char *virt); int context_open(jk_context_t *c, char *virt); int context_close(jk_context_t *c); int context_alloc(jk_context_t **c, char *virt); int context_free(jk_context_t **c); jk_context_item_t *context_find_base(jk_context_t *c, char *cbase); char *context_item_find_uri(jk_context_item_t *ci, char *uri); void context_dump_uris(jk_context_t *c, char *cbase, FILE * f); jk_context_item_t *context_add_base(jk_context_t *c, char *cbase); int context_add_uri(jk_context_t *c, char *cbase, char *uri); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_CONTEXT_H */ tomcat-connectors-1.2.50-src/native/common/jk_worker_list.h0000644000000000000020000000605114655113617022305 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Worker list * * Author: Gal Shachor * * Author: Henri Gomez * ***************************************************************************/ /* * This file includes a list of all the possible workers in the jk library * plus their factories. * * If you want to add a worker just place it in the worker_factories array * with its unique name and factory. * * If you want to remove a worker, hjust comment out its line in the * worker_factories array as well as its header file. For example, look * at what we have done to the ajp23 worker. * * Note: This file should be included only in the jk_worker controller. * Currently the jk_worker controller is located in jk_worker.c */ #ifdef _PLACE_WORKER_LIST_HERE #ifndef _JK_WORKER_LIST_H #define _JK_WORKER_LIST_H #include "jk_ajp12_worker.h" #include "jk_ajp13_worker.h" #include "jk_ajp14_worker.h" #include "jk_lb_worker.h" #include "jk_status.h" struct worker_factory_record { const char *name; int type; worker_factory fac; }; typedef struct worker_factory_record worker_factory_record_t; static worker_factory_record_t worker_factories[] = { /* * AJPv12 worker, this is the stable worker. */ {JK_AJP12_WORKER_NAME, JK_AJP12_WORKER_TYPE, ajp12_worker_factory}, /* * AJPv13 worker, fast bi-directional worker. */ {JK_AJP13_WORKER_NAME, JK_AJP13_WORKER_TYPE, ajp13_worker_factory}, /* * AJPv14 worker, next generation fast bi-directional worker. */ {JK_AJP14_WORKER_NAME, JK_AJP14_WORKER_TYPE, ajp14_worker_factory}, /* * Load balancing worker. Performs round robin with sticky * session load balancing. */ {JK_LB_WORKER_NAME, JK_LB_WORKER_TYPE, lb_worker_factory}, /* * Status worker. Performs display display and * worker management. */ {JK_STATUS_WORKER_NAME, JK_STATUS_WORKER_TYPE, status_worker_factory}, /* * Marks the end of the worker factory list. */ {NULL, 0, NULL} }; #endif /* _JK_WORKER_LIST_H */ #endif /* _PLACE_WORKER_LIST_HERE */ tomcat-connectors-1.2.50-src/native/common/jk_ajp12_worker.h0000644000000000000020000000315414655113617022250 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: ajpv1.2 worker header file * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_AJP12_WORKER_H #define JK_AJP12_WORKER_H #include "jk_logger.h" #include "jk_service.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define JK_AJP12_WORKER_NAME ("ajp12") #define JK_AJP12_WORKER_TYPE (1) int JK_METHOD ajp12_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_AJP12_WORKER_H */ tomcat-connectors-1.2.50-src/native/common/jk_map.h0000644000000000000020000000674614655113617020531 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Map object header file * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_MAP_H #define JK_MAP_H #include "jk_pool.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define JK_MAP_HANDLE_NORMAL 0 #define JK_MAP_HANDLE_DUPLICATES 1 #define JK_MAP_HANDLE_RAW 2 struct jk_map { jk_pool_t p; jk_pool_atom_t buf[SMALL_POOL_SIZE]; const char **names; const void **values; unsigned int *keys; unsigned int capacity; unsigned int size; int id; }; typedef struct jk_map jk_map_t; int jk_map_alloc(jk_map_t **m); int jk_map_free(jk_map_t **m); int jk_map_open(jk_map_t *m); int jk_map_close(jk_map_t *m); void *jk_map_get(jk_map_t *m, const char *name, const void *def); int jk_map_get_id(jk_map_t *m, const char *name); int jk_map_get_int(jk_map_t *m, const char *name, int def); double jk_map_get_double(jk_map_t *m, const char *name, double def); int jk_map_get_bool(jk_map_t *m, const char *name, int def); const char *jk_map_get_string(jk_map_t *m, const char *name, const char *def); char **jk_map_get_string_list(jk_map_t *m, const char *name, unsigned *list_len, const char *def); int *jk_map_get_int_list(jk_map_t *m, const char *name, unsigned int *list_len, const char *def); int jk_map_add(jk_map_t *m, const char *name, const void *value); int jk_map_put(jk_map_t *m, const char *name, const void *value, void **old); int jk_map_read_property(jk_map_t *m, jk_map_t *env, const char *str, int treatment, jk_log_context_t *log_ctx); int jk_map_read_properties(jk_map_t *m, jk_map_t *env, const char *f, time_t *modified, int treatment, jk_log_context_t *log_ctx); int jk_map_size(jk_map_t *m); const char *jk_map_name_at(jk_map_t *m, int idex); void *jk_map_value_at(jk_map_t *m, int idex); void jk_map_dump(jk_map_t *m, jk_log_context_t *log_ctx); int jk_map_copy(jk_map_t *src, jk_map_t *dst); int jk_map_resolve_references(jk_map_t *m, const char *prefix, int wildcard, int depth, jk_log_context_t *log_ctx); int jk_map_inherit_properties(jk_map_t *m, const char *from, const char *to, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_MAP_H */ tomcat-connectors-1.2.50-src/native/common/jk_ajp12_worker.c0000644000000000000020000005605314655113617022251 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: ajpv1.2 worker, used to call local or remote jserv hosts * * This worker is deprecated * * Author: Gal Shachor * * Based on: jserv_ajpv12.c from Jserv * ***************************************************************************/ #include "jk_ajp12_worker.h" #include "jk_pool.h" #include "jk_connect.h" #include "jk_util.h" #include "jk_sockbuf.h" #if defined(AS400) && !defined(AS400_UTF8) #include "util_ebcdic.h" #include #endif #define AJP_DEF_HOST ("localhost") #define AJP_DEF_PORT (8007) #define READ_BUF_SIZE (8*1024) #define DEF_RETRY_ATTEMPTS (1) struct ajp12_worker { jk_sockaddr_t worker_inet_addr; jk_sockaddr_t worker_source_inet_addr; unsigned connect_retry_attempts; char *name; jk_worker_t worker; }; typedef struct ajp12_worker ajp12_worker_t; struct ajp12_endpoint { ajp12_worker_t *worker; jk_sock_t sd; jk_sockbuf_t sb; jk_endpoint_t endpoint; }; typedef struct ajp12_endpoint ajp12_endpoint_t; static int ajpv12_mark(ajp12_endpoint_t * p, unsigned char type); #if defined(AS400) && !defined(AS400_UTF8) static int ajpv12_sendasciistring(ajp12_endpoint_t * p, char *buffer); #endif #if defined(AS400) && !defined(AS400_UTF8) static int ajpv12_sendstring(ajp12_endpoint_t * p, char *buffer); #else static int ajpv12_sendstring(ajp12_endpoint_t * p, const char *buffer); #endif static int ajpv12_sendint(ajp12_endpoint_t * p, int d); static int ajpv12_sendnbytes(ajp12_endpoint_t * p, const void *buffer, int bufferlen); static int ajpv12_flush(ajp12_endpoint_t * p); static int ajpv12_handle_response(ajp12_endpoint_t * p, jk_ws_service_t *s, jk_log_context_t *l); static int ajpv12_handle_request(ajp12_endpoint_t * p, jk_ws_service_t *s, jk_log_context_t *l); /* * Return values of service() method for ajp12 worker: * return value is_error reason * JK_FALSE JK_HTTP_SERVER_ERROR Invalid parameters (null values) * Error during connect to the backend * ajpv12_handle_request() returns false: * Any error during reading a request body from the client or * sending the request to the backend * JK_FALSE JK_HTTP_OK ajpv12_handle_response() returns false: * Any error during reading parts of response from backend or * sending to client * JK_TRUE JK_HTTP_OK All other cases */ static int JK_METHOD service(jk_endpoint_t *e, jk_ws_service_t *s, jk_log_context_t *l, int *is_error) { ajp12_endpoint_t *p; unsigned int attempt; int rc = -1; /* * AJP12 protocol is not recoverable. */ JK_TRACE_ENTER(l); if (!e || !e->endpoint_private || !s || !is_error) { JK_LOG_NULL_PARAMS(l); if (is_error) *is_error = JK_HTTP_SERVER_ERROR; JK_TRACE_EXIT(l); return JK_FALSE; } p = e->endpoint_private; /* Set returned error to OK */ *is_error = JK_HTTP_OK; for (attempt = 0; attempt < p->worker->connect_retry_attempts; attempt++) { p->sd = jk_open_socket(&p->worker->worker_inet_addr, p->worker->worker_source_inet_addr.ipaddr_ptr != NULL ? &p->worker->worker_source_inet_addr : NULL, JK_FALSE, 0, 0, 0, l); jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, sd = %d", p->sd); if (IS_VALID_SOCKET(p->sd)) { break; } } if (IS_VALID_SOCKET(p->sd)) { jk_sb_open(&p->sb, p->sd); if (ajpv12_handle_request(p, s, l)) { jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, sent request"); rc = ajpv12_handle_response(p, s, l); JK_TRACE_EXIT(l); return rc; } } jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, Error sd = %d", p->sd); *is_error = JK_HTTP_SERVER_ERROR; JK_TRACE_EXIT(l); return JK_FALSE; } static int JK_METHOD done(jk_endpoint_t **e, jk_log_context_t *l) { jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::done"); if (e && *e && (*e)->endpoint_private) { ajp12_endpoint_t *p = (*e)->endpoint_private; if (IS_VALID_SOCKET(p->sd)) { jk_shutdown_socket(p->sd, l); } free(p); *e = NULL; return JK_TRUE; } jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::done, NULL parameters"); return JK_FALSE; } static int JK_METHOD validate(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::validate"); if (pThis && pThis->worker_private) { ajp12_worker_t *p = pThis->worker_private; int port = jk_get_worker_port(props, p->name, AJP_DEF_PORT); const char *host = jk_get_worker_host(props, p->name, AJP_DEF_HOST); const char *source = jk_get_worker_host(props, p->name, ""); jk_log(l, JK_LOG_DEBUG, "In jk_worker_t::validate for worker %s target is %s:%d", p->name, host, port); if (host) { if (!jk_resolve(host, port, &p->worker_inet_addr, we->pool, JK_FALSE, l)) { jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, host '%s:%d' resolve failed", host, port); return JK_FALSE; } } else { jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, Error no host name given"); return JK_FALSE; } if (source && *source) { if (!jk_resolve(source, 0, &p->worker_source_inet_addr, we->pool, JK_FALSE, l)) { p->worker_source_inet_addr.ipaddr_ptr = NULL; jk_log(l, JK_LOG_WARNING, "In jk_worker_t::validate, source addr '%s' resolve failed" " - ignored", source); } } return JK_TRUE; } else { jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, NULL parameters"); } return JK_FALSE; } static int JK_METHOD init(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { /* Nothing to do for now */ return JK_TRUE; } static int JK_METHOD get_endpoint(jk_worker_t *pThis, jk_endpoint_t **pend, jk_log_context_t *l) { jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::get_endpoint"); if (pThis && pThis->worker_private && pend) { ajp12_endpoint_t *p = (ajp12_endpoint_t *) malloc(sizeof(ajp12_endpoint_t)); if (p) { p->sd = JK_INVALID_SOCKET; p->worker = pThis->worker_private; p->endpoint.endpoint_private = p; p->endpoint.service = service; p->endpoint.done = done; *pend = &p->endpoint; return JK_TRUE; } jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, malloc failed"); } else { jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, NULL parameters"); } return JK_FALSE; } static int JK_METHOD destroy(jk_worker_t **pThis, jk_log_context_t *l) { jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::destroy"); if (pThis && *pThis && (*pThis)->worker_private) { ajp12_worker_t *private_data = (*pThis)->worker_private; free(private_data->name); free(private_data); return JK_TRUE; } jk_log(l, JK_LOG_ERROR, "In jk_worker_t::destroy, NULL parameters"); return JK_FALSE; } int JK_METHOD ajp12_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *l) { jk_log(l, JK_LOG_DEBUG, "Into ajp12_worker_factory"); if (NULL != name && NULL != w) { ajp12_worker_t *private_data = (ajp12_worker_t *) malloc(sizeof(ajp12_worker_t)); if (private_data) { private_data->name = strdup(name); if (private_data->name) { private_data->connect_retry_attempts = DEF_RETRY_ATTEMPTS; private_data->worker.worker_private = private_data; private_data->worker.validate = validate; private_data->worker.init = init; private_data->worker.get_endpoint = get_endpoint; private_data->worker.destroy = destroy; private_data->worker.maintain = NULL; *w = &private_data->worker; return JK_AJP12_WORKER_TYPE; } free(private_data); } jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, malloc failed"); } else { jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, NULL parameters"); } return 0; } static int ajpv12_sendnbytes(ajp12_endpoint_t * p, const void *buffer, int bufferlen) { unsigned char bytes[2]; static const unsigned char null_b[2] = { (unsigned char)0xff, (unsigned char)0xff }; if (buffer) { bytes[0] = (unsigned char)((bufferlen >> 8) & 0xff); bytes[1] = (unsigned char)(bufferlen & 0xff); if (jk_sb_write(&p->sb, bytes, 2)) { return jk_sb_write(&p->sb, buffer, bufferlen); } else { return JK_FALSE; } } else { return jk_sb_write(&p->sb, null_b, 2); } } #if defined(AS400) && !defined(AS400_UTF8) static int ajpv12_sendasciistring(ajp12_endpoint_t * p, const char *buffer) { int bufferlen; if (buffer && (bufferlen = strlen(buffer))) { return ajpv12_sendnbytes(p, buffer, bufferlen); } else { return ajpv12_sendnbytes(p, NULL, 0); } } #endif static int ajpv12_sendstring(ajp12_endpoint_t * p, const char *buffer) { int bufferlen; if (buffer && (bufferlen = (int)strlen(buffer))) { #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) char buf[2048]; if (bufferlen < 2048) { memcpy(buf, buffer, bufferlen); jk_xlate_to_ascii(buf, bufferlen); return ajpv12_sendnbytes(p, buf, bufferlen); } else return -1; #else return ajpv12_sendnbytes(p, buffer, bufferlen); #endif } else { return ajpv12_sendnbytes(p, NULL, 0); } } static int ajpv12_mark(ajp12_endpoint_t * p, unsigned char type) { if (jk_sb_write(&p->sb, &type, 1)) { return JK_TRUE; } else { return JK_FALSE; } } static int ajpv12_sendint(ajp12_endpoint_t * p, int d) { char buf[20]; sprintf(buf, "%d", d); return ajpv12_sendstring(p, buf); } static int ajpv12_flush(ajp12_endpoint_t * p) { return jk_sb_flush(&p->sb); } static int ajpv12_handle_request(ajp12_endpoint_t * p, jk_ws_service_t *s, jk_log_context_t *l) { int ret; jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_request"); /* * Start the ajp 12 service sequence */ jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the ajp12 start sequence"); ret = (ajpv12_mark(p, 1) && ajpv12_sendstring(p, s->method) && ajpv12_sendstring(p, 0) && /* zone */ ajpv12_sendstring(p, 0) && /* servlet */ ajpv12_sendstring(p, s->server_name) && ajpv12_sendstring(p, 0) && /* doc root */ ajpv12_sendstring(p, 0) && /* path info */ ajpv12_sendstring(p, 0) && /* path translated */ #if defined(AS400) && !defined(AS400_UTF8) ajpv12_sendasciistring(p, s->query_string) && #else ajpv12_sendstring(p, s->query_string) && #endif ajpv12_sendstring(p, s->remote_addr) && ajpv12_sendstring(p, s->remote_host) && ajpv12_sendstring(p, s->remote_user) && ajpv12_sendstring(p, s->auth_type) && ajpv12_sendint(p, s->server_port) && #if defined(AS400) && !defined(AS400_UTF8) ajpv12_sendasciistring(p, s->method) && #else ajpv12_sendstring(p, s->method) && #endif ajpv12_sendstring(p, s->req_uri) && ajpv12_sendstring(p, 0) && ajpv12_sendstring(p, 0) && /* SCRIPT_NAME */ #if defined(AS400) && !defined(AS400_UTF8) ajpv12_sendasciistring(p, s->server_name) && #else ajpv12_sendstring(p, s->server_name) && #endif ajpv12_sendint(p, s->server_port) && ajpv12_sendstring(p, s->protocol) && ajpv12_sendstring(p, 0) && /* SERVER_SIGNATURE */ ajpv12_sendstring(p, s->server_software) && ajpv12_sendstring(p, s->route) && /* JSERV_ROUTE */ ajpv12_sendstring(p, "") && /* JSERV ajpv12 compatibility */ ajpv12_sendstring(p, "")); /* JSERV ajpv12 compatibility */ if (!ret) { jk_log(l, JK_LOG_ERROR, "In ajpv12_handle_request, " "failed to send the ajp12 start sequence"); return JK_FALSE; } if (s->num_attributes > 0) { unsigned i; jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the environment variables"); for (i = 0; i < s->num_attributes; i++) { ret = (ajpv12_mark(p, 5) && ajpv12_sendstring(p, s->attributes_names[i]) && ajpv12_sendstring(p, s->attributes_values[i])); if (!ret) { jk_log(l, JK_LOG_ERROR, "In ajpv12_handle_request, failed to send environment"); return JK_FALSE; } } } jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the headers"); /* Send the request headers */ if (s->num_headers) { unsigned i; for (i = 0; i < s->num_headers; ++i) { ret = (ajpv12_mark(p, 3) && ajpv12_sendstring(p, s->headers_names[i]) && ajpv12_sendstring(p, s->headers_values[i])); if (!ret) { jk_log(l, JK_LOG_ERROR, "In ajpv12_handle_request, failed to send headers"); return JK_FALSE; } } } jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the terminating mark"); ret = (ajpv12_mark(p, 4) && ajpv12_flush(p)); if (!ret) { jk_log(l, JK_LOG_ERROR, "In ajpv12_handle_request, failed to send the terminating mark"); return JK_FALSE; } if (s->content_length) { char buf[READ_BUF_SIZE]; jk_uint64_t so_far = 0; jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the request body"); while (so_far < s->content_length) { unsigned this_time = 0; unsigned to_read; if (s->content_length > so_far + READ_BUF_SIZE) { to_read = READ_BUF_SIZE; } else { to_read = (unsigned int)(s->content_length - so_far); } if (!s->read(s, buf, to_read, &this_time)) { jk_log(l, JK_LOG_ERROR, "In ajpv12_handle_request, " "failed to read from the web server"); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, read %d bytes", this_time); if (this_time > 0) { so_far += this_time; if ((int)this_time != send(p->sd, buf, this_time, 0)) { jk_log(l, JK_LOG_ERROR, "In ajpv12_handle_request, " "failed to write to the container"); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sent %d bytes", this_time); } else if (this_time == 0) { jk_log(l, JK_LOG_ERROR, "In ajpv12_handle_request, Error: short read. " "Content length is %" JK_UINT64_T_FMT ", read %" JK_UINT64_T_FMT, s->content_length, so_far); return JK_FALSE; } } } jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request done"); return JK_TRUE; } static int ajpv12_handle_response(ajp12_endpoint_t * p, jk_ws_service_t *s, jk_log_context_t *l) { int status = 200; char *reason = NULL; char **names = NULL; char **values = NULL; int headers_capacity = 0; int headers_len = 0; int write_to_ws; jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_response"); /* * Read headers ... */ while (1) { char *line = NULL; char *name = NULL; char *value = NULL; #ifdef _MT_CODE_PTHREAD char *lasts; #endif if (!jk_sb_gets(&p->sb, &line)) { jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, error reading header line"); return JK_FALSE; } #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) jk_xlate_from_ascii(line, strlen(line)); #endif jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s", line); if (0 == strlen(line)) { jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, headers are done"); break; /* Empty line -> end of headers */ } name = line; while (jk_isspace(*name) && *name) { name++; /* Skip leading white chars */ } if (!*name) { /* Empty header name */ jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, empty header name"); return JK_FALSE; } if (!(value = strchr(name, ':'))) { jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, no value supplied"); return JK_FALSE; /* No value !!! */ } *value = '\0'; value++; while (jk_isspace(*value) && *value) { value++; /* Skip leading white chars */ } if (!*value) { /* Empty header value */ jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, empty header value"); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s=%s", name, value); if (0 == strcmp("Status", name)) { #ifdef _MT_CODE_PTHREAD char *numeric = strtok_r(value, " \t", &lasts); #else char *numeric = strtok(value, " \t"); #endif status = atoi(numeric); if (status < 100 || status > 999) { jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, invalid status code"); return JK_FALSE; } #ifdef _MT_CODE_PTHREAD reason = jk_pool_strdup(s->pool, strtok_r(NULL, " \t", &lasts)); #else reason = jk_pool_strdup(s->pool, strtok(NULL, " \t")); #endif } else { if (headers_capacity == headers_len) { jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, allocating header arrays"); names = (char **)jk_pool_realloc(s->pool, sizeof(char *) * (headers_capacity + 5), names, sizeof(char *) * headers_capacity); values = (char **)jk_pool_realloc(s->pool, sizeof(char *) * (headers_capacity + 5), values, sizeof(char *) * headers_capacity); if (!values || !names) { jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, malloc error"); return JK_FALSE; } headers_capacity = headers_capacity + 5; } names[headers_len] = jk_pool_strdup(s->pool, name); values[headers_len] = jk_pool_strdup(s->pool, value); headers_len++; } } jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, starting response"); if (!s->start_response(s, status, reason, (const char *const *)names, (const char *const *)values, headers_len)) { jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, error starting response"); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, reading response body"); /* * Read response body */ write_to_ws = JK_TRUE; while (1) { unsigned to_read = READ_BUF_SIZE; unsigned acc = 0; char *buf = NULL; if (!jk_sb_read(&p->sb, &buf, to_read, &acc)) { jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, error reading from "); return JK_FALSE; } if (!acc) { jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, response body is done"); break; } if (write_to_ws) { if (!s->write(s, buf, acc)) { jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, error writing back to server"); write_to_ws = JK_FALSE; } } } jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response done"); return JK_TRUE; } tomcat-connectors-1.2.50-src/native/common/.indent.pro0000644000000000000020000000050114655113617021157 0ustar rootbin-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 -nut -ncs -Tjk_env_t -Tjk_worker_t -Tjk_worker_env_t -Tjk_endpoint_t -Tjk_channel_t -Tjk_sockbuf_t -Tjk_msg_t -Tjk_msg_buf_t -Tjk_map_t -Tjk_uri_worker_map_t -Tjk_pool_t -Tjk_pool_atom_t -Tjk_logger_t -Tjk_ws_service_t -Tjk_context_item_t -Tjk_context_t -Tjk_login_service_t tomcat-connectors-1.2.50-src/native/common/jk_ajp_common.c0000644000000000000020000040371414655113617022065 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: common stuff for bi-directional protocols ajp13/ajp14. * * Author: Gal Shachor * * Author: Henri Gomez * ***************************************************************************/ #include "jk_global.h" #include "jk_util.h" #include "jk_ajp13.h" #include "jk_ajp14.h" #include "jk_ajp_common.h" #include "jk_connect.h" #if defined(AS400) && !defined(AS400_UTF8) #include "util_ebcdic.h" #endif /* Macro for checking the availability of the cache slot */ #define IS_SLOT_AVAIL(s) ((s) != NULL && (s)->avail) const char *response_trans_headers[] = { "Content-Type", "Content-Language", "Content-Length", "Date", "Last-Modified", "Location", "Set-Cookie", "Set-Cookie2", "Servlet-Engine", "Status", "WWW-Authenticate" }; static const char *long_res_header_for_sc(int sc) { const char *rc = NULL; sc = sc & 0X00FF; if (sc <= SC_RES_HEADERS_NUM && sc > 0) { rc = response_trans_headers[sc - 1]; } return rc; } static const char *ajp_state_type[] = { JK_AJP_STATE_TEXT_IDLE, JK_AJP_STATE_TEXT_OK, JK_AJP_STATE_TEXT_ERROR, JK_AJP_STATE_TEXT_PROBE, "unknown", NULL }; static char ajp_cping_mode[] = { AJP_CPING_CONNECT_TEXT, AJP_CPING_PREPOST_TEXT, AJP_CPING_INTERVAL_TEXT, }; #define UNKNOWN_METHOD (-1) static int sc_for_req_method(const char *method, size_t len) { /* Note: the following code was generated by the "shilka" tool from the "cocom" parsing/compilation toolkit. It is an optimized lookup based on analysis of the input keywords. Postprocessing was done on the shilka output, but the basic structure and analysis is from there. Should new HTTP methods be added, then manual insertion into this code is fine, or simply re-running the shilka tool on the appropriate input. */ /* Note: it is also quite reasonable to just use our method_registry, but I'm assuming (probably incorrectly) we want more speed here (based on the optimizations the previous code was doing). */ switch (len) { case 3: switch (method[0]) { case 'A': return (method[1] == 'C' && method[2] == 'L' ? SC_M_ACL : UNKNOWN_METHOD); case 'P': return (method[1] == 'U' && method[2] == 'T' ? SC_M_PUT : UNKNOWN_METHOD); case 'G': return (method[1] == 'E' && method[2] == 'T' ? SC_M_GET : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 4: switch (method[0]) { case 'H': return (method[1] == 'E' && method[2] == 'A' && method[3] == 'D' ? SC_M_HEAD : UNKNOWN_METHOD); case 'P': return (method[1] == 'O' && method[2] == 'S' && method[3] == 'T' ? SC_M_POST : UNKNOWN_METHOD); case 'M': return (method[1] == 'O' && method[2] == 'V' && method[3] == 'E' ? SC_M_MOVE : UNKNOWN_METHOD); case 'L': return (method[1] == 'O' && method[2] == 'C' && method[3] == 'K' ? SC_M_LOCK : UNKNOWN_METHOD); case 'C': return (method[1] == 'O' && method[2] == 'P' && method[3] == 'Y' ? SC_M_COPY : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 5: switch (method[2]) { case 'R': return (memcmp(method, "MERGE", 5) == 0 ? SC_M_MERGE : UNKNOWN_METHOD); case 'C': return (memcmp(method, "MKCOL", 5) == 0 ? SC_M_MKCOL : UNKNOWN_METHOD); case 'B': return (memcmp(method, "LABEL", 5) == 0 ? SC_M_LABEL : UNKNOWN_METHOD); case 'A': return (memcmp(method, "TRACE", 5) == 0 ? SC_M_TRACE : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 6: switch (method[0]) { case 'U': switch (method[5]) { case 'K': return (memcmp(method, "UNLOCK", 6) == 0 ? SC_M_UNLOCK : UNKNOWN_METHOD); case 'E': return (memcmp(method, "UPDATE", 6) == 0 ? SC_M_UPDATE : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 'R': return (memcmp(method, "REPORT", 6) == 0 ? SC_M_REPORT : UNKNOWN_METHOD); case 'S': return (memcmp(method, "SEARCH", 6) == 0 ? SC_M_SEARCH : UNKNOWN_METHOD); case 'D': return (memcmp(method, "DELETE", 6) == 0 ? SC_M_DELETE : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 7: switch (method[1]) { case 'P': return (memcmp(method, "OPTIONS", 7) == 0 ? SC_M_OPTIONS : UNKNOWN_METHOD); case 'H': return (memcmp(method, "CHECKIN", 7) == 0 ? SC_M_CHECKIN : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 8: switch (method[0]) { case 'P': return (memcmp(method, "PROPFIND", 8) == 0 ? SC_M_PROPFIND : UNKNOWN_METHOD); case 'C': return (memcmp(method, "CHECKOUT", 8) == 0 ? SC_M_CHECKOUT : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 9: return (memcmp(method, "PROPPATCH", 9) == 0 ? SC_M_PROPPATCH : UNKNOWN_METHOD); case 10: switch (method[0]) { case 'U': return (memcmp(method, "UNCHECKOUT", 10) == 0 ? SC_M_UNCHECKOUT : UNKNOWN_METHOD); case 'M': return (memcmp(method, "MKACTIVITY", 10) == 0 ? SC_M_MKACTIVITY : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 11: return (memcmp(method, "MKWORKSPACE", 11) == 0 ? SC_M_MKWORKSPACE : UNKNOWN_METHOD); case 15: return (memcmp(method, "VERSION-CONTROL", 15) == 0 ? SC_M_VERSION_CONTROL : UNKNOWN_METHOD); case 16: return (memcmp(method, "BASELINE-CONTROL", 16) == 0 ? SC_M_BASELINE_CONTROL : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } /* NOTREACHED */ } static int sc_for_req_header(const char *header_name) { char header[16]; size_t len = strlen(header_name); const char *p = header_name; int i = 0; /* ACCEPT-LANGUAGE is the longest header * that is of interest. */ if (len < 4 || len > 15) return UNKNOWN_METHOD; while (*p) { header[i++] = toupper((unsigned char)*p); p++; } header[i] = '\0'; p = &header[1]; /* Always do memcmp including the final \0-termination character. */ switch (header[0]) { case 'A': if (memcmp(p, "CCEPT", 6) == 0) { if (!header[6]) return SC_ACCEPT; if (header[6] == '-') { p += 6; if (memcmp(p, "CHARSET", 8) == 0) return SC_ACCEPT_CHARSET; if (memcmp(p, "ENCODING", 9) == 0) return SC_ACCEPT_ENCODING; if (memcmp(p, "LANGUAGE", 9) == 0) return SC_ACCEPT_LANGUAGE; } return UNKNOWN_METHOD; } if (memcmp(p, "UTHORIZATION", 13) == 0) return SC_AUTHORIZATION; break; case 'C': if(memcmp(p, "OOKIE2", 7) == 0) return SC_COOKIE2; if (memcmp(p, "OOKIE", 6) == 0) return SC_COOKIE; if(memcmp(p, "ONNECTION", 10) == 0) return SC_CONNECTION; if(memcmp(p, "ONTENT-TYPE", 12) == 0) return SC_CONTENT_TYPE; if(memcmp(p, "ONTENT-LENGTH", 14) == 0) return SC_CONTENT_LENGTH; break; case 'H': if(memcmp(p, "OST", 4) == 0) return SC_HOST; break; case 'P': if(memcmp(p, "RAGMA", 6) == 0) return SC_PRAGMA; break; case 'R': if(memcmp(p, "EFERER", 7) == 0) return SC_REFERER; break; case 'U': if(memcmp(p, "SER-AGENT", 10) == 0) return SC_USER_AGENT; break; default: break;; } return UNKNOWN_METHOD; } /* Return the string representation of the worker state */ const char *jk_ajp_get_state(ajp_worker_t *aw, jk_log_context_t *l) { return ajp_state_type[aw->s->state]; } /* Return the int representation of the worker state */ int jk_ajp_get_state_code(const char *v) { if (!v) return JK_AJP_STATE_DEF; if (*v == 'i' || *v == 'I' || *v == 'n' || *v == 'N' || *v == '0') return JK_AJP_STATE_IDLE; if (*v == 'o' || *v == 'O' || *v == '1') return JK_AJP_STATE_OK; if (*v == 'e' || *v == 'E' || *v == '4') return JK_AJP_STATE_ERROR; if (*v == 'p' || *v == 'P' || *v == '6') return JK_AJP_STATE_PROBE; return JK_AJP_STATE_DEF; } void jk_ajp_get_cping_text(int mode, char *buf) { int bit = 1; int log2 = 0; int pos = 0; while (bit <= mode && bit <= AJP_CPING_MAX) { if (mode & bit) { buf[pos] = ajp_cping_mode[log2]; pos +=1; } bit *= 2; log2 += 1; } buf[pos] = '\0'; } int jk_ajp_get_cping_mode(const char *m, int def) { int mv = 0; if (!m) return def; while (*m != '\0') { if (*m == AJP_CPING_CONNECT_TEXT || *m == tolower(AJP_CPING_CONNECT_TEXT)) mv |= AJP_CPING_CONNECT; if (*m == AJP_CPING_PREPOST_TEXT || *m == tolower(AJP_CPING_PREPOST_TEXT)) mv |= AJP_CPING_PREPOST; if (*m == AJP_CPING_INTERVAL_TEXT || *m == tolower(AJP_CPING_INTERVAL_TEXT)) mv |= AJP_CPING_INTERVAL; if (*m == AJP_CPING_ALL_TEXT || *m == tolower(AJP_CPING_ALL_TEXT)) { mv = AJP_CPING_CONNECT | AJP_CPING_PREPOST | AJP_CPING_INTERVAL; break; } m++; } if (mv) return mv; return def; } /* * Message structure * * AJPV13_REQUEST/AJPV14_REQUEST= request_prefix (1) (byte) method (byte) protocol (string) req_uri (string) remote_addr (string) remote_host (string) server_name (string) server_port (short) is_ssl (boolean) num_headers (short) num_headers*(req_header_name header_value) ?context (byte)(string) ?servlet_path (byte)(string) ?remote_user (byte)(string) ?auth_type (byte)(string) ?query_string (byte)(string) ?route (byte)(string) ?ssl_cert (byte)(string) ?ssl_cipher (byte)(string) ?ssl_session (byte)(string) ?ssl_key_size (byte)(int) via JkOptions +ForwardKeySize request_terminator (byte) ?body content_length*(var binary) */ static int ajp_marshal_into_msgb(jk_msg_buf_t *msg, jk_ws_service_t *s, jk_log_context_t *l, ajp_endpoint_t * ae) { int method; unsigned int i; JK_TRACE_ENTER(l); if ((method = sc_for_req_method(s->method, strlen(s->method))) == UNKNOWN_METHOD) method = SC_M_JK_STORED; if (jk_b_append_byte(msg, JK_AJP13_FORWARD_REQUEST) || jk_b_append_byte(msg, (unsigned char)method) || jk_b_append_string(msg, s->protocol) || jk_b_append_string(msg, s->req_uri) || jk_b_append_string(msg, s->remote_addr) || jk_b_append_string(msg, s->remote_host) || jk_b_append_string(msg, s->server_name) || jk_b_append_int(msg, (unsigned short)s->server_port) || jk_b_append_byte(msg, (unsigned char)(s->is_ssl)) || jk_b_append_int(msg, (unsigned short)(s->num_headers))) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the message begining", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } for (i = 0; i < s->num_headers; i++) { int sc; if ((sc = sc_for_req_header(s->headers_names[i])) != UNKNOWN_METHOD) { if (jk_b_append_int(msg, (unsigned short)sc)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the header code for '%s'", ae->worker->name, s->headers_names[i]); JK_TRACE_EXIT(l); return JK_FALSE; } } else { if (jk_b_append_string(msg, s->headers_names[i])) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the header name '%s'", ae->worker->name, s->headers_names[i]); JK_TRACE_EXIT(l); return JK_FALSE; } } if (jk_b_append_string(msg, s->headers_values[i])) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the header value for header '%s' of " "length %u", ae->worker->name, s->headers_names[i], strlen(s->headers_names[i])); JK_TRACE_EXIT(l); return JK_FALSE; } } if (s->secret) { if (jk_b_append_byte(msg, SC_A_SECRET) || jk_b_append_string(msg, s->secret)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending secret", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } } if (s->remote_user) { if (jk_b_append_byte(msg, SC_A_REMOTE_USER) || jk_b_append_string(msg, s->remote_user)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the remote user", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } } if (s->auth_type) { if (jk_b_append_byte(msg, SC_A_AUTH_TYPE) || jk_b_append_string(msg, s->auth_type)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the auth type", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } } if (s->query_string) { if (jk_b_append_byte(msg, SC_A_QUERY_STRING) || #if defined(AS400) && !defined(AS400_UTF8) jk_b_append_asciistring(msg, s->query_string)) { #else jk_b_append_string(msg, s->query_string)) { #endif jk_log(l, JK_LOG_ERROR, "(%s) failed appending the query string of length %u", ae->worker->name, strlen(s->query_string)); JK_TRACE_EXIT(l); return JK_FALSE; } } if (s->route) { if (jk_b_append_byte(msg, SC_A_ROUTE) || jk_b_append_string(msg, s->route)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the route", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } } if (s->ssl_cert_len) { if (jk_b_append_byte(msg, SC_A_SSL_CERT) || jk_b_append_string(msg, s->ssl_cert)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the SSL certificates", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } } if (s->ssl_cipher) { if (jk_b_append_byte(msg, SC_A_SSL_CIPHER) || jk_b_append_string(msg, s->ssl_cipher)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the SSL ciphers", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } } if (s->ssl_session) { if (jk_b_append_byte(msg, SC_A_SSL_SESSION) || jk_b_append_string(msg, s->ssl_session)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the SSL session", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } } /* * ssl_key_size is required by Servlet 2.3 API * added support only in ajp14 mode * JFC removed: ae->proto == AJP14_PROTO */ if (s->ssl_key_size != -1) { if (jk_b_append_byte(msg, SC_A_SSL_KEY_SIZE) || jk_b_append_int(msg, (unsigned short)s->ssl_key_size)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the SSL key size of length %d", ae->worker->name, s->ssl_key_size); JK_TRACE_EXIT(l); return JK_FALSE; } } /* If the method was unrecognized, encode it as an attribute */ if (method == SC_M_JK_STORED) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) unknown method %s", ae->worker->name, s->method); if (jk_b_append_byte(msg, SC_A_STORED_METHOD) || jk_b_append_string(msg, s->method)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the request method", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } } /* Forward the SSL protocol name. * Modern Tomcat versions know how to retrieve * the protocol name from this attribute. */ if (s->ssl_protocol && *s->ssl_protocol) { if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) || jk_b_append_string(msg, SC_A_SSL_PROTOCOL) || jk_b_append_string(msg, s->ssl_protocol)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the ssl protocol name %s", ae->worker->name, s->ssl_protocol); JK_TRACE_EXIT(l); return JK_FALSE; } } /* Forward the remote port information, which was forgotten * from the builtin data of the AJP 13 protocol. * Since the servlet spec allows to retrieve it via getRemotePort(), * we provide the port to the Tomcat connector as a request * attribute. Modern Tomcat versions know how to retrieve * the remote port from this attribute. */ if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) || jk_b_append_string(msg, SC_A_REQ_REMOTE_PORT) || jk_b_append_string(msg, s->remote_port)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the remote port %s", ae->worker->name, s->remote_port); JK_TRACE_EXIT(l); return JK_FALSE; } /* Forward the local ip address information, which was forgotten * from the builtin data of the AJP 13 protocol. * Since the servlet spec allows to retrieve it via getLocalAddr(), * we provide the address to the Tomcat connector as a request * attribute. Modern Tomcat versions know how to retrieve * the local address from this attribute. */ if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) || jk_b_append_string(msg, SC_A_REQ_LOCAL_ADDR) || jk_b_append_string(msg, s->local_addr)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the local address %s", ae->worker->name, s->local_addr); JK_TRACE_EXIT(l); return JK_FALSE; } /* Forward activation information from the load balancer. * It can be used by the backend to deny access by requests, * which come with a session id but for an invalid session. * Such requests get forwarded to backends even if they * are disabled" in the load balancer, because the balancer * does not know, which sessions are valid. * If the backend can check, that is was "disabled" it can * delete the session cookie and respond with a self-referential * redirect. The new request will then be balanced to some * other node that is not disabled. */ if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) || jk_b_append_string(msg, SC_A_JK_LB_ACTIVATION) || jk_b_append_string(msg, s->activation)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the activation state %s", ae->worker->name, s->activation); JK_TRACE_EXIT(l); return JK_FALSE; } if (s->num_attributes > 0) { for (i = 0; i < s->num_attributes; i++) { if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) || jk_b_append_string(msg, s->attributes_names[i]) || jk_b_append_string(msg, s->attributes_values[i])) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending attribute %s=%s", ae->worker->name, s->attributes_names[i], s->attributes_values[i]); JK_TRACE_EXIT(l); return JK_FALSE; } } } if (jk_b_append_byte(msg, SC_A_ARE_DONE)) { jk_log(l, JK_LOG_ERROR, "(%s) failed appending the message end", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) ajp marshaling done", ae->worker->name); JK_TRACE_EXIT(l); return JK_TRUE; } /* AJPV13_RESPONSE/AJPV14_RESPONSE:= response_prefix (2) status (short) status_msg (short) num_headers (short) num_headers*(res_header_name header_value) *body_chunk terminator boolean req_header_name := sc_req_header_name | (string) res_header_name := sc_res_header_name | (string) header_value := (string) body_chunk := length (short) body length*(var binary) */ static int ajp_unmarshal_response(jk_msg_buf_t *msg, jk_res_data_t * d, ajp_endpoint_t * ae, jk_log_context_t *l) { jk_pool_t *p = &ae->pool; JK_TRACE_ENTER(l); d->status = jk_b_get_int(msg); if (!d->status) { jk_log(l, JK_LOG_ERROR, "(%s) NULL status", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } if (d->status == 0xFFFF) { jk_log(l, JK_LOG_ERROR, "(%s) Not enough bytes available to read status", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } d->msg = jk_b_get_string(msg); if (d->msg) { #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) jk_xlate_from_ascii(d->msg, strlen(d->msg)); #endif } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) status = %d", ae->worker->name, d->status); d->num_headers = jk_b_get_int(msg); if (d->num_headers == 0xFFFF) { jk_log(l, JK_LOG_ERROR, "(%s) Not enough bytes available to read header count", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } d->header_names = d->header_values = NULL; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Number of headers is = %d", d->num_headers); if (d->num_headers) { d->header_names = jk_pool_alloc(p, sizeof(char *) * d->num_headers); d->header_values = jk_pool_alloc(p, sizeof(char *) * d->num_headers); if (d->header_names && d->header_values) { unsigned int i; for (i = 0; i < d->num_headers; i++) { /* * Looking for a specific value. No need to check for errors. * That will be handled by jk_b_get_string if the specific * value is not found. */ unsigned short name = jk_b_pget_int(msg, msg->pos); if ((name & 0XFF00) == 0XA000) { /* Consume bytes just peeked with jk_b_pget_int */ jk_b_get_int(msg); name = name & 0X00FF; if (name <= SC_RES_HEADERS_NUM) { d->header_names[i] = (char *)long_res_header_for_sc(name); } else { jk_log(l, JK_LOG_ERROR, "(%s) No such sc (%d)", ae->worker->name, name); JK_TRACE_EXIT(l); return JK_FALSE; } } else { d->header_names[i] = jk_b_get_string(msg); if (!d->header_names[i]) { jk_log(l, JK_LOG_ERROR, "(%s) NULL header name", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) jk_xlate_from_ascii(d->header_names[i], strlen(d->header_names[i])); #endif } d->header_values[i] = jk_b_get_string(msg); if (!d->header_values[i]) { jk_log(l, JK_LOG_ERROR, "(%s) NULL header value", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) jk_xlate_from_ascii(d->header_values[i], strlen(d->header_values[i])); #endif if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) Header[%d] [%s] = [%s]", ae->worker->name, i, d->header_names[i], d->header_values[i]); } } } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Abort endpoint use */ static void ajp_abort_endpoint(ajp_endpoint_t * ae, int shutdown, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) aborting endpoint with socket %d", ae->worker->name, ae->sd); if (IS_VALID_SOCKET(ae->sd)) { if (shutdown == JK_TRUE) { if (ae->hard_close) { /* Force unclean connection close to communicate client write * errors back to Tomcat by aborting AJP response writes. */ jk_close_socket(ae->sd, l); } else { jk_shutdown_socket(ae->sd, l); } } JK_ATOMIC_DECREMENT(&(ae->worker->s->connected)); ae->sd = JK_INVALID_SOCKET; } ae->last_op = JK_AJP13_END_RESPONSE; JK_TRACE_EXIT(l); } /* * Reset the endpoint (clean buf and close socket) */ static void ajp_reset_endpoint(ajp_endpoint_t * ae, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) resetting endpoint with socket %d%s", ae->worker->name, ae->sd, ae->reuse? "" : " (socket shutdown)"); if (!ae->reuse) { ajp_abort_endpoint(ae, JK_TRUE, l); } jk_reset_pool(&(ae->pool)); JK_TRACE_EXIT(l); } /* * Close the endpoint (close pool and close socket) */ void ajp_close_endpoint(ajp_endpoint_t * ae, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) closing endpoint with socket %d%s", ae->worker->name, ae->sd, ae->reuse ? "" : " (socket shutdown)"); if (IS_VALID_SOCKET(ae->sd)) { jk_shutdown_socket(ae->sd, l); JK_ATOMIC_DECREMENT(&(ae->worker->s->connected)); ae->sd = JK_INVALID_SOCKET; } jk_close_pool(&(ae->pool)); free(ae); JK_TRACE_EXIT(l); } /** Steal a connection from an idle cache endpoint * @param ae endpoint that needs a new connection * @param l log context * @return JK_FALSE: failure * JK_TRUE: success * @remark Always closes old socket endpoint */ static int ajp_next_connection(ajp_endpoint_t *ae, jk_log_context_t *l) { unsigned int i; int ret = JK_FALSE; ajp_worker_t *aw = ae->worker; JK_TRACE_ENTER(l); /* Close previous socket */ if (IS_VALID_SOCKET(ae->sd)) { jk_shutdown_socket(ae->sd, l); JK_ATOMIC_DECREMENT(&(ae->worker->s->connected)); ae->sd = JK_INVALID_SOCKET; } JK_ENTER_CS(&aw->cs); for (i = 0; i < aw->ep_cache_sz; i++) { /* Find cache slot with usable socket */ if (IS_SLOT_AVAIL(aw->ep_cache[i]) && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { ae->sd = aw->ep_cache[i]->sd; aw->ep_cache[i]->sd = JK_INVALID_SOCKET; break; } } JK_LEAVE_CS(&aw->cs); if (IS_VALID_SOCKET(ae->sd)) { ret = JK_TRUE; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) Will try pooled connection socket %d from slot %d", ae->worker->name, ae->sd, i); } JK_TRACE_EXIT(l); return ret; } /** Handle the cping/cpong query * @param ae endpoint * @param timeout wait timeout in milliseconds * @param l log context * @return JK_FALSE: failure * JK_TRUE: success * @remark Always closes socket in case of * a socket error */ static int ajp_handle_cping_cpong(ajp_endpoint_t * ae, int timeout, jk_log_context_t *l) { int i; int cmd; jk_msg_buf_t *msg; JK_TRACE_ENTER(l); ae->last_errno = 0; msg = jk_b_new(&ae->pool); if (!msg) { jk_log(l, JK_LOG_ERROR, "(%s) Failed allocating AJP message", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } if (jk_b_set_buffer_size(msg, 16)) { jk_log(l, JK_LOG_ERROR, "(%s) Failed allocating AJP message buffer", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } jk_b_reset(msg); jk_b_append_byte(msg, AJP13_CPING_REQUEST); /* Send CPing query */ if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) { jk_log(l, JK_LOG_INFO, "(%s) can't send cping query", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } for (i = 0; i < 2; i++) { /* wait for Pong reply for timeout milliseconds */ if (jk_is_input_event(ae->sd, timeout, l) == JK_FALSE) { ae->last_errno = errno; jk_log(l, JK_LOG_INFO, "(%s) timeout in reply cpong after %d ms. " "Socket = %d (event=%d)", ae->worker->name, timeout, ae->sd, errno); /* We can't trust this connection any more. */ ajp_abort_endpoint(ae, JK_TRUE, l); JK_TRACE_EXIT(l); return JK_FALSE; } /* Read and check for Pong reply */ if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) { jk_log(l, JK_LOG_INFO, "(%s) awaited reply cpong, not received", ae->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } if ((cmd = jk_b_get_byte(msg)) != AJP13_CPONG_REPLY) { /* If the response was not CPONG it means that * the previous response was not consumed by the * client but the AJP messages was already in * the network buffer. * silently drop this single extra packet instead * recycling the connection */ if (i || ae->last_op == JK_AJP13_END_RESPONSE || cmd < JK_AJP13_SEND_BODY_CHUNK || cmd > AJP13_CPONG_REPLY) { jk_log(l, JK_LOG_WARNING, "(%s) awaited reply cpong, received %d instead. " "Closing connection", ae->worker->name, cmd); /* We can't trust this connection any more. */ ajp_abort_endpoint(ae, JK_TRUE, l); JK_TRACE_EXIT(l); return JK_FALSE; } else { jk_log(l, JK_LOG_INFO, "(%s) awaited reply cpong, received %d instead. " "Retrying next packet", ae->worker->name, cmd); } } else { ae->last_op = AJP13_CPONG_REPLY; /* We have received Pong reply */ break; } } JK_TRACE_EXIT(l); return JK_TRUE; } /** Connect an endpoint to a backend * @param ae endpoint * @param l log context * @return JK_FALSE: failure * JK_TRUE: success * @remark Always closes socket in case of * a socket error * @remark Cares about ae->last_errno */ int ajp_connect_to_endpoint(ajp_endpoint_t * ae, jk_log_context_t *l) { char buf[64]; int rc = JK_TRUE; int connected; JK_TRACE_ENTER(l); ae->last_errno = 0; ae->sd = jk_open_socket(&ae->worker->worker_inet_addr, ae->worker->worker_source_inet_addr.ipaddr_ptr != NULL ? &ae->worker->worker_source_inet_addr : NULL, ae->worker->keepalive, ae->worker->socket_timeout, ae->worker->socket_connect_timeout, ae->worker->socket_buf, l); if (!IS_VALID_SOCKET(ae->sd)) { ae->last_errno = errno; jk_log(l, JK_LOG_INFO, "(%s) Failed opening socket to (%s) (errno=%d)", ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf)), ae->last_errno); JK_TRACE_EXIT(l); return JK_FALSE; } connected = JK_ATOMIC_INCREMENT(&(ae->worker->s->connected)); /* Update maximum number of connections */ if (connected > ae->worker->s->max_connected) ae->worker->s->max_connected = connected; /* set last_access only if needed */ if (ae->worker->cache_timeout > 0) ae->last_access = time(NULL); /* Check if we must execute a logon after the physical connect * XXX: Not sure, if we really should do logon before cping/cpong * and if no cping/cpong is allowed before or after logon. */ if (ae->worker->logon != NULL) { rc = ae->worker->logon(ae, l); if (rc == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "(%s) ajp14 worker logon to the backend server failed", ae->worker->name); /* Close the socket if unable to logon */ ajp_abort_endpoint(ae, JK_TRUE, l); } } /* XXX: Should we send a cping also after logon to validate the connection? */ else if (ae->worker->connect_timeout > 0) { rc = ajp_handle_cping_cpong(ae, ae->worker->connect_timeout, l); if (rc == JK_FALSE) jk_log(l, JK_LOG_ERROR, "(%s) cping/cpong after connecting to the backend server " "failed (errno=%d)", ae->worker->name, ae->last_errno); } JK_TRACE_EXIT(l); return rc; } /* Syncing config values from shm */ void jk_ajp_pull(ajp_worker_t * aw, int locked, jk_log_context_t *l) { int address_change = JK_FALSE; int port = 0; shm_str host; jk_sockaddr_t inet_addr; JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "syncing mem for ajp worker '%s' from shm (%d->%d) [%d->%d]", aw->name, aw->sequence, aw->s->h.sequence, aw->addr_sequence, aw->s->addr_sequence); if (locked == JK_FALSE) jk_shm_lock(); aw->cache_timeout = aw->s->cache_timeout; aw->connect_timeout = aw->s->connect_timeout; aw->ping_timeout = aw->s->ping_timeout; aw->reply_timeout = aw->s->reply_timeout; aw->prepost_timeout = aw->s->prepost_timeout; aw->recovery_opts = aw->s->recovery_opts; aw->retries = aw->s->retries; aw->retry_interval = aw->s->retry_interval; aw->busy_limit = aw->s->busy_limit; aw->max_packet_size = aw->s->max_packet_size; aw->sequence = aw->s->h.sequence; if (aw->addr_sequence != aw->s->addr_sequence) { address_change = JK_TRUE; aw->addr_sequence = aw->s->addr_sequence; jk_shm_str_copy(host, aw->s->host, l); port = aw->s->port; } if (locked == JK_FALSE) jk_shm_unlock(); if (address_change == JK_TRUE && port != 0) { aw->port = port; jk_shm_str_copy(aw->host, host, l); if (!jk_resolve(host, port, &inet_addr, aw->worker.we->pool, aw->prefer_ipv6, l)) { jk_log(l, JK_LOG_ERROR, "Failed resolving address '%s:%d' for worker '%s'.", host, port, aw->name); /* Disable contact */ aw->port = 0; } else { unsigned int i; JK_ENTER_CS(&aw->cs); for (i = 0; i < aw->ep_cache_sz; i++) { /* Close all avail connections in the cache * Note that this won't change active connections. */ if (IS_SLOT_AVAIL(aw->ep_cache[i]) && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { jk_sock_t sd = aw->ep_cache[i]->sd; aw->ep_cache[i]->sd = JK_INVALID_SOCKET; aw->ep_cache[i]->addr_sequence = aw->addr_sequence; jk_shutdown_socket(sd, l); JK_ATOMIC_DECREMENT(&(aw->s->connected)); } } jk_clone_sockaddr(&(aw->worker_inet_addr), &inet_addr); JK_LEAVE_CS(&aw->cs); } } JK_TRACE_EXIT(l); } /* Syncing config values to shm */ void jk_ajp_push(ajp_worker_t * aw, int locked, jk_log_context_t *l) { int address_change = JK_FALSE; JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "syncing shm for ajp worker '%s' from mem (%d->%d) [%d->%d]", aw->name, aw->s->h.sequence, aw->sequence, aw->s->addr_sequence, aw->addr_sequence); if (locked == JK_FALSE) jk_shm_lock(); aw->s->cache_timeout = aw->cache_timeout; aw->s->connect_timeout = aw->connect_timeout; aw->s->ping_timeout = aw->ping_timeout; aw->s->reply_timeout = aw->reply_timeout; aw->s->prepost_timeout = aw->prepost_timeout; aw->s->recovery_opts = aw->recovery_opts; aw->s->retries = aw->retries; aw->s->retry_interval = aw->retry_interval; aw->s->busy_limit = aw->busy_limit; aw->s->max_packet_size = aw->max_packet_size; /* Force squence update on push */ ++aw->s->h.sequence; aw->sequence = aw->s->h.sequence; if (aw->s->addr_sequence != aw->addr_sequence) { ++aw->s->addr_sequence; address_change = JK_TRUE; jk_shm_str_copy(aw->s->host, aw->host, l); aw->s->port = aw->port; aw->addr_sequence = aw->s->addr_sequence; } if (locked == JK_FALSE) jk_shm_unlock(); if (address_change == JK_TRUE) { unsigned int i; JK_ENTER_CS(&aw->cs); for (i = 0; i < aw->ep_cache_sz; i++) { /* Close all connections in the cache */ if (IS_SLOT_AVAIL(aw->ep_cache[i]) && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { jk_sock_t sd = aw->ep_cache[i]->sd; aw->ep_cache[i]->sd = JK_INVALID_SOCKET; aw->ep_cache[i]->addr_sequence = aw->addr_sequence; jk_shutdown_socket(sd, l); JK_ATOMIC_DECREMENT(&(aw->s->connected)); } } JK_LEAVE_CS(&aw->cs); } JK_TRACE_EXIT(l); } /** Send a message to an endpoint, using corresponding PROTO HEADER * @param ae endpoint * @param msg message to send * @param l log context * @return JK_FATAL_ERROR: endpoint contains unknown protocol * JK_FALSE: other failure * JK_TRUE: success * @remark Always closes socket in case of * a socket error, or JK_FATAL_ERROR * @remark Cares about ae->last_errno */ int ajp_connection_tcp_send_message(ajp_endpoint_t * ae, jk_msg_buf_t *msg, jk_log_context_t *l) { int rc; JK_TRACE_ENTER(l); ae->last_errno = 0; if (ae->proto == AJP13_PROTO) { jk_b_end(msg, AJP13_WS_HEADER); if (JK_IS_DEBUG_LEVEL(l)) jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp13", msg); } else if (ae->proto == AJP14_PROTO) { jk_b_end(msg, AJP14_WS_HEADER); if (JK_IS_DEBUG_LEVEL(l)) jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp14", msg); } else { jk_log(l, JK_LOG_ERROR, "(%s) unknown protocol %d, supported are AJP13/AJP14", ae->worker->name, ae->proto); /* We've got a protocol error. * We can't trust this connection any more, * because we might have send already parts of the request. */ ajp_abort_endpoint(ae, JK_TRUE, l); JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } /* This is the only place in this function where we use the socket. * If sendfull gets an error, it implicitely closes the socket. * So any socket error inside ajp_connection_tcp_send_message * results in a socket close and invalidated endpoint connection. */ if ((rc = jk_tcp_socket_sendfull(ae->sd, msg->buf, msg->len, l)) > 0) { ae->endpoint.wr += (jk_uint64_t)rc; JK_TRACE_EXIT(l); return JK_TRUE; } ae->last_errno = errno; jk_log(l, JK_LOG_INFO, "(%s) sendfull for socket %d returned %d (errno=%d)", ae->worker->name, ae->sd, rc, ae->last_errno); ajp_abort_endpoint(ae, JK_FALSE, l); JK_TRACE_EXIT(l); return JK_FALSE; } /** Receive a message from an endpoint, checking PROTO HEADER * @param ae endpoint * @param msg message to send * @param l log context * @return JK_TRUE: success * JK_FALSE: could not read the AJP packet header * JK_AJP_PROTOCOL_ERROR: failure after reading * the AJP packet header * @remark Always closes socket in case of * a socket error * @remark Cares about ae->last_errno */ int ajp_connection_tcp_get_message(ajp_endpoint_t * ae, jk_msg_buf_t *msg, jk_log_context_t *l) { unsigned char head[AJP_HEADER_LEN]; int rc; int msglen; unsigned int header; char buf[64]; JK_TRACE_ENTER(l); ae->last_errno = 0; /* If recvfull gets an error, it implicitely closes the socket. * We will invalidate the endpoint connection. */ rc = jk_tcp_socket_recvfull(ae->sd, head, AJP_HEADER_LEN, l); /* If the return code is not negative * then we always get back the correct number of bytes. */ if (rc < 0) { if (rc == JK_SOCKET_EOF) { ae->last_errno = EPIPE; jk_log(l, JK_LOG_INFO, "(%s) can't receive the response header message from tomcat, " "tomcat (%s) has forced a connection close for socket %d", ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf)), ae->sd); } else { ae->last_errno = -rc; jk_log(l, JK_LOG_INFO, "(%s) can't receive the response header message from tomcat, " "network problems or tomcat (%s) is down (errno=%d)", ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf)), ae->last_errno); } ajp_abort_endpoint(ae, JK_FALSE, l); JK_TRACE_EXIT(l); return JK_FALSE; } ae->endpoint.rd += (jk_uint64_t)rc; header = ((unsigned int)head[0] << 8) | head[1]; if (ae->proto == AJP13_PROTO) { if (header != AJP13_SW_HEADER) { if (header == AJP14_SW_HEADER) { jk_log(l, JK_LOG_ERROR, "(%s) received AJP14 reply on an AJP13 connection from %s", ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf))); } else { jk_log(l, JK_LOG_ERROR, "(%s) wrong message format 0x%04x from %s", ae->worker->name, header, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf))); } /* We've got a protocol error. * We can't trust this connection any more. */ ajp_abort_endpoint(ae, JK_TRUE, l); JK_TRACE_EXIT(l); return JK_AJP_PROTOCOL_ERROR; } } else if (ae->proto == AJP14_PROTO) { if (header != AJP14_SW_HEADER) { if (header == AJP13_SW_HEADER) { jk_log(l, JK_LOG_ERROR, "(%s) received AJP13 reply on an AJP14 connection from %s", ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf))); } else { jk_log(l, JK_LOG_ERROR, "(%s) wrong message format 0x%04x from %s", ae->worker->name, header, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf))); } /* We've got a protocol error. * We can't trust this connection any more. */ ajp_abort_endpoint(ae, JK_TRUE, l); JK_TRACE_EXIT(l); return JK_AJP_PROTOCOL_ERROR; } } msglen = ((head[2] & 0xff) << 8); msglen += (head[3] & 0xFF); if (msglen > msg->maxlen) { jk_log(l, JK_LOG_ERROR, "(%s) wrong message size %d %d from %s", ae->worker->name, msglen, msg->maxlen, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf))); /* We've got a protocol error. * We can't trust this connection any more. */ ajp_abort_endpoint(ae, JK_TRUE, l); JK_TRACE_EXIT(l); return JK_AJP_PROTOCOL_ERROR; } msg->len = msglen; msg->pos = 0; /* If recvfull gets an error, it implicitely closes the socket. * We will invalidate the endpoint connection. */ rc = jk_tcp_socket_recvfull(ae->sd, msg->buf, msglen, l); /* If the return code is not negative * then we always get back the correct number of bytes. */ if (rc < 0) { if (rc == JK_SOCKET_EOF) { ae->last_errno = EPIPE; jk_log(l, JK_LOG_ERROR, "(%s) can't receive the response body message from tomcat, " "tomcat (%s) has forced a connection close for socket %d", ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf)), ae->sd); } else { ae->last_errno = -rc; jk_log(l, JK_LOG_ERROR, "(%s) can't receive the response body message from tomcat, " "network problems or tomcat (%s) is down (errno=%d)", ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf, sizeof(buf)), ae->last_errno); } ajp_abort_endpoint(ae, JK_FALSE, l); JK_TRACE_EXIT(l); /* Although we have a connection, this is effectively a protocol error. * We received the AJP header packet, but not the packet payload */ return JK_AJP_PROTOCOL_ERROR; } ae->endpoint.rd += (jk_uint64_t)rc; if (JK_IS_DEBUG_LEVEL(l)) { if (ae->proto == AJP13_PROTO) jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp13", msg); else if (ae->proto == AJP14_PROTO) jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp14", msg); } JK_TRACE_EXIT(l); return JK_TRUE; } /* * Read all the data from the socket. * * Socket API doesn't guaranty that all the data will be kept in a * single read, so we must loop until all awaited data is received */ static int ajp_read_fully_from_server(jk_ws_service_t *s, jk_log_context_t *l, unsigned char *buf, unsigned int len) { unsigned int rdlen = 0; unsigned int padded_len = len; JK_TRACE_ENTER(l); if (s->is_chunked && s->no_more_chunks) { JK_TRACE_EXIT(l); return 0; } if (s->is_chunked) { /* Corner case: buf must be large enough to hold next * chunk size (if we're on or near a chunk border). * Pad the length to a reasonable value, otherwise the * read fails and the remaining chunks are tossed. */ padded_len = (len < CHUNK_BUFFER_PAD) ? len : len - CHUNK_BUFFER_PAD; } while (rdlen < padded_len) { unsigned int this_time = 0; if (!s->read(s, buf + rdlen, len - rdlen, &this_time)) { /* Remote Client read failed. */ JK_TRACE_EXIT(l); return JK_CLIENT_RD_ERROR; } if (0 == this_time) { if (s->is_chunked) { s->no_more_chunks = 1; /* read no more */ } break; } rdlen += this_time; } JK_TRACE_EXIT(l); return (int)rdlen; } /* * Read data from AJP13/AJP14 protocol * Returns -1 on error, else number of bytes read */ static int ajp_read_into_msg_buff(ajp_endpoint_t * ae, jk_ws_service_t *s, jk_msg_buf_t *msg, int len, jk_log_context_t *l) { unsigned char *read_buf = msg->buf; int maxlen; JK_TRACE_ENTER(l); jk_b_reset(msg); read_buf += AJP_HEADER_LEN; /* leave some space for the buffer headers */ read_buf += AJP_HEADER_SZ_LEN; /* leave some space for the read length */ maxlen = ae->worker->max_packet_size - AJP_HEADER_LEN - AJP_HEADER_SZ_LEN; /* Pick the max size since we don't know the content_length */ if (s->is_chunked && ae->left_bytes_to_send == 0) { len = maxlen; } else { if ((jk_uint64_t)maxlen > ae->left_bytes_to_send) { maxlen = (int)ae->left_bytes_to_send; } if (len < 0 || len > maxlen) { len = maxlen; } } if ((len = ajp_read_fully_from_server(s, l, read_buf, len)) < 0) { jk_log(l, JK_LOG_INFO, "(%s) receiving data from client failed. " "Connection aborted or network problems", ae->worker->name); JK_TRACE_EXIT(l); return JK_CLIENT_RD_ERROR; } if (!s->is_chunked) { ae->left_bytes_to_send -= len; } if (len > 0) { /* Recipient recognizes empty packet as end of stream, not * an empty body packet */ if (0 != jk_b_append_int(msg, (unsigned short)len)) { jk_log(l, JK_LOG_INFO, "(%s) Failed appending message length", ae->worker->name); JK_TRACE_EXIT(l); return JK_CLIENT_RD_ERROR; } } msg->len += len; JK_TRACE_EXIT(l); return len; } /* * send request to Tomcat via Ajp13 * - first try to find reuseable socket * - if no such available, try to connect * - send request, but send must be seen as asynchronous, * since send() call will return noerror about 95% of time * Hopefully we'll get more information on next read. * * nb: op->request is the original request msg buffer * op->reply is the reply msg buffer which could be scratched * * Return values of ajp_send_request() function: * return value op->recoverable reason * JK_FATAL_ERROR JK_FALSE ajp_connection_tcp_send_message() * returns JK_FATAL_ERROR * Endpoint belongs to unknown protocol. * JK_FATAL_ERROR JK_TRUE ajp_connection_tcp_send_message() * returns JK_FALSE * Sending request or request body in jk_tcp_socket_sendfull() * returns with error. * JK_FATAL_ERROR JK_TRUE Could not connect to backend * JK_CLIENT_RD_ERROR JK_FALSE Error during reading parts of POST * body from client * JK_TRUE JK_TRUE All other cases (OK) */ static int ajp_send_request(jk_endpoint_t *e, jk_ws_service_t *s, jk_log_context_t *l, ajp_endpoint_t * ae, ajp_operation_t * op) { int err_conn = 0; int err_cping = 0; int err_send = 0; int rc; int postlen; JK_TRACE_ENTER(l); ae->last_errno = 0; /* Up to now, we can recover */ op->recoverable = JK_TRUE; /* Check if the previous request really ended */ if (ae->last_op != JK_AJP13_END_RESPONSE && ae->last_op != AJP13_CPONG_REPLY) { jk_log(l, JK_LOG_INFO, "(%s) did not receive END_RESPONSE, " "closing socket %d", ae->worker->name, ae->sd); ajp_abort_endpoint(ae, JK_TRUE, l); } /* First try to check open connections... */ while (IS_VALID_SOCKET(ae->sd)) { int err = JK_FALSE; if (jk_is_socket_connected(ae->sd, l) == JK_FALSE) { ae->last_errno = errno; jk_log(l, JK_LOG_DEBUG, "(%s) failed sending request, " "socket %d is not connected any more (errno=%d)", ae->worker->name, ae->sd, ae->last_errno); ajp_abort_endpoint(ae, JK_FALSE, l); err = JK_TRUE; err_conn++; } if (ae->worker->prepost_timeout > 0 && !err) { /* handle cping/cpong if prepost_timeout is set * If the socket is disconnected no need to handle * the cping/cpong */ if (ajp_handle_cping_cpong(ae, ae->worker->prepost_timeout, l) == JK_FALSE) { jk_log(l, JK_LOG_INFO, "(%s) failed sending request, " "socket %d prepost cping/cpong failure (errno=%d)", ae->worker->name, ae->sd, ae->last_errno); /* XXX: Is there any reason to try other * connections to the node if one of them fails * the cping/cpong heartbeat? * Tomcat can be either too busy or simply dead, so * there is a chance that all other connections would * fail as well. */ err = JK_TRUE; err_cping++; } } /* We've got a connected socket and the optional * cping/cpong worked, so let's send the request now. */ if (err == JK_FALSE) { rc = ajp_connection_tcp_send_message(ae, op->request, l); /* If this worked, we can break out of the loop * and proceed with the request. */ if (rc == JK_TRUE) { ae->last_op = JK_AJP13_FORWARD_REQUEST; break; } /* Error during sending the request. */ err_send++; if (rc == JK_FATAL_ERROR) op->recoverable = JK_FALSE; jk_log(l, JK_LOG_INFO, "(%s) failed sending request (%srecoverable) " "(errno=%d)", ae->worker->name, op->recoverable ? "" : "un", ae->last_errno); JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } /* If we got an error or can't send data, then try to steal another * pooled connection and try again. If we are not successful, break * out of this loop and try to open a new connection after the loop. */ if (ajp_next_connection(ae, l) == JK_FALSE) break; } /* If we failed to reuse a connection, try to reconnect. */ if (!IS_VALID_SOCKET(ae->sd)) { /* Could not steal any connection from an endpoint - backend * is disconnected or all connections are in use */ if (err_conn + err_cping + err_send > 0) if (err_cping + err_send > 0) jk_log(l, JK_LOG_INFO, "(%s) no usable connection found, will create a new one, " "detected by connect check (%d), cping (%d), send (%d).", ae->worker->name, err_conn, err_cping, err_send); else jk_log(l, JK_LOG_DEBUG, "(%s) no usable connection found, will create a new one, " "detected by connect check (%d), cping (%d), send (%d).", ae->worker->name, err_conn, err_cping, err_send); else if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) no usable connection found, will create a new one.", ae->worker->name); /* Connect to the backend. */ if (ajp_connect_to_endpoint(ae, l) != JK_TRUE) { jk_log(l, JK_LOG_ERROR, "(%s) connecting to backend failed. " "Tomcat is probably not started " "or is listening on the wrong port (errno=%d)", ae->worker->name, ae->last_errno); JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } if (ae->worker->connect_timeout <= 0 && ae->worker->prepost_timeout > 0) { /* handle cping/cpong if prepost_timeout is set * and we didn't already do a connect cping/cpong. */ if (ajp_handle_cping_cpong(ae, ae->worker->prepost_timeout, l) == JK_FALSE) { jk_log(l, JK_LOG_INFO, "(%s) failed sending request, " "socket %d prepost cping/cpong failure (errno=%d)", ae->worker->name, ae->sd, ae->last_errno); JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } } /* We've got a connected socket and the optional * cping/cpong worked, so let's send the request now. */ rc = ajp_connection_tcp_send_message(ae, op->request, l); /* Error during sending the request. */ if (rc != JK_TRUE) { if (rc == JK_FATAL_ERROR) op->recoverable = JK_FALSE; jk_log(l, JK_LOG_ERROR, "(%s) failed sending request on a fresh connection " "(%srecoverable), socket %d (errno=%d)", ae->worker->name, op->recoverable ? "" : "un", ae->sd, ae->last_errno); JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } ae->last_op = JK_AJP13_FORWARD_REQUEST; } else if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) Statistics about invalid connections: " "connect check (%d), cping (%d), send (%d)", ae->worker->name, err_conn, err_cping, err_send); /* * From now on an error means that we have an internal server error * or Tomcat crashed. */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) request body to send %" JK_UINT64_T_FMT " - request body to resend %d", ae->worker->name, ae->left_bytes_to_send, op->post->len > AJP_HEADER_LEN ? op->post->len - AJP_HEADER_LEN : 0); /* * POST recovery job is done here and will work when data to * POST are less than 8k, since it's the maximum size of op-post buffer. * We send here the first part of data which was sent previously to the * remote Tomcat * * Did we have something to resend (ie the op-post has been feeded previously */ postlen = op->post->len; if (postlen > AJP_HEADER_LEN) { rc = ajp_connection_tcp_send_message(ae, op->post, l); /* Error during sending the request body. */ if (rc != JK_TRUE) { if (rc == JK_FATAL_ERROR) op->recoverable = JK_FALSE; jk_log(l, JK_LOG_ERROR, "(%s) failed sending request body of size %d " "(%srecoverable), socket %d (errno=%d)", ae->worker->name, postlen, op->recoverable ? "" : "un", ae->sd, ae->last_errno); JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) Resent the request body (%d)", ae->worker->name, postlen); } } else if (s->reco_status == RECO_FILLED) { /* Recovery in LB MODE */ postlen = s->reco_buf->len; if (postlen > AJP_HEADER_LEN) { rc = ajp_connection_tcp_send_message(ae, s->reco_buf, l); /* Error during sending the request body. */ if (rc != JK_TRUE) { if (rc == JK_FATAL_ERROR) op->recoverable = JK_FALSE; jk_log(l, JK_LOG_ERROR, "(%s) failed sending request body of size %d (lb mode) " "(%srecoverable), socket %d (errno=%d)", ae->worker->name, postlen, op->recoverable ? "" : "un", ae->sd, ae->last_errno); JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) Resent the request body (lb mode) (%d)", ae->worker->name, postlen); } } else { /* We never sent any POST data and we check if we have to send at * least one block of data (max 8k). These data will be kept in reply * for resend if the remote Tomcat is down, a fact we will learn only * doing a read (not yet) * * || s->is_chunked - this can't be done here. The original protocol * sends the first chunk of post data (based on Content-Length), * and that's what the java side expects. * Sending this data for chunked would break other ajp13 servers. * * Note that chunking will continue to work - using the normal read. */ if (ae->left_bytes_to_send > 0) { int len; if ((len = ajp_read_into_msg_buff(ae, s, op->post, -1, l)) <= 0) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) browser stop sending data, no need to recover", ae->worker->name); op->recoverable = JK_FALSE; /* Send an empty POST message since per AJP protocol * spec whenever we have content length the message * packet must be followed with initial POST packet. * Size zero will be handled as error in container. */ jk_b_reset(op->post); jk_b_append_int(op->post, 0); ajp_connection_tcp_send_message(ae, op->post, l); JK_TRACE_EXIT(l); return JK_CLIENT_RD_ERROR; } /* If a RECOVERY buffer is available in LB mode, fill it */ if (s->reco_status == RECO_INITED) { jk_b_copy(op->post, s->reco_buf); s->reco_status = RECO_FILLED; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) sending %d bytes of request body", ae->worker->name, len); s->content_read = (jk_uint64_t)len; rc = ajp_connection_tcp_send_message(ae, op->post, l); /* Error during sending the request body. */ if (rc != JK_TRUE) { if (rc == JK_FATAL_ERROR) op->recoverable = JK_FALSE; jk_log(l, JK_LOG_ERROR, "(%s) failed sending request body of size %d " "(%srecoverable), socket %d (errno=%d)", ae->worker->name, len, op->recoverable ? "" : "un", ae->sd, ae->last_errno); JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } } } JK_TRACE_EXIT(l); return JK_TRUE; } /* * What to do with incoming data (dispatcher) */ static int ajp_process_callback(jk_msg_buf_t *msg, jk_msg_buf_t *pmsg, ajp_endpoint_t * ae, jk_ws_service_t *s, jk_log_context_t *l) { int code = (int)jk_b_get_byte(msg); JK_TRACE_ENTER(l); switch (code) { case JK_AJP13_SEND_HEADERS: { int rc; jk_res_data_t res; if (ae->last_op == JK_AJP13_SEND_HEADERS) { /* Do not send anything to the client. * Backend already send us the headers. */ if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "(%s) Already received AJP13_SEND HEADERS", ae->worker->name); } JK_TRACE_EXIT(l); return JK_AJP13_ERROR; } if (!ajp_unmarshal_response(msg, &res, ae, l)) { jk_log(l, JK_LOG_ERROR, "(%s) ajp_unmarshal_response failed", ae->worker->name); JK_TRACE_EXIT(l); return JK_AJP13_ERROR; } if (s->num_resp_headers > 0) { char **old_names = res.header_names; char **old_values = res.header_values; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) Adding %d response headers " "to %d headers received from tomcat", ae->worker->name, s->num_resp_headers, res.num_headers); res.header_names = jk_pool_alloc(s->pool, (s->num_resp_headers + res.num_headers) * sizeof(char *)); res.header_values = jk_pool_alloc(s->pool, (s->num_resp_headers + res.num_headers) * sizeof(char *)); if (!res.header_names || !res.header_values) { jk_log(l, JK_LOG_ERROR, "(%s) Failed allocating one %d response headers.", ae->worker->name, s->num_resp_headers + res.num_headers); res.header_names = old_names; res.header_values = old_values; } else { if (res.num_headers) { memcpy(res.header_names, old_names, res.num_headers * sizeof(char *)); memcpy(res.header_values, old_values, res.num_headers * sizeof(char *)); } if (s->num_resp_headers) { memcpy(res.header_names + res.num_headers, s->resp_headers_names, s->num_resp_headers * sizeof(char *)); memcpy(res.header_values + res.num_headers, s->resp_headers_values, s->num_resp_headers * sizeof(char *)); } res.num_headers = res.num_headers + s->num_resp_headers; } } s->http_response_status = res.status; if (s->extension.fail_on_status_size > 0) rc = is_http_status_fail(s->extension.fail_on_status_size, s->extension.fail_on_status, res.status); else rc = is_http_status_fail(ae->worker->http_status_fail_num, ae->worker->http_status_fail, res.status); if (rc > 0) { JK_TRACE_EXIT(l); return JK_STATUS_FATAL_ERROR; } if (rc < 0) { JK_TRACE_EXIT(l); return JK_STATUS_ERROR; } if (s->extension.use_server_error_pages && s->http_response_status >= s->extension.use_server_error_pages) s->response_blocked = JK_TRUE; /* * Call even if response is blocked, since it also handles * forwarding some headers for special http status codes * even if the server uses an own error page. * Example: The WWW-Authenticate header in case of * HTTP_UNAUTHORIZED (401). */ s->start_response(s, res.status, res.msg, (const char *const *)res.header_names, (const char *const *)res.header_values, res.num_headers); if (!s->response_blocked) { if (s->flush && s->flush_header) s->flush(s); } } return JK_AJP13_SEND_HEADERS; case JK_AJP13_SEND_BODY_CHUNK: if (ae->last_op == JK_AJP13_FORWARD_REQUEST) { /* AJP13_SEND_BODY_CHUNK with length 0 is * explicit flush packet message. * Ignore those if they are left over from previous responses. * Reportedly some versions of JBoss suffer from that problem. */ if (jk_b_get_int(msg) == 0) { jk_log(l, JK_LOG_DEBUG, "(%s) Ignoring flush message received while sending the " "request", ae->worker->name); return ae->last_op; } /* We have just send a request but received something * that probably originates from buffered response. */ if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "(%s) Unexpected AJP13_SEND_BODY_CHUNK", ae->worker->name); } JK_TRACE_EXIT(l); return JK_AJP13_ERROR; } if (!s->response_blocked) { unsigned int len; /* Check there is sufficient data in the ajp message to read a valid * length. It must be at least 3 bytes - the magic byte for * JK_AJP13_SEND_BODY_CHUNK (1 byte) and the length of the chunk * (2 bytes). The remaining part of the message is the chunk. */ if (msg->len < 3) { jk_log(l, JK_LOG_ERROR, "(%s) Invalid AJP message. Length of AJP message " "is %d, but it should be at least 3.", ae->worker->name, msg->len); JK_TRACE_EXIT(l); return JK_INTERNAL_ERROR; } /* * Once we have len, do a sanity check to prevent reading beyond * buffer boundaries and thus revealing possible sensitive memory * contents to the client. */ len = (unsigned int)jk_b_get_int(msg); if (len > (unsigned int)(msg->len - 3)) { jk_log(l, JK_LOG_ERROR, "(%s) Chunk length too large. Length of AJP message " "is %d, chunk length is %d.", ae->worker->name, msg->len, len); JK_TRACE_EXIT(l); return JK_INTERNAL_ERROR; } if (len == 0) { /* AJP13_SEND_BODY_CHUNK with length 0 is * explicit flush packet message. */ if (s->response_started) { if (s->flush) { s->flush(s); } } else { jk_log(l, JK_LOG_DEBUG, "(%s) Ignoring flush message received before headers", ae->worker->name); } } else { if (!s->write(s, msg->buf + msg->pos, len)) { jk_log(l, JK_LOG_INFO, "(%s) Writing to client aborted or client network " "problems", ae->worker->name); JK_TRACE_EXIT(l); return JK_CLIENT_WR_ERROR; } if (s->flush && s->flush_packets) s->flush(s); } } break; case JK_AJP13_GET_BODY_CHUNK: { int len = (int)jk_b_get_int(msg); if (len == 0xFFFF) { jk_log(l, JK_LOG_ERROR, "(%s) Invalid AJP message: Not enough bytes available to read chunk length", ae->worker->name); JK_TRACE_EXIT(l); return JK_AJP13_ERROR; } /* the right place to add file storage for upload */ if ((len = ajp_read_into_msg_buff(ae, s, pmsg, len, l)) >= 0) { s->content_read += (jk_uint64_t)len; JK_TRACE_EXIT(l); return JK_AJP13_HAS_RESPONSE; } jk_log(l, JK_LOG_INFO, "(%s) Reading from client aborted or client network problems", ae->worker->name); JK_TRACE_EXIT(l); return JK_CLIENT_RD_ERROR; } break; case JK_AJP13_END_RESPONSE: ae->reuse = (int)jk_b_get_byte(msg); if (ae->reuse == 0xFF) { jk_log(l, JK_LOG_ERROR, "(%s) Not enough bytes available to read reuse flag", ae->worker->name); JK_TRACE_EXIT(l); return JK_AJP13_ERROR; } else if (!ae->reuse) { /* * AJP13 protocol reuse flag set to false. * Tomcat will close its side of the connection. */ jk_log(l, JK_LOG_WARNING, "(%s) AJP13 protocol: Reuse is set to false", ae->worker->name); } else if (s->disable_reuse) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "(%s) AJP13 protocol: Reuse is disabled", ae->worker->name); } ae->reuse = JK_FALSE; } else { /* Reuse in all cases */ if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "(%s) AJP13 protocol: Reuse is OK", ae->worker->name); } ae->reuse = JK_TRUE; } if (!s->response_blocked) { if (s->done) { /* Done with response */ s->done(s); } else if (s->flush && !s->flush_packets) { /* Flush after the last write */ s->flush(s); } } JK_TRACE_EXIT(l); return JK_AJP13_END_RESPONSE; break; default: jk_log(l, JK_LOG_ERROR, "(%s) Unknown AJP protocol code: %02X", ae->worker->name, code); JK_TRACE_EXIT(l); return JK_AJP13_ERROR; } JK_TRACE_EXIT(l); return JK_AJP13_NO_RESPONSE; } /* * get replies from Tomcat via Ajp13/Ajp14 * ajp13/ajp14 is async but handling read/send this way prevent nice recovery * In fact if tomcat link is broken during upload (browser -> apache -> tomcat) * we'll loose data and we'll have to abort the whole request. * * Return values of ajp_get_reply() function: * return value op->recoverable reason * JK_REPLY_TIMEOUT ?recovery_options Reply timeout while waiting for * response packet * JK_FALSE ?recovery_options Error during * ajp_connection_tcp_get_message() * Could not read the AJP packet header * JK_AJP_PROTOCOL_ERROR: ?recovery_options Error during * ajp_connection_tcp_get_message() * Failure after reading the AJP packet header * JK_STATUS_ERROR mostly JK_TRUE ajp_process_callback() returns * JK_STATUS_ERROR * Recoverable, if callback didn't return with a JK_HAS_RESPONSE before. * JK_HAS_RESPONSE: parts of the post buffer are consumed. * JK_STATUS_FATAL_ERROR mostly JK_TRUE ajp_process_callback() returns * JK_STATUS_FATAL_ERROR * Recoverable, if callback didn't return with a JK_HAS_RESPONSE before. * JK_HAS_RESPONSE: parts of the post buffer are consumed. * JK_FATAL_ERROR ? ajp_process_callback() returns * JK_AJP13_ERROR * JK_AJP13_ERROR: protocol error, or JK_INTERNAL_ERROR: * chunk size to large * JK_CLIENT_RD_ERROR ? ajp_process_callback() returns * JK_CLIENT_RD_ERROR * JK_CLIENT_RD_ERROR: could not read post from client. * JK_CLIENT_WR_ERROR ? ajp_process_callback() returns * JK_CLIENT_WR_ERROR * JK_CLIENT_WR_ERROR: could not write back result to client * JK_TRUE ? ajp_process_callback() returns * JK_AJP13_END_RESPONSE * JK_FALSE ? Other unhandled cases * (unknown return codes) */ static int ajp_get_reply(jk_endpoint_t *e, jk_ws_service_t *s, jk_log_context_t *l, ajp_endpoint_t * p, ajp_operation_t * op) { /* Don't get header from tomcat yet */ int headeratclient = JK_FALSE; JK_TRACE_ENTER(l); p->last_errno = 0; /* Start read all reply message */ while (1) { int rc = 0; /* Allow to overwrite reply_timeout on a per URL basis via service struct */ int reply_timeout = s->extension.reply_timeout; if (reply_timeout < 0) reply_timeout = p->worker->reply_timeout; /* If we set a reply timeout, check if something is available */ if (reply_timeout > 0) { if (jk_is_input_event(p->sd, reply_timeout, l) == JK_FALSE) { p->last_errno = errno; jk_log(l, JK_LOG_ERROR, "(%s) Timeout with waiting reply from tomcat. " "Tomcat is down, stopped or network problems (errno=%d)", p->worker->name, p->last_errno); /* We can't trust this connection any more. */ ajp_abort_endpoint(p, JK_TRUE, l); if (headeratclient == JK_FALSE) { if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST) op->recoverable = JK_FALSE; /* * We revert back to recoverable, if recovery_opts allow it * for GET or HEAD */ if (op->recoverable == JK_FALSE) { if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_HEAD) { if (!strcmp(s->method, "HEAD")) op->recoverable = JK_TRUE; } else if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_GET) { if (!strcmp(s->method, "GET")) op->recoverable = JK_TRUE; } } } else { if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER) op->recoverable = JK_FALSE; } JK_TRACE_EXIT(l); return JK_REPLY_TIMEOUT; } } if ((rc = ajp_connection_tcp_get_message(p, op->reply, l)) != JK_TRUE) { if (headeratclient == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "(%s) Tomcat is down or refused connection. " "No response has been sent to the client (yet)", p->worker->name); /* * communication with tomcat has been interrupted BEFORE * headers have been sent to the client. * * We mark it unrecoverable if recovery_opts set to * RECOVER_ABORT_IF_TCGETREQUEST */ if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST) op->recoverable = JK_FALSE; /* * We revert back to recoverable, if recovery_opts allow it * for GET or HEAD */ if (op->recoverable == JK_FALSE) { if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_HEAD) { if (!strcmp(s->method, "HEAD")) op->recoverable = JK_TRUE; } else if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_GET) { if (!strcmp(s->method, "GET")) op->recoverable = JK_TRUE; } } } else { jk_log(l, JK_LOG_ERROR, "(%s) Tomcat is down or network problems. " "Part of the response has already been sent to the client", p->worker->name); /* communication with tomcat has been interrupted AFTER * headers have been sent to the client. * headers (and maybe parts of the body) have already been * sent, therefore the response is "complete" in a sense * that nobody should append any data, especially no 500 error * page of the webserver! * * We mark it unrecoverable if recovery_opts set to * RECOVER_ABORT_IF_TCSENDHEADER */ if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER) op->recoverable = JK_FALSE; } JK_TRACE_EXIT(l); return rc; } rc = ajp_process_callback(op->reply, op->post, p, s, l); p->last_op = rc; /* no more data to be sent, fine we have finish here */ if (JK_AJP13_END_RESPONSE == rc) { JK_TRACE_EXIT(l); return JK_TRUE; } if (JK_AJP13_SEND_HEADERS == rc) { if (headeratclient == JK_FALSE) { headeratclient = JK_TRUE; continue; } else { /* Backend send headers twice? * This is protocol violation */ jk_log(l, JK_LOG_ERROR, "(%s) Tomcat already send headers", p->worker->name); op->recoverable = JK_FALSE; JK_TRACE_EXIT(l); return JK_FALSE; } } if (JK_STATUS_ERROR == rc || JK_STATUS_FATAL_ERROR == rc) { jk_log(l, JK_LOG_INFO, "(%s) request failed%s, " "because of response status %d, ", p->worker->name, rc == JK_STATUS_FATAL_ERROR ? "" : " (soft)", s->http_response_status); JK_TRACE_EXIT(l); return rc; } if (JK_AJP13_HAS_RESPONSE == rc) { /* * in upload-mode there is no second chance since * we may have already sent part of the uploaded data * to Tomcat. * In this case if Tomcat connection is broken we must * abort request and indicate error. * A possible work-around could be to store the uploaded * data to file and replay for it */ op->recoverable = JK_FALSE; rc = ajp_connection_tcp_send_message(p, op->post, l); if (rc != JK_TRUE) { jk_log(l, JK_LOG_ERROR, "(%s) Tomcat is down or network problems", p->worker->name); JK_TRACE_EXIT(l); return JK_FALSE; } } if (JK_AJP13_ERROR == rc) { /* * Tomcat has send invalid AJP message. * Loadbalancer if present will decide if * failover is possible. */ JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } if (JK_CLIENT_RD_ERROR == rc) { /* * Client has stop sending to us, so get out. * We assume this isn't our fault, so just a normal exit. */ JK_TRACE_EXIT(l); return JK_CLIENT_RD_ERROR; } if (JK_CLIENT_WR_ERROR == rc) { /* * Client has stop receiving to us, so get out. * We assume this isn't our fault, so just a normal exit. */ JK_TRACE_EXIT(l); return JK_CLIENT_WR_ERROR; } if (JK_INTERNAL_ERROR == rc) { /* * Internal error, like memory allocation or invalid packet lengths. */ JK_TRACE_EXIT(l); return JK_FATAL_ERROR; } if (JK_AJP13_NO_RESPONSE == rc) { /* * This is fine, loop again, more data to send. */ continue; } if (rc < 0) { op->recoverable = JK_FALSE; jk_log(l, JK_LOG_ERROR, "(%s) Callback returns with unknown value %d", p->worker->name, rc); JK_TRACE_EXIT(l); return JK_FALSE; } } /* XXX: Not reached? */ JK_TRACE_EXIT(l); return JK_FALSE; } static void ajp_update_stats(jk_endpoint_t *e, ajp_worker_t *aw, int rc, jk_log_context_t *l) { aw->s->readed += e->rd; aw->s->transferred += e->wr; JK_ATOMIC_DECREMENT(&(aw->s->busy)); if (rc == JK_TRUE) { aw->s->state = JK_AJP_STATE_OK; } else if (rc == JK_CLIENT_ERROR) { aw->s->state = JK_AJP_STATE_OK; aw->s->client_errors++; } else { aw->s->state = JK_AJP_STATE_ERROR; aw->s->errors++; aw->s->error_time = time(NULL); } } /* * service is now splitted in ajp_send_request and ajp_get_reply * much more easier to do errors recovery * * We serve here the request, using AJP13/AJP14 (e->proto) * * Return values of service() method for ajp13/ajp14 worker: * return value is_error e->recoverable reason * JK_FALSE JK_HTTP_SERVER_ERROR TRUE Invalid Parameters * (null values) * JK_SERVER_ERROR JK_HTTP_SERVER_ERROR TRUE Error during * initializing empty * request, response or * post body objects * JK_CLIENT_ERROR JK_HTTP_REQUEST_TOO_LARGE JK_TRUE Request doesn't fit * into buffer * (error during * ajp_marshal_into_msgb()) * JK_CLIENT_ERROR JK_HTTP_BAD_REQUEST JK_FALSE Error during * reading parts of * POST body from client * JK_FATAL_ERROR JK_HTTP_SERVER_ERROR JK_FALSE If ajp_send_request() * returns JK_FATAL_ERROR * and !op->recoverable. * JK_FATAL_ERROR JK_HTTP_SERVER_ERROR JK_FALSE If ajp_send_request() * returns JK_TRUE * but !op->recoverable. * This should never happen. * JK_CLIENT_ERROR JK_HTTP_BAD_REQUEST ? ajp_get_reply() * returns JK_CLIENT_RD_ERROR * JK_CLIENT_ERROR JK_HTTP_OK ? ajp_get_reply() * returns JK_CLIENT_WR_ERROR * JK_FATAL_ERROR JK_HTTP_SERVER_ERROR JK_TRUE ajp_get_reply() * returns JK_FATAL_ERROR * JK_FATAL_ERROR: protocol error or internal error * JK_FATAL_ERROR JK_HTTP_SERVER_ERROR JK_FALSE ajp_get_reply() * returns JK_FATAL_ERROR * JK_FATAL_ERROR: protocol error or internal error * JK_STATUS_ERROR JK_HTTP_SERVER_BUSY JK_TRUE ajp_get_reply() * returns JK_STATUS_ERROR * Only if op->recoverable and no more ajp13/ajp14 direct retries * JK_STATUS_ERROR JK_HTTP_SERVER_BUSY JK_FALSE ajp_get_reply() * returns JK_STATUS_ERROR * Only if !op->recoverable * JK_STATUS_FATAL_ERROR JK_HTTP_SERVER_BUSY JK_TRUE ajp_get_reply() * returns JK_STATUS_ERROR * Only if op->recoverable and no more ajp13/ajp14 direct retries * JK_STATUS_FATAL_ERROR JK_HTTP_SERVER_BUSY JK_FALSE ajp_get_reply() * returns JK_STATUS_FATAL_ERROR * Only if !op->recoverable * JK_REPLY_TIMEOUT JK_HTTP_GATEWAY_TIME_OUT JK_TRUE ajp_get_reply() * returns JK_REPLY_TIMEOUT * JK_AJP_PROTOCOL_ERROR JK_HTTP_GATEWAY_TIME_OUT ? ajp_get_reply() * returns JK_AJP_PROTOCOL_ERROR * ??? JK_FATAL_ERROR JK_HTTP_GATEWAY_TIME_OUT JK_FALSE ajp_get_reply() * returns something else * Only if !op->recoverable * ??? JK_FALSE JK_HTTP_SERVER_BUSY JK_TRUE ajp_get_reply() * returns JK_FALSE * Only if op->recoverable and no more ajp13/ajp14 direct retries * JK_TRUE JK_HTTP_OK ? OK */ static int JK_METHOD ajp_service(jk_endpoint_t *e, jk_ws_service_t *s, jk_log_context_t *l, int *is_error) { int i; int err = JK_TRUE; ajp_operation_t oper; ajp_operation_t *op = &oper; ajp_endpoint_t *p; ajp_worker_t *aw; int log_error; int rc = JK_UNSET; char *msg = ""; int retry_interval; int busy; JK_TRACE_ENTER(l); if (!e || !e->endpoint_private || !s || !is_error) { JK_LOG_NULL_PARAMS(l); if (is_error) *is_error = JK_HTTP_SERVER_ERROR; JK_TRACE_EXIT(l); return JK_FALSE; } /* Reset endpoint read and write sizes for * this request. */ e->rd = e->wr = 0; e->recoverable = JK_TRUE; p = e->endpoint_private; aw = p->worker; if (aw->sequence != aw->s->h.sequence) jk_ajp_pull(aw, JK_FALSE, l); aw->s->used++; /* Set returned error to SERVER ERROR */ *is_error = JK_HTTP_SERVER_ERROR; op->request = jk_b_new(&(p->pool)); if (!op->request) { jk_log(l, JK_LOG_ERROR, "(%s) Failed allocating AJP request message", aw->name); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } if (jk_b_set_buffer_size(op->request, aw->max_packet_size)) { jk_log(l, JK_LOG_ERROR, "(%s) Failed allocating AJP request message buffer", aw->name); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } jk_b_reset(op->request); op->reply = jk_b_new(&(p->pool)); if (!op->reply) { jk_log(l, JK_LOG_ERROR, "(%s) Failed allocating AJP reply message", aw->name); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } if (jk_b_set_buffer_size(op->reply, aw->max_packet_size)) { jk_log(l, JK_LOG_ERROR, "(%s) Failed allocating AJP reply message buffer", aw->name); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } op->post = jk_b_new(&(p->pool)); if (!op->post) { jk_log(l, JK_LOG_ERROR, "(%s) Failed allocating AJP post message", aw->name); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } if (jk_b_set_buffer_size(op->post, aw->max_packet_size)) { jk_log(l, JK_LOG_ERROR, "(%s) Failed allocating AJP post message buffer", aw->name); JK_TRACE_EXIT(l); return JK_SERVER_ERROR; } jk_b_reset(op->post); /* Set returned error to OK */ *is_error = JK_HTTP_OK; op->recoverable = JK_TRUE; op->uploadfd = -1; /* not yet used, later ;) */ p->left_bytes_to_send = s->content_length; p->reuse = JK_FALSE; p->hard_close = JK_FALSE; s->secret = aw->secret; /* * We get here initial request (in op->request) */ if (!ajp_marshal_into_msgb(op->request, s, l, p)) { *is_error = JK_HTTP_REQUEST_TOO_LARGE; jk_log(l, JK_LOG_INFO, "(%s) Creating AJP message failed " "without recovery - check max_packet_size", aw->name); aw->s->client_errors++; JK_TRACE_EXIT(l); return JK_CLIENT_ERROR; } if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "processing %s with %d retries", aw->name, aw->retries); } busy = JK_ATOMIC_INCREMENT(&(aw->s->busy)); if (aw->busy_limit > 0 && busy > aw->busy_limit) { JK_ATOMIC_DECREMENT(&(aw->s->busy)); e->recoverable = JK_TRUE; aw->s->errors++; aw->s->error_time = time(NULL); *is_error = JK_HTTP_SERVER_BUSY; rc = JK_BUSY_ERROR; jk_log(l, JK_LOG_ERROR, "(%s) sending request to tomcat failed (recoverable), " "busy limit %d reached (rc=%d, errors=%d, client_errors=%d).", aw->name, aw->busy_limit, rc, aw->s->errors, aw->s->client_errors); JK_TRACE_EXIT(l); return rc; } if (aw->s->state == JK_AJP_STATE_ERROR) aw->s->state = JK_AJP_STATE_PROBE; if (busy > aw->s->max_busy) aw->s->max_busy = busy; retry_interval = p->worker->retry_interval; for (i = 0; i < aw->retries; i++) { /* Reset reply message buffer for each retry */ jk_b_reset(op->reply); /* * ajp_send_request() already locally handles * reconnecting and broken connection detection. * So if we already failed in it, wait a bit before * retrying the same backend. */ if (i > 0 && retry_interval >= 0) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) retry %d, sleeping for %d ms before retrying", aw->name, i, retry_interval); jk_sleep(retry_interval); /* Pull shared memory if something changed during sleep */ if (aw->sequence != aw->s->h.sequence) jk_ajp_pull(aw, JK_FALSE, l); } /* * We're using op->request which hold initial request * if Tomcat is stopped or restarted, we will pass op->request * to next valid tomcat. */ log_error = JK_TRUE; rc = JK_UNSET; msg = ""; err = ajp_send_request(e, s, l, p, op); e->recoverable = op->recoverable; if (err == JK_CLIENT_RD_ERROR) { *is_error = JK_HTTP_BAD_REQUEST; msg = "because of client read error"; aw->s->client_errors++; rc = JK_CLIENT_ERROR; log_error = JK_FALSE; e->recoverable = JK_FALSE; /* Ajp message set reuse to TRUE in END_REQUEST message * However due to client bad request if the recovery * RECOVER_ABORT_IF_CLIENTERROR is set the physical connection * will be closed and application in Tomcat can catch that * generated exception, knowing the client aborted the * connection. This AJP protocol limitation, where we * should actually send some packet informing the backend * that client broke the connection in a middle of * request/response cycle. */ if (aw->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) { /* Mark the endpoint for shutdown */ p->reuse = JK_FALSE; p->hard_close = JK_TRUE; } } else if (err == JK_FATAL_ERROR) { *is_error = JK_HTTP_SERVER_BUSY; msg = "because of error during request sending"; rc = err; if (!op->recoverable) { *is_error = JK_HTTP_SERVER_ERROR; msg = "because of protocol error during request sending"; } } else if (err == JK_TRUE && op->recoverable) { /* Up to there we can recover */ err = ajp_get_reply(e, s, l, p, op); e->recoverable = op->recoverable; if (err == JK_TRUE) { *is_error = JK_HTTP_OK; /* Done with the request */ ajp_update_stats(e, aw, JK_TRUE, l); JK_TRACE_EXIT(l); return JK_TRUE; } if (err == JK_CLIENT_RD_ERROR) { *is_error = JK_HTTP_BAD_REQUEST; msg = "because of client read error"; aw->s->client_errors++; rc = JK_CLIENT_ERROR; log_error = JK_FALSE; e->recoverable = JK_FALSE; op->recoverable = JK_FALSE; if (aw->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) { /* Mark the endpoint for shutdown */ p->reuse = JK_FALSE; p->hard_close = JK_TRUE; } } else if (err == JK_CLIENT_WR_ERROR) { /* XXX: Is this correct to log this as 200? */ *is_error = JK_HTTP_OK; msg = "because of client write error"; aw->s->client_errors++; rc = JK_CLIENT_ERROR; log_error = JK_FALSE; e->recoverable = JK_FALSE; op->recoverable = JK_FALSE; if (aw->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) { /* Mark the endpoint for shutdown */ p->reuse = JK_FALSE; p->hard_close = JK_TRUE; } } else if (err == JK_FATAL_ERROR) { *is_error = JK_HTTP_SERVER_ERROR; msg = "because of server error"; rc = err; } else if (err == JK_REPLY_TIMEOUT) { *is_error = JK_HTTP_GATEWAY_TIME_OUT; msg = "because of reply timeout"; aw->s->reply_timeouts++; rc = err; } else if (err == JK_STATUS_ERROR || err == JK_STATUS_FATAL_ERROR) { *is_error = JK_HTTP_SERVER_BUSY; msg = "because of response status"; rc = err; } else if (err == JK_AJP_PROTOCOL_ERROR) { *is_error = JK_HTTP_BAD_GATEWAY; msg = "because of protocol error"; rc = err; } /* This should only be the cases err == JK_FALSE */ else { /* if we can't get reply, check if unrecoverable flag was set * if is_recoverable_error is cleared, we have started * receiving upload data and we must consider that * operation is no more recoverable */ *is_error = JK_HTTP_BAD_GATEWAY; msg = ""; rc = JK_FALSE; } } else { /* XXX: this should never happen: * ajp_send_request() never returns JK_TRUE if !op->recoverable. * and all other return values have already been handled. */ e->recoverable = JK_FALSE; *is_error = JK_HTTP_SERVER_ERROR; msg = "because of an unknown reason"; rc = JK_FATAL_ERROR; jk_log(l, JK_LOG_ERROR, "(%s) unexpected condition err=%d (%srecoverable)", aw->name, err, op->recoverable ? "" : "un"); } if (!op->recoverable && log_error == JK_TRUE) { jk_log(l, JK_LOG_ERROR, "(%s) sending request to tomcat failed (unrecoverable), " "%s " "(attempt=%d)", aw->name, msg, i + 1); } else { jk_log(l, JK_LOG_INFO, "(%s) sending request to tomcat failed (%srecoverable), " "%s " "(attempt=%d)", aw->name, op->recoverable ? "" : "un", msg, i + 1); } if (!op->recoverable) { ajp_update_stats(e, aw, rc, l); JK_TRACE_EXIT(l); return rc; } /* Get another connection from the pool and try again. * Note: All sockets are probably closed already. */ ajp_next_connection(p, l); } ajp_update_stats(e, aw, rc, l); /* Log the error only once per failed request. */ jk_log(l, JK_LOG_ERROR, "(%s) connecting to tomcat failed " "(rc=%d, errors=%d, client_errors=%d).", aw->name, rc, aw->s->errors, aw->s->client_errors); JK_TRACE_EXIT(l); return rc; } /* * Validate the worker (ajp13/ajp14) */ int ajp_validate(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l, int proto) { int port; const char *host; JK_TRACE_ENTER(l); if (proto == AJP13_PROTO) { port = AJP13_DEF_PORT; host = AJP13_DEF_HOST; } else if (proto == AJP14_PROTO) { port = AJP14_DEF_PORT; host = AJP14_DEF_HOST; } else { if (pThis && pThis->worker_private) { ajp_worker_t *p = pThis->worker_private; jk_log(l, JK_LOG_ERROR, "(%s) unknown protocol %d", p->name, proto); } else { jk_log(l, JK_LOG_ERROR, "(unset worker) unknown protocol %d", proto); } JK_TRACE_EXIT(l); return JK_FALSE; } if (pThis && pThis->worker_private) { const char *tmp; ajp_worker_t *p = pThis->worker_private; p->worker.we = we; p->port = jk_get_worker_port(props, p->name, port); if (!host) { host = "undefined"; } tmp = jk_get_worker_host(props, p->name, host); if (jk_shm_str_init(p->host, tmp, "host name", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } p->prefer_ipv6 = jk_get_worker_prefer_ipv6(props, p->name, JK_FALSE); tmp = jk_get_worker_source(props, p->name, ""); if (jk_shm_str_init(p->source, tmp, "source address", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (p->s->h.sequence == 0) { /* Initial setup. */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s target is '%s:%d'", p->name, p->host, p->port); if (p->port > 0) { if (!jk_resolve(p->host, p->port, &p->worker_inet_addr, we->pool, p->prefer_ipv6, l)) { jk_log(l, JK_LOG_ERROR, "worker %s can't resolve tomcat address %s", p->name, p->host); p->s->port = p->port = 0; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s contact is disabled", p->name); } } if (p->source && *p->source) { if (!jk_resolve(p->source, 0, &p->worker_source_inet_addr, we->pool, p->prefer_ipv6, l)) { p->worker_source_inet_addr.ipaddr_ptr = NULL; jk_log(l, JK_LOG_WARNING, "worker %s can't resolve source address '%s'", p->name, p->source); } } p->addr_sequence = 0; p->s->addr_sequence = 0; p->s->last_maintain_time = time(NULL); p->s->last_reset = p->s->last_maintain_time; p->s->port = p->port; jk_shm_str_copy(p->s->host, p->host, l); jk_ajp_push(p, JK_TRUE, l); } else { /* Somebody already setup this worker. */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "worker %s contact '%s:%d' already configured " "type=%d (%d) [%d]", p->name, p->host, p->port, p->s->h.type, p->s->h.sequence, p->s->addr_sequence); /* Force resolve */ p->addr_sequence = -1; jk_ajp_pull(p, JK_TRUE, l); } JK_TRACE_EXIT(l); return JK_TRUE; } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return JK_FALSE; } static int ajp_create_endpoint_cache(ajp_worker_t *p, int proto, jk_log_context_t *l) { unsigned int i; time_t now = time(NULL); JK_TRACE_ENTER(l); p->ep_cache = (ajp_endpoint_t **)calloc(1, sizeof(ajp_endpoint_t *) * p->ep_cache_sz); if (!p->ep_cache) { JK_TRACE_EXIT(l); return JK_FALSE; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) setting connection pool size to %u with min %u " "and acquire timeout %d", p->name, p->ep_cache_sz, p->ep_mincache_sz, p->cache_acquire_timeout); for (i = 0; i < p->ep_cache_sz; i++) { p->ep_cache[i] = (ajp_endpoint_t *)calloc(1, sizeof(ajp_endpoint_t)); if (!p->ep_cache[i]) { jk_log(l, JK_LOG_ERROR, "(%s) allocating endpoint slot %d (errno=%d)", p->name, i, errno); JK_TRACE_EXIT(l); return JK_FALSE; } p->ep_cache[i]->sd = JK_INVALID_SOCKET; p->ep_cache[i]->reuse = JK_FALSE; p->ep_cache[i]->avail = JK_TRUE; p->ep_cache[i]->hard_close = JK_FALSE; p->ep_cache[i]->last_access = now; jk_open_pool(&(p->ep_cache[i]->pool), p->ep_cache[i]->buf, sizeof(p->ep_cache[i]->buf)); p->ep_cache[i]->worker = p; p->ep_cache[i]->endpoint.endpoint_private = p->ep_cache[i]; p->ep_cache[i]->proto = proto; p->ep_cache[i]->endpoint.service = ajp_service; p->ep_cache[i]->endpoint.done = ajp_done; p->ep_cache[i]->last_op = JK_AJP13_END_RESPONSE; p->ep_cache[i]->addr_sequence = 0; } JK_TRACE_EXIT(l); return JK_TRUE; } int ajp_init(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l, int proto) { int rc = JK_FALSE; int cache; /* * start the connection cache */ JK_TRACE_ENTER(l); cache = jk_get_worker_def_cache_size(proto); if (pThis && pThis->worker_private) { ajp_worker_t *p = pThis->worker_private; p->worker.we = we; p->ep_cache_sz = jk_get_worker_cache_size(props, p->name, cache); p->ep_mincache_sz = jk_get_worker_cache_size_min(props, p->name, (p->ep_cache_sz+1) / 2); p->socket_timeout = jk_get_worker_socket_timeout(props, p->name, AJP_DEF_SOCKET_TIMEOUT); p->socket_connect_timeout = jk_get_worker_socket_connect_timeout(props, p->name, p->socket_timeout * 1000); p->keepalive = jk_get_worker_socket_keepalive(props, p->name, JK_FALSE); p->cache_timeout = jk_get_worker_cache_timeout(props, p->name, AJP_DEF_CACHE_TIMEOUT); p->ping_timeout = jk_get_worker_ping_timeout(props, p->name, AJP_DEF_PING_TIMEOUT); p->ping_mode = jk_get_worker_ping_mode(props, p->name, AJP_CPING_NONE); p->connect_timeout = jk_get_worker_connect_timeout(props, p->name, AJP_DEF_CONNECT_TIMEOUT); p->prepost_timeout = jk_get_worker_prepost_timeout(props, p->name, AJP_DEF_PREPOST_TIMEOUT); if ((p->ping_mode & AJP_CPING_CONNECT) && p->connect_timeout == AJP_DEF_CONNECT_TIMEOUT) p->connect_timeout = p->ping_timeout; if ((p->ping_mode & AJP_CPING_PREPOST) && p->prepost_timeout == AJP_DEF_PREPOST_TIMEOUT) p->prepost_timeout = p->ping_timeout; p->conn_ping_interval = jk_get_worker_conn_ping_interval(props, p->name, 0); if ((p->ping_mode & AJP_CPING_INTERVAL) && p->conn_ping_interval == 0) { /* XXX: Ping timeout is in miliseconds * and ping_interval is in seconds. * Use 10 times larger value for ping interval * (ping_timeout / 1000) * 10 */ p->conn_ping_interval = p->ping_timeout / 100; } p->reply_timeout = jk_get_worker_reply_timeout(props, p->name, AJP_DEF_REPLY_TIMEOUT); p->recovery_opts = jk_get_worker_recovery_opts(props, p->name, AJP_DEF_RECOVERY_OPTS); p->retries = jk_get_worker_retries(props, p->name, JK_RETRIES); p->lb_retries = jk_get_worker_lb_retries(props, p->name, JK_LB_RETRIES); p->max_packet_size = jk_get_max_packet_size(props, p->name); p->socket_buf = jk_get_worker_socket_buffer(props, p->name, p->max_packet_size); p->retry_interval = jk_get_worker_retry_interval(props, p->name, JK_SLEEP_DEF); p->cache_acquire_timeout = jk_get_worker_cache_acquire_timeout(props, p->name, p->retries * p->retry_interval); p->busy_limit = jk_get_worker_busy_limit(props, p->name, 0); jk_get_worker_fail_on_status(props, p->name, &(p->http_status_fail), &(p->http_status_fail_num)); if (p->retries < 1) { jk_log(l, JK_LOG_INFO, "(%s) number of retries must be greater then 1. " "Setting to default=%d", p->name, JK_RETRIES); p->retries = JK_RETRIES; } p->maintain_time = jk_get_worker_maintain_time(props); if(p->maintain_time < 0) p->maintain_time = 0; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "(%s) setting endpoint options:", p->name); jk_log(l, JK_LOG_DEBUG, "keepalive: %d", p->keepalive); jk_log(l, JK_LOG_DEBUG, "socket timeout: %d", p->socket_timeout); jk_log(l, JK_LOG_DEBUG, "socket connect timeout: %d", p->socket_connect_timeout); jk_log(l, JK_LOG_DEBUG, "buffer size: %d", p->socket_buf); jk_log(l, JK_LOG_DEBUG, "pool timeout: %d", p->cache_timeout); jk_log(l, JK_LOG_DEBUG, "ping timeout: %d", p->ping_timeout); jk_log(l, JK_LOG_DEBUG, "connect timeout: %d", p->connect_timeout); jk_log(l, JK_LOG_DEBUG, "reply timeout: %d", p->reply_timeout); jk_log(l, JK_LOG_DEBUG, "prepost timeout: %d", p->prepost_timeout); jk_log(l, JK_LOG_DEBUG, "recovery options: %d", p->recovery_opts); jk_log(l, JK_LOG_DEBUG, "retries: %d", p->retries); jk_log(l, JK_LOG_DEBUG, "max packet size: %d", p->max_packet_size); jk_log(l, JK_LOG_DEBUG, "retry interval: %d", p->retry_interval); jk_log(l, JK_LOG_DEBUG, "busy limit: %d", p->busy_limit); } /* * Need to initialize secret here since we could return from inside * of the following loop */ p->secret = jk_get_worker_secret(props, p->name); if (!ajp_create_endpoint_cache(p, proto, l)) { jk_log(l, JK_LOG_ERROR, "(%s) allocating connection pool of size %u", p->name, p->ep_cache_sz); JK_TRACE_EXIT(l); return JK_FALSE; } rc = JK_TRUE; } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return rc; } int JK_METHOD ajp_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *l) { int rc; ajp_worker_t *aw; JK_TRACE_ENTER(l); if (name == NULL || w == NULL) { JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } aw = (ajp_worker_t *) calloc(1, sizeof(ajp_worker_t)); if (!aw) { jk_log(l, JK_LOG_ERROR, "(%s) malloc of private_data failed", name); JK_TRACE_EXIT(l); return JK_FALSE; } jk_open_pool(&aw->p, aw->buf, sizeof(jk_pool_atom_t) * TINY_POOL_SIZE); if (jk_shm_str_init(aw->name, name, "name", l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } aw->login = NULL; aw->ep_cache_sz = 0; aw->ep_cache = NULL; aw->connect_retry_attempts = AJP_DEF_RETRY_ATTEMPTS; aw->worker.worker_private = aw; aw->worker.maintain = ajp_maintain; aw->worker.shutdown = ajp_shutdown; aw->logon = NULL; *w = &aw->worker; aw->s = jk_shm_alloc_ajp_worker(&aw->p, name, l); if (!aw->s) { jk_close_pool(&aw->p); free(aw); jk_log(l, JK_LOG_ERROR, "(%s) allocating ajp worker record from shared memory", aw->name); JK_TRACE_EXIT(l); return JK_FALSE; } JK_INIT_CS(&aw->cs, rc); if (!rc) { jk_log(l, JK_LOG_ERROR, "(%s) creating thread lock (errno=%d)", aw->name, errno); jk_close_pool(&aw->p); free(aw); JK_TRACE_EXIT(l); return JK_FALSE; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "ajp worker '%s' type=%d created", aw->name, aw->s->h.type); JK_TRACE_EXIT(l); return JK_TRUE; } int ajp_destroy(jk_worker_t **pThis, jk_log_context_t *l, int proto) { JK_TRACE_ENTER(l); if (pThis && *pThis && (*pThis)->worker_private) { unsigned int i; ajp_worker_t *aw = (*pThis)->worker_private; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) up to %u endpoints to close", aw->name, aw->ep_cache_sz); for (i = 0; i < aw->ep_cache_sz; i++) { if (aw->ep_cache[i]) ajp_close_endpoint(aw->ep_cache[i], l); } free(aw->ep_cache); JK_DELETE_CS(&aw->cs); if (aw->login) { /* take care of removing previously allocated data */ if (aw->login->servlet_engine_name) free(aw->login->servlet_engine_name); free(aw->login); aw->login = NULL; } jk_close_pool(&aw->p); free(aw); JK_TRACE_EXIT(l); return JK_TRUE; } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } int JK_METHOD ajp_done(jk_endpoint_t **e, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (e && *e && (*e)->endpoint_private) { ajp_endpoint_t *p = (*e)->endpoint_private; ajp_worker_t *w = p->worker; /* set last_access only if needed */ if (w->cache_timeout > 0) p->last_access = time(NULL); if (w->s->addr_sequence != p->addr_sequence) { p->reuse = JK_FALSE; p->addr_sequence = w->s->addr_sequence; } ajp_reset_endpoint(p, l); *e = NULL; JK_ENTER_CS(&w->cs); p->avail = JK_TRUE; JK_LEAVE_CS(&w->cs); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "recycling connection pool for worker %s and socket %d", p->worker->name, (int)p->sd); JK_TRACE_EXIT(l); return JK_TRUE; } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } int ajp_get_endpoint(jk_worker_t *pThis, jk_endpoint_t **je, jk_log_context_t *l, int proto) { JK_TRACE_ENTER(l); if (pThis && pThis->worker_private && je) { ajp_worker_t *aw = pThis->worker_private; ajp_endpoint_t *ae = NULL; int retry = 0; *je = NULL; /* Loop until cache_acquire_timeout interval elapses */ while ((retry * JK_SLEEP_DEF) < aw->cache_acquire_timeout) { unsigned int slot; JK_ENTER_CS(&aw->cs); /* Try to find connected socket cache entry */ for (slot = 0; slot < aw->ep_cache_sz; slot++) { if (IS_SLOT_AVAIL(aw->ep_cache[slot]) && IS_VALID_SOCKET(aw->ep_cache[slot]->sd)) { ae = aw->ep_cache[slot]; if (ae->reuse) { aw->ep_cache[slot]->avail = JK_FALSE; break; } else { /* XXX: We shouldn't have non reusable * opened socket in the cache */ ajp_reset_endpoint(ae, l); ae->avail = JK_TRUE; ae = NULL; jk_log(l, JK_LOG_WARNING, "(%s) closing non reusable pool slot=%d", aw->name, slot); } } } if (!ae) { /* No connected cache entry found. * Use the first free one. */ for (slot = 0; slot < aw->ep_cache_sz; slot++) { if (IS_SLOT_AVAIL(aw->ep_cache[slot])) { ae = aw->ep_cache[slot]; aw->ep_cache[slot]->avail = JK_FALSE; break; } } } JK_LEAVE_CS(&aw->cs); if (ae) { if (aw->cache_timeout > 0) ae->last_access = time(NULL); *je = &ae->endpoint; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) acquired connection pool slot=%u " "after %d retries", aw->name, slot, retry); JK_TRACE_EXIT(l); return JK_TRUE; } else { retry++; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "could not get free endpoint for worker %s" " (retry %d, sleeping for %d ms)", aw->name, retry, JK_SLEEP_DEF); jk_sleep(JK_SLEEP_DEF); } } jk_log(l, JK_LOG_WARNING, "Unable to get the free endpoint for worker %s from %u slots", aw->name, aw->ep_cache_sz); } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return JK_FALSE; } int JK_METHOD ajp_maintain(jk_worker_t *pThis, time_t mstarted, int global, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && pThis->worker_private) { ajp_worker_t *aw = pThis->worker_private; int i; unsigned int n = 0, k = 0, cnt = 0; unsigned int m, m_count = 0; jk_sock_t *m_sock; /* Do connection pool maintenance only if timeouts or keepalives are set */ if (aw->cache_timeout <= 0 && aw->conn_ping_interval <= 0) { /* Nothing to do. */ JK_TRACE_EXIT(l); return JK_TRUE; } JK_ENTER_CS(&aw->cs); /* Count open slots */ for (i = (int)aw->ep_cache_sz - 1; i >= 0; i--) { if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) cnt++; } m_sock = (jk_sock_t *)malloc((cnt + 1) * sizeof(jk_sock_t)); /* Handle worker cache timeouts */ if (aw->cache_timeout > 0) { for (i = (int)aw->ep_cache_sz - 1; i >= 0; i--) { /* Skip the closed sockets */ if (IS_SLOT_AVAIL(aw->ep_cache[i]) && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { int elapsed = (int)difftime(mstarted, aw->ep_cache[i]->last_access); if (elapsed > aw->cache_timeout) { time_t rt = 0; n++; if (JK_IS_DEBUG_LEVEL(l)) rt = time(NULL); aw->ep_cache[i]->reuse = JK_FALSE; m_sock[m_count++] = aw->ep_cache[i]->sd; aw->ep_cache[i]->sd = JK_INVALID_SOCKET; ajp_reset_endpoint(aw->ep_cache[i], l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) cleaning pool slot=%d elapsed %d in %d", aw->name, i, elapsed, (int)(difftime(time(NULL), rt))); } } if (cnt <= aw->ep_mincache_sz + n) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "(%s) reached pool min size %u from %u cache slots", aw->name, aw->ep_mincache_sz, aw->ep_cache_sz); } break; } } } /* Handle worker connection keepalive */ if (aw->conn_ping_interval > 0 && aw->ping_timeout > 0) { for (i = (int)aw->ep_cache_sz - 1; i >= 0; i--) { /* Skip the closed sockets */ if (IS_SLOT_AVAIL(aw->ep_cache[i]) && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { int elapsed = (int)difftime(mstarted, aw->ep_cache[i]->last_access); if (elapsed > aw->conn_ping_interval) { k++; /* handle cping/cpong. */ if (ajp_handle_cping_cpong(aw->ep_cache[i], aw->ping_timeout, l) == JK_FALSE) { jk_log(l, JK_LOG_INFO, "(%s) failed sending request, " "socket %d keepalive cping/cpong " "failure (errno=%d)", aw->name, aw->ep_cache[i]->sd, aw->ep_cache[i]->last_errno); aw->ep_cache[i]->reuse = JK_FALSE; m_sock[m_count++] = aw->ep_cache[i]->sd; aw->ep_cache[i]->sd = JK_INVALID_SOCKET; ajp_reset_endpoint(aw->ep_cache[i], l); } } } } } JK_LEAVE_CS(&aw->cs); /* Shutdown sockets outside of the lock. * This has benefits only if maintain was * called from the watchdog thread. */ for (m = 0; m < m_count; m++) { if (IS_VALID_SOCKET(m_sock[m])) { jk_shutdown_socket(m_sock[m], l); JK_ATOMIC_DECREMENT(&(aw->s->connected)); } } free(m_sock); if ((k + n) && JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) pinged %u and recycled %u sockets in %d seconds " "from %u pool slots", aw->name, k, n, (int)(difftime(time(NULL), mstarted)), aw->ep_cache_sz); JK_TRACE_EXIT(l); return JK_TRUE; } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return JK_FALSE; } int JK_METHOD ajp_shutdown(jk_worker_t *pThis, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && pThis->worker_private) { ajp_worker_t *aw = pThis->worker_private; int i; unsigned int n = 0; JK_ENTER_CS(&aw->cs); for (i = (int)aw->ep_cache_sz - 1; i >= 0; i--) { /* Skip the closed sockets */ if (IS_SLOT_AVAIL(aw->ep_cache[i]) && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) { n++; aw->ep_cache[i]->reuse = JK_FALSE; aw->ep_cache[i]->hard_close = JK_TRUE; ajp_reset_endpoint(aw->ep_cache[i], l); aw->ep_cache[i]->sd = JK_INVALID_SOCKET; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) shut down pool slot=%d", aw->name, i); } } JK_LEAVE_CS(&aw->cs); if (n && JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "(%s) shut down %u sockets from %u pool slots", aw->name, n, aw->ep_cache_sz); JK_TRACE_EXIT(l); return JK_TRUE; } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return JK_FALSE; } int ajp_has_endpoint(jk_worker_t *pThis, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (pThis && pThis->worker_private) { ajp_worker_t *aw = pThis->worker_private; unsigned int slot; JK_ENTER_CS(&aw->cs); /* Try to find connected socket cache entry */ for (slot = 0; slot < aw->ep_cache_sz; slot++) { if (IS_SLOT_AVAIL(aw->ep_cache[slot])) { JK_LEAVE_CS(&aw->cs); return JK_TRUE; } } JK_LEAVE_CS(&aw->cs); } else { JK_LOG_NULL_PARAMS(l); } JK_TRACE_EXIT(l); return JK_FALSE; } tomcat-connectors-1.2.50-src/native/common/jk_pool.c0000644000000000000020000001076614655113617020715 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Simple memory pool * * Author: Gal Shachor * ***************************************************************************/ #include "jk_pool.h" #define DEFAULT_DYNAMIC 10 void jk_open_pool(jk_pool_t *p, jk_pool_atom_t *buf, size_t size) { p->pos = 0; p->size = size; p->buf = (char *)buf; p->dyn_pos = 0; p->dynamic = NULL; p->dyn_size = 0; } void jk_close_pool(jk_pool_t *p) { jk_reset_pool(p); if (p->dynamic) { free(p->dynamic); } } void jk_reset_pool(jk_pool_t *p) { if (p->dyn_pos && p->dynamic) { size_t i; for (i = 0; i < p->dyn_pos; i++) { if (p->dynamic[i]) { free(p->dynamic[i]); } } } p->dyn_pos = 0; p->pos = 0; } void *jk_pool_alloc(jk_pool_t *p, size_t size) { void *rc = NULL; if (size == 0) return NULL; size = JK_ALIGN_DEFAULT(size); if ((p->size - p->pos) >= size) { rc = &(p->buf[p->pos]); p->pos += size; } else { if (p->dyn_size == p->dyn_pos) { size_t new_dyn_size = p->dyn_size * 2 + DEFAULT_DYNAMIC; void **new_dynamic = (void **)realloc(p->dynamic, new_dyn_size * sizeof(void *)); if (new_dynamic) { p->dynamic = new_dynamic; p->dyn_size = new_dyn_size; } else { return NULL; } } rc = p->dynamic[p->dyn_pos] = malloc(size); if (p->dynamic[p->dyn_pos]) { p->dyn_pos++; } } return rc; } void *jk_pool_calloc(jk_pool_t *p, size_t size) { void *rc = jk_pool_alloc(p, size); if (rc) memset(rc, 0, size); return rc; } void *jk_pool_realloc(jk_pool_t *p, size_t sz, const void *old, size_t old_sz) { char *rc; if (!p || (sz < old_sz)) { return NULL; } if (!old) return jk_pool_calloc(p, sz); rc = (char *)jk_pool_alloc(p, sz); if (rc) { memcpy(rc, old, old_sz); memset(rc + old_sz, 0, sz - old_sz); } return rc; } char *jk_pool_strdup(jk_pool_t *p, const char *s) { char *rc = NULL; if (s && p) { size_t size = strlen(s); if (!size) { return ""; } size++; rc = jk_pool_alloc(p, size); if (rc) { memcpy(rc, s, size); } } return rc; } char *jk_pool_strcat(jk_pool_t *p, const char *s, const char *a) { char *rc = NULL; if (s && a && p) { size_t szs = strlen(s); size_t sza = strlen(a); if ((szs + sza) == 0) { return ""; } rc = jk_pool_alloc(p, szs + sza + 1); if (rc) { memcpy(rc, s, szs); memcpy(rc + szs, a, sza + 1); } } return rc; } char *jk_pool_strcatv(jk_pool_t *p, ...) { char *cp; char *rc = NULL; va_list ap; if (p) { char *str; size_t size = 0; va_start(ap, p); while ((str = va_arg(ap, char *)) != 0) { size += strlen(str); } va_end(ap); if (size == 0) { return ""; } size++; cp = rc = jk_pool_alloc(p, size); if (rc) { size_t len = 0; va_start(ap, p); while ((str = va_arg(ap, char *)) != 0) { len = strlen(str); memcpy(cp, str, len); cp += len; } va_end(ap); *cp = '\0'; } } return rc; } tomcat-connectors-1.2.50-src/native/common/ap_snprintf.c0000644000000000000020000010532514655113617021577 0ustar rootbin/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * This code is based on, and used with the permission of, the * SIO stdio-replacement strx_* functions by Panos Tsirigotis * for xinetd. */ #define BUILD_STANDALONE #ifndef BUILD_STANDALONE #include "httpd.h" #else #include "ap_snprintf.h" #endif #include #include #include #include #include #include #include #ifdef WIN32 #include #endif typedef enum { NO = 0, YES = 1 } boolean_e; #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #ifndef AP_LONGEST_LONG #define AP_LONGEST_LONG long #endif #define NUL '\0' #define WIDE_INT long #define WIDEST_INT AP_LONGEST_LONG typedef WIDE_INT wide_int; typedef unsigned WIDE_INT u_wide_int; typedef WIDEST_INT widest_int; #ifdef __TANDEM /* Although Tandem supports "long long" there is no unsigned variant. */ typedef unsigned long u_widest_int; #else typedef unsigned WIDEST_INT u_widest_int; #endif typedef int bool_int; #define S_NULL "(null)" #define S_NULL_LEN 6 #define FLOAT_DIGITS 6 #define EXPONENT_LENGTH 10 /* * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions * * XXX: this is a magic number; do not decrease it */ #define NUM_BUF_SIZE 512 /* * cvt - IEEE floating point formatting routines. * Derived from UNIX V7, Copyright(C) Caldera International Inc. */ /* * ap_ecvt converts to decimal * the number of digits is specified by ndigit * decpt is set to the position of the decimal point * sign is set to 0 for positive, 1 for negative */ #define NDIG 80 /* buf must have at least NDIG bytes */ static char *ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf) { register int r2; double fi, fj; register char *p, *p1; if (ndigits >= NDIG - 1) ndigits = NDIG - 2; r2 = 0; *sign = 0; p = &buf[0]; if (arg < 0) { *sign = 1; arg = -arg; } arg = modf(arg, &fi); p1 = &buf[NDIG]; /* * Do integer part */ if (fi != 0) { p1 = &buf[NDIG]; while (p1 > &buf[0] && fi != 0) { fj = modf(fi / 10, &fi); *--p1 = (int) ((fj + .03) * 10) + '0'; r2++; } while (p1 < &buf[NDIG]) *p++ = *p1++; } else if (arg > 0) { while ((fj = arg * 10) < 1) { arg = fj; r2--; } } p1 = &buf[ndigits]; if (eflag == 0) p1 += r2; *decpt = r2; if (p1 < &buf[0]) { buf[0] = '\0'; return (buf); } while (p <= p1 && p < &buf[NDIG]) { arg *= 10; arg = modf(arg, &fj); *p++ = (int) fj + '0'; } if (p1 >= &buf[NDIG]) { buf[NDIG - 1] = '\0'; return (buf); } p = p1; *p1 += 5; while (*p1 > '9') { *p1 = '0'; if (p1 > buf) ++ * --p1; else { *p1 = '1'; (*decpt)++; if (eflag == 0) { if (p > buf) *p = '0'; p++; } } } *p = '\0'; return (buf); } static char *ap_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) { return (ap_cvt(arg, ndigits, decpt, sign, 1, buf)); } static char *ap_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) { return (ap_cvt(arg, ndigits, decpt, sign, 0, buf)); } /* * ap_gcvt - Floating output conversion to * minimal length string */ static char *ap_gcvt(double number, int ndigit, char *buf, boolean_e altform) { int sign, decpt; register char *p1, *p2; register int i; char buf1[NDIG]; p1 = ap_ecvt(number, ndigit, &decpt, &sign, buf1); p2 = buf; if (sign) *p2++ = '-'; for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) ndigit--; if ((decpt >= 0 && decpt - ndigit > 4) || (decpt < 0 && decpt < -3)) { /* use E-style */ decpt--; *p2++ = *p1++; *p2++ = '.'; for (i = 1; i < ndigit; i++) *p2++ = *p1++; *p2++ = 'e'; if (decpt < 0) { decpt = -decpt; *p2++ = '-'; } else *p2++ = '+'; if (decpt / 100 > 0) *p2++ = decpt / 100 + '0'; if (decpt / 10 > 0) *p2++ = (decpt % 100) / 10 + '0'; *p2++ = decpt % 10 + '0'; } else { if (decpt <= 0) { if (*p1 != '0') *p2++ = '.'; while (decpt < 0) { decpt++; *p2++ = '0'; } } for (i = 1; i <= ndigit; i++) { *p2++ = *p1++; if (i == decpt) *p2++ = '.'; } if (ndigit < decpt) { while (ndigit++ < decpt) *p2++ = '0'; *p2++ = '.'; } } if (p2[-1] == '.' && !altform) p2--; *p2 = '\0'; return (buf); } /* * The INS_CHAR macro inserts a character in the buffer and writes * the buffer back to disk if necessary * It uses the char pointers sp and bep: * sp points to the next available character in the buffer * bep points to the end-of-buffer+1 * While using this macro, note that the nextb pointer is NOT updated. * * NOTE: Evaluation of the c argument should not have any side-effects */ #define INS_CHAR(c, sp, bep, cc) \ { \ if (sp >= bep) { \ vbuff->curpos = sp; \ if (flush_func(vbuff)) \ return -1; \ sp = vbuff->curpos; \ bep = vbuff->endpos; \ } \ *sp++ = (c); \ cc++; \ } #define NUM(c) (c - '0') #define STR_TO_DEC(str, num) \ num = NUM(*str++); \ while (ap_isdigit(*str)) \ { \ num *= 10; \ num += NUM(*str++); \ } /* * This macro does zero padding so that the precision * requirement is satisfied. The padding is done by * adding '0's to the left of the string that is going * to be printed. We don't allow precision to be large * enough that we continue past the start of s. * * NOTE: this makes use of the magic info that s is * always based on num_buf with a size of NUM_BUF_SIZE. */ #define FIX_PRECISION(adjust, precision, s, s_len) \ if (adjust) { \ int p = precision < NUM_BUF_SIZE - 1 ? precision : NUM_BUF_SIZE - 1; \ while (s_len < p) \ { \ *--s = '0'; \ s_len++; \ } \ } /* * Macro that does padding. The padding is done by printing * the character ch. */ #define PAD(width, len, ch) do \ { \ INS_CHAR(ch, sp, bep, cc); \ width--; \ } \ while (width > len) /* * Prefix the character ch to the string str * Increase length * Set the has_prefix flag */ #define PREFIX(str, length, ch) *--str = ch; length++; has_prefix = YES /* * Convert num to its decimal format. * Return value: * - a pointer to a string containing the number (no sign) * - len contains the length of the string * - is_negative is set to TRUE or FALSE depending on the sign * of the number (always set to FALSE if is_unsigned is TRUE) * * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) * * Note: we have 2 versions. One is used when we need to use quads * (conv_10_quad), the other when we don't (conv_10). We're assuming the * latter is faster. */ static char *conv_10(register wide_int num, register bool_int is_unsigned, register bool_int *is_negative, char *buf_end, register int *len) { register char *p = buf_end; register u_wide_int magnitude; if (is_unsigned) { magnitude = (u_wide_int) num; *is_negative = FALSE; } else { *is_negative = (num < 0); /* * On a 2's complement machine, negating the most negative integer * results in a number that cannot be represented as a signed integer. * Here is what we do to obtain the number's magnitude: * a. add 1 to the number * b. negate it (becomes positive) * c. convert it to unsigned * d. add 1 */ if (*is_negative) { wide_int t = num + 1; magnitude = ((u_wide_int) -t) + 1; } else magnitude = (u_wide_int) num; } /* * We use a do-while loop so that we write at least 1 digit */ do { register u_wide_int new_magnitude = magnitude / 10; *--p = (char) (magnitude - new_magnitude * 10 + '0'); magnitude = new_magnitude; } while (magnitude); *len = buf_end - p; return (p); } static char *conv_10_quad(widest_int num, register bool_int is_unsigned, register bool_int *is_negative, char *buf_end, register int *len) { register char *p = buf_end; u_widest_int magnitude; /* * We see if we can use the faster non-quad version by checking the * number against the largest long value it can be. If <=, we * punt to the quicker version. */ if ((num <= ULONG_MAX && is_unsigned) || (num <= LONG_MAX && !is_unsigned)) return(conv_10((wide_int)num, is_unsigned, is_negative, buf_end, len)); if (is_unsigned) { magnitude = (u_widest_int) num; *is_negative = FALSE; } else { *is_negative = (num < 0); /* * On a 2's complement machine, negating the most negative integer * results in a number that cannot be represented as a signed integer. * Here is what we do to obtain the number's magnitude: * a. add 1 to the number * b. negate it (becomes positive) * c. convert it to unsigned * d. add 1 */ if (*is_negative) { widest_int t = num + 1; magnitude = ((u_widest_int) -t) + 1; } else magnitude = (u_widest_int) num; } /* * We use a do-while loop so that we write at least 1 digit */ do { u_widest_int new_magnitude = magnitude / 10; *--p = (char) (magnitude - new_magnitude * 10 + '0'); magnitude = new_magnitude; } while (magnitude); *len = buf_end - p; return (p); } #ifndef BUILD_STANDALONE static char *conv_in_addr(struct in_addr *ia, char *buf_end, int *len) { unsigned addr = ntohl(ia->s_addr); char *p = buf_end; bool_int is_negative; int sub_len; p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); *--p = '.'; p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); *--p = '.'; p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); *--p = '.'; p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); *len = buf_end - p; return (p); } static char *conv_sockaddr_in(struct sockaddr_in *si, char *buf_end, int *len) { char *p = buf_end; bool_int is_negative; int sub_len; p = conv_10(ntohs(si->sin_port), TRUE, &is_negative, p, &sub_len); *--p = ':'; p = conv_in_addr(&si->sin_addr, p, &sub_len); *len = buf_end - p; return (p); } #endif /* * Convert a floating point number to a string formats 'f', 'e' or 'E'. * The result is placed in buf, and len denotes the length of the string * The sign is returned in the is_negative argument (and is not placed * in buf). */ static char *conv_fp(register char format, register double num, boolean_e add_dp, int precision, bool_int *is_negative, char *buf, int *len) { register char *s = buf; register char *p; int decimal_point; char buf1[NDIG]; if (format == 'f') p = ap_fcvt(num, precision, &decimal_point, is_negative, buf1); else /* either e or E format */ p = ap_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); /* * Check for Infinity and NaN */ if (ap_isalpha(*p)) { *len = strlen(strcpy(buf, p)); *is_negative = FALSE; return (buf); } if (format == 'f') { if (decimal_point <= 0) { *s++ = '0'; if (precision > 0) { *s++ = '.'; while (decimal_point++ < 0) *s++ = '0'; } else if (add_dp) *s++ = '.'; } else { while (decimal_point-- > 0) *s++ = *p++; if (precision > 0 || add_dp) *s++ = '.'; } } else { *s++ = *p++; if (precision > 0 || add_dp) *s++ = '.'; } /* * copy the rest of p, the NUL is NOT copied */ while (*p) *s++ = *p++; if (format != 'f') { char temp[EXPONENT_LENGTH]; /* for exponent conversion */ int t_len; bool_int exponent_is_negative; *s++ = format; /* either e or E */ decimal_point--; if (decimal_point != 0) { p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, &temp[EXPONENT_LENGTH], &t_len); *s++ = exponent_is_negative ? '-' : '+'; /* * Make sure the exponent has at least 2 digits */ if (t_len == 1) *s++ = '0'; while (t_len--) *s++ = *p++; } else { *s++ = '+'; *s++ = '0'; *s++ = '0'; } } *len = s - buf; return (buf); } /* * Convert num to a base X number where X is a power of 2. nbits determines X. * For example, if nbits is 3, we do base 8 conversion * Return value: * a pointer to a string containing the number * * The caller provides a buffer for the string: that is the buf_end argument * which is a pointer to the END of the buffer + 1 (i.e. if the buffer * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) * * As with conv_10, we have a faster version which is used when * the number isn't quad size. */ static char *conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register int *len) { register int mask = (1 << nbits) - 1; register char *p = buf_end; static const char low_digits[] = "0123456789abcdef"; static const char upper_digits[] = "0123456789ABCDEF"; register const char *digits = (format == 'X') ? upper_digits : low_digits; do { *--p = digits[num & mask]; num >>= nbits; } while (num); *len = buf_end - p; return (p); } static char *conv_p2_quad(u_widest_int num, register int nbits, char format, char *buf_end, register int *len) { register int mask = (1 << nbits) - 1; register char *p = buf_end; static const char low_digits[] = "0123456789abcdef"; static const char upper_digits[] = "0123456789ABCDEF"; register const char *digits = (format == 'X') ? upper_digits : low_digits; if (num <= ULONG_MAX) return(conv_p2((u_wide_int)num, nbits, format, buf_end, len)); do { *--p = digits[num & mask]; num >>= nbits; } while (num); *len = buf_end - p; return (p); } /* * Do format conversion placing the output in buffer */ API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *), ap_vformatter_buff *vbuff, const char *fmt, va_list ap) { register char *sp; register char *bep; register int cc = 0; register int i; register char *s = NULL; char *q; int s_len; register int min_width = 0; int precision = 0; enum { LEFT, RIGHT } adjust; char pad_char; char prefix_char; double fp_num; widest_int i_quad = (widest_int) 0; u_widest_int ui_quad; wide_int i_num = (wide_int) 0; u_wide_int ui_num; char num_buf[NUM_BUF_SIZE]; char char_buf[2]; /* for printing %% and % */ enum var_type_enum { IS_QUAD, IS_LONG, IS_SHORT, IS_INT }; enum var_type_enum var_type = IS_INT; /* * Flag variables */ boolean_e alternate_form; boolean_e print_sign; boolean_e print_blank; boolean_e adjust_precision; boolean_e adjust_width; bool_int is_negative; sp = vbuff->curpos; bep = vbuff->endpos; while (*fmt) { if (*fmt != '%') { INS_CHAR(*fmt, sp, bep, cc); } else { /* * Default variable settings */ adjust = RIGHT; alternate_form = print_sign = print_blank = NO; pad_char = ' '; prefix_char = NUL; fmt++; /* * Try to avoid checking for flags, width or precision */ if (!ap_islower(*fmt)) { /* * Recognize flags: -, #, BLANK, + */ for (;; fmt++) { if (*fmt == '-') adjust = LEFT; else if (*fmt == '+') print_sign = YES; else if (*fmt == '#') alternate_form = YES; else if (*fmt == ' ') print_blank = YES; else if (*fmt == '0') pad_char = '0'; else break; } /* * Check if a width was specified */ if (ap_isdigit(*fmt)) { STR_TO_DEC(fmt, min_width); adjust_width = YES; } else if (*fmt == '*') { min_width = va_arg(ap, int); fmt++; adjust_width = YES; if (min_width < 0) { adjust = LEFT; min_width = -min_width; } } else adjust_width = NO; /* * Check if a precision was specified */ if (*fmt == '.') { adjust_precision = YES; fmt++; if (ap_isdigit(*fmt)) { STR_TO_DEC(fmt, precision); } else if (*fmt == '*') { precision = va_arg(ap, int); fmt++; if (precision < 0) precision = 0; } else precision = 0; } else adjust_precision = NO; } else adjust_precision = adjust_width = NO; /* * Modifier check */ if (*fmt == 'q') { var_type = IS_QUAD; fmt++; } else if (*fmt == 'l') { var_type = IS_LONG; fmt++; } else if (*fmt == 'h') { var_type = IS_SHORT; fmt++; } else { var_type = IS_INT; } /* * Argument extraction and printing. * First we determine the argument type. * Then, we convert the argument to a string. * On exit from the switch, s points to the string that * must be printed, s_len has the length of the string * The precision requirements, if any, are reflected in s_len. * * NOTE: pad_char may be set to '0' because of the 0 flag. * It is reset to ' ' by non-numeric formats */ switch (*fmt) { case 'u': if (var_type == IS_QUAD) { i_quad = va_arg(ap, u_widest_int); s = conv_10_quad(i_quad, 1, &is_negative, &num_buf[NUM_BUF_SIZE], &s_len); } else { if (var_type == IS_LONG) i_num = (wide_int) va_arg(ap, u_wide_int); else if (var_type == IS_SHORT) i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int); else i_num = (wide_int) va_arg(ap, unsigned int); s = conv_10(i_num, 1, &is_negative, &num_buf[NUM_BUF_SIZE], &s_len); } FIX_PRECISION(adjust_precision, precision, s, s_len); break; case 'd': case 'i': if (var_type == IS_QUAD) { i_quad = va_arg(ap, widest_int); s = conv_10_quad(i_quad, 0, &is_negative, &num_buf[NUM_BUF_SIZE], &s_len); } else { if (var_type == IS_LONG) i_num = (wide_int) va_arg(ap, wide_int); else if (var_type == IS_SHORT) i_num = (wide_int) (short) va_arg(ap, int); else i_num = (wide_int) va_arg(ap, int); s = conv_10(i_num, 0, &is_negative, &num_buf[NUM_BUF_SIZE], &s_len); } FIX_PRECISION(adjust_precision, precision, s, s_len); if (is_negative) prefix_char = '-'; else if (print_sign) prefix_char = '+'; else if (print_blank) prefix_char = ' '; break; case 'o': if (var_type == IS_QUAD) { ui_quad = va_arg(ap, u_widest_int); s = conv_p2_quad(ui_quad, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); } else { if (var_type == IS_LONG) ui_num = (u_wide_int) va_arg(ap, u_wide_int); else if (var_type == IS_SHORT) ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); else ui_num = (u_wide_int) va_arg(ap, unsigned int); s = conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); } FIX_PRECISION(adjust_precision, precision, s, s_len); if (alternate_form && *s != '0') { *--s = '0'; s_len++; } break; case 'x': case 'X': if (var_type == IS_QUAD) { ui_quad = va_arg(ap, u_widest_int); s = conv_p2_quad(ui_quad, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); } else { if (var_type == IS_LONG) ui_num = (u_wide_int) va_arg(ap, u_wide_int); else if (var_type == IS_SHORT) ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); else ui_num = (u_wide_int) va_arg(ap, unsigned int); s = conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len); } FIX_PRECISION(adjust_precision, precision, s, s_len); if (alternate_form && i_num != 0) { *--s = *fmt; /* 'x' or 'X' */ *--s = '0'; s_len += 2; } break; case 's': s = va_arg(ap, char *); if (s != NULL) { s_len = strlen(s); if (adjust_precision && precision < s_len) s_len = precision; } else { s = S_NULL; s_len = S_NULL_LEN; } pad_char = ' '; break; case 'f': case 'e': case 'E': fp_num = va_arg(ap, double); /* * * We use &num_buf[ 1 ], so that we have room for the sign */ #ifdef HAVE_ISNAN if (isnan(fp_num)) { s = "nan"; s_len = 3; } else #endif #ifdef HAVE_ISINF if (isinf(fp_num)) { s = "inf"; s_len = 3; } else #endif { s = conv_fp(*fmt, fp_num, alternate_form, (adjust_precision == NO) ? FLOAT_DIGITS : precision, &is_negative, &num_buf[1], &s_len); if (is_negative) prefix_char = '-'; else if (print_sign) prefix_char = '+'; else if (print_blank) prefix_char = ' '; } break; case 'g': case 'G': if (adjust_precision == NO) precision = FLOAT_DIGITS; else if (precision == 0) precision = 1; /* * * We use &num_buf[ 1 ], so that we have room for the sign */ s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1], alternate_form); if (*s == '-') prefix_char = *s++; else if (print_sign) prefix_char = '+'; else if (print_blank) prefix_char = ' '; s_len = strlen(s); if (alternate_form && (q = strchr(s, '.')) == NULL) { s[s_len++] = '.'; s[s_len] = '\0'; /* delimit for following strchr() */ } if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) *q = 'E'; break; case 'c': char_buf[0] = (char) (va_arg(ap, int)); s = &char_buf[0]; s_len = 1; pad_char = ' '; break; case '%': char_buf[0] = '%'; s = &char_buf[0]; s_len = 1; pad_char = ' '; break; case 'n': if (var_type == IS_QUAD) *(va_arg(ap, widest_int *)) = cc; else if (var_type == IS_LONG) *(va_arg(ap, long *)) = cc; else if (var_type == IS_SHORT) *(va_arg(ap, short *)) = cc; else *(va_arg(ap, int *)) = cc; break; /* * This is where we extend the printf format, with a second * type specifier */ case 'p': switch(*++fmt) { /* * If the pointer size is equal to or smaller than the size * of the largest unsigned int, we convert the pointer to a * hex number, otherwise we print "%p" to indicate that we * don't handle "%p". */ case 'p': #ifdef AP_VOID_P_IS_QUAD if (sizeof(void *) <= sizeof(u_widest_int)) { ui_quad = (u_widest_int) va_arg(ap, void *); s = conv_p2_quad(ui_quad, 4, 'x', &num_buf[NUM_BUF_SIZE], &s_len); } #else if (sizeof(void *) <= sizeof(u_wide_int)) { ui_num = (u_wide_int) va_arg(ap, void *); s = conv_p2(ui_num, 4, 'x', &num_buf[NUM_BUF_SIZE], &s_len); } #endif else { s = "%p"; s_len = 2; prefix_char = NUL; } pad_char = ' '; break; #ifndef BUILD_STANDALONE /* print a struct sockaddr_in as a.b.c.d:port */ case 'I': { struct sockaddr_in *si; si = va_arg(ap, struct sockaddr_in *); if (si != NULL) { s = conv_sockaddr_in(si, &num_buf[NUM_BUF_SIZE], &s_len); if (adjust_precision && precision < s_len) s_len = precision; } else { s = S_NULL; s_len = S_NULL_LEN; } pad_char = ' '; } break; /* print a struct in_addr as a.b.c.d */ case 'A': { struct in_addr *ia; ia = va_arg(ap, struct in_addr *); if (ia != NULL) { s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); if (adjust_precision && precision < s_len) s_len = precision; } else { s = S_NULL; s_len = S_NULL_LEN; } pad_char = ' '; } break; #endif case NUL: /* if %p ends the string, oh well ignore it */ continue; default: s = "bogus %p"; s_len = 8; prefix_char = NUL; break; } break; case NUL: /* * The last character of the format string was %. * We ignore it. */ continue; /* * The default case is for unrecognized %'s. * We print % to help the user identify what * option is not understood. * This is also useful in case the user wants to pass * the output of format_converter to another function * that understands some other % (like syslog). * Note that we can't point s inside fmt because the * unknown could be preceded by width etc. */ default: char_buf[0] = '%'; char_buf[1] = *fmt; s = char_buf; s_len = 2; pad_char = ' '; break; } if (prefix_char != NUL && s != S_NULL && s != char_buf) { *--s = prefix_char; s_len++; } if (adjust_width && adjust == RIGHT && min_width > s_len) { if (pad_char == '0' && prefix_char != NUL) { INS_CHAR(*s, sp, bep, cc); s++; s_len--; min_width--; } PAD(min_width, s_len, pad_char); } /* * Print the string s. */ for (i = s_len; i != 0; i--) { INS_CHAR(*s, sp, bep, cc); s++; } if (adjust_width && adjust == LEFT && min_width > s_len) PAD(min_width, s_len, pad_char); } fmt++; } vbuff->curpos = sp; return cc; } static int snprintf_flush(ap_vformatter_buff *vbuff) { /* if the buffer fills we have to abort immediately, there is no way * to "flush" an ap_snprintf... there's nowhere to flush it to. */ return -1; } API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...) { int cc; va_list ap; ap_vformatter_buff vbuff; if (len == 0) return 0; /* save one byte for nul terminator */ vbuff.curpos = buf; vbuff.endpos = buf + len - 1; va_start(ap, format); cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); va_end(ap); *vbuff.curpos = '\0'; return (cc == -1) ? len : cc; } API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap) { int cc; ap_vformatter_buff vbuff; if (len == 0) return 0; /* save one byte for nul terminator */ vbuff.curpos = buf; vbuff.endpos = buf + len - 1; cc = ap_vformatter(snprintf_flush, &vbuff, format, ap); *vbuff.curpos = '\0'; return (cc == -1) ? len : cc; } tomcat-connectors-1.2.50-src/native/common/jk_types.h.in0000644000000000000020000000373014655113617021513 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Platform specific, auto-detected types. * * Author: Rainer Jung * ***************************************************************************/ #ifndef JK_TYPES_H #define JK_TYPES_H /* GENERATED FILE WARNING! DO NOT EDIT jk_types.h * * You must modify jk_types.h.in instead. * */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* jk_uint32_t defines a four byte word */ typedef unsigned @int32_value@ jk_uint32_t; /* And JK_UINT32_T_FMT */ @uint32_t_fmt@ /* And JK_UINT32_T_HEX_FMT */ @uint32_t_hex_fmt@ /* jk_uint64_t defines a eight byte word */ typedef unsigned @int64_value@ jk_uint64_t; /* And JK_UINT64_T_FMT */ @uint64_t_fmt@ /* And JK_UINT64_T_HEX_FMT */ @uint64_t_hex_fmt@ /* And JK_PID_T_FMT */ @pid_t_fmt@ /* jk_pthread_t defines a eight byte word */ typedef unsigned @pthread_t_value@ jk_pthread_t; /* And JK_PTHREAD_T_FMT */ @pthread_t_fmt@ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_TYPES_H */ tomcat-connectors-1.2.50-src/native/common/jk_context.c0000644000000000000020000001362314655113617021423 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Context handling (Autoconf) * * Author: Henri Gomez * ***************************************************************************/ #include "jk_global.h" #include "jk_context.h" #include "jk_ajp_common.h" /* * Set the virtual name of the context */ int context_set_virtual(jk_context_t *c, char *virt) { if (c) { if (virt) { c->virt = jk_pool_strdup(&c->p, virt); if (!c->virt) return JK_FALSE; } return JK_TRUE; } return JK_FALSE; } /* * Init the context info struct */ int context_open(jk_context_t *c, char *virt) { if (c) { jk_open_pool(&c->p, c->buf, sizeof(jk_pool_atom_t) * SMALL_POOL_SIZE); c->size = 0; c->capacity = 0; c->contexts = NULL; return context_set_virtual(c, virt); } return JK_FALSE; } /* * Close the context info struct */ int context_close(jk_context_t *c) { if (c) { jk_close_pool(&c->p); return JK_TRUE; } return JK_FALSE; } /* * Allocate and open context */ int context_alloc(jk_context_t **c, char *virt) { if (c) return context_open(*c = (jk_context_t *)calloc(1, sizeof(jk_context_t)), virt); return JK_FALSE; } /* * Close and destroy context */ int context_free(jk_context_t **c) { if (c && *c) { context_close(*c); free(*c); *c = NULL; return JK_TRUE; } return JK_FALSE; } /* * Ensure there will be memory in context info to store Context Bases */ static int context_realloc(jk_context_t *c) { if (c->size == c->capacity) { jk_context_item_t **contexts; int capacity = c->capacity + CBASE_INC_SIZE; contexts = (jk_context_item_t **)jk_pool_alloc(&c->p, sizeof(jk_context_item_t *) * capacity); if (!contexts) return JK_FALSE; if (c->capacity && c->contexts) memcpy(contexts, c->contexts, sizeof(jk_context_item_t *) * c->capacity); c->contexts = contexts; c->capacity = capacity; } return JK_TRUE; } /* * Ensure there will be memory in context info to URIS */ static int context_item_realloc(jk_context_t *c, jk_context_item_t *ci) { if (ci->size == ci->capacity) { char **uris; int capacity = ci->capacity + URI_INC_SIZE; uris = (char **)jk_pool_alloc(&c->p, sizeof(char *) * capacity); if (!uris) return JK_FALSE; memcpy(uris, ci->uris, sizeof(char *) * ci->capacity); ci->uris = uris; ci->capacity = capacity; } return JK_TRUE; } /* * Locate a context base in context list */ jk_context_item_t *context_find_base(jk_context_t *c, char *cbase) { int i; jk_context_item_t *ci; if (!c || !cbase) return NULL; for (i = 0; i < c->size; i++) { ci = c->contexts[i]; if (!ci) continue; if (!strcmp(ci->cbase, cbase)) return ci; } return NULL; } /* * Locate an URI in a context item */ char *context_item_find_uri(jk_context_item_t *ci, char *uri) { int i; if (!ci || !uri) return NULL; for (i = 0; i < ci->size; i++) { if (!strcmp(ci->uris[i], uri)) return ci->uris[i]; } return NULL; } void context_dump_uris(jk_context_t *c, char *cbase, FILE * f) { jk_context_item_t *ci; int i; ci = context_find_base(c, cbase); if (!ci) return; for (i = 0; i < ci->size; i++) fprintf(f, "/%s/%s\n", ci->cbase, ci->uris[i]); fflush(f); } /* * Add a new context item to context */ jk_context_item_t *context_add_base(jk_context_t *c, char *cbase) { jk_context_item_t *ci; if (!c || !cbase) return NULL; /* Check if the context base was not allready created */ ci = context_find_base(c, cbase); if (ci) return ci; if (context_realloc(c) != JK_TRUE) return NULL; ci = (jk_context_item_t *)jk_pool_alloc(&c->p, sizeof(jk_context_item_t)); if (!ci) return NULL; c->contexts[c->size] = ci; c->size++; ci->cbase = jk_pool_strdup(&c->p, cbase); ci->status = 0; ci->size = 0; ci->capacity = 0; ci->uris = NULL; return ci; } /* * Add a new URI to a context item */ int context_add_uri(jk_context_t *c, char *cbase, char *uri) { jk_context_item_t *ci; if (!uri) return JK_FALSE; /* Get/Create the context base */ ci = context_add_base(c, cbase); if (!ci) return JK_FALSE; if (context_item_find_uri(ci, uri) != NULL) return JK_TRUE; if (context_item_realloc(c, ci) == JK_FALSE) return JK_FALSE; ci->uris[ci->size] = jk_pool_strdup(&c->p, uri); if (ci->uris[ci->size] == NULL) return JK_FALSE; ci->size++; return JK_TRUE; } tomcat-connectors-1.2.50-src/native/common/jk_worker.h0000644000000000000020000000377614655113617021265 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Workers controller header file * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_WORKER_H #define JK_WORKER_H #include "jk_logger.h" #include "jk_service.h" #include "jk_map.h" #include "jk_uri_worker_map.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ int wc_open(jk_map_t *init_data, jk_worker_env_t *we, jk_log_context_t *log_ctx); void wc_close(jk_log_context_t *log_ctx); jk_worker_t *wc_get_worker_for_name(const char *name, jk_log_context_t *log_ctx); const char *wc_get_name_for_type(int type, jk_log_context_t *log_ctx); int wc_create_worker(const char *name, int use_map, jk_map_t *init_data, jk_worker_t **rc, jk_worker_env_t *we, jk_log_context_t *log_ctx); void wc_maintain(jk_log_context_t *log_ctx); void wc_shutdown(jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_WORKER_H */ tomcat-connectors-1.2.50-src/native/common/jk_msg_buff.c0000644000000000000020000002162614655113617021531 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Data marshaling. XDR like * * Author: Costin * * Author: Gal Shachor * * Author: Henri Gomez * ***************************************************************************/ #include "jk_pool.h" #include "jk_connect.h" #include "jk_util.h" #include "jk_sockbuf.h" #include "jk_msg_buff.h" #include "jk_logger.h" static char *jk_HEX = "0123456789ABCDEFX"; /* * Simple marshaling code. */ void jk_b_reset(jk_msg_buf_t *msg) { msg->len = 4; msg->pos = 4; if (msg->buf && msg->maxlen) { /* Clear the message buffer */ memset(msg->buf, 0, msg->maxlen); } } int jk_b_append_long(jk_msg_buf_t *msg, unsigned long val) { if (msg->len + 4 > msg->maxlen) { return -1; } msg->buf[msg->len++] = (unsigned char)((val >> 24) & 0xFF); msg->buf[msg->len++] = (unsigned char)((val >> 16) & 0xFF); msg->buf[msg->len++] = (unsigned char)((val >> 8) & 0xFF); msg->buf[msg->len++] = (unsigned char)((val) & 0xFF); return 0; } int jk_b_append_int(jk_msg_buf_t *msg, unsigned short val) { if (msg->len + 2 > msg->maxlen) { return -1; } msg->buf[msg->len++] = (unsigned char)((val >> 8) & 0xFF); msg->buf[msg->len++] = (unsigned char)((val) & 0xFF); return 0; } int jk_b_append_byte(jk_msg_buf_t *msg, unsigned char val) { if (msg->len + 1 > msg->maxlen) { return -1; } msg->buf[msg->len++] = val; return 0; } void jk_b_end(jk_msg_buf_t *msg, int protoh) { /* * Ugly way to set the size in the right position */ int hlen = msg->len - 4; msg->buf[0] = (unsigned char)((protoh >> 8) & 0xFF); msg->buf[1] = (unsigned char)((protoh) & 0xFF); msg->buf[2] = (unsigned char)((hlen >> 8) & 0xFF); msg->buf[3] = (unsigned char)((hlen) & 0xFF); } jk_msg_buf_t *jk_b_new(jk_pool_t *p) { jk_msg_buf_t *msg = (jk_msg_buf_t *)jk_pool_alloc(p, sizeof(jk_msg_buf_t)); if (!msg) { return NULL; } memset(msg, 0, sizeof(jk_msg_buf_t)); msg->pool = p; return msg; } int jk_b_set_buffer(jk_msg_buf_t *msg, unsigned char *data, int buffSize) { if (!msg) { return -1; } msg->len = 0; msg->buf = data; msg->maxlen = buffSize; return 0; } int jk_b_set_buffer_size(jk_msg_buf_t *msg, int buffSize) { unsigned char *data = jk_pool_alloc(msg->pool, buffSize); if (!data) { return -1; } jk_b_set_buffer(msg, data, buffSize); return 0; } #if defined(AS400) && !defined(AS400_UTF8) int jk_b_append_asciistring(jk_msg_buf_t *msg, const char *param) { int len; if (!param) { jk_b_append_int(msg, 0xFFFF); return 0; } len = strlen(param); if (msg->len + len + 2 > msg->maxlen) { return -1; } /* ignore error - we checked once */ jk_b_append_int(msg, (unsigned short)len); /* We checked for space !! */ strncpy((char *)msg->buf + msg->len, param, len + 1); /* including \0 */ msg->len += len + 1; return 0; } #endif int jk_b_append_string(jk_msg_buf_t *msg, const char *param) { unsigned short len; if (!param) { jk_b_append_int(msg, 0xFFFF); return 0; } len = (unsigned short)strlen(param); if (msg->len + len + 3 > msg->maxlen) { return -1; } /* ignore error - we checked once */ jk_b_append_int(msg, len); /* We checked for space !! */ memcpy(msg->buf + msg->len, param, len + 1); /* including \0 */ #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX) /* convert from EBCDIC if needed */ jk_xlate_to_ascii((char *)msg->buf + msg->len, len + 1); #endif msg->len += len + 1; return 0; } int jk_b_append_bytes(jk_msg_buf_t *msg, const unsigned char *param, int len) { if (!len) { return 0; } if (msg->len + len > msg->maxlen) { return -1; } /* We checked for space !! */ memcpy(msg->buf + msg->len, param, len); msg->len += len; return 0; } unsigned long jk_b_get_long(jk_msg_buf_t *msg) { unsigned long i; if (msg->pos + 4 > msg->len) { return 0xFFFFFFFF; } i = ((msg->buf[(msg->pos++)] & 0xFF) << 24); i |= ((msg->buf[(msg->pos++)] & 0xFF) << 16); i |= ((msg->buf[(msg->pos++)] & 0xFF) << 8); i |= ((msg->buf[(msg->pos++)] & 0xFF)); return i; } unsigned long jk_b_pget_long(jk_msg_buf_t *msg, int pos) { unsigned long i; if (pos + 4 > msg->len) { return 0xFFFFFFFF; } i = ((msg->buf[(pos++)] & 0xFF) << 24); i |= ((msg->buf[(pos++)] & 0xFF) << 16); i |= ((msg->buf[(pos++)] & 0xFF) << 8); i |= ((msg->buf[(pos)] & 0xFF)); return i; } unsigned short jk_b_get_int(jk_msg_buf_t *msg) { unsigned short i; if (msg->pos + 2 > msg->len) { return 0xFFFF; } i = ((msg->buf[(msg->pos++)] & 0xFF) << 8); i += ((msg->buf[(msg->pos++)] & 0xFF)); return i; } unsigned short jk_b_pget_int(jk_msg_buf_t *msg, int pos) { unsigned short i; if (pos + 2 > msg->len) { return 0xFFFF; } i = ((msg->buf[pos++] & 0xFF) << 8); i += ((msg->buf[pos] & 0xFF)); return i; } unsigned char jk_b_get_byte(jk_msg_buf_t *msg) { unsigned char rc; if (msg->pos + 1 > msg->len) { return 0xFF; } rc = msg->buf[msg->pos++]; return rc; } unsigned char jk_b_pget_byte(jk_msg_buf_t *msg, int pos) { if (pos + 1 > msg->len) { return 0xFF; } return msg->buf[pos]; } char *jk_b_get_string(jk_msg_buf_t *msg) { unsigned short size = jk_b_get_int(msg); int start = msg->pos; if ((size == 0xFFFF) || (size + start > msg->maxlen)) { /* Error of overflow in AJP packet. * The complete message is probably invalid. */ return NULL; } msg->pos += size; msg->pos++; /* terminating NULL */ return (char *)(msg->buf + start); } int jk_b_get_bytes(jk_msg_buf_t *msg, unsigned char *buf, int len) { int start = msg->pos; if ((len < 0) || (len + start > msg->maxlen)) { return (-1); } memcpy(buf, msg->buf + start, len); msg->pos += len; return (len); } /** Helpie dump function */ void jk_dump_buff(jk_log_context_t *l, const char *file, int line, const char *funcname, int level, char *what, jk_msg_buf_t *msg) { int i = 0; char lb[80]; char *current; int j; int len = msg->len; if (l == NULL || l->logger == NULL) return; if (l->logger->level != JK_LOG_TRACE_LEVEL && len > 1024) len = 1024; jk_log(l, file, line, funcname, level, "%s pos=%d len=%d max=%d", what, msg->pos, msg->len, msg->maxlen); for (i = 0; i < len; i += 16) { current = &lb[0]; for (j = 0; j < 16; j++) { unsigned char x = (msg->buf[i + j]); if ((i + j) >= len) x = 0; *current++ = jk_HEX[x >> 4]; *current++ = jk_HEX[x & 0x0f]; *current++ = ' '; } *current++ = ' '; *current++ = '-'; *current++ = ' '; for (j = 0; j < 16; j++) { unsigned char x = msg->buf[i + j]; if ((i + j) >= len) x = 0; if (x > 0x20 && x < 0x7F) { #ifdef USE_CHARSET_EBCDIC *current = x; jk_xlate_from_ascii(current, 1); current++; #else *current++ = x; #endif } else { *current++ = '.'; } } *current++ = '\0'; jk_log(l, file, line, funcname, level, "%.4x %s", i, lb); } } int jk_b_copy(jk_msg_buf_t *smsg, jk_msg_buf_t *dmsg) { if (smsg == NULL || dmsg == NULL) return (-1); if (dmsg->maxlen < smsg->len) return (-2); memcpy(dmsg->buf, smsg->buf, smsg->len); dmsg->len = smsg->len; return (smsg->len); } tomcat-connectors-1.2.50-src/native/common/jk_md5.h0000644000000000000020000000516714655113617020435 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * This is work is derived from material Copyright RSA Data Security, Inc. * * The RSA copyright statement and Licence for that original material is * included below. This is followed by the Apache copyright statement and * licence for the modifications made to that material. */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ #ifndef JK_APACHE_MD5_H #define JK_APACHE_MD5_H #ifdef __cplusplus extern "C" { #endif /* MD5.H - header file for MD5.C */ #define JK_MD5_DIGESTSIZE 16 /* MD5 context. */ typedef struct { jk_uint32_t state[4]; /* state (ABCD) */ jk_uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ } JK_MD5_CTX; char *JK_METHOD jk_hextocstr(unsigned char *org, char *dst, int n); char *JK_METHOD jk_md5(const unsigned char *org, const unsigned char *org2, char *dst); #ifdef __cplusplus } #endif #endif /* !JK_APACHE_MD5_H */ tomcat-connectors-1.2.50-src/native/common/jk_util.c0000644000000000000020000020421714655113617020715 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Utility functions (mainly configuration) * * Author: Gal Shachor * * Author: Henri Gomez * * Author: Rainer Jung * ***************************************************************************/ #include "jk_util.h" #include "jk_ajp12_worker.h" #include "jk_ajp13_worker.h" #include "jk_ajp14_worker.h" #include "jk_lb_worker.h" #include "jk_mt.h" #define SYSPROPS_OF_WORKER "sysprops" #define STDERR_OF_WORKER "stderr" #define STDOUT_OF_WORKER "stdout" #define SECRET_OF_WORKER "secret" #define MX_OF_WORKER "mx" #define MS_OF_WORKER "ms" #define CP_OF_WORKER "class_path" #define BRIDGE_OF_WORKER "bridge" #define JVM_OF_WORKER "jvm_lib" #define LIBPATH_OF_WORKER "ld_path" #define CMD_LINE_OF_WORKER "cmd_line" #define NATIVE_LIB_OF_WORKER "native_lib" #define REFERENCE_OF_WORKER "reference" #define HOST_OF_WORKER "host" #define SOURCE_OF_WORKER "source" #define PORT_OF_WORKER "port" #define TYPE_OF_WORKER "type" #define CACHE_OF_WORKER_DEPRECATED "cachesize" #define CACHE_OF_WORKER "connection_pool_size" #define CACHE_OF_WORKER_MIN "connection_pool_minsize" #define CACHE_TIMEOUT_DEPRECATED "cache_timeout" #define CACHE_TIMEOUT_OF_WORKER "connection_pool_timeout" #define CACHE_ACQUIRE_OF_WORKER "connection_acquire_timeout" #define RECOVERY_OPTS_OF_WORKER "recovery_options" #define CONNECT_TIMEOUT_OF_WORKER "connect_timeout" #define PREPOST_TIMEOUT_OF_WORKER "prepost_timeout" #define REPLY_TIMEOUT_OF_WORKER "reply_timeout" #define SOCKET_TIMEOUT_OF_WORKER "socket_timeout" #define SOCKET_CONNECT_TIMEOUT_OF_WORKER "socket_connect_timeout" #define PING_TIMEOUT_OF_WORKER "ping_timeout" #define PING_MODE_OF_WORKER "ping_mode" #define SOCKET_BUFFER_OF_WORKER "socket_buffer" #define SOCKET_KEEPALIVE_OF_WORKER "socket_keepalive" #define CONN_PING_INTERVAL_OF_WORKER "connection_ping_interval" #define RECYCLE_TIMEOUT_DEPRECATED "recycle_timeout" #define LOAD_FACTOR_OF_WORKER "lbfactor" #define DISTANCE_OF_WORKER "distance" #define BALANCED_WORKERS_DEPRECATED "balanced_workers" #define BALANCE_WORKERS "balance_workers" #define STICKY_SESSION "sticky_session" #define STICKY_SESSION_FORCE "sticky_session_force" #define SESSION_COOKIE_OF_WORKER "session_cookie" #define SESSION_PATH_OF_WORKER "session_path" #define SET_SESSION_COOKIE "set_session_cookie" #define SESSION_COOKIE_PATH_OF_WORKER "session_cookie_path" #define LOCAL_WORKER_DEPRECATED "local_worker" #define LOCAL_WORKER_ONLY_DEPRECATED "local_worker_only" #define JVM_ROUTE_OF_WORKER_DEPRECATED "jvm_route" #define ROUTE_OF_WORKER "route" #define DOMAIN_OF_WORKER "domain" #define REDIRECT_OF_WORKER "redirect" #define MOUNT_OF_WORKER "mount" #define METHOD_OF_WORKER "method" #define LOCK_OF_WORKER "lock" #define IS_WORKER_DISABLED_DEPRECATED "disabled" #define IS_WORKER_STOPPED_DEPRECATED "stopped" #define ACTIVATION_OF_WORKER "activation" #define WORKER_RECOVER_TIME "recover_time" #define WORKER_ERROR_ESCALATION_TIME "error_escalation_time" #define MAX_REPLY_TIMEOUTS_OF_WORKER "max_reply_timeouts" #define RETRY_INTERVAL_OF_WORKER "retry_interval" #define BUSY_LIMIT_OF_WORKER "busy_limit" #define WORKER_MAX_PACKET_SIZE "max_packet_size" #define STYLE_SHEET_OF_WORKER "css" #define NAMESPACE_OF_WORKER "ns" #define XML_NAMESPACE_OF_WORKER "xmlns" #define XML_DOCTYPE_OF_WORKER "doctype" #define PROP_PREFIX_OF_WORKER "prefix" #define READ_ONLY_OF_WORKER "read_only" #define USER_OF_WORKER "user" #define USER_CASE_OF_WORKER "user_case_insensitive" #define GOOD_RATING_OF_WORKER "good" #define BAD_RATING_OF_WORKER "bad" #define PREFER_IPV6_ADDRESS "prefer_ipv6" #define DEFAULT_WORKER_TYPE JK_AJP13_WORKER_NAME #define SECRET_KEY_OF_WORKER "secretkey" #define RETRIES_OF_WORKER "retries" #define LB_RETRIES_OF_WORKER "lb_retries" #define STATUS_FAIL_OF_WORKER "fail_on_status" #define DEFAULT_WORKER JK_AJP13_WORKER_NAME #define WORKER_LIST_PROPERTY_NAME "worker.list" #define LIST_PROPERTY_NAME "list" #define WORKER_MAINTAIN_PROPERTY_NAME "worker.maintain" #define MAINTAIN_PROPERTY_NAME "maintain" #define DEFAULT_MAINTAIN_TIME 60 #define DEFAULT_LB_FACTOR 1 #define DEFAULT_DISTANCE 0 #define TOMCAT32_BRIDGE_NAME "tomcat32" #define TOMCAT33_BRIDGE_NAME "tomcat33" #define TOMCAT40_BRIDGE_NAME "tomcat40" #define TOMCAT41_BRIDGE_NAME "tomcat41" #define TOMCAT50_BRIDGE_NAME "tomcat5" #define LOG_BUFFER_SIZE 1024 /* * Our longest worker attribute name is below 30 bytes. * Add space for "worker.", another ".", the * worker name and the final '\0'. */ #define JK_MAX_ATTRIBUTE_NAME_LEN (30) #define PARAM_BUFFER_SIZE (JK_MAX_NAME_LEN + 8 + JK_MAX_ATTRIBUTE_NAME_LEN + 1) #define MAKE_WORKER_PARAM(P) \ { \ size_t remain = PARAM_BUFFER_SIZE; \ strcpy(buf, "worker."); remain -= strlen("worker."); \ strncat(buf, wname, remain); remain -= strlen(wname); \ strncat(buf, ".", remain); remain -= 1; \ strncat(buf, P, remain); \ } /* * define the log format, we're using by default the one from error.log * * [Mon Mar 26 19:44:48.123 2001] [jk_uri_worker_map.c (155)]: Into jk_uri_worker_map_t::uri_worker_map_alloc * log format used by apache in error.log */ #define JK_TIME_CONV_MILLI "%Q" #define JK_TIME_CONV_MICRO "%q" #define JK_TIME_PATTERN_MILLI "000" #define JK_TIME_PATTERN_MICRO "000000" #define JK_TIME_FORMAT_NONE "[%a %b %d %H:%M:%S %Y] " #define JK_TIME_FORMAT_MILLI "[%a %b %d %H:%M:%S." JK_TIME_CONV_MILLI " %Y] " #define JK_TIME_FORMAT_MICRO "[%a %b %d %H:%M:%S." JK_TIME_CONV_MICRO " %Y] " #define JK_TIME_SUBSEC_NONE 0 #define JK_TIME_SUBSEC_MILLI 1 #define JK_TIME_SUBSEC_MICRO 2 /* Visual C++ Toolkit 2003 support */ #if defined (_MSC_VER) && (_MSC_VER == 1310) extern long _ftol(double); /* defined by VC6 C libs */ extern long _ftol2(double dblSource) { return _ftol(dblSource); } #endif static const char *list_properties[] = { BALANCE_WORKERS, MOUNT_OF_WORKER, USER_OF_WORKER, GOOD_RATING_OF_WORKER, BAD_RATING_OF_WORKER, STATUS_FAIL_OF_WORKER, LIST_PROPERTY_NAME, NULL }; static const char *unique_properties[] = { SECRET_OF_WORKER, REFERENCE_OF_WORKER, HOST_OF_WORKER, SOURCE_OF_WORKER, PORT_OF_WORKER, TYPE_OF_WORKER, CACHE_OF_WORKER_DEPRECATED, CACHE_OF_WORKER, CACHE_OF_WORKER_MIN, CACHE_TIMEOUT_DEPRECATED, CACHE_TIMEOUT_OF_WORKER, CACHE_ACQUIRE_OF_WORKER, RECOVERY_OPTS_OF_WORKER, CONNECT_TIMEOUT_OF_WORKER, PREPOST_TIMEOUT_OF_WORKER, PING_TIMEOUT_OF_WORKER, PING_MODE_OF_WORKER, REPLY_TIMEOUT_OF_WORKER, SOCKET_TIMEOUT_OF_WORKER, SOCKET_CONNECT_TIMEOUT_OF_WORKER, SOCKET_BUFFER_OF_WORKER, SOCKET_KEEPALIVE_OF_WORKER, CONN_PING_INTERVAL_OF_WORKER, RECYCLE_TIMEOUT_DEPRECATED, LOAD_FACTOR_OF_WORKER, STICKY_SESSION, STICKY_SESSION_FORCE, SESSION_COOKIE_OF_WORKER, SESSION_PATH_OF_WORKER, SET_SESSION_COOKIE, SESSION_COOKIE_PATH_OF_WORKER, LOCAL_WORKER_DEPRECATED, LOCAL_WORKER_ONLY_DEPRECATED, JVM_ROUTE_OF_WORKER_DEPRECATED, ROUTE_OF_WORKER, DOMAIN_OF_WORKER, REDIRECT_OF_WORKER, METHOD_OF_WORKER, LOCK_OF_WORKER, IS_WORKER_DISABLED_DEPRECATED, IS_WORKER_STOPPED_DEPRECATED, ACTIVATION_OF_WORKER, WORKER_RECOVER_TIME, WORKER_ERROR_ESCALATION_TIME, MAX_REPLY_TIMEOUTS_OF_WORKER, RETRY_INTERVAL_OF_WORKER, BUSY_LIMIT_OF_WORKER, WORKER_MAX_PACKET_SIZE, STYLE_SHEET_OF_WORKER, READ_ONLY_OF_WORKER, RETRIES_OF_WORKER, LB_RETRIES_OF_WORKER, WORKER_MAINTAIN_PROPERTY_NAME, NAMESPACE_OF_WORKER, XML_NAMESPACE_OF_WORKER, XML_DOCTYPE_OF_WORKER, PROP_PREFIX_OF_WORKER, USER_CASE_OF_WORKER, PREFER_IPV6_ADDRESS, NULL }; static const char *deprecated_properties[] = { SYSPROPS_OF_WORKER, STDERR_OF_WORKER, STDOUT_OF_WORKER, MX_OF_WORKER, MS_OF_WORKER, CP_OF_WORKER, BRIDGE_OF_WORKER, JVM_OF_WORKER, LIBPATH_OF_WORKER, CMD_LINE_OF_WORKER, NATIVE_LIB_OF_WORKER, CACHE_OF_WORKER_DEPRECATED, CACHE_TIMEOUT_DEPRECATED, RECYCLE_TIMEOUT_DEPRECATED, BALANCED_WORKERS_DEPRECATED, JVM_ROUTE_OF_WORKER_DEPRECATED, LOCAL_WORKER_DEPRECATED, LOCAL_WORKER_ONLY_DEPRECATED, IS_WORKER_DISABLED_DEPRECATED, IS_WORKER_STOPPED_DEPRECATED, NULL }; static const char *supported_properties[] = { SYSPROPS_OF_WORKER, STDERR_OF_WORKER, STDOUT_OF_WORKER, SECRET_OF_WORKER, MX_OF_WORKER, MS_OF_WORKER, CP_OF_WORKER, BRIDGE_OF_WORKER, JVM_OF_WORKER, LIBPATH_OF_WORKER, CMD_LINE_OF_WORKER, NATIVE_LIB_OF_WORKER, REFERENCE_OF_WORKER, HOST_OF_WORKER, SOURCE_OF_WORKER, PORT_OF_WORKER, TYPE_OF_WORKER, CACHE_OF_WORKER_DEPRECATED, CACHE_OF_WORKER, CACHE_OF_WORKER_MIN, CACHE_TIMEOUT_DEPRECATED, CACHE_TIMEOUT_OF_WORKER, CACHE_ACQUIRE_OF_WORKER, RECOVERY_OPTS_OF_WORKER, CONNECT_TIMEOUT_OF_WORKER, PREPOST_TIMEOUT_OF_WORKER, PING_TIMEOUT_OF_WORKER, PING_MODE_OF_WORKER, REPLY_TIMEOUT_OF_WORKER, SOCKET_TIMEOUT_OF_WORKER, SOCKET_CONNECT_TIMEOUT_OF_WORKER, SOCKET_BUFFER_OF_WORKER, SOCKET_KEEPALIVE_OF_WORKER, CONN_PING_INTERVAL_OF_WORKER, RECYCLE_TIMEOUT_DEPRECATED, LOAD_FACTOR_OF_WORKER, DISTANCE_OF_WORKER, BALANCED_WORKERS_DEPRECATED, BALANCE_WORKERS, STICKY_SESSION, STICKY_SESSION_FORCE, SESSION_COOKIE_OF_WORKER, SESSION_PATH_OF_WORKER, SET_SESSION_COOKIE, SESSION_COOKIE_PATH_OF_WORKER, LOCAL_WORKER_DEPRECATED, LOCAL_WORKER_ONLY_DEPRECATED, JVM_ROUTE_OF_WORKER_DEPRECATED, ROUTE_OF_WORKER, DOMAIN_OF_WORKER, REDIRECT_OF_WORKER, MOUNT_OF_WORKER, METHOD_OF_WORKER, LOCK_OF_WORKER, IS_WORKER_DISABLED_DEPRECATED, IS_WORKER_STOPPED_DEPRECATED, ACTIVATION_OF_WORKER, WORKER_RECOVER_TIME, WORKER_ERROR_ESCALATION_TIME, MAX_REPLY_TIMEOUTS_OF_WORKER, RETRY_INTERVAL_OF_WORKER, BUSY_LIMIT_OF_WORKER, WORKER_MAX_PACKET_SIZE, STYLE_SHEET_OF_WORKER, NAMESPACE_OF_WORKER, XML_NAMESPACE_OF_WORKER, XML_DOCTYPE_OF_WORKER, PROP_PREFIX_OF_WORKER, READ_ONLY_OF_WORKER, USER_OF_WORKER, USER_CASE_OF_WORKER, GOOD_RATING_OF_WORKER, BAD_RATING_OF_WORKER, SECRET_KEY_OF_WORKER, RETRIES_OF_WORKER, LB_RETRIES_OF_WORKER, STATUS_FAIL_OF_WORKER, LIST_PROPERTY_NAME, MAINTAIN_PROPERTY_NAME, PREFER_IPV6_ADDRESS, NULL }; static const char *jk_level_verbs[] = { "[" JK_LOG_TRACE_VERB "] ", "[" JK_LOG_DEBUG_VERB "] ", "[" JK_LOG_INFO_VERB "] ", "[" JK_LOG_WARN_VERB "] ", "[" JK_LOG_ERROR_VERB "] ", "[" JK_LOG_EMERG_VERB "] ", NULL }; const char *jk_get_bool(int v) { if (v == 0) return "False"; else return "True"; } int jk_get_bool_code(const char *v, int def) { if (!v) { return def; } if (!strcasecmp(v, "off") || *v == 'F' || *v == 'f' || *v == 'N' || *v == 'n' || (*v == '0' && *(v + 1) == '\0')) { return JK_FALSE; } if (!strcasecmp(v, "on") || *v == 'T' || *v == 't' || *v == 'Y' || *v == 'y' || (*v == '1' && *(v + 1) == '\0')) { return JK_TRUE; } return def; } /* Sleep for 100ms */ void jk_sleep(int ms) { #ifdef OS2 DosSleep(ms); #elif defined(BEOS) snooze(ms * 1000); #elif defined(WIN32) Sleep(ms); #else struct timeval tv; tv.tv_usec = (ms % 1000) * 1000; tv.tv_sec = ms / 1000; select(0, NULL, NULL, NULL, &tv); #endif } /* Replace the first occurence of a sub second time format character * by a series of zero digits with the right precision. * We format our timestamp with strftime, but this can not handle * sub second timestamps. * So we first patch the milliseconds or microseconds literally into * the format string, and then pass it on the strftime. * In order to do that efficiently, we prepare a format string, that * already has placeholder digits for the sub second time stamp * and we save the position and time precision of this placeholder. */ void jk_set_time_fmt(jk_logger_t *l, const char *jk_log_fmt) { if (l) { char *s; if (!jk_log_fmt) { #ifndef NO_GETTIMEOFDAY jk_log_fmt = JK_TIME_FORMAT_MILLI; #else jk_log_fmt = JK_TIME_FORMAT_NONE; #endif } l->log_fmt_type = JK_TIME_SUBSEC_NONE; l->log_fmt_offset = 0; l->log_fmt_size = 0; l->log_fmt = jk_log_fmt; /* Look for the first occurence of JK_TIME_CONV_MILLI */ if ((s = strstr(jk_log_fmt, JK_TIME_CONV_MILLI))) { size_t offset = s - jk_log_fmt; size_t len = strlen(JK_TIME_PATTERN_MILLI); /* If we don't have enough space in our fixed-length char array, * we simply stick to the default format, ignoring JK_TIME_CONV_MILLI. * Otherwise we replace the first occurence of * JK_TIME_CONV_MILLI by JK_TIME_PATTERN_MILLI. */ if (offset + len < JK_TIME_MAX_SIZE) { l->log_fmt_type = JK_TIME_SUBSEC_MILLI; l->log_fmt_offset = offset; memcpy(l->log_fmt_subsec, jk_log_fmt, offset); memcpy(l->log_fmt_subsec + offset, JK_TIME_PATTERN_MILLI, len); memcpy(l->log_fmt_subsec + offset + len, s + strlen(JK_TIME_CONV_MILLI), JK_TIME_MAX_SIZE - offset - len - 1); /* Now we put a stop mark into the string to make it's length * at most JK_TIME_MAX_SIZE-1 plus terminating '\0'. */ l->log_fmt_subsec[JK_TIME_MAX_SIZE - 1] = '\0'; l->log_fmt_size = strlen(l->log_fmt_subsec); } } /* Look for the first occurence of JK_TIME_CONV_MICRO */ else if ((s = strstr(jk_log_fmt, JK_TIME_CONV_MICRO))) { size_t offset = s - jk_log_fmt; size_t len = strlen(JK_TIME_PATTERN_MICRO); /* If we don't have enough space in our fixed-length char array, * we simply stick to the default format, ignoring JK_TIME_CONV_MICRO. * Otherwise we replace the first occurence of JK_TIME_CONV_MICRO * by JK_TIME_PATTERN_MICRO. */ if (offset + len < JK_TIME_MAX_SIZE) { l->log_fmt_type = JK_TIME_SUBSEC_MICRO; l->log_fmt_offset = offset; memcpy(l->log_fmt_subsec, jk_log_fmt, offset); memcpy(l->log_fmt_subsec + offset, JK_TIME_PATTERN_MICRO, len); memcpy(l->log_fmt_subsec + offset + len, s + strlen(JK_TIME_CONV_MICRO), JK_TIME_MAX_SIZE - offset - len - 1); /* Now we put a stop mark into the string to make it's length * at most JK_TIME_MAX_SIZE-1 plus terminating '\0'. */ l->log_fmt_subsec[JK_TIME_MAX_SIZE - 1] = '\0'; l->log_fmt_size = strlen(l->log_fmt_subsec); } } } } static int set_time_str(char *str, int len, jk_logger_t *l) { time_t t; struct tm *tms; #ifdef _MT_CODE_PTHREAD struct tm res; #endif int done; /* We want to use a fixed maximum size buffer here. * If we would dynamically adjust it to the real format * string length, we could support longer format strings, * but we would have to allocate and free for each log line. */ char log_fmt[JK_TIME_MAX_SIZE]; if (!l || !l->log_fmt) { return 0; } log_fmt[0] = '\0'; #ifndef NO_GETTIMEOFDAY if (l->log_fmt_type != JK_TIME_SUBSEC_NONE) { struct timeval tv; int rc = 0; #ifdef WIN32 gettimeofday(&tv, NULL); #else rc = gettimeofday(&tv, NULL); #endif if (rc == 0) { /* We need this subsec buffer, because we convert * the integer with sprintf(), but we don't * want to write the terminating '\0' into our * final log format string. */ char subsec[7]; t = tv.tv_sec; strncpy(log_fmt, l->log_fmt_subsec, l->log_fmt_size + 1); if (l->log_fmt_type == JK_TIME_SUBSEC_MILLI) { sprintf(subsec, "%03d", (int)(tv.tv_usec/1000)); strncpy(log_fmt + l->log_fmt_offset, subsec, 3); } else if (l->log_fmt_type == JK_TIME_SUBSEC_MICRO) { sprintf(subsec, "%06d", (int)(tv.tv_usec)); strncpy(log_fmt + l->log_fmt_offset, subsec, 6); } } else { t = time(NULL); } } else { t = time(NULL); } #else t = time(NULL); #endif #ifdef _MT_CODE_PTHREAD tms = localtime_r(&t, &res); #else tms = localtime(&t); #endif if (log_fmt[0]) done = (int)strftime(str, len, log_fmt, tms); else done = (int)strftime(str, len, l->log_fmt, tms); return done; } static int JK_METHOD log_to_file(jk_logger_t *l, int level, int used, char *what) { if (l && (l->level <= level || level == JK_LOG_REQUEST_LEVEL) && l->logger_private && what) { jk_file_logger_t *p = l->logger_private; if (p->logfile) { what[used++] = '\n'; what[used] = '\0'; #if defined(JK_LOG_LOCKING) #if defined(WIN32) && defined(_MSC_VER) LockFile((HANDLE)_get_osfhandle(_fileno(p->logfile)), 0, 0, 1, 0); #endif #endif fputs(what, p->logfile); /* [V] Flush the dam' thing! */ fflush(p->logfile); #if defined(JK_LOG_LOCKING) #if defined(WIN32) && defined(_MSC_VER) UnlockFile((HANDLE)_get_osfhandle(_fileno(p->logfile)), 0, 0, 1, 0); #endif #endif } return JK_TRUE; } return JK_FALSE; } int jk_parse_log_level(const char *level) { if (!strcasecmp(level, JK_LOG_TRACE_VERB)) return JK_LOG_TRACE_LEVEL; if (!strcasecmp(level, JK_LOG_DEBUG_VERB)) return JK_LOG_DEBUG_LEVEL; if (!strcasecmp(level, JK_LOG_INFO_VERB)) return JK_LOG_INFO_LEVEL; if (!strcasecmp(level, JK_LOG_WARN_VERB)) return JK_LOG_WARNING_LEVEL; if (!strcasecmp(level, JK_LOG_ERROR_VERB)) return JK_LOG_ERROR_LEVEL; if (!strcasecmp(level, JK_LOG_EMERG_VERB)) return JK_LOG_EMERG_LEVEL; return JK_LOG_DEF_LEVEL; } int jk_open_file_logger(jk_logger_t **l, const char *file, int level) { if (l && file) { jk_logger_t *rc = (jk_logger_t *)malloc(sizeof(jk_logger_t)); jk_file_logger_t *p = (jk_file_logger_t *) malloc(sizeof(jk_file_logger_t)); if (rc && p) { rc->log = log_to_file; rc->level = level; rc->logger_private = p; #if defined(AS400) && !defined(AS400_UTF8) p->logfile = fopen(file, "a+, o_ccsid=0"); #elif defined(WIN32) && defined(_MSC_VER) p->logfile = fopen(file, "a+c"); #else p->logfile = fopen(file, "a+"); #endif if (p->logfile) { *l = rc; jk_set_time_fmt(rc, NULL); return JK_TRUE; } } if (rc) { free(rc); } if (p) { free(p); } *l = NULL; } return JK_FALSE; } int jk_attach_file_logger(jk_logger_t **l, int fd, int level) { if (l && fd >= 0) { jk_logger_t *rc = (jk_logger_t *)malloc(sizeof(jk_logger_t)); jk_file_logger_t *p = (jk_file_logger_t *) malloc(sizeof(jk_file_logger_t)); if (rc && p) { rc->log = log_to_file; rc->level = level; rc->logger_private = p; #if defined(AS400) && !defined(AS400_UTF8) p->logfile = fdopen(fd, "a+, o_ccsid=0"); #elif defined(WIN32) && defined(_MSC_VER) p->logfile = fdopen(fd, "a+c"); #else p->logfile = fdopen(fd, "a+"); #endif if (p->logfile) { *l = rc; jk_set_time_fmt(rc, NULL); return JK_TRUE; } } if (rc) { free(rc); } if (p) { free(p); } *l = NULL; } return JK_FALSE; } int jk_close_file_logger(jk_logger_t **l) { if (l && *l) { jk_file_logger_t *p = (*l)->logger_private; if (p) { fflush(p->logfile); fclose(p->logfile); free(p); } free(*l); *l = NULL; return JK_TRUE; } return JK_FALSE; } int jk_log(jk_log_context_t *log_ctx, const char *file, int line, const char *funcname, int level, const char *fmt, ...) { int rc = 0; jk_logger_t *l; /* * Need to reserve space for terminating zero byte * and platform specific line endings added during the call * to the output routing. */ static int usable_size = LOG_BUFFER_SIZE - 3; if (!log_ctx || !(l = log_ctx->logger) || !file || !fmt) { return -1; } if ((l->level <= level) || (level == JK_LOG_REQUEST_LEVEL)) { char buf[LOG_BUFFER_SIZE]; char *f = (char *)(file + strlen(file) - 1); va_list args; int used = 0; while (f != file && '\\' != *f && '/' != *f) { f--; } if (f != file) { f++; } used = set_time_str(buf, usable_size, l); if (line) { /* line==0 only used for request log item */ /* Log [requestid] for all levels except REQUEST. */ const char *context_id; if (log_ctx == NULL) { context_id = "-"; rc = 1; } else if (log_ctx->id == NULL) { context_id = "NO-ID"; rc = 5; } else { context_id = log_ctx->id; rc = (int)strlen(context_id); } if (usable_size - used >= rc + 3) { strncpy(buf + used, "[", 1); used += 1; strncpy(buf + used, context_id, rc); used += rc; strncpy(buf + used, "] ", 2); used += 2; } else { strcpy(buf, "Logging failed in context_id formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; } /* Log [pid:threadid] for all levels except REQUEST. * This information helps to correlate lines from different logs. * Performance is no issue, because with production log levels * we only call it often, if we have a lot of errors */ rc = snprintf(buf + used, usable_size - used, "[%" JK_PID_T_FMT ":%" JK_PTHREAD_T_FMT "] ", getpid(), jk_gettid()); used += rc; if (rc < 0) { strcpy(buf, "Logging failed in pid/tid formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; } rc = (int)strlen(jk_level_verbs[level]); if (usable_size - used >= rc) { strncpy(buf + used, jk_level_verbs[level], rc); used += rc; } else { strcpy(buf, "Logging failed in log level formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; /* [V] not sure what to return... */ } if (funcname) { rc = (int)strlen(funcname); if (usable_size - used >= rc + 2) { strncpy(buf + used, funcname, rc); used += rc; strncpy(buf + used, "::", 2); used += 2; } else { strcpy(buf, "Logging failed in function name formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; /* [V] not sure what to return... */ } } rc = (int)strlen(f); if (usable_size - used >= rc) { strncpy(buf + used, f, rc); used += rc; } else { strcpy(buf, "Logging failed in source file name formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; /* [V] not sure what to return... */ } rc = snprintf(buf + used, usable_size - used, " (%d): ", line); used += rc; if (rc < 0 || usable_size - used < 0) { strcpy(buf, "Logging failed in line number formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; /* [V] not sure what to return... */ } } va_start(args, fmt); rc = vsnprintf(buf + used, usable_size - used, fmt, args); va_end(args); /* Depending on the snprintf implementation used, * "rc == usable_size - used" can indicate not enough space in buffer */ if (rc < usable_size - used) { used += rc; } else { used = usable_size; buf[used - 1] = '.'; buf[used - 2] = '.'; buf[used - 3] = '.'; } l->log(l, level, used, buf); } return rc; } const char *jk_get_worker_type(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(TYPE_OF_WORKER); return jk_map_get_string(m, buf, DEFAULT_WORKER_TYPE); } const char *jk_get_worker_route(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; const char *v; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(ROUTE_OF_WORKER); v = jk_map_get_string(m, buf, def); if (v) { return v; } /* Try old jvm_route directive */ MAKE_WORKER_PARAM(JVM_ROUTE_OF_WORKER_DEPRECATED); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_domain(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(DOMAIN_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_redirect(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(REDIRECT_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_secret(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SECRET_OF_WORKER); return jk_map_get_string(m, buf, NULL); } const char *jk_get_worker_host(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(HOST_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_source(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SOURCE_OF_WORKER); return jk_map_get_string(m, buf, def); } int jk_get_worker_port(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PORT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_prefer_ipv6(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PREFER_IPV6_ADDRESS); return jk_map_get_bool(m, buf, def); } static int def_cache_size = -1; int jk_get_worker_def_cache_size(int protocol) { if (def_cache_size < 1) { if (protocol == AJP14_PROTO) def_cache_size = AJP14_DEF_CACHE_SZ; else def_cache_size = AJP13_DEF_CACHE_SZ; } return def_cache_size; } void jk_set_worker_def_cache_size(int sz) { def_cache_size = sz; } int jk_get_worker_cache_size(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; int rv; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CACHE_OF_WORKER); if ((rv = jk_map_get_int(m, buf, -1)) >= 0) return rv; MAKE_WORKER_PARAM(CACHE_OF_WORKER_DEPRECATED); return jk_map_get_int(m, buf, def); } int jk_get_worker_cache_size_min(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CACHE_OF_WORKER_MIN); return jk_map_get_int(m, buf, def); } int jk_get_worker_cache_acquire_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CACHE_ACQUIRE_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_socket_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(SOCKET_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_socket_connect_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(SOCKET_CONNECT_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_recover_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(WORKER_RECOVER_TIME); return jk_map_get_int(m, buf, def); } int jk_get_worker_error_escalation_time(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(WORKER_ERROR_ESCALATION_TIME); return jk_map_get_int(m, buf, def); } int jk_get_worker_max_reply_timeouts(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(MAX_REPLY_TIMEOUTS_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_retry_interval(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(RETRY_INTERVAL_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_busy_limit(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(BUSY_LIMIT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_socket_buffer(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; int i; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(SOCKET_BUFFER_OF_WORKER); i = jk_map_get_int(m, buf, 0); if (i > 0 && i < def) i = def; return i; } int jk_get_worker_socket_keepalive(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(SOCKET_KEEPALIVE_OF_WORKER); return jk_map_get_bool(m, buf, def); } int jk_get_worker_conn_ping_interval(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CONN_PING_INTERVAL_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_cache_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; int rv; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CACHE_TIMEOUT_OF_WORKER); if ((rv = jk_map_get_int(m, buf, -1)) >= 0) return rv; MAKE_WORKER_PARAM(CACHE_TIMEOUT_DEPRECATED); return jk_map_get_int(m, buf, def); } int jk_get_worker_connect_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CONNECT_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_prepost_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PREPOST_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_ping_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PING_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_ping_mode(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; char mode[100]; const char *v; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PING_MODE_OF_WORKER); jk_ajp_get_cping_text(def, mode); v = jk_map_get_string(m, buf, mode); return jk_ajp_get_cping_mode(v, def); } int jk_get_worker_reply_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(REPLY_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_recycle_timeout(jk_map_t *m, const char *wname, int def) { return def; } int jk_get_worker_retries(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; int rv; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(RETRIES_OF_WORKER); rv = jk_map_get_int(m, buf, def); if (rv < 1) rv = 1; return rv; } int jk_get_worker_lb_retries(jk_map_t *m, const char *wname, int def) { char buf[1024]; int rv; if (!m || !wname) { return -1; } MAKE_WORKER_PARAM(LB_RETRIES_OF_WORKER); rv = jk_map_get_int(m, buf, def); if (rv < 1) rv = 1; return rv; } int jk_get_worker_recovery_opts(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(RECOVERY_OPTS_OF_WORKER); return jk_map_get_int(m, buf, def); } const char *jk_get_worker_secret_key(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SECRET_KEY_OF_WORKER); return jk_map_get_string(m, buf, NULL); } int jk_get_worker_list(jk_map_t *m, char ***list, unsigned *num_of_workers) { if (m && list && num_of_workers) { char **ar = jk_map_get_string_list(m, WORKER_LIST_PROPERTY_NAME, num_of_workers, DEFAULT_WORKER); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num_of_workers = 0; } return JK_FALSE; } int jk_get_is_worker_disabled(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(IS_WORKER_DISABLED_DEPRECATED); return jk_map_get_bool(m, buf, def); } return JK_TRUE; } int jk_get_is_worker_stopped(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(IS_WORKER_STOPPED_DEPRECATED); return jk_map_get_bool(m, buf, def); } return JK_TRUE; } int jk_get_worker_activation(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; const char *v; if (!m || !wname) { return JK_LB_ACTIVATION_ACTIVE; } MAKE_WORKER_PARAM(ACTIVATION_OF_WORKER); v = jk_map_get_string(m, buf, NULL); if (v) return jk_lb_get_activation_code(v); if (jk_get_is_worker_stopped(m, wname)) return JK_LB_ACTIVATION_STOPPED; if (jk_get_is_worker_disabled(m, wname)) return JK_LB_ACTIVATION_DISABLED; return JK_LB_ACTIVATION_DEF; } int jk_get_lb_factor(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return DEFAULT_LB_FACTOR; } MAKE_WORKER_PARAM(LOAD_FACTOR_OF_WORKER); return jk_map_get_int(m, buf, DEFAULT_LB_FACTOR); } int jk_get_distance(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return DEFAULT_DISTANCE; } MAKE_WORKER_PARAM(DISTANCE_OF_WORKER); return jk_map_get_int(m, buf, DEFAULT_DISTANCE); } int jk_get_is_sticky_session(jk_map_t *m, const char *wname) { int def = JK_TRUE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(STICKY_SESSION); return jk_map_get_bool(m, buf, def); } return def; } int jk_get_is_sticky_session_force(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(STICKY_SESSION_FORCE); return jk_map_get_bool(m, buf, def); } return def; } int jk_get_lb_method(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; const char *v; if (!m || !wname) { return JK_LB_METHOD_DEF; } MAKE_WORKER_PARAM(METHOD_OF_WORKER); v = jk_map_get_string(m, buf, JK_LB_METHOD_DEF); return jk_lb_get_method_code(v); } int jk_get_lb_lock(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; const char *v; if (!m || !wname) { return JK_LB_LOCK_DEF; } MAKE_WORKER_PARAM(LOCK_OF_WORKER); v = jk_map_get_string(m, buf, JK_LB_LOCK_DEF); return jk_lb_get_lock_code(v); } int jk_get_max_packet_size(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; int sz; if (!m || !wname) { return AJP13_DEF_PACKET_SIZE; } MAKE_WORKER_PARAM(WORKER_MAX_PACKET_SIZE); sz = jk_map_get_int(m, buf, AJP13_DEF_PACKET_SIZE); sz = JK_ALIGN(sz, AJP13_PACKET_SIZE_ALIGN); if (sz < AJP13_DEF_PACKET_SIZE) sz = AJP13_DEF_PACKET_SIZE; else if (sz > AJP13_MAX_PACKET_SIZE) sz = AJP13_MAX_PACKET_SIZE; return sz; } int jk_get_worker_fail_on_status(jk_map_t *m, const char *wname, int **list, unsigned int *list_size) { char buf[PARAM_BUFFER_SIZE]; int *ar; if (!m || !wname || !list || !list_size) { return 0; } MAKE_WORKER_PARAM(STATUS_FAIL_OF_WORKER); ar = jk_map_get_int_list(m, buf, list_size, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *list_size = 0; return JK_FALSE; } int jk_get_worker_user_case_insensitive(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(USER_CASE_OF_WORKER); return jk_map_get_bool(m, buf, def); } return def; } const char *jk_get_worker_style_sheet(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(STYLE_SHEET_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_name_space(jk_map_t *m, const char *wname, const char *def) { const char *rc; char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(NAMESPACE_OF_WORKER); rc = jk_map_get_string(m, buf, def); if (*rc == '-') return ""; else return rc; } const char *jk_get_worker_xmlns(jk_map_t *m, const char *wname, const char *def) { const char *rc; char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(XML_NAMESPACE_OF_WORKER); rc = jk_map_get_string(m, buf, def); if (*rc == '-') return ""; else return rc; } const char *jk_get_worker_xml_doctype(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(XML_DOCTYPE_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_prop_prefix(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PROP_PREFIX_OF_WORKER); return jk_map_get_string(m, buf, def); } int jk_get_is_read_only(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(READ_ONLY_OF_WORKER); return jk_map_get_bool(m, buf, def); } return def; } int jk_get_worker_user_list(jk_map_t *m, const char *wname, char ***list, unsigned int *num) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num && wname) { char **ar = NULL; MAKE_WORKER_PARAM(USER_OF_WORKER); ar = jk_map_get_string_list(m, buf, num, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num = 0; } return JK_FALSE; } int jk_get_worker_good_rating(jk_map_t *m, const char *wname, char ***list, unsigned int *num) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num && wname) { char **ar = NULL; MAKE_WORKER_PARAM(GOOD_RATING_OF_WORKER); ar = jk_map_get_string_list(m, buf, num, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num = 0; } return JK_FALSE; } int jk_get_worker_bad_rating(jk_map_t *m, const char *wname, char ***list, unsigned int *num) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num && wname) { char **ar = NULL; MAKE_WORKER_PARAM(BAD_RATING_OF_WORKER); ar = jk_map_get_string_list(m, buf, num, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num = 0; } return JK_FALSE; } int jk_get_lb_worker_list(jk_map_t *m, const char *wname, char ***list, unsigned int *num_of_workers) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num_of_workers && wname) { char **ar = NULL; MAKE_WORKER_PARAM(BALANCE_WORKERS); ar = jk_map_get_string_list(m, buf, num_of_workers, NULL); if (ar) { *list = ar; return JK_TRUE; } /* Try old balanced_workers directive */ MAKE_WORKER_PARAM(BALANCED_WORKERS_DEPRECATED); ar = jk_map_get_string_list(m, buf, num_of_workers, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num_of_workers = 0; } return JK_FALSE; } int jk_get_worker_mount_list(jk_map_t *m, const char *wname, char ***list, unsigned int *num_of_maps) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num_of_maps && wname) { char **ar = NULL; MAKE_WORKER_PARAM(MOUNT_OF_WORKER); ar = jk_map_get_string_list(m, buf, num_of_maps, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num_of_maps = 0; } return JK_FALSE; } int jk_get_worker_maintain_time(jk_map_t *m) { return jk_map_get_int(m, WORKER_MAINTAIN_PROPERTY_NAME, DEFAULT_MAINTAIN_TIME); } int jk_get_worker_mx(jk_map_t *m, const char *wname, unsigned *mx) { char buf[PARAM_BUFFER_SIZE]; if (m && mx && wname) { int i; MAKE_WORKER_PARAM(MX_OF_WORKER); i = jk_map_get_int(m, buf, -1); if (-1 != i) { *mx = (unsigned)i; return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_ms(jk_map_t *m, const char *wname, unsigned *ms) { char buf[PARAM_BUFFER_SIZE]; if (m && ms && wname) { int i; MAKE_WORKER_PARAM(MS_OF_WORKER); i = jk_map_get_int(m, buf, -1); if (-1 != i) { *ms = (unsigned)i; return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_classpath(jk_map_t *m, const char *wname, const char **cp) { char buf[PARAM_BUFFER_SIZE]; if (m && cp && wname) { MAKE_WORKER_PARAM(CP_OF_WORKER); *cp = jk_map_get_string(m, buf, NULL); if (*cp) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_bridge_type(jk_map_t *m, const char *wname, unsigned *bt) { char buf[PARAM_BUFFER_SIZE]; const char *type; if (m && bt && wname) { MAKE_WORKER_PARAM(BRIDGE_OF_WORKER); type = jk_map_get_string(m, buf, NULL); if (type) { if (!strcasecmp(type, TOMCAT32_BRIDGE_NAME)) *bt = TC32_BRIDGE_TYPE; else if (!strcasecmp(type, TOMCAT33_BRIDGE_NAME)) *bt = TC33_BRIDGE_TYPE; else if (!strcasecmp(type, TOMCAT40_BRIDGE_NAME)) *bt = TC40_BRIDGE_TYPE; else if (!strcasecmp(type, TOMCAT41_BRIDGE_NAME)) *bt = TC41_BRIDGE_TYPE; else if (!strcasecmp(type, TOMCAT50_BRIDGE_NAME)) *bt = TC50_BRIDGE_TYPE; return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_jvm_path(jk_map_t *m, const char *wname, const char **vm_path) { char buf[PARAM_BUFFER_SIZE]; if (m && vm_path && wname) { MAKE_WORKER_PARAM(JVM_OF_WORKER); *vm_path = jk_map_get_string(m, buf, NULL); if (*vm_path) { return JK_TRUE; } } return JK_FALSE; } /* [V] This is unused. currently. */ int jk_get_worker_callback_dll(jk_map_t *m, const char *wname, const char **cb_path) { char buf[PARAM_BUFFER_SIZE]; if (m && cb_path && wname) { MAKE_WORKER_PARAM(NATIVE_LIB_OF_WORKER); *cb_path = jk_map_get_string(m, buf, NULL); if (*cb_path) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_cmd_line(jk_map_t *m, const char *wname, const char **cmd_line) { char buf[PARAM_BUFFER_SIZE]; if (m && cmd_line && wname) { MAKE_WORKER_PARAM(CMD_LINE_OF_WORKER); *cmd_line = jk_map_get_string(m, buf, NULL); if (*cmd_line) { return JK_TRUE; } } return JK_FALSE; } int jk_stat(const char *f, struct stat * statbuf) { int rc; /** * i5/OS V5R4 expect filename in ASCII for fopen but required them in EBCDIC for stat() */ #ifdef AS400_UTF8 char *ptr; ptr = (char *)malloc(strlen(f) + 1); jk_ascii2ebcdic((char *)f, ptr); rc = stat(ptr, statbuf); free(ptr); #else rc = stat(f, statbuf); #endif return (rc); } int jk_file_exists(const char *f) { if (f) { struct stat st; if ((0 == jk_stat(f, &st)) && (st.st_mode & S_IFREG)) return JK_TRUE; } return JK_FALSE; } static int jk_is_some_property(const char *prp_name, const char *suffix, const char *sep) { if (prp_name && suffix && sep) { size_t prp_name_len = strlen(prp_name); size_t suffix_len = strlen(suffix); size_t sep_len = strlen(sep); size_t sep_off = sep_len + suffix_len; if (prp_name_len >= sep_off) { if (!strncmp(prp_name + prp_name_len - sep_off, sep, sep_len) && !strncmp(prp_name + prp_name_len - suffix_len, suffix, suffix_len)) { return JK_TRUE; } } } return JK_FALSE; } int jk_is_path_property(const char *prp_name) { return jk_is_some_property(prp_name, "path", "_"); } int jk_is_cmd_line_property(const char *prp_name) { return jk_is_some_property(prp_name, CMD_LINE_OF_WORKER, "."); } int jk_is_list_property(const char *prp_name) { const char **props = &list_properties[0]; while (*props) { if (jk_is_some_property(prp_name, *props, ".")) return JK_TRUE; props++; } return JK_FALSE; } int jk_is_unique_property(const char *prp_name) { const char **props = &unique_properties[0]; while (*props) { if (jk_is_some_property(prp_name, *props, ".")) return JK_TRUE; props++; } return JK_FALSE; } int jk_is_deprecated_property(const char *prp_name) { const char **props = &deprecated_properties[0]; while (*props) { if (jk_is_some_property(prp_name, *props, ".")) return JK_TRUE; props++; } return JK_FALSE; } int jk_check_buffer_size() { const char **props; size_t len = 0; size_t max_len = 0; props = &supported_properties[0]; while (*props) { len = strlen(*props); if (len > max_len) max_len = len; props++; } return JK_MAX_ATTRIBUTE_NAME_LEN - (int)max_len; } /* * Check that property is a valid one (to prevent user typos). * Only property starting with worker. */ int jk_is_valid_property(const char *prp_name) { const char **props; /* Any property not starting with "worker." is "valid". * It is interpreted as the definition of a custom variable. */ if (memcmp(prp_name, "worker.", 7)) return JK_TRUE; props = &supported_properties[0]; while (*props) { if (jk_is_some_property(prp_name, *props, ".")) return JK_TRUE; props++; } return JK_FALSE; } int jk_get_worker_stdout(jk_map_t *m, const char *wname, const char **stdout_name) { char buf[PARAM_BUFFER_SIZE]; if (m && stdout_name && wname) { MAKE_WORKER_PARAM(STDOUT_OF_WORKER); *stdout_name = jk_map_get_string(m, buf, NULL); if (*stdout_name) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_stderr(jk_map_t *m, const char *wname, const char **stderr_name) { char buf[PARAM_BUFFER_SIZE]; if (m && stderr_name && wname) { MAKE_WORKER_PARAM(STDERR_OF_WORKER); *stderr_name = jk_map_get_string(m, buf, NULL); if (*stderr_name) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_sysprops(jk_map_t *m, const char *wname, const char **sysprops) { char buf[PARAM_BUFFER_SIZE]; if (m && sysprops && wname) { MAKE_WORKER_PARAM(SYSPROPS_OF_WORKER); *sysprops = jk_map_get_string(m, buf, NULL); if (*sysprops) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_libpath(jk_map_t *m, const char *wname, const char **libpath) { char buf[PARAM_BUFFER_SIZE]; if (m && libpath && wname) { MAKE_WORKER_PARAM(LIBPATH_OF_WORKER); *libpath = jk_map_get_string(m, buf, NULL); if (*libpath) { return JK_TRUE; } } return JK_FALSE; } const char *jk_get_lb_session_cookie(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SESSION_COOKIE_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_lb_session_path(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SESSION_PATH_OF_WORKER); return jk_map_get_string(m, buf, def); } int jk_get_lb_set_session_cookie(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(SET_SESSION_COOKIE); return jk_map_get_bool(m, buf, def); } return def; } const char *jk_get_lb_session_cookie_path(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SESSION_COOKIE_PATH_OF_WORKER); return jk_map_get_string(m, buf, def); } int is_http_status_fail(unsigned int http_status_fail_num, int *http_status_fail, int status) { unsigned int i; int soft_status = -1 * status; for (i = 0; i < http_status_fail_num; i++) { if (http_status_fail[i] == status) return 1; if (http_status_fail[i] == soft_status) return -1; } return 0; } char **jk_parse_sysprops(jk_pool_t *p, const char *sysprops) { char **rc = NULL; #ifdef _MT_CODE_PTHREAD char *lasts; #endif if (p && sysprops) { char *prps = jk_pool_strdup(p, sysprops); if (prps && strlen(prps)) { unsigned num_of_prps; for (num_of_prps = 1; *sysprops; sysprops++) { if ('*' == *sysprops) { num_of_prps++; } } rc = jk_pool_alloc(p, (num_of_prps + 1) * sizeof(char *)); if (rc) { unsigned i = 0; #ifdef _MT_CODE_PTHREAD char *tmp = strtok_r(prps, "*", &lasts); #else char *tmp = strtok(prps, "*"); #endif while (tmp && i < num_of_prps) { rc[i] = tmp; #ifdef _MT_CODE_PTHREAD tmp = strtok_r(NULL, "*", &lasts); #else tmp = strtok(NULL, "*"); #endif i++; } rc[i] = NULL; } } } return rc; } void jk_append_libpath(jk_pool_t *p, const char *libpath) { char *env = NULL; char *current = getenv(PATH_ENV_VARIABLE); if (current) { env = jk_pool_alloc(p, strlen(PATH_ENV_VARIABLE) + strlen(current) + strlen(libpath) + 5); if (env) { sprintf(env, "%s=%s%c%s", PATH_ENV_VARIABLE, libpath, PATH_SEPERATOR, current); } } else { env = jk_pool_alloc(p, strlen(PATH_ENV_VARIABLE) + strlen(libpath) + 5); if (env) { sprintf(env, "%s=%s", PATH_ENV_VARIABLE, libpath); } } if (env) { putenv(env); } } void jk_init_ws_service(jk_ws_service_t *s) { memset(s, 0, sizeof(jk_ws_service_t)); s->server_port = 80; s->ssl_key_size = -1; s->activation = JK_LB_ACTIVATION_TEXT_ACTIVE; s->reco_status = RECO_NONE; s->extension.reply_timeout = -1; s->http_response_status = JK_HTTP_OK; } /* Match = 0, NoMatch = 1, Abort = -1 * Based loosely on sections of wildmat.c by Rich Salz */ int jk_wildchar_match(const char *str, const char *exp, int icase) { int x, y; for (x = 0, y = 0; exp[y]; ++y, ++x) { if (!str[x] && exp[y] != '*') return -1; if (exp[y] == '*') { while (exp[++y] == '*'); if (!exp[y]) return 0; while (str[x]) { int ret; if ((ret = jk_wildchar_match(&str[x++], &exp[y], icase)) != 1) return ret; } return -1; } else if (exp[y] != '?') { if (icase && (tolower(str[x]) != tolower(exp[y]))) return 1; else if (!icase && str[x] != exp[y]) return 1; } } return (str[x] != '\0'); } int jk_servlet_normalize(char *path, jk_log_context_t *log_ctx) { int l, w; if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "URI on entering jk_servlet_normalize: [%s]", path); } // This test allows the loops below to start at index 1 rather than 0. if (path[0] != '/') { if (path[0] == '*' && path[1] == '\0') { /* Most likely an "OPTIONS *" request */ return 0; } jk_log(log_ctx, JK_LOG_WARNING, "Uri [%s] does not start with '/'.", path); return JK_NORMALIZE_BAD_PATH; } /* First pass. * Remove path parameters ;foo=bar/ from any path segment */ for (l = 1, w = 1; path[l] != '\0';) { if (path[l] == ';') { l++; while (path[l] != '/' && path[l] != '\0') { l++; } } else path[w++] = path[l++]; } path[w] = '\0'; /* * Second pass. * Collapse ///// sequences to / */ for (l = 1, w = 1; path[l] != '\0';) { if (path[w - 1] == '/' && (path[l] == '/')) { l++; } else path[w++] = path[l++]; } path[w] = '\0'; /* Third pass. * Remove /./ segments * Both leading and trailing segments will be removed. */ for (l = 1, w = 1; path[l] != '\0';) { if (path[l] == '.' && (path[l + 1] == '/' || path[l + 1] == '\0') && (l == 0 || path[l - 1] == '/')) { l++; if (path[l] == '/') { l++; } } else path[w++] = path[l++]; } path[w] = '\0'; /* Fourth pass. * Remove /xx/../ segments * Trailing segments will be removed but leading /../ segments are an error * condition. */ for (l = 1, w = 1; path[l] != '\0';) { if (path[l] == '.' && path[l + 1] == '.' && (path[l + 2] == '/' || path[l + 2] == '\0') && (l == 0 || path[l - 1] == '/')) { // Wind w back to remove the previous segment if (w == 1) { jk_log(log_ctx, JK_LOG_EMERG, "[%s] contains a '/../' sequence that tries to escape above the root.", path); return JK_NORMALIZE_TRAVERSAL; } do { w--; } while (w != 0 && path[w - 1] != '/'); // Move l forward to the next segment l += 2; if (path[l] == '/') { l++; } } else path[w++] = path[l++]; } path[w] = '\0'; if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "URI on exiting jk_servlet_normalize: [%s]", path); } return 0; } int jk_strip_session_id(char* path, char* session_name, jk_log_context_t *log_ctx) { char *jsessionid; jsessionid = strstr(path, session_name); if (jsessionid) { int i; int j; if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "removing session identifier for non servlet uri [%s]", path); } // Found a session path parameter. // Need to skip at least as many characters as there are in // strip_session_name i = (int) strlen(session_name); j = 0; // Increment i until the first character after the parameter while (jsessionid[i] != '\0' && jsessionid[i] != ';' && jsessionid[i] != '/') { i++; } // Copy until the end while (jsessionid[i] != '\0') { jsessionid[j++] = jsessionid[i++]; } // Terminate jsessionid[j] = '\0'; if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "result of removing session identifier for non servlet uri is [%s]", path); } return 1; } return 0; } #ifdef _MT_CODE_PTHREAD jk_pthread_t jk_gettid() { union { pthread_t tid; jk_uint64_t alignme; } u; #ifdef AS400 /* OS400 use 64 bits ThreadId */ pthread_id_np_t tid; #endif /* AS400 */ u.tid = pthread_self(); #ifdef AS400 /* Get only low 32 bits for now */ pthread_getunique_np(&(u.tid), &tid); return ((jk_uint32_t)(tid.intId.lo & 0xFFFFFFFF)); #else return ((jk_pthread_t)u.tid); #endif /* AS400 */ } #endif /*** * ASCII <-> EBCDIC conversions * * For now usefull only in i5/OS V5R4 where UTF and EBCDIC mode are mixed */ #ifdef AS400_UTF8 /* EBCDIC to ASCII translation table */ static u_char ebcdic_to_ascii[256] = { 0x00,0x01,0x02,0x03,0x20,0x09,0x20,0x7f, /* 00-07 */ 0x20,0x20,0x20,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */ 0x10,0x11,0x12,0x13,0x20,0x0a,0x08,0x20, /* 10-17 */ 0x18,0x19,0x20,0x20,0x20,0x1d,0x1e,0x1f, /* 18-1f */ 0x20,0x20,0x1c,0x20,0x20,0x0a,0x17,0x1b, /* 20-27 */ 0x20,0x20,0x20,0x20,0x20,0x05,0x06,0x07, /* 28-2f */ 0x20,0x20,0x16,0x20,0x20,0x20,0x20,0x04, /* 30-37 */ 0x20,0x20,0x20,0x20,0x14,0x15,0x20,0x1a, /* 38-3f */ 0x20,0x20,0x83,0x84,0x85,0xa0,0xc6,0x86, /* 40-47 */ 0x87,0xa4,0xbd,0x2e,0x3c,0x28,0x2b,0x7c, /* 48-4f */ 0x26,0x82,0x88,0x89,0x8a,0xa1,0x8c,0x8b, /* 50-57 */ 0x8d,0xe1,0x21,0x24,0x2a,0x29,0x3b,0xaa, /* 58-5f */ 0x2d,0x2f,0xb6,0x8e,0xb7,0xb5,0xc7,0x8f, /* 60-67 */ 0x80,0xa5,0xdd,0x2c,0x25,0x5f,0x3e,0x3f, /* 68-6f */ 0x9b,0x90,0xd2,0xd3,0xd4,0xd6,0xd7,0xd8, /* 70-77 */ 0xde,0x60,0x3a,0x23,0x40,0x27,0x3d,0x22, /* 78-7f */ 0x9d,0x61,0x62,0x63,0x64,0x65,0x66,0x67, /* 80-87 */ 0x68,0x69,0xae,0xaf,0xd0,0xec,0xe7,0xf1, /* 88-8f */ 0xf8,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, /* 90-97 */ 0x71,0x72,0xa6,0xa7,0x91,0xf7,0x92,0xcf, /* 98-9f */ 0xe6,0x7e,0x73,0x74,0x75,0x76,0x77,0x78, /* a8-a7 */ 0x79,0x7a,0xad,0xa8,0xd1,0xed,0xe8,0xa9, /* a8-af */ 0x5e,0x9c,0xbe,0xfa,0xb8,0x15,0x14,0xac, /* b0-b7 */ 0xab,0xf3,0x5b,0x5d,0xee,0xf9,0xef,0x9e, /* b8-bf */ 0x7b,0x41,0x42,0x43,0x44,0x45,0x46,0x47, /* c0-c7 */ 0x48,0x49,0xf0,0x93,0x94,0x95,0xa2,0xe4, /* c8-cf */ 0x7d,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50, /* d0-d7 */ 0x51,0x52,0xfb,0x96,0x81,0x97,0xa3,0x98, /* d8-df */ 0x5c,0xf6,0x53,0x54,0x55,0x56,0x57,0x58, /* e0-e7 */ 0x59,0x5a,0xfc,0xe2,0x99,0xe3,0xe0,0xe5, /* e8-ef */ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, /* f0-f7 */ 0x38,0x39,0xfd,0xea,0x9a,0xeb,0xe9,0xff /* f8-ff */ }; /* ASCII to EBCDIC translation table */ static u_char ascii_to_ebcdic[256] = { 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, /* 00-07 */ 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */ 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, /* 10-17 */ 0x18,0x19,0x3f,0x27,0x22,0x1d,0x1e,0x1f, /* 18-1f */ 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, /* 20-27 */ 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, /* 28-2f */ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, /* 30-37 */ 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, /* 38-3f */ 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, /* 40-47 */ 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, /* 48-4f */ 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, /* 50-57 */ 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, /* 58-5f */ 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, /* 60-67 */ 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, /* 68-6f */ 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, /* 70-77 */ 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, /* 78-7f */ 0x68,0xdc,0x51,0x42,0x43,0x44,0x47,0x48, /* 80-87 */ 0x52,0x53,0x54,0x57,0x56,0x58,0x63,0x67, /* 88-8f */ 0x71,0x9c,0x9e,0xcb,0xcc,0xcd,0xdb,0xdd, /* 90-97 */ 0xdf,0xec,0xfc,0x70,0xb1,0x80,0xbf,0x40, /* 98-9f */ 0x45,0x55,0xee,0xde,0x49,0x69,0x9a,0x9b, /* a8-a7 */ 0xab,0xaf,0x5f,0xb8,0xb7,0xaa,0x8a,0x8b, /* a8-af */ 0x40,0x40,0x40,0x40,0x40,0x65,0x62,0x64, /* b0-b7 */ 0xb4,0x40,0x40,0x40,0x40,0x4a,0xb2,0x40, /* b8-bf */ 0x40,0x40,0x40,0x40,0x40,0x40,0x46,0x66, /* c0-c7 */ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x9f, /* c8-cf */ 0x8c,0xac,0x72,0x73,0x74,0x89,0x75,0x76, /* d0-d7 */ 0x77,0x40,0x40,0x40,0x40,0x6a,0x78,0x40, /* d8-df */ 0xee,0x59,0xeb,0xed,0xcf,0xef,0xa0,0x8e, /* e0-e7 */ 0xae,0xfe,0xfb,0xfd,0x8d,0xad,0xbc,0xbe, /* e8-ef */ 0xca,0x8f,0x40,0xb9,0xb6,0xb5,0xe1,0x9d, /* f0-f7 */ 0x90,0xbd,0xb3,0xda,0xea,0xfa,0x40,0x40 /* f8-ff */ }; void jk_ascii2ebcdic(char *src, char *dst) { char c; while ((c = *src++) != 0) { *dst++ = ascii_to_ebcdic[(unsigned int)c]; } *dst = 0; } void jk_ebcdic2ascii(char *src, char *dst) { char c; while ((c = *src++) != 0) { *dst++ = ebcdic_to_ascii[(unsigned int)c]; } *dst = 0; } #endif #if defined (WIN32) static PSECURITY_ATTRIBUTES pNullSA; static SECURITY_ATTRIBUTES stEmptySA; /* To share the objects with other processes, we need a 0 ACL * Code from MS KB Q106387 */ PSECURITY_ATTRIBUTES jk_get_sa_with_null_dacl() { DWORD rc = 0; PSECURITY_DESCRIPTOR pSD; if (pNullSA != NULL) { return pNullSA; } else { stEmptySA.nLength = (DWORD)sizeof(SECURITY_ATTRIBUTES); stEmptySA.lpSecurityDescriptor = 0; } if (!(pNullSA = LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES)))) { rc = GetLastError(); goto cleanup; } pNullSA->nLength = (DWORD)sizeof(SECURITY_ATTRIBUTES); pSD = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (pSD == 0) { rc = GetLastError(); goto cleanup; } pNullSA->lpSecurityDescriptor = pSD; if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { rc = GetLastError(); goto cleanup; } if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL)0, FALSE)) { rc = GetLastError(); goto cleanup; } pNullSA->lpSecurityDescriptor = pSD; pNullSA->bInheritHandle = FALSE; SetLastError(0); return pNullSA; cleanup: if (pSD) LocalFree(pSD); if (pNullSA) LocalFree(pNullSA); pNullSA = &stEmptySA; pNullSA->bInheritHandle = FALSE; SetLastError(rc); return pNullSA; } #endif tomcat-connectors-1.2.50-src/native/common/jk_version.h0000644000000000000020000000450414655113617021427 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: JK version header file * ***************************************************************************/ #ifndef __JK_VERSION_H #define __JK_VERSION_H #define JK_VERMAJOR 1 #define JK_VERMINOR 2 #define JK_VERMICRO 50 #if defined(JK_ISAPI) #define JK_DISTNAME "isapi_redirector" #define JK_DLL_SUFFIX "dll" #elif defined(JK_NSAPI) #define JK_DISTNAME "nsapi_redirector" #define JK_DLL_SUFFIX "dll" #else #define JK_DISTNAME "mod_jk" #define JK_DLL_SUFFIX "so" #endif /* Build JK_EXPOSED_VERSION and JK_VERSION */ #define JK_EXPOSED_VERSION JK_DISTNAME "/" JK_VERSTRING #if !defined(JK_VERSUFIX) #define JK_VERSUFIX "" #endif #define JK_FULL_EXPOSED_VERSION JK_EXPOSED_VERSION JK_VERSUFIX #define JK_MAKEVERSION(major, minor, fix) \ (((major) << 24) + ((minor) << 16) + ((fix) << 8)) #define JK_VERSION JK_MAKEVERSION(JK_VERMAJOR, JK_VERMINOR, JK_VERMICRO) /** Properly quote a value as a string in the C preprocessor */ #define JK_STRINGIFY(n) JK_STRINGIFY_HELPER(n) /** Helper macro for JK_STRINGIFY */ #define JK_STRINGIFY_HELPER(n) #n #define JK_VERSTRING \ JK_STRINGIFY(JK_VERMAJOR) "." \ JK_STRINGIFY(JK_VERMINOR) "." \ JK_STRINGIFY(JK_VERMICRO) /* macro for Win32 .rc files using numeric csv representation */ #define JK_VERSIONCSV JK_VERMAJOR ##, \ ##JK_VERMINOR ##, \ ##JK_VERMICRO #endif /* __JK_VERSION_H */ tomcat-connectors-1.2.50-src/native/common/jk_sockbuf.h0000644000000000000020000000310614655113617021373 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Socket buffer header file * * Author: Gal Shachor * ***************************************************************************/ #include "jk_global.h" #define SOCKBUF_SIZE (8*1024) struct jk_sockbuf { char buf[SOCKBUF_SIZE]; unsigned int start; unsigned int end; jk_sock_t sd; }; typedef struct jk_sockbuf jk_sockbuf_t; int jk_sb_open(jk_sockbuf_t *sb, jk_sock_t sd); int jk_sb_write(jk_sockbuf_t *sb, const void *buf, unsigned sz); int jk_sb_read(jk_sockbuf_t *sb, char **buf, unsigned sz, unsigned *ac); int jk_sb_flush(jk_sockbuf_t *sb); int jk_sb_gets(jk_sockbuf_t *sb, char **ps); tomcat-connectors-1.2.50-src/native/common/jk_ajp14_worker.c0000644000000000000020000002476214655113617022255 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: AJP14 next generation Bi-directional protocol. * * Author: Henri Gomez * ***************************************************************************/ #include "jk_context.h" #include "jk_ajp14_worker.h" /* * AJP14 Autoconf Phase * * CONTEXT QUERY / REPLY */ #define MAX_URI_SIZE 512 static int handle_discovery(ajp_endpoint_t * ae, jk_worker_env_t *we, jk_msg_buf_t *msg, jk_log_context_t *l) { int cmd; int i, j; #if 0 /* Not used for now */ jk_login_service_t *jl = ae->worker->login; #endif jk_context_item_t *ci; jk_context_t *c; char *buf; #ifndef TESTME JK_TRACE_ENTER(l); ajp14_marshal_context_query_into_msgb(msg, we->virtual, l); jk_log(l, JK_LOG_DEBUG, "send query"); if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) { JK_TRACE_EXIT(l); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "wait context reply"); jk_b_reset(msg); if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) { JK_TRACE_EXIT(l); return JK_FALSE; } if ((cmd = jk_b_get_byte(msg)) != AJP14_CONTEXT_INFO_CMD) { jk_log(l, JK_LOG_ERROR, "awaited command %d, received %d", AJP14_CONTEXT_INFO_CMD, cmd); JK_TRACE_EXIT(l); return JK_FALSE; } if (context_alloc(&c, we->virtual) != JK_TRUE) { jk_log(l, JK_LOG_ERROR, "can't allocate context room"); JK_TRACE_EXIT(l); return JK_FALSE; } if (ajp14_unmarshal_context_info(msg, c, l) != JK_TRUE) { jk_log(l, JK_LOG_ERROR, "can't get context reply"); JK_TRACE_EXIT(l); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "received context"); buf = malloc(MAX_URI_SIZE); /* Really a very long URI */ if (!buf) { jk_log(l, JK_LOG_ERROR, "can't malloc buf"); JK_TRACE_EXIT(l); return JK_FALSE; } for (i = 0; i < c->size; i++) { ci = c->contexts[i]; for (j = 0; j < ci->size; j++) { #ifndef USE_SPRINTF snprintf(buf, MAX_URI_SIZE - 1, "/%s/%s", ci->cbase, ci->uris[j]); #else sprintf(buf, "/%s/%s", ci->cbase, ci->uris[j]); #endif jk_log(l, JK_LOG_INFO, "worker %s will handle uri %s in context %s [%s]", ae->worker->name, ci->uris[j], ci->cbase, buf); uri_worker_map_add(we->uri_to_worker, buf, ae->worker->name, SOURCE_TYPE_DISCOVER, l); } } free(buf); context_free(&c); #else uri_worker_map_add(we->uri_to_worker, "/examples/servlet/*", ae->worker->name, SOURCE_TYPE_DISCOVER, l); uri_worker_map_add(we->uri_to_worker, "/examples/*.jsp", ae->worker->name, SOURCE_TYPE_DISCOVER, l); uri_worker_map_add(we->uri_to_worker, "/examples/*.gif", ae->worker->name, SOURCE_TYPE_DISCOVER, l); #endif JK_TRACE_EXIT(l); return JK_TRUE; } /* * AJP14 Logon Phase * * INIT + REPLY / NEGO + REPLY */ static int handle_logon(ajp_endpoint_t * ae, jk_msg_buf_t *msg, jk_log_context_t *l) { int cmd; jk_login_service_t *jl = ae->worker->login; JK_TRACE_ENTER(l); ajp14_marshal_login_init_into_msgb(msg, jl, l); jk_log(l, JK_LOG_DEBUG, "send init"); if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) { JK_TRACE_EXIT(l); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "wait init reply"); jk_b_reset(msg); if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) { JK_TRACE_EXIT(l); return JK_FALSE; } if ((cmd = jk_b_get_byte(msg)) != AJP14_LOGSEED_CMD) { jk_log(l, JK_LOG_ERROR, "awaited command %d, received %d", AJP14_LOGSEED_CMD, cmd); JK_TRACE_EXIT(l); return JK_FALSE; } if (ajp14_unmarshal_login_seed(msg, jl, l) != JK_TRUE) { JK_TRACE_EXIT(l); return JK_FALSE; } jk_log(l, JK_LOG_DEBUG, "received entropy %s", jl->entropy); ajp14_compute_md5(jl, l); if (ajp14_marshal_login_comp_into_msgb(msg, jl, l) != JK_TRUE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) { JK_TRACE_EXIT(l); return JK_FALSE; } jk_b_reset(msg); if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) { JK_TRACE_EXIT(l); return JK_FALSE; } switch (jk_b_get_byte(msg)) { case AJP14_LOGOK_CMD: if (ajp14_unmarshal_log_ok(msg, jl, l) == JK_TRUE) { jk_log(l, JK_LOG_DEBUG, "Successfully connected to servlet-engine %s", jl->servlet_engine_name); JK_TRACE_EXIT(l); return JK_TRUE; } break; case AJP14_LOGNOK_CMD: ajp14_unmarshal_log_nok(msg, l); break; } JK_TRACE_EXIT(l); return JK_FALSE; } static int logon(ajp_endpoint_t * ae, jk_log_context_t *l) { jk_pool_t *p = &ae->pool; jk_msg_buf_t *msg; int rc; JK_TRACE_ENTER(l); msg = jk_b_new(p); jk_b_set_buffer_size(msg, AJP13_DEF_PACKET_SIZE); if ((rc = handle_logon(ae, msg, l)) == JK_FALSE) ajp_close_endpoint(ae, l); JK_TRACE_EXIT(l); return rc; } static int discovery(ajp_endpoint_t * ae, jk_worker_env_t *we, jk_log_context_t *l) { jk_pool_t *p = &ae->pool; jk_msg_buf_t *msg; int rc; JK_TRACE_ENTER(l); msg = jk_b_new(p); jk_b_set_buffer_size(msg, AJP13_DEF_PACKET_SIZE); if ((rc = handle_discovery(ae, we, msg, l)) == JK_FALSE) ajp_close_endpoint(ae, l); JK_TRACE_EXIT(l); return rc; } /* -------------------- Method -------------------- */ static int JK_METHOD validate(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { ajp_worker_t *aw; const char *secret_key; JK_TRACE_ENTER(l); if (ajp_validate(pThis, props, we, l, AJP14_PROTO) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } aw = pThis->worker_private; secret_key = jk_get_worker_secret_key(props, aw->name); if ((!secret_key) || (!strlen(secret_key))) { jk_log(l, JK_LOG_ERROR, "validate error, empty or missing secretkey"); JK_TRACE_EXIT(l); return JK_FALSE; } /* jk_log(l, JK_LOG_DEBUG, "Into ajp14:validate - secret_key=%s", secret_key); */ JK_TRACE_EXIT(l); return JK_TRUE; } static int JK_METHOD get_endpoint(jk_worker_t *pThis, jk_endpoint_t **pend, jk_log_context_t *l) { int rc; JK_TRACE_ENTER(l); rc = ajp_get_endpoint(pThis, pend, l, AJP14_PROTO); JK_TRACE_EXIT(l); return rc; } static int JK_METHOD init(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { ajp_worker_t *aw; ajp_endpoint_t *ae; jk_endpoint_t *je; int rc; JK_TRACE_EXIT(l); if (ajp_init(pThis, props, we, l, AJP14_PROTO) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } aw = pThis->worker_private; /* Set Secret Key (used at logon time) */ aw->login->secret_key = jk_get_worker_secret_key(props, aw->name); if (aw->login->secret_key == NULL) { jk_log(l, JK_LOG_ERROR, "can't malloc secret_key"); JK_TRACE_EXIT(l); return JK_FALSE; } /* Set WebServerName (used at logon time) */ aw->login->web_server_name = strdup(we->server_name); if (aw->login->web_server_name == NULL) { jk_log(l, JK_LOG_ERROR, "can't malloc web_server_name"); JK_TRACE_EXIT(l); return JK_FALSE; } if (get_endpoint(pThis, &je, l) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } ae = je->endpoint_private; if (ajp_connect_to_endpoint(ae, l) == JK_TRUE) { /* connection stage passed - try to get context info * this is the long awaited autoconf feature :) */ rc = discovery(ae, we, l); ajp_close_endpoint(ae, l); JK_TRACE_EXIT(l); return rc; } JK_TRACE_EXIT(l); return JK_TRUE; } static int JK_METHOD destroy(jk_worker_t **pThis, jk_log_context_t *l) { int rc; ajp_worker_t *aw = (*pThis)->worker_private; JK_TRACE_ENTER(l); if (aw->login) { free(aw->login); aw->login = NULL; } rc = ajp_destroy(pThis, l, AJP14_PROTO); JK_TRACE_EXIT(l); return rc; } int JK_METHOD ajp14_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *l) { ajp_worker_t *aw; JK_TRACE_ENTER(l); if (ajp_worker_factory(w, name, l) == JK_FALSE) return 0; aw = (*w)->worker_private; aw->proto = AJP14_PROTO; aw->login = (jk_login_service_t *)malloc(sizeof(jk_login_service_t)); if (aw->login == NULL) { jk_log(l, JK_LOG_ERROR, "malloc failed for login area"); JK_TRACE_EXIT(l); return 0; } memset(aw->login, 0, sizeof(jk_login_service_t)); aw->login->negotiation = (AJP14_CONTEXT_INFO_NEG | AJP14_PROTO_SUPPORT_AJP14_NEG); aw->login->web_server_name = NULL; /* must be set in init */ aw->worker.validate = validate; aw->worker.init = init; aw->worker.get_endpoint = get_endpoint; aw->worker.destroy = destroy; aw->logon = logon; /* LogOn Handler for AJP14 */ JK_TRACE_EXIT(l); return JK_AJP14_WORKER_TYPE; } tomcat-connectors-1.2.50-src/native/common/jk_url.h0000644000000000000020000000543214655113617020545 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: URL manipulation subroutines header file. (mod_proxy) * * Version: $Revision: 500534 $ * ***************************************************************************/ #ifndef _JK_URL_H #define _JK_URL_H #include "jk_global.h" #include "jk_pool.h" #include "jk_util.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * Do a canonical encoding of the url x. * String y contains the result and is pre-allocated * for at least maxlen bytes, including a '\0' terminator. */ int jk_canonenc(const char *x, char *y, int maxlen); /** * Unescapes a URL, leaving reserved characters intact. * @param escaped Optional buffer to write the encoded string, can be * NULL, in which case the URL decoding does not actually take place * but the result length of the decoded URL will be returned. * @param url String to be unescaped * @param slen The length of the original url, or -1 to decode until * a terminating '\0' is seen * @param forbid Optional list of forbidden characters, in addition to * 0x00 * @param reserved Optional list of reserved characters that will be * left unescaped * @param plus If non zero, '+' is converted to ' ' as per * application/x-www-form-urlencoded encoding * @param len If set, the length of the escaped string will be returned * @return JK_TRUE on success, JK_FALSE if no characters are * decoded or the string is NULL, if a bad escape sequence is * found, or if a character on the forbid list is found. * Implementation copied from APR 1.5.x. */ int jk_unescape_url(char *const escaped, const char *const url, size_t slen, const char *const forbid, const char *const reserved, const int plus, size_t *len); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _JK_URL_H */ tomcat-connectors-1.2.50-src/native/common/jk_uri_worker_map.h0000644000000000000020000001605714655113617022775 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: URI to worker mapper header file * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_URI_WORKER_MAP_H #define JK_URI_WORKER_MAP_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #include "jk_global.h" #include "jk_map.h" #include "jk_logger.h" #include "jk_mt.h" #define MATCH_TYPE_EXACT 0x0001 /* deprecated #define MATCH_TYPE_CONTEXT 0x0002 */ /* match all context path URIs with a path component suffix */ /* deprecated #define MATCH_TYPE_CONTEXT_PATH 0x0004 */ /* deprecated #define MATCH_TYPE_SUFFIX 0x0010 */ /* match all URIs of the form *ext */ /* deprecated #define MATCH_TYPE_GENERAL_SUFFIX 0x0020 */ /* match multiple wild characters (*) and (?) */ #define MATCH_TYPE_WILDCHAR_PATH 0x0040 #define MATCH_TYPE_NO_MATCH 0x1000 #define MATCH_TYPE_DISABLED 0x2000 /* deprecated #define MATCH_TYPE_STOPPED 0x4000 */ #define SOURCE_TYPE_WORKERDEF 0x0001 #define SOURCE_TYPE_JKMOUNT 0x0002 #define SOURCE_TYPE_URIMAP 0x0003 #define SOURCE_TYPE_DISCOVER 0x0004 #define SOURCE_TYPE_TEXT_WORKERDEF ("worker definition") #define SOURCE_TYPE_TEXT_JKMOUNT ("JkMount") #define SOURCE_TYPE_TEXT_URIMAP ("uriworkermap") #define SOURCE_TYPE_TEXT_DISCOVER ("ajp14") #define JK_MAX_URI_LEN 4095 struct rule_extension { /* reply_timeout overwrite */ int reply_timeout; /* Whether to ignore session routing info */ int sticky_ignore; /* Whether the request is stateless and should not * influence session load balancing */ int stateless; /* activation state overwrites for load balancers */ /* Number of elements in the array activations. */ int activation_size; /* Dynamically allocated array with one entry per lb member. */ int *activation; /* Temporary storage for the original extension strings. */ char *active; char *disabled; char *stopped; /* fail_on_status overwrites */ /* Number of elements in the array fail_on_status. */ int fail_on_status_size; /* Dynamically allocated array with one entry per status. */ int *fail_on_status; /* Temporary storage for the original extension strings. */ char *fail_on_status_str; /* Use server error pages for responses >= 400. */ int use_server_error_pages; /* session_cookie overwrite */ char *session_cookie; /* session_path overwrite */ char *session_path; int set_session_cookie; char *session_cookie_path; }; typedef struct rule_extension rule_extension_t; struct uri_worker_record { /* Original uri for logging */ char *uri; /* Name of worker mapped */ const char *worker_name; /* Base context */ const char *context; /* Match type */ unsigned int match_type; /* Definition source type */ unsigned int source_type; /* char length of the context */ size_t context_len; /* extended mapping properties */ rule_extension_t extensions; }; typedef struct uri_worker_record uri_worker_record_t; struct jk_uri_worker_map { /* Memory Pool */ jk_pool_t p; jk_pool_atom_t buf[BIG_POOL_SIZE]; /* Index 0 or 1, which map instance do we use */ /* Needed to make map reload more atomically */ int index; /* map Id. * Unique value which gets incremented each time we * call uri_worker_map_alloc */ int id; /* Memory Pool - cleared when doing reload */ /* Use this pool to allocate objects, that are deleted */ /* when the map gets dynamically reloaded from uriworkermap.properties. */ jk_pool_t p_dyn[2]; jk_pool_atom_t buf_dyn[2][BIG_POOL_SIZE]; /* map URI->WORKER */ uri_worker_record_t **maps[2]; /* Map Number */ unsigned int size[2]; /* Map Capacity */ unsigned int capacity[2]; /* NoMap Number */ unsigned int nosize[2]; /* Dynamic config support */ JK_CRIT_SEC cs; /* should we forward potentially unsafe URLs */ int reject_unsafe; /* uriworkermap filename */ const char *fname; /* uriworkermap reload check interval */ int reload; /* Last modified time */ time_t modified; /* Last checked time */ time_t checked; }; typedef struct jk_uri_worker_map jk_uri_worker_map_t; void extension_fix(jk_pool_t *p, const char *name, rule_extension_t *extensions, jk_log_context_t *log_ctx); void parse_rule_extensions(char *rule, rule_extension_t *extensions, jk_log_context_t *log_ctx); const char *uri_worker_map_get_source(uri_worker_record_t *uwr); char *uri_worker_map_get_match(uri_worker_record_t *uwr, char *buf); int uri_worker_map_alloc(jk_uri_worker_map_t **uw_map, jk_map_t *init_data, jk_log_context_t *log_ctx); int uri_worker_map_free(jk_uri_worker_map_t **uw_map, jk_log_context_t *log_ctx); int uri_worker_map_open(jk_uri_worker_map_t *uw_map, jk_map_t *init_data, jk_log_context_t *log_ctx); void uri_worker_map_switch(jk_uri_worker_map_t *uw_map, jk_log_context_t *log_ctx); void uri_worker_map_ext(jk_uri_worker_map_t *uw_map, jk_log_context_t *log_ctx); int uri_worker_map_add(jk_uri_worker_map_t *uw_map, const char *puri, const char *worker, unsigned int source_type, jk_log_context_t *log_ctx); const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, const char *uri, const char *vhost, rule_extension_t **extensions, int *index, jk_log_context_t *log_ctx); rule_extension_t *get_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, int index); int uri_worker_map_load(jk_uri_worker_map_t *uw_map, jk_log_context_t *log_ctx); int uri_worker_map_update(jk_uri_worker_map_t *uw_map, int force, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_URI_WORKER_MAP_H */ tomcat-connectors-1.2.50-src/native/common/jk_logger.h0000644000000000000020000001235014655113617021217 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Logger object definitions * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_LOGGER_H #define JK_LOGGER_H #include "jk_global.h" #ifdef __cplusplus extern "C" { #endif #define JK_TIME_MAX_SIZE (64) typedef struct jk_logger jk_logger_t; struct jk_logger { void *logger_private; int level; const char *log_fmt; /* the configured timestamp format for logging */ char log_fmt_subsec[JK_TIME_MAX_SIZE]; /* like log_fmt, but milli/micro seconds marker replaced, because strftime() doesn't handle those */ int log_fmt_type; /* do we want milli or microseconds */ size_t log_fmt_offset; /* at which position should we insert */ size_t log_fmt_size; /* how long is this format string */ int (JK_METHOD * log) (jk_logger_t *l, int level, int used, char *what); }; typedef struct jk_file_logger_t jk_file_logger_t; struct jk_file_logger_t { FILE *logfile; /* For Apache 2 APR piped logging */ void *jklogfp; /* For Apache 1.3 piped logging */ int log_fd; int is_piped; }; typedef struct jk_log_context_t jk_log_context_t; struct jk_log_context_t { jk_logger_t *logger; const char *id; }; /* Level like Java tracing, but available only at compile time on DEBUG preproc define. */ #define JK_LOG_TRACE_LEVEL 0 #define JK_LOG_DEBUG_LEVEL 1 #define JK_LOG_INFO_LEVEL 2 #define JK_LOG_WARNING_LEVEL 3 #define JK_LOG_ERROR_LEVEL 4 #define JK_LOG_EMERG_LEVEL 5 #define JK_LOG_REQUEST_LEVEL 6 #define JK_LOG_DEF_LEVEL JK_LOG_INFO_LEVEL #define JK_LOG_TRACE_VERB "trace" #define JK_LOG_DEBUG_VERB "debug" #define JK_LOG_INFO_VERB "info" #define JK_LOG_WARN_VERB "warn" #define JK_LOG_ERROR_VERB "error" #define JK_LOG_EMERG_VERB "emerg" #define JK_LOG_DEF_VERB JK_LOG_INFO_VERB #if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER > 1200)) #define JK_LOG_TRACE __FILE__,__LINE__,__FUNCTION__,JK_LOG_TRACE_LEVEL #define JK_LOG_DEBUG __FILE__,__LINE__,__FUNCTION__,JK_LOG_DEBUG_LEVEL #define JK_LOG_ERROR __FILE__,__LINE__,__FUNCTION__,JK_LOG_ERROR_LEVEL #define JK_LOG_EMERG __FILE__,__LINE__,__FUNCTION__,JK_LOG_EMERG_LEVEL #define JK_LOG_INFO __FILE__,__LINE__,__FUNCTION__,JK_LOG_INFO_LEVEL #define JK_LOG_WARNING __FILE__,__LINE__,__FUNCTION__,JK_LOG_WARNING_LEVEL #else #define JK_LOG_TRACE __FILE__,__LINE__,NULL,JK_LOG_TRACE_LEVEL #define JK_LOG_DEBUG __FILE__,__LINE__,NULL,JK_LOG_DEBUG_LEVEL #define JK_LOG_ERROR __FILE__,__LINE__,NULL,JK_LOG_ERROR_LEVEL #define JK_LOG_EMERG __FILE__,__LINE__,NULL,JK_LOG_EMERG_LEVEL #define JK_LOG_INFO __FILE__,__LINE__,NULL,JK_LOG_INFO_LEVEL #define JK_LOG_WARNING __FILE__,__LINE__,NULL,JK_LOG_WARNING_LEVEL #endif #define JK_LOG_REQUEST __FILE__,0,NULL,JK_LOG_REQUEST_LEVEL #if defined(JK_PRODUCTION) /* TODO: all DEBUG messages should be compiled out * when this define is in place. */ #define JK_IS_PRODUCTION 1 #define JK_TRACE_ENTER(l) #define JK_TRACE_EXIT(l) #else #define JK_IS_PRODUCTION 0 #define JK_TRACE_ENTER(l) \ do { \ if ((l) && (l)->logger && (l)->logger->level == JK_LOG_TRACE_LEVEL) { \ int tmp_errno = errno; \ jk_log((l), JK_LOG_TRACE, "enter"); \ errno = tmp_errno; \ } } while (0) #define JK_TRACE_EXIT(l) \ do { \ if ((l) && (l)->logger && (l)->logger->level == JK_LOG_TRACE_LEVEL) { \ int tmp_errno = errno; \ jk_log((l), JK_LOG_TRACE, "exit"); \ errno = tmp_errno; \ } } while (0) #endif /* JK_PRODUCTION */ #define JK_LOG_NULL_PARAMS(l) jk_log((l), JK_LOG_ERROR, "NULL parameters") /* Debug level macro * It is more efficient to check the level prior * calling function that will not execute anyhow because of level */ #define JK_IS_DEBUG_LEVEL(l) ((l) && (l)->logger && (l)->logger->level < JK_LOG_INFO_LEVEL) #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_LOGGER_H */ tomcat-connectors-1.2.50-src/native/common/jk_lb_worker.h0000644000000000000020000002221114655113617021723 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: load balance worker header file * * Author: Gal Shachor * * Author: Rainer Jung * ***************************************************************************/ #ifndef JK_LB_WORKER_H #define JK_LB_WORKER_H #include "jk_logger.h" #include "jk_service.h" #include "jk_mt.h" #include "jk_shm.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define JK_LB_WORKER_NAME ("lb") #define JK_LB_WORKER_TYPE (5) #define JK_LB_SUB_WORKER_TYPE (7) #define JK_LB_DEF_DOMAIN_NAME ("unknown") #define JK_LB_METHOD_REQUESTS (0) #define JK_LB_METHOD_TRAFFIC (1) #define JK_LB_METHOD_BUSYNESS (2) #define JK_LB_METHOD_SESSIONS (3) #define JK_LB_METHOD_NEXT (4) #define JK_LB_METHOD_DEF (JK_LB_METHOD_REQUESTS) #define JK_LB_METHOD_MAX (JK_LB_METHOD_NEXT) #define JK_LB_METHOD_TEXT_REQUESTS ("Request") #define JK_LB_METHOD_TEXT_TRAFFIC ("Traffic") #define JK_LB_METHOD_TEXT_BUSYNESS ("Busyness") #define JK_LB_METHOD_TEXT_SESSIONS ("Sessions") #define JK_LB_METHOD_TEXT_NEXT ("Next") #define JK_LB_METHOD_TEXT_DEF (JK_LB_METHOD_TEXT_REQUESTS) #define JK_LB_LOCK_OPTIMISTIC (0) #define JK_LB_LOCK_PESSIMISTIC (1) #define JK_LB_LOCK_DEF (JK_LB_LOCK_OPTIMISTIC) #define JK_LB_LOCK_MAX (JK_LB_LOCK_PESSIMISTIC) #define JK_LB_LOCK_TEXT_OPTIMISTIC ("Optimistic") #define JK_LB_LOCK_TEXT_PESSIMISTIC ("Pessimistic") #define JK_LB_LOCK_TEXT_DEF (JK_LB_LOCK_TEXT_OPTIMISTIC) /* * The following definitions for state and activation * need to be kept in sync with the two macros * JK_WORKER_USABLE() and JK_WORKER_USABLE_STICKY() in jk_lb_worker.c. * Since we use ordered comparisons there instead of multiple * equal/unequal compares, order of the values is critical here. */ #define JK_LB_STATE_IDLE (0) #define JK_LB_STATE_OK (1) #define JK_LB_STATE_RECOVER (2) #define JK_LB_STATE_FORCE (3) #define JK_LB_STATE_BUSY (4) #define JK_LB_STATE_ERROR (5) #define JK_LB_STATE_PROBE (6) #define JK_LB_STATE_DEF (JK_LB_STATE_IDLE) #define JK_LB_STATE_TEXT_IDLE ("OK/IDLE") #define JK_LB_STATE_TEXT_OK ("OK") #define JK_LB_STATE_TEXT_RECOVER ("ERR/REC") #define JK_LB_STATE_TEXT_FORCE ("ERR/FRC") #define JK_LB_STATE_TEXT_BUSY ("OK/BUSY") #define JK_LB_STATE_TEXT_ERROR ("ERR") #define JK_LB_STATE_TEXT_PROBE ("ERR/PRB") #define JK_LB_STATE_TEXT_MAX (JK_LB_STATE_PROBE) #define JK_LB_STATE_TEXT_DEF (JK_LB_STATE_TEXT_IDLE) /* All JK_LB_ACTIVATION_* values must be single digit. */ /* Otherwise the string encoding of the activation array */ /* fails e.g. in the isapi redirector. */ /* JK_LB_ACTIVATION_UNSET is not allowed as an actual worker state. */ /* It will not work e.g. when the status worker tries to show the state. */ /* It is only used in rule extension data to indicate, that the */ /* activation state should not be overwritten. */ #define JK_LB_ACTIVATION_ACTIVE (0) #define JK_LB_ACTIVATION_DISABLED (1) #define JK_LB_ACTIVATION_STOPPED (2) #define JK_LB_ACTIVATION_UNSET (9) #define JK_LB_ACTIVATION_DEF (JK_LB_ACTIVATION_ACTIVE) #define JK_LB_ACTIVATION_MAX (JK_LB_ACTIVATION_STOPPED) #define JK_LB_ACTIVATION_TEXT_ACTIVE ("ACT") #define JK_LB_ACTIVATION_TEXT_DISABLED ("DIS") #define JK_LB_ACTIVATION_TEXT_STOPPED ("STP") #define JK_LB_ACTIVATION_TEXT_DEF (JK_LB_ACTIVATION_TEXT_ACTIVE) #define JK_LB_UINT64_STR_SZ (21) #define JK_LB_NOTES_COUNT (10) #define JK_NOTE_LB_FIRST_NAME ("JK_LB_FIRST_NAME") #define JK_NOTE_LB_FIRST_VALUE ("JK_LB_FIRST_VALUE") #define JK_NOTE_LB_FIRST_ACCESSED ("JK_LB_FIRST_ACCESSED") #define JK_NOTE_LB_FIRST_SESSIONS ("JK_LB_FIRST_SESSIONS") #define JK_NOTE_LB_FIRST_READ ("JK_LB_FIRST_READ") #define JK_NOTE_LB_FIRST_TRANSFERRED ("JK_LB_FIRST_TRANSFERRED") #define JK_NOTE_LB_FIRST_ERRORS ("JK_LB_FIRST_ERRORS") #define JK_NOTE_LB_FIRST_BUSY ("JK_LB_FIRST_BUSY") #define JK_NOTE_LB_FIRST_ACTIVATION ("JK_LB_FIRST_ACTIVATION") #define JK_NOTE_LB_FIRST_STATE ("JK_LB_FIRST_STATE") #define JK_NOTE_LB_LAST_NAME ("JK_LB_LAST_NAME") #define JK_NOTE_LB_LAST_VALUE ("JK_LB_LAST_VALUE") #define JK_NOTE_LB_LAST_ACCESSED ("JK_LB_LAST_ACCESSED") #define JK_NOTE_LB_LAST_SESSIONS ("JK_LB_LAST_SESSIONS") #define JK_NOTE_LB_LAST_READ ("JK_LB_LAST_READ") #define JK_NOTE_LB_LAST_TRANSFERRED ("JK_LB_LAST_TRANSFERRED") #define JK_NOTE_LB_LAST_ERRORS ("JK_LB_LAST_ERRORS") #define JK_NOTE_LB_LAST_BUSY ("JK_LB_LAST_BUSY") #define JK_NOTE_LB_LAST_ACTIVATION ("JK_LB_LAST_ACTIVATION") #define JK_NOTE_LB_LAST_STATE ("JK_LB_LAST_STATE") /* Time to wait before retry. */ #define WAIT_BEFORE_RECOVER (60) /* We divide load values by 2^x during global maintenance. */ /* The exponent x is JK_LB_DECAY_MULT*#MAINT_INTV_SINCE_LAST_MAINT */ #define JK_LB_DECAY_MULT (1) struct lb_sub_worker { jk_worker_t *worker; /* Shared memory worker data */ jk_shm_lb_sub_worker_t *s; shm_str name; /* Sequence counter starting at 0 and increasing * every time we change the config */ volatile unsigned int sequence; /* route */ shm_str route; /* worker domain */ shm_str domain; /* worker redirect route */ shm_str redirect; /* worker distance */ int distance; /* current activation state (config) of the worker */ int activation; /* Current lb factor */ int lb_factor; /* Current worker index */ int i; /* Current lb reciprocal factor */ jk_uint64_t lb_mult; }; typedef struct lb_sub_worker lb_sub_worker_t; struct lb_worker { jk_worker_t worker; /* Shared memory worker data */ jk_shm_lb_worker_t *s; shm_str name; /* Sequence counter starting at 0 and increasing * every time we change the config */ volatile unsigned int sequence; jk_pool_t p; jk_pool_atom_t buf[TINY_POOL_SIZE]; JK_CRIT_SEC cs; lb_sub_worker_t *lb_workers; unsigned int num_of_workers; int sticky_session; int sticky_session_force; int recover_wait_time; int error_escalation_time; int max_reply_timeouts; int retries; int lb_retries; int retry_interval; int lbmethod; int lblock; int maintain_time; unsigned int max_packet_size; unsigned int next_offset; /* Session cookie */ shm_str session_cookie; /* Session path */ shm_str session_path; int set_session_cookie; shm_str session_cookie_path; }; typedef struct lb_worker lb_worker_t; int JK_METHOD lb_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *log_ctx); const char *jk_lb_get_lock_direct(int lblock, jk_log_context_t *log_ctx); const char *jk_lb_get_lock(lb_worker_t *p, jk_log_context_t *log_ctx); int jk_lb_get_lock_code(const char *v); const char *jk_lb_get_method_direct(int lbmethod, jk_log_context_t *log_ctx); const char *jk_lb_get_method(lb_worker_t *p, jk_log_context_t *log_ctx); int jk_lb_get_method_code(const char *v); const char *jk_lb_get_state_direct(int state, jk_log_context_t *log_ctx); const char *jk_lb_get_state(lb_sub_worker_t *p, jk_log_context_t *log_ctx); int jk_lb_get_state_code(const char *v); const char *jk_lb_get_activation_direct(int activation, jk_log_context_t *log_ctx); const char *jk_lb_get_activation(lb_sub_worker_t *p, jk_log_context_t *log_ctx); int jk_lb_get_activation_code(const char *v); void reset_lb_values(lb_worker_t *p, jk_log_context_t *log_ctx); void jk_lb_pull(lb_worker_t * p, int locked, jk_log_context_t *log_ctx); void jk_lb_push(lb_worker_t * p, int locked, int push_all_members, jk_log_context_t *log_ctx); void update_mult(lb_worker_t * p, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_LB_WORKER_H */ tomcat-connectors-1.2.50-src/native/common/jk_url.c0000644000000000000020000002302414655113617020535 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: URL manipulation subroutines. (ported from mod_proxy). * * Version: $Revision: 531816 $ * ***************************************************************************/ #include "jk_global.h" #include "jk_url.h" static void jk_c2hex(int ch, char *x) { #if !CHARSET_EBCDIC int i; x[0] = '%'; i = (ch & 0xF0) >> 4; if (i >= 10) { x[1] = ('A' - 10) + i; } else { x[1] = '0' + i; } i = ch & 0x0F; if (i >= 10) { x[2] = ('A' - 10) + i; } else { x[2] = '0' + i; } #else /*CHARSET_EBCDIC*/ static const char ntoa[] = { "0123456789ABCDEF" }; char buf[1]; ch &= 0xFF; buf[0] = ch; jk_xlate_to_ascii(buf, 1); x[0] = '%'; x[1] = ntoa[(buf[0] >> 4) & 0x0F]; x[2] = ntoa[buf[0] & 0x0F]; x[3] = '\0'; #endif /*CHARSET_EBCDIC*/ } /* * Convert a URL-encoded string to canonical form. * It encodes those which must be encoded, and does not touch * those which must not be touched. * String x must be '\0'-terminated. * String y must be pre-allocated with len maxlen * (including the terminating '\0'). */ int jk_canonenc(const char *x, char *y, int maxlen) { int i, j; int ch = x[0]; char *allowed; /* characters which should not be encoded */ char *reserved; /* characters which much not be en/de-coded */ /* * N.B. in addition to :@&=, this allows ';' in an http path * and '?' in an ftp path -- this may be revised */ allowed = "~$-_.+!*'(),;:@&="; reserved = "/"; for (i = 0, j = 0; ch != '\0' && j < maxlen; i++, j++, ch=x[i]) { /* always handle '/' first */ if (strchr(reserved, ch)) { y[j] = ch; continue; } /* recode it, if necessary */ if (!jk_isalnum(ch) && !strchr(allowed, ch)) { if (j+2= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); digit *= 16; digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); #else /*USE_CHARSET_EBCDIC*/ char xstr[5]; xstr[0]='0'; xstr[1]='x'; xstr[2]=what[0]; xstr[3]=what[1]; xstr[4]='\0'; digit = convert_a2e[0xFF & strtol(xstr, NULL, 16)]; #endif /*USE_CHARSET_EBCDIC*/ return (digit); } #define jk_isxdigit(c) (isxdigit(((unsigned char)(c)))) /** * Unescapes a URL, leaving reserved characters intact. * @param unescaped Optional buffer to write the encoded string, can be * NULL, in which case the URL decoding does not actually take place * but the result length of the decoded URL will be returned. * @param url String to be unescaped * @param slen The length of the original url, or -1 to decode until * a terminating '\0' is seen * @param forbid Optional list of forbidden characters, in addition to * 0x00 * @param reserved Optional list of reserved characters that will be * left unescaped * @param plus If non zero, '+' is converted to ' ' as per * application/x-www-form-urlencoded encoding * @param len If set, the length of the unescaped string will be returned * @return JK_TRUE on success, JK_FALSE if the string is NULL, * if a bad escape sequence is found, or if a character on the * forbid list is found. * Implementation copied from APR 1.5.x. */ int jk_unescape_url(char *const unescaped, const char *const url, size_t slen, const char *const forbid, const char *const reserved, const int plus, size_t *len) { size_t size = 1; int found = 0; const char *s = (const char *) url; char *d = (char *) unescaped; register int badesc, badpath; if (!url) { return JK_FALSE; } badesc = 0; badpath = 0; if (s) { if (d) { for (; *s && slen; ++s, d++, slen--) { if (plus && *s == '+') { *d = ' '; found = 1; } else if (*s != '%') { *d = *s; } else { if (!jk_isxdigit(*(s + 1)) || !jk_isxdigit(*(s + 2))) { badesc = 1; *d = '%'; } else { char decoded; decoded = x2c(s + 1); if ((decoded == '\0') || (forbid && strchr(forbid, decoded))) { badpath = 1; *d = decoded; s += 2; slen -= 2; } else if (reserved && strchr(reserved, decoded)) { *d++ = *s++; *d++ = *s++; *d = *s; size += 2; } else { *d = decoded; s += 2; slen -= 2; found = 1; } } } size++; } *d = '\0'; } else { for (; *s && slen; ++s, slen--) { if (plus && *s == '+') { found = 1; } else if (*s != '%') { /* character unchanged */ } else { if (!jk_isxdigit(*(s + 1)) || !jk_isxdigit(*(s + 2))) { badesc = 1; } else { char decoded; decoded = x2c(s + 1); if ((decoded == '\0') || (forbid && strchr(forbid, decoded))) { badpath = 1; s += 2; slen -= 2; } else if (reserved && strchr(reserved, decoded)) { s += 2; slen -= 2; size += 2; } else { s += 2; slen -= 2; found = 1; } } } size++; } } } if (len) { *len = size; } if (badesc) { return JK_FALSE; } else if (badpath) { return JK_FALSE; } else if (!found) { return JK_TRUE; } return JK_TRUE; } tomcat-connectors-1.2.50-src/native/common/jk_shm.h0000644000000000000020000001764014655113617020536 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Shared Memory object header file * * Author: Mladen Turk * * Author: Rainer Jung * ***************************************************************************/ #ifndef _JK_SHM_H #define _JK_SHM_H #include "jk_global.h" #include "jk_pool.h" #include "jk_util.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * @file jk_shm.h * @brief Jk shared memory management * * */ #define JK_SHM_MAJOR '1' #define JK_SHM_MINOR '3' #define JK_SHM_STR_SIZ (JK_ALIGN(JK_MAX_NAME_LEN + 1, 8)) #define JK_SHM_MAGIC '!', 'J', 'K', 'S', 'H', 'M', JK_SHM_MAJOR, JK_SHM_MINOR #define JK_SHM_MAGIC_SIZ 8 /* XXX: Check if adding struct members for overflow */ #define JK_SHM_SLOT_SIZE 384 /* Really huge numbers, but 64 workers should be enough */ #define JK_SHM_DEF_WORKERS 64 #define JK_SHM_ALIGNMENT JK_SHM_SLOT_SIZE #define JK_SHM_ALIGN(x) JK_ALIGN((x), JK_SHM_ALIGNMENT) #define JK_SHM_MIN_SIZE ((JK_SHM_SLOT_SIZE * JK_SHM_DEF_WORKERS * 3) + \ JK_SHM_ALIGNMENT) typedef char shm_str[JK_SHM_STR_SIZ]; /** jk shm generic worker record structure */ struct jk_shm_worker_header { /* Shared memory slot id */ int id; /* JK_XXX_WORKER_TYPE */ int type; /* worker name */ shm_str name; /* parent slot id. * Zero in case worker does not belong to balancer. */ int parent_id; /* Sequence counter starting at 0 and increasing * every time we change the config. */ volatile unsigned int sequence; }; typedef struct jk_shm_worker_header jk_shm_worker_header_t; /** jk shm ajp13/ajp14 worker record structure */ struct jk_shm_ajp_worker { jk_shm_worker_header_t h; shm_str host; int port; volatile int addr_sequence; /* Configuration data mirrored from ajp_worker */ int cache_timeout; int connect_timeout; int ping_timeout; int reply_timeout; int prepost_timeout; unsigned int recovery_opts; int retries; int retry_interval; int busy_limit; unsigned int max_packet_size; /* current error state (runtime) of the worker */ volatile int state; /* Statistical data */ /* Number of currently connected channels */ volatile int connected; /* Maximum number of connected channels */ volatile int max_connected; /* Number of currently busy channels */ volatile int busy; /* Maximum number of busy channels */ volatile int max_busy; volatile time_t error_time; /* Number of bytes read from remote */ volatile jk_uint64_t readed; /* Number of bytes transferred to remote */ volatile jk_uint64_t transferred; /* Number of times the worker was used */ volatile jk_uint64_t used; /* Number of times the worker was used - snapshot during maintenance */ volatile jk_uint64_t used_snapshot; /* Number of non 200 responses */ volatile jk_uint32_t errors; /* Decayed number of reply_timeout errors */ volatile jk_uint32_t reply_timeouts; /* Number of client errors */ volatile jk_uint32_t client_errors; /* Last reset time */ volatile time_t last_reset; volatile time_t last_maintain_time; }; typedef struct jk_shm_ajp_worker jk_shm_ajp_worker_t; /** jk shm lb sub worker record structure */ struct jk_shm_lb_sub_worker { jk_shm_worker_header_t h; /* route */ shm_str route; /* worker domain */ shm_str domain; /* worker redirect route */ shm_str redirect; /* worker distance */ volatile int distance; /* current activation state (config) of the worker */ volatile int activation; /* current error state (runtime) of the worker */ volatile int state; /* Current lb factor */ volatile int lb_factor; /* Current lb reciprocal factor */ volatile jk_uint64_t lb_mult; /* Current lb value */ volatile jk_uint64_t lb_value; /* First consecutive error time */ volatile time_t first_error_time; /* Last consecutive error time */ volatile time_t last_error_time; /* Number of times the worker was elected - snapshot during maintenance */ volatile jk_uint64_t elected_snapshot; /* Number of non-sticky requests handled, that were not marked as stateless */ volatile jk_uint64_t sessions; /* Number of non 200 responses */ volatile jk_uint32_t errors; }; typedef struct jk_shm_lb_sub_worker jk_shm_lb_sub_worker_t; /** jk shm lb worker record structure */ struct jk_shm_lb_worker { jk_shm_worker_header_t h; /* Number of currently busy channels */ volatile int busy; /* Maximum number of busy channels */ volatile int max_busy; int sticky_session; int sticky_session_force; int recover_wait_time; int error_escalation_time; int max_reply_timeouts; int retries; int retry_interval; int lbmethod; int lblock; unsigned int max_packet_size; /* Last reset time */ volatile time_t last_reset; volatile time_t last_maintain_time; }; typedef struct jk_shm_lb_worker jk_shm_lb_worker_t; int jk_shm_str_init(shm_str dst, const char *src, const char *name, jk_log_context_t *l); int jk_shm_str_init_ne(shm_str dst, const char *src, const char *name, jk_log_context_t *l); void jk_shm_str_copy(shm_str dst, shm_str src, jk_log_context_t *l); const char *jk_shm_name(void); /* Calculate needed shm size */ int jk_shm_calculate_size(jk_map_t *init_data, jk_log_context_t *log_ctx); /* Open the shared memory creating file if needed */ int jk_shm_open(const char *fname, int sz, jk_log_context_t *log_ctx); /* Close the shared memory */ void jk_shm_close(jk_log_context_t *log_ctx); /* Attach the shared memory in child process. * File has to be opened in parent. */ int jk_shm_attach(const char *fname, int sz, jk_log_context_t *log_ctx); /* allocate shm ajp worker record * If there is no shm present the pool will be used instead */ jk_shm_ajp_worker_t *jk_shm_alloc_ajp_worker(jk_pool_t *p, const char *name, jk_log_context_t *log_ctx); /* allocate shm lb sub worker record * If there is no shm present the pool will be used instead */ jk_shm_lb_sub_worker_t *jk_shm_alloc_lb_sub_worker(jk_pool_t *p, int lb_id, const char *name, jk_log_context_t *log_ctx); /* allocate shm lb worker record * If there is no shm present the pool will be used instead */ jk_shm_lb_worker_t *jk_shm_alloc_lb_worker(jk_pool_t *p, const char *name, jk_log_context_t *log_ctx); int jk_shm_check_maintain(time_t trigger); /* Lock shared memory for thread safe access */ int jk_shm_lock(void); /* Unlock shared memory for thread safe access */ int jk_shm_unlock(void); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _JK_SHM_H */ tomcat-connectors-1.2.50-src/native/common/jk_ajp13.h0000644000000000000020000000732514655113617020664 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Experimental bi-directionl protocol handler. * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_AJP13_H #define JK_AJP13_H #include "jk_ajp_common.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define AJP13_PROTO 13 #define AJP13_WS_HEADER 0x1234 #define AJP13_SW_HEADER 0x4142 /* 'AB' */ #define AJP13_DEF_HOST ("localhost") #define AJP13_DEF_PORT (8009) #define AJP13_DEF_PACKET_SIZE (8*1024) #define AJP13_MAX_PACKET_SIZE (64*1024) #define AJP13_PACKET_SIZE_ALIGN (1024) #define AJP13_DEF_CACHE_SZ (1) #define JK_INTERNAL_ERROR (-2) #define JK_FATAL_ERROR (-3) #define JK_CLIENT_ERROR (-4) #define JK_SERVER_ERROR (-5) #define JK_CLIENT_RD_ERROR (-6) #define JK_CLIENT_WR_ERROR (-7) #define JK_STATUS_ERROR (-8) #define JK_STATUS_FATAL_ERROR (-9) #define JK_REPLY_TIMEOUT (-10) #define JK_AJP_PROTOCOL_ERROR (-11) #define JK_BUSY_ERROR (-12) #define AJP13_DEF_TIMEOUT (0) /* Idle timout for pooled connections */ /* * Message does not have a response (for example, JK_AJP13_END_RESPONSE) */ #define JK_AJP13_ERROR -1 /* * Message does not have a response (for example, JK_AJP13_END_RESPONSE) */ #define JK_AJP13_NO_RESPONSE 0 /* * Message have a response. */ #define JK_AJP13_HAS_RESPONSE 1 /* * Forward a request from the web server to the servlet container. */ #define JK_AJP13_FORWARD_REQUEST (unsigned char)2 /* * Write a body chunk from the servlet container to the web server */ #define JK_AJP13_SEND_BODY_CHUNK (unsigned char)3 /* * Send response headers from the servlet container to the web server. */ #define JK_AJP13_SEND_HEADERS (unsigned char)4 /* * Marks the end of response. */ #define JK_AJP13_END_RESPONSE (unsigned char)5 /* * Marks the end of response. */ #define JK_AJP13_GET_BODY_CHUNK (unsigned char)6 /* * Asks the container to shutdown */ #define JK_AJP13_SHUTDOWN (unsigned char)7 /* * Told container to take control (secure login phase) */ #define AJP13_PING_REQUEST (unsigned char)8 /* * Check if the container is alive */ #define AJP13_CPING_REQUEST (unsigned char)10 /* * Reply from the container to alive request */ #define AJP13_CPONG_REPLY (unsigned char)9 /* * Functions */ int ajp13_marshal_shutdown_into_msgb(jk_msg_buf_t *msg, jk_pool_t *p, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_AJP13_H */ tomcat-connectors-1.2.50-src/native/common/jk_ajp13.c0000644000000000000020000000341314655113617020651 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Experimental bi-directionl protocol handler. * * Author: Gal Shachor * * Author: Henri Gomez * ***************************************************************************/ #include "jk_global.h" #include "jk_util.h" #include "jk_ajp_common.h" #include "jk_ajp13.h" int ajp13_marshal_shutdown_into_msgb(jk_msg_buf_t *msg, jk_pool_t *p, jk_log_context_t *l) { JK_TRACE_ENTER(l); /* To be on the safe side */ jk_b_reset(msg); /* * Just a single byte with s/d command. */ if (jk_b_append_byte(msg, JK_AJP13_SHUTDOWN)) { jk_log(l, JK_LOG_ERROR, "failed appending shutdown message"); JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } tomcat-connectors-1.2.50-src/native/common/jk_ajp14_worker.h0000644000000000000020000000342014655113617022246 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: ajpv14 worker header file * * Author: Henri Gomez * ***************************************************************************/ #ifndef JK_AJP14_WORKER_H #define JK_AJP14_WORKER_H #include "jk_pool.h" #include "jk_connect.h" #include "jk_util.h" #include "jk_msg_buff.h" #include "jk_ajp13.h" #include "jk_ajp14.h" #include "jk_logger.h" #include "jk_service.h" #include "jk_ajp13_worker.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define JK_AJP14_WORKER_NAME ("ajp14") #define JK_AJP14_WORKER_TYPE (3) int JK_METHOD ajp14_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_AJP14_WORKER_H */ tomcat-connectors-1.2.50-src/native/common/config.h.in0000644000000000000020000000655114655113623021131 0ustar rootbin/* common/config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have IPv6 support */ #undef HAVE_AF_INET6 /* Define to 1 if the compiler provides atomic builtins */ #undef HAVE_ATOMIC_BUILTINS /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Have flock() */ #undef HAVE_FLOCK /* Have getaddrinfo() */ #undef HAVE_GETADDRINFO /* Have gethostbyname_r() */ #undef HAVE_GETHOSTBYNAME_R /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Have poll() */ #undef HAVE_POLL /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H /* Have snprintf() */ #undef HAVE_SNPRINTF /* Define to 1 if you have struct sockaddr_storage */ #undef HAVE_SOCKADDR_STORAGE /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILIO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Have vsnprintf() */ #undef HAVE_VSNPRINTF /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* The size of `char', as computed by sizeof. */ #undef SIZEOF_CHAR /* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT /* The size of `long', as computed by sizeof. */ #undef SIZEOF_LONG /* The size of `longlong', as computed by sizeof. */ #undef SIZEOF_LONGLONG /* The size of `long double', as computed by sizeof. */ #undef SIZEOF_LONG_DOUBLE /* The size of `long long', as computed by sizeof. */ #undef SIZEOF_LONG_LONG /* The size of pid_t */ #undef SIZEOF_PID_T /* The size of pthread_t */ #undef SIZEOF_PTHREAD_T /* The size of `short', as computed by sizeof. */ #undef SIZEOF_SHORT /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Define to use SOCK_CLOEXEC with socket() */ #undef USE_SOCK_CLOEXEC /* Define to use SO_RCVTIMEO with setsockopt() */ #undef USE_SO_RCVTIMEO /* Define to use SO_SNDTIMEO with setsockopt() */ #undef USE_SO_SNDTIMEO /* Version number of package */ #undef VERSION tomcat-connectors-1.2.50-src/native/common/jk_ajp13_worker.c0000644000000000000020000000555214655113617022250 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Bi-directional protocol. * * Author: Costin * * Author: Gal Shachor * * Author: Henri Gomez * ***************************************************************************/ #include "jk_ajp13_worker.h" /* -------------------- Method -------------------- */ static int JK_METHOD validate(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { int rc; JK_TRACE_ENTER(l); rc = ajp_validate(pThis, props, we, l, AJP13_PROTO); JK_TRACE_EXIT(l); return rc; } static int JK_METHOD init(jk_worker_t *pThis, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *l) { int rc; JK_TRACE_ENTER(l); rc = ajp_init(pThis, props, we, l, AJP13_PROTO); JK_TRACE_EXIT(l); return rc; } static int JK_METHOD destroy(jk_worker_t **pThis, jk_log_context_t *l) { int rc; JK_TRACE_ENTER(l); rc = ajp_destroy(pThis, l, AJP13_PROTO); JK_TRACE_EXIT(l); return rc; } static int JK_METHOD get_endpoint(jk_worker_t *pThis, jk_endpoint_t **pend, jk_log_context_t *l) { int rc; JK_TRACE_ENTER(l); rc = ajp_get_endpoint(pThis, pend, l, AJP13_PROTO); JK_TRACE_EXIT(l); return rc; } int JK_METHOD ajp13_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *l) { ajp_worker_t *aw; JK_TRACE_ENTER(l); if (ajp_worker_factory(w, name, l) == JK_FALSE) return 0; aw = (*w)->worker_private; aw->proto = AJP13_PROTO; aw->worker.validate = validate; aw->worker.init = init; aw->worker.get_endpoint = get_endpoint; aw->worker.destroy = destroy; JK_TRACE_EXIT(l); return JK_AJP13_WORKER_TYPE; } tomcat-connectors-1.2.50-src/native/common/jk_ajp13_worker.h0000644000000000000020000000334014655113617022246 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: ajpv1.3 worker header file * * Author: Gal Shachor * ***************************************************************************/ #ifndef JK_AJP13_WORKER_H #define JK_AJP13_WORKER_H #include "jk_pool.h" #include "jk_connect.h" #include "jk_util.h" #include "jk_msg_buff.h" #include "jk_ajp_common.h" #include "jk_ajp13.h" #include "jk_logger.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define JK_AJP13_WORKER_NAME ("ajp13") #define JK_AJP13_WORKER_TYPE (2) int JK_METHOD ajp13_worker_factory(jk_worker_t **w, const char *name, jk_log_context_t *log_ctx); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_AJP13_WORKER_H */ tomcat-connectors-1.2.50-src/native/common/jk_worker.c0000644000000000000020000002673014655113617021253 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Workers controller * * Author: Gal Shachor * * Author: Henri Gomez * ***************************************************************************/ #define _PLACE_WORKER_LIST_HERE #include "jk_worker_list.h" #include "jk_worker.h" #include "jk_shm.h" #include "jk_util.h" #include "jk_mt.h" #define JK_WORKER_SHUTDOWN_WAIT 100 #define JK_WORKER_SHUTDOWN_COUNT 10 static void close_workers(jk_log_context_t *l); static worker_factory get_factory_for(const char *type); static int build_worker_map(jk_map_t *init_data, char **worker_list, unsigned num_of_workers, jk_worker_env_t *we, jk_log_context_t *l); /* Global worker list */ static jk_map_t *worker_map; static int running_maintain = 0; #if _MT_CODE static JK_CRIT_SEC worker_lock; #endif static int worker_maintain_time = 0; int wc_open(jk_map_t *init_data, jk_worker_env_t *we, jk_log_context_t *l) { int rc; JK_TRACE_ENTER(l); if (!jk_map_alloc(&worker_map)) { JK_TRACE_EXIT(l); return JK_FALSE; } JK_INIT_CS(&worker_lock, rc); if (rc == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "creating thread lock (errno=%d)", errno); JK_TRACE_EXIT(l); return JK_FALSE; } jk_map_dump(init_data, l); we->init_data = init_data; if (!jk_get_worker_list(init_data, &(we->worker_list), &we->num_of_workers)) { JK_TRACE_EXIT(l); we->num_of_workers = 0; we->worker_list = NULL; return JK_FALSE; } worker_maintain_time = jk_get_worker_maintain_time(init_data); if(worker_maintain_time < 0) worker_maintain_time = 0; if (!build_worker_map(init_data, we->worker_list, we->num_of_workers, we, l)) { close_workers(l); we->num_of_workers = 0; we->worker_list = NULL; JK_TRACE_EXIT(l); return JK_FALSE; } JK_TRACE_EXIT(l); return JK_TRUE; } void wc_close(jk_log_context_t *l) { JK_TRACE_ENTER(l); JK_DELETE_CS(&worker_lock); close_workers(l); JK_TRACE_EXIT(l); } jk_worker_t *wc_get_worker_for_name(const char *name, jk_log_context_t *l) { jk_worker_t *rc; JK_TRACE_ENTER(l); if (!name) { JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return NULL; } rc = jk_map_get(worker_map, name, NULL); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "%s a worker %s", rc ? "found" : "did not find", name); JK_TRACE_EXIT(l); return rc; } int wc_create_worker(const char *name, int use_map, jk_map_t *init_data, jk_worker_t **rc, jk_worker_env_t *we, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (rc) { const char *type = jk_get_worker_type(init_data, name); worker_factory fac = get_factory_for(type); jk_worker_t *w = NULL; unsigned int i, num_of_maps; char **map_names; int wtype; *rc = NULL; if (!fac) { jk_log(l, JK_LOG_ERROR, "Unknown worker type %s for worker %s", type, name); JK_TRACE_EXIT(l); return JK_FALSE; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "about to create instance %s of %s", name, type); if (((wtype = fac(&w, name, l)) == 0) || !w) { jk_log(l, JK_LOG_ERROR, "factory for %s failed for %s", type, name); JK_TRACE_EXIT(l); return JK_FALSE; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "about to validate and init %s", name); if (!w->validate(w, init_data, we, l)) { w->destroy(&w, l); jk_log(l, JK_LOG_ERROR, "validate failed for %s", name); JK_TRACE_EXIT(l); return JK_FALSE; } if (!w->init(w, init_data, we, l)) { w->destroy(&w, l); jk_log(l, JK_LOG_ERROR, "init failed for %s", name); JK_TRACE_EXIT(l); return JK_FALSE; } if (use_map && jk_get_worker_mount_list(init_data, name, &map_names, &num_of_maps) && num_of_maps) { for (i = 0; i < num_of_maps; i++) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "mounting %s to worker %s", map_names[i], name); if (uri_worker_map_add(we->uri_to_worker, map_names[i], name, SOURCE_TYPE_WORKERDEF, l) == JK_FALSE) { w->destroy(&w, l); jk_log(l, JK_LOG_ERROR, "mounting %s failed for %s", map_names[i], name); JK_TRACE_EXIT(l); return JK_FALSE; } } } w->type = wtype; *rc = w; JK_TRACE_EXIT(l); return JK_TRUE; } JK_LOG_NULL_PARAMS(l); return JK_FALSE; } static void close_workers(jk_log_context_t *l) { int sz = jk_map_size(worker_map); JK_TRACE_ENTER(l); if (sz > 0) { int i; for (i = 0; i < sz; i++) { jk_worker_t *w = jk_map_value_at(worker_map, i); if (w) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "close_workers will destroy worker %s", jk_map_name_at(worker_map, i)); w->destroy(&w, l); } } } jk_map_free(&worker_map); JK_TRACE_EXIT(l); } static int build_worker_map(jk_map_t *init_data, char **worker_list, unsigned num_of_workers, jk_worker_env_t *we, jk_log_context_t *l) { unsigned i; JK_TRACE_ENTER(l); for (i = 0; i < num_of_workers; i++) { jk_worker_t *w = NULL; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "creating worker %s", worker_list[i]); if (wc_create_worker(worker_list[i], 1, init_data, &w, we, l)) { jk_worker_t *oldw = NULL; if (!jk_map_put(worker_map, worker_list[i], w, (void *)&oldw)) { jk_log(l, JK_LOG_ERROR, "failed to add worker %s to worker map", worker_list[i]); w->destroy(&w, l); JK_TRACE_EXIT(l); return JK_FALSE; } if (oldw) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "removing old %s worker", worker_list[i]); oldw->destroy(&oldw, l); } } else { jk_log(l, JK_LOG_ERROR, "failed to create worker %s", worker_list[i]); JK_TRACE_EXIT(l); return JK_FALSE; } } JK_TRACE_EXIT(l); return JK_TRUE; } static worker_factory get_factory_for(const char *type) { worker_factory_record_t *factory = &worker_factories[0]; while (factory->name) { if (0 == strcmp(factory->name, type)) { return factory->fac; } factory++; } return NULL; } const char *wc_get_name_for_type(int type, jk_log_context_t *l) { worker_factory_record_t *factory = &worker_factories[0]; while (factory->name) { if (type == factory->type) { jk_log(l, JK_LOG_DEBUG, "Found worker type '%s'", factory->name); return factory->name; } factory++; } return NULL; } void wc_maintain(jk_log_context_t *l) { static time_t last_maintain = 0; int needs_global_maintenance; int sz = jk_map_size(worker_map); JK_TRACE_ENTER(l); /* Only proceed if all of the below hold true: * - there are workers * - maintenance wasn't disabled by configuration * - time since last maintenance is big enough */ if (sz > 0 && worker_maintain_time > 0 && difftime(time(NULL), last_maintain) >= worker_maintain_time && !running_maintain) { int i; JK_ENTER_CS(&worker_lock); if (running_maintain || difftime(time(NULL), last_maintain) < worker_maintain_time) { /* Already in maintain */ JK_LEAVE_CS(&worker_lock); JK_TRACE_EXIT(l); return; } /* Set the maintain run flag so other threads skip * the maintain until we are finished. */ running_maintain = 1; last_maintain = time(NULL); JK_LEAVE_CS(&worker_lock); needs_global_maintenance = jk_shm_check_maintain(last_maintain - worker_maintain_time); for (i = 0; i < sz; i++) { jk_worker_t *w = jk_map_value_at(worker_map, i); if (w && w->maintain) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Maintaining worker %s", jk_map_name_at(worker_map, i)); w->maintain(w, time(NULL), needs_global_maintenance, l); } } JK_ENTER_CS(&worker_lock); running_maintain = 0; JK_LEAVE_CS(&worker_lock); } JK_TRACE_EXIT(l); } void wc_shutdown(jk_log_context_t *l) { int sz = jk_map_size(worker_map); JK_TRACE_ENTER(l); if (sz > 0) { int i; i = JK_WORKER_SHUTDOWN_COUNT; while (running_maintain && i > 0) { jk_sleep(JK_WORKER_SHUTDOWN_WAIT); i--; } if (running_maintain) jk_log(l, JK_LOG_WARNING, "Worker maintain still running while shutting down worker %s", jk_map_name_at(worker_map, i)); running_maintain = 1; for (i = 0; i < sz; i++) { jk_worker_t *w = jk_map_value_at(worker_map, i); if (w && w->shutdown) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Shutting down worker %s", jk_map_name_at(worker_map, i)); w->shutdown(w, l); } } } JK_TRACE_EXIT(l); } tomcat-connectors-1.2.50-src/native/common/jk_service.h0000644000000000000020000005034114655113617021402 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Definitions of the objects used during the service step. * * These are the web server (ws) the worker and the connection* * JVM connection point * * Author: Gal Shachor * * Author: Dan Milstein * * Author: Henri Gomez * ***************************************************************************/ #ifndef JK_SERVICE_H #define JK_SERVICE_H #include "jk_global.h" #include "jk_logger.h" #include "jk_pool.h" #include "jk_map.h" #include "jk_uri_worker_map.h" #include "jk_msg_buff.h" #define JK_RETRIES 2 #define JK_LB_RETRIES 2 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * Env Information to be provided to worker at init time * With AJP14 support we need to have access to many informations * about web-server, uri to worker map.... */ struct jk_worker_env { /* The original configuration map */ jk_map_t *init_data; /* The URI to WORKER map, will be feeded by AJP14 autoconf feature */ jk_uri_worker_map_t *uri_to_worker; unsigned int num_of_workers; char **worker_list; /* Web-Server we're running on (Apache/IIS/NES) */ char *server_name; /* Virtual server handled - "*" is all virtual */ char *virtual; /* Optional APR pool used for configuration */ void *pool; }; typedef struct jk_worker_env jk_worker_env_t; struct jk_ws_service; struct jk_endpoint; struct jk_worker; typedef struct jk_ws_service jk_ws_service_t; typedef struct jk_endpoint jk_endpoint_t; typedef struct jk_worker jk_worker_t; struct svc_extension { /* reply_timeout overwrite */ int reply_timeout; /* Whether to ignore session routing info */ int sticky_ignore; /* Whether the request is stateless and should not * influence session load balancing */ int stateless; /* activation state overwrites for load balancers */ /* Dynamically allocated array with one entry per lb member. */ int *activation; /* fail_on_status overwrites */ /* Number of elements in the array fail_on_status. */ int fail_on_status_size; /* Dynamically allocated array with one entry per status. */ int *fail_on_status; /* Use server error pages for responses >= 400. */ int use_server_error_pages; /* session_cookie overwrite */ char *session_cookie; /* session_path overwrite */ char *session_path; /* Whether mod_jk should set the session cookie itself */ int set_session_cookie; /* An optional PATH to add the the set session cookie */ char *session_cookie_path; }; typedef struct svc_extension svc_extension_t; /* * The web server service 'class'. An instance of this class is created * for each request which is forwarded from the web server to the servlet * container. Contains the basic information about the request * (e.g. protocol, req_uri, etc), and also contains a series of methods * which provide access to core web server functionality (start_response, * read, write). * * As with all the core jk classes, this is essentially an abstract base * class which is implemented/extended by classes which are specific to a * particular web server. By using an abstract base class in this manner, * workers can be written for different protocols (e.g. ajp12, ajp13, ajp14) * without the workers having to worry about which web server they are * talking to. * * This particular OO-in-C system uses a 'ws_private' pointer to point to * the platform-specific data. So in the subclasses, the methods do most * of their work by getting their hands on the ws_private pointer and then * using that to get at the correctly formatted data and functions for * their platform. * * Try imagining this as a 'public abstract class', and the ws_private * pointer as a sort of extra 'this' reference. Or imagine that you are * seeing the internal vtables of your favorite OO language. Whatever * works for you. * * See apache1.3/mod_jk.c and iis/jk_isapi_plugin.c for examples. */ struct jk_ws_service { /* * A 'this' pointer which is used by the subclasses of this class to * point to data which is specific to a given web server platform * (e.g. Apache or IIS). */ void *ws_private; /* * Provides memory management. All data specific to this request is * allocated within this pool, which can then be reclaimed at the end * of the request handling cycle. * * Alive as long as the request is alive. */ jk_pool_t *pool; /* * log context */ jk_log_context_t *log_ctx; /* * CGI Environment needed by servlets */ const char *method; const char *protocol; char *req_uri; const char *remote_addr; const char *remote_port; const char *remote_host; const char *remote_user; const char *auth_type; const char *query_string; const char *server_name; const char *local_addr; unsigned server_port; char *server_software; jk_uint64_t content_length; /* 64 bit integer that represents the content */ /* length should be 0 if unknown. */ unsigned is_chunked; /* 1 if content length is unknown (chunked rq) */ unsigned no_more_chunks; /* 1 if last chunk has been read */ jk_uint64_t content_read; /* number of bytes read */ /* * SSL information * * is_ssl - True if request is in ssl connection * ssl_protocol- Name of the SSL protocol (SSLv3, TLSv1, TLSv1.1, TLSv1.2) * ssl_cert - If available, base64 ASN.1 encoded client certificates. * ssl_cert_len - Length of ssl_cert, 0 if certificates are not available. * ssl_cipher - The ssl cipher suite in use. * ssl_session - The ssl session string * * In some servers it is impossible to extract all this information, in this * case, we are passing NULL. */ int is_ssl; char *ssl_protocol; char *ssl_cert; unsigned ssl_cert_len; char *ssl_cipher; char *ssl_session; /* * SSL extra information for Servlet 2.3 API * * ssl_key_size - ssl key size in use */ int ssl_key_size; /* * Headers, names and values. */ char **headers_names; /* Names of the request headers */ char **headers_values; /* Values of the request headers */ unsigned num_headers; /* Number of request headers */ /* * Request attributes. * * These attributes that were extracted from the web server and are * sent to Tomcat. * * The developer should be able to read them from the ServletRequest * attributes. Tomcat is required to append org.apache.tomcat. to * these attrinbute names. */ char **attributes_names; /* Names of the request attributes */ char **attributes_values; /* Values of the request attributes */ unsigned num_attributes; /* Number of request attributes */ /* * Response headers, names and values. * These are additional headers that we want to add to * the headers send to us from tomcat. * Example: a stickyness cookie header */ char **resp_headers_names; /* Names of the response headers */ char **resp_headers_values; /* Values of the response headers */ unsigned num_resp_headers; /* Number of response headers */ /* * JK_TRUE iff handled by a load balancer, the request * contained a route and it is the route of the current worker. */ int sticky; /* * The route is in use when the adapter load balance among * several workers. It is the ID of a specific target in the load balance * group. We are using this variable to implement target session * affinity */ const char *route; /* * Activation state of the worker in the load balancer. * Will be forwarded as a request attribute. */ const char *activation; /* Temp solution for auth. For native1 it'll be sent on each request, if an option is present. For native2 it'll be sent with the first request. On java side, both cases will work. For tomcat3.2 or a version that doesn't support secret - don't set the secret, and it'll work. */ const char *secret; /* * Area to get POST data for fail-over recovery in POST */ jk_msg_buf_t *reco_buf; int reco_status; /* * If set call flush after each write */ int flush_packets; /* * If set call flush after AJP13_SEND_HEADERS. */ int flush_header; /* * service extensions */ svc_extension_t extension; /* * JK_TRUE if response headers have been sent back */ int response_started; /* * JK_TRUE if response should not be send to the client */ int response_blocked; /* * HTTP status sent from container. */ int http_response_status; /* Uri worker map. Added for virtual host support */ jk_uri_worker_map_t *uw_map; /* * Callbacks into the web server. For each, the first argument is * essentially a 'this' pointer. All return JK_TRUE on success * and JK_FALSE on failure. */ /* * Send the response headers to the browser. */ int (JK_METHOD * start_response) (jk_ws_service_t *s, int status, const char *reason, const char *const *header_names, const char *const *header_values, unsigned num_of_headers); /* * Read a chunk of the request body into a buffer. Attempt to read len * bytes into the buffer. Write the number of bytes actually read into * actually_read. */ int (JK_METHOD * read) (jk_ws_service_t *s, void *buffer, unsigned len, unsigned *actually_read); /* * Write a chunk of response data back to the browser. */ int (JK_METHOD * write) (jk_ws_service_t *s, const void *buffer, unsigned len); /* * Flush a chunk of response data back to the browser. */ void (JK_METHOD * flush) (jk_ws_service_t *s); /* * Done with sending response back to the browser. */ void (JK_METHOD * done) (jk_ws_service_t *s); /* * If set do not reuse socket after each full response */ int disable_reuse; /* * Add more data to log facilities. */ void (JK_METHOD * add_log_items) (jk_ws_service_t *s, const char *const *log_names, const char *const *log_values, unsigned num_of_items); /* * Iterate through all vhosts */ void *(JK_METHOD * next_vhost) (void *d); /* * String representation of a vhost */ void (JK_METHOD * vhost_to_text) (void *d, char *buf, size_t len); /* * Get uw_map associated with a vhost */ jk_uri_worker_map_t *(JK_METHOD * vhost_to_uw_map) (void *d); }; /* * The endpoint 'class', which represents one end of a connection to the * servlet engine. Basically, supports nothing other than forwarding the * request to the servlet engine. Endpoints can be persistent (as with * ajp13/ajp14, where a single connection is reused many times), or can last for a * single request (as with ajp12, where a new connection is created for * every request). * * An endpoint for a given protocol is obtained by the web server plugin * from a worker object for that protocol. See below for details. * * As with all the core jk classes, this is essentially an abstract base * class which is implemented/extended by classes which are specific to a * particular protocol. By using an abstract base class in this manner, * plugins can be written for different servers (e.g. IIS, Apache) without * the plugins having to worry about which protocol they are talking. * * This particular OO-in-C system uses a 'endpoint_private' pointer to * point to the protocol-specific data/functions. So in the subclasses, the * methods do most of their work by getting their hands on the * endpoint_private pointer and then using that to get at the functions for * their protocol. * * Try imagining this as a 'public abstract class', and the * endpoint_private pointer as a sort of extra 'this' reference. Or * imagine that you are seeing the internal vtables of your favorite OO * language. Whatever works for you. * * See jk_ajp13_worker.c/jk_ajp14_worker.c and jk_ajp12_worker.c for examples. */ struct jk_endpoint { jk_uint64_t rd; jk_uint64_t wr; /* * Flag to pass back recoverability status from * a load balancer member to the load balancer itself. * Depending on the configuration and request status * recovery is not allowed. */ int recoverable; /* * A 'this' pointer which is used by the subclasses of this class to * point to data/functions which are specific to a given protocol * (e.g. ajp12 or ajp13 or ajp14). */ void *endpoint_private; /* * Forward a request to the servlet engine. The request is described * by the jk_ws_service_t object. * is_error is either 0 meaning recoverable or set to * the HTTP error code. */ int (JK_METHOD * service) (jk_endpoint_t *e, jk_ws_service_t *s, jk_log_context_t *log_ctx, int *is_error); /* * Called when this particular endpoint has finished processing a * request. For some protocols (e.g. ajp12), this frees the memory * associated with the endpoint. For others (e.g. ajp13/ajp14), this can * return the endpoint to a cache of already opened endpoints. * * Note that the first argument is *not* a 'this' pointer, but is * rather a pointer to a 'this' pointer. This is necessary, because * we may need to free this object. */ int (JK_METHOD * done) (jk_endpoint_t **p, jk_log_context_t *log_ctx); }; /* * The worker 'class', which represents something to which the web server * can delegate requests. * * This can mean communicating with a particular servlet engine instance, * using a particular protocol. A single web server instance may have * multiple workers communicating with a single servlet engine (it could be * using ajp12 for some requests and ajp13/ajp14 for others). Or, a single web * server instance could have multiple workers communicating with different * servlet engines using the same protocol (it could be load balancing * among many engines, using ajp13/ajp14 for all communication). * * There is also a load balancing worker (jk_lb_worker.c), which itself * manages a group of workers. * * Web servers are configured to forward requests to a given worker. To * handle those requests, the worker's get_endpoint method is called, and * then the service() method of that endpoint is called. * * As with all the core jk classes, this is essentially an abstract base * class which is implemented/extended by classes which are specific to a * particular protocol (or request-handling system). By using an abstract * base class in this manner, plugins can be written for different servers * (e.g. IIS, Apache) without the plugins having to worry about which * protocol they are talking. * * This particular OO-in-C system uses a 'worker_private' pointer to * point to the protocol-specific data/functions. So in the subclasses, the * methods do most of their work by getting their hands on the * worker_private pointer and then using that to get at the functions for * their protocol. * * Try imagining this as a 'public abstract class', and the * worker_private pointer as a sort of extra 'this' reference. Or * imagine that you are seeing the internal vtables of your favorite OO * language. Whatever works for you. * * See jk_ajp14_worker.c, jk_ajp13_worker.c and jk_ajp12_worker.c for examples. */ struct jk_worker { jk_worker_env_t *we; /* * A 'this' pointer which is used by the subclasses of this class to * point to data/functions which are specific to a given protocol * (e.g. ajp12 or ajp13 or ajp14). */ void *worker_private; int type; /* * For all of the below (except destroy), the first argument is * essentially a 'this' pointer. */ /* * Given a worker which is in the process of being created, and a list * of configuration options (or 'properties'), check to see if it the * options are. This will always be called before the init() method. * The init/validate distinction is a bit hazy to me. * See jk_ajp13_worker.c/jk_ajp14_worker.c and jk_worker.c->wc_create_worker() */ int (JK_METHOD * validate) (jk_worker_t *w, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *log_ctx); /* * Update worker either from jk_status or reloading from workers.properties */ int (JK_METHOD * update) (jk_worker_t *w, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *log_ctx); /* * Do whatever initialization needs to be done to start this worker up. * Configuration options are passed in via the props parameter. */ int (JK_METHOD * init) (jk_worker_t *w, jk_map_t *props, jk_worker_env_t *we, jk_log_context_t *log_ctx); /* * Obtain an endpoint to service a particular request. A pointer to * the endpoint is stored in pend. */ int (JK_METHOD * get_endpoint) (jk_worker_t *w, jk_endpoint_t **pend, jk_log_context_t *log_ctx); /* * Shutdown this worker. The first argument is not a 'this' pointer, * but rather a pointer to 'this', so that the object can be free'd (I * think -- though that doesn't seem to be happening. Hmmm). */ int (JK_METHOD * destroy) (jk_worker_t **w, jk_log_context_t *log_ctx); /* * Maintain this worker. */ int (JK_METHOD * maintain) (jk_worker_t *w, time_t now, int global, jk_log_context_t *log_ctx); /* * Shut this worker down. */ int (JK_METHOD * shutdown) (jk_worker_t *w, jk_log_context_t *log_ctx); }; /* * Essentially, an abstract base class (or factory class) with a single * method -- think of it as createWorker() or the Factory Method Design * Pattern. There is a different worker_factory function for each of the * different types of workers. The set of all these functions is created * at startup from the list in jk_worker_list.h, and then the correct one * is chosen in jk_worker.c->wc_create_worker(). See jk_worker.c and * jk_ajp13_worker.c/jk_ajp14_worker.c for examples. * * This allows new workers to be written without modifing the plugin code * for the various web servers (since the only link is through * jk_worker_list.h). */ typedef int (JK_METHOD * worker_factory) (jk_worker_t **w, const char *name, jk_log_context_t *log_ctx); void jk_init_ws_service(jk_ws_service_t *s); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* JK_SERVICE_H */ tomcat-connectors-1.2.50-src/native/common/jk_uri_worker_map.c0000644000000000000020000013504114655113617022763 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: URI to worker map object. * * * * Author: Gal Shachor * * Author: Mladen Turk * ***************************************************************************/ #include "jk_pool.h" #include "jk_util.h" #include "jk_map.h" #include "jk_mt.h" #include "jk_uri_worker_map.h" #include "jk_worker.h" #include "jk_lb_worker.h" #ifdef WIN32 #define JK_STRCMP strcasecmp #define JK_STRNCMP strnicmp #else #define JK_STRCMP strcmp #define JK_STRNCMP strncmp #endif #define JK_UWMAP_EXTENSION_REPLY_TIMEOUT "reply_timeout=" #define JK_UWMAP_EXTENSION_STICKY_IGNORE "sticky_ignore=" #define JK_UWMAP_EXTENSION_STATELESS "stateless=" #define JK_UWMAP_EXTENSION_ACTIVE "active=" #define JK_UWMAP_EXTENSION_DISABLED "disabled=" #define JK_UWMAP_EXTENSION_STOPPED "stopped=" #define JK_UWMAP_EXTENSION_FAIL_ON_STATUS "fail_on_status=" #define JK_UWMAP_EXTENSION_USE_SRV_ERRORS "use_server_errors=" #define JK_UWMAP_EXTENSION_SESSION_COOKIE "session_cookie=" #define JK_UWMAP_EXTENSION_SESSION_PATH "session_path=" #define JK_UWMAP_EXTENSION_SET_SESSION_COOKIE "set_session_cookie=" #define JK_UWMAP_EXTENSION_SESSION_COOKIE_PATH "session_cookie_path=" #define IND_SWITCH(x) (((x)+1) % 2) #define IND_THIS(x) ((x)[uw_map->index]) #define IND_NEXT(x) ((x)[IND_SWITCH(uw_map->index)]) #define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)") static volatile int map_id_counter = 0; static const char *uri_worker_map_source_type[] = { "unknown", SOURCE_TYPE_TEXT_WORKERDEF, SOURCE_TYPE_TEXT_JKMOUNT, SOURCE_TYPE_TEXT_URIMAP, SOURCE_TYPE_TEXT_DISCOVER, NULL }; /* Return the string representation of the uwr source */ const char *uri_worker_map_get_source(uri_worker_record_t *uwr) { return uri_worker_map_source_type[uwr->source_type]; } /* Return the string representation of the uwr match type */ char *uri_worker_map_get_match(uri_worker_record_t *uwr, char *buf) { unsigned int match; buf[0] = '\0'; match = uwr->match_type; if (match & MATCH_TYPE_DISABLED) strcat(buf, "Disabled "); /* deprecated if (match & MATCH_TYPE_STOPPED) strcat(buf, "Stopped "); */ if (match & MATCH_TYPE_NO_MATCH) strcat(buf, "Unmount "); if (match & MATCH_TYPE_EXACT) strcat(buf, "Exact"); else if (match & MATCH_TYPE_WILDCHAR_PATH) strcat(buf, "Wildchar"); /* deprecated else if (match & MATCH_TYPE_CONTEXT) strcat(buf, "Context"); else if (match & MATCH_TYPE_CONTEXT_PATH) strcat(buf, "Context Path"); else if (match & MATCH_TYPE_SUFFIX) strcat(buf, "Suffix"); else if (match & MATCH_TYPE_GENERAL_SUFFIX) return "General Suffix"; */ else strcat(buf, "Unknown"); return buf; } /* * Given context uri, count the number of path tokens. * * Servlet specification 2.4, SRV.11.1 says * The container will recursively try tomatch the longest * path-prefix. This is done by stepping down the path tree a * directory at a time, using the / character as a path * separator. The longest match determines the servlet selected. * * The implication seems to be `most uri path elements is most exact'. * This is a little helper function to count uri tokens, so we can * keep the worker map sorted with most specific first. */ static int worker_count_context_uri_tokens(const char * context) { const char * c = context; int count = 0; while (c && *c) { if ('/' == *c++) count++; } return count; } static int worker_compare(const void *elem1, const void *elem2) { uri_worker_record_t *e1 = *(uri_worker_record_t **)elem1; uri_worker_record_t *e2 = *(uri_worker_record_t **)elem2; int e1_tokens = 0; int e2_tokens = 0; e1_tokens = worker_count_context_uri_tokens(e1->context); e2_tokens = worker_count_context_uri_tokens(e2->context); if (e1_tokens != e2_tokens) { return (e2_tokens - e1_tokens); } /* given the same number of URI tokens, use character * length as a tie breaker */ if(e2->context_len != e1->context_len) return ((int)e2->context_len - (int)e1->context_len); return ((int)e2->source_type - (int)e1->source_type); } static void worker_qsort(jk_uri_worker_map_t *uw_map) { /* Sort remaining args using Quicksort algorithm: */ qsort((void *)IND_NEXT(uw_map->maps), IND_NEXT(uw_map->size), sizeof(uri_worker_record_t *), worker_compare); } /* Dump the map contents - only call if debug log is active. */ static void uri_worker_map_dump(jk_uri_worker_map_t *uw_map, const char *reason, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (uw_map) { int i, off; if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "uri map dump %s: id=%d, index=%d file='%s' " "reject_unsafe=%d reload=%d modified=%d checked=%d", reason, uw_map->id, uw_map->index, STRNULL_FOR_NULL(uw_map->fname), uw_map->reject_unsafe, uw_map->reload, uw_map->modified, uw_map->checked); } for (i = 0; i <= 1; i++) { jk_log(l, JK_LOG_DEBUG, "generation %d: size=%d nosize=%d capacity=%d", i, uw_map->size[i], uw_map->nosize[i], uw_map->capacity[i], uw_map->maps[i]); } off = uw_map->index; for (i = 0; i <= 1; i++) { char buf[32]; int k; unsigned int j; k = (i + off) % 2; for (j = 0; j < uw_map->size[k]; j++) { uri_worker_record_t *uwr = uw_map->maps[k][j]; if (uwr && JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "%s (%d) map #%d: uri=%s worker=%s " "context=%s source=%s type=%s len=%d", i ? "NEXT" : "THIS", i, j, STRNULL_FOR_NULL(uwr->uri), STRNULL_FOR_NULL(uwr->worker_name), STRNULL_FOR_NULL(uwr->context), STRNULL_FOR_NULL(uri_worker_map_get_source(uwr)), STRNULL_FOR_NULL(uri_worker_map_get_match(uwr, buf)), uwr->context_len); } } } } JK_TRACE_EXIT(l); } int uri_worker_map_alloc(jk_uri_worker_map_t **uw_map_p, jk_map_t *init_data, jk_log_context_t *l) { int i; JK_TRACE_ENTER(l); if (uw_map_p) { int rc; jk_uri_worker_map_t *uw_map; *uw_map_p = (jk_uri_worker_map_t *)calloc(1, sizeof(jk_uri_worker_map_t)); uw_map = *uw_map_p; JK_INIT_CS(&(uw_map->cs), rc); if (rc == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "creating thread lock (errno=%d)", errno); JK_TRACE_EXIT(l); return JK_FALSE; } jk_open_pool(&(uw_map->p), uw_map->buf, sizeof(jk_pool_atom_t) * BIG_POOL_SIZE); for (i = 0; i <= 1; i++) { jk_open_pool(&(uw_map->p_dyn[i]), uw_map->buf_dyn[i], sizeof(jk_pool_atom_t) * BIG_POOL_SIZE); uw_map->size[i] = 0; uw_map->nosize[i] = 0; uw_map->capacity[i] = 0; uw_map->maps[i] = NULL; } uw_map->id = 0; uw_map->index = 0; uw_map->fname = NULL; uw_map->reject_unsafe = 0; uw_map->reload = JK_URIMAP_DEF_RELOAD; uw_map->modified = 0; uw_map->checked = 0; if (init_data) rc = uri_worker_map_open(uw_map, init_data, l); if (rc == JK_TRUE) uw_map->id = ++map_id_counter; JK_TRACE_EXIT(l); return rc; } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } static int uri_worker_map_close(jk_uri_worker_map_t *uw_map, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (uw_map) { JK_DELETE_CS(&uw_map->cs); jk_close_pool(&uw_map->p_dyn[0]); jk_close_pool(&uw_map->p_dyn[1]); jk_close_pool(&uw_map->p); JK_TRACE_EXIT(l); return JK_TRUE; } JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } int uri_worker_map_free(jk_uri_worker_map_t **uw_map, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (uw_map && *uw_map) { uri_worker_map_close(*uw_map, l); free(*uw_map); *uw_map = NULL; JK_TRACE_EXIT(l); return JK_TRUE; } else JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return JK_FALSE; } /* * Ensure there will be memory in context info to store Context Bases */ #define UW_INC_SIZE 4 /* 4 URI->WORKER STEP */ static int uri_worker_map_realloc(jk_uri_worker_map_t *uw_map) { if (IND_NEXT(uw_map->size) == IND_NEXT(uw_map->capacity)) { uri_worker_record_t **uwr; int capacity = IND_NEXT(uw_map->capacity) + UW_INC_SIZE; uwr = (uri_worker_record_t **) jk_pool_alloc(&IND_NEXT(uw_map->p_dyn), sizeof(uri_worker_record_t *) * capacity); if (!uwr) return JK_FALSE; if (IND_NEXT(uw_map->capacity) && IND_NEXT(uw_map->maps)) memcpy(uwr, IND_NEXT(uw_map->maps), sizeof(uri_worker_record_t *) * IND_NEXT(uw_map->capacity)); IND_NEXT(uw_map->maps) = uwr; IND_NEXT(uw_map->capacity) = capacity; } return JK_TRUE; } /* * Delete all entries of a given source type */ static int uri_worker_map_clear(jk_uri_worker_map_t *uw_map, jk_log_context_t *l) { uri_worker_record_t *uwr = NULL; unsigned int i; unsigned int new_size = 0; unsigned int new_nosize = 0; JK_TRACE_ENTER(l); IND_NEXT(uw_map->maps) = (uri_worker_record_t **) jk_pool_alloc(&(IND_NEXT(uw_map->p_dyn)), sizeof(uri_worker_record_t *) * IND_THIS(uw_map->size)); IND_NEXT(uw_map->capacity) = IND_THIS(uw_map->size); IND_NEXT(uw_map->size) = 0; IND_NEXT(uw_map->nosize) = 0; for (i = 0; i < IND_THIS(uw_map->size); i++) { uwr = IND_THIS(uw_map->maps)[i]; if (uwr->source_type == SOURCE_TYPE_URIMAP) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "deleting map rule '%s=%s' source '%s'", uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr)); } else { IND_NEXT(uw_map->maps)[new_size] = uwr; new_size++; if (uwr->match_type & MATCH_TYPE_NO_MATCH) new_nosize++; } } IND_NEXT(uw_map->size) = new_size; IND_NEXT(uw_map->nosize) = new_nosize; JK_TRACE_EXIT(l); return JK_TRUE; } static void extract_activation(jk_pool_t *p, lb_worker_t *lb, int *activations, char *workers, int activation, jk_log_context_t *l) { unsigned int i; char *worker; #ifdef _MT_CODE_PTHREAD char *lasts; #endif JK_TRACE_ENTER(l); worker = jk_pool_strdup(p, workers); #ifdef _MT_CODE_PTHREAD for (worker = strtok_r(worker, ", ", &lasts); worker; worker = strtok_r(NULL, ", ", &lasts)) { #else for (worker = strtok(worker, ", "); worker; worker = strtok(NULL, ", ")) { #endif for (i = 0; i < lb->num_of_workers; i++) { if (!strcmp(worker, lb->lb_workers[i].name)) { if (activations[i] != JK_LB_ACTIVATION_UNSET) jk_log(l, JK_LOG_WARNING, "inconsistent activation overwrite for member %s " "of load balancer %s: '%s' replaced by '%s'", worker, lb->name, jk_lb_get_activation_direct(activations[i], l), jk_lb_get_activation_direct(activation, l)); activations[i] = activation; break; } } if (i >= lb->num_of_workers) jk_log(l, JK_LOG_WARNING, "could not find member %s of load balancer %s", worker, lb->name); } JK_TRACE_EXIT(l); } static void extension_fix_fail_on_status(jk_pool_t *p, const char *name, rule_extension_t *extensions, jk_log_context_t *l) { unsigned int i; int j; int cnt = 1; size_t status_len; char *status; #ifdef _MT_CODE_PTHREAD char *lasts; #endif JK_TRACE_ENTER(l); status_len = strlen(extensions->fail_on_status_str); for (i = 0; i < status_len; i++) { if (extensions->fail_on_status_str[i] == ',' || extensions->fail_on_status_str[i] == ' ') cnt++; } extensions->fail_on_status_size = cnt; status = jk_pool_strdup(p, extensions->fail_on_status_str); extensions->fail_on_status = (int *)jk_pool_alloc(p, extensions->fail_on_status_size * sizeof(int)); if (!extensions->fail_on_status) { jk_log(l, JK_LOG_ERROR, "can't alloc extensions fail_on_status list for worker (%s)", name); JK_TRACE_EXIT(l); return; } else if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Allocated fail_on_status array of size %d for worker (%s)", extensions->fail_on_status_size, name); for (j=0; jfail_on_status_size; j++) { extensions->fail_on_status[j] = 0; } cnt = 0; #ifdef _MT_CODE_PTHREAD for (status = strtok_r(status, ", ", &lasts); status; status = strtok_r(NULL, ", ", &lasts)) { #else for (status = strtok(status, ", "); status; status = strtok(NULL, ", ")) { #endif extensions->fail_on_status[cnt] = atoi(status); cnt++; } JK_TRACE_EXIT(l); } static int extension_fix_activation(jk_pool_t *p, const char *name, jk_worker_t *jw, rule_extension_t *extensions, jk_log_context_t *l) { JK_TRACE_ENTER(l); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Checking extension for worker %s of type %s (%d)", name, wc_get_name_for_type(jw->type, l), jw->type); if (jw->type == JK_LB_WORKER_TYPE && (extensions->active || extensions->disabled || extensions->stopped)) { int j; lb_worker_t *lb = (lb_worker_t *)jw->worker_private; if (!extensions->activation) { extensions->activation_size = lb->num_of_workers; extensions->activation = (int *)jk_pool_alloc(p, extensions->activation_size * sizeof(int)); if (!extensions->activation) { jk_log(l, JK_LOG_ERROR, "can't alloc extensions activation list"); JK_TRACE_EXIT(l); return JK_FALSE; } else if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Allocated activations array of size %d for lb worker %s", extensions->activation_size, name); for (j=0; jactivation_size; j++) { extensions->activation[j] = JK_LB_ACTIVATION_UNSET; } } if (extensions->active) extract_activation(p, lb, extensions->activation, extensions->active, JK_LB_ACTIVATION_ACTIVE, l); if (extensions->disabled) extract_activation(p, lb, extensions->activation, extensions->disabled, JK_LB_ACTIVATION_DISABLED, l); if (extensions->stopped) extract_activation(p, lb, extensions->activation, extensions->stopped, JK_LB_ACTIVATION_STOPPED, l); } else if (extensions->active) { jk_log(l, JK_LOG_WARNING, "Worker %s is not of type lb, activation extension " JK_UWMAP_EXTENSION_ACTIVE " for %s ignored", name, extensions->active); } else if (extensions->disabled) { jk_log(l, JK_LOG_WARNING, "Worker %s is not of type lb, activation extension " JK_UWMAP_EXTENSION_DISABLED " for %s ignored", name, extensions->disabled); } else if (extensions->stopped) { jk_log(l, JK_LOG_WARNING, "Worker %s is not of type lb, activation extension " JK_UWMAP_EXTENSION_STOPPED " for %s ignored", name, extensions->stopped); } JK_TRACE_EXIT(l); return JK_TRUE; } static void extension_fix_session(jk_pool_t *p, const char *name, jk_worker_t *jw, rule_extension_t *extensions, jk_log_context_t *l) { if (jw->type != JK_LB_WORKER_TYPE && extensions->session_cookie) { jk_log(l, JK_LOG_WARNING, "Worker %s is not of type lb, extension " JK_UWMAP_EXTENSION_SESSION_COOKIE " for %s ignored", name, extensions->session_cookie); } if (jw->type != JK_LB_WORKER_TYPE && extensions->session_path) { jk_log(l, JK_LOG_WARNING, "Worker %s is not of type lb, extension " JK_UWMAP_EXTENSION_SESSION_PATH " for %s ignored", name, extensions->session_path); } if (jw->type != JK_LB_WORKER_TYPE && extensions->set_session_cookie) { jk_log(l, JK_LOG_WARNING, "Worker %s is not of type lb, extension " JK_UWMAP_EXTENSION_SET_SESSION_COOKIE " for %s ignored", name, extensions->set_session_cookie ? "'true'" : "'false'"); } if (jw->type != JK_LB_WORKER_TYPE && extensions->session_cookie_path) { jk_log(l, JK_LOG_WARNING, "Worker %s is not of type lb, extension " JK_UWMAP_EXTENSION_SESSION_COOKIE_PATH " for %s ignored", name, extensions->session_cookie_path); } } void extension_fix(jk_pool_t *p, const char *name, rule_extension_t *extensions, jk_log_context_t *l) { jk_worker_t *jw = wc_get_worker_for_name(name, l); if(!jw) { jk_log(l, JK_LOG_ERROR, "Could not find worker with name '%s' in uri map post processing.", name); return; } if (!extension_fix_activation(p, name, jw, extensions, l)) return; if (extensions->fail_on_status_str) { extension_fix_fail_on_status(p, name, extensions, l); } extension_fix_session(p, name, jw, extensions, l); } void uri_worker_map_switch(jk_uri_worker_map_t *uw_map, jk_log_context_t *l) { int new_index; JK_TRACE_ENTER(l); if (uw_map) { new_index = IND_SWITCH(uw_map->index); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Switching uri worker map from index %d to index %d", uw_map->index, new_index); uw_map->index = new_index; jk_reset_pool(&(IND_NEXT(uw_map->p_dyn))); } JK_TRACE_EXIT(l); } void uri_worker_map_ext(jk_uri_worker_map_t *uw_map, jk_log_context_t *l) { unsigned int i; JK_TRACE_ENTER(l); for (i = 0; i < IND_NEXT(uw_map->size); i++) { uri_worker_record_t *uwr = IND_NEXT(uw_map->maps)[i]; jk_pool_t *p; if(uwr->match_type & MATCH_TYPE_NO_MATCH) continue; if (uwr->source_type == SOURCE_TYPE_URIMAP) p = &IND_NEXT(uw_map->p_dyn); else p = &uw_map->p; extension_fix(p, uwr->worker_name, &uwr->extensions, l); } if (JK_IS_DEBUG_LEVEL(l)) uri_worker_map_dump(uw_map, "after extension stripping", l); JK_TRACE_EXIT(l); return; } /* Parse rule extensions */ void parse_rule_extensions(char *rule, rule_extension_t *extensions, jk_log_context_t *l) { char *param; #ifdef _MT_CODE_PTHREAD char *lasts = NULL; #endif extensions->reply_timeout = -1; extensions->sticky_ignore = JK_FALSE; extensions->stateless = JK_FALSE; extensions->active = NULL; extensions->disabled = NULL; extensions->stopped = NULL; extensions->activation_size = 0; extensions->activation = NULL; extensions->fail_on_status_size = 0; extensions->fail_on_status = NULL; extensions->fail_on_status_str = NULL; extensions->use_server_error_pages = 0; extensions->session_cookie = NULL; extensions->session_path = NULL; extensions->set_session_cookie = JK_FALSE; extensions->session_cookie_path = NULL; #ifdef _MT_CODE_PTHREAD param = strtok_r(rule, ";", &lasts); #else param = strtok(rule, ";"); #endif if (param) { #ifdef _MT_CODE_PTHREAD for (param = strtok_r(NULL, ";", &lasts); param; param = strtok_r(NULL, ";", &lasts)) { #else for (param = strtok(NULL, ";"); param; param = strtok(NULL, ";")) { #endif if (!strncmp(param, JK_UWMAP_EXTENSION_REPLY_TIMEOUT, strlen(JK_UWMAP_EXTENSION_REPLY_TIMEOUT))) { extensions->reply_timeout = atoi(param + strlen(JK_UWMAP_EXTENSION_REPLY_TIMEOUT)); } else if (!strncmp(param, JK_UWMAP_EXTENSION_STICKY_IGNORE, strlen(JK_UWMAP_EXTENSION_STICKY_IGNORE))) { int val = atoi(param + strlen(JK_UWMAP_EXTENSION_STICKY_IGNORE)); if (val) { extensions->sticky_ignore = JK_TRUE; } else { extensions->sticky_ignore = JK_FALSE; } } else if (!strncmp(param, JK_UWMAP_EXTENSION_STATELESS, strlen(JK_UWMAP_EXTENSION_STATELESS))) { int val = atoi(param + strlen(JK_UWMAP_EXTENSION_STATELESS)); if (val) { extensions->stateless = JK_TRUE; } else { extensions->stateless = JK_FALSE; } } else if (!strncmp(param, JK_UWMAP_EXTENSION_USE_SRV_ERRORS, strlen(JK_UWMAP_EXTENSION_USE_SRV_ERRORS))) { extensions->use_server_error_pages = atoi(param + strlen(JK_UWMAP_EXTENSION_USE_SRV_ERRORS)); } else if (!strncmp(param, JK_UWMAP_EXTENSION_ACTIVE, strlen(JK_UWMAP_EXTENSION_ACTIVE))) { if (extensions->active) jk_log(l, JK_LOG_WARNING, "rule extension '" JK_UWMAP_EXTENSION_ACTIVE "' only allowed once"); else extensions->active = param + strlen(JK_UWMAP_EXTENSION_ACTIVE); } else if (!strncmp(param, JK_UWMAP_EXTENSION_DISABLED, strlen(JK_UWMAP_EXTENSION_DISABLED))) { if (extensions->disabled) jk_log(l, JK_LOG_WARNING, "rule extension '" JK_UWMAP_EXTENSION_DISABLED "' only allowed once"); else extensions->disabled = param + strlen(JK_UWMAP_EXTENSION_DISABLED); } else if (!strncmp(param, JK_UWMAP_EXTENSION_STOPPED, strlen(JK_UWMAP_EXTENSION_STOPPED))) { if (extensions->stopped) jk_log(l, JK_LOG_WARNING, "rule extension '" JK_UWMAP_EXTENSION_STOPPED "' only allowed once"); else extensions->stopped = param + strlen(JK_UWMAP_EXTENSION_STOPPED); } else if (!strncmp(param, JK_UWMAP_EXTENSION_FAIL_ON_STATUS, strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS))) { if (extensions->fail_on_status_str) jk_log(l, JK_LOG_WARNING, "rule extension '" JK_UWMAP_EXTENSION_FAIL_ON_STATUS "' only allowed once"); else extensions->fail_on_status_str = param + strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS); } else if (!strncmp(param, JK_UWMAP_EXTENSION_SESSION_COOKIE, strlen(JK_UWMAP_EXTENSION_SESSION_COOKIE))) { if (extensions->session_cookie) jk_log(l, JK_LOG_WARNING, "extension '" JK_UWMAP_EXTENSION_SESSION_COOKIE "' in uri worker map only allowed once"); else extensions->session_cookie = param + strlen(JK_UWMAP_EXTENSION_SESSION_COOKIE); } else if (!strncmp(param, JK_UWMAP_EXTENSION_SESSION_PATH, strlen(JK_UWMAP_EXTENSION_SESSION_PATH))) { if (extensions->session_path) jk_log(l, JK_LOG_WARNING, "extension '" JK_UWMAP_EXTENSION_SESSION_PATH "' in uri worker map only allowed once"); else { // Check if the session identifier starts with semicolon. if (!strcmp(param, JK_UWMAP_EXTENSION_SESSION_PATH)) { #ifdef _MT_CODE_PTHREAD param = strtok_r(NULL, ";", &lasts); #else param = strtok(NULL, ";"); #endif extensions->session_path = param; } else extensions->session_path = param + strlen(JK_UWMAP_EXTENSION_SESSION_PATH); } } else if (!strncmp(param, JK_UWMAP_EXTENSION_SET_SESSION_COOKIE, strlen(JK_UWMAP_EXTENSION_SET_SESSION_COOKIE))) { if (extensions->set_session_cookie) jk_log(l, JK_LOG_WARNING, "extension '" JK_UWMAP_EXTENSION_SET_SESSION_COOKIE "' in uri worker map only allowed once"); else { int val = atoi(param + strlen(JK_UWMAP_EXTENSION_SET_SESSION_COOKIE)); if (val) { extensions->set_session_cookie = JK_TRUE; } else { extensions->set_session_cookie = JK_FALSE; } } } else if (!strncmp(param, JK_UWMAP_EXTENSION_SESSION_COOKIE_PATH, strlen(JK_UWMAP_EXTENSION_SESSION_COOKIE_PATH))) { if (extensions->session_cookie_path) jk_log(l, JK_LOG_WARNING, "extension '" JK_UWMAP_EXTENSION_SESSION_COOKIE_PATH "' in uri worker map only allowed once"); else extensions->session_cookie_path = param + strlen(JK_UWMAP_EXTENSION_SESSION_COOKIE_PATH); } else { jk_log(l, JK_LOG_WARNING, "unknown rule extension '%s'", param); } } } } /* Add new entry to NEXT generation */ int uri_worker_map_add(jk_uri_worker_map_t *uw_map, const char *puri, const char *worker, unsigned int source_type, jk_log_context_t *l) { uri_worker_record_t *uwr = NULL; char *uri; jk_pool_t *p; unsigned int match_type = 0; JK_TRACE_ENTER(l); if (*puri == '-') { /* Disable urimap. * This way you can disable already mounted * context. */ match_type = MATCH_TYPE_DISABLED; puri++; } if (*puri == '!') { match_type |= MATCH_TYPE_NO_MATCH; puri++; } if (uri_worker_map_realloc(uw_map) == JK_FALSE) { JK_TRACE_EXIT(l); return JK_FALSE; } if (source_type == SOURCE_TYPE_URIMAP) p = &IND_NEXT(uw_map->p_dyn); else p = &uw_map->p; uwr = (uri_worker_record_t *)jk_pool_alloc(p, sizeof(uri_worker_record_t)); if (!uwr) { jk_log(l, JK_LOG_ERROR, "can't alloc map entry"); JK_TRACE_EXIT(l); return JK_FALSE; } uri = jk_pool_strdup(p, puri); if (!uri || !worker) { jk_log(l, JK_LOG_ERROR, "can't alloc uri/worker strings"); JK_TRACE_EXIT(l); return JK_FALSE; } if (*uri == '/') { char *w = jk_pool_strdup(p, worker); parse_rule_extensions(w, &uwr->extensions, l); uwr->source_type = source_type; uwr->worker_name = w; uwr->uri = uri; uwr->context = uri; uwr->context_len = strlen(uwr->context); if (strchr(uri, '*') || strchr(uri, '?')) { /* Something like * /context/ * /user/ * * /context/ *.suffix */ match_type |= MATCH_TYPE_WILDCHAR_PATH; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "wildchar rule '%s=%s' source '%s' was added", uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr)); } else { /* Something like: JkMount /login/j_security_check ajp13 */ match_type |= MATCH_TYPE_EXACT; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "exact rule '%s=%s' source '%s' was added", uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr)); } } else { /* * JFC: please check... * Not sure what to do, but I try to prevent problems. * I have fixed jk_mount_context() in apaches/mod_jk.c so we should * not arrive here when using Apache. */ jk_log(l, JK_LOG_ERROR, "invalid context '%s': does not begin with '/'", uri); JK_TRACE_EXIT(l); return JK_FALSE; } uwr->match_type = match_type; IND_NEXT(uw_map->maps)[IND_NEXT(uw_map->size)] = uwr; IND_NEXT(uw_map->size)++; if (match_type & MATCH_TYPE_NO_MATCH) { /* If we split the mappings this one will be calculated */ IND_NEXT(uw_map->nosize)++; } worker_qsort(uw_map); JK_TRACE_EXIT(l); return JK_TRUE; } int uri_worker_map_open(jk_uri_worker_map_t *uw_map, jk_map_t *init_data, jk_log_context_t *l) { int rc = JK_TRUE; JK_TRACE_ENTER(l); if (uw_map) { int sz = jk_map_size(init_data); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "rule map size is %d", sz); if (sz > 0) { int i; for (i = 0; i < sz; i++) { const char *u = jk_map_name_at(init_data, i); const char *w = jk_map_value_at(init_data, i); /* Multiple mappings like : * /servlets-examples|/ * * will create two mappings: * /servlets-examples * and: * /servlets-examples/ * */ if (strchr(u, '|')) { char *s, *r = strdup(u); s = strchr(r, '|'); *(s++) = '\0'; /* Add first mapping */ if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_JKMOUNT, l)) { jk_log(l, JK_LOG_ERROR, "invalid mapping rule %s->%s", r, w); rc = JK_FALSE; } for (; *s; s++) *(s - 1) = *s; *(s - 1) = '\0'; /* add second mapping */ if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_JKMOUNT, l)) { jk_log(l, JK_LOG_ERROR, "invalid mapping rule %s->%s", r, w); rc = JK_FALSE; } free(r); } else if (!uri_worker_map_add(uw_map, u, w, SOURCE_TYPE_JKMOUNT, l)) { jk_log(l, JK_LOG_ERROR, "invalid mapping rule %s->%s", u, w); rc = JK_FALSE; break; } if (rc == JK_FALSE) break; } } if (rc == JK_FALSE) { jk_log(l, JK_LOG_ERROR, "there was an error, freeing buf"); jk_close_pool(&uw_map->p_dyn[0]); jk_close_pool(&uw_map->p_dyn[1]); jk_close_pool(&uw_map->p); } else if (JK_IS_DEBUG_LEVEL(l)) uri_worker_map_dump(uw_map, "after map open", l); } JK_TRACE_EXIT(l); return rc; } static int find_match(jk_uri_worker_map_t *uw_map, const char *url, jk_log_context_t *l) { unsigned int i; JK_TRACE_ENTER(l); for (i = 0; i < IND_THIS(uw_map->size); i++) { uri_worker_record_t *uwr = IND_THIS(uw_map->maps)[i]; /* Check for match types */ if ((uwr->match_type & MATCH_TYPE_DISABLED) || (uwr->match_type & MATCH_TYPE_NO_MATCH)) continue; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Attempting to map context URI '%s=%s' " "source '%s'", uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr)); if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) { /* Map is already sorted by context_len */ if (jk_wildchar_match(url, uwr->context, #ifdef WIN32 0 #else 0 #endif ) == 0) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Found a wildchar match '%s=%s'", uwr->context, uwr->worker_name); JK_TRACE_EXIT(l); return i; } } else if (JK_STRNCMP(uwr->context, url, uwr->context_len) == 0) { if (strlen(url) == uwr->context_len) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Found an exact match '%s=%s'", uwr->context, uwr->worker_name); JK_TRACE_EXIT(l); return i; } } } JK_TRACE_EXIT(l); return -1; } static int is_nomatch(jk_uri_worker_map_t *uw_map, const char *uri, int match, jk_log_context_t *l) { unsigned int i; const char *worker = IND_THIS(uw_map->maps)[match]->worker_name; JK_TRACE_ENTER(l); for (i = 0; i < IND_THIS(uw_map->size); i++) { uri_worker_record_t *uwr = IND_THIS(uw_map->maps)[i]; /* Check only nomatch mappings */ if (!(uwr->match_type & MATCH_TYPE_NO_MATCH) || (uwr->match_type & MATCH_TYPE_DISABLED)) continue; /* Check only matching workers */ if (strcmp(uwr->worker_name, worker) && strcmp(uwr->worker_name, "*")) continue; if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) { /* Map is already sorted by context_len */ if (jk_wildchar_match(uri, uwr->context, #ifdef WIN32 0 #else 0 #endif ) == 0) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Found a wildchar no match '%s=%s' source '%s'", uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr)); JK_TRACE_EXIT(l); return JK_TRUE; } } else if (JK_STRNCMP(uwr->context, uri, uwr->context_len) == 0) { if (strlen(uri) == uwr->context_len) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Found an exact no match '%s=%s' source '%s'", uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr)); JK_TRACE_EXIT(l); return JK_TRUE; } } } JK_TRACE_EXIT(l); return JK_FALSE; } const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, const char *uri, const char *vhost, rule_extension_t **extensions, int *index, jk_log_context_t *l) { unsigned int i; unsigned int vhost_len; int reject_unsafe; size_t uri_len; size_t remain; int rv = -1; char url[JK_MAX_URI_LEN+1]; JK_TRACE_ENTER(l); if (!uw_map || !uri || !extensions) { JK_LOG_NULL_PARAMS(l); JK_TRACE_EXIT(l); return NULL; } *extensions = NULL; if (index) *index = -1; if (*uri != '/') { if (*uri == '*' && *(uri+1) == '\0') { /* Most likely an "OPTIONS *" request */ if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Uri %s can't be mapped.", uri); } } else { jk_log(l, JK_LOG_WARNING, "Uri %s is invalid. Uri must start with /", uri); } JK_TRACE_EXIT(l); return NULL; } if (uw_map->fname) { uri_worker_map_update(uw_map, 0, l); if (!IND_THIS(uw_map->size)) { jk_log(l, JK_LOG_INFO, "No worker maps defined for %s.", uw_map->fname); JK_TRACE_EXIT(l); return NULL; } } reject_unsafe = uw_map->reject_unsafe; vhost_len = 0; /* * In case we got a vhost, we prepend a slash * and the vhost to the url in order to enable * vhost mapping rules especially for IIS. */ if (vhost) { int off = 0; /* Add leading '/' if necessary */ if (vhost[0] != '/') { url[0] = '/'; off = 1; } /* Size including leading slash. */ vhost_len = (unsigned int)strlen(vhost); if (vhost_len + off >= JK_MAX_URI_LEN) { vhost_len = 0; jk_log(l, JK_LOG_WARNING, "Host prefix %s for URI %s is invalid and will be ignored." " It must be smaller than %d chars", vhost, JK_MAX_URI_LEN - off); } else { memcpy(&url[off], vhost, vhost_len + 1); if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Prefixing mapping uri with vhost '%s'", vhost); } } vhost_len += off; } /* Make the copy of the provided uri, check length * and look for potentially unsafe constructs */ uri_len = strlen(uri); remain = JK_MAX_URI_LEN - vhost_len; for (i = 0; i < uri_len; i++) { if (i == remain) { jk_log(l, JK_LOG_WARNING, "URI %s is invalid. URI must be smaller than %d chars", uri, remain); JK_TRACE_EXIT(l); return NULL; } url[i + vhost_len] = uri[i]; if (reject_unsafe && (uri[i] == '%' || uri[i] == '\\')) { jk_log(l, JK_LOG_INFO, "Potentially unsafe request url '%s' rejected", uri); JK_TRACE_EXIT(l); return NULL; } } url[i + vhost_len] = '\0'; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Attempting to map URI '%s' from %d maps", url, IND_THIS(uw_map->size)); rv = find_match(uw_map, url, l); /* If this doesn't find a match, try without the vhost. */ if (rv < 0 && vhost_len) { rv = find_match(uw_map, &url[vhost_len], l); } /* In case we found a match, check for the unmounts. */ if (rv >= 0 && IND_THIS(uw_map->nosize)) { int rc; /* Again first including vhost. */ rc = is_nomatch(uw_map, url, rv, l); /* If no unmount was found, try without vhost. */ if (!rc && vhost_len) rc = is_nomatch(uw_map, &url[vhost_len], rv, l); if (rc) { if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Denying match for worker %s by nomatch rule", IND_THIS(uw_map->maps)[rv]->worker_name); } rv = -1; } } if (rv >= 0) { *extensions = &(IND_THIS(uw_map->maps)[rv]->extensions); if (index) *index = rv; JK_TRACE_EXIT(l); return IND_THIS(uw_map->maps)[rv]->worker_name; } JK_TRACE_EXIT(l); return NULL; } rule_extension_t *get_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, int index) { if (index >= 0) { return &(IND_THIS(uw_map->maps)[index]->extensions); } else { return NULL; } } int uri_worker_map_load(jk_uri_worker_map_t *uw_map, jk_log_context_t *l) { int rc = JK_FALSE; jk_map_t *map; jk_map_alloc(&map); if (jk_map_read_properties(map, NULL, uw_map->fname, &uw_map->modified, JK_MAP_HANDLE_NORMAL, l)) { int i; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Loading urimaps from %s with reload check interval %d " "seconds", uw_map->fname, uw_map->reload); uri_worker_map_clear(uw_map, l); for (i = 0; i < jk_map_size(map); i++) { const char *u = jk_map_name_at(map, i); const char *w = jk_map_value_at(map, i); /* Multiple mappings like : * /servlets-examples|/ * * will create two mappings: * /servlets-examples * and: * /servlets-examples/ * */ if (strchr(u, '|')) { char *s, *r = strdup(u); s = strchr(r, '|'); *(s++) = '\0'; /* Add first mapping */ if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_URIMAP, l)) { jk_log(l, JK_LOG_ERROR, "invalid mapping rule %s->%s", r, w); } for (; *s; s++) *(s - 1) = *s; *(s - 1) = '\0'; /* add second mapping */ if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_URIMAP, l)) { jk_log(l, JK_LOG_ERROR, "invalid mapping rule %s->%s", r, w); } free(r); } else if (!uri_worker_map_add(uw_map, u, w, SOURCE_TYPE_URIMAP, l)) { jk_log(l, JK_LOG_ERROR, "invalid mapping rule %s->%s", u, w); } } uw_map->checked = time(NULL); if (JK_IS_DEBUG_LEVEL(l)) uri_worker_map_dump(uw_map, "after file load", l); rc = JK_TRUE; } else { jk_log(l, JK_LOG_ERROR, "Failed to load uri_worker_map file %s " "(errno=%d, err=%s).", uw_map->fname, errno, strerror(errno)); } jk_map_free(&map); return rc; } int uri_worker_map_update(jk_uri_worker_map_t *uw_map, int force, jk_log_context_t *l) { int rc = JK_TRUE; time_t now = time(NULL); if (force || (uw_map->reload > 0 && difftime(now, uw_map->checked) > uw_map->reload)) { struct stat statbuf; uw_map->checked = now; if ((rc = jk_stat(uw_map->fname, &statbuf)) == -1) { jk_log(l, JK_LOG_ERROR, "Unable to stat the %s (errno=%d)", uw_map->fname, errno); return JK_FALSE; } if (statbuf.st_mtime == uw_map->modified) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "File %s is not modified", uw_map->fname); return JK_TRUE; } JK_ENTER_CS(&uw_map->cs); /* Check if some other thread updated status */ if (statbuf.st_mtime == uw_map->modified) { JK_LEAVE_CS(&uw_map->cs); if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "File %s is not modified", uw_map->fname); return JK_TRUE; } rc = uri_worker_map_load(uw_map, l); uri_worker_map_ext(uw_map, l); uri_worker_map_switch(uw_map, l); JK_LEAVE_CS(&uw_map->cs); jk_log(l, JK_LOG_INFO, "Reloaded urimaps from %s", uw_map->fname); } return JK_TRUE; } tomcat-connectors-1.2.50-src/native/NEWS0000644000000000000020000007265714655113621016325 0ustar rootbin2024 News & Status 2024 News & Status 12 August - JK-1.2.50 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.50. This is a maintenance release. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2023 News & Status 2023 News & Status 11 September - JK-1.2.49 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.49. This is a maintenance release. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2020 News & Status 2020 News & Status 6 March - JK-1.2.48 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.48. This is a maintenance release. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2018 News & Status 2018 News & Status 13 October - JK-1.2.46 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.46. This is a maintenance release. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. 1 September - JK-1.2.44 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.44. This is a maintenance release. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. 6 March - JK-1.2.43 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.43. This is a maintenance release. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2016 News & Status 2016 News & Status 5 October - JK-1.2.42 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.42. This is a maintenance release. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2015 News & Status 2015 News & Status 11 August - JK-1.2.41 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.41. This is a maintenance and security release. This release includes the fix for CVE-2014-8111. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2014 News and Status 2014 News & Status 15 April - JK-1.2.40 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.40. This is a stable release concentrating mainly on bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. 11 March - JK-1.2.39 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.39. This is a stable release containing both bug fixes and few new features like IPV6 support. Note that version 1.2.38 was not released due to some minor issues found in release process. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2012 News and Status 2012 News & Status 31 May - JK-1.2.37 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.37. This is a stable release concentrating mainly on bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. 14 May - JK-1.2.36 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.36. This is a stable release concentrating mainly on bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. 24 March - JK-1.2.35 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.35. This is a stable release concentrating mainly on bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. 19 March - JK-1.2.33 stability issue The Apache Tomcat team wishes to draw your attention to stability issues that have been identified with the recent mod_jk 1.2.33 release. If you have not yet upgraded to mod_jk 1.2.33 we recommend that you wait for the mod_jk 1.2.34 release which is currently in progress. If you have upgraded and are experienced issues we recommend that you downgrade to mod_jk 1.2.32 until mod_jk 1.2.34 is available. We apologise for any inconvenience. 13 March - JK-1.2.33 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.33. This is a stable release concentrating mainly on some bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2011 News and Status 2011 News & Status 8 July - JK-1.2.32 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.32. This is a stable release concentrating mainly on some bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2010 News and Status 2010 News & Status 1 November - JK-1.2.31 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.31. This is a stable release concentrating mainly on some bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. 1 March - JK-1.2.30 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.30. This is a stable release concentrating mainly on some bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. 1 March - JK-1.2.29 withdrawn Tomcat Connectors 1.2.29 has been withdrawn because of regression inside Microsoft IIS connector. 26 February - JK-1.2.29 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.29. This is a stable release concentrating mainly on some bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. Copyright © 1999-2024, The Apache Software Foundation 2009 News and Status 2009 News & Status 22 March - JK-1.2.28 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.28. This is a stable release concentrating mainly on some bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. The most important new features in this version are: Better Error Detection for Load Balancer Workers Local and global error states have been improved. You can fine tune the behaviour with the new "error_escalation_time" attribute (see the timeouts documentation). Dynamic Address and Port Change Using the Status Worker The status worker now allows you to change the address and the port of an AJP13 worker on the fly. You can e.g. provision dummy workers with a port equal to "0", which will be automatically put into stopped mode during startup. Later, when you want to actually use these workers, you set their address and port to the final values. Note that already existing connections will go on using the old address and port. This will be improved in future versions. New Data in Status Worker Display The status worker display now also contains the timestamp of the last worker errors. Improved Proxy Flexibility You can now overwrite more request metadata before the request gets send to the backend. This is helpful in case there are other reverse proxies in front of your web server. A new documentation page explains this in detail. Improved IIS Support IIS support has been improved especially when using mutltiple application pools. Furthermore you can now configure the ISAPI plugin to update the uriworkermap.properies file on a regular interval using the watchdog thread. JNI Worker Deprecation Workers of type jni are broken since a long time. Since there is no more use for them, they have been deprecated now, and will be removed in a future release. Copyright © 1999-2024, The Apache Software Foundation 2008 News and Status 2008 News & Status 28 October - JK-1.2.27 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.27. This is a stable release adding lots of new features and some bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. The most important new features in this version are: Watchdog Thread for Periodic Tasks The connector has to run some periodic tasks independant of request processing. Examples are probing or closing down idle backend connections, adjusting load numbers and recovering workers from error state. Before version 1.2.27 these tasks were done inside the request processing loop. When a new request came in and the task was due, the thread handling the request first executed the internal task and then handled the request. If there were no requests coming in, the tasks would not run. If any of the tasks took unexpectedly long, the response time of the request waiting for the finishing of the task went up. Starting with this release you can configure a separate watchdog thread inside the web server to run all those tasks independantly of request processing. This new feature is avaliable for the connector when used with Apache httpd 2.x or with Microsoft IIS. To keep the behaviour of the new version consistent with previous releases, this feature is turned off by default. You can activate the watchdog thread via JkWatchdogInterval for Apache or watchdog_interval for IIS. Connection Probing In previous releases connection probing (checking whether connections still work) could only be done immediately after a new connection was established and directly before sending each request. Since we now have the watchdog thread available, we also added a periodic probing option, which you can activate with the worker attribute ping_mode. This will also be useful as a protection against the infamous firewall idle connection drop. The older attributes connect_timeout and prepost_timeout still exist and work the same way they did in previous releases. Since there are now three different probing options, we recommend to migrate your configuration to the newer attributes ping_mode, ping_timeout and connection_ping_interval. Mount Extensions Usually one defines workers and mounts for the connector. A worker defines a backend we want to talk to and the configuration parameters of the communication, connection pools etc. The mounts define which URIs we want to forward to which worker (so we also call a mount an URI map rule). In version 1.2.27 you can overwrite certain worker parameter per mount. One easy to understand example is reply timeouts. Until this release you had to specify a reply timeout for the whole worker. But reply times depend a lot on the type of request. So normally you want to define a general reply timeout and for some special URLs you need to relax the reply timeout, because you know those URLs take much longer to process (like e.g. reporting or other compute intensive tasks). Another possible case is the activation status. You might use a load balancer worker to forward requests to certain webapps in a farm of Tomcat nodes. If you wanted to update some webapp on one node, you previously had to stop forwarding requests for all webapps on this Tomcat node. What was not possible until now, was stopping forwarding requests restricted to the webapp and the node you wanted to update. Starting with this release, you can add so-called rule extensions to your uriworkermap file to influence worker parameters per mount. This will work for all Apache versions and for IIS. Remember, that the uriworkermap file automatically gets reloaded after changes without web server restart. Improved IIS support We improved IIS support im various ways. It is now possible to use multiple IIS 6 application pools with the ISAPI redirector. Furthermore some improvements were added as compile time features. The most notable one is chunked encoding support, which was a major refactoring and is therefore still considered experimental. You can download binaries with and without chunked encoding support. In future versions, chunked encoding will likely be availabe in all builds. Another new feature is an elegant way of configuring error page redirects. All new features are documented on the documentation page about configuring IIS. Enhanced Status Worker The status worker now can also manage and show statistics for AJP workers that are not part of a load balancer. Other improvements are the new dump action, the integration of the new configuration attributes, showing average request and transfer rates since the last statistics reset and the ability to display only a single member of a load balancer. Unfortunately we had to change some request parameters used for the update action of the status worker. Miscellaneous Improvements Further enhancements are: * Configurable session stickyness indicator: cookie name and URL path parameter name can be freely chosen instead of the servlet spec compliant JSESSIONID and ;jsessionid. * Automatically determining the size of the shared memory segment needed to accommodate all workers. * New connection establishment timeout socket_connect_timeout. * New timeout connection_acquire_timeout for acquiring a free connection from the pool. * Improved retry handling by adjusting the meaning of the attribute retries for AJP workers and for load balancers and by adding the new retry_interval. * Allowing the web server to provide error pages instead of Tomcat. Copyright © 1999-2024, The Apache Software Foundation 2007 News and Status 2007 News & Status 21 December - JK-1.2.26 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.26. This is a stable release adding few new features and some bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 7 August - JK-1.2.25 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.25. This is a stable release adding new features and a few bug fixes. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 27 July - JK-1.2.24 released This release has been withdrawn. ---------------------------------------------------------------------- 18 May - JK-1.2.23 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.23. This is a stable release adding new features and a few bug fixes to version 1.2.23. It fixes an Important vulnerability. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 17 April - JK-1.2.22 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.22. This is a stable release adding new features and a few bug fixes to version 1.2.22. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 1 March - JK-1.2.21 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.21. This is a stable release adding new features and a few bug fixes to version 1.2.20. It fixes a Critical vulnerability introduced in version 1.2.19 Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- Copyright © 1999-2024, The Apache Software Foundation 2006 News and Status 2006 News & Status 10 December - JK-1.2.20 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.20. This is a stable release adding new features and a few bug fixes to version 1.2.19. Furthermore the documentation has been reorganised. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 17 September - JK-1.2.19 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.19. This is a stable release adding some features and a few bug fixes to version 1.2.18. Furthermore the non-functional code trees for isapi and domino have been removed. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 13 July - JK-1.2.18 released The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.18. This is a stable release adding a few bug fixes to the not released 1.2.17 version. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- JK-1.2.17 not released Version 1.2.17 of Tomcat Connectors 1.2.17 has not been released due to a bug in the types chosen for socket arguments. Please see the ChangeLog for a full list of changes. ---------------------------------------------------------------------- JK-1.2.16 not released Version 1.2.16 of Tomcat Connectors 1.2.16 has not been released due to a bug in the jk status worker. This version adds some features and a few bug fixes to the 1.2.15 version. Furthermore some worker attributes have been deprecated. Please see the ChangeLog for a full list of changes. ---------------------------------------------------------------------- Copyright © 1999-2024, The Apache Software Foundation 2005 News and Status 2005 News & Status 8 November - JK-1.2.15 released The Apache Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.15. This is Stable release and it contains few bug fixes found in 1.2.14 version. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 13 July - JK-1.2.14 released The Apache Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.14. This is Stable release and it contains few bug fixes found in 1.2.13 version. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 7 May - JK-1.2.13 released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.13. This is development release and contains few bug fixes found in 1.2.12 version. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 7 May - JK-1.2.12 released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.12 The release contains a significant number of bug fixes and new features. We expect it to be ratified as a Stable release when the vote takes place in the next week. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 29 April - JK-1.2.11 released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.11 The release contains a significant number of bug fixes and new features. This version has not been released. Please see the ChangeLog for a full list of changes. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 30 March - JK-1.2.10 released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.10 The release contains a significant number of bug fixes and new features. We expect it to be ratified as a Stable release when the vote takes place in the next two weeks. Please see the ChangeLog for a full list of changes. Since release 1.2.10 the JkShmFile property has been added for Apache 1.3.x and Apache 2.x web servers on UNIX and LINUX platforms. Load balancer will not work properly if this directive is not present. If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 18 March - JK-1.2.9-beta released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.9-beta. The release contains a significant number of bug fixes and new features. We expect it to be ratified as a Stable release when the vote takes place in the next two weeks. Please see the ChangeLog for a full list of changes. Since release 1.2.9 the JkShmFile property has been added for Apache 1.3.x and Apache 2.x web servers on UNIX and LINUX platforms. Load balancer will not work properly if this directive is not present. If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- Copyright © 1999-2024, The Apache Software Foundation 2004 News and Status 2004 News & Status 17 December - JK-1.2.8 released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.8. Please see the ChangeLog for a full list of changes. If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 17 December - JK-1.2.8-rc-1 released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.8-rc-1 (Relase Canditate 1). We expect it to be ratified as a Stable release when the vote takes place in the next week. Please see the ChangeLog for a full list of changes. If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 13 December - JK-1.2.7-beta-3 released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.7-beta-3. The release contains a fix to few configuration problems detected with JK-1.2.7-beta-2 version. We expect it to be ratified as a Stable release when the vote takes place in the next week. Please see the ChangeLog for a full list of changes. If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 7 December - JK-1.2.7-beta-2 released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.7-beta-2. The release contains a fix to few compilation problems detected with JK-1.2.7-beta version. This release also introduces a new domain concept clustering support. See 32317 for details. We expect it to be ratified as a Stable release when the vote takes place in the next two weeks. Please see the ChangeLog for a full list of changes. If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 30 November - JK-1.2.7-beta released The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.7-beta. The release contains a significant number of bug fixes and new features. We expect it to be ratified as a Stable release when the vote takes place in the next two weeks. Please see the ChangeLog for a full list of changes. Since release 1.2.7 the socket_timeout property has been renamed to recycle_timeout. The socket_timeout now sets the real timeout for socket operations. If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component. ---------------------------------------------------------------------- 15 November - JK2 is officially unsupported JK2 has been put in maintainer mode and no further development will take place. The reason for shutting down JK2 development was the lack of developers interest. Other reason was lack of users interest in adopting JK2, caused by configuration complexity when compared to JK. The latest official JK2 release is 2.0.4. JK2 will have it's successor within core Apache2.1/2.2 distribution. We have developed new proxy_ajp that is an addition to the mod_proxy and uses Tomcat's AJP protocol stack. It is developped in httpd-2.1 and integrated in it. We have also developed a new proxy_balancer module for load balancing http and ajp protocol stacks. JK will be fully supported for all other web servers. The next JK release is planned for the end of November. Lots of code from JK2 has been ported to JK ---------------------------------------------------------------------- Copyright © 1999-2024, The Apache Software Foundation tomcat-connectors-1.2.50-src/native/TODO.txt0000644000000000000020000003167114655113617017130 0ustar rootbin Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. TODO for tomcat-connectors 1) Optimize "distance" ====================== Sorting the list of balanced workers by distance would be nice, but: How to combine the sorting with the offset implementation (especially useful for strategy BUSYNESS under low load). Local error states and likely other features will also break in case we do naive reordering. 2) Reduce number of string comparisons in most_suitable ======================================================== a) redirect/domains It would be easy to improve the redirect string b an integer, giving the index of the worker in the lb. Then lb would not need to search for the redirect worker. The same way, one could add a list with indizes to workers in the same domain. Whenever domain names are managed (init and status worker update) one would scan the worker list and update the index list. Finally one could have a list of workers, whose domain is the same as the redirect attribute of the worker, because that's also something we consider. What I'm not sure about, even in the existing code, is the locking between updates by the status worker and the process local information about the workers, especially in the case, when status updates a redirect or domain attribute. I would like to keep these attributes and the new index arrays process local, and the processes should find out about changes made by status to shm (redirect/domain) and then rebuild their data. No need to get these on every request from the shm, only the check for up-to-date should be made. b) exact matches for jvmRoutes Could we use hashes instead of string comparisons all the time? I'm not sure, if a good enough hash takes longer than a string comparison though. 3) Code separation between factory, validate and init in lb ============================================================ The factory contains: private_data->worker.retries = JK_RETRIES; private_data->s->recover_wait_time = WAIT_BEFORE_RECOVER; I think, this should move to validate() or init(). It might even be obsolete, because in init, we already have: pThis->retries = jk_get_worker_retries(props, p->s->name, p->s->retries = pThis->retries; p->s->recover_wait_time = jk_get_worker_recover_timeout(props, p->s->name, WAIT_BEFORE_RECOVER); if (p->s->recover_wait_time < WAIT_BEFORE_RECOVER) p->s->recover_wait_time = WAIT_BEFORE_RECOVER; Then: In validate there is p->lb_workers[i].s->error_time = 0; So shouldn't there also be p->lb_workers[i].s->maintain_time = time(NULL); 4) Logging ========== a) Allow logging of request url or uuid in jk log to ease matching with access log. b) Implement log rotation for IIS. (done in 1.2.31) c) Allow adding of log notes for IIS like we do with Apache. d) Add error type info to access log notes e) Refactor: Use the same code files for the request logging functions in Apache 1.3 and 2.0. f) Refactor: Use the same code files for piped logging in Apache 1.3 and 2.0. 5) ajpget ========== Combine ajplib and Apache ab to an ajp13 commandline client ajpget. 6) Parsing workers.properties ============================= Parsing of workers.properties aditionally to just looking up attributes would help users to detect syntax errors in the file. At the moment no information will be logged, e.g. when attributes contain typos. Example: worker.list vs. worker.lists. 7) Persisting workers.properties ================================ Make workers.properties persist from inside status worker. Add additional properties file, that contains a journal of property changes done via the status worker. When initializing those overwrite the initial workers.properties. Update actions in the status worker will allow to optionally add a change to this journal. We can also add a comment with timestamp etc. to each journal line. 8) Reduce number of uses of time(NULL) ====================================== We use time(NULL) a lot. Since it only has resolution of a second, I'm asking myself, if we could update the actual time in only a few places and get time out of some variables when needed. The same does not hold true for millisecond time, but in several cases we use the time, it's not very critical, that it is exact. These cases are related to: Some of this is already been done, the remaining parts are: - last_access for usage against timeout value that is ~minutes - error_time for usage against retry timeout that is ~minutes - uri_worker_map checked for usage against JK_URIMAP_RELOAD=1 minute So I think, it would suffice to set an actual time at the beginning of the request/response cycle (used by everything before the request is being sent over the socket) and maybe after the response shows up/ an error occurs (for everything else, if there is). For which cases would it be OK, to use the time before sending to TC: - uri_worker_map "checked" (uri map lookup starts early) - setting/testing last_access in - jk_ajp_common.c:ajp_connect_to_endpoint() - jk_ajp_common.c:ajp_get_endpoint() - jk_ajp_common.c:ajp_maintain() What about the others: - setting last_access in init should use the actual time in jk_ajp_common.c:ajp_create_endpoint_cache() - setting last_access again after the service could also use the actual time in jk_ajp_common.c:ajp_done() - setting error_time should better use the actual time jk_lb_worker.c service(): rec->s->error_time = time(NULL); The last two cases could again use the same time, which then would be needed to be generated at the end or directly after service. 9) Access/Modification Time in shm ================================== a) [Discussion] What will this generally be used for? At the moment, only jk_status "uses" it, but it only sets the values, it never asks for them. b) [Improvement, minor] jk_shm_set_workers_time() implicitly calls jk_shm_sync_access_time(), but jk_status does: jk_shm_set_workers_time(time(NULL)); /* Since we updated the config no need to reload * on the next request */ jk_shm_sync_access_time(); two times. So depending on the idea of the functionality of these calls, either set_workers_time and sync_access_time should be independently, or the second call in jk_status coulkd be removed. 10) "Destroy" functionality =========================== [Hint] Destroy on a worker never seems to free shm, but I think that was already a flaw without shm. 11) Locks against shm ===================== It might be an interesting experiment to implement an improved locking structure. It looks like one would need in fact different types of locks. In shm we have as read/write information: Changed only by status worker: - redirect, domain, lb_factor, sticky_session, sticky_session_force, recover_wait_time, retries, status (is_disabled, is_stopped). These changes need some kind of reconfiguration in the threads after change and before the next request/response. Since changes are rare, here we would be better of, with a simple detect change and copy from shm to process procedure. status updates the data in shm and after that the time stamp on the shh. Each process checks the time stamp before doing a request, and when the time stamp changed it does a writer CS lock and updates it's local copy. All threads always do a reader CS lock when doing a request/response cycle. Reader CS locks are concurrent, writers are exclusive. So readers are not allowed, when the config data is being updated. Changed by the threads themselves (and via reset by the status worker): - counters needed by routing decisions (lb_value, readed, transferred, busy) - timers needed by maintenance functions (error_time, servic_time/maintain_time) - status is_busy, in_error_state - uncritical data with no influence on routing decisions (max_busy, elected, errors, in_recovering) Here again we could improve by using reader/writer locks. I have a tendency for the PESSIMISTIC side of locking, but I think we could shrink the code blocks that should be locked. At the monent they are pretty big (most of get_most_suitable_worker). Read-only: name and id. By the way: at several places we don't check for errors on getting the lock. 12) Global locks ================ We might want to make the lock technology choosable, like httpd does. E.g. on Solaris the default lock type if fcntl, and we can easily get an invalid EDEADLOCK for our jk_log_lock. The following pthread based non global locks are used: - one mutex for each AJP worker, synchronizing access to the connection pool, which exists per process - one mutex for each lb worker - a mutex used during dynamic update of uriworkermap.properties to prevent concurrent updates. Updates are done per process. - a mutex to prevent concurrent execution of the process local internal maintenance task - a mutex for access to the shared memory when changing or reading configuration parameters. That might be a little unsafe, because it actually should be a global mutex, not a process local, but those config changes are only done due to interaction with the status worker, so there's very little chance for unwanted concurrency here. All dynamic runtime data are already marked as being volatile. All except the last seem to be safe. The last might need some hybrid model using thread local mostly and process global when doing updates. See also: http://marc.info/?t=123394059800003&r=1&w=2 13) Understand the exact behaviour of shm and restarts ====================================================== Furthermore: rotatelogs (?) and gzip (mod_mime_magic) seem to close the (non-existing) shm file. Maybe a problem on some platforms? 14) What I didn't yet check =========================== a) Correctness of is_busy handling b) Correctness of the reset values after reset by status worker c) What would be the exact behaviour, if shm does not work (memory case). Will this be a critical failure, or will we only experience a degradation in routing decisions. d) How complete is mod_proxy_ajp/mod_proxy_balancer. Port changes from mod_jk to them. 15) Status worker ================= Allow managing pool and connection parameters. Add flags to pool and connections to signal workers and maintenance whether existing connections should be closed and renewed. Check completeness of attribute manageability for AJP workers. Check completeness of runtime data display, e.g. reset_time, recover_time, etc. Maybe also add "last error type". Work on a global display of process local data, e.g. state of the process local connection pools (sizes, num connected/idle). Rework the GUI: - Basic overview start page with links to the workers, maybe a checkbox to decide whether you want to see config data too. - Detail view (what type of error was last and when etc.), detail view for connection pools. 16) URI mapping =============== Add more extensions? 17) Connection Pool =================== How would a good global maximum count look like? Simply limit busyness? Soft limit (applies only to non-sticky requests) and a hard limit (applies to all requests)? 18) IP V6 ========= There's a Bugzilla with a patch. 19) IIS Chunked Encoding ======================== Move from alternative build to default. What about the other ifdef'd features? 20) Add REMORE_PORT as a default JkEnvVar ========================================= ... and port to IIS to fix the getRemotePort() problem. 21) Rework HowTo docs ===================== 22) Add better example config ============================= 23) Remove JNI worker ===================== Done 24) Watchdog reload of uriworkermap.properties ============================================== Questions about uriworkermap.properties watchdog reload (r745898): - shm lock needed? - Apache port (need to iterate over vhosts) 25) Watchdog backend probing ============================ Configurable probe URL to test backend, e.g. to decide about recovery instead of using random real requests. 26) Commandline shm =================== Commandline tool to read data from shm file. 27) Status worker property format ================================= Check whether we return list properties as one line (because Java doesn't allow the same property key multiple times). Applies possibly to: "list", BALANCE_WORKERS, MOUNT_OF_WORKER, USER_OF_WORKER, GOOD_RATING_OF_WORKER, BAD_RATING_OF_WORKER, STATUS_FAIL_OF_WORKER, tomcat-connectors-1.2.50-src/native/apache-2.0/0000755000000000000020000000000014655113617017330 5ustar rootbintomcat-connectors-1.2.50-src/native/apache-2.0/Makefile.in0000644000000000000020000000607014655113617021400 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. srcdir=@srcdir@ top_srcdir=@top_srcdir@ top_builddir=@top_builddir@ APXS=@APXS@ CP=@CP@ APACHE_DIR=@APACHE_DIR@ MKDIR=@MKDIR@ APXSCFLAGS=@APXSCFLAGS@ APXSCPPFLAGS=@APXSCPPFLAGS@ APXSLDFLAGS=@APXSLDFLAGS@ JKLDFLAGS=-export-symbols-regex ^jk_module\$$ CC=@CC@ SHELL=@SHELL@ # Defaults libexecdir=${APACHE_DIR}/modules JK=${top_builddir}/common/ # Defines APACHE_OBJECTS - the list of all common files include ${top_builddir}/common/list.mk # Apache settings, values guessed by Apache config and used to build it # Will define libexecdir, LIBTOOL, etc include @APACHE_CONFIG_VARS@ # Local settings ( overriding/appending to Apache's ) COMMON=common JK_INCL=-DUSE_APACHE_MD5 -I${top_builddir}/${COMMON} -I ${top_srcdir}/${COMMON} CFLAGS=@apache_include@ @CFLAGS@ ${JK_INCL} ${APXSCPPFLAGS} ${APXSCFLAGS} ${EXTRA_CFLAGS} ${EXTRA_CPPFLAGS} # Implicit rules include ${top_srcdir}/scripts/build/rules.mk OEXT=.lo all: Makefile @LIB_JK_TYPE@ install: @INSTALL_TYPE@ Makefile: ${srcdir}/Makefile.in echo Regenerating Makefile ( cd ..; ./config.status ) lib_jk.la: mod_jk.lo ${APACHE_OBJECTS} $(LIBTOOL) --mode=link $(CC) -o lib_jk.la -static -rpath ${libexecdir}/jk mod_jk.lo $(APACHE_OBJECTS) install_static: @echo "" @echo "Copying files to Apache Modules Directory..." -${MKDIR} ${APACHE_DIR}/modules/jk ${CP} config.m4 ${APACHE_DIR}/modules/jk ${LIBTOOL} --mode=install cp lib_jk.la ${APACHE_DIR}/modules/jk @echo "" @echo "Please be sure to re-compile Apache..." @echo "" @echo "cd ${APACHE_DIR}" @echo "./buildconf" @echo "./configure --with-mod_jk" @echo "make" @echo "" #################### Dynamic .so file #################### # APXS will compile every file, this is derived from apxs mod_jk.lo: ${srcdir}/mod_jk.c ${LT_COMPILE} mod_jk.la: mod_jk.lo $(APACHE_OBJECTS) $(LIBTOOL) --mode=link ${COMPILE} $(APXSLDFLAGS) ${JKLDFLAGS} -o $@ -module -rpath ${libexecdir} -avoid-version mod_jk.lo $(APACHE_OBJECTS) mod_jk.so: mod_jk.la ${top_srcdir}/scripts/build/instdso.sh SH_LIBTOOL='$(LIBTOOL)' mod_jk.la `pwd` install_dynamic: @echo "" @echo "Installing files to Apache Modules Directory..." $(APXS) -i mod_jk.la @echo "" @echo "Please be sure to arrange ${APACHE_DIR}/conf/httpd.conf..." @echo "" clean: rm -f *.o *.lo *.a *.la *.so *.so.* *.slo rm -rf .libs maintainer-clean: clean distclean: clean tomcat-connectors-1.2.50-src/native/apache-2.0/mod_jk.c0000644000000000000020000044115314655113617020747 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Apache 2 plugin for Tomcat * * Author: Gal Shachor * * Henri Gomez * ***************************************************************************/ /* * mod_jk: keeps all servlet related ramblings together. */ #include "ap_config.h" #include "apr_lib.h" #include "apr_date.h" #include "apr_file_info.h" #include "apr_file_io.h" #include "httpd.h" #include "http_config.h" #include "http_request.h" #include "http_core.h" #include "http_protocol.h" #include "http_main.h" #include "http_log.h" #include "util_script.h" #include "ap_mpm.h" #if defined(AS400) && !defined(AS400_UTF8) #include "ap_charset.h" #include "util_charset.h" /* ap_hdrs_from_ascii */ #endif /* deprecated with apr 0.9.3 */ #include "apr_version.h" #if (APR_MAJOR_VERSION == 0) && \ (APR_MINOR_VERSION <= 9) && \ (APR_PATCH_VERSION < 3) #define apr_filepath_name_get apr_filename_of_pathname #endif #include "apr_strings.h" /* Yes; sorta sucks - with luck we will clean this up before httpd-2.2 * ships, leaving AP_NEED_SET_MUTEX_PERMS def'd as 1 or 0 on all platforms. */ #ifdef AP_NEED_SET_MUTEX_PERMS # define JK_NEED_SET_MUTEX_PERMS AP_NEED_SET_MUTEX_PERMS #else /* A special case for httpd-2.0 */ # if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(AS400) # define JK_NEED_SET_MUTEX_PERMS 1 # else # define JK_NEED_SET_MUTEX_PERMS 0 # endif #endif #if JK_NEED_SET_MUTEX_PERMS #include "unixd.h" /* for unixd_set_global_mutex_perms */ #endif /* * jk_ include files */ #include "jk_global.h" #include "jk_ajp13.h" #include "jk_logger.h" #include "jk_map.h" #include "jk_pool.h" #include "jk_service.h" #include "jk_uri_worker_map.h" #include "jk_util.h" #include "jk_worker.h" #include "jk_shm.h" #include "jk_url.h" #define JK_LOG_DEF_FILE ("logs/mod_jk.log") #define JK_SHM_DEF_FILE ("logs/jk-runtime-status") #define JK_ENV_REQUEST_ID ("UNIQUE_ID") #define JK_ENV_REMOTE_ADDR ("JK_REMOTE_ADDR") #define JK_ENV_REMOTE_PORT ("JK_REMOTE_PORT") #define JK_ENV_REMOTE_HOST ("JK_REMOTE_HOST") #define JK_ENV_REMOTE_USER ("JK_REMOTE_USER") #define JK_ENV_AUTH_TYPE ("JK_AUTH_TYPE") #define JK_ENV_LOCAL_NAME ("JK_LOCAL_NAME") #define JK_ENV_LOCAL_ADDR ("JK_LOCAL_ADDR") #define JK_ENV_LOCAL_PORT ("JK_LOCAL_PORT") #define JK_ENV_IGNORE_CL ("JK_IGNORE_CL") #define JK_ENV_HTTPS ("HTTPS") #define JK_ENV_SSL_PROTOCOL ("SSL_PROTOCOL") #define JK_ENV_CERTS ("SSL_CLIENT_CERT") #define JK_ENV_CIPHER ("SSL_CIPHER") #define JK_ENV_SESSION ("SSL_SESSION_ID") #define JK_ENV_KEY_SIZE ("SSL_CIPHER_USEKEYSIZE") #define JK_ENV_CERTCHAIN_PREFIX ("SSL_CLIENT_CERT_CHAIN_") #define JK_ENV_REPLY_TIMEOUT ("JK_REPLY_TIMEOUT") #define JK_ENV_STICKY_IGNORE ("JK_STICKY_IGNORE") #define JK_ENV_STATELESS ("JK_STATELESS") #define JK_ENV_ROUTE ("JK_ROUTE") #define JK_ENV_WORKER_NAME ("JK_WORKER_NAME") #define JK_NOTE_WORKER_NAME ("JK_WORKER_NAME") #define JK_NOTE_WORKER_TYPE ("JK_WORKER_TYPE") #define JK_NOTE_REQUEST_DURATION ("JK_REQUEST_DURATION") #define JK_NOTE_WORKER_ROUTE ("JK_WORKER_ROUTE") #define JK_HANDLER ("jakarta-servlet") #define JK_MAGIC_TYPE ("application/x-jakarta-servlet") #define NULL_FOR_EMPTY(x) ((x && !strlen(x)) ? NULL : x) #define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)") #define JK_LOG_LOCK_KEY ("jk_log_lock_key") #define JKLOG_MARK __FILE__,__LINE__ /* * If you are not using SSL, comment out the following line. It will make * apache run faster. * * Personally, I (DM), think this may be a lie. */ #define ADD_SSL_INFO /* Needed for Apache 2.3/2.4 per-module log config */ #ifdef APLOG_USE_MODULE APLOG_USE_MODULE(jk); #endif /* module MODULE_VAR_EXPORT jk_module; */ AP_MODULE_DECLARE_DATA module jk_module; /* * Environment variable forward object */ typedef struct { int has_default; char *name; char *value; } envvar_item; /* * Configuration object for the mod_jk module. */ typedef struct { /* * Log stuff */ char *log_file; int log_level; jk_logger_t *log; /* * Mount stuff */ char *mount_file; int mount_file_reload; jk_map_t *uri_to_context; int mountcopy; jk_uri_worker_map_t *uw_map; int was_initialized; /* * Automatic context path apache alias */ char *alias_dir; /* * Request Logging */ char *stamp_format_string; char *format_string; apr_array_header_t *format; /* * Setting target worker via environment */ char *worker_indicator; /* * Configurable environment variables to overwrite * request information using meta data send by a * proxy in front of us. */ char *request_id_indicator; char *remote_addr_indicator; char *remote_port_indicator; char *remote_host_indicator; char *remote_user_indicator; char *auth_type_indicator; char *local_name_indicator; char *local_addr_indicator; char *local_port_indicator; /* * Configurable environment variable to force * ignoring a request Content-Length header * (useful to make mod_deflate request inflation * compatible with mod_jk). */ char *ignore_cl_indicator; /* * SSL Support */ int ssl_enable; char *https_indicator; char *ssl_protocol_indicator; char *certs_indicator; char *cipher_indicator; char *session_indicator; /* Servlet API 2.3 requirement */ char *key_size_indicator; /* Servlet API 2.3 requirement */ char *certchain_prefix; /* Client certificate chain prefix */ /* * Jk Options */ int options; int exclude_options; int strip_session; char *strip_session_name; /* * Environment variables support */ int envvars_has_own; apr_table_t *envvars; apr_table_t *envvars_def; apr_array_header_t *envvar_items; server_rec *s; } jk_server_conf_t; /* * Request specific configuration */ struct jk_request_conf { rule_extension_t *rule_extensions; char *orig_uri; const char *request_id; int jk_handled; }; typedef struct jk_request_conf jk_request_conf_t; struct apache_private_data { jk_pool_t p; int read_body_started; request_rec *r; }; typedef struct apache_private_data apache_private_data_t; static server_rec *main_server = NULL; static jk_logger_t *main_log = NULL; static apr_hash_t *jk_log_fps = NULL; static jk_worker_env_t worker_env; static apr_global_mutex_t *jk_log_lock = NULL; static char *jk_shm_file = NULL; static int jk_shm_size = 0; static int jk_shm_size_set = 0; static volatile int jk_watchdog_interval = 0; static volatile int jk_watchdog_running = 0; /* * Worker stuff */ static jk_map_t *jk_worker_properties = NULL; static char *jk_worker_file = NULL; static int jk_mount_copy_all = JK_FALSE; static int JK_METHOD ws_start_response(jk_ws_service_t *s, int status, const char *reason, const char *const *header_names, const char *const *header_values, unsigned num_of_headers); static int JK_METHOD ws_read(jk_ws_service_t *s, void *b, unsigned len, unsigned *actually_read); static int init_jk(apr_pool_t * pconf, jk_server_conf_t * conf, server_rec * s); static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned l); static void JK_METHOD ws_add_log_items(jk_ws_service_t *s, const char *const *log_names, const char *const *log_values, unsigned num_of_log_items); static void * JK_METHOD ws_next_vhost(void *d); static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len); static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d); /* ========================================================================= */ /* JK Service step callbacks */ /* ========================================================================= */ static int JK_METHOD ws_start_response(jk_ws_service_t *s, int status, const char *reason, const char *const *header_names, const char *const *header_values, unsigned num_of_headers) { unsigned h; apache_private_data_t *p = s->ws_private; request_rec *r = p->r; jk_log_context_t *l = s->log_ctx; /* If we use proxy error pages, still pass * through context headers needed for special status codes. */ if (s->extension.use_server_error_pages && status >= s->extension.use_server_error_pages) { if (status == HTTP_UNAUTHORIZED) { int found = JK_FALSE; for (h = 0; h < num_of_headers; h++) { if (!strcasecmp(header_names[h], "WWW-Authenticate")) { char *tmp = apr_pstrdup(r->pool, header_values[h]); apr_table_set(r->err_headers_out, "WWW-Authenticate", tmp); found = JK_TRUE; } } if (found == JK_FALSE) { jk_log(l, JK_LOG_INFO, "origin server sent 401 without" " WWW-Authenticate header"); } } return JK_TRUE; } /* If there is no reason given (or an empty one), * we'll try to guess a good one. */ if (!reason || *reason == '\0') { /* We ask Apache httpd about a good reason phrase. */ reason = ap_get_status_line(status); /* Unfortunately it returns with a 500 reason phrase, * whenever it does not know about the given status code, * e.g. in the case of custom status codes. */ if (status != 500 && !strncmp(reason, "500 ", 4)) { reason = "Unknown Reason"; } else { /* Apache httpd returns a full status line, * but we only want a reason phrase, so skip * the prepended status code. */ reason = reason + 4; } } r->status = status; r->status_line = apr_psprintf(r->pool, "%d %s", status, reason); for (h = 0; h < num_of_headers; h++) { if (!strcasecmp(header_names[h], "Content-type")) { char *tmp = apr_pstrdup(r->pool, header_values[h]); ap_content_type_tolower(tmp); /* It should be done like this in Apache 2.0 */ /* This way, Apache 2.0 will be able to set the output filter */ /* and it make jk usable with deflate using */ /* AddOutputFilterByType DEFLATE text/html */ ap_set_content_type(r, tmp); } else if (!strcasecmp(header_names[h], "Location")) { #if defined(AS400) && !defined(AS400_UTF8) /* Fix escapes in Location Header URL */ ap_fixup_escapes((char *)header_values[h], strlen(header_values[h]), ap_hdrs_from_ascii); #endif apr_table_set(r->headers_out, header_names[h], header_values[h]); } else if (!strcasecmp(header_names[h], "Content-Length")) { ap_set_content_length(r, apr_atoi64(header_values[h])); } else if (!strcasecmp(header_names[h], "Transfer-Encoding")) { apr_table_set(r->headers_out, header_names[h], header_values[h]); } else if (!strcasecmp(header_names[h], "Last-Modified")) { /* * If the script gave us a Last-Modified header, we can't just * pass it on blindly because of restrictions on future values. */ ap_update_mtime(r, apr_date_parse_http(header_values[h])); ap_set_last_modified(r); } else { apr_table_add(r->headers_out, header_names[h], header_values[h]); } } /* this NOP function was removed in apache 2.0 alpha14 */ /* ap_send_http_header(r); */ s->response_started = JK_TRUE; return JK_TRUE; } /* * Read a chunk of the request body into a buffer. Attempt to read len * bytes into the buffer. Write the number of bytes actually read into * actually_read. * * Think of this function as a method of the apache1.3-specific subclass of * the jk_ws_service class. Think of the *s param as a "this" or "self" * pointer. */ static int JK_METHOD ws_read(jk_ws_service_t *s, void *b, unsigned len, unsigned *actually_read) { if (s && s->ws_private && b && actually_read) { apache_private_data_t *p = s->ws_private; if (!p->read_body_started) { if (ap_should_client_block(p->r)) { p->read_body_started = JK_TRUE; } } if (p->read_body_started) { #if defined(AS400) && !defined(AS400_UTF8) int long rv = OK; if (rv = ap_change_request_body_xlate(p->r, 65535, 65535)) { /* turn off request body translation */ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0, NULL, "mod_jk: Error on ap_change_request_body_xlate, rc=%d", rv); return JK_FALSE; } #else long rv; #endif if ((rv = ap_get_client_block(p->r, b, len)) < 0) { return JK_FALSE; } else { *actually_read = (unsigned)rv; } return JK_TRUE; } } return JK_FALSE; } static void JK_METHOD ws_flush(jk_ws_service_t *s) { #if ! (defined(AS400) && !defined(AS400_UTF8)) if (s && s->ws_private) { apache_private_data_t *p = s->ws_private; ap_rflush(p->r); } #endif } static void JK_METHOD ws_done(jk_ws_service_t *s) { #if ! (defined(AS400) && !defined(AS400_UTF8)) if (s && s->ws_private) { apache_private_data_t *p = s->ws_private; ap_finalize_request_protocol(p->r); } #endif } /* * Write a chunk of response data back to the browser. If the headers * haven't yet been sent over, send over default header values (Status = * 200, basically). * * Write len bytes from buffer b. * * Think of this function as a method of the apache1.3-specific subclass of * the jk_ws_service class. Think of the *s param as a "this" or "self" * pointer. */ static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned int l) { #if defined(AS400) && !defined(AS400_UTF8) int rc; #endif jk_log_context_t *log_ctx = s->log_ctx; if (s && s->ws_private && b) { apache_private_data_t *p = s->ws_private; if (l) { /* BUFF *bf = p->r->connection->client; */ int r = 0; int ll = l; const char *bb = (const char *)b; if (!s->response_started) { jk_log(log_ctx, JK_LOG_INFO, "Write without start, starting with defaults"); if (!s->start_response(s, 200, NULL, NULL, NULL, 0)) { return JK_FALSE; } } if (p->r->header_only) { #if ! (defined(AS400) && !defined(AS400_UTF8)) ap_rflush(p->r); #endif return JK_TRUE; } #if defined(AS400) && !defined(AS400_UTF8) /* turn off response body translation */ rc = ap_change_response_body_xlate(p->r, 65535, 65535); if (rc) { ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0, NULL, "mod_jk: Error on ap_change_response_body_xlate, rc=%d", rc); return JK_FALSE; } #endif while (ll > 0 && !p->r->connection->aborted) { r = ap_rwrite(bb, ll, p->r); if (JK_IS_DEBUG_LEVEL(log_ctx)) jk_log(log_ctx, JK_LOG_DEBUG, "written %d out of %d", r, ll); if (r < 0) return JK_FALSE; ll -= r; bb += r; } if (ll && p->r->connection->aborted) { /* Fail if there is something left to send and * the connection was aborted by the client */ return JK_FALSE; } } return JK_TRUE; } return JK_FALSE; } static void JK_METHOD ws_add_log_items(jk_ws_service_t *s, const char *const *log_names, const char *const *log_values, unsigned num_of_log_items) { unsigned h; apache_private_data_t *p = s->ws_private; request_rec *r = p->r; for (h = 0; h < num_of_log_items; h++) { if (log_names[h] && log_values[h]) { apr_table_set(r->notes, log_names[h], log_values[h]); } } } static void * JK_METHOD ws_next_vhost(void *d) { server_rec *s = (server_rec *)d; if (s == NULL) return main_server; return s->next; } static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len) { server_rec *s = (server_rec *)d; size_t used = 0; if (s->server_hostname) { used += strlen(s->server_hostname); } if (!s->is_virtual) { if (s->port) used += strlen(":XXXXX"); } else if (s->addrs) { used += strlen(" ["); if (s->addrs->virthost) used += strlen(s->addrs->virthost); if (s->addrs->host_port) used += strlen(":XXXXX"); used += strlen("]"); } if (len < used && len > strlen("XXX")) { strcpy(buf, "XXX"); return; } used = 0; if (s->server_hostname) { strcpy(buf + used, s->server_hostname); used += strlen(s->server_hostname); } if (!s->is_virtual) { if (s->port) { sprintf(buf + used, ":%hu", s->port); used = strlen(buf); } } else if (s->addrs) { strcpy(buf + used, " ["); used += strlen(" ["); if (s->addrs->virthost) { strcpy(buf + used, s->addrs->virthost); used += strlen(s->addrs->virthost); } if (s->addrs->host_port) { sprintf(buf + used, ":%hu", s->addrs->host_port); used = strlen(buf); } strcpy(buf + used, "]"); used += strlen("]"); } } static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d) { server_rec *s = (server_rec *)d; jk_server_conf_t *conf = NULL; if (s == NULL) return NULL; conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); return conf->uw_map; } /* ========================================================================= */ /* Utility functions */ /* ========================================================================= */ static void dump_options(server_rec *srv, apr_pool_t *p) { char server_name[80]; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; jk_server_conf_t *conf = (jk_server_conf_t *)ap_get_module_config(srv->module_config, &jk_module); int options = conf->options; l->logger = conf->log; l->id = "CONFIG"; ws_vhost_to_text(srv, server_name, 80); if (options & JK_OPT_FWDURICOMPAT) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "ForwardURICompat", server_name, JK_OPT_DEFAULT & JK_OPT_FWDURICOMPAT ? " (default)" : ""); if (options & JK_OPT_FWDURICOMPATUNPARSED) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "ForwardURICompatUnparsed", server_name, JK_OPT_DEFAULT & JK_OPT_FWDURICOMPATUNPARSED ? " (default)" : ""); if (options & JK_OPT_FWDURIESCAPED) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "ForwardURIEscaped", server_name, JK_OPT_DEFAULT & JK_OPT_FWDURIESCAPED ? " (default)" : ""); if (options & JK_OPT_FWDURIPROXY) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "ForwardURIProxy", server_name, JK_OPT_DEFAULT & JK_OPT_FWDURIPROXY ? " (default)" : ""); if (options & JK_OPT_FWDDIRS) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "ForwardDirectories", server_name, JK_OPT_DEFAULT & JK_OPT_FWDDIRS ? " (default)" : ""); if (options & JK_OPT_FWDLOCAL) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "ForwardLocalAddress", server_name, JK_OPT_DEFAULT & JK_OPT_FWDLOCAL ? " (default)" : ""); if (options & JK_OPT_FWDPHYSICAL) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "ForwardPhysicalAddress", server_name, JK_OPT_DEFAULT & JK_OPT_FWDPHYSICAL ? " (default)" : ""); if (options & JK_OPT_FWDCERTCHAIN) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "ForwardSSLCertChain", server_name, JK_OPT_DEFAULT & JK_OPT_FWDCERTCHAIN ? " (default)" : ""); if (options & JK_OPT_FWDKEYSIZE) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "ForwardKeySize", server_name, JK_OPT_DEFAULT & JK_OPT_FWDKEYSIZE ? " (default)" : ""); if (options & JK_OPT_FLUSHPACKETS) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "FlushPackets", server_name, JK_OPT_DEFAULT & JK_OPT_FLUSHPACKETS ? " (default)" : ""); if (options & JK_OPT_FLUSHEADER) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "FlushHeader", server_name, JK_OPT_DEFAULT & JK_OPT_FLUSHEADER ? " (default)" : ""); if (options & JK_OPT_DISABLEREUSE) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "DisableReuse", server_name, JK_OPT_DEFAULT & JK_OPT_DISABLEREUSE ? " (default)" : ""); if (options & JK_OPT_REJECTUNSAFE) jk_log(l, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s", "RejectUnsafeURI", server_name, JK_OPT_DEFAULT & JK_OPT_REJECTUNSAFE ? " (default)" : ""); } /* ========================================================================= */ /* Log something to Jk log file then exit */ static void jk_error_exit(const char *file, int line, int level, const server_rec * s, apr_pool_t * p, const char *fmt, ...) { va_list ap; char *res; char *ch; va_start(ap, fmt); res = apr_pvsprintf(s->process->pool, fmt, ap); va_end(ap); /* Replace all format characters in the resulting message */ /* because we feed the message to ap_log_error(). */ ch = res; while (*ch) { if (*ch == '%') { *ch = '#'; } ch++; } #if (MODULE_MAGIC_NUMBER_MAJOR >= 20100606) ap_log_error(file, line, APLOG_MODULE_INDEX, level, 0, s, "%s", res); #else ap_log_error(file, line, level, 0, s, "%s", res); #endif if (s) { #if (MODULE_MAGIC_NUMBER_MAJOR >= 20100606) ap_log_error(file, line, APLOG_MODULE_INDEX, level, 0, NULL, "%s", res); #else ap_log_error(file, line, level, 0, NULL, "%s", res); #endif } /* Exit process */ exit(1); } static jk_uint64_t get_content_length(request_rec * r) { if (r->main == NULL || r->main == r) { char *lenp = (char *)apr_table_get(r->headers_in, "Content-Length"); if (lenp) { jk_uint64_t rc = 0; if (sscanf(lenp, "%" JK_UINT64_T_FMT, &rc) > 0 && rc > 0) { return rc; } } } return 0; } /* Retrieve string value from env var, use default if env var does not exist. */ static const char *get_env_string(request_rec *r, const char *def, char *env, int null_for_empty) { char *value = (char *)apr_table_get(r->subprocess_env, env); if (value) return null_for_empty ? NULL_FOR_EMPTY(value) : value; return null_for_empty ? NULL_FOR_EMPTY(def) : def; } /* Retrieve integer value from env var, use default if env var does not exist. */ static int get_env_int(request_rec *r, int def, char *env) { char *value = (char *)apr_table_get(r->subprocess_env, env); if (value) return atoi(value); return def; } static int init_ws_service(apache_private_data_t * private_data, jk_ws_service_t *s, jk_server_conf_t * conf) { int size; request_rec *r = private_data->r; char *ssl_temp = NULL; char *uri = NULL; const char *reply_timeout = NULL; const char *sticky_ignore = NULL; const char *stateless = NULL; const char *route = NULL; rule_extension_t *e; jk_request_conf_t *rconf; jk_log_context_t *l = apr_pcalloc(r->pool, sizeof(jk_log_context_t)); l->logger = conf->log; l->id = NULL; /* Copy in function pointers (which are really methods) */ s->start_response = ws_start_response; s->read = ws_read; s->write = ws_write; s->flush = ws_flush; s->done = ws_done; s->add_log_items = ws_add_log_items; s->next_vhost = ws_next_vhost; s->vhost_to_text = ws_vhost_to_text; s->vhost_to_uw_map = ws_vhost_to_uw_map; rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module); l->id = rconf->request_id; s->auth_type = get_env_string(r, r->ap_auth_type, conf->auth_type_indicator, 1); s->remote_user = get_env_string(r, r->user, conf->remote_user_indicator, 1); s->log_ctx = l; s->protocol = r->protocol; s->remote_host = (char *)ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_HOST, NULL); s->remote_host = get_env_string(r, s->remote_host, conf->remote_host_indicator, 1); if (conf->options & JK_OPT_FWDLOCAL) { s->remote_addr = r->connection->local_ip; /* We don't know the client port of the backend connection. */ s->remote_port = "0"; } else { #if (MODULE_MAGIC_NUMBER_MAJOR >= 20111130) if (conf->options & JK_OPT_FWDPHYSICAL) { s->remote_addr = r->connection->client_ip; s->remote_port = apr_itoa(r->pool, r->connection->client_addr->port); } else { s->remote_addr = r->useragent_ip; s->remote_port = apr_itoa(r->pool, r->useragent_addr->port); } #else s->remote_addr = r->connection->remote_ip; s->remote_port = apr_itoa(r->pool, r->connection->remote_addr->port); #endif } s->remote_addr = get_env_string(r, s->remote_addr, conf->remote_addr_indicator, 1); s->remote_port = get_env_string(r, s->remote_port, conf->remote_port_indicator, 1); if (conf->options & JK_OPT_FLUSHPACKETS) s->flush_packets = 1; if (conf->options & JK_OPT_FLUSHEADER) s->flush_header = 1; e = rconf->rule_extensions; if (e) { s->extension.reply_timeout = e->reply_timeout; s->extension.sticky_ignore = e->sticky_ignore; s->extension.stateless = e->stateless; s->extension.use_server_error_pages = e->use_server_error_pages; if (e->activation) { s->extension.activation = apr_palloc(r->pool, e->activation_size * sizeof(int)); memcpy(s->extension.activation, e->activation, e->activation_size * sizeof(int)); } if (e->fail_on_status_size > 0) { s->extension.fail_on_status_size = e->fail_on_status_size; s->extension.fail_on_status = apr_palloc(r->pool, e->fail_on_status_size * sizeof(int)); memcpy(s->extension.fail_on_status, e->fail_on_status, e->fail_on_status_size * sizeof(int)); } if (e->session_cookie) { s->extension.session_cookie = apr_pstrdup(r->pool, e->session_cookie); } if (e->session_path) { s->extension.session_path = apr_pstrdup(r->pool, e->session_path); } if (e->set_session_cookie) { s->extension.set_session_cookie = e->set_session_cookie; } if (e->session_cookie_path) { s->extension.session_cookie_path = apr_pstrdup(r->pool, e->session_cookie_path); } } reply_timeout = apr_table_get(r->subprocess_env, JK_ENV_REPLY_TIMEOUT); if (reply_timeout) { int r = atoi(reply_timeout); if (r >= 0) s->extension.reply_timeout = r; } sticky_ignore = apr_table_get(r->subprocess_env, JK_ENV_STICKY_IGNORE); if (sticky_ignore) { if (*sticky_ignore == '\0') { s->extension.sticky_ignore = JK_TRUE; } else { int r = atoi(sticky_ignore); if (r) { s->extension.sticky_ignore = JK_TRUE; } else { s->extension.sticky_ignore = JK_FALSE; } } } stateless = apr_table_get(r->subprocess_env, JK_ENV_STATELESS); if (stateless) { if (*stateless == '\0') { s->extension.stateless = JK_TRUE; } else { int r = atoi(stateless); if (r) { s->extension.stateless = JK_TRUE; } else { s->extension.stateless = JK_FALSE; } } } if (conf->options & JK_OPT_DISABLEREUSE) s->disable_reuse = 1; /* get route if known */ route = apr_table_get(r->subprocess_env, JK_ENV_ROUTE); if (route && *route) { s->route = route; } /* get server name */ s->server_name = get_env_string(r, (char *)ap_get_server_name(r), conf->local_name_indicator, 0); /* get the local IP address */ s->local_addr = get_env_string(r, r->connection->local_ip, conf->local_addr_indicator, 0); /* get the real port (otherwise redirect failed) */ /* XXX: use apache API for getting server port * * Pre 1.2.7 versions used: * s->server_port = r->connection->local_addr->port; */ s->server_port = get_env_int(r, ap_get_server_port(r), conf->local_port_indicator); #if ((AP_MODULE_MAGIC_AT_LEAST(20051115,4)) && !defined(API_COMPATIBILITY)) || (MODULE_MAGIC_NUMBER_MAJOR >= 20060905) s->server_software = (char *)ap_get_server_description(); #else s->server_software = (char *)ap_get_server_version(); #endif s->method = (char *)r->method; s->content_length = get_content_length(r); s->is_chunked = r->read_chunked; if (s->content_length > 0 && get_env_string(r, NULL, conf->ignore_cl_indicator, 0) != NULL) { s->content_length = 0; s->is_chunked = 1; } s->no_more_chunks = 0; #if defined(AS400) && !defined(AS400_UTF8) /* Get the query string that is not translated to EBCDIC */ s->query_string = ap_get_original_query_string(r); #else s->query_string = r->args; #endif /* * The 2.2 servlet spec errata says the uri from * HttpServletRequest.getRequestURI() should remain encoded. * [http://java.sun.com/products/servlet/errata_042700.html] * * We use JkOptions to determine which method to be used * * ap_escape_uri is the latest recommended but require * some java decoding (in TC 3.3 rc2) * * unparsed_uri is used for strict compliance with spec and * old Tomcat (3.2.3 for example) * * uri is use for compatibility with mod_rewrite with old Tomcats */ uri = rconf->orig_uri ? rconf->orig_uri : r->uri; switch (conf->options & JK_OPT_FWDURIMASK) { case JK_OPT_FWDURICOMPATUNPARSED: s->req_uri = r->unparsed_uri; if (s->req_uri != NULL) { char *query_str = strchr(s->req_uri, '?'); if (query_str != NULL) { *query_str = 0; } } break; case JK_OPT_FWDURICOMPAT: s->req_uri = uri; break; case JK_OPT_FWDURIPROXY: size = 3 * (int)strlen(uri) + 1; s->req_uri = apr_palloc(r->pool, size); jk_canonenc(uri, s->req_uri, size); break; case JK_OPT_FWDURIESCAPED: s->req_uri = ap_escape_uri(r->pool, uri); break; default: return JK_FALSE; } if (conf->ssl_enable || conf->envvars) { ap_add_common_vars(r); if (conf->ssl_enable) { ssl_temp = (char *)apr_table_get(r->subprocess_env, conf->https_indicator); if (ssl_temp && !strcasecmp(ssl_temp, "on")) { s->is_ssl = JK_TRUE; s->ssl_cert = (char *)apr_table_get(r->subprocess_env, conf->certs_indicator); if (conf->options & JK_OPT_FWDCERTCHAIN) { const apr_array_header_t *t = apr_table_elts(r->subprocess_env); if (t && t->nelts) { int i; const apr_table_entry_t *elts = (const apr_table_entry_t *) t->elts; apr_array_header_t *certs = apr_array_make(r->pool, 1, sizeof(char *)); *(const char **)apr_array_push(certs) = s->ssl_cert; for (i = 0; i < t->nelts; i++) { if (!elts[i].key) continue; if (!strncasecmp(elts[i].key, conf->certchain_prefix, strlen(conf->certchain_prefix))) *(const char **)apr_array_push(certs) = elts[i].val; } s->ssl_cert = apr_array_pstrcat(r->pool, certs, '\0'); } } if (s->ssl_cert) { s->ssl_cert_len = (unsigned int)strlen(s->ssl_cert); if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "SSL client certificate (%d bytes): %s", s->ssl_cert_len, s->ssl_cert); } } s->ssl_protocol = (char *)apr_table_get(r->subprocess_env, conf->ssl_protocol_indicator); /* Servlet 2.3 API */ s->ssl_cipher = (char *)apr_table_get(r->subprocess_env, conf->cipher_indicator); s->ssl_session = (char *)apr_table_get(r->subprocess_env, conf->session_indicator); if (conf->options & JK_OPT_FWDKEYSIZE) { /* Servlet 2.3 API */ ssl_temp = (char *)apr_table_get(r->subprocess_env, conf-> key_size_indicator); if (ssl_temp) s->ssl_key_size = atoi(ssl_temp); } } } if (conf->envvars) { const apr_array_header_t *t = conf->envvar_items; if (t && t->nelts) { int i; int j = 0; envvar_item *elts = (envvar_item *) t->elts; s->attributes_names = apr_palloc(r->pool, sizeof(char *) * t->nelts); s->attributes_values = apr_palloc(r->pool, sizeof(char *) * t->nelts); for (i = 0; i < t->nelts; i++) { s->attributes_names[i - j] = elts[i].name; s->attributes_values[i - j] = (char *)apr_table_get(r->subprocess_env, elts[i].name); if (!s->attributes_values[i - j]) { if (elts[i].has_default) { s->attributes_values[i - j] = elts[i].value; } else { s->attributes_values[i - j] = ""; s->attributes_names[i - j] = ""; j++; } } } s->num_attributes = t->nelts - j; } } } if (r->headers_in && apr_table_elts(r->headers_in)) { int need_content_length_header = (!s->is_chunked && s->content_length == 0) ? JK_TRUE : JK_FALSE; const apr_array_header_t *t = apr_table_elts(r->headers_in); if (t && t->nelts) { int i; int off = 0; apr_table_entry_t *elts = (apr_table_entry_t *) t->elts; s->num_headers = t->nelts; /* allocate an extra header slot in case we need to add a content-length header */ s->headers_names = apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1)); s->headers_values = apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1)); if (!s->headers_names || !s->headers_values) return JK_FALSE; for (i = 0; i < t->nelts; i++) { char *hname = apr_pstrdup(r->pool, elts[i].key); if (!strcasecmp(hname, "content-length")) { if (need_content_length_header) { need_content_length_header = JK_FALSE; } else if (s->is_chunked) { s->num_headers--; off++; continue; } } s->headers_values[i - off] = apr_pstrdup(r->pool, elts[i].val); s->headers_names[i - off] = hname; } /* Add a content-length = 0 header if needed. * Ajp13 assumes an absent content-length header means an unknown, * but non-zero length body. */ if (need_content_length_header) { s->headers_names[s->num_headers] = "content-length"; s->headers_values[s->num_headers] = "0"; s->num_headers++; } } /* Add a content-length = 0 header if needed. */ else if (need_content_length_header) { s->headers_names = apr_palloc(r->pool, sizeof(char *)); s->headers_values = apr_palloc(r->pool, sizeof(char *)); if (!s->headers_names || !s->headers_values) return JK_FALSE; s->headers_names[0] = "content-length"; s->headers_values[0] = "0"; s->num_headers++; } } s->uw_map = conf->uw_map; /* Dump all connection param so we can trace what's going to * the remote tomcat */ if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Service protocol=%s method=%s ssl=%s host=%s addr=%s name=%s port=%d auth=%s user=%s laddr=%s raddr=%s uaddr=%s uri=%s", STRNULL_FOR_NULL(s->protocol), STRNULL_FOR_NULL(s->method), s->is_ssl ? "true" : "false", STRNULL_FOR_NULL(s->remote_host), STRNULL_FOR_NULL(s->remote_addr), STRNULL_FOR_NULL(s->server_name), s->server_port, STRNULL_FOR_NULL(s->auth_type), STRNULL_FOR_NULL(s->remote_user), STRNULL_FOR_NULL(r->connection->local_ip), #if (MODULE_MAGIC_NUMBER_MAJOR >= 20111130) STRNULL_FOR_NULL(r->connection->client_ip), STRNULL_FOR_NULL(r->useragent_ip), #else STRNULL_FOR_NULL(r->connection->remote_ip), STRNULL_FOR_NULL(r->connection->remote_ip), #endif STRNULL_FOR_NULL(s->req_uri)); } return JK_TRUE; } /* * The JK module command processors * * The below are all installed so that Apache calls them while it is * processing its config files. This allows configuration info to be * copied into a jk_server_conf_t object, which is then used for request * filtering/processing. * * See jk_cmds definition below for explanations of these options. */ /* * JkMountCopy directive handling * * JkMountCopy On/Off/All */ static const char *jk_set_mountcopy(cmd_parms * cmd, void *dummy, const char *mount_copy) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); if (! strcasecmp(mount_copy, "all")) { const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err_string != NULL) { return err_string; } jk_mount_copy_all = JK_TRUE; } else if (strcasecmp(mount_copy, "on") && strcasecmp(mount_copy, "off")) { return "JkMountCopy must be All, On or Off"; } else { conf->mountcopy = strcasecmp(mount_copy, "off") ? JK_TRUE : JK_FALSE; } return NULL; } /* * JkMount directive handling * * JkMount URI(context) worker */ static const char *jk_mount_context(cmd_parms * cmd, void *dummy, const char *context, const char *worker) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); const char *c, *w; if (worker != NULL && cmd->path == NULL) { c = context; w = worker; } else if (worker == NULL && cmd->path != NULL) { c = cmd->path; w = context; } else { if (worker == NULL) return "JkMount needs a path when not defined in a location"; else return "JkMount can not have a path when defined in a location"; } if (c[0] != '/') return "JkMount context should start with /"; if (!conf->uri_to_context) { if (!jk_map_alloc(&(conf->uri_to_context))) { return "JkMount Memory error"; } } /* * Add the new worker to the alias map. */ jk_map_put(conf->uri_to_context, c, w, NULL); return NULL; } /* * JkUnMount directive handling * * JkUnMount URI(context) worker */ static const char *jk_unmount_context(cmd_parms * cmd, void *dummy, const char *context, const char *worker) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); char *uri; const char *c, *w; if (worker != NULL && cmd->path == NULL) { c = context; w = worker; } else if (worker == NULL && cmd->path != NULL) { c = cmd->path; w = context; } else { if (worker == NULL) return "JkUnMount needs a path when not defined in a location"; else return "JkUnMount can not have a path when defined in a location"; } if (c[0] != '/') return "JkUnMount context should start with /"; uri = apr_pstrcat(cmd->temp_pool, "!", c, NULL); if (!conf->uri_to_context) { if (!jk_map_alloc(&(conf->uri_to_context))) { return "JkUnMount Memory error"; } } /* * Add the new worker to the alias map. */ jk_map_put(conf->uri_to_context, uri, w, NULL); return NULL; } /* * JkWorkersFile Directive Handling * * JkWorkersFile file */ static const char *jk_set_worker_file(cmd_parms * cmd, void *dummy, const char *worker_file) { const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err_string != NULL) { return err_string; } if (jk_worker_file != NULL) return "JkWorkersFile only allowed once"; /* we need an absolute path (ap_server_root_relative does the ap_pstrdup) */ jk_worker_file = ap_server_root_relative(cmd->pool, worker_file); if (jk_worker_file == NULL) return "JkWorkersFile file name invalid"; if (jk_file_exists(jk_worker_file) != JK_TRUE) return "JkWorkersFile: Can't find the workers file specified"; return NULL; } /* * JkMountFile Directive Handling * * JkMountFile file */ static const char *jk_set_mount_file(cmd_parms * cmd, void *dummy, const char *mount_file) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); /* we need an absolute path (ap_server_root_relative does the ap_pstrdup) */ conf->mount_file = ap_server_root_relative(cmd->pool, mount_file); if (conf->mount_file == NULL) return "JkMountFile file name invalid"; if (jk_file_exists(conf->mount_file) != JK_TRUE) return "JkMountFile: Can't find the mount file specified"; if (!conf->uri_to_context) { if (!jk_map_alloc(&(conf->uri_to_context))) { return "JkMountFile Memory error"; } } return NULL; } /* * JkMountFileReload Directive Handling * * JkMountFileReload seconds */ static const char *jk_set_mount_file_reload(cmd_parms * cmd, void *dummy, const char *mount_file_reload) { server_rec *s = cmd->server; int interval; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); interval = atoi(mount_file_reload); if (interval < 0) { interval = 0; } conf->mount_file_reload = interval; return NULL; } /* * JkWatchdogInterval Directive Handling * * JkWatchdogInterval seconds */ static const char *jk_set_watchdog_interval(cmd_parms * cmd, void *dummy, const char *watchdog_interval) { const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err_string != NULL) { return err_string; } #if APR_HAS_THREADS jk_watchdog_interval = atoi(watchdog_interval); if (jk_watchdog_interval < 0) { jk_watchdog_interval = 0; } return NULL; #else return "JkWatchdogInterval: APR was compiled without threading support. Cannot create watchdog thread"; #endif } /* * JkLogFile Directive Handling * * JkLogFile file */ static const char *jk_set_log_file(cmd_parms * cmd, void *dummy, const char *log_file) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); /* we need an absolute path */ if (*log_file != '|') conf->log_file = ap_server_root_relative(cmd->pool, log_file); else conf->log_file = apr_pstrdup(cmd->pool, log_file); if (conf->log_file == NULL) return "JkLogFile file name invalid"; return NULL; } /* * JkShmFile Directive Handling * * JkShmFile file */ static const char *jk_set_shm_file(cmd_parms * cmd, void *dummy, const char *shm_file) { const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err_string != NULL) { return err_string; } /* we need an absolute path */ jk_shm_file = ap_server_root_relative(cmd->pool, shm_file); if (jk_shm_file == NULL) return "JkShmFile file name invalid"; return NULL; } /* * JkShmSize Directive Handling * * JkShmSize size in kilobytes */ static const char *jk_set_shm_size(cmd_parms * cmd, void *dummy, const char *shm_size) { int sz = 0; const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err_string != NULL) { return err_string; } sz = atoi(shm_size) * 1024; if (sz < JK_SHM_MIN_SIZE) sz = JK_SHM_MIN_SIZE; else sz = JK_SHM_ALIGN(sz); jk_shm_size = sz; if (jk_shm_size) jk_shm_size_set = 1; return NULL; } /* * JkLogLevel Directive Handling * * JkLogLevel debug/info/error/emerg */ static const char *jk_set_log_level(cmd_parms * cmd, void *dummy, const char *log_level) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->log_level = jk_parse_log_level(log_level); return NULL; } /* * JkLogStampFormat Directive Handling * * JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " */ static const char *jk_set_log_fmt(cmd_parms * cmd, void *dummy, const char *log_format) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->stamp_format_string = apr_pstrdup(cmd->pool, log_format); return NULL; } /* * JkAutoAlias Directive Handling * * JkAutoAlias application directory */ static const char *jk_set_auto_alias(cmd_parms * cmd, void *dummy, const char *directory) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->alias_dir = apr_pstrdup(cmd->pool, directory); if (conf->alias_dir == NULL) return "JkAutoAlias directory invalid"; return NULL; } /* * JkStripSession directive handling * * JkStripSession On/Off [session path identifier] */ static const char *jk_set_strip_session(cmd_parms * cmd, void *dummy, const char *flag, const char *name) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); if (strcasecmp(flag, "on") && strcasecmp(flag, "off")) { return "JkStripSession must be On or Off"; } else { conf->strip_session = strcasecmp(flag, "off") ? JK_TRUE : JK_FALSE; } /* Check for optional path value */ if (name) conf->strip_session_name = apr_pstrdup(cmd->pool, name); else conf->strip_session_name = apr_pstrdup(cmd->pool, JK_PATH_SESSION_IDENTIFIER); return NULL; } /***************************************************************** * * Actually logging. */ typedef const char *(*item_key_func) (request_rec *, char *); typedef struct { item_key_func func; char *arg; } request_log_format_item; static const char *process_item(request_rec * r, request_log_format_item * item) { const char *cp; cp = (*item->func) (r, item->arg); return cp ? cp : "-"; } static int request_log_transaction(request_rec * r) { request_log_format_item *items; char *str, *s; int i; int len = 0; const char **strs; int *strl; jk_server_conf_t *conf; jk_request_conf_t *rconf; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; apr_array_header_t *format; conf = (jk_server_conf_t *) ap_get_module_config(r->server->module_config, &jk_module); format = conf->format; if (format == NULL) { return DECLINED; } rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module); if (rconf == NULL || rconf->jk_handled == JK_FALSE) { return DECLINED; } l->logger = conf->log; l->id = rconf->request_id; strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts)); strl = apr_palloc(r->pool, sizeof(int) * (format->nelts)); items = (request_log_format_item *) format->elts; for (i = 0; i < format->nelts; ++i) { strs[i] = process_item(r, &items[i]); } for (i = 0; i < format->nelts; ++i) { len += strl[i] = (int)strlen(strs[i]); } str = apr_palloc(r->pool, len + 1); for (i = 0, s = str; i < format->nelts; ++i) { memcpy(s, strs[i], strl[i]); s += strl[i]; } *s = 0; jk_log(l, JK_LOG_REQUEST, "%s", str); return OK; } /***************************************************************** * * Parsing the log format string */ static char *format_integer(apr_pool_t * p, int i) { return apr_psprintf(p, "%d", i); } static char *pfmt(apr_pool_t * p, int i) { if (i <= 0) { return "-"; } else { return format_integer(p, i); } } static const char *constant_item(request_rec * dummy, char *stuff) { return stuff; } static const char *log_worker_name(request_rec * r, char *a) { return apr_table_get(r->notes, JK_NOTE_WORKER_NAME); } static const char *log_worker_route(request_rec * r, char *a) { return apr_table_get(r->notes, JK_NOTE_WORKER_ROUTE); } static const char *log_request_duration(request_rec * r, char *a) { return apr_table_get(r->notes, JK_NOTE_REQUEST_DURATION); } static const char *log_request_line(request_rec * r, char *a) { /* NOTE: If the original request contained a password, we * re-write the request line here to contain XXXXXX instead: * (note the truncation before the protocol string for HTTP/0.9 requests) * (note also that r->the_request contains the unmodified request) */ return (r->parsed_uri.password) ? apr_pstrcat(r->pool, r->method, " ", apr_uri_unparse(r->pool, &r-> parsed_uri, 0), r-> assbackwards ? NULL : " ", r->protocol, NULL) : r->the_request; } /* These next two routines use the canonical name:port so that log * parsers don't need to duplicate all the vhost parsing crud. */ static const char *log_virtual_host(request_rec * r, char *a) { return r->server->server_hostname; } static const char *log_server_port(request_rec * r, char *a) { return apr_psprintf(r->pool, "%u", r->server->port ? r->server-> port : ap_default_port(r)); } /* This respects the setting of UseCanonicalName so that * the dynamic mass virtual hosting trick works better. */ static const char *log_server_name(request_rec * r, char *a) { return ap_get_server_name(r); } static const char *log_request_uri(request_rec * r, char *a) { return r->uri; } static const char *log_request_method(request_rec * r, char *a) { return r->method; } static const char *log_request_protocol(request_rec * r, char *a) { return r->protocol; } static const char *log_request_query(request_rec * r, char *a) { return (r->args != NULL) ? apr_pstrcat(r->pool, "?", r->args, NULL) : ""; } static const char *log_status(request_rec * r, char *a) { return pfmt(r->pool, r->status); } static const char *clf_log_bytes_sent(request_rec * r, char *a) { if (!r->sent_bodyct) { return "-"; } else { return apr_off_t_toa(r->pool, r->bytes_sent); } } static const char *log_bytes_sent(request_rec * r, char *a) { if (!r->sent_bodyct) { return "0"; } else { return apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->bytes_sent); } } static struct log_item_list { char ch; item_key_func func; } log_item_keys[] = { { 'T', log_request_duration }, { 'r', log_request_line }, { 'U', log_request_uri }, { 's', log_status }, { 'b', clf_log_bytes_sent }, { 'B', log_bytes_sent }, { 'V', log_server_name }, { 'v', log_virtual_host }, { 'p', log_server_port }, { 'H', log_request_protocol }, { 'm', log_request_method }, { 'q', log_request_query }, { 'w', log_worker_name }, { 'R', log_worker_route}, { '\0', NULL } }; static struct log_item_list *find_log_func(char k) { int i; for (i = 0; log_item_keys[i].ch; ++i) if (k == log_item_keys[i].ch) { return &log_item_keys[i]; } return NULL; } static char *parse_request_log_misc_string(apr_pool_t * p, request_log_format_item * it, const char **sa) { const char *s; char *d; it->func = constant_item; s = *sa; while (*s && *s != '%') { s++; } /* * This might allocate a few chars extra if there's a backslash * escape in the format string. */ it->arg = apr_palloc(p, s - *sa + 1); d = it->arg; s = *sa; while (*s && *s != '%') { if (*s != '\\') { *d++ = *s++; } else { s++; switch (*s) { case '\\': *d++ = '\\'; s++; break; case 'n': *d++ = '\n'; s++; break; case 't': *d++ = '\t'; s++; break; default: /* copy verbatim */ *d++ = '\\'; /* * Allow the loop to deal with this *s in the normal * fashion so that it handles end of string etc. * properly. */ break; } } } *d = '\0'; *sa = s; return NULL; } static char *parse_request_log_item(apr_pool_t * p, request_log_format_item * it, const char **sa) { const char *s = *sa; struct log_item_list *l; if (*s != '%') { return parse_request_log_misc_string(p, it, sa); } ++s; it->arg = ""; /* For safety's sake... */ l = find_log_func(*s++); if (!l) { char dummy[2]; dummy[0] = s[-1]; dummy[1] = '\0'; return apr_pstrcat(p, "Unrecognized JkRequestLogFormat directive %", dummy, NULL); } it->func = l->func; *sa = s; return NULL; } static apr_array_header_t *parse_request_log_string(apr_pool_t * p, const char *s, const char **err) { apr_array_header_t *a = apr_array_make(p, 0, sizeof(request_log_format_item)); char *res; while (*s) { if ((res = parse_request_log_item(p, (request_log_format_item *) apr_array_push(a), &s))) { *err = res; return NULL; } } return a; } /* * JkRequestLogFormat Directive Handling * * JkRequestLogFormat format string * * %b - Bytes sent, excluding HTTP headers. In CLF format * %B - Bytes sent, excluding HTTP headers. * %H - The request protocol * %m - The request method * %p - The canonical Port of the server serving the request * %q - The query string (prepended with a ? if a query string exists, * otherwise an empty string) * %r - First line of request * %s - request HTTP status code * %T - Request duration, elapsed time to handle request in seconds '.' micro seconds * %U - The URL path requested, not including any query string. * %v - The canonical ServerName of the server serving the request. * %V - The server name according to the UseCanonicalName setting. * %w - Tomcat worker name */ static const char *jk_set_request_log_format(cmd_parms * cmd, void *dummy, const char *format) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->format_string = apr_pstrdup(cmd->pool, format); return NULL; } /* * JkWorkerIndicator Directive Handling * * JkWorkerIndicator JkWorker */ static const char *jk_set_worker_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->worker_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } /* * Directives Handling for setting various environment names * used to overwrite the following request information: * - request_id * - remote_addr * - remote_port * - remote_host * - remote_user * - auth_type * - server_name * - server_port */ static const char *jk_set_request_id_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->request_id_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } static const char *jk_set_remote_addr_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->remote_addr_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } static const char *jk_set_remote_port_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->remote_port_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } static const char *jk_set_remote_host_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->remote_host_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } static const char *jk_set_remote_user_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->remote_user_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } static const char *jk_set_auth_type_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->auth_type_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } static const char *jk_set_local_name_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->local_name_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } static const char *jk_set_local_addr_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->local_addr_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } static const char *jk_set_local_port_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->local_port_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } static const char *jk_set_ignore_cl_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->ignore_cl_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } /* * JkExtractSSL Directive Handling * * JkExtractSSL On/Off */ static const char *jk_set_enable_ssl(cmd_parms * cmd, void *dummy, int flag) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); /* Set up our value */ conf->ssl_enable = flag ? JK_TRUE : JK_FALSE; return NULL; } /* * JkHTTPSIndicator Directive Handling * * JkHTTPSIndicator HTTPS */ static const char *jk_set_https_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->https_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } /* * JkSSLPROTOCOLIndicator Directive Handling * * JkSSLPROTOCOLIndicator SSL_PROTOCOL */ static const char *jk_set_ssl_protocol_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->ssl_protocol_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } /* * JkCERTSIndicator Directive Handling * * JkCERTSIndicator SSL_CLIENT_CERT */ static const char *jk_set_certs_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->certs_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } /* * JkCIPHERIndicator Directive Handling * * JkCIPHERIndicator SSL_CIPHER */ static const char *jk_set_cipher_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->cipher_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } /* * JkCERTCHAINPrefix Directive Handling * * JkCERTCHAINPrefix SSL_CLIENT_CERT_CHAIN_ */ static const char *jk_set_certchain_prefix(cmd_parms * cmd, void *dummy, const char *prefix) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->certchain_prefix = apr_pstrdup(cmd->pool, prefix); return NULL; } /* * JkSESSIONIndicator Directive Handling * * JkSESSIONIndicator SSL_SESSION_ID */ static const char *jk_set_session_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->session_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } /* * JkKEYSIZEIndicator Directive Handling * * JkKEYSIZEIndicator SSL_CIPHER_USEKEYSIZE */ static const char *jk_set_key_size_indicator(cmd_parms * cmd, void *dummy, const char *indicator) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->key_size_indicator = apr_pstrdup(cmd->pool, indicator); return NULL; } /* * JkOptions Directive Handling * * * +ForwardSSLKeySize => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2 * -ForwardSSLKeySize => Don't Forward SSL Key Size, will make mod_jk works with all TC release * ForwardURICompat => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC) * ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC) * ForwardURIEscaped => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part * ForwardDirectories => Forward all directory requests with no index files to Tomcat * +ForwardSSLCertChain => Forward SSL Cert Chain * -ForwardSSLCertChain => Don't Forward SSL Cert Chain (default) */ static const char *jk_set_options(cmd_parms * cmd, void *dummy, const char *line) { int opt = 0; int mask = 0; char action; char *w; server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); while (line[0] != 0) { w = ap_getword_conf(cmd->pool, &line); action = 0; if (*w == '+' || *w == '-') { action = *(w++); } mask = 0; if (action == '-' && (!strncasecmp(w, "ForwardURI", strlen("ForwardURI")))) { return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '-", w, "': option can not be disabled", NULL); } if (!strcasecmp(w, "ForwardURICompat")) { opt = JK_OPT_FWDURICOMPAT; mask = JK_OPT_FWDURIMASK; } else if (!strcasecmp(w, "ForwardURICompatUnparsed")) { opt = JK_OPT_FWDURICOMPATUNPARSED; mask = JK_OPT_FWDURIMASK; } else if (!strcasecmp(w, "ForwardURIEscaped")) { opt = JK_OPT_FWDURIESCAPED; mask = JK_OPT_FWDURIMASK; } else if (!strcasecmp(w, "ForwardURIProxy")) { opt = JK_OPT_FWDURIPROXY; mask = JK_OPT_FWDURIMASK; } else if (!strcasecmp(w, "CollapseSlashesAll")) { opt = JK_OPT_COLLAPSEALL; mask = JK_OPT_COLLAPSEMASK; } else if (!strcasecmp(w, "CollapseSlashesNone")) { opt = JK_OPT_COLLAPSENONE; mask = JK_OPT_COLLAPSEMASK; } else if (!strcasecmp(w, "CollapseSlashesUnmount")) { opt = JK_OPT_COLLAPSEUNMOUNT; mask = JK_OPT_COLLAPSEMASK; } else if (!strcasecmp(w, "ForwardDirectories")) { opt = JK_OPT_FWDDIRS; } else if (!strcasecmp(w, "ForwardLocalAddress")) { opt = JK_OPT_FWDLOCAL; mask = JK_OPT_FWDADDRMASK; } else if (!strcasecmp(w, "ForwardPhysicalAddress")) { opt = JK_OPT_FWDPHYSICAL; mask = JK_OPT_FWDADDRMASK; } else if (!strcasecmp(w, "FlushPackets")) { opt = JK_OPT_FLUSHPACKETS; } else if (!strcasecmp(w, "FlushHeader")) { opt = JK_OPT_FLUSHEADER; } else if (!strcasecmp(w, "DisableReuse")) { opt = JK_OPT_DISABLEREUSE; } else if (!strcasecmp(w, "ForwardSSLCertChain")) { opt = JK_OPT_FWDCERTCHAIN; } else if (!strcasecmp(w, "ForwardKeySize")) { opt = JK_OPT_FWDKEYSIZE; } else if (!strcasecmp(w, "RejectUnsafeURI")) { opt = JK_OPT_REJECTUNSAFE; } else return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '", w, "'", NULL); conf->options &= ~mask; if (action == '-') { conf->exclude_options |= opt; } else if (action == '+') { conf->options |= opt; } else { /* for now +Opt == Opt */ conf->options |= opt; } } return NULL; } /* * JkEnvVar Directive Handling * * JkEnvVar MYOWNDIR */ static const char *jk_add_env_var(cmd_parms * cmd, void *dummy, const char *env_name, const char *default_value) { server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); conf->envvars_has_own = JK_TRUE; if (!conf->envvars) { conf->envvars = apr_table_make(cmd->pool, 0); conf->envvars_def = apr_table_make(cmd->pool, 0); conf->envvar_items = apr_array_make(cmd->pool, 0, sizeof(envvar_item)); } /* env_name is mandatory, default_value is optional. * No value means send the attribute only, if the env var is set during runtime. */ apr_table_setn(conf->envvars, env_name, default_value ? default_value : ""); apr_table_setn(conf->envvars_def, env_name, default_value ? "1" : "0"); return NULL; } /* * JkWorkerProperty Directive Handling * * JkWorkerProperty name=value */ static const char *jk_set_worker_property(cmd_parms * cmd, void *dummy, const char *line) { jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; server_rec *s = cmd->server; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err_string != NULL) { return err_string; } l->logger = conf->log; l->id = "CONFIG"; if (!jk_worker_properties) jk_map_alloc(&jk_worker_properties); if (jk_map_read_property(jk_worker_properties, NULL, line, JK_MAP_HANDLE_DUPLICATES, l) == JK_FALSE) return apr_pstrcat(cmd->temp_pool, "Invalid JkWorkerProperty ", line, NULL); return NULL; } static const command_rec jk_cmds[] = { /* * JkWorkersFile specifies a full path to the location of the worker * properties file. * * This file defines the different workers used by apache to redirect * servlet requests. */ AP_INIT_TAKE1("JkWorkersFile", jk_set_worker_file, NULL, RSRC_CONF, "The name of a worker file for the Tomcat servlet containers"), /* * JkMountFile specifies a full path to the location of the * uriworker properties file. * * This file defines the different mapping for workers used by apache * to redirect servlet requests. */ AP_INIT_TAKE1("JkMountFile", jk_set_mount_file, NULL, RSRC_CONF, "The name of a mount file for the Tomcat servlet uri mapping"), /* * JkMountFileReload specifies the reload check interval for the * uriworker properties file. * * Default value is: JK_URIMAP_DEF_RELOAD */ AP_INIT_TAKE1("JkMountFileReload", jk_set_mount_file_reload, NULL, RSRC_CONF, "The reload check interval of the mount file"), /* * JkWatchdogInterval specifies the maintain interval for the * watchdog thread. * * Default value is: 0 meaning watchdog thread will not be created */ AP_INIT_TAKE1("JkWatchdogInterval", jk_set_watchdog_interval, NULL, RSRC_CONF, "The maintain interval of the watchdog thread"), /* * JkMount mounts a url prefix to a worker (the worker need to be * defined in the worker properties file. */ AP_INIT_TAKE12("JkMount", jk_mount_context, NULL, RSRC_CONF|ACCESS_CONF, "A mount point from a context to a Tomcat worker"), /* * JkUnMount unmounts a url prefix to a worker (the worker need to be * defined in the worker properties file. */ AP_INIT_TAKE12("JkUnMount", jk_unmount_context, NULL, RSRC_CONF|ACCESS_CONF, "A no mount point from a context to a Tomcat worker"), /* * JkMountCopy specifies if mod_jk should copy the mount points * from the main server to the virtual servers. */ AP_INIT_TAKE1("JkMountCopy", jk_set_mountcopy, NULL, RSRC_CONF, "Should the base server mounts be copied to the virtual server"), /* * JkStripSession specifies if mod_jk should strip the ;jsessionid * from the unmapped urls */ AP_INIT_TAKE12("JkStripSession", jk_set_strip_session, NULL, RSRC_CONF, "Should the server strip the jsessionid from unmapped URLs"), /* * JkLogFile & JkLogLevel specifies to where should the plugin log * its information and how much. * JkLogStampFormat specify the time-stamp to be used on log */ AP_INIT_TAKE1("JkLogFile", jk_set_log_file, NULL, RSRC_CONF, "Full path to the Tomcat module log file"), AP_INIT_TAKE1("JkShmFile", jk_set_shm_file, NULL, RSRC_CONF, "Full path to the Tomcat module shared memory file"), AP_INIT_TAKE1("JkShmSize", jk_set_shm_size, NULL, RSRC_CONF, "Size of the shared memory file in KBytes"), AP_INIT_TAKE1("JkLogLevel", jk_set_log_level, NULL, RSRC_CONF, "The Tomcat module log level, can be debug, " "info, error or emerg"), AP_INIT_TAKE1("JkLogStampFormat", jk_set_log_fmt, NULL, RSRC_CONF, "The Tomcat module log format, follow strftime syntax"), AP_INIT_TAKE1("JkRequestLogFormat", jk_set_request_log_format, NULL, RSRC_CONF, "The mod_jk module request log format string"), /* * Automatically Alias webapp context directories into the Apache * document space. */ AP_INIT_TAKE1("JkAutoAlias", jk_set_auto_alias, NULL, RSRC_CONF, "The mod_jk module automatic context apache alias directory"), /* * Enable worker name to be set in an environment variable. * This way one can use LocationMatch together with mod_env, * mod_setenvif and mod_rewrite to set the target worker. * Use this in combination with SetHandler jakarta-servlet to * make mod_jk the handler for the request. * */ AP_INIT_TAKE1("JkWorkerIndicator", jk_set_worker_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the worker name"), /* * Environment variables used to overwrite the following * request information which gets forwarded: * - request_id * - remote_addr * - remote_port * - remote_host * - remote_user * - auth_type * - server_name * - server_port */ AP_INIT_TAKE1("JkRequestIdIndicator", jk_set_request_id_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the request id."), AP_INIT_TAKE1("JkRemoteAddrIndicator", jk_set_remote_addr_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the remote address"), AP_INIT_TAKE1("JkRemotePortIndicator", jk_set_remote_port_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the remote port"), AP_INIT_TAKE1("JkRemoteHostIndicator", jk_set_remote_host_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the remote host name"), AP_INIT_TAKE1("JkRemoteUserIndicator", jk_set_remote_user_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the remote user name"), AP_INIT_TAKE1("JkAuthTypeIndicator", jk_set_auth_type_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the type of authentication"), AP_INIT_TAKE1("JkLocalNameIndicator", jk_set_local_name_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the local name"), AP_INIT_TAKE1("JkLocalAddrIndicator", jk_set_local_addr_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the local IP address"), AP_INIT_TAKE1("JkLocalPortIndicator", jk_set_local_port_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the local port"), AP_INIT_TAKE1("JkIgnoreCLIndicator", jk_set_ignore_cl_indicator, NULL, RSRC_CONF, "Name of the Apache environment that forces to ignore a request " "Content-Length header"), /* * Apache has multiple SSL modules (for example apache_ssl, stronghold * IHS ...). Each of these can have a different SSL environment names * The following properties let the administrator specify the envoiroment * variables names. * * HTTPS - indication for SSL * CERTS - Base64-Der-encoded client certificates. * CIPHER - A string specifing the ciphers suite in use. * KEYSIZE - Size of Key used in dialogue (#bits are secure) * SESSION - A string specifing the current SSL session. */ AP_INIT_TAKE1("JkHTTPSIndicator", jk_set_https_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains SSL indication"), AP_INIT_TAKE1("JkSSLPROTOCOLIndicator", jk_set_ssl_protocol_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains the SSL protocol name"), AP_INIT_TAKE1("JkCERTSIndicator", jk_set_certs_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains SSL client certificates"), AP_INIT_TAKE1("JkCIPHERIndicator", jk_set_cipher_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains SSL client cipher"), AP_INIT_TAKE1("JkSESSIONIndicator", jk_set_session_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains SSL session"), AP_INIT_TAKE1("JkKEYSIZEIndicator", jk_set_key_size_indicator, NULL, RSRC_CONF, "Name of the Apache environment that contains SSL key size in use"), AP_INIT_TAKE1("JkCERTCHAINPrefix", jk_set_certchain_prefix, NULL, RSRC_CONF, "Name of the Apache environment (prefix) that contains SSL client chain certificates"), AP_INIT_FLAG("JkExtractSSL", jk_set_enable_ssl, NULL, RSRC_CONF, "Turns on SSL processing and information gathering by mod_jk"), /* * Options to tune mod_jk configuration * for now we understand : * +ForwardSSLKeySize => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2 * -ForwardSSLKeySize => Don't Forward SSL Key Size, will make mod_jk works with all TC release * ForwardURICompat => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC) * ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC) * ForwardURIEscaped => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part * +ForwardSSLCertChain => Forward SSL certificate chain * -ForwardSSLCertChain => Don't forward SSL certificate chain */ AP_INIT_RAW_ARGS("JkOptions", jk_set_options, NULL, RSRC_CONF, "Set one of more options to configure the mod_jk module"), /* * JkEnvVar let user defines envs var passed from WebServer to * Servlet Engine */ AP_INIT_TAKE12("JkEnvVar", jk_add_env_var, NULL, RSRC_CONF, "Adds a name of environment variable and an optional value " "that should be sent to servlet-engine"), AP_INIT_RAW_ARGS("JkWorkerProperty", jk_set_worker_property, NULL, RSRC_CONF, "Set workers.properties formated directive"), {NULL} }; /* ========================================================================= */ /* The JK module handlers */ /* ========================================================================= */ /** Util - cleanup for all processes. */ static apr_status_t jk_cleanup_proc(void *data) { /* If the main log is piped, we need to make sure * it is no longer used. The external log process * (e.g. rotatelogs) will be gone now and the pipe will * block, once the buffer gets full. NULLing * jklogfp makes logging switch to error log. */ jk_logger_t *l = (jk_logger_t *)data; jk_log_context_t log_ctx; log_ctx.logger = l; log_ctx.id = "CLEANUP"; if (l && l->logger_private) { jk_file_logger_t *p = l->logger_private; if (p && p->is_piped == JK_TRUE) { p->jklogfp = NULL; p->is_piped = JK_FALSE; } } jk_shm_close(&log_ctx); return APR_SUCCESS; } /** Util - cleanup for child processes. */ static apr_status_t jk_cleanup_child(void *data) { /* If the main log is piped, we need to make sure * it is no longer used. The external log process * (e.g. rotatelogs) will be gone now and the pipe will * block, once the buffer gets full. NULLing * jklogfp makes logging switch to error log. */ jk_logger_t *l = (jk_logger_t *)data; jk_log_context_t log_ctx; log_ctx.logger = l; log_ctx.id = "CLEANUP"; if (l && l->logger_private) { jk_file_logger_t *p = l->logger_private; if (p && p->is_piped == JK_TRUE) { p->jklogfp = NULL; p->is_piped = JK_FALSE; } } /* Force the watchdog thread exit */ if (jk_watchdog_interval > 0) { jk_watchdog_interval = 0; while (jk_watchdog_running) apr_sleep(apr_time_from_sec(1)); } wc_shutdown(&log_ctx); return jk_cleanup_proc(data); } /** Main service method, called to forward a request to tomcat */ static int jk_handler(request_rec * r) { const char *worker_name; jk_server_conf_t *xconf; jk_request_conf_t *rconf; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; int rc, dmt = 1; int worker_name_extension = JK_FALSE; /* We do DIR_MAGIC_TYPE here to make sure TC gets all requests, even * if they are directory requests, in case there are no static files * visible to Apache and/or DirectoryIndex was not used. This is only * used when JkOptions has ForwardDirectories set. */ /* Not for me, try next handler */ if (strcmp(r->handler, JK_HANDLER) && (dmt = strcmp(r->handler, DIR_MAGIC_TYPE))) return DECLINED; xconf = (jk_server_conf_t *) ap_get_module_config(r->server->module_config, &jk_module); l->logger = xconf->log; l->id = NULL; JK_TRACE_ENTER(l); if (apr_table_get(r->subprocess_env, "no-jk")) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Into handler no-jk env var detected for uri=%s, declined", r->uri); JK_TRACE_EXIT(l); return DECLINED; } /* Was the option to forward directories to Tomcat set? */ if (!dmt && !(xconf->options & JK_OPT_FWDDIRS)) { JK_TRACE_EXIT(l); return DECLINED; } rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module); if (rconf == NULL) { rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t)); rconf->jk_handled = JK_FALSE; rconf->rule_extensions = NULL; rconf->orig_uri = NULL; rconf->request_id = get_env_string(r, NULL, xconf->request_id_indicator, 1); if (rconf->request_id == NULL) { rconf->request_id = get_env_string(r, NULL, JK_ENV_REQUEST_ID, 1); } ap_set_module_config(r->request_config, &jk_module, rconf); } l->id = rconf->request_id; worker_name = apr_table_get(r->notes, JK_NOTE_WORKER_NAME); if (worker_name == NULL) { /* we may be here because of a manual directive (that overrides translate and sets the handler directly). We still need to know the worker. */ worker_name = apr_table_get(r->subprocess_env, xconf->worker_indicator); if (worker_name) { /* The JkWorkerIndicator environment variable has * been used to explicitly set the worker without JkMount. * This is useful in combination with LocationMatch or mod_rewrite. */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Retrieved worker (%s) from env %s for %s", worker_name, xconf->worker_indicator, r->uri); if (ap_strchr_c(worker_name, ';')) { rule_extension_t *e = apr_palloc(r->pool, sizeof(rule_extension_t)); char *w = apr_pstrdup(r->pool, worker_name); worker_name_extension = JK_TRUE; parse_rule_extensions(w, e, l); worker_name = w; rconf->rule_extensions = e; } } else { if (!xconf->uw_map) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "missing uri map for %s:%s", xconf->s->server_hostname ? xconf->s->server_hostname : "_default_", r->uri); } else { rule_extension_t *e; char *clean_uri; clean_uri = apr_pstrdup(r->pool, r->uri); rc = jk_servlet_normalize(clean_uri, l); if (rc != 0) { JK_TRACE_EXIT(l); return HTTP_BAD_REQUEST; } worker_name = map_uri_to_worker_ext(xconf->uw_map, clean_uri, NULL, &e, NULL, l); if (worker_name) { rconf->rule_extensions = e; rconf->orig_uri = r->uri; r->uri = clean_uri; } } } if (worker_name) apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker_name); } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Into handler %s worker=%s" " r->proxyreq=%d", r->handler, STRNULL_FOR_NULL(worker_name), r->proxyreq); rconf->jk_handled = JK_TRUE; /* If this is a proxy request, we'll notify an error */ if (r->proxyreq) { jk_log(l, JK_LOG_INFO, "Proxy request for worker=%s" " is not allowed", STRNULL_FOR_NULL(worker_name)); JK_TRACE_EXIT(l); return HTTP_INTERNAL_SERVER_ERROR; } /* Set up r->read_chunked flags for chunked encoding, if present */ if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != APR_SUCCESS) { JK_TRACE_EXIT(l); return rc; } if (worker_name) { jk_worker_t *worker = wc_get_worker_for_name(worker_name, l); /* If the remote client has aborted, just ignore the request */ if (r->connection->aborted) { jk_log(l, JK_LOG_INFO, "Client connection aborted for" " worker=%s", worker_name); JK_TRACE_EXIT(l); return OK; } if (worker) { long micro, seconds; char *duration = NULL; apr_time_t rd; apr_time_t request_begin = 0; int is_error = HTTP_INTERNAL_SERVER_ERROR; int rc = JK_FALSE; apache_private_data_t private_data; jk_ws_service_t s; jk_pool_atom_t buf[SMALL_POOL_SIZE]; jk_open_pool(&private_data.p, buf, sizeof(buf)); private_data.read_body_started = JK_FALSE; private_data.r = r; if (worker_name_extension == JK_TRUE) { extension_fix(&private_data.p, worker_name, rconf->rule_extensions, l); } /* Maintain will be done by watchdog thread */ if (!jk_watchdog_interval) wc_maintain(l); jk_init_ws_service(&s); s.ws_private = &private_data; s.pool = &private_data.p; apr_table_setn(r->notes, JK_NOTE_WORKER_TYPE, wc_get_name_for_type(worker->type, l)); request_begin = apr_time_now(); if (init_ws_service(&private_data, &s, xconf)) { jk_endpoint_t *end = NULL; /* Use per/thread pool (or "context") to reuse the endpoint. It's a bit faster, but I don't know how to deal with load balancing - but it's usefull for JNI */ /* worker->get_endpoint might fail if we are out of memory so check */ /* and handle it */ if (worker->get_endpoint(worker, &end, l)) { rc = end->service(end, &s, l, &is_error); end->done(&end, l); if ((s.content_read < s.content_length || (s.is_chunked && !s.no_more_chunks)) && /* This case aborts the connection below and typically * means the request body reading already timed out, * so lets not try to read again here. */ !(rc == JK_CLIENT_ERROR && is_error == HTTP_BAD_REQUEST)) { /* * If the servlet engine didn't consume all of the * request data, consume and discard all further * characters left to read from client */ char *buff = apr_palloc(r->pool, 2048); int consumed = 0; if (buff != NULL) { int rd; while ((rd = ap_get_client_block(r, buff, 2048)) > 0) { s.content_read += rd; consumed += rd; } } if (JK_IS_DEBUG_LEVEL(l)) { jk_log(l, JK_LOG_DEBUG, "Consumed %d bytes of remaining request data for worker=%s", consumed, STRNULL_FOR_NULL(worker_name)); } } } else { /* this means we couldn't get an endpoint */ jk_log(l, JK_LOG_ERROR, "Could not get endpoint" " for worker=%s", worker_name); rc = 0; /* just to make sure that we know we've failed */ is_error = HTTP_SERVICE_UNAVAILABLE; } } else { jk_log(l, JK_LOG_ERROR, "Could not init service" " for worker=%s", worker_name); jk_close_pool(&private_data.p); JK_TRACE_EXIT(l); return HTTP_INTERNAL_SERVER_ERROR; } rd = apr_time_now() - request_begin; seconds = (long)apr_time_sec(rd); micro = (long)(rd - apr_time_from_sec(seconds)); duration = apr_psprintf(r->pool, "%.1ld.%.6ld", seconds, micro); apr_table_setn(r->notes, JK_NOTE_REQUEST_DURATION, duration); if (s.route && *s.route) apr_table_set(r->notes, JK_NOTE_WORKER_ROUTE, s.route); jk_close_pool(&private_data.p); if (rc > 0) { if (s.extension.use_server_error_pages && s.http_response_status >= s.extension.use_server_error_pages) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Forwarding status=%d" " for worker=%s", s.http_response_status, worker_name); JK_TRACE_EXIT(l); return s.http_response_status; } /* * If Tomcat returned no body, the status is not OK and it is * not a HEAD request, let httpd generate the response body. */ if (!r->sent_bodyct && r->status >= HTTP_BAD_REQUEST && strcmp(r->method, "HEAD")) { jk_log(l, JK_LOG_INFO, "No body with status=%d" " for worker=%s", r->status, worker_name); JK_TRACE_EXIT(l); return r->status; } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Service finished" " with status=%d for worker=%s", r->status, worker_name); JK_TRACE_EXIT(l); return OK; /* NOT r->status, even if it has changed. */ } else if (rc == JK_CLIENT_ERROR) { if (is_error != HTTP_REQUEST_ENTITY_TOO_LARGE) r->connection->aborted = 1; jk_log(l, JK_LOG_INFO, "Aborting connection" " for worker=%s", worker_name); JK_TRACE_EXIT(l); return is_error; } else { jk_log(l, JK_LOG_INFO, "Service error=%d" " for worker=%s", rc, worker_name); JK_TRACE_EXIT(l); return is_error; } } else { jk_log(l, JK_LOG_INFO, "Could not find a worker" " for worker name=%s", worker_name); JK_TRACE_EXIT(l); return HTTP_INTERNAL_SERVER_ERROR; } } rconf->jk_handled = JK_FALSE; JK_TRACE_EXIT(l); return DECLINED; } /** Standard apache hook, cleanup jk */ static apr_status_t jk_apr_pool_cleanup(void *data) { server_rec *s = data; if (jk_worker_properties) { jk_map_free(&jk_worker_properties); jk_worker_properties = NULL; jk_worker_file = NULL; jk_mount_copy_all = JK_FALSE; } while (NULL != s) { jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module); if (conf && conf->was_initialized == JK_TRUE) { /* On pool cleanup pass NULL for the jk_logger to prevent segmentation faults on Windows because we can't guarantee what order pools get cleaned up between APR implementations. */ wc_close(NULL); if (conf->uri_to_context) { jk_map_free(&conf->uri_to_context); /* We cannot have allocated uw_map * unless we've allocated uri_to_context */ if (conf->uw_map) uri_worker_map_free(&conf->uw_map, NULL); } conf->was_initialized = JK_FALSE; } s = s->next; } return APR_SUCCESS; } /** Create default jk_config. XXX This is mostly server-independent, all servers are using something similar - should go to common. */ static void *create_jk_config(apr_pool_t * p, server_rec * s) { jk_server_conf_t *c = (jk_server_conf_t *) apr_pcalloc(p, sizeof(jk_server_conf_t)); c->was_initialized = JK_FALSE; if (s->is_virtual) { c->mountcopy = JK_UNSET; c->mount_file_reload = JK_UNSET; c->log_level = JK_UNSET; c->ssl_enable = JK_UNSET; c->strip_session = JK_UNSET; } else { if (!jk_map_alloc(&(c->uri_to_context))) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Memory error"); } c->mountcopy = JK_FALSE; c->mount_file_reload = JK_URIMAP_DEF_RELOAD; c->log_level = JK_LOG_DEF_LEVEL; c->options = JK_OPT_DEFAULT; c->worker_indicator = JK_ENV_WORKER_NAME; /* * Configurable environment variables to overwrite * request information using meta data send by a * proxy in front of us. */ c->request_id_indicator = JK_ENV_REQUEST_ID; c->remote_addr_indicator = JK_ENV_REMOTE_ADDR; c->remote_port_indicator = JK_ENV_REMOTE_PORT; c->remote_host_indicator = JK_ENV_REMOTE_HOST; c->remote_user_indicator = JK_ENV_REMOTE_USER; c->auth_type_indicator = JK_ENV_AUTH_TYPE; c->local_name_indicator = JK_ENV_LOCAL_NAME; c->local_addr_indicator = JK_ENV_LOCAL_ADDR; c->local_port_indicator = JK_ENV_LOCAL_PORT; c->ignore_cl_indicator = JK_ENV_IGNORE_CL; /* * By default we will try to gather SSL info. * Disable this functionality through JkExtractSSL */ c->ssl_enable = JK_TRUE; /* * The defaults ssl indicators match those in mod_ssl (seems * to be in more use). */ c->https_indicator = JK_ENV_HTTPS; c->ssl_protocol_indicator = JK_ENV_SSL_PROTOCOL; c->certs_indicator = JK_ENV_CERTS; c->cipher_indicator = JK_ENV_CIPHER; c->certchain_prefix = JK_ENV_CERTCHAIN_PREFIX; c->session_indicator = JK_ENV_SESSION; c->key_size_indicator = JK_ENV_KEY_SIZE; c->strip_session = JK_FALSE; } c->envvars_has_own = JK_FALSE; c->s = s; apr_pool_cleanup_register(p, s, jk_apr_pool_cleanup, apr_pool_cleanup_null); return c; } /* * Utility - copy items from apr table src to dst, * for keys that exist in src but not in dst. */ static void merge_apr_table(apr_table_t *src, apr_table_t *dst) { int i; const apr_array_header_t *arr; const apr_table_entry_t *elts; arr = apr_table_elts(src); elts = (const apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; ++i) { if (!apr_table_get(dst, elts[i].key)) { apr_table_setn(dst, elts[i].key, elts[i].val); } } } /** Standard apache callback, merge jk options specified in context or . */ static void *merge_jk_config(apr_pool_t * p, void *basev, void *overridesv) { jk_server_conf_t *base = (jk_server_conf_t *) basev; jk_server_conf_t *overrides = (jk_server_conf_t *) overridesv; int mask = 0; if (!overrides->log_file) overrides->log_file = base->log_file; if (overrides->log_level == JK_UNSET) overrides->log_level = base->log_level; if (!overrides->stamp_format_string) overrides->stamp_format_string = base->stamp_format_string; if (!overrides->format_string) overrides->format_string = base->format_string; if (!overrides->worker_indicator) overrides->worker_indicator = base->worker_indicator; if (!overrides->request_id_indicator) overrides->request_id_indicator = base->request_id_indicator; if (!overrides->remote_addr_indicator) overrides->remote_addr_indicator = base->remote_addr_indicator; if (!overrides->remote_port_indicator) overrides->remote_port_indicator = base->remote_port_indicator; if (!overrides->remote_host_indicator) overrides->remote_host_indicator = base->remote_host_indicator; if (!overrides->remote_user_indicator) overrides->remote_user_indicator = base->remote_user_indicator; if (!overrides->auth_type_indicator) overrides->auth_type_indicator = base->auth_type_indicator; if (!overrides->local_name_indicator) overrides->local_name_indicator = base->local_name_indicator; if (!overrides->local_port_indicator) overrides->local_port_indicator = base->local_port_indicator; if (!overrides->ignore_cl_indicator) overrides->ignore_cl_indicator = base->ignore_cl_indicator; if (overrides->ssl_enable == JK_UNSET) overrides->ssl_enable = base->ssl_enable; if (!overrides->https_indicator) overrides->https_indicator = base->https_indicator; if (!overrides->ssl_protocol_indicator) overrides->ssl_protocol_indicator = base->ssl_protocol_indicator; if (!overrides->certs_indicator) overrides->certs_indicator = base->certs_indicator; if (!overrides->cipher_indicator) overrides->cipher_indicator = base->cipher_indicator; if (!overrides->certchain_prefix) overrides->certchain_prefix = base->certchain_prefix; if (!overrides->session_indicator) overrides->session_indicator = base->session_indicator; if (!overrides->key_size_indicator) overrides->key_size_indicator = base->key_size_indicator; /* Don't simply accumulate bits in the JK_OPT_FWDURIMASK or * JK_OPT_COLLAPSEMASK region, because those are multi-bit values. */ if (overrides->options & JK_OPT_FWDURIMASK) mask |= JK_OPT_FWDURIMASK; if (overrides->options & JK_OPT_COLLAPSEMASK) mask |= JK_OPT_COLLAPSEMASK; overrides->options |= (base->options & ~base->exclude_options) & ~mask; if (base->envvars) { if (overrides->envvars && overrides->envvars_has_own) { /* merge_apr_table() preserves existing entries in overrides table */ merge_apr_table(base->envvars, overrides->envvars); merge_apr_table(base->envvars_def, overrides->envvars_def); } else { overrides->envvars = base->envvars; overrides->envvars_def = base->envvars_def; overrides->envvar_items = base->envvar_items; } } if (overrides->mountcopy == JK_UNSET && jk_mount_copy_all == JK_TRUE) { overrides->mountcopy = JK_TRUE; } if (overrides->uri_to_context && overrides->mountcopy == JK_TRUE) { /* jk_map_copy() preserves existing entries in overrides map */ if (jk_map_copy(base->uri_to_context, overrides->uri_to_context) == JK_FALSE) { jk_error_exit(JKLOG_MARK, APLOG_EMERG, overrides->s, p, "Memory error"); } if (!overrides->mount_file) overrides->mount_file = base->mount_file; } if (overrides->mountcopy == JK_TRUE) { if (!overrides->alias_dir) overrides->alias_dir = base->alias_dir; } if (overrides->mount_file_reload == JK_UNSET) overrides->mount_file_reload = base->mount_file_reload; if (overrides->strip_session == JK_UNSET) { overrides->strip_session = base->strip_session; overrides->strip_session_name = base->strip_session_name; } return overrides; } static int JK_METHOD jk_log_to_file(jk_logger_t *l, int level, int used, char *what) { if (l && (l->level <= level || level == JK_LOG_REQUEST_LEVEL) && l->logger_private && what && used > 0) { jk_file_logger_t *p = l->logger_private; if (p->jklogfp) { apr_status_t rv; apr_size_t wrote; #if defined(WIN32) what[used++] = '\r'; #endif what[used++] = '\n'; wrote = used; rv = apr_global_mutex_lock(jk_log_lock); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_global_mutex_lock(jk_log_lock) failed"); /* XXX: Maybe this should be fatal? */ } rv = apr_file_write(p->jklogfp, what, &wrote); if (rv != APR_SUCCESS) { char error[256]; apr_strerror(rv, error, 254); ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "mod_jk: jk_log_to_file %.*s failed: %s", used, what, error); } rv = apr_global_mutex_unlock(jk_log_lock); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_global_mutex_unlock(jk_log_lock) failed"); /* XXX: Maybe this should be fatal? */ } } else { /* Can't use mod_jk log any more, log to error log instead. * Choose APLOG_ERR, since we already checked above, that if * the mod_jk log file would still be open, we would have * actually logged the message there */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%.*s", used, what); } return JK_TRUE; } return JK_FALSE; } /* ** +-------------------------------------------------------+ ** | | ** | jk logfile support | ** | | ** +-------------------------------------------------------+ */ static apr_status_t jklog_cleanup(void *d) { /* hgomez@20070425 */ /* Clean up pointer content */ if (d != NULL) *(jk_logger_t **)d = NULL; return APR_SUCCESS; } static int open_jklog(server_rec * s, apr_pool_t * p) { jk_server_conf_t *conf; const char *fname; apr_status_t rc; apr_file_t *jklogfp; piped_log *pl; jk_logger_t *jkl; jk_file_logger_t *flp; int jklog_flags = (APR_WRITE | APR_APPEND | APR_CREATE); apr_fileperms_t jklog_mode = (APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD); conf = ap_get_module_config(s->module_config, &jk_module); if (conf->log_file == NULL) { conf->log_file = ap_server_root_relative(p, JK_LOG_DEF_FILE); if (conf->log_file) ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "No JkLogFile defined in httpd.conf. " "Using default %s", conf->log_file); } if (*(conf->log_file) == '\0') { ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, "mod_jk: Invalid JkLogFile EMPTY"); conf->log = main_log; return 0; } jklogfp = apr_hash_get(jk_log_fps, conf->log_file, APR_HASH_KEY_STRING); if (!jklogfp) { if (*conf->log_file == '|') { if ((pl = ap_open_piped_log(p, conf->log_file + 1)) == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_jk: could not open reliable pipe " "to jk log %s", conf->log_file + 1); return -1; } jklogfp = (void *)ap_piped_log_write_fd(pl); } else { fname = ap_server_root_relative(p, conf->log_file); if (!fname) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, "mod_jk: Invalid JkLog " "path %s", conf->log_file); return -1; } if ((rc = apr_file_open(&jklogfp, fname, jklog_flags, jklog_mode, p)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, "mod_jk: could not open JkLog " "file %s", fname); return -1; } } apr_file_inherit_set(jklogfp); apr_hash_set(jk_log_fps, conf->log_file, APR_HASH_KEY_STRING, jklogfp); } jkl = (jk_logger_t *)apr_palloc(p, sizeof(jk_logger_t)); flp = (jk_file_logger_t *) apr_palloc(p, sizeof(jk_file_logger_t)); if (jkl && flp) { jkl->log = jk_log_to_file; jkl->level = conf->log_level; jkl->logger_private = flp; flp->jklogfp = jklogfp; if (*conf->log_file == '|') flp->is_piped = JK_TRUE; else flp->is_piped = JK_FALSE; conf->log = jkl; jk_set_time_fmt(conf->log, conf->stamp_format_string); if (main_log == NULL) { main_log = conf->log; /* hgomez@20070425 */ /* Shouldn't we clean both conf->log and main_log ? */ /* Also should we pass pointer (ie: main_log) or handle (*main_log) ? */ apr_pool_cleanup_register(p, &main_log, jklog_cleanup, apr_pool_cleanup_null); } return 0; } return -1; } #if APR_HAS_THREADS static void * APR_THREAD_FUNC jk_watchdog_func(apr_thread_t *thd, void *data) { int i; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; jk_server_conf_t *conf = (jk_server_conf_t *)data; l->logger = conf->log; l->id = "WATCHDOG"; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Watchdog thread initialized with %d second interval", jk_watchdog_interval); for (;;) { for (i = 0; i < (jk_watchdog_interval * 10); i++) { /* apr_sleep() uses microseconds */ apr_sleep((apr_time_t)(100000)); if (!jk_watchdog_interval) break; } if (!jk_watchdog_interval) break; if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Watchdog thread running"); jk_watchdog_running = 1; wc_maintain(l); if (!jk_watchdog_interval) break; } jk_watchdog_running = 0; return NULL; } #endif /** Standard apache callback, initialize jk. */ static void jk_child_init(apr_pool_t * pconf, server_rec * s) { jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; jk_server_conf_t *conf; apr_status_t rv; int rc; apr_thread_t *wdt; conf = ap_get_module_config(s->module_config, &jk_module); l->logger = conf->log; l->id = "CHILD_INIT"; rv = apr_global_mutex_child_init(&jk_log_lock, NULL, pconf); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, "mod_jk: could not init JK log lock in child"); } JK_TRACE_ENTER(l); if (jk_watchdog_interval) { #if APR_HAS_THREADS rv = apr_thread_create(&wdt, NULL, jk_watchdog_func, conf, pconf); if (rv != APR_SUCCESS) { jk_log(l, JK_LOG_ERROR, "Could not init watchdog thread, error=%d", rv); jk_watchdog_interval = 0; } apr_thread_detach(wdt); #endif } if ((rc = jk_shm_attach(jk_shm_file, jk_shm_size, l)) == 0) { apr_pool_cleanup_register(pconf, l->logger, jk_cleanup_child, apr_pool_cleanup_null); } else { jk_log(l, JK_LOG_ERROR, "Attaching shm:%s errno=%d", jk_shm_name(), rc); } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Initialized %s", JK_FULL_EXPOSED_VERSION); JK_TRACE_EXIT(l); } /** Initialize jk, using worker.properties. We also use apache commands (JkWorker, etc), but this use is deprecated, as we'll try to concentrate all config in workers.properties, urimap.properties, and ajp14 autoconf. Apache config will only be used for manual override, using SetHandler and normal apache directives (but minimal jk-specific stuff) */ static int init_jk(apr_pool_t * pconf, jk_server_conf_t * conf, server_rec * s) { int rc; int is_threaded; int mpm_threads = 1; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; l->logger = conf->log; l->id = "JK_INIT"; if (!jk_worker_properties) jk_map_alloc(&jk_worker_properties); jk_map_put(jk_worker_properties, "ServerRoot", ap_server_root, NULL); /* Set default connection cache size for multi-threaded MPMs */ if (ap_mpm_query(AP_MPMQ_IS_THREADED, &is_threaded) == APR_SUCCESS && is_threaded != AP_MPMQ_NOT_SUPPORTED) { if (ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads) != APR_SUCCESS) mpm_threads = 1; } if (mpm_threads > 1) { #if _MT_CODE /* _MT_CODE */ if (JK_IS_DEBUG_LEVEL(l)) { #if !defined(WIN32) #if USE_FLOCK_LK jk_log(l, JK_LOG_DEBUG, "Using flock() for locking."); #else jk_log(l, JK_LOG_DEBUG, "Using fcntl() for locking."); #endif /* USE_FLOCK_LK */ #else /* WIN32 */ jk_log(l, JK_LOG_DEBUG, "Not using locking."); #endif } #else /* !_MT_CODE */ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "Cannot run prefork mod_jk on threaded server."); return JK_FALSE; #endif } if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Setting default connection pool max size to %d", mpm_threads); jk_set_worker_def_cache_size(mpm_threads); if ((jk_worker_file != NULL) && !jk_map_read_properties(jk_worker_properties, NULL, jk_worker_file, NULL, JK_MAP_HANDLE_DUPLICATES, l)) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "Error in reading worker properties from '%s'", jk_worker_file); return JK_FALSE; } if (jk_map_resolve_references(jk_worker_properties, "worker.", 1, 1, l) == JK_FALSE) { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "Error in resolving configuration references"); return JK_FALSE; } #if !defined(WIN32) if (!jk_shm_file) { jk_shm_file = ap_server_root_relative(pconf, JK_SHM_DEF_FILE); if (jk_shm_file) ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "No JkShmFile defined in httpd.conf. " "Using default %s", jk_shm_file); } #endif if (jk_shm_size == 0) { jk_shm_size = jk_shm_calculate_size(jk_worker_properties, l); } else if (jk_shm_size_set) { jk_log(l, JK_LOG_WARNING, "The optimal shared memory size can now be determined automatically."); jk_log(l, JK_LOG_WARNING, "You can remove the JkShmSize directive if you want to use the optimal size."); } if ((rc = jk_shm_open(jk_shm_file, jk_shm_size, l)) == 0) { apr_pool_cleanup_register(pconf, l->logger, jk_cleanup_proc, apr_pool_cleanup_null); } else { jk_error_exit(JKLOG_MARK, APLOG_EMERG, s, s->process->pool, "Initializing shm:%s errno=%d. Unable to start due to shared memory failure.", jk_shm_name(), rc); } /* we add the URI->WORKER MAP since workers using AJP14 will feed it */ worker_env.uri_to_worker = conf->uw_map; worker_env.virtual = "*"; /* for now */ #if ((AP_MODULE_MAGIC_AT_LEAST(20051115,4)) && !defined(API_COMPATIBILITY)) || (MODULE_MAGIC_NUMBER_MAJOR >= 20060905) worker_env.server_name = (char *)ap_get_server_description(); #else worker_env.server_name = (char *)ap_get_server_version(); #endif worker_env.pool = pconf; if (wc_open(jk_worker_properties, &worker_env, l)) { ap_add_version_component(pconf, JK_EXPOSED_VERSION); jk_log(l, JK_LOG_INFO, "%s initialized", JK_FULL_EXPOSED_VERSION); } else { ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, "Error in creating the workers." " Please consult your mod_jk log file '%s'.", conf->log_file); return JK_FALSE; } return JK_TRUE; } static int jk_post_config(apr_pool_t * pconf, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * s) { apr_status_t rv; jk_server_conf_t *conf; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; server_rec *srv = s; const char *err_string = NULL; int remain; void *data = NULL; l->logger = NULL; l->id = "POST_CONFIG"; remain = jk_check_buffer_size(); if (remain < 0) { ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, "mod_jk: JK_MAX_ATTRIBUTE_NAME_LEN in jk_util.c is too small, " "increase by %d", -1 * remain); return HTTP_INTERNAL_SERVER_ERROR; } apr_pool_userdata_get(&data, JK_LOG_LOCK_KEY, s->process->pool); if (data == NULL) { /* create the jk log lockfiles in the parent */ if ((rv = apr_global_mutex_create(&jk_log_lock, NULL, APR_LOCK_DEFAULT, s->process->pool)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, "mod_jk: could not create jk_log_lock"); return HTTP_INTERNAL_SERVER_ERROR; } #if JK_NEED_SET_MUTEX_PERMS #if (MODULE_MAGIC_NUMBER_MAJOR >= 20090208) rv = ap_unixd_set_global_mutex_perms(jk_log_lock); #else rv = unixd_set_global_mutex_perms(jk_log_lock); #endif if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, "mod_jk: Could not set permissions on " "jk_log_lock; check User and Group directives"); return HTTP_INTERNAL_SERVER_ERROR; } #endif apr_pool_userdata_set((const void *)jk_log_lock, JK_LOG_LOCK_KEY, apr_pool_cleanup_null, s->process->pool); } else { jk_log_lock = (apr_global_mutex_t *)data; } main_server = s; jk_log_fps = apr_hash_make(pconf); if (!s->is_virtual) { conf = (jk_server_conf_t *)ap_get_module_config(s->module_config, &jk_module); l->logger = conf->log; if (conf->was_initialized == JK_FALSE) { /* step through the servers and open each jk logfile * and do additional post config initialization. */ for (; srv; srv = srv->next) { jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config, &jk_module); /* * If a virtual server contains no JK directive, httpd shares * the config structure. But we don't want to share some settings * by default, especially the JkMount rules. * Therefore we check, if this config structure really belongs to this * vhost, otherwise we create a new one and merge. */ if (sconf && sconf->s != srv) { jk_server_conf_t *srvconf = (jk_server_conf_t *)create_jk_config(pconf, srv); sconf = (jk_server_conf_t *)merge_jk_config(pconf, sconf, srvconf); ap_set_module_config(srv->module_config, &jk_module, sconf); } if (sconf && sconf->was_initialized == JK_FALSE) { sconf->was_initialized = JK_TRUE; if (open_jklog(srv, pconf)) return HTTP_INTERNAL_SERVER_ERROR; l->logger = sconf->log; sconf->options &= ~sconf->exclude_options; dump_options(srv, pconf); if (sconf->uri_to_context) { if (!uri_worker_map_alloc(&(sconf->uw_map), sconf->uri_to_context, l)) jk_error_exit(JKLOG_MARK, APLOG_EMERG, srv, srv->process->pool, "Memory error"); if (sconf->options & JK_OPT_REJECTUNSAFE) sconf->uw_map->reject_unsafe = 1; else sconf->uw_map->reject_unsafe = 0; if (sconf->mount_file) { sconf->uw_map->fname = sconf->mount_file; sconf->uw_map->reload = sconf->mount_file_reload; uri_worker_map_switch(sconf->uw_map, l); uri_worker_map_load(sconf->uw_map, l); } if (sconf->options & JK_OPT_COLLAPSEMASK) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Deprecated CollapseSlashes setting ignored"); } } else { if (sconf->mountcopy == JK_TRUE) { sconf->uw_map = conf->uw_map; } } if (sconf->format_string) { sconf->format = parse_request_log_string(pconf, sconf->format_string, &err_string); if (sconf->format == NULL) ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "JkRequestLogFormat format array NULL"); } if (sconf->envvars && sconf->envvars_has_own) { int i; const apr_array_header_t *arr; const apr_table_entry_t *elts; envvar_item *item; const char *envvar_def; arr = apr_table_elts(sconf->envvars); if (arr) { elts = (const apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; ++i) { item = (envvar_item *)apr_array_push(sconf->envvar_items); if (!item) return HTTP_INTERNAL_SERVER_ERROR; item->name = elts[i].key; envvar_def = apr_table_get(sconf->envvars_def, elts[i].key); if (envvar_def && !strcmp("1", envvar_def)) { item->value = elts[i].val; item->has_default = 1; } else { item->value = ""; item->has_default = 0; } } } } } } conf->was_initialized = JK_TRUE; l->logger = conf->log; if (init_jk(pconf, conf, s) == JK_FALSE) return HTTP_INTERNAL_SERVER_ERROR; if (conf->uw_map) { uri_worker_map_ext(conf->uw_map, l); uri_worker_map_switch(conf->uw_map, l); } for (srv = s; srv; srv = srv->next) { jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config, &jk_module); l->logger = sconf->log; if (conf->uw_map != sconf->uw_map && sconf->uw_map) { uri_worker_map_ext(sconf->uw_map, l); uri_worker_map_switch(sconf->uw_map, l); } } } } return OK; } /** Use the internal mod_jk mappings to find if this is a request for * tomcat and what worker to use. */ static int jk_translate(request_rec * r) { jk_request_conf_t *rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t)); rconf->jk_handled = JK_FALSE; rconf->rule_extensions = NULL; rconf->orig_uri = NULL; ap_set_module_config(r->request_config, &jk_module, rconf); if (!r->proxyreq) { jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; jk_server_conf_t *conf = (jk_server_conf_t *) ap_get_module_config(r->server-> module_config, &jk_module); l->logger = conf->log; l->id = "JK_TRANSLATE"; if (conf) { char *clean_uri; int rc; const char *worker; JK_TRACE_ENTER(l); rconf->request_id = get_env_string(r, NULL, conf->request_id_indicator, 1); if (rconf->request_id == NULL) { rconf->request_id = get_env_string(r, NULL, JK_ENV_REQUEST_ID, 1); } l->id = rconf->request_id; if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) { /* Somebody already set the handler, probably manual config * or "native" configuration, no need for extra overhead */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Manually mapped, no need to call uri_to_worker"); JK_TRACE_EXIT(l); return DECLINED; } if (apr_table_get(r->subprocess_env, "no-jk")) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Into translate no-jk env var detected for uri=%s, declined", r->uri); JK_TRACE_EXIT(l); return DECLINED; } clean_uri = apr_pstrdup(r->pool, r->uri); rc = jk_servlet_normalize(clean_uri, l); if (rc != 0) { JK_TRACE_EXIT(l); return HTTP_BAD_REQUEST; } /* Special case to make sure that apache can serve a directory listing if there are no matches for the DirectoryIndex and Tomcat webapps are mapped into apache using JkAutoAlias. */ if (r->main != NULL && r->main->handler != NULL && (conf->alias_dir != NULL) && !strcmp(r->main->handler, DIR_MAGIC_TYPE)) { /* Append the request uri to the JkAutoAlias directory and determine if the file exists. */ apr_finfo_t finfo; finfo.filetype = APR_NOFILE; /* Map uri to a context static file */ if (strlen(clean_uri) > 1) { char *context_path = NULL; context_path = apr_pstrcat(r->pool, conf->alias_dir, clean_uri, NULL); if (context_path != NULL) { apr_stat(&finfo, context_path, APR_FINFO_TYPE, r->pool); } } if (finfo.filetype != APR_REG) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "JkAutoAlias, no DirectoryIndex file for URI %s", r->uri); JK_TRACE_EXIT(l); return DECLINED; } } if (!conf->uw_map) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "missing uri map for %s:%s", conf->s->server_hostname ? conf->s->server_hostname : "_default_", r->uri); JK_TRACE_EXIT(l); return DECLINED; } else { rule_extension_t *e; worker = map_uri_to_worker_ext(conf->uw_map, clean_uri, NULL, &e, NULL, l); if (worker) { rconf->rule_extensions = e; rconf->orig_uri = r->uri; r->uri = clean_uri; } } if (worker) { r->handler = apr_pstrdup(r->pool, JK_HANDLER); apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker); /* This could be a sub-request, possibly from mod_dir */ /* Also add the the HANDLER to the main request */ if (r->main) { r->main->handler = apr_pstrdup(r->main->pool, JK_HANDLER); apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker); } JK_TRACE_EXIT(l); return OK; } else if (conf->alias_dir != NULL) { /* Automatically map uri to a context static file */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "check alias_dir: %s", conf->alias_dir); if (strlen(clean_uri) > 1) { /* Get the context directory name */ char *context_dir = NULL; char *context_path = NULL; char *child_dir = NULL; char *index = clean_uri; char *suffix = strchr(index + 1, '/'); if (suffix != NULL) { int size = (int)(suffix - index); context_dir = apr_pstrndup(r->pool, index, size); /* Get the context child directory name */ index = index + size + 1; suffix = strchr(index, '/'); if (suffix != NULL) { size = (int)(suffix - index); child_dir = apr_pstrndup(r->pool, index, size); } else { child_dir = index; } /* Deny access to WEB-INF and META-INF directories */ if (child_dir != NULL) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "AutoAlias child_dir: %s", child_dir); if (!strcasecmp(child_dir, "WEB-INF") || !strcasecmp(child_dir, "META-INF")) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "AutoAlias HTTP_NOT_FOUND for URI: %s", r->uri); JK_TRACE_EXIT(l); return HTTP_NOT_FOUND; } } } else { context_dir = apr_pstrdup(r->pool, index); } context_path = apr_pstrcat(r->pool, conf->alias_dir, context_dir, NULL); if (context_path != NULL) { apr_finfo_t finfo; finfo.filetype = APR_NOFILE; apr_stat(&finfo, context_path, APR_FINFO_TYPE, r->pool); if (finfo.filetype == APR_DIR) { char *ret = apr_pstrcat(r->pool, conf->alias_dir, clean_uri, NULL); /* Add code to verify real path ap_os_canonical_name */ if (ret != NULL) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "AutoAlias OK for file: %s", ret); r->filename = ret; JK_TRACE_EXIT(l); return OK; } } else { /* Deny access to war files in web app directory */ int size = (int)strlen(context_dir); if (size > 4 && !strcasecmp(context_dir + (size - 4), ".war")) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "AutoAlias HTTP_FORBIDDEN for URI: %s", r->uri); JK_TRACE_EXIT(l); return HTTP_FORBIDDEN; } } } } } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "no match for %s found", r->uri); } } } return DECLINED; } /* bypass the directory_walk and file_walk for non-file requests */ static int jk_map_to_storage(request_rec * r) { jk_server_conf_t *conf; jk_request_conf_t *rconf = ap_get_module_config(r->request_config, &jk_module); if (rconf == NULL) { rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t)); rconf->jk_handled = JK_FALSE; rconf->rule_extensions = NULL; rconf->orig_uri = NULL; ap_set_module_config(r->request_config, &jk_module, rconf); } if (!r->proxyreq) { conf = (jk_server_conf_t *) ap_get_module_config(r->server-> module_config, &jk_module); if (conf) { rconf->request_id = get_env_string(r, NULL, conf->request_id_indicator, 1); if (rconf->request_id == NULL) { rconf->request_id = get_env_string(r, NULL, JK_ENV_REQUEST_ID, 1); } } } if (!r->proxyreq && !apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) { if (conf) { char *clean_uri; int rc; const char *worker; jk_log_context_t log_ctx; jk_log_context_t *l = &log_ctx; l->logger = conf->log; l->id = rconf->request_id; JK_TRACE_ENTER(l); if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) { /* Somebody already set the handler, probably manual config * or "native" configuration, no need for extra overhead */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Manually mapped, no need to call uri_to_worker"); JK_TRACE_EXIT(l); return DECLINED; } if (apr_table_get(r->subprocess_env, "no-jk")) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "Into map_to_storage no-jk env var detected for uri=%s, declined", r->uri); JK_TRACE_EXIT(l); return DECLINED; } // Not a URI based request - e.g. file based SSI include if (strlen(r->uri) == 0) { jk_log(l, JK_LOG_DEBUG, "File based (sub-)request for file=%s. No URI to match.", r->filename); JK_TRACE_EXIT(l); return DECLINED; } clean_uri = apr_pstrdup(r->pool, r->uri); rc = jk_servlet_normalize(clean_uri, l); if (rc != 0) { JK_TRACE_EXIT(l); return HTTP_BAD_REQUEST; } if (!conf->uw_map) { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "missing uri map for %s:%s", conf->s->server_hostname ? conf->s->server_hostname : "_default_", r->uri); JK_TRACE_EXIT(l); return DECLINED; } else { rule_extension_t *e; worker = map_uri_to_worker_ext(conf->uw_map, clean_uri, NULL, &e, NULL, l); if (worker) { rconf->rule_extensions = e; rconf->orig_uri = r->uri; r->uri = clean_uri; } } if (worker) { r->handler = apr_pstrdup(r->pool, JK_HANDLER); apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker); /* This could be a sub-request, possibly from mod_dir */ if (r->main) apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker); } else { if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, "no match for %s found", r->uri); if (conf->strip_session == JK_TRUE && conf->strip_session_name) { if (r->uri) { jk_strip_session_id(r->uri, conf->strip_session_name, l); } if (r->filename) { jk_strip_session_id(r->filename, conf->strip_session_name, l); } JK_TRACE_EXIT(l); return DECLINED; } } JK_TRACE_EXIT(l); } } if (apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) { /* First find just the name of the file, no directory */ r->filename = (char *)apr_filepath_name_get(r->uri); /* Only if sub-request for a directory, most likely from mod_dir */ if (r->main && r->main->filename && (!apr_filepath_name_get(r->main->filename) || !strlen(apr_filepath_name_get(r->main->filename)))) { /* The filename from the main request will be set to what should * be picked up, aliases included. Tomcat will need to know about * those aliases or things won't work for them. Normal files should * be fine. */ /* Need absolute path to stat */ if (apr_filepath_merge(&r->filename, r->main->filename, r->filename, APR_FILEPATH_SECUREROOT | APR_FILEPATH_TRUENAME, r->pool) != APR_SUCCESS) { return DECLINED; /* We should never get here, very bad */ } /* Stat the file so that mod_dir knows it's there */ apr_stat(&r->finfo, r->filename, APR_FINFO_TYPE, r->pool); } return OK; } return DECLINED; } static void jk_register_hooks(apr_pool_t * p) { ap_hook_post_config(jk_post_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_child_init(jk_child_init, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_translate_name(jk_translate, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_map_to_storage(jk_map_to_storage, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_handler(jk_handler, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_log_transaction(request_log_transaction, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA jk_module = { STANDARD20_MODULE_STUFF, NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ create_jk_config, /* server config */ merge_jk_config, /* merge server config */ jk_cmds, /* command ap_table_t */ jk_register_hooks /* register hooks */ }; tomcat-connectors-1.2.50-src/native/apache-2.0/.gitignore0000644000000000000020000000014014655113617021313 0ustar rootbin.libs Makefile Makefile.apxs *.a *.o *.lo *.la *.slo *.so Release Debug *.dsw *.ncb *.opt *.plg tomcat-connectors-1.2.50-src/native/apache-2.0/config.m40000644000000000000020000000246714655113617021050 0ustar rootbindnl -------------------------------------------------------- -*- autoconf -*- dnl Licensed to the Apache Software Foundation (ASF) under one or more dnl contributor license agreements. See the NOTICE file distributed with dnl this work for additional information regarding copyright ownership. dnl The ASF licenses this file to You under the Apache License, Version 2.0 dnl (the "License"); you may not use this file except in compliance with dnl the License. You may obtain a copy of the License at dnl dnl http://www.apache.org/licenses/LICENSE-2.0 dnl dnl Unless required by applicable law or agreed to in writing, software dnl distributed under the License is distributed on an "AS IS" BASIS, dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. dnl See the License for the specific language governing permissions and dnl limitations under the License. AC_MSG_CHECKING(for mod_jk module) AC_ARG_WITH(mod_jk, [ --with-mod_jk Include the mod_jk (static).], [ modpath_current=modules/jk module=jk libname=lib_jk.la BUILTIN_LIBS="$BUILTIN_LIBS $modpath_current/$libname" cat >>$modpath_current/modules.mk<NUL tomcat-connectors-1.2.50-src/native/apache-2.0/bldjk54.qclsrc0000644000000000000020000002415614655113617022010 0ustar rootbinPGM CRTCMOD MODULE(MOD_JK/MOD_JK) + SRCSTMF('/home/apache/jk/native/apache-2.0/mod_jk.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('mod_jk.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP_COM) + SRCSTMF('/home/apache/jk/native/common/jk_ajp_common.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp_common.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP12_W) + SRCSTMF('/home/apache/jk/native/common/jk_ajp12_worker.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp12_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP13) + SRCSTMF('/home/apache/jk/native/common/jk_ajp13.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp13.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP13_W) + SRCSTMF('/home/apache/jk/native/common/jk_ajp13_worker.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp13_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP14) + SRCSTMF('/home/apache/jk/native/common/jk_ajp14.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp14.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP14_W) + SRCSTMF('/home/apache/jk/native/common/jk_ajp14_worker.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp14_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_CONNECT) + SRCSTMF('/home/apache/jk/native/common/jk_connect.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT' + 'USE_SO_RCVTIMEO' + 'USE_SO_SNDTIMEO' ) + TEXT('jk_connect.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_CONTEXT) + SRCSTMF('/home/apache/jk/native/common/jk_context.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_context.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_LB_WORK) + SRCSTMF('/home/apache/jk/native/common/jk_lb_worker.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_lb_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_MAP) + SRCSTMF('/home/apache/jk/native/common/jk_map.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_map.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_MD5) + SRCSTMF('/home/apache/jk/native/common/jk_md5.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_md5.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_MSG_BUF) + SRCSTMF('/home/apache/jk/native/common/jk_msg_buff.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_msg_buff.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_POOL) + SRCSTMF('/home/apache/jk/native/common/jk_pool.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_pool.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_SOCKBUF) + SRCSTMF('/home/apache/jk/native/common/jk_sockbuf.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_sockbuf.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_URI_W_M) + SRCSTMF('/home/apache/jk/native/common/jk_uri_worker_map.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_uri_worker_map.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_URL) + SRCSTMF('/home/apache/jk/native/common/jk_url.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_url.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_UTIL) + SRCSTMF('/home/apache/jk/native/common/jk_util.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_util.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_WORKER) + SRCSTMF('/home/apache/jk/native/common/jk_worker.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_STATUS) + SRCSTMF('/home/apache/jk/native/common/jk_status.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_status.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_SHM) + SRCSTMF('/home/apache/jk/native/common/jk_shm.c') + DEFINE('AS400' 'AS400_UTF8' 'HAVE_APR' + '_XOPEN_SOURCE=520' 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_shm.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALEUTF) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TERASPACE(*YES) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTSRVPGM SRVPGM(MOD_JK/MOD_JK) + MODULE(MOD_JK/MOD_JK + MOD_JK/JK_AJP_COM MOD_JK/JK_AJP12_W + MOD_JK/JK_AJP13 MOD_JK/JK_AJP13_W + MOD_JK/JK_AJP14 MOD_JK/JK_AJP14_W + MOD_JK/JK_CONNECT MOD_JK/JK_CONTEXT + MOD_JK/JK_LB_WORK + MOD_JK/JK_MAP MOD_JK/JK_MD5 + MOD_JK/JK_MSG_BUF MOD_JK/JK_POOL + MOD_JK/JK_SOCKBUF MOD_JK/JK_URI_W_M + MOD_JK/JK_URL + MOD_JK/JK_UTIL MOD_JK/JK_WORKER + MOD_JK/JK_STATUS MOD_JK/JK_SHM) + EXPORT(*SRCFILE) + BNDDIR() + TGTRLS(*CURRENT) + SRCFILE(MOD_JK/QSRVSRC) + SRCMBR(MOD_JK) + USRPRF(*USER) + BNDSRVPGM(QHTTPSVR/QZSRAPR QHTTPSVR/QZSRCORE + QHTTPSVR/QZSRXMLP QHTTPSVR/QZSRSDBM) + TEXT('Apache Tomcat mod_jk connector module') ENDPGM tomcat-connectors-1.2.50-src/native/apache-2.0/bldjk.qclsrc0000644000000000000020000002250514655113617021633 0ustar rootbinPGM CRTCMOD MODULE(MOD_JK/MOD_JK) + SRCSTMF('/home/apache/jk/native/apache-2.0/mod_jk.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('mod_jk.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP_COM) + SRCSTMF('/home/apache/jk/native/common/jk_ajp_common.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp_common.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP12_W) + SRCSTMF('/home/apache/jk/native/common/jk_ajp12_worker.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp12_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP13) + SRCSTMF('/home/apache/jk/native/common/jk_ajp13.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp13.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP13_W) + SRCSTMF('/home/apache/jk/native/common/jk_ajp13_worker.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp13_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP14) + SRCSTMF('/home/apache/jk/native/common/jk_ajp14.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp14.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_AJP14_W) + SRCSTMF('/home/apache/jk/native/common/jk_ajp14_worker.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_ajp14_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_CONNECT) + SRCSTMF('/home/apache/jk/native/common/jk_connect.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT' 'USE_SO_RCVTIMEO' + 'USE_SO_SNDTIMEO' ) + TEXT('jk_connect.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_CONTEXT) + SRCSTMF('/home/apache/jk/native/common/jk_context.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_context.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_LB_WORK) + SRCSTMF('/home/apache/jk/native/common/jk_lb_worker.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_lb_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_MAP) + SRCSTMF('/home/apache/jk/native/common/jk_map.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_map.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_MD5) + SRCSTMF('/home/apache/jk/native/common/jk_md5.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_md5.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_MSG_BUF) + SRCSTMF('/home/apache/jk/native/common/jk_msg_buff.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_msg_buff.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_POOL) + SRCSTMF('/home/apache/jk/native/common/jk_pool.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_pool.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_SOCKBUF) + SRCSTMF('/home/apache/jk/native/common/jk_sockbuf.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_sockbuf.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_URI_W_M) + SRCSTMF('/home/apache/jk/native/common/jk_uri_worker_map.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_uri_worker_map.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_URL) + SRCSTMF('/home/apache/jk/native/common/jk_url.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_url.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_UTIL) + SRCSTMF('/home/apache/jk/native/common/jk_util.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_util.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_WORKER) + SRCSTMF('/home/apache/jk/native/common/jk_worker.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_worker.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_STATUS) + SRCSTMF('/home/apache/jk/native/common/jk_status.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_status.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTCMOD MODULE(MOD_JK/JK_SHM) + SRCSTMF('/home/apache/jk/native/common/jk_shm.c') + DEFINE('AS400' 'HAVE_APR' '_XOPEN_SOURCE=520' + 'USE_APACHE_MD5' '_REENTRANT') + TEXT('jk_shm.c') + OPTIMIZE(40) + LOCALETYPE(*LOCALE) + SYSIFCOPT(*IFSIO) + LANGLVL(*EXTENDED) + TGTRLS(*CURRENT) + INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include') CRTSRVPGM SRVPGM(MOD_JK/MOD_JK) + MODULE(MOD_JK/MOD_JK + MOD_JK/JK_AJP_COM MOD_JK/JK_AJP12_W + MOD_JK/JK_AJP13 MOD_JK/JK_AJP13_W + MOD_JK/JK_AJP14 MOD_JK/JK_AJP14_W + MOD_JK/JK_CONNECT MOD_JK/JK_CONTEXT + MOD_JK/JK_LB_WORK + MOD_JK/JK_MAP MOD_JK/JK_MD5 + MOD_JK/JK_MSG_BUF MOD_JK/JK_POOL + MOD_JK/JK_SOCKBUF MOD_JK/JK_URI_W_M + MOD_JK/JK_URL + MOD_JK/JK_UTIL MOD_JK/JK_WORKER + MOD_JK/JK_STATUS MOD_JK/JK_SHM) + EXPORT(*SRCFILE) + BNDDIR() + TGTRLS(*CURRENT) + SRCFILE(MOD_JK/QSRVSRC) + SRCMBR(MOD_JK) + USRPRF(*USER) + BNDSRVPGM(QHTTPSVR/QZSRAPR QHTTPSVR/QZSRCORE + QHTTPSVR/QZSRXMLP QHTTPSVR/QZSRSDBM) + TEXT('Apache Tomcat mod_jk connector module') ENDPGM tomcat-connectors-1.2.50-src/native/BUILDING.txt0000644000000000000020000001064714655113617017560 0ustar rootbin Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. General Build Instructions ========================== To build tomcat-connectors you need to run "configure" and "make": ./configure [autoconf arguments] [tomcat-connectors arguments] make It is possible to set CFLAGS and LDFLAGS to add some platform specifics: LDFLAGS=-lc \ ./configure -with-apxs=/home2/local/apache/bin/apxs To find out about all available configure flags use ./configure --help Build for the Apache HTTP Server ================================ If you want to build mod_jk for the Apache HTTP Server you need to locate the apxs tool coming with the Apache HTTP server. If apxs is located in /usr/sbin/apxs, run: ./configure --with-apxs=/usr/sbin/apxs make The resulting module file mod_jk.so of mod_jk will be located in the directory apache-2.0 (for any version of Apache 2.x). Simply copy the file to your web server modules or libexec directory. Apache related configure arguments for tomcat-connectors -------------------------------------------------------- --with-apxs[=FILE] FILE is the location of the apxs tool. Default is finding apxs in PATH. It builds a shared Apache module. It detects automatically the Apache version. (2.x and 1.3) --with-apache=DIR DIR is the path where apache sources are located. The apache sources should have been configured before configuring mod_jk. DIR is something like: /home/apache/apache_1.3.19 It builds a static Apache module. --enable-EAPI This parameter is needed when using Apache 1.3 and mod_ssl, otherwise you will get the error message: "this module might crash under EAPI!" when loading libjk.so in httpd. Static build needs more tests, and we strongly recommend dynamic build using DSO/APXS. Misc Notes ========== Build for Multiple Web Servers ------------------------------ If you want to build for multiple web servers, you need to call "make clean" between the individual builds. HP-UX build notes ----------------- If you plan to use GCC on HP-UX to build mod_jk, be sure to have -DHPUX11GCC defined (usually by setting CLAGS before configure) Reports are that the stripped down cc version that ships with HP-UX won't be able to work, you should have the HP add-on ANSI C Compiler package. A good repository for HP-UX gnu tools is: http://gatekeep.cs.utah.edu/ Solaris build notes ------------------- The build should work with the GNU gcc compiler, on both SPARC and x86 architecture systems. A good repository for Solaris gnu tools is: http://www.sunfreeware.com/ Be carefull when mixing native compiler and gnu compiler, and ensure that apache and mod_jk will be compiled and linked with the same tools (i.e. full Solaris or full GNU) Building from the subversion tree ================================= This is only necessary if you want to build a not yet released versions. When using a subversion tree, "buildconf.sh" must be run before configure. This script uses the auto tools to provide the following files: - libtool files in scripts/build/unix (should copy them?) - Makefile.in from Makefile.am - aclocal.m4 from different m4 files located on the local machine - configure from configure.ac and aclocal.m4 buildconf.sh is known to work with libtool 1.5.2, automake 1.10 and autoconf 2.59 or newer. The use of more recent versions is strongly encouraged, e.g. for reliable detection of the features of recent version of operating systems (e.g. AIX 6.1). The script is run without arguments: ./buildconf.sh If you see error messages from automake, don't care about them. After running buildconf you can build as usual using configure and make. tomcat-connectors-1.2.50-src/native/Makefile.am0000644000000000000020000000252214655113617017647 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Tell automake what it should do AUTOMAKE_OPTIONS = foreign MAINTAINERCLEANFILES=config.cache config.status config.log \ config.nice Makefile.in configure common/config.h.in \ common/config.h aclocal.m4 SUBDIRS = @WEBSERVER@ all: target="all"; \ list='$(SUBDIRS)'; \ for i in $$list; do \ echo "Making $$target in $$i"; \ if test "$$i" != "."; then \ (cd $$i && $(MAKE) $$target) || exit 1; \ fi; \ done; apidocs: common/*.h ../../scandoc/scandoc.pl -i ../../scandoc/template.pl -p \ ./docs/api/ -dproject="mod_jk Library" common/*.h common/*.c tomcat-connectors-1.2.50-src/native/configure0000755000000000000020000171200614655113624017526 0ustar rootbin#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for mod_jk 1.2.50. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='mod_jk' PACKAGE_TARNAME='mod_jk' PACKAGE_VERSION='1.2.50' PACKAGE_STRING='mod_jk 1.2.50' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="common/jk_worker.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS INSTALL_TYPE LIB_JK_TYPE APACHE20_OEXT MAKE_DYNAMIC_APACHE_FALSE MAKE_DYNAMIC_APACHE_TRUE WEBSERVER APXSLDFLAGS APXSCPPFLAGS APXSCFLAGS APACHE_DIR apache_include pthread_t_value pthread_t_fmt pid_t_fmt uint64_t_hex_fmt uint64_t_fmt int64_t_fmt int64_value uint32_t_hex_fmt uint32_t_fmt int32_t_fmt int32_value LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LIBTOOL LD FGREP EGREP am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CC APACHE_CONFIG_VARS APXS PERL CFLAGS MKDIR CP SED ECHO GREP TEST AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V CSCOPE ETAGS CTAGS am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules with_apxs enable_dependency_tracking with_gnu_ld enable_shared enable_static with_pic enable_fast_install with_aix_soname with_sysroot enable_libtool_lock enable_sock_cloexec with_apache enable_EAPI enable_maintainer_mode enable_prefork enable_trace enable_api_compatibility enable_flock ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS LT_SYS_LIBRARY_PATH' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" 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 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures mod_jk 1.2.50 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/mod_jk] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _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] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of mod_jk 1.2.50:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --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) --disable-sock-cloexec Disable use of SOCK_CLOEXEC. This ensures the built module can be used on systems that do not support SOCK_CLOEXEC --enable-EAPI Enable EAPI support (mod_ssl, Apache 1.3) --enable-maintainer-mode Turn on debugging and compile time warnings --enable-prefork Turn on prefork web server mode (single-threaded) --disable-trace Exclude trace log code from compilation --enable-api-compatibility Only use httpd API functions available in all production releases. This improves binary compatibility of module builds with httpd releases older than the release against we build (only between minor versions). --enable-flock Turn on flock for shared locking if present Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-apxs[=FILE] Build shared Apache module. FILE is the optional pathname to the apxs tool; defaults to finding apxs in your PATH. --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-aix-soname=aix|svr4|both shared library versioning (aka "SONAME") variant to provide on AIX, [default=aix]. --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-apache=DIR Build static Apache module. DIR is the pathname to the Apache source directory. 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 LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory LT_SYS_LIBRARY_PATH User-defined run-time library search path. Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF mod_jk configure 1.2.50 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* 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_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid; break else $as_nop as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_lo=$ac_mid; break else $as_nop as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done else $as_nop ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid else $as_nop as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval (void) { return $2; } static unsigned long int ulongval (void) { return $2; } #include #include int main (void) { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : echo >>conftest.val; read $3 config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by mod_jk $as_me 1.2.50, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append 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 as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } 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. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Auxiliary files required by this configure script. ac_aux_files="ltmain.sh compile missing install-sh config.guess config.sub" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}/scripts/build/unix" # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$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. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers common/config.h" # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 printf %s "checking target system type... " >&6; } if test ${ac_cv_target+y} then : printf %s "(cached) " >&6 else $as_nop if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 printf "%s\n" "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- am__api_version='1.16' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_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 rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$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' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # 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 ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file 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 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". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file 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 $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ 'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$MKDIR_P" >&6; } 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 # Check whether --enable-silent-rules was given. if test ${enable_silent_rules+y} then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else $as_nop if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi 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='mod_jk' VERSION='1.2.50' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # 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"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi rm -f config.nice cat >config.nice<> config.nice fi if test -n "$CFLAGS"; then echo "CFLAGS=\"$CFLAGS\"; export CFLAGS" >> config.nice fi if test -n "$CPPFLAGS"; then echo "CPPFLAGS=\"$CPPFLAGS\"; export CPPFLAGS" >> config.nice fi if test -n "$LDFLAGS"; then echo "LDFLAGS=\"$LDFLAGS\"; export LDFLAGS" >> config.nice fi if test -n "$LTFLAGS"; then echo "LTFLAGS=\"$LTFLAGS\"; export LTFLAGS" >> config.nice fi if test -n "$LIBS"; then echo "LIBS=\"$LIBS\"; export LIBS" >> config.nice fi if test -n "$INCLUDES"; then echo "INCLUDES=\"$INCLUDES\"; export INCLUDES" >> config.nice fi if test -n "$NOTEST_CFLAGS"; then echo "NOTEST_CFLAGS=\"$NOTEST_CFLAGS\"; export NOTEST_CFLAGS" >> config.nice fi if test -n "$NOTEST_CPPFLAGS"; then echo "NOTEST_CPPFLAGS=\"$NOTEST_CPPFLAGS\"; export NOTEST_CPPFLAGS" >> config.nice fi if test -n "$NOTEST_LDFLAGS"; then echo "NOTEST_LDFLAGS=\"$NOTEST_LDFLAGS\"; export NOTEST_LDFLAGS" >> config.nice fi if test -n "$NOTEST_LIBS"; then echo "NOTEST_LIBS=\"$NOTEST_LIBS\"; export NOTEST_LIBS" >> config.nice fi # Retrieve command-line arguments. eval "set x $0 $ac_configure_args" shift for arg do jk_last= jk_cur="$arg" while test "x${jk_cur}" != "x${jk_last}"; do jk_last="${jk_cur}" jk_cur=`eval "echo ${jk_cur}"` done arg="${jk_cur}" echo "\"$arg\" \\" >> config.nice done echo '"$@"' >> config.nice chmod +x config.nice # Extract the first word of "test", so it can be a program name with args. set dummy test; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_TEST+y} then : printf %s "(cached) " >&6 else $as_nop case $TEST in [\\/]* | ?:[\\/]*) ac_cv_path_TEST="$TEST" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_TEST="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_TEST" && ac_cv_path_TEST="$PATH" ;; esac fi TEST=$ac_cv_path_TEST if test -n "$TEST"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEST" >&5 printf "%s\n" "$TEST" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Extract the first word of "grep", so it can be a program name with args. set dummy grep; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop case $GREP in [\\/]* | ?:[\\/]*) ac_cv_path_GREP="$GREP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_GREP="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_GREP" && ac_cv_path_GREP="$PATH" ;; esac fi GREP=$ac_cv_path_GREP if test -n "$GREP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GREP" >&5 printf "%s\n" "$GREP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Extract the first word of "echo", so it can be a program name with args. set dummy echo; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ECHO+y} then : printf %s "(cached) " >&6 else $as_nop case $ECHO in [\\/]* | ?:[\\/]*) ac_cv_path_ECHO="$ECHO" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ECHO="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_ECHO" && ac_cv_path_ECHO="echo" ;; esac fi ECHO=$ac_cv_path_ECHO if test -n "$ECHO"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ECHO" >&5 printf "%s\n" "$ECHO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Extract the first word of "sed", so it can be a program name with args. set dummy sed; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 else $as_nop case $SED in [\\/]* | ?:[\\/]*) ac_cv_path_SED="$SED" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_SED="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_SED" && ac_cv_path_SED="$PATH" ;; esac fi SED=$ac_cv_path_SED if test -n "$SED"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 printf "%s\n" "$SED" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Extract the first word of "cp", so it can be a program name with args. set dummy cp; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_CP+y} then : printf %s "(cached) " >&6 else $as_nop case $CP in [\\/]* | ?:[\\/]*) ac_cv_path_CP="$CP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_CP="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_CP" && ac_cv_path_CP="$PATH" ;; esac fi CP=$ac_cv_path_CP if test -n "$CP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CP" >&5 printf "%s\n" "$CP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # Extract the first word of "mkdir", so it can be a program name with args. set dummy mkdir; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_MKDIR+y} then : printf %s "(cached) " >&6 else $as_nop case $MKDIR in [\\/]* | ?:[\\/]*) ac_cv_path_MKDIR="$MKDIR" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_MKDIR="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_MKDIR" && ac_cv_path_MKDIR="$PATH" ;; esac fi MKDIR=$ac_cv_path_MKDIR if test -n "$MKDIR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR" >&5 printf "%s\n" "$MKDIR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi CFLAGS="${CFLAGS} -DHAVE_CONFIG_H" configure_dir=`dirname $0` configure_dir=`cd $configure_dir; pwd` APACHE_CONFIG_VARS=$configure_dir/scripts/build/config_vars.mk WEBSERVER="" apache_dir="" apache_include="" APXS="apxs" # Check whether --with-apxs was given. if test ${with_apxs+y} then : withval=$with_apxs; case "${withval}" in y | yes | true) find_apxs=true ;; n | no | false) find_apxs= ;; *) find_apxs=${withval} ;; esac if ${TEST} ${find_apxs} ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: need to check for Perl first, apxs depends on it..." >&5 printf "%s\n" "need to check for Perl first, apxs depends on it..." >&6; } # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PERL+y} then : printf %s "(cached) " >&6 else $as_nop case $PERL in [\\/]* | ?:[\\/]*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PERL="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="$PATH" ;; esac fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 printf "%s\n" "$PERL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if ${TEST} ${find_apxs} = true ; then # Extract the first word of "apxs", so it can be a program name with args. set dummy apxs; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_APXS+y} then : printf %s "(cached) " >&6 else $as_nop case $APXS in [\\/]* | ?:[\\/]*) ac_cv_path_APXS="$APXS" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_APXS="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_APXS" && ac_cv_path_APXS="$PATH" ;; esac fi APXS=$ac_cv_path_APXS if test -n "$APXS"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $APXS" >&5 printf "%s\n" "$APXS" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi else APXS=${find_apxs} fi if ${TEST} -n "${APXS}" ; then if ${TEST} ! -x "${APXS}" ; then as_fn_error $? "Invalid location for apxs: '${APXS}'" "$LINENO" 5 fi ${APXS} -q PREFIX >/dev/null 2>/dev/null || apxs_support=false if ${TEST} "${apxs_support}" = "false" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: could not find ${APXS}" >&5 printf "%s\n" "could not find ${APXS}" >&6; } as_fn_error $? "You must specify a valid --with-apxs path" "$LINENO" 5 fi apache_dir=`$APXS -q PREFIX` apache_include="-I`$APXS -q INCLUDEDIR`" APA=`${GREP} STANDARD20 ${APXS}` if ${TEST} -z "$APA" ; then as_fn_error $? "No Apache 2.x found" "$LINENO" 5 fi WEBSERVER="apache-2.0" APRINCLUDEDIR="" INCTEMP="`$APXS -q APR_INCLUDEDIR` `$APXS -q APU_INCLUDEDIR`" for INC in ${INCTEMP}; do APRINCLUDEDIR="${APRINCLUDEDIR} -I${INC}" done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: APRINCLUDEDIR is $APRINCLUDEDIR" >&5 printf "%s\n" "APRINCLUDEDIR is $APRINCLUDEDIR" >&6; } APXSCC="`$APXS -q CC`" APXSCFLAGS="`${APXS} -q CFLAGS` `${APXS} -q EXTRA_CFLAGS` -DHAVE_APR ${APRINCLUDEDIR}" APXSCPPFLAGS="`${APXS} -q EXTRA_CPPFLAGS`" APXSLDFLAGS="`$APXS -q LDFLAGS`" APACHE_CONFIG_VARS="`${APXS} -q exp_installbuilddir`/config_vars.mk" LIBTOOL=`$APXS -q LIBTOOL` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: building connector for \"$WEBSERVER\"" >&5 printf "%s\n" "building connector for \"$WEBSERVER\"" >&6; } if ${TEST} -z "${CC}" ; then CC="${APXSCC}" else if ${TEST} "${CC}" != "$APXSCC" ; then WARN_CC=1 fi fi fi fi else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no apxs given" >&5 printf "%s\n" "no apxs given" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_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" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; 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 ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" 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 DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop 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". rm -rf conftest.dir 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 # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub 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 am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # 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. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # 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. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; 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 ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/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 # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 printf %s "checking for a sed that does not truncate output... " >&6; } if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 else $as_nop ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in sed gsed do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 printf "%s\n" "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 printf %s "checking for fgrep... " >&6; } if test ${ac_cv_path_FGREP+y} then : printf %s "(cached) " >&6 else $as_nop if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in fgrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 printf "%s\n" "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 printf %s "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case $ECHO in printf*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5 printf "%s\n" "printf" >&6; } ;; print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 printf "%s\n" "print -r" >&6; } ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5 printf "%s\n" "cat" >&6; } ;; esac # Check whether --with-gnu-ld was given. if test ${with_gnu_ld+y} then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else $as_nop with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 printf %s "checking for ld used by $CC... " >&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. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname 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 yes = "$with_gnu_ld"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 printf %s "checking for GNU ld... " >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 printf %s "checking for non-GNU ld... " >&6; } fi if test ${lt_cv_path_LD+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs 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 variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 printf "%s\n" "$LD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 printf %s "checking if the linker ($LD) is GNU ld... " >&6; } if test ${lt_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 else $as_nop # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld SAVE_LIBTOOL="$LIBTOOL" enable_dlopen=yes case `pwd` in *\ * | *\ *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.6' macro_revision='2.4.6' ltmain=$ac_aux_dir/ltmain.sh # Backslashify metacharacters that are still active within # double-quoted strings. 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' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if test ${lt_cv_path_NM+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_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 # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) 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 ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 printf "%s\n" "$lt_cv_path_NM" >&6; } if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 printf "%s\n" "$DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DUMPBIN+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 printf "%s\n" "$ac_ct_DUMPBIN" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 printf %s "checking the name lister ($NM) interface... " >&6; } if test ${lt_cv_nm_interface+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 printf "%s\n" "$lt_cv_nm_interface" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 printf %s "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 printf "%s\n" "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 printf %s "checking the maximum length of command line arguments... " >&6; } if test ${lt_cv_sys_max_cmd_len+y} then : printf %s "(cached) " >&6 else $as_nop i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n "$lt_cv_sys_max_cmd_len"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 printf "%s\n" "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 printf %s "checking how to convert $build file names to $host format... " >&6; } if test ${lt_cv_to_host_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 printf %s "checking how to convert $build file names to toolchain format... " >&6; } if test ${lt_cv_to_tool_file_cmd+y} then : printf %s "(cached) " >&6 else $as_nop #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 printf %s "checking for $LD option to reload object files... " >&6; } if test ${lt_cv_ld_reload_flag+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_reload_flag='-r' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 printf "%s\n" "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; then reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 printf "%s\n" "$OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OBJDUMP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 printf "%s\n" "$ac_ct_OBJDUMP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 printf %s "checking how to recognize dependent libraries... " >&6; } if test ${lt_cv_deplibs_check_method+y} then : printf %s "(cached) " >&6 else $as_nop 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 # that responds to the $file_magic_cmd with a given extended 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 aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) 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*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) 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|DragonFly)/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 ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) 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_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' 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 ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) 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 ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 printf "%s\n" "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 printf "%s\n" "$DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DLLTOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 printf "%s\n" "$ac_ct_DLLTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 printf %s "checking how to associate runtime and link libraries... " >&6; } if test ${lt_cv_sharedlib_from_linklib_cmd+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 printf "%s\n" "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cr} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 printf %s "checking for archiver @FILE support... " >&6; } if test ${lt_cv_ar_at_file+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 printf "%s\n" "$lt_cv_ar_at_file" >&6; } if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop 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 case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 printf %s "checking command to parse $NM output from $compiler object... " >&6; } if test ${lt_cv_sys_global_symbol_pipe+y} then : printf %s "(cached) " >&6 else $as_nop # 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]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5 if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_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 -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5 printf "%s\n" "failed" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5 printf "%s\n" "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 printf %s "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test ${with_sysroot+y} then : withval=$with_sysroot; else $as_nop with_sysroot=no fi lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 printf "%s\n" "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 printf "%s\n" "${lt_sysroot:-no}" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 printf %s "checking for a working dd... " >&6; } if test ${ac_cv_path_lt_DD+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then ac_path_lt_DD_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in dd do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_lt_DD" || continue if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi $ac_path_lt_DD_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_lt_DD"; then : fi else ac_cv_path_lt_DD=$lt_DD fi rm -f conftest.i conftest2.i conftest.out fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 printf "%s\n" "$ac_cv_path_lt_DD" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 printf %s "checking how to truncate binary pipes... " >&6; } if test ${lt_cv_truncate_bin+y} then : printf %s "(cached) " >&6 else $as_nop printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 printf "%s\n" "$lt_cv_truncate_bin" >&6; } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # Check whether --enable-libtool-lock was given. if test ${enable_libtool_lock+y} then : enableval=$enable_libtool_lock; fi test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else 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 fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; 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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 printf %s "checking whether the C compiler needs -belf... " >&6; } if test ${lt_cv_cc_needs_belf+y} then : printf %s "(cached) " >&6 else $as_nop 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_cc_needs_belf=yes else $as_nop lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 printf "%s\n" "$lt_cv_cc_needs_belf" >&6; } if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 printf "%s\n" "$MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if test ${lt_cv_path_mainfest_tool+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; } if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 printf "%s\n" "$DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_DSYMUTIL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 printf "%s\n" "$ac_ct_DSYMUTIL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 printf "%s\n" "$NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_NMEDIT+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 printf "%s\n" "$ac_ct_NMEDIT" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 printf "%s\n" "$LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_LIPO+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 printf "%s\n" "$ac_ct_LIPO" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 printf "%s\n" "$OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 printf "%s\n" "$ac_ct_OTOOL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 printf "%s\n" "$OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_OTOOL64+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 printf "%s\n" "$ac_ct_OTOOL64" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 printf %s "checking for -single_module linker flag... " >&6; } if test ${lt_cv_apple_cc_single_mod+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 printf %s "checking for -exported_symbols_list linker flag... " >&6; } if test ${lt_cv_ld_exported_symbols_list+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_ld_exported_symbols_list=yes else $as_nop lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 printf %s "checking for -force_load linker flag... " >&6; } if test ${lt_cv_ld_force_load+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cr libconftest.a conftest.o" >&5 $AR cr libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 printf "%s\n" "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[912]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[012][,.]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*|11.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes then : printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h fi # Set options enable_win32_dll=no # Check whether --enable-shared was given. if test ${enable_shared+y} 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. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac else $as_nop enable_shared=yes fi # Check whether --enable-static was given. if test ${enable_static+y} 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. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac else $as_nop enable_static=yes fi # Check whether --with-pic was given. if test ${with_pic+y} then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac else $as_nop pic_mode=default fi # Check whether --enable-fast-install was given. if test ${enable_fast_install+y} 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. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac else $as_nop enable_fast_install=yes fi shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[5-9]*,yes) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 printf %s "checking which variant of shared library versioning to provide... " >&6; } # Check whether --with-aix-soname was given. if test ${with_aix_soname+y} then : withval=$with_aix_soname; case $withval in aix|svr4|both) ;; *) as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 ;; esac lt_cv_with_aix_soname=$with_aix_soname else $as_nop if test ${lt_cv_with_aix_soname+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_with_aix_soname=aix fi with_aix_soname=$lt_cv_with_aix_soname fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 printf "%s\n" "$with_aix_soname" >&6; } if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 printf %s "checking for objdir... " >&6; } if test ${lt_cv_objdir+y} then : printf %s "(cached) " >&6 else $as_nop rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 printf "%s\n" "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir printf "%s\n" "#define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h 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 set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o func_cc_basename $compiler cc_basename=$func_cc_basename_result # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 printf %s "checking for ${ac_tool_prefix}file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs 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 <<_LT_EOF 1>&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 _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5 printf %s "checking for file... " >&6; } if test ${lt_cv_path_MAGIC_CMD+y} then : printf %s "(cached) " >&6 else $as_nop case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs 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 <<_LT_EOF 1>&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 _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 printf "%s\n" "$MAGIC_CMD" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC=$CC 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 # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if test ${lt_cv_prog_compiler_rtti_exceptions+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi lt_prog_compiler_pic='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # 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_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # 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). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # 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_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 printf %s "checking for $compiler option to produce PIC... " >&6; } if test ${lt_cv_prog_compiler_pic+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if test ${lt_cv_prog_compiler_pic_works+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works"; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if test ${lt_cv_prog_compiler_static_works+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_static_works=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; } if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && 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 $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if test ${lt_cv_prog_compiler_c_o+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && 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 $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 printf %s "checking if we can lock with hard links... " >&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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 printf "%s\n" "$hard_links" >&6; } if test no = "$hard_links"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 printf "%s\n" "$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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # 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 extended regexp 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_|_GLOBAL__F[ID]_.*' # 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. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # 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 yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, 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 install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) 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 ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': 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* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='$wl--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' link_all_deplibs=yes ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) export_dynamic_flag_spec='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) 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 $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&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. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' 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 ;; 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 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $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 no = "$ld_shlibs"; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= 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 yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test ia64 = "$host_cpu"; 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 # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi 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 # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; 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. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct=no hardcode_direct_absolute=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : 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' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi export_dynamic_flag_spec='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; 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' # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; 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 $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if test ${lt_cv_aix_libpath_+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' $wl-bernotok' allow_undefined_flag=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) 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 ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # 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. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''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' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test yes = "$lt_cv_ld_force_load"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=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* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test yes = "$GCC"; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 printf %s "checking if $CC understands -b... " >&6; } if test ${lt_cv_prog_compiler__b+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_prog_compiler__b=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 printf "%s\n" "$lt_cv_prog_compiler__b" >&6; } if test yes = "$lt_cv_prog_compiler__b"; then archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if test ${lt_cv_irix_exported_symbol+y} then : printf %s "(cached) " >&6 else $as_nop save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : lt_cv_irix_exported_symbol=yes else $as_nop lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; } if test yes = "$lt_cv_irix_exported_symbol"; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi link_all_deplibs=no else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler ld_shlibs=yes archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd* | netbsdelf*-gnu) 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 ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' else archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes ;; osf3*) if test yes = "$GCC"; 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" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then allow_undefined_flag=' $wl-expect_unresolved $wl\*' archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$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='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test yes = "$GCC"; then wlarc='$wl' archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' 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' ;; *) wlarc='$wl' archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test sequent = "$host_vendor"; 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' ;; 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*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='$wl-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='$wl-z,text' allow_undefined_flag='$wl-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 printf "%s\n" "$ld_shlibs" >&6; } test no = "$ld_shlibs" && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test yes,yes = "$GCC,$enable_shared"; 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. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 printf %s "checking whether -lc should be explicitly linked in... " >&6; } if test ${lt_cv_archive_cmds_need_lc+y} then : printf %s "(cached) " >&6 else $as_nop $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$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=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 printf %s "checking dynamic linker characteristics... " >&6; } if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([A-Za-z]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so 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" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' 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 # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # 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$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # 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$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) 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=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $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' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$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" # 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* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # 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 library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' 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. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") 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" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # 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 dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if test ${lt_cv_shlibpath_overrides_runpath+y} then : printf %s "(cached) " >&6 else $as_nop lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # 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 # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # 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' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_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$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$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 # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' 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 ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$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$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no 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 ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 printf "%s\n" "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 printf %s "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct" && # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && test no != "$hardcode_minus_L"; 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 printf "%s\n" "$hardcode_action" >&6; } if test relink = "$hardcode_action" || test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi if test yes != "$enable_dlopen"; 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 ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else $as_nop lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes then : lt_cv_dlopen=shl_load else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char shl_load (); int main (void) { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes else $as_nop ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes then : lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld else $as_nop ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes then : lt_cv_dlopen=dlopen else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 printf %s "checking for dlopen in -lsvld... " >&6; } if test ${ac_cv_lib_svld_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_svld_dlopen=yes else $as_nop ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 printf "%s\n" "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 printf %s "checking for dld_link in -ldld... " >&6; } if test ${ac_cv_lib_dld_dld_link+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char dld_link (); int main (void) { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_dld_link=yes else $as_nop ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 printf "%s\n" "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes then : lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld fi fi fi fi fi fi ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 printf %s "checking whether a program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #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 /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 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; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 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_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 printf "%s\n" "$lt_cv_dlopen_self" >&6; } if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 printf %s "checking whether a statically linked program can dlopen itself... " >&6; } if test ${lt_cv_dlopen_self_static+y} then : printf %s "(cached) " >&6 else $as_nop if test yes = "$cross_compiling"; 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 <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #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 /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 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; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 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_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 printf "%s\n" "$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 striplib= old_striplib= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 printf %s "checking whether stripping libraries is possible... " >&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" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } ;; esac fi # Report what library types will actually be built { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 printf %s "checking if libtool supports shared libraries... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 printf "%s\n" "$can_build_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 printf %s "checking whether to build shared libraries... " >&6; } test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 printf "%s\n" "$enable_shared" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 printf %s "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 printf "%s\n" "$enable_static" >&6; } 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 CC=$lt_save_CC ac_config_commands="$ac_config_commands libtool" # Only expand once: if ${TEST} -n "${SAVE_LIBTOOL}" ; then LIBTOOL="$SAVE_LIBTOOL" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: LIBTOOL=\"$LIBTOOL\"" >&5 printf "%s\n" "LIBTOOL=\"$LIBTOOL\"" >&6; } # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of char" >&5 printf %s "checking size of char... " >&6; } if test ${ac_cv_sizeof_char+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_char" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (char) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_char=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5 printf "%s\n" "$ac_cv_sizeof_char" >&6; } printf "%s\n" "#define SIZEOF_CHAR $ac_cv_sizeof_char" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 printf %s "checking size of int... " >&6; } if test ${ac_cv_sizeof_int+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_int" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 printf "%s\n" "$ac_cv_sizeof_int" >&6; } printf "%s\n" "#define SIZEOF_INT $ac_cv_sizeof_int" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 printf %s "checking size of long... " >&6; } if test ${ac_cv_sizeof_long+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_long" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 printf "%s\n" "$ac_cv_sizeof_long" >&6; } printf "%s\n" "#define SIZEOF_LONG $ac_cv_sizeof_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 printf %s "checking size of short... " >&6; } if test ${ac_cv_sizeof_short+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_short" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (short) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_short=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 printf "%s\n" "$ac_cv_sizeof_short" >&6; } printf "%s\n" "#define SIZEOF_SHORT $ac_cv_sizeof_short" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 printf %s "checking size of long double... " >&6; } if test ${ac_cv_sizeof_long_double+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_long_double" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long double) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_double=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_double" >&5 printf "%s\n" "$ac_cv_sizeof_long_double" >&6; } printf "%s\n" "#define SIZEOF_LONG_DOUBLE $ac_cv_sizeof_long_double" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 printf %s "checking size of long long... " >&6; } if test ${ac_cv_sizeof_long_long+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_long_long" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_long=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 printf "%s\n" "$ac_cv_sizeof_long_long" >&6; } printf "%s\n" "#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long" >>confdefs.h # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of longlong" >&5 printf %s "checking size of longlong... " >&6; } if test ${ac_cv_sizeof_longlong+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (longlong))" "ac_cv_sizeof_longlong" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_longlong" = yes; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (longlong) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_longlong=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_longlong" >&5 printf "%s\n" "$ac_cv_sizeof_longlong" >&6; } printf "%s\n" "#define SIZEOF_LONGLONG $ac_cv_sizeof_longlong" >>confdefs.h # Now we need to find what jk_uint32_t (sizeof == 4) will be. # The first match is our preference. if test "$ac_cv_sizeof_int" = "4"; then int32_t_fmt='#define JK_INT32_T_FMT "d"' uint32_t_fmt='#define JK_UINT32_T_FMT "u"' uint32_t_hex_fmt='#define JK_UINT32_T_HEX_FMT "x"' int32_value="int" elif test "$ac_cv_sizeof_long" = "4"; then int32_t_fmt='#define JK_INT32_T_FMT "ld"' uint32_t_fmt='#define JK_UINT32_T_FMT "lu"' uint32_t_hex_fmt='#define JK_UINT32_T_HEX_FMT "lx"' int32_value="long" else int32_t_fmt='#error could not detect a 32-bit integer type' uint32_t_fmt='#error could not detect a 32-bit integer type' uint32_t_hex_fmt='#error could not detect a 32-bit integer type' as_fn_error $? "could not detect a 32-bit integer type" "$LINENO" 5 fi # Now we need to find what jk_uint64_t (sizeof == 8) will be. # The first match is our preference. if test "$ac_cv_sizeof_int" = "8"; then int64_t_fmt='#define JK_INT64_T_FMT "d"' uint64_t_fmt='#define JK_UINT64_T_FMT "u"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "x"' int64_value="int" elif test "$ac_cv_sizeof_long" = "8"; then int64_t_fmt='#define JK_INT64_T_FMT "ld"' uint64_t_fmt='#define JK_UINT64_T_FMT "lu"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "lx"' int64_value="long" elif test "$ac_cv_sizeof_long_long" = "8"; then # Linux, Solaris, FreeBSD all support ll with printf. # BSD 4.4 originated 'q'. Solaris is more popular and # doesn't support 'q'. Solaris wins. Exceptions can # go to the OS-dependent section. int64_t_fmt='#define JK_INT64_T_FMT "lld"' uint64_t_fmt='#define JK_UINT64_T_FMT "llu"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "llx"' int64_value="long long" elif test "$ac_cv_sizeof_long_double" = "8"; then int64_t_fmt='#define JK_INT64_T_FMT "Ld"' uint64_t_fmt='#define JK_UINT64_T_FMT "Lu"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "Lx"' int64_value="long double" elif test "$ac_cv_sizeof_longlong" = "8"; then int64_t_fmt='#define JK_INT64_T_FMT "qd"' uint64_t_fmt='#define JK_UINT64_T_FMT "qu"' uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "qx"' int64_value="__int64" else int64_t_fmt='#error could not detect a 64-bit integer type' uint64_t_fmt='#error could not detect a 64-bit integer type' uint64_t_hex_fmt='#error could not detect a 64-bit integer type' as_fn_error $? "could not detect a 64-bit integer type" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pid_t" >&5 printf %s "checking size of pid_t... " >&6; } if test ${ac_cv_sizeof_pid_t+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_sizeof_pid_t=8 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main() { FILE *f=fopen("conftestval","w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(pid_t)); exit(0); } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_sizeof_pid_t=`cat conftestval` else $as_nop ac_cv_sizeof_pid_t=0 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pid_t" >&5 printf "%s\n" "$ac_cv_sizeof_pid_t" >&6; } printf "%s\n" "#define SIZEOF_PID_T $ac_cv_sizeof_pid_t" >>confdefs.h if test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_short"; then pid_t_fmt='#define JK_PID_T_FMT "hd"' elif test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_int"; then pid_t_fmt='#define JK_PID_T_FMT "d"' elif test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_long"; then pid_t_fmt='#define JK_PID_T_FMT "ld"' elif test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_long_long"; then pid_t_fmt='#define JK_PID_T_FMT JK_INT64_T_FMT' else pid_t_fmt='#error Can not determine the proper size for pid_t' fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5 printf %s "checking size of pthread_t... " >&6; } if test ${ac_cv_sizeof_pthread_t+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_sizeof_pthread_t=8 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main() { FILE *f=fopen("conftestval","w"); if (!f) exit(1); fprintf(f, "%d\n", sizeof(pthread_t)); exit(0); } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_sizeof_pthread_t=`cat conftestval` else $as_nop ac_cv_sizeof_pthread_t=0 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_t" >&5 printf "%s\n" "$ac_cv_sizeof_pthread_t" >&6; } printf "%s\n" "#define SIZEOF_PTHREAD_T $ac_cv_sizeof_pthread_t" >>confdefs.h if test "$ac_cv_sizeof_pthread_t" = "$ac_cv_sizeof_short"; then pthread_t_fmt='#define JK_PTHREAD_T_FMT "hu"' pthread_t_value="short" elif test "$ac_cv_sizeof_pthread_t" = "$ac_cv_sizeof_int"; then pthread_t_fmt='#define JK_PTHREAD_T_FMT "u"' pthread_t_value="int" elif test "$ac_cv_sizeof_pthread_t" = "$ac_cv_sizeof_long"; then pthread_t_fmt='#define JK_PTHREAD_T_FMT "lu"' pthread_t_value="long" elif test "$ac_cv_sizeof_pthread_t" = "$ac_cv_sizeof_long_long"; then pthread_t_fmt='#define JK_PTHREAD_T_FMT "llu"' pthread_t_value="long long" else pthread_t_fmt='#error Can not determine the proper size for pthread_t' fi # Basically, we have tried to figure out the correct format strings # for pid_t which varies between platforms, but we don't always get # it right. If you find that we don't get it right for your platform, # you can override our decision below. case $host in *-solaris*) if test "$ac_cv_sizeof_pid_t" = "$ac_cv_sizeof_long"; then pid_t_fmt='#define JK_PID_T_FMT "ld"' fi ;; esac ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" if test "x$ac_cv_func_snprintf" = xyes then : printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" if test "x$ac_cv_func_vsnprintf" = xyes then : printf "%s\n" "#define HAVE_VSNPRINTF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock" if test "x$ac_cv_func_flock" = xyes then : printf "%s\n" "#define HAVE_FLOCK 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5 printf %s "checking for setsockopt in -lsocket... " >&6; } if test ${ac_cv_lib_socket_setsockopt+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char setsockopt (); int main (void) { return setsockopt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_socket_setsockopt=yes else $as_nop ac_cv_lib_socket_setsockopt=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5 printf "%s\n" "$ac_cv_lib_socket_setsockopt" >&6; } if test "x$ac_cv_lib_socket_setsockopt" = xyes then : LIBS="$LIBS -lsocket" fi ac_fn_c_check_header_compile "$LINENO" "sys/filio.h" "ac_cv_header_sys_filio_h" "$ac_includes_default" if test "x$ac_cv_header_sys_filio_h" = xyes then : printf "%s\n" "#define HAVE_SYS_FILIO_H 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use SO_RCVTIMEO with setsockopt()" >&5 printf %s "checking whether to use SO_RCVTIMEO with setsockopt()... " >&6; } if test "$cross_compiling" = yes then : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main(void) { int s; struct timeval tv; tv.tv_sec = 3; tv.tv_usec = 0; #ifndef SO_RCVTIMEO exit(3); #else if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) exit(2); /* fails on Solaris 2.6,8,9,10 and some Linuxes because SO_RCVTIMEO|SO_SNDTIMEO are defined but not implemented */ if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const void *)&tv, sizeof(tv)) == -1) exit(1); exit(0); #endif } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define USE_SO_RCVTIMEO 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use SO_SNDTIMEO with setsockopt()" >&5 printf %s "checking whether to use SO_SNDTIMEO with setsockopt()... " >&6; } if test "$cross_compiling" = yes then : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main(void) { int s; struct timeval tv; tv.tv_sec = 3; tv.tv_usec = 0; #ifndef SO_SNDTIMEO exit(3); #else if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) exit(2); /* fails on Solaris 2.6,8,9,10 and some Linuxes because SO_RCVTIMEO|SO_SNDTIMEO are defined but not implemented */ if (setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (const void *)&tv, sizeof(tv)) == -1) exit(1); exit(0); #endif } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define USE_SO_SNDTIMEO 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi # Check whether --enable-sock-cloexec was given. if test ${enable_sock_cloexec+y} then : enableval=$enable_sock_cloexec; case "${enableval}" in y | Y | YES | yes | TRUE | true ) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use SOCK_CLOEXEC with socket()" >&5 printf %s "checking whether to use SOCK_CLOEXEC with socket()... " >&6; } if test "$cross_compiling" = yes then : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main(void) { int s; #ifndef SOCK_CLOEXEC exit(3); #else if ((s = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) exit(2); exit(0); #endif } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define USE_SOCK_CLOEXEC 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi ;; esac else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use SOCK_CLOEXEC with socket()" >&5 printf %s "checking whether to use SOCK_CLOEXEC with socket()... " >&6; } if test "$cross_compiling" = yes then : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main(void) { int s; #ifndef SOCK_CLOEXEC exit(3); #else if ((s = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)) == -1) exit(2); exit(0); #endif } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define USE_SOCK_CLOEXEC 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi ac_fn_c_check_header_compile "$LINENO" "poll.h" "ac_cv_header_poll_h" "$ac_includes_default" if test "x$ac_cv_header_poll_h" = xyes then : printf "%s\n" "#define HAVE_POLL_H 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "poll" "ac_cv_func_poll" if test "x$ac_cv_func_poll" = xyes then : printf "%s\n" "#define HAVE_POLL 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default" if test "x$ac_cv_header_netinet_in_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" if test "x$ac_cv_header_netdb_h" = xyes then : printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for IPv6 with socket()" >&5 printf %s "checking for IPv6 with socket()... " >&6; } if test "$cross_compiling" = yes then : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main(void) { int s; if ((s = socket(AF_INET6, SOCK_STREAM, 0)) == -1) exit(2); exit(0); } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_AF_INET6 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct sockaddr_storage" >&5 printf %s "checking for struct sockaddr_storage... " >&6; } if test "$cross_compiling" = yes then : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main(void) { struct sockaddr_storage sa; exit(sizeof(sa) == 0); } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_SOCKADDR_STORAGE 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" if test "x$ac_cv_func_getaddrinfo" = xyes then : printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" if test "x$ac_cv_func_gethostbyname_r" = xyes then : printf "%s\n" "#define HAVE_GETHOSTBYNAME_R 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler provides atomic builtins" >&5 printf %s "checking whether the compiler provides atomic builtins... " >&6; } if test "$cross_compiling" = yes then : { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main() { unsigned long val = 1010; if (__sync_add_and_fetch(&val, 1010) != 2020 || val != 2020) return 1; if (__sync_sub_and_fetch(&val, 1010) != 1010 || val != 1010) return 1; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } printf "%s\n" "#define HAVE_ATOMIC_BUILTINS 1" >>confdefs.h else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for target platform" >&5 printf %s "checking for target platform... " >&6; } #PLATFORM=`${CONFIG_SHELL-/bin/sh} $ac_config_guess` PLATFORM=$host case "$PLATFORM" in *beos*) OS_APACHE="beos" OS_APACHE_DIR=$OS_APACHE ;; *pc-os2_emx*) OS_APACHE="os2" OS_APACHE_DIR=$OS_APACHE ;; bs2000*) OS_APACHE="unix" OS_APACHE_DIR=bs2000 # only the OS_APACHE_DIR is platform specific. ;; *) OS_APACHE="unix" OS_APACHE_DIR=$OS_APACHE;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OS_APACHE" >&5 printf "%s\n" "$OS_APACHE" >&6; } apache_dir_is_src="false" # Check whether --with-apache was given. if test ${with_apache+y} then : withval=$with_apache; if ${TEST} ! -z "$WEBSERVER" ; then as_fn_error $? "Sorry cannot use --with-apxs=${APXS} and --with-apache=${withval} together, please choose one of both" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Apache source directory (assume static build)" >&5 printf %s "checking for Apache source directory (assume static build)... " >&6; } if ${TEST} -n "${withval}" && ${TEST} -d "${withval}" ; then if ${TEST} -d "${withval}/src" ; then # handle the case where people use relative paths to # the apache source directory by pre-pending the current # build directory to the path. there are probably # errors with this if configure is run while in a # different directory than what you are in at the time if ${TEST} -n "`${ECHO} ${withval}|${GREP} \"^\.\.\"`" ; then withval=`pwd`/${withval} fi apache_dir=${withval} apache_dir_is_src="true" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${apache_dir}" >&5 printf "%s\n" "${apache_dir}" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Apache include directory" >&5 printf %s "checking for Apache include directory... " >&6; } if ${TEST} -d "${withval}/src/include" ; then # read osdir from the existing apache. osdir=`${GREP} '^OSDIR=' ${withval}/src/Makefile.config | ${SED} -e 's:^OSDIR=.*/os:os:'` if ${TEST} -z "${osdir}" ; then osdir=os/unix fi apache_include="-I${withval}/src/include \ -I${withval}/src/${osdir}" WEBSERVER="apache-1.3" LIB_JK_TYPE=mod_jk.a CFLAGS="${CFLAGS} -DJK_PREFORK" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${apache_include}, version 1.3" >&5 printf "%s\n" "${apache_include}, version 1.3" >&6; } else as_fn_error $? "Sorry Apache 1.2.x is no longer supported." "$LINENO" 5 fi else if ${TEST} -d "${withval}/include" ; then # osdir for Apache20. WEBSERVER="apache-2.0" apache_dir=${withval} apache_dir_is_src="true" LIB_JK_TYPE=lib_jk.la apache_include="-I${withval}/include -I${withval}/srclib/apr/include -I${withval}/os/${OS_APACHE_DIR} -I${withval}/srclib/apr-util/include" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${apache_dir}" >&5 printf "%s\n" "${apache_dir}" >&6; } fi fi fi if ${TEST} -z "$WEBSERVER" ; then as_fn_error $? "Directory $apache_dir is not a valid Apache source distribution" "$LINENO" 5 fi # VT: Now, which one I'm supposed to use? Let's figure it out later configure_apache=true configure_src=true { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: building connector for \"$WEBSERVER\"" >&5 printf "%s\n" "building connector for \"$WEBSERVER\"" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no apache given" >&5 printf "%s\n" "no apache given" >&6; } fi APACHE_DIR=${apache_dir} CFLAGS="${CFLAGS}" # Check whether --enable-EAPI was given. if test ${enable_EAPI+y} then : enableval=$enable_EAPI; case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DEAPI" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ...Enabling EAPI Support..." >&5 printf "%s\n" "...Enabling EAPI Support..." >&6; } ;; esac fi CFLAGS="${CFLAGS}" # Check whether --enable-maintainer-mode was given. if test ${enable_maintainer_mode+y} then : enableval=$enable_maintainer_mode; case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DDEBUG -Wall" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ...Enabling Maintainer mode..." >&5 printf "%s\n" "...Enabling Maintainer mode..." >&6; } ;; esac fi CFLAGS="${CFLAGS}" # Check whether --enable-prefork was given. if test ${enable_prefork+y} then : enableval=$enable_prefork; case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DJK_PREFORK" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ...Enabling Prefork mode..." >&5 printf "%s\n" "...Enabling Prefork mode..." >&6; } ;; esac fi CFLAGS="${CFLAGS}" # Check whether --enable-trace was given. if test ${enable_trace+y} then : enableval=$enable_trace; case "${enableval}" in no ) CFLAGS="${CFLAGS} -DJK_PRODUCTION" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ...Exclude trace log code..." >&5 printf "%s\n" "...Exclude trace log code..." >&6; } ;; esac fi CFLAGS="${CFLAGS}" # Check whether --enable-api-compatibility was given. if test ${enable_api_compatibility+y} then : enableval=$enable_api_compatibility; case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DAPI_COMPATIBILITY" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ...Only using compatible httpd API..." >&5 printf "%s\n" "...Only using compatible httpd API..." >&6; } ;; esac fi CFLAGS="${CFLAGS}" # Check whether --enable-flock was given. if test ${enable_flock+y} then : enableval=$enable_flock; case "${enableval}" in y | Y | YES | yes | TRUE | true ) CFLAGS="${CFLAGS} -DJK_USE_FLOCK" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ...Enabling flock() shared memory locking..." >&5 printf "%s\n" "...Enabling flock() shared memory locking..." >&6; } ;; esac fi if ${TEST} -n "${CFLAGS}" ; then APXSCFLAGS="${APXSCFLAGS} ${CFLAGS}" fi if ${TEST} -n "${LDFLAGS}" ; then APXSLDFLAGS="${APXSLDFLAGS} ${LDFLAGS}" fi jk_new_val="" jk_val_changed=0 for i in $APXSLDFLAGS; do case $i in -Wl,*) jk_new_val="$jk_new_val $i" ;; *) jk_new_val="$jk_new_val -Wl,$i" jk_val_changed=1 ;; esac done if test $jk_val_changed = "1"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: tokens in APXSLDFLAGS have been prefixed with '-Wl,'" >&5 printf "%s\n" "$as_me: tokens in APXSLDFLAGS have been prefixed with '-Wl,'" >&6;} APXSLDFLAGS=$jk_new_val fi if ${TEST} -z "$WEBSERVER" ; then as_fn_error $? "Cannot find the WebServer" "$LINENO" 5 fi WEBSERVER="common ${WEBSERVER}" if ${TEST} "${apache_dir_is_src}" = "false"; then MAKE_DYNAMIC_APACHE_TRUE= MAKE_DYNAMIC_APACHE_FALSE='#' else MAKE_DYNAMIC_APACHE_TRUE='#' MAKE_DYNAMIC_APACHE_FALSE= fi if ${TEST} "${apache_dir_is_src}" = "false" ; then APACHE20_OEXT=.c LIB_JK_TYPE=mod_jk.so INSTALL_TYPE=install_dynamic else APACHE20_OEXT=.lo INSTALL_TYPE=install_static fi ac_config_files="$ac_config_files Makefile apache-2.0/Makefile apache-2.0/Makefile.apxs common/Makefile common/list.mk common/jk_types.h" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${MAKE_DYNAMIC_APACHE_TRUE}" && test -z "${MAKE_DYNAMIC_APACHE_FALSE}"; then as_fn_error $? "conditional \"MAKE_DYNAMIC_APACHE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # 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 # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by mod_jk $as_me 1.2.50, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ mod_jk config.status 1.2.50 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SED \ GREP \ EGREP \ FGREP \ SHELL \ ECHO \ LD \ PATH_SEPARATOR \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "common/config.h") CONFIG_HEADERS="$CONFIG_HEADERS common/config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "apache-2.0/Makefile") CONFIG_FILES="$CONFIG_FILES apache-2.0/Makefile" ;; "apache-2.0/Makefile.apxs") CONFIG_FILES="$CONFIG_FILES apache-2.0/Makefile.apxs" ;; "common/Makefile") CONFIG_FILES="$CONFIG_FILES common/Makefile" ;; "common/list.mk") CONFIG_FILES="$CONFIG_FILES common/list.mk" ;; "common/jk_types.h") CONFIG_FILES="$CONFIG_FILES common/jk_types.h" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; 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+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries 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[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; "libtool":C) # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool 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 . # The names of the tagged configurations supported by this script. available_tags='' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # 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 # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # 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 # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # 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 # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # 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 # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # 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 # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # 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 a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # 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\$shared_ext during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \$shlibpath_var if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # 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 # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # 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 # 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 # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # 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 set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain=$ac_aux_dir/ltmain.sh # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # 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 || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi if ${TEST} -n "${WARN_CC}" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ===========================================" >&5 printf "%s\n" "$as_me: WARNING: ===========================================" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Using CC from environment:" >&5 printf "%s\n" "$as_me: WARNING: Using CC from environment:" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: CC=\"$CC\"" >&5 printf "%s\n" "$as_me: WARNING: CC=\"$CC\"" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: instead of CC from apxs:" >&5 printf "%s\n" "$as_me: WARNING: instead of CC from apxs:" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: CC=\"$APXSCC\"" >&5 printf "%s\n" "$as_me: WARNING: CC=\"$APXSCC\"" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: If \"make\" throws an error of the form" >&5 printf "%s\n" "$as_me: WARNING: If \"make\" throws an error of the form" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"libtool: compile: unable to infer tagged configuration\"" >&5 printf "%s\n" "$as_me: WARNING: \"libtool: compile: unable to infer tagged configuration\"" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: \"libtool: compile: specify a tag with \`--tag'\"" >&5 printf "%s\n" "$as_me: WARNING: \"libtool: compile: specify a tag with \`--tag'\"" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: try running configure without setting CC," >&5 printf "%s\n" "$as_me: WARNING: try running configure without setting CC," >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: or at least CC should start with \"$APXSCC\"" >&5 printf "%s\n" "$as_me: WARNING: or at least CC should start with \"$APXSCC\"" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: ===========================================" >&5 printf "%s\n" "$as_me: WARNING: ===========================================" >&2;} fi tomcat-connectors-1.2.50-src/native/CHANGES0000644000000000000020000026415714655113621016617 0ustar rootbin Preface This is the Changelog for Apache Tomcat Connectors. This changelog does not contain all updates and fixes to the Tomcat connectors (yet). It should contain fixes made only after November 10th 2004, when the new documentation project for JK was started. Changes between 1.2.49 and 1.2.50 Apache * Fix: 68117: Fix typo in new libtool flag introduced in 1.2.49 to reduce symbol visibility. Also improve escaping of it in the Makefile. Patch provided by lzsiga@freemail.c3.hu. (rjung) * Fix: Improve shared memory handling on non-Windows. (rjung) IIS * Update: Update PCRE bundled with the ISAPI redirector to 8.45. (rjung) Common * Fix: #8: Fix compilation on musl. Patch provided by conrad+github@kostecki.com. (rjung) * Update: Update config.guess and config.sub from https://git.savannah.gnu.org/git/config.git. (rjung) Changes between 1.2.48 and 1.2.49 Apache * Update: Retrieve default request id from mod_unique_id. It can also be taken from an arbitrary environment variable by configuring "JkRequestIdIndicator". (rjung) * Fix: 65901: Don't delegate the generatation of the response body to httpd when the status code represents an error if the request used the HEAD method. (markt) * Fix: 66005: Only export the main module symbol. Visibility of module internal symbols led to crashes when conflicting with library symbols. Based on a patch provided by Josef Čejka. (rjung) * Fix: Remove support for implicit mapping of requests to workers. All mappings must now be explicit. (rjung) IIS * Update: Set default request id as a GUID. It can also be taken from an arbitrary request header by configuring "request_id_header". (rjung) * Fix: Fix non-empty check for the Translate header. (rjung) Common * Fix: Fix compiler warning when initializing and copying fixed length strings. (rjung) * Update: Add a request id to mod_jk log lines. (rjung) * Fix: 64878: Enable configure to find the correct sizes for pid_t and pthread_t when building on MacOS. (markt) * Fix: Fix Clang 15/16 compatability. Pull request #6 provided by Sam James. (markt) * Update: Improve XSS hardening in status worker. (rjung) * Update: Add additional bounds and error checking when reading AJP messages. (schultz/markt) Docs * Update: Remove support for the Netscape / Sun ONE / Oracle iPlanet Web Server as the product has been retired. (markt) * Update: Remove links to the old JK2 documentation. The JK2 documentation is still available, it is just no longer linked from the current JK documentation. (markt) * Update: Restructure subsections in changelog starting with version 1.2.45. (rjung) Changes between 1.2.47 and 1.2.48 IIS * Update: Update the installation how-to to remove windows versions that are no longer supported and to add Windows Server 2019. (markt) Changes between 1.2.46 and 1.2.47 Apache * Add: Extend trace level logging of method entry/exit to aid debugging of request mapping issues. (markt) * Fix: Fix a bug in the normalization checks that prevented file based requests, such as SSI file includes, from being processed. (markt) * Fix: 63214: When using JkAutoAlias, ensure that files that include spaces in their name are accessible. (markt) Common * Update: Update the documentation to reflect that the source code for the Apache Tomcat Connectors has moved from Subversion to Git. (markt) * Fix: 64051: When using set_session_cookie, ensure that an updated session cookie is issued if the load-balancer has to failover to a different worker. (markt) * Update: Update config.guess and config.sub from https://git.savannah.gnu.org/git/config.git. (markt) * Update: Update release script for migration to git. (rjung) Changes between 1.2.45 and 1.2.46 Apache * Fix: 62751: Fix regression in 1.2.44 which resulted in socket_connect_timeout to be interpreted in units of seconds instead of milliseconds on platforms that provide poll(). (rjung) Changes between 1.2.44 and 1.2.45 Apache * Update: Update the documentation to note additional limitations of the JkAutoAlias directive. (markt) * Fix: Improve path parameter handling so that JkStripSession can remove session IDs that are specified on path parameters in any segment of the URI rather than only the final segment. (markt) IIS * Fix: Improve path parameter handling so that strip_session can remove session IDs that are specified on path parameters in any segment of the URI rather than only the final segment. (markt) Common * Fix: 62689: Correct regression in 1.2.44 that broke request handling for OPTIONS * requests. (rjung) * Code: Optimize path parameter handling. (rjung) * Fix: Improve path parameter parsing so that the session ID specified by the session_path worker property for load-balanced workers can be extracted from a path parameter in any segment of the URI, rather than only from the final segment. (markt) Changes between 1.2.43 and 1.2.44 Native * Update: Remove the Novell Netware make files and Netware specific source code since there has not been a supported version of Netware available for over five years. (markt) * Update: 57946: Apache: Update the documentation to use httpd 2.4.x style access control directives. (markt) * Fix: 58287: Common: Use Local, rather than Global, mutexs on Windows to better support multi-user environments. (markt) * Fix: 59897: Apache: Use poll rather than select to avoid the limitations of select triggering an httpd crash. Patch provided by Koen Wilde. (markt) * Fix: 60745: ISAPI: Remove the check that rejects requests that contain path segments that match WEB-INF or META-INF as it duplicates a check that Tomcat performs and, because ISAPI does not have visibility of the current context path, it is impossible to implement this check without valid requests being rejected. (markt) * Add: Clarify the behvaiour of lb workers when all ajp13 workers fail with particular reference to the role of the retries attribute. (markt) * Add: 62408: Add the new load-balancer worker property lb_retries to improve the control over the number of retries. Based on a patch provided by Frederik Nosi. (markt) * Fix: Refactor normalisation of request URIs to a common location and align the normalisation implementation for mod_jk with that implemented by Tomcat. (markt) * Add: Add a note to the documentation that the CollapseSlashes options are now effectively hard-coded to CollpaseSlashesAll due to the changes made to align normalization with that implemented in Tomcat. (markt) * Update: Update PCRE bundled with the ISAPI redirector to 8.42. (rjung) * Update: Update config.guess and config.sub from https://git.savannah.gnu.org/git/config.git. (rjung) Changes between 1.2.42 and 1.2.43 Native * Fix: 61733: LB: Propagate load factor changes applied by the status worker to a load balancer sub worker correctly to all processes. Based on a patch provided by Jonathan Oddy. (rjung) * Fix: ISAPI: Align the make files for 32-bit and 64-bit builds. (markt) * Update: Update config.guess and config.sub from http://git.savannah.gnu.org/cgit/config.git. (rjung) * Update: Update PCRE bundled with the ISAPI redirector to 8.41. (rjung) * Fix: Update the ISAPI redirector installation documentation to reflect the currently supported versions of Windows. (markt) * Fix: Align the normalization performed by the ISAPI redirector with that implemented by Tomcat. (markt) Changes between 1.2.41 and 1.2.42 Native * Fix: Status: Fix displayed number of bytes read from and written to the backend when an AJP worker is used without a load balancer worker. (rjung) * Fix: Apache: Don't try to read remaining request body parts during clean up if reading the request body from the client already failed during earlier processing phases. (rjung) * Fix: 57485: Apache: Propagate errors reading the request body from the client to mod_jk so Tomcat sees an error rather than a truncated body. (markt) * Fix: 57836: ISAPI: Empty REMOTE_USER should not be translated to "". (rjung) * Fix: 58249: Add a note the the documentation that max_packet_size will be aligned to the next multiple of 1024 if a value is specified that is not a multiple of 1024. (markt) * Update: 58309: ISAPI: Update bundled pcre from version 5.0 to 8.38. (rjung) * Fix: 58286: Fix crash in mod_jk and in the ISAPI Redirector. The crash only happens on Windows when retrieving the jk-status for the HTML format (which is the default format). This regression was introduced by the fix to 54177. (rjung) * Fix: 58285: Don't use GCC atomics on platforms, for which GCC doesn't provide an atomics implementation. This regression was introduced by the fix to 44454 and 56703. (rjung) * Fix: 58425: Fix regression in 1.2.41 that prevented AJP 1.2 workers from initialising. Note that the AJP 1.2 protocol is deprecated. Patch provided by yagisita. (markt) * Fix: 58504: If a background thread is used to perform worker maintenance, ensure that maintenance runs are not skipped. Patch provided by Hiroto Shimizu. (markt) * Fix: 58608: ISAPI: Add a new registry option "flush_packets" that allows the flushing behaviour of IIS7+ to be controlled. The default is not to flush. Setting the option to "true" with cause IIS to write data to the client as each AJP packet is received. (markt) * Fix: 58813: ISAPI: Correctly release a mutex allowing the plugin to complete initialization. Prior to this fix, the incomplete initialization was causing a hang on shutdown. Patch provided by Matthew Reiter. (markt) * Fix: 58895: Correct an off-by-one error in the log messages for the number of attempts made to communicate with the backend server. Patch provided by Hiroto Shimizu. (markt) * Fix: 59164: Fix crash on first connection if a host name is specified for the worker that cannot be resolved to an IP address. (markt) * Fix: 59184: HTTPD: Avoid segmentation fault if mod_jk is configured with an invalid value for JkShmFile. This causes the server startup to fail. (markt) * Fix: Minor code clean-up and optimization. (markt) Changes between 1.2.40 and 1.2.41 Native * Fix: AJP, LB: Reduce lock contention during maintenance function. This was observable when using a big number of AJP13 and LB workers, especially in combination with the Apache httpd prefork MPM. (rjung) * Fix: 57060: Allow building from outside of source tree. Patch contributed by Petr Sumbera. (rjung) * Fix: 56703: Status: Fix inflated counter for current number of backend connections especially when a connection timeout occurred on the backend. (rjung) * Fix: 56661: Fix Servlet API getLocalAddr(). Works for Tomcat 6.0.42, 7.0.55 and 8.0.11 and Apache and ISAPI plugins. (rjung) * Update: Status: Log old and new values when changing worker attributes. (rjung) * Fix: 56667: Status: Fix log message when changing activation state of all members. (rjung) * Fix: 56565: Fix IPV6 address resolve on non-dual network stacks. (mturk) * Fix: 50511: Reduce log level for "OPTIONS *" requests from warning to debug. (rjung) * Fix: Apache: Copy log notes instead of using references to prevent access to memory from closed pool. (rjung) * Add: Add option to control handling of multiple adjacent slashes in mount and unmount. New default is collapsing the slashes only in unmount. Configuration is done via new JkOption for Apache ("CollapseSlashesAll", "CollapseSlashesNone" or "CollapseSlashesUnmount") and via property "collapse_slashes" for IIS (values "all", "none", "unmount"). This is the fix for CVE-2014-8111. (rjung) * Add: Add more checks for shared memory allocation. (rjung) * Add: 56869: Status: Add maximum number of open backend connections to status worker. Patch contributed by Martin Knoblauch. (rjung) * Add: 56770: AJP: Add worker name to all log messages. Patch contributed by Martin Knoblauch. (rjung) * Fix: 50186: Docs: Clarify relation between "connection_pool_timeout" and "keepAliveTimeout" or "connectionTimeout" in the Tomcat AJP connector configuration. (rjung) * Fix: 52334: LB: Calculate worker recovery time based on last recovery attempt time instead of original error time after the first recovery attempt. (rjung) * Fix: 54596 part 1: IIS: Fix missing last character when parsing relative file names with no ".." directory components from configuration. (rjung) * Fix: 54596 part 2: IIS: Fix using relative file names in config with ".." path segments that go up the directory hierarchy higher than the starting point of the relative file name. (rjung) * Fix: Status: Add logging if status worker output was dropped due to insufficient buffer size. (rjung) * Fix: Reduce log buffer from 8KB to 1KB. Add logging in case of failed logging and add trailing "..." to lines which were likely truncated. (rjung) * Update: Replace fixed allocation of 32 entries for fail_on_status by dynamic allocation. (rjung) * Add: Enforce implementation restriction on maximal length "60" of worker attributes "name", "host", "route", "domain", "redirect", "session_cookie", "session_path" and "set_session_cookie". Checks were added to configuration file processing and configuration updates via the status worker. (rjung) * Add: 52483: Apache: Add debug logging for result of JkOptions configuration processing. (rjung) * Fix: 54177: Status: Use numeric time stamps instead of textual ones to avoid non-well-formed XML output. Textual timestamps are formatted according to locale settings and reencoding them to UTF-8 would be cumbersome. (rjung) * Fix: 56618: Status: Use percent decoding when reading query string parameters. For example this fixes editing IPv6 addresses via the status worker if the client encodes ":" as "%3A". Patch contributed by Christopher Schultz. (rjung) * Fix: 56452: Fix crash in debug logging for IPv6 adresses. Patch contributed by Christopher Schultz. (rjung) * Fix: 34526: Apache: Improve compatibility with mod_deflate request body inflation. An automatic detection of mod_deflate inflation is not implemented. Use the new Apache environment variable JK_IGNORE_CL instead, to let mod_jk ignore an existing Content-Length request header. (rjung) * Update: 44454: LB: Add warning to docs about problems with "busyness" load balancing method. (rjung) * Fix: 44454: Improve busy counter by using atomics. (rjung) * Fix: 56703: Status: Improve connected counter. Use atomics and for mod_jk (Apache) currectly count down connections closed by child processes that are stopped. (rjung) * Fix: 44571: Ensure that we return with status 503 if we can not get and endpoint for a worker. (rjung) * Fix: Apache: Improve log handling during graceful or normal restart. (rjung) * Fix: Don't update last access time of worker connections during optional checking of idle connections using CPing. Updating the time stamp breaks closing idle connections. (rjung) * Fix: Adjust linger parameters used during connection shutdown. (rjung) * Fix: Fix annoying redefine warnings for the autoconf PACKAGE defines during configure based builds. (rjung) * Fix: Status: Use multi-line table headers and fix invalid xml output. (rjung) * Fix: 44571: Implement an optional limit on concurrent requests allowed for a worker (attribute "busy_limit"). Original patch contributed by zealot0630 at gmail dot com. (rjung) * Fix: Correct log message "all endpoints are disconnected" to "no usable connection found, will create a new one". Tone done from info log level to debug for the common case. (rjung) * Add: 57536: AJP: Allow to configure connection source address. This should only be used on multi-homed hosts. The feature is experimental. (rjung) * Add: 57540: AJP: Forward name of SSL protocol used for handling the request (SSLv3, TLSv1, TLSv1.1, TLSv1.2). (rjung) Changes between 1.2.39 and 1.2.40 Native * Fix: Fix forwarding of chunked requests, which is broken in version 1.2.39. (rjung) * Fix: 56352: Fix regression in memory release. (mturk) * Fix: Fix status worker display of worker IP address after name or port was changed. (rjung) * Update: 56297: Improve key hash function. Copied from APR. (rjung) * Fix: 55683: Remove quotes from quoted session cookies. (rjung) * Fix: 53542: ISAPI: Fix grammar in 503 error page. (rjung) * Fix: 55696: Crash on Mac OS X 10.9 during config parsing. (rjung) Changes between 1.2.37 and 1.2.39 Native * Update: Deprecate nt_service from Apache Tomcat Connectors. (mturk) * Fix: 56133: Fix possible crash when a request fails during request body transfer to the back end and reply_timeout was set. Patch contributed by Hiroto Shimizu. (rjung) * Fix: Fix status worker not updating parameters for all members. (mturk) * Fix: 55853: HTTPD: Use the correct API for setting Content-Length. Patch contributed by areese yahoo-inc.com. (rjung) * Add: Add IPV6 support for connection to webserver. New directive prefer_ipv6 has been added to control the hostname resolution and preserve backward compatibility. (mturk) * Add: Add --disable-sock-cloexec to configure to disable use of SOCK_CLOEXEC (using FD_CLOEXEC + fnctl instead) so built modules will work with Linux kernels prior to 2.6.27. (timw) * Update: Clean up config file parsing. Worker names are now restricted to 60 bytes. (rjung) * Update: Allow to set a stickyness cookie in case a web framework breaks Tomcat's adding of the routing ID to the end of the JSESSIONID cookie. (rjung) * Update: Use max_packet_size also for request body forwarding. (rjung) * Update: Apache 2.4: By default forward logical client address as provided by mod_remoteip. When setting JkOptions ForwardPhysicalAddress mod_jk will instead forward the physical peer address. (rjung) * Update: Minor documentation improvements. (rjung) Changes between 1.2.36 and 1.2.37 Native * Fix: Fix regression which can crash webserver in case worker is defined both as member of load balancer and as standalone worker. (mturk) * Fix: Fix core if debug log level is specified and there is no session identifier present. (mturk) Changes between 1.2.35 and 1.2.36 Native * Fix: Use named shared memory objects so that we preserve runtime configured data instead of resetting on each child creation. (mturk) * Fix: Fix dead-lock caused by not releasing mutex on close. (mturk) * Fix: Fix compilation of mod_jk for HTTPD 1.3. (rjung) * Fix: 46893: HTTPD 1.3: Apply fix to HTTPD 1.3. It was fixed for HTTPD 2.x already in version 1.2.30. (rjung) * Update: HTTPD 1.3: Allow to set path parameter used when doing JkStripSession. This was available for HTTPD 2.x already since mod_jk 1.2.27. (rjung) Changes between 1.2.33 and 1.2.35 Native * Fix: HTTPD: Fix crash on unknown worker names. (mturk) * Fix: IIS: Fix crash on worker process recycle. (mturk) * Fix: 52659: IIS: Fix shared memory corruption. (mturk) * Fix: 52921: HTTPD: Fix crash in uri mapping. (mturk) Changes between 1.2.32 and 1.2.33 Native * Fix: 52793: AJP: Fix default value of forwarded worker activation state. Contributed by Yoshihito Fukuyama. (rjung) * Fix: HTTPD: Improve support for HTTPD 2.4 by using client_* instead of remote_* variables. (rjung) * Fix: 52564: Fix building with format checking gcc security hardening cflags. Contributed by Tony Mancill. (rjung) * Fix: 52567: Balancer member in recovery state can switch back into error state if it is idle. (rjung) * Update: Log error if unable to load URI workermap file, and improve logging of unreadable worker files on IIS. (timw) * Update: Remove deprecated JNI worker and build dependency on Java SDK. (mturk) * Fix: 51253: Forward WWW-Authenticate header when using server generated error pages (rjung, mturk). * Update: 46406: IIS: Support relative paths in configuration. The paths are presumed to be relative from isapi_redirect.dll. (mturk) * Fix: 50233: Do not use hard limit on uri size (mturk). * Update: IIS: Use Windows Server 2003 SP1, Windows XP SP2 as minimal version supported. (mturk) * Fix: 47038: Fix compiler warning when using --enable-flock for configure. (rjung) * Add: 51326: URI Map: Add "session_cookie" and "session_path" rule extensions. Contributed by Eiji Takahashi. (rjung) * Update: 51333: IIS: Document configuration requirement for 64 Bit environment. (rjung) * Add: 51743: HTTPD: Support rule extensions when defining the request worker with an environment variable (e.g. JK_WORKER_NAME). (rjung) * Fix: 51769: IIS: Allow URIs which contain "META-INF" or "WEB-INF" as long as they are not path components of the URI. (rjung) * Fix: 52056: HTTPD: JK request log does not always log correct response status. Fixed by refactoring JK request log to use the standard request log hook. (rjung) * Add: HTTPD: Allow to choose a sticky worker using the environment variable JK_ROUTE. This can be used if sessions and routes are send with the request in a non-standard way. (rjung) * Add: URI Map: Add "sticky_ignore" extension attributes to uri worker map. It allows to disable stickyness for individual mounts. (rjung) * Add: HTTPD: Allow dynamic disabling of stickyness using the environment variable JK_STICKY_IGNORE. This can be useful to break cookie stickyness for non-sticky requests like login forms. (rjung) * Add: LB: New balancing method "Next" to distribute sessions in a round-robin way. (rjung) * Add: LB: Add counter for created sessions to status worker and HTTPD notes. It actually counts the number of requests that do not carry a session id. (rjung) * Add: URI Map: Add "stateless" extension attributes to uri worker map. This can improve session load balancing. (rjung) * Add: HTTPD: Allow dynamic switching of requests to "stateless" using the environment variable JK_STATELESS. (rjung) * Update: AJP: Improve logging when request does not fit into an AJP packet. (rjung) Changes between 1.2.31 and 1.2.32 Native * Fix: 51417: Fix worker busy detection by querying the worker endpoint. Abandoned connections can leave a worker in busy state without decrementing busy counter. (mturk) * Fix: 50339: Fix whitespace trimming when parsing attribute lists. (rjung) * Fix: 41263: Support Servlet API getRemotePort(). Works for Tomcat 5.5.28, 6.0.20 and 7.0.0 and Apache and ISAPI plugins. (rjung) * Fix: 41923: AJP: Close AJP connection to Tomcat on client write error when recovery_options 4 is specified, aborting the response write on the Tomcat side. (timw) * Update: AJP: Cap the lingering bytes that will be read when shutting down an AJP socket at 32k to prevent CPU spikes in the web server when a client aborts on a large response body. Also reduce total linger time to 2s. (timw) * Fix: 50839: AJP: Fix 30sec CPU spike due to incorrect counting of lingering bytes causing a busy loop when a client aborts connection during a response write. Fixes regression in 1.2.31. (timw) * Add: LB: Forward worker activation state as request attribute "JK_LB_ACTIVATION". Possible values are "ACT" (active), "DIS" (disabled) and "STP" (stopped). (rjung) * Fix: HTTPD: Forward WWW-Authenticate from backend when status is 401 and server generated error pages are used. (rjung) * Fix: 50363: IIS: Prevent chunk encoding of empty message bodies for 204, 205 and 304 responses. (timw) * Fix: 50975: IIS: Fix hanging of Transfer-Encoding: chunked requests when Content-Length header is present in request as well. Also addresses situation where IIS appears to create a Content-Length header for a small chunk encoded request when none was present in the original request. (timw) * Fix: 47679: IIS: stop truncation of request headers when ISAPI redirector used as an extension without the corresponding filter installed. (timw) * Fix: NSAPI: Use lower case header names for responses. Otherwise the web server might add chunked transfer encoding header in addition to our content length header. * Update: Docs: Improve load balancer documentation. (rjung) Changes between 1.2.30 and 1.2.31 Native * Fix: 49413: AJP13: Drop flush packets send by the backend after the response has been finished. (rjung) * Update: AJP: Log the local and remote socket address. (mturk) * Update: Watchdog: Move the maintain workers outside the critical section allowing other threads to use the connection pool during maintenance. (mturk) * Update: Common: Add svn revision to init log message. (rjung) * Fix: Common: Don't destroy errno during trace logging. (rjung) * Update: Apache: Add support for Apache 2.3/2.4. (rjung) * Update: Apache: Added version number resource for mod_jk.so on Windows. (timw) * Update: 48501: IIS: Added rotatelogs style log rotation to ISAPI Redirector. (timw) * Fix: 38895: IIS: Use RAW headers instead of CGI headers by default to prevent conversion of underscores '_' to hyphens '-' in header names. Old behaviour can be enabled by defining USE_CGI_HEADERS. (timw) * Fix: 49511: IIS: Do not override IIS log information when subsequent requests on a keep-alive connection are not mapped into the ISAPI Redirector. (timw) * Fix: Docs: Document SSLOptions needed for SSL information forwarding. (rjung) * Update: Docs: Grammar and style improvements and clarification about serving static content by IIS. Patch provided by André Warnier. (rjung) * Fix: Docs: Update subversion paths used in docs. (rjung) Changes between 1.2.28 and 1.2.30 Native * Update: Apache: Improve compatibility with Apache 2.3. (rjung) * Fix: 46632: Apache: Do not register child cleanup for our pools. (mturk) * Fix: 46893: Apache: Log warning only if JkShmSize was actually set in the configuration. (mturk) * Update: IIS: Include optional chunking support. Off by default. (mturk) * Fix: 48763: IIS: Do not send Content-Length when using chunked encoding or length larger 4GB. (mturk) * Fix: 48223: IIS: Propagate correct backend error code to IIS. (rjung) * Fix: 47867: IIS: crash during startup, when compiled with VS2008 and workers.properties contains unsupported properties. Patch provided by Indrek Juhani (rjung) * Fix: 47628: IIS: Fix deadlock when restarting the Application Pool caused by not releasing the critical section lock. Patch provided by Bret Prucha. (mturk) * Fix: IIS/NSAPI: Correct log file flushing after each line. (mturk) * Add: NSAPI: Add Microsoft Visual C++ Makefile. (mturk) * Update: AJP: Improve socket shutdown handling. (mturk) * Update: AJP: Ensure we never reuse a non reusable socket. (mturk) * Update: AJP: Tolerate a single excess packet when waiting for cpong. (mturk) * Update: AJP: Check protocol correctness more strictly. (mturk) * Update: 48410: AJP: Use poll instead select so we can work with more then 1024 sockets. (mturk) * Fix: 46503: AJP/Status: Garbage data in worker domain and route. (mturk) * Fix: 48276: AJP: When worker contact cannot be resolved mark the worker as disabled instead failing to start the server. (mturk) * Fix: 48169: AJP: Improve CGI interoperability by closing all sockets during EXEC. (mturk) * Add: Status: Add number of open backend connections to status worker. This feature is experimental, the displayed value might not be accurate. (mturk) * Update: 47224: Status: When address gets changed invalidate all opened sockets in the endpoint cache. This will cause new backend connections to get opened using new address. (mturk) * Fix: 48305: Status: Do not show "secret" property when doing dump. (mturk) * Fix: 45610: Status: Don't accept requests with empty value for sub worker parameter. (rjung) * Fix: 45610: Status: Fix erroneous unsetting of sticky_session and sticky_session_force when updating other load balancer attributes via the status worker. (rjung) * Fix: 47222: Status: Add ping_timeout to the shared memory and allow dynamic configuration. (mturk) * Fix: Status: Remove duplicate "errors" line in property view of AJP13 workers that are part of a load balancer. (rjung) * Fix: LB: Fix route logging. (rjung) * Update: Logging: Automatically detect size of thread id for logging. (rjung) * Update: Logging: Add optional log file locking for Windows when defining JK_LOG_LOCKING. (mturk) * Update: Configuration: Update example configuration. (rjung) * Update: Docs: Update information about tools needed to create a release. (rjung) * Fix: 47983: Docs: Fix typo in example config which breaks startup. (rjung) * Update: Build: Force copy of automake files. (rjung) * Update: Build: Tomcat code repository structure cleanup reflected in documentation and build script. (rjung, mturk) Changes between 1.2.27 and 1.2.28 Native * Add: Apache: Add more environment variables to overwrite request information. Useful in case a proxy is in front of Apache and sends us original request information e.g. via custom headers. (rjung) * Update: Apache: No longer preallocate entries for JK request log. (rjung) * Fix: 46352: Apache: Fix crash when using SetHandler jakarta-servlet in VHost without any JkMount. Crash due to incorrect initialization of mount extensions. (rjung) * Fix: Apache: JkWatchdogInterval had wrong interval calculation causing a 10 times higher watchdog interval then configured. (mturk) * Fix: Apache: Activate forwarding of SSL key size by default. (rjung) * Fix: 46169: Apache 1.3: Backport use_server_errors mount extension. (rjung) * Fix: 46763: Apache 2.0: Survive the log mutex during graceful restart. Patch provided by Eiji Takahashi. (mturk) * Fix: 46416: Apache 2.0 on Windows: Include mstcipip.h even if the apr doesn't include it. (mturk) * Update: IIS: Update uriworkermap.properties file on a regular interval. This requires both worker_mount_reload and watchdog_interval to be defined. (mturk) * Update: IIS: Remove obsolete entries from registry file. (mturk) * Fix: 46579: IIS: Use local environment table instead environment variables for setting the JKISAPI_PATH and JKISAPI_NAME. (mturk) * Update: LB: Add new property error_escalation_time to fine tune escalation of local errors to global errors. (rjung) * Update: LB: If the sticky session affinity mark contains a dot, treat the part before the dot as the domain name. This allows to have full node session affinity with domain failover. (mturk) * Fix: LB: make forced recovery work with local error states. (rjung) * Fix: LB: Only update error state and error time, if we actually have a new state. (rjung) * Fix: LB: Set global worker state to error when we reach max_reply_timeouts, or fail_on_status triggered hard error. (rjung) * Update: AJP: Add a new error type JK_AJP_PROTOCOL_ERROR. (mturk) * Update: AJP: Allow worker ports lower or equal to 1024. (rjung) * Update: AJP: Improve some AJP error log messages. (mturk) * Update: Status: Allow changing worker address and port of AJP workers. The address is resolved on next request for that worker. (mturk) * Update: Status: Allow update actions to show error messages in the result page. (rjung) * Update: Status: Refactor update actions. (rjung) * Update: Status: Do not redirect to the show or list page, if an error occured during an action. (rjung) * Update: Status: Include error time in display. (rjung) * Update: Status: Remove redundant port information from worker display. Rename address column and remove its explanation from the legend. (rjung) * Update: Status: Optimize forced uriworkermap.properties reload. (mturk) * Fix: Status: Fix crash in text display. (rjung) * Fix: Status: Show - Edit - Show always ends in single lb member show, even when started from all members lb show. (rjung) * Fix: Status: Wildcards in sub worker names were broken for update actions. (rjung) * Fix: Status: Add use_server_errors to map display. (rjung) * Update: SHM: Move locking into the data pull and push methods. (rjung) * Update: JNI: Deprecate JNI workers. (rjung) * Fix: Netware: Missing define for MAX_PATH. Patch by Guenter Knauf. (rjung) * Update: Docs: Add a new HowTo page about reverse proxies. (rjung) * Update: Docs: Add an explanation of local error states to the timeouts documentation. (rjung) * Update: Docs: Clarify relation between socket_timeout and socket_connect_timeout. (rjung) * Update: Docs: Clarify IIS URL rewrite feature. (rjung) * Fix: 46834,46734: Docs: Fix a couple of missing or broken links. (markt,rjung) * Fix: Docs: Add 2008 news to main page and menues. (mturk, rjung) Changes between 1.2.26 and 1.2.27 Native * Fix: 46109: Decay reply_timeouts even when lb method is busyness. Also reset reply_timeouts during forced recovery. (rjung) * Update: AJP13: Recycle connection if previous request didn't complete. (mturk) * Update: Maintain should not run multiple times in parallel. (mturk) * Fix: Apache: Fix small memory leak during restart. (mturk) * Update: Improve signal handling during socket shutdown. (mturk) * Add: URI Map: Add debug dump function for uri worker map. (rjung) * Update: Add revision number to version info for non-release builds. (rjung) * Add: IIS: Optionally allow chunked encoding for responses. At the moment only usable, if build with ISAPI_ALLOW_CHUNKING defined. Based on patch by Tim Whittington. (rjung) * Update: IIS: Optionally use raw headers instead of CGI headers. Fixes problem "underscore=dash" problem in header names. At the moment only available, if build with USE_RAW_HEADERS defined. (rjung) * Update: IIS: Optionally improve IIS 5.1 compatibility. At the moment only available, if build with AUTOMATIC_AUTH_NOTIFICATION defined. Based on patch by Tim Whittington. (rjung) * Fix: IIS: Fix memory corruption due to parallel initialization by multiple threads. (rjung) * Update: Windows: Use non-default socket keepalive interval. (mturk) * Add: IIS: Add environment variables JKISAPI_PATH and JKISAPI_NAME. (mturk) * Add: Added socket_connect_timeout directive for setting the connect timeout for the socket. This enables to have low connection timeout but higher operational timeouts. (mturk) * Fix: AJP13: [CVE-2008-5519] Always send initial POST packet even if the client disconnected after sending request but before providing POST data. In that case or in case the client broke the connection in a middle of read send an zero size packet informing container about broken client connection. (mturk) * Add: AJP13: Added connection_acquire_timeout directive for setting the absolute timeout the worker will wait for a free endpoint. (mturk) * Update: Apache: Allow to set path parameter used when doing JkStripSession. (mturk) * Update: Refactor retries implementation and change semantics of retries attributes. (mturk) * Update: Status: Allow showing only a single member for a load balancer. (rjung) * Update: Status: Add display of seconds since last statistics reset and access and transfer rates. (rjung) * Add: AJP13: Add a configurable retry_interval time. (rjung) * Update: Documentation: Enhance description of connection_pool_size. (rjung) * Update: IIS: Refactor error page generation. (mturk) * Fix: IIS: SERVER_NAME variable can be the same for multiple different server instances if requests are handled according to the ip:port combination. Use INSTANCE_ID variable to which the request belongs instead. (mturk) * Add: Allow forwarding server error pages. This can be done on per-uri basis using new use_server_errors extension. (mturk) * Add: Added session_cookie and session_path for configuring default session identifiers. (mturk) * Update: Use max_packet_size also as TCP send and receive buffer size. (mturk) * Update: Apache: Do not allow Apache to start in multi-threaded mode if mod_jk was only build for single threaded server (prefork). (mturk) * Fix: 45812: Add done() service method that causes sending EOS bucket for Apache httpd 2.x. This allows filter chain to work properly. (mturk) * Add: Added connection_ping_interval, ping_timeout and ping_mode directives. (mturk) * Fix: Apache: Use correct ld flags provided by apxs when building module. Prevents some crashes on AIX for httpd 1.3 module. (rjung) * Fix: Documentation: "val" attribute numbering in status worker needs to start with 0 instead of 1. (rjung) * Update: Documentation: Remove JNI parameters from sample configuration in the workers common howto. (rjung) * Fix: 45026: For Apache httpd 2.x add "Unknown Reason" as the reason phrase, if we get an empty one from the backend. Otherwise httpd 2.x returns status 500. (rjung) * Fix: Build: Fix Cygwin build. (rjung) * Update: Documentation: Add info to docs, that variables sent via JkEnvVar are not listed in request.getAttributeNames(). (rjung) * Add: Add watchdog background thread for Apache 2.x and IIS doing internal maintenance (idle connection checks, backend probing). See JkWatchdogInternal (Apache) and watchdog_interval (IIS). (mturk) * Update: Change log level of some messages from error to info. (mturk) * Fix: Documentation: Fix docs for worker attribute "secret". (rjung) * Update: Detect correct plugin name for various web servers via additional preprocessor defines. (rjung) * Fix: LB: Do not put loadbalancer node in error state if there is opened channel. This fixes the bug when new connection fails due to busyness, causing opened connections fail stickyness. This brings back per-node busy counter and private state array for each request. We can mark the state as error for failover to work while still operating and reporting node as OK if there are opened working connections. (mturk) * Fix: 44738: Fix merging of JkOption ForwardURI* between virtual hosts. Patch contributed by Toshihiro Sasajima. (rjung) * Add: URI Map: Add extension attributes to uri worker map. Allowed are reply_timeout, active/disabled/stopped and fail_on_status. Usage currently only implemented for httpd and IIS. (rjung+mturk) * Fix: URI Map: Make dynamic reloading atomic and free memory not needed any longer. (rjung) * Add: Configure: Don't use post httpd 2.2.0 API functions when building with new --enable-api-compatibility configure switch. (rjung) * Fix: Apache: JkAutoAlias does not work in combination with JkMountCopy if there are no JkMount in virtual host. (rjung) * Update: LB: Optimize state macros to improve performance. (rjung) * Add: Apache: Allow dynamic setting of reply timeout using the environment variable JK_REPLY_TIMEOUT. (rjung) * Add: Status: Add manageability for ajp parameters of ajp workers and ajp lb members. (rjung) * Update: Status: Change parameter names of update action to make them more easily distinguishable from other parameters. (rjung) * Add: Status: Add ajp worker statistics also for workers, that are not lb members. (rjung) * Update: AJP: Refactor factories, move ajp13/ajp14 common parts into ajp_factory. (rjung) * Update: Status: Only sync shm worker config values of the workers for which we changed values. (rjung) * Fix: Status: Set lb_factor instead of distance. (rjung) * Update: Status: Minor layout changes, use drop down instead of multiple text links. (rjung) * Update: SHM: Use local copies of read mostly attributes of lb sub workers in lb and status worker. (rjung) * Update: Status: Add "dump" action to dump our initial configuration. (rjung) * Update: Status: Use property table to decide which cmd action uses which output elements. (rjung) * Update: Common: Include original configuration map in worker_env to make it available for workers, e.g. the status worker. (rjung) * Update: LB: Refactor "route" return for httpd note. Don't use a member of the worker_record, because that's not thread safe. (rjung) * Update: Common: Refactor "retries", remove from service and jk_worker, move into ajp worker instead. (rjung) * Update: SHM: Use distinct structs for lb and ajp13 in shm. Improves type safety and saves a few bytes. (rjung) * Update: SHM: Remove unused attributes. (rjung) * Update: SHM: Automatically determine shm size for all web servers. (rjung) * Update: SHM: Make open/attach logging consistent for all web servers. (rjung) * Update: Status: Include server local time in output. (rjung) * Fix: 44116: Fix handling of multiple JSESSIONID cookies. (rjung) * Fix: 37850: Use thread safe localtime_r where appropriate. (rjung) * Fix: Use thread safe strtok_r on more platforms, especially AIX. (rjung) * Update: Status: Improve XSS hardening. (rjung) * Update: 35303: Move initialization of service members with defaults from web server specific code to our generic jk_init_ws_service() function. (rjung) * Fix: 36385: Add missing prepost CPing/CPong directly after connect in case prepost CPing is used, but no connect CPing. (rjung) * Update: 37322: Apache: Enhance robustness of message formating in jk_error_exit(). (rjung) * Fix: 44147: Multiple load balancing workers problem. (rjung) Changes between 1.2.25 and 1.2.26 Native * Fix: 42003: Allocate memory instead using fixed size from the stack. (mturk) * Fix: 43229: Load balancer does not do fail over after reply timeouts. (rjung) * Fix: JKStatus: Repair detailed Apache httpd version display. This was broken for httpd version 2.2.4+. (rjung) * Update: LB/AJP: Refactoring of jk_connect.c, jk_ajp_common.c, jk_lb_worker.c (rjung) * Fix: Configure: Repair broken apxs auto-detection. (rjung) * Update: Configure: Remove trace logging from compiled code via new --disable-trace configure switch. (rjung) * Update: Common: Maintain idle connections in decreasing (LRU) slot order. (rjung) * Update: Apache: Create JK_WORKER_ROUTE and JK_REQUEST_DURATION notes for access log even if no JkRequestLogFormat is set. (rjung) * Update: JKStatus: Enhance URI to worker map listing for Apache httpd. We now list maps for all virtual servers and not only the one, in which JKStatus itself was called. (rjung) * Update: JKStatus: Enhance URI to worker map listing. Update stale uriworkermap.properties immediately. (rjung) * Fix: 43873: Fix small memory leak occuring during httpd restart. (rjung) * Update: Common: Allow '*' for the worker name in exclusion rules (resp. JkUnMount) which will override all workers. (rjung) * Fix: 42038: Correct overlay of mounts and unmounts for IIS. (rjung) * Fix: 43684: Replace JkMountFile by JkMountFileReload in uriworkermap.properties docs. (rjung) * Update: Apache: Add new value "All" for JkMountCopy. (rjung) * Fix: 43516: Memory leak for Apache httpd module of size 8KB for every virtual host without JK directive after each restart. (rjung) * Update: Apache: Cleanup init and destroy of server configuration. (rjung) * Update: Apache: Remove global configuration items from per server configuration. (rjung) * Update: Apache: Remove unused attributes secret_key and automount/JkAutoMount. (rjung) * Update: Cleanup of jk_uri_worker_map. (rjung) * Update: Documentation: Small additions to JkShmFile documentation. Contributed by Gerhardus Geldenhuis. (rjung) * Fix: AJP13: Ignore flush packets before we received the response headers. (rjung) * Fix: Fix crash during startup when using worker configuration inheritance (attribute "reference") and log level debug. (rjung) * Fix: AJP13: Match header names exactly against pre defined constants. Avoid possible confusion with custom header names using a standard header name as a prefix. (rjung) * Fix: jkstatus: Fix correct parameter validation at JkStatusUpdateTask and JkStatusUpdateLoadbalancerTask ant tasks. Reported by Christian Mittendorf. (pero) Changes between 1.2.24 and 1.2.25 Native * Update: IIS: Fix shm shutdown behaviour. (rjung) * Update: General: fail_on_status used in a load balancer can optionally do fail over without putting the failed worker in error state. (rjung) * Update: NSAPI: Improve build description for Unix. (rjung) * Update: NSAPI: Add initialization startup message containing JK version. (rjung) * Fix: General: Declare static functions as static. (jim) * Update: Documentation: Clarify fail_on_status behaviour. (rjung) * Fix: General: Do fail_on_status before returning the response headers. (rjung) * Update: NSAPI: Fix shm shutdown behaviour. (rjung) * Update: NSAPI: Set return status even if request ended with an error. (rjung) * Update: NSAPI: Allow using without shm_file on WIN32 and Netware. (rjung) * Fix: NSAPI: Fix Crash of nsapi for log level debug and unset refect_unsafe. (rjung) * Update: NSAPI: Improve Solaris and Linux Makefiles for nsapi build. (rjung) * Fix: Build: Improve pid_t type detection during configure on Solaris. (rjung) * Update: Build: Experimental build support for gcc on WIN32 and Netware. (fuankg) * Update: Build: Makefile optimizations for Apache httpd 1.3/Netware . (fuankg) * Fix: General: Fix missing flush bug introduced in 1.2.24. (rjung) Changes between 1.2.23 and 1.2.24 Native * Update: Documentation: Improved workers.properties description in the reference guide. (rjung) * Update: Documentation: Add a HowTo about the various timeouts. rjung) * Update: Logging: add milliseconds to the default timestamp format, if we have gettimeofday(). (rjung) * Update: Apache: add milliseconds (%Q) and microseconds (%q) as possible JkLogStampFormat conversion specifiers. This does not use strftime(), but needs gettimeofday(). (rjung) * Update: IIS & Sun: Log service failures also, if return code is negative. (rjung) * Fix: 42849: Abort startup of Apache httpd 1.3 in case mod_jk initialization failed. We already do the same for Apache httpd 2.x. (rjung) * Fix: 42849: Refuse to operate with IIS in case the initialization failed. Instead requesting isapi_redirect.dll 500 will be returned to the user. This is as closest as it can get to Apache Httpd where we refuse to start the server in case of fatal initialization errors. (mturk) * Fix: Load Balancer: Fix a deadlock in lb worker, which was exposed on Solaris for threaded Apache MPMs. (rjung) * Update: Logging: handle LWP IDs as 32 Bit unsigned. Try to make it work, although pthread IDs are opaque. (rjung) * Update: JkStatus: Added manipulation of max_reply_timeouts. (rjung) * Update: LB, Status: Add feature max_reply_timeouts, to make lb tolerant against occasional long running requests. (rjung) * Update: JkStatus: Added OK/IDLE as the successor of N/A. (rjung) * Update: Status worker: Renamed runtime states. All states have a major state (OK or ERR) and a substate. Changed the name N/A to OK/IDLE. Added docs about the meaning of the states to the status worker page in the reference guide. No new states have been added to code. (rjung) * Update: Common: Add recovery options for recovering idempotent http methods HEAD and GET. (rjung) * Fix: Correct documentation for worker attributes retries and recovery_options. (rjung) * Fix: Make writing log lines and line endings more atomic. (rjung) * Update: Common: Refactored and unified jk_map_read_prop* and jk_map_load_prop* for all use cases. (rjung) * Update: Common/Apache/IIS/Netscape: Add an option to check decoded URLs for potentially malicious constructions. (rjung) * Update: IIS: Document auth_complete and uri_select. (rjung) * Update: Apache/IIS/Netscape: Change the default forwarding encoding to the new proxy method. (jfclere, rjung) * Update: Common: Optionally reencode URIs before forwarding to the backend. Based on the URI reencoding done bei httpd mod_proxy. (jfclere, rjung) * Update: Common: auto-detect correct print format for pid_t. This fixes at least compiler warnings on Solaris. (rjung) * Fix: 42608: Handle Content-length as unsigned 64Bit to allow for huge up- and downloads. (rjung) * Update: Apache: Add forwarding uri to debug log. (rjung) * Update: Docs: Clarify relation between worker names and jvmRoute for load balancing. (rjung) * Fix: Use initial zero timeout for jk_is_socket_connected. The resulting detection is the same but offers a huge performance increase with mod_jk. In most cases the Operating System does not favor the 1 microsecond timeout, but it rather rounds that up to much higher value (frequency of interrupt timer which on most systems defaults to 100Hz). Patch provided by David McLaughlin. (mturk) * Update: NSAPI: Check correct log file and shm file configuration during startup. (rjung) * Fix: NSAPI: Add support for the general options concerning retries, flushing and connection persistance. (rjung) * Fix: NSAPI: fix crashes due to use of mount attribute in workers.properties. Changed initialization order. (rjung) * Fix: Improved handling of libtool and discrepancies between CC env variable and CC used during apache build by configure script. (rjung) * Fix: Always build with thread support, unless flag --enable-prefork is set during for configure. (rjung) * Update: Use snprintf/vsnprintf from ap_snprintf.c for platforms other than Windows, which might lack snprintf/vsnprintf implementations when NOT build for Apache httpd 2.x/APR (e.g. Sub Web Server) or without using configure. (fuankg) * Update: Imported ap_snprintf() from Apache 1.3. (fuankg) * Fix: Fix incorrect log object cleanup during statup, leading to crashes at least on iSeries. (rjung) * Update: Add jk_stat() and jk_file_exists() as wrapper functions. i5/OS V5R4 expects filename in ASCII for fopen but requires them in EBCDIC for stat(). (hgomez) * Update: i5/OS (AS/400) V5R4 port where Apache 2.0 modules should now use UTF8. (hgomez) * Update: Docs: Add comments on i5/OS build for V5R4 and previous releases. (hgomez) Changes between 1.2.22 and 1.2.23 Native * Update: [CVE-2007-0450] and [CVE-2007-1860]: Change the default value of JkOptions to ForwardURICompatUnparsed. The old default value was ForwardURICompat. This should make URL interpretation between Apache httpd and Tomcat consistent (prevent double decoding problems). (rjung) Changes between 1.2.21 and 1.2.22 Native * Fix: Refactor line endings logging to make it correct for all platforms and webservers. (mturk) * Update: Added command line windows make files. (mturk) * Update: Allow fail_on_status directive to be multi line. (mturk) * Fix: 42076: Fix name of new option from ForwardCertChain to ForwardSSLCertChain as documented. (rjung) * Fix: Docs: Fix a couple of typos, change format of a few tables, fix links to news pages. (rjung) * Fix: Fix correct URL for TC 6 examples in new IIS rewrite.properties configuration example file. (rjung) * Fix: Add svn properties to several files. (rjung) * Update: Add TC 6 examples to uriworkermap.properties in config examples. (rjung) * Update: Allow multiple status codes for fail_on_status directive. The status codes can be delimited by space or comma characters. (mturk) * Update: IIS. Added pcre like regular expressions for url rewrite rules. (mturk) * Fix: 41922: Apache 1.3. Enable JkEnvVar. (mturk) * Update: Apache. Add --enable-flock configure parameter for explicit compilation of faster flock() system calls for OS supporting those calls. By default the fcntl system call for locking will be used that is a little bit slower but it can work on NFS mounted volumes as well. (mturk) * Fix: 41562: Add Debug logging for read from client in ISAPI Redirector. Contributed by Tim Whittington. (mturk) * Update: Apache. Add ForwardSSLCertChain JkOption. Contributed by Patrik Schnellmann. (mturk) * Fix: IIS. Do not forbid access to web-inf or meta-inf if there is no mapped worker. This allows to have resource with those names that are outside mapped contexts. (mturk) * Update: Apache. Use process id for creating shared memory name and delete shared memory and shared memory lock files on exit. (mturk) * Fix: IIS. Fix Keep-Alive regression introduced in 1.2.21. (mturk) * Update: Delete unused check for empty init_map during startup. (rjung) * Fix: 41770: Fix startup error if no JkWorkersFile is used. (rjung) * Update: Use JK_TRUE/JK_FALSE instead of OK/!OK as return values in init_jk(). (rjung) * Update: Minor adjustments to apache startup log messages (when to use STDERR, remove deprecated NOERRNO flag, shm warning and warnings for usage of default files). (rjung) * Update: Replace APR precompiler directive by httpd mpm_query to detect MPM threading. Add a debug log message about auto-detected pool size. (rjung) * Fix: Make MMN check easier to understand and a little more precise (for new ap_get_server_banner()/ap_get_server_description()). We use the new API only for Apache httpd 2.3. This way our binaries are not tightly coupled to a minor 2.0 version, and we don't use ap_get_server_banner() any way. (rjung) * Fix: Use the full description string ap_get_server_description() instead of the truncated info from ap_get_server_banner(), because this info gets used internally (status worker display and ajp14 backend communication) and is not send back to the normal user. (rjung) * Fix: 41757: Document the "--enable-prefork" flag of configure. (rjung) * Update: Enhance log messages for failures when parsing attribute maps. (rjung) * Fix: Correct log message during worker initialization, in case remote host could not be resolved. We logged the default host name "localhost" instead of the configured one. (rjung) * Fix: 41770: Fix the second part of the bug: local_worker and local_worker_only is missing from the list of deprecated attributes (and not supported either), so prevents the web server from startup. (rjung) Changes between 1.2.20 and 1.2.21 Native * Fix: [CVE-2007-0774]: A denial of service and critical remote code execution vulnerability. Caused by buffer overflow in map_uri_to_worker() when URL were longer that 4095 bytes. Reported by ZDI (www.zerodayintiative.com). Please note this issue only affected versions 1.2.19 and 1.2.20 of the Apache Tomcat JK Web Server Connector and not previous versions. Tomcat 5.5.20 and Tomcat 4.1.34 included a vulnerable version in their source packages. Other versions of Tomcat were not affected. * Add: Check the worker. parameters and don't start if the parameter is not a valid one. (jfclere) * Add: 41439: Allow session IDs to get stripped off URLs of static content in Apache by adding JkStripSession directive (configurable per vhost). (mturk) * Add: Change semantics of empty defaults for JkEnvVar variables. Until 1.2.19: not allowed. In 1.2.20: send variables as empty strings, if neither set to non empty in config, nor during runtime. Starting with 1.2.21: If config has no second argument only send variable if set (even when set to empty string) during runtime. Allows good combination with condition attribute in tomcat access log. (rjung) * Fix: 41610: Fix incorrect detection of missing Content-Length header leading to duplicate headers. Contributed by Boris Maras. (rjung) * Fix: Better build support for SunONE (Netscape/iPlanet) webservers. (jim) * Add: Add warning if duplicate map keys are read and are not allowed, e.g. when parsing uriworkermap.properties. (rjung) * Fix: Don't concat worker names, if uriworkermap.properties has a duplicate pattern, instead overwrite the worker. (rjung) * Fix: Log deprecation message even in duplication case. (rjung) * Fix: uriworkermap.properties: Fix off-by-one problem when deleting URL mapping during reloading of uriworkermap.properties. (rjung) * Add: 41439: Allow session IDs to get stripped off URLs of static content in IIS (configurable). (rjung) * Add: 41333: Refactoring isapi_plugin configuration reading. (rjung) * Add: 41332: Add some more errno logging and unify the format. (rjung) * Add: JkStatus: Improved logging by adding status worker name to messages. Added messages to the recover worker action. (rjung) * Add: JkStatus: Refactoring searching for workers and sub workers. (rjung) * Add: 41318: Add configuration to make status worker user name checks case insensitive. (rjung) * Add: JkStatus: Add estimated time until next global maintenance to other mime types and adopt jkstatus ant task. (rjung) * Add: JkStatus: Show estimated time until next global maintenance. Change displayed time until next recovery to a min/max pair. (rjung) * Add: JkStatus: Allow a user of a read/write status worker to switch it to and from read_only mode temporarily. (rjung) * Fix: JkStatus: Do not show read/write commands in a read_only status worker. (rjung) * Add: JkStatus: Allow lb sub workers in error state to be marked for recovery administratively from the status worker. (rjung) * Add: Load Balancer: Do not try to recover multiple times in parallel. Use additional runtime states "PROBE" and "FORCED". (rjung) * Fix: JkStatus: Improve data synchronization between different processes. (rjung) * Fix: 41381: Fix segfault in feature fail_on_status (wrong order of log arguments). Patch by Juri Haberland. (rjung) * Fix: Use correct windows line endings for log file on WIN32 platform. (rjung) Changes between 1.2.19 and 1.2.20 Native * Add: JkStatus Ant Task documentation page. (pero/rjung) * Add: JkStatus Ant Tasks: Add new tasks for update and reset. (pero) * Update: JkStatus Ant Tasks: Update for new xml status format. (pero) * Update: Allow integer and string values when setting enumeration/boolean attributes via status worker update action. (rjung) * Add: Docs: New reference guide page for status worker. (rjung) * Update: Docs: Renaming the config dir to reference and using the title Reference Guide in the docs. (rjung) * Update: Added retry_on_status for workers directive. (mturk) * Update: Status Worker: Add directive to make property prefix and good/bad rule configurable. (rjung) * Update: Status Worker: Omit lb members when att=nosw. (rjung) * Update: Status Worker: New command cmd=version for a short version output. (rjung) * Update: Status Worker: New output stype mime=prop produces property lists. (rjung) * Fix: Apache: Fix incorrect handling of JkEnvVar when Vars are set multiple times. (rjung) * Update: Renamed jvm_route to route. Deprecated jvm_route, but still use it as fallback when parsing the worker configuration. (rjung) * Update: IIS: Make uriworkermap file reload check interval configurable. (mturk) * Update: Apache: Make uriworkermap file reload check interval configurable. (rjung) * Update: Status Worker: Add directives for customizing the XML output (ns, xmlns, doctype). (mturk) * Add: Docs: New page with description of uriworkermap. (rjung) * Update: Docs: Added short description of max_packet_size to worker reference. (rjung) * Update: Status Worker: All functions accessible also for xml and txt mime types (list, show, update, reset). (rjung) * Update: Status Worker: New global health indicators for load balancers named bad (error, recovering or stopped), degraded (busy or disabled) and good (the rest, active and OK or N/A). (rjung) * Update: Status Worker: New edit page, to change one attribute for all members of a load balancer. (rjung) * Update: Status Worker: Standard logging for status worker. (rjung) * Update: Status Worker: code refactoring. (rjung) * Update: Status Worker: New attribute user (list) denies access, if the request user in the sense of remote_user is not in this list. Empty list = no deny (rjung) * Update: Status Worker: New attribute read_only disables the parts of the status worker, that change states and configurations. (rjung) * Fix: 36121: Don't change main uri when mod_jk serves included uri. (markt) * Update: Apache VHosts: Merge JkOptions +base - -base + +vhost - -vhost. (rjung) * Update: Apache Docs: Adding requirements, context information, default values and inheritance rules to the Apache config documentation. (rjung) * Update: Status Worker: Add source type to status worker, remove the redundant "context" column in the map listing (context=uri). (rjung) * Update: uriworkermap: On reload of the file, all old entries from the previous file version get deleted, before the new ones are being read. (rjung) * Fix: Keep normal maps and exclusion maps internally separate. Don't treat them as the same when adding a rule. (rjung) * Update: Status Worker: Display mapping rules also for non-lb workers and in global view. (rjung) * Update: Apache VHosts: Use the vhost log files instead of the main log. (rjung) * Update: Apache VHosts: Allow individual timestamp formats by refactoring the formatting method. (rjung) * Update: Apache VHosts: Adding all missing config items to the virtual host level. Don't overwrite the settings from the global server, but inherit them in case they are not set in the virtual host. (rjung) * Update: Apache: remove unnecessary function names from log messages. (rjung) * Update: Apache: add a default log file location and a message, if the default gets used. (rjung) * Update: Apache: add missing JK_IS_DEBUG_LEVEL() (rjung) * Update: Apache VHosts: Allow JkWorkersFile, JKWorkerProperty, JkShmFile and JkShmFileSize only in global virtual server. (rjung) * Update: Add some more jk_close_socket() and reduce log level for some info messages. (rjung) * Update: Load Balancer: Added the Sessions strategy. Contributed by Takayuki Kaneko. (rjung) * Update: Docs: Minor enhancements and syncing with more recent versions. (rjung) * Fix: 40997: Separate uri mappings from their '!' counterpart when checking for duplicates in uriworkermap reloading. (rjung) * Fix: 40877: Make sure the shared memory is reset on attach for multiple web server child processes. (mturk) * Update: IIS: Added shm_size property to be able to deal with over 64 workers configurations. (mturk) * Update: IIS: Increase default thread count to 250, so its the same as Apache Httpd default configuration. (mturk) * Fix: 40966: Fix socket descriptor checks on windows. (mturk) * Fix: 40965: Initialize missing service parameters. (mturk) * Fix: 40938: Fix releasing of rewrite map. Thanks to Chris Adams for spotting that. (mturk) * Update: Apache: Added +FlushHeader JkOptions. (mturk) * Update: Added explicit flush when AJP body packet size is zero. (mturk) * Fix: 40856: Fixing case sensitivity bug in URL mapping. (rjung) * Fix: 40793: Documentation: Improvements to Apache HowTo provided by Paul Charles Leddy. (markt) * Fix: 40774: Fixing wrong recursion termination. This one restricted the "reference" feature unintentionally to 20 workers. (rjung) * Fix: 40716: Adding "reference" feature to IIS and Netscape. (rjung) * Fix: Documentation: Corrected SetEnvIf syntax in JK_WORKER_NAME example. (rjung) * Fix: Documentation: Added forgotten STATE and ACTIVATION notes for load balancer logging in Apache. (rjung) * Update: Apache: Use instdso.sh instead libtool: libtool does not work on HP-UX for example. (jfclere) Changes between 1.2.18 and 1.2.19 Native * Update: Docs: Add SetHandler and new env var to Apache config docs. (rjung) * Update: Apache 1.3: Backport "no-jk" feature. (rjung) * Update: Apache: Add an environment variable to make SetHandler "jakarta-servlet" more useful. The variable is JK_WORKER_NAME, but can be changed by the new directive JkWorkerIndicator. (rjung) * Fix: LB: Don't use single worker shortcut, if the single worker is being diabled. (rjung) * Fix: Status worker: Add short explanation of activation and error states to legend. (rjung) * Fix: Docs: Add meaning of zero timeout values for various timeouts in workers.properties. (rjung) * Fix: LB: Cleanup of Mladens forced recovery. (rjung) * Fix: LB: Do not change lb_value for recovering workers to max, if we are using BUSYNESS method. (rjung) * Fix: Apache: Since 1.2.14 mod_jk failed to detect client abort. (rjung) * Fix: Docs: Corrected description of JkEnvVar. (rjung) * Fix: Solaris: Detect filio.h in configure to make the new connection detection build on solaris (r432825). (rjung) * Update: Add feature to force the recovery of workers that are member of loadbalancer if all the members are in error state. This fixes the time gap where 503 was returned caused by recovery_timeout although the backend was ready to handle the requests. (mturk) * Update: Docs: Seperate deprecated directives in their own table. (rjung) * Update: Docs: Allow "-" and "_" in worker names. (rjung) * Update: Allow multiple lines with attributes "balance_workers" and "mount". (rjung) * Fix: Make jk_is_some_property match more precisely. (rjung) * Update: JkStatus: Make refresh interval changeable. (rjung) * Fix: JkStatus: Adjust display of recover time wrt. global maintenance. (rjung) * Update: LB: Resetting worker state from OK to NA, if worker has been idle too long. (rjung) * Fix: Avoid compiler warnings concerning the use of lb_*_type arrays. Use functions instead. (rjung) * Update: Added %R JkRequestLogFormat option for Apache 1 and Apache 2. (mturk) * Update: Allow changing jvm Route from status manager. (mturk) * Fix: Do not retun 400 if Tomcat fails in the midle of the post request. Return 500 insted. (mturk) * Update: LB: Combine ok/error/recovering/busy runtime states into a single scalar. (rjung) * Update: LB: Combine active/disabled/stopped configuration states into a single scalar. (rjung) * Update: LB: Add several Apache notes to enable standard logging for load balancer results. (rjung) * Update: LB: Reorganisation of the main load balancer service loop. (rjung) * Update: Implement hierarchical worker configuration via attribute "reference". (rjung) * Update: Log deprecated properties. (rjung) * Fix: IIS: Fix simple_rewrite for the cases where the rewritten url is larger then the original one. (mturk) * Update: New JkOption "DisableReuse" to disable connection persistence. (jim) * Update: LB: Move sessionid retrieval out of get_most_suitable_worker into service. (rjung) * Update: Code cleanup for all service methods (use TRACE, JK_LOG_NULL_PARAMS, null pointer checks). (rjung) * Update: JKSTATUS: add refresh link. No refresh for updates. Redirect to list view after update. (rjung) * Update: Add new hook add_log_items into servers. (rjung) * Update: APACHE httpd: Rename apache logging notes. (rjung) * Update: LB: Rename lock and method constants. Add constants for defaults. (rjung) * Fix: Default log level should be INFO and not DEBUG. Default log level should be the same for all server types. (rjung) * Fix: Make rewrite_rule_map and log_level as non mandatory directives for isapi_redirect. (mturk) * Fix: 40107: Rewrite is_socket_connected function. Non blocking socket is not used any more. (mturk) * Update: Allow building with VS2005 without too many warnings. (mturk) * Fix: Decide by MMN, which piped log API we should use. mod_jk 1.2.18 broke compilation with Apache 1.3 pre 1.3.28. (rjung) Changes between 1.2.17 and 1.2.18 Native * Fix: Using socklen_t in getsockopt. Also introducing jk_sock_t. (mturk) * Update: Allow recovery wait time below 60 seconds (new minimum is 1 second). (mturk) Changes between 1.2.16 and JK 1.2.17 Native * Fix: Fix hanging jk status worker when certain attributes are being updated due to double locking. (rjung) * Update: Allow JkMount to behave like uriworkermap.properties by parsing pipe symbol as two directive marker. (mturk) Changes between 1.2.15 and JK 1.2.16 Native * Update: Added simple rewrite capability for IIS. Although simple it will fulfill most needs. (mturk) * Update: Added RECOVER_ABORT_IF_CLIENTERROR recovery_option that closes the connection if client connection is broken during the request. (mturk) * Update: Renamed cache_timeout directive to connection_pool_timeout. (mturk) * Update: Added connection_pool_minsize directive. (mturk) * Update: Deprecate recycle_timeout directive. (mturk) * Update: Corrected some HTML syntax bugs in output of status worker. (rjung) * Update: Added the refresh=n parameter to the status worker. It will update the display every n seconds. (rjung) * Update: Balancer: Add attribute distance to balanced workers to express preferences between workers. (rjung) * Update: Balancer: Add attribute jvm_route to balanced workers to be able to use the same target in different balancers. (rjung) * Update: Status: Add lb_mult to status. (rjung) * Update: Balancer: Make different balancing strategies work in a similar way (use lb_value, use decay during global maintenance, use integer factors for weights. (rjung) * Update: Balancer: Improve locking. (rjung) * Update: Balancer: Workers start slower after recovering. (rjung) * Update: Balancer: Make different balancing strategies work in a similar way (use lb_value, use decay during global maintenance, use integer factors lb_mult for weights). (rjung) * Update: Balancer: Move recovery check to global maintenance. (rjung) * Update: Balancer: Add global maintenance method, that is called in only one process. (rjung) * Update: Extend our use of autoconf to find a 32Bit and a 64Bit unsigned type and their printf formats. (rjung) * Update: Logging: piped loggers for JkLogFile and Apache 1.3. (rjung) * Update: Logging: Add PID to log lines for each log level apart from REQUEST. (rjung) * Update: Logging: flush buffered logs to keep lines in correct order. Output final newline together with log message. (rjung) * Update: Reducing shm size. (rjung) * Update: Only log removing of old worker, when we actually do it. (rjung) * Fix: 37469: Fix shared memory close for forked childs. The shared memory will be closed by the parent process. (mturk) * Fix: 37332: Fix potential misuse of buffer length with snprintf functions. (mturk) * Fix: 38859: [CVE-2006-7197] Protect mod_jk against buggy or malicious AJP servers in the backend. Patch provided by Ruediger Pluem. (mturk) * Fix: 38889: Use worker map sorting depending on the path elements, to comply with Servlet spec. Patch provided by Steve Revilak. (mturk) * Update: 36138: Added Busyness lb method. Patch provided by Chris Lamprecht. (mturk) * Fix: Fix pessimistic locking mode. The patch correctly handles the burst load, by syncing the access to the shared memory data. (mturk) * Fix: 38806: Reclycle worker even if it is disabled. This fixes hot-standby workers in error state. (mturk) * Fix: 37167: Allow building with BSD-ish like make. (mturk) * Fix: ISAPI plugin (isapi_redirect.dll) did not provide correct request data for IIS to include in the IIS log. (markt) Changes between 1.2.14 and 1.2.15 Native * Fix: Fix AJP13 Cookie2 parsing. Cookie2 was always send as Cookie. Patch provided by Andre Gebers. (mturk) * Fix: 35862: NSAPI plugin attempts to read freed memory and attempts to dereference a null pointer. Patch provided by Brian Kavanagh. (markt) Changes between 1.2.13 and 1.2.14 Native * Fix: Fix lb for worker mpm's with cachesize set to lower number then ThreadsPerChild is. If retries is set to value larger then 3 sleep for 100 ms on each attempt. This enables to tune the connection cache, and serialize incoming connections instead returning busy if connection count is larger then cachesize. (mturk) * Fix: 36525: Solaris core dump. (mturk) * Fix: 36102: Worker actions do not persist. (mturk) * Fix: 35864: Status worker doesn't list workers. Patch provided by Martin Goldhahn. (mturk) * Fix: 35809: JkMountCopy don't work for Apache 2.0 Patch provided by Christophe Dubach. (mturk) * Fix: 35298: Multiple JK/ISAPI redirectors on a single IIS site are not supported Patch provided by Tim Whittington. (mturk) Changes between 1.2.12 and 1.2.13 Native * Fix: 34397: Emergency was handled as Error. (jfclere) * Fix: 34474: // in URL were not handled correctly with Apache-1.3. (jfclere) * Fix: Use 64 bits int for transferred/read bytes. * Update: Added JkOptions +FlushPackets used to optimize memory usage when sending large data. (mturk) * Update: Added lock directive for load balancer that allows more acurate load balancing in case of burst load. (mturk) * Update: Added worker.maintain directive to allow customizing default 10 second timeout. On busy servers this value needs to be set on higher value. (mturk) * Fix: Fix for NetWare compiler to deal with different types between AP13 and AP2 SDKs. (fuankg) * Update: Emit much more legible user.dmp crash analysis output for WIN32. (wrowe) * Fix: 34558: Fix first failover request. (mturk) Changes between 1.2.11 and 1.2.12 Native * Update: Added ForwardLocalAddress JkOptions flag for passing local instead remote address. Useful for remote addr valve. (mturk) * Fix:Fix that worker does not get used, when stopped flag is set to true. (pero) * Update: Add loadbalance default worker secret attribute to the documentation (pero) Changes between 1.2.10 and 1.2.11 Native * Fix:Backport SC_M_JK_STORED from JK2 for passing arbitrary methods instead failing the request. (mturk) * Fix:Added missing SEARCH and ACL http methods. (mturk) * Update: Add worker secret attribute to the documentation (pero) * Update: Add a stopped flag to worker configuration. Set flag to true and the complete traffic to the worker will be stopped. Also update the Ant JkStatusUpdateTask at Tomcat 5.5.10 release. Only usefull in a replicated session cluster.(pero) * Update:Added worker maintain function that will maintain all the workers instead just the current one. This enables to recycle the connections on all workers. (mturk) * Update:Use shutdown when recycling connections instead hard breaking the socket. (mturk) * Update:Add unique directives checking. The directives if unique are now overwritten instead concatenated. (mturk) * Update:Allow multiple worker.list directives. (mturk) * Fix: 34577: For IIS log original request instead loging the request for ISAPI extension. (mturk) * Fix: 34558: Make sure the returned status codes are the same for ajp and lb workers. (mturk) * Fix: 34423: Use APR_USE_FLOCK_SERIALIZE for setting log lock on platforms like FreeBSD. Patch provided by Allan Saddi. (mturk) * Fix: 33843: Fix obtaining LDFLAGS that were used for building Apache HTTPD. Patch provided by Beat Kneubuehl. (mturk) * Fix: 34358: Enable load balancer method configuration. (glenn) * Fix: 34357: In some situations Apache 2 mod_jk could segfault when the JkAutoAlias directive is used. (glenn) * Update: Add --enable-prefork to the documentation (pero) * Update:Update tomcat_trend.pl for new error log string formatting. (glenn) Changes between 1.2.8 and 1.2.10 Native * Update:Set default shared memory to 64K instead 1M. (mturk) * Fix:Do not mark the worker in error state if headers are larger then AJP13 limit. (mturk) * Update: On iSeries you should use the latest PTF for Apache 2.0 (which is now 2.0.52) and ad minima SI17402/SI17061 or cumulative including them. (hgomez) * Update: Change the xml status format to xml attribute syntax (pero) * Fix: 33248: Fix builds where apxs defines multiple directories for APR includes. (mturk) * Fix: 32696: Return 404 instead 403 when WEB-INF is requested to comply with Servlet spec. (mturk) * Update:Added ANT task for managing jkstatus. (pero) * Update: If socket_timeout is set, check if socket is alive before sending any request to Tomcat. (mturk) * Update: Added JkMountFile for Apache web servers. This file can contain uri mappings in the form (/url=worker), and is checked for updates at regular 60 second interval. (mturk) * Update: Added status worker for managing worker runtime data using web page. (mturk) * Update: Added load balancer method directive that is used for setting the algorithm used for balancing workers. Method can be either Request (default) or Traffic. (mturk) * Update: Added shared memory to allow dynamic configuration. Shared memory is needed only for unix platform and web servers having multiple child processes. For Apache web server two new directives has been added (JkShmFile and JkShmSize). (mturk) * Update: Added textupdate mode to status worker to handle remote updates from ant tasks.(pero) * Fix: 33562: Fix Reply_timeout when recovery_options is larger than 1. Patch provided by Takashi Satou. (mturk) * Fix: 33308: Fix segfaults when ForwardDirectories is enabled with Apache 1.3 Changes between 1.2.7 and 1.2.8 Native * Update: Allow anyone to debug and diagnose stack dumps using windbg or any other debugging tool, and (if they add the .pdb files to their installation) to make sense of dr watson logs. Patch provided by William A. Rowe (wrowe) * Fix: Fix in_addr_t usage by using the real struct ignoring typedef. Patch provided by William A. Rowe (wrowe) * Fix: Fix url rewriting by restoring the in place uri from which the jsessionid was removed. (mturk) * Update: Make load balancer algorithm thread safe by introducing mutex to the load balancer worker. (mturk) * Fix: Fix sending error pages for IIS to client by adding Content-Type header using correct api function call. (mturk) * Fix: 32696: Prevent IIS from crushing when web-inf url was requested. (mturk) * Update: Use default cachesize for servers that support discovering the number of threads per child process. (mturk). * Fix: Fix Apache content-length header parsing using case insensitive compare. (billbarker) * Fix: Fix parsing AJP headers using case insensitive compare. (mturk) * Fix: Use infinite socket timeout if socket_timeout is set to zero or less then zero. (mturk) * Update: Change balanced_workers to balance_workers but keep backward compatibility preserving the old directive. (mturk). * Fix: Fix ajp initialization for workers with cache_size set to zero. (mturk) * Update: 32317: Making mod_jk replication aware (Clustering Support). Patch provided by Rainer Jung. (mturk). * Fix: 31132: Core dump when JkLogFile is missing from conf. (mturk) Changes between 1.2.6 and 1.2.7 Native * Update: Added new property named recover_time that can be used to change the default 60 second recover time. (mturk) * Update: Added custom retries for worker, so we don't depend on default setting. If set to a number grater then 3, it will sleep for 100ms on retry greater then 3 and then try again. (mturk) * Update: Added JkWorkerProperty directive that enables omiting workers.properties file. For example: JkWorkerProperty worker.ajp13a.port=8009. (mturk) * Fix: Check all JSESSIONID cookies for a valid jvmRoute. If you have multiple Tomcats with overlapping domains, then you can get multiple cookies without a defined order. This will route correctly as long as the different domains don't have any Tomcats in common. (billbarker) * Update: Added JkUnMount directive for negative mappings that works as opposite to JkMount directives. It is used for blocking of particular URL or content type. (mturk) * Update: Added wildchar match uri mappings. One can now use JkMount to map /app/*/servlet/* or /app?/*/*.jsp. (mturk) * Update: Rewrite the logging by adding Trace options. (mturk) * Update: Added socket_timeout property that sets the timeout for the socket itself. (mturk) * Fix: Changed socket_timeout property to recycle_timeout. This better explains what the directive actually does. (mturk) * Fix: Changed the load balancer algorithm. The idea behind this new scheduler is the following: lbfactor is how much we expect this worker to work, or the worker's work quota. lbstatus is how urgent this worker has to work to fulfill its quota of work. We distribute each worker's work quota to the worker, and then look which of them needs to work most urgently (biggest lbstatus). This worker is then selected for work, and its lbstatus reduced by the total work quota we distributed to all workers. Thus the sum of all lbstatus does not change.(*) If some workers are disabled, the others will still be scheduled correctly. (mturk) * Fix: Fix iis redirector that was figuring .properties file on each request. (mturk) * Fix: Start fixing 64/32 bit compatibility issues. (mturk) Changes between 1.2.5 and 1.2.6 Native * Fix: Fix POST Recovery problems in LB mode. (hgomez) * Add: Add CPING/CPONG support to avoid problems with hang tomcats. (hgomez) * Update: Make POST recovery in LB configurable. (hgomez) * Update: Update to Apache License 2.0. (hgomez) * Add: For Apache 2.0, when the env var no-jk is present, mod_jk didn't handle request (declined) and as such dont forward requests to tomcats even if URL match. To be used with SetEnvIf or BrowserMatch directives for example to exclude some URL/URI or Browser (hgomez). * Fix: Add a fix for iSeries (AS/400) which use XOPEN/Unix98 APIs and need sa_len to be set when calling connect(), it will resolve the error EINVAL in jk_connect. (hgomez) Changes between 1.2.4 and 1.2.5 Native * Fix: Fix a thread safe bug when mapping URI's. (billbarker) * Fix: Fix a thread safe bug when resolving worker host name when using mod_jk with Apache 2 and the worker MPM. (hgomez) * Fix: Remove an unnecessary error message when connections to all load balanced workers fail. (glenn) * Fix: When mod_jk cannot connect to a worker include the name of the worker in the error message. This is especially helpful when you are using load balanced workers. (glenn) * Fix: Fix problem with mod_jk.log getting opened multiple times for Apache 2. Only one mod_jk.log can be configured. (glenn) * Fix: Fix Apache 2 connector so that DirectoryIndex works for an index.jsp page if JkOptions ForwardDirectories was configured. (hgomez) * Fix: Fix exposure of JSP source if a //path/to.jsp URL was requested in Apache 1.3 and Apache 2.0 connector. (billbarker) Changes between 1.2.3 and 1.2.4 Native * Add: Fix use of libtool for Apache mod_jk builds with more recent versions of Apache 2. (jfclere) * Fix: Use reentrant version of strtok() for web server's which use threads. This fixes a thread safe bug under Apache 2 and the worker MPM. (glenn) * Fix: Fix the Apache 2 mod_jk hook priority so that mod_jk works well with both mod_alias and mod_dir. (glenn) Changes between 1.2.2 and 1.2.3 Native * Add: Add the ability to configure JkLog to pipe its log output to an executable such as Apache rotatelogs or cronolog. Apache 2.0 only. (glenn) * Add: Add JkAutoAlias to Apache 2.0. (glenn) * Update: Apache 2/1.3, if Tomcat returns an error but not content, let Apache handle processing the error returned by Tomcat. (glenn) * Add: Added the load balancer sticky_session property. If set to 0 requests with servlet SESSION ID's can be routed to any Tomcat worker. Default is 1, sessions are sticky. (glenn) * Fix: Cleaned up detection and reporting of aborted client connections. This cleanup also makes sure that mod_jk does not pass any requests on to Tomcat if the remote client aborted its connection. (glenn) * Fix: Fixed a bug in Apache 2.0 which caused a POST request forwarded to Tomcat to fail if it generated SSI directives which were post processed by mod_include. (glenn) * Fix: Fixed a bug in JkRequestLogFormat when printing the request URI that could cause a URI with hex escapes sequences to be formatted wrong. (glenn) Changes between 1.2.1 and 1.2.2 Native * Update: tomcat_trend.pl updated script to support changed logging of aborted requests. (glenn) * Fix: jk set correctly the content-type in Apache 2.0, making it ready to works with mod_deflate and AddOutputFilterByType. (hgomez) * Fix: jk will check result of get_endpoint and handle a failure. This call can fail if the allocation for the endpoint fails because of low memory conditions causing a dereference of NULL when we try and access the endpoint. (mmanders) Changes between 1.2.0 and 1.2.1 Native * Fix: 14282: Don't send initial chunk for chunked encoding. (costin) * Add: Add perl scripts for analyzing mod_jk logs and generating graphs/reports. (glenn) * Fix: Make JK honor the CanonicalHost directive. (hgomez) * Fix: Log cleanup. (costin) * Fix: Fix typos in jk xdocs/docs. (hgomez) * Fix: Add JkRequestLogFormat to Apache 2.0. (hgomez) * Fix: Final patches to make JK iSeries compliant. (hgomez) JK 2 JK2 has been put in maintainer mode and no further development will take place. The reason for shutting down JK2 development was the lack of developers interest. Other reason was lack of users interest in adopting JK2, caused by configuration complexity when compared to JK. Copyright © 1999-2024, The Apache Software Foundation tomcat-connectors-1.2.50-src/native/aclocal.m40000644000000000000020000133140214655113622017452 0ustar rootbin# generated automatically by aclocal 1.16.5 -*- Autoconf -*- # Copyright (C) 1996-2021 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. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, [m4_warning([this file was generated for autoconf 2.71. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # 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. m4_define([_LT_COPYING], [dnl # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool 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 . ]) # serial 58 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_PREPARE_CC_BASENAME # ----------------------- m4_defun([_LT_PREPARE_CC_BASENAME], [ # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } ])# _LT_PREPARE_CC_BASENAME # _LT_CC_BASENAME(CC) # ------------------- # It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, # but that macro is also expanded into generated libtool script, which # arranges for $SED and $ECHO to be set by different means. m4_defun([_LT_CC_BASENAME], [m4_require([_LT_PREPARE_CC_BASENAME])dnl AC_REQUIRE([_LT_DECL_SED])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl func_cc_basename $1 cc_basename=$func_cc_basename_result ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl m4_require([_LT_CMD_TRUNCATE])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl 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 set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. 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' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from 'configure', and 'config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # 'config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain=$ac_aux_dir/ltmain.sh ])# _LT_PROG_LTMAIN # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the 'libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to 'config.status' so that its # declaration there will have the same value as in 'configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags='_LT_TAGS'dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into 'config.status', and then the shell code to quote escape them in # for loops in 'config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # '#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test 0 = "$lt_write_fail" && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ '$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -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 Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test 0 != $[#] do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try '$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try '$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test yes = "$silent" && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 _LT_COPYING _LT_LIBTOOL_TAGS # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE _LT_PREPARE_MUNGE_PATH_LIST _LT_PREPARE_CC_BASENAME # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # 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 set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS=$save_LDFLAGS ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[912]]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[[012]][[,.]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*|11.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test yes = "$lt_cv_ld_force_load"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" m4_if([$1], [CXX], [ if test yes != "$lt_cv_apple_cc_single_mod"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script that will find a shell with a builtin # printf (that we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case $ECHO in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [Search for dependent libraries within DIR (or the compiler's sysroot if not specified).])], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([$with_sysroot]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and where our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else 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 fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cr} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test yes = "[$]$2"; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS ]) if test yes = "[$]$2"; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n "$lt_cv_sys_max_cmd_len"; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes = "$cross_compiling"; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #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 /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 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; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes != "$enable_dlopen"; 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 ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen=shl_load], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen=dlopen], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) ]) ]) ]) ]) ]) ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) 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 _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && 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 $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links=nottested if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) 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 AC_MSG_RESULT([$hard_links]) if test no = "$hard_links"; then AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", [Define to the sub-directory where libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then # We can hardcode non-existent directories. if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && # 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 no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) 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" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_PREPARE_MUNGE_PATH_LIST # --------------------------- # Make sure func_munge_path_list() is defined correctly. m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], [[# func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ]])# _LT_PREPARE_PATH_LIST # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so 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" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown AC_ARG_VAR([LT_SYS_LIBRARY_PATH], [User-defined run-time library search path.]) case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' 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 # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # 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$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a[(]lib.so.V[)]' # 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$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) 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=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $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' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$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" # 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* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # 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 library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' 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. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") 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" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # 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 dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # 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 # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # 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' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_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$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$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 # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' 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 ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$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$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no 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 ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[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]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], [Detected run-time system search path for libraries]) _LT_DECL([], [configure_time_lt_sys_library_path], [2], [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program that can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$1"; then lt_cv_path_MAGIC_CMD=$ac_dir/"$1" 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 <<_LT_EOF 1>&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 _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac]) MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program that can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) 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. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname 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 yes = "$with_gnu_ld"; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs 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 variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], [if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi]) rm -f conftest.i conftest2.i conftest.out]) ])# _LT_PATH_DD # _LT_CMD_TRUNCATE # ---------------- # find command to truncate a binary pipe m4_defun([_LT_CMD_TRUNCATE], [m4_require([_LT_PATH_DD]) AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], [printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) _LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], [Command to truncate a binary pipe]) ])# _LT_CMD_TRUNCATE # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [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 # that responds to the $file_magic_cmd with a given extended 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 aix[[4-9]]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[[45]]*) 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*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) 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|DragonFly)/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 ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) 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_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' 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 ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) 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 ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_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 # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) 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 ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi]) if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # _LT_DLL_DEF_P([FILE]) # --------------------- # True iff FILE is a Windows DLL '.def' file. # Keep in sync with func_dll_def_p in the libtool script AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ])# _LT_DLL_DEF_P # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM=-lm) ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test yes = "$GCC"; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # 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]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && 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 $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], [Transform the output of nm into a list of symbols to manually relocate]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([nm_interface], [lt_cv_nm_interface], [1], [The name lister interface]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # 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_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # 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). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # 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). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' if test ia64 != "$host_cpu"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64, which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test yes = "$GCC"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # 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_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # 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). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # 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). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # flang / f18. f95 an alias for gfortran or flang on Debian flang* | f18* | f95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp 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'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # 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. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # 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 yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, 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 install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$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)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&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. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$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. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; 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 # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi 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 # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; 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. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=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 _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$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)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # 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. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=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*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS=$save_LDFLAGS]) if test yes = "$lt_cv_irix_exported_symbol"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi _LT_TAGVAR(link_all_deplibs, $1)=no else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; osf3*) if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test yes = "$GCC"; then wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='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' ;; *) wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test yes,yes = "$GCC,$enable_shared"; then case $_LT_TAGVAR(archive_cmds, $1) 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. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC=$CC AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report what library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC=$lt_save_CC ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_caught_CXX_error"; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test yes = "$GXX"; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; 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 # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; 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. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GXX"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=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 _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ func_to_tool_file "$lt_outputfile"~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(GCC, $1)=$GXX _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test yes != "$_lt_caught_CXX_error" AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case @S|@2 in .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $prev$p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test x-L = "$p" || test x-R = "$p"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test no = "$pre_test_object_deps_done"; then case $prev in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)=$prev$p else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test no = "$pre_test_object_deps_done"; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)=$p else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)=$p else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test no = "$F77"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_F77"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$G77 _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_F77" AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test no = "$FC"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_FC"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && 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 yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_FC" AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code=$lt_simple_compile_test_code # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# 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_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f "$lt_ac_sed" && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test 10 -lt "$lt_ac_count" && break lt_ac_count=`expr $lt_ac_count + 1` if test "$lt_ac_count" -gt "$lt_ac_max"; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine what file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS # Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # 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. # serial 8 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option '$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl 'shared' nor 'disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], [_LT_WITH_AIX_SONAME([aix])]) ]) ])# _LT_SET_OPTIONS # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the 'shared' and # 'disable-shared' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [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. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the 'static' and # 'disable-static' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [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. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the 'fast-install' # and 'disable-fast-install' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [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. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_AIX_SONAME([DEFAULT]) # ---------------------------------- # implement the --with-aix-soname flag, and support the `aix-soname=aix' # and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT # is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) AC_ARG_WITH([aix-soname], [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], [case $withval in aix|svr4|both) ;; *) AC_MSG_ERROR([Unknown argument to --with-aix-soname]) ;; esac lt_cv_with_aix_soname=$with_aix_soname], [AC_CACHE_VAL([lt_cv_with_aix_soname], [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) with_aix_soname=$lt_cv_with_aix_soname]) AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac _LT_DECL([], [shared_archive_member_spec], [0], [Shared archive member basename, for filename based shared library versioning on AIX])dnl ])# _LT_WITH_AIX_SONAME LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the 'pic-only' and 'no-pic' # LT_INIT options. # MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac], [pic_mode=m4_default([$1], [default])]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # 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. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59, which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) # ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # 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. # @configure_input@ # serial 4179 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.6]) m4_define([LT_PACKAGE_REVISION], [2.4.6]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.6' macro_revision='2.4.6' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software # Foundation, Inc. # Written by Scott James Remnant, 2004. # # 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. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) # Copyright (C) 2002-2021 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. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.16.5], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2021 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. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2021 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. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2021 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. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [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". rm -rf conftest.dir 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 # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # 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. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # 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. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; 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 ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/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 # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2021 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. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2021 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 macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl m4_ifdef([_$0_ALREADY_INIT], [m4_fatal([$0 expanded multiple times ]m4_defn([_$0_ALREADY_INIT]))], [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi 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 AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi AC_SUBST([CTAGS]) if test -z "$ETAGS"; then ETAGS=etags fi AC_SUBST([ETAGS]) if test -z "$CSCOPE"; then CSCOPE=cscope fi AC_SUBST([CSCOPE]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # 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. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2021 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. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2021 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. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [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 AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2021 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. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2021 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. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2021 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. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2021 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. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2021 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. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2021 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. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # 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 ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file 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 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". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2021 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. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2021 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. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # 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. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2021 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. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2021 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. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR tomcat-connectors-1.2.50-src/native/docs/0000755000000000000020000000000014655113617016542 5ustar rootbintomcat-connectors-1.2.50-src/native/docs/api/0000755000000000000020000000000014655113617017313 5ustar rootbintomcat-connectors-1.2.50-src/native/docs/api/README.txt0000644000000000000020000000165314655113617021016 0ustar rootbin Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. To generate the API documentation for the mod_jk library, simply invoke make apidocs from the mod_jk Library root source path. (tomcat-connectors/jk/native) tomcat-connectors-1.2.50-src/native/buildconf.sh0000755000000000000020000000237514655113617020125 0ustar rootbin#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. scripts/build/unix/buildcheck.sh || exit 1 rm -rf autom4te.cache 2>/dev/null || true echo "buildconf: ${LIBTOOLIZE:-libtoolize} --automake --copy" ${LIBTOOLIZE:-libtoolize} --automake --copy echo "buildconf: aclocal" #aclocal --acdir=`aclocal --print-ac-dir` #aclocal --acdir=/usr/local/share/aclocal aclocal echo "buildconf: autoheader" autoheader echo "buildconf: automake -a --foreign --copy" automake -a --foreign --copy echo "buildconf: autoconf" autoconf rm -rf autom4te.cache tomcat-connectors-1.2.50-src/jkstatus/0000755000000000000020000000000014655113617016174 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/src/0000755000000000000020000000000014655113617016763 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/src/share/0000755000000000000020000000000014655113617020065 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/src/share/org/0000755000000000000020000000000014655113617020654 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/0000755000000000000020000000000014655113617022075 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/0000755000000000000020000000000014655113617022501 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/0000755000000000000020000000000014655113617024024 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkStatus.java0000644000000000000020000000437714655113617026452 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * @author Peter Rossbach * @see org.apache.jk.status.JkStatusParser */ public class JkStatus implements Serializable { JkServer server ; JkSoftware software ; JkResult result ; List balancers = new ArrayList() ; /** * @return Returns the balancers. */ public List getBalancers() { return balancers; } /** * @param balancers The balancers to set. */ public void setBalancers(List balancers) { this.balancers = balancers; } public void addBalancer(JkBalancer balancer) { balancers.add(balancer); } public void removeBalancer(JkBalancer balancer) { balancers.remove(balancer); } /** * @return Returns the server. */ public JkServer getServer() { return server; } public void setServer(JkServer server) { this.server = server ; } /** * @return the result */ public JkResult getResult() { return result; } /** * @param result the result to set */ public void setResult(JkResult result) { this.result = result; } /** * @return Returns the software. */ public JkSoftware getSoftware() { return software; } /** * @param software The software to set. */ public void setSoftware(JkSoftware software) { this.software = software; } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkStatusUpdateTask.java0000644000000000000020000003506414655113617030435 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.catalina.ant.AbstractCatalinaTask; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /status command, supported by the * mod_jk status (1.2.13) application. * * * @author Peter Rossbach * @since 5.5.10 * @deprecated */ public class JkStatusUpdateTask extends AbstractCatalinaTask { /** * The descriptive information about this implementation. */ private static final String info = "org.apache.jk.status.JkStatusUpdateTask/1.1"; private String worker = "lb"; private String workerType = "lb"; private int internalid = 0; private Integer lbRetries; private Integer lbRecovertime; private Boolean lbStickySession = Boolean.TRUE; private Boolean lbForceSession = Boolean.FALSE; private Integer workerLoadFactor; private String workerJvmRoute ; private int workerDistance = -1; private String workerRedirect; private String workerClusterDomain; private Boolean workerDisabled ; private Boolean workerStopped ; private int workerActivation = -1; private boolean isLBMode = true; private String workerLb; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } /** * */ public JkStatusUpdateTask() { super(); setUrl("http://localhost/jkstatus"); } /** * @return Returns the workerDistance. */ public int getWorkerDistance() { return workerDistance; } /** * @param workerDistance The workerDistance to set. */ public void setWorkerDistance(int workerDistance) { this.workerDistance = workerDistance; } /** * @return Returns the workerJvmRoute. */ public String getWorkerJvmRoute() { return workerJvmRoute; } /** * @param workerJvmRoute The workerJvmRoute to set. */ public void setWorkerJvmRoute(String workerJvmRoute) { this.workerJvmRoute = workerJvmRoute; } /** * @return Returns the internalid. */ public int getInternalid() { return internalid; } /** * @param internalid * The internalid to set. */ public void setInternalid(int internalid) { this.internalid = internalid; } /** * @return Returns the lbForceSession. */ public Boolean getLbForceSession() { return lbForceSession; } /** * @param lbForceSession * The lbForceSession to set. */ public void setLbForceSession(Boolean lbForceSession) { this.lbForceSession = lbForceSession; } /** * @return Returns the lbRecovertime. */ public Integer getLbRecovertime() { return lbRecovertime; } /** * @param lbRecovertime * The lbRecovertime to set. */ public void setLbRecovertime(Integer lbRecovertime) { this.lbRecovertime = lbRecovertime; } /** * @return Returns the lbRetries. */ public Integer getLbRetries() { return lbRetries; } /** * @param lbRetries * The lbRetries to set. */ public void setLbRetries(Integer lbRetries) { this.lbRetries = lbRetries; } /** * @return Returns the lbStickySession. */ public Boolean getLbStickySession() { return lbStickySession; } /** * @param lbStickySession * The lbStickySession to set. */ public void setLbStickySession(Boolean lbStickySession) { this.lbStickySession = lbStickySession; } /** * @return Returns the worker. */ public String getWorker() { return worker; } /** * @param worker * The worker to set. */ public void setWorker(String worker) { this.worker = worker; } /** * @return Returns the workerType. */ public String getWorkerType() { return workerType; } /** * @param workerType * The workerType to set. */ public void setWorkerType(String workerType) { this.workerType = workerType; } /** * @return Returns the workerLb. */ public String getWorkerLb() { return workerLb; } /** * @param workerLb * The workerLb to set. */ public void setWorkerLb(String workerLb) { this.workerLb = workerLb; } /** * @return Returns the workerClusterDomain. */ public String getWorkerClusterDomain() { return workerClusterDomain; } /** * @param workerClusterDomain * The workerClusterDomain to set. */ public void setWorkerClusterDomain(String workerClusterDomain) { this.workerClusterDomain = workerClusterDomain; } /** * @return Returns the workerDisabled. */ public Boolean getWorkerDisabled() { return workerDisabled; } /** * @param workerDisabled * The workerDisabled to set. */ public void setWorkerDisabled(Boolean workerDisabled) { this.workerDisabled = workerDisabled; } /** * @return Returns the workerActivation. */ public int getWorkerActivation() { return workerActivation; } /** *
    *
  • 0 active
  • *
  • 1 disabled
  • *
  • 2 stopped
  • *
* @param workerActivation The workerActivation to set. * */ public void setWorkerActivation(int workerActivation) { this.workerActivation = workerActivation; } /** * @return Returns the workerStopped. */ public Boolean getWorkerStopped() { return workerStopped; } /** * @param workerStopped The workerStopped to set. */ public void setWorkerStopped(Boolean workerStopped) { this.workerStopped = workerStopped; } /** * @return Returns the workerLoadFactor. */ public Integer getWorkerLoadFactor() { return workerLoadFactor; } /** * @param workerLoadFactor * The workerLoadFactor to set. */ public void setWorkerLoadFactor(Integer workerLoadFactor) { this.workerLoadFactor = workerLoadFactor; } /** * @return Returns the workerRedirect. */ public String getWorkerRedirect() { return workerRedirect; } /** * @param workerRedirect * The workerRedirect to set. */ public void setWorkerRedirect(String workerRedirect) { this.workerRedirect = workerRedirect; } /** * Execute the requested operation. * * @exception BuildException * if an error occurs */ public void execute() throws BuildException { super.execute(); checkParameter(); StringBuffer sb = createLink(); execute(sb.toString(), null, null, -1); } /** * Create JkStatus link *
    *
  • load balance example: * http://localhost/jkstatus?cmd=update&mime=txt&w=lb&vlf=false&vls=true
  • *
  • worker example: * http://localhost/jkstatus?cmd=update&mime=txt&w=lb&sw=node1&vwn=node01&vwf=1&vwa=2&vwx=0 *
    *
      *
    • vwa=0 active
    • *
    • vwa=1 disabled
    • *
    • vwa=2 stopped
    • *
    *
  • *
* *
Loadbalacing parameter: *
*
    *
  • w: name lb worker
  • *
  • vlr: Number of Retries
  • *
  • vlt: recover wait time
  • *
  • vlf: Force Sticky Session
  • *
  • vls: Sticky session
  • *
* *
Tcp worker parameter: *
*
    *
  • w: name worker
  • *
  • sw: name lb sub worker
  • *
  • vwf: load factor
  • *
  • vwn: jvm route
  • *
  • vwx: distance
  • *
  • vwa: activation state
  • *
  • vwr: redirect route
  • *
  • vwd: cluster domain
  • *
  • ws: stopped deprecated 1.2.16
  • *
  • wd: disabled deprecated 1.2.16
  • *
* * @return create jkstatus link */ private StringBuffer createLink() { // Building URL StringBuffer sb = new StringBuffer(); try { sb.append("?cmd=update&mime=txt"); sb.append("&w="); if (isLBMode) { sb.append(URLEncoder.encode(worker, getCharset())); //http://localhost/jkstatus?cmd=update&mime=txt&w=lb&vlf=false&vls=true if ((lbRetries != null)) { // > 0 sb.append("&vlr="); sb.append(lbRetries); } if ((lbRecovertime != null)) { // > 59 sb.append("&vlt="); sb.append(lbRecovertime); } if ((lbStickySession != null)) { sb.append("&vls="); sb.append(lbStickySession); } if ((lbForceSession != null)) { sb.append("&vlf="); sb.append(lbForceSession); } } else { //http://localhost/status?cmd=update&mime=txt&sw=node1&w=lb&vwf=1&wd=false&ws=false if (workerLb != null) { // must be configured sb.append(URLEncoder.encode(workerLb, getCharset())); } sb.append("&sw="); sb.append(URLEncoder.encode(worker, getCharset())); if (workerLoadFactor != null) { // >= 1 sb.append("&vwf="); sb.append(workerLoadFactor); } if (workerJvmRoute != null) { sb.append("&vwn="); sb.append(URLEncoder.encode(workerJvmRoute, getCharset())); } if (workerDisabled != null) { sb.append("&vwd="); sb.append(workerDisabled); } if (workerStopped != null) { sb.append("&vws="); sb.append(workerStopped); } if (workerActivation >= 0 && workerActivation < 3) { sb.append("&vwa="); sb.append(workerActivation); } if (workerDistance >= 0) { sb.append("&vwx="); sb.append(workerDistance); } if (workerRedirect != null) { // other worker conrecte lb's sb.append("&vwr="); sb.append(URLEncoder.encode(workerRedirect, getCharset())); } if (workerClusterDomain != null) { sb.append("&vwc="); sb.append(URLEncoder.encode(workerClusterDomain, getCharset())); } } } catch (UnsupportedEncodingException e) { throw new BuildException("Invalid 'charset' attribute: " + getCharset()); } return sb; } /** * check correct lb and worker pararmeter */ protected void checkParameter() { if (worker == null) { throw new BuildException("Must specify 'worker' attribute"); } if (workerType == null) { throw new BuildException("Must specify 'workerType' attribute"); } if ("lb".equals(workerType)) { if (lbRecovertime == null && lbRetries == null) { throw new BuildException( "Must specify at a lb worker either 'lbRecovertime' or" + "'lbRetries' attribute"); } if (lbStickySession == null || lbForceSession == null) { throw new BuildException("Must specify at a lb worker either" + "'lbStickySession' and 'lbForceSession' attribute"); } if (null != lbRecovertime && 60 < lbRecovertime.intValue()) { throw new BuildException( "The 'lbRecovertime' must be greater than 59"); } if (null != lbRetries && 1 < lbRetries.intValue()) { throw new BuildException( "The 'lbRetries' must be greater than 1"); } isLBMode = true; } else if ("worker".equals(workerType)) { if (workerLoadFactor == null ) { throw new BuildException( "Must specify at a node worker 'workerLoadFactor' attribute"); } if (workerClusterDomain == null) { throw new BuildException( "Must specify at a node worker 'workerClusterDomain' attribute"); } if (workerRedirect == null) { throw new BuildException( "Must specify at a node worker 'workerRedirect' attribute"); } if (workerLb == null) { throw new BuildException("Must specify 'workerLb' attribute"); } if (workerLoadFactor.intValue() < 1) { throw new BuildException( "The 'workerLoadFactor' must be greater or equal 1"); } isLBMode = false; } else { throw new BuildException( "Only 'lb' and 'worker' supported as workerType attribute"); } } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkStatusResetTask.java0000644000000000000020000000671214655113617030273 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /jkstatus?cmd=reset&w=loadbalancer command, supported by the * mod_jk status (1.2.20) application. * * @author Peter Rossbach * @since mod_jk 1.2.20 */ public class JkStatusResetTask extends AbstractJkStatusTask { /** * The descriptive information about this implementation. */ private static final String info = "org.apache.jk.status.JkStatusResetTask/1.1"; private String worker; private String loadbalancer; /** * */ public JkStatusResetTask() { super(); setUrl("http://localhost/jkstatus"); } /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } /** * @return the loadbalancer */ public String getLoadbalancer() { return loadbalancer; } /** * @param loadbalancer the loadbalancer to set */ public void setLoadbalancer(String loadbalancer) { this.loadbalancer = loadbalancer; } /** * @return the worker */ public String getWorker() { return worker; } /** * @param worker the worker to set */ public void setWorker(String worker) { this.worker = worker; } /** * Create jkstatus reset link *
    *
  • loadbalancer example: * http://localhost/jkstatus?cmd=reset&mime=txt&w=loadbalancer
  • *
  • loadbalancer + sub worker example: * http://localhost/jkstatus?cmd=reset&mime=txt&w=loadbalancer&sw=node01
  • *
* * @return create jkstatus reset link */ protected StringBuffer createLink() { // Building URL StringBuffer sb = new StringBuffer(); try { sb.append("?cmd=reset"); sb.append("&mime=txt"); sb.append("&w="); sb.append(URLEncoder.encode(loadbalancer, getCharset())); if(worker != null) { sb.append("&sw="); sb.append(URLEncoder.encode(worker, getCharset())); } } catch (UnsupportedEncodingException e) { throw new BuildException("Invalid 'charset' attribute: " + getCharset()); } return sb; } /** * check correct pararmeter */ protected void checkParameter() { if (loadbalancer == null) { throw new BuildException("Must specify 'loadbalanacer' attribute"); } } }tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/antlib.xml0000644000000000000020000000251114655113617026016 0ustar rootbin tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkStatusAccessor.java0000644000000000000020000001044614655113617030127 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.net.URLConnection; import org.apache.catalina.util.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.tomcat.util.digester.Digester; /** * Create connection to mod_jk jkstatus page. * Optional you can use Http basic auth user and password. * @author Peter Rossbach * @see org.apache.jk.status.JkStatusParser * @since 5.5.10 */ public class JkStatusAccessor { private static Log log = LogFactory.getLog(JkStatusAccessor.class); /** * The descriptive information about this implementation. */ protected static final String info = "org.apache.jk.status.JkStatusAccessor/1.0"; /** * Parse Apache mod_jk Status from base url http://host:port/jkstatus) * @param url * @param username * @param password * */ public JkStatus status(String url, String username, String password) throws Exception { if(url == null || "".equals(url)) return null ; HttpURLConnection hconn = null; JkStatus status = null; try { // FIXME: use cmd show for older mod_jk versions hconn = openConnection(url + "?cmd=list&mime=xml", username, password); Digester digester = JkStatusParser.getDigester(); synchronized (digester) { status = (JkStatus) digester.parse(hconn.getInputStream()); } } catch (Throwable t) { throw new Exception(t); } finally { if (hconn != null) { try { hconn.disconnect(); } catch (Throwable u) { ; } hconn = null; } } return status; } /** * Create a auth http connection for this url * * @param url * @param username * @param password * @return HttpConnection * @throws IOException * @throws MalformedURLException * @throws ProtocolException */ protected HttpURLConnection openConnection(String url, String username, String password) throws IOException, MalformedURLException, ProtocolException { URLConnection conn; conn = (new URL(url)).openConnection(); HttpURLConnection hconn = (HttpURLConnection) conn; // Set up standard connection characteristics hconn.setAllowUserInteraction(false); hconn.setDoInput(true); hconn.setUseCaches(false); hconn.setDoOutput(false); hconn.setRequestMethod("GET"); hconn.setRequestProperty("User-Agent", "JkStatus-Client/1.0"); if(username != null && password != null ) { setAuthHeader(hconn, username, password); } // Establish the connection with the server hconn.connect(); return hconn; } /** * Set Basic Auth Header * * @param hconn * @param username * @param password */ protected void setAuthHeader(HttpURLConnection hconn, String username, String password) { // Set up an authorization header with our credentials String input = username + ":" + password; String output = new String(Base64.encode(input.getBytes())); hconn.setRequestProperty("Authorization", "Basic " + output); } }tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/jkstatus.tasks0000644000000000000020000000210014655113617026734 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Apache mod_jk jk status tasks jkUpdateWorker=org.apache.jk.status.JkStatusUpdateWorkerTask jkUpdateLoadbalancer=org.apache.jk.status.JkStatusUpdateLoadbalancerTask jkUpdate=org.apache.jk.status.JkStatusUpdateTask jkReset=org.apache.jk.status.JkStatusResetTask jkStatus=org.apache.jk.status.JkStatusTask tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/AbstractJkStatusTask.java0000644000000000000020000001536314655113617030756 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.net.URLConnection; import org.apache.catalina.ant.AbstractCatalinaTask; import org.apache.catalina.util.Base64; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; /** * Ant task that implements mod_jk 1.2.20 result message string * * @author Peter Rossbach * @since mod_jk 1.2.20 */ public abstract class AbstractJkStatusTask extends AbstractCatalinaTask { /** * Execute the requested operation. * * @exception BuildException * if an error occurs */ public void execute() throws BuildException { super.execute(); checkParameter(); StringBuffer sb = createLink(); execute(sb.toString(), null, null, -1); } protected abstract void checkParameter() ; protected abstract StringBuffer createLink() ; /** * Execute the specified command, based on the configured properties. * The input stream will be closed upon completion of this task, whether * it was executed successfully or not. * * @param command Command to be executed * @param istream InputStream to include in an HTTP PUT, if any * @param contentType Content type to specify for the input, if any * @param contentLength Content length to specify for the input, if any * * @exception BuildException if an error occurs */ public void execute(String command, InputStream istream, String contentType, int contentLength) throws BuildException { InputStreamReader reader = null; try { HttpURLConnection hconn = send(command, istream, contentType, contentLength); // Process the response message reader = new InputStreamReader(hconn.getInputStream(), "UTF-8"); String error = null; error = handleResult(reader, error); if (error != null && isFailOnError()) { // exception should be thrown only if failOnError == true // or error line will be logged twice throw new BuildException(error); } } catch (Throwable t) { if (isFailOnError()) { throw new BuildException(t); } else { handleErrorOutput(t.getMessage()); } } finally { closeRedirector(); if (reader != null) { try { reader.close(); } catch (Throwable u) { ; } reader = null; } if (istream != null) { try { istream.close(); } catch (Throwable u) { ; } istream = null; } } } private String handleResult(InputStreamReader reader, String error) throws IOException { StringBuffer buff = new StringBuffer(); int msgPriority = Project.MSG_INFO; boolean first = true; while (true) { int ch = reader.read(); if (ch < 0) { break; } else if ((ch == '\r') || (ch == '\n')) { // in Win \r\n would cause handleOutput() to be called // twice, the second time with an empty string, // producing blank lines if (buff.length() > 0) { String line = buff.toString(); buff.setLength(0); if (first) { if (!line.startsWith("Result: type=OK")) { error = line; msgPriority = Project.MSG_ERR; } first = false; } handleOutput(line, msgPriority); } } else { buff.append((char) ch); } } if (buff.length() > 0) { handleOutput(buff.toString(), msgPriority); } return error; } protected HttpURLConnection send(String command, InputStream istream, String contentType, int contentLength) throws IOException, MalformedURLException, ProtocolException { URLConnection conn; // Create a connection for this command conn = (new URL(url + command)).openConnection(); HttpURLConnection hconn = (HttpURLConnection) conn; // Set up standard connection characteristics hconn.setAllowUserInteraction(false); hconn.setDoInput(true); hconn.setUseCaches(false); if (istream != null) { hconn.setDoOutput(true); hconn.setRequestMethod("PUT"); if (contentType != null) { hconn.setRequestProperty("Content-Type", contentType); } if (contentLength >= 0) { hconn.setRequestProperty("Content-Length", "" + contentLength); } } else { hconn.setDoOutput(false); hconn.setRequestMethod("GET"); } hconn.setRequestProperty("User-Agent", "JkStatus-Ant-Task/1.1"); // Set up an authorization header with our credentials String input = username + ":" + password; String output = new String(Base64.encode(input.getBytes())); hconn.setRequestProperty("Authorization", "Basic " + output); // Establish the connection with the server hconn.connect(); // Send the request data (if any) if (istream != null) { BufferedOutputStream ostream = new BufferedOutputStream(hconn.getOutputStream(), 1024); byte buffer[] = new byte[1024]; while (true) { int n = istream.read(buffer); if (n < 0) { break; } ostream.write(buffer, 0, n); } ostream.flush(); ostream.close(); istream.close(); } return hconn; } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkSoftware.java0000644000000000000020000000307714655113617026755 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.Serializable; /** * @author Peter Rossbach * @see org.apache.jk.status.JkStatusParser */ public class JkSoftware implements Serializable { String web_server; String jk_version ; /** * @return Returns the software. */ public String getWeb_server() { return web_server; } /** * @param software The software to set. */ public void setWeb_server(String software) { this.web_server = software; } /** * @return Returns the version. */ public String getJk_version() { return jk_version; } /** * @param version The version to set. */ public void setJk_version(String version) { this.jk_version = version; } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkResult.java0000644000000000000020000000262614655113617026440 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.Serializable; /** * @author Peter Rossbach * @see org.apache.jk.status.JkStatusParser */ public class JkResult implements Serializable { String type ; String message; /** * @return the message */ public String getMessage() { return message; } /** * @param message the message to set */ public void setMessage(String message) { this.message = message; } /** * @return the type */ public String getType() { return type; } /** * @param type the type to set */ public void setType(String type) { this.type = type; } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkBalancerMember.java0000644000000000000020000002346214655113617030022 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.Serializable; /** * @author Peter Rossbach * @see org.apache.jk.status.JkStatusParser */ public class JkBalancerMember implements Serializable { int id = -1; String name; /* possible with >= 1.2.16 */ String jvm_route; /* possible with >= 1.2.20 */ String route; String type; String host; int port; String address; /* deprecated with mod_jk 1.2.16*/ String status; /* possible with > 1.2.16 */ String activation; /* possible with > 1.2.16 */ String state; int lbfactor; long lbvalue; /* possible with > 1.2.16 */ long lbmult = -1 ; int elected; long readed; long transferred; long errors; long clienterrors = -1; int busy; /* possible with > 1.2.16 */ int maxbusy = -1; String redirect; String domain; /* possible with > 1.2.16 */ int distance = -1; /* possible with > 1.2.20 */ int time_to_recover = -1 ; /* possible with > 1.2.21 */ int time_to_recover_max = -1 ; /* possible with > 1.2.21 */ int time_to_recover_min = -1 ; /** * @return Returns the jvm_route. * @since mod_jk 1.2.16 * @deprecated */ public String getJvm_route() { return jvm_route; } /** * @param jvm_route The jvm_route to set. * @since mod_jk 1.2.16 * @deprecated */ public void setJvm_route(String jvm_route) { this.jvm_route = jvm_route; } /** * @return the route * @since mod_jk 1.2.20 */ public String getRoute() { return route; } /** * @param route the route to set * @since mod_jk 1.2.20 */ public void setRoute(String route) { this.route = route; } /** * @return Returns the address. */ public String getAddress() { return address; } /** * @param address * The address to set. */ public void setAddress(String address) { this.address = address; } /** * @return Returns the busy. */ public int getBusy() { return busy; } /** * @param busy * The busy to set. */ public void setBusy(int busy) { this.busy = busy; } /** * @return Returns the maxbusy. * @since mod_jk 1.2.18 */ public int getMax_busy() { return maxbusy; } /** * @param maxbusy The maxbusy to set. * @since mod_jk 1.2.18 */ public void setMax_busy(int maxbusy) { this.maxbusy = maxbusy; } /** * @return Returns the elected. */ public int getElected() { return elected; } /** * @param elected * The elected to set. */ public void setElected(int elected) { this.elected = elected; } /** * @return Returns the clienterrors. * @since mod_jk 1.2.19 */ public long getClient_errors() { return clienterrors; } /** * @param clienterrors The clienterrors to set. * @since mod_jk 1.2.19 */ public void setClient_errors(long clienterrors) { this.clienterrors = clienterrors; } /** * @return Returns the errors. */ public long getErrors() { return errors; } /** * @param errors * The errors to set. */ public void setErrors(long errors) { this.errors = errors; } /** * @return Returns the host. */ public String getHost() { return host; } /** * @param host * The host to set. */ public void setHost(String host) { this.host = host; } /** * @return Returns the id. */ public int getId() { return id; } /** * @param id * The id to set. */ public void setId(int id) { this.id = id; } /** * @return Returns the lbfactor. */ public int getLbfactor() { return lbfactor; } /** * @param lbfactor * The lbfactor to set. */ public void setLbfactor(int lbfactor) { this.lbfactor = lbfactor; } /** * @return Returns the lbvalue. */ public long getLbvalue() { return lbvalue; } /** * @param lbvalue * The lbvalue to set. */ public void setLbvalue(long lbvalue) { this.lbvalue = lbvalue; } /** * @return Returns the lbmult. * @since mod_jk 1.2.19 */ public long getLbmult() { return lbmult; } /** * @param lbmult The lbmult to set. * @since mod_jk 1.2.19 */ public void setLbmult(long lbmult) { this.lbmult = lbmult; } /** * @return Returns the name. */ public String getName() { return name; } /** * @param name * The name to set. */ public void setName(String name) { this.name = name; } /** * @return Returns the port. */ public int getPort() { return port; } /** * @param port * The port to set. */ public void setPort(int port) { this.port = port; } /** * @return Returns the readed. */ public long getReaded() { return readed; } /** * @param readed * The readed to set. */ public void setReaded(long readed) { this.readed = readed; } /** * @return Returns the status. * @deprecated since 1.2.16 */ public String getStatus() { return status; } /** * @param status * The status to set. * @deprecated since 1.2.16 */ public void setStatus(String status) { this.status = status; } /** * @return Returns the activation. * @since mod_jk 1.2.19 */ public String getActivation() { return activation; } /** * @param activation The activation to set. * @since mod_jk 1.2.19 */ public void setActivation(String activation) { this.activation = activation; } /** * @return Returns the state. * @since mod_jk 1.2.19 */ public String getState() { return state; } /** * @param state The state to set. * @since mod_jk 1.2.19 */ public void setState(String state) { this.state = state; } /** * @return Returns the transferred. */ public long getTransferred() { return transferred; } /** * @param transferred * The transferred to set. */ public void setTransferred(long transferred) { this.transferred = transferred; } /** * @return Returns the type. */ public String getType() { return type; } /** * @param type * The type to set. */ public void setType(String type) { this.type = type; } /** * @return Returns the domain. */ public String getDomain() { return domain; } /** * @param domain The domain to set. */ public void setDomain(String domain) { this.domain = domain; } /** * @return Returns the redirect. */ public String getRedirect() { return redirect; } /** * @param redirect The redirect to set. */ public void setRedirect(String redirect) { this.redirect = redirect; } /** * @return Returns the distance. * @since mod_jk 1.2.18 */ public int getDistance() { return distance; } /** * @param distance The distance to set. * @since mod_jk 1.2.18 */ public void setDistance(int distance) { this.distance = distance; } /** * @return the time_to_recover * @since mod_jk 1.2.20 */ public int getTime_to_recover() { return time_to_recover; } /** * @param time_to_recover the time_to_recover to set * @since mod_jk 1.2.20 */ public void setTime_to_recover(int time_to_recover) { this.time_to_recover = time_to_recover; } /** * @return the time_to_recover_min * @since mod_jk 1.2.21 */ public int getTime_to_recover_min() { return time_to_recover_min; } /** * @param time_to_recover_min the time_to_recover_min to set * @since mod_jk 1.2.21 */ public void setTime_to_recover_min(int time_to_recover_min) { this.time_to_recover_min = time_to_recover_min; } /** * @return the time_to_recover_max * @since mod_jk 1.2.21 */ public int getTime_to_recover_max() { return time_to_recover_max; } /** * @param time_to_recover_max the time_to_recover_max to set * @since mod_jk 1.2.21 */ public void setTime_to_recover_max(int time_to_recover_max) { this.time_to_recover_max = time_to_recover_max; } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkBalancer.java0000644000000000000020000001717314655113617026674 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * @author Peter Rossbach * @see org.apache.jk.status.JkStatusParser */ public class JkBalancer implements Serializable { int id =-1; String name ; String type ; boolean sticky ; boolean stickyforce; int retries ; int recover ; String method ; String lock ; int good = -1 ; int degraded = -1; int bad = -1 ; int busy = -1; int max_busy = -1 ; int member_count = -1 ; int map_count = -1 ; int time_to_maintenance_min = -1 ; int time_to_maintenance_max = -1 ; List members = new ArrayList() ; List mappings = new ArrayList() ; /** * @return Returns the id. */ public int getId() { return id; } /** * @param id The id to set. */ public void setId(int id) { this.id = id; } /** * @return Returns the mappings. */ public List getBalancerMappings() { return mappings; } /** * @param mappings The mappings to set. */ public void setBalancerMappings(List mappings) { this.mappings = mappings; } public void addBalancerMapping(JkBalancerMapping mapping) { mappings.add(mapping); } public void removeBalancerMapping(JkBalancerMapping mapping) { mappings.remove(mapping); } /** * @return Returns the members. */ public List getBalancerMembers() { return members; } /** * @param members The members to set. */ public void setBalancerMembers(List members) { this.members = members; } public void addBalancerMember(JkBalancerMember member) { members.add(member); } public void removeBalancerMember(JkBalancerMember member) { members.remove(member); } /** * @return Returns the name. */ public String getName() { return name; } /** * @param name The name to set. */ public void setName(String name) { this.name = name; } /** * @return Returns the recover. */ public int getRecover_time() { return recover; } /** * @param recover The recover to set. */ public void setRecover_time(int recover) { this.recover = recover; } /** * @return Returns the retries. */ public int getRetries() { return retries; } /** * @param retries The retries to set. */ public void setRetries(int retries) { this.retries = retries; } /** * @return Returns the sticky. */ public boolean isSticky_session() { return sticky; } /** * @param sticky The sticky to set. */ public void setSticky_session(boolean sticky) { this.sticky = sticky; } /** * @return Returns the stickyforce. */ public boolean isSticky_session_force() { return stickyforce; } /** * @param stickyforce The stickyforce to set. */ public void setSticky_session_force(boolean stickyforce) { this.stickyforce = stickyforce; } /** * @return Returns the type. */ public String getType() { return type; } /** * @param type The type to set. */ public void setType(String type) { this.type = type; } /** * @return the bad * @since mod_jk 1.2.20 */ public int getBad() { return bad; } /** * @param bad the bad to set * @since mod_jk 1.2.20 */ public void setBad(int bad) { this.bad = bad; } /** * @return the busy * @since mod_jk 1.2.20 */ public int getBusy() { return busy; } /** * @param busy the busy to set * @since mod_jk 1.2.20 */ public void setBusy(int busy) { this.busy = busy; } /** * @return the degraded * @since mod_jk 1.2.20 */ public int getDegraded() { return degraded; } /** * @param degraded the degraded to set * @since mod_jk 1.2.20 */ public void setDegraded(int degraded) { this.degraded = degraded; } /** * @return the good * @since mod_jk 1.2.20 */ public int getGood() { return good; } /** * @param good the good to set * @since mod_jk 1.2.20 */ public void setGood(int good) { this.good = good; } /** * @return the lock * @since mod_jk 1.2.20 */ public String getLock() { return lock; } /** * @param lock the lock to set * @since mod_jk 1.2.20 */ public void setLock(String lock) { this.lock = lock; } /** * @return the max_busy * @since mod_jk 1.2.20 */ public int getMax_busy() { return max_busy; } /** * @param max_busy the max_busy to set * @since mod_jk 1.2.20 */ public void setMax_busy(int max_busy) { this.max_busy = max_busy; } /** * @return the method * @since mod_jk 1.2.20 */ public String getMethod() { return method; } /** * @param method the method to set * @since mod_jk 1.2.20 */ public void setMethod(String method) { this.method = method; } /** * @return the member_count * @since mod_jk 1.2.20 */ public int getMember_count() { return member_count; } /** * @param member_count the member_count to set * @since mod_jk 1.2.20 */ public void setMember_count(int member_count) { this.member_count = member_count; } /** * @return the map_count * @since mod_jk 1.2.20 */ public int getMap_count() { return map_count; } /** * @param map_count the map_count to set * @since mod_jk 1.2.20 */ public void setMap_count(int map_count) { this.map_count = map_count; } /** * @return the time_to_maintenance_min * @since mod_jk 1.2.21 */ public int getTime_to_maintenance_min() { return time_to_maintenance_min; } /** * @param time_to_maintenance_min the time_to_maintenance_min to set * @since mod_jk 1.2.21 */ public void setTime_to_maintenance_min(int time_to_maintenance_min) { this.time_to_maintenance_min = time_to_maintenance_min; } /** * @return the time_to_maintenance_max * @since mod_jk 1.2.21 */ public int getTime_to_maintenance_max() { return time_to_maintenance_max; } /** * @param time_to_maintenance_max the time_to_maintenance_max to set * @since mod_jk 1.2.21 */ public void setTime_to_maintenance_max(int time_to_maintenance_max) { this.time_to_maintenance_max = time_to_maintenance_max; } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/package.html0000644000000000000020000001313214655113617026305 0ustar rootbin

This package contains a set of Task implementations for Ant (version 1.6.x or later) that can be used to interact with the Apaache mod_jk status page to show, update, disable and stop mod_jk worker. For more information, see JK Documenation.

The attributes of each task element correspond exactly to the request parameters that are included with an HTTP request sent directly to jk status page. They are summarized as follows:

General parameter
Attribute Description
url The URL of the jk status page you will use to perform the requested operations. If not specified, defaults to http://localhost:80/jkstatus (which corresponds to a standard installation of Apache mod_jk).
username The username of a mod_jk status user that has been configured with the Allow user Apache Location constraint. This attribute is optional.
password The password of a mod_jk status user that has been configured with the Allow user Apache Location constraint. This attribute is optional.
resultProperty Bind all show results with this prefix property name. This attribute is optional.
echo show result at ant console. (default false)
errorProperty set this property, as a failure detected. This attribute is optional.
Command show parameter
Attribute Description
worker only bind properties from this balancer tcp worker (node)
loadbalancer only bind properties from this loadbalancer worker
Command reset parameter
Attribute Description
workerLb name of loadbalancer worker.
Command update loadbalancer parameter
Attribute Description
workerType=loadbalancer type of update
workerLb name of loadbalancer worker.
lbForceSession Force Sticky Session. (true/false)
lbStickySession Sticky Session. (true/false)
lbRetries loadbalancer retries after worker connection failure (int)
lbRecovertime Recover timeout after a worker set to "error" state (int sec's)
Command update worker parameter
Attribute Description
workerType=worker type of update
worker name of tcp worker.
workerActivation (>=1.2.19 set worker activation (1 Active, 2 Disabled, 3 Stopped)
workerDisabled (< 1.2.19) set disable state. (true/false)
workerStoppend (< 1.2.19) set stopped state. (true/false)
workerJvmRoute set jvm route
workerLaodFactor set load factor (int)
workerDistance set worker distance (int)
workerRedirect other worker name to redirect after failure
workerClusterDomain cluster domain name, group of worker at a repliation cluster.
tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/LocalStrings.properties0000644000000000000020000000141614655113617030550 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/mbeans-descriptors.xml0000644000000000000020000000330614655113617030354 0ustar rootbin tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkServer.java0000644000000000000020000000274314655113617026430 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.Serializable; /** * @author Peter Rossbach * @see org.apache.jk.status.JkStatusParser */ public class JkServer implements Serializable { String name ; String port; /** * @return Returns the name. */ public String getName() { return name; } /** * @param name The name to set. */ public void setName(String name) { this.name = name; } /** * @return Returns the port. */ public String getPort() { return port; } /** * @param port The port to set. */ public void setPort(String port) { this.port = port; } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkBalancerMapping.java0000644000000000000020000000436014655113617030202 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.Serializable; /** * @author Peter Rossbach * @see org.apache.jk.status.JkStatusParser */ public class JkBalancerMapping implements Serializable { int id =-1 ; String type ; String uri; String context ; String source ; /** * @return the id */ public int getId() { return id; } /** * @param id the id to set */ public void setId(int id) { this.id = id; } /** * @return Returns the context. * @deprecated mod_jk 1.2.20 */ public String getContext() { return context; } /** * @param context The context to set. * @deprecated mod_jk 1.2.20 */ public void setContext(String context) { this.context = context; } /** * @return Returns the type. */ public String getType() { return type; } /** * @param type The type to set. */ public void setType(String type) { this.type = type; } /** * @return Returns the uri. */ public String getUri() { return uri; } /** * @param uri The uri to set. */ public void setUri(String uri) { this.uri = uri; } /** * @return the source * @since mod_jk 1.2.20 */ public String getSource() { return source; } /** * @param source the source to set * @since mod_jk 1.2.20 */ public void setSource(String source) { this.source = source; } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkStatusUpdateWorkerTask.java0000644000000000000020000001467214655113617031631 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /status update worker command, supported by the * mod_jk status (1.2.20) application. * * @author Peter Rossbach * @since mod_jk 1.2.20 */ public class JkStatusUpdateWorkerTask extends AbstractJkStatusTask { /** * The descriptive information about this implementation. */ private static final String info = "org.apache.jk.status.JkStatusUpdateWorkerTask/1.0"; protected String loadbalancer ; protected String worker ; protected int loadfactor =-1; protected String route ; protected int distance = -1; protected String redirect; protected String domain; protected int activationCode = -1; protected String activation ; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } /** * */ public JkStatusUpdateWorkerTask() { super(); setUrl("http://localhost/jkstatus"); } /** * @return the activation */ public String getActivation() { return activation; } /** * @param activation the activation to set */ public void setActivation(String activation) { this.activation = activation; } /** * @return the activationCode */ public int getActivationCode() { return activationCode; } /** * @param activationCode the activationCode to set */ public void setActivationCode(int activationCode) { this.activationCode = activationCode; } /** * @return the distance */ public int getDistance() { return distance; } /** * @param distance the distance to set */ public void setDistance(int distance) { this.distance = distance; } /** * @return the domain */ public String getDomain() { return domain; } /** * @param domain the domain to set */ public void setDomain(String domain) { this.domain = domain; } /** * @return the loadbalancer */ public String getLoadbalancer() { return loadbalancer; } /** * @param loadbalancer the loadbalaner to set */ public void setLoadbalancer(String loadbalancer) { this.loadbalancer = loadbalancer; } /** * @return the loadfactor */ public int getLoadfactor() { return loadfactor; } /** * @param loadfactor the loadfactor to set */ public void setLoadfactor(int loadfactor) { this.loadfactor = loadfactor; } /** * @return the redirect */ public String getRedirect() { return redirect; } /** * @param redirect the redirect to set */ public void setRedirect(String redirect) { this.redirect = redirect; } /** * @return the route */ public String getRoute() { return route; } /** * @param route the route to set */ public void setRoute(String route) { this.route = route; } /** * @return the worker */ public String getWorker() { return worker; } /** * @param worker the worker to set */ public void setWorker(String worker) { this.worker = worker; } /** * Create JkStatus worker update link *
    * http://localhost/jkstatus?cmd=update&mime=txt&w=loadbalancer&sw=node01&wn=node01&l=lb&wf=1&wa=1&wd=0 *
    * * *
    Tcp worker parameter: *
    *
      *
    • w: name loadbalancer
    • *
    • sw: name tcp worker node
    • *
    • wf: load factor
    • *
    • wn: route
    • *
    • wd: distance
    • *
    • wa: activation state
    • *
    • wr: redirect route
    • *
    • wc: cluster domain
    • *
    *
      *
    • wa=1 active
    • *
    • wa=2 disabled
    • *
    • wa=3 stopped
    • *
    * *
* * @return create jkstatus update worker link */ protected StringBuffer createLink() { // Building URL StringBuffer sb = new StringBuffer(); try { sb.append("?cmd=update&mime=txt"); sb.append("&w="); sb.append(URLEncoder.encode(loadbalancer, getCharset())); sb.append("&sw="); sb.append(URLEncoder.encode(worker, getCharset())); if (loadfactor >= 0) { sb.append("&vwf="); sb.append(loadfactor); } if (route != null) { sb.append("&vwn="); sb.append(URLEncoder.encode(route, getCharset())); } if (activation == null && activationCode > 0 && activationCode < 4) { sb.append("&vwa="); sb.append(activation); } if (activation != null) { sb.append("&vwa="); sb.append(URLEncoder.encode(activation, getCharset())); } if (distance >= 0) { sb.append("&vwd="); sb.append(distance); } if (redirect != null) { // other worker conrecte lb's sb.append("&vwr="); sb.append(URLEncoder.encode(redirect, getCharset())); } if (domain != null) { sb.append("&vwc="); sb.append(URLEncoder.encode(domain, getCharset())); } } catch (UnsupportedEncodingException e) { throw new BuildException("Invalid 'charset' attribute: " + getCharset()); } return sb; } /** * check correct lb and worker pararmeter */ protected void checkParameter() { if (worker == null) { throw new BuildException("Must specify 'worker' attribute"); } if (loadbalancer == null) { throw new BuildException("Must specify 'loadbalancer' attribute"); } } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkStatusParser.java0000644000000000000020000001775514655113617027633 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.tomcat.util.digester.Digester; /** * mod_jk 1.2.19 document:
* * * <?xml version="1.0" encoding="UTF-8" ?> * <jk:status xmlns:jk="http://tomcat.apache.org"> * <jk:server name="localhost" port="2010" software="Apache/2.0.58 (Unix) mod_jk/1.2.19-dev" version="1.2.19" /> * <jk:balancers> * <jk:balancer id="0" name="loadbalancer" type="lb" sticky="True" stickyforce="False" retries="2" recover="60" > * <jk:member id="0" name="node01" type="ajp13" host="localhost" port="20012" address="127.0.0.1:20012" activation="ACT" state="N/A" distance="0" lbfactor="1" lbmult="1" lbvalue="0" elected="0" errors="0" transferred="0" readed="0" busy="0" maxbusy="0" jvm_route="node01" /> * <jk:member id="1" name="node02" type="ajp13" host="localhost" port="20022" address="127.0.0.1:20022" activation="ACT" state="N/A" distance="0" lbfactor="1" lbmult="1" lbvalue="0" elected="0" errors="0" transferred="0" readed="0" busy="0" maxbusy="0" jvm_route="node02" /> * <jk:map type="Wildchar" uri="/ClusterSession*" context="/ClusterSession*" /> * <jk:map type="Wildchar" uri="/ClusterTest*" context="/ClusterTest*" /> * <jk:map type="Wildchar" uri="/test*" context="/test*" /> * </jk:balancer> * </jk:balancers> * </jk:status> * *
* mod_jk 1.2.20 document:
* * <?xml version="1.0" encoding="UTF-8" ?> * <jk:status xmlns:jk="http://tomcat.apache.org"> * <jk:server * name="127.0.0.1" * port="2080" * software="Apache/2.0.59 (Unix) mod_jk/1.2.20-dev" * version="1.2.20"/> * <jk:balancers> * <jk:balancer * name="loadbalancer" * type="lb" * sticky="True" * stickyforce="False" * retries="2" * recover="60" * method="Request" * lock="Optimistic" * good="2" * degraded="0" * bad="0" * busy="0" * max_busy="0"> * <jk:member * name="node01" * type="ajp13" * host="localhost" * port="7309" * address="127.0.0.1:7309" * activation="ACT" * lbfactor="1" * jvm_route="node01" * redirect="" * domain="" * distance="0" * state="N/A" * lbmult="1" * lbvalue="0" * elected="0" * errors="0" * clienterrors="0" * transferred="0" * readed="0" * busy="0" * maxbusy="0" * time-to-recover="0"/> * <jk:member * name="node02" * type="ajp13" * host="localhost" * port="7409" * address="127.0.0.1:7409" * activation="ACT" * lbfactor="1" * jvm_route="node02" * redirect="" * domain="" * distance="0" * state="N/A" * lbmult="1" * lbvalue="0" * elected="0" * errors="0" * clienterrors="0" * transferred="0" * readed="0" * busy="0" * maxbusy="0" * time-to-recover="0"/> * <jk:map * type="Wildchar" * uri="/ClusterTest*" * source="JkMount"/> * <jk:map * type="Wildchar" * uri="/myapps*" * source="JkMount"/> * <jk:map * type="Wildchar" * uri="/last*" * source="JkMount"/> * </jk:balancer> * </jk:balancers> * </jk:status> * * * *
* mod_jk 1.2.24 runtime state N/A changed to OK/IDLE:
* * state="OK/IDLE" * * @author Peter Rossbach * @since 5.5.10 */ public class JkStatusParser { private static Log log = LogFactory.getLog(JkStatusParser.class); /** * The descriptive information about this implementation. */ private static final String info = "org.apache.jk.status.JkStatusParser/1.1"; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } /** * The Digester instance used to parse registry descriptors. */ public static final Digester digester = createDigester(); public static Digester getDigester() { return digester; } /** * Create and configure the Digester we will be using for setup mod_jk jk status page. */ public static Digester createDigester() { long t1 = System.currentTimeMillis(); // Initialize the digester Digester digester = new Digester(); digester.setValidating(false); digester.setClassLoader(JkStatus.class.getClassLoader()); // parse status digester.addObjectCreate("jk:status", "org.apache.jk.status.JkStatus", "className"); digester.addSetProperties("jk:status"); digester.addObjectCreate("jk:status/jk:server", "org.apache.jk.status.JkServer", "className"); digester.addSetProperties("jk:status/jk:server"); digester.addSetNext("jk:status/jk:server", "setServer", "org.apache.jk.status.JkServer"); digester.addObjectCreate("jk:status/jk:software", "org.apache.jk.status.JkSoftware", "className"); digester.addSetProperties("jk:status/jk:software"); digester.addSetNext("jk:status/jk:software", "setSoftware", "org.apache.jk.status.JkSoftware"); digester.addObjectCreate("jk:status/jk:result", "org.apache.jk.status.JkResult", "className"); digester.addSetProperties("jk:status/jk:result"); digester.addSetNext("jk:status/jk:result", "setResult", "org.apache.jk.status.JkResult"); digester.addObjectCreate("jk:status/jk:balancers/jk:balancer", "org.apache.jk.status.JkBalancer", "className"); digester.addSetProperties("jk:status/jk:balancers/jk:balancer"); digester.addSetNext("jk:status/jk:balancers/jk:balancer", "addBalancer", "org.apache.jk.status.JkBalancer"); digester.addObjectCreate( "jk:status/jk:balancers/jk:balancer/jk:member", "org.apache.jk.status.JkBalancerMember", "className"); digester .addSetProperties("jk:status/jk:balancers/jk:balancer/jk:member"); digester.addSetNext("jk:status/jk:balancers/jk:balancer/jk:member", "addBalancerMember", "org.apache.jk.status.JkBalancerMember"); digester.addObjectCreate("jk:status/jk:balancers/jk:balancer/jk:map", "org.apache.jk.status.JkBalancerMapping", "className"); digester.addSetProperties("jk:status/jk:balancers/jk:balancer/jk:map"); digester.addSetNext("jk:status/jk:balancers/jk:balancer/jk:map", "addBalancerMapping", "org.apache.jk.status.JkBalancerMapping"); long t2 = System.currentTimeMillis(); if (log.isDebugEnabled()) log.debug("Digester for apache mod_jk jkstatus page is created " + (t2 - t1)); return (digester); } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootroottomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkStatusUpdateLoadbalancerTask.javatomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkStatusUpdateLoadbalancerTask.0000644000000000000020000001575314655113617032066 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import org.apache.tools.ant.BuildException; /** * Ant task that implements the /status update loadbalancer command, supported by the * mod_jk status (1.2.20) application. * * * @author Peter Rossbach * @since mod_jk 1.2.20 */ public class JkStatusUpdateLoadbalancerTask extends AbstractJkStatusTask { /** * The descriptive information about this implementation. */ private static final String info = "org.apache.jk.status.JkStatusUpdateLoadbalancerTask/1.0"; protected String loadbalancer ; protected int retries = -1; protected int recoverWaitTime = -1; protected int methodCode = -1; protected String method; protected Boolean stickySession ; protected Boolean forceStickySession ; protected int lockCode = -1; protected String lock; protected int maxReplyTimeouts = -1; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } /** * */ public JkStatusUpdateLoadbalancerTask() { super(); setUrl("http://localhost/jkstatus"); } /** * @return the forceStickySession */ public Boolean getForceStickySession() { return forceStickySession; } /** * @param forceStickySession the forceStickySession to set */ public void setForceStickySession(Boolean forceStickySession) { this.forceStickySession = forceStickySession; } /** * @return the loadbalancer */ public String getLoadbalancer() { return loadbalancer; } /** * @param loadbalancer the loadbalancer to set */ public void setLoadbalancer(String loadbalancer) { this.loadbalancer = loadbalancer; } /** * @return the locking */ public String getLock() { return lock; } /** * @param locking the locking to set */ public void setLock(String locking) { this.lock = locking; } /** * @return the lockingCode */ public int getLockCode() { return lockCode; } /** * @param lockingCode the lockingCode to set */ public void setLockCode(int lockingCode) { this.lockCode = lockingCode; } /** * @return the method */ public String getMethod() { return method; } /** * @param method the method to set */ public void setMethod(String method) { this.method = method; } /** * @return the methodCode */ public int getMethodCode() { return methodCode; } /** * @param methodCode the methodCode to set */ public void setMethodCode(int methodCode) { this.methodCode = methodCode; } /** * @return the recoverWaitTime */ public int getRecoverWaitTime() { return recoverWaitTime; } /** * @param recoverWaitTime the recoverWaitTime to set */ public void setRecoverWaitTime(int recoverWaitTime) { this.recoverWaitTime = recoverWaitTime; } /** * @return the retries */ public int getRetries() { return retries; } /** * @param retries the retries to set */ public void setRetries(int retries) { this.retries = retries; } /** * @return the stickySession */ public Boolean getStickySession() { return stickySession; } /** * @param stickySession the stickySession to set */ public void setStickySession(Boolean stickySession) { this.stickySession = stickySession; } /** * @return the maxReplyTimeouts */ public int getMaxReplyTimeouts() { return maxReplyTimeouts; } /** * @param maxReplyTimeouts the maxReplyTimeouts to set */ public void setMaxReplyTimeouts(int maxReplyTimeouts) { this.maxReplyTimeouts = maxReplyTimeouts; } /** * Create JkStatus worker update link *
    * http://localhost/jkstatus?cmd=update&mime=txt&w=loadbalancer&vlm=1&vll=1&vlr=2&vlt=60&vls=true&vlf=false&vlx=0 *
    * * *
    Tcp worker parameter: *
    *
      *
    • w: name loadbalancer
    • *
    • vlm: method (lb strategy)
    • *
    • vll: lock
    • *
    • vlr: retries
    • *
    • vlt: recover wait timeout
    • *
    • vls: sticky session
    • *
    • vlf: force sticky session
    • *
    • vlx: max reply timeouts
    • *
    *
      *
    • vlm=0 or Requests
    • *
    • vlm=1 or Traffic
    • *
    • vlm=2 or Busyness
    • *
    • vlm=3 or Sessions
    • *
    *
      *
    • vll=0 or Optimistic
    • *
    • vll=1 or Pessimistic
    • *
    * * @return create jkstatus update worker link */ protected StringBuffer createLink() { // Building URL StringBuffer sb = new StringBuffer(); try { sb.append("?cmd=update&mime=txt"); sb.append("&w="); sb.append(URLEncoder.encode(loadbalancer, getCharset())); if (stickySession != null) { sb.append("&vls="); sb.append(stickySession); } if (forceStickySession != null) { sb.append("&vlf="); sb.append(forceStickySession); } if (retries >= 0) { sb.append("&vlr="); sb.append(retries); } if (recoverWaitTime >= 0) { sb.append("&vlt="); sb.append(recoverWaitTime); } if (method == null && methodCode >= 0 && methodCode < 4) { sb.append("&vlm="); sb.append(methodCode); } if (method != null) { sb.append("&vlm="); sb.append(method); } if (lock == null && lockCode >= 0 && lockCode < 2) { sb.append("&vll="); sb.append(lockCode); } if (lock != null) { sb.append("&vll="); sb.append(lock); } if (maxReplyTimeouts >= 0) { sb.append("&vlx="); sb.append(maxReplyTimeouts); } } catch (UnsupportedEncodingException e) { throw new BuildException("Invalid 'charset' attribute: " + getCharset()); } return sb; } /** * check correct lb and worker pararmeter */ protected void checkParameter() { if (loadbalancer == null) { throw new BuildException("Must specify 'loadbalancer' attribute"); } } } tomcat-connectors-1.2.50-src/jkstatus/src/share/org/apache/jk/status/JkStatusTask.java0000644000000000000020000007130114655113617027264 0ustar rootbin/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.util.Iterator; import java.util.List; import org.apache.catalina.ant.BaseRedirectorHelperTask; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; /** * Ant task that implements the show /jkstatus command, supported * by the mod_jk status (1.2.13) application. * * @author Peter Rossbach * @since 5.5.10 */ public class JkStatusTask extends BaseRedirectorHelperTask { /** * The descriptive information about this implementation. */ private static final String info = "org.apache.jk.status.JkStatusTask/1.2"; /** * Store status as resultProperty prefix. */ protected String resultproperty; /** * Echo status at ant console */ protected boolean echo = false; /** * The login password for the mod_jk status page. */ protected String password = null; /** * The URL of the mod_jk status page to be used. */ protected String url = "http://localhost:80/jkstatus"; /** * The login username for the mod_jk status page. */ protected String username = null; private String errorProperty; private String worker; private String loadbalancer; /** * Return descriptive information about this implementation and the * corresponding version number, in the format * <description>/<version>. */ public String getInfo() { return (info); } public String getPassword() { return (this.password); } public void setPassword(String password) { this.password = password; } public String getUrl() { return (this.url); } public void setUrl(String url) { this.url = url; } public String getUsername() { return (this.username); } public void setUsername(String username) { this.username = username; } /** * @return Returns the echo. */ public boolean isEcho() { return echo; } /** * @param echo * The echo to set. */ public void setEcho(boolean echo) { this.echo = echo; } /** * @return Returns the resultproperty. */ public String getResultproperty() { return resultproperty; } /** * @param resultproperty * The resultproperty to set. */ public void setResultproperty(String resultproperty) { this.resultproperty = resultproperty; } /** * @return Returns the loadbalancer. */ public String getLoadbalancer() { return loadbalancer; } /** * @param loadbalancer The loadbalancer to set. */ public void setLoadbalancer(String loadbalancer) { this.loadbalancer = loadbalancer; } /** * @return Returns the worker. */ public String getWorker() { return worker; } /** * @param worker The worker to set. */ public void setWorker(String worker) { this.worker = worker; } // --------------------------------------------------------- Public Methods /** * Get jkstatus from server. * * @exception BuildException * if a validation error occurs */ public void execute() throws BuildException { if (url == null) { throw new BuildException("Must specify an 'url'"); } boolean isWorkerOnly = worker != null && !"".equals(worker); boolean isLoadbalancerOnly = loadbalancer != null && !"".equals(loadbalancer); StringBuffer error = new StringBuffer(); try { JkStatusAccessor accessor = new JkStatusAccessor(); JkStatus status = accessor.status(url, username, password); if (status.result != null && !"OK".equals(status.result.type) ) { if (getErrorProperty() != null) { getProject().setNewProperty(errorProperty, status.result.message); } if (isFailOnError()) { throw new BuildException(status.result.message); } else { handleErrorOutput(status.result.message); return; } } if (!isWorkerOnly && !isLoadbalancerOnly) { JkServer server = status.getServer(); JkSoftware software = status.getSoftware(); JkResult result = status.getResult(); if (resultproperty != null) { createProperty(server, "server", "name"); createProperty(server, "server", "port"); createProperty(software, "web_server"); createProperty(software, "jk_version"); createProperty(result, "result", "type"); createProperty(result, "result", "message"); } if (isEcho()) { handleOutput("server name=" + server.getName() + ":" + server.getPort() + " - " + software.getWeb_server() + " - " + software.getJk_version()); } } List balancers = status.getBalancers(); for (Iterator iter = balancers.iterator(); iter.hasNext();) { JkBalancer balancer = (JkBalancer) iter.next(); String balancerIndex = null; if (isLoadbalancerOnly) { if (loadbalancer.equals(balancer.getName())) { if (resultproperty != null) { setPropertyBalancerOnly(balancer); } echoBalancer(balancer); return; } } else { if (!isWorkerOnly) { if (resultproperty != null) { if ( balancer.getId() >= 0) balancerIndex = Integer.toString(balancer.getId()); else balancerIndex = balancer.getName() ; setPropertyBalancer(balancer,balancerIndex); } echoBalancer(balancer); } List members = balancer.getBalancerMembers(); for (Iterator iterator = members.iterator(); iterator .hasNext();) { JkBalancerMember member = (JkBalancerMember) iterator .next(); if (isWorkerOnly) { if (worker.equals(member.getName())) { if (resultproperty != null) { setPropertyWorkerOnly(balancer, member); } echoWorker(member); return; } } else { if (resultproperty != null) { setPropertyWorker(null, member); } echoWorker(member); if (member.getStatus() != null && !"OK".equals(member.getStatus())) { error.append(" worker name=" + member.getName() + " status=" + member.getStatus() + " host=" + member.getAddress()); } if (member.getState() != null && !("OK".equals(member.getState()) || "N/A".equals(member.getState()) || "OK/IDLE".equals(member.getState())) ){ error.append(" worker name=" + member.getName() + " state=" + member.getState() + " host=" + member.getAddress()); } } } if (!isWorkerOnly) { if (resultproperty != null && members.size() > 0) { getProject().setNewProperty( resultproperty + "." + balancer.getName() + ".length", Integer.toString(members.size())); } List mappings = balancer.getBalancerMappings(); int j = 0; String mapIndex ; if( balancerIndex != null ) mapIndex = balancerIndex + ".map" ; else mapIndex = "map" ; for (Iterator iterator = mappings.iterator(); iterator .hasNext(); j++) { JkBalancerMapping mapping = (JkBalancerMapping) iterator .next(); if (resultproperty != null) { String stringIndex2 ; if( mapping.getId() >= 0) { stringIndex2 = Integer.toString(mapping.getId()) ; } else { stringIndex2 = Integer.toString(j); } createProperty(mapping, mapIndex, stringIndex2, "type"); createProperty(mapping, mapIndex, stringIndex2, "uri"); createProperty(mapping, mapIndex, stringIndex2, "context"); createProperty(mapping, mapIndex, stringIndex2, "source"); } if (isEcho()) { String mappingOut ; if(mapping.source != null) { mappingOut = "balancer name=" + balancer.getName() + " mappingtype=" + mapping.getType() + " uri=" + mapping.getUri() + " source=" + mapping.getSource() ; } else { mappingOut = "balancer name=" + balancer.getName() + " mappingtype=" + mapping.getType() + " uri=" + mapping.getUri() + " context=" + mapping.getContext() ; } handleOutput(mappingOut); } } if (resultproperty != null && mappings.size() > 0) { getProject().setNewProperty( resultproperty + "." + mapIndex + ".length", Integer.toString(mappings.size())); } } } } if (!isWorkerOnly && !isLoadbalancerOnly) { if (resultproperty != null && balancers.size() > 0) { getProject().setNewProperty( resultproperty + ".length", Integer.toString(balancers.size())); } } } catch (Throwable t) { error.append(t.getMessage()); if (getErrorProperty() != null) { getProject().setNewProperty(errorProperty, error.toString()); } if (isFailOnError()) { throw new BuildException(t); } else { handleErrorOutput(t.getMessage()); return; } } if (error.length() != 0) { if (getErrorProperty() != null) { getProject().setNewProperty(errorProperty, error.toString()); } if (isFailOnError()) { // exception should be thrown only if failOnError == true // or error line will be logged twice throw new BuildException(error.toString()); } } } /** * @param member */ private void echoWorker(JkBalancerMember member) { if (isEcho()) { StringBuffer state = new StringBuffer("worker name=") ; state.append( member.getName()) ; if(member.getStatus() != null) { state.append(" status="); state.append(member.getStatus()); } if(member.getState() != null) { state.append(" state="); state.append(member.getState()) ; } state.append(" host="); state.append(member.getAddress()); handleOutput(state.toString()); } } /** * @param balancer */ private void echoBalancer(JkBalancer balancer) { if (isEcho()) { handleOutput("balancer name=" + balancer.getName() + " type=" + balancer.getType()); } } /** * @param balancer */ private void setPropertyBalancerOnly(JkBalancer balancer) { String prefix = resultproperty + "." + balancer.getName(); if(balancer.getId() >= 0 ) { getProject().setNewProperty(prefix + ".id", Integer.toString(balancer.getId())); } getProject().setNewProperty(prefix + ".type", balancer.getType()); getProject().setNewProperty(prefix + ".stick_session", Boolean.toString(balancer.isSticky_session())); getProject().setNewProperty(prefix + ".sticky_session_force", Boolean.toString(balancer.isSticky_session_force())); getProject().setNewProperty(prefix + ".retries", Integer.toString(balancer.getRetries())); getProject().setNewProperty(prefix + ".recover_time", Integer.toString(balancer.getRecover_time())); getProject().setNewProperty(prefix + ".method", balancer.getMethod()); getProject().setNewProperty(prefix + ".good", Integer.toString(balancer.getGood())); getProject().setNewProperty(prefix + ".degraded", Integer.toString(balancer.getDegraded())); getProject().setNewProperty(prefix + ".bad", Integer.toString(balancer.getBad())); getProject().setNewProperty(prefix + ".busy", Integer.toString(balancer.getBusy())); getProject().setNewProperty(prefix + ".map_count", Integer.toString(balancer.getMap_count())); getProject().setNewProperty(prefix + ".member_count", Integer.toString(balancer.getMember_count())); getProject().setNewProperty(prefix + ".max_busy", Integer.toString(balancer.getMax_busy())); getProject().setNewProperty(prefix + ".time_to_maintenance_min", Integer.toString(balancer.getTime_to_maintenance_min())); getProject().setNewProperty(prefix + ".time_to_maintenance_max", Integer.toString(balancer.getTime_to_maintenance_max())); getProject().setNewProperty(prefix + ".lock", balancer.getLock()); } /** * @param balancer * @param balancerIndex */ private void setPropertyBalancer(JkBalancer balancer,String balancerIndex) { if(balancer.id >= 0) { createProperty(balancer, balancerIndex, "id"); } createProperty(balancer, balancerIndex, "name"); createProperty(balancer, balancerIndex, "type"); createProperty(balancer, balancerIndex, "sticky_session"); createProperty(balancer, balancerIndex, "sticky_session_force"); createProperty(balancer, balancerIndex, "retries"); createProperty(balancer, balancerIndex, "recover_time"); if(balancer.getMethod() != null) { createProperty(balancer, balancerIndex, "method"); } if(balancer.getLock() != null) { createProperty(balancer, balancerIndex, "lock"); } if(balancer.getGood() >= 0) { createProperty(balancer, balancerIndex, "good"); } if(balancer.getDegraded() >= 0) { createProperty(balancer, balancerIndex, "degraded"); } if(balancer.getBad() >= 0) { createProperty(balancer, balancerIndex, "bad"); } if(balancer.getBusy() >= 0) { createProperty(balancer, balancerIndex, "busy"); } if(balancer.getMax_busy() >= 0) { createProperty(balancer, balancerIndex, "max_busy"); } if(balancer.getMember_count() >=0) { createProperty(balancer, balancerIndex, "member_count"); } if(balancer.getMap_count() >=0) { createProperty(balancer, balancerIndex, "map_count"); } if(balancer.getTime_to_maintenance_min() >=0) { createProperty(balancer, balancerIndex, "time_to_maintenance_min"); } if(balancer.getTime_to_maintenance_max() >=0) { createProperty(balancer, balancerIndex, "time_to_maintenance_max"); } } /** * @param balancerIndex * @param member */ private void setPropertyWorker(String balancerIndex, JkBalancerMember member) { String workerIndex ; if(member.getId() >= 0) { workerIndex = Integer.toString(member.getId()); createProperty(member, balancerIndex, workerIndex, "id"); createProperty(member, balancerIndex, workerIndex, "name"); } else { workerIndex = member.getName(); } createProperty(member, balancerIndex, workerIndex, "type"); createProperty(member, balancerIndex, workerIndex, "host"); createProperty(member, balancerIndex, workerIndex, "port"); createProperty(member, balancerIndex, workerIndex, "address"); if(member.getJvm_route() != null) { createProperty(member, balancerIndex, workerIndex, "jvm_route"); } if(member.getRoute() != null) { createProperty(member, balancerIndex, workerIndex, "route"); } if(member.getStatus() != null) { createProperty(member, balancerIndex, workerIndex, "status"); } if(member.getActivation() != null) { createProperty(member, balancerIndex, workerIndex, "activation"); } if(member.getState() != null) { createProperty(member, balancerIndex, workerIndex, "state"); } createProperty(member, balancerIndex, workerIndex, "lbfactor"); createProperty(member, balancerIndex, workerIndex, "lbvalue"); if(member.getLbmult() >= 0) { createProperty(member, balancerIndex, workerIndex, "lbmult"); } createProperty(member, balancerIndex, workerIndex, "elected"); createProperty(member, balancerIndex, workerIndex, "readed"); createProperty(member, balancerIndex, workerIndex, "busy"); if(member.getMax_busy() >= 0) { createProperty(member, balancerIndex, workerIndex, "max_busy"); } createProperty(member, balancerIndex, workerIndex, "transferred"); createProperty(member, balancerIndex, workerIndex, "errors"); if(member.getClient_errors() >= 0) { createProperty(member, balancerIndex, workerIndex, "client_errors"); } if(member.getDistance() >= 0) { createProperty(member, balancerIndex, workerIndex, "distance"); } if (member.getDomain() != null) { createProperty(member, balancerIndex, workerIndex, "domain"); } else { getProject().setNewProperty(resultproperty + "." + balancerIndex + "." + workerIndex + ".domain", ""); } if (member.getRedirect() != null) { createProperty(member, balancerIndex, workerIndex, "redirect"); } else { getProject().setNewProperty(resultproperty + "." + balancerIndex + "." + workerIndex + ".redirect", ""); } } /** * @param balancer * @param member */ private void setPropertyWorkerOnly(JkBalancer balancer, JkBalancerMember member) { //String prefix = resultproperty + "." + balancer.getName() + "." + member.getName(); String prefix = resultproperty + "." + member.getName(); Project currentProject = getProject(); if ( balancer.getId() >= 0) { currentProject.setNewProperty(prefix + ".lb.id", Integer.toString(balancer.getId())); } //currentProject.setNewProperty(prefix + ".lb.name", balancer.getName()); if( member.getId() >= 0) { currentProject.setNewProperty(prefix + ".id", Integer.toString(member.getId())); } currentProject.setNewProperty(prefix + ".type", member.getType()); if (member.getJvm_route() != null) { currentProject.setNewProperty(prefix + ".jvm_route", member.getJvm_route()); } if (member.getRoute() != null) { currentProject.setNewProperty(prefix + ".route", member.getRoute()); } if (member.getStatus() != null) { currentProject.setNewProperty(prefix + ".status", member.getStatus()); } if (member.getActivation() != null) { currentProject.setNewProperty(prefix + ".activation", member.getActivation()); } if (member.getState() != null) { currentProject.setNewProperty(prefix + ".state", member.getState()); } currentProject.setNewProperty(prefix + ".host", member.getHost()); currentProject.setNewProperty(prefix + ".address", member.getAddress()); currentProject.setNewProperty(prefix + ".port", Integer.toString(member.getPort())); currentProject.setNewProperty(prefix + ".lbfactor", Integer.toString(member.getLbfactor())); currentProject.setNewProperty(prefix + ".lbvalue", Long.toString(member.getLbvalue())); if(member.getLbmult() >= 0) { currentProject.setNewProperty(prefix + ".lbmult", Long.toString(member.getLbmult())); } currentProject.setNewProperty(prefix + ".elected", Long.toString(member.getElected())); currentProject.setNewProperty(prefix + ".readed", Long.toString(member.getReaded())); currentProject.setNewProperty(prefix + ".transferred", Long.toString(member.getTransferred())); currentProject.setNewProperty(prefix + ".busy", Integer.toString(member.getBusy())); if(member.getMax_busy() >= 0) { currentProject.setNewProperty(prefix + ".max_busy", Long.toString(member.getMax_busy())); } currentProject.setNewProperty(prefix + ".errors", Long.toString(member.getErrors())); if(member.getClient_errors() >= 0) { currentProject.setNewProperty(prefix + ".client_errors", Long.toString(member.getClient_errors())); } if(member.getDistance() >= 0) { currentProject.setNewProperty(prefix + ".distance", Integer.toString(member.getDistance())); } if (member.getDomain() != null) { currentProject.setNewProperty(prefix + ".domain", member.getDomain()); } else { currentProject.setNewProperty(prefix + ".domain", ""); } if (member.getRedirect() != null) { currentProject.setNewProperty(prefix + ".redirect", member.getRedirect()); } else { currentProject.setNewProperty(prefix + ".redirect", ""); } if(member.getTime_to_recover() >= 0) { currentProject.setNewProperty(prefix + ".time_to_recover", Integer.toString(member.getTime_to_recover())); } if(member.getTime_to_recover_min() >= 0) { currentProject.setNewProperty(prefix + ".time_to_recover_min", Integer.toString(member.getTime_to_recover_min())); } if(member.getTime_to_recover_max() >= 0) { currentProject.setNewProperty(prefix + ".time_to_recover_max", Integer.toString(member.getTime_to_recover_max())); currentProject.setNewProperty(prefix + ".time_to_recover", (Integer.toString((member.getTime_to_recover_min() + member.getTime_to_recover_max()) / 2))); } } /* * Set ant property for save error state * * @see org.apache.catalina.ant.BaseRedirectorHelperTask#setErrorProperty(java.lang.String) */ public void setErrorProperty(String arg0) { errorProperty = arg0; super.setErrorProperty(arg0); } /** * @return Returns the errorProperty. */ public String getErrorProperty() { return errorProperty; } protected void createProperty(Object result, String attribute) { createProperty(result, null, null, attribute); } protected void createProperty(Object result, String arraymark, String attribute) { createProperty(result, arraymark, null, attribute); } /** * create result as property with name from attribute resultproperty */ protected void createProperty(Object result, String arraymark, String arraymark2, String attribute) { if (resultproperty != null) { Object value = IntrospectionUtils.getProperty(result, attribute); if (value != null ) { StringBuffer propertyname = new StringBuffer(resultproperty); if (result instanceof JkBalancer) { if (arraymark != null) { propertyname.append("."); propertyname.append(arraymark); } } else if (result instanceof JkServer) { if (arraymark != null) { propertyname.append("."); propertyname.append(arraymark); } } else if (result instanceof JkSoftware) { if (arraymark != null) { propertyname.append("."); propertyname.append(arraymark); } } else if (result instanceof JkResult) { if (arraymark != null) { propertyname.append("."); propertyname.append(arraymark); } } else if (result instanceof JkBalancerMember) { if (arraymark != null) { propertyname.append("."); propertyname.append(arraymark); } if (arraymark2 != null) { propertyname.append("."); propertyname.append(arraymark2); } } else if (result instanceof JkBalancerMapping) { if (arraymark != null) { propertyname.append("."); propertyname.append(arraymark); } if (arraymark2 != null) { propertyname.append("."); propertyname.append(arraymark2); } } propertyname.append("."); propertyname.append(attribute); getProject().setNewProperty(propertyname.toString(), value.toString()); } } } } tomcat-connectors-1.2.50-src/jkstatus/conf/0000755000000000000020000000000014655113617017121 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/conf/jkstatus-tasks.xml0000644000000000000020000000331614655113617022641 0ustar rootbin Apache mod_jk ant jkstatus Tasks tomcat-connectors-1.2.50-src/jkstatus/build.properties.default0000644000000000000020000000145314655113617023037 0ustar rootbin# ----------------------------------------------------------------------------- # build.properties.default # # This is an example "build.properties" file, used to customize building Tomcat # for your local environment. It defines the location of all external # modules that Tomcat depends on. Copy this file to "build.properties" # in the top-level source directory, and customize it as needed. # ----------------------------------------------------------------------------- # ----- Compile Control Flags ----- compile.debug=on compile.deprecation=off compile.optimize=off # ----- Path to Tomcat installation ----- catalina.build=/usr/local/share/tomcat-5.5 # ----- Some version dependent jar file names ----- commons-modeler.jar=commons-modeler-2.0.1.jar commons-logging.jar=commons-logging-api-1.1.1.jar tomcat-connectors-1.2.50-src/jkstatus/.gitignore0000644000000000000020000000001314655113617020156 0ustar rootbinbuild dist tomcat-connectors-1.2.50-src/jkstatus/build.xml0000644000000000000020000001405414655113617020021 0ustar rootbin tomcat-connectors-1.2.50-src/jkstatus/example/0000755000000000000020000000000014655113617017627 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/example/jkstatus.properties.default0000644000000000000020000000201014655113617025231 0ustar rootbin# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. jkstatus.host=localhost jkstatus.port=2090 jkstatus.username=manager jkstatus.password=tomcat jkstatus.url=http://${jkstatus.host}:${jkstatus.port}/jkstatus jkstatus.testlb=loadbalancer jkstatus.testworker=node01 catalina.home=../../../../build/buildtomcat-connectors-1.2.50-src/jkstatus/example/jkstatus.xml0000644000000000000020000001042114655113617022217 0ustar rootbin tomcat-connectors-1.2.50-src/jkstatus/example/show.xml0000644000000000000020000000401114655113617021325 0ustar rootbin tomcat-connectors-1.2.50-src/jkstatus/example/show.txt0000644000000000000020000000177614655113617021363 0ustar rootbin Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. How to use the show example: ant -f show.xml Configure mod_jk (httpd.conf and workers.properties): JkMount /jkstatus jkstatus worker.list=jkstatus worker.jkstatus.type=status Adjust jkstatus.properties.default: jkstatus.port (for example). tomcat-connectors-1.2.50-src/jkstatus/test/0000755000000000000020000000000014655113617017153 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/test/src/0000755000000000000020000000000014655113617017742 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/test/src/share/0000755000000000000020000000000014655113617021044 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/test/src/share/org/0000755000000000000020000000000014655113617021633 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/test/src/share/org/apache/0000755000000000000020000000000014655113617023054 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/test/src/share/org/apache/jk/0000755000000000000020000000000014655113617023460 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/test/src/share/org/apache/jk/status/0000755000000000000020000000000014655113617025003 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/test/src/share/org/apache/jk/status/JkStatusParserTest.java0000644000000000000020000000644714655113617031446 0ustar rootbin/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jk.status; import java.io.IOException; import java.io.StringReader; import junit.framework.TestCase; import org.apache.tomcat.util.digester.Digester; import org.xml.sax.SAXException; /** * @author Peter Rossbach * */ public class JkStatusParserTest extends TestCase { public void testDigester() throws IOException, SAXException { Digester digester = JkStatusParser.createDigester(); String example = "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" ; StringReader reader = new StringReader(example); JkStatus status = (JkStatus) digester .parse(reader); assertNotNull(status); assertNotNull(status.getServer()); assertEquals(1,status.getBalancers().size()); JkBalancer balancer = (JkBalancer)status.getBalancers().get(0); assertEquals(2,balancer.getBalancerMembers().size()); assertEquals("node1",((JkBalancerMember)balancer.getBalancerMembers().get(0)).getName()); assertEquals("node2",((JkBalancerMember)balancer.getBalancerMembers().get(1)).getName()); assertEquals(4,balancer.getBalancerMappings().size()); } } tomcat-connectors-1.2.50-src/jkstatus/test/conf/0000755000000000000020000000000014655113617020100 5ustar rootbintomcat-connectors-1.2.50-src/jkstatus/test/conf/jkstatus.xml0000644000000000000020000000350714655113617022477 0ustar rootbin tomcat-connectors-1.2.50-src/jkstatus/test/conf/log4j.xml0000644000000000000020000000476414655113617021654 0ustar rootbin tomcat-connectors-1.2.50-src/jkstatus/test/build.xml0000644000000000000020000001072414655113617021000 0ustar rootbin This ant script implements some testcases to verify the key functions of tomcat apache mod_jk jkstatus module. You find this script at: ${ant.file} tomcat-connectors-1.2.50-src/docs/0000755000000000000020000000000014655113621015247 5ustar rootbintomcat-connectors-1.2.50-src/docs/ajp/0000755000000000000020000000000014655113620016020 5ustar rootbintomcat-connectors-1.2.50-src/docs/ajp/ajpv13a.html0000644000000000000020000006676014655113620020172 0ustar rootbin The Apache Tomcat Connectors - AJP Protocol Reference (1.2.50) - AJPv13

    AJPv13

    Intro

    The original document was written by Dan Milstein, danmil@shore.net on December 2000. The present document is generated out of an xml file to allow a more easy integration in the Tomcat documentation.

    This describes the Apache JServ Protocol version 1.3 (hereafter ajp13). There is, apparently, no current documentation of how the protocol works. This document is an attempt to remedy that, in order to make life easier for maintainers of JK, and for anyone who wants to port the protocol somewhere (into jakarta 4.x, for example).

    author

    I am not one of the designers of this protocol -- I believe that Gal Shachor was the original designer. Everything in this document is derived from the actual implementation I found in the tomcat 3.x code. I hope it is useful, but I can't make any grand claims to perfect accuracy. I also don't know why certain design decisions were made. Where I was able, I've offered some possible justifications for certain choices, but those are only my guesses. In general, the C code which Shachor wrote is very clean and comprehensible (if almost totally undocumented). I've cleaned up the Java code, and I think it's reasonably readable.

    Design Goals

    According to email from Gal Shachor to the jakarta-dev mailing list, the original goals of JK (and thus ajp13) were to extend mod_jserv and ajp12 by (I am only including the goals which relate to communication between the web server and the servlet container):

    • Increasing performance (speed, specifically).
    • Adding support for SSL, so that isSecure() and getScheme() will function correctly within the servlet container. The client certificates and cipher suite will be available to servlets as request attributes.

    Overview of the protocol

    The ajp13 protocol is packet-oriented. A binary format was presumably chosen over the more readable plain text for reasons of performance. The web server communicates with the servlet container over TCP connections. To cut down on the expensive process of socket creation, the web server will attempt to maintain persistent TCP connections to the servlet container, and to reuse a connection for multiple request/response cycles.

    Once a connection is assigned to a particular request, it will not be used for any others until the request-handling cycle has terminated. In other words, requests are not multiplexed over connections. This makes for much simpler code at either end of the connection, although it does cause more connections to be open at once.

    Once the web server has opened a connection to the servlet container, the connection can be in one of the following states:

    • Idle
      No request is being handled over this connection.
    • Assigned
      The connecton is handling a specific request.

    Once a connection is assigned to handle a particular request, the basic request informaton (e.g. HTTP headers, etc) is sent over the connection in a highly condensed form (e.g. common strings are encoded as integers). Details of that format are below in Request Packet Structure. If there is a body to the request (content-length > 0), that is sent in a separate packet immediately after.

    At this point, the servlet container is presumably ready to start processing the request. As it does so, it can send the following messages back to the web server:

    • SEND_HEADERS
      Send a set of headers back to the browser.
    • SEND_BODY_CHUNK
      Send a chunk of body data back to the browser.
    • GET_BODY_CHUNK
      Get further data from the request if it hasn't all been transferred yet. This is necessary because the packets have a fixed maximum size and arbitrary amounts of data can be included the body of a request (for uploaded files, for example). (Note: this is unrelated to HTTP chunked tranfer).
    • END_RESPONSE
      Finish the request-handling cycle.

    Each message is accompanied by a differently formatted packet of data. See Response Packet Structures below for details.

    Basic Packet Structure

    There is a bit of an XDR heritage to this protocol, but it differs in lots of ways (no 4 byte alignment, for example).

    AJP13 uses network byte order for all data types.

    There are four data types in the protocol: bytes, booleans, integers and strings.

    Byte
    A single byte.
    Boolean
    A single byte, 1 = true, 0 = false. Using other non-zero values as true (i.e. C-style) may work in some places, but it won't in others.
    Integer
    A number in the range of 0 to 2^16 (32768). Stored in 2 bytes with the high-order byte first.
    String
    A variable-sized string (length bounded by 2^16). Encoded with the length packed into two bytes first, followed by the string (including the terminating '\0'). Note that the encoded length does not include the trailing '\0' -- it is like strlen. This is a touch confusing on the Java side, which is littered with odd autoincrement statements to skip over these terminators. I believe the reason this was done was to allow the C code to be extra efficient when reading strings which the servlet container is sending back -- with the terminating \0 character, the C code can pass around references into a single buffer, without copying. If the \0 was missing, the C code would have to copy things out in order to get its notion of a string. Note a size of -1 (65535) indicates a null string and no data follow the length in this case.

    Packet Size

    According to much of the code, the max packet size is 8 * 1024 bytes (8K). The actual length of the packet is encoded in the header.

    Packet Headers

    Packets sent from the server to the container begin with 0x1234. Packets sent from the container to the server begin with AB (that's the ASCII code for A followed by the ASCII code for B). After those first two bytes, there is an integer (encoded as above) with the length of the payload. Although this might suggest that the maximum payload could be as large as 2^16, in fact, the code sets the maximum to be 8K.
    Packet Format (Server->Container)
    Byte 0 1 2 3 4...(n+3)
    Contents 0x12 0x34 Data Length (n) Data
    Packet Format (Container->Server)
    Byte 0 1 2 3 4...(n+3)
    Contents A B Data Length (n) Data

    For most packets, the first byte of the payload encodes the type of message. The exception is for request body packets sent from the server to the container -- they are sent with a standard packet header (0x1234 and then length of the packet), but without any prefix code after that (this seems like a mistake to me).

    The web server can send the following messages to the servlet container:
    Code Type of Packet Meaning
    2 Forward Request Begin the request-processing cycle with the following data
    7 Shutdown The web server asks the container to shut itself down.
    8 Ping The web server asks the container to take control (secure login phase).
    10 CPing The web server asks the container to respond quickly with a CPong.
    none Data Size (2 bytes) and corresponding body data.

    To ensure some basic security, the container will only actually do the Shutdown if the request comes from the same machine on which it's hosted.

    The first Data packet is send immediatly after the Forward Request by the web server.

    The servlet container can send the following types of messages to the web server:
    Code Type of Packet Meaning
    3 Send Body Chunk Send a chunk of the body from the servlet container to the web server (and presumably, onto the browser).
    4 Send Headers Send the response headers from the servlet container to the web server (and presumably, onto the browser).
    5 End Response Marks the end of the response (and thus the request-handling cycle).
    6 Get Body Chunk Get further data from the request if it hasn't all been transferred yet.
    9 CPong Reply The reply to a CPing request

    Each of the above messages has a different internal structure, detailed below.

    Request Packet Structure

    For messages from the server to the container of type "Forward Request":

    AJP13_FORWARD_REQUEST :=
        prefix_code      (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
        method           (byte)
        protocol         (string)
        req_uri          (string)
        remote_addr      (string)
        remote_host      (string)
        server_name      (string)
        server_port      (integer)
        is_ssl           (boolean)
        num_headers      (integer)
        request_headers *(req_header_name req_header_value)
        attributes      *(attribut_name attribute_value)
        request_terminator (byte) OxFF
    

    The request_headers have the following structure:

    req_header_name := 
        sc_req_header_name | (string)  [see below for how this is parsed]
    
    sc_req_header_name := 0xA0xx (integer)
    
    req_header_value := (string)
    

    The attributes are optional and have the following structure:

    attribute_name := sc_a_name | (sc_a_req_attribute string)
    
    attribute_value := (string)
    

    Not that the all-important header is "content-length', because it determines whether or not the container looks for another packet immediately.

    Detailed description of the elements of Forward Request.

    request_prefix

    For all requests, this will be 2. See above for details on other prefix codes.

    method

    The HTTP method, encoded as a single byte:

    Command NameCode
    OPTIONS1
    GET2
    HEAD3
    POST4
    PUT5
    DELETE6
    TRACE7
    PROPFIND8
    PROPPATCH9
    MKCOL10
    COPY11
    MOVE12
    LOCK13
    UNLOCK14
    ACL15
    REPORT16
    VERSION-CONTROL17
    CHECKIN18
    CHECKOUT19
    UNCHECKOUT20
    SEARCH21
    MKWORKSPACE22
    UPDATE23
    LABEL24
    MERGE25
    BASELINE_CONTROL26
    MKACTIVITY27

    protocol, req_uri, remote_addr, remote_host, server_name, server_port, is_ssl

    These are all fairly self-explanatory. Each of these is required, and will be sent for every request.

    Headers

    The structure of request_headers is the following: First, the number of headers num_headers is encoded. Then, a series of header name req_header_name / value req_header_value pairs follows. Common header names are encoded as integers, to save space. If the header name is not in the list of basic headers, it is encoded normally (as a string, with prefixed length). The list of common headers sc_req_header_nameand their codes is as follows (all are case-sensitive):

    NameCode valueCode name
    accept0xA001SC_REQ_ACCEPT
    accept-charset0xA002SC_REQ_ACCEPT_CHARSET
    accept-encoding0xA003SC_REQ_ACCEPT_ENCODING
    accept-language0xA004SC_REQ_ACCEPT_LANGUAGE
    authorization0xA005SC_REQ_AUTHORIZATION
    connection0xA006SC_REQ_CONNECTION
    content-type0xA007SC_REQ_CONTENT_TYPE
    content-length0xA008SC_REQ_CONTENT_LENGTH
    cookie0xA009SC_REQ_COOKIE
    cookie20xA00ASC_REQ_COOKIE2
    host0xA00BSC_REQ_HOST
    pragma0xA00CSC_REQ_PRAGMA
    referer0xA00DSC_REQ_REFERER
    user-agent0xA00ESC_REQ_USER_AGENT

    The Java code that reads this grabs the first two-byte integer and if it sees an '0xA0' in the most significant byte, it uses the integer in the second byte as an index into an array of header names. If the first byte is not '0xA0', it assumes that the two-byte integer is the length of a string, which is then read in.

    This works on the assumption that no header names will have length greater than 0x9FFF (==0xA000 - 1), which is perfectly reasonable, though somewhat arbitrary. (If you, like me, started to think about the cookie spec here, and about how long headers can get, fear not -- this limit is on header names not header values. It seems unlikely that unmanageably huge header names will be showing up in the HTTP spec any time soon).

    Note: The content-length header is extremely important. If it is present and non-zero, the container assumes that the request has a body (a POST request, for example), and immediately reads a separate packet off the input stream to get that body.

    Attributes

    The attributes prefixed with a ? (e.g. ?context) are all optional. For each, there is a single byte code to indicate the type of attribute, and then a string to give its value. They can be sent in any order (though the C code always sends them in the order listed below). A special terminating code is sent to signal the end of the list of optional attributes. The list of byte codes is:

    InformationCode ValueNote
    ?context0x01Not currently implemented
    ?servlet_path0x02Not currently implemented
    ?remote_user0x03
    ?auth_type0x04
    ?query_string0x05
    ?route0x06
    ?ssl_cert0x07
    ?ssl_cipher0x08
    ?ssl_session0x09
    ?req_attribute0x0AName (the name of the attribut follows)
    ?ssl_key_size0x0B
    ?secret0x0C
    ?stored_method0x0D
    are_done0xFFrequest_terminator

    The context and servlet_path are not currently set by the C code, and most of the Java code completely ignores whatever is sent over for those fields (and some of it will actually break if a string is sent along after one of those codes). I don't know if this is a bug or an unimplemented feature or just vestigial code, but it's missing from both sides of the connection.

    The remote_user and auth_type presumably refer to HTTP-level authentication, and communicate the remote user's username and the type of authentication used to establish their identity (e.g. Basic, Digest). I'm not clear on why the password isn't also sent, but I don't know HTTP authentication inside and out.

    The query_string, ssl_cert, ssl_cipher, and ssl_session refer to the corresponding pieces of HTTP and HTTPS.

    The route, as I understand it, is used to support sticky sessions -- associating a user's session with a particular Tomcat instance in the presence of multiple, load balancing servers. I don't know the details.

    Beyond this list of basic attributes, any number of other attributes can be sent via the req_attribute code (0x0A). A pair of strings to represent the attribute name and value are sent immediately after each instance of that code. Environment values are passed in via this method.

    Finally, after all the attributes have been sent, the attribute terminator, 0xFF, is sent. This signals both the end of the list of attributes and also then end of the Request Packet.

    Response Packet Structure

    For messages which the container can send back to the server.

    AJP13_SEND_BODY_CHUNK := 
      prefix_code   3
      chunk_length  (integer)
      chunk        *(byte)
    
    
    AJP13_SEND_HEADERS :=
      prefix_code       4
      http_status_code  (integer)
      http_status_msg   (string)
      num_headers       (integer)
      response_headers *(res_header_name header_value)
    
    res_header_name := 
        sc_res_header_name | (string)   [see below for how this is parsed]
    
    sc_res_header_name := 0xA0 (byte)
    
    header_value := (string)
    
    AJP13_END_RESPONSE :=
      prefix_code       5
      reuse             (boolean)
    
    
    AJP13_GET_BODY_CHUNK :=
      prefix_code       6
      requested_length  (integer)
    

    Details:

    Send Body Chunk

    The chunk is basically binary data, and is sent directly back to the browser.

    Send Headers

    The status code and message are the usual HTTP things (e.g. "200" and "OK"). The response header names are encoded the same way the request header names are. See above for details about how the the codes are distinguished from the strings. The codes for common headers are:

    NameCode value
    Content-Type0xA001
    Content-Language0xA002
    Content-Length0xA003
    Date0xA004
    Last-Modified0xA005
    Location0xA006
    Set-Cookie0xA007
    Set-Cookie20xA008
    Servlet-Engine0xA009
    Status0xA00A
    WWW-Authenticate0xA00B

    After the code or the string header name, the header value is immediately encoded.

    End Response

    Signals the end of this request-handling cycle. If the reuse flag is true (anything other than 0 in the actual C code), this TCP connection can now be used to handle new incoming requests. If reuse is false (==0), the connection should be closed.

    Get Body Chunk

    The container asks for more data from the request (If the body was too large to fit in the first packet sent over or when the request is chuncked). The server will send a body packet back with an amount of data which is the minimum of the request_length, the maximum send body size (8186 (8 Kbytes - 6)), and the number of bytes actually left to send from the request body.
    If there is no more data in the body (i.e. the servlet container is trying to read past the end of the body), the server will send back an "empty" packet, which is a body packet with a payload length of 0. (0x12,0x34,0x00,0x00)

    Questions I Have

    What happens if the request headers > max packet size? There is no provision to send a second packet of request headers in case there are more than 8K (I think this is correctly handled for response headers, though I'm not certain). I don't know if there is a way to get more than 8K worth of data into that initial set of request headers, but I'll bet there is (combine long cookies with long ssl information and a lot of environment variables, and you should hit 8K easily). I think the connector would just fail before trying to send any headers in this case, but I'm not certain.

    What about authentication? There doesn't seem to be any authentication of the connection between the web server and the container. This strikes me as potentially dangerous.

    tomcat-connectors-1.2.50-src/docs/ajp/ajpv13ext.html0000644000000000000020000006405514655113620020545 0ustar rootbin The Apache Tomcat Connectors - AJP Protocol Reference (1.2.50) - AJPv13 extensions Proposal

    AJPv13 extensions Proposal

    Introduction

    This document is a proposal of evolution of the current Apache JServ Protocol version 1.3, also known as ajp13. I'll not cover here the full protocol but only the add-on from ajp13. This nth pass include comments from the tomcat-dev list and misses discovered during developpment.

    Missing features in AJP13

    ajp13 is a good protocol to link a servlet engine like tomcat to a web server like Apache:

    • use persistent connections to avoid reconnect time at each request
    • encode many http commands to reduce stream size
    • send to servlet engine much info from web server (like SSL certs)

    But ajp13 lacks support for:

    • security between web server and servlet engine. Anybody can connect to an ajp13 port (no login mechanism used) You could connect, for example with telnet, and keep the remote thread up by not sending any data (no timeout in connection)
    • context information passed from servlet engine to web server. Part of the configuration of JK, the web server connector, is to indicate to the web server which URI to handle. The mod_jk JkMount directive, told to web server which URI must be forwarded to servlet engine. A servlet engine already knows which URI it handle and TC 3.3 is allready capable to generate a config file for JK from the list of available contexts.
    • state update of contexts from servlet engine to web server. Big site with farm of Tomcat, like ISP and virtuals hosters, may need to stop a context for admin purposes. In that case the front web server must know that the context is currently down, to eventually relay the request to another Tomcat
    • verify state of connection before sending request. Actually JK send the request to the servlet engine and next wait for the answer. But one of the beauty of the socket API, is you that you could write() to a closed connection without any error reporting, but a read() to a closed connection return you the error code.

    Proposed add-ons to AJP13

    Let's describe here the features and add-on that could be added to AJP13. Since this document is a proposal, a reasonable level of chaos must be expected at first. Be sure that discussion on tomcat list will help clarify points, add features but the current list seems to be a 'minimun vital'

    • Advanced login features at connect time
    • Basic authorisation system, where a shared secret key is present in web server and servlet engine.
    • Basic protocol negociation, just to be sure that if functionnalities are added to AJP13 in the future, current implementations will still works.
    • Clean handling of 'Unknown packets'
    • Extended env vars passed from web-server to servlet engine.
    • Add extra SSL informations needed by Servlet 2.3 API (like SSL_KEY_SIZE)

    Advanced login

    1. WEB-SERVER send LOGIN INIT CMD + NEGOCIATION DATA + WEB SERVER INFO
    2. TOMCAT respond with LOGIN SEED CMD + RANDOM DATA
    3. WEB-SERVER calculted the MD5 of RANDOM DATA+SECRET DATA
    4. WEB-SERVER send LOGIN COMP CMD + MD5 (SECRET DATA + RANDOM DATA)
    5. TOMCAT respond with LOGIN STATUS CMD + NEGOCIED DATA + SERVLET ENGINE INFO
    To prevent DOS attack, the servlet engine will wait the LOGIN CMD only 15/30 seconds and reports the timeout exception for admins investigation. The login command will contains basic protocol negociation information like compressing ability, crypto, context info (at start up), context update at run-time (up/down), level of SSL env vars, AJP protocol level supported (level1/level2/level3...) The web server info will contain web server info and connector name (ie Apache 1.3.26 + mod_ssl 2.8.8 + mod_jk 1.2.41 + mod_perl 1.25). The servlet engine will mask the negociation mask with it's own mask (what it can do) and return it when loggin is accepted. This will help having a basic AJP13 implementation (level 1) on a web-server working with a more advanced protocol handler on the servlet engine side or vice-versa. AJP13 was designed to be small and fast and so many SSL informations present in the web-server are not forwarded to the servlet engine. We add here four negociations flags to provide more informations on client SSL data (certs), server SSL datas, crypto used, and misc datas (timeout...).

    Messages Stream

    +----------------+------------------+-----------------+
    | LOGIN INIT CMD | NEGOCIATION DATA | WEB SERVER INFO |
    +----------------+------------------+-----------------+
    
    +----------------+----------------+
    | LOGIN SEED CMD | MD5 of entropy |
    +----------------+----------------+
    
    +----------------+----------------------------+
    | LOGIN COMP CMD | MD5 of RANDOM + SECRET KEY |
    +----------------+----------------------------+
    
    +-----------+---------------+---------------------+
    | LOGOK CMD | NEGOCIED DATA | SERVLET ENGINE INFO |
    +-----------+---------------+---------------------+
    
    +------------+--------------+
    | LOGNOK CMD | FAILURE CODE |
    +------------+--------------+
    
    • LOGIN INIT CMD, LOGIN SEED CMD, LOGIN COMP CMD, LOGOK CMD, LOGNOK CMD are 1 byte long.
    • MD5, MD5 of RANDOM + SECRET KEY are 32 chars long.
    • NEGOCIATION DATA, NEGOCIED DATA, FAILURE CODE are 32 bits long.
    • WEB SERVER INFO, SERVLET ENGINE INFO are CString.
    The secret key will be set by a new property in workers.properties: secretkey
    worker.ajp13.port=8009
    worker.ajp13.host=localhost
    worker.ajp13.type=ajp13
    worker.ajp13.secretkey=myverysecretkey
    

    Shutdown feature

    AJP13 miss a functionality of AJP12, which is shutdown command. A logout will tell servlet engine to shutdown itself.

    +--------------+----------------------------+
    | SHUTDOWN CMD | MD5 of RANDOM + SECRET KEY |
    +--------------+----------------------------+
    
    +------------+
    | SHUTOK CMD |
    +------------+
    
    +-------------+--------------+
    | SHUTNOK CMD | FAILURE CODE |
    +-------------+--------------+
    
    • SHUTDOWN CMD, SHUTOK CMD, SHUTNOK CMD are 1 byte long.
    • MD5 of RANDOM + SECRET KEY are 32 chars long.
    • FAILURE CODE is 32 bits long.

    Extended Env Vars feature

    NOTA: While working on AJP13 in JK, I really discovered "JkEnvVar". The following "Extended Env Vars feature" description may not be implemented in extended AJP13 since allready available in original implementation. DESC: Many users will want to see some of their web-server env vars passed to their servlet engine. To reduce the network traffic, the web-servlet will send a table to describing the external vars in a shorter fashion. We'll use there a functionality allready present in AJP13, attributes list: In the AJP13, we've got:

    AJP13_FORWARD_REQUEST :=
        prefix_code      2
        method           (byte)
        protocol         (string)
        req_uri          (string)
        remote_addr      (string)
        remote_host      (string)
        server_name      (string)
        server_port      (integer)
        is_ssl           (boolean)
        num_headers      (integer)
        request_headers *(req_header_name req_header_value)
    
        ?context       (byte string)
        ?servlet_path  (byte string)
        ?remote_user   (byte string)
        ?auth_type     (byte string)
        ?query_string  (byte string)
        ?route         (byte string)
        ?ssl_cert      (byte string)
        ?ssl_cipher    (byte string)
        ?ssl_session   (byte string)
    
        ?attributes   *(attribute_name attribute_value)
        request_terminator (byte)
    
    Using short 'web server attribute name' will reduce the network traffic.
    +-------------------+---------------------------+-------------------------------+----+
    | EXTENDED VARS CMD | WEB SERVER ATTRIBUTE NAME | SERVLET ENGINE ATTRIBUTE NAME | ES |
    +-------------------+---------------------------+-------------------------------+----+
    
    ie:
    JkExtVars S1 SSL_CLIENT_V_START javax.servlet.request.ssl_start_cert_date
    JkExtVars S2 SSL_CLIENT_V_END   javax.servlet.request.ssl_end_cert_date
    JkExtVars S3 SSL_SESSION_ID     javax.servlet.request.ssl_session_id
    
    
    +-------------------+----+-------------------------------------------+
    | EXTENDED VARS CMD | S1 | javax.servlet.request.ssl_start_cert_date |
    +-------------------+----+-------------------------------------------+
    +----+-----------------------------------------+
    | S2 | javax.servlet.request.ssl_end_cert_date |
    +----+-----------------------------------------+
    +----+-----------------------------------------+
    | S3 | javax.servlet.request.ssl_end_cert_date |
    +----+-----------------------------------------+
    
    During transmission in extended AJP13 we'll see attributes name containing S1, S2, S3 and attributes values of 2001/01/03, 2002/01/03, 0123AFE56. This example showed the use of extended SSL vars but any 'personal' web-server vars like custom authentification vars could be reused in the servlet engine. The cost will be only some more bytes in the AJP traffic.
    • EXTENDED VARS CMD is 1 byte long.
    • WEB SERVER ATTRIBUTE NAME, SERVLET ENGINE ATTRIBUTE NAME are CString.
    • ES is an empty CString.

    Context informations forwarding for Servlet engine to web server

    Just after the LOGON PHASE, the web server will ask for the list of contexts and URLs/URIs handled by the servlet engine. It will ease installation in many sites, reduce questions about configuration on tomcat-user list, and be ready for servlet API 2.3. This mode will be activated by a new directive JkAutoMount ie: JkAutoMount examples myworker1 /examples/ If we want to get ALL the contexts handled by the servlet engine, willcard could be used: ie: JkAutoMount * myworker1 * A servlet engine could have many contexts, /examples, /admin, /test. We may want to use only some contexts for a given worker. It was done previously, in Apache HTTP Server for example, by setting by hand the JkMount accordingly in each [virtual] area of Apache. If you web-server support virtual hosting, we'll forward also that information to servlet engine which will only return contexts for that virtual host. In that case the servlet engine will only return the URL/URI matching these particular virtual server (defined in server.xml). This feature will help ISP and big sites which mutualize large farm of Tomcat in load balancing configuration.

    +-----------------+-------------------+----------+----------+----+
    | CONTEXT QRY CMD | VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES |
    +-----------------+-------------------+----------+----------+----+
    
    +------------------+-------------------+----------+-------------------+----------+---------------+----+
    | CONTEXT INFO CMD | VIRTUAL HOST NAME | CONTEXTA | URL1 URL2 URL3 ES | CONTEXTB | URL1 URL2 ... | ES |
    +------------------+-------------------+----------+-------------------+----------+---------------+----+
    
    We'll discover via context-query, the list of URL/MIMES handled by the remove servlet engine for a list of contextes. In wildcard mode, CONTEXTA will contains just '*'.
    • CONTEXT QRY CMD and CONTEXT INFO CMD are 1 byte long.
    • VIRTUAL HOST NAME is a CString, ie an array of chars terminated by a null byte (/0).
    • An empty string is just a null byte (/0).
    • ES is an empty CString. Indicate end of URI/URLs or end of CONTEXTs.
    NB:
    When VirtualMode is not to be used, the VIRTUAL HOST NAME is '*'. In that case the servlet engine will send all contexts handled.

    Context informations updates from Servlet engine to web server

    Context update are messages caming from the servlet engine each time a context is desactivated/reactivated. The update will be in use when the directive JkUpdateMount. This directive will set the AJP13_CONTEXT_UPDATE_NEG flag. ie: JkUpdateMount myworker1

    +--------------------+-------------------+----------+--------+----------+--------+----+
    | CONTEXT UPDATE CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES |
    +--------------------+-------------------+----------+--------+----------+--------+----+
    
    • CONTEXT UPDATE CMD, STATUS are 1 byte long.
    • VIRTUAL HOST NAME, CONTEXTS are CString.
    • ES is an empty CString. Indicate end of CONTEXTs.
    NB:
    When VirtualMode is not in use, the VIRTUAL HOST NAME is '*'. STATUS is one byte indicating if context is UP/DOWN/INVALID

    Context status query to Servlet engine

    This query will be used by the web-server to determine if a given contexts are UP, DOWN or INVALID (and should be removed).

    +-------------------+--------------------+----------+----------+----+
    | CONTEXT STATE CMD |  VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES |
    +-------------------+--------------------+----------+----------+----+
    
    +-------------------------+-------------------+----------+--------+----------+--------+----+
    | CONTEXT STATE REPLY CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES |
    +-------------------------+-------------------+----------+-------------------+--------+----+
    
    • CONTEXT STATE CMD, CONTEXT STATE REPLY CMD, STATUS are 1 byte long.
    • VIRTUAL HOST NAME, CONTEXTs are CString
    • ES is an empty CString
    NB:
    When VirtualMode is not in use, the VIRTUAL HOST NAME is an empty string.

    Handling of unknown packets

    Sometimes even with a well negocied protocol, we may be in a situation where one end (web server or servlet engine), will receive a message it couldn't understand. In that case the receiver will send an 'UNKNOW PACKET CMD' with attached the unhandled message.

    +--------------------+------------------------+-------------------+
    | UNKNOWN PACKET CMD | UNHANDLED MESSAGE SIZE | UNHANDLED MESSAGE |
    +--------------------+------------------------+-------------------+
    
    Depending on the message, the sender will report an error and if possible will try to forward the message to another endpoint.
    • UNKNOWN PACKET CMD is 1 byte long.
    • UNHANDLED MESSAGE SIZE is 16bits long.
    • UNHANDLED MESSAGE is an array of byte (length is contained in UNHANDLED MESSAGE SIZE)
    NB:
    added UNHANDLED MESSAGE SIZE (development)

    Verification of connection before sending request

    NOTA: This fonctionality may never be used, since it may slow up the normal process since requiring on the web-server side an extra IO (read) before forwarding the request..... One of the beauty of socket APIs, is that you could write on a half closed socket. When servlet engine close the socket, the web server will discover it only at the next read() to the socket. Basically, in the AJP13 protocol, the web server send the HTTP HEADER and HTTP BODY (POST by chunk of 8K) to the servlet engine and then try to receive the reply. If the connection was broken the web server will learn it only at receive time. We could use a buffering scheme but what happen when you use the servlet engine for upload operations with more than 8ko of datas ? The hack in the AJP13 protocol is to add some bytes to read after the end of the service:

    EXAMPLE OF DISCUSSION BETWEEN WEB SERVER AND SERVLET ENGINE
    
    AJP HTTP-HEADER (+ HTTP-POST)   (WEB->SERVLET)
    
    AJP HTTP-REPLY					(SERVLET->WEB)
    
    AJP END OF DISCUSSION			(SERVLET->WEB)
    						
    ---> AJP STATUS 				(SERVLET->WEB AJP13)
    
    The AJP STATUS will not be read by the servlet engine at the end of the request/response #N but at the begining of the next session. More at that time the web server could also use OS dependants functions (or better APR functions) to determine if there is also more data to read. And that datas could be CONTEXT Updates. This will avoid the web server sending a request to a desactivated context. In that case, if the load balancing is used, it will search for another servlet engine to handle the request. And that feature will help ISP and big sites with farm of tomcat, to updates their servlet engine without any service interruption.
    +------------+-------------+
    | STATUS CMD | STATUS DATA |
    +------------+-------------+
    
    • STATUS CMD and STATUS DATA are one byte long.

    Conclusion

    The goal of the extended AJP13 protocol is to overcome some of the original AJP13 limitation. An easier configuration, a better support for large site and farm of Tomcat, a simple authentification system and provision for protocol updates. Using the stable ajp13 implementation in JK (native) and in servlet engine (java), it's a reasonable evolution of the well known ajp13.

    Commands and IDs in extended AJP13 Index

    Index of Commands and ID to be added in AJP13 Protocol

    Commands IDs

    Command NameCommand Number
    AJP13_LOGINIT_CMD0x10
    AJP13_LOGSEED_CMD0x11
    AJP13_LOGCOMP_CMD0x12
    AJP13_LOGOK_CMD0x13
    AJP13_LOGNOK_CMD0x14
    AJP13_CONTEXT_QRY_CMD0x15
    AJP13_CONTEXT_INFO_CMD0x16
    AJP13_CONTEXT_UPDATE_CMD0x17
    AJP13_STATUS_CMD0x18
    AJP13_SHUTDOWN_CMD0x19
    AJP13_SHUTOK_CMD0x1A
    AJP13_SHUTNOK_CMD0x1B
    AJP13_CONTEXT_STATE_CMD0x1C
    AJP13_CONTEXT_STATE_REP_CMD0x1D
    AJP13_UNKNOW_PACKET_CMD0x1E

    Negociations Flags

    Command NameNumberDescription
    AJP13_CONTEXT_INFO_NEG0x80000000web-server want context info after login
    AJP13_CONTEXT_UPDATE_NEG0x40000000web-server want context updates
    AJP13_GZIP_STREAM_NEG0x20000000web-server want compressed stream
    AJP13_DES56_STREAM_NEG0x10000000web-server want crypted DES56 stream with secret key
    AJP13_SSL_VSERVER_NEG0x08000000Extended info on server SSL vars
    AJP13_SSL_VCLIENT_NEG0x04000000Extended info on client SSL vars
    AJP13_SSL_VCRYPTO_NEG0x02000000Extended info on crypto SSL vars
    AJP13_SSL_VMISC_NEG0x01000000Extended info on misc SSL vars

    Negociation IDNumberDescription
    AJP13_PROTO_SUPPORT_AJPXX_NEG0x00FF0000mask of protocol supported
    AJP13_PROTO_SUPPORT_AJP13L1_NEG0x00010000communication could use AJP13 Level 1
    AJP13_PROTO_SUPPORT_AJP13L2_NEG0x00020000communication could use AJP13 Level 2
    AJP13_PROTO_SUPPORT_AJP13L3_NEG0x00040000communication could use AJP13 Level 3

    All others flags must be set to 0 since they are reserved for future use.

    Failure IDs

    Failure IdNumber
    AJP13_BAD_KEY_ERR0xFFFFFFFF
    AJP13_ENGINE_DOWN_ERR0xFFFFFFFE
    AJP13_RETRY_LATER_ERR0xFFFFFFFD
    AJP13_SHUT_AUTHOR_FAILED_ERR0xFFFFFFFC

    Status

    Failure IdNumber
    AJP13_CONTEXT_DOWN0x01
    AJP13_CONTEXT_UP0x02
    AJP13_CONTEXT_OK0x03

    tomcat-connectors-1.2.50-src/docs/images/0000755000000000000020000000000014655113620016513 5ustar rootbintomcat-connectors-1.2.50-src/docs/images/docs.gif0000644000000000000020000000040514655113620020131 0ustar rootbinGIF89a„ÿÿÿþþþ000ðððààà///111ÀÀÀÏÏÏßßß¿¿¿ÐÐÐýÿþ/10ÎÎÎÞàßÀÀ¾þÿÿ€€€NNN___ááá°°°OOOáßàÿÿý002,Š Ždi–A0ªç(¼p ŸÂ`ß¡Åi ‡àA$&> bX4"Mµ`‘ iƒâ˜è>IŒÁÑìv_’€P6Ó.6ñáF@ࢵњ Bî& Uf}vx…rˆ4lŽxy–˜(Ž ¡-23­³³£³!;tomcat-connectors-1.2.50-src/docs/images/tomcat.gif0000644000000000000020000000402214655113620020467 0ustar rootbinGIF89a’\ÄÿÿÿÒ¦)ýÝu" GB4pl^¨”W‹r+’’‘ÓÓÓóóô³´´Ð´bñÑp¸”.!ù,’\ÿ Ždižhª®bQ(l,›LÁ”P®C@>ú³ pxRŽq ¨!Q¼_´7eZ¯%ÃñHH`e í–%ñν¯úJØn_k”¢í(qæ4:Οbc7}" umƒx?"QU„4 uGŠq[^&UŽ‘¤&†–˜_š[ Z'¡‹¥¶Z®[wX†–¹¸¶ÃD•– _ ʺËÄÕ`mǩПV tu“ÍÖç( GÒÈÐd# õö÷ Í¿–ìä˜CGpÄv@3`´‡“@1`¯‚èR¤¨ ¢ÇcÄU^5¥~tT¹Çxw̵ܜç©ÙÖŠYwQ€ Hçí{¦nÍ›3L8nÿþõñ2?À«äänÁ+:Pðy–Õ¿¹²¹ìˆ‡ÏëîOI5§½Î[ŠpŽWáâÇ/³*÷@ý¿)otî²ülÎe˜à-{a ñ:U0/€tÞ$—ˆYÇ/êàa2åY΃”_¯àóë! ƒ¿ÀDà¸ð@f=@y@JÅ׫èL8‘à €Sª ªª…ëgX´çÍÆP:$Pdá>Ú‰¯`D¤áN cBž%1@€PU‡E)úCH¼" ð'ÿ"îm0c¿¶‰¶ð b,„Ô8·^Ñq°sÙ¯À¶¿8’ñ "ŇF.$fR9Œ£þ8 $P!dü ç2€ÜI}YÙ%á?.J2~`[Ðþæ— ¹ßCœ'?IÈa(¿ Àñ é5ñaƒ•ÛËðÊ‚ è´ÔL†I̘Ü—òãZå FJ“¸ˆº,‘%rä˜`™s“àÅ€ð…]“8rôl6¬#ÛL¢*<Ci~ä(¤™fK0D<†rÍ´†)óè2Á0Àï[d<è‘“•¸¤ž!” ¸Œ‚@_þok£$û<²AôÌ£Pþ9J*gè‚×ÿ’t,·¦*ÛLô!=ü­P…+ 4›ß<`VéÑý4t…ɧA¦£)—2Œ&CM™ŽpÖÁb<Í!|:CJÂѡ˘٠Ypš1|ÁV]+P KóTMâxª@êˆþ³¬:G†á3ÜQt5>+Zcœëê þ鎆ÆmË`jÙZÄÅéÊc(aŒjE»!S¸ÛhøÂz°¨ÆÕ¯JªjNrÔKÕ€ë ŠV'æÑê x}H¯€›oå¥åš*$~C¢2§«’.‹„Ìâk³‹¹HeØ 4‡¢‘HV%m‰ÏH8ÐanU]QÚ[+”³g4ŠNç Ø{IP¶D°Õ=¶[Ù!ØÊ´¶ @!»é¦Ã(…S­"gkZNÎ?ØXËÆ”­ ˜B§{É5»£¹?CÈòŽÐÜûÊ@¸GI«ÿ&ÑË_@“ÀŽ‚÷Äw9Éeò¯}#¼† ‡o„:ÝMw9¬×Q®+ ™Š»4b—ˆ±Œgì?µ¹x½ÂÉIœc”!;tomcat-connectors-1.2.50-src/docs/images/add.gif0000644000000000000020000000201514655113620017730 0ustar rootbinGIF89açÿÿÿÿþÿþþþÿÿýþÿÿ# ê£aì¥c 4Àn ì£_ÿ¡Iÿ­Uï´r ÿüï5؉Pñ†8ùCÞ˜\Cö¡Qý¡Jÿ­Sý±Yÿ½fôÄ„ ÿüñ1ݘ]ï“@ÿ@ÿžCý¢Iý±[ÿ½dóà æÓµ ÿþô$ ä˜Mÿž>ÿŸAóà õÓ–ûЋðÒ  é£^õ¤Ué²yI+ 8."0000026/%A/ ïЙùщõÑ•î±n÷²díÀ‡>,˜¢×°û ÐÿµØëïЗúÑ‚õÒñÀ~ûÁwìÄ‘ */B—³Û“Âðµ×ò àÇ©5/#äÒ®,-I€†Úžÿ«Êùÿ÷ÿJKšR)£:‰1!zohÅxwì†õ7«»Ô ÿúÿEP*»OÜdÿk2ýwNòhÔ2ÿüÿ FR%³e*ärCß)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,ò ÀÀƒppÀ€ƒ&dˆ‰ p(£@†0p„(XÀ ÀÈ@ˆP ,\ÀAÃ<|yD#H”0ñàŠ*V°háâà 1d˜øÙaÆ5lÜÀQu :vðèáã B†)’0‚‘#H’(Y¤‰“'P¢HIøa •*V®`É¢e —.Dz òL1c–)c¦ãCgФQ³†M7oàÄ‘3¡EsèÔ±sO={øôé30âÀ~þ $hEQ ,°›7ÆçУG§(@@;tomcat-connectors-1.2.50-src/docs/images/tomcat.png0000644000000000000020000001175714655113620020523 0ustar rootbin‰PNG  IHDR’\…™ìJ pHYs  šœ¡IDATxÚí]klSgš~Ì$µF8tdZwŠ I¢¸*jÐv×ÃÄÝ!7 ù12Ùbµ] !™QQ¥iš’’˜N;i ¨3?HÁ!mÂ6ݑԪ¶SŒS"uh(g8ßá;ÇçîããcÖ¯d•Æ·syü¼Ï{ùÞ à ÿxðXUSŬª©bB¡“‹Ç2dVÕT1'ƒAÁãÀˆ=èç…Þ#õ½yðPP(ÄX­ìc›ÿåœ}ìrïGH:<¶ù_æ©Àje\%O2½½ûM &Àn;n­@’úoH ®’'Sny˜ÑÝ…B!Fê˜åŽWO ÍCÞáp˜‰Æf~_sÊóc!¬Y]‡àð0c†ãíëëe–WU31¯Ç §Ã˜¾rEóç3 c±X, Ã0%¯ÏiÎÈEw:ìøumàk¢±¼¸n]ÖÁÔÖº‘iïüàsÏ?óžr=¸¹dØ1å4gôEw—/„×ã}m6ÁÔÖº‘ ôˆ>ÿ/5ÿˆòŠ @ä›si}—R6ʉ2rÑɯ™Ü )0…ÃaCÁÔ××+ "¯Ç wùBöÿ§ÎŸW 1ðÈ*$ÞE'so´ulmŲÈfÄñ‡‡Eݱ–¦Ò¬]¿<X,‹l#×9“soD€÷ö¾7âø¶ú_“|ÓaGÝJ๲»€‹‘놽 £Bš¾ ð»ö§Q5’|ßÛÝ]hmÝ’rãC¡ñ8ñJEïRW’QJ–,Û]S”t)7½½oÆåØhw‡6[¡À9-@HY(4_^U•òwwùBìÙ¼ oø›$ÛZ72Ä=^Œ\Gõ6„>OÕ±"îtØQë]>[ i£õuNÑs`É)ËÖ¾¹Ÿ|ucÌ$%€ÓeI~žHÈ¥éùyÖ¯SH ìT5ê}¹©O¹GyE~òÈ9,vUÊJæãÐè=AÀy=néù9._½ ¸0}p5Æÿ|ÿ,ËrB€r:ì8øEŠK£múÊTVVæd„)ÉŸê¯ÆÑ‘RìØ;hlN‡/4Ö๲»(+™¥‹ðnh=çý»ÏâDОˆòŠ Øl…lØþ |'®ê1$³€‘Oc¸ 㓯~Ìj8:ÜÏ3RŽØú:'êV:pùêmàH›ÍVˆkRXIIš|OR9Ñ®â˜ÊnçÕFØC ˆÄ@ãtØMÃ(y å¹Ër Â/4Ö<4çfj×fÆF\?}ÕÕ5p»kŠæFBÏï)Y²Ä°súumýÉÓ9+=­¬dþÃ$’i% ;‚àH-N&ÿí*±ÇÛZ7â•W;QYYi1 èCS7qhôNÇ$kv-M¥)ù’1›±™è<#)ÎÉàÁøØèL?W‰ÑØ 'aW`E¼téb6t–ÊÍDc3ô Ð?¯ÇÍìÝ0m@¹Ý5EVÄà/¬X_§îýÛ{¾e—¤Æ&Bs邵)`"51-:K‰‘ð [ž³@ ‡ÃÌïuÁUbÅ‹ëÖɾž$ßär5´M„°¼ª ~_3óv`$-—çtØe“BVïK&+½7'M=&ÿìØ;º•hêV:²â~r HË"Û6]œÏ($ïâúé³)¿¢F¾9‡©óçU‰°—«Ä‡ÃšØ‰an$j½+ÍÌu<¦˜‰Æ&Bðûš±¯í±FÂýËWos¢3:o”i3JÿèÍB®+Ç-ù}ÍðÖnÀêÆ–¢ž¾Ã %@$nFwy|pilhȸv MÝD N‡»|Å’ÂúÂô´“HÌâòÕÛ¸0}¹`ÅsewEëk9ÍHÁáaf«ÿ5Ð}Ï´ f˜ŠÙ¡tébMnH6œiSyEÆ&B¸¹ŽDbV‘~ñzÜhi*•}­ÝÅñ|†Ÿ’(ÔròTÉ@&7€fhÔÝõZ[·hf…mík›ÐLI—;€hl&ʼnå„NõWgôæÐ"ž€–h«¥‹H—DŽ—.‘È F ‡Ã iºr:ìØx麖92owwif¦±Ñ#hlhPüzZ³5ùÏ`w‡'E$iD|¯ÄäZlM ¤Ž­-ìÍÖD4˜¶lùOÛÉà ›:ª‚“ÔI\ªÝ«[Ø@46ƒ—¶Áé°cw‡G³!a¸ÚÄãÑ‘(ýCðzÜšXô/Éõ›H}}½ ‰°º»Þ‚Þ"w.œ·fI&3¤$3#ÓwÓ¦p!mFµc¯=-†Rê'³Ø±wBsŸQhê&{$B65,–E6W‰•õßéh"•À¨Ž?=…$]÷zܼ_ô]QíDÚ<Ä´ÊÒÅ D_÷‘OcˆÆfà÷5Ãf+LyŸ‰YŒ|ÃÁc—8©“êjãjy–¹å¸šØˆâ/''MU®H‡aÉ9MþR‘.9:ÅŽ½¢) âzÕ¦2ÄÞÃwµ¡©›øm÷×)¹7§ÃŽÈô]Ýë’º2ŸrD¤QÿìÙq }ÄþýÐè=ì+Wöd-œN!úM©¶! Rúž¥‹̹Àd—%•‘›f Œ“pßß¾3'ÁCꮫ`£¾Ò ÷ú:§ ?:ÅKÛ‡T‰u-ï¡]»|! à†µ¿2ÔFZ;œ;V7¶’ðÒx,Yö1²ÂO m#õ‘f ‘<…Ñô©5Ïuöì¸ xˆ yþ™ïàvýOßÁéÉGñÆäÍ |µ¹œÐÔMö}Fæ¡ÞcÏËh¹Q å—Mô‘Ñô©Æ‚ÃÃL {§ %àYUui¹¸XUu¿Ÿë «4Ôög“ú»ö§5¥ ”–THýíÐè=N±;—šIk¶Ù÷ÕÛûf|xè£y=nóȉgzM™%³8×Ôí._§Ã®XŸñëpÞÚ æ½*Õ¨¦)¥r•Xkt^]›¸Ì#eÏ?óÆ&ÔGoüx¯KpUIKS)*Š¿æ°ˆÛUŒžc ²“œ{“b4ñç“d§º•üGÿ-úP5×ß½ËWŒ?þ/v\ŽR’ëeçO/¹¹Žž>“2ð`Í™ÓaÇ¥ËW3†ø¾¾^Éæ6§ÃŽ¡ÝE¢ Ãg'nô¦ÌNOÎãÜp)’Œvyì#ÆRjŒ”Tàøà V7¶ ýð’¦%Û$OÍdd g8fj½+˜öÎßp\ ß½Dc3øðó¢çŽbÎ{Æ&B¸¿àŸT˪ªûl%þDp\q;ˆP¨NÚRÈ9•WTh!z=n464XæF‚ÿ0­F":©Àz;@WD¢1ZH;v¼Þô¨¤’Ò>ü÷üqßZŽ;ä¿FÌeÐÇC'.•t0†¦n¢É†e¡–¦R¶wH)+ µ«Èµ©<åz£c_XLËH s#A~étëEº,´ªf D{6/ÃÐî"D„!†vaÏæeìüm÷ײ¬BØIL°J™Óag¿‹Ö!r­¬‰Ä,¶÷|‹ªub“”§ú«±¾Î‰SýÕøã¾µ¸¹ŽªuÂöžoU±Ö^'S1Ñ/z5¶ÑŸÅFiû~†'Šå/,ašµä^Ÿ,“¨sQ×n¢qû_Ù›÷åÇòIJ¢a¤X'‘˜åd¥å>—ÿz±æ5‹e‘Íô®Ÿðûš5…™b«rˆº ©­jM­ð&-°J’™GG¢l¤'eÝN±Çp|p0+åÝ\qo¤ÊèP-ºçVåÆÅ†E~g¥–iI\z²•|½ÍV¨¸Ì!Ö Ç d³€(- À+¯>¨ë|ð^—*WFïìãõ¸9šÈÎÚ,%Öµé{œ/mÒT˜Õš> £´·#Efº.š]?§¤T+ñçíÙ¼Œ£m:ߟÏ&Þ”ê$£¯—¤2ÒzX"1‹åkþÌöH}|rÄt}òiþ{åÕNöÚ±µERÕzW0ô!>ˆÈ/ž°S(òƒ)Yé‰âYìÙ¼Œžšüg4ç—”€hCÛgœE¨f\l‘6*++-¤ual"$¸ý íéšÐ;Å¢Q ×ÅØàÃÏWàü­§³záVUÝç€iCÛg‰ÐHÎÎLºHWׯàø!i8fÖ¬®ãè¡¶¦ï5»,:r2ƒë£GiZ@©‘!^D\U€Í #‘nà]ö×¹Í_Qצ;iÝ|R¡w:ì¦ÐO|fZ¾æÏi ðDb6§@¤ ±¡ÁBš¸ýhkÝ("½LéÂl€©ÉF65 Ñî,@¤›k£]­…Ä"³t¢¥ß{ ÑØŒnŸ™)7Gλ}s½*‘š\.HWF".Ž¿òVÏŠü`Ú,43‘(öC½ï¬"W×}à[“Ë5é$‹e‘-нSPÓèmn×L ¦w:ŠY0M„$]]hê&ê}g9LÖÝõVNHW ñÝ}!Åz†´šY„¶Tž‰î…"s–ê}g9€::E“ÿ §Uöøà aí˦ÔHtÆš„ø=ÇáˆÆûç/Òú’õÖ[¸©›Èõ!?2úoz ŸÏiF⃈„ømMß³ÌèÈz1[®.¸ïgœ:âƒ]˜¿}gNJHô^ôN‡mMß§P<]äLLÙ˜¨—«#Íx|f"ì´Õÿš`Uàÿ…k£Ç"“²‡v¡Ãv€Ûk¤Xe%óÙÐX7™-»v«=Çá,£".Û¬ÙŒ‰Ÿµ–+Wðµ=‹H‹Ø¦7Àáï«ti¶™ÀEwä"˜47ÿ“Úš\®èÚ­B„"?à“¯~¬z­€”MŠÕt[mtëL®‚Ij½+رÈb ºv«£žÁ‰à¸îID²AŽÔìm){®ì.þS¦H!Eu¹&Õ@ŠÐ„.ŽÐâƵ¿Buu ¦¯\½o‰Z£³¾ôF‚ÓW®àrä»Ë’È òÈ9M ôtiôü&¢'žLkhq-""$•äGøKy=nEëµÈÄZ°á¡$ÁEoÁn„+ì|?9¡ÞüàÄëqãôøÓƒI1è/¡ñ#3¯Ç ûNÉF,­`Jç—JCŽ|sNÔõÒ®°¶ì+ÝÙŠhG)m™K`R$~ùƒ¯‹ø òûš¡tGÇp8ÌtlmQ-ÄõO–J‹ì P)áf/â*­‹ä@¤e ·Xû‰”ej¤^¡cÊ4¨„$‚ÙÁ$ $9]´vGœQº öRwÖ–vo™œ„Âg+¡§äšðÇëèÅÑ›-›L’@’ÓE4õêÅBË·ÅÌ蕦R JW¨Ó,$MòWùš L’@’ÊeòÄøÛšfBtë*¡ùMZ\ßéÉdÙS* A_s#§å¥$š„’ŽÄ¥eêf*á|=<lôHŠPÏD:!^ c@ ‡Ã ™¥-¤‹ŒúeH ™àƒ‰$ åoíC]ŸÜÀx½´ &³ ’íÒ„Š±tƒ™ƒœäFªa,#]ßïu‰²TºŸÙÀ4Oè¦Ñºˆ²×n²'`Ô^$­­[,Ÿœ,+gþôõõÞçSYYiéé;l‰Lß-êîz‹Óvè@ãö¿¦µb¸kÓö3_\·.ë½LF¢£4±:Ú‡Ÿ¯Dj´ÐUêê„Bt£FàÉi)¡vÒq{´VÍf‘—ÃHôŽÙt§#m'‚ã’{f-jæF¢§ï°åøà ª‘w#×Ùân6­±¡Á2:ö…åËÉIø}Íœ/mBçûóU3é@Æf°fu]F†Ãªb$:ñ(ÕBªÕÙŽHø­Ä–ºJM9|A,…@¶PÊPtuÁé°sö#Yê*EÉ’%g* Ã0)C ÄfWÓ@2ÓØ¹\7í ê…ÆEmÅüR•{'m<™•…aÙœ‘PØÿ°ì¬m6@ Œóu”R@‘ì8ß­óÁå÷5ã•W;u½Àβ‘Üz1H÷î.ȉ†«\5!a®†¡ø E~à4:v켫›W™×Ûûf\N`ç-{Âüøà`Jê`편ªÕËOÏræ““ÏÒ3m`q•<ÉHí$F“y×–» ŦGÚÀR`µjBd^lç6 ô.º[¶ù_Ö$£ëXyS¨×›UüD3éÑۥ렭¼™PZlöïO Hóò·âáåjMqþÂ62¶i‡ØIEND®B`‚tomcat-connectors-1.2.50-src/docs/images/fix.gif0000644000000000000020000000053114655113620017767 0ustar rootbinGIF89a¥ÿÿÿþþþŸŸŸ€€€ÀÀÀ°°° OOOÁÁÁŒ{s¢t\ŒN7J<ÿûûÿÿý€¯±°,B“K2ÿ¯¦S .þÿÿþþü3–J2ÿ®—QÿûúÿûôC“K5Q 0ÿ¯˜Qÿûó“K3R R>‰O9è¼±3ÿüûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,~@€ȤrY\2KÁ`*… „BÁ@8 ’M‘H¦NÅ`‘eœŸƒCQh8ˆ$9™`)FCX^B !"K#$C%&'()FaJ‘*+zVB,&-. ¨*/0–Vª1234°B¾ÂþA;tomcat-connectors-1.2.50-src/docs/images/asf-logo.svg0000644000000000000020000005000614655113620020744 0ustar rootbin tomcat-connectors-1.2.50-src/docs/images/fonts/0000755000000000000020000000000014655113620017644 5ustar rootbintomcat-connectors-1.2.50-src/docs/images/fonts/OpenSans600italic.woff0000644000000000000020000005140414655113620023675 0ustar rootbinwOFFS‡\FFTMl\Ú,OS/2ˆ]`¢·Øcmapèh²ŒèÜ™cvt P^¦öfpgm°©´~a¶gasp\ glyfh2‡HøSýõhead:ð46øÈæhhea;$!$[æhmtx;HX9 kern=h# – locaK|®®U¶DPmaxpM, inameML1,²ÁpostP€yò‚léÕprepQüx¬œ%ɉo1ÉcH–ÉíØdxœc`fÑgŠ``eà`ÅjÌÀÀ(¡™/2¤11000q³³1s°01±<``zïÀ  ÔbCÇ`gE…5lòÿDZ8z™"çƒäX‚X·) LÑ >xœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@,A " m ÿ߀xòŸˆêý3åÿë•ÿ¿ü[ñoƒø¿= du€aÆŠS€¬³ GÎ3ìb˜ÅhȰ Ë’"“xœuUÏSÛFÞ "SÊ0Õ!«nìÂ`—t’¶@)lmÉØuÓb 3+èA"&czâ”C¦ñ­ŒHÿ—'r19åÚCÿ‡Ú[9&×ô½•M 3Õkß÷~î÷Þ.jûð Ðû{íÝÖÎO?>ú¡ù}£¾]ó½jå;µµùíÆ7ëk«_õå÷W>/—?+îÉOÝ» syûÎÌôÔäDv|l43bqVÀCF "_‹¤/£z¹$ü…®W.ù²‚ˆà'S”õºd"PÄOtA¡å“,Uj©®-¹-6Ø¥þò¤èóƒ–Æõž \™õ#³Î0‚뢇©Šª>Ôžvc?Äy25Y•ÕãÉr‰%“S¸œÂ,ÊÓ„/nr³°ýõÄbÙiJ‹;õ£ì´´ï9®”K ˜‘žQ±ª cU7!Å •ÎÎERz?ïÛì(\Îud'úYÃH„¾ñˆÇ¿C~–¤KÏþ^ÀCIz>,SÔæîužæû”F ¶ñ†Û‘WÿÞF¢2V°ß0Z‚U¾«]zœrÇ5)jqGýw½#)l'¹\|ê#ÝlGcˆþ»—çÔž`‡]¾ ¶^ÛmÂG­C V¡&º"ønIwÕqó×6;ÿ§fH ’ƒ ».ÑpÞWìèµt* vä\0µ²€’æÕPóñ>izC͵{(±·Í¶Ž!Sht¤ŒŸGÐ;Âéú…#m˜yë¸2žÍ‹µ•ÀØ ¬ªÑ90ZD’Ðë¦Î ¹Ä¶fÞ¦Ÿ+ó³bMbŠãK?¼O» @ Ñõåtö4(*tÌOGbÃN<ÓLX‘§0'+×Ý¥²ü“¶6.7˜« ¼`Å7çJøqè¥%P,ÙÒ—ìÁ»×ÉCá¼xÀ²À#ãù*NYÑuç Ü ž»'B;.¨;H}ÐØ!CK¯3™•=ÝlËfë@¯ I.Sð?#µ“†Á„l!+´åŒhh# j¸• ü…ñBÿl$Ü 4¸• ¡¹Ã†ÖX, ÿØØ‘|+è(Sµ>Œ6F"Æ©Ö7pÓ§\²P-‰Ñ#K¤Ö‡*¼¦P‘Åù¬Ö D\.ÐÐ -e »Ôަ½=†å†óA¯önI7ÈBš˜‹ê¡@dBmÙ¹I.lùZ¬ n Õ"ÎÊf;¦àraå `4Âj5€´Ä»WØx¤ÍŽ¥è0w×)ˆltbÙÖÆï“ßœg”k–5ys¯R.áÕVI$?k%ŠŸµô¥Í˜8ÛÓ·ªa%Hî¡N_ Æ”A-B $A@‘vQÈ{çR1Ö3ÚŒŒü¸Ï™Á²CŒ³Ç}+Åì4QÑ$RÌBM&Õ¨¡u±lŠõ fž„ejrTeÕ„ÊYÓ–“p‚.yÉ›àìEŽOs'A¯]÷y/™PNjÑC •Vx¶ÿ>õþ~‘cèf~1Q…—….6ÿ­ø¢CƒòkÐÀ›ÇÖàËËMl“ÜÄBÆr0)+0%+„o¾•âc„ãˆòyŽî=ìýpš€Cí⑟üéÄöu*ÀK%¶ÿ)ÿ)÷!) ÿÿxœ…\ @SGúŸ™÷òrr‡€\†¢"F ©  —ˆxá]ŠxÑRÄ›ªÕZµVYk­µ–"âQ«õÀ£J]ku]{¹nµZÛí¶®E2ügÞ mûßu©~™ùæ;~ß1ß @ÀØq刚”À×á¡7b¼ÅcœÞZ|ã41Ö Ik„‘Ѷ½Ž3…„ÂŒ†½P庘7.&±05v8<δµíË(‰:ºx ÿCà3fSɯ+ÞM3 ˆ³µFŲy!ö•-ɨhË«)¢f×OHE_Âgmˆìä³þ ؾ X¥òÓ«Y‰\¼ÕÞj™AËp2 Y/Φ‰‰±Zm6›šÿ?}ÑŒbºƒ‰¾ìF­‘¼lŒ¾ÄЦ5±ò,¨Tâ« ›?Zx ¼M }³ð#´,l\ؾðÀÂvEûí¶Ì6fþv/.„õôµí…{p.}íÅß r²¡+ÙdNC¸4ƒ0ïÑ;”šä³7¦e9GO9'íd8½Ö᪠MsúhÕ¦¶¾ªÖîwšµÁFøÖqJh²‡Z¢‚ AÛFEFÇA›ØÇ µ0AÆ’¿±0 ¨×˜?þ=¼6¼eeú¥ü¬íµ?|l®5íZš½|vÆÒòA¸({r™Âéœ ìÿDwíš÷°«}!X=èò7/ªÿò†*áh‚¯µå<‹¿ñ*N›Ü%z¤÷!bk;îsI¢KÀ ø@ÐØÅ¡ ŠâTQäO@  q¯þZ^øqq¼øÕDì„ûÊ™-‚riÐ!j'Q‘j4fh‚Ú?ýW¤±çDeDŽ|jNsÙó/–¬¨ªA§Ÿ9ÃÆÊ#ÇÇŒ‰Ì¡ÿ2¯ª¦ôàüª"Ó¢¯§Ö>woJõ²¸uëŽM{ eó–ê6jDæ²[3——ß™V]µ _ÚúꆷaßM›‰ž:î‹rE­@t` ˆtŠ|MJÖØKѧ¦ £œ¬Õk”Óê¶{Áö5†5yÑÃqDê”ùPm‡ô0>æÈh;9…Û/ÄÚh» ‰µF‹’Ó¡ûã c7NOÆ×ÒÖ¤àG5çâ]o_ÌùæèÎ#/ß›•|wÞ‘V|¯°ô“çO\ifæÌÊUž˜0âñ²zeJmvö¬?/~åŦÏêW.û(›{ÿ|ß­Îq@ê_ˆåýKÚˆ¨oµ žÅ{•àPÄ— HÇÇ¡“ÙA©…Æ  Ui  ¨UZJÿ t\ÅŠ²Ã¡ŽGàÄõ×|ÿ EäóSðqdužµH„ÏC‚&òyƦAÖ‡_…?“˜|¼Ïu ÿŠz¡àèÿKö?…²Ùj.(Ÿœ¸ù4‹ÍZ±´@³]¤eJžƒåxý¾Ö)·ê¡×€ÅfÑ/x½¡5¿2–á /AYÉ™FXø3•CÀ²{‰jK!‚™N¹‹,nŒ2ƒ4êjü ×ÀÅMp!®mBM°W7á•tŽ­øÌ$ï±X [f›¢µ0]R¹¶qú„Ü~ã”{Zá ”‰Vy{5Aê$CæwÜgS‰={ƒÀà{)Òœ^bVŸædýÜÆË«ˆ5… (•¦õÀƒµEDk¢Tlê|çèé“{ ¡ùýÓxîÄ=3ÒsKÞ˜Äü‚?ÆÁ¿‚Žû0þó὿ÆsN×m¾7_ƒrz¶Ÿ M¼-¨šÅ,”rÐð0p€ÑD¬Ÿ —ÚP僢cÒß/…íç˜)›Ø­åûàPrưq[üA C©–¥9ÕbÔÂéNºP˜ZbxÞû@;ŒEÄÕL!œØ yÉ) êL]û„^ð‹†ÊA“r“VM.[ðeù¡ÏÓ÷^ÀÑì&¸çõ—'›4dôΉcí˜yìÌÛø‘[ÁDftïÞ Üa` ¾¾†ÑN__¯ÐÐà4g¨ØKMDØ)<ž+ÿ‹Çd±>ˆx;GÄI™È0*Òh²ó¿=8dãÎí«Z½w4|³3ëRák øûséî+“r“7åL[pmááÙe;> ûî^\såÙÑ_ Œª«¼qxSåè<Ûà]câßãuÛÑNd” :Fd¬}(ÒˆÒœR¥&Xƒ24P£a”bŽ¡b'‘ÏZPÐiô4ÔíD8#Q„‰CÖp1ñöp×3cÂ/â1‰ÁÃ%¶,À†â3ph 1«dµâßÙ%˜×m‘OsC: í@ìãã—îôáÄò4§ø)á-ysæ…âÓ) ±EK#o4*>ôÅüˉÏ×¾ùî;§Ÿ_2á…œ èb8æJ ˜ÕWšwýR3úzÉžÓ«L‰èìUü²F°ë9„‡YDG~‚–¼ *UÏÑN•Ê c‰ =Òœ†?Ô’6²$vN¥)06Á×ø #â#Ž)DÁt>s^…æ³åÙaɳZñ£x®òâöwW~ÿêé«ð/cžOl´9‡B“à‰V¸lð;íƒ]ø·}çÞ©Çß×ýÔâþ)BŸQ0lörÁ¦*‰®¶™q4s¾"‚Ã(Äû.[8ÀIò!†•ègWa³Ûè’±w[÷¶O"žžJÎ[HüØLÀJ´­ã4¾¾}ûzЋÈ_ì4Úéýäqm¼³ ¢S«äCM”ÊÌ' Z>* ÊÐÒ€å#D,tãà_w¼µ`úâ¾vé6œ›7'lZ>RÙê‰= žM/«,µ6n~ñLBú»Ï.<9ýÂ^ا6ióøƒ7Ú¯E¯ŸV0wéÔ¼ôÖÜü±3-aÏO“׉Av^W¡TW •Ae¤ºx-‰yý‰GÉ`—ÙhMžyBˆÇXûsàßÖÌXXvüþ`nÞ‡oZþã¶[ñÄ̪Äüœòú"¦­໵=¯„=„²—m‡²ºûî)š>ûø†™Ëx›¢xÜÆ–<6P¬d¤cœŒJ¯ãÔûta¥Öœ÷­¨'¦% Ý߉ØL…ìÑSF´مݨc;‰%tŽø¬Þ!eœL5Æ)SñX{|ÜZüŸÈ¡i˜i˜0uFç&|¼ùöDçÜ{ð6Vn²þì}>N“±ž#‹Á(¨—BÖ¿=‡ÙëŽÞ„Â;gð^|•?s9<À2?ó¹w°CÍŠ2,„ Ó©„ð%HÞà œ©ÎѳGõ¼Ê™½t9&îàA<§©éw{sÂÞZ)Ý–¡fW ý¬‡V˜sû.Ä™üÞõ·™3¼]˜Ù¡“,Ĥ2Žqš|TÄ$Tì&¡¡ö íÝhß™LQ¸÷”«™±xÆhó¸1iÒÓ¯\zûlÕÞiùJ|J¯85a(<^ónnZƘI9vsü·_[p¦"eþ8\Ï ³d8å­¤#‰Û'jƒ@"èçЉe1juï(VÖ#.N& 7F1½ÃIÁ#«æ´jú†gQÀ‹‡±’ $öî„¶—)„Ez°EØõ„¤v¬FäÎzIÊí«øüÅâérnrÃâšÚ×EŽKÉŸ4:ùù¸ãÞçxßIè÷øÂ¿nÜûŸ{ëWxª/À^Û\¶ìõ™s3+ú8¢˜ô|cO~Êž×Ö¼á&™*/x6<¿æo‹þùãyüò׫þ™½-÷M8è*IO›Û6á;ógšúÚK/ÿ$ÔUµ¯ÒEGˆU(@‡·¦: VÌh¼XÆ]LñÈNj'h$Õ âHÝ6û_ÅŒjö|ÓÛË>~?ÜŒKEGڒѸóÝÈÕ{qàñ,‰¬‰à¡’øZOŠ \O‚à£*(”JCªSÉ(|É–š?DAí|¨eû@¨åQ 27²/o½óêÌ ü)þ“}~õ–¯Ýújã› ž» jÞ»{Ãé IÀ+3¯?"Ùïî…sö?¾±bIñTjǵ$ÿ7›ô¥ %É›–•‹Srmw¶Ô™ñú#™­†&ý!³}ëÏëߨµöxÓéGø»k°èÛëû ãÖ±¸¿}¹édbë0ØÊ! OÜÉ?2@ˆcD¢`")ÐÒ9Mª“cDÚT§HóD~FŽiì `D/pBQðüÆxñ±yP {µŸ}JÖ6ìÝp‹©ÄÿÆ3ÿ.jÆ_¶G퇃.9õø=•y5ÙË‹ÆmNJvâ B¢T'b Œ¤©š§ã6Ý”ÄhþŤ·?‚QŒ$Ìu; >ìƒ%EÈ_ÔÜŠË/áAîµ—ñç ùš°6‚añ®î@Mþ:—„¶Èz\˜ë»"’c9]ì™K:È':äó‹ÀT’_ˆär"9+ò#’Ñþ.¿0’J×ÔÓ­ >´³n%iŒ׿~ö"~Œ¿n…?ι<5÷ÀÎojÜ=«4ßcü\={›a/è%°ùç>/eÂïµ>n„en¹‰Vór#ž aR‰HÆ1P¤ñð#ß© Y•Qkc³¬q}´šœï‡*]õÚèšE,mÊîõÐ4wþ äï6hƒIÐ~_¤é;¥Ã'ð4TFèä@}˜TSD–$øóG8€ ±ØéñȧpË´QÖð‹Q0ì¾Òÿ;<ÍMTÛ–{ýJ'ÿSøuHÄ‘ 'y¡jfÄ<ëvh„lnkßTNye-$é½k ª+q}FøÝƒ\“@瘅dMáœh:y£G1Š“È ø!ò'åÈcC+ýL"Ümò-ðwÈÕI9/1eEà…öˆ91*dHkDµeœ´ÿ‘ÄØ‡ÍâP!ÌÁWn5[¬œ«’=1ÿËöÍdj¶²-…™vlûãa/ÑM²—šž™ñ’¨¤ ”ÔW,\¿Ïr^ÔÜžH¢­ëÓócÇ35í9ISæí:Äì%{#¾˜ÌãªYά¡ÇgKæhŠ`FƦ%¨ Û’†ÁóØÅbüÒ)‚«™•´—Ñ^1õ…Tž_ Ä´¯@1Ä )¤þ¥‚kwbA4 _ÙÒ•ubÝEkÛHúm"3ÆfŽå¬I¸ªDÝÖzscÃêo‚F¥…S2)GK_ÚØÞL6>°â“›Ë™‘íGß:žs#ŒI§ý—õälAVJð”}O ª)œª:À‡8ÿ¥´=l$µ¢Ìue¸„š\ÿ$xúŒ *#Àû³Š€*3¢.Iéb&-cCI°|~ý³*üÌø¡×Úç¸n >ÌZÂÓubõ|ü%v)fE,‰“ ’@‰;®óÖ 4hË„¯4DOYF&Óµ/ŒYfjßjö²qWö?>CÖ»3*Þ®‡H±ÊA >k ¶“`7âLX Xnâ«7ñq®­¡m*9ÇM✵O÷¦ IáþW¯wv¦`Ç<|mu¯Olˆ;×Û ÉNö(½Þ´À¸gm½ÚðÇËÉŒüXè©3M"X¬BÞ­%,‘]̨¨ ªŽÇéÈy£=5ºx%’ý6v$¾$ïAÚ¤'±Qyû• f >¾@È^g6sF¢Y#·””>=hÒÔZ¢l>fóKñËC~µŽc¯Ç½7L¿uC…ªØ)$øõ‡ÎK Är¥¸G’S¬Rê6É Üµ#ÿCÍÛ‡¨«Š5Øì6ÆD,Õ"À£IKX·v÷ê_6L\c‘Å6ÝoÖs;¦gî˜R˜:nsîÝ¥#Á¢Ö¼ñ;h8{bd·æÌØŠÿ»nÊdÊ•ð“ÁéÈ®&ÊK|N 8½ÊDRkÔÍÏS?Õ)É¢¨¸;"Œ'r£„âµ½eŽF˜ro„w„R’»9{}ýêŸåcê'Œ÷r¶.7{;§ÃãÞ·Î¥ù#üÚæØNüxMьנ¸î"Õ‘ÓJdÅW×b9•ÐxpÔ)™ÎîŒ{w’gö³Ûeoí®IZ4i󅹓R–ůÑ}ÚrŽ=9ôHnýv΂~=ÏŒ]:¹Id@âèïðe¼Ä\@ÙI%•%;¥z…>É©ðC·j`„€…–Ú Iè—Ei=•ƒætJ¼}Sïâæ#ZqÎîüºúºŸä™»&ŽwŽ{9‡Ò¸aœòÛý†ÒÜKÇZaÉÙöÄÝPR›7{+þeõ¥.þ˜6")ÑÉpßd®dj5HvªU²ÀN™Ïï2\Rï q„éÑk4‰;e¤€hKÑ[æÀãŸ:¾h¹¹ Jwï:ˆâËahÞÜäu‹v1û×Î(¶Å´?óåùspܱõ5Í­Ás–„ö¿Ÿ™ïscs€ &‘¾ÃG©Kr*ÄßË××?Ùé«""?ÿN¾)yy1B„³kMq¨;º)¡Ml"Ö”š;ر<ìúAýi}¿C{ÊŠ†¦Ä룹m¾ýUïf¬3œÐµ2¸45ÿÜ›a ÙÅÙo}ÐHRËŽZ¬c+ˆŒ, ădGoÿÞ½Äb†¤8ÙžRFlî-î-Ö›-(ÙiQš£F:Í*}ÿ‘N½¿‡Vù8ìkµÒk™0wóS ….…³`È—F*RázÆ}Gc€Ý%‹¶³×Dëw¶"øÃ€"{ωRÕ°‚¿¿ôÕê­©%µ¿^ÌÈÀ©sÌyö/GrçÕÄGHˆŸÅf®4>3úÔ-IoGh€DåS½èì盫§nŽ Ï>Ù:æí³?é¨)MO›9ÙöŒœiI«="-}Řuô.àz ±å À¡PÉt:¢Ê ™žfœ;·1j£iç’òx*·‹tbfÙÜ3áÅ÷‰ïÆø÷×J²Þ*X±Þ°íÌ5×¶]ÇáÄoÛ–¼9ª´pÛK©Å®2ÞFɾ([ÔFbœ˜=¤ÁŒ•A˜9Ló:ó.óó#‰ã ¥7á"ÎZ0¥ggÌD\(%}DTBF|T’õþý{¢âĬ¨è™‘mŸ³™á6¬ã×—“J{€£§C© VYU£UTuª×UWT_©¤ F%yÂî¬ (&w_üxî;Ø[Tµ²wñÃЃ°OêˆèxÂA"oiÇØ3‡ö‰ÓNlÂ] ‘o-‘¯ø9¼‘·ˆc%R”¬D¯š¿Ð3’,”Hˆ¸!SU8špÛÕiT¨µM,›‰ý]áEx%§s­m}^X•µi,DêùXh¤±Óï{ò1ò/< w€Øy(í€1½€ÁÛ¨×P°â€*DI>!Än›­  ºTkêÖºÇ;ÉwË?B$£NN­Yí³æ^váÌ÷Ã&ß«S—Ï~ŸØÁý#zéËì”{ÏU¼ºÚQî*C;'„.{ÔŠƒÑÎÌðZ| ‡±™­ß€.ù¤þ|©ý)¼4¢J®^d$~ ÕÏ~±‚ßiþŒ-k†ÏuÛ]aÇÖΖtÖU~L’ÓO¥‘‘M»£¤XÜå’ö®b ŠLJq^ÁÆ1“&æ¾”ñÆŽ=~[Ñ[gþNÌXX÷ëê9óWüºò#|è½Û-çaêÑ;|¯ë"Áš rF-‰áeÀÛ› Ÿ7±>±?ð÷ˆá]¹½(Ä"T©TØ/åÈÄš¢»0“ûµ÷ëê×ü[>fçd!X6LÌÁ¹ØãýøðeüÚ9æØë¸­;Ròr <ѼBBh—3JÀRniSúlþ}§¶a'¡KK„ògÑkÞá<Åñþ»£äqbIÖÎÜÕ;7üè±cbÞ˜ì—$|íøí4,ôH=3·µù¯pÊ©öÄz(YY8c~´îR—M0+ o*Z3ˆ¼e@%Ó{QSSÇDðlðA Ë˜ÀØþ¶èKÎYJ#ØÃN‘ßP|{ˉúL§k*HLœGÖ áëªF§óA€Ž‘Øèót]Å=QWA²Ýe•!1ŠûŸœxñÕ×'.>£rêçÍg7§®Y22/aÊôœþ0ë÷‡]ÊÍn9tØê Û²R‡'ÙgM"|ä>Ì¢dàGg”j‡—N¡VëH`Vr€ø¤g¤ó¤„‰ Á×Ô“ÖH$ÚÄ´¿EçÇš ÁT ëõ'–mˆ„ ¾·È;b_p£ºÇcRÐ3³3ïz¡b‚ßUß±+ÄYhosí# î{}UJs”ýøYc!Á°B²½«õ&¦*«T~¹Åz¡(Swuv,v‚×´&ã…Û¬7½‘”Kƒ>˜ü§Î°þóW*Kº»Ä5˜ì½hüކ"4õ;êûˆë³¢—ŒèEBj8ZnY¨OùK¥ïÊNÊL¦ µè´´‰oåï…£"æ)†Ûi‹C1õ`èznJÈ×þzxŸU‡+®ZÔù ÈݼxHŸ¢ñš$ß%ÏíT…yŧáã÷‡&_Œ7®}Üd¨]^;äHb&¾4³RÍ…ï {z@›õ(!ðgmvs*~&…ÞXi™hS›àϜꑒÊd/©Ù®þC)ÿ=d²w¥'¥H* ÕjÌ¡¿ãßͤÍÍvŒ¢B^Q¡î£…šè,N,ÏÿÂu>q!›K xîw¨ÃdÙé&Qó½¡É—âëŽe•àßX~ Ï€Q³©¹oÚZú=ÓûõS4˜ c¦»v(”£ÑÈ3d’˜m¥×xa@å{–ï†f¢øBào (bÁÛ¢!%›³ò“rFT>3ucÜ¢´Ôñ¨)vðÉ™¾– ¿ØgNÌ1{øøt ¯F2¶Ÿ»38dx cwîKC~ìŽ`‘F÷ÑÍ{ðd/ÌœXœ?Õ´s¢ìŒ’¸!™%t†œ!X3Pt‰äúÄÞPPoš3úIårõh§\ƸV!íhòf‘ÉNqVÓ5dÖ€é¡Ä(a{ø‹kªno4m7??qxåÄIõN¾H«Ù©û,äâŽ0á¼ÏîÝòð£Quëæ,ëyz¸ˆ÷1:çq„ð:ü¼ tÔBâë«@”æb­R£Lwj|»ÂÕ¶;™@_Loè% ùe' šì6¢w&çøîœº²£}c`Zn0ê'ŒEáí‘¡"Lg{µ ý—èRöá”Vüýþ-ÅËû^9þÝîý0ìèi!þ®… ÖÝB0ÍB¼ß[*Wi =H¬7‹Õv6ÂÀØ-v >vƒ˜¦;±…Æ&±Åjï,HTº:tYEÕ”é3'U-\6thUEÕ„¹ ÆW•W Ý[™Ÿ÷ yù•èÚì „fhܲòe“f>;¡²¢jðàÊŠÊ só–<_P°d)ÕY)‘Uñ0Ôa”)”Š §XÉi´š '´z¥6X‹”Z¥VõœÜ=÷cµü"– 7)+>L‘?&»‘ÿCàe†G®¶ë&ü€ ¢ÿuÓ†4BuþÉtíüÚqrI¶½¼í—_ÈôˆÊÉÃÅ@{˜aV È[+IÈÖ‚O«Ý~M=»ý_xxû?[:~f~áL D²_= ×Ùzôá‚%ÅH§÷é öýnw…ûþ°3ÞÓ‰±»¬óH „Nk¨¿aýêhãÖÄØÚ´ì‰#çVULŸ9åá•ãU[Þ|î¹ô)/̇ùÃÇTÅŽš„ÚWô,‰_õFúŽÀ°áC†E ª+Êß14µüµ†aïŒ6rÀ:ߣ4vèø˜^³† qR9ì!Ö ºÏÏÈ*½”X ?ÂêQž˜=o©÷%Å ˆñŒ5Vu¾• IµˆO±ÚÜ¿…»ÒêŽû\1ñ=0ƒ(`uø‹¼”^Á^¯{1@ Ô*5òR{©C"z°}C´Ýƒ®j[0kÉéU]àÓ™+A>]f5$%dé-´]§amüí"âo¨™úy•¬/ô+_Üòé­ó«–&–¶×^€…‡—Zðî¯àú3‹÷À^o¿Íõ»ñÍwöâ{YÙ–møZOíÛ?ýÛo íø*ýÌ9üúÅóx÷å+0÷Ü^üÕþиç hzç-|ƒ·ƒ b‹Î $ˆªK-«äHØ ? â"âTŸDÄÄœíÌq=òžX¨uíc€?Ï‹â,ó7.–±ECó¦¾"Ž˜0xJæ<Ñù©¹®¬é±öŸ]zóY×±¢×GWœ©©ì0”°æàHÕ!?(I ïá´§h€Z1c~eÀÕµøëW¯Ã#pÙJ|gcÓUwÏÇM¸.¶ Ø8ïÂõ©ð@çÜ!FïÇš‰æ™NTô Ä%ŒQlàA—æú VÐŠŽŽÎ¹AIè%<Û¥w%‘A?¢y›#ÐÜGÙ'¸Šê úªú"KxŸ¾}û„3ò–ÕÉݺ7Ý[mÚ×þ=›émˆ‰1Q–zv]UÿOU3æ»va^#ô†cpVrVnÞØdtã¨[:öù^$ÅŽßgfã©Éq#Q\›ÃéX3wìéÞ,ÓÞ^faê8Ý¢£ãÌ`&È‚ö äUR¦SGÝ>Õz‚îñÓ+V|øáŠœ­9[¦¥$O›:2e»lÅéÓ+V~³9'iÚ´¤”iS…@gDÏð½Ž^¤ÖòÎtÊÜâ*ç"ÊTÁ<›;=57J‡b&¥0*ÑE’ÛkËTÁÈ×öÔS…žºÝìkñ˜aT’änŸkwôž3Ê4h@^IFâ¦Â²•ÖÉóÀ2”RûÕ„ÌäÐþ‘‹£í & Ÿ3;ö‹¦¡~Úýõaôz¥O°âøøÈŒÁJ™±óÒšœHóÄÔb7|†Aaf‘òCÅ˨fMKO9¿oÕÜ%‹r'm˜PàœQž_”¸äçW±rç÷`5Š˶z}DÊðy5‰ñ%ñ sçðy^;{¹íî©3K%îžz´ÝHj&± ¶O\ %ѱýyæmÂÉHšÐz|#É…{мO#—‰ J™^ÉtW½qî´ºo¤º¡³,g88%!nÞ©ð)ßÝ;â#µ}üL«D”@êñ{kµÐŸüøSxýñs&YOs±®â,"¿ý¸mâtÄ´‡%È(€vúÐË5ýé*Úfd›V_;öo—ÿ~ Çíܔ߶26MÛcÈbâÏ›Q <ԪĦ˅»ÿŽD¬÷É; %ðV9¼É*•RÂø+IÌä/+©Óvé‚F2»Mïï^父\™4¼xCD²?*]¤¬Uõ“î-òËêòS(5ó3·ŠCR¦'G’;TJ6Ú "µ—Ø‚tõÇNNR÷ÖÇT¦‰šÛ_†­£Wéúg,£~°›à°„à°7‰a:‡L X‹X…A`ÛÙËt] + óóJQ‘Œ$kÇìE«rþ2ãùðÃ1Sç¦Mf›—œ›»¡zÑù9u²w—­}÷ÅUÖÊ@>s…¹Ác­¢‰”7rudkMK,±kEÂ/æ .[ƒ_mºŽ“qÕè·áà5ˆqaLϦâ„3æÁ|X”Š3(vn"c‹¨Ye×ÐFT¡`ñç@-Ÿ¢S®Ã@zAj’EEQZZ¯¹i+Ú£”ö9FAhÅHEILžIh­¢‹”–1Z ø”`öa5ÊY@ÖEÖ%yúM\Ž0›Ëϳ…;|ÅÀO凼??•‰ŸjSñSm!Oôö'PÕ(:¯; î8m§µ·GJ¶ûÍznFš9kLêÆÑ£Z/8¹ôÍ‚"h)Ê4¬`tBªÞ°oìèôŒ#ÆÛCß›ûööçÊå`á¸IñCÒ§$’ós]â2M(è虇u¸`&5!•J ÂÔQnšý4óÁyÆ`x‚¦Æƒ¦ä 4zý4—ÄÉ]4çA™@ãëûM™8¶‹¦äù!õê%En¾Ån:œóŸÅkµ#Hß=³&6ó3eZ0ÄÑSæê”É §eRZ-äD©F˜¯‚ Ïi' êêÎ1÷Ü“ÖÈßsºgŸhÏ@ôSû³qFÀmL=ÓÎA= òbäïJ[•‰çò“nt ꎂÛPµ«’ÚO-ÖÑy2Âw( Wq‹PoWü,/¿Þn=ü›— ôöî”ÍïhæƒJF§ûSš'Ðh4OÑÄvÑ”‚(^Æ2æç’æókõxÂ_ k‰Džk1+5@WÃñí\÷šsUuOÒá‘p.៟/âm{ `Ûgô÷ï:#?#ÄË!B'˜#Ø`àŸÒÌ'¹&OÓiþ@Ó. 4!!OÑ$wќ׳ù)šØ.šRÐâöµ»eÁF̶–äC>8)‹dzÓN;.¾™f—BƒŠ)d_ÄUÂA0¦ ·@ûb|_X„®A{%¾£èž_ £pëb’ÝÍêØ'jâXRÇ‘ªº¿£G 1 „íå£ÖI9–U*‰B•,ÛËc†Š/ûÜOUñ©ð¥µð  _s ÓEª´@¾õ. Vªœ_³l*/ú`iEMM¡ëÆÚ¯_ðEÛ3Nj]3FU¬þêy÷ÕØMÓv®ºÅnš¶ç…uÇðÞ+9©Lb<Þœco??è$‘?'Ãë`[—邾»1ñw4ó¡¿@ô§4- Y  xŠ&¶‹¦4¸}#,ÌÓ_ù™~­!n|˜"¬¥V dî9©aöÎwKõ©No6Õ)õ–zsîA¾Z ãŸ)Älbmºj¶ÄÍL ¶‰·î¹ž)jh©X¸øü|EÔüŸ0|íåYÅüÌ"&¹[3çb@?‡ï@™ ”Ë#G8å 0$ÙèóÄ-²Gaï¾Ñ‹¶ÃΛ#þÑÅ ô»ª^ŒB®LÂfùðä¡‘ñc} 7 íëãWΚ2#9ôιæÉK–LŸoÍÉLwæ)÷I$~Ô÷(ÖNéÇOc?ùîòÎÚ·^oê“•=iÈþ ñ³s2¤$9ʆZ:$!?2>ùÇǺ–TÎüŒg$rNäcϰ£@ð>µ å?¢™ŸËÓôéóÿд¸x‹åiÑÃ.šóž¦oßßÑÜï¢)í¼GG DQ]{mí¢9w¸£ª›†ø#¡áêØ)ü“›ñ ÎalLvÌ!•ªôÊAU“œ=T*Voî+íK4'%é·» êüM½“Ÿ3çôœšp·ˆÝ ¥³ î©ió“Ã.]£ lý—c ¯è$ãv.eÕks–ö“ƽìgÛY²feg–U6½Û¾|ܶ¢´Qã6Ma^Ÿú¶9øýOu+ËJs?>t_Ÿ·£<.åÕÊæÖ!å ²>}bT¼˜7{'n[=½˜‘ì_;£è™H^ŽXGçQˆŒ’„Ø —uÊ—iãõ”,èû éS:ðñ ™?§é×ï)©MË—¨K¦×¥@SúwAO11ݺ¤÷Ⱦü:§Ýqù„¸¬îÄ z'èA3¿c@#—?A#õ iÁ_ 42™' zÌó#ДbÚ¬â²Ú#.g³-æÌ „hG€HüY. €ñSèõæN½^AÓ¬ ]s6]ƒ˜ú,褴ñáQ\Í7'º­&”À¼ÐÕéì3£Ú~y¥Ë2Ú’®oۀ۵ܨ~°±è¥>œlq[rFþêôiùy«SŠEá}ì[’SVU-lÅ­¸æäçgê¡f{ZÒÖ¬[öøAÅùÒ‰ÏÍ=S6mŽ»ßB°±’÷µ1‚¯™yi<å×X;/³LÁ^Bÿhæ'!‚ÿ?4-ÿù# yÀæòü4çÑÙY‡×@Sú#pGðn¿.÷Ù@VxNß8äbo?­·–¬‡>‹JüÖæKƒ¹û‘®¤Úã}9³×u .66~ø3Ï ëü*šš0vŒHŽsŒÚÝo„>¥­c›Ën$‘&d»$¾ôò7³AÝñ}„S©b‰M°>ßùk|!¾GzÄw!¼3¼5ÏF½ìª_Y<}qYÒZˆÞZ15»²$ç¬=.ÇÂ/:_ÇáÔ>èø_qÃÁÕEk§½v¦:³¨¼$ß¼a1!³Éjî­ ÷q}k$òäï\y½äúÝ„,ÎCæOÓÌ/û½=ê,ïèS.í3Sâ¿LœGGÔu]3é¡ÐÓú³Š`a8]ðSÏðs V’ v)‘Üæ›ì´ÙDò&¹)É©–«úŠh8u‡Sþ—ZÓù“[c݃-†§Â(?ñ;/á¨òÌÝqôâ‚£VþpìïAÇžŠG~Tùú»øþØÊÌ›7¼zNÞ^WÁøµã'æÕ½3 ­œ~ $øƒO†èòó›¿kù¦½ûaÞÔMË_2g‰iàa½˜æ¥¿®n4ß›S®z{ÝÌÉhϳ×Ù0ÎÈwq¯¥m’õàï;L„m±‰Þ¾Ú| lØ–ÔqÕÓw¯Zâÿ(t{=®lv¢ßÒÚÞ“.„Ù/˜_¸­ü‰ŸC¡TJƒ¥V)3W ¥zÚÞ½\ 4º[ âH÷9(óË‹¥¥U/L¶¼zˆ5|p”Í:DtlÚâES§.^8="&&b Ý.Ü5'±_°9¢‡ÔŽÄAD^dG¯*]é–JµÇåÏo¦èèìŠIc‹BTÎ6Äd…JŒë¡Ys¾ú°!½# +Øë!}Bìƒ` ©)j¾å~ö¿…Ù‰jù^6ýO›ûÁÿ0&) ¶œ>í¦Wü8°‹¦‚9…òóÑÒFÀ ßÙ µDkè×FTr!ëÇ7,JcNù¤BÙJüíBÿ¯Œ|ÆÊÏKEôë>&ç1pôqRY$æ™aKEÍ>cñª&@G6øóï7àÜßo0sÿýwÒ¯7@”/æ"ÿ³x71ãÕõ]-–h-aÎèf¤Y‡ “®ÅÝÜž€F¬ÓˆòÌœæÞÉzÞ"åÛöq„çFÇÇ‹à#°FPݧâÔØ;‡ª¥ùï6,í>¤ácü#ô»IŸ€­h7+!Ö"yOJ Òúäã¿[Þ\SR¾{ý”yhÿög=»ýÃ2ò™ P‚Šù»$É{´s|¶ë©ëú …{æãF¼>žâõ&ù(ï‰JÞƒ"þ3î^( ÄÏÕBãփ׹0ÎNÅZg‘Ô€AøèqK ;Ôó; ’P ÊŽÓïbf‡Î[ ERÇЉK¤R1â ¦'_Z 6·˜ø‹aþ;â §„è»E–ÃüRx³eáb|%2¤gÂû¨­¡a%ŠqµÞ\f˸!ؠĸë¢K¤¾ë°rN&Þëg8%¾ÊÀà@$¾s}‘èè«5AšÓ(Ö*ÒZÏ'ÀéØî„‚ÂáκóæšÖ ½ù]`¢(“Ým'?4€ú¯?dÖÏ?«x¶F³ŒøÔÂÚ«–½÷·ÖW+å+{¾œGü5çÕŒ)Ñ¥"t`ïÖaÉÛvmri(dÛ·M跲пŸ½)¤9ÒÿÃt xœc`d```”œU±3žßæ+ƒ<œ|{#Fÿcú'¾…½˜™ƒ $ € ›xœc`d`àèý»H2ücúǾ…!…A”\ˆ›Pxœm’?hSQÅÏ»÷Ë5tplRBÉPB†Á¡‹<Þ$’ÉA$H Ä$HèP2d¥db¥ˆ” %Hè$%H ˆC‘RŠd¥CAD‚ƒHÈõÜÿ„Ò?Î}߻߻ïóE1»$(GKú>N"ËHK+¦…F¤†ÛÞ)NTwUÕ>’UòÙ3uÍn« ¤T‚=1ÛfíKÁ~£Æ©j†”È:¹ãö¸ý*aw¸.»÷8Õ›Ø5Ÿ—ž­Ë2@=’£fˆB©ð¾†@=$ùi_ºôOf?rL>¢.Mîsú†=KHÈ"öÙ×’zf‚RµÏÅGO|;T{¦cQŸJ7uÒúRR‹²‹œì#¥{Ô.I#§ú6.Ëü®þkÚ1ý%·fë+בružÍ>;p=Úgÿ6®ªïôã%}†¼¬IÔvôW{O·xþ¢RðÆêÈî9fÞÛc®ßýñ¯A»=ú”ÿRò:f55Ä+‰#úOï]M×yFoÃÚ93:Gû'òÞ"+xM¿›^Ûú¬òÜ6ûÌ:^5³…'zÓŽBß/Á ©Ì"ÌaŽ0‡9˜UæoáwmQ‹.‹yÂ,˜™Œ§ÓÐ÷K0}úÙ›å0Ï,‡ÿð=Ù9\ÄÍX“óÌ,æqY¸Ìœ†YÔ9'9z·*/9 %/ПYï"åm BÊnæõ THYw8ÿ?ÐREdÉ‚g¦ŠŠ˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€,JžrÜð0Z|”¨ÄÚ6tÈFž¾p¢Ðê(vö&rªà4|¤¸Ü  V † Æ ú F ‚ Ê ê  B „ ® Î ö  & B ^ p Š Ò T ¤ ð6ºö&j˜ªú2l¶.r°ê Nx®Ø&8„¼¼æ*vÀ (޼,l–°¸,>lžÒ4r˜¢Ðð"Ndzâô*>Pš¦¸ÊÜð&:†˜ª¼Îàô ~¢´ÈÚ|Ž ²ÄÖèht†˜ª¼ÎàòhzŒž°ÂÔ  j | Ž   ² Ä!!&!8!’""("\"’"¤"¶"Ð"ì##*#T#x#’#¬#Æ#Ü$$|ÖE</\SxœT=G}³ˆ²–êÀeÝÎ~‰uk„tÉgX—ôÎ4³ »3£ž^–À‘ÿ '$Ä$Hü,ÿ'–g–å75½º[öl#ïª{^×T¿ª®z=nD9"4¿ÛðG¸‚w·°…?n#޾ ¸ƒÏ¢7w±ýð®¶â€Ïà›ÖoŸÅ§mðy\o¿xqçfÀˆß|_vÇ_¹î_Æ'ÝWÌ$êœãÊIV5Žð9VöY ¸Cüp£èEÀ]\‹~ x‹çú+à3ø©õuÀgñEû«€ÏãVûû€·qØþ9à 8ìL¾ˆo;ト+Ý2à˸Ñý÷`‘qxŽç0H¡84ך(AKž¨öšÒªð’c„†½€†Ø¡õ>½ úÍÈ£°G츻žµðÈ÷lf½}nR•j¯UR”Kg³©W/Õh0ô8 wÔý¢ÈfFí®,œö¶È¹õù YÈ™£d0'û„ü3æŽG¥ÉÕÎ+u`ævRÌh{ šÑ-áÂë™ås—ûáK9;rõ8>&†Z#T¸‹Qó¦®Ë€äUbòÔ8ÕS› ©&uwa¹w´õ°§T­ŽöXT…¢×IÅ’W±–jO]…ìm„ÜXÇë­â­Â–¼•¹V‘¤Â¬‰ŸÑVàɆb´tB‰×’ωXçLؼªÑ¨•h‰Xê ›õSöÁ‰o*¯TWÕº;.—­”VÞéÔ̵{¦Š'+µéMB§ËþX' ¹QžÎwÐçÿHþ1·­“&24§'¦Þ—wúý£££Xæ„ÄqRÌûÿŸÖ³ì¥؈v2ú6:Š…sÎFýkh¿,Mj*›å”Y<õsúïK'Œt¡éÝâD¹<‰ë.ï2°¦_³ZßS[>ôˆ)QÀû–TìÑBŠë§Fí–:á#¼ÙQ+ÅâÁ?Wæ8x,UÉøv¶–DEË>¯ÃÆxH™åã'Iœ¬ˆ —õgMUÿÁÞøáÁ¸' lÞ”c]â¿.ü‡×üoª…oˆxœmÐWo€áçt¨R{ï½Wí=Jkï½WrŒžúêÔ^± !®ˆuCì1.{žàÚŽQn9?À›<à•À߸9þ׫¸‰’$+"EQ©Š).M %•RZe•S^URYUUS] 5ÕR[uÕS_ 5ÒXM5Ó\ -µ’®µ6Új§½:ꤳ.ºê¦»zê%Co}dÊÒW?ý 0Ð ƒ 1Ô0Ã0Ò(£1Ö8ãM0Ñ$“M1Õ4ÓÍpÜaëmpÍl´Ã6ûu$”`k(Ñ:»ýôËv{mvÓ{?ìwÌo…þ8ä„{î8i¦l;Íò@Ø]÷=ñÐ#}Œß{î©gN™í»]ño/¼4Çg_m1WÄ< ̗뀨…òòÅ,R`±O–Xf©åVZᲃV[eµ¾øæŠ×N;ãwÞ:뜋.¹å¼ nÛ亮†’BÉ)±ÜHzzFfj´ ägGƒpZN4äÇòÂA$$eÅ‚è?zÞmGxœ5‡;NÃ@Eç1Ž£Tcaþ<ó ;†>Q ãØ„ŸyRœH©è)œ¤4Al‚Úã.{HÁ(XKGºGçößZq@ø„q=„ßóKŸ_E.^ŽEûxrfQ÷Xã^GcÓÐhr©‹iä`G¶©œ É 9Þã%çëä#ùJøzqÔÆózÃŽâCr¥C¶Ü¡mdIAïP€ŸB nn#ŒØ#+Ù73,O64`¯Õ]†éª©oSÕºž*X¨n¶qÿf¢Ì…b4™Ž+€—üy¹d/U§ÙX^žªû:,¯²Ù /Š0œóy¸¡vQýÏïÝý/ßG±tomcat-connectors-1.2.50-src/docs/images/fonts/OpenSans400italic.woff0000644000000000000020000005114414655113620023674 0ustar rootbinwOFFRd†pFFTMl\ÚLOS/2ˆ]`¡L¶Žcmapèh²ŒèÜ™cvt PW Àfpgm¨©´~a¶gaspT#glyfd2BI¿ËUhead:¨36ø«Îhhea:Ü!$?þhmtx;XdÝB2kern=# – locaK0®®[°JJmaxpLà ]únameMíEjú postOðyò‚léÕprepQlø T–“ɉo1ÉcHÀÉíØZxœc`fágœÀÀÊÀÁ:‹Õ˜QB3_dHcb```âfccfeabbyÀÀôÞA!(¨Ä †ŽÁÎ Œ kØäÿ‰0´pô2E(00Îɱx°nR@.OT 'xœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@, " þ¿ñä? ÒõgÊÿ×ÿZÿÅý[ñÿ5ƒØ¿= dÕÍÐÈp—aC?CÃL††FF~Ü,æxœuUÏSÛFÞ "SÊ0Õ!«nìÂ`—t’¶@)lmÉØuÓb 3+èA"&czâ”C¦ñ­ŒHÿ—'r19åÚCÿ‡Ú[9&×ô½•M 3Õkß÷~î÷Þ.jûð Ðû{íÝÖÎO?>ú¡ù}£¾]ó½jå;µµùíÆ7ëk«_õå÷W>/—?+îÉOÝ» syûÎÌôÔäDv|l43bqVÀCF "_‹¤/£z¹$ü…®W.ù²‚ˆà'S”õºd"PÄOtA¡å“,Uj©®-¹-6Ø¥þò¤èóƒ–Æõž \™õ#³Î0‚뢇©Šª>Ôžvc?Äy25Y•ÕãÉr‰%“S¸œÂ,ÊÓ„/nr³°ýõÄbÙiJ‹;õ£ì´´ï9®”K ˜‘žQ±ª cU7!Å •ÎÎERz?ïÛì(\Îud'úYÃH„¾ñˆÇ¿C~–¤KÏþ^ÀCIz>,SÔæîužæû”F ¶ñ†Û‘WÿÞF¢2V°ß0Z‚U¾«]zœrÇ5)jqGýw½#)l'¹\|ê#ÝlGcˆþ»—çÔž`‡]¾ ¶^ÛmÂG­C V¡&º"ønIwÕqó×6;ÿ§fH ’ƒ ».ÑpÞWìèµt* vä\0µ²€’æÕPóñ>izC͵{(±·Í¶Ž!Sht¤ŒŸGÐ;Âéú…#m˜yë¸2žÍ‹µ•ÀØ ¬ªÑ90ZD’Ðë¦Î ¹Ä¶fÞ¦Ÿ+ó³bMbŠãK?¼O» @ Ñõåtö4(*tÌOGbÃN<ÓLX‘§0'+×Ý¥²ü“¶6.7˜« ¼`Å7çJøqè¥%P,ÙÒ—ìÁ»×ÉCá¼xÀ²À#ãù*NYÑuç Ü ž»'B;.¨;H}ÐØ!CK¯3™•=ÝlËfë@¯ I.Sð?#µ“†Á„l!+´åŒhh# j¸• ü…ñBÿl$Ü 4¸• ¡¹Ã†ÖX, ÿØØ‘|+è(Sµ>Œ6F"Æ©Ö7pÓ§\²P-‰Ñ#K¤Ö‡*¼¦P‘Åù¬Ö D\.ÐÐ -e »Ôަ½=†å†óA¯önI7ÈBš˜‹ê¡@dBmÙ¹I.lùZ¬ n Õ"ÎÊf;¦àraå `4Âj5€´Ä»WØx¤ÍŽ¥è0w×)ˆltbÙÖÆï“ßœg”k–5ys¯R.áÕVI$?k%ŠŸµô¥Í˜8ÛÓ·ªa%Hî¡N_ Æ”A-B $A@‘vQÈ{çR1Ö3ÚŒŒü¸Ï™Á²CŒ³Ç}+Åì4QÑ$RÌBM&Õ¨¡u±lŠõ fž„ejrTeÕ„ÊYÓ–“p‚.yÉ›àìEŽOs'A¯]÷y/™PNjÑC •Vx¶ÿ>õþ~‘cèf~1Q…—….6ÿ­ø¢CƒòkÐÀ›ÇÖàËËMl“ÜÄBÆr0)+0%+„o¾•âc„ãˆòyŽî=ìýpš€Cí⑟üéÄöu*ÀK%¶ÿ)ÿ)÷!) ÿÿxœ•¼ @”ÕÚ8~λÍÂ0ûÂÃÈ&*Â0Œ¸Àˆì ":ˆˆ,Џ"nˆHd†ˆŠ[fjfFDä‚df–{jV^33óš×¼]o~éµå–2‡ß9ï;,Z}ßÿŸá <óœgßÎó @h÷m*”í P7› EÉZ.g—ëAl(p‹UG‡…•@“Z#£Ìz–3ùR¡èÇ9á5è³qñƒ‡eÄ…[ÙÎÇ7 ™zðhkú$kT|Þ0(p‹ÞKÇaÜ4׎Ñ4ˆ5_Œ i“ƈ¿à—f%SîÛf%³Ž”’|@Þ ;¿×ø³Í ø*•î:•JÈe2èåê*5hhNªÆøb͘F³Ù¬Âÿ÷|CN0ŠŒÎSŒV#ÿe¦ù/ÄÿddÐÛ]¨n¨E—jê£Ç®Ð«ýà /m¨†á5õÕP,ë: ÃòÑ%ºµÕ¢,ØN¾já„ØÒÉW jƒ0½4Hî^Í„qJàÀ 0Üæë+£Cüy¹pœ†“¥Ù=5iv½ÿK£cu ,L¦2‡ªþRCt„Š®åÐd ²ø@³f´DFÅB³HoÑ>ÆàŸàïäP§Õèö[§ÃëÃO.Êz?¥ ¡ú«ƒêƒv.‹]\“·©UÍZ7^<»2!ÞÛ}^ë¦|ø¶ÁðTø¦;?Rí; ³­Š• dë´ÛuYnÔ?*ÕeaÅîEZºï±]ìÌ™ó †ƒ›šñò¢ÂÃ)š£Ü|‡‰¤:w^þ±ÄJxáó¦iB9"Jm‰4h)9Äc‰TóÎ_ÅPø{ôñÉ­LŒqÌÌØÒÑ% ±ÅÙs—·-X¸¨ËWj›9!6p­xÍÄ9ÂOÙÎG©Øl2j[øöJè2cï–Yí/Ü´~/ ßÚDå.ÿ½ªmܦsI{·ÎFŽ}›ùŸ¯ÃÅaÞ|Ù‹Àè µyèÁ*ƒEðÐÁŒo˜Ú¤Ú}³,ÕnÖ^À{‚!ÚM¼ús:­p#¢¬PNaUDFY1'‚‹È)Œ²š9‘ÆijHÝš¹0«¡$æYôúÄÝ Ð§+æ¨G_u\™ñÅ;›Þ=wýx¨¯In)î¼p®bÑ7«[γñ‹æ.*OÊÈ>ÖþØ7îSP‘RZ{sãõ鯯ÛsnG}FeAÖ@´tî{÷ö¡‡{‹²?ø¼Ãû›äE|í¢ài¼— †m‚,t”úùéAš–ØØð¡¥š¥P¥Ô˜¨¬PüʯÔ5C%|†²A zèhA'ÐÛÈ¥Gw>: Æ8¤‡˜fPIAP)i³þüz¼>(«Û@磷¢‡TU Ÿ…ý„i¸J•2µœ'—ƒ'؈héQ€FDà `e5töR¸WŒª:ö–!´ZPƒ–‡°¿¡Zõ+a¨6nF-‹¡×œmïÁug 3fæKÞ!£@‰­ÑbT™UFQe¢´Ö7ÂçÑ’Fªa-\…¯EÕª*šW~´Œþ]CnA÷C(‡w_÷=šöUÛáï`Û}8†œ a¦±ž×¿²“A ݉ÑáC&ÚŠƒXNém§FxGØdÂã›èõ-° Ÿ[½x˜fÀXqŒñ^69å¡rI³«DÐ#ÝNpñ´ãÐ>4Za ½Íäω‚œEPg¤›ºª}á¥é›¦…-š1¶Ùžõáß÷]÷î´‹ÚÛ ÷Li¬^šV¸0:¾|Ûþ—çù|?º(&ç†a™…ãsƒÁ`›vswwK³»»»ú¥ÙE.*,Âáá¸íÆ¿ð¡Y¤óät“?Ÿ#¢0Y¡Ð*|ÓK~þವË~Üó·wòþöìîŽu¾ ¯½°0s[AæÉ;O1«¶_ó“Þ¨®¿°`ÜžpËÎëV5µ¯ÉW¹®è{*“ÎÃòÕÈËi"ÈjØt»D£¡E-H;ŒÏ*ÁÈM|ªƒfÚlŒRkLDDLèÝä=©ŽùÞtÜ©Ïþ…*†Ø&ˆU…Ç0€;è¿u…|#àïUÞŽ&"›L,+€‘§õX;"ƒ«ûNd¢?— oÑ ‘‹¾Ÿ44$ GQÙW7 Gû¯ÞÓúá—ÍuC rROSÛŽ_k&ÒÕ—¼úóâq{¦Ô¶¼ÙÕ-šj{ ¥ˆ ê1-9XO‚¦\ÝX•q¬]¥rcYiš¹y¦ÙÝþ”M¤`ŽÀ9Óähs ä†"ÇF jòç£výâO¡Ïáy)¦øé_ ›ñâï”në¨ÿ®¹ó,lÊk#nYþÐŰåÜM͆õzô%úz\Þé¶WÑ/ÿ´Ï>Vö[ôÔ«wöŒÇ,Ʋã€Þ&e)àFSévš$*2C\†ˆ`; á¾ôROÃ75<º‚==óšýØ×á Âæ©áBLŒ+ä‘f4È\<‘+¶P×?rlèU€¨Ç¨››µ,jdÓôœR¬³ÌGhŸÎ䬛Q5Ön4²n¼¶D¼æþ»¤°Ç~xóí+ xª…ª! ÿ.êj{¡ôùùçÙ¤æ× ß<\ûýºŽ³¨fsçœÙé+ì!•Œôšˆ®­ñß=à ´‰§½º›îLüÇþeÏE—.É©{ ðµ/<ÉñuŽ í8»BÙ¨…ØÙ?XkÈ÷OÅí]™IӞݿé×ÇN.I™bÁöË炟* ³I'UŒ³K•<ò0O{ÓK?Ä=™¦Ð‰×™q¨O{Ðb;[ 2JæÆk°I ŲCc"ÅdD4_ý@ ÔI £ìšIoq訽ðæ&Ôˆ y£e ô¾6W¿Ë2 ŸÇÌaSH.³uÕÐ[»Jè­tNC*X»¸8ÝšáPG÷ÓdôÅå+2‡ÌÈ¿1nTîÇYo®ÛU=Éð?™Iƒ,D¨°yå“‹&ÅL)6ûÖš#Z¶-ýlÑä²ô.ÑbÊ”H¾y݉\ÛkÄÑ` M*’D)ÝFb$Jü'Ô7‚´3§„*ÞÜÃ91dh‚LoÀ<‘94ª»0ù3”N ŒVgòÃÕ’z€1‚Q³þN7õ„\ÓÜ—œVŠçu”×½ðŸ5£«'Ùâéé5©ÝàáwèåÓÐJOß¼þ-:ƒ¶8àèú!Ô®w¤æíÊýþ³‰±ô„ƒèï{Þòü+hÛ€‡]C*ž¿[s‚/ѪïÐCt5»&–ÁÑ…ÇÝ‚îM{jÁ”gàH‘¸ÛÝ€ã˜Ç1®Î¼mrFSìr9ÍÐ"šï¸pâR3ÄíîRL.0º4=)ù€öm?Üšfrc&~ /¡0R®Ps`èÁ·&µãJ‹ÙÿŒ_ ÀD ÖO¡ðKµ+®r¹!Õ.§]ÝRí®ê?~ªž,̘ŒPÓ“‚icÏ7Ü×¾£|)ú¼…CKÐoÛÔ7]~¥‡NlZsíDûOxKý^™ûÅpI¼vÃò’ç¾Ú¼p©`Û›qo Å6éF"‚¤ØµŒ«(Åîªé«¦ˆþˆ¢¬:£xò©†noGÿóêÉ·ÞÍÞ>÷!ºwÝ:½%áEÖ|­¾ñþÍèM¾^0RDê÷2xò`µXœçñ‰œ:ÕÎѬ&ÕΪŸ¨ßB 4ú1@-pÉjÿ†– Ghv²l¨…¾]oŸ‡¯}zöÀ#zzŒæ…Y½Ò%~f\½zãñ|‘{)_÷Ú´œ$ÅÎq¢Ø;ECìoð)“Ê ’üÍчZ¨›~Žó”ÂÛqea;_B¡[ÿê‡[‚-F!ঠZ@Þ;I%ÅaJHµ|>ŽçRJ?Ç}ŒÌñÃK=:ÈÀ:ð&tï\€0..ê» ø§ØÍÓtb3ìq%âl¢!ÐÔ«$ ¦^ØöÕôº~–\¯¸X7vé›è‡mo+ÍG7)äˆNƒFHCWøÞ/Áƒ¶úG\@oû:uÊ-çåæasÓ)v±˜•r4d{ÇmÁç)ß´‹Hþ¾¡‰ãÏ‚æ(+V[ù!Éù lÃçtÀ œÏÀö=ÌÙ§»®cô#¿=D‡ yØg®Õ\qçBz.9o™º~–éì¹zLôkº"Ùº}èðÕn€þñ÷·Ÿ¡›ãûW~[}ªeëÖ¥ÐOhâ]'äP ;î¡O¶ŸG[¿>{ó$œ}ãìÍž˜Á¬â{/ ñ6&Õîâ"âÔ"6DOxÔ#n  1BßÛ¬0«ÐatrÕR¬_˜úå7MýWß6¬{õzä8Îv~àøªs_õ<Â'ÚãäÓ˜l*_¥·RdÀ!ÑÀ(qHT>á†Ê3ü`¤—PÔÇ¿J D¸?)åÙÜñ°þ(:¥Röú÷=¨¾ÎZV?†3¯Ÿ½ùè=ªŸpÖ:ˆ<2Ð6'ÿ«yÔ᡹¤’%¥Ô´,ÅN;eÀ{¦3m!ø©”,ÉU”ÈÙ¡ÀÚZ"<†ÖÝ?riætyËñÏWm¥ò»pôÜ€ö;SùÔq¤ݺsñbSA¸¾5áØülJ_™ŽÖy¥Øu #Ý_ |A‹ËÙÀÞ~(ˆTã}ñ W´>ÐàCÑëÑ÷Ý¥¯&í>°ûØÌ¦-P|µð­©qq{žÍ?ufó l¹|×Û¿u–ç2ªÆ?Ûºðý‡lÔP56~Ô¤¢Å¼­Á2éàs6î= Z„“5¶G"œ¨‰S’Àk%a÷û6¨C¥Fúš*a}·l|e¶éü~ÐÚ$:)ͨúÌ™§’.g°›ÐB1Ž=†­¹hE·ýçßÝ>hýP¿a}Û‡ƒ.²]ÃÑïŽÏOŽ_DÏíª/ͪXõÎyú9SÖ—×›²Ó…ÃÅGBß¼ðÌD›5z¼9ªÞü°ë§ŽÝ­Ó´§× w’yGWÞ©Vì¢ZŒÇ›ÄFáFK¼4RJ×vÆhÁ¡„ÇiЊÌäŒ\ø†¹Û.æÜ“Ñ ö˜V_JÊÙÇÀMB%P’6 ÖuÒ§_Øüz—ºtRÁ®ŸÖÐù]{^ÚòÌ·+éj»·bY_ìÏ&SŒç扸BC“‡Y¢v\A¾G¨ è÷¶ ðý#Ž+T­£†S펋”Ù‘ê” sãc¹G?–— )x%…IC›)wx÷¸£±¬­êÇVêõC× Çm*€^OæEðû›ùÜ‹mRÄPb–I±³4÷Ï逗3™¥ð=¨‘®èZêEow”ùÑ9]EÔ{«™ /7<žGð¡£Ô¡þ;ÄâÂñ¼‘<‹ã: —å¨VÃ:ßÛèÄmt”{ÔøÈˆù¸ƒSæÓs+¨ÁÒ¨º¶íZÏÔ v—bü¥NüØN¨¿›€ŸQu ÚnûÀzôZÖÉÞlüãõn¡BŠ=Žûy CᆃçJÃÛ®&²ç@éúsh0BúꇎœÏkìNæguâguDÔ¼®+>t(:º@*–¹F¯âŒXâýägÐ4YÌz½ªdÔ*¯C¡%̵QGFê^xÃÙçæ3¹8éù ›VÊÈ«ë€G¢(ešD»Lß7:ŽUñv[tƒÙj¦MVgo Ž¢…Xi"'U“».ØeLÍÝzñÁ3 ;Ö> ™öÑ¢ù“KNÏcr §´=>|éΙ¶ÏaÑù.Ï÷`ȦKÚÐׯ-(òÒLS4§Å>ìOhrapnœN¡OÄ}-ðÆ”ý‘&G(Ñ)‡£bïœDÓ?’SÆiÍÒÄj˜Úb¶•L9”߸cõ/~ùg+æÍ,|«D;}R+§}ˆºÛ*çyûzå,}ûúvËÜŠÝ0´å6Ö–ÝŠeÅ×Ô"Y¢]¤š~ÔðT`iôLlzÎÆ |tâË}mu]Ø¢Âùïͬ¯H^³LûåÉaÖæFóKèþ®kƒ=›b:9‰ùÇIðO»È±©HtÀ‹èD®Kì½ÔzB'>÷cÃë9<¡ªæÄD©Ê+c/êlЋ‹÷å5l_÷K`Þdzg¿=“É9örœþû½KÕ%§Ú¿„E'º¼ß‡¦-󾎮¼~›× ῃçߟT´^òD»—‰ÜyI¨ûI¢·¢e{g¸Ï1šDNyÈ!ÖŒ3{Á{‡ÿ¶é×/mCè‚‘YZ[_˜·.rÆ¡¡²ï~JÑ~}ü(´T_Õq1³®yÀÐ ƒLô­£oT•YùY·'ÒÒuœ/¶Þ6½ÌCâ­ÄV¢ÞIv`1Mž}²ê‰´sºgÕ˜b)¡±åõ¥€f‘‰–Ã’„a¶¡éYî·»~jòÚ®à…~¡é£&NñvÿÑýþ´iuúeåÌð1qE¿n×zO«]ó¸óƒvr‡Ö]‹´L:–S0î¸Ç€d[°§ÙŒe%ŠN²3~Zh™Eºà@[’=PL%ÙƒºAIvÝ”’Üë†;rœBMª ƒ ’¸|!ß;… Yï˜ ‹Ú{¦da¸ìàÿÁÏÉL¸3gÒÝ/‡Ü=iõnˆ‹­8ôúý÷Ä7ë^͘>96óþ‘ŒtGêÊg¯Ü¹hÔçdŽ«Œ”•Q1šIžå“ÿám±%#ÄS,×?·âðùæçgn‹ ÉL( õ«~æÄoÚG¿ŒÍ©Y“,Wº/§ÕÏÚ'4gge_ýfŽë!Øž½I®vÑËpÑé±nôJgb&FŒó&ŠŸh u³œîudGS×6ª›íoÖ‹[°ÿª¦O—¼w‹êš A¥TG^ÈÆÊ[;Q§ÍÚ¶³}úÒÒuÏÅ”GFg<Áù²7qÜ”ãH-Q ¨Ã1ýT.ñM¸è›ZÝnùwËb›yÒ˜AÁ‘L2t–”cMÇoGi)oŒC†{}\™è”â'¬‹àrZ)°Øû®Jˆ5¼:Š÷¢_¼'ØÌÙcFòFt‘¹þXÿÖNQzÏI$?Dcy±¼ää&›“K @‹¹¢ÜçS N¼ ¤PS)ù9 ƒÞÿakV+LmM^0˜ £ÜÑ`G%[ŠæqZ´Ïq¯¶?5ã'ù¼,ˆ$ ùV LoÁ¿tÆ­Â6<G ^!Ó¸*€Q¦ â4\¢ÝCƒg*2³ÙI¯½@§ú4f§ò ½:Ä?ì oTǤMعëóß zéÄ·sË–¸ˆ³OÖ4è×µnÔ&¤ŽßQå;‹¨61cÑÍWP“|¡ªdåÂêÅ/¬ŒŸëȧ:JƤ-¼²É@az݉ äÊt„VÍŸØØ¨$äa Ó&e&FHÊ?˜_ÓlhÂçǦ/úûž‚%Å ÕãŠùÎxø€ñf²{ú' "ñYä†=½/#ÀÞ=‰ƒ0²_ZPSuǾY÷ëË}½á7XW=kÎÛSkªJöNa²o>ŠtþãÔ18î *+oÚˆ~µ®itåí¹û Ž/ÑLNO~Ä)[!UH<ÿ?äG9é0ÓQ‘7KZ1k/ÌlÀ™ûøê/þÜ—‹rÝsÍE^º}rßhÇé'ó#–¦‹Ô=t¹®%3˜àãÜñ µ«Ì‡Öé<í:%-I´Óú§û)®ÿµ[POØš„k ŠºyãÜ›/$îNX¾"qáÊÙç_kgÔ°âª)¥IófM­ÛßIØ1pHQFtF|ÊšüßL]í:1aXfìÈìBžßœî{Ôu6xÿUªm2B­Ö%ÙÕ $Ú9}ÿrÚÃMI®ˆƒ@¾9ÂyÑ,".Bl°Úý‹|ªëÕ5mò÷ª ¬Píîת‡WxÔʵU•q¨œ”Œïºj{&6’?¿ ×0yL2®°¼j©›ÂU§ÆòV;OÚHð“ôDÚ±¾ÊŪ'7«›'µ®ô/Úû}ƒ^Vp`êŠ ú L²#ÅÑ´èÛðúãê jcæR{ÈyØÿÕø<á%8Zb#Œ µ¸÷MjYMÂòÍê›W 8öcd/#T5ùTîãÃGŽyÆáKú1VáNK¼5RoO?FŽ‚&…Ðézû1oˆ¿S“&'Ö‘D<ƒnœÝ£sa90¨3€£8¯¹PvqTN^ÆöÊëñé퓚—,;CU8Ú[ò,³¡„šÄÓÑ› †ãyÁ}(£p¡t}}…Îwe¼Œöž„×ï·¶ÃÔ(º«@”…Ò "¸ÝqÇqãýRÍëçV! …;£gïtw˜,%¬>{õ\ÆÂ‚–T©†3•¸™%Oé\‘ŸUaMÇ ÜL@?eMüG(5íj{^·J]\ø¡ÿ6¹÷Ççõëã’쬊“ì$ÙüyGp„¨Ndô¤Ö{;&Qš :»zM×q¬Ot”Ã}VÖ‹‹§Têâ¨UÓ€ìj˜#¢ÃKâí&E𬤰‹# ט¸šép¬S@¾Û×Á#[´Ææ’_e“>Þÿ·Œ¾3sµI^ËK¶¨Ã)Ï £3«"í^Ó55M,‰»V4¦LD.]¢bCÚF$_l _‹y¤¼‘’jqæPÌ®§Ð#šU&Ê»¡Óþ·‹è÷kÇyº=m2/©T« ´†¡2÷PÑCžÙIp(´,X-˜©XÈg,+ô^÷’.\yÉXµV?fÀÞC®å%šd÷å³6«#äã ½ØÎ™•C§\mZ—]‚Žì©^›<ÆUT«¹oŽH¾2ÚßÞˆeYNe2fz®bÔ À­ÑjrYæq1"‚|‰,$7øàD.vüI|‚¹QµëfÛ¦EXkÍEë’—'§åPç"·ÌñðôгnžkôósòÓCÔ2yüζ8D´¿Èuiúvñ vxøÄeל}ŸAñøÄA–ñ£‡FQmo²¡é¹‘QISÌd'Ç“öðÁ6å#“HTcí>niv‰.DÐ]XÛ í±-ÖÄWÄêÞ½³':2•Xú\SÍ?×›–T„Í™‹Û²ç*q[¶ô5íUÿ϶½cÎêZ[$Ák#IwV½!Ø«)†!ö}ûç6öÎúá6wƒ›!Ã.vsSÀ’»mB­H·«ÝzFVÎfÈì,â… #"7便X1&+ŽRtêá­qž»‘x Æ0ý¤Lꊱ+Éó¢%ìcséiì¹ìúqÿƒŽÔ\/Xº­qÈO7j`œFj‘hd”Ì*LS`Ó°”‡A£”IÄ"µ›NÊøêDXͧ">P~Á2M¤5Èj yÇj‘ç’—DAÖ@kO%v'¾6·fÆ‚ŵ¹µ‰‰59µU595ñµM3J6l(™¾Žº\QÀÿ²6§¶¤Lø%¬É¯šÑD`ÈlÔ`™Ýþ £lF©\!k)8µF=ÖNN¡ñÕP B#ƒ:Næ&Œ°2§à´!(T$ñ™Iä܈Äpˆ§áï;~øÞ ]5Âot-zÛ0tÃúñ߷οƚPý®zô+”âšT?áúMJÓ"†ak%άŠS fª2©œnM»ë7äÚõßž9ÅoôÎ×ÈÃÀ`›»»™¬5ÔÄùˆ|$Ù}t"Y’cìMÿ†haÇ ?Йôûr>¹v6xý‹(¬Hò-\ûUŸíûà9ËÆÊé‹Ó—D.™·à»OöU {5½~mñôçà Y¥Å3§ÒÔ¹ÒÄúšñKGŽOO6h\‘mÚÞaI•[ßµÑýÙ¡YCF5ÀñKólƒ–ÇœLx‚çX9}—½ ¤8ÊÊiÛ ¿êÚ×Ðô»æ?7lHƈ Sœ=,l,ù†-2&3<~P°ðBvJºïq¥Øwõ DIq2 VÈ|eP+Õ”L-S{†âzË“éÉqXñSœÛ@Ε‰ÞÚDä§,ŒW‡ŒÉeÕª3©H wfô®êú•+²jãò¢?úÛ7ÇVVŽ,íÚò1Ì;æ|~½qñ3´ûäÌv8¸­|§]Ý׎¾|‡1µo{óÕÐ%^Úûß|þËÈEt˜¼çÚýù'èóŸÁœ3o£Ëo·Ã}ηñvÐJki{×–>$ÒK°=id€ññÀ•.B”_DœêÑXû×91îiÍ1—ðá‚ . »!WÎ¥Œ-|f³~ÔŒ„èèÜjöìŒÇŒŠa©‹Jk®.utì“ðéš|ö$PF·ÐLJ»£Mî*’r€–Ò¬ÊX(ÌñÙ*ç6± FD³ÂË$¸*]m+û6ÀyÙèÎŽ²«T2¬£êpxD7% f´;6 54¿—H»HP ‹ ƒ8ö£…1¬éú™vw܇u8=vw÷ìª9²˜^P`™ lº€Æ2p Œ1 "ób­LÓ»­ŽVõmãjþuhÉŽ*m"¾Ê_ñ7D ÿ§ÂéΩÏÞÞôYYÍ×^A9¹'§NÏ¡®ÿ*g,7¡˜vÑó—£;›ÒcˆlnsZÆÀm}z6KÿÜußHk8ísXWWé<:Ë@†+1ÙA¥TOòìa«&ãâRýƒïÕC+ŸY?áP]]GÙ¬g”geV2Í+㟭8thEæÂŠqY ²ÙŠkF±~mÔÿqe]e,oêÞ'IÉzLÿeR´”ÞJÕ5ÂТFTÝ  ùT*õ+Îy¸nxWªð¥ôzèȇ0O·8×Yz9.éÖ;>3@qùÄà˜93GTošS=sý Ø@¥–~WT81ÌbËÌ).Ë+|µú}Þ¾ª°ÅüŒÏð'^ä¯TªTœ›·¯ gìgø0§ ø ÕÙok±çlѹ»zvõ‚‹rôS§-L1=Ï:g炟12Õô„皇Õ$·®ž••4rTü”Ió§vD‘šNË\£àÓ$doV"ÌÎqfÆ¡Gd¢´ÃŽ~’6“ùyä»ÃuáŸ÷ð½x)®u=H­«–)D…T§÷TP}Ýn¬³l‡Ow:A&¡'7Íö½uþ3_»Ûà&›ÒQ0ß,q1$ï™-ÕPÚ\ùí+ðï_\\’Ÿ±íæ")¹X^gQÓ‰ó—xØ\8±XÎB9b—ƒ0²—EFN%NaRñe”ÙÈt.¸R3á« _ÿ‹Œº¸êßëh³úÑcÈ â·­TÜMç(E@j¨~Æš´à2þN…­VL+Øj?ÁAÓO AV\c]Þ]28Ч=cdqé¨:t¯ RRÄÍ*î\ ¤° 5ñ÷½¸Gãh?.ccyɘÉpÈŠÅD¹WY5ßÝè±ÈÌvvm¤ä3–¸‡ŽËákZKÝÅq–Ìà\;4´«Ô—,.E8[êž%¥ gÊÀFAÝÝ¿µlÕ„-…Ë™^‘žWÁœüðÁÚêŠÓsŸ÷}gí³Ïî_·WÈåPN—ÐÇù8êks-r•:ã(ï¥ý¢¨AÚª ^èT•CÚÊî¢ ´.zì(»ï µYp \FËѼDX "Ð\,ߥ¸JÌb;•Aà2…{Ve Xz¨Dà jºã] 9HS¤r´Xˆ.â0ì ‹a6þ!€À.¤Ú1¬è¥$ €·1ì¿Øs¶â[ö7 àírâ(àÅõy*£~c&ñ;š&›ŠswWšLÞãì&¥R’bWšžâõÈ¡³}•³¡w+“زSîÄï¨õú¢ò©;gägnŒ‹É93±¥ó¹Ï×ÿÈoŽ ‹¢ZVî™’V³qÊt³oíÐÈ7¶-û¼ª`N$‡‘ISÍ<ÂΖ¨\ðôéþ fi¥T² TeqÂŒíS š7·'`†õƒ9 âî ˜&QX/ÌYÿ§xBE½0¥<Ù!šò÷€,ýè¦záÎ`›ªÅýª‚¦î»Á›npžT¸A7 š‚ÿô°î¿×¡#m~R×»T 9 öar¬Z¢æÔ)vކò'o@ÝÈ´*¬ÿ~“ÆM};Nd.À¶8| P*º~šn¥[Ž E”ÒËq¿œŠrÔ4O@ÂFÛK(t³ãŸ8Wïsdòv´iÉÞæ#[§,¡LüÏù½(^žÁN½<æe]]{dõ˜JP-ÀôÉü0§A¢£V?Ð Ó#s úúö“9¿4žÇ5H  p±l\t\?˜ÊîþŒn:¸ÌéîF*}&„§I€)í¶9i2ziÂ:OvîÁ‘™ð`›ÁC$¥Ø dÑJªOµã€âÙo%îÉÎߎÓNð‰ 9¢ÑÞ-¹U›ü67>µ(7¦Qg©s]ŽZ½™ÚÒ·1çèÚŒ¤˜~~‡ˆ·õpÁÖ¡XàÑݽ—G~ˆ—C„ OP"øƒ·÷_ÂTB£ð—0§Á¦ÇezaÂza΂;' ¦|æô½°°>™CÜû†Ó˜*²ÿŒ»8HJ*&·ê$lø™U ("‘û{t¼Úà˜BtÆMC ò©Ëpt!úÚòÑQt,ÚЉ|\ÉUu·±Ãow†àH©ñ5ù `Ýn)vÃ>¹ÂÇ/¯óO¨ð=´Å¹Ä‡»k(l` &2òãvawêãçjç¯.%ËC…;“ëlÁ¯P…P·r.¦Ék·þgs“*Wnë ?ð[DQÑ{sÇ…±dÍhU.½eÊ©œØU–zÎ&~ÁïÀðòæÔã$A×=¦ú'0•8~ð0=.ö'0§ÁÆËë)˜€^˜RpÄé!!ý}•ß áqtƆ Oú½s*‹ßÔ›F¢KµK$œÈ•Iµ»ºrÎ5›'_Ï^˜™6÷ß ËÂÌñúD²ùgÙuå†C¹êê?Ö¬ßK“Õ0tœíìÇ×:÷-ŸË÷5Ý×p“8\K€A6·(]í#“E'ÚeÀg@¢ÝGÿÇ[dAÙ½·ÈÐy‡„ëòDßÉ÷kâ‡À ᆾ•oœQë¢FEŒž`€n¡ÿ8±»càøçN ›m¾vø)æU1e/è†ÄMJˆ™’ã?Ó^õ¼ú1˜Ü;7é§Îeý?>³¶:ºpòÌgâ‡ÅùÏ*óÎÙ¤]!æ…ÅÁ1ì sGZ²“†ÅŽ °¥T¯xt÷ƒv,~σ3bùÇcùs`Ì~ x¤J>ø˜ÊxfàÀÿæôy˜  §aؽ0gÕ‡½Ü Sê¼gGF @–Þ³j{aÎ|-À à„Á>Ša¸IL.ˆí/ÄÙèÜhŽ‘ªFí#G²z«‹ŽPE$Ú=TÊ€Pi(V¥Tßwy)¼ô•ÁyQ&ê¿Dan¨DXbàžXz½ Lãìׂ}xˆç¼>uÉ‹×f-r3Çw饪ft}ÄT×Y—Vìéš5õýªÉc ÷¥ÒW*ކÉÿñK¢v\fÃ¥ç¦iýNÿdÚÔ¶ {_XØy!³®ÙhÞœÖð.¸yÆ’·Ñß÷,(§³?Ø[1oTœPÿ -ÙMÁ²Jò6¬î‘3ÝÁë+YÐûJ^="셹ߦÒÂà ôÌ™~0§?çaBBž‚ù€×©Sú… ¯¨¨>ŽÀwÇs™³‹r¶ª'¦ûú÷ƒ©ì*À¸º>sªÌiô©#•>sœ§G€)E_àÌÙª~9;ÛY€£üiórWè}€˜eh_}p¢]¯Wø*p ¦0öutæ>ƒ® qû£7ø§–œ †‚áXIkÄiú60ÈzÔž¸Ì©•‰±=˜8® ýÞÑyqÕý3_2q)©èá°ðY{§×•ÍÙ5±œn­˜¸af}ùãu´ìÔçïí‚Ú“ÇQª>Ÿ²iöãæ» òÅòÏV,_)ðËdò~7^ð;#/“é =`¼y¹e ö°þ©ŒBfþ_`Nßÿ³xò€±ðô0g¹¿ÀÃëH€)ýpfø>¯]Œiá÷7Üòn%U2ÿäyXÏ3>‘½ ª¾okè­ŽSó,#FFFŽp¾P k×¢/5rxl õ‹ðJf”£º;˜L¦gDž¥V+D 'ñ÷ò6ª´b#\®38!0úþ9ßMy†_ž•á?¯z~ªð‡´Ï~Þ¶¡¨`æœøæŸ7o(-™YƒæÏ~§HEqQk\(ºxÆ[S©ã Öc£«³VÍØ}f싯W;mæ„¶ä¦êÃÐ &GÍà&H ¾Ïßµòº˜$èô%^ïýäü4Le 󄾞†9-BEð4 ¯/¦ÔéQ=Á‚ôLü}#'W8ëÛ§ÎêÙaà´¸¶Àï ¸•ˆ=Un‰v•øþõƒ°èNq½åW°1H*VMß ÷µL ÖHŠ÷Mmxbaú¤’dä!(iw|uÉŸ­2ôðÀó)ðPúüS| ;ð"“,ìÑ(z÷h4f²F„îܱ…°±]A´ÍO©Á ¶ÊdŠ»Œ–z⎡õ)vZ ÕP›bç¹}b ÌÙàõ=bèm󨫦'û°?;ò22{VÑ·>Köå[>_ǃrÊÒµ'!ê×ôr²¶®í]F7ÍŸNÃ¬Ö ëÎ|Ú†ó©ÇÂa`„͇’³²¬•ˆVæ/óÇú‘)½Bج"ö©LŠÕä|À‰hË/¨/‡úœÚêŸ?{÷ìÕªÈÀ€¾ôy=ÌN¸¸ôðW›»^†r{ÚŪ†íè]ôy³´6mMæn5§=ÙÜý竨ÕÕRÿÀ¦½5kÁw'ŽÃŒý·æ,©[üîyœ1ÃM›ÓèØk^nÜGC—eÏ3ì]²phy¹FÿÊqD‘¤]Ȧ¬pËa âD& ûé}!ýëŒè’çgÏY_eØ0y smhcU¢g}mPá qü܈ Âxnpµ¸÷0ÍEá+ “ÄJh‰ŽÌv?™Òo6EòÈ9ê' o,*,®\6µ¸²Äf1Ìlc÷.,/È«X0Íc‰5JxF=“¹Æ„±7° ©;YË %€°S7Îð$C(RRšÔæŠÖLщÁiIcü™õEÃß4.)ÆsÙ£(޹n 5E‡Ô€ÐQ±áùz=UñÇçÿi«?¼²k—FTòg0"y/ÌRú8%柖ÎÏlÐEiÌ”¨–+h«iF×_†2ôÆv¾g«Æð2~wZr€%{ j ƒVµ•bÄÁk'Õ>ŸÀvê'w×ÃÀÿÏÏ5 =ôRžWàÚD´´÷3[ªŒÂ üYœùQÍîÇ¥^*Á¨~I/±¡•®áiU`\2VAè5Ÿ‰è£ØhàhST?Ê©ÁÒ¼Žšè ¯^ôŸ¢ûËa@–ð<-µçÃ[Ÿ‹+Ï‹9¢—[ST¨dê¾Ú5±Næ Ñpä2ÿ…÷¨õô]l{âý𗇦ßúÙæêܼ+ìS¨¶õm¹ ñ{&2j0_¤îä°¢ KÔó¨ëS÷BT\6@uá°¿×Êá=~FªÆ‚¥i²}ïuEá=´h, n+û|€ê²àXXÒxý!w,ÌöyÔƒÇ'^bFõÿ<ˆ\*•ºÉ%ŸËŒ6…«ˆSâQ¢TÒ"ÚÏù¡üêÂgà’]øÌÿ™ Ô¹ÚКPÔl€·ê× 6ç"­=¾˜ã¸ãR”ý*ÜiÅâ|v•=Aš-¤ç.Ÿóòök§½Þ¾Þ”„vóvóV Ýn©]ÓíêþÏ}“%Ý©ySTæþ·Ô¤À!šÿK)ÏóÒo1éÐxœ%Ù»o$gvðÞ@I9˜mÀc›"MK­¨)’Ž4-R-‰lÚÿƒãÍúiÚ»I£_h>Š˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€.L¤ zæú<f†œ®Êà>zÌN¦Ä(~®Úü>Ž :ˆÀö$J’ºÎò  6 n š Ú  Z ˜ ä  6 Z š  â & : V r „ œ æ 2 f ² üFÎ0f–¨:vÂ@ˆÈ"fŽÆî8J”ÆÆð6€Ð:¤Î>|²ÈÐ@R€°â"<z¤®Òò Tj€–äö,@Z¤°ÂÔæú 0D¢´ÆØêþ*†˜ª¼Ðâ¢´ÆØêü€Œž°ÂÔæø ‚”¦¸ÊÜî ~ ¢ ´ Æ Ø!(!:!L!¤""<"n"œ"®"À"Ø"ò##.#V#z#”#²#Ò#è$$€ÖD9/\KxœT=oA};_Ê„BÛ !ŸíT)V%A¡¡ÙÜmΛœï¬½µ"§EÊï  I?‚AK àgÐñn½&v(ðiwߎgÞÌÍ<À½à >Oa=0‹O` ß<®àaP󸊛AÏãIÌo=žÂà‹ÇÓx1ñÆãÜ®Àã9ܯìz<°òÉã„ÕW/âqõ;3ÕYÞŒË^â·ðÁã Fö¸‚çøéq"Øóxwƒ3§ð xïñ4Þ?<žÁ£‰¯ÏáIåŽÇóx]I=^ þåñ"^Vϰ„ËrB!†à’¼K¢9ºè³òÒ«M«À9×2hrÕ•xœmÐWo€áçt¨R{ï½Wí=Jkï½WrŒžúêÔ^± !®ˆuCì1.{žàÚŽQn9?À›<à•À߸9þ׫¸‰’$+"EQ©Š).M %•RZe•S^URYUUS] 5ÕR[uÕS_ 5ÒXM5Ó\ -µ’®µ6Új§½:ꤳ.ºê¦»zê%Co}dÊÒW?ý 0Ð ƒ 1Ô0Ã0Ò(£1Ö8ãM0Ñ$“M1Õ4ÓÍpÜaëmpÍl´Ã6ûu$”`k(Ñ:»ýôËv{mvÓ{?ìwÌo…þ8ä„{î8i¦l;Íò@Ø]÷=ñÐ#}Œß{î©gN™í»]ño/¼4Çg_m1WÄ< ̗뀨…òòÅ,R`±O–Xf©åVZᲃV[eµ¾øæŠ×N;ãwÞ:뜋.¹å¼ nÛ亮†’BÉ)±ÜHzzFfj´ ägGƒpZN4äÇòÂA$$eÅ‚è?zÞmGxœM‹»NÃ@Ew¼N¢Tcˆ°ˆÀópšíXúD)L‚x˜‘âDJEOaSCƒ”&ˆ–¯ðºË_ð!|‚q¨8ÅÕ=ºº£ÏîÑ$âB¦‰d ÃaX†òÚ èÊh2ILƒsc}Êý^M·¦¶¬érªiÚl=½Ë-ìêæ-åP–R^$}úNàäXÓ¡>`_ïñ {ñÂ/tktÚ-øI¼ˆRü×ðêC 6ðQ=¤J™M§¾7¶{»°°²qºÍÑÝܶWVð|1«Þ³·õZŒcÏÒ™‚ÌØÇ¦xAå‹q–çJ-óâYm)T^¨ÿüéþòMº@Ðtomcat-connectors-1.2.50-src/docs/images/fonts/OpenSans400.woff0000644000000000000020000005270414655113620022511 0ustar rootbinwOFFUÄŽŒFFTMl\¬yOS/2ˆ]`¡=¿cmapèh²ŒèÜ™cvt PY¢M¤fpgm¬©´~a¶gaspX#glyfh5¿QT¬Á­µhead>(36ù6Úhhea>\$·úhmtx>|X˜wWkern@Œ# – locaN ®®v—cLmaxpPP ]JnamePpã ÞˆrÂpostSTxò‚xéÕprepTÌø C·–¤ɉo1É51‹ÉíØ`xœc`fñcœÀÀÊÀÁ:‹Õ˜QB3_dHcüÈÁÄÄÍÆÆÌÊÂÄÄò€é½ƒB4ƒ3:;3Ö°ÉÿaháèeŠP``œ’cñ`ݤ€\¯·Ÿxœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@, " þ¿ñä? Ô%ügÊÿ·ÿZÿ¿ú·("ñoY€Bu342Üe˜ÁÐÏÐÇ0“¡ƒ¡‘‘Ÿ¡ M=ÿxœuUÏSÛFÞ "SÊ0Õ!«nìÂ`—t’¶@)lmÉØuÓb 3+èA"&czâ”C¦ñ­ŒHÿ—'r19åÚCÿ‡Ú[9&×ô½•M 3Õkß÷~î÷Þ.jûð Ðû{íÝÖÎO?>ú¡ù}£¾]ó½jå;µµùíÆ7ëk«_õå÷W>/—?+îÉOÝ» syûÎÌôÔäDv|l43bqVÀCF "_‹¤/£z¹$ü…®W.ù²‚ˆà'S”õºd"PÄOtA¡å“,Uj©®-¹-6Ø¥þò¤èóƒ–Æõž \™õ#³Î0‚뢇©Šª>Ôžvc?Äy25Y•ÕãÉr‰%“S¸œÂ,ÊÓ„/nr³°ýõÄbÙiJ‹;õ£ì´´ï9®”K ˜‘žQ±ª cU7!Å •ÎÎERz?ïÛì(\Îud'úYÃH„¾ñˆÇ¿C~–¤KÏþ^ÀCIz>,SÔæîužæû”F ¶ñ†Û‘WÿÞF¢2V°ß0Z‚U¾«]zœrÇ5)jqGýw½#)l'¹\|ê#ÝlGcˆþ»—çÔž`‡]¾ ¶^ÛmÂG­C V¡&º"ønIwÕqó×6;ÿ§fH ’ƒ ».ÑpÞWìèµt* vä\0µ²€’æÕPóñ>izC͵{(±·Í¶Ž!Sht¤ŒŸGÐ;Âéú…#m˜yë¸2žÍ‹µ•ÀØ ¬ªÑ90ZD’Ðë¦Î ¹Ä¶fÞ¦Ÿ+ó³bMbŠãK?¼O» @ Ñõåtö4(*tÌOGbÃN<ÓLX‘§0'+×Ý¥²ü“¶6.7˜« ¼`Å7çJøqè¥%P,ÙÒ—ìÁ»×ÉCá¼xÀ²À#ãù*NYÑuç Ü ž»'B;.¨;H}ÐØ!CK¯3™•=ÝlËfë@¯ I.Sð?#µ“†Á„l!+´åŒhh# j¸• ü…ñBÿl$Ü 4¸• ¡¹Ã†ÖX, ÿØØ‘|+è(Sµ>Œ6F"Æ©Ö7pÓ§\²P-‰Ñ#K¤Ö‡*¼¦P‘Åù¬Ö D\.ÐÐ -e »Ôަ½=†å†óA¯önI7ÈBš˜‹ê¡@dBmÙ¹I.lùZ¬ n Õ"ÎÊf;¦àraå `4Âj5€´Ä»WØx¤ÍŽ¥è0w×)ˆltbÙÖÆï“ßœg”k–5ys¯R.áÕVI$?k%ŠŸµô¥Í˜8ÛÓ·ªa%Hî¡N_ Æ”A-B $A@‘vQÈ{çR1Ö3ÚŒŒü¸Ï™Á²CŒ³Ç}+Åì4QÑ$RÌBM&Õ¨¡u±lŠõ fž„ejrTeÕ„ÊYÓ–“p‚.yÉ›àìEŽOs'A¯]÷y/™PNjÑC •Vx¶ÿ>õþ~‘cèf~1Q…—….6ÿ­ø¢CƒòkÐÀ›ÇÖàËËMl“ÜÄBÆr0)+0%+„o¾•âc„ãˆòyŽî=ìýpš€Cí⑟üéÄöu*ÀK%¶ÿ)ÿ)÷!) ÿÿxœ…|`TEúø”W¶÷’Mß,É’ÉfShYZ¡ÅEz“¢ô€ˆˆ€"MZ與†"‡* ""¢"Ç)ÅÃãä8õ< d‡ÿ÷ÞÛM6(÷˲Ù%oÞÌ×Û|óAî]ÇÕü!D‘elT­&g4a¬#:¡_Pç eš-¨0&ËlÁ…fŸÏìËn‹=ÔGs}9»Mð¤¤áâñ¾ _=Ù®(P˜Û ¯á*¿íþK?í‚ãØùŠê v±|I»ƒ“º±ïpfùÒrœ]±¨«þ޳º°‹t!Û;Ÿ•ã}Ò{>®˜‡ëYoé=íÅ@Ñ…÷ª9`AÉ( µFc~¯95ÁÉq6=ïFÈÅ›Õ|›¬T½ ï¤B C†¡w0!#3Þß'ḛ̀ql¼0Î’ñµæHXš}Q¿-XÆÏ瓉 0É&ˆv?%ÍëOÄ>sìÏÍË÷û짘æ5'1>ò°Íá40§ûàðü)w}øJðüËç^™dOîºM[·”ÖŸ½úbÐäQcñÉ%vþãš'iKj>Òyï’…»-‡êùî ÛkYßœasÆ”[±9‰Tì=8/4 AˆGãîÝZóçÙ‘0ÏFÝ-‰×8ZƧ¤´i©ikr|TŸ”©‡WÛl¡mŒ+Õ%ZE8xÉèJh5â§Èˆ/Çlò¤¼,Ø€9–þšçÏM»ïïjìÁ?–>¼k×Ã¥øýk—m^·zÕ\[ZQQVVQQŠÏm\»bãºÕ+^d¬áÓ54“#uu¸—ï®ûææík×oÜn¸ºçÕWþ´çå—÷\¿yûËë7¾£ÉwJA¼á‡¢©÷nñ—øóH 8úÑC¶VJ<™m2[{ i®‡:/ß§ëôYÞÖ†¶|u¥ÑŒŒä,K²º4˜Ì¡¢L¨f9 A,%-n†«Ä NXÁÊš“ Äns¤+Û=ÐmwÂù>"b×€%EßVòÈü1 NÞüˬ×äÁ­6³7–Ö÷ïØâÝ×v]²¯/èêÜÝ­gþý™?Õ\þ·¦ûܽæ=ÜgÄð»[7áÝÝ‚c;WVßYðÞØa#'Öì~eÝăCØìN¯Œb_¯e_˜0ø„°d3p‘l3l‡¥O$[q^±@Š™M„b$zaTÎŽ7Ü£Gñˆ4â F­Wº±(ÊÄXM–|Ÿ¸Zœž4R¾yõÎV­]º}Í&’ÕøÃ}'YÎOß³¼7ëðieÞŽ0¯.2/§™‘Á¨¡œ·ù¼ØDDOžÅŸK¼>‡…è6¯Þ¾tíªvJ³ßX»ÝÇð¹ïž|eËó ó8ƒ`ËÛ6Gy‹zZ«6š8 ÖN¯;¦2 TônN#ß$Jø§:y«¨Å^kj>OɪL¼"–-üuïþíûd‹ðâLÁÆ*'JbG‡â ¬f(.N:4/•Ö‡®séÜ; W-VÄqjž×驨˂ȨÂ*”5$¢úæì™Ùc;fö‘åx ½”Å›–Rçól®{ï…y‹Ø¯ø t©ù Ô`HQ–Ì18Õ)ÈÔÉÇC±#ýsã:ëo;G³_¦Ã9ƒáÞ |…‘©ÀoóA‚xþ”å ßkõ»íø;|eÙn²ÏB?ü1­€N¯¦ý‚j’%\–üˆü‚ÈnèXØ®s—B_× ]»wïÚ¹¸HšÃÎäª,_ÖÃq<¥Äagv[I¯ÉÕеZIžÂ IÐØ{·¸Ö²>:r6 Ò HpÅ¨í½‚j‘{©KÑ¸ÌæRáI!f“Å—cÁòo³ü®õ¿¾õóíŸnÿÒðUÍ®ÚuëjwÕ/X{ÏÃÓð3x{†­f'ÙØ‹ÛÃ+•]¸ ç j0©Va­ŽS‹"V 8Iv ŒxxyXÝí1çæ°èÅ>rn§ÊžûÉ@¼pgY0ÃÞfï4œ)Ós4øÔT°¥.ˆœ1X´"+˜íØ8“¦WÐ$â˜ÞAiêbÎ0béØ;Åzˆ^…Ü`'ìn.µ¡Ïß?¥`Å3¾4zàû·?üç–ÏØ òýJ¼ðÀ†®¬îÐoêîK–²ï?bgTŠŽ ÚÆ ^Ô5Ð"YEQGŠ^h™N§£WÐéÔ¤¦&ö ¦Šs¯ ¦‰ÒR`"DÁ&;¨Dl·qî°“J6›Ü£½0@Loo}aû’ýwÆÉG‡]Žç°¡/¬ÞóÞšg†×=Q1軟Þâ†.;¨rÔ¯¾ø•§Õ¶¬lœŽ5+×/šøTnñ”½#ÉP‘›ÀžXP‡@¢…W¢)¢<µÚ0oá{ÕFÑb¡¢@yí\}ƒì‘u \ªÏ |ó€õå&\y1THí¿Â–hTm3X>.cûqÙ*úEC:¾±²~xQh¦d/~ ±¨] ÉH]6•ÍI¹ø8ÄBH°Û‹vAÐõ ¿#]Ùr8» yRdŠ©LîÑk•B™<Òú[¬fר/ Š?³ÿV=ìÅùärèpêt:÷ïg®3Öo{k_íVœ“Oönd=HÖ™J€+ øê@-P·€'Ö¬uCX"˜iZªNkHèÔ 6jsö Ú\T1ŠØ ºÂf!ˆb½‘;Çi&ê K'ña΀鉸÷Ã%S;÷õݯ:ݤۧ®ÿöÉuö3þnÅÖÕ«ÕËÖ©ø5¼ÇºÒÅ®²Ó{oð »‹û¿÷ú««jK?v`œ"“À×L ©Q« ó<"`$)é ŠQ¢b0P3 –ÑŽqÚpžÕñ «î\ëq —.㟂ڠ>t§1ÍÖŠ&¨ÕT0ÛŒBV[ÁœžœžÜ+˜ž®CºØ>A yú‘ø{/¼ß+Z’s%$I•#1 VÀcãÁñò¤ä½.Zs †}ñÏœóü“ßÍzeýºÚ-o¯[„ÛÍ]1óÅ•³VñçŽîzü@Ïþ™sèÊùcw—õ=8åÅ7ïÖ>¹hÙS#Ö÷l¦=9zðs]:ZwíIf[¹å…5nX¾†7ÔÚVÆ‚®ú~ä}ƒUÙUÜöÈ®^.}¶xü±2ì²áFËñØs¨B§ÁÚ/h05º”ˆ={ÂhÏb†è>3sN´§¡Y¼Xr8DöU°– lD H“^Ï«Õ6«ÖÔ/¨5ÉŽ²Ù*î’6.Ñä8í³`‘v›ü'ù·´L±âÛß~dÖPsˆÇˆ,LŸRÁjÛÕ˜Ko(¢'~¤†qíH|m[ÎŽH4™…Or.z]ÎÕ2v‘pðGµŠãË‚P•ƒgTÉŠör’‹ÆðžEw6 ¥;é êjöXuµbÛ›ÁÄcp·¢J M0YÕPx56ü@áj\Œ+×1÷H6H‚)îÞuZ29Na Á VM´ZQ¼ó¶D¨…©Eb¿` ‡IÓ3h⚉WsÙ’’”H¸qXà 8Gg²î’‘Kz,œÓ¯fDû7?|ëoïgÆt>Ð˜ÙæU®¯˜>£|ìäÔìÅ£Žíé9yÔ¤Ó†¹ÙåHº ðξW,áë!f/‚¬$ÅÓ&ÏÐ^´Å!”n3´ác ¸Ž*³^™I94-³)á„Ì”4Fê²6x#Ja„ÃIí6YÏI O Gì’]Ì· ždÁF wgÁp=Kè Gn7`¦VÕrÝØšWoè¶·»«êÑikÙ¿ÿ|Ú‡»à¬¿>ñ[Ç&†—at÷;|÷çw.X %ý¬!WVÜZ0î¡GFžßÿºçr° ÇË{bÓš7Ø«_± ìÈ€ª ¼Å®¹v½Îv1\ˆy[½b#à‡7ñÇ@¢ À¿DbЪ0/IåDÎd4žA-o0@†8‹”ŸÉ²I¼”œÚ-Õ°OÁ´pëðC¡Cõ{I—•¤ˆ©s{é{ñE–Å»ÓLÀ§Ì>µ—ó¨³`Žƒ7€•JF=iV.Act¹ N4@„ 2ÆcJƒF£\¥Aƒ9Kƒp߃#Œ°Ð»“9ÉÛ9³ó@Z/[ÝLìÂÊ7ÏY¼InÕR܇ýr›‘:S¿mÿ‰;8ûϯþ hß±¯º4…ì껣ݦ.šóDhUè‹êÕKžUôf.ØÖ ²ïH بÁ¦6PgŒõ Z8­4³6Ê@LR€÷`0ÃbkiáË”œ¶ÿÝÄúß6¾»á{“íx}~coI-ïco±›ì+v&]!^‚Ç+ŽT¬î+ñ hÆšA,/ÙF§F²Xy}i§œ¡4(qê÷±.JÇfw2¢ Œ³/æ`³ØJ6ŸÀýñSõ°Öß¹€Ás‘›¬†Íç±E윈SîN‘‚Q,­K…uµR#h4˜C*Ìéô‚ºgP0!|Ï ¡t[ÇH@@¾"¿é¯ iVhÚIªøCëYzMèŠ^Kr±G`ªÂT£½o)KSý+z À/¼ž^Y¦Ý\æßQ¶Y€‡Må"ħââP\OˆÇxÎÜ3¨ãxgÏ o}p<æ6ƒÂGqRVnIÏ¯Þø‡ßocõlÅa<ðÛ¾ßåôaö_ö v㘠«Ø„… SÓðR<úüÈÁ5ìmvƒ}Î>ôà·Üù$™Î¾€K 6]Åq<âõ:íT©x@!r•‹% QºØˆ<„ª>øíã“êX]%ud¨ òñÕdŠÐO—s,ó!H±0E‘+»­4ÑÙ:)¹’ÇÞÎæáqrŽÐkU*ƒQM0Â&™:‘ÄŽ*ñAžî· º¡y=úŒz¬î›·ÊöäT˜oàñ‹áµ¹›2~àÅ$Üx¢ÕHø¯ŽÆ­°O±(£…}˜»ù^è»uudýÙP=9µ$ô –I> U5“bC8Xbuˆø`KÀ2ĦnûÙ:Iøî|³I¹WP‘ä.FÅóÄÀzAo³c™ 9 'Áç,¼ŸôØã°KiÀè3KéÓ2fR¶b„/¨ð%VgP1oÚôIÃPþÐÝRˆL÷í<~çÇ0ߥºŠ µ ØÕ@m4‚a6[´T4ª(£éÒœåá…aÙ4’|/z»á+•ië š "ò"wîóú†“°`»8œZD{(¶_Òƒã”3÷ ª9jì¤Ö?´#nEÒ“QtÎÌg[Ù»’ ÃÃq7ȉGÞúá?¿þòãB;ï`“@ÞÇá1¸šMaÛÙevçà ÈŸ³ÙyŦqãd}· Ü@¬(”FV›†+ j4‚(ZJƒ"îÓøÂ¦òI9EKƾ°­çƱ‹ìÆÞ:<‡´i7~ýþñ³Ç9Ý—ÿ%Bq«w¬Z¦Û%ÓÁ!7©µ€¡°T/ê]=ƒzN´‚1€ä»èt£9ˆ¶&©‡Å?¦Ë×âÁ¿°ëù¤Í·lYVƒKÉÿ PØîƒÏ9„t—RõÚ,j5QM8‡S­- êõ„Rà!¥Z"KÌݤ »L3ÎnâƒÔéÀnâUV`ÅËϲmìÂÍúÝ{Þü‚ mç}x}964™ _½råªge“r 6µ…DÁD+ë1VžKMÓ%R‡쪃£êf… ›8Or$µ…4Â+gKŠ]•ò‹DìLÄaÿøž5,ôɸº½W®þà5vñ¯‡ý÷,ÞPPU}ãO¸êäç]w¥µš?½÷ˆòÜžïíxõ½²µ½g<Ö{ÄCÙåÇ»gЍEÀ‚0>ªRCÄÖ‹ø“ƬV1¦:»ÉÒ:–Í•°l>i½ìCŽ‚î¸`3J ˜MX#bÑj1«(§‡‰ÂXú¢ÕÆl“$C6Šä]ìcö+¼®Õ½÷öïñ‡úÞa_ã亯¡øð»§ŽÐ#°üpïÈ5¥Ø€œ­2ŽR P_¸˜“û€w>ìpæåsºÃ¡v‡~ªÇeíRZ´S*d }_Ú´s‡Œ?Dºbo˜Ï%Õ¨\š¸X»ÁÀ«cÌŠÕŠyñ…wOä™Á²3Iº}Viþð2Vj7»bÏÅŽ¶ìëÝlNý·mq~,Ôck[·Õ£ž^ê|ÚöÜÖ,?ûø¦Ã¯ÑÙ ó6¿³âZ%Á¡¼jdà X8 H€“×ÜH`¨1üƒŒÍIˆ[¦Ôã¬ý1<O:ÈÚ“…¡¹¤ ½Iº†z£0ÝæÈ1RrÀÈñ„©| )ßD;…ÇÒ¤ ØG:âEGXÌ^æ:J®’« óCgI]¬Ô¯a¾"Ù>eœŠˆHä0§ÑòŠUÍbžfu8¹úàæŠ¬T2Ñ·~¥‰U܆UwÇüµì™,ËcrÀ `©¶ªRó„ Ø+Ó Z„ÂQ™ÌòñYv »Ù1áÎò;n >'ˆ/Â5S à}5S+ðï(ñÔ†þ_cÉîñ±c¸!²6E¬¿JD/hÃýk;Ýr}ÙíƒE¯Áâù‡økË”y²‰—óð'Á\ÇÔˆŠ*ÒH9d“„Z%Uãl|`þb[Æ/ÝÔ0–Ü 9壢›î•È5f)3†L4Kòõ â~7 I·±S ÆÕÜjÜÀ +Ä.Zð,¤½±‘j6ö€Äú}`1¨eRç-Ï%OkÅ]É=Qdï~Ð/ÛÑ¡÷nÑóÜ IP@jŠJ›˜èrYTb2¢Mì$Z-²ÛÅA°Š±ÅA޷藾ܑüÏ”š/§±á*¦Ýœš“×QÊdí6-w«Ê_zê¥7ˆõè䧪ÿä{èäˆwßd†Í®=ýÚ[ë¹{3îmºÍŸS1¯Uξ![eÝÆQ¢øÄôACîý`c+Ä&I¨[ Eãtºª£Én=ÒÙ-fX d+Bml}1Q;"‘"•⤠y¥ÐÊ&úòœárŽäȾÏÿýÃgÿÜAç™U«RÍø ®fSÝÆšn»Â~„×§ýÊ— 6¶hÞ˜]KßùöÛ3×.~ö±"ÓÆK¹ÁJ~d¤¦1NA°™`sÜŸñáüÈáÛ@\-[IÈ•ÈØÛì.Vÿ·ß¶Ö¾ü9ìÀKÛ«_˜déX‡­¸UŠs¹# xÿóök eÞº\>ÐÈ4êp'Nd0˜s²Ûb7`XGÕj ‘ÚD­ÅAêx0‰”ZGˆì8}Yþî‘ù™«¸%ݤžþ÷Ëÿþþ³k³ô"W»˜m«Û¸¹nõæMk^ÁiدV;ûõÁÇ»5ë=7Ï\¿ðñgpZ€>V‹Ú’b4N-¥`…ããœÚâ Ó‰Á&ËÐŒXÑYˆ/šl–ì–¼g¾Ý€iŠ º{óþþÅüß>ü>¤çߨýç? ܺ幭Òq™ ·Ä"Vãö×ãO¾Wº6ÍMÿ¾wÃÖWÞ%@ül’MªèØt:+!`6©Ý¡•ЀÓùâ U4RI+äZySˆ(ÎR(+ˆÆüù~“;ìÄ@²Ý¬}÷]<â‘ÊÌá݆=ÓPHÏôêЯõT%Í}¾‡Tð2— ´É@ù¨3šè”é*HÕ%uä³­ØÊ“Œ”ø¤T—¦K×x£ßè/ªÚ÷jRTF•QåÈÈ =‚Æ–E=‚-MŽ6=‚ޏ0ñÙ#· 3Ù#E[¯Äàör!WÚªJTÊnz$6iÜyÎÄ)‚¼9íÏD¹ìsñ­þv";sBé ·¼ÅþÆþqùæ³32 ÝûOüüô€îÌ\³ìâÙIÎL}fЂÿù¹ò®d|Œgj'Tý[gÖ¬<ôÖöÕ£WÇZËüexv?^ÿŽí. ž;1ØýqÚaúÌ[¿<|Ú>©ȺCÊ :o‡ÚáŒ1¨-®8h1iRÛ%SÞ±F´_²XfEˆÍaÍ›+ºí©z±¶V¥É>8ãìYrjÑsÇ> ½ZžÞ¿ ß£o}òKò»e, ¸en–êÊ›Ìz±$¨'F,IƇÑES©ä@£Ê³x@mm}AFËvíZfp%8½ÐŸWPŸsß[ÅlòÜ:ƒZV­V¯R¹b¦’ # 6">æjl³E¬Q ¨)zµÌaí»wíÛ³iEfs-¶õ„k¸kbÇÄ!‘Åš&MM(2ƒF£ÕªŽWqf Ä´&“JEE­•" V.RD¨0LV,ÅHÒ¥&,®ÈˆGžbÝðÕ³lîÜ]»T$»ã(<‹µ-%Âãl¬`k8“?]Y€µ)4ÁTAØ‚dJFl‰ˆá` RÆ ç@O<¨8à±›ÍÚâ¡-Rãv»ÅÅé]`q“\&«ò*»œ¶…7·@ |÷7XD‰D“l8%ÉHvFäCH2sóÚÚ)³¶¬ª]§ÊÚ3ã~ªì£³Ž¾AÎ.\xàÐéó/Ÿ†Nr%5eƒŽýÖÇ’Ì„åൡì@ ²IkS;ì:µÉâj2iŒ׿ÒꌖսÛ%0|G¦ž~O’Õ£ŸÉë>”UììHXS’%Èq­H‘[¬KãKf¢¦f. :Ç¡!~ɰ¢èþn$ûñöšožÆºÛ7°±áÍÝ/½ôê«/¿TKRÙOìÒó˜ü ÜR&ûÝýøoW/]¼¢Øúý`Ï*e¼Ý¨(ìÒr¢¨J²¨,)N‹ŒF{qÐhRUq(¾ÉØ5%IJ+Û{pÖŽ(2H\2øQN[rغÚÅNU nÒ_ÿõÃíÝ5dSÝŠ;lýʇ`…ÜšAeì3öÉÓëGÏ¥~{æÆûç¯*~ `Í—é¥Ä¦u™\ÉîØ8§1!1Ñ¡·ZE°ÿ&=*êÿ—U˜"ý5ͺ@"ùd„|dWÏvÎn¹UoÖV[U÷rƒu›ŒŸïÕs%ç&Έäµt:¬ÓìA¼’×òÖÆ¼¶8è0 TÝ(EY”Ù M›¶¹iÞpÿN³Ä–NÿæÃ¿>Õï`Å‚e“wlœ_ô×ã~µýË‹f>ÙzôŠwªqæÆÚî›Z¶y¸àÑN…ýïµhsÉân¥[u*ð÷x`Lºw‹ìæ‹Ar¤ê…֪ͦ-”‹qj¬&k !`2ŠÀ*1̪ØóÍ‚W…Cv©–éÂöÙ¥,Ãæ –Vå1qã3ØÛ[·ÇØÛC+õâ<½÷#Ëʺÿ“ÍÍ5A¢Ñ.бB®ä;7àÂVQ§ÓX5v‡N¯7©lFY·ÚH-å¾fª#1ˆD$Š6ãÞ Ú/ÖVǨ}g¼w†+ ‚#ú”îYóЀãÉy%V‘ò<kKý&¬Ñéy56Êáº/’{¸åÔÕ—g±ú0ÞΆ¸UfPi+?8À†Ã´3¿éæÇ}HÛ»GP8<0_Ý7a²J¥Í¶œ­·À¦âOxïÃdl¾ƒ:íÝEÝÎe¾KW>9×^†«HŠ‹ø³Àû’@ZŒU­×Ç:ÌDë°ò‰IºWLß Úå²"«©wЃø^÷7 4kWºßÓ1—öAáÃy«ÇïÁ uÇë:nZ9g.®eƒ:—Ò¸»wÏŸ>ýÿø³U}ž^Æ®Ìûbô’V›–gýtmîpà¼ÄŸ9XàœÜv %ôñ(Å€ -Ó“ìöTA$™]-²ææ{ó’—ËwŠ‚‹NÑ+yAÑ›Ÿ–N)]›ˆ PÕ娨Yä¢:;}r!Û ÉR4üÊô ¿ÈqÚœ{¿Ò!e£Ž¨k -Y…ŒÄ—+Q' ЩÈNÛçÅ·Üj··GÐmW›zÕ¨Ijœ¿Û/oÊk• Œ¯É©°¨dQÍÊóø˜„ÃLKô-­¸pjè‹#ü#÷ž1cΦ£5å¥ÿùÉ_Ÿíûvù¢åmŸ¾bQ—ÕϽ’]½ænýiú€êÔ–“ûÏ^šà]èkèP‘ßmýÄAËÓZ½lc絩­{÷hÓ®]fî i#ûŒïh-›üð”Bëh oìç tIÞ³J ²: ²Ä¸ŒÔ®1l~\!*LN=ýþÔ´üü´T?žëOMÍÏOMõóSsÛ´ÉÍÉÎÎ JuˆÑ÷n Ý”=~”9–×ë¤Æ¬¤$›Úèäó ²uI:‚,& ÑYt–¸LÕÇE¼±rFÁܼPi—’C®°Ù]Åò62g±ƒéó¤´òZ8_N K¤…„λxÞÂsÛŽ)~û£/Þzvf»ÇÖ¿‡‡¾/½ßf;?ºÀv¾3~n½wÎxm»¼ûì5γoÓî­Ÿ¶ÅÿðùÅŸ;Ìô±#ò=lçû§XíGð Ób—þ´§ïß&ÉV1µ‘©üÀ; åâBœc‡é&»ã5‹Ë¨‰ª·$ªŸ yWÊ„›)  é wâa©(îé1§Ú|9r5”Øb/6yÓË•kGËœVµ š•M9;rÊcÔ]1bÔØ±ãÎ[å^0~6ëplt}6Ç)õ½rTIëèq$ =JX©F›ÓªÕœ^à F¯’z“³~wr;ÕXÄ©ÊG90K*ŸÏbux)XɾÂI•l7ñâõÝÙN¶£^×ô5ì± |¢ñ(. #˜Ã‚ÈseA^*sGRÇðfšŸK¯nx:C?àªçѽ{‘þi‹€¤fx®Q®TaÉðyòwN Ò¥Wë,N!¿@g‚Ñ«Á¢²-IößJ,V‹õR&1¡9æŠ רxÐd«‡Ê›¤9ŽÿKàÈ¥ÇËF 2èßçöî ‹×b¾vóÝkÿ§È‘;zu^R6'‘Uâ‘l³€ú¿„ß»#@ü)¬y`ýŸîþÄéÛ. Ò먺_¢¬Æ#Öè# ”öVr©K÷î]Âg(R™ K-~)Ò0´`J¤ŽwƒÙ¬¢&”õAN´Ån¬RDš“ó}¢×o¬ñµnݾßCýž8)¿ž]1A=AÕ2/Óo>0Ý kô&¥ø+yo:9` ÂiXbš, D)_”)>ën‡‘O;”¯¬y‹»ò‡Ö’®r´6\¶í]Àï¿#ùöÔ€E::' ð튷±«%oóîf.>ê¼¥ÚäøžšÕ¯î^¿áå{tÜøÁƒÇ?6˜›¼ëðÑ/<´ó)ø™3s¦¼fø“ÝaªUs€ˆH4jἉ zÕ8óÊÝÍvWâ$öU%È*›¾ßÃC»³ñqM_Áôa¹È2yÑ%²!SDrÈ,¢OhBè0R¿N‰‚R¿_òm`ìÕðØ"eì×ÒØ´/Œ“4Ѐ±± nþ,Œ©ü Éw\CʼO„çÍTæ•Îi²Y´r­ÔRê WÙ=8Þï±qé(ëhB‚9--¹_0ÍdÖö š=ͲaC‡4h¤Q>ž&%N…!H~'ÜGef¤o¯³;ºž{ª¬fdûS§î óÆt®ŸÝ¾S—|)Yó=µ¶bB¯>£§¦µ]<üh]ñø`yÖÀC’pæâî]=2žr¿ª8Ý’†ZÈøu½÷6.Gª×‰‰OC™þ?3U)cb<æò(cî“Õ8æ â0Oj㘠(Æhê)i!ò7Ž”1&F…h>"÷ðl>èYQß@+HSÌ©tØÄóvÞ¦¶ ÖžAíÔèáScÒ`òlhj5PrÔÌL9ÿÃʉW_c—%õàÆNKi;N˜²„Øõýä(=:FB×I·»øøL¹57Ü|‰?&%¼æ‚½ÀŸ˜Ód˜Ÿ"DÆWî­“éÖ2LÿÃ2M°¾‰&÷™‰Š”1ö9uï®2&öþ1©c& ‹L[‚Ý´åÁØ­çi¥ÀÞVæá›æy„¾CÔ˜™÷2î‡ùÞ3>jÌ)öeŒ¥iX‹Èð(c&°Âð¸x@·²€×%r–=È1Ûí*N•¸(Šúd‹Ä×Ä â5ü†(rjµ©4¨¦œ½YçnX×î;èÛÔÊ+¥òr;o¸ÛÕ—Ì—È ½s6mÂðCøéƒ¡3ßâ9¬ê8©´ô’겞U³]$j¨a…Æ|‘,ãÙa_ó;>È}‚2mr£ÙЏà6Œ‚ÿn…‡±£ðp<| Û*å…sï½Ãç­ƒ 4בäLäâmñ8\#¯’‚-G¢Û¥w÷ -*ž£&=G]=ƒ´ž]½ÿàr<Ý„ÜJ¥Dî&–+(ÔäÅùŒ¢S:2îµüní˜'? u^Ü:âÉ 'ê'…†OßÿŸ_¼cÈÖ »#m—£—÷Ût?!õ]\¶ö}¶›65ô.—š ÙMôµžr{!ÐUîi“ùSæs±" Ö&Úß?f&º Œ‰{ð˜Sh®2&ùþ1©c&  a]òFÛMnŽ3S¾ÞæA×O}._÷5»ÎÑxýÌ›p?©ñú„¯‘¬ÝíÌŠv7ÁXÕ8æô/ʘ–‘1 §0FöîÒQ.jF|¨…¹mËŵ-Œ‰Ij«E|‡Žq­½­‹ƒ®l.»G° …×Ìq†¯Ã¯2¨Šƒ6ƒ E\äÝþðÑÐûM²¥0•áèæ/§¼A›€ÝwdÍ•†Ê…¬4ë ý•™1ë…—rKÏŒ\ðrºϤÿuUávn­°n »6÷¡S‹^zcßÄ«vo;º‹¾9{©–ˆÏ⬯«”†±tÿ#Ãgÿýr"«ôxצ¹oΛP·~XðÕM£DÕ$§vÛ–ÝŠžOg6©7 hW¬øv\¬ü]êI’ùV¢ðý Ì—ø_î¿>³¯|½Åƒ®ŸúE¾žÞìºÌWåú³¶M|½÷WP¨Qòo‡ýùCÉþÜÜh;^Åω3ó^²2Fß8æžäóûG9Å^QÆXšÆÜ‚1I2AéÌOóò`î½ùÙØ[¨¤ßÊž(7’ÝýåKv‹ûz´ªð<û¡çÍÁC»o{»÷… /ï®ßÂ^{mçk;ˆ}Ë>Æú¯o`a6÷Ù[›¯ê”]Ù³×óg­dÓØ?ÖÔ± ¯>+ÑNîÁuï!E÷ 2U£y4R¦[¹"ŸÈ<Œ}Ðõ™äë)º~JžŸx›]—×W®Ÿùáî—y¢\Ÿ§ÈH›(½‡¸tn·\‰C¾@ŒC£1q„ÃÒ>ŽÕŠE½Kç!±”1ƒîJe±¬¨ ’ð‘Èf‡E›¾£'CûÚçå¶kïËíù$ËŸžý£CÇ¢v…"òSø @0ýÞ1n$·8 ô ¤;“âm6Mü}€«¸10Qw1Žÿ†E$„·Rx›|®äÉý(›¦TL:ënošQQ9b^Û~|±×´—jÉzËê1õ¥W•î”î•}nÀHjPé=«wÕ†ßöŒ%‹üŸ}²kth®ïª$ò>¾Ì» ïß•eÃáÍý×gNm.;÷_?e‘¯{š]—y«\ŸàV´-#Ê®ËûÐòƒ•5”9’­ ÷ÒÈ=o)¨S )Yˆ³™LfÁÜÂcAæ8CMÕ‰ÅAµƒ:A›5Àþ®·GÚg¤Ói„K 7Ó$›sÓðÀ.u.ÿÃg_>¥ãTµµ.Ù½lªÃYki}°û„ýW"펔>E̯B¬Mî ¸#gÓ¿=ƒ÷_¾Ø„Œ³‚Ï„ƒ ΙòîûâJû¾x.ÜAwߌ ŸÛ¾åÏ#JBÚÄF«5éÍ Ÿì6Z æ4"­òD- Ÿå‰ë¤dm:Õ¬#2ú`›’< ‘ÃlΦ 2r~Ñœ&|Bc³7Ø‹x0ŒD !ÐðÐÒ§¡ÛoìÆ¿Ly䮯ð8¼È©$–ÜVv]‘Nµ¸¹ÊÄÈ3tÄ$nJD}ô´NRˆÃ‘še·Ç§ª¸_fKmKˆœÅA´mÚðf­)&…O)"ÞÑÌ3[$ ÛÌ-‡}2¯xÜHoñý9º¹+UñÄ| »:·ÓÅêkì',|·ð|§v'ž9{;äUáÒ¡;¸á®{Ã+/mÜürí:®Ç¼U:’üœí»³p6VAŽÑjÖ´)³Ù/_g³À{“IᥫŸ^üâÓÏ?ßµmÛ.©ý˜»B÷?1H½ò"2µÜ³ië*6¼w.€Bh÷H‡i=X7o¬³ÖñÄÜY«–<<û~ɳéU œù åÊç—ðd˜³µPÙ³:¥n¦¶S˜øƒÌÄÜÆ]ë<ÚzÎØ1OÎ=æéÇ»ø|]:æv挜U9räôYC :v,€·$«Xk}Ï!÷À1.3âu}ëìr÷ƒ¨G7)½mˆT0öH„O$R…ÈgÀÔ–YÞ¯gJŽÏ0R?ýÑ6ú–$g·5ŽÒO宦¶NíÐqv5|´ï4;|F½ÍÂÏŸA„ãïþL9Üøü+þϱbÓX=‰»Éç,‡0¯R#.ò#i°7Oz‘˜ªsŒ,˜Ó%•žt Â:à-úݽÃ\¤^žËˆb:ë՜ɌTT×ø693ôæY}0±; ®1<5'±½>t¹ ÆËX5]kôü&i~µ,ŒÙ¢çM̾Óó‡¡v7>(>ñb†Ìí¢oBÄñ(ûù©Ñ8wˆSºØo¤݆(êC„î äɽ¾Dæq‹KüÄ ‰xœc`d```”œe¤öZ1žßæ+ƒ<œ|{#Fÿ«ü'À¾Ž½Èå``‰o× zxœc`d`àèý»H2ü«üW;Ž(‚®”ÏÀxœm’Od\QÆ¿wïyTUC¤Q1¢²1²ˆ1†¨*í"FeU£bÔbŒQctQ³È2Bd•EDµ»G¨ªÈ¦bÌ¢jÄ(¥«.¢TUU#òúÛIM#Ÿsï¹÷ÜûÎ÷Ý?IF™Æ¶GÛŸEV6ñ<ØBÅÿˆºw„¶)¡HòRÅ2×*ÞoÌ&˜4¶Í¤˜{LH™”È,i“'Ãy…TÝþ4 ÃùS¶†É0ƒ5ÿ*àÏ¡ë¡å÷Ñ•Is~Ìù º&G¦“Gò•ùtÃtƒˆäÐ’Þ0þäZUYÅ5Ö½•w@XÁ¤ì ’&{Ý`»xÁgÌÊ22v+9•o÷•ä±ý€cCZh˜×¸!+˜á± °k‚dC²n‡uÄš—¾Ûk½Íúû<Æ×öÄÁÆ%Ã3"{ˆ¢¨cÅûÎxWû?מãC¢Ú4É”îaÿMþÛ|ðeÓÇ;@ÑÕP{Í ’]Å3—ë CÒ®—_ˆý<ꪷ×ÃMæï[`‘õKA÷È-rÚgî—œ&gê…óaúà“}“K::ö;˜;÷á"ú4ª£8/¾ð¼uSÝ/!øŒ’ó¢õ?ôàõŸO¾Éêÿ|¸ˆ¾3êÅ(ôÂyÆè¼\A+\ç9Þõ«1F#â=Ä„Cßü{L(6O öL渚%ïÊÙ5NÉþ¨—ÍŸxœ%Ù»o$gvðÞ@I9˜mÀc›"MK­¨)’Ž4-R-‰lÚÿƒãÍúiÚ»I£_h>Š˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€2Xà\ÎLf’¾ú&DZ|–ØD¢ä0ް ~´è2Rª2rÎ H ~ ¬ ü . D l œ º ø 0 v ´  V ª Î  * n ž Æ ò0TvŒ¬^šî<|N|ºøh¢ä:ŽÂT’º6pœÞö<vv¨ôF”èŠÀ<ŠÆäìvŒÄâlŒÌüPx²ê,Šœ®ÀÒäð>J\n€’¤¶ÈÚ2DVhzŒžÌ 8 J \ n € ’ Ô!y\×7«ô˜~z\£å íñÝ ^yÖ*évÂZa3¬ck®°Í,Kú’­g:Ï´0*Kú |,ŒvÁ™RS.S¶+RÀ¼KhˆüÂözG&þhÃ/rq1vè:Öe.FkˆVˆ·]°÷ \D2¥fuv–Š­ U?fÍ0üWI{.aá/oI¹#¦=© ܉5ys‚äEÉpU™ÊíV ãšk¯5p—>‚-£ƒKbwyæ¼Æxî;«v ³lÆÕYʯ\¶ÈYì”çC´F;ß{t&ha%=ïŒ*˜`F‹X„>bÙÁ©"Ù@ŒÙ¾dZ&ª0RcTÊ"©Àóp¨U«ÈJ]ð«T»z¢Îš˜rÃjà¼J |GîËv‘4ò”Ü¡<©gL¾ÚhŒF#.Ûd¶sÌ3W®}¢æËˆ‰[ ßB,²ÄbK-·ÌEû­´Â*«}òÅ%/tÊ+o¼vÚç]pÃYçÜ´ÁU×\…CIÉñÜœ´´ôŒ”h~$ˆeEƒHjv4Äây‘ '„3ãAô/¸¬kTxœM‹»NÃ@Ew¼N¢Tcˆ°ˆÀópšíXúD)L‚x˜‘âDJEOaSCƒ”&ˆ–¯ðºË_ð!|‚q¨8ÅÕ=ºº£ÏîÑ$âB¦‰d ÃaX†òÚ èÊh2ILƒsc}Êý^M·¦¶¬érªiÚl=½Ë-ìêæ-åP–R^$}úNàDó¡>`_ïñ {ñÂ/tktÚ-øI¼ˆRü×ðêC 6ðQ=¤J™M§¾7¶{»°°²qºÍÑÝܶWVð|1«Þ³·õZŒcÏÒ™‚ÌØÇ¦xAå‹q–çJ-óâYm)T^¨ÿüéþòq;Atomcat-connectors-1.2.50-src/docs/images/fonts/OpenSans700italic.woff0000644000000000000020000005130014655113620023671 0ustar rootbinwOFFRÀ‡ÀFFTMl\Ú¢OS/2ˆ]`¢x¹cmapèh²ŒèÜ™cvt Pb¬gifpgm´´à»s¤ugasph glyft2‰Iì|«„ohead;46øåÂhhea;4!$xËhmtx;XX™þ0kern=l# – locaK€®®s„aÞmaxpM0 VnameMPþ~^ØkÔpostPPyò‚léÕprepQÌôâ¯ɉo1ÉcIÉíØRxœc`fñgÚÃÀÊÀÁ:‹Õ˜QB3_dHcb```âæ`cfeabbyÀÀôÞA!(¨Ä †ŽÁÎ Š kØäÿ‰0´pô2E(00ÎɱınR@.{ö Ìxœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@,q ¢ Õ ÿ߀xòŸˆêý3åÿëùÿŸÿÛÿÿ%ƒÌ¿= dõ”á#£6Ãe†ãŒL@63¼e¸Ï°‰1ä_¢ò#ßxœUÏOGžY 0d¦ê2Û‰]vI•´Jaj{»nZŒAš%=ì‚A¦§œrˆZÉ= ôy›\LN¹öÐÿ!‡öVŽÉ5}oÖ&$R¥®Ö»ó¾÷sÞûv¬î?Ü õîNg»½õÃ÷¾k}Ûlܯµjåµ¹ñõúWk«+_~ñùgw–?-—>)nËý[ó7òîµ¹Ù™é©ìäÄxfÌá¬$€GŒD¾Ë@ÆrIó½Z¹Èz"€¯LQ6’1ˆH@_ñ8…–GïYªÔR]ZrW¬³uJ!üY“bÀ÷Ú׿×d(à®Øu¦h…Y|=lUT­ þ¸g‚käÉÌtUV§Ë%–LÏàrW° %|aƒÛ…³¬%ËÎRZÜiwa«­ƒšçûa¹Ô„9Y³*Vµ!a¢ “6¤8¦ÒÙ©HJ/ÌÙÀeûÑR®+»ñÆbô5c1¿A~ e Ÿü5;?„’¬°DQ[Û—yZoSr/¸R˜W ·#/þy‰‡ÈDÁ}Åh Nø¶öéòêØkcêRÔMdâÁ›þ¾®4I.gØn¶¥1ÄàÍóSêg!¸Q¯…í׷[ðAû¡§P½¼7¥¿âùùK›­ÿR3l 6;ìûÔ†Óbû(@¿­SY°}ï)SËK!8i^Œ4î’¦?Ò\ºGgÛêh™B³+ìøi ý}d×O4éÂÜkÏ—æz^¬.‡ÖV`UÍî±€ñ"6 ½®: oÈŸV˜{¾.O]ZÊPö¨-M{£ö؉ ›aç3œëÎ;Ò•fa›˜ê‘@Í„ú’wµ¹pßÊ—bã=us¤&+[CÁå0 ÃÊ›Àˆîj%ïÙsƒ#ñœ.rÆ2Æ$J[ˆÂÈf×ÈŽ^·Öxöüâ=¡\×Y‹·v*僕Dò“v¢øIgOŸ»Œ‰“ýÔáN5ª„ÉmÔésÁ˜²¨C($(Ò6 Ykï+ÆúV›±€•œY,;Â8;8)榉Š6‘bj2©F¬3ˆeS¬o1{%ŒZ¦¦ÇUVM©œ3ëx 'è)"Ï9cSœ=ËñYî%èµmáï'SÊK-úh¡Ò OvߦÞÝÓÏr ÝìUèBºÌ÷pØøˆ.åç°g¢>6vGƒ7.7pLr ™ÈÁ´<¬ÀŒ¬¾IøfŠO>‰å79º÷qö[À‰µŸ¤øèϸ4© ãþ]þ##2¿ ÿÿxœ…| \”ÅÿÿÌ3ϱ»,{ÃròŠˆ ¬xÀŠÜ"""²Šf’ᙚ©©©y•ššš™j™å]™’_3óg¦Vv§eå×”þ3óìZý¿/ÝCŸyf>ó9ÞŸc>϶^çæ M-ˆt´0rJ¡/‡|¥—¯?Hé†ÔøÃ+ºC«Ñ“Rì‰þ~&Ñ çÿö",q/Ÿ02³x¢+¯^Ggï¾[þHAÖÐGúÀÑ6ô6›_¾{ENB¤ÛO'’©™‹¼¸¨µÇr¸kNæ Mî_9}@ï@H&÷ƒpÐ˦à}|B &hµ~†î§Ó4•ÙˆD•Ìšn7¤¦ÆÇWêív»žý¥/²’d‘èJVúrXäe´#;}I‚ÝaåÕY3â “¿˜r¤î¤è—Ýb€–i§œœ|aòMƒ[<žu ~ƒkéëÌ÷gá<ž¾Î~ÿ= »³·.à«DQ ôsFÅ«£xÑ/:È/h Ëàî#ú¹§Î”+ˆHô#ºšHgëíºÓ±±z@Èeïs*¡Ú$j¡ÕmÓû›Ý`rRJ:´Kþf)Ú†Â8˜Fþ‡|Ó@?“™WÝ»e{¶ëÙå'Îäly_±.²l›]ýôÄô9³2pnza‚Õ–UÝAòCu>TMPÁŒ>{Ÿxí¼vÍÿÌïû*ñyûÈÙØ­ÌMëÖKÃõ‘2{Œ 2@]ë q©p (™ÈÁ’Aœ3 ¤»ÚíÁBºj4AÁbPð“"»2¤Se©´ëéÙE$çg²'’“Ì&ŽjLr’ªO´Bc$¥ÞžH·rÿUNLÑ£ïðÛz|ÑÒÚ·g.XÅ]¾wüWÞ™jËíæˆÉÿó‘ƒ3ž[V}艫ø»¸uUŸ«ªÙ†¯.ß¾îúܦEw‰:µ´5ëèµ——àï—ã¿Rg×à“ûa‘}BaßÒ^ܤ^ãz§Ú+óºU©qQÌΔµ±Ó²…1ë’ Ðqùø Ê%ã|€êM„T6žžÐݨ#Ú®‚zÑÊåÿ [ÿœòã*séÐÿè~¿‹?Æ_A™£µäªÉ*2‡ñòPÇ! ÐëÝÀUßiÅwáï“X…ÊñN÷{ø/ÎÂ͇vŽïvqü|1 h­¢xh’¢Œ’´ÅA‡`DS&Á9¼{ÓíòãÍЈß.…ÅáÞŠcñž<8ÿ¸õNÅ/»á$2_ ¸ÃGñ{Èž¢œ>J òZŽÒŠGÑ{è º‰â+'@H¤ÈcI¶èíz‹ŸEo…—ðr8ñ¬ÅË.q£/ÁIxé%¼’âl]ïÀÙઑŸ@|!4Ê,JÖ#œ¡˜úܵüé7Ì­W·ÃŒ·1pWÍm&2P¼AþOÔßè°H1Éœ:î¸{—Ž!x gÂTB«ú-%*q))À&twtÀÔ@/˜Öµá(lÝF”ö6“/•g`óÇï0^ýíî'xòκ)ŸÂyïÕŽ!û"+£ëL'tM¼•"  ˜‘S(Ù Ûƒ›÷Zc”ãÿ3—Kù õY;_Q8ç¬ùÝ ŸO°&„9µ Ô) ]: ºèdŒp½°ÐkT’- 2Ö‘? ZÖ’ /ï]Pœ•±hÌò§}êЗÅ[àß¹çáŽï•ôØoÈ©GG{iÂÁƒk¾¤ú 4„_Ed]‚nÎd0r© / ð±D…tEI>ú.ŸÀDPè!‡ µäF¬]ä­‘6}¡'%9Ébu°OB¤‡F¾èÝísæ¯Ä?¿{seÉ±Ê ;1^Ø-oûû¥…óÖ5 åƒ^š1÷?SBŸD{ä]—Ÿ˜Ø/ôǃú¾EdÛúáQ㳑h»A‡$(…"—¨4‘$"™ëñv#¡ÔY‘Åhq@ ²[š¬¢y~g:¾”înìŽ8è8º'ôT÷Ј֑ø$ŒÇgaüèÅ–ñwz~jMŸŠŸ¥< &<GÖ ÑN0¹Ìæ B1ß.é~ÞPcêLBX;#ˆË· ®vß§KñÃSNõÙݸ~w]͘ÚqÍÜïl.ËEëÏìß~w~7+ô}hÉÌáÃ-…Üe|_Ò2Ý.#tÌ&º¢‰'2ûšuºˆ"—NgÕ@— ™‰·5?@Œ,%cRìdO$þ“j]¶7ætu °Ë?»6ײ—L8r3ƒ¯;öâ«KnnøôsøöCõý²z×dÁóÁ90ø¹àÛŸÿ²íÈžWð•%X:¸$gHÎôÑÃÆ1]…DN‡ ¿D ßWèB¢LUqžD ,䮹õ@Í1nßù#÷ÔĺdcÈþÌÀ â@„Sã @§A. ù† rùvÜn"Ó;‰é?õDº(âˆÒ Ñã|èÆŒÔó˜é7îìÌ#_Z}±á§>ûV¼<ù ÅäÇF©¬É )(Ÿy` pºdí¨y'“_}üpõ;a—YOoŸöθ–¦¸'† 1aHÞnceÞÓY¹«2 ‰,J ­™L6¯,,T¼™IAâ•]ü?Ê‚8 f*þÔùl÷üB¤‡rfß|æ ÜtcÖ£µ“g¼V×…¯Ý¿åÍå··œ:‡ûö}ØÑ?³÷Ø>9èü=Š ð;êÍš›¶Aó‚Û\Ésƒ†ºòF”T˱$sø:‚‰fЉHYâB:?m‰ËÏ¿ @uøÞ\;’çöiu©¿`kˆÀüœJ4KPéJ\*[ >è qÌwX:Ng3?CwzW¹À< wȳ„¬O5à%2·ß>]â úÄSF¢F23L†~JÈGµä¢ýîznÎ)Ø´þú+>Š¿£û¯›‰,vêäÃ/4W„›/0ïx‚øFc²Å’W ÚOgB¶‹ñÌK— !È©¢I !ðP&CÏþ ””XÃÍq×Ó9àÛ$Œèó+Ö-Åù„Žm­×Ñ †ñÑ “Ó¨%¡=É7ˆ†+µ|§°W'8ìmÅ,ª ëS¼P¯!VG.òcÍÔ'úÍMœ´¬âÛ oœI}ägßμiâˆÌAËòIfR8vå ’Òäi™—ë_qðÜIÃb{gåã%Ã&P ÈzRÑš-'vÛd‚Dg Â'ÕpSƒœ¼ÓçWhð1øt¶¤ Î݈wïnèíä­Œ(6«lL§Í¨=Ì%(Ã_ ˆe:üÈÈNuÁ–Ц÷FG´x|Ö׋Ë&éÄÄ'K–Ìÿuå%Õ>ºž“³þûó)|`TßšrzÚ·?]ćvþß…Fâ «ÝaÅ y q‹sS;¡Ü×ðçÛdÈÞ¸zDk¸¢k߈ÌYŸM8í ÞñÅïø—ÎÝÞ.ö8ÍpïñÛc_uõ͇ê¹Ö¹» ‰¦ñ8µjÄkaK«å%dàIhÉ„ãµd‚çÎ|`t(’ì.Ûvá÷9 §¬ÀlAª®} ¼U8x7“«‚Ãç<Þiú<ÜÀbðd²Îׄ×Zb“áÔ÷Šá:]ø—ZG|¯N§ÑjÍdY¤ (pi ÿæ{™Èî—ÐÈ0/"ï§éúÛÖž†Ïà[îÛ0yߪ3v®ýhû^š¶l^}4B Z<ñú#¿;rØ‚–ÜÉc7]ŸIòÃ6‚FPà2òj©À¥6¶GPިɡ'‚$‘/ ¥IzÖ ¢OŸ›µ`õò÷O~ˆñ·ŸÀНêÔN­^ÈŸÚŒ¿µ}óÜ2ÆBáëq½ïöŠ–uðCˆ%üPßNV . Æ—`è·ä$P×È…Øcxq îC ïY’uØZ.­üâ‰eÏÔ}„l|ès¡ Õ2n-´ZÿRK®Œ'”÷/°< ›3PT’‰„éÔ¦9¡ÀÅ!¨*pÁ¿3Æ^fÓì…Æ´4Ãd”˜‚A?xÙ­E ‹á÷0žïYc-ÛO¨SK×EäùÛÊ ÷M Ç`:a·Ì„{`m¾Û#"P„øCP« ‡Ô¼H8dü[üa!fgðÈ…ŠÅÚ&0£…»ÅÙ7Ï»> »ñ·ŸÁ§ñÿ½_—¿rèºß,[]0<ÿ‰’Ýb7 Œ&¶¥†oüôнÎÝ·áÓoìz)Æzù'leü sê¨ÀU € … ¼µˆx™_Ff"4ãkñ™y8fÝ$Lœ/Ì€ Ü4÷¢{G¹>Þy¹ ž8" Çù$` 7ô€ øæ“qø.æÉ8__ü$<%ƒ'¾@‘¶dêûIÌGÔaþðʲ‚‡f†À(rÿÙ¤ÿââ`·iÆaôÝI^½o/j`uêÔ‡||DD6Ó¶’ôRt§tCHb¢ÓóSðîsõ5ò†Ön€ëàx÷n®(ÛMrwÆiø›;³MßÕ7ÐKöE â!2]2¢•˜AŠÐt/¿´Ý'™È}FèTû(ŒHõHÅë(]”É´RBÓ É1¬d«È1@BÙœ nǧð÷Ë’“÷Iü]Þ'eþ…¬²2Nâ³îæs{ÿ{äÞ ¾¦ åV’Eß‘×éz:æÁ}Z%‚жâÓU«$2@{ŠÈô Þ‰_ùˆÈelò‡a ¯NY |qÄç;Ý$V¿wªqͲS=^KôØS÷Ѹ|xÞ¯C‘ÁcãÍQ÷egÂÚxÇÕV€¯€߀VàþdÆGusgÌ8ùèSh'¾Žû~mY”ðÝøjØ>üþ;+Vï†i'–<ïÁ~ÙŸDØO¬RMM­Öj Z‰BmG«„LÀb¥ûMôçT=–l9šÏ9ñkø³RYêÅ·î qáä½»~ÿ¸ Šž÷ì“@>ݧ„‹S'H=AqIAs‰î•ä'¬¤¢;Áv,Ñbà¿núÏO1^×ôïû>†-£ð4˜û¿ö¾‹ì]ü ŠJ5P @¢öó1¨„¨=öðº9„Ž…>q€ú¢eœ¡pÎòcòLc<ûËm/@ïmFqM).vÏp7 MßðµÃ½‚K`µ–“Ÿ"FJbzŸ0äï\àòçYˆéMÞØ˜,Ý ÚhíæræB¸bƒ¨î¾<ÿðË>œøÐÂGŸ¸¾êâÞšž\Q7c:Üsö÷rhxdH~lßùytö©Iý_žßgXÿ¢ÃÌ®v^œezàïTAƒ„xb’Ô¹Ër‘q‹"× 7c¼Én9ðF~/ä0¦÷/&z¼žÜo&§Ò¤B¼®]…iÙq¬¾D°‰4úIq…õ¦àŸþ®=Žèßù\Ä¡©¥߯·¾>’›žoŸoo\·­¢kì'¸4‰aœ®ÉW$¨#äàƒÌÏÀ‚ª¿Ÿ(qæÂ¸öv›pc´Ùyއ±—ÓУ¬ø\\ÙØxÏ|Òwd¾0Š%ª0#âÍZñ²yËX™|-F"g; < ’˜H®(/fKr ݲðA¼;†‹ Qô/×ÂIPã§cË`>LvÏÀÛü9Ý]¾Î@–þ*éV²ó‡PdoY³üÉÙ_ :g•eËõŽEd3˜ pª>ÇóJ‚¹z9liÇb¤X;¿µ OÆ;9ç è\'À2÷.Ü}káÞvßåDw¬Œ™o“yÓ™ž›*’*JHððŽUÄ•ò¤Dºup*,u¯ž†ÏNûö@c¸¢–î³\<š/Óx”èÉæÃ;9 /ÈòÌOtHÞù%;´:Èç¡õB¼ˆçà˜IBɹ¿DÆ;§àmÂ!’ãøîO•Ó‰´z@(²"ÞOXý®ìÆ9jjÉçf¸ç³ýd“õÖ·æºÔ{9!rùÛâ°p3[N…¡|ðYòÿ-üE´M´Ù¨ÅYP®)B+1ód‹¿mÛŸ3¿ttÈ_Ìz%Ëo%ír‚H^iF½V­•‚r\’s\À_ëG¸Ð^ &Ô mù´Ùî°#+I±mÞüƒåpõŠWžûñÙ‘‹mŠÔïo\×ðóúeÍ*ž93¯Ÿéüû'àØã%EKïm^öòïó®/Ë©|îçÉee”–(Z‰Õ ˆuú«ô*½D Tíü):)„åß^.O׳ɧÓÜÈf•¨Ÿfæ%uLöQÜòWž¹ñÜ‘bEÏïˆ-Å¥ÅÄ* gÇe>Q”ß·ßãýùºÏÂ/~²e©hÂW›¦ŒÊýã©ïæU-ümÊ"7Â#t‹ðˆÅë’/cމ2§Í«Ê<—V×Y³¾ïøùFŒí_ÉWl‹IÊ8úµ*ئ0ø5L?wuÍÓcVt/ÍŸðdùÉÌ÷6hJ3êÊ‹m]4èƒuuÓÖM™Bq-Šàx ÑÙ@âÔè|L&1ÇeÒ©ôñ£ÀØŽßÆ¹ÔB#> ¤VÊô@Bgñ¹ºG*VÇŽÂç¨}ÚºôU¤­½p™[œiŸùÍÇ8A4½uäÓ•ÛŸÏ›À°‚¼-&kª€‰'Ræ¹ðÕª©u°8·½€Cc ˜1bh^AYÅ>÷ ŒFu¥õ,zèž™ÎtßÁ&ŽX?ñ—þ È©Ñúå¹´@qŸæÐi=CmŒëPÒ+'ª’¼ “vÃÿPæYŠiÈN~ç½¼X*’^~ýJÖÒ’XÁW#߬P å2»ô,V°?êI†¨B¢µ° k`(Þ³oz¾Ì¤• ¿žŽîõpk.Þ*šÜù1c€w î²õeÄgø1_F“aX,ß-š¼ãÄóDO£iÅ? ³¯ÅÏÔŠ@©%·%ÊQ›]ÎQ`¢¹]l–vvøf'A *¸+fÿÌRó\|n¡nTŪ®UTÈ£d!ÿò­Ÿ¸œ¯ûfâÔk ƹç01_=ƒãÛäÍoþÆ«[„>ª[½žè–^§Öþt‹ðŠÅÖ<ÛQ§èL¡dl+a5\†òf.ÇeÖéCÚQ&YÛN•£L´ÊìÅ2µ´ÿ´þ«ûOïããÛûŽþ°jÞ:ö ·ÿøã?טyiö9üö›?=ìû™ê[ëA‚ãÈzÔל×iµÁ*ƒ<>Žù»Ž‘{ EÚNlVfDt£æýÜ‚KO·+Ôá¹DÐ¥ßê• {f6 ðø¹ ‡ßÛó]ŸÁ»Äüïý1ÿÚ3?Gx@hÚÀxÝÉã{¾Z]°‚x…Çû<à}©ï¡(Ô@ ­¹?à{üáü²g tnOœö\|ROEî’>Ά<æ|òL#šfÑÀ ¿ké_MÿwóÀð‚ߟýrs>46`z€vÚ´4'ðU @§òó¡ê™ž¨—ÕEwÔ¿ü^QqŽÉ¯GUË‚_Á×ùà/uû^Åj¦YtN3ñë›Èœ‘4oR‡"?¿ l—Ÿ)³]ÈÿÁ¼‰±=ÙsìaóBoÇ´©Ï__Nؘõâæ¢1ùÃgT]>ýáæ‡žšší,›9N:øa˜õNyß±™I™ó+v¾3âB‰=ÖÖ+.]>à -µB œ7jõN“F¯7e»ôZ丄6rhGP€Ž'²*/˃ˆû²³FB ÇõYûüêÅ꺵¡Çž>’ƒñ·uâëµä'ŸNLã‚W”ü|ãºûz˜9Ÿ¬[Kô¾‘€ ?vújõ* eæïë 3䔨=Ѳ°ˆO^—¤Ãqó‚q”ËËþ³py?Ü]Ç 6ßÛÜüõË/TN—÷H ‰_JÖò!9—ɹ´¢ß?å\ð¤# ÆÀ~î­øÝ…Ð'Á¸uÙ\ñ½Íd⦹£ä¹ê n5‘¹X¾ŒJ$ó~ZAÛ¡vCkÆtJŸi¡\OÒ-9>² ’n•¥õù´Ã@ž—xQWоƒ¹*1$Ïÿ´»oà&Q…*»¿&«ßþª)ö[ž p¿äù¢OáÍ{›9ÅóäØã²¯­l_$×RŠñ><Ô*d„ò‚,Ádƒ4—°À™×`ߺ?à(÷~»ž¸žÍ\΂a¡»ÙMlï”ç­#ö¸ŒÉ&ÀéÃû+Ö×ãòõ¸#;ë  ““IÈY<áL:m=4¢‰À"sÜeoà3å©™ÝKR‚ï>þª}Á.è‡÷õ­z8¬u–Ø×I²V{.–í´,ËvQ÷ñ¹˜ƒæbÜÏ-×­\:®³s7bÝÁ}{¹Ã?|àLæ¼Cò°Ñ$O²ÝRsÈh W«U(,\N—ôž|јduPÅJƒ½ D¢䩸k!5,»Sµt˜òáÙ¸Çû÷‰~û’„òAÚŒ¸ï† Öv’úõLÞþ脾éÏ^<†î\të›/4‡*‚&vÍj 1§tþªaFjæþ,’#$.f³¨a½,xúCìz+½¿«1wŽ6P?Õ„sQD/hŸÅ©Ä-±35_¹…O+Ÿ?zÔŒvâ•Lž¶%²rÓ­ xWKO)ÏÌ o‰2+&d©É—íx+ÁŸ^Â)·kÕ†"—RíTIa]\ØþÖ÷ßÒsÃ` Sl"Uú Ó‰4ݲ:d¯ãéZ£9×–IH\úÁ„y ë¿[k9h:¡"y\ÆÜmåÅýŸÊzf‹é?>Øpf~hÞ°AcÿÖ‰¿:\UE²¯¥ls[¾(œ!ôÔYm¦íʀ a  Hm¡Ëp_~Ú!˜òä†%‘98yV‡Ý‘Ѹ£»'-®ê_eЇ±qø¼¡Ëvn©£%<áXwÿ÷ãÞOˆ¹%œ.ý>s`åõ/JŽöÇ-·»>î‹ÿo&>¹`ÞÊïdýqÝœf£.ˆS+…äç.i£Â£Ò£FD5D½Õu3JE+'å&?c’Ãæ0S/å0ÓC|É,ÑŽ2›dsD;¼ø„äC)³W4 «?¬aõìääúå #®+©_ÖÒ\S4¨vÒÀÂZîܘ +’³—ÎvMœPQ¿¬ÞnŸ¹¬¾rÜ€Ú‰…E•eIµ "vãÒœ¢Áh(v‘Ö•ȨUi´šb—¤Õª¡Ÿ¨ðõ1öèŽõ!d§Ê̤%$’‚IôE[*íô…,\¬ƒ,ž²µ„´DµÄãËñä#´Åvì}ƒÆq…n¿Æ…—/“7î'Àu°u è›x‰Z|¼§j@¬^ï±|jû-gqCËYš[˜ˆNòb è’i.k4'tC5JêߎéÆ)•= (›Yׄ5²c° ÷ë™iL´zÄ„.=~<¶kWñŠùÏ zëptRË¥ŸÞõÚCÃ2†O™GÛÓ†ŽNHæî¸VfF>œºêÕ²Ã%Õ±¶êãë¬÷|é@ÿ«ã³Smýº¥®„ÉÃRR†t ѽ†Ð ówøl‘'nš½¾ ÞÎNÎY:ÄÈŠjÏZàâ!æχËK ûf4_SXôHÞP"ÒIyCÙ9j}ëÏb±O‚†) Ç™€ƒÎð¨a–á9ÃUïÉ`‰Tµêpuƒz©z£ú¦ºU-©ÕV{0k5¶XMb›“dhj3W/XBMó?\wâ&oOìdHNâ:ÑÃm´µv\í¸Ø9½æÌ9öåOŸ,YÒÿ±–'?€Ã?: +OÇ[Ï4ãÍGo¡[¶Ã —^Â×·mÅ_oF·–/ž·0<ä½Ô??»Ö’»»'þÞsoüð$Þúq3,?±»u ܲn{Kt`-÷+ªN=A‚§J¥•4à …“Ýû4ñ˜œ EF{Êç÷WÂXL'}¬býèé½EÛú ë\QB\arYÞÃܯÏΚòåô±åqk¿XPýþ´ZV_Éå|¯ õAÐÇæ+’ BœÏ«» P FÉqŠO P>8“¿0¯ÔÖ(ÍÐ(¡(ù#.{ÿ0ÿöGð;¸üþá™Û§¸TØü¾‘Ö§W/üÇÿRæGîŠ&Þ.^&èÔsZÓa-l€¯Ã›PêPÀåÅ{ÄñjÑô¡\cÛŠQá•– ¾¿ÓÇø¨ŽPCu .¢x••´†©EÚÒ vÄò­•›‡U¾TQ±ixå¦ÊCÃúf”ëÛw?‰üßðM•›†•ož>¬"-}øy=|ƒÄ®Z’÷*}Õ>JEžrß 2ïëi¥=<úZñr´ŸÛìém]O±v¢C½¸|KöHÏ:¹¨Ò…ÀoàÇö•Æuì`¤Û!Þ“;êžn…úÚÞ¡vké˜Ñù['Î\ѵjñl8ŒËßviXZ.‹7¤ö~rdvõÃcFе*¸T'|HrD›ÓŒüýµæpó{æfó³`6+ìáZ¥¥ „<­4$Èô´÷´át,ìÐTIAÅ©[ÿYcÿʼnõ³ F%¥5D–—ŒLŠ+S¼äÕ§Öñ·‡N ã-Kç¼ø~nŸžQöM=R;wÎX]QKâ̯ù‹¼ÎS‹G³žZ|ŠÃâGB\+üzàR8°Ûç¥gù[eô=§Q¡5C$Ö ¢ù¨A­‘ÌZÿ` ÊqiüUÞtÌsT eôlÏÆhW\,‚;Ò»—/‹£Ùuƒ8e•}€ITgáO`)Œ›¯ƒ½ûž?ÏßÛ¼ç˜-$c9> æ»gfS>®À-|#«K÷)"Ú@MT€ð$èé†×:ƒÝÂ7nÞöRZÉç_ø™«À-bÑ_{Ýp÷ x9Àp`¯£zñ¾ šËdv‘€Mž†èIlí£Óùú*5¢R‰HNC´Ä‘†Ô'ÈZB›¥þÓA‚<(n[Sš‘ž6&m`ÕÛ⻓Ÿ4ï0GÆ)×ç²3ÐÙ\>wÅÓ#,’5 eK×3^h6¦8HhfãtÍoß. ×9猚ZVÂÅ5£´qƒ^–ma3Áü‚ùj‚S¾{ ¼¯Š¡=íêöt@&Ém„Þ+йãÑyÏ|òÚìøšshQz ¿sÖÙñ«Ÿ9þÇ ý›k_}œÕ*Èåè6Ãõ,§­×y æ ŠïZa P+,^š…›‚$tø¿á»Ú rùƒwàÚ÷ ™<ÄA3x3NxÂác±ÝÐþ•Ée$Éó…& œãŽ“ˆ>̼ ôø…º÷囈3@zr²wì lìd4ɽ¯m,»H€žÓ%ËòžKÆÎ>¤ó"Þ“ÏOQ¹{Ÿ^Sb™—ƒ’ñÿ!V­?{LÌÚ¡ƒË[–›Üi*Ÿ,7!Ò_îl2Ãh£ ²þ&¹£kײַ1Šö65Í¿fÊ0÷™'Ï<¦àJ²v î7{ âãIžæ®œuk^b-Ns¦,›çÚ‡½‘ÅÝŠÅg‹Ü!Q°åëÏa¼îá‘Y¦,×vLûÛ˜©Ð ý÷1ÇÁVyLðƒcJÛÆTƒÝïÜf‹¬'…ÍÓÛc÷3åy¼XíéÏšÆúM$«Ñó÷”&ÂW%¯=Í?2®ÑsoWšd÷&±Ÿ†_ÅŸ—¦É툉Ö[wÜ£‹¶ÍG¶ßñoø’Ðtý<¶Í¶—Å¿¸…à˜I =AWg@´2™c@LŽ‹dÏæl—Á¿{rŽ«û'Òæö–c¹\ð…zìÛötmBõžG¦tB…ŸÜ5;¯[×Ô ýÿûÙ;g=õððäâáÙåS2 R5=Ç~òZyvŸ”¹Q8jÄð½«{!¿Krˆ99vðüÁ;?èókaFrçì´ÜÉ™%gD¦¦å~¯Ï‰·où5òû®~LåÁúED áu&ó1ýÞÌÊô”Óÿp}j»sÿõˆ¶ëÇA+½n»ÿº¦íúI»¿Ëý×ù¶ëô jIzÙ:ÛillsâOyL'ïbodŒx’¯#ˆÚ“èo‰³»)‰¼JŸÙߥMƒj1- ûkƒ{廂uú$zèlÙ. RÅå¸Tþ‹Ç ~v8¸§žÑÛ=n–Û2lëİÞ×2#yÒûÚ¢î?0ó¶KðM5‹ãu5bΚŠå[ü°¤jv¢˜zÐÐu]Å‹o’¤ýTW;.cWÁ›-ësŸÈÏÈÊœžÝM’;)L)½‡/+ðï|Gœ0tiyBÚö…ïœ2«ÆvëüuéïÏüÐPTµð‡ú’ îÖ]Áx‡M´×…ð.[ö¿p~O3˜\se¹¿Êäbí(—Ž×§Æý]n:\?þ »Þùþûù¶ëÕWe™%w+=ÓîÇæ8âñ¹ôy[êsõmxAÏ ‹:Œ™Úê”ǨÛÇè è0æ8þE£º£GScšF|®Þëss ÍsEAì®Àá !‚BCCÅ ­¿t¶‹d¢´ûLžíÒzðN$ê=ýŸìa_bð$½ñgàí©^´k Ñ›ñ>µàª#˧ÎõKÁûƒœ‹ðï~þÕìïW ^ÐM4ü®lbƤ¾²óK/B#»½Ý§pÎÚê ­`Í_xÙÉ/μ ukÓÒÏœ³¢ÅRûöèê÷N4 x÷Êïb67H¶¹XÆˆŽ²)aü*–e¿É.¸ãõq®O-û;& épýøŸìú}óÏbëË×O¶þ]·J˜,äëÕ{Žë`Ï5à2ÅŸdçÁÀîì¸Ñ¾@*’ª¤G%^ôçÒ!Їá{ð ¼ (—±*UzžN:<ö£ïð½íw¯ÉÏÈÈËïÛ·~F¿\úɾtéfAÿ¼ìâBÄ÷0('{P!¥%¶u=?†_A|y(á-ñåA‘aÄ—-ÐñaÙ.þogËí¾<©ƒ/×ÀP£Q¢¡„a/¡3ÇÔ,ž–K› æTe/+ÉÀƒ²`u×cðzŸn?í3HžÿÈÊ «h¯A²‰ã'¤Ôö¤pAÕÎTh OÙ¹/“IY™Â/ϼ>µ]ÿ·ëÇÍìzèý×ù¶ëÕÙzº´Û³|¾Éæ¨×ÐtXÃÛ#!šY/œÊHÒÖ úÝ€÷õŠžî™›$¢QÜê—~µ ±ÒÓ$ñ&ŒËµ+æøåLÍë—›5½¾îüÑ“xåÁ-´OBðé9«vþñÔM‚—Oý2»¬¬v¾öêWØŸ§'©Þä´m=8FÖƒó ŒóôјSš)œ&û´€ g”ÎXà}L ª¡‰æ_j-í W‘^Å#ÿmÝÚÚ³1±ýÙ”¶œL AB´ç11Û­¨êmx6 Å$cÃyž²iI.Ë>’VM;àMm-ïf9SÓE •6¹÷´ùÑKÄZAw ú;c´ø&'šDœhRðÕ'äçéÛ)Çå«cs\¢?;¯•ä¾ò¸O¯ë¤;Iù›ÓÔ@è•+ÍY¢ÚœæîÉû»¥ï˜ùÎå…Pl<;nýŸ¬™ð”C› +¸Çå<š•—Wól>÷LÙóqÏï2 ÈÌðãŸÃ¼½›6uè.ìÖ-›ñý“ÃFAߪ}q*u“D¶ÐÁ_ä«D ÐÍ^ä3K¤ä±Ÿ±FÛDÉJ‚-aÐÌWHh|ÃÅô½I°Ø\"1¹®¬(0uoFʹ€ãLü^%6²gGN¥–Ä•~ˆL÷qe¢·ñD®lHÞ_z »äUÏ>6qá‚ډϽèèÒ%¥{÷.á䄹 µ5³žšg·ÇÅÞ:{‘ùg‹ª[N>d%ŸZSƒ‰3ÍR‚ø +å aÕõÈn+­{bGYlçШ„þÎ^–ðͽ¾LÑ3<²»ÿ® þ¢Åféa‡É[„ÝOy~£`/ÚÍ­ÿÛo$ ’¸÷Ûo=c¤¹ÿ4FŠmS‡såìùfŸ7Á,úƒ´xj´zD4S1vãµacÑaÿ¯[Îã«t|5_ìO †ìFþ1.ŸÜð•«Zh"7œ¶ÿýÛ dþ²êæ¯[šÉhjŸ„>Íï ´oiRÑš‘Å-Se‘?¸TºØÈQî¨T~oxiå(­¼ŽÍ¥!sùð³4"›ëLbÅú‘Û(ç.ÑÉÌñõÞ-÷äɰxž Fl/Té|d?‰Œ´¨¶éλ3î²rô–k‰3<[4_Æ8u&Ìëöãàn®‰!y’Þ©T¥ó üFÑóžÓÞƒK7äùñÓë÷½8e.·»zÏÈyO¼ñÁMMElÌDˆ<Äô!jªb•§¾TTÍDÔD#¦Æô¡ò4{˜¨‰™˜¾ìif*ºœ}çÞ†¨^~¾sÿçüÏ9¾ïÌ ú$(Kóú-zî"’ÇRìe÷=«YôTÕ1EɢŹ¢Z1uµ„J³'gš¬="É›ÏÔ9êõyJÖÉ2Ù°ëUÚÔít Mž•uc¦*ÈOTÜuƒ¤¸Uþ×ð¼@5Çå‚u7‹ FÜ>*Ò¸ÖïœKòþ)»oP“.ºÞºrnöd$cNUÓ|Ó9 ¨[²‚¸^2kRr®ä6å¾Píø6Õ•ñ剩ÉWøê™e|){ÑØK·uiÛ>sb{¸¯¯{¸«ÓÈq®$óx[Ƕ¤Ì¡,˜²n˜/ªo.%ïœQC/Cï ½Cƒ¾ý¡–#ßœ3=Dœw«Åޱ­òé°‡ÞÛšÀŒtÑöÑǬ’,×å‡9q“ا߻Nʘ§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€0N¤|äø:bަ¸Ôê$F‚ØX¬Èt¦Ôô8ˆ >ŒÆü.TœÈÜ  4 P ˆ ¸ ø , v ´ ü  N v ¾ ê  < X l ˆ ¤ ¸ Ò  d š è6~ô.VŒ¾Ò"VŽØ&P–Ò.t ÖJ\¦ââZ¢ø@\¸â^˜Üü~šÒþ4~˜Ø 6X„Ìâø^p‚”¦¸Ê&8J\n€’¤¶$6HZl–ìþ"4F~êú *<NÚæö(:L^pÔäô   $ 6 | Î Þ î þ!! !n!€!”!ò"n"’"Â"ø# ##4#L#d#Š#²#Ú#ú$$H$^$’$öÖE;/\TxœTËnÓ@½ŽÓ—ú@Z!ÄbVUóXÑ.Ú4T•ª"Ѫ«n¦öÔ™Ö±Íx¢(ý–ü;XtÆ-køÖ|ŸÀ™ñ¤MiÊ‚D3>s}çœë;Ç&¢ÇÞ ò¨ü­“vØ£9úæp…æé—Ã>­z/®Ò²÷Þá)Zð~8FàL©@();à)àû»¶þš!ÂY±]͉Å&ö„–#¬[øÍËî`3ñ>PyÇô Ò"i$«±«rؘ,ÛêK,šÆ¤G¸KŠ&rÙ ×PSD` ¡#¡ ô‰5ƒæ˜ÐH¦v%sKÄhÔŒÆHbR‘ÒÎÆÚž¨é_WEçˆetzËÜv™Ù¬!®'6ª0Ç–MÛ)='­Zh#¦ºr}†^+›ÙjG.*Œ®Û# Æ™V<=®ÎYv:rO#ÖãCv"˜±,´P°LY(”渞õ•,"Á${L¶ñõ‘”좑¼Auüö`ÛMÒÐQõI]­óz}0Ü1‡ ¬WÿZ¶ç¶ÁÂú%FnéÀröpPÿ”ÖÃ\D¢q k]ÝCþž= aO¡<»þX»4ˆÍ)oB˜#¯\ÝÜc¾›¸…’`Ú=‰ œQß6WwÛÌyˆ‹»³ÆF.o»;s-خĸ›Ü(¢@d¯B›:´›wìÇÌ1Þ+d*®'eE}o·ÝÙ?èÔLxkI|xœmÐWo€áçt¨R{ï½Wí=Jkï½WrŒžúêÔ^± !®ˆuCì1.{žàÚŽQn9?À›<à•À߸9þ׫¸‰’$+"EQ©Š).M %•RZe•S^URYUUS] 5ÕR[uÕS_ 5ÒXM5Ó\ -µ’®µ6Új§½:ꤳ.ºê¦»zê%Co}dÊÒW?ý 0Ð ƒ 1Ô0Ã0Ò(£1Ö8ãM0Ñ$“M1Õ4ÓÍpÜaëmpÍl´Ã6ûu$”`k(Ñ:»ýôËv{mvÓ{?ìwÌo…þ8ä„{î8i¦l;Íò@Ø]÷=ñÐ#}Œß{î©gN™í»]ño/¼4Çg_m1WÄ< ̗뀨…òòÅ,R`±O–Xf©åVZᲃV[eµ¾øæŠ×N;ãwÞ:뜋.¹å¼ nÛ亮†’BÉ)±ÜHzzFfj´ ägGƒpZN4äÇòÂA$$eÅ‚è?zÞmGxœs˜Ä©è¡ªÀÈ*ïÁ*Çü_>ÀGLÞß7EÞÏ'E^ÍD TÕX%TRø¿<;Ëy6 ¼¯œ|Š£¯¼°±P(+P+‹1P;3#?³=ózff6o·Ón·Ý˜••Bý•eŒ¥CÅŒECùCŒùC×óŸçg2àgdbde4fÍg¨gXÏðžE€±AŒ‘•qã„!ÁÚÚÞ;Øÿyoà ˆÞÀرA5D:Fm`ëØÀ±‘‘±/²µ·—ÁIÖ{ƒQpÄÙHï )@†€ìF1§Èâbmm’ÚÅqÅ% ˜€‰8‘HAxtomcat-connectors-1.2.50-src/docs/images/fonts/OpenSans600.woff0000644000000000000020000005411414655113620022510 0ustar rootbinwOFFXL’ÀFFTMl\Ä2OS/2ˆ^`¢ ¸cmapèh²ŒèÜ™cvt P[¦‘4fpgm¬©´~a¶gaspX glyfd8T¸2bhead@h46ù5âhhea@œ$µúhmtx@¼X±ÄPkernBÐ# – locaPä®®Ðó¼ÚmaxpR” R?nameR´Ï‡postUÌxò‚xéÕprepWDx¬›nɉo1ÉLê}ÉíØbxœc`fÉaŠ``eà`ÅjÌÀÀ(¡™/2¤1~c``âfgcæ`abbyÀÀôÞA!šAˆ ƒÖ°ÉÿaháèeŠP``œ’c bݤ€\¢÷oxœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@,A " m ÿ߀xòŸˆê’ü3åÿÛÕÿ?ý[ñoÐ 2„:À°ƒaÃb†)@ÖY†£ çv1Ìb4dØ36 ÕxœuUÏSÛFÞ "SÊ0Õ!«nìÂ`—t’¶@)lmÉØuÓb 3+èA"&czâ”C¦ñ­ŒHÿ—'r19åÚCÿ‡Ú[9&×ô½•M 3Õkß÷~î÷Þ.jûð Ðû{íÝÖÎO?>ú¡ù}£¾]ó½jå;µµùíÆ7ëk«_õå÷W>/—?+îÉOÝ» syûÎÌôÔäDv|l43bqVÀCF "_‹¤/£z¹$ü…®W.ù²‚ˆà'S”õºd"PÄOtA¡å“,Uj©®-¹-6Ø¥þò¤èóƒ–Æõž \™õ#³Î0‚뢇©Šª>Ôžvc?Äy25Y•ÕãÉr‰%“S¸œÂ,ÊÓ„/nr³°ýõÄbÙiJ‹;õ£ì´´ï9®”K ˜‘žQ±ª cU7!Å •ÎÎERz?ïÛì(\Îud'úYÃH„¾ñˆÇ¿C~–¤KÏþ^ÀCIz>,SÔæîužæû”F ¶ñ†Û‘WÿÞF¢2V°ß0Z‚U¾«]zœrÇ5)jqGýw½#)l'¹\|ê#ÝlGcˆþ»—çÔž`‡]¾ ¶^ÛmÂG­C V¡&º"ønIwÕqó×6;ÿ§fH ’ƒ ».ÑpÞWìèµt* vä\0µ²€’æÕPóñ>izC͵{(±·Í¶Ž!Sht¤ŒŸGÐ;Âéú…#m˜yë¸2žÍ‹µ•ÀØ ¬ªÑ90ZD’Ðë¦Î ¹Ä¶fÞ¦Ÿ+ó³bMbŠãK?¼O» @ Ñõåtö4(*tÌOGbÃN<ÓLX‘§0'+×Ý¥²ü“¶6.7˜« ¼`Å7çJøqè¥%P,ÙÒ—ìÁ»×ÉCá¼xÀ²À#ãù*NYÑuç Ü ž»'B;.¨;H}ÐØ!CK¯3™•=ÝlËfë@¯ I.Sð?#µ“†Á„l!+´åŒhh# j¸• ü…ñBÿl$Ü 4¸• ¡¹Ã†ÖX, ÿØØ‘|+è(Sµ>Œ6F"Æ©Ö7pÓ§\²P-‰Ñ#K¤Ö‡*¼¦P‘Åù¬Ö D\.ÐÐ -e »Ôަ½=†å†óA¯önI7ÈBš˜‹ê¡@dBmÙ¹I.lùZ¬ n Õ"ÎÊf;¦àraå `4Âj5€´Ä»WØx¤ÍŽ¥è0w×)ˆltbÙÖÆï“ßœg”k–5ys¯R.áÕVI$?k%ŠŸµô¥Í˜8ÛÓ·ªa%Hî¡N_ Æ”A-B $A@‘vQÈ{çR1Ö3ÚŒŒü¸Ï™Á²CŒ³Ç}+Åì4QÑ$RÌBM&Õ¨¡u±lŠõ fž„ejrTeÕ„ÊYÓ–“p‚.yÉ›àìEŽOs'A¯]÷y/™PNjÑC •Vx¶ÿ>õþ~‘cèf~1Q…—….6ÿ­ø¢CƒòkÐÀ›ÇÖàËËMl“ÜÄBÆr0)+0%+„o¾•âc„ãˆòyŽî=ìýpš€Cí⑟üéÄöu*ÀK%¶ÿ)ÿ)÷!) ÿÿxœ•||TUöÿ-¯Lï%=L&“BÉ$CËÐB€!"Ë  ˆ"Fˆ¡H¯Ò-‹ˆYDD@D& ²ˆX~ˆèúS°ÅEä‡\þç¾7I&Qw?ÿÃÌλóîéç|ï=÷!‚æÞýï÷ ŠÌ¨EÈ®£%ÄjÁØH¨Qî6ÚQA:Š)°ågZm8ßXYm°—zpN^ ÛåtHÞ”4@oß>ѳwI÷î÷– „`º•ÜRæ‘QrÈ( fÒj$"SŠ g²ùÝáöÊÝ)Ü^x|‹5-ÈøGÜSû ±ð¿W&BÂmq7ŠGÉha¨§&9Á)8´VƒAk3›ô‚Înw¸“dAr Å 1¢(9$‡Æ¹iŒ.¦™G# ؘŒ,–X§Õ¢ÛNu¢ )Øòó33π«ú¦Ðæ†w…D›;_y)Ÿ²³ÕwN¶Ç dÛ½ü•ë±{à þrâ|})ˆMì\É®’[%;Šoãø|v ûJv—Ô”ì(©©E·óoÓ2ömŠ7óWN¨Â[Ù þªbßâÒ›xwà—l¨JChL(ßàp'úZJ‚ zߊD5VÌl-J®ÙVär‡©´eKÉí3H†¾a*¥'8Üa7ÊL·"à.&3 |°qãb,gÒ-g€a…?øSYsH²Ó››æÏMÂn«¿5ÎÍÉ æœ.·œæ·º“°œïyØár[MXð|rî­ç\¹¿ÿ–µŸí›{zOg7\YÝoØNæï>¤¤?>¾â€ëÂy¡è|Ë|Œ§%¼V±p—½ê%¹×ÞŽ¶:±Çæ9m{yÙáxòM~± =Qÿ»ÕÒ ñ4Ò"JB-€ÿ¿…Úd´Lo—ìô‰:dÑY’}-[I™­^ðc¿?ƒ7â׌Øhl•A[Ùd›“bWt\ÀíyȤ€þ D1«þq~]l«Å›"‰Š}çZ<Ù®?ýR‹½»Ûvž3§s[|䥿¯{<û ¾Ù®seeçvøÈÖç×UáІWÙg5Ÿ¡ézf%ÚV®ºòݵ/ñ©Ÿj>f5n}ËŸ¹r姯ð©jê¹Ýü„ëzøÝjñàWüf£þ¡Ö­ÒmNsɃâÓñžæbNÀgÊh)´òÓÔjö'µ²%i{…“„6†âp›ˆãªÎk˜lcVFÝA›iÀ•=ì;.(WQ±êß2Î ˆŒ=~ö¦¤â£]ÚOºÿoE}‡<³÷)V1®d+Ÿýò°nö¾þþüçð ~y× 7à vï_a·…™„&vëÔ§ßÿ{Ïè:½xäÌ3•G‡O\_ºnç«+&ïÂv=t–}û»´¢ôÞÏu„y¼Àã•xáØ‹(ÂãÄ5©!B jdPSÊbø"Œ‰ zª“‘AHà?ͬ 0nø¹Ýb $âtØÜÞ4Rºqå™E«W/8½jÉÂZüÏXÆ,ï­mø=¸o¸o°þ¾:=d$À}]Óûb ‘½y¶Üâ¸l$¸qåé…«V/:ÃoÌ~gm«ÞÆ'oü†Ï½óËRiîIÆ ÉL(>d6±lÔiõZ³EcB¨à˜¢0ήÏ-Úe=öÛ}A‘’ZàŠ¶®úÄÖgÎ|Ç6xñc-${êá ‰ìÔC¸”íx/<ŒŸTæ޾²„£`G­B.‰êtz=ÖP£A‹ . K™CL‰Š@œƒI!€_Ô¬^ü3›Œ—îÆËؤÝdÆ.¼ŽÝÅÆÁ½ †mB?# %…ÌH¤¢F¦!©DúP¢ÜôLD:Ym|õ‚Ðñ¦6³ÿÑ-å»Ïö³‹Øô½B_>Lz’ kgHKõcŸøA[¹g!øðÉ“ªmðœ…ÀOLH/!œÐ~a-7ø:ûF%§¹ÅE=Š{—÷èÓ¯°û½¥ü`2Ô¤ØWBÈ@&楔@(ˆJEܽ©©ö__¸GuL‚Þ­òÅ30¿59lÈ I(6FëìÖÊÔÜ;Lc#¾Ô,Ä›™Õȶaå_«òÿ[ÍšßîüVSkœ9~yùüù3ÉEVÉ–â'ñ$\‰'²Ùl)ûä.ÂDŽ4,3ôoú @ŽyB$h´Æ½ c­„coùŠ,¸Uz¼Öœ  Ë~ †«w—CÓðŽctç+£bÚn|+ò95bM<Ê ÅÉŽ8BLŽx!1Áªë¶Ê$ã¸>a~gà 嫬¹#¬µÀ¹¸#QƒˆìïˆÉ›°;=B~Ïxy|öôû?;fÖãWžúàf÷U¯2²gžùê²'‹FMîØo㘟ìµë¿ßÔ)úòÍZÒP—Pª]ŽÒd£;Ejî§î˜wßpLŒ.55©w8UÖYz‡u ÒÊ2•·(ê”Ü•qMð¤ðüÈÎRÓqn YÉyȲyÕÎìSöÓ¯/ùpø¶ªý'fUà¡O¿wÃSNaÝ¥[BÙ¢·ši\¯­8¹ï¹ÖÙOΙ:áÐõ¡e™]·¬>¨Ô8~ t¼¸tbCE!¿c“^l¢ÅŽÃŽE›"•ذٖl#65ËåÊ ðl4$í¼òˆ”ZV¯Õ“‹áÿx@^ÇÂøã—kG“M—³:MB{ö .`‡qÁ›ô½š"<ñXy硵¿€§‚!@¢Ô6”l¦qNªqÆI‰ÈÚ;ŒärÅö »$ÉÐ;,ýA„ âËœÔ :‹‡KÌÎKŽ˜ô¼„ »È®ÿ¶¸ßGƒžßÊve.Ìyðr«ö3÷ºâÇ÷d¿÷ý¤uöÒX²:’÷ϱ5’d5h+O¥¢®!o¼5EÊ­4ͧs˜LI}Ã&“ƒ¹o˜ÈŽ˜ÞaÇR²U éžl·“ë“"&ˆÀù‰¨¨Û›¢d¶¡äí ÅÅ£¯Vë ™Û¦œø’ÝýòÙïË1›Q9sfñìžëÉD:ÈzÌUÃ~ì¾qî ûm-öÜÜ´âÉå&µ[rX‰× ãP{JȲI‹ˆˆT#£Jú@u¥%>¢NŒé\«¡¿Ö.ŸÝrû%¿«qär!/jƒ‚¡Dª19Ò=Rv–hõxÒÓõ¥ö #Y×7¬oÌ@õo%7pVEÅÀ!;çÖånÊ«Îz&$uœ"9Pº)©ž}x]ß¾‚Ýüægv{Á¦y“o®,¯X6g^âœG±qôã­ú~lÔLñÔ¡¾ž;ààÔ7?ÿàíÇ—ìšøü;wv2½¬ß¼|cÛE´`Ô}9¥]2s§ö¹o·î·Aà'ù¸NS ”`C’úÓ f§9¹oØl¦Nglï°S¦š¾ÑaòÏuŠ-Šá#6»—i¹9Tkóq~TþZc!ȶ°ÍsÛ†ýü£ÞÐîåGŽ|‰ñ—›¾’‘ÇŸš1súænOÐBVÂXŽÇb„mƒJ®Ÿ¿ŒÍëØW7Ÿ_^¾lé°ðÆA*FáyEqÝÅ㺕‡uã69ú…M–úS×#Y2:ÓXsþ˜tV÷ê{èsk9(*åóñܹæ“e‡â 2–$A¦v›€$‹´\¢F*iÍ0­E™6sØÐ!ïE™–Ï­¤TÚ0)^bV²«72éÏn5Ë’Ë‘Iy-p jj˜3-äA·^3Åt"]F¯*ƒ´=©n˜‚»S‹…¬šLz®ÖK.]Â;fàï²*vx(Ã;…ôº‚ë2BñPQA«ÄÒ0$$T6ãLÜO„Ü·&,ï¥Gì–gu ¯2z´¦=J ÞxƒMÚµ«)X$¢4JÿF»–‰‡“Kµ^z®&o†Ye13X)Ðh¹û ¯ä¶4Ô)äñ$Ä#ÙŽLö¡¹_p»¡HµXt½Â!5©_8ÕÞÈ*m ΋6Jîbu53äŽH¶“M8Gë"¾dôôn<8lsïþ§¿?v¥Uxü‚ŸV÷îÞ½MXÙgèØ¢þƒòÒvNz÷•^SÇÝ×cx¿ vxmߢî÷öSìqâÝÒAñ ÊE¨8”Ú9ÚÊ®<“·529\Í[KB}«5;æž{½>=9›¦¥£LÃfòìð>FQ__õ+Îä¯ó)¨F\nêt(ER½)q‚ëe’·‚š%5-Ø0\·9×ÒÁA/>Ô÷Q‡!kù ß¾u®ø­"ר¾C3öò'ìøVœ‡S.ýòÑÿAÙ2ò_xÉ øÞ·ïÔì=l3Í^F¾YöÓœþE}ú|ôÆ?1Ža™1/|ðÜ«˜.ÞÉÞúö%;9h˼ ?€E¼öv³7ØË?`ß5ë6E&ð?±§x¬Í 3I H¦&‚¬1˜e«ÅLŠ!ʈH°DÁóQù D1™¯.`ÓÖØ/ÁÏ‹WÖž[VC¼X ^–µÀœ«‹Ï™ƒ×°qâÛ]Éh¼´ùöæ3W²J°rHÂÈ©fˆrÔ#”æ’ô–¸8³ Ñ›!kb-–X0%‹BGqQsdûN1aO3ÁY_©x=öº2%6R°xã]¸56Îybà öÓoµ¿\»²fá3›Ï²5ë7=/îÙypö6—.ñÕ•Ç¿¢ƒ†M3¸vËšòÄä àO3 .ŸûrP³Öì¤q±vT¶ ©8lˆŠjª?áH¡š1€nn¹5¦™ÿ¬þæ³!;†nÿœbU/ãöŸüëà€ž/ Œ}Áî²_Yµ/ñL'<ûØ3ô„7—ë d&–Ì4 5ˆ«FA ðÉb¥ŠT0‡ÛŸÕ˨¶zš!jú5ÐL,cØ<6ÃCðœæ<»XÈl «÷°§Ù‹Äx碊©`>ZóéQ‡P3ˆ¥:Ä9x$mqX’ Ö‹Ã„b]qÿA3QžÎçð£¼hMÍqÚ®v7ñ×^à ó}6ù$Ëm˜ï6̧E÷€EÂ7P†Lä³™%¬§’D°M³~1 byt•,F¦Â;~¢ùê<|–àiuС˜:Œãµ\ ±kˆ&Î(@$óñêõ–â°^] Rû_×r+x<÷hpn· ®Œœ\ÏAàÏMâæüº„ífëð<úò™þ»výÈ~ùíÊ£sØ9[›’žŠà2</x¢”}~—Ý`?$âþÅΊ¼¡X ˆPù"ŒZÖhDDqýâZfƒ’X‡€¦5 vþ¥vèµkdó/dU-ÀÿÚmd@½ŒñN¯Y÷p„HQRËjÃotøÇgÊØ»£ÙX¼ Æ8^×QY6%äuV]}–¯D»Z]ä ’fdçþýò {ÊyK\p{Ö¿~ª›[L„û™Pn(AoÀˆóuŸÁ$B¼1QHwú(ÝM}»ƲÂa^{,&²«,wɵk#GàEØÂ*¶’5Sj/·…MÄçYÇCêœB<Ì)*kð&KÀ3ÈÙxPœ5 `ôÃ×ÈCâž;î3êo¥Íð[êJ¶éM&£i‰F%Ik¤.'±i©¤—)2Iœä&4×¥ ¥xõÚœ~àæ:ʱç³ëܯ‘ Ñ–^Ñ ÖC8Î~ù¹6H˜*,ºÝ“œ‡úît¨—_%Ðë·[,ˆêdY£Av5h ²Âšú¥×z㨣„çu»"T¤P•XÉ.ÖfiDÓˆSg$b¸(,é´C­&ŸáÆž~„!%WpŸ9ß€Ó À­„bbµÎâ°V æâ0µÿiÜñ¨Ò Eãtñ<ÛÈÞbo²g!3õÂ…xô-ŸúÉ…Ï>ùì"¹×ÿsØ4¶]g?`¶b#v±Õ(,Pðº¤kFz®ätèp\½,Ùd{qXnÑnÂ3¶àQ€`3¡À ØÇìêºkø%lÃÖZÿ¬}Û7¼¸•Ö\¾Áé_Ì5ûé'ŸPäÀ¶(r0CÔ.”, Tr!‹ ’¾1¶8lDü„S ¬¢ jéM옯naO]i*žÓGðPvUûÿRF7Ùêžl>.ú‚BuùB§ä 'Ç6§`qØ_¶²Ø‚ÛeÓ"m/ˆz‡ÞfÐ@‹HM.¨é‚.ÞL:-"ðwn}yÍæŸ»†ŸÅñà‡ßâgÙ/l35=ñø×®Ý'îùøSvíÑÚ¤H±ãÑG ƒSQTë(Ñ&ÚÜHHóÕ@v TÛȨP~ã…¨V ”Ut%¯ò’JgID0°+·n=7úëKç?qää,\üèÃâ£ë}¬Í„e_Sˆ—ý²÷ÿfæ=|éä>ý>\¹÷£ÁGK¸7¿_Q».®ÁÎÆ‚ìdŽOÆT¢Z ¶A‘±C åÔ§z}¡÷ý×X©Ð ^?œá1d7øN;Åg}!«ë5l·YµT45d˜@´Û@À2”Pê 4‹Åb»Eì÷½ Ñ~©ÚKÅ=5}6ÿZ‰›ÕÐ5£ÞÜŽGÑ0Rörx¬n µ Ñ¢° ¥&£–"R›º<Ò¸€ƒpä…—hƒ¹ÅP #7qVLžÆ˜gUêj¦t:“]|² Ìa@H®TÖAB!F1:­s|‚Ñ ,1 bR¢EŒ¡ºx‡j55‰â‘ÿx4â5#TûÔ£Ç;_<Úù{¼I«¹ei#ê2Ì×YÍ;ïÞ8—åÔ·²ýüÓ ¯ßœÿáu:6ÿ³–¡²k6‘/Èç5ÛÏ<{ßG耚­ÓZv‰–*6&€Ù`­Þ×B?iãŠ9äéOÌ{Ê[a3¶àÌ¿Oï†Wý^½â¥ƒ/îõœÛyjÿ¾ÃóA.°Àî!¬.TGuVš˜£/ bbˆ…ÆÄ IrqJMÝ£…ÅQS#x¦ˆN)z ÜIÄ%ƒsÉQУ§5&‹c—°©ú"«M·<3ò•vnzd¾ß$³8k€ÚïÄ¥TŸÍM/î>ìðÞƒì}vñ®x4³Ca·}óQæ˜8·à‰wŒY¼ëé<4úƒÆ”=(”Vx½eù¯Ód¤¥mZuàƒV—-Šw„³:hé{ù‘Ýïå;¤¸tÂýE†Ñîcùüá©*z«‚œ6üÀÉ1/Ff£V«C:·Ë¬³ÛŰݢGXçäIº>—ÕãuGN±q:d¾cÑÌ*L­óÈêEW¯Ìm^ŒW’ªÙO¾þaíEpÿ©Ã.ÈRëã @Àfñ¶Ò³“JB‚¶ÕbL–3e2Lž(Ï’Ÿ—_“¿’¯É²LÌÈ(È2éLT_R¡Ñ <«®^ý½[¨c·nCÝ„Rì+èÚµ }·n|¾»ó™C™Ï€bP—PK»NÁF–ãb]!³%Ù’iékfYfyÞrÖò•Ek¢ Pĸ3©Ùƒ·Ð4EÝÑTÇví¾æê…u”0Gì~Û6áüÄWwÊ£hRå¿@Ù7oJ&TMУPnÒÈ‚ #zDÌRD Ö&Wq› Z(©è\Æ‹æâ>ØÌºà ¬š=[ñÃR´f¾Úøò86WrÔj?Auócž#(r… h…$M"èºh.a.U/Kàc^Tò&ÄÛá;n2XO}©£Îª7'€Á4­ 97„š:gxnm\æÙòÿ`Bnŀܑ/kÝ%¡¸zxÙÓ³®îóZ¿ö º{¯%k×”÷Þ¼:¢lÁ,²mVùëÿ¬½ ”®è;`Géà“gj3ùw¯¾Þ`ß@¯e…bJº:œ@('ÐjÑ›ÿܼÿ‚4Õ¶ŸYÈIÉÞ÷^Êm{çÙÈôŠa«q»æ4€WñuBÙ e”Ë­ƒD¢³Psa˜ºþ¯óm¾\œ‘zšYù¥PÎ~¼µñçÙØqçSs^ »²z.I‡œúáb,ýgkvšÝfxžyLÉûW)<7C¡f1|åNN²ÊVO Õ#“ R¾ l[ŽGñ ©­ èÕI  ¤6¿WÑDÀåä©0ó¨\¾È…5™®ÔÄ&|qö»«ìÖâŠÙ+ŸSéX»8‰µ“:&O­R* —îß²Ûûþ›'ßÚH‘ÐÙèÔ¡P³$‹‹Õ™cÍ)ž¸x·9Ùe°Ùä°Íb@…aCtbˉª`UB•ÒIU—ÅÉÇ@r0À­(/è•ÈÐÕsW?9çè™ï«ÏŽ}©“&îhµ†ÇV½úß™Ý'ßfs@Š3Á_Vï+~?‚?i52 QžW@C! ·!¢³uN¾+È.È.§q®³r¡{kwvÞ’×®îK6_Êt ûVÕJŽz”ß$Ô?ËàþŽÇu(Ê« 06ø”ÃÛ=ì°PMQ´Ñ4Åã<á(‘(jÚH†Qˆ€$`œ.«þâÒ¼£UÚLyhþåãGw¿ñøþ/.x¢=n·ù]NªlyOû´ž«§-}¶ïë=Çå䜢ÆÿÝjò‹X–Ü!”l6Øù‚­Î*¸]FsHk3˜Í¶"ÈŸŠª•n<ހ݄ãSJ4/àion89l¨ë€þ™Ù®µ›KVàvìø}Ûâ_·ºñpÒì€oîªÝy_?•ŽçÀ§Æ ¥P µ ¹±ÕêÐk—“ˆ6­9ESa}éAwQn\Wp«¬>ÐÝCÖ›žzï§±W/ª^Ñ{àÉÓä|í€Y³^ÿøïì¨Ã’E0§¼ØZǼˆÑ‰JÇ‘Y‘€êëꀺ¹0à(ã-lð­¯Û4Ú_ßfƒ„ÒÚòÍ£‹’J~w~ˆ¨Ò¸"êò$"·Ý&hdS|‚N+hMî19 ÝTãÔÆ Ôe“;Pàüš÷Ð4ê%€åÕÙ9–÷ØÙ¨teq]µmSV±öþ/KÚ8$] s&/š39¸¬š$*ÓÙõIµ ¨üêýå=ÞÉ$…µû³Þ¿gæ%â©£@ÔW¥Êúxd&‘`”¢$ë%Þ»¤°Y£wþ¢‡_éŸcK°¡†a[Œç³›ì„›$—$²r\YûMíi1RÑĈžŠÞaN‡NÐhá;Ak\NÁáÔ ³Á ±!’¡ÆXËêQåR ‘ø@Ó_¬m›+Œù+Øù>=s»nëÖ_2oZðY²ñN<{Ùºßp|,Ÿ¿+øþ"˜¿óä×Öa~À{fó…yÎü¯˜Ÿ.ªy‹dÖþJµ—H`5îÞR+©²Í¼ýƒ²¶Ó-ä×ÇØˆIv:HLMJ´b¦³è2ú=DÏR 0@L¬^§"qÞr½ž‘oU+éO.·tàwN¨ÍœÆ!8!>à »9¿òÂ…Éc._.›òÝiœ¼ÿÐýCppÓª=â½¥ì³~Cê)öIi²—¬•Ó•D2Yƒ÷1ÞÇHáë‚Ìú>F³øÂîÝ’å–¹žŸÓÀO’ÂO¼Mp›d™ïÐfɆøxsܬ¸eq¯ÅŠ;'ÅÅÙÁÀíÅOÀ ñCÀ™Ûs†‚¹àÊ9iþÜl…£€b->{ââ°qãf^¾ÂWGg•ϬplZIöâ^ƒ±4cŽÓà?[”Þ+îY¿ƒ}=ºÿ¡ûPû I;!‹ŽG…RÍULµZõ¥a€HV¢¥V)$ñ­)Y*&J‚¤lýóÈÆa²Ä³¼W·˜*W©ë]‘íÆ”4î™=³Ã¨µ§ ¬ ç”·}pE§òþ³Èîö=ç vl{pb²7¨ÖÂsÁ!vC•Z¸yÈ&HÊ'dTÛ×#­Û×í»«=¼JõyxG€]Åž^=‹Š‹‹Šz“¹5ñžž}úöèÖ¿ð»òÌMñ4ØXÏP ÑÑ¥5–!)Q$$¶w DI„X“½wX¿’¡AFg†dsï:®€ÉèÎ.µRé¨&¹9¶ºNjo]WK^œ¾hÓÙ“§þùܺÊ•cW.^¾°×ü¿ýÜN²+ÉÇ{(ÁFˆ§ &Þj§ÑëÝf;ÑZìî)9IÓ7¬1Çb=µ!$ͲÝl3÷ ÛbêÖ„ oãF4¢©‰P%¤ °)x³êY)¦Evy³xóãgð6¥s ¹qçúÈ¡|#ž*ÝÓýâí{îŸqöhÒœGömÇèÀÇ\oS1â…-€üPÁûRL ð­¨5˜€ä8]‹æZÿ@DM²Óg–“ÔP™7©ËvGÇ{NÐtó´tË€"d·ìçY]öÓ‚u¥ÈuhîŒÊÑS¦Œ„·‚‚ŠésGM~2\9½2TõôÐO?=bÈr~üعÓ+ :UN;zÊô‘Ó+:t˜5½bÔ£#çÎ cÔxÂÊÁ?]èþPɪ׺mN9Æ-Ùì¶¾éoOéS»Ýàԙ̦’°l6°S2ÔuûյܫânÔzË{c´8 æzøóæz”?ø†áN7ؤoØw8–}÷5»ŒãÙå±i7i"Y_«Y»aýë7¬%·߈Š=2J }Bè´*P7U)ÊQ‡†^&¬‘ˆÄcRÍÖ­æ[ÅϦܽNH^”òQïP«wZ|kd³cƒ|¹BïŽ÷hÚµ¥±AGvK)I£1÷kpRjpRTùõ‡tU…yÁˆòƒHñ…A—**TwLÔù6‰²{b½{¬¼øÖý[Gu}ô±G&<ýÚšE‹ª?üx^ïwû]m9zÄ’§:ìk3~ñø'žÏëFý%•é÷®«X™ÒrsvÜø¼¾®ÏŽ=\²léKÝßh¨LÏËK ™:"£°ë=Æô“k¹äç ]#V+û‡I!ƒÁ&úccÌÔ©E™MެD¡X_4®öui“[ÊiÓ/€O¡Î6]Ä郃¹¡¶íø{^A[¾3únµÔbŒ ¥¡<ÀˆÍ©93ÙïÖšîdñv6 o—̆dÃój0xñBº×^·­>䇔è (Îú`nŒsÔ†§ƒð–AªMd§ÚêzhùÄÇž|²õ”ÇŽ_øâØÂ§;«™w}Ÿ¿Ž°Íže›Î|§Vmé/¿Â.¾\žÚ.èþ¾tÕsIÎçÿþòÓÿ+\dç”ß°Íïg[?<‹½·]ªz{^©Â¾ª­ì nWù”Uâ °å‡õØãqÇ˲ÕM½)½ÞžÈË‹@“]V?r, øO“ !ÝÒp‚e"mYVå·"çžæ¾É­ÛÍl²/&¢?ì‹A=ôhñ¸ü^lÍ9Û]¸[¸½ƒ³Ãá\e=0ÙTÀD1¨](Q'Š+r:].M\¬Uo’Üf­Óo"…aSýÒÒ;b8‡(îUñ¹ß üZ•ÕÆÏW.¬Þ›bl³lì⾕¯^Å[kTX¾êÞþƒv¥²w¥Žª~'±aºä«Ê9!ΈHÔCÝŒEÆ$šh¯° eÖδÌ}ØkUÏ¿å<Âô‡tìÿ?§?ÿžte5Ò¬ß+hÀvû˜zV‡äã”÷T»C:å¬Õö ÓÈáž&^ÒÐ5MÎGÕ,‹y÷§hu› üœ€ÚmsHo*2›M2‰jÕöF´:"ØÜÎ €]àmìlç`^·¼‚7ú¯kQ2ˆ]ÿÒ¼Àäɸ/vë@ç0>W°{‡Ò§“ÂÏÕðÞ$lÐËZÜLÐ&q£«[$q«Â(Àü`/@û©hÍœ6Ǿ ·@cî·µ ?rNñáãÎBŽãu„/dãç…u¢P“A1¡Ž!ʉ(p"Fröµg×ì|}ýºÌÒgàÀ>ü%ŒÞrðЋ¯ìgëÄ &N?^™³$*gÁœz­@•‰N+™Ì€¼ "OY™ÙQÒÒb¿±¨¾ ¶¾Š——Ux ëÀ6Tá8v¥ —7ë7ÆC‡²’¸†ˆçšöIYâ‹'[²¤¡™ß#«Œ>¦ƒk÷"í”X¡þÍÍåc[ÃØ¢ÈØJuìç|ì£t3Œ•w Š”ûBõ#O)c¡´…÷éªÚ½V M[оA°¬Þø²ét àAŽ+ŠBi )(^¶ÛãSh‹æ‚Ûâ-ñDOãã->_r¿°OmûNiºõ÷‡–oŽx”Ýe^K¹UÝ€·sdRYTZöDLJTUZúÅg¿o9`òÐŽ×`eÁ¸5%#Göê34˜öÆ„C¯ô˜aš7ÉV!³ö8qÔV“vw‚ø¹™J³w¤©¯' ï3 ^ŸO_i`u2zœ˜”ï•þbE¶Í#:Ú«È ;äÖtÌ4Ô翎9~÷wuLLÓ1ëÇŒC‚"‚=uò¿{׿”û´RéaËÕûîó(a}Ô˜iw{4s÷M³7jÌqö‘:ÆÒpˆÆd²B:fû"Bj|¹êù|q¨ÒÓƒº‡|FdÓ¸\ ÌŠ‹uJ²T¶É² ÕZ‹ÃZ*¸5€+§›Emhç« JK8IW{³ÍÄ¡J_øÄ•+ñA|?žSóûã8Àμ@lä¶ŽÍ"O’Yl>Û…–õ8ÉEä*V*¶Ÿ±ý]*¯q ¼*ý£Š<²U¹¢éªxþzÌ4ìÿ¯cŽ£ýê˜Ô¦cŠêÇœ@;Ô1ÍšŽéX?f:ñÅŒˆì1ªÄ&Á$¬ƒ\“2c*ÊZ¾Æœ‰†ñ³±™C"‡o Äk`QŸbûËqîQÎöân3Ù^v œœÇ…³Ø~\8“íaûÊq! QzfÜÝ-žkÀ‹ã¡Nëʬž,8(A‡DÎ,úRÝI®dÁk¶iDÞ_JcwF6=®>f@9ïÅ×nÔ6¾¦Csü˜Ã7N«ïÃýdõÐ%#ð.Ó-u”•Ôî±è“ 5›û^ƒÕµäö[0tù1<ƒ7›–V ^|‚-ÿúéšíyÃéw•´´û‘ËUéuTôsODÏAÕâdßtÌ4ôós-RÇ$5Ó±~Ì8´.â?þèx*PîÓ>2×@õ>¶È}"ýÄ+s¢ÂÏŠŒZ¥¡ØíâíÍHkѨ´´’l@üFI¦¼×» !hF:\¢šêzŒÎ@t—ñ ö»ZuíÚqlÀ–Úä¹ooß´} Õ|sƒ÷üú/æ|rñ¬™êž1ðF¤d@B)>$%ÇšZe “#9CÌ͉õY³2œYÍ ÃYÈê. [w|5ÝõÀu7'‘Fë@i‘ÇOÔÁR¶»9žÊ{w”—‘?lðßZ}úÁÁñm7wy·ÛŒéc»vïš7qÖ¼«_ûôåžsÝÚ&$ÒB‡=Òý¥íNø²ÖvسÇý Ì Þ(ê÷ðƒw¦+Ÿ©â:SúÙ$裫’ߺ¬GÜ3ÛX¹6þäú´âÿ|ýø÷Êõ@£ëâÍúë'¾U®g6¾^]}ÜoHñúöVÕëhÜT?æ=“:¦eÝð]#íÊ ›µšjJ¨Àcv 9.WF®ÓÃqbþ=fOªQÈè„TcŽ«G8''ÕhÍ* ePšÑ’Ó=œÚ¢(œ”êâ= ÊöQzt§Oä­éRŸ‚Dí|&7‡#DŽÄøÂ-o¨²yÔ]Δ4u'¨®ÙÈÊÁUÙ““6è×ßœZ²µçÀs£þ=ê±ÿýçÚ{tØ»oû€W',¾Ðeèá/½}cëËço\N·®l‚ ðTÔ˜iw³›Ž¹ËÇ<5æ8{KcióŒ¨Ðs$’ßá]ÍïÖºü®ôið§@]J7$$ @4{ŒØ¢¹+Öj²ˆn³ÙÁãOr÷°VKÝL}Ýëwâß«‹B|ý»q£u¤Ÿ)ç|ÝÁ4%øƒ.%ØhNÉPÎ~ºs•ý/–¾øôošŽ/ÝøÁ€~ýOûnàuÏÿ²¶rí¼Õ VÏ#Aöû[.‡…w6­™;½]úÊ‚~ +&-fsسÖlynýæ=*ÎPz^?ì§ú¡G‘NB´®Êù•ª¶ð¶¢Ë俺>mâ¾~Ü \Oit]™_½~â®r=©ñõêúëãlª­¤GùøpT-d êóœâQN(ÎeÑñg-Y„ÄÙk7Ú•c¹™+r¡ÎâÊŒ†ÍÊÁÜF§š>§çjׄ:„ºæ·ïR÷NfìÚÅjBÝ‹ zv'uBOÙÝ}B¹°H©RPßPk¥^Hp$ ‡Z/ؤTo“‚!¶0l´PO£~Ÿ¿,¼õCd(R(H¢R84S:–+ž_º;î,ŸÜíé>ók.úðüö[=—<¬æd¬ì™±X×ÏdÍIë:¼8îŸßÿpæâD“FºzU¦8viÅìl&=< /ûˆýÊ[™Ÿ)Ì‚ÄJÆÇoÙå{ÿM\qðí~žU~ƽ߄纞;¡4ºçÎü§=wBiÝù/9^<ƒ( e‘ÙnOŒHeM<ÍÌ6~Rëõ-õT=†lb;‡ZÕÕÇúçDU)ÕŸ§l@š‘6ª 5Mޝù l<{—½„â‚)CiÛÚwI|íeºÃ>üôã+ú—8”ãPcñ<· ?…\ö#HëWö½W@>Õ‡ªåbÈÛ‰¨dF’šáp¤¶¶'ɲ=.UÈÎ2A—á( 22ˆ…fd:sË¢°Y§óóæ9äîF‚.%¸ÔíÞ: ݨlšµ•œ-6óKžµûÙÅ36ŠnÆQ«S>5Y‹Ï±ïÍa7ªÙ÷ØöÛŒ:WÞº„Qm’þ™ eÛ†÷íN÷Ê•K*ç¬XV!ÄN˜¯Çÿ~Òqäο³àô‘ð߾Ÿµe›/ýPs/)xçÈ¡ï:øÁ¢Eó–søF¸@/Cî1ðÝ~­† ?¦b &#ÑÎÊÌŽ;“Ýds(Í/ÉÞܼ ÇåvÒ™Žyü¹CX(8,\èñИޱï=8áp,"x¸ðm'mRžÿÐ2ä2 Ô1nó#ZlÖ&k3µTë |ÝlÈ_.ÖÉ‘ 2¡í*~xö¬ñcçÏmß:³ýC­Û‹Êf•—=PþDYv~~ö¸ ç§ædâMðÓìPŒÍ.kì·Ë‚D=P¡Ÿe_f'öÙ”÷Áõ±tÖFÇXRZƒGÊ^îI .`ÂTÓ²_Ÿž)ý7T–¥—öé‘Ò7¾Üð”pÁ›î²h%ÿwÞZu ¸Ÿ ;È\õLÄ÷±¢ž¹TJãÖ•ÿãX¹al,=Œ§(g`Ü!€˜²¨Õ ¡îé]ꚯ?ÏÆŸ)æ38Êò¶…|ô°ë^7ù.ú-ú÷’ò{I4² ÁïßkØëR}G›sgnë–,îqc×±çc•¯&Ϥâgþ?ŸIE8 Ô¡Ð`â+Á²‘?ÛJo,fÉDtõ,¬_jγ;^ŸÊ–ïË-º~`¥*?ÐÏNcûŸ3 l6šÃ¨Ìaàsè ‚Ù¤£êÓ Þk4‡J­!zŠÂúwxgîÌí@¼ø‚*Eæ+üþéìm¡Èï[ºß?J Yñ5žf~pÆöΩßãmfó÷Ï>eÿ‡…ëʃE„몼+ñ92KÀbí{"ãB™gþl}¿rÎã3æÎ{ì±y¤záò æ¯^¡ØK†*kÕ1!•ˆÀŸ÷!‚kxÂÇvQ£wNá%îÜóçš`1ú‘n2ôÏW³^Øtøé2åìW\H†Ž ©?ú…•ˆ’­>Œ,«©z—ª?úÅŸ3Bz’OÄH‡¬¨c¨™c½,@.~ì6 ð\ÙN•i3“ÙMñÖèÇ>©Û,J߇òÔ§Üœ dÆä“òwÙcxñrvTÊI]MnïÜ9‹t©=³kÄè±y»‡ºa®xðݤPgÕh\É4^ÔYcâSåæ~)1)±$LÍIÉI™I‡’-MrkcÜ1%aucu»í))¨w8E¶›z‡í±MWÅ‘sÁð1»aÎ ²)JOìäiЦ>:$ù½¹nþÍCJëM^òF>ÉZ‚×±!ÜjÙšÊÿfç[¯{š§×¤áìë'Ÿë¿A`UÛ6dýëÙÉŽ§;`Ííõ>_§ wpÒÀ·\ÿ?>Æ xœc`d```”œu莈O<¿ÍWy8ùöFŒþWþO„}{1#HŒyxœc`d`àèý»H2ü+ÿW;Ž(‚®”¡¾xœm“1hQÆ¿{ïw¡d é$C°RBHƒ2ˆ8)ŠˆH()Á¡S:…@é á¦"´]Ú,Î:t :Hpq(¡”"û½[lÈÁïîÿïø¿ï»[Àí%a@£©_¢é®!!§¨zWÈ»#k4Õ rdKJȰWT+H©3¤U’{"ÄÚSÒ"{¤@VÉ òŒdfý‚Y¯62ï £ú B~U7¸iôÝ%4ÜïèË!Ùæó4<…¾ª‘ò´ìFY/ ï—Ð÷vH ݪíUP–cDÝx/cÀ?Å"Uä‚gma[uÑ23S“’ETW§¹pžK—³Oè_œkBÚ¨¨!V¤Že7Œ@m¢¥6§Çrfïÿ©ËÀ®Ì]çþ+”t «ìu$ x'Ë>"Âó靨Ñˈ˾s©~S—3ïyNÒ3ß–ÌQ¨s¶˜ ¬®±ÁYrv½75Át¬p`kC$IÜœ…>îjÆoç#ß?D^/2¿:v½.žGdÞ¯[ßïÁÏNoL6‡9Tm:f﨨Ž{‰Äßl.Ìb›ÅOf›§oÆ÷{ð#سY´ÿ‡|¢ÿmªa(ßPù—Ã]Ìw6°ýÎ<& ›Õfù ÿ-ׯ@:N‘: ·@œWˆT )GÄÒÚV8R=þ=ì:néqˆs§þÌ0ÍŠxœ%Ù»o$gvðÞ@I9˜mÀc›"MK­¨)’Ž4-R-‰lÚÿƒãÍúiÚ»I£_h>Š˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€4ZØVÎLf’Àò BZ|šÜJ¦î<˜¾&†¾ø JrÎX˜ò 2 j ¢ Ô " T j ’ Ì ê 2 n ´ ò J – è @ r È2fЍÊô *ŠÞjÀœÚ\œ´ F†Ú.^¬ð*Z²ì,`°È``’ä<˜îŽÄ@’Îðø‚˜Ð F–¶ü0Rˆ²ì&<RhÈÚìþ"4Žš¬¾Ðâô   * | Ž   ² Ä Ö è!!‚!”!¦!¸!Ê!Ü"&"’"¢"²"Â"Ò"ä"ö#„## #°#À#Ò#ä#ö$$$†$–$¦$¶$Æ$Ö$è%0%˜%¨%º%Ê%Ü%ì&D&V&n&Ò'X'†'À'þ((*(J(j(Œ(¾(î)")B)d)ˆ)¦)æ*\ÖD?/\Šxœ¥”ÑjA†ÿmÛÒ*mñBDd”‚"Í&)""^XÛZ„b¡ñ›éît35Ù]f'ÔôôD¤Ïàµà#ø‚^xç•â¿“©imÑ,3ûíì™ÿœœsf\ Rþ®cÇs€9¼ó<†q|ô\Á•àŽç*悞k˜Þz>…Ùà³çql޽ö<³•Kž§p¡’{žFXùäù4Âê3Ïgp­úÍó &k·=Ïb¢ö˜‘ÕI>u\T%˜ÇKÏcÜýÁsðÅsóAÇs ç‚WžOárðÞó8^ß=OàêØWÏS¸Y¹áyO*Ï=ŸÆ“êyÏgð°úÆó æjW=Ïb¦v+ÐH8,ÇbÉgIŠ!ÇÆYu¸*°Ï±ˆ&Z¼Èk´Éø¶ËÝËdÃ=å,j†!°¢mõžŠE,­Q–ŒN:Vì‹Åf«µ Ö²,é*±œ™<3Òê,å® J) ´)—¢p¤Ð£ð¥» ¹JE[¦…h«žÞʺ\Û¤Q‚> $#Á¦Jú]IX¢Dä$cΆruŽ¿q#p—zÚs‹hR®ˆT+#êâxân_sn5›ÿñG¹0 ŸÈÒqèœã‘2“$ZaëþzýdõR¼>?)*íæ²úÖÕ0v:eŸr-Ãö±šK—Mᬼo¹Uã*PªY÷†½¥·È­”=6|Þaf³9G?û¦(;g”])¬‘±êIóTdÛM#ÓXôä@l)aT¢ « M§"RÆJÞwúF±ŽÊ¶*“Úà䯸P_ÂKã[hðÚuWÈmGE#/:êÑkó[Æîîn(½rDá0Êz—µL{î¬\§$´vMè4{,Ô]ÛA®bUè$eS…Û£ýº«„rUÖ®(]–Âe•—èXÒnøttOùuøµ}Ûu]3‚‚5ê»äÚŽK¹ŒxóoÄA/†ÍßgfäÛd¶sÌ3W®}¢æËˆ‰[ ßB,²ÄbK-·ÌEû­´Â*«}òÅ%/tÊ+o¼vÚç]pÃYçÜ´ÁU×\…CIÉñÜœ´´ôŒ”h~$ˆeEƒHjv4Äây‘ '„3ãAô/¸¬kTxœ5‡;NÃ@Eç1Ž£Tcaþ<ó ;LŸ(…q<„ŸyRœH©è)&=4Hi‚صÇ]ö‚P° –`GºGçößZI@ø„I=„ßó Ÿ_Å.^ŽÅûxrfQ÷8Á½N…M£B“Wx!]”±ƒ¨M àdDœƒà=^p¾N?Ò¯”¯‡Äm<¯7Œá(9$7rÈŽvhY‘ w(@ˆOQ nn#ˆ=°GV°ofX žlhÀ ^Ë», åªYÝJݺžjXèn¶qÿf¢Í…f4™ŽK€—üy¹dOêÓl¬/—ú¾Ë+m6È• ÙšÏà µ•RýÏïÝý†eFútomcat-connectors-1.2.50-src/docs/images/fonts/OpenSans700.woff0000644000000000000020000005433414655113620022515 0ustar rootbinwOFFXÜ”ÜFFTMl\¹_"OS/2ˆ^`¢tÁBcmapèh²ŒèÜ™cvt P]ª-”fpgm°´à»s¤ugaspd glyfp8ãWd`û…ŽheadAT46ùC¾hheaAˆ$ÃøhmtxA¨XÌJ°kernC¬# – locaQÀ®®ð æmaxpSp OX÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{Žxœcag``Ý$KY·±že@,q@ñj†ÿo@<ùODu‰þ™òÿõ¿þÿþíŠý c p@¨§ ßµ.3lbd²˜á-Ã}†M Œ! È!ÓxœUÏOGžY 0d¦ê2Û‰]vI•´Jaj{»nZŒAš%=ì‚A¦§œrˆZÉ= ôy›\LN¹öÐÿ!‡öVŽÉ5}oÖ&$R¥®Ö»ó¾÷sÞûv¬î?Ü õîNg»½õÃ÷¾k}Ûlܯµjåµ¹ñõúWk«+_~ñùgw–?-—>)nËý[ó7òîµ¹Ù™é©ìäÄxfÌá¬$€GŒD¾Ë@ÆrIó½Z¹Èz"€¯LQ6’1ˆH@_ñ8…–GïYªÔR]ZrW¬³uJ!üY“bÀ÷Ú׿×d(à®Øu¦h…Y|=lUT­ þ¸g‚käÉÌtUV§Ë%–LÏàrW° %|aƒÛ…³¬%ËÎRZÜiwa«­ƒšçûa¹Ô„9Y³*Vµ!a¢ “6¤8¦ÒÙ©HJ/ÌÙÀeûÑR®+»ñÆbô5c1¿A~ e Ÿü5;?„’¬°DQ[Û—yZoSr/¸R˜W ·#/þy‰‡ÈDÁ}Åh Nø¶öéòêØkcêRÔMdâÁ›þ¾®4I.gØn¶¥1ÄàÍóSêg!¸Q¯…í׷[ðAû¡§P½¼7¥¿âùùK›­ÿR3l 6;ìûÔ†Óbû(@¿­SY°}ï)SËK!8i^Œ4î’¦?Ò\ºGgÛêh™B³+ìøi ý}d×O4éÂÜkÏ—æz^¬.‡ÖV`UÍî±€ñ"6 ½®: oÈŸV˜{¾.O]ZÊPö¨-M{£ö؉ ›aç3œëÎ;Ò•fa›˜ê‘@Í„ú’wµ¹pßÊ—bã=us¤&+[CÁå0 ÃÊ›Àˆîj%ïÙsƒ#ñœ.rÆ2Æ$J[ˆÂÈf×ÈŽ^·Öxöüâ=¡\×Y‹·v*僕Dò“v¢øIgOŸ»Œ‰“ýÔáN5ª„ÉmÔésÁ˜²¨C($(Ò6 Ykï+ÆúV›±€•œY,;Â8;8)榉Š6‘bj2©F¬3ˆeS¬o1{%ŒZ¦¦ÇUVM©œ3ëx 'è)"Ï9cSœ=ËñYî%èµmáï'SÊK-úh¡Ò OvߦÞÝÓÏr ÝìUèBºÌ÷pØøˆ.åç°g¢>6vGƒ7.7pLr ™ÈÁ´<¬ÀŒ¬¾IøfŠO>‰å79º÷qö[À‰µŸ¤øèϸ4© ãþ]þ##2¿ ÿÿxœ•| |SUöÿ½ï¾%/ûžtoš.´¥”6M;ek(XjiK[km+BAöUDÀŠˆˆ¨ˆˆ ¢ã BE†q”ap\ ""ƒ ?†_eq\Ap„æöî{Iš"þæó7¦ y·ïž{Öï9÷܇84¿ûs|\Ø2¡Ì€•hµÏ›-X2HAƒ#¨¬,ׂ|+.µø|_Aì%\Tì+t:ì¢7-oºäãéæÑM7ÛÐ8NŽ]9ÕØÔÜ0jL!-'í¤\™CB /!B4"'¸¹ïH¡Ãm?,„¸3¼ñ³ÙÙÜ[ðCØúŽ3³7»OB<v¡”‚ÚÃ5‰)Þ.ËZ£8Þ-¢ÕdÔñZ›ÍîLN’xÑår»í¢–Oõhx.SÉç°á¥uÙˆ¨µe>kii~>,Χ,PýeÅ.X¯Åz½Ÿ@©äq¥6/{û=%ð¶ùˆ½‚¯ÄK¾ÌÇ=YóIí¾ê“U°#¿ {j:kÔž¬ý.”ô^þ{¤ú«èT¼ž½?úê~ŠNaïc_}…à?‚š»WòÃE+JE™¨/z0pCº‹$%Ù bNŽ';9 eiL^‹Ç‡,(¯_NRB†t‹Ç’•Ÿå‘3D}¢+qTÐîõuAA$¢ ^y„ÊÂk5aB͵X‘º¨ÒR哲"fø\X¨|Ãþ©²–m%‡×Ÿ™eIÆ.KV?ì/*.ñûN—ľㄢÌ,G1¶;]~‘þÅÑ•—^¿åÇqÃlýìðÊÏßhyvËþ­5ôøðáÑ™ƒ‡/Ň~·×väP5¹å".ޝ}mÅš¿ØŸ^§mø&`¤§FÎ|àŽœ)?»¸·û–&Ÿ³_TÖ}AüI8ŒddGn”:QHwº\‚ 5#³ÛላËö&{ÍÞ~ù©¹‰™qnÑå&É*¤ß+,+c?ë4¿[he‹|`ësú ýEÞ4QP4Ûoö:3°Û®wÌ+7®0ÿe玭»pð¥?s¯tøŽä.¿ö{-i뺲¸í‹/¿ýúöïWª„Ý]œúÝç_~{¾c2oè>/"X[È¼Í ”æ¼ZœäDZ§ÁfËŠ‹Ï2 #äK–¤B—'Þ©MOÏÏ7ÇÇófsNMÐÌóžê oÃVf´È]Æä[êÎg‹S„[ª˜{©º–¹ò?,?gÁâÒ™PѪ.áâXkãA 6b\” ŒpØ]C°ˆèŠyïüûýçµ#‡½ÿÍ3oĉ#Šðô{ëºÞ]:ñÞ‰t×€aøŽÊÒa5·5³üÓwVîmlúí­ÞüÚAznþë+h÷„eM“㪾ã¸ýƒ›§ö¿aæ7ð³Šß°ÂÂsÌaQÖ : ÅQ¨>Áøº‡[ã (5`Ôiµ„ç‘$™téìïÊ”¿ó…}˜Íl-ñ‰œÃnuy3¹†gž¸²êñµ]^»‘+À2þèå½´ðÒ´äíø³GŒý[#÷†ÃíáÞF˜#ýÚ{c3'y‹­þ".Ëç´r­ÏLRX™Î¢øß€ÿ³xq'mÃË:ñ2ÚÖɵvâé¢NºD]½Œ£ HDŽ× ˆ‚D”@aÔ>ðõ"ñZK<øpÑ=Ÿ MÇî“ÐsX{^å5ÞÆ5q›Aî–?Ã_ñðU¾/,v›ßãÌÅámW®(c•ø…K~g@+é2i Ê6º¯þAIL¤š Q«£Ñ‰Ý˜K†+z–Ðc –C<È€cföìN2ö`2IIí#jÜ+ÞÄ ÞÔBÌ­S|Òà@r¢KȉÉ)NIâ´VmmÐ*q8'ÖÙ4ª¿Q©³©˜Añ-~<„ó+®CÊÂù “±ÃnÄ&ìððu]žõBkßÛëoÞt˶ém›¼òã;G¬Û³‡k;‰ç½¸tæÀæ¦Úʃc«³[wÝ9ñÕ7w¼jThÞ—m™hL ?Í>R"‰‰vÉêãINOî»]nW]PïÆâvkÓ%ƒYkÔ2¡@tC<Ì¿­åV…âÌQ=cØ;†ƒ#–÷¤±ÀÒ‚eäb¿òAYN±§ç]íë_ÝM?¢ÿºðúͶ>ýĶ×gÍÙþÛ¿V®³ú}ìø Kü¬•曆Î߯9~n–r‹'Ï»£éÛàôöþO<þ:Ã7^àõEŽ6TH3IDæ8@›‘dž›Pêm#&I$Š`a>Fys·ªLW‰`ñø1˜¬‡ùu/¸s~Î+ôãÐãÜRœô MÓMF½„óé1œ’¼Ò5åòó¶†Z:M‘+ðØ4% ¦@.„W‰³Û#ÑÄ$»M¶é!ìŽ Æ!$:îÚ Cõ£‚bÒ³¤Ò•°D"³fœ(ÌÚT‘‡1ÔD“’bnÒß®Òé——Öú¸'ÐNÿ}}—¸ÐO ÞÁ¤ýÂÑéåQX—ãÿê´C_Î}M¯Ð³¨ð²è®FHGCѪק¥¡D+²fdšRê‚&“ƒ8âFqDj"õ¢·ÇV•ØÈÂòº ¼`>Õ¡ p(œ (ƒ•xžÙ6"xËïµÊ† ÿûÞ?èåo6ÿ{gž0uBkËò6nÞ‰·™þc·çÛ:õ ½¸§¾³|ñ´Å‹êlQ}Q‰bo»À‰ô 8ÁŸq œ iÀ­®6HÀ¹(ˆœYX 3 úû@ÆþŒËåóq¡“ü+˜ßw•¹6…UÂ!ðPi¨º)m} qËîL‡Ã”œ,›äüþ¢Õêñdgë‘>¡>¨CÞú ŠåŠ%y"sFÄÈ„È3¤ XI ‚H' 30e‰6…G€à_\ÕÇßóð–Õô‹/¾£–¯m›‰yÛÝ“çͳäÄ?GÝ^3q|m«pèͳÿxCó;swu~ø—¶}U£vMûí¾«{šÆM¨6¿|<÷aýðA·öWvCRd^®¬ó ŠC¨,š$Øôz¯Œ)3ËœZ4›‰Ó?*蔈¦.Ö/ÇŠ\8ËEÌL'ý@þ\â5búŠÞš¡,D]_EŸ¤«ïÖ8ö™÷§jô6Ì}ç¬ûbó÷‡.Ž›>¾µåÁ6RAëh“ñ²cÌþß·Tÿø¿ç°e=³÷{¦Þ³¸ŽI=œƒñó”’°YÁ„r›A“9ÎRqcÄF5Ëõ"û}k}O¤#°õÁf˜Åf6Ÿˆ¬³lI²^Ä¢hÓšƒZ3/B¤ÏfÞW¨Æ¬ —±Ilâ·Ç¤DïüÈd\jç:#“):ÝŒó¥àÄD”0 ˜ÅsIÃÐe h°2|=ºÅ&ƒhá1_Ú•BΆ¹‡ñîÕø»ïè~ú¥*ëf¼p RrÊô€rI|¡ŽÇC« _þ­ 5„égÀû™œe7%^:;{Ó—°rhƒC¢P€\*FBB”F›ÌˆÄÍÜŽP#»'~ÇáÁßQójZ¥Ò(vN6A|bú8<–n¸m5X3³LË!¯7©1èµ™´£‚&>"fL,*Å›Š˜a)äMƒ¨ÆçFœ„{åãö†S†kZÿîŒ3W>ú¡õÑq>z²'9¯÷XÝÈ–C‡ïl;°uæ¦ÖUƒÑí1ùú¤îIâAðE¨ ¹Ri©Ýnóû m}lâ‰óäÅAÞêÔ””ðÚÁQµæœ¤>=¸M§-‘D:P{R‹ŠZíŠUeyŨm¹ˆ]±«~pçÌé—8DO*²YÓ!ÈZ1P†™ÇŽÝ6«jnœyú‹¯~ˆõo::ÌU¨~ð‡g? ÿó;À5î©tñÿЫôzË)¼ ŸàÑ{ºÐŽÑ-Zƒ/Ðö÷Ýã1`é‰7ŽcÎ㢮GþòÔóÿ¹¿€þÄfÄ„TˆÏ}%»çã“uº4È M&ÆgŽ« êÍ€~Ìf2ÅWMVä®Â_Çz¿ê!Г͓ªøvy=Qü§~ò¼Žâ·xÒ#‹é™Ë¡Ó¸x×½s/áƒûÑ.a÷«{—m³hS¶¯zÿS2¯vt㡺lüÄÝ`w À_ûp¢‚€[²Ù Q7¸ìÈ‚ªƒ^´BuPk‹5EÈíIýð–XD¯ª¾B—Ô2¡?¾‹gmìÜõº—¾ÜŽKŽ8ÙÚÐ΢?Ÿ£®Ú5ôÔá[^»£+kÈx(Ìj€‹€ße„,ž7 úê @x¤ÓÖXçÁïà3¨%6{¼_ª0ŸN¤÷Ðñø0ž„¥oÓq[—ãw·8§E2 ðDEɬ#pKѲ²JE´ÔfUòîB8ŸpˆÞz@!b·X2aß@;ÛB °«oऻ¸] –`öõ¥Rgp0?eAÈ¥E§l«Ê<1U‰íº~Ê£Ú¸*0›T‹Ò+áKº¾¯ x ®‡×Ä«'Þ|Ï£«ßØÃ¦ëè"ü ž¯¥àÓžüñ2þ_ø©¾’ß®øJó"¼,;Ñh2Ù ˆE;“Ù¬©š‰éW½H4vL+™i*/LZýØ‚%«¸=ôýn9¨Òq¬Å"Ι>cò範. »?WñÔˆŒ&@Tå4ÀÏ ¯u ”`Öjã‰Há%`‹ Gôä/×”>Õ:è°÷zzíU<ŽÎ£—\¿Ê&J_¨§ på¯óJ¨TxåBµL›ËÅky³YëtÄ!- Û&ë‘\Q§×ÛôÄ©SÔ¦'‰Òlv¿WhéÉôb"°ÂA‘˃ñ…Öµ®^ß,ÜŽspòc÷ãªVº¾@òÆO™ÜZ:*ì>uzé¡Rj{œ+Pm«b° üvÄ£´„øxòv=˜ZŸl»é=údÙ•\tñDŽÕ±p:ßï¢Ä±0Z&釳úq2l'1T©S2v%cÞE?£ßìzòÈÍ“fô¿uõƒÖa髹Gç´Îºª¹%ó¦gŽlÀëü«§–×Öä2¼ìÎwìûGqÁ¿ûg6”g.­ßÁèÏd5_‰í^AL#kd‰ðà]øH<ëµ{qÝÜyúÇ×Á{æ(…{½ 6Ö÷²¢Œ€Å‚±]§Ñج2øЦðÒ{a‹]äA}˜V3B‹Ð²†^ø ý‚¾ýýv„‚®ÚÍ—îÇž«ä宥/=÷»í¤Má;Ã>%ål„“e±Z€ÕaÌØc<¥áÚ«ò—+¸”šèËÔŒK±ÍU êjQ²kcÍ‘>c¿PçöÀI¬š¤•Mv›€‘Û-˜ˆ>11))E¯Ó%'Úq›LXÙ ƒ©ÊX®ÓƒS]¥‘¶Â;’Ée±Äàª%ó%6 ÈQ>ˆ•ôwt~^ìo耰ð.øKS̵À'Œ9:m_뛸€rÂ}‹/úB€‚ºþyzséÅrâë:RòÏúÚ¯+Ir„7M o†RuBI–DY+jY¨&¼^§á—!`ñWkQÉV|~iOüR©–¸fÿc¡‰>GwÀkþœÀMx $qµÔÏe‡Nrßs猡\•ž*ö ~^#I`$Ä@‚¬ˆX´T玔V­¥…å`³^`·À ôCš€ëÈXntײÐA.Ÿ¬`k-×üd40¤á1‘$øV«“`*žaP ÁØòjO¡2\]UÊ?~ÎÕw¹·BM||h8wôù£÷»¬ª­¯¦{¸yŠ­$ " d#"Nh›âfÔåq°åæÑDü¯O?¥{Ä+ǯì`÷Ѓ‰•Gjåʦ ÆÑZyi°ÕÃÒ=ô\èL¸VŽ‘æw)ó§ŒXeX¬Ié`­=ꮺ—Ïâõ¾3gð¿hâ¡ñøÏ ±" §á oC®ž°sXDžg»ÉL^3p"RK¢¸06ÓÄaß+/w?Ž/^ˆþ§!»»ª¸e¡6†½ºèRÛ]©î5 –ŘÙkòø=¤¶ëeÒ@÷<ªðWó§È*Ñú‘Ð!)@˜f÷!”ZÕ…øX < ßãt9¸ýe—†ã¦²ü©¾厉ï'¨1­ üï@~¾²—YÈ´ê5z.-ÍíNOÒh¼ú¸‘A½^°ÛMA;à)‰DK/Ó£Û¶í9úÜâÚ±µC` Yص‚,\ÛÐðÎ+ùŸ&Õ ªÏ R;?ø•ŠQÝ®KJ<˜ïo±pÙR*ïÅ<_Ÿ“ãr•x½Cã È€ ¢¡H02(§òàë2‹²¹ª`vvffÙÈ`¦ÙžW´'ÄÖüàS>8/—²¹~xO§§&ã*ÂX‹CR*~ùô` ²Â{“W·ï£›ø.1¥\-üo?ãý¯ž)ÉËßööë{éô£oþsï¢üŠªŠæ;.œÎ_j¥Y glysæ¼ççÌºéæ¦ºöm|Ë3y#oÝuˆé}ËŸ{ú½¿¿°vâCIö1¾ÀÍÙ™Ûæ¾ö¾…¿Ê—UŽ®-ë?ŠÔŒ™:uÌ »Mà›·=8?¡Õe’õ,;M¼ÕÊZÍZ„!—€Ð «[K£Ù6ÛgS’&‹Ý„Õ ~=ºë¾¹ô(.$ó¤t|È­úþåý¡ïÁìÏX9zË߀ޝå9sk r¥,³ü6èLZ'ÝäÊþè>Š"_¡RGeª²¶½ý¦›Úñ6‰°dݺ£®ºø°î6jWîkó͸­`à€S\fÇA3’M,qÓNˆT¯"µ{u ucAÉÞí"‰LX1¿±âÆš¸à£ÙÊ´Ô÷­©‘ß~5{ç^i›]㌟?)ý7¼<ÄPŽQÌF­Á Ñhµ&bßjŒF"jÄE)ð.ëñuá¬>ŒÛKT€¤æöîX°²™Ç'ʽ½Œ1ÀÌÛŽiBhî˜B·ˆöPЃ=Ù^ƒÐÈs;"p@Üø» ‰Œ—ÊÁ޼¨&i·Ù”JTbbBB†A–µÚt›Á`I,À@—Ŭ3%b­CÉìË"=H!ZOŽèIfXQ|.ß̼&ûédߨ—ø•ôhý-ó§Ò£_g[ò¶Ï¼LÈûãÌ·÷Óêo™=‹[µpᎎÐ÷|Ëêš[¶Ô6í?Êbßmz9Â÷m@·Õ+A ¹ƒ`a´2RUJcµ8V‡¯¡MUᦦÃ@ŒïOs÷À&ûý…€ú›ŽìñÓ”ý¡8–û‹z}²Ùâòˆ Ól"#‚¦kY¤—)¼9)°Í¬LÎϛӊ×ÎX¼hÚôÅ‹¦~J»ŸÿéH)üâ Ú·¿ôb{ûÖéEúá*¬y[qÿG镎Màÿv6ˆkÃinQ”´!’Ì’9|(2ì# ThLRJè le‘|±×Þº…¶,¯3Ì0i«ÅΉ$ù]Dì˜m6Ó£—sÓ>>ðé”}§•Èd¢}õ£N:P¬ZÓN?¢ßý‰^~˜¬U?nˆÆ6 uŽÂ³T†Qœ$‰ÄÇÇÅ¥É&“'>ÁeJvê­V‰ù=Ôÿz Vw©3"!=W8";]¾¥’Äö¹YwNf->9?ðéç§>7H“YåGCÁæÎåí»ž¥/ok¿™€XZT׸úçÝøÄàiõª^‘@«™åœUÑ* sQA`è Py˜¢°­ºH/]"æ!Ù® ÿ/У_晊^åçÉôŸÚõ+Bù–=-óP í€9ØÎhŠ)>ÊJ±Û3‘Þž¢OÑ&¹’*‚.3ÑV‰óI~ 3”~¶mãgq=šáûˆ‰íñ&sdÇÅ ‹vŒ¼ùD}{ß飗.,ùòo¼3¶ñ‰ê·¬]¶h®Þ±Ë“ÚÕ§x\z^ifñØ·¬{¡ù“ô~7fè{7£7è-ª!f $ë5&“ͦÕpÅéÒZMÖŠ Ao2 :!L®oo¯þœË(,q(Lõ˰ÏÁªØšÔÍžÛþÚ‹OlkÞiôÁÏx?ó½ñ—°tÒù Ÿ‡>:„Ѱìn3¸{;* ¸9‹Ånwê4‡U6q‚Q0ŽèÁâJ^˧ÞSðXÈëÙæ‚]ó:ÞÇÌîqÁêÚ›àN…æ1³çŒW7‡ó_~Ì«C}vŽi„2-½ŒaÑ0galqÀ©p²œÜW ©8ÆÛi.û{º, }Nâ2ÚÄ·„–-œ>n9צήXì€9’Xÿ¤ÀkÁ$!—‹h‰”˜˜"‰b²K«%‚É” š ø5µ1Ôò«õNé VÉ(ì6@˜~2Šø’¦;¥éëtî¿4%UäSÌãºe¼ÅlÀ¢ÜOû Î¥oãøB×#| µ,ÿ¦zëÍœ;ô•³éö[+¯öÅpÈŒ7ëÞTÒEm¢²5^À‚òtƒV§ÓË"5jt›z×bŒ::˜´ ô%(P1p9Ý€GŸêģ铸n=wž¶s9/}·†N‡:ðºT­á€arr-:»Ýìtò…ÕKˆ]“’bq»S ‰‰žØlЩtƒ>œæ«ûÙÆXÀÜ xWañ`ÌÚ [pX 8“0s¸0#œ²¬íÞû÷]š0Rü×7U­—öaã-c/67hð§ÛÎ’ŠáôÄž4½÷U™ž^AþÙ¶QÍÓÒ|n³hlb `/€f ²|5EgµT‹ìì—=(ÜCJ4°Ž4¶ŽñȬѤÛyÞ›’l4Ú»ƒ|úÿ±mkû‡`¿EiŽÎÌ‚@–ågÝn×à¶9MÃ[/Ny×¼ÏĪÖß®_¼¼mYÞì¹þrÃGà\]Ó4‹>mέNÎúçͤû´n÷RpY|)iPp‹È¢C:b2¹ˆÓd4ŠÚŽ["M#\KWÑÓ0‚Ñjð»fá0 çá¯E/$$p.—–Ó&&ÅÙF5ÆQA$hâà%&ĉL©ôÀÜÜkš&X«i:„ëp›ºZƒ6« —^ÎGÇ;¾³}9KëÞùmíKÞùÊ@| 81¥ý9y蹤ôOßHÉ£ƒå=ªŽ€šªôD6úš¬:N6âNÎmv[­æä½;Î]”ãâ B•©6hu#aÔ5íTj[\OIJ–FÚö”<º'9…e—Xß<4ËLäöìßëoçÕ6âtåSÜGW¿º£fçÎÏ…Ã _‚7íí\½½–v]î;·uMçþC§<4QÞÃožfAfÖÛdÁÏiј–ˆûd»læxN/ ÉáH‘2@‡*þ]‘$ëRê¶¢’¬‹÷%.–J.‰ugIY%™%1˜sOñÒµKÆL2fÉú¥~ÛKn›8¯±mÍ’â£3êêgÍU;‹;>é¶%k—øK–®^œ9mlÛš6Ÿoñš¶['×ÌšY[7s6ãµ¼^ öèDs¿1ZíV‡4\ˆÀiYÖ‰1ǹ‡K´Ú¬ AD0±™´F“±!(™Lzìõ½ú$Ýf¶¬Ò^íád(" åC>‡×ÁÞ?c=¼±‡«Ä K÷ÿôÓOôìþóŸ·é <ˆvCŽï<}~pçã{$ä ˜8QdO™'<‘/¤4ÊĬgd ;$æ’ºŽÑ%]ÇT<;ðÐ1å¡ß ›9Z‹Ë"ýÒPVb¢Ï…\¥Hq±-®  Ç–cÌHÉLqjŒ#ƒü 0׳k£Öm"HÉî*3É)íz¬éCiëc"Ž|DíRûŒxaåàågvoßÛ0|Um}Õ„¹/llRvñÐá'êTìË]÷ÚÃgvâò ?ɵ¬OãºeÏ5¾êë׿ */ðÒŒWoê3¥êÉ?Ž:š]:?«¿/­ê· ›Ü¯48¼¥ÀÈ^»øË¤Cä•þ¸Ô€ÁªgZáŽ3â‘êæTUÅtBeÄvE¹FÊGV ŒÄkë ­© ªÚ†VT tcEYÅÐʲÁ•CÕ³7­ÝçÅá`ß@Ë~¶gNŒ²ÍhËì—éì—ìL..tàx៓f+ŒçcÅl‰õr¹Ÿñ‚`ÞXéZá­;Çš&¹@ ¾Âtvp õ?‘%·O=\ú@éÝ|øééƒëž­šÓÕö>nù€½÷ÑÍ=J7ïl Nܼ'¼°…þkóúù äû'—ѯ’“Þ)½rú“k·  _+C7ÐAÛÿz>À†Åü™ª_ùÜwÜëÂAà° $»%ìr%›%.YJNóš †ΆÀm)¨ì½ÒüB5ì±£3½ºz•gõTŸ•âs8 WÎ@Œ—D® %÷žªùm[ߘ°¤þ¡òòßMX¹Žï—Zœ°†ëš9 0êŒ2?ðŠÔÂÇ–ÑŠ™é7 MµŒÖÔÂoäyÐÈÕô2€>"B$‚^£×› ÌÔ‚ì”Óñ¼^°QæìD´¥4ß×µ£1Òü?…°¨½ÊÎyo!Û4pÉXÂê¯<¯“~]t„‡¹Ÿ°ÏŸÐǸÁøàº…nY€;â{>*}…—!V—!ÅØÖ•D0 D8ÒWé×îáK;»®³—ñôNGwwä „U„xÕI}X+' x ‚„,1€_!š~™Wc0ð^ã5ðú= ·»^£®Q1ªU‰r¿Ä´˜žù¯Ú‹»¯ˆv^OÇìÝ Þ{7¼xõ¯í‡ÂµG¾0¢xäÈÈdJL°êÝL0ïF¡­ˆé¬zHT96´»©eìó·ÞºéÖ5‡Þ –—340†ŸÃ¾Ý<öÖçG\=vHYËXÖ§ Â+8ð]¬cÄm’$Q«Õé1&:ÙbÐëdÐ žCj‹©/¿8Y"É^'n 9uCÛÈYns'¤,‹;éz¦³“åÎ\÷¶ÒW×'`uè1ÀDlq¹ec çpàTe‡¬¬÷ñ ˜ã¥&uo‡~:©´Ÿú ‹×¾µò¹–¥Sð8®j[gk°0³Oó†¥Ëçß¼~þm0ç@®”Û-ÝH²ë8?(ULÕ™E˜™Eìv‡CNô¦eO¤©êÝ‹äÍ qŽhÀQNÝEÏZ„ÏŽ0WÂmÜÞ2ù•7WßÿäâÕ͵³ÇÞT_èËo,8ä©;–læÏ®.1ØgŽZøHÅÛ£§ùý›ŠJ3ÜUùCîûåÞá„d-¯ìÝ ïÝb‘Ä_\âLDÂÕ;ÊpSÑÕü©„÷':ŠŽ†ë˜ÿm,ìf5(Êr¼Õ‰§3Nr™œ S&¢–ç´Ñ2+.ùzÕ·ÕEG*ÞpÙ +EéSÀÇš[î‹ ¾Ì5åÜݶpáÞcõ‚õ7ßܯïÍ¿¥ïŠJšC»øÕ¢´-?àЙ!-†›- 6IMÐ(0˜ÞÁ ‡MÖ]¢a/õxc±Ïï~¾}óÆ¿þ߯¸±´K¬ûùâ³^¹ŠyÖ+1ŸËÆÇ!Ñ!G@f箈Ü$(?rìÊvmSºõÇö…wwR;Þ Ÿ¬¨(à2Xµ ‚ŒÝl6Ø 6ÙÈ£%0Cöå«g%5ȱ $«Ä8o~ê¹Úá câ*Ûk÷&T5_¹o®c›drSÜÆÁî‰J l£2rVŠ—{Ÿ•JfÆq³RÀõ¬T†«¼@„„þµ3pÞ;\~{ömé9ƒ—œSüJ)ÄгCNI "gÁLSRPÌÁSÕ±ö$DBŒoáξö»§ßøÓ Þ¤Þ¡••ee••Cù±¿ßÛñâKû:Ú['Nlm0áš8:£“e­¤á9vÔkô±'òJèÂQ …ÿ5î-TßO…ÀY2.\HùÅo¤«:±“~Ó‰çQ±ç3ç¥à±xìZßó‘ű~‰O»Í™hñÇÈœ…Žsà„-úy6ô’ÿD8HŽÊüþÈØ]×{'ù ÆJ;93ªÆÇÑ0öጟ¢Œ%æð}ß ß7O½/ðj0]HN‚²Ü§"ž–˜˜Àµívcc6J0'p h )Á “E;*hñ^Û‰ÃJ…êj㽺G]⊠–£ÅŠ–;œ>£ô–à¨]ã&ÿÏÔO®Þ¾ú6?îÓ“ûV¬¦¶¹¬´j@Îéßܰ÷¥éÏMH:7E,¥»[í7—æY3Qº²ÆaHÄ Hó'Î)d¢\?ºÞ˜»Ð±ÿ:¦5©c®3.:æ`dŒõÚ1MÑ1S•1Ú]„ó*ƒüÑ1Úð˜ß¬HÅKT©„ûè¥ ¥—Ò†f‰6b¶ oÁZ£3$‡ƒ»™Tµ†ê ^Ëúصf-m²Ò¹Lx+6ötI‡+àdó•VéžýÈfQ¸b©îJ±Re¤wƒë•2ºž¢Žõ´ƒ[ͯጡï9ßÕ$¼h‰Ò~X«êàðÿDŽðÆL„ÌZÄ%)ß+=Þ Ÿû¨òê~Má!¶÷ððÚ1w¡±¿óGcÓÑý£:&îÚû4EÇLíþY‘‡=YtfKÊ}úªôÐEê}ô=÷yÆ|3æ®î1׎éfûB̘ú…:ÆÒ3&÷ù½B:fª2†Ñ£íg¹F¸ç^‘³2ž*Þnu:õX«s葾:hÇÅi v+gaé×'Œ´BGꧬÊdQ{]A²Þ ,>ÖÔš¿2Ü–¯´è¯äù¿~ü·ß.ÃûH×J¤`]ú\㪯.Ò”îPy*Rl  lÇ!¥WáEaØ&ç«v’üëcîÂÿuLÚ¯Žñ^;f\tÌÁȘøkÇ4EÇLUÆ0›Ì ó£¥XÏ›ùŸ’:‘ YÖ”Ry\~aÏ)oæôKd%åïwÐp.xpGÞ:z”_ÏÇyé œ»þy ®Â–7/èn¾„<Ýž6 •])‰v»6‚­7Ý™ì‰3ıæ\âùE'il9{Ç Jj++4a»K9õ#ea§/UíaîxdôæÑX{î'75ï»zâ7øJã”7öp_ø¨¾z2D&¥ŸyèŠéíÃËX›nEÛäeûèƒïÜÉ]ÊûùÇ]óC–,…Jï§"‡ß„噫Ê<Æ7^;æ.lü¯c:ÐFuLêµcš¢c¦*c˜ô‰õŸ½pq¶oPNå‚úÀÔ‚’º~ƒê§Œ»ºŸwè³W™ì”~=Ñr®Äµa/ f‰¹&•ë\¿kÆõ®§F¯wü§›]ïßûº1zý Vùû¬Þ×ùèõ©€½™•ÿÆ¢Zy;£cd«c2#cÀVaŒHùù5 A —nðwjj¡Ý`(,”‹‹3SRäÉriFª×ŸZôûÙqó„_U0ÁlÈ4œ¢ÓRtš‘·"ˆD1¿‚õû)8¶G,jãÖëvŒ©‚Vž3Ãú2³b»#ɨ‹¥|‘V2ÖIÖÓĈÓX»™P°òlåøŽçžßÿý¿ß Ö<ºuÂ[_6¯üwŸÆ(”'<~ÿ{¯z=4tÎ=÷<:ñnÎ{Ê‚_æ¦Ú'N™|k+ërl¼¡¼æƒ‰ËCé·_?yÿÍç³úpñ<˘¥‹&âïÎϾG÷c©õ_+Ôx—©ß³>:E敪N¼¤È,="³k¯ß5ïÿ¾Þ¡Q®g÷¾ÎG¯Oµªò,è‘y÷3`ŒŸ(÷ØŽñ¬vÊâ·%êwÖ€Óø8fÌ]Ý7\;¦ûAs.fLýPcéóŒY£Ð³/ãÙ%Æ["1^éY½ æ¾+0Åq.W¢ !:Âq–ÄD.;Íbé‡Ü|)Ën7çt¦Øí)A€åœ1£"htndàëôZ#&ê›Ø"¾5²™¾#3«Ä©«´4 )‡L]%™Z"ϰaðӺʉÏ=ÛºýÙ'é?º¤ÿ‹ùÓG*4ÃÚ¾h嬋¦-œu÷ìÅS—?ë•¡Õlœ¼š®ûŠ~Eb빯±e<¿yÁcφ&O¿å>¶…ñYíwc6\¯Ú°Oá`\¬<7(¢æKùƒÊ^_äËV§Vk†œ“$”g3HÊ1ë÷ ß+Œi³Œœµ~å„z39ZVU^~cÕС#«Ê‡U²ß\kgçÅꑵ7V4Ô~dMýˆŠúZ…†±Ý»ø üSx{cŠŒ0¦`=GÄ3âÚÆ•ÿ_LQXÌo`íP÷N¶qøÖõÀ%<ÖuÕ†ç–-šŽèéáÌâEÓ¸Ö•7qJë³ØÎ:¤Š¦7>C¯¶TâN×ÖëÑBÓKÀc¥D‘QsŒ_ÀIô¾ÎäÜŽbF(r¾öʈ´Þ÷à£×§æ«–˜”>åcUÿ3X¹GŠ:K¸¯KéÏô°sê)¢èuèÍñ6“ÉlN³ s‚Þ!9iDPv'ðùWºc:º™ÃŽ4u«…,‹ »bZ»ð±ÂÍS|zæà‰ÉFIR{8¿ww‘#õ7+ÝÀä•CZè@ ¢ ﮬíéðŠ®‰®iê'êºûFõ7Ü—¨ìU‡ûM×ïKdá3vRp9AÓ&Š-‡§¦J6Bñ’”n±CjÔ? fÀ²Dë‚…ç“Ø9aìˆ9¯y_çÜn¤E¡¡çt«ÓÕ“ŒF\S‰¥–꺞Ê|,à›ðÁxIk49}½}ÇŽ-Cez—Ë:ü0 áix™QVUrøê—~vXÉ#6gØ–ÎK‹ùy(åBÔŸßßÈ9™™šþý“ìö¢TÆ—èˆËwTóó‘ÙÜ·*h6sFœõˆ ÎŒâ Ðó¼wD¿6ЗþMá=á=•mGÚÙ2‹éŽhxlÇb†ÚG.´Ó¯[ueóåå8s³ßñøÅKØrJë–O{³µþ­«“¢­Œß´Ü#ã}Ü|û3Ï<Š5¯bÎUó,ë"×,Y•Ó…ôÂÝûæ-œÕúñ&ŠO=ÈÀ|;K>PÖpœÑÄÉ÷ 寉yøUX·3³DÉËJÃÉØå ¿­©}êð[ÃðÄ”§+ùS·ÞT[Â[³‹þT¡žïÀüIR%î ï]šD«5Îm2É)2'ËyJE¤%¦r$ÅD(RõØìÙ­˜3óñçŠsrŠû÷Ï)Nྙӗ>0%ÏçËË+*‚õåOòzÑ3âÌ&à qÇémH²Ák–y‰™3ßÇ£üøoݬ´øâÍïª!^eÓƒcñ1(ÖÇRJ ët«ïÊUS•®|^s'û,”û‹×lñd¥)¿ä¯7ÞÛyCаÛÉj}ލßóL3w@æX‹·¹Ê!á×kþæ' ”5˜PFÀ¬ÓkŒ„;[$£ž‡a­þV¨Ð£.È“þÏ«+ø‘ùDN†³Øž¹X}Ø0ÉZI¯<†Í¨%zMu 0¼êðL*áB˜þ-Êúq>«~p ›TNô0DyŽ yNᇥŒ½çPûGb§Èè=E„EøŸ½y~† ð{<ÀôM|6ØŽm7Ûb0È„1;ºA×*Æ?ùÈÊõO=ôð:îüƶ<½¡½]íÓi¿g5òþGx{XЈˆu ò ;«[±±\>¶ÝùÙòÝæ½öÞáº;–DåDŸxá—÷î]Sç6]¿€®è]À0¶rÎ.>ªÁaŽãcÙ)ûÓ2öbnM׉‹$7|ÈN‘‹ž«â~öD²²î« ÙcÄdÄ œÍn”%Y´'¬V"%“T¥4‹l ö´Á`¯Ãë÷øÙ¬Q {f÷SÛº/=ßF׉²ß´„;ûÔS¹¡¡#[šÆÇOw½£Ø {Ó2a/d*E¢ÉÈHLIs&Èz‹%]¢HOÏv%%iúè].Ù-&%'5I²)yI2ìNv'ÛÒ2PL“ÌF›±6h‹>¸­w©×¢Ö}‘2Bl[EyÌŠ%üˆÓð%‡Gr°€ëTŸ!’†²¼~_¦¿~£ð³D¼‹žsáµ´:¾ìÃÆÕÜùêô½ì•wñÜË3ððölÃÝü¡U¾âÍ÷ìü¡´ ÄÚs;]YþW¾Çq _¥xÿÌŸxœc`d```”œõ³žoQ<¿ÍWy8ùöFŒþWþO„}{1#Hæ/xœc`d`àèý»H2ü+ÿWɾ‡(‚®•Êxœm“?hSQÅÏ»÷»ï…¤CAB)ED¤H R¤ˆ„@¦¤H(A$‘ ApÈ ¡ˆC‡t ¥[ åDÔ©Ïœ§.H9[KË0¸%_Ñp“ˆeMjSöдÌñ·BWAl:Ø4ô©üòu k_~úù±®±Äö˜ºŠ"Ƕä9~ÔĘÐÚ~Ç¢½ŒYiÔº÷2óžuŸh¯CB?çy¶óák´ì$Šr”­¡÷Ú¤ÇöϪ>æP$7õ[èCìJè¨ßÁ‹tÈ~ÓNㆮò¸šq—Þ—¼ïgíP™…ÏaÄ[UfðžÞ½¢Æä³*žæð/<ך¯™Å8š…fæÞÑ?ú~Qƒ:3Êaf°Mÿ7¨ëäÐûŸåðzÇFã[ãh>kªÏòºÑÎbOv‚eê'áÝÏ‘`Å,£lû((r‰µÁ}óƒÿ Lœtéq^ïø_£ÇÇxœ%Ù»o$gvðÞ@I9˜mÀc›"MK­¨)’Ž4-R-‰lÚÿƒãÍúiÚ»I£_h>Š˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€2VÌXÆNf”Â,J`‚ â^ÆlÈòfÂú2\‚® šÞ > € ¸ ô $ z ° Æ ò 2 R ˜ Ô  V ¬ ` † ¼ îJŒÀö6X„œÀnªþT–2pœÚ":–ÒlÂôLŽÊüXžî$pˆØJšôP®ÔRŠZ®ÌÔbz°ê$zžè>x¦Ü0F\rÒäö   , > ž ª ¼ Î à ò!!!(!:!Š!œ!®!À!Ò!ä!ö"&"„"–"¨"º"Ì"Þ# #˜#¨#¸#È#Ø#ê#ü$–$¢$²$Â$Ò$ä$ö%%%,%ª%º%Ê%Ü%ì%ü&&P&®&¾&Ð&à&ò''\'n'†'ö(~(°(æ)()>)T)v)–)¶)ì**N*n*œ*Ì*ê+.+²ÖA=/\Œxœ”»nA†ÿµ›r)B)FJƒP¼¾4@ P.&Šd‰D©h&»“õ&ö®5;–å</@K“†‚†ŽAGMCEÇK ñïì$¶‰¡ÀÖÌ|3{æ?gÏ96€ûÞSx(>O`{XÂ'Ç%TðÍqÞ†ã Ö<åx+ÞkÇóXõ>8^ÀËÒ…ãEÜ-ýt¼Œõò#Ç+ðËï¯Â¯­SÚu©#°KÖ¼ÏÒê§Hà{q›øR…"”FŠ ítuŒ¸Íz£^åÔØûiu•ØMu?ÕÒÄi«/¨§¨"pDÍú*G2!îÐC—Ñc'írÞæãÀš‡œ5/U9nKˆ›‹9 hÁù Ö)“* •UqãKäÄÎ æÜ¨×g6VÅô5àĆ“¹ŒäŽ|ë 'Jg|QÑðš×ŠÕiÅ\°ZÎòÛ9/¢±ÈsÐãªqÁ³g· &m¦„µq=µ§šsdÕŒ »h‘Øz ìIÞ*ÅþœÙÓÖ6äÜ=ËË>ÎBœ )Œ–¡êI}!Ò³ëbË$=9§JhÅ™Qš]'"PÚH®çgaäíù³J<»ëÆEœè'؆64ÞBß¡ýú¼6-8IßR–èÓߪՆá/r@a?H{µÿ—5L{ß&XÙîˆh[tŠo5{,Ô?]›Q_…*‹£„äwLöm[ e«PÔn0‘.Cá¼ÊÛt,iWì¦ïä?í?[¶ÉØ¢í˜d¬ÑÀ&×t”ØîË€‹{²)®{ºé×ÿž™±sßf%âÓîTOÚ8`}[8d›·ì b2#Ö¹Ÿê¨Ö-ÈjíƒÝÖáQ«šðʸ87xœmÐÇoÍÀñÏk_U©½÷Þ«ö¥µ÷Þ«^©ÑW¿çÕ^± !Nĺ{GŒb¯ØÎvì+³Oòý¾üó'[¶ÿyQPH‚DaI IVXŠ"ŠJULq%”TJie”UNyTTIeUTUMu5ÔTKmuÔUO} 4ÔHcM4ÕLs-¤i©•ÖÚh«ö:訓κ誛îzH×S/2õÖG_ýô7À@ƒ 6ÄPà 7ÂH£Œ6ÆXãŒ7ÁD“L6ÅTÓuÐZë\±Ë;ëm³Å‡ %ØJ´ÆNßý°Õn]÷Ö7{ñËO¿pÌ·7]–íf¸'â¶»¹ï‡ÞÜ{ê±'N˜é«ßžyn–>Ûd¶sÌ3W®}¢æËˆ‰[ ßB,²ÄbK-·ÌEû­´Â*«}òÅ%/tÊ+o¼vÚç]pÃYçÜ´ÁU×\…CIÉñÜœ´´ôŒ”h~$ˆeEƒHjv4Äây‘ '„3ãAô/¸¬kTxœsèæTôPU`d•÷`•cþ/à#&ïï›"ïç“"¯f"ªj¬*)ü_žå¿<PÞ×GN>ŇÑÇW^ØX(”¨•Ũ™‘ŸÙžy=33›·Ûi·ÛnÌÊÆJ¡2ÆÒ¡bÆ¢¡‚Œü¡Æü¡ëùÏó3ð323„æ3Ô3¬gxÏÀ"ÀÀØ ÆÈʸƒqÂÆ`mmïìÿƒ¼7pDo`ìØ  "£6°ul`ŠŽØÈÈØÙÚÛËà$ë½Á(8bƒ‚l¤÷† C@v£ƒSdq±6@q\q ˆp ìL@ tomcat-connectors-1.2.50-src/docs/images/fonts/fonts.css0000644000000000000020000000362714655113620021517 0ustar rootbin@charset "utf-8"; /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 400; src: local('Open Sans'), local('OpenSans'), url('OpenSans400.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 400; src: local('Open Sans Italic'), local('OpenSans-Italic'), url('OpenSans400italic.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 600; src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('OpenSans600.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 600; src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('OpenSans600italic.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 700; src: local('Open Sans Bold'), local('OpenSans-Bold'), url('OpenSans700.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 700; src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('OpenSans700italic.woff') format('woff'); }tomcat-connectors-1.2.50-src/docs/images/cors-flowchart.png0000644000000000000020000025103314655113620022162 0ustar rootbin‰PNG  IHDRÐôk†H+sRGB®ÎégAMA± üa pHYsÃÃÇo¨dÿ¥IDATx^ì½ëw×¹¯ë?`8_ϧ=Æ1>ÿÀùpF clï5Æf¯áE¸íí˜ácƒˆÄ¶Ql#0Ñ Žc.†|àh¯¬cÙ–½l`ËqÌUÁŽ ‡˜‹#ÄErs‘Äý&cÈyTïd¦èVK­VuwuõïùP¼ó³fUWwW=]¼ê¾gûöíóEþá8ÿ]!„"`ïÞ½MMM õõõ54IÒ剤p.xÈ?gwÈ…BQ–\¾|¹¥¥eÑ¢EcÇŽõ†½víÚ/¼3€a f·²(e$ÜBÂ-„B”-x32=yòd4zÛ¶m7nܸ=( `ƒY…¥Ý¥Ž„»@H¸…Bˆò¤©©iêÔ©xóž«°"«3‰›N” î!áB!ÊÞÞÞªªª_ÿú×ÝÝÝ·F«3 S1¡›Z”î!áB!ÊŠC‡¡ÈíííΚG S1!Óº ˆÒAÂ] $ÜB!DùÐÒÒ2kÖ¬ÞØN‡ ™vÛ¶mn3¢Dp ·BQ&´¶¶þô§?½víÚ÷y€i™ü“O>q¥€„»@H¸…Bˆr ££cæÌ™y²mƒÉÙÄÁƒÝ&Eì‘p ·B‘xz{{Qáo¾ùÆ©qÞ`Ó¦MëééqñFÂ] $ÜB!Dâ©®®>pàÀÍ‚°gÏ6÷Ýwß¹m‹#á.n!„"Ùlܸñ—¿ü¥Óá‚ðóŸÿüÃ?¼uë–ÛWâ.Ü6lø?ÿÏÿÓ5ò [a[®‘$ÜBôööîÝ»·©©©¡¡¡®®®&`ÕªU4¹JÑÕ××ç† !D©Áìá‡>sæŒsá‚pâĉiÓ¦:uÊ턈+…ûÑGmmm=ðÚk¯¹ì=÷üßÿ÷ÿ˜ZÂ]@kt…]™¦­B“¸ìÆokÞ}ÿÿü?ÿÅQñÀø‡@`;ÃVhÚ€| áeKWW’]]]=yòd »¾¾Ãþàƒ¾ xûí·i.]º”®±cÇ>÷ÜsÍÍÍúe!DÉÁ‰îÕW_ý®à°ÑÕ«W_¿~Ý퇈% ÷K/½„}>ûì³h(zŠ+“ÇMÉÓ$Þ’m- —um­p—‰8«£àLõ“ŸüÄò’¬kÓ‚7rKZ ì3Û?öÖ䞘mÙ˜Üà!øÏ éH¸E»~j’}ðàA÷;Ńò§?ý©®®ÎÔ¼££ÃM$„±‡×éÓ§6:qâÄîîn·"– ÜÈ.>ú¨kü§ÿôŸX"”)N‰@ã©~0±©9 °ÌÃ2%? &Ü®‚¤Í`°o4S2¶oF¸‹¼wbÛ®`«³¢í€m"èùý› } 0¬iyÀÝÑ‹ôa†„[”‡˜Ÿ{î¹ÎÎN§ÒÃäË/¿¬ªªZºt©îv !âÏÞ½{gÍšå¸àØOá\¹rÅíˆw&÷ò)"X¦·px±¶{ÉfŸŒ°§p³šÌcKŸôýÀ°E?ž|ÊǺü.¥@Ó² KÆñ‰"Ø÷~Hú OÆÆ“& #áeB__ߢE‹ª««1fû]´‘ðñÇO™2¥©©ÉÍ.„±¤®®nýúõœ‹›^¼xñÙ³gÝÞˆø1€p›\ºF³U¯³¤ÓG7­¤ä'?ù ±WaÓYÈtŸÛ„›a†wbKØVLÙYÛä|`LÿÐ;eâì€5‰S> òY‚­ðèüûùÁvLèmßRÆ“xÜ ·(z{{QímÛ¶9_Ž‚ëׯÿú׿^¸p!·!„ˆS¦Lùúë¯M ›~衇¾ýöÛ›7oº1#á‹&: 4Y†e°dTØ 8 “[îǯë„+¿½:[M‹cuÄh± 3¸p‡»2Ù³ßVÊxÈ´Š!ቧ£££ªªª½½Ý™r¤ ñO=õ”ÊK„1„³_eeå;ì èììtíA™°"€&+Z>LEEE[[›kd€صk×åË—Ý>‰˜1€poþÀÑ5B °¬`º†Á~<Šw˜¦×ŸØÍi?Þ“I…½àúÀg6<ÛÌÛ/^Úa÷Ý]ãnR:lÏö9&ú#2«¤#áÉf÷îÝ3gÎ<{ö¬û ´<Àõ†M|ûí·n“B8Î;×™ï÷ßÿÂ… ÑhDÙ¥2€dÏž=›€ñ@0à*L˜"â Kzv`ãÆúáÉØ2€p›•⬮‚¼/Øðô÷ž‰ñN‹_ •š„ »²gÀ$ôÂÖ÷ðx¶Î†è5Ã&¶Œß+}fHÿ™„›ÁäýÑðû#áÂÓÑÑ _»vÍ©qÞøæ›o¸Ì\¼xÑmX!b¦»dÉg¾ÁMk å¶¶¶uëÖ!ÇæÓÐÐÐ`7³ÛÆxá¦×º‚[Þ+̳™gË–-4YÒĪÉ0’ Û;ðî»ï~ûí··ô#8±dáTwôãøÀ˜¤šæÒ´<`Õaï$fŒÅf· fž°ã(âaCÒ™6Ÿ6˜Á—Xõ3l«*!3àg&ñscì#D&ák´±uSÆC¦‡`H¸ER¹|ùree%*ì¤8Ïüå/™5krï6/„Å÷ÅIœùÞ-ܨ6K2ø´eœ M–@3ðí~á5jK’æå6 #À¹a˜ºù·Áüú׿VwlX¸±IsV[Âøñã­Ë ›¼`jñ ô"¸Hmÿ¡Ù«C ·Y5øíÚƒ †1ÄŒ'NÆœ›@0¸pÛÎ÷Ë~PiClû“2¼÷3Ò¥BH¸E"éëë«­­E‚„÷ßÿ—¿ü¥îâ!b‚}E‰3ß@šñcäØÚ,™ ­­¸¿¾{çN ¼gûÀ„Û–fä68<Ìg<öE%7§e·["N ,ÜNi¸öpÐG}ô'?ùIz_i ta±á»ãaX+}6HI²:“¤d+á$1›v°ñáU ÜdüžÛãµ=÷IHYldxŒGÂ-ɪU«ƒ.(÷ºuëÜN!DQ©¯¯÷Ýwù†îp^ŽYbÒ&Í+‚ª‹Ã©63+Z…I6ÂÍ,[¶ á¾zõªÛ-'n!n‘<ººº*++9¹; . gΜy衇ôËjBˆ8ðÎ;ïüÛ¿ýÛõ;Œ?ÞE&Ç>æÄEpòäI–&Ðáá¶a›7of-ægðÃÂsìÀ¿ÿû¿#Üú¢’x"á.n‘<ž{î¹O>ùÄ)p>|ØE1}útpi.3no„¢HØMšøBEE…‹h8pÀ⦦&tlÌò€p`²ŽO›[ÓĹý ~˜Íóúë¯þ&õ{“ñDÂ] $Ü"a:thæÌ™îg…ÈØƒ.Z´ˆ&~Lƺ²áóÏ?=z´k¤±uëV&t.*?üð±cÇnß¾íöI!ŠÁÞ½{Ÿ~úig¾#fgPámqXÖ‡ضm­¿)'î!á £¦¦æÏþ³“ßti&@ŽYvuuél\¸ñøt}ï½÷–-[¦Û9BˆâÂéî±ÇÃt£bùòåý·ÁÇojjr©¡xøá‡÷ï߯?šŒ-î!áI¢··wòäÉN{ïà…Û0E†à®÷zßxãéÓ§[`V®\i]\®¼pkL˜3gN0S?Ö•Â_ÿúׇzèÌ™3ºÉ-„(.S§Nmoowò[pØô#<‚mÃ÷ßïöIÄ wp‹$±qãÆ_þò—}w³k×.´¥Æži“Q£F!è$ hØ„› ¡¡µè"cy›aöìÙtÙ€E‹¤c¿f¬›ÜBˆâÂiêw¿ûó߂æíK¸OŸ>­ñDÂ] $Ü"I<÷ÜsÛ·owÎ{78´÷é~ݾ£Ñ0a ÂlŒI¯Ýá¦iFN` žŽýÖC~ÍXQT:ôÄO\-lúÓO?E¸ÏŸ?ïvHÄ wp‹Ä€æŽ7îòå˦¼éàÇ4‡ö é½~ýz‚­[·ÒîþAw@µý é>|xÚ´i\fô;8Bˆâ2eÊ”'N8. lô¡‡ê¯&Ñ—pÇ wp‹ÄÐÑÑQYYé~k!Ò¼páÂÙ³gд¯‰µ?·÷,@©Y’Va¹nÝ:?’LEE…MÕÖÖF`?ý‰x@—!DÑÙ¸qãâÅ‹.(Æúõë9 ž>}Z·b‹„»@H¸Ebؽ{÷ܹsí†èìì4ö&®œ)°1èõ–-[ˆéófáƒ0iҤÇŸ;wÎíŸB‰ªªª\) lÎþ—tŒ3î!á‰Á~âÁÙîÀ¤½g‰Ÿ={¶kdÀþnòÌ™3nÿ„¢H´¶¶Î›7ϹpAxæ™g8'›p÷Ýwn?Düp ·H ¯½öš³ÝàïggŸ}öÃ?äbãöO!ŠGmmí§Ÿ~êt8Ï|ðÁØ…Ù¶noÇœ{¶oßγ%ò ÇÙòR£«««¥¥Ç‚)S¦þøãyrn¦å¶k×.³m“”nqõõõS¦LA_n%¶¶¶Y³faÞœ¼ÜƒÙÑÒÒ2þ|g»™5jÔ믿îw“)ŸŽýa¥kdà±ÇÛ³g„[+ÚÛÛ§M›öç?ÿùR¤0!ÓzÛîîî¾­Ÿ–,$ÜÂwÖÔÔ¬]»Ö iyðùçŸWUUutt¸£ ²`ïÞ½O?ý´³Ý  ÔãÇwí¯ÎjôÉ“'-8`q6Âýàƒ;vŒ J…±âôéÓÕÕÕï¿ÿ¾“åÃTLxøða³íÞÞ^÷J ·èãÄ;¿üòKç¡åÄßþö7û¿9w,ÄPpŠŸ4iÒµAA”Oœ8aKšû÷ï'æËÕ«W5Ê‚ رc4a&ë6]™èîîF¸íÚãöO!bÃåË—9Ë=õÔS#¼ÕÍêL2þ|û+Ièéé‘m—nÑïO3gÎüæ›oxë–'xÛOúSNg¡˜2eÊÉ“'MyÓ1Õ&X@€@755ýxNnRÎrHáÞ¸qã¼yó¸öœ>}ÚíœBÄ ®2Ÿ~úéŒ3~ö³Ÿ:tèâ0aVduûcãüùóª$)-$ÜåN___MMM[[›©gÙráÂ…ÊÊJLÑ1(õõõÿñÿáœ7 ${üøñ˜´ÝÒ&“â̓÷êÕ«Y²nÿ%ÝÝÝnç„"f Ç(ò‡~øÈ#<ú裿þõ¯÷íÛç„: `ƒYÅ~jÀ8sæÌ%}'I "á.wêêêÞÿý›âæÍ#GŽÌ˜1C'²lØ»wïSO=u5XòÚµk? æ²1mÚ42®;@/¿Y³fÐK’Ïîq'ð#3á ¸õÄ !bN___ooïž={þýßÿ³â~ô£'ëéÓ§“$°Ìĉ@Æþ"Ü8{öì… néJ wYÓÑÑQYYé|Sܼùꫯ®^½ú{UÅeÁ¸qã8û;í ^›:¦Ô–´[×$,X@“C}üøqÄš$—ëò±MB0ˆpþùçÕÕÕv)ÒW”!J‚7n Ý§OŸÞ¿ÿ¶ÄúÀ¶ ,ãÿ,Ò`ðùóç¹H¹)D "á.kjkkwìØñ¸'µGyľ}Ü#‘úúúwÞyÇ™o‘˜7ožýOë™3gÜn !D)pëÖ-NbçÎ3ŸF¸µ¾ ò.\¸~ýº.I @Â]¾´¶¶>ûì³Î4ÅÞ{ï½eË–]¹rÅ&‘ÞÞÞªªªo¾ùÆÜ·ð´µµM›6Í.K/^t»%„¥òp÷õõqéáäF ÿ²KîòeÑ¢E[¶lqš)îpúôé‰'ž={VurCÒÔÔ´|ùr®Eá™gžÙ¸q£ 7OœÛ'!„(An‰„"á.Søô|™C¾Ýñ™yûí·ëëë/p1‰no !€„;ñH¸Ë”¥K—þþ÷¿w‚5·³gÏ^±bÁºuëHVTTXˆÉ¤œ‘>o+2`áÂ…Ö$ ¹eËò7Ížž늜®®®‡z™SUI–,X°àøƒÓá<³|ùòÕ«W›mwwwë÷… @Âx$ÜeJMMÍ_|á3j0c»Ã}ÿý÷Ólkk#C@Ò–ôâÙ @ÉÛH°»×Xµ)8|Éf0cXöΜûð¹ÞÞ^w¼Ä ôõõ=õÔSŸ|ò‰“â¼±víÚùóç{ÛÖ7¦ !’„;ñH¸Ë”©S§vtt8»ŒÓ芊 ³d»9Í̧}Mˆ%Ó…›&ëÒÅ’uQv28zxL^™4iÒáÇϞ=뎗 lxΜ9kÖ¬¹”7–-[¶xñb³màirÛBˆGÂx$ÜeJUUÕ¡C‡L.#Çnc–ÜÙÙiÞŒUƒ•tg#Üèµ­by`¤Í\á¶ ?}ú´;^" 8n¿úÕ¯Ðb'ÈÑqêÔ©§žzê­·Þr®ýí·ø½ÛªB”&á?JnýQòp—)µµµ­­­×óÃøñã-0Ÿ>yò$möÜÔÔd–/_¾yófò ƒCÓKL@óõ×_¯¨¨°U`i3Û`‚<ÑÓÓƒp›Ø¹ã%²ãÖ­[ï¾ûîã?¾cÇ'Ë#æ£>zä‘G¶mÛfÏ\ÑÏ !JŸÞÞÞ©S§®ZµŠË1½wï^š$UИ<$ÜeJ]]ݺuëœ`F ºlAww7bM€+î½Àºˆéª©©! ‰ˆ°ôëô¯ø:¶íc?˜Émdä=zÃ3·sÇK ‡?ÿùÏÕÕÕ?ûÙÏ:tq`íÓ§OŸ7oÞáÇíéàI×!DbàZŒj§€s»n‘ $ÜeÊ;ï¼óoÿöo׊͂׈ ­­­³fÍBïôUÜ9ÃaüðÃùÜò /lß¾Ýtv`Õ}ô¾ŽµïÚµËTzzzôW’Bˆ$ÑÑÑá,û“'OÖm…D"á.Sººº{ì1óË"²)À5bË/¾håÂúO½‘€Ÿ;wîÝwßåÓ˃>ø‹_übÆ ƒÜóþâ‹/Ö¬Y3gΜÿößþÛ¼yóðuólà“ÏåË—õ €BˆäñÜsÏ9×hjjr"YH¸Ë—©S§¶··;Ç!&Nœh5 .\pKäJ__Ÿ[Ž;¶~ýúùóç?òÈ#vQyüñÇ'Mšôä“ONŸ>Ý23fÌX¼x±ÿEãìÙ³¸¸~KR‘T¬€Û¨ªªrY‘8$Üå˪U«Þxã«ânþò—¿ØÏLÂõë×ÝÁ#ãÆ|z9}ú´XøôÓO¹ºlÛ¶-\4â9sæLww÷¥K—TC"„H477s>¬­­um‘D$ÜeM}}ý;#ßãÀÓ¦M3 䣈;L"?paùÝwß©bDQÎôõõMž<¹££ÃµE‘p—5½ÁMîsçÎ9ß,{žyæ_CŒºÃ$òƒ ·B”9]]]µµµîd#á.wZ[[ö³Ÿ]—/¿ýöÛË–-3ÛæCˆ;@"oH¸…¢¥¥¥ººÚ–ÍÍÍ.+‡„[üѬ¯¯wÖY®|òÉ'öÝÛ†no ·¢œéëë«««[´hÑ¥K—nß¾}ãÆ š ,à’äFˆ!áý<ûì³h·©g²sçÎêêêcÇŽ™m_Ñ/‡ ·¢léêêâºóÁ Úa¶mÛöÄO¨¼$yH¸…cùòåË–-ëééá£vY±fÍšY³fyÛ¾xñ¢;""ÏH¸…å‰=zÔYöÝtvvš‹»Ñ"H¸Å?xï½÷žzê©;v8M:HöóÏ?¿xñâ®®.³ísçÎq²s‡Cä ·¢ÜH)#É„ÊK’‡„[ÜÅŸÿüg>XÏ™3gß¾}ý?·P:;;9—=ôÐCëׯ7ÕòœæÜùGÂ-„(+2•‘dBå%IBÂ-R¹~ýúƧM›öè£b¥I2oN[?þøÄ‰W¯^íD;@uÛ…GÂ-„(¬Œ¤½½ýÖp8yò¤ÊK’„[ À÷ßþüù={ö`¥˜7bôàƒ>ùä“=ôqiñ£ýˆ=ǰ‰ÙÿeË–}úé§Î²z{{õ$EgÄEB‘\¬ŒdáÂ…/^t=®_¿þÊ+¯¨¼¤Ô‘p‹Œ ¡h·ýìö±cǶmÛ¶k×.“ÔÈÁ½\5|l`Ï>ìÚwàq¡ÚœÝ£GÂ-„H<¾ŒÄés®¨¼¤Ô‘p‹!à}~õêUÌûÌ™3¦ª>ˆü ·çÔ©S,ñlûeM—{„¢HH¸…É&·2’L¨¼¤¤‘p‹asóæMEG¾Ýëûï¿¿­?ˆŒn!DRaI&T^RºH¸E,{•!zÒ…‰¤««kæÌ™ï¿ÿþ÷ùaëÖ­*/)9$Ü"ȽÊ=éBˆäÑÒÒ‚m···;;Î'Nœ`+*/)!$Ü"ȽÊ=éBˆ$áËH.\¸à¼8Ÿ\»vMå%%„„[ĹW¢']‘ò]F’ •—” n ä^eˆžt!DÁ¸|ùr}}½küýïK–,qQXÉ‘#Gn•—”n ä^eBGGÇ©S§,?éä:äB5{öì¹ï¾û¼g[0B|Éùóçÿƒ«W¯¾üòË*/‰3n $ÜeBooïØ±c«««Ÿ{î9žô†††ÚÚÚ©S§’¤Ë Bˆ¨A¸çÎ;fÌSR/Üõõõ“&Mª¬¬üöÛo-“=¾ŒÄio±Ù²e‹ÊKb‹„[Ä wùPWWÇÓªU«\·Bä„{InMÓ„Û¶fss3ÚÝ?.kŠ[F’ •—Ä ·ˆ(—‹DÒéèè0ÉöLž<¹O¿±/„È'&ÜcÆŒioo7á&&ô÷Ç ILÊH2¡ò’x"á±ër‘(¬žÄÓÔÔä:„"?xá¶›ÙéÂeU·•‘lذá»x£ò’¸!á±ër‘(Z[[Mµ¡ªªÊe…"oxá/ÜVRB—¯-+#ùꫯœÕÆ›ãÇ«¼$>H¸E,@¼\$Ê<Û„ùv)!„È—/_Þ¾}»Åíííþ+qßÌ„•‘,X°àܹsÎgK+W®¨¼$&H¸E,p—ÍÍÍ<éµµµ®-„q¥TÊH2¡ò’8 á±@Â]nôõõMžxð  @²Í°±vš`w²Yúü å+C¢ò’Â#á±@Âx¬€äèѣβ靈³Ó\ÜBˆ‚ƒ"óáñ½‘+7ËŠNk– sÿý÷ïܹÓ5nÜX@†¼el€ 7Mæ¡éøÕmÅþFÀ¦M›t³£`H¸E,p'˜¾»ËH2ÁÙ_å%BˆbÑÒÒ‚}:tÈd47L¸aË–-Èq[[›5=htX”ÏHïÓ`J½nÝ:T›^œ'ál›G­›@Â-b„;©d*#É„ÊK„Æn ði¿§§Çyh®˜p7440•Ýœ¶¼§³³sÔ¨Q   c6ö> ¦Ô+V¬`uoÕ~@ä —.]z饗t³#ßH¸E,p'+#ioo¿5Nž<©ò!DayILš%ºŒ [œÎmºÌ0Ë`ç>& i½¸õºuëx?Àz ¶kDƒÊKò„[Ä w°;F\3.^¼è}:ÒL†'ð·½mŒœÙÈ[’‚žþ&ëöÏ2LFR^"J ·È7¾¼äÀ&»EçÈ‘#*#‰-nQ|0³±cÇFòõÉ"ðÑa•‘„ñÂ=H™m·· Æ&Ð`0o’4Ñkš`÷ÂY(îÃ%çòQŠH¸Eðå%k×®uÎ[¨pX‚͘]ã+V¬ ï@ãÓa{6¥fļIæI¸ÛæQ«¼$ÙH¸E!)by‰ÊHJ ·(}A%âE‹.]ºtûömLÈ ô?þÀ>G›S³ihnxáF©í&72m]aÈ3€‘&L0ùäù.á¶ÕƒRí 4¦ï%¯2BxɽôÒKz±% ·(0áòN,…áøƒÊHJ ·(]]]ÕÕÕ|ð'©0Û¶mÓÿøç›–‘¤`ÊnE –L'Pè^ÇYË»¾%ñuëÖǹ}~ÀU"Aå% FÂ-Š‚//9}ú´“âüÐÛÛ»lÙ2•‘”nQ¬€äèѣβïi3w£E¤Œ¼Œ$OÌž=Ûî‚ÛÍr—Í3*/I*nQ,¬¼äñÇß¿¿³ã¨ùꫯTFRrH¸EAI)#É&¤ò’ȉªŒ$ðYkgZ x¾QyI"‘p‹"ÂU,å%*#)Q$Ü¢pd*#É„ÊK¢åé§ŸþÍo~ã4SÜÍ›o¾ù/ÿò/XšH îu/D‘ðå%§NâƒýÈéééQIé"áÂÊHÚÛÛù ž='OžTyITØž¨J·“ĦM›ìŽ‘n% ·ˆ¾¼dß¾}ΚsåðáÃ*#)i$Ü"ïX%ÃÂ… /^¼h=,®_¿þÊ+¯èü#çbñâÅy­*Ù@Õ7ЬX±ÂövÈ¿ËÌ.c/½ôRøŽQoo¯;X¢”‘p‹˜pûNyÉš5kLsà£>RI©#áùÅ—‘˜=çŒÊK¢Â_,×>ÌDNÿW÷-\H0jÔ(ËŒûZÀÔÔÔ¼þúë47oÞìúFÆÑ£GuÇ(©H¸E¬È¹¼„“’ÊH’„[ä‘ÜÊH2¡ò’¨ðw\Ö­[çÜsdðÔàÄ(Üô2Æ5îà3>ÀªÃìiÂíRׯãÜ6ÿñe$v Ý1Jn7r(/QI’p‹¼àËHøXÿ}t\»vMå%Qaw\æÏŸÏÜIhN,_¾¼¢¢¢¦¦3¦øö?„i&Ofüøñ,Ñe“·{Õ6€.–LB/]4 €$ó„…›1lÑ5rââÅ‹)e$ºc”<$Ü"†„ËK8 ŽÊH†„[DOWW×Ì™3ßÿ}§ÉQ³uëV•—DB´å%v+:ðí7ÒÜÔÔô»Œy6&íÃLºP0Ìnl[Ó¦%èîî¦Ë&Ï•‘” n[ìfÇ/~ñ Î?N®ï†sÝÒ¥KuS aH¸EÄ´´´`ÛíííÎŽóÉ'ØŠÊKFÎÈËK°aìÙߊ|ûÂíuÙb–Œ´U†g{íf|0Íxé ôZ*#)$Ü"΄ËKœeßÁNȺ)<$Ü"2òTF’ •—Dˆ//éîîæÀ „xÇŽ>àš4KìyõêÕgÏže/AÙ¿?mIÆ!0ø@eyðóƒM•<À_|QwŒÊ ·ˆ9–—¨Œ$ÁH¸E4仌$*/‰ _^rðàAg©Ù^7¦ûÕ9]¸±jòÖÛÔÔD™¦kÓ¦M6ÿ&›Ðqš,YL¸YÒ ÆöövÝ1*7$Ü¢$ðå%*#I6nVFräȤ­ð¨¼$*Âå%ÎUKŸ7êŽQ"á¥W±æææ±cÇê¦@²‘p‹áËHÓߢpõêÕ—_~yÊK¢`$å%±Be$匄[”·oßæk§)ÐMDRáîêêjiii˜2e /²Ò‚}®¯¯gçùHzèÐ!÷¨Ê_Fâ´·ØlÙ²Eå%‘ÀÁ´ò’¶¶6>Ì”"*#)s8W»HˆR€Wìµk×NŸ>­›I¥pœ­ZµjjÀ¢E‹L¸=ʻҢ³³síÚµì|]]]uuõäÉ“ vïÞígÙPÜ2’L¨¼$*x©[yISS“sØÒáã?VI™#᥅^±‰§Â}êÔ) Ï~ûí·±UÓÖÄÐÓÓƒÞÕÖÖ"ß{÷îu¹¨\¾|¹¾¾Þ5þþ÷%K–¸("¬ŒdÁ‚çÎû.~\¹rEå%QáËKΞ=ëd6Þ Ö*# }¥…^±‰'ïÂùM™2eÛ¶m·’N[[Û¬Y³0ï¢{Þž={î»ï>ïÙÄD‚•‘lذÁém\QyITÜ,ò•‘ôE”zÅ&ž< 7ÞYSS³víZ'¤åÁçŸ^UUU\ÏC¸çÎ;fÌS/Ü|ø™4iRee%"b™ábe$_}õ•ImÌ9~ü¸ÊK"áv)”—¨ŒD„‘¾ˆÒB¯ØÄ“/áÆ8ñÎ/¿üÒ4´¬øÛßþV]]y»cQpî%¸5MnlÛšÍÍÍhwÿ¸áó2’L¨¼$B¬¼äùçŸ?sæ 6>ðšT‰HAú"J‹ôW¬ÿoj—‰Š%/ÂÝÛÛ;sæÌo¾ùÆý6IùqíÚµŸþô§þóŸÝ),&ÜcÆŒioo7á&&ô÷ÇdI©”‘dBå%QáËK8`²[tŽ9¢2‘Ž„[”靨ÊÊÊÆÆFl;,ߢD‰^¸ûúújjjÚÚÚœ{–+.\àÝ‚ªºãR@¼pÛÍìtáVU·•‘>|˜g6B<è¢èdÎcÇŽ©¼$|yÉÚµk󕑈LH¸Ei‘þŠå„fwÇü=2»¦ÛV:NS.^*D/Üuuuï¿ÿ>~6qâÄà‹Úú Çaæ¢/¼ðãaÆ 4¿þúëéÓ§‡3`Mضm›el Kk¦`ûsæÌq©¡`»°–ÃÅî½¾˜Á 7xá¶’º|mÉà©VFÒÛÛkÚšÜE}}&LpÑP¬_¿~Ñ¢E| aV’Öë±ïŽt™64zôhÜË5Òà‰PyIT½¼De$bp$Ü¢´ðËÅzîܹvAooo·rP®ã4MÄ9ûõ±'báîèèàõkîÞ½ûñú;jÔ( R` #]#!¶µð]Ì›€1o¼ñ†eˆÍ°M‚‰mfVyõÕW Rf3Â+2Õ€–Ÿ‚í¿ÅÙŒÏ{µzõêï¿ÿÞ ‚€Pnß¾ÝbÞ“¾ö‹Oüo³,³2’t N!ì¾<. ?’ƒlJÍæˆ·nÝjùÁðN63dñ0›7oVyI$ðònnn~üñÇ÷ïßÏK®|õÕW*#)üñä3ØéÓ§­Ö—¦¦¦>úÈ5„ˆ% 7'7ÿ?Ò\¾í~6XR··K‹ˆ…»¶¶vÇŽ\ù>ÿüóE‹¡P‡¢‰`Y²ÿNfz„û’g ½†ô`` vï¾c$nMà“¬nwIW®\i™tø”Þ”=a'-ö;CÌž°$&É’ØŠ±ey i6D Ìo]œýyä6qûömwŒJìËHx°.º£Ñ8:IŽuÙ3aK¶ÛÛÖeÀ¼9 ³ñÀ1ºfϞ̈́Àš,ÃÏk1ǹ¢¡PyIT„ËKœ çŸ?üá*#éðÚø§ú'¬eܸqÿßÿ÷ÿTWW[òøñãnœ±d@ᆰpÏ;wOç=K666÷²D±ˆR¸[[[Ÿ}öYMî 6àC4M£#3QïÍ>c“q&× `IžÉ}o¿ M˜€uY3LÊVÀglOˆÙÃs¶«á=± ²}NyP`³±iÀ$~]xï½÷–-[V*ÿÙYF†ƒ`GˆÉø9XyŽŒeRèjó6l«0Mbiò4}!Šmˆ˜ny¶B=\›U^¾¼„—ýFœ7xUðVR‰ÈÄsÏ=‡µ¤ƒy»BÄ^¨.º/Üœñìo± ¹¹™SâöíÛ-iD̉R¸ -[¶˜e" 4 Ì·ÌMmigiªjk®Á$6áØŠøV¸×6d7›Ã08EÄSö$¼]ëJÏø=ñ]~ÛzÉ0øu ™8qâ™3gâ“»««ë‰'žÀ_od ÖE7nðð-˜={6yš;î¿ÿþ… ZW’á¼´¥eüËWTT¬X±‚¦mÈ÷†W›6mRyI$ ¼De$"þûÿï&Ùžú§âõ㺅ˆ+¼V]t7ᢠ»¿ dÉ« Ç"þD&Ü}}}“&Mòw7wíÚ…€ØíI ‰Ø–`7> è"¶¤Á_Àlþî¦a[­~NÕ³a¬öÀ5Rö„¥ßŠu¥gßîD¾ËOb‚­°uˤ0sæÌO?ý4Ó­8¯‹ŠJKK öÉÇg£Ù‘.ÜdÖ­[G`–ôÜ@”MŽÃ´µµ…EÙ|:]¸FACCƒåmCÖK³p¶Í£VyÉÈÉky‰ÊHD–¬ZµÊ<ÛóÜsϹ>!b ¯U‰„™pïÞ½{îܹN0C Ȯ¹)>j÷¤1T+3 I2\r€TÑËL†%G†ÀK°n’Vû˰¸¯`·1䑸”=I×k$˜€>Ó?ûÝÂÍT6M’dlyšž·Þz«®®îÌ™3î`ÝaïÞ½ÕÕÕS¦Lqí"ÁZIOOóÐ¬á ¸èŽ#Ç<|T˜&*LÌäoN§@žL`Òœ.ÜLÅ00ç¶ Y/ÁH„.]ºôÒK/©¼$|yÉ©S§8°#‡×¤ÊHİàDaª ÿý¿ÿw—"~ôööVUUñ)±µµ•—+J@@“$]nH ‘ 7/‘7ß|Ó)L@ØÞÚÚÚ|€¡PÖš)žG/Ipí;k¥d,`][=Ó ð›NÙ?ž¤6Àgü† <˜ØçŒ³oß¾3fà 7oÞ´Ã…ŽørC$Ò’E!‡2’0þP€àþ°Ø³–]ý‡,tÐüàà÷p|°vËx)gi½Aú®ÝÈ •—D…//áeï¬9W>¬21\þøÇ?Ú©¸0¹¬±¤®®Î½XCèu›H"î¥K—þþ÷¿wò"î©}衇ÐâòåËõõõî]PDÉË­Œ¤À¬[·Ï^¸p!Ú]QQá²y@å%QáËKÖ¬Ycêœ}ô‘ÊHDnØ·”L˜0Áµ…ˆ+\wÌ<“'OîëësÝ"AD&Ü555_|ñ…3‘ï"´ûw¿ûݸqãìMå)J%ÃHÊHŠÂλÿc$Oày*/‰ŠœËKxMªŒDŒ„ãÇsjýãÿèÚBĘ”o×ijjr"YD&ÜS§N僚Ó‘Æ„ þÇÿøîýðþßüæ7nçÄݼùæ›O=õ”{e‹Cy‰ÊHÀZZZ¸p¸SRé0eÊ”úúzv1:tè{TBäŠpUUU.+GdÂÍ«$æ• ÅåÁäMUSSãÞUw;v¬;‚…¥«««ºº:çÒí³iÓ&«dPC$„ËK.…ÊH žm†°.Z´(ðí†/¿ü’WHiÁËríÚµì<Úm¿­³téÒÝ»w»Ç)ÄðÁ L ð—‰#2á®­­å…r= 8°páB–ÖÜ`q,_¾¼»»Û5ŠDOOÂm±wï^ÿÖ2ŠõÇÈ}}}‹/ŽOUɖ׊àÏ,Sÿ8u„\ êI• ú;ñ¨°ò’_üâU'×wÛkQI"á}Ä“‹g#©Î[“ç?þ˜+ 'vi·Èææfd€W‘k‹$™p×ÕÕ­[·Î æÈ¸ÿþû›šš¸Ð ¾üm!Á믿ôÃXqüøñ,Ož<É3s}a[É+G}ä‘GL#ìpmܸqòäÉ&ÜEþ¿,€8Ü´ÞLã‰Yø©)ªK¾ŒÄlTÉü‹-\^¢2’¤rùòåçž{În”FZ|ùå—V`鎂Y€<ûì³úcýd™pwuu=öØcN0G@EEÅ=÷Ü3~üxÄ×ÌÛ„{õêÕ4,™€$ȱgºˆY`SŒ¤«¦¦†€9O“ui¢Y ð[!Ãê,›šš‚U#ãÅ_´»w===îxÝ¡··7’lÿã?þ|öÐ470ætá¶ç…§€¥5-扠iÿ#A“'bÀñô2’eØÑ¡»»›U\#W¾”2U2ä_^ÂG)•‘$•S§NUWWÿéOrZNpjš5kÖþðw,„l›¦˜W=9w‚‰L¸aêÔ©íííÎ1G€°úuûî;Üx˜91ÆŒŠ™pÓ?ÆCÆûy ßô[áµNÀê¬Ò?":&Nœxøða|Õp+~DR^‚1sôxR€K©"c½aifK’VdÏñp<Ëôj"³‰.*#)öb;v¬~"A*++Oœ8ñ}¹Âiÿç?ÿùöíÛÝ"fÛVYÚÑÑñä“O^¼xѺDˆR¸W­ZõÆo\1xX803&@¼>ûì3 À¬Ž.’4ûW¸z•ÌêÕ«-6è²µü<Ó¦Mc“[3e+áÙ"á/ù VgJÁYجX2òòŒ9å7MŽpð\õƒ[cÏ“g˜-ÏÓ‘^Ob#]#'TFR\x±=ðÀîÐëà'‹ÚÚZÞYÎ=óƅב)_`؇™3g¶··»ƒ"DfÛŸþ9çCãèÑ£?ùÉOä܉$Jáîíí}øá‡¹p:ÓÌ3`xöêŒ1¯]»¶D@X‘±m,Íâ3)Âmø&AÊVülûöíc9ræÍ›÷ᇢ§OŸæíäVŒá:aå%Ènpƒ~p ýÿ0Ø!=qâÇÓ2<Ðkuó555ާ™ò¿žÉà‹/¾¨J†Èillä`Z\__?äÿ"Ü<¼/tð“Oýš5kn‡W_}õðáî‘5/°âôéÓ]*Àò®°aƉlÈ2 °ŒÉ$–yã7,ãÇpQ³Ìpùæ›o¸Zqzq‡Fˆé¶mȹ“J” œjßyç.Ÿ#áÞ{ï ˜Xðƒüàµ×^Óì(ÍÖÖV‚`~fÍše½,IÀò6ÏÆÉÛMnšäS¶âg#o+Ž„°-³ºsçιÃ{¸TXyÉÁƒMR³cNnLiæ¨M–A·‰5Ÿ‘À„{ÀñézM2¥X?KÚÛÛUF’'+++ 8È“&M²ä Ü.I¡££ƒ×€éfö ¶»wïv¬a- øúë¯-cø¼m=ÚÆX·öŽN`IÄš%ümÛ6´ÛÆÉY¸ÏË–-#pHˆ€L¶mȹIÄÂm7¹1Kç›eÏ3Ï<ƒâ›Ø•–Õñž÷å%ÎUKž •‘ä•1cưD¹¬zó&F¾í?ÖI›”ƒ„;yàŸ|ò çºa±hÑ"̃΄”ß%?jÔ(°2`Μ9ÖK@’µÀÖ¢É täƒõú¡É×ðÓBWWlÀ³Ùº ·eFW®‰|áŒêŽ‘({·mCÎ<"nhmmýÙÏ~vY\¾üöÛo/[¶ÌÄ®„no‡IyI¬PIa°›Üþö6þÍ¡æ½`"~ß}÷“±^ w°ÛÛÎ4‡~Œ|*Ì©̉QÞ­[·àĘ1Ã1¾Ý¿¢3KbÖ"ß?. ¬×àÇ{lIÖb]°ø1ïPÀn-ƒ[@†Þ††KöööZÀ2ðêþm-¿Šå-ÚV÷0ýµ˜.ؘíàÁƒÃúõë}WÎÌ;wãÆÒ&1,Û6ä܉!_ uuuË–-ëéé¹Tf¬Y³fÖ¬YÞ¶/Äø»·‡…//9{ö¬“ÙxƒX«Œ¤ðxᶸ¹¹™fcc#M–|­¬¬´î$Ágò™3g:Á&æÍ ÷ôéÓ}L/~ì3&Ö~­Ù³gÓÅ?&¬ÑöÌò$m$“Ð$I`zí­Ú6±råJ¿ÊÖ­[ãw#°vNž|qK”%9ض!çNynøÿø§žzjÇŽNE“b÷üóÏsbíêê2Ã;wîïw8JŸ*/QI±! ‡ÝJJL¸éò1H¸“Ä;ï¼ó›ßüæFNðÞ´€‹;wî´|ÈwvvZ†µlÅðZ¶¢ŸÐã» &IÉ„·b± `¤%ÇKGGÇ#<ÂÛùvÇK”fÛ·r…+šœ»Ôɯpãš_|ñEuuõœ9söíÛÇk%©pR®««{衇֯_Ø]?çÏŸO’m<¢ø——¨Œ¤$p' >M½ûî»N0ÅÝðàÁäDtéÒ%w¼D91BÛ6äÜ¥N~…Û¸råÊÆ§M›öè£b¥I2ïŽŽŽÆÆÆÇ|âĉ«W¯6·3üM¾Dbå%Ï?ÿü™3gx~ãùsçTFR*H¸“ÄsÏ=÷Ç?þÑ ¦Hcܸqœ”8¹ã%ʆHlÛs—4…nèëëëííݳgVŠys¡åãþ“O>ùÐC—?úÑØs ›˜ý_¶lÙ§Ÿ~jngpJ-‡ÿ7ôå%0Ù-:GŽQI Á;ÈE¢ô©©©ùâ‹/œ]Š4~øáýû÷Ÿ9sÆ/QÔÕÕ}ðÁΗ£@Î]ºH¸ N:™Ÿõ·mÛþOÿR ìùáÇ]ûœI»»»¯_¿îmàËKÖ®]뜷x¨Œ¤äp' ÷à˜ps^rÇK” ¯¿þº‰r„ȹK”‚ ·ñý÷ߣG½½½fE€ªº¨4á±ðˆx\î–E//QI‰"áNK—.ýðï‹ ðj·³Âä™H4y²mCÎ]ŠA¸Søî»ïnÞ¼é¥û¬Z•—<þøãû÷ïïÿòòÕW_©Œ¤D‘p'‰U«V½ùæ›Î.seáÂ…÷Œ?þäÉ“.¢»»»©©É5r…ÉÁâššÛ"nnVTTØ€Hà¼4qâD–§NJÞ_Ò‹tòjÛ†œ»ä(¾p‹d./q.œþð‡?¨Œ¤t‘p' >r¿øâ‹×FÆ‚ vìØA°|ùr”×’`I °a‹Oœ8‘xhòùßòaV¯^mÛ$›6m²­œ={vÔ¨Q¶"X3*¾üòKÎTœ ôUÜå€Ùö÷ùGÎ]ZH¸E”øò®+NŠóCooï²eËTFRÒH¸“Ä©S§~øa'˜¹â…›̉YÒd‰ [ì{f-°.š Ý®ömØ`n¦e~Ÿ÷‚îDÅï~÷»_ÿúל¦0{w¼DB)˜mrîBÂ-"¦å%*#Iî„Q]]ýå—_:ÇÌ Ó{›I%Àž—/_Vá…Ûgšššúµ=wƒI6mÚä'¡‹ØºlÎZæôlËò‘ðØcíÙ³‡3Õ¹sçÜÁI¤À¶mȹK ·ˆž¼–—¨Œ$1H¸Æ;ï¼ó¿ÿ÷ÿv¿>•ðgŸ}væÌô÷øñãd즵+ÓK— ¦Ë2äÃ]–!|{%™Iȯ^½šûöí£‹ØzÉØ šlÎ5F>d?3 4ÝÁ‰ƒ×ÿoû[gÁ…EÎ]H¸E¾ðå%§N²Ÿ¾!===*#Iî„ÑÛÛû裞={ÖD30`庺ºY³f ¾øwÐÙOت‡+ÜÌcMff]6mO›6ͺl6ïÜÌ`.¶ðÜxñÅí¿ãNŸ>­[IeãÆ¿úÕ¯œÿ9wü‘p‹<âËKöíÛç¬9W>¬2’ÐÕÕ…–Ynò®!J–¦¦¦åË—÷[gNÌŸ?¿µµÕâ{ï½—åš5k~ðƒØnN#d¬I€7ÒÌZ`y °y˜,éa?ÒfcùÚk¯Ñ$¶&KšH¹9sàÀvÏNYþ•/FÑmÛsÇ ·È/¾¼„ §sçáóÑG©Œ$àcÇŽ­®®~î¹ç†ÚÚÚ©S§’”Ž$€¾¾¾)S¦üõ¯u¾YöÌ›7ïÃ?´³ÖõrúY´ò!&¶mȹ㌄[‚œËKTF’<êêêPíV­ZåºE‰³wïÞgžy†Oî¯.ʘµk×rÞó'.w€D‚À¶ùË_ÞŒGŽ‘sÇ ·(œ†[^¢2’DÒÑÑá,û“'OîëësÝ¢ôA4—/_\Ù³gOuuuWW—»tâJÞ¶wïÞ¸n¶¼ð _ýµÅÃ]7äÜñDÂ- G¸¼„sÁ਌$ÁX=‰§©©Éuˆ¤ðòË/ÿö·¿uîY~ì߿ڴi‡¶s×¥K—ÜqIÁÛöo¼1jÔ(žk“Ý!aäĉ-F»Y÷ÕW_µf„ȹcˆ„[+/ùÅ/~ÁuÈÜ:…îîî¥K—ªŒ$Á´¶¶:×~પ*—ÉâÿïÿýüóÏóæµÿ°*ìf·m}÷vòhiiY¸p¡©-öü /LŸ>Ýšø7O½94>M@ƺ C8=z´5Á¬b÷¿YÒ»mÛ6ëbÚp“€¦ Ç9wÜp‹"À¹À——˜d{ì¸ÊHžmÂ|»”H¨çüãO>ùÄ©hÒéêêâ3Ƽyó|% §¯Û·o»Ã!ÁîÝ»þóŸ_½z• Žkºì¥yÔ¨QÈ·é/ITž3gŽõ¦`k¡ìvƒœa¬Ë*¶ú† ˜Š^†±iãå4ŽƒYÿœ;VH¸Eq°¼De$埸°íÚÚZ× W˜5kÖ“O>ùÅ_¸÷yéì쬫«{衇֯_ïN^Á½m¾Fض™e„;èéï2Ÿ Ã[ÃjK0f3òð0VGµ]#r†1Kq2vK;ƒmÑbsÇ ·(&¾¼ääÉ“*#)+úúú&Ož¬ïÞ.®_¿Ž‹ðYúG?úVºcÇ“ÔÀ ¸±±‘ÏêÕ«ým¸¤ºíÄȆmp_àÙ·%/Íè2–€%[2 ’í×µµÂÂm+ºF°!Æ[ÒÌž%ëš©ûøüùó6† X¯9wLp‹"Ãé ¹¹yìØ±*#)+P“ÚÚZ w™ÀÛüܹsû÷ïÇJ«««xàÿößþžúÐC…E¥üž³\¶lºãÎ\ÝÝÝ7nÜp\$lûÙgŸ½rå ×&ãСCx°k|÷ºì—°uëÖéÓ§[Ìé΂0ŒäMañ„ ÏlŸþ9Mb¿:ë2lÑ¢E+W® Æ~GÓVdÉŠá8耯¾úJÎ]t$Ü¢øÜ¾}›K—»X©Œ¤ hiiÁºlÉÇ-—I§¯¯¯··÷ôéÓ¼ÍÑ<õÓO?µw}´ ÿõ¿þW–®)|l`ÏYºvˆ³gÏ^»vÍ=Z‘ ÒmÞxã /Á0gÎ,9l½X2M p©; ë^ÇaÆ ŒÁ¶m<3“dBkÚÆ[“­0Þb‚pl#DÎ]t$Ü" Ü\¨¸«Œ$Ù \uuu\Z.]ºÄ­7nÐ\°`ÁåË—Ý‘tø8ÍÛüܹsÎR¿ýöÌ™3.ŠˆÇ{ŒS K×Î3ÝÝݼ€oÞ¼é¡HÚv)"ç..n ¸:ºH$—®®®êêê>øÕ³mÛ¶'žxBå%å žŠ ¸Fôöör>1ˆ]6j¾ÿþ{ýZS9°wïÞŸþô§ °mCÎ]D$Ü"pit‘H(V@rôèQgÙwÓÙÙi.îF ‘+?þñͶØe…>³fͲ"éÄ ç.n ¸4ºH$Ž”2’L¨¼DŒœðím#7¹E²I¤mrî¢ á±€ë¢‹D²ÈTF’ •—ˆ‘¾½mè&·ÈÛ¶!ç.<n ¸.ºH$+#ioo¿5Nž<©ò‘é·· ÝäÃÛ~úé§yÙôõõmݺuQð•|]]]4#a×®]&Lp¶ÅV ¡¡Á¥òÏáÇåÜ…DÂ-bE‰DÀÙ¼®®náÂ…œÍG‡ëׯ¿òÊ+*/Ã"ýö¶¡›Ü‰‡E}}½küýïK–,qÑð Û6ú;zôhœ›`úôéý–:˜ôÁƒ]#7ÓºF™Ù³g³d+YnhXØg×!ç.$n ¸(ºH”>¾ŒÄés®¨¼DdÝÞþçþççŸ~ÅŠÄ,aâĉÿôOÿ¤›ÜÉfÏž=÷ÝwŸ÷lb †KضaÔ¨Q>6Ö¯_|çuÿ—aÓÄ’-ƒÑÒ$É*$ È£étØH?l@á¶.` l[lCx3yëµ›îäm ¢¬3ÆŒŸ} &ÃC 9wq‘p‹X áN ¹•‘dBå%"K¾üò˰U§œR$ÜÉáž;wî˜1cìÿļp×××Oš4©²²òÛo¿µÌ à¯3gÎô†®Åˆ,0ÒºXšþâµè5]d,@ ‰™„Ù%É0“P¸ébÉ ÿ( 8¥aŒ7î‹/¾pÚ8L¸ñcD™¦—Wò,nÓqßkFKlu?˜&`äÖ –É$Ü6ÀÏÀ0KØVl*[Ýo:Óx?`„pqî[·n¹·™n 8'ºHÄ+#9|øp_üè pA9vìØÿüŸÿ3·òlì“¡îæææp^ÄR„‡ÞO?ýtOð{éÃIÅY V7|»Ú2ŒÍJ¸ív¸a3æü€ð ,ÁJDh®[·Žf&áNOL08€ÕÕÕ»víâ ,çÎ ·ˆº:Æ<ÕÊH}ôQÓÖt¦OŸî¢ >xðà„€Ñ£G[°hÑ"kZ†Ëž ëׯwk¶b“ƒÅCrï½÷æV^bVmµO&Üö;Ì3`M”ˆ:¥ˆ0¹97’jâËI µ Ë«ùw¿ÒîܹeËòv®c)ºLÀºæÇ4;;;­¤„&òn–6› ÉZÌc{EÓJJè —”„ÇÛæ€1ö@†…·mN€€s»#+²FÂ-b®ŽqÀÊH̉¹x˜³¦îB©9§Ç6c[…ù³uëVK ®+„§[kóæÍÃ-/A¸YÚ9™p[5”õÚ_&X,â‰N)"…¯¾új¸ÎÍ`“i@j}`“à²fƸ/M,–˜ñ†ÙZ °‘–l˜&Kâ™ÁÆÓk±_ad¼a§Œ÷û È·ípö°nŠm÷Ýwî°Š¬‘p‹X «cÑI)#1EFŽ Àß`ë2†%ÜN«Ìž=Û–ä üíó`³ý“¼çž{ˆÙ †ÙýrÛ^qE±¦_׿$é5ýرcÃúön.-ØvºpÓ+áŽ9:¥ˆt¼s_/W6oÞ¼|ùr×ÈÙvTH¸E,ÐÕ±ˆà£VF®6Óe™~CÚ\ÖÀh³nº˜Š1]]]–¿:ÞLÀ4c¶æúõëM£½:›pÐÅ´¬ôô{9k±ÀÌ~-¸|ùröå%&Ü€dãú¾¤„ ¹¹™ÀzElÑ)E ˆœ{Xȶ#DÂ-b®ŽÅý}â‰'W÷‡wÀeYî *ÞùûúŒpi`8ûM‹mH©Dˆ-ðsÚ$,$KûC%?Òæ!°a¶´.û_ZÃ2~-ϦM›²)/illtQè[w¶oßÜæv_¹#âŒN)"rî,‘mG‹„[Ä]‹BKK ö9à×Ó†­Úª]#'á¯&“pÓ´FO&á¶??ò]ì*̾҅°mµ~'Ùè”"AÎ=$Ó¦M“mGˆ„[Ä] Lß2.9ÎCïÆ ØJ;***°XËC„Û&°ØË³·–$cÂm]ì'Ikr`ZšÌ9 pÃ¥K—^z饾½D” :¥ˆÁ‰Ð¹8à¢,Öàt8ï¹ènržvÀ 9‹VWWïß¿_¶!n tu,$™ÊHÂXí§]NÇ)u áf¦¸’Å)]&·ÀðmÚ°&Á€Ó†G‚ f™i»F–å%¢Ñ)E ÉÛ;.õ9áX<8 c°käĨQ£X¾`#û}HÁ& Ù3lÛÝÝݲíHp‹X «cÁ¤Œ¤ QyIRÑ)EdÃHœÛ«já…;¨„;Ŷ{{{¿ÿþ{w°ÄÈp‹X «c²Œ¤ôsQLgÕªUn„È'.\X¼xñüùó9É: >veüøñ4S„ÛîF“a¹yófšŒôyLYÚ0‹ÉÓdZ– 7]Ë—/wásñâÅ”2ŽÀ•+WÜq‰€3‰‹„&)ß[’T<˜ro[wòŠ„[“ªª*“lÏäÉ“}‰È7–—˜¾ýáfÉE‹Û6#·<± 6 çÓ—F¥¦™~‡Û2¬åÚÃGe$e' 1|pî§žzêìÙ³WJ[[›l»ÀH¸E1imm5Ïö ^®O„–— Ç(2 (Üa]fŒ-éeÉ0Ÿ›%ôÏä`¥~å1.>*#)8™¸HˆœH°s˶‹‚„[™ÚÚZSm¨ªªrYQX|yÉpÿ!ö§<;îüiœfÏž-Ꮎ¼¤­­Í­K •‘”9n-Ù8÷´iÓfÍšÅrüøñ4S„ÛJìȰܴi“Ýœöy¬šYÚ0‹É3Ìædžtá^»v­mnRlûܹs·oßvL ·(2---ÕÕÕ¶Dò\V_^ÒÔÔäÎÙ¥ÃǬ2’2GÂ-"ÇœûÌ™3W†âÞ{ïe9?À7ðƒغ7nD‘-Ã’Ø¿öÚk¸õš5kü°cÇŽY/´¶¶Zla¼kdàÓO?•mÇ ·(}}}uuu‹-ºtéïÿ7nÐäcýåË—ÝQl|yI©ü>b­2n‘wntE†…Û–cl‰@³dëšX³„þY‚<,o])ÂÍe@¶$Ü¢8ðþ¯®®þàƒxó‡Ù¶mÛO<¡ò’øPBå%*# ·Èƒ8·Wê…]>vìÁš5kì¶t]]Á¬Y³¬˜ÄÄÚßá6¿Ã¦»h >þøcÙv|p‹"`$G5ÉN¡³³Ó\Üņ'%þå%*#a$Ü"drn¤]öêœ"ÜvÛzͼYÒµqãFƒ[Ò†ù4s’‚áf-›*®¡óæÍ“mÇ ·(()e$™PyI ±ò’çŸ>›ÆBÂ…De$" ·È+Ù×sl×·ó!ȶ〄[ŽLe$™PyIÜðå%pçõbsäÈ•‘ˆt$Ü"ßÄÖ¹Slûüùó\OÝN‹â!áÂÊHÚÛÛo ‡“'Oª¼$Vpâ¶ò’µk׺³{ñP‰È„„[€:wŠm_¸pÁí«(6n‘w¬ŒdáÂ…/^4ׯ_å•WT^+Š^^¢218nQ̹OŸ>ͪèȶ㌄[ä_Fâô9WT^7¬¼äñÇß¿¿;Ù ®p*#ƒ#á#&Î-ÛŽ9n‘Gr+#É„ÊKâF¸¼ÄòóÏþ𕑈!‘p‹BRtç~ûí·eÛ1GÂ-ò‚/#ámÿ}t\»vMå%q×—äûbÓÛÛ»lÙ2•‘ˆlp‹SDçþío˹ÑΊ ÛŽ'n=]]]3gÎ|ÿý÷&GÍÖ­[U^+ P^¢21,$Ü¢ðʱí_ÿú×î´(ÛŽ1n1---Øv{{»³ãüpâÄ ¶¢ò’ø×ò•‘ˆá"áE¡ÀÎbÛ/^tû!⇄[DFžÊH2¡ò’âËKN:u) zzzTF"r@Â-ŠEÁœ;Ŷ9aº=±DÂ-¢!ße$™PyIÜðå%ûöí3iΙÇ«ŒD䆄[sî¨î; ˆl»äp‹°2’#GŽ […Gå%q×—¬Y³Æ® 9ðÑG©ŒD䌄[—¼:·l»‘p‹áËH!ç¿ÅàêÕ«/¿ü²ÊKbEÎå%*##GÂ-ŠNžœ›Ó£l»)‚pwuuµ´´4L™2…ÓbiÁ>××׳óÍÍ͇rª,ñe$N{‹Í–-[T^+xR†[^¢2 œ«]$DñˆÜ¹_xá…ð鑌ےˆ=…nälÕªUS-ZdÂ}ôèÑÛ¥FggçÚµkÙùºººêêêÉ“'ìÞ½Û=β¡¸e$™PyIÜà-ãËK.…ÊHDTH¸ELˆÐ¹±íwß}×eÛ¥F!„›×†g¿ýöÛØªikbèééAïjkk‘ï½{÷ºÇ\T._¾\__ïÿû’%K\VF²`Á‚sçÎ}?®\¹¢ò’¸aå%¿øÅ/¸H8¹¾›îîî¥K—ªŒDD…„[ćHœ;Ŷuz,9ò.ܘߔ)S¶mÛv+é´µµÍš5 ó.ºçíÙ³ç¾ûîóžMlA$XɆ œÞÆ•—Ä›¡ògÙw°[à*#"á±b„ÎbÛW¯^uóŠÒ!ÂwÖÔÔ¬]»Ö iyðùçŸWUU×óî¹sçŽ3ÆÔß 7~&MšTYYÉÛÕ2ÃÅÊH8q˜ÔÆœãÇ«¼$Vܨ¼De$"H¸EÜàÒùä“OrŠs羬‘m'ƒ| 7Ɖw~ùå—¦¡eÅßþö·êêjÌÛ‹‚ƒp/ À­išpcÛÖlnnF»ûÇ ‡˜—‘dBå%1Ä——œì¢»¹àŃ}¨¬¬DUÝq) ^¸ífvºp«ªÛÊH8Ú<³¥Ë±cÇT^+nß¾¹ËˆÊHDÔH¸ElÉÆ¹Í¶?üðC;C‚l»Ô‰^¸ëêê†ûÅÌÓ§OwÑp=zôîÝ»Á”Õ_p€ 6L xõÕW-ÃËø‘Lb™7ÞxÃ2~LÎ?éräÈ‘3f¾˜Á 7xá¶’º|mÉà©VFÒÛÛkÚZÒðD¨¼$¯466rU°˜—ÙÇ%ºvíÚéÓ§UF""GÂ-âÌàÎm¶½qãÆÀ´û‘m'€ˆ…»££™s¾™5H­‹†ƒ 7Á×_m£_·CÂm3ÒÆX·öŽN`IÛ†1xÛ¶mh·!3’ßPDñW¯^ýý÷ß»TíÛ·[ÜÞÞŽúXŒ!â¾98VF²~ýz³Õİyóf•—ä ^`öYŽW]6' %ùC¯.s29wºm_¿~Ý­#J™ˆ…»¶¶vÇŽV8›=&L`yèÐ!@yñ]2£F ú¿[0gÎë% IðùçŸÛZ4‰É‹- Öë‡&c\#ÀO h%lÀ³Ùº ·eFÂéÓ§yä¶rûömwŒJd”‘dBå%ùÃþ<í¶|˜71òM@“$±ÿ)‘Èzu‰ø“îÜé¶}ãÆ 7Z”8Q wkkë³Ï>ëLs8xcF…Ϙ£¼[·n%À‰qVè}ǘI²Šy¶o°VX¸Ãz ~¼ÇÏÆZ¬ –GëIšú„÷Þ{oÙ²e¥òŸæøh’ÊH2¡ò’=qâÄ3gÎÄÿ&7÷‰'žX¿~=oòr`Ó¦M*/‰¬Únoï¹óL@@®"6RJ$ò‡^]¢T0ç>yò¤l;ÙD&Ü}}}“&MÊí¶(ŽËr×®]Ø­e` È`Ï –´ù­—.VñkùUL¸-&·Õ=ŒÄ,-¦Ë¶nK`¶ƒZ اïÊ™™3g~úé§™nr³3.**---Ø'ŸjLFËl›G­ò’ñ߇ÃÒb°’ÀÅIZSJ$ò‡^]¢„À¹ÇŽ+ÛN6‘ ÷îÝ»çÎës˜ "ÜÓ§O÷1½ø±Ï¤÷ìÙ³ébÉlaáÆž@ž¤dš$ L¯½UÛ&V®\éWÙºu+cünäÀ[o½UWWwæÌw°î°wïÞêêê)S¦¸v‘`­Œ¤§§Ç4Ô³eË–ô¤§¢¢¢³³“€åÂŽžu…!ï¢Ì ®bçÎ<®1¶Q ,cø¼AÌœ°nÝ:— qéÒ¥—^zIå%Qá…Ûâææfš4Yr+ƒoË¡)%ùC¯.QZðŠu®-ÛN(‘ ÷ªU«Þ|óM3˜áÒÖÖ–`]€OyÜÎ2®e+¦;¢ï2˜$%ÞŠÅ6À„ÒšäÀ¾}ûf̘Á»èæÍ›v¸N:õÜsÏñ$Õ’Eað2T5ÓG^n¼™O#4I†*6À3 …sÃÇÜÃW¬XáCѯÕX§lÂç {yU°Ÿ–IGå%QþB@^óVRbÂM—¿BDŽ^]¢´àk5¨\\J$‹È„{éÒ¥¿ÿýïÍ]D HíC=„|\ºt A;úEûE”¼!ËHÐVnŒv„ a‹E‹ÍŒSî›Ô¢Ý$éBvÍËÑëþ›ÌÁ$¸/½@/#É7ÿ¶Áò0˜}`Ìá¶ÈŠ@à×" —¥åS¸ÿþû]4*/)0¼ø]$DÔèÕ%J ½bOdÂ]SSóÅ_8sið^B»÷»ß7Ž8LQ*)# ƒ¶"ܨ°©ª¿ß&å¶1#Y…%Ök²nȰ:„˜f Êý“Ó»eË[¥ý»a°‰¸æÙÌcsÚ$Öd RN/SYÞʘ}ŠÍ§£ò’B‹ßEBD^]¢´Ð+6ñD&ÜS§NíèèpÚ"ÒÀÿÇÿøý~ðþßüæ7nç2ƒ¶š4³ÿ) ëÉ$ܶ"xáFîI2Í~S&÷ž2@[ŠF†n?ƒÏ{h²¢k Å›o¾ùÔSO¹W¶È¼]$DÔèÕ%J ½bOdÂ]UUUn_p1,|ðÁÖÖÖššš~Û 1vìXw KWWWuuõ߈§zoFX½õ†!þóG¯×)ÂgvÇ:Pâ¡…`’mñº XÜÛ$Öô3ø¼gÅŠ¶Ý!Ù´iÓŒ3víÚuþüù[·n¹ã%ò¯ 5zu‰ÒB¯ØÄ™p×ÖÖ"”×Å@ôôô Üý{üí·{÷îåÃI¿kß¡··×ÄÂÒ××·xñâÁ«JÐVì–(µ•j¸Ž0y+ ©¸óG“dR„›¥yp¸ü:áÆÑé²j ðol“XÞF"Öì å=ìUøSÁ€X=ɼyóŽ;fOV±žš2¿‹„ˆ½ºDi‘þŠ]²d‰‹‚¿8w‘(Y":DÊ f® IèŒ?þäÉ“.bóæÍp\ar°¸¦¦Æ¶øúë¯û.ßŒŠ£G>òÈ#æpv¸6nÜ8yòä~Ý~àÝ»w[²ðܼy³¹¹ÙþnÒíëÝpÀ»»» ³]HÓò)·þ¸-_¾ÜVò,9ªè5 å<‰¬ŒadxX: öclClÅ6d“øu Àæ·ŒÁ ƒ¿rxŽf̘ñÖ[oÙÓ|Ìøî»ïÜ‘y ý#DTèÕ%J‹ôWleeecèû,)J—È„ûwÞù·û·k#cÁ‚;vì @Ð2Kž8qbÿþý3,&Ÿ€´Œ_+ÌêÕ«M©‰7mÚd[9{öì¨Q£lEöÁDEkkë¬Y³p¸ðWq÷ßù=nܸE‹¹T1¸}û6¶kŽüóÒ »anŽÿ€Ÿ¦Šˆ/#1ÕÕ“)‘Èzu‰Ò"ýË•h̘1¶„æææI“&!âÖDÇiÊÅK…È„»««ë±Çs‚™+^¸½X#ÄPSSÃFÚ€˜.‚þu®]CŽY‹ñ€R³ÄêìîuXÇŒ÷iVa°Ï{Aë~$¼øâ‹vë´§§Ç¯;ôöö655¹Fñ¸páÂâÅ‹çÏŸÏ: œ{áÂ…ÛXÙöÅ‹SÊH8™~TD‹”H佺Di1à+·ž;w®)u{{;zM°gÏš&â\¶ú‡ŠØ™pÃÔ©Sy8ÇÌ /Íæ»¸2±u Äý~çwºp{K&ƒÅ„Ç ¾iÓ¦°p›ßƒMb÷¿™™a–„‰'>|˜w^ëVü²¼$y¨Œ¤¸H‰DþЫK”¾b¹*Ýwß}£Ýv?,©ÛÛ¥E”½jÕª7ÞxãêÀ€?ûì³3gΠ¿Ç'Æ}1`ƒ|àÏ l0]0˜‘á.Ë„“LÈ$äíø¾}ûè"¶^Û¢ÅlÈO>rþò—¿`uæsÈ·;X±¤0å%1Ae$EGJ$ò‡^]¢´ÈôŠ ÷ܹs÷pÁ²dcc£/81'Jáîíí}øá‡±gšÃ6Q®««›5kŒ[—øsŽÂí}™Y—M`ÛÓ¦M³®æiþí-að_|ñE•‘)‘Èzu‰ÒbHáæR…[›p777_¾|yûöí–´"æD)ÜP__ÿÎ;ïà.¹äµ¶¶Z|ï½÷²DŽðƒØnš7n¤‰%û.k²ëBÿšW®0Øæ '=ûöí³Ù€Õ‰Y¾öÚkè—o29½H¹™`÷©ûöܹsî0Å_^rðàAg©I¡½½]e$EäÔ©SþËÃò®!Ĉ‘p‹Ò"Ó+6\4‚a÷”,YB@3‹ø±pÛMnÌÒùfÙóÌ3Ïð!ÁÄ®´¬.\^â\µôá¹PIqá1vìØšššU«VqihhàSzUUI/âBŒ ·(-ôŠM< 7´¶¶þìg?»,._~ûí·—-[fbWB··Ã$¦¼De$ñ¡®®ŽKK ø·ë" xQ¹HˆR@¯ØÄ½p¢Y__דּ\ùä“Ofß½m”nÑ‚//ikkse饆ÊHbEGGGàØÿ`òäÉ}}}®[ˆ(àuå"!âÊîÝ»[[[-¿bIññDžÈ‹püyóÐnçžåÇÎ;«««ýÍÔR¿“êËKšššœÃ–ü±ÊHâÆsÏ=˜¶#_E/¯+ W¬ÄnòäÉ555¼bYM•Ø%’| 7ÔÕÕ-[¶¬§§çR™±fÍšY³fyÛŽówo _^röìY'³ñ±VI¹qi©­­um!"…W—‹„ˆ7*±+ò+ÜÆ•àû³§M›öè£b¥I2o>›666>þøã'N\½zµ“»€Ë—/»ÇŸD¬¼äùçŸ?sæ Ïo|8wîœÊHJ‚¾¾¾É“'ë»·Ež@\\$D¼Q‰]™Pá.®½½½{öì±wäUõàƒ>ùä“=ô½ÈJˆýèGì9†MÌþ/[¶ìÓO?5·30¼røÿ _^ràÀ“Ý¢säÈ•‘” |"}öÙg“ý¹TÎÏ."ö¨Ä®(p7nÜ@€Ì„Ž;¶mÛ¶ðúGHWWZï ©£… ìùáÇ]ûgΜéîî¾~ýº{´e€//Y»v­sÞâ¡2’Ï®©©Ù¸q#K9·ÈnQB¨Ä®(¨pßÿ=zÔÛÛë´(PUEÄêÕ«yí¦Ôxä ˆÇåa™Qôò•‘”fÛVLÂòÉ'Ÿ¼xñ¢u nQB¨Ä®(‚p§ðÝwßݼyÓ5¢À^¸œmóú§¾ì³jg͹røða•‘”\TfÍšÕÞÞ~k80^Î-Fˆ„[Ä–lnCp“s'ŒäwoooتSζîbÁ‰ÃÊKÖ¬YãÜyø|ôÑG*#)9r³mCÎ-Fˆ„[Ä“ìÿÓ+]UU'C·¦(q’öG“mcEÎå%*#)QFbÛ†œ[Œ]D ÉÞ¶ .‚Œ—s' ·(9”—¨Œ¤D¹mrn‘3ºˆ¸1\Û6¸²ÖW_}åf%‹„[ξ¼‹•‘”(QÙ¶!繡K€ˆ#91rd]9w©#á…ÆÊK~ñ‹_àÐZ§ÒÝݽtéR•‘”"ÑÚ¶!ç9 K€ˆ#?1r”s—:nQÂå%cÿ»®2’RÄ_T¾9·.ºˆ˜ÕmN€rî’FÂ-ŠÃ€å%*#)]ògÛ†œ[ ]Dˆö?ý8ʹK ·(&¾¼ääÉ“*#)]òmÛ†œ[d.¢èDkÛ'Àêêê;v¸mˆÒAÂ-ŠŒ•—Œ;Ve$%JalÛs‹,Ñ%@—|ضqýúõŸÿüçrî’CÂ-ŠÏíÛ·y¾œk«Œ¤¤(¤m¥èÜUUU¼ÂË©{Ìņq‘'¶m˜söÙgn{¢p‹XÀóuíÚµÓ§O«Œ¤„(¼m%çܼ¼û¿P· ˆÏ‰W—Q, sbäŠ)ç.-$Ü"èù*9ì¢räÈ‘›Å€í–s—•pûí·ÝÝÝî‘RDQ(äm9wi!á±@ÏWiQ\Û6JȹËM¸Á=òâ¡SŠ(<…ÿO?9w !á±`ÈçkÉ’%.úûßëëë]$ŠAlÛ(ç–p]D)¼mæÜüãÝ~ˆ¸"á±`È竲²²±±‘ÛË·(0ñ±m£$œ›—·û[§¤#áåI±lÛ0çþýïïöFÄ ·ˆC>_\ÂÇŒC`KÀ¼'Mšäå7E>à¢R]]ýÖ[o9Û1_ýõ o¼ñ†K… ï¢Û\# þÎ=,áæ,^¼Ø5BLÉOœ8ñ‹/¾p€Lë ·(CŠkÛž_ýêW~ø¡Û'?$Ü"dó|UVVÎ;×”Û&¶€ g:ñ8\铊]TÖ¯_? çÞ‹± “o–“&M"£ÛÛyÅ.*_}õÕ矾hÑ¢ï¾ûnëÖ­&L@”‰=H3I–Ä]]] &ÃJ† õ’ 4YZo–¬b]¬î'' ÃTl4Xµ-’¹Ÿ„}‹­sK¸ymðÁ'Ntí[·~üãÓdiÂÍ#µfºp§¬ëGÐdušH¹uÙ´ÖõÍ7ßX“ŽûgnQV؉1>%vðË_þRÎO$Ü¢8 Ú“'O7n\mmmCCÏKŒjÊ”)cÇŽíííuãî&,Ü{,dÈ»†ˆoÛx­nüøÜ¹sh1±A!&@šW®\ÉHÆ!=z4y䨛7¶‡16“& cL¬™Ü&aë~ØŠåm7ØÃx:7/owj(>Œéð ,CóÍ7ßüë_ÿJæ…^°.<›Ï«¼l¤¯k#Y—Á¯¾ú*M’Ù¬‹ü… l0+¾ÿþûýëÜ ·(r¶íóçÏ»(?ȹ㉄[¦¦&ž¦tV­ZåF¤á…·®¬¬4áÞ¾};'>–\æ%Ü‘¶mðÂCX¸¦×îF{ÏSg¼™U,ŸI¸Í¶Á ÷† îþAwV´8*çÿoI}}=Á5r‚WµÒ¡xæ™gLˆ}Àk>èù¾¿Ôý…h¯e²nx$„0­MhÖÎx</§7³´aÁzCÃ#•p‹rÀÛ¶}Ðuª›áñÄ)” rî"áÅ$ý'¯'OžìëLÒ kÎMìên1Úm½"Rl¼pÃÖ­[Ñ8»i h1rÌ«$1{¶®°£Ý6±Ý7l Éáf6¦õ¥#ýºY¸!çFC­T øþ”à…í„t(Ø.`àAe¬ËÄ7¬ÑÞ¡!eÝðH°ŒÅÖÅÐKþõ¯ýñüꫯ†ã .Ø03$‡æaV´ØÖ²{Û¬H° ø^¯â¡s›U[…’ ·}‡›´|öðÚvÀA _‰GÍ…œñbë% ‰ÓôÅ Áª©ëÚH°¤94]Ä)_ÈH’˜)ñpá‘J¸E‚I±mÞtvšÓši1ªmïDßÅ›Ô+u –G¬ímHÓÔœ©üê†ÃÛ“<ïP“rÇé¬^½ZÎ$Ü¢Ètttðd­­­.+Š •§Ÿ~]닚ٳg744¸Fvp[¿~ý®]»¸Ì¸l°ÿ9;7ÂÍÒ~nÉ„Ûj–¬×þ~Àâlàµí®~I‡G*áI%Ŷ“Mí‹M_2vohÛ½ç…f-Ö%` ¿.°ºMh0ØT¬E†˜À,ßÇœôˆ X¯œû·¿ý­{ ¢xH¸EñYºt)ÏWmm­k‹¢’?Û†áÚ6tuu­ nœøÕ³mÛ¶'žxBå%…Älã3ϰعsçý÷ßOÀ’Ø’#aa€k ‡,w€ÇXçætä¬ÿnx »[·n%nhhÈæ? ü‡œÁaLú'Ù³g#ÜþïVmL–f‰„[$†DÚ¶ñÑGɹ „[+ 9zô¨³ì»éìì4w£E>–m¯[·cÃnYÒLnò6`Ë–-<6ÌX`3?°µl#,Ü6Œ$Mb¿¢ Àm­Q£Fe#ÜPçÎ$Ü<œ•+WºFúkÐqÜbœØD™˜Ë’˜äôà'6ˆíȱÿ"0™&C’ YúfàÛN¸™ßf`Nš,í“ÚN®_¿~Èÿp‹d`Û6pnÞÎîÑŠ‚ á…Kr¸Œ$ˆ‘ÊK Àpïm÷ôôX€ã"¸&ʾ‰ó­X±‚&ªíó,19¤°-¥ÃÅ+**È3[xuòaáf X%Ãl~¿![y²n(¼sgnS^×ðÊKÌC³ÒvkïÇ@Æœ˜¥Y2Ðk7ÎSföcl€ŒñÚÆÖãlyó{–CÞƒ—p‹`'Æá–Øeoç”OÚEá÷¿ÿ½œ»H¸EáÈTF’ •—ä•áÚ¶awRMp!lÌÞ›-Ã’Áxmö†% Ô¬Î$`Ãh+¥–” è¬k›£éç·a~ëá®,)°s"ÜfÌ©‹Áõ6 Ö•ž®š`1ÇÙÆ°äh‡¹_—Ñh®ñ$ l° ü´þN6Þ³Œ'@l€MÈÌÁØT$Ü¢ÔI±m^í¼òÁ>I¦·F˜ðÛͰŒm+åœ Ì9à§e9w!‘p‹ae$ííí·†ÃÉ“'U^’r³m®ëÖ­#0ÁõÊkMz·lÙ tMÒŒÙnftvv¢Ý\ºl˜aƒÁLÚb o÷Ôm€·j†ŽÛÖÃ]Ù¹sŸ:uÊEip:r[½…Ýì÷øCaÇ“¥Œþ¦d |Héµ#“r@lÇ lc†&ì?Øbû°D²«"á%Mºm{öŒ¹zyµÿ, »,ÆŒ=»ÆÝ]>? pÛ§Ü”®ðT`MÛ¨-S Þ"± cr›?9wÁp‹¼Ã[º®®Ž 6rãRN:u÷îÝ®"“p{n‡‹ÇŽõÚáIžO/þƒ>±˜:ûŒ%FÒŽ!™”b‡Ñ5‚^/å~,YÝ6mÃÐn6ÁäŒ!ðŸ¦AÂ-Šç´úúz×}wþ°H±mT5E‹ o“éÓ§óF³&ÆóFãBL€ÅX –AÜnzmfV! iM`{ƒ³ kš3ÆÖe¯Àv¦í1ÚÍ*`ùtpî_üâî@ˆü áù…sÝ¢vúœ+*/‰ŠœmÛÀ½p5_ÌMì—`ræ›àÓ–„~Ñ ¡oú™ ’¬•²Æøa ð›È›ËÕ¸qã8óÔÔÔ¤¼Pnzÿô&'¥iI l@8cÐô¿–>bÀä4ý˜ð&ü †o¦ä3!áEaÏž=÷ÝwŸ÷lb ²'Ŷ!]‹‘`ÖbºY–ëׯ§é­7ìÁ^pIö¿0`>= p#Ät‘·{Ò~¶¸råJ¿iÿçá AøãI¶M6ÆâÙ¼yó¿þ뿸Ã!ò€„[ä‘ÜÊH2¡ò’‘3BÛN$:7—4Î<ÆÒ¥K¹4Zž¦ÛXÒá‘J¸EáA¸çÎ;fÌNq4½p×××Oš4©²²rð×dºmƒ9«k„µý5o[/AzÂó„…›i26G§I`þm éé³¥lˆ8¼ 'öŸÀ¤ßÆXh†Ù±cÎÍ»Ø5n‘x÷ZÉ… ¾Žk×®©¼$gdÛ™ˆÊ¹¹RræñŒ;– ‡Øm)éðH%Ü¢ð ÜKpkš&ÜØ¶5›››Ñîþq1 mH­/ÝÆhy;‡oZÛMå°õZ>%cI»Ù¼~ýzf`ë2ÈØ`<غXÚnÃoÚßáFšmßPÖ ßác ‚}q;3rî¼"áÑÃ;æÌ™ï¿ÿ¾Óä¨á,£ò’à¢òÅ_˜‰82ÿò/ÿÂy#r&OžÌÒm&éðH%Ü¢ð˜pŒ3¦½½Ý„›˜|Ðß[Âà·!vá€ÚÚ_8 îßÕ´j«…Ћû ÐôótuwÄÖeñƒÓÖÖfÓ¿±à¯;,oM„›¦ öÄÖ%ðcl¼ý} [ܲe‹5ÉÎgŸ}&çÎn1---Ø6§|:åQŒ?žå믿î²w àÀ׸ò®‘F¸Q ·( ØóöíÛ-nooǰ-nllDÄ}ÓSº¶]0pî'Ÿ|òÒ¥Kî‰#á`e$G޹Y T^2\¼s;Kº›“'Ozå"¶¤7%þZÓ 9à´Ò$ï·ÎûÉiЬeÍð[7<>/_¾œ#ÓÿÀ‚fÉSÀ£  —Âÿ¤ÐôÔf0üÑ —¦±ƒã± ý˜ô655ÙŠl…'zÈz$Ü"æÈ¶‡*Ú_ä-g$Ü"w|‰ÓÞb³eË•—dÏ€ÎNy Lnš¨f®F¾»»› Cq8`],YÅOHÌœá­`{`±áW1×ôIóo›Ÿ%™ô,m€Ÿ–Œm4Lä¶=8œŽ®¥ÁŽíرÃ5®]ãã¢Ác´Œ °$MŽ0M O“Ã{öìY?¬…»a€-Oœ8acõêÕLe1ëîß¿?}£wî¦7®\¹¢ò’ìй›šš°U»aL‘åìO@#xýNyÓYš–´›Óæ¾¶Š÷Ýp ¶•“'O2‰Ý&Û¨ ßÀ6üüéw¸ ¿nàÛwámn3c‹Ïž=ËAÀ§õ½Ë}i2’Àn-é¾>ï0±¶˜Ù8Œ³î€eÇXúUߨGÂ-âIn÷¶ÃÂÍkž3‰Å>0hvvvºÆmmm4Ãã-c±öÕÚ`c8Y¥ü½8ï5–érQ@J3}»át®=LäÜ#GÂ-†‡•‘lذÁì6¶¨¼${ÂΊ§l+Ì è¿YTT[Ó2,1c2\|†¦é²5mbNúÀE…¼yyx+dÂk…W±›¬d€¦ŸŸÕ-“2€¥­øv¿pûŶa@á¿ó,ñ`2a÷%Ô’!CL¯w_f1дƒÃxš,íP‡ KèµìÍôÚ*6fÿþýCnÔ#á1$çJ’táFj 8«ÐeÒì›,iòÞš¼YÌw‰gÏžMÒ¾1‰<à"Å’µÈ{ÿöØ0û-š)Û[—$ó0 e»)ãÉØ„Œ ¦Ï9÷‘p‹a`e$ø™ImÌ9~ü¸ÊK²Äœ»»»ÛyS8ƒ§h'qÅ]Ql8]ÍÔö³Ï>#8sæ ±%ó O«k×®ÅÅ-Άø÷¸qãØ!€Cn?²ËI5LdV»mºlÀ.w7˜-C@™¶ß¤f°¥Ýf^±b…ïJ‡a=A)¶Í“i»(5¤o7e<Ûúá0âÜ#ùu°rFÂ@ø4þÚQÿs#!æe$™PyIödãÜé÷59‰»(ÞѶӑÒá³úNM6˜y€Y³fÙ§M›æRÙÁ#µ#ì¹1 çü «­‰,K ˜.y¤™Øò6 <ž1œ$m¼Ý]‹/½ ðÇü0?-Ø<¶]f#fÍôíÃÿ1>< güÿrþ”s瀄;ìÙ³ç¾ûîóž=àOÚ‹R)#ÉñU^’ YÞç.9ŠkÛ0á.-$Ü"žäæÜت‹Òî^d-ü·n`—Â[ñ¤wÊvqhðÁ w¸ ¿ŸF[ZËxÛ¶78gQwdEÖH¸Â=wîÜ1cÆØm]/Üõõõ“&Mª¬¬ÖåÐÊH>Ü7bx¯ºèn<袼qìØ1•—dCòœ»è¶ n!ŠŽÜ†åÜa&F[Mm‰Áj²iÚÍf ILÆ’Œ· 24½I¯X±Âò–øa Hßî–-[l4ͼS¶›2ž MHL—ÅY’nÛ…?‹& wA¸—àÖ4M¸±mk677£Ýýã†båÊ•óæÍ[°`ï.ç­#ƒ3KÞü`côèÑ™\¹ö–¸ÆP0’ì+>Rˆ‰mC$Â]àÃaß¾}Ó¦Ms<#á1Ç;÷õrž²)KdÛ"áN ^¸ífvºpYÕme$555æÁÓ§OŸ0aKÓVX¿~=D™¥Kõõ-Z´håÊ•ÓÅ’^Æxš&ÜŒ±a tù°p“a[6Øþl€­B“ôS“$`X0¼ÿ?éhnݺ՚ `•{˜¤ÊK†„ËÒSO=…^»Z€µ®‚'ËEi òWwØö€³!ÐàƒræÌ™M›6?~œ­àÜ.ÀžÇç:‰pÏpáÐÚÚúƒüÀ5òŒ„[Ä9w–ȶ£EÂ@¼pƒn+)¡Ë×– ’jßFÂ[ æ8.ù0ôZ@,îê겑­Ù9–~sh¦K2UŠpÓd?clpÊ*~*¿ –¶Q„;7½¦iØÀåË—õí%C’îÜûÐ\ŽKËs`-ÀzyýXlxNé•ï¾Xšcî¿y[WG@W¿nÂm[±$¤Oî¡ËV1beÛ¡p¿àRW®sL,>vìXpë,³qãFVY³fîðxòŒd€5#AÂ-J‚ýû÷ãÜ/^tj)ÒmGŽ„; ‘Û·o·¸½½ÝE`cc#"î›é ªO<ñÄúõë­rkað]Bv›9¥êË’˜–1P¨ÎÎN_"¶nÝ:Æš füQõ_cd1Ø0`13Ø$髨T4}WxüŠ+,oc¬×ŸSyÉà¤8w` pn–Ÿ}öÙøñãͧ9°,§M›†ÌqTqè`x?™ºˆéš5k³±¤ÉTp GKK öþ-.<Õ{pø[‡£µ¯"éÇŽËZ6Ò~éŠ lÃ,ûyáBß )“x-Nù]€ôUl*š)›HÁöŠ ½ÛæQ«¼dÂÎm*l^‹æbxÖäÀ²¤ Aç?¤‹§Ì±ôñãljm°mÅÜÚno#å6ÂkdLÊ!†¶ Q ·yöŸþô'\yïÞ½,‰­É’.^Ï÷Þ{/12mI>ž%‚΀‘p‹bpçæüã¢aRQQa?Ä!¶3Ý–1rÞÖ N¶'$Üâe$¼Íœ‡ ©ˆ,škåf´or’ À®Œ—“1K6G·º[—.–ýŽè/IF2Á€Â tÙx›Ó¯bÛeßèõ› ¦×Æû='ƒsûÙRæ¥K—^zé%>ºàŽˆ¸ïÜ ÷ßáædM`K4—gÁ|×îR‡+³é¢iê>lÉŒa‰mÛŠØ?xÀ;ÜÖ o‹ dZ lW7»}Nà»dÛCÂ]¾ôõõ-^¼˜wo«JV¬X‘åÖfß4âÙàQp)¨'™7oÞ±cÇü©Ç,q7qpîR±mp Q*|øá‡æÜæ¦PQQ±ÿ~ HŠìájbæZ/™ôñdhöO8ºåm˜‡v#ÍÃìwþÄÂÉ‘pôèÑ3f¼õÖ[vÞ_§žA(®s—mƒ„[ˆ‚Ë¢¿Ï`dÛFÂ]îܾ}ÛÆ5×­[çÜ3W싇¼@§˜t¸9êΙpûï92˜'}]Эù˜ž28|‰w@õ$Ù`Îáïf [,­ë„„[ˆÒ"ñÎ-Û.<nÑÏ… /^<þüžž'¡Ãü[ÿtÿieŠŒO,\¸$1î¹ç‹Éû‘æëôBʺִL $S|}X )e$+W®¸ã"†¢ðÎ]r¶ åó7Ü>ø =/î‘ Q²àÜ\íËþÆÙÿjA‚‘p ÇÈËKn>4 Áv×Ùº)øJÿÍ›7£×6’%0ÀºÐqÀ¹½U#Ù˃ï+µ,}—aëÍ •‘DB!»mÛcû\0Ð_÷˜…(eéܲíb!áÿ`„å%^£ÍªÁ„›%¬š|JI · ¶.LšŒî2È0À5†ÊH"¤0Î]Ò¶ ì¿íya(¢póHÝc¢ÄyçwV¬Xá\µô‘m ·HÅ——tww»j¯ì@£-@¬-@‘wÜù-Ë~¤ X`_rd]5Áב².Kšv?Ûº Nþë†ðÅ_TI´äÛ¹Kݶ Âí"!ÄXàŒu8Øu€KžeF×ÖÏ>ûÌ5®^µ_ç%¹oß>—Ùvq‘p‹ðå%t–šéÂM€›FƒÙ³Åûƒ 7•kÛšŒ±&æmãIºFÖ´··«Œ$OäϹeÛ9 á"*rsn»®D%Ü\ ÃÂ}üøq–k×®åâh™Am ·˜py‰sÕÒgãÆ*#É+æÜ§N²ßŒfÓu"$ÜBDÈoûÛ!ÛÜh¦ ÷¬Y³èµ$clÞL>èïÀ²®®Îƒ}ûöÑœ6mZŠp¬NÞ52 ÛŽn19——Ä •‘Œh[¶3n!¢eHçöm†øö?„i^½z5VM6Q¦iè%ƶ½vÛêæÙöó)ÂÍDܦ̈́l;&H¸Åøò’¶¶6÷ö-5TFR`¢rnÙöHp 9æÜý?¾•×^{mþüù÷Þ{/1XÓ–pìØ±üà¶´»×ø·-I"ܬȒ®ÖÖVfãiZl0€Ù\c Jë7Â’„[ //ijjr[:|üñÇ*#)<#wnÙö‘p ‘qn„xÍš58ñàÂmVM€R3iFÓ‰-É’&“˜[³´¼uYÒƒ£»h dÛ±BÂ-²Å——œ={ÖÉl¼A¬UFRDFâܲí‘#á"OÔÕÕ½óÎ;&µaPj.7èò€ÂX³"ÆŒ%3†ÌÆqh’6Æì™.‚~Ýnme€uáå6-I2ætQ²í¸!áà„ÊKTFrsnÙv$H¸…È/¼ðÂ|àÜöø1†ƒ5͘M»·¶Öš˜1]ûöí³$ȃ•‹'f³Ù`yÝl;†H¸Åð(‰ò•‘ćá:·l;*$ÜBä•;ȶ㉄[ä‚•—<ÿüó)Ÿ¶‹Î¹sçTF7pî'Ÿ|’çââP0F׉¨pžªª*{YÁCv¾,Y´hQÜœ[¶[$Ü"G|yÉܽØ9rDe$ñ$ç¦W׉A†\$ Es½Ìbåܲí8#á¹ãËKÖ®]ëÞîÅCe$1gpç&¯ëD´È„ Çœ³bYÁCæ ÛÝÝíAYbÎí~·xèycŽ„[Œ”¢——¨Œ¤TÈäÜdtˆ wá)[áwÊ•¢;·l;þH¸EXyÉã?¾ÿ~÷î/8œÊHJˆtç&Öu"H¸ „»œù×ý×­[·º+Sa‘m—n œy}y‰;äŸ?üá*#)9ÂÎÍR׉zô¨®ùCÂ]x8æ|à/+$Üa ïܲíBÂ-"¦å%*#I<‰ÿüÏÿ¬ëDþpžH„û®°xñb|óÍ7)Šˆ„;…7n̹eÛ¥…„[DÏí|–—¨Œ$1øKµ®ù@Â]x†%ÜHó}÷݇=»öÐëÃf˜‹&Nœè×3fÌüc‹‹‚„;Â8·l»äp‹|áËK†ûËÞ™èééQIœilläI±¸¾¾žK‚Å™àRÍâÌ™3ºNä wá–p#Êvk4ú«¯¾ |Û%¿øâ‹‹/†…› ’m1ã‘oß4à¢;ºÆ­[Äa¿LéÊ ÷€xçvW¯¨Ñ/ò–"n‘G|yɾ}ûÜy"W>¬2’˜ƒpWVV´··Oš4É’ƒ #Ì+:¼…‡cþ}ÖŒ=úÂ… ,­ùæ›o£àèõ /¼`žyæ–dlŒÁÉÐzYË––±U°pÆØ„4™“.’Û`ºØ ™pWÿÃD‰ü9·l»D‘p‹üâËKÖ¬YãÎÃç£>RII0fÌ–h÷öíÛ 0ob䛀&Ib“ræÞ“½p›(˜`Àø7yTØ ™"ÜVaÉêLBàW1ü„îb6V±u 2ýë_]c˜H¸ç~òÉ'ÿüç?»+YȶK ·(9——¨Œ¤´°›Üþö6þÍSvùòeq®ëÄd¬WF˜Wtx OöÂ"ÿøÇ?F¬- ã­š¤Ç2 7ÒLÞ†™1[ìºï^ËÆ°-¿¹÷ßßnr›²[ÞÆØ]ðlpW1œ{äÿÇkȶK ·(9”—pPIÉÁuÝnoïÙ³‡xIM\xm¤Œ0¯èðž,…9Fv¿¸ƒ™1»Íìïp›gºÃM﫯¾j3° q¦;Ü,Sº<áûÜ `*×È ÷p-ûÉO~2rç–m—:nQ8Âå%Á †ÊHJ”1cÆàÖ,-+)\œ¤5e„yE‡·ðpÌofr+)1á¦ËÇ #Ì+:¼…GÂ- œ9·]첄c+ÛNnQ,/QIY!#Ì+:¼…GÂ-‡Ëܰœ›+ÛN nQL|yÉÉ“'UFRnÈóŠoáá˜ãCe…„{¸ ÑÓ§Oïèè0¥Žªl;IH¸E‘¹”—Œ;Ve$册0¯èð ·È†¿ýío?ùÉOwn©l;aH¸Eñ¹}û¶?kƒÊHÊa^Ñá-ÈóŠoá\¸í{ú-Z„õ¨ÈédãÇL®qœ~Ô¨Q~+~ IËD…„;g¾ùæ››ƒ)ÛN$n $eˆžô¼¢Ã[x8æ}À€±m×èëâX¦këÖ­fáLùlV1“öcL¸S6ÍTŒ$Ï´¶"Û¥!‘psî£G^¸páoû›l;ÁH¸E,R–,Yâ¢àëœ]$Ja^Ñá-<ƒ·W^Žkw¯Á<Øß~6NÉ Á´91àÇ6-Ðd[‹1&Ð fù~ŒM˜¾i›“< ñ¬Åæ>?g&$Ü#Çœ{ïÞ½²íd#á±`H9¨¬¬ ÿxŠ%EI##Ì+:¼…‡c~#¸/.ë÷ßÿÎ;}Ì÷õMëJϰ´ÁÀœ ïÐÓÓãt™1lŽ¥Í`]Öô³Y̲¢¢bË–-¬²"À’düŠ™pGÎýÏÿüϲíd#á±`H9à4fÌ[æ=iÒ$/ßᦈ?2¼¢Ã[xn@vQX‚ÎÎÎuëÖ¡Åæ²¸¯¹x6 $±j³ät'ö€™ÃclÂôMÛç’ìÛ²d6 .Ü}}}.CÁ‘ij9’²í¤"á± 9¨¬¬œ;w®)5¶Ml™öövñLç}Cd„yE‡·ðṗD[["k“Á˜ÃM‚``Þ2˜±õú ëÁJý~LÓîI[Ø`×3Ìa-˧l|LÀZ–ràÛ©'Þ7ÖÔÔ¸†ÈŽä÷ßæÌÙvR‘p‹XpN¿ï¾û,F¯M¾YNš4‰Œno—§Nêííµ8ü¤“ïèèp Ù¼§D´ṗ– <äáFµ§L™B¾¡¡Á¥Dè ›x$Ü"dy® wccãžË_p"â ¶=vìØšššU«VÙ%¹¾¾¾ªªŠ¤q º~޹óв‡ì…Û«¶±wï^;,"8b. EÂ-bA–ç/ܸuee¥ ÷öíÛ/_¾Ì’“¾„;þÔÕÕ—ã»À¿]·ˆŽª‹D¡à˜;-xÈœxß}÷ݰj§NrÇEdGÌEwÿŸm½¾›«ô‘p‹X~®ð ç¦ vsÅb´ÛzEléèè.Çÿ`òäÉúãªÈáÀºH ޹óв‡üÐCõ¿ EUU•;ÜÉ‚‡æ¢;軹†„[Ä‚ôsH0Ï=÷\pét455¹X‰BÁ1wZ6ð÷ïß?þüþwòÝäé73»(Y¤?.ÿ¶þn›››'Mš„ˆ[×/•n ’zÒÚÚÚAHêýª¢Ã±u‘(óëƒròäÉ;w²tí¡XàÙÑà!Æï¢&‡/ôzéÒ¥ýoé;䩆›™]”,|\áïæjoo·oسg¾›«äp‹XÔs¨ÈžÝM~àäÛ¥D¤è=Ux8æÎCâõ×_¿ÿþû.\ˆæf©Ñ ×”ŠŠ óø¦K†5j”‹îÀxöÇ5r…‡lÂmG ¬Ýyúà fvQ²ðqq`ý_.¡Ýv?,©ÛÛ¥…„[Ä‚¤žCE&š››yÒkkk][DÞS…‡cî<4»íîîF‹IzŸFÇÃnÍššš°.3Ðܼy3Mb&gÁ’,Y—d°Æ?„ÛÏÃä6ÒÃl¬bsúæà÷ãyÈaá6L»§L™âÚ‘’Ôv¦Çî¹sçÚWøÞ¨ïæ*$Ü"Hʾ¾¾É“'ë»·ó‡ÞS…‡cî<4 ³g×@‘ÇÑz]F£­Æƒ‘d°dî”¶.M´ÉZ¦È¶ 3ìܹӦ¢iÂMlšÎFi†1Agff[`30Ørºphw>¾ë3©/ìLË 7·6ánnnÖws•n $1ÁWz$Œ2¬çQ»H Žùµ ,p\yÓ¦Mû÷ï'Þ`rlcl­ô¶ôÒ3ÀŠ«W¯¦‹ØæÄ¿!è&a3˜ÜŸ8qÂud€‡øváʈ“úÂÎô¸ÂE#vAÉïã Ç"þH¸E,ÄžˆÛI¤ _`zO޹óÐ4_üÕ5¼"³Ä†M”—/_N&E¸Ód#ÜlŽ{ 7˜‚ãÓÖô`ç¶Š-Éðy€xpAç!K¸#AoØÄ#á±@皘Àá5Y˜tww»ÇYè=Ux8æÎCåµ[Ú'Nœ°jSd >{ö¬uYÓFVTT˜û¦\¸‰ÉÐL¹Ãm«³u[+Œ­H`w¸ms,S>'¤`ï, ÷ÈÑ6ñH¸E,й&&ðD8EM…ׂ¢£÷Táá˜;»…l#Ó,­Ëê7€$MtÙšè²ÝÒNà×¥7<ÀÆ[†1€=³¤I/KšÁ4ý;@3 .NžÁØ63ø-¸QøwVR_ØzÃ& ·ˆ:×Äž§¨É¢ðZPtôž*<ó«eFáßYI}aë ›x$Ü"è\x"n%‘ÂkAÑÑ{ªðṗ– …g%é…ÝÛÛ[UUÕÜܼwï^K Y]]/xÅEÂ-bä &ðD8EM…ׂ¢£÷Táá˜;- ÿÎJØ û¹çžã¥P__ïºE‚p‹XÀ)ÆE¢¨ðD8EM<®kAÑÑ{ªðṗ– …g%ì…ÝÚÚÊ# 3vìXÝÞN$n 8˸Hžˆï“«ÀZPtôž*<ó+eFáßYÉ{aOž<™åÑíí¤"á±€³Œ‹DQá‰pŠš,x\Ö‚¢£÷Táá˜;šiÓ¦;vÌ5†Ikkëøñã]#j ÿÎJÞ »¡¡eèöv‚‘p‹XÀ‰ÆE¢¨ðD8E”/¾øÂE!^ p€‰'ºè.\8|ø°kWµ èè=Ux8æÎC#eÍš57Áüùóëêê,™=¹­•%…g%ï…aó  ÝÞN0n 8ѸHž§¨™yóÍ7ï»ï¾to~!À5æ¢;üøÇ?NOWµ èè=Ux8æÎC#]†3gÎØc;vlÖÐq`˜%mFZÞd=Oþ•ȶýé¤no' ·ˆ’ƒ˜Àqs(&NœˆXOŸ>ݵoÞ|ã7^}õÕ9sæ§ùõ×_lÛ¶mÔ¨Q6À3zôhVd¼k߼Ɋ¾É*¬ˆÊ[Ó¦µÂÍ”®!)¼½§ Çür> {ÖÞ½{ÿô§?Ý{ï½ø4ñüzIþà? øáHÁÔ©S?þøãþ5óFáßY‰|aÛŸNêöv²‘p‹X 9ˆ <NQ3€L#Ͷ<Û½F—mÀ† H¦7cŒO£ì–a¤ 7° ÍÝ»w›Ê[Ò“d$F~þüùpL34…ׂ¢£÷Táá˜;Íén=`·$æm]ù£ðﬤ¾°§L™¢ÛÛÉFÂ-bä &ðD8Eͦ X/ÊKà­ÛzYZ&E¸Qg»{m²NlA/¶m±uÑ 0u°ÞpŒsÛ0kf¢ðZPtôž*<sç¡ùÁ4š`Há&6‚!y¤ðï¬D¾°»ººž}öÙŽŽ×IDÂ-Šg––––¾¾>k†Ï¡{÷î=tèkˆÂÂñÝ  ¿0aÂ[’Áª­kQËø.ƒ&«ÁÊ•+?ÿüs&q}ÁÌd,&`ŒMÅHK¾ñƌٰaC8Þºu« ³1™(¼DzIÌá˜;ͯ¼òŠ/)ñÂýñÇÿð‡?$3uêTK0’ ]§OŸ¶ay¢ðï¬ä½°¹VWWoÛ¶å{ï½ÇùÊuˆd!áÅÕžþ•˜vWWWuuõ|€j‡Ù¶mÛŒ3¾üòË[·n¹¡"H¸E1©ªªâìfòäɾÎDž§¨É‚ÇU`-(:ó×ÕÕ-\¸#æ3cLµm€Œ”UÌÚ­ÐÅòˆ8ËLu/nQ0NŸ>m/¶BR\áæ!»ŸòúÂÆ­çÎkJÝÞÞŽ^ìÙ³‡€¦‰8·è tuuÍœ9óý÷ßwš5[·nUyIÉ!áÅaÙzâ‰'T^R,†nÚSgoÃ`]éÀŒMŽÁJSl]üØwað^å-°1~°Ÿ–^VñîŽ[`K›0ż%Ü"Ù”ÏÓ×GÊ)â¾ûî³í¶ûÙ`É,oo·´´`Ûº³ãüpâÄ ¶¢ò’BÂ-Š€ þ#[¸¸- HŠpã¾àÞ¡í¦u؃³nüØ;tOOK Ï`ºÌžmXÂ÷¶×­[G‰ÇÂY—¤­ÂÌÁX‡„[$ wT„…{îܹ{ü©£±±Ñœ¤“§2’L¨¼¤´p‹‚’RF’ Iå%E‹Ùõ'OžÄƒ_ýu–«ËñãÇ/_¾œÇµ<ÖkƒÉòÀæÇ>N655Ùx?ÆØ¼y33»FÐ˦m Ø*ÌÆêÖ¤—LMM 1“³ºíg°öH¸E²‘pG…nN¸µ wss3£íÛ·[Ò¤àËHn–-[¶¨¼¤$HŽpófØÀ%¹!„%O:åÆ‰â‘©Œ$*/)<) ¨mÿÝé… ½Î"ܾÙÝÝMÓò$-°á àÄ4Á\™1¬k]@/¸Æõ뼋Ñhã7á÷Ä´ŒÅ> ·H6î¨`Øý%K–Ð Ç)XÉ‘#Gœ•—”¥-ÜHöÆ-Z4vìØqãÆÕÔ××;×°ä”)Sx—p!—|+#ÉíG¶T^R0x›8EM<. ·H0åótÇí‘ú2’óçÏ;ÿ-W¯^}ùå—U^gJR¸ñìæææÚÚZ${éÒ¥Û¶m»qㆻ):(_~ù%:Ž|WUUáâ2ïÂàÏGGð#[*/) îÄ á.+$ÜE¡Xe$™PyIœ)1áFÝÞyçŒûüóÏGŸ£G"Ü6Ooo¯›]ä_Fböœ3*/) \Ì®% ·H6îÂUÉôéÓ]*/‰-¥$Ü7nD‘W­Z5øßÛ D9‘oÝ=͹•‘dBå%@Â$Üe…„»ØÛ.X°àܹsxí™0a‚‹"âÊ•+*/‰!¥!܇ªªªZºtiOO3åè¸|­ïÔ©Sz·=1b|I>~dKå%ùCÂ$Üe…„»`XɆ œÞŽîE‹õ+jtò­ò’¸QÂÝÒÒ2kÖ¬¨î’f¢»»ûW¿úÕ¯ýk·U1|Y›Óä¨Ùºu«ÊKò³«ƒrüøq>ðÀêÕ«]*y…Øà¹2mÚ46 Ÿ}ö[Ù·oIâñãÇÛ€Á‘p‹d#á. VFòÕW_9«“ìQ£FY3B8aª¼$>Ä]¸W­Zeßöå¼8Ϭ]»ö™gžÑÝÓ‘`ç£ÂüÈ–ÊK"gpáÆ›¹*ð6Át1`> »Ž; háȱùqΰE6çƒûï¿ß6y×ÕÕC†@Â-’„;ßD[FÆ„û7Þ=z4KKF…ÊKâC|…›÷sÏ=÷öÛo;.Ÿþùÿú_ÿ«¬.ÌQ‘§2’L\SyI\¸ÇòºÆÕ«È7KÜ—$]Ç7-2<;8:½@/#ÉOño^6$YÅòX»­k½À°À„›4ýæ†DÂ-’„;¯ØÛ®_¿žË\ä Ü.êë›>}ú®]»\#:6oÞ¬ò’¢SáF¡xqúé§Î­ ˉ'*++ÛÛÛÝÞˆ,ÈwI&T^-ƒ ·¶ñýì³ÏX"¾dlM¤ùÌ™3tÑDôâß¶Jÿúw°ûâæÙ8·õ"èAç]0'yf#p©ìp‹d#áÎöß¶‡vö5&ܨvCCÃèÑ£0Ãf‰ötuuY2\¾|Yå%E$ŽÂ]__ÏÕÚ™oñhkk«®®æRívK ïaÎG1ù‘-N‹*/!ƒ 7B¼qãF׸ãÍéÂ:ãÜx3odšƒ 7¶m3¼öÚk~@8Ž—„[$˜òyº öHóZFRDT^R,b'ÜÍÍͯ¼òŠsÞb³uëV> ¸wãËHœö›-[¶¨¼d„p13Cƹñc”±&iºl̤Qmºl>ŒÑ\¸÷íÛGþÌ™3v‡›€ùÍÂ݈,`]“ûLH¸E²‘pGK¾ËHŠ‹ÊKŠB¼„{ïÞ½?ýéO¯^½ê*üû¿ÿûï~÷»Û·o»]w(nI&T^2B¸˜]”?þØš÷…eø„|úôi‹É³üáˆþþéO¢ XCæa*2Œ±9ûgšÖ› lnðñn‘l$ÜQZIOOÏäréÒ¥—^zIå%…$FÂÍ«üá‡æ¹wê*++¿üòK·—¥zQ__ïÿû’%K\v>*zI&T^2†îl¸÷Þ{M¸§NJà²EEÂ-’„;ºººžxâ‰õë×;-M:›6mRyIÁˆ‘p744¬^½ÚISœØ³gOuu5×l·£±‡¾ï¾û¼g[ VFálå •—äF$ÂÍaå•WæÏŸ¿wï^—*6n‘l$Ü#§¥¥…«Æ¡C‡œ–===+V¬paÂéšG­ò’áîíí}øá‡cULæç?ÿù‡~X*/G„{îܹcÆŒÁ3hzᮯ¯Ÿ4iReeeÎÚae$ÑþÈVþ°ÙRyɰˆD¸cˆ„[$ ÷H(JICCƒ‹îfçÎ÷ßÿ„ X®[·ÎeÅVqAp£*/) qn\ð½÷Þs¢?PÌiÓ¦;wÎín¼A¸—àÖ4M¸9ÂÖlnnF»ûÇ >ŠüG¶òÊ•àG¶T^’=\Ì8ù& ·H6Œµ ³³3%â¶¶6³ôã z€"‡göcÂyŸô¤ÌO¼p§ïOxÝðä)¨¼$ßÄB¸y¹ã‚¸‘³¤XòË_þòÝwß%p;cL¸ ÆŒÓÞÞnÂML>èï-È’R)#É„ÊK²GÂ$ÜeBUUÏõ¸qã\;éDû¼Œ„kÇ„ .\ØÐЖÚQ£F±$?{ö슊 C†4Iú‘~Œ5íÖ52‰¬kkaÆ4‰m]ƒ^†ÙH°mÙlŒ'o›2¬kSÙ$$ioV÷íŸ: •—ä•Xw]]]¾eî\€k¤P.Z´È52püøñGy¤»»ÛítŒñÂm7³Ó…{XUݹ};Rž~++Ü´} ’ÊK†DÂ$ÜeB¹=ÑQ=^® C–‘¬X±[µ8“p‡3,m6ò¬‹×ú¬k~ìe—Øn6ãÄ>Éœ`±AÓìX%}Ú‰m0r^”°uëVš–Ï|z¥ž3gÎo¼á™yì±ÇpÖëׯ»ýŽ+^¸Á ·•”ÐåkK†ÄŸü‘­éÓ§»(õë×s´ ø$Ã0{âüÏX“^…¼ÿ™/›2;°=;žá@v¨­Ë2À·ãì“<;&Ê^-¶ÕýSiÐäe@O´ ök±´yÀœÛâL¨¼d$܉A–TRþNOtÎp9xùå—çÏŸÅ^ˆåË—¨©©¡‰­Z“€& K`¼þúëdpeb?üx›ßµ.[ñf njj"OÆOB&På…¶ Më‚Ödu– `+~M–¶9? KØÞ¦Ã©ÒêI¸Jr¶ä°|§bîè(¾pO:•§ÖLhÐ5¼ÊT ì*Ms8ë%0í¶&a  —‘¶® ³ÀÌŒXš%‡dÒ¤IhèÕ«WÝÞ'ã e$aì8³Ìtôü17RüØ?eá.‹m-{Š=¶],ù(e­eÏãªíQyI&$܉A–T89WUU½óÎ;‡¢iOô©S§ZZZ81ê–äpÙ¶m›ýݤ³Î¬ñëá²å¢äèÑ£3fÌxë­·ìT©z’È)²pcH=ö˜“ ,@ª¼O³ääÞÒ¼„y]³1½ä™ìªW½lÀÒx9ž+‘ï.<œw²ù/6à²äÓ3—9éX2ŒŒ\#ô'6üù.‹m-ž Ë °.–Ö´ 6ë…+V¤¬2$›6mRyI QÕGÆ|Ю"îq–ëô';Lªli/woi^Ý`>gÌk#} –§!ôGÄÙðî»ï.[¶ìôéÓ·oßv!) þíHé˜pv„]ã)G»¢¢‚aá ÿ¬YlS1ŒgÇ’VÖF@— 7S±Jx~ ÉF]#;ì[T^’‚¹i¾Á\T@Ü#,8¼.‰£÷ÿoï]¿£ªò}ýþGÎ+áo8CåÅ}F³Ï¶#ûgëa B¶’ ‘á­ºÁÆB· rØ4 Ú±•€€´¢6[î`D.AmBB¸ÊM”ý{²>3³WªR•º×ªUßçÅßyY—9×Zs=µ2SÕÝ=tèÐÀ±ÿ 9öz;gôB-Íô’¸rÙ¦‘”Š2 wKK gÚ¹Ojp,t ÙÒ’œL„c#“] *:ð‰Ù”’”dŸ¹.¹(¹L]BðùÁÈߎ”Œ¼™ÎD‹½L'@¾Î—c­ÆŸ5Å:Sòu,É71‚Š=z Ú5“·œ ú$›^†”ÁE¥‚v¹Vt¯‹Œ8’ü’Û^oçOÎÓK*›FRJÊ,Ü‹/^¹r¥Ÿ´ _˜–)ëB½#ú@uäÙT“O‡k’©|±eŽÿ¿É°œ¯Y³fäÈ‘4ÇeUYM# £~¦éL^’щ—î]1p¦?S uÙ‹’á¢àöä³T5åç†M/)=(‚‹Œ"`Ýo^rÛëíBá§—\;­­­6¤””Y¸gÏžý׿þÕ)OAÑ+ðôpGKd·âƒ>ÈÕyùòeŽÿìÙ³ÍÍÍ~ÔÓ¿°TÙN#‰76½¤Äp˸È(Ö½±'ü’Û^o?½¤««ËÉif|öÙg. 1/À% ÊæÍ›§œì,5ÆŒã¢Os‰¾8p r‰ìÙ°aª­ï tYÐÖÖfÓHÊB™…{ôèÑÇw²S!Œ1bþüùO=õTbW,þÈVu²råÊ'žxÂ]£FÑà:t‘Q¬{«½ä¶×ÛE"Ûé%K—.õ’O{áFŽ 6oÞTéj¸²Þ‹ËžUÓo‡Ll*aÝ0™ ·M#)#eîqãÆUÜ|†ûî»ïË/¿|óÍ7{¼5ÄСC]«*Æ‘ d«Ú`DÓxdŸû‹ w‹Œ"`Ý[ tww×ÔÔØëíâ‘Õô’Aƒ±D—G I94È­½CCcc#u(%¦tذaÄÚŽ2µ EcÆŒ ¯™¿á¶i$e§ÌÂ=uêÔO?ýÔ™NÉÑ·adÅ•+W~õ«_q±ž={vß¾}|`dÛQY£ãÈÌ™3¹½+tVIþÿ(™€æ“øñì1VT¸e\dëÞÒ“ðDˆ1´Ôµ¹:Ðô’C‡]K ¢ì¢k×p<˜enO›vâÄ ’X¸+PÅáR¿mÛÆà Xúú¢!À%RcÓH¢@ùÿiò½÷ÞsßO“1[¶lárg É“cÇŽ¹¨—/¾øÂE‘¡Ê…4½ä…^8wîœ7"\¸pÁ¦‘D“2 7 Á»wïv>;þ‹u„Œ™œÎÎN-½F£nH»@¸©OM’>ð53äÒ¥K÷Ýwm¹ˆ¹¬]b‡Ÿ^Ò•ålù6àOŠÀ¡—_,ê¿ÀÈw>IÎ¥œ&å„Qåð–=¬å¢,Iøv$ I1>¡‘ÅŒ°¨X÷–ž¬„±>|¸K„2dH‚a<ØE½,\¸pìØ±.QL¸…¦—¾„§—8W-þÏ e!ü#[Â^”3¢bÝ[z²nŒùرc,•ļ‹‚^K¸1r’Hy‚pëÕ8õ© _g]Å*•Öƒ¶ÉSLÉ„8[L¸Ã”}z‰M#©Ê/Ü0zôè¶¶6gµ†éèÑ£\ͱœÀÝ/9O/I­—Ö%Ʀ‘D3¢bÝ[zèóŸ2cûöícÇŽ%¸÷Þ{¿ýö[,©$ܾ19zåÊ•ZÅ×d² ›õElV•ÛJØlV˜p'³mÛ¶Ç{ìÀWK ÀlIE á^¾|ùâÅ‹ÕF•Ý»w븳îЫ?½dÀÙŠ,6$šðÌ6ŠGMMëh£TÐíNH~õÕW1c‚3fHˆAÆL&('ÁŒ©€Ik‚pMW&Ÿ¤^ckû˜:|=sÔ ‹{zh©ÆR×r#ÀO/q.\|>øà›FR)DB¸¹hFýÝwß9?Š$ÜEü1×´ÿÉêÁO/ÙöG¶¢IxZ›°g¶‹ #d.Üx°D°Þ£GJˆ™FǧL™¢œ°CcØTЊT¸»â¾•à ÃZì"9ÎîTøé%¨‚œ¸HtwwÏ™3Ǧ‘T‘nÀäæÍ›LFŠ"[·nmjjÒørùòewÐU†Ÿ^Ò™âG¶¢bmÓH¢Œ ·3¸¤ogÀŠ+}ôQ—¸}Û ÷“O>I>Áž={Μ93hÐ Lzøðá®êíÛT`u—¸}›"jJÁ)b;ÚI*x;WR«ká8ØX˜p§§ØÓKlI%áæCáÃ?üí·ßJp£ÆØ±cõŠôܹsÕ|Y3ÎVÊô›FMNœ8áÿFîƒîÞ½Û% £2ÉP¸Ñ#p‰Û·1f%ñlÜב/ó q‚+©š¾ˆC8Ibê'ÄÙbÂ= š^²nݺ+…æý÷ß·i$•HT„¶oßþ /Hp#ÅúõëgΜ©Á¥j_o{*bz‰M#‰,7êšššúúz‚††ÎÔ¿þë¿Sä*Fe’¡pÇîLðÓKΞ=ëd9?Ðk›FR¹DH¸gðÞ½{çFƒsçÎ5êhðå$Äè¦;ÖêFÓK¢ÿ#[’ÈwÇmD€1cÆð´N€{ßFÅ•ì„4îÐR °®åFj4½dÿþýΚs ÿÙÖÞ"UÑn>N˜0áÌ™3nšR˜2eJkk«®oó¶0Œ¹š^ÙÙ{A>úè£À±ÿÉ/ùKî5Wl 3N5@K5ƺ–iÉz‰M#‰Ñn8|øðO<ÑÝÝ-ß-/óæÍ[ºt©†•ÎÎN{½€Ÿ^µÙö ²üÛ¿ý[`ÚŽçŸÞF%ÃÅì„4îÐR ³®åÆ@ä<½Ä¦‘Ä†È 7|øá‡\”ÎyËGxê6—øíXÿ–{>”}z‰M#©8/^˜vÿò/ÿâr £Âáz––Œ—^zÉE©Q­ÊÉZªÁÖµÜÈ ?½ärfè•–M#‰Qnxíµ×Þxã g¾åàoû[CCC{{»®ò7n¸#3ú£ŒÓKlI…‚g¾ý¿o—e׳|4™'Ÿ|òÞ€xÀe¥9F¶\"5ƒ rQíË%zë Ý™Øy†ÐR·®åFÆøé%ΩScÓHbFD…^~ùåææf÷7•ÒÂU^__ï_—âßԄ§—èCK ÿÈ–°•ÂŒ3xf#.m•—ô­þÀt}ôQÅŒW / r@±üX±òAIÖò12­ Œ´eWRu6>Œ„ L¸óœ;wîoû[:ÐÉu_ºººfÏžmÓHbFt…V­ZÅ'õB}ŸN†,Z´ˆ«œ¡'LzΑ~zI‰d ì@eÁIüå/ùÑG¹´aT>©„NÐYü&OžLIT˜€–7n<|ø0– ä`Æ41ùT 2IÙ3EÁöþ žMM-•£:=º¬B>ø]³Ô±ÈÂÙ8;"Hƒ wþ¤š^bÓHâJ¤…ûÎ;<¹"‘*§ÃÅc{úé§_ýu]åpáÂûGÉlÑô’RþÈØ €Šƒgüã?~üøq—6ŒÊ'•p'h1¿dß  Â$Q^y?–p÷T \W¬ÌdᦎÞmû]„…;y×,—/_.•×1ø i0á.œŽ„é%6$ÆDZ¸vU[[»zõjçÅÅáoû{yï½÷4ˆ—¾;#KŠ:½Ä¦‘Ä€íÛ·×××kÉÇ3—kNáÖ[dá­h©0„‹’s€€¤YJ¦‘l½WŽÖ%À¤}e&ïÕf]Ì›$E,¥Ýd‚¶Œ w¡ 35½äÔ©S6$ÞT€pWÞœ9s~ó›ßlÙ²EŸ Èþýûüñ†††½{÷jk×®¹}¹â§—éG¶À^T<]š››yÌsBù`vóæM’Ó¦M㣔«a Ê%̘1c¦OŸ®øÐ¡C§OŸ¾çž{”Ô fJUa×®]*JζCe†>e"ÓA‰ƒRê° cÌdªŽ6˜¼krT“%«øá‡Ay:Ò ·ÝÎÙ²mÛ¶¡C‡ö;¤­­M`).2*Ênà£ÞÑ£G›šš{ì±Ï>ûÌÉr~?~œ•µµµ\ëºÊ¡³³'p{5òÃO/)øl½¨8ÚÛÛëëëÿò—¿ Úa¸'L˜`ÓKŒJ'•p.+¯’Èn8)&@”•ƒõRAö¬@ֵ˷ß~›œá¦(¬Ë* 7A®½C0þü„ ¦"•p·¶¶Ú¯Ææ]zýúõŽŽŽð[$ {ðàÁþÏ€Ä ŒJ¤b„øÀ‡%üñÇÜÏÿïÿý¿… fþe–ax®¯ZµêñÇðÁ7nܨQC\ºtÉ&'tJÓK õ#[¦‘Tš@òõ×_K²8}ú´\ÜÕ6Œ $pÇŒdáFµ~øaò›››]–‘ t‹B ÜuuuC† QÒ w[[Û¬Y³0%Š ’„[ܾ}ûÂ… \…¯¿þzmmío~ó›Ù³gïØ±#½|#ÙŸ}ö«<úè£xöœ9sÂoµmÚëÒâ‘óô›F¦‘¤‚§x¼§—Œ7ŽgjUA“]㫚,=´T2­öª-öìÙ£Þ0²‚®sQT±Æ¹Y’”p·´´ à555QT4*€ÊnÁ#¼»»›»ýÀo½õVCCò­»¥~üñÇ'NœÈ”‰d×××/\¸0ü–T°›CRr˜^bÓHb@ªi$©ˆñô"U ÕÖdÚë„4îÐRäµk׆U[pË»î0²®sQ ÷Õ«W1l–î#F¯ 6ɤ‚¨Tá8Ü?ü€„uttHÈ¥Þ¼yóC=Ä2á5¶‡úzQÊܶŒâƒNùé%îO©±i$1@ÓHÚÚÚ8q™sêÔ©XN/áªÕMæÎíêêr]wh¯Ò¸CK|ðA–Ѥÿ´Âa»(„„›€eSS“ôZ¯·ƒòžX}*[¸=<¤±ç .tww#ÓK—.åÚe)Q“޳¤”:Ô¤¾[Ó(9š^’ùlM#©84dúôéœÐÀ¢³ãƯ¼òJ̦—0(9­h²na×q‡ö:!;´ôÀ/¾ø"AgÏžuÝQ>8 Uý³nÀ­%ܘ·2)1bDPhT1î0<éGŽɵ˅ÈÓš$ÏoWfDƒðôI¶'áG¶À¦‘T~‰ì9gb6½„AÉyhÕ@“u».ˆ;´—ÏŠý|Sß®S§N¹tò]¢+À%Š@ž;õg½ž={6IϾ}û\w”ÃE•C¿ÇÜÖÖ¶hÑ"Å<4½^×ÕÕCøKˆCáÞ°aCp×÷@ìrˆÁÃ8yz‰M#‰¹M#IEœ¦—0"IC«š¬ÙuAÜ¡½NHCp ßsÏ=Ó§O'X¶l™+èe̘1. Áà \¢ä¹Ó„3ÖîåË—+³Œp.ª*ñ˜¬ˆ›pû×Û‚˜WfD?½$áG¶À¦‘TÜkšFÂiý©p\¿~=ÓK‘ÜLjª&ëvv]wh¯Ò¨í¼yówuu 4ˆ¯eÐãf!ö N@ή]»¨v0@™ªÉRÕ¥dúuUgË–-JŠ„:™ï”šlÊv2ýžYi÷èÑ£]º|px.ª*ñ˜¬ˆ›p3LpÕ†!Ç•‘DÓKÂ?²6¤âhooŸ8qâ»ï¾ë4¹ÐlݺµÒ§—09̓… ^M‹'&Ç%>úè£p…òB“uG».ˆ;´× i¶çž{îÁnY6 Óõ NÜØØÈ‹"i1O)Ê®ü`2Ù«P_›¥š+¤Y™ªCN†;eJ nêK$Í™E»ËþÙ˜ÃsQåP‰ÇldE¬„;áõ¶°—ÜÑ'ü§g°i$ÇöíÛ±í¶¶6gÇÅáäÉ“ì¥r§—p‘KC3aÊ”)C† q‰d~ñÅ.ñóÏÄáj¨v89xð`>ǺD9ð÷µë‚¸C{¯'¼º(µýì³ÏXnÞ¼Y9ª€Ú’O@Ëi¾´¢bqàÀ¥K—’Ï­Þ ðm$Ãêðz*%¼'âg–ÃsQåP‰ÇldE¬„›é\²ÉïjQ…ÓÄ ÞÑ÷WmèS¤i$©à"©Üé%\äÎC3o>|øG}äÒ?ÿ|ìØ±ï¾û.,Ü Â=3@1ª=vìX6¢¤ðë‚6è}‹ œL(Êše-+8Ç»Do’e‚ sU£¿ä766* ¾«•©@eòI²Í1cÆ©R×WpNššp—…J/28@RîëK!¼Šwb½áV&„cZ[ rV;õî’Q‰ÇldE|„»»»;üÒ+áÚ­ô·Š=6ÖTšFòÕW_Ý.•8½„‹Üyè@àÁt/äXÞ”ôä ÜTÐç–¾(Œ_Ÿ¿ „7¾HªM}¯×rqÅ9@“£¬e‡ö:!í ‹Ú‚7o9.¯)2Œšƒ/U¿ VaÉíl¾ç·+ HùZ‘d&;¥Épµd"~f+ñR‰ÇldEÜþiÒc×neaç«‚ðÓH.^¼èü·\»vmîܹ¸B¥|œæ"w:ƒž@°råJ Û[/’,I†‹Â ÍzKí_iûU a-b ¾V!‡%9a§'ùV‚`½¡ÉQÖ²‚C{¹,scРAçÎ#àæe›œwñ3[‰”JP¢ã*G›ÀâÅ‹]±#L¸H0àù1bÄŽ;V­ZUWW§L£4hÉ;ï¼óc!ؽ{÷K/½¤xÁ‚+V¬Pœ?™^2+€™2dˆ2 ¹óЪ&GYË íý¡:ˆø™ð¯8Ú0öã!qńۈž/lç&`©Q¾­­ 1’…™á¤Q(4䨱cÎjóÆ ·æ3P¸áĉùO/‘gs9ñéN9‹-R ľ(s¸È‡V 49°2î,6lØÎ;]"^ p‰"ñ3;à%R<ÿüó°gƒýrHL1á6"A&ç Õö¯·[ZZHîÝ»—$1ã>’D’X•üÑ4’iÓ¦]¸pÁùl! wam[`yN/AµQjÿz›€ O—œ’Ĺ ·;Ī&GYË í•æÃÝwßmÂ'™å+G«$Ô'Ð*J„ˆŸÙL(‘Ïæ˜ùvYFì0á6"A†ç R€ô455Í g3ô×ÕÕ餑'šFrôèÑ[EàóÏ?dz ðl–“'O&'()0ß|óMÎÓKäÖ,¹êt¥ùY%ÄTÈÖ6¸È‡¦àÈ‘#|q‰ñ裲Y—Þ‘êË*49°2î,@¸eÌ«–+òÉ' ÈÔRI–Ä|¶dE„;¹þ]wÝ…p“$.?³>P¢CKK Ç|xÁ‚<ð†Ê/\¹M/ñ­X«K/´äóž¯!\äÎCûƒ~ CôÊ¿_EN€:O>ù¤K¤†­%KüŠ+ ä÷¢:@ œBA“+3áμYrÜ3A$oV€:“[#ÐH95I*Têû $âg6ÃJt`°9rdžÿðmDn#dx¾Â/°õ>vìØÁ¸¯wÅFöhÉÆe«±aË–-ÙN/áêòß ¨ÙÛ ÿP 8+¸ÈÝ%±|ùòä[·nÅ¿Y*Éy!Ög`üX öc8‰¾š¯Ffï÷¨:@ 6Hý Â_ìû£JOĵ¬àÐ^'¤y,ܸ59À5 ª°dÉ’T®®P@"~f3| D‡³gÏN:•óåÒF1á6"¯²SÔi$e'Ÿé%…‚‹ÜMp‚ÂNž<!F‚)B  „cÒ䨂rˆ ¨,EFšQdé8EÉ­:^¯U|>{áx¨Ìޤïì—˜€%ÛïYs "®e‡ö^Éù4Á _ýµràÏþó—_~I?›4iÕî¿ÿþ¹sç~ðÁÉõ©€p÷l÷ÊЍ£8O"~f+ë²gÏžqãÆmÛ¶­¾¾¾šÿïßOdþaM¸H`竌 FÅžF®æ:½¤Pp‘»CIBÊë8´‚Ç«T6 *JÎÌX ø±ê°ä̲Õ‘@ãè²|Õí®gýÞ­‘#Å'_EZj•ô× M޲–Úë„4¸JñiH¾•\²d‰b‚žzÕï·>AP«‡pœ?³…} „+Û‰dÂgשS§Ò¥wîܹyó¦†ârQå…³F'Ä5šp‘ÀÎW¹hooŸ0aÂÆë«Í›7çÿã8¹ÁEî"‰1cÆÌŸ?ß%ph§OŸ¾çž{víÚÅR9*JÎéŠÙ¦ê°üðÃ}9€Ck©êøÊ,ƒ ÜDü*Úõß~ûm­lo:ùAÝþ¡ÉQÖ²‚C{壱'âg¶€ýÛ´ñìÿ(°jT›»ÌyY/Û¶mcŒbdvõªΚë‚x¡›¥««Ë„Ûˆv¾ÊÂöíÛÙ9âü¨:À¶iué§—p‘»#HmEjqkŇ’ã’DÄñÚ°§nV‘ Ÿ?^¥,©ö -»Dã7H&« ì:6Kä€: Ÿ Ò 'Mdµ¬àÐ^'¤q'âg¶€„»®®Îÿ;¾nýòÚªœ¾!…Æ·{÷n'e}a( tÓ¦M®vuÀYsíþf1á6"¯s«w‰Ôªìð€Áçdœ™€8b.‘=Ãþð‡büévöìÙ­­­.Ñ.r·ûþЛcP»h`BÒ·—L(ö9€+Ÿ ’d-ÖU`Ìa]žPnÄçÖäK¸[ZZôEFMMM9üÿ4«×××ÿý÷?§æÆ¿ÿýï÷»ß1V»ÕâgÍ)j¼ð7‹ · ì|•’rM#Áçúu5½7•)føöÔ¿ŽT;…bL/Á¶¹˜~øádí&ßí¸jðO×q‡ö:!;?³ž‹òFÂÍ's}=¨„{Dð;ǪÕ$½éxå•WðigÖiÙ´iÓØ±c«dz gÍ5;^ø›Å„Ûˆv¾JÆ€ÓHÂ/Aõ–ÈôIJ•T:žË{èÐ!’É4É|½S÷{¡4¬Î”úU”ãk vDuüZá ä³’:ž„&Sðé%ÝÝÝ\Ì"A»Éq{­h²ž4® âíuBw"~f9<å„›€eSS“ô:á{ú ÈÙ³gëëëmœˆeÆ©S§XkÛ¶mn+ñ…³æÚ/üÍbÂmD;_% “i$c‚ÿÞÃV©~‹ì'ûR©} ø®:å+‡",Y+Nž<™|­¢É l“Ê~ƒß ™=ûèůâuY{¤HÛ×T9\$*°}ð;íÙt|z s¯ÝÄn—UMÖ“F={h¯Ò¸ñ3Ëá¹(o¼pn-áÖïP:"³Ÿ7Þ³gO]ðíþ?eÏ¥K—çÎïé%œ5§¨ñÂß,&ÜF$°óU&MšôÚk¯9Jnêõ·_á&“À)x²« àWñ²ëWïE+*~•CÁø± (ðÛWNr-©à7ësÒ³råÊ_ÿú×\‡EífévV5Ðd=iÜ%wjjj‚³î»ï¾(ŸYŽÐEyƒ"û_5Öo`)Æž‰!ü¥©X¾|ùSO=…7;ƒÎ‰wß}wB¬¿½„³æš/h—nn#Øù*ŒÔõõõNÝæÙ€¤¾ýöÛòWef(Üa»U…„û½èå´ÇWcÉöµeM )NUA™áœ4lÞ¼yüøñŸþùÅ‹þùg×_¹ÂÅœÀìٳϞ=KàöW5Ðd=i\×TjrÉð\\›#}â¢r£ïþ[¶l™“¯ü@î'NœøÉ'Ÿ¸­Ç Κkg¼ðw¨ · ì|•†[·nÍœ93ͬ’ÓÁÿâÁتŸ]­‰$5Q„R½¢&c&@š©F¦4Ç•F‡}×Çá½°½ÒOJ! Ä:T­â·^S”\Á¯K5Õ o-Í'yæ™g¾ùæ‰ÝÝÝ®³r"<‡¤Ú*"y#-äP]"8¬â™Ño}2Ù”Kô2/À%r…&«WÕUBGG‡Z]|'—ZêÚ1è••ãÇ×ÕÕñIÞ™W!¸téÒsÏ=÷ꫯÆoz gÍ5254ÿèÑ£.bøðá.  Îرc]¢2óü#Cnø;Ô„Ûˆv¾JÆíÛ·[ZZô“N‹B466 ™)ÉRB†¼ú Aõ¸2Eª£%A[KᆠÈ_¶lYÂ^X* ÄÉ«€”Ä•“PÁ¯ë}Ñï”8¯¿þzüøño½õ–FCÀÝüñG×S9¡o)°j 2ÝŽûƒ#ç8ù@'ûæ§GŸ%\"5lÍŸ‚S§N)ö°6å½pa˜8qâ»ï¾ël«˜\¼xñ¹çž{ã7ܾ ŠÿÞCÇѳæ–4÷É'Ÿyø"LW±*PÔÙÙIÌ*¸o¿”T çàÍ@2á ·V'“œžÚ!´¢TÛÖvRáŸ4® Œ"`ƒg2%ë“«W¯bœúî?>‚:ÃÊïpò¼PÌd›Çö$|¡ûË–-sGVPíU½¯·¹‹‡ Bcq&%÷îÝÛÒÒ¢ÊùÃYS£ú…æ?ù䓊åÓ4\L c¦½G@å°pSíwÞQ¬í° M’>§ë¼©÷ôfo‘J€6¨¶ ú™à‡An£<?~|çÎ.Ñ÷|QÄP—0JÅíÞé%‡vº”ýúVÍ¥õ°œa³ÃÒ¿XM ­­­\ÓHÂp‘»êZ¤¦Éž ”¾ÕêUžë>‰š'W èY-xq® *õ9è2IbêÏ›7¿SÅ  õ*Eǩϲg‹Ã†iû©ðO×F°‡]2%ëŒ÷BIù*»Ê<kÄ 19„ÏË¥Ç+cž•à?þÈà0iÒ¤BM/A¯¬ûϦ™´”)ÿVÍ‚ÀYsÍèú$ÜRQ¦—XzE& XµÏr\Ôûºš@몈>W¬:X»’Ô÷1E¬Þø€øaЄÛ(·nÝ9rdMMÍÔ©S—/_ÎùbÉýðÃ:´àÓÑŒLO/qÆ4Œï. ÆÉü’᱄¥¹DöèÅjgg§‰; ­­­eœF†‹üZ•áŸ4® Œ"`»dJÖ'ÍÍÍÿóþÏ3gΠËR1mžÉ“'“ÉRIJõ;_7n$I |’àóCKrü*lù#“íÃã’ö¬¬å7þÊ+¯`Æûöís‡˜ú){˜5kÖˆ#Xª`V ÷5;Ò´“‚ÀYsŠ/ü0hÂm” 6pš’Y¼x±«a”ƒ¬¦—èm¨^‘bÒšˆì…[ïbÃòÝ|c†rX…úT@£ÉWÿzUEáuÃh Dz¢0$ ×¶óЪ&«ç]E€Nv‘ÑK úÇŶ¸*åÇÝÝÝbA!&@”,X@@ò59>|ø0ù dØê|þùçXµ­E ±V’jT‚ðÆ'MšTé%^¸wìØ¡¹%¾£‡ ⢼á¬M~4á6Êɸqã8SaFŽÉêŠ2á§—:tÈ©S åYnÞ¼ùĉxðþýû{t{Ú4’dªH àd~úé§Ä¬Ë‹TS™,ÉohhPÀ¦‚Çúõë)ª­­uéDdI.owpUMVç».0Šì"£—b÷‰¾ûoãÆrbžYx0„…ÐhJõ6š¤Wj©3ÞÌ*J²ô¥Buzl:X×ç° ûíW¸ƒZ®Á›o¾ÙÔÔtõêUwÐ9~­—Ü@ÀMícWœ7œ55!føaЄÛ(';wîäL…Ù°aƒ+3ÊŠŸ^ÂqöÔòcÀ¹1c’ØsàÛ=–¬WÔª ’Ý’3Ibլ˒¨H‰µ»D 6mÚ‘i$a¸¼ÝñU 4YýïºÀ(t²‹Œ^ŠÚ'{‚ïþ;zô(.%'–WmݺÙÕKk@‹‘c*Lž<9• Ý*%Öq¡Ê=6ÝW¸Ù›Eâ5“ÄWHÞ8|öÙg<ò#¹;ôhÃYÓaÇ ? špefêÔ©œ,1nÜ8—kD?½¤³³Ó9T_äÇh±ÞUëíun÷z¶^i+†Ì…›Éå{ØÑþýû]" Ä:RÓHÂp…s$UMÖYp]`:ÙEF/Åëü¸©©‰QåfÀ®]»¦OŸN@>™cÆŒ!GEóçÏGŽOŸ>«ƒ›ŠßTúdR‡øí·ß&ÿÃ?¤ˆ|Ö%“µ.h-¶F™l?\!yãâìÙ³&LX½zµk@¹ioowQœ5wÐñƒ&ÜF™9~ü8'K„¿·Äˆ駗ȇ †oÞ¼™$Š,á>wšðPeÐ<i´Ö~Ee²µÚÚÚÝþôS6¢:¹OÈñDpI®pç¡…†þwQöði \¢ÐÐd×F “]dôRŒ>Ñwÿ½ùæ›N£aPdôñE»•/”‰þªŽÌXùRvŠ• TëÑçÐvÈѺ µnÔœI‚¯¼ñ0¯½öÚ³Ï>›çô’‚ÐØØ8zôè~¿2œ³æ·šF»h‘>“ ž2. ¡ÎT¬6,ß^rÃ&ÜFù™={6狱̥ˆ‘fz ŠÌ«&hnn^¿~½<[NÜãÝÓ¦%ø±Ÿ–­¥`E’,ýt‚ž•§M O‡To¸£9$ ¹óЂÂ'$€í¦g”™9¹­•!þIãºÀ(ö°K¦à}rüøñºº:>ÿ;‡*“'ONpôA%ÜcÆŒ!p¹ðÑGÑ„²O/immåìæM¯ºÜ2ݱÐ3|A‚ h¬ËM ~|èÐ!—HM¿Â;@±ÿ ÄÒ„{`h¡‹ŒÈÓÝÝ=tèЄ{ψš^ò / ÔΧ¢Á… ";$ ƒ’¸°ÔÖÖbÌ<Æîºë.ä›`ݺu(8&M@ÝB5bP@kST¼×ÛàŸ4® Œ"`»d Û'ú_{{»¨Â‘­mÃéÓ§ç/Î31Ëh¤I“Ö¯_ïV®^½ÊÙñÌž=PIw hq«z>` Ô WÑ|\QŽÞî“É*dOßR¤Ï$dúj,ÜTVõj²p‡wÍ) rÏjÁ¤ >'Ú¥aЄÛ(?úS]þÚe¤ÇO/9xð SªróÕW_EyI%.ò"ÑÑÑq÷Ýw/Y²„‡&þä“O”I@…`æÈ‹ûöí»ÿþûI’© ¨ø'ë£ØÃ.™BõÉ­à»ÿþð‡?\¹rÅÙS…CC,XPÞé%C‡åyHâ».ÜQ&M¶T˜†w|×Û°4ëe ‘£·&f#ÄX2™T£²œ;Y¸©Ãö¥Ý$„;y×Ú‚ŸLŸß/´Kà ·Qf¸Í[[[Y–q02ÄO/Y¿~½sÞòýi$a”¸Â‹G‚[÷› x¶‚»îºKuЇÒ¸.0Š€=ì’©©©¡[ò‡í¼öÚkΛbÄÚµkýë_»FFƒ‘#G²tÇןpãÊÒeÀ°Ue¸(9¼^'è²êèe¹ò¥ì~ïÚ j’íš%+bç0þ|L]SçU“@•íÒ0hÂm”É~"ËÇüòåË*2¢LÙ§—TÊ4’0 JÒÐ"‘¡p744ÜqªS<ü“ÆuQìaW<ÚÛÛëëë7nÜèÔ)üõ¯Õ{ FѲ¼žxøá‡¹hàGŽ!p‡ðZ.«øàeÃá¢äðÛÑ‹jŸCMàÁ.“Ó3_ä0iòS ·v-Û&Fâƒõþ9TÓC»4 špeƒç1·Ù×_}§âÿøÿ0ç®Ê8½¤‚¦‘„aP’†‰ûï¿ßO)e¢×°iÓ&½ØF²¥à°nÝ:Õ)þIãºÀ(ö°+*·nÝÒW£2ÈÜȆaÆI¿\V~à‚. ²}ذaƒËJ M˜5kmñï)üüéRÂëA¾ý·“‘t€èuò–-[xÐHi)”$ÐË–-ëêêò9Êœ7o5Ù¥ä$ô$Ûa㊩ †w‘¼k`#lYu|f¿Ð.õ¶ ·Qx'ض0ç® 8_~z‰«|ðÁ4$ ƒÒ•bòå—_¾ð ôp¹W® ”*“¥rÂuŠ„Ò¸.0Š€=승Àpç*0 ÒÛXæô+ܧNb‰bö[fß¾}Œœk×®Õ- eyOÑÞÞÎ 555ø«Ë Ók/è¯ÔYÍļÃI4š†+0cJ•r5É—m±‘ÔfYú˜€­Q ´ki´”Ù/´KnÂm”´©_󾆥…Ÿ^ÒÑÑ!'.ÝÝÝsæÌ©¬i$a”œ‡V þIãºÀ(ö°+<˜ôráí·ßv•ÖÕóª¹÷es²póÔ£TzçÕ-°µžúÈ¢Œ“óÕ€R’¬›^©ÓkýÊ•+ëëë÷îÝ«û·ËòžbñâÅC‡eÉî²záJv‡/ü0hÂm”n³4¶-̹+ ½zì±Ç8¸qá9vìX%N# àä<´jðO×F°‡]Éð¿¼ÛÕÕu= ̘åÉ“'1c ø³’HóÒ¥K xüM›6 «f©jcÆŒ!`¹yófò©@RQ©ÐÙÙIR›M†ý²Š6’Ì÷ß?eÊ”æææöövÝŒŒœ×®]sM*9<)Ξ=ë}áJvŠ/ü0hÂm”Ìi@󾆥§¬xÓK>¨Øi$a”œ‡V þIãºÀ(ö°+%~zÉáÇ҆ÐÏuõ+Ü^—1rr´$‰ˆ+ðK9KŠ gµÐ ‚T>™;wÖÖÖ¶¶¶ê6„îînšà1¸’ÝqÇ ? šp¥sÊж…9wÅá§—œ={Ö9W~œ?¾¢§‘„aPâb®*ü“ÆuQìaWbx6ùé%N©på 6`Øé…[/­ TÞ¼ycÆŒÁ˜ÑkekE’™7[`›.âOúSCCÃÑ£Gu#*ïš=¸’Ý¡Ç ? šp%Ûææokkû9¨oÎ]Yøé%û÷ï—4ç ŠJŸF†AIZ=ø'ë£ØÃ®,$O/AˆOž<‰.÷+Üø4fLRzMNcc#E¸òæÍ›YE™,© É—£Ý©„›íPÓ%N:5a„×_]wp7oÞt‡U¸’]â…M¸R›m sîŠÃ¿Z·nsçìyÿý÷c0$ ƒ’4´zðO×F°‡]¹ðÓK:tíÚ5¬-Ƙdssó¹’ÊQ%Oœ8AR±€ $ $ׯ_OÌÒ¯˜›Ý¿¿K\»¶iÓ¦ÚÚÚ?þX·twwWÄÈÉ•ìÚ‚„ž CçƒK„ ²‹ò€K,éd:V甤Ž$(? špE'󾆥HÎÓKâ4$ ƒ’4´zðO×F°‡]ñ/6lØàôª|\¼x‘!7¥dö¢°wöËRfÏñô»Çdü0hÂm—üm[˜sW"9L/‰Ù4’0…ú¹é â¾ûîÓIt]`úÙEF™ðÓK:;;d•œC‡á‚á¯Ùîêêºuë–;ÄJ€+Ù5& ž È®K/õñ œ›¥X@K©¹^?(i&VÒÃfÉ¡¾þ Á•Ô;lAÕÈ!_°5jføzh—Έ ·QD eÛœ» O/ ^z¦#~ÓH’q +!~¸/#®ñF°‡]H˜^RbÖ¬YÃÈþší ý'מ$‚éÿÜO?ýÿf9hÐ ô!V”ƒX«þ]wÝåK «ˆÖÖVЍFÑ›o¾‰s“ãÊ „ ·Q\¼mÿTh̹+”ðôI¶GO©XN#‰6Æ;¿‘Âÿï *ì„«hìÝ»wÔ¨Qá¯Ùfäd¤u‡Ri¤nÚˆ »D ÐF¿ÂÝ3ç#˜R¢üôÂÍFPse²$‡-°.™ªPL¸"R<ÛæÜJ¿ÓKªaIy±Á0ÞØù~zÉÁƒsÅ‹3r†¿f›á”1ÖD’F¸'FšõÆŒ“…{ÿþýª¦˜üôš³5l^o¸y0±Yÿv<¤ø.‘n£XÛ¶…9wåâ§—œ:uªJ¦‘” ãßž^Â3±°œ9sæ±Ç[¸p¡†MèììŒþ×lW²ka ^yå©óñãÇIvtt£¢M½Œ=ú“Äš|*ûR‚ð*Àv¨@ªMK%]qfhi0á6Š×V l[˜sW.z4tèP›FRl0Œ7v~#‹Ÿ^‚ÌɽògëÖ­£F Í6#g<þ$8 p®,áFï¿ÿ~—[nL¸ÂÃ…U2󾆥Ë;wü06¤xØ`oìüFÿ¿+~åLww÷œ9sšššüŸáÊ•+nO•W²kjlÚ´éÅ_\²d‰KGÿ¤3á6 WU‰m[˜sW.ܤׯ_ïèè°i$EÅÃxcç7âdzɱcÇjkkÃìì쬬¯Ù®d×ÚxA»tÊL¸À%…mõÕW|š/=ìל»±›´4X?Ç;¿Ÿ^’í/ïºuë°íð×l_¸p!~äJv Ž´KgÍ„ÛÈ—òÚ¶0ç®Dì&- ÖÏñÆÎo¥À£Ê5ªs±ÀÎqtL=ü5Ûqý“ W²kv¼ ]:w&ÜF^DÁ¶…9wDØ»w¯‹þû¿ÛÚÚ\Ôv“–ëçxcç·‚5ªÓ±Ôüýﯭ­Ý¸q£t °mvn[±ƒ+Ùµ<^Ð.>n#w¢cÛœ; <¸©©Iñ!CÂþ€Ý¤¥Áú9ÞØù­8üå]X¶l^~àÀ¹YÑ_³= \Éj{Ì ]:ƒ&ÜFŽlÚ´©¾¾^¶½-@Ö; >úè™3gϘ1ÃÇÁœ»ì ÙÀà¢XÂMrQ@PÅa7ii°~Ž7v~+žV©~y÷ôéÓ?þxsss i=tuu]¿~Ý­_¸’]Ä Ú¥óhÂmäÂÕ«Wï¹çž7JsñfPœžwÞyáV|ôèÑ{ï½÷É'ŸT²P˜s——#F¬ZµŠ%±„›†€§ ùªv“–ëçxcç·B O/‘™ÁŽ;FµmÛ6)œ?þ§Ÿ~rëÄ®d× ñ‚véTšpY£™$»wïþ1à¥ìù`©ü+VT‘X óÆ¿qn%ê“IÌHDLIÖ oŠ€äÖ­[‰“÷rìØ1sîr!ÕfÉ“C½hÑ¢Y³fùR?ÉÄnÒÒ`ýoìüV4~zÉéÓ§›››y¶Æõk¶„+Y†3h—Φ ·‘²mŒÁE¬Y‚|÷Â… 2`òñcDY2ÝÞÞhp"*E©µA $Ü”"ô¬K)[“İ#Ÿd©öbÎ].$ÜØ6„ÛöÂ]WWgÂ]b¬ŸãßJçv0½døðáK—.•™Aü¾f{@jjj¸˜ãÇ}÷ݧsjÂmd·mŒñÅqby“‰þzÿ&™ðk!ÍiQÿIDATâ9 jh’ Á Aƒ‚’ØføÍ7±vÁ’mJ²eçà÷‚Isî² áÜú¿øz-ù&‡ëǦ””ëçxcç7ܹs‡G•´ º»»«ö—w]î•n#S¶ x-Zìc:‡ýÐâ°:{¨I>® RíôÂíåÞeõÎ*Qì÷’PÇœ»ôàÙ _ðl–ijfÍ"†––•‚ݤ¥Áú9ÞØù öË»@vZ\J/Ü´Ë„ÛȈÛ|׫mn÷ÎôhooǃIj† É~…;¬×È7ÆÌZlm².™¬…Á³–”Jå8räKVI¿0çŽ,v“–ëçxcç×0²¥,w ·10ɶ h®fn(ͱ–“ìÑð—^R†©éÁDÍÛV}’ÊT2¨Òó[IÜÚiÞ¶âä½x̹£‰Ý¤¥Áú9ÞØù5Œl1á.$6 l{Ò¤IG½UÉpüæÜQàĉŠÃ7éÁƒùœæFA±Á0ÞØù5Œl1á.$6„xض0çŽ7÷fMMM}}=ACCÃøñãÿõ_ÿ•˜"WÉ((6Æ;¿†‘-e¹kL¸ãI[[›‹þû¿ý·°eKœl[˜sG1cÆp{&€»b£Ðн.2âˆ_ÃÈ–²Ü5&Ü1Ãâö óË_þ’ëÍ…†v‘GìüF¶”å®1áŽ!w]]ÿÂc/Ümmm³fÍZµj•’i(ªmw¸D90ç.;ÿöoÿÆêyþùç]QèaqÄίadKYîî‚p#Ö8·~ÞOÂÝÒÒ¢Ÿýkjjòß”Ü/aÛ~4ø­u–‡–­¦§½½ÝE©Ñ—ЏDÀ‚àgÛ!!¿P$¼9wyY¼x1w¨ø—ù—k:ÙEF±ókÙR–»Æ„;†H¸ñf ›¥„{Ĉä«BšI&aÛ¾÷Þ{Qa‚­[·nܸ10Õt|þùç¬â©In’¬K€Ù'ŽJÛcÎ]^ðlnR£ÔÔÔ¸N7â§ØE†adFYîî"á&`ÙÔÔ$½Öëí ¼'V€lûÈ‘#7oÞüðÃxàÏ®]»ôNŸ>MÎ=÷Ü3yòd-I’?hÐ –ŠÉ$yèСåË—“¤Ú˜1c(š@à!ÉÆ ¨©:ZHRÊêÚÑüùóÉ!f Ôa 1‡§˜Õà¾6†–šs—‹3fp“rŽ\Ú0Œœ0á6Œl1á.$&ÜŠqk 7æ­LJGŒö!lÛ¬Å8k‚#²Ê¡ë•÷T rüê>“µX7yË$1i@¿¼Ê«ˆ€–Ú[кì:(ï©@ëʧß~ûmÕ!GÀ¯žŒ9w¹àzã&ýè£\Ú0Œœ0á6Œl1á.$Õ<µµµ-Z´HqKK‹×뺺:bi H°mHpVðŽ ˜1Ëë‚pA8f³Aïy¼Ÿ&‰.Sªš¬Â–UJ@¿#­K°k–@}–ú0@Làõ]CŽò{ÖìÅœ»,´··:ôøñã.mFNÔÔÔð¼3*›eWJÊ2Ñ΄ÛèǶ!¬¹pþüyŸD^ÑV‚ë‚pÛñ™¸òüùó½4{Hª2ŠO…ð*b@áæx>üðCåxü¬0©0ç.1Û·o¯¯¯×Ò¥aFÕbÒ{L¸«~m[è}0‚K€cÃ$ñWÙm‚õž>}š qØq‰YW+’$PIUÖìö«Uô6Z»fé·¯ djGAÏvƒ—å ³—pkÝd#cÎ]nݺÕÜÜüÒK/]¹råÎ;ô<ÉiÓ¦qº†aÕAGG‡‹’¤%\dÄîª&m‹CÁÌl–á¤æi€Wê„ áA¦¯|>@±'}5­ÞÛ”R‡süºÔ Ö賺b NØi2æÜŦ½½½¾¾þ/ù ªfÛ¶m&L°é%†aT<‚ÿýßÿý­·ÞB¯%-$ÇŒcï ⇠wõ2 mG°psîâ¡ $_ýµ³ì¾ðyI.îj†aT ¿&ÆïŠaÂ]¥T¢mCÏ»ñ^Tç‰9wÁI˜F’ :ߦ—†QU„ÌsâÄ WlÄˆØ ·ýãvzèŸ/¾øBŠi$@ÏàÜ?ÿü³»˜Œ_º|*@E@® $»ººnâaÆ)S¤ÚÂÁƒ]âÆ âpØ pJ†ëk;”*™ŒÙv¡ÈmI*8qrw·õJ†§©SÑê€öênrí7 #ú×I{½oL¸tΡ"¾Ø°„uË–-þ·fpY•/[¶ u&‡€LÕܰa+Ccc#9Á†{ì\I 7æ­|‘f ,•T,S×Áhƒ\ŸLj²Lpta¶]ü4’K—.ýT8®_¿é%&܆a¤âÿïÿm¯·ã ·ÑC*ç–pãИ+IäçF[É'– “#ëU>«¨>I2‘u–$üyóæù ú7Ü ¤ÙAXšµº?–ýÖgÉN•“€ÙvAhooŸ8qâ»ï¾ë4¹ÐlݺµÒ§—  î½}u`ÂmÂø9eÊ”#Gޏ´GL¸ G¿Î-á&@X‘cY,Ky0 ÚàëxáVŽªiIb•‚rR ·*ø-PMûŽ{V¬Õý®SÕ÷0Û.Û·oǶÛÚÚœ‡“'O²—Ê^bÂmF2š†·mÛ¶ÆÆÆ5kÖ¸\#v˜pÿ$Ù¹‘T‰ï˜`v‡^K^ýKe—Ú]NxÃÍF€ÕI¦yÃj ¯¥€­éØ’ßp ’:¶0fÛùS¤i$©¨èé%&܆a„ÑøéìæÍ›‹/njjâaäjTñø¥‚4¿?`Âmô!Á¹‘T‰ïÁƒ½ã6Œ|I­^!Kv©Iq,÷ê2¥x¶¯Ü³‰À€•$PN˜·ÀÉf©Õ5iÄgö[?A¸Í¶ó§ØÓHRQ¡ÓK‹]ªÚ«›Ëµß0Œ©~l÷îÝHÛž={\½ªÃE•LšV˜p‰È¹»ºº®ÇZg¶'šFòÕW_Ý.•8½Ä„Û0 ¡i$_ýµ³ì¾œ?~êÔ©o¼ñÆ­[·Ü U#†k%£qÇp­ aÂmôC¼Ûl;Oü4’‹/:ÿ-×®]›;wnM/1á6 ßþ(ØêÕ«y···»5ãNœ„»ßqÏ„Û蟸:·Ùvžøi$N{Ë͇~X)ÓKL¸ £ÊñÓHœSÄ¡C‡¨¿mÛ6·~¬1á6ª—ø9·Ùvž„§‘ìÙ³GÊ›9>úèÑ£G]"^ p‰$*ez ±;â ¸xñb¿}•ЇÄä¸DÀŒ3Μ9£8‡sT@L¸ #Œ¦‘dû£`—/_ž>}úï~÷»ØO/aÄpm®dL¸‰“s›mçCÂ4”nРAi$¸_î½÷Þ܉—èN/áq袾qþd%Üh4=ì!ú˜—ü{øðáŠs;GÄ„Û0„?sþ6§>ø`ìØ±ýCbÂmT;ÅvîÍ›7ãIpòäI—U̶óAÓHÞyç:M¼€ê)IÑ… ,X°uëV’,9¢¢+V(êSä«[&éë( Ê¡ˆä“O>Éî|_Ÿý’£"(Èô’Y\'C† QfAÈJ¸é+œ›–ºt𚟤îmÛ¶ñ!„ wø“‰âp©Vñ/ȵAÅdRD%USoÊY†‹2Ç„Û0€1JÓðœ;çŠþ”·~ýz·ÝØaÂm=ÎýÄOtvv^+ 'Nœ`yÏ=÷¸¬BÑ›m猦‘p HjÇòX“$–ü!Ó€,’Ï“F5EB5•H©©À’¤´RIIç Aƒ°êäúÚ Eè~Ï~ü‘k)ÿé%òl´{ÕªUÊ!X´h‘b öE™“¹pÓd~]MKñcÄ÷¿ø­>ÔT'å³¶*³®¦ K¸"ª©ˆ˜’H6¶­µÈïÙh6˜p†ÆÏBý(Øõë×.\øÔSOUâ #†kg—.]bs‰ \.  Îرc]¢2Kó3„ÛÈ—¢:·(’p›mçŒþ :mÚ4¯³ÉFs 03/¾»wï&À}A9,1c  Õ(BìÈ”Zu°jŸô™©ê³Aü[u±dËŠPŸ:Të·¾ß`¿|óÍ79O/‘[°dLæu÷¼öV)1úRÓ¡pcØ2]ðfL‡ ¹´š$™òcò©¬ ¨¾b#V¡2Ii7k©Â‘#GØ”Š€Lå³dEeB¿{I ·Qhü,Á‚!ÇìˆÑØí8°mý¥îY–á¹s$÷$åE‚Ã5¬/+úN±Ó<·wÞy‡Ç9ÄÊa ÁJêlÛ¶ W’~]Lš ²YU P‘*û¤ŸM§µ8’`«é0á6 F1œ{Ú´iŸ~ú©K³íÜÀS5Ä+u˜´·^ظq#ºFù$ñ6P#ÔòåË‹äj¬‹ÕOR HrúTÊvú­ï7˜Š«W¯æ6½Ä ·b­®1T˦¦&_!C2n¥ù$‚Æâ¾ ô¾á*U’n¡¾jz¨Îä9ÁZZ…g ±ß ¶F}%Qsê+&@ñk YaÂmTŒ9áos*|ä‘GvîÜéŽ Pmÿz›Û–q½Æ¹ë”dÄkiiQåbJ¸ý?¢ðLa‰£ËAÉm ·þ…€¥êx””=„×­.(bd @¾÷o•{ÛVT§Ø„Û($wnýߤK³íÜÀ®&NœˆCËVó„ÊEåfË–-ÙN/á©ã¿P³·A"г‚ØPu`ÂmT?ù˜ªœ%ƒäÏ>ûì+¯¼ÂMç%'ÐëÁƒë†Å³â0lP¦ü[5‹D*áFQj 1'7Ï ˜€¥ÄZ Ëáu±öðº ÕùTS¹5΂“é+°q2UÇ»x&ÜF‘sŸ;wî‡BP[[»nÝ:—ÈŽÊl;ÒO#ɖÇOž<Ù%"@>ÓK … ·aÄŸ<%ÁùþWæ úcÇŽEúÝån­`Ö¬Y#FŒè™H×ûeMÜÈ(8™ªP 1\cB,Hšb·5ø’3ô'8*S¡§jÕüçmGóIÒQ|P¡²¦Ø‘ï‹Tª´Aå°ÕOƒ ·Qx ëÜ…Âl;p£ôÓHâAÎÓK … ·aÄ.õ~¿Í)Œ0˜œõOL…·Àl9qâNœÏk/Ü;vìðÄ ßÂC úÓ ô+ÜHpò;Ä—€¥Wä k§Ø‘ã¢Þþ&к*¢Ÿ¯þ ߟ#êû˜"Vo<&ÜFQˆšs›mçÃÊ„ 6nÜx³:ؼysþ?Ž“&܆3?3™FâÕú¸4ä,ÜÀspîܹÏ=÷\n¯Â/°õ’¸‹}슋@¿Â]q˜pÅ":Îm¶Û·oÇ>9âl´:À¶iué§—0»#¨L¸x“ù4¼AÁ×.yüÛSÜš˜œÉ“'“C’€¤*¨þòåË•Lø7ôTìØ±ã‘Ga`wZ!˜pÆDÁ¹Í¶³…AY=þ¼ó£âÃÃEÙ3?À%òæÊ•+øÃŠ1½äìÙ³ô­Kô%•pï p‰1f̘C‡¹DIí\V‘1á6âŠ?3™†Çƒ ‡v‰¾¼ ÙÃ.+øwóÁ—2¡Ý üêôéèèàÃÀêÕ«ÝWŒîè+n£¸”׹Ͷ³…!»,ÓH ä¢$ÄÓ§O»DLp‰QŒé% ¸?üðòå˹]V/ý ÷=÷ÜCÛy²¸¬´ð©ãí·ßv‰Ô°µ±&G}.«È˜p±„ñ—ÍüÛœúnLúà—­äÜà «fåS-xÁÝS?ý¡&ðÚk¯Mš4)y,Š&&܆‘rn>U_--ìÑl;+òœFr(¡—uóæ‡~ˆÆyc¦I2•$_I/ܬ~]}þüytL½n×êáí9Ê ¯˜°ß(Æôž‘Œ¹C‡={6Ïf—ÛŸp£Úɯíic¸Qè5ÍôÕPs ‹T$ˆ:-Y¸yZ»(À×TÀ.:SI–Jú“¨dBå~1á6âGnã'CŸ¿Y帹‹‰¹‰€$K•‚¿yUÊ­MŽŠrà‹/¾xä‘GöìÙãaL¸ #SJïÜfÛYÁXÿ4’cd‘˜) O”އ þG@’ ÄäPŸ€¤„[–‰±ùà ¦ˆPSÏ’ÔTðûõù={ íWÕr àÓK8HÆ\ÏÔ©Sõ´#v»ìÅñÐFu¢uÔ¡ídÒLzŒ%T=@œÜiJj›‚µÈu;IöºlœLêpä”j;äSLD’ìH¥ Ò4=O{ucª[ £¢ÉgüÔÅ-¦;‹¤î,eêþ" HzÍÍÅZä•YQ‚íeÜÔÔ´páBšàS>ø¬’ê0’GHi™ ‡º‘þÑ+Œ0É9’fÜ3á6 I)Ûl;[&MšôÚk¯¹Q!Wü3€qÚG z$èABR)]°ªóËY Þî„ñÏVWa vÛg; ûUQά\¹ò׿þ5ce‘=z4K·³^ „𫬰 +G•ƒnèÓÿÜiêO$,UDŽÖųIò £¦¶@¿)­èL‡$!Њ@i°U×óÔ!N~>Ñ^Ý›îú3ŒŠ%ÿixrGPRw ô]¥º‰ü­D‘J!X5/õ\»v-MÿÍ­,´´´Œ9’§Ã€“îüÆ7ÆC—›jº(5t£î»`Lóã°?fKšqÏ„Û(0¥qn³í`¨¥ÓòœºÝ£lI­L™ÉÀ!LA°ê?ýR#©^— ’l0(VÉÛIدŠrcóæÍãÇçrºxñâÏ?ÿìú+W6lØÀ˜¦±±ñÈ‘#n½Ð„°§†Ÿtí ç¨Õj/A¸(¹Ó”îÿäGu”™¼)¦tBŒ3Fõz^Ÿ ’Ÿˆ´W·§ëèLbómN4¡®®nÓ¦M®a倇u0(0éÎé;ÈdyêÔ)2ÃEÐiª "á+Ѻښ6*Ò)ð}®þ¨”„4=ŸæÁcAA¦áEµk×u]$Lºc¨—Η k _* çè•rìMZ¯¼[h-eêI•úM¥~à_–C‡1Z‘jÜ3á6Š…œûìÙ³|¤.lÍl;îܹƒmãš|ŽwrT}øi$º–  óI¸&‡ºxñb>º¬^ˆÝ¾#Ï !.Q8Òª­­-Ô ºxøá‡Â$OºÃ}Þ"3F1Rù˜ezáVŽ7e²M/ÜXrѯÀ•‰C“O¼œÊÚÉ1Á×Ô9*¿—`ÿüî&A+R{&ÜF)¬s›m–K—.Íœ9óÅ_dÄqŠT\¾|9a =ðÃ?¸~ÉãÇs¡ºD_ˆÝDŒ„—å…"̓Ç0*…[·n1V0bð rJUÞæÔ1òHïú%}©” MX°`ASSSgÐå#ƒ'aÒ;ðZýôÔ©S6l@Êé1’4vXðç>*ôÔ»qCzÝoéÿôÊɧTE‚ͪ2›õ[Pà·£€Ã`#óæÍã`‚Zý@+Ô·jTn£¸ʹͶ‹AžÓK*‘"M#É„„ÇIìIóà1Œ ‚qò?ÿó?'MšÄÅì.îüÀ %p ùCõæ€/õà‹ Õ0¿eË–ižžËJÁéÓ§iÂÒ¥KuWZúÇh{{;# 8é.(ñЦµµ•gºKôÅ„Û0 CnÎm¶]2üô’Ç;cŠº'¿›àÑŒsSO›6‘JEht¸ˆÛ’>`IÌ* j$})èîóÂP9Õxøý÷ß3¤¿þúëºÃNõCe'`IÌ˜æ· óV)°q–Ü›ùW‚:Tv‰`ɤI“.\¨»Ð÷ÈN# !`´Ñ¸”9ê—È ¡.‘=&ÜF´HïÜä›m—?½„G…H’à AáIC´ x00rÈíTSEè2™<$¨¯a” hXjk¾²ß ‡ X»KôǦM›"2$LøqB衎Jèê °$Õª uSÕ÷îØÂÛQýôûAõþë‡7˜€ ·{ôO<ñÄwß}—âêfÌ–Ý»w3ºnÛ¶M·D|I˜4ÂÍ “jœIExìÊŠ4cZ&˜p‘#•s“c¶üô’ÎÎN7œ„àÃØ$”ÃC‚LÙ0c–òY‡‡?ÿ\Ñ䇿æf* ‰= òÕ“c¬â¢$ëHM# Ã@Ì‘zÀE?üp÷Ýwïܹ“å›o¾Id®[·Žfãµô?ÒÔ‡»îºKÐ|u¬K÷¢«~úýŠ zÿõYú &`ÂmTþÿÇÿønÊ}T ³bÅŠ<==ªû®\¹â޲H%Üt‹>Þû?£ñt I&E$×ÓÞž Ô¡™>ŸÕ‰ýv´ø¿úÍJ¸ꓯUÒ¿î1á6¢H²s›mG4ÓKŒP: ›7o>wî\#O›FÌD)cPªjŒYJ2fP€‘‹"Öbܤ¥À|eŠ’…[ÛO&‚ÓH¤n,–Kí‘8 iÆ=n£œ„›¥Ùv4I3½„A 'fILà3¤0f4Ú—&Mô†á—ªrB)K½ÃC¾‹BDsI˜ðã„g†‹‚žî" “‡0Ê+ŸX^K’ç I2Iö[Ÿ€%ð !¦¦’aXÑçûúé÷«­±ôÇ®Þ GÞéÿ2á6ª ÿº=KÆÞ½{GÅÝªÛ *hIF פ¾ÈwéUŒ?aáf ÒÛð/@9ÔaE–”*“€$EÊ´–ꤩï+¤'͸gÂm”9÷×_m¶q4½ä…^Èðq’áð”?.\ˆì4’0©'q%̓Ç0b š‹øN˜0áàÁƒî6(2kÖ¬?~|åN# Óï‰ã»(5н|øGµ%ÙT`‰ó¬½2*÷n-aÿþýä“dS$S wr}b‚ô˜p‘çþ?ÿçÿ˜mG?½$“ÇIsï‹Û¢òÕW_EyIâ«Õ„ ·Qè7mÚä©âÀèúÌ3ÏÌ™3GwtvvÞ¼yÓDÒï‰æîÛ·Oñ’%KFýÊ+¯°”O“yüøqê|€@«&ø äS€%H²’x6ëÔf)eÙo}í…î¿ÿ~ÖUœ€ ·uü5j¶qüô’õë×»¿|DInè.÷~cà… ÜhUPöîÝ[[[ûÞ{ïéƒóçÏWâ4’0ýŽ’fZLKÜF|ÉäAØõ‹ªÄJvttPŸEV5 4¥Š•mÜvB}JÙTP±Oœ€ ·u¸Fñl>²›mWÙN/)8•2$Œ ·aTþÏœ9ãn‰±zõêúúúèþüÞíµ’Ép„D²%Ü,\nd0á6¢ר‹Œ !«é%…¥‚¦‘„1á6ŒªÂcà®]»Ü]‘/¼ðœ9sÚÛÛusuuuݸqÃí¯Âaĸ’K–,¡>øà—Ž&ÜFÔ1á®DÂÓKÜ¡ø0ÈVÐ4’0™?Nâ ·aÀ¹à—/_\9pàC߯u[Aww÷O?ýävSùÄc„4á6¢Î€Â½wï^õ²ã§—¤šÓV(xºÌ™3§²¦‘„1á6ŒêDßøôÓOŸ={ÖÝY²nÝ:l›gŸî)¸|ùò;wÜb ·a”‚…{Ĉ;vì XµjU]]2ˆ é%=öØœšcÇŽUâ4’0&܆Qµè$÷ïßïîÌ` {á…fΜ駑sýúu·ÝaÂm¥`@áÆ¶qn–º”ÛÚÚfÍš% 2ÃI£ÄuzIåN# cÂmU޾1ðý÷ßw7É@P¿¶¶6<Û¾}û¶Û\¼`ĸ\ù˜pQg@áTÛ¿Þnii!¹wï^’Ä\ÜC† !I¬ÊFYðÓKrþËi<]*zI˜x5ת&ÜF$à2uQZ¼pãÙ‹-R|õêU€ˆ»È(79O/‰Ó4’0\äî‰ZÐ^>×~Ã0ú¢o \¶l™»g._N~ÑÀ@ãi$ɸf?(•מ&ÜF$ÈP¸Ã/°õ>vìØÁÅ­wÅFÈazI̦‘„‰Çû›ÌIó¦Ç0 á¿1ðôéÓ³gÏNxÑpíÚ5W¯jèèèPó‹ã’‹Š ­pí aÂmDnñ"<½Ä½ÃIMü¦‘$ãVBJöŒI…k¹aý¡o :th,_4DŠòš† · L¸ã¦—üö·¿åAâäº/]]]Éowb0$™¢¾¿é—ò w¿oz ÃH |Ÿ†_4´µµ)€½ö£oùaÂm&Üñ'<½ÄYv/znowŠ„Ý\†}¸OoܸÁÔð‹ {ðàÁþëný1¹aÂmæUA¿ÓKªaIy±›Ë0¢O¿÷)Â]WWç¿ À ·~÷mÕªUJbÂmæU„Ÿ^rêÔ©*™FR^ìæ2Œè“J¸kœ[ß ániiAÁ)jjj¢(¨hd„ ·a˜Tš^bÿ$Tìæ2Œè“F¸¯^½Ša³”p~eYl’IV˜p†9AÕqçÎNºsm›FRLìæ2ŒèSSS3nÜ8—èEÂMÀ²©©Iz­×ÛA¹ýôDv˜p†9A|ðOÿ}2œôëׯ'ü“Qpìæ2ŒŠ ùVõ ¸µ„[¿²L@éûqål0á6 s‚øÀ#çâð›˜d줗ëgÈ&áŸI†„[õÖ­[mmmþ7•[ZZ¼^ûß}KÿRÃHÀ„Û0Ì â’ ÿ~îÄ 7IþÉ!줗ëgÈ&ÝÝÝ­­­2o«?~œÑáVÒ(&܆aNFŒ±jÕ*–Änl› ¥¥…|U;é¥ÁúÙ0" bÍê9r¤‚„×FA c]TL¸HPÞÛÀ( Rm–;vìpóäðÓÉ÷“L줗ëgÈ,ÝÝÝC‡å& Cù®†Q8è[•n#”÷60 ˆ„Û&pcÛ^¸ëêêL¸KŒõ³aD™„—Ü`¯·‹}ë¢r`ÂmD‚òÞF‘pný‹_ü½–|“£o“U)ØI/ Öφe^rÛëíâA÷º¨˜p‘ ¼·Q@ü/ŸýãÿÀ³õß“³fÍ"†––•‚ôÒ`ýl'ü’Û^oº×EåÀ„Ûˆå½ Œ²`'½4X?FÄñ/¹íõvQ1á6 s‚jÄNzi°~6Œè£—Üöz»¨˜p†9A5b'½4X?Fôéî©±×ÛEÅ„Û0Ì ª;é¥ÁúÙ0¢O{{ûÔ©S9âÒF0á6 s‚jÄNzi°~6ŒˆÓÚÚZ__¿mÛ¶ÆÆÆ5kÖ¸\£Ð˜pÕÈñãÇ÷ìÙã}o>èÛ§ü¸ÒÝÝí¯8|ÒÉç¼»„QPL¸ #²\½zuvÀ•+WîܹsóæÍÅ‹755ÙÜ’b`ÂmT#X×È€E‹-_¾œÛ€%Œ=ÚþM;Æpfkjjxº„OúóÏ?o'½x˜p™0nÜ8.•J‡V¸öTGŽ©¯¯ß´iªf÷îÝ4$üNÊ(\!.*&ÜFÙØ°aƒ†Èø|ïjq¤¹¹ÙévÒ‹Ýë"ÃH ׉ӽ$®\¹2sæL—1bĈ¿ÿýï.0xð`õòÑG-\¸Ð%ŠO]íkÖ¬ill<}ú´;ô¾œ?~êÔ©o¼ñ†ÿ“ ‘?å½còg_@kkkò¿|DŽyÍš5jÂÕ«W]“" G뤵/è/* H3d.Üøqx]|=\„› l $ÖðÑG±â±cÇÂ1PG™ÉЊœ…ÛÆ¹ Xj ,-Z„%å=ÉY³fIʳbûöíü¡C‡œ;çÊÉ“''Nœ¸~ýz·]#K¸<\TL¸òÓÝÝ=tèPûà^Uè{!í¤—€ò>crƒËGá£xMMMc1žá&êVŸ|òÉâŋյeÆ gÏžuíŒ\'NëBpÐe—øé§{ï½÷Ûo¿E”ß}÷Ý•+Wà¾G%Ÿ`ÆŒ个?ý„@¿ú꫊Y‹:¾&ë³e*hEU 6Î*Ô¹téÒØ±cÉ ÇÚ`*òn@µýëm6‚â£×8wSS“’{÷îmiiQåLàJæÒ>}:Çï1?®_¿¾pá§žz*âŸß¢‰ ·Q0Xè­ŸåË—ÿþ÷¿×W2+3š¤ê‡g¡µµ•3R‰¯G­Ë ] !®UÕ â¢J€k1áá‡~饗6mÚ¤_‰ _~ù%öFë°¨r\'ÎéBpKüô*Œ(ŠŒ+S$$ŸY¸j–©¤jz'6HÌÖ”Ô©C¬ †ãôЊÀ·snôšÏ Z3…ycØ Lù·jfÂñãÇÙÂ|à®p|þùçŒr6¸eKyCn£¤9r„QŒ‘¿¸")7Êä4räHžI;wîäìV6Š Ÿ‚lý gþ猬^½úæÍ›Î*„Ó§OërBÚhˆ~j‡§¸kg•QAÂÍýÎà°páÂlÿ«¬âà³-eô‹ÎøÖ¯pWy 7àÖ fÍš5bÄ– Y%lÖ´“ásãĉOžûÊ+¯Ø Ìô˜p1äøñã£G^½zõ€?]›-Ÿ|ò [®Â‰‡¡™O/Ë–-s=[MpYNŸ>}éÒ¥®/bMÄ…{Ñ¢EëÖ­sîY­|÷Ýwµµµh“ë”r`ÂÝÝÝ|ŒgHq \Þyç±cÇÚïÀ§Á„ÛˆÛ·ogè)ÞKSlé÷¿ÿýÂ… ÝþŒœÀ¶·nÝêøUÉo¼±råJ×ñ%ÊÂÝÒÒ2wî\çJÕÍÞ½{®]»æº¦äp8qË—^ziÁ‚HžË*ƒ rQö”E¸wîÜùÈ#<ñľèؽ{÷< œ¬X±b…‹~ü‘î哘6è!ÓETPδiÓþïÿý¿ùË_Ü‘}1á6bÅâÅ‹§OŸ^ðÛɬ_¿~Ê”)Wí»HsbùòåË–-sâYÅ<÷ÜsHƒë”˜Yáîîî~衇Jðe•«¯¾Ši1¸¹*-Ù 7‡zï½÷rû<úè£.7-Øç‘#G\"5$Ü·nÝjnn~öÙgÿþ÷¿ÓO>ù¤CŒp“©œ¬k:[`;‚žqQEt>ÕX…€äÝwßý /0²ÙÃ1n#><ÿüóùütm¶|þùç?þ¸ +Ù²sçN†c÷¯n°½ººº¯¾úÊuM‰¬pk2‰;FðEo>ø`GG‡ë Ò’­p#.\p‰€wÞyí,\I¹¸tœLVAI TDMŠÈ$ÆP{¶R9ÂÝÞÞÎè±qãF´›6`ÀÄ áæ ås&Ož¬6SSk±òƒòž €š.ºu‹-°ÅôŒ.ò«h×;vìxä‘Gìk0á6bBYæb:tè?þã?nܸáÂFä‡zˆG»{ÈW=»víjhh [\ÅŽh ·^oÿðÃN”Œ€W_}uéÒ¥t‹ë¦Âu[F„UR>|˜N+©"´€ä‚ ðQŠH._¾œ@El„S$“ú'ù Z™%î––lû›o¾Ñ~ÕdšÉÇ ‚ç wBÕWJª±”†…›Rm¨•pèøä6qâÄÕ«W»#6L¸xÐÚÚúûßÿÞYpiùàƒ¦OŸ^®¿ÃV6là¡îïFÀ³Ï>ûÞ{ïq-¹>ŠÑîÅ‹¿õÖ[î½ IÇçóð;w\O•Š<…[v¨車Ïñ•½ ú"ðéM]9ª#wÌœ÷Õ«W9°¹sçh§$M&ظq£¼oxrµDŽ©kTé|Ö¾Ó p³ðñF9âµ×^›4ilÜÑW7&ÜFÅsäÈ‘†††ëׯˀKÏÂ… W®\YúGTÅÁâ‘G)ý·VEœcÇŽ•ý;"ŠG4…{ôèÑþí fâĉüqé_rg%Ü RLÅòEŸ#k$ð‚è‹ÀoÇ¿÷U5S 3¥ØÂÍî®®nË–-nè²÷]¼Èñ‡[áwÛØ9õõn[™ò]Ôתú<\^%¿ÿýï û{öìqm¨bL¸Ê†‘¨ìS0þO?ýÔ“‘‚ÖÖÖßýîwN3²×S1"‚ÂÝÞÞŽ8èKd}þyøm_&0 ¥73½Dt‰,GáH´¯„WŒ™ CUœFwDæë­·š››Q]gõ¥xßÏur3èÀ1cÆìÚµëÃ?$8tèÐ=÷ÜCòí·ß& Âô2•#¿<þ¼/Ræüùó©ÃF(%­TQ¤nN·‹rbÍš5&L`#ng½„X­Pà Oh#F™Ä¬N~ÏʽPßE7oªW'ôL¸(¼J2ôySSÓÂ… ¹À\cÒ²oß>Å n£²™={ö|à´·|œ]ÇÇ¹ÆÆÆ~/Zß:A¹ÕÀpQB$(b-eŠp5JU z&\^%k×®Õת$üeÆÒeÅ n£‚9~üx]]”·ìèÿ'wpF_虚š?ï¯è²"Ûw °:ZÃóOÛa™ðöq@xfpä,‰(¿_29Úo¾ùfÔ¨Q<§ûýg*¤yJEœ ÷¢E‹xö; è‹÷]DVâ-M±2Á6ÏG;°=êËù€IRGf,¨æ [ÛQPgåƒÖõ›¢¦@µ½H Öâ’÷«ÃÖÒRæó“¡Â}÷ÝÇ¥xåÊúêìÙ³ÈâСC9P¼_ðfãî*ZøvpsÛ¶¶¶Ö××=÷¿rþãÀž={yä‘/¾øÂí£’Ñ”˜M›6¹¶õ’p™ñÃÄ šæ¢r`ÂmäÅóÏ?ÿ·¿ýM”/;>ø C­MæîMMMnÜMzE7 T–L°Ìüu]¿ Uò¶ÃÖð"¢üôÈ–°¶Ã*àÊúC{q‰ÔŒ1âèÑ£ sgõnŒg¶KW å}Æô Ÿµ6oÞìú½/n|T—×9\!\~Ää«ç]È¡È_úë<5ýêZ*GpIP“øk%19ä³)¬—:@&{ÔUJ9ª£íxö+ùÖº\®á½£jiœûW¿úÞ'Ÿ|ÂøÏ?)Þ?6îv_ÉÐ {÷îå¶­©© úÌqüøq×ÔŒAÙùpȰé_$Ç>ÈÍš5‹ëójðºûöíK¸Ìè75?~Ð:•n#wvîÜùì³Ï:ÛþóŸçÌ™S–/ÕŠ>­­­Œ³s‘¼A±@)Èñ™ÁÃC¸äyƒ"ëÁƒ1°$ÉZ Ü^g•Z °ŠpoJõ½ŽHqØ/±ŽÇo‡€|rÈWeÁFØ>PÁW¦¦r”Ô^zÚjQ2uuuŸÿ¤E_%¼[¼x±ú°)ï3¦_S½/Ä\QR–\$½°²Ôy×’|àbà‚Ñ5Z%PM¾«íøkLø¤TŸÀoAÇì‚ø-ø:ž„ý*N^×—Ç›òSâÿ÷ÿýÿþïÿ®k¯”¸ÝW2´büøñjNþ ž ,p›Žk×®}ì±ÇÆçšZ”÷³„ ·‘;èÈœêFT{äÈ‘'Ož´—ÜÉ ,o¾ù¦FÛcÅ"¦^k°’z}ˆÓ°ŠäÆÛ9á·z>_E,©äËTä7…þRŸR­ˆ:ÕóÒZÇCMbj²–öÅ‘øO¡’CÀ6©F@R{I®–@SS’ý_ÿõ_ÉïÆÈwXpü.Š i„› €%§^§ŒóÈù2Éáô©”+¨@¦*èÂt-I*Vø¤|M¿m¸ Ã[ ˆ«W±HØ/¥!+j™¼—`«)…û¡‡¢ ºüÂè­d1`ãn÷• ­à©ôâ‹/½Õ‡º®½½ÇÜÆÝÖãÂG}T[[ûyðßÉO=õ”ë ^°p×~£ ˜p9ÒÝÝÚ:ÏÓ¦Mc|ÔôG# éŸÞââÿ(Nà… Ù|N‚dø|PKåË™T~S +úr<’fð›b ¾ŽÇçøí€^f+©½ô[-ÌóÏ?è¸gNŒˆàˆ5¥äF 6LçèÔ©Sœ²yóæ)§««‹å²e˨C>¥ÔQýàÜN'à:马ΉÆì•ÏFÈQèªOà·À–•#|M`›\ŸŠ9– û §g¿:€ä½ø ý¢)%ÿøÇ?¾üòË„wERâv_<˜”ZÑ3ƒûÿ8{öììÙ³ƒ>sä0¥nݺ5sæL+úãÞ€$|Ë. žŒ ,hjjúæ›oÔQ<Ê÷íÛ¾Ìb<¥¤¼˜p9ÒÒÒ2wî\£¨±eË–gžy¦££Ã^r'þO5ü ü`Ðã_±L×çÈä á/Á*òù "–Úø7Üà7•°¢j*ЫAÀ›Éñû"I‘b¡j~;ZËWR{I®–À¬Y³/^Üï»1û Û¢KÑ)R_¼È¢ÈrYrp_àÖV±4Ž`Æ TåôÔÖòu€R¿e HIøú(2õ‰Aë®O2¼®%$P¾¶Ã‡rˆ)e×~]¿—àx݉;ýÓ$ƒ˜þ…·µµuäÈ‘º‹úO“îrBÝå½-t¯¹¬’@+ä‘jTX»sþ§ÉÛ·oó¼›0aÂ×_ív“‚|ÚËç¢lÐeÆNu#¤‡AxÒ¤IK—.Uö½ß…¾ÌâúO“åÅ„ÛÈ‘È~Á#ÅðáÃÛÛÛ_ܱkÖ¬ùÓŸþ¤‘ZƒÊèaÉø«€À?BX‡süBEzãH’­©ˆmj•ü¦€Vô;e þðØ,ËðÓˆXîE¿–¶ã·F»(3¡ëÊ~¢mÛ¶ñ:sæL»1·®B KñºÑ‡Ö×"‹®¿‚÷¬|Ô¬©©)ê׺;!'ôAEŸ‘@7¿×J­L²Ï×J»yf¹töܹsG_×øÞ{ï¹=õG>íÍM¸ãØ€ûå£ÇÿñÇ«àÂ… _Êä/³¸~-`y1á6rÛ’{2üs‘BætéÒ%w¸F@kðO“nôMzEç“ ¯ ýË9ò)åêsH²’2W=tYª™=[ Ð|áë+Õ÷¥ ¾Š€8ùPY‚? –ýV£‚rÄ#<²wï^žC\BtWøÝXss³úÐ(|¦·`}Y±b××aòoßtww/Z´È% ×¹»ráãÎòÚGnÆ îVbKê33w·îA}r&ÈZÈd??|CïKäÏ”_|‘QôòåËn}Q{ÕR}ö §gœ FE’†z•@¾Vñ­ @L—ºDðdª¦'ÜóýÂçÛ††?Ò|µ½d¯Š ·‘ ú~÷—øè±víÚ9sættt¸Ã5Ž92aÂ÷T7’¸ï¾ûô@úé§Ÿ\—õj÷È‘#eáF¡=zt[[›ëz#7©^Cæi‡Ù‚ªº#Ȟ͛7ãÐhßÉ“'|@ dO½ëש¶4ÑT>IÀòÀA•¼H#ÜáöíÛ|6;vl¿W/íÅ›;ÈñB{iuP«‡i¾ß´"¯Æ^(ò$‡.¢>A=>l5]º/ßÿ=WÔ믿®n®®.ÍÊ‚ ·‘ |üýÃþàô¶/çÏŸÞkdôÿšûvðU»$YT&aÎî€0*=óÌ3Œ,6¬$PSSÃhëFb#ÄîÝ»ëëë¹f0ìäÙÿd–Ø~bÏâÅ‹W¬XqÍèËwß}7|øðÀ‹þQ¼/$é—|„5œ7oÎG€G’n-Uô0Qê ”ª w ‹i¶[¸ñáðáÃãÇommu{í%ÜR 4K5Š|ºˆ–$É”»‡ º«O5P} 7*(öõ=TvQ k£F O#aë÷·½Œ`ÂmäË•+W:½íËôàŸÕôÿjþ¿6CŒ ›€%æ AIT&½‚ïß¿ŸÑÁ¥ÄO¬è3{öl>,¹ÁØ1þ|ó\3ö‡‘ÒÀƒÿ¡‡ºxñ¢3M#À_‡þKK ÈG¸Ãú(Ad‰ Ê8 L ‚¼M$¦±È¥*äI „[ð!á™gžyùå—/]ºäöB¸•´]¯ö{z*è %A5é–ðkìð«°¢K¨?“Y²dI}}}x‰=Ë‹ ·‘ xÛ_ÿúW§·}A¸õzÛ¿·–F1 N}Ÿ.ÕbT™@¥rôÓÁÏ©,~ðB¥ZQßt^±_ÚÛÛõ““6;;wòpÏv#ò‡Ø5SJ-Z´fÍšŒ^¾ýö[.}! >纩T ªîfȤ¹¶¶Ö%®]C÷ïßÏòÓe644`ŠJBss3Ãø‰'¨C€e*?OJ&ÜpûöíÿüÏÿœ0a‚Ÿ^’,Ü4YoýkFú ¥fI52Ož19QŸÊZWI†¤œj¾T«OÒ¯Øïü¡aצ$3nÜ8>½¸§“°mÛ¶¦¦&=™¸x\OEF/¹/\¸à|³êA¤0*]‡$]7•Šœ…û\€K\»†C“Ĺ•ôü[±ðÉ„ü|(¥pÃÏ?ÿüå—_Ž?ž1Dn¯rˆÃ¢"uš>r°ô”£:ï“_SìÞ½›Ï?úÂ%aÓH"‚ ·‘ £G>~ü¸Ô6<-F¬Y&ü<™ziÍR™òlôèöôéè J1l’¾È—ÍûœTŒ1âèÑ£]]]îˆ^ô’[xCŒ;öóÏ?çÉd_ß^bZZZ^~ùewª®À††½Þ.ËÀ•³pGŠ ·@ùÄ>þü²O‘Z±bE}}=Ï>uØoÀEn#ÆwäÈç¶}A‘åÄ",Ü“ûþJs¿ÂM@M)»f˜ä ÜúÆ ›Û/œ¾ƒºç|Õ³fÍš9sæØÃ©\,\¸põêÕW«›'NÔÖÖúé¶7Êñ¨ª»%*™²7üøãÈîOkÖ¬a³i$ÑÇ„ÛÈ…åË—/Y²Äém¡Á³ñi‚®ÞŸÏ–={öè;•ûÜI¬ZµjΜ9RÏ*ÛFòü;!ûÿÚò‚e¾úꫜ‘o¾ùF&{pëÕ«W‡U‰‹°Ä_Uu÷F1á¾{å•W\¢”]¸áÖ­[‹/ž0a·ß~뤸8ð€{æ™güŒ8èìì¼iÿöUL¸\Hø‘ð‚£Øþ}v¶¼÷Þ{/¾ø"£4wÄF¬]»ö‰'ž8{ö¬S€ªÅAt¼móÑÎþüZv8œ‘Q£F577Ÿ>}úr¬yçwh)ª¤ÿ’«2Ú6d.ÜŸ|ò ¬ï¿ÿ~Å™@ý»ï¾Û%Š@„4½D?:ãì¸ÐìÝ»·¶¶–‡Ú \B6ŽEn#öíÛ7iÒ$÷ŸÑcÉ’%ú Ò .¸#6R°k×.Fí?üЩh ×Š~& ¶}ûöm×F¹A–.]úàƒþö·¿ÅJ9ANQcÁgŸ}ÆÇ Z‡°ê{ß#UÙU)gá 4I]½züøñpHBªúÀ“Ŭ®8+""Ü¢£££¡¡á7ÞpW8Äêëë×W—Û«UL¸‰ò„ûoy³1(Nœ8ÑÔÔôè£bÄ×™3gŽÿ:³írãÆï¾ûnãÆXÝ}÷Ý÷xÀŒ3ødˆNUÜV|øWh ’Älj°';wr-/+­dn@°ädá^²dÉý÷ßO¾^x¿òÊ+£GF7UŠ@(©œ„ú*R>5Yül¡êXתrsëÖ­?þñO<ñÄ™3gÜ!æÿ /„ÿ6 Æ-ãögDn#G"û#á§Nòÿ1ùƒý\fðTøâ‹/°ßüæ7ÍÍÍÄNQcÁ–-[еáÇóP»Žý#”áæÅ-8MÛÖ®]린 .¨¼×—ÂòÞ{ï½þúëj‚ÿ˜'hÝ•+W¢s¢ªúЀ ÙwÝuZ ²d2YjrÚ¤I“æÎTì|êcÏþóŸI²ì·>Iž®\aã_ýµâl‰šp§˜àÛµk—³æ\aø?~<ŸEÕF(ï¼#+L¸Ù¾};úâ¾4JlذaæÌ™Œl$Êž /^d@GkÓyn!ß?þ8Ÿ^ˆ+ 9 Ù$›ššÐµðñŸ;wÎ>ŒU7oÞä#n*ù†®®.…‚ ž‹¤H6Ÿ –Évýúõ¨}Ø£œ´úˆûXí>øàò“¯:,ÓÔgƒ~›_~ù%™Þ¿³‚V¨Ÿ]«"Ÿèêëëó™^²~ýúð\8àÖ°o2­ L¸¹uëÖ¯ýë²ÿ°V2O<ñĶàWmy0»c52æÇìîî–Ü ßz3W¤—ÅÃyX²Mã©l/¶+Ncp»¬BÀGމ¥±$v¹…&ø_îl?Êó—ònÿÆZxÃV€=/Y²„dònn1iÒ$m!«·Ý‘nàøãÿøä“O†ž çÏŸ§sfΜé‡brøÌæ¶kT&ÜFî<ÿüó847"|÷Ýw>ø F%Æ)w F– 7?üðÃ… 4¸Ã¹sç\T™àÙ—/_¶™ŽF6l@ѱ˭Jèž XðñÇã>¾ÿþû Ö®]‹C/¬ïÿ¯ÿú/*(&“:ä¨ófÙo}¿Mò©Æ²­­mîܹªŸ!´B·¼kUÄ`hå¡9jÔ¨¿ÿýï’é9zôhmmmx ¶mÿyR‰˜p¹süøñ±cÇ:ÕóçÏ÷þñÇÝùq+À%*‡Ÿ~ú‰Ã¶'“‘ .½ÞE}É}è'­• ­ÐøïZIÚÛÛÇŸÉ/=½ûî»Ø¶M#‰&ÜF^,Z´hÍš5?Dƒƒ26iT²ù$†a¤'üz[TóKnš/g­hh…®UQåæÍ›óçÏúé§9Twè}á6cÆŒ_|ÑO#!Ǧ‘T4&ÜF^tww?ôÐC.\pÎ[Vžyæÿ+6yÀ0Œ4$¼ÞÕü’»¦¦ÆõB%sß}÷éàZa~þùçM›6ÕÖÖ&+Ô‘#GÆ¿víZµ°mûc]¥cÂmäKD^r‡_oó1ÀœaF$¿ÞU>“[Ch pí‰<ß|óM}}ýªU«œk_¾üþûïcÛú) qéÒ%›FL¸|¹uë–~òÊ}wQ9èèè_’ÍÞ6 # z½ ‹-Z¾|9ž½fÍ‚qãÆUóKnð_¿XÑРמJÉþÃþðôÓOŸ>}zöìÙÏ<óŒÿÊöóçÏ_+è×òeÄ„Û(gÏž}ì±Ç õKZ90eÊ”ÖÖVPösî†a¤§½½}ß¾}.L_vQ0šÙŸÈŒóÓO?ñ:tè[o½¥`Ûý¾¹ÿ~}·hA8}útssó¨Q£üw”²#ûñ-Ã0òÁ„ÛˆY 7àÖnÌ[™”Ž1"(4"‡ ·Q,nß¾½uëÖÚÚÚ3f ÊN™s¥««ëõ×_Gµ—.]*Õû/IÃ0òDŽۈ™\‡mmm‹-RÜÒÒâõº®®ŽÂ_hD n£ˆüüóÏÝÝÝk×®}ðÁÑî÷ßov1Ÿ}öYss3[X¸p¡ÿ9`Ëö €†aä ·ì:Œ7&ÜFѹuë~Œv?óÌ3¿úÕ¯ž~úéuëÖ¥ŸjrüøqìG¿ï¾ûêëë—.]zôèQy6tvvÚ’†Q(LtŒ(`×a¼1á6JÄõë×Ï;‡.¿÷Þ{3gά­­epG}ôñÊ|ðÁ±s=üJØBš/(5 ÃÈÆFù°ë0Þ˜p%í¾téRGG‡3èüãóÏ?ßÂåöåìÙ³/^¼víÚ;w܆ Ã0 „‰Žì:Œ7&ÜFy¸uëÖåË—»»»%ßa÷9”RÇf†QTLtŒ(`×a¼1á6"ÁÏ?ÿŒ‚ ûWHÃ0J‰‰Žì:Œ7&܆aFUSSSƒëFyá:tW¤GL¸ Ã0 Ã0 £hü÷ÿÿïm4ûHo»ìIEND®B`‚tomcat-connectors-1.2.50-src/docs/images/void.gif0000644000000000000020000000005314655113620020141 0ustar rootbinGIF89a€ÿÿÿÿÿÿ!ù ,L;tomcat-connectors-1.2.50-src/docs/images/update.gif0000644000000000000020000000116314655113620020465 0ustar rootbinGIF89aÆÿÿÿþþþþÿÿ???>>>??=@@@=?>>@?*EVe¹èO¿ÿB±ø?®ö2£é-Ÿæ“Ù‹Ñ ƒÄz²%sšJbòÿÿÿÿý*FT1¢èIaooopno@>?¯¯¯ïïïðîïðððÏÏÏ¿¿¿°°°    ÿþÿÍÒÎÂή¿¯®¾±©Â¬2 ›Ä¢5E:®®®ÏÑлÀº¡¯¢“­’~ nod|d$,#}&Y¿\/t1 /%¾ÐIJϹ¤Í«›Ð¦“Π¿7ˆÐ‘u܃XÊjtÜ…”Þ¡*¼Á»¡®¤•®™~ ‡m’sk‰q$**w/؆4q5 / ÁϯÀ°±¿°°¾¯¬Á® -¯ÍµÐÐв®­«¡Ÿ#ÐÎÏÏÏÑÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,Ø€‚‚ƒƒ†Šƒ…‹Ž’••Ž Š¢¤§©«®Š¼½¾ŽÅÆ !ÂÄ"#$%Ô&Öƒ''ÃÅ()*++*,-./‰†0123456789:;<=>é(?@ABCˆ1rI%K XǤ‰“'P¢H™B¥Š•+ùqû€K–,Z¶péâE Dˆ(9û͘0aÄ\S4`Ì2dDèÔùEÄa0YZiR¤IH%M:(;tomcat-connectors-1.2.50-src/docs/images/code.gif0000644000000000000020000000061214655113620020113 0ustar rootbinGIF89a¥ÿÿÿþþþ000ðððààà///111ÀÀÀVVãssä]]êÏÏÏßßß¿¿¿––Î..ô¢¢ÚŠŠßEEï••êJJôýÿþ/10ÎÎÎddñ||í¸¸ÔÇÇã22øÆÇãÀÀ¾þÿÿ€€ÔKKõ@@退€NNN___ÈÈäûkkÛø««Å°°°OOO°®ç––Ìÿÿý002‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”,¯@€pH,‹ÀPy žÐ(ô(X¯‚–P8‡0"‘P, Üp< 7Zm¬†#’³dBHSgxg ~E eh tE† “T—q›o”D–g† ¦F }’ °§B† !g"»±u#$%&' ()*+½N,+-.ÛÓÔH//#+°ÝÞM00RSêððàðA;tomcat-connectors-1.2.50-src/docs/images/printer.gif0000644000000000000020000000066614655113620020675 0ustar rootbinGIF89a ÄÿÿÿÿÿÞßÞÖ×ÖÎÏÎÎ1ÆÇƵ¶µ¥¦¥œžœ”–”„†„sqscžcacÿ0œÀÀÀ!ù, ÿ $ŽdI.¨©®ê2¦l\º3-³4Õw[ê"C$Ò›‰€$a‘”HØ$HåRÒ”äv#i±:0<Ú×Ë8@±¢ê©/‹áA G†¬ä~rt^ yD"nxz €r…(Š‹# ‰ yo“‡B~ š‹4TAp‡¸ª««‹ˆ¯ ”±””ˆ¹o¼« qÁǸˆoɪšjDÁ’“T‰^Îkp¼ÌŒ í” ÎåçÙC# ë íàûòòÐK6„'ÑŠù/ß< †¨2ØhÂbþ)8oˆ½û—Àa5ï3™Pi1‘Æ’Cò½a¹â c ‘猦Œ!à¼ì è³ÈyrÊ+:EÂK)6]É4F;tomcat-connectors-1.2.50-src/docs/images/jakarta-logo.gif0000644000000000000020000002061014655113620021554 0ustar rootbinGIF89aù0ç:5:[Q,‡{Dß:³«N¿JñÉ[£%·.•#Ñ;Td-ð×\‡*÷T@™5Mðá]~ &æSI÷|J†2Em¡/èàbîîî¶V:NÈ‘v_ "v8:\I’ˆI®¦bK>–T=çÎbÐEöòŠ[]_¶ivŠ•N &‘hk<5¸±[ÚÙÙ:Jf.Y¸xP.--c*]î3t2¡–YbF2}FöööÝBvh7˜Œf= Sö£Q¢,F¶®jÈĈÜ,Tˤ„îæj¢‚IZxY;>¥´ºfed¥:o{ƒÁ=Y6ÊEîÒfúúúL#4Rm>>>c&`Ú$Ako“pQ§šeÝ9Xv6S{oFááà/ IÎvЇGC7$2 DlùhF 08¤*["4” *ʦ¦ÒÒв²°h6M¯o^’~^¼)Qž%DŽ-Oª Rö›WÌixì<Ž":è5R4g‡ a–¤¬TTUºº†•S„ÚÊj––•€[_MXIJJöHAn0ééè¡D3µÄÈþþþi"^®¢jƒ?qË´˜vP‚`lpìxJÎʘb 2‰œ¦‚*Q¥H” \Ö>*0’&R°W~ 2Í(Vö1¹›‘õ4>´®n.UuDvljh¼SQ5W{(9ï»ZK)PrSoèiMvvvò>àÍ˦¦¥³AKN 6’fV¶Œxòòòî~Ftt¯gb0"5h7ie,<‡HgÎ~††|N| f~>F”T[$%a:dÄ»¼¶¶Š·|y€€º¤”ÐÌÆ†1p a` N{c_ô$>u¢`…††n[Arrr¬®¯?TiDvhú‹KïµTX"b AP&&&μ}ù3žžê)Ju*UY8e¾J„$`!þ+Thanks to Brian.Ewins@i-documentsystems.com,ù0þ H° Áå4\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠôè…ÍÈ“(Sª\ɲ¥Ë—0c†œá¥¢—‰^¤xL¦ÏŸ@ƒ J´¨LCePô”¨¤'"ikñ1Ó‹…TOª‹ÆuiVƒÇ¸FS÷µ,A b£a5›Ò‹KâElR.Qº=kí¨¡¾VjîyÑH >¶«(^¼8QÑ@–cìÊècº¥dر¡ŠÝ0¨ÂRÃM/³@Žê¬˜O4“'_ˆPS¤¡7S›%3ŸÊ _¨P²&ŠgJö&²U @Œ5ê©Ñ©1@øð½X‹xàìïRþù]ˆeÑšQ†þŽ'Åõ£YŽBò2{ÑÀCz™í>¤ýôl€oêHÁÐ]å ¢Ä#*çÉP³CsÈàa!¡pÓ 7ÜÒŠWÝI!☉hàc‘é¤CA/Äó‚ÉöÝgDý—|ßÕ6|¤­4fvdß}˜‘’!£D“$wÙØ]<½a&@1º´F<“ìÍ#{4ˆ@ùÔ…PœC—\’F…Ôa u0AŒ,E胈_ýHÐcU "^ (Zý8[]5Ò‡’!é4Š#¡ñÈR4Šzd_ÝtSŽ ¢UÙÝž•v·Š¢Í ñÁÇ$“ðÑ¥4þ‰¬áÌpØp@þ@Å `áWàQidÃ+ô|‚9àüUVztÙ(Ï`¶D":”À‹®@D÷™gÐ,äêfˆ4ÝÄ#A³\éJ7ÒăêAƒn:k¬ëä ®¸¢£A%M9鬑³ýÛn<ïÆ;¯@’T.¹éÐ"º®¤ó°@W<‹ð!Z1»"_Ǥó.Ç0É}Uˆ(P9³×±ÄëŽÀ«Hóo"R[².'ðÀ3dÃݤS›Ì0rÉw²¶˜€‚rR ‡ (LÂe"­XbIöÌf=ÈQf—ÜÑ\dƒGuܸÉÌþ†Ü0ã‰\FQ ¨ã%B"iêp­†`öóAñˆ¦Íl§3›"óG‘g"† 9²@ÿy1¹hBœÜáÇyDÒÌ+ Žttƒ…=bƒÒ·­ì²—¿þÍÉ 'š2¬¤ŠÆ1†”MÅ®ŒFÄ40½¨  M€£0‡q a½èE)̦¿P$cš`ÄÎAÒ Àá—hÎ%žêàáá  °9}N>Á“ÖQÁD„æ[«ë¤AB¨ lÑp cÔè9HÙe6a¡<ņ2àRÏz”@PXñP4^¡htäÔ1DR€ÐÜ ƒ :ÊUó;KXB Õ ™½Ð ‰[¡C˜ˆ­!ш=ƒÅ\áDÌø®‹õ”ÞQ¹Vž‚Õ¨Õ[—žÅÿØ¡y X¨>Ì@€ˆ#¨„~Œ£É…ðh ]° µi8þ€l ÿ銂ôÕž€V0C$G8Žeã¦'™¤Nu) ¨ Å膟ŠFp‡…Å ˆY²·jc4PãD¸åá²}³Ù ¹9̬â`j5È«EXÊR4ÊYÈ,ë :uwÝ+ˆ ÁUjŽS}\áƒ)wˆNÌ– íÍé@¤†™ƒ6±ë…°hÞ+Ù¸ìdNÂ,½VAáÙ`ÒpÅhWÌyà"m6z! ~¤müØ#Û@R”é PduaÕ 6¸‡*È LÄB N I³ÓžbkÖkóþ$¼zK»P­Øl¼âWˆN4Égþ‰\Å@.æ\92LÚ¤ÌU0¥h`Ÿifw\lãß*a‚Ðõ ^°%‘öŠÄ¬å¨ñ² R-ÌU±cai8ÑLšÍq»Qâ~Î`óà@8ð jø`ãÀB°Œ`°Öΰ%ô7‡9|@¶P8@ Sƒ¼ÂWG&‡² ì­oàÈ ¹„:TÊ•LÍvÈv1™½‘sÂQCBEü&¢Îr†¯ìB=öœ•H¨,HUKØßËÀ¹à¢Ç]ÂA,¾ìbAÄÍíz¢»|T'¿£'ê³Ä¥Äâ>`Às`ޏ8.2ŠGFô‚µg›ÕþΠ Røªw@išLq7V¼ãw«A x¢­ˆ²YôM$D=ÍMœ\¼<šn¤ÌÞ_¹Ó{îÙð!IPWÒX"‚ØÚ½ ®8úžë+BòZi6BD<ªNh:TF#Ë: t6F1ƒpÅÆžˆUˆæZ¶ ³¦eWgD=êd±O¼•ŽvQ»¢{pÅ#š°Y!,!ÚÐs禱TØàÀP ãf‚Ö§G™p‡ÇaþcyuÀ‰A~€2…À!îñŠW8¡jhµ‹²åF#UïMÏôTgDlÃüæ½;N#þÈóS|®—AT,úÀþéBæ×{ëÁ·˜Eã 2–»wóÏà3ƒ‚ðŸv¾/ÉØÝÒ osÃW÷Œ%¨à¡(Ѓ0†0 y ’·û0«¦j‡ã ßpZÉ Ô`ÇÁ0Âc{t¡²Çv ` ¬€,¹p—PÕ‘d2 ‹° ÆÐ 9W€DQ`%TÛ–26Õ7 5cî±tæ–Tô^ôï—DÁ‡kQg|FN91Vnݶ9™v…mwv˜Z/|æ—svt×]à'%æsæTôAñÇ÷8µab¸/° ¬òªòÐ;a Xà4þ˜ gep óðýPq7߉H@ ãPò #W¹ÀQp)… +À.øð`d5` $  ` að D,è S¿¹w ê`ƒååéc=&4‡¢mzD¨Ô{]5Ø#à^!Ðs^\ˆ€3F¯BjÝ wûõ„Ô„Œa…mïÆiuwT,Ä„mµn@$Tß&0"ˆåIGxäØfO£CŒ\VpàHý€Gö` Ê€GzÀD6PþGVmÀ )Ui`Ë€@vp´Çµx¾ PÖ ɇD¸Aa(VõsœSºÁY ¥0ò”¢‘M%&n¦¢3U0XjíV)X©•àÁu=‚Œí—ÄÑ :µQ†£ÔOU 1óÅYfw|Åt—l·BÑ@Oâ$ýQ–U@Eéq|Ó— ‡˜³Q}y†la+ñ ®¢(Ð%5¡Ð ³b ŒÐ Í@ òÓ yB €¬Vqщ_à§SP½ gÀ6õ€»Æ‚„¦àe6ð“ÜÃvd°ŠN€7}sáþP‹°‚¶·»Ð£Dñƒq|81F÷Ñ÷˜À‡Xî–pú§…Í':°•ßjDtwëÒž³¡o㑘씳 yúö}kf ŠFÀG˜Vè÷8ÞètCsE®3Ú<IFÕ ^`JP  2 **npùp¤Prà –àY Ô€ ûР ó  8Z—X >ÀHP ‚¼– ¯Åbr&à |tæ`Ôaœxp9`.Xrà ¬@p‚÷ ddPúÐ#‘>œyau1FlÀBP9`w ãUh@Ó *{„þ[¨]gVÏà)qÉÔ‹ú¸B|jo>5¡@CO a,T•qTzY³@D=R`3 Ij…¹‡ù;‚™Œñ†!épfð ÁdÅ g( #Ÿ ˜˜õV¡¢“ð&: 4’xpÓ L¤0sÀ,€£µ€ y0>Ó00Ѐã hkfã ÁP Éà’²»6+À ‚¹àceò 6ŠGÆÈ'$çЮü°}ó ²'YžP‘ s,±]³ M)·±F±_ª¨Á87a ûªDS2éÇ8š~ñ° R2³3;†2c·þ}šmvš±ç¦IëI&;²l±k€²{Ô5P@à?cpõ  ¢àš4P Õ Š0¥@$e°Óµ¬6 ÕÀq¤…S6s`cÀZÙ H—@š [p¶’&p#ï   õ@RàrPx÷ Sd@@c°¸á=¸Žû¸Qi˜A±;X2Ä!­PD[™`!p$Œ­VµÔµH€ ²é£˜¡€X‹É ø ŒÀQTP µÐ ü0¤˜ b« ›pº¢+ p¾`lÙÂÒ Ì@W@èþP‹¹` –ðÈ Y@×° /ð@)Ѹ•{¾èk93ÀYs‰¾("ÇàÇ0´/ˆ¥50xÐŒà Îð´ÕàP[ ¢À ˜ˆœ¥pj>0 X°Zz —84p²ÅfS‘,Ðk|t=¦+¦  éʉ'•Rc w³!Ÿð›½ÀQm mÚ°G–ÄP¾¥ê¾8Üpêù|9¼Ï"¶`qPgðÕqG†ÿàš ¨ÀÀ:ú‘˜àºêƒ ¨€ ºicÕ r  e…à :†Œ°Z–Pº°¶erâ‚[@qsôq¹{hà¹edL@]þa¾=<ÈŸ¢žBP„ŒÄ@¬ !pP¯à‚z@ þðPÅ:*ÅÿÀ‚ ó`ÀÐh¬‹µ¬… ²[ /Ö›æ  úc¨ð´0°½l“ p RÞ0 “8ã` và[¹Àº’Räpnà5øÃ5DC¹‰Í_1 2 ÍÒ씇€ôpÕA p¢œ`µ`6k|‘¢°»º[  µþ;Õ€ ó0 ‰DÚàf¯6 IZVð<4ð€ò  (i\à»p› ¼ ‰` p2!¼Œp¸@ Ö` ûÐjð¦Ú4%ŠÈ×<Ò$]Òq dþ÷ Í.ç‚™°ÕàÀõÐkü­–ÀÍpÎP‹ ® ®Ù ,4 €¡ŒDÀp hÓ Õ@GÁy¬¢c+Üì?6ГXq>` Äö›¬ÕcÀ Ÿ ,3• ÷ð5À Ö Äpíp Q '€°&×z½×E0„pôÀ àDÀ ,P™`çÉsà ¸v»6êZzÀæ0ö€É\[ ó`óУ›æ-J} Zûóy² ·;rJk T’à¡°¯€ œ¹°7|ó[°Ñ[¾ $À?ð×p ] CC Ò|þ=ÝÔmÒ†° ´Pù  „à ÷ðàù[a2£õ0Áv~ÀÙö& Π] 0 Ó,@Êpˆû VÌJjf@Xà»fi@ !9‰æðcS‰ã0i°H¦Pzô$LVJÙ7p•!Ý'QŽz[²*è8T/¾ê`$ Ñ˜#aÍî‹âîÛ8)@ Y¸Œ°d‘Ü cPà68ÍqcP¤ÀÞ*έ®•ß6 ,PåëlŠ  Ø fðß÷!¥`X; ¯6;6H‰¸°Èvd‚ÀÍk&‡pÊR‹þá âP7•`ë`= A`k@žQù¥t~Vœ Ú€°U€\ñõ›.–sÍŽî¾lÐé(a ìP±P~Ps°Õq þ`—p9@@ ¯9@lO¾´T>~°´šcö XP Õ  Ðßµ0@1@· ÔG]ÚÞ2¹0¥Ø0  (Õ Љ7F ¹`Ø¿)€â è°FÀ 7à < ³ê{é3é$1•*ð#Ñ 6Ÿ.Íú~¾BÀÌ*q  à @ô@ v !LÞ '5Š&ð@ð‚ðJ ›þü°cçM ÿ€kŠÐksÀÓÕº`£¸€ Iêf ðŒ bp o±ª¼£ Øž 90Ê0xDwpÂÕ±Gp À• ë°)ÐQÀ •Ðîëpk)ép Rãs¡šÉÁôhÙ :@3Àð<÷ á x9y¿:À2tBK ÅДo4Å0U€t-‘á«À€"¯aÝ€}bö‘£ ø«@¹^ ³ A(ú‰¿ø¿UŠ*¦:öR“…`á'so(âìÆ°Ïð9RPe ® õG„4‹À@„€@þps3ÄÕ¬Íñ&Õ±·Í1³^z& š +¡À¶9 ´ª¹å,ð¸ ?\Ð< xôÓ ›0€ V@¨€ Ñ~  y™)S@Aî ²'8xœÇ£„„8… „¸ Tª´H /‰<~R$È*Bø¬I€È5BF¥‹'¤BÒ¥3R!Ý^Sd7³Fz¬òâh¢Aé–z”’ŽO´‘(Ò½XƒbÆÈnT¡4Rš´c/\¹s”€hB=êàfGR^¾8VÅÓ‘«Ø¬y1*ÀÈtf\4X䨲gÝ‚¤-Þšr«D–äó¢°º‘êf¼þЯ̾!©œ/ÀJ‘F¹Œw¹ àrr¦[RZ÷î£^NÑqC‚$FjÔȆî½pðàyÇ„«ÏñdsžÊ¥KÎ3‘¦@& @isà@=Ršø±ç£Y³qh,9K–‡Ã~0šYP™<¾á€š/QfTæÙgLn1˜2 °Â2„pgàÁ#@ ‹v@ñ."‡\ám)8óH°.‹«*ŽÚÉ(¤, I CÒ‘i$R$)ˆÔ­›Qø2¤¨¡–Œ†Ýfè&-j)tk²È9R©ÒÑæ#)ÊÀò(*EbÌéÅQþ ¤!uLDy‚ENóÒ#ž9Š:¹ò(>Òü²Ñ¥|\C˜7®ùá‡Åœ36G¥–^zQ†zQ*¹šº€fÛ1ìâˆ.Ä a‘­ú_ƒ?ª‚Q¨ºþ£ŠºÅE—…5‰½¸ ¿ÎÒ`(ž¶:ê¬%؈§'+?þ7é… 6Î")ˆ†6ŸÚàh¨ÿÈ{ðŘ䥂ODó4€hŒ¢€÷ãþ&(‚Y~$ñ¢Œ—ˆý΂K9†8@CFp@ ôVƒy!àÐÛª:Ñ ¸ÕàÈ0Ž& 7~8q¨Ž©:Nàä¸Äs®°‰ñ4à§ëE3`xîРzÀÎC,tËɰÁvEŽÿØÃ8¨ˆ½@t„DÁ#BÀ) á€ÜÀƒ†Bð»âÕo$ òpd>C}éHíKD󔉩 AÊÑP<6ƒÜ© Ò«B=²“™$€˜"-É— LQ Í>±=’x’üJ9~F0&¬Lüê’™@šàDÕØ—^З#yÁ "þ‰7°ª<¨ÄM±B ŒpÇŽƒŽ;0C¡¸T €p½­ÐDhÕŒS&\¡UÊ`%œ•.êÌÅÆamn68ÇxLð„9Ô£¦àEP¸ ë@ XG±¯­P”u©‚4F"…npo|¸¼Y]2’¼,åà’ ¦<d/TÙ *wâRàÉtcÚ¤G8É›60I S(v$FÍô”"Ä+ÿ‡¥V&¢“#É,ÞÔ#PÔ©-mÔ@" !@m‚e é/Åú|AÂèZ°_ЃÌ0ÅÙ±ƒ* £òŧìþº®0p7M•¬šðg=<`‡nâáõ8@.Æ™œgq Àƒ©Î-î ÁB€Jdà ACê‚!XТÉKD4¡ƒ©’4jR¨-OÓ¡)«Úƒj"^=?% MG4À'½´|V…J[ßÚt)MÚWnÑ !dÏUÈi'§@ÒÀ”c À ¤0 (ÕLÒ¥.P9‹2ŒÂ(^(.ñX™Ó* 'Rx*©z\¸¢»‰˜Å –Ôš[B%|Hw¯’Àv¬6©!z PÁ^Ü!³5„h tó‡@:èñŠþ\ÊgëÄâ`V –m3¸1d˜b;¦è&,Ïñx€Cf9¶p7Sˆ#E@%Bà ð` Èx‘­ò«ŽÂ’6(V¬‚BùMÄNÑ®Ajì·!)ƒvAR†2/¥u‰ ´½'}de©j(ÔQ›R ©GA¡*´écì¥Gž1¡GÚ2K˜4ª\EËwM"ñxP†L[4§‰ …é#-X$¦ÕçIcmITHÊ¡Q ›7î>ñ†]„:±8Bòcz„a8d8DÞj`xL‡䈱[õÃÂÜágÈñ vþ¯HÃs ˆ*H@fñ€LÜ Øri+‰nרuyÔÇ–§5/xÕ‡*Í3t`ƒ·H ¤n¤Ð¾YT¼4:ðx<ª°q¾\<ã“Ôs£Ö{òGi å~ôtH´Qçƒ×üKÁlE$ޱ†n£N‡) Í: */ border-collapse: separate; } th { text-align: left; } main { /* Remove this once all IEs support
    element */ display: block; } /* Layout */ #wrapper { min-width: 400px; } #header { border-bottom: 1px solid #bbb; } @media not print { #header { box-shadow: 0 0 7px #aaa; } } #header > div { padding-left: 15px; padding-right: 15px; /* Work-around for old browsers: */ background-color: #F8F3E4; background: linear-gradient(to bottom, #ffffff -10%, #F8F3E4 100%); position: relative; } #header .logo { float: left; padding-top: 10px; min-width: 190px; } #header .logo img{ /* To avoid that the Font Descender being added to the parent div's height */ vertical-align: middle; } #header .asfLogo { float: right; position: relative; top: 8px; } #header h1 { margin-top: 0.6em; margin-bottom: 0; } #header .versionInfo { font-size: 13pt; margin-bottom: 1em; } #middle { display: table; table-layout: fixed; margin: 0; width: 100%; } #middle > div { display: table-row; } #middle > div > div { display: table-cell; vertical-align: top; } #mainLeft { width: 190px; } #mainLeft > div { margin-top: -1px; /* to overwrite border of element above */ padding-left: 16px; padding-right: 14px; padding-top: 6px; padding-bottom: 15px; background-color: #F8F3E4; border-right: 1px solid #bbb; border-bottom: 1px solid #bbb; font-size: 10pt; border-bottom-right-radius: 20px; box-shadow: 0 0 5px #aaa; } #mainLeft h2 { margin-bottom: 0.2em; font-size: 1.2em; } #mainLeft ul { padding: 0; margin: 0; list-style-type: none; } #mainLeft ul a { text-indent: -0.6em; padding-left: 1.4em; display: block; text-decoration: none; color: #444; } #mainLeft ul a:hover { color: #000; background-color: #D1c9b9; } #mainRight { padding-left: 14px; padding-right: 20px; } #footer { margin-top: 30px; padding-top: 20px; padding-bottom: 20px; padding-left: 20px; padding-right: 20px; border-top: 1px solid #ccc; color: #444; text-align: center; /* font-style: italic; */ font-size: 9pt; } /* Content */ #content div.text { padding-left: 1em; padding-left: 1em; } #content h3, #content h4, #content h5, #content h6 { padding-left: 5px; padding-right: 5px; background-color: #eaeaea; } @media not print { #content h3, #content h4, #content h5, #content h6 { border: 1px solid #ccc; border-radius: 4px; } } #content h4, #content h5, #content h6 { background-color: #f6f6f6; } code { background-color: rgb(224,255,255); } div.codeBox pre code, code.attributeName, code.propertyName, code.noHighlight, .noHighlight code { background-color: transparent; } div.codeBox { overflow: auto; margin: 1em 0; } div.codeBox pre { margin: 0; padding: 4px; border: 1px solid #999; border-radius: 5px; background-color: #eff8ff; display: table; /* To prevent
    s from taking the complete available width. */
      /*
      When it is officially supported, use the following CSS instead of display: table
      to prevent big 
    s from exceeding the browser window:
      max-width: available;
      width: min-content;
      */
    }
    
    div.codeBox pre.wrap {
      white-space: pre-wrap;
    }
    
    
    table.defaultTable tr, table.detail-table tr {
        border: 1px solid #CCC;
    }
    
    table.defaultTable tr:nth-child(even), table.detail-table tr:nth-child(even) {
        background-color: #FAFBFF;
    }
    
    table.defaultTable tr:nth-child(odd), table.detail-table tr:nth-child(odd) {
        background-color: #EEEFFF;
    }
    
    table.defaultTable th, table.detail-table th {
      background-color: #88b;
      color: #fff;
    }
    
    table.defaultTable th, table.defaultTable td, table.detail-table th, table.detail-table td {
      padding: 5px 8px;
    }
    
    
    p.notice {
      border: 1px solid rgb(255, 0, 0);
      background-color: rgb(238, 238, 238);
      color: rgb(0, 51, 102);
      padding: 0.5em;
      margin: 1em 2em 1em 1em;
    }
    
    
    /* Changelog-Styles */
    
    ul.changelog {
      padding-left: 1em;
      list-style-type: none;
    }
    
    ul.changelog  li{
      padding-top: 5px;
      padding-bottom: 5px;
    }
    
    ul.changelog img {
      vertical-align: middle
    }
    
    
    /* Printer-only Styles */
    @media print {
        .noPrint { display: none; }
        #middle > div > div#mainLeft { display: none; }
        a { color: inherit; text-decoration: none; }
    }
    
    /* Fix for Comments section which contains a 

    */ #comments_thread h1, #comments_thread h2, #comments_thread h3, #comments_thread h4, #comments_thread h5, #comments_thread h6 { border: none; background-color: transparent; }tomcat-connectors-1.2.50-src/docs/images/design.gif0000644000000000000020000000114014655113620020447 0ustar rootbinGIF89aÆÿÿÿþþþþÿÿ???>>>??=@@@=?>>@?*EVe¹èO¿ÿB±ø?®ö2£é-Ÿæ“Ù‹Ñ ƒÄz²%sšJbòÿÿÿÿý*FT1¢èIaooopno@>?¯¯¯ïïïðîïðððÏÏÏ¿¿¿°°°   «¡ŸÿþÿÍÒÎÂή¿¯®¾±©Â¬‘¥”®®®ÏÑлÀº¡¯¢“­’~ nod|dSkS#}&¾ÐIJϹ¤Í«›Ð¦“Π¿ˆÐ‘u܃¼Á»¡®¤•®™~ ‡m’sk‰q*w/ÁϯÀ°±¿°°¾¯¬Á®ÐÐв®­ÐÎÏÏÏÑ,Å€‚‚ƒƒ†Šƒ…‹Ž’••Ž Š¢¤§©«®Š¼½¾ŽÅÆ !ÂÄ"#$%%&&̃''ÃÅ()*++*,-ØŠ./012345667ç†Ã(89:;<=>>?ê 2 H!Cˆ‘gD  nPA‚$‰’%æ!¢äŒI4M¬]æÄÉ“'"R¦d"Â!¥˜,ɬ4)Ò¤›’lâ;tomcat-connectors-1.2.50-src/docs/webserver_howto/0000755000000000000020000000000014655113620020472 5ustar rootbintomcat-connectors-1.2.50-src/docs/webserver_howto/iis.html0000644000000000000020000007143314655113620022154 0ustar rootbin The Apache Tomcat Connectors - Web Server HowTo (1.2.50) - ISAPI redirector for Micrsoft IIS HowTo

    ISAPI redirector for Micrsoft IIS HowTo

    Introduction

    This document explains how to set up the ISAPI redirector for IIS to cooperate with Tomcat.

    Normally IIS can not execute Servlets and Java Server Pages (JSPs). Configuring IIS to use the ISAPI redirector plugin will let IIS send servlet and JSP requests to Tomcat (and this way, serve them to clients).

    It is recommended that you also read the Workers HowTo document to learn how to setup the working entities between your web server and Tomcat Engines. For more detailed configuration information consult the Reference Guide for workers.properties, uriworkermap and IIS.

    Document Conventions and Assumptions

    ${tomcat_home} is the root directory of tomcat. Your Tomcat installation should have the following subdirectories:

    • ${tomcat_home}\conf - Where you can place various configuration files
    • ${tomcat_home}\webapps - Containing example applications
    • ${tomcat_home}\bin - Where you place web server plugins

    In all the examples in this document ${tomcat_home} will be c:\tomcat. A worker is defined to be a tomcat process that accepts work from the IIS server.

    Supported Configuration

    The IIS to Tomcat redirector is supported for:

    • IIS running on any currently supported version of Windows
    • All currently supported versions of Tomcat

    The redirector may work with IIS running on older, unsupported versions of Windows and/or Tomcat but such configurations are not supported.

    AJP protocols?

    The redirector uses the AJP protocol to send requests to the Tomcat containers. The AJP version used is ajp13. All current versions Tomcat support the ajp13 protocol. Others servlet engines such as Jetty and JBoss also support the ajp13 protocol.

    The ajp12 protocol has been deprecated and you should no longer use it. The ajp14 protocol is considered experimental.

    How does it work ?

    1. The ISAPI redirector is a Microsoft IIS plugin (filter + extension). IIS loads the redirector plugin and calls its filter function for each in-coming request.
    2. The filter then tests the request URL against a list of URI-paths held inside uriworkermap.properties. If the current request matches one of the entries in the list of URI-paths, the filter transfers the request to the extension.
    3. The extension collects the request parameters and forwards them to the appropriate worker using the defined protocol like ajp13.
    4. The extension collects the response from the worker and returns it to the browser.

    Installation

    Pre-built versions of the ISAPI redirector plugin, isapi_redirect.dll, for 32-bit and 64-bit environments are available from the Apache Tomcat Connectors Downloads page. You can also build a copy locally from the Tomcat Connectors source distribution. The ISAPI redirector requires three entities:

    • isapi_redirect.dll - The ISAPI redirector for Microsoft IIS plugin, either obtain a pre-built DLL or build it yourself (see the build section).
    • workers.properties - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). A sample workers.properties can be found under the conf directory.
    • uriworkermap.properties - A file that maps URL-Path patterns to workers. A sample uriworkermap.properties can be found under the conf directory as well.

    The installation includes the following parts:

    • Configuring the ISAPI redirector with a default /examples context and checking that you can serve servlets with IIS.
    • Adding more contexts to the configuration.

    Configuring the ISAPI Redirector

    These instructions have been written based on Windows Server 2012 R2 and tested with all supported Windows operating systems up to Windows 11 / Windows Server 2022.

    These installation instructions have been tested with a default installation of IIS plus ISAPI Extensions and Filters on a clean, fully patched OS installation with Tomcat 9 installed in C:\Program Files\Apache Software Foundation\Tomcat 9.0. This is referred to as ${tomcat_home} for the remainder of this document.

    1. Create a directory ${tomcat_home}\isapi
    2. Allow the IIS process to create the ISAPI redirector log file. Modify the path as necessary if the log file is to be written to a different directory. Enter the following at a command prompt:
      >icacls "C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi" /grant "IIS APPPOOL\DefaultAppPool":(OI)(CI)M
      
      On client operating systems with User Account Control (UAC) enabled, the command prompt must be opened using Run as administrator for the above command to complete successfully.
    3. Download the appropriate (32-bit or 64-bit) isapi_redirect.dll for your operating system and place it in ${tomcat_home}\isapi
    4. Set the premissions for isapi_redirect.dll. On Windows Server 2019 it appears to be necessary to explicitly set the permissions for this dll. Enter the following at a command prompt:
      >icacls "C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi\isapi_redirect.dll" /grant "Everyone":RX
      
    5. Create ${tomcat_home}\isapi\isapi_redirect.properties file to configure the ISAPI redirctor. Configuration can also be performed via registry settings - see below. The contents of this file should be:
      extension_uri=/jakarta/isapi_redirect.dll
      log_file=C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi\isapi_redirect.log
      log_level=info
      worker_file=C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi\workers.properties
      worker_mount_file=C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi\uriworkermap.properties
      
      Be careful so that Windows does not add a .txt extension to the file.
    6. Create ${tomcat_home}\isapi\workers.properties file to configure the Tomcat instances that requests will be passed to. For a single Tomcat instance on the local machine the contents of this file should be:
      worker.list=tomcat01
      worker.tomcat01.type=ajp13
      worker.tomcat01.host=localhost
      worker.tomcat01.port=8009
      
    7. Create ${tomcat_home}\isapi\uriworkermap.properties file to configure which requests will be passed to Tomcat. To expose the examples web application the contents of this file should be:
      /examples/*=tomcat01
      
    8. Using the IIS management console, add a new virtual directory to your IIS web site. In a clean install, this will be the Default Web Site. The name of the virtual directory must be jakarta. Its physical path should be the directory where you placed isapi_redirect.dll.
    9. Select the newly created virtual directory in the management console and then double-click Handler Mappings. Select the (currently disabled) ISAPI-dll entry and then click Edit Feature Permissions in the action pane. In the dialog box that opens, select Execute so all three permissions are selected. Click OK and ISAPI-dll should now be in the enabled state.
    10. Again using the IIS management console, add the ISAPI redirector as a filter to your web site. Select your web site and then double-click ISAPI Filters. From the action pane, click Add.... For the filter name use tomcat and the executable should be the full path to isapi_redirect.dll. Once configured, click OK.
    11. Still using the IIS management console, configure the ISAPI redirector as allowed. Select your server (not the web site) and then double-click on ISAPI and CGI Restrictions. From the action pane, click Add.... Select the isapi_redirect.dll, add a descripion (e.g. tomcat) and select the Allow extension path to execute and then click OK.
    12. Restart IIS (stop + start the IIS service).

    That's all, you should now start Tomcat and ask IIS to serve you the /examples context. Try http://localhost/examples/ for example and execute some of the Servlet or JSP examples.

    If this does not work successfully, refer to the Troubleshooting section below for help on correcting the problem.

    IIS logging

    If the IIS access logs show entries such as /jakarta/isapi_redirect.dll rather than /examples/servlets then this can be corrected via the IIS management console. Select your server (not the web site) and then double-click on Modules. In the Actions pane, click View Ordered List..., select the IsapiFilterModule and move it up until it is above the HttpLoggingModule.

    Registry configuration

    As an alternative to using the isapi_redirector.properties file, the ISAPI redirector may be configured via the registry. To do this, follow these steps:

    1. In the registry, create a new registry key named "HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0"
    2. Add a string value with the name extension_uri and a value of /jakarta/isapi_redirect.dll
    3. Add a string value with the name log_file and a value pointing to where you want your log file to be (for example c:\tomcat\logs\isapi.log).
    4. Add a string value with the name log_level and a value for your log level (can be debug, info, error or emerg).
    5. Add a string value with the name worker_file and a value which is the full path to your workers.properties file (for example c:\tomcat\conf\workers.properties)
    6. Add a string value with the name worker_mount_file and a value which is the full path to your uriworkermap.properties file (for example c:\tomcat\conf\uriworkermap.properties)

    64 Bit notes

    In a 64-bit environment the IIS Application Pool should have "Enable 32-bit Applications" set to "False". To check this, select Application Pools in the IIS management console, then right-click on the pool you are using and select Set Application Pool Defaults.... Enable 32-bit Applications may be found in the General section. If this is not configured correctly, the redirector will not be called and IIS will return an HTTP code 404.

    You must use the 64-bit version of the ISAPI redirector on 64-bit operating systems. If you attempt to use the 32-bit version, you will get an HTTP code 500 for every request because the library is not loadable into a 64-bit IIS.

    Adding additional Contexts

    The examples context is useful for verifying your installation, but you will also need to add your own contexts. Adding a new context requires two operations:

    1. Adding the context to Tomcat (not discussed here).
    2. Adding the context to the ISAPI redirector.

    Adding a context to the ISAPI redirector is simple, all you need to do is to edit your uriworkermap.properties and to add a line that looks like:

    /context/*=worker_name
    

    Workers and their name are defined in workers.properties. As an example, if you want to add a context named "shop", to be served by the worker named "tomcat01" the line that you should add to uriworkermap.properties will be:

    /shop/*=tomcat01
    
    After saving uriworkermap.properties restart IIS and it will serve the new context.

    The above should be all you need for IIS to pass through to Tomcat any request for any URI which corresponds to a Tomcat context (webapp).

    Advanced Context Configuration

    If your website is very busy (more than 100 requests/second, or more than 100 simultaneous client connections), it might sometimes be desirable to have IIS serve static content (html, gif, jpeg etc.) directly, even if these files are part of a context served by Tomcat. Allowing IIS to serve such files directly may avoid the small overhead consisting of passing the request to Tomcat via the redirector, and may free up Tomcat somewhat, by using it only to process requests that only Tomcat can handle (e.g. requests to JSP pages and java servlets).

    For example, consider the html and gif files in the examples context: you could serve these files directly with IIS; there is no need to serve them from the Tomcat process.

    However, you should be very careful when you implement the following configuration style, because by doing so you are in fact providing a "back-door" to IIS, and allowing it to serve files out of a Tomcat context without Tomcat's knowledge, thus bypassing any security restrictions which Tomcat itself and the Tomcat context (webapp) may place on those files.

    Making IIS serve static files that are part of the Tomcat contexts requires the following:

    1. Configuring IIS to know about the Tomcat contexts
    2. Configuring the redirector to leave the static files for IIS

    Adding a Tomcat context to IIS requires the addition of a new IIS virtual directory that covers the Tomcat context. For example adding a /example IIS virtual directory that covers the c:\tomcat\webapps\examples directory.

    Configuring the redirector is somewhat harder, you will need to specify the exact URL-Path pattern(s) which you want Tomcat to handle (usually only JSP files and servlets). This requires a change to the uriworkermap.properties:

    For the examples context it requires to replace the following line
    /examples/*=tomcat01
    with the following two lines
    /examples/*.jsp=tomcat01
    /examples/servlet/*=tomcat01
    

    As you can see the second configuration is more explicit, it actually instruct the redirector to redirect only requests to resources under /examples/servlet/ and resources under /examples/ whose name ends with .jsp.

    You can even be more explicit and provide lines such as:

    /example/servlets/chat=tomcat01
    

    that instructs the redirector to redirect all requests whose URL-path matches the leading string "/example/servlets/chat" to the worker named tomcat01.

    Protecting the content of your Tomcat contexts

    Once again, be aware that by allowing IIS to access the content of your Tomcat context directly, you are potentially bypassing Tomcat's protection of that content. You should thus make sure to protect this content at the IIS level if needed, by using the corresponding IIS management console functions.

    In particular, each servlet application (context) has a special directory named WEB-INF, which contains sensitive configuration data and Java classes, and which should always be kept hidden from web users. Using the IIS management console it is possible to protect the WEB-INF directory from user access, but considering that this is a general requirement, and considering that it is easy to forget to implement this protection at the IIS level, the ISAPI redirector plugin does it automatically for you, and it will reject any request which contains WEB-INF in its URL path. It will also reject any request which contains META-INF in its URL path.

    Advanced Worker Configuration

    Sometimes you may want to serve different contexts with different Tomcat processes (for example to spread the load among different machines). To achieve such a goal you will need to define several workers and assign each context to its own worker.

    Defining additional workers is done in the workers.properties file. This file includes two types of entries:

    # An entry that lists all the workers defined
    worker.list=worker1, worker2
    # Entries that define the host and port associated with each of these workers
    worker.worker1.host=localhost
    worker.worker1.port=8009
    worker.worker1.type=ajp13
    worker.worker2.host=otherhost
    worker.worker2.port=8009
    worker.worker2.type=ajp13
    

    The above example defined two workers, now we can use these workers to serve two different contexts each with its own worker:

    example uriworkermap.properties fragment
    /examples/*=worker1
    /webpages/*=worker2
    

    As you can see the examples context is served by worker1 while the webpages context is served by worker2.

    More information on using and configuring workers in the Workers HowTo and in the worker.properties configuration reference.

    Building the ISAPI redirector

    To build the ISAPI redirector you will need Mladen's Custom Microsoft Compiler. The remainder of this document assumes this installed to c:\cmsc.

    The steps to build the ISAPI redirector are:

    • Download the sources as a zip file and unpack it.
    • Change directory to the ISAPI redirector source directory.
    • c:\cmsc\setenv.bat x86
      nmake -f Makefile.vc
      c:\cmsc\setenv.bat x64
      nmake -f Makefile.vc
      

    The resulting file isapi_redirect.dll (and the debug symbol file isapi_redirect.pdb) is located in the "x86_RELEASE" or "x64_RELEASE" sub directory.

    Troubleshooting

    It is easy to have the ISAPI redirector not work the first time you try to install it.

    If this happens to you, here are some steps to follow to try to correct the problem.

    These steps aren't guaranteed to cover all possible problems, but they should help find the typical mistakes.

    If you make any corrections during these steps, restart the IIS service as described above in the last step of the installation, then retry the step.

    Note: These steps are based on the configuration used in the installation instructions that proxies requests for the examples web application to a single Tomcat instance. It is also assumed that the "/examples" context works correctly if you access Tomcat directly.

    Diagnostics steps

    Delete (or move elsewhere) the ISAPI redirector log file if present.

    Start the IIS service and Tomcat.

    Check for the presence of the ISAPI redirector log file at the specified location. If not found, that indicates that the ISAPI redirector has not started correctly. This is usually caused by incorrect configuration settings.

    • Check your configuration carefully against the installation instructions, particularly the location, name and contents of the ${tomcat_home}\isapi\isapi_redirect.properties file.
    • If using the registry based configuration, check the path, name and values of the registry keys. Registry names are not case sensitive.
    • Check that the directory specified for the log file exists and that the file permissions have been configured as per the installation instructions.
    If the above are set correctly, the ISAPI redirector should be able to create the log file.

    Invoke the URL http://localhost/examples/ in your browser. Case is important in URLs. The characters following "localhost" in the URL must be lower case. If the page fails to appear, stop the IIS service (required to view the IIS log file). Then examine the last line in the IIS log file in found in C:\inetpub\logs\LogFiles\W3SVC1:

    If the last line contains:

    GET "/examples/ HTTP/1.1" 404
    
    then the ISAPI redirector is not recognising that it should be handling requests for the "/examples" context.

    If the last line contains something like:

    GET "/jakarta/isapi_redirect.dll HTTP1.1"
    
    then the ISAPI redirector is recognising that it should handle the request, but is not successful at getting Tomcat to service the request.

    Check the following:

    • Check your configuration carefully against the installation instructions, particularly the name of the virtual directory and the location, name and contents of the ${tomcat_home}\isapi\uriworkermap.properties and ${tomcat_home}\isapi\workers.properties files.
    • If these are set correctly, the ISAPI redirector should recognise that it should handle requests for the "/examples" context.

    If the browser shows a 503 error page then the ISAPI redirector is recognising that it should handle the request but is not receiving a timely response from Tomcat. Check the following:

    • Check your configuration carefully against the installation instructions, particularly the location, name and ${tomcat_home}\isapi\workers.properties file.
    • Check the AJP connector configuration in Tomcta matches the configuration in the ${tomcat_home}\isapi\workers.properties file.

    If the browser shows a 500 error page then an internal error has occurred within IIS or the ISAPI redirector when trying to serve the request. There should be a textual description of the error towards the top of the page and an 8-digit hex error code towards the end of the page. The last four digits should be the standard windows error code associated with the problem.

    A common cause of 500 errors is Windows creating configuration files with hidden ".txt" file extensions that are not shown in Windows Explorer. Even if file extensions are shown for other files, double check to make sure that Windows Explorer is configured to show file extensions for all files.

    If the error message is Calling GetFilterVersion on ISAPI filter "...isapi_redirect.dll" failed and the code is 0x8007047e then the code translates to an error code 0x047e or 1150 which is "The specified program requires a newer version of Windows". Together these indicate that the initialisation of the ISAPI redirector failed because the configuration could not be read - either from ${tomcat_home}\isapi\isapi_redirect.properties of from the registry. Check the name location and contents of the ${tomcat_home}\isapi\isapi_redirect.properties file or the registry keys as appropriate.

    If the above settings are correct, the index.html page should appear in your browser. You should also be able to click the links to execute some Servlet or JSP examples.

    tomcat-connectors-1.2.50-src/docs/webserver_howto/apache.html0000644000000000000020000013651014655113620022607 0ustar rootbin The Apache Tomcat Connectors - Web Server HowTo (1.2.50) - Apache HTTP Server HowTo

    Apache HTTP Server HowTo

    Introduction

    This document explains how to connect Tomcat to the popular open source web server, Apache HTTP Server. You can use the connection module mod_jk with any supported version of Apache and any supported version of Tomcat.

    It is recommended that you also read the Workers HowTo document to learn how to setup the working entities between your web server and Tomcat Engines. For more detailed configuration information consult the Reference Guide for workers.properties, uriworkermap and Apache.

    Warning: If Apache and Tomcat are configured to serve content from the same file system location then care must be taken to ensure that Apache is not able to serve inappropriate content such as the contents of the WEB-INF directory or JSP source code. This could occur if the Apache DocumentRoot overlaps with a Tomcat Host's appBase or the docBase of any Context. It could also occur when using the Apache Alias directive with a Tomcat Host's appBase or the docBase of any Context.

    This document was originally part of Tomcat: A Minimalistic User's Guide written by Gal Shachor, but has been split off for organisational reasons.

    Document Conventions and Assumptions

    ${tomcat_home} is the root directory of tomcat. Your Tomcat installation should have the following subdirectories:

    • ${tomcat_home}\conf - Where you can place various configuration files
    • ${tomcat_home}\webapps - Containing example applications
    • ${tomcat_home}\bin - Where you place web server plugins

    In all the examples in this document ${tomcat_home} will be /var/tomcat3. A worker is defined to be a tomcat process that accepts work from the Apache server.

    Supported Configuration

    The mod_jk module is supported for:

    • All currently supported versions of Apache Web Server (httpd)
    • Any operating system supported by Apache Web Server
    • All currently supported versions of Tomcat

    The mod_jk module may work with older, unsupported versions of Apache Web Server and/or Tomcat but such configurations are not supported.

    AJP protocols?

    The mod_jk module uses the AJP protocol to send requests to the Tomcat containers. The AJP version used is ajp13. All current versions Tomcat support the ajp13 protocol. Others servlet engines such as Jetty and JBoss also support the ajp13 protocol.

    The ajp12 protocol has been deprecated and you should no longer use it. The ajp14 protocol is considered experimental.

    How does it work ?

    In a nutshell a web server is waiting for client HTTP requests. When these requests arrive the server does whatever is needed to serve the requests by providing the necessary content.

    Adding a servlet container may somewhat change this behaviour. Now the web server needs also to perform the following:

    • Load the servlet container adaptor library and initialise it (prior to serving requests).
    • When a request arrives, it needs to check and see if a certain request belongs to a servlet, if so it needs to let the adaptor take the request and handle it.

    The adaptor on the other hand needs to know what requests it is going to serve, usually based on some pattern in the request URL, and to where to direct these requests.

    Things are even more complex when the user wants to set a configuration that uses virtual hosts, or when they want multiple developers to work on the same web server but on different servlet container JVMs. We will cover these two cases in the advanced sections.

    Obtaining mod_jk

    mod_jk can be obtained in two formats - binary and source. Depending on the platform you are running your web server on, a binary version of mod_jk may be available.

    It is recommended to use the binary version if one is available. If the binary is not available, follow the instructions given in the below "Building mod_jk" sections for building mod_jk from source. The mod_jk source can be downloaded from a mirror here

    The binaries for mod_jk are now available for several platforms. The binaries are located in subdirectories by platform.

    For some platforms, such as Windows, this is the typical way of obtaining mod_jk since most Windows systems do not have C compilers.

    For others, the binary distribution of mod_jk offers simpler installation.

    For example JK 1.2.x can be downloaded from a mirror here (look for JK 1.2 Binary Releases). The "JK 1.2 Binary Releases" link contains binary version for a variety of operating systems for both Apache 1.3 and Apache 2.x.

    Installation

    mod_jk requires two entities:

    • mod_jk.xxx - The Apache HTTP Server module, depending on your operating system, it will be mod_jk.so, mod_jk.nlm or MOD_JK.SRVPGM (see the build section).
    • workers.properties - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). A sample workers.properties can be found under the conf directory in the source download.

    Also as with other Apache modules, mod_jk should be first installed on the modules directory of your Apache HTTP Server, ie: /usr/lib/apache and you should update your httpd.conf file.

    Disabling old mod_jserv

    If you've previously configured Apache to use mod_jserv, remove any ApJServMount directives from your httpd.conf.

    If you're including tomcat-apache.conf or tomcat.conf, you'll want to remove them as well - they are specific to mod_jserv.

    The mod_jserv configuration directives are not compatible with mod_jk !

    Using Tomcat auto-configure

    Tomcat auto-configure is deprecated and has been removed in Tomcat 7 and later.

    The auto-configure works only for a single Tomcat running on the same machine where the Apache HTTP Server is running. The simplest way to configure Apache HTTP Server to use mod_jk is to turn on the Apache HTTP Server auto-configure setting in Tomcat and put the following include directive at the end of your Apache httpd.conf file (make sure you replace $TOMCAT_HOME with the correct path for your Tomcat installation:

    # To be added at the end of your httpd.conf
    Include $TOMCAT_HOME/conf/jk/mod_jk.conf-auto
    

    Note: this file may also be generated as $TOMCAT_HOME/conf/auto/mod_jk.conf

    This will tell the Apache HTTP Server to use directives in the mod_jk.conf-auto file in the Apache configuration. This file is created by enabling the Apache auto-configuration by creating your workers.properties file at $TOMCAT_HOME/conf/jk/workers.properties and adding the listener to the Engine element in the server.xml file as per the following example. Please note that this example is specific to Tomcat 5.x, unlike other sections of this document which also apply to previous Tomcat branches.

    ...
    <Engine ...>
      ...
        <Listener className="org.apache.jk.config.ApacheConfig" modJk="/path/to/mod_jk.so" />
      ...
    </Engine>
    ...
    

    Then restart Tomcat and mod_jk.conf should be generated. For more information on this topic, please refer to the API documentation at the Tomcat docs website.

    Custom mod_jk configuration

    You should use custom configuration when:

    • You couldn't use mod_jk.conf-auto since Tomcat engine isn't on the same machine that your Apache web server, ie when you have an Apache in front of a Tomcat Farm.
    • Another case for custom configuration is when your Apache is in front of many different Tomcat engines, each one having it's own configuration, a general case in ISP hosting
    • Also most Apache web masters will retain custom configuration to be able to tune the settings to their real needs.

    Simple configuration example

    Here is a simple configuration:

    # Load mod_jk module
    LoadModule    jk_module  modules/mod_jk.so
    # Add the module (activate this lne for Apache 1.3)
    # AddModule     mod_jk.c
    # Where to find workers.properties
    JkWorkersFile /etc/httpd/conf/workers.properties
    # Where to put jk shared memory
    JkShmFile     /var/log/httpd/mod_jk.shm
    # Where to put jk logs
    JkLogFile     /var/log/httpd/mod_jk.log
    # Set the jk log level [debug/error/info]
    JkLogLevel    info
    # Send requests for context /examples to worker named worker1
    JkMount  /examples/* worker1
    

    mod_jk Directives

    We'll discuss here the mod_jk directives and details behind them

    Define workers

    JkWorkersFile specify the location where mod_jk will find the workers definitions.

    JkWorkersFile     /etc/httpd/conf/workers.properties
    

    Logging

    JkLogFile specify the location where mod_jk is going to place its log file.

    JkLogFile     /var/log/httpd/mod_jk.log
    

    Since JK 1.2.3 for Apache 2.x and JK 1.2.16 for Apache 1.3 this can also be used for piped logging:

    JkLogFile     "|/usr/bin/rotatelogs /var/log/httpd/mod_jk.log 86400"
    

    JkLogLevel set the log level between:

    • info log will contains standard mod_jk activity (default).
    • error log will contains also error reports.
    • debug log will contains all information on mod_jk activity
    JkLogLevel    info
    

    info should be your default selection for normal operations.

    JkLogStampFormat will configure the date/time format found on mod_jk logfile. See the mod_jk Apache HTTP Server reference for details.

    JkLogStampFormat "[%y-%m-%d %H:%M:%S.%Q] "
    

    You can log mod_jk information using the Apache standard module mod_log_config. The module sets several notes in the Apache notes table. Most of them are are only useful in combination with a load balancer worker. See the mod_jk Apache HTTP Server reference for details.

    LogFormat     "%h %l %u %t \"%r\" %>s %b %{JK_WORKER_NAME}n %{JK_LB_FIRST_NAME}n \
                  %{JK_LB_FIRST_BUSY}n %{JK_LB_LAST_NAME}n %{JK_LB_LAST_BUSY}n" mod_jk_log
    CustomLog     logs/access_log     mod_jk_log
    

    You can also log a request protocol in the mod_jk log file instead of the access log. This is not recommended and mostly a backward compatibility feature. The directive JkRequestLogFormat will configure the format of this protocol. It gets configured and enabled on a per virtual host basis. See the mod_jk Apache HTTP Server reference for details.

    JkRequestLogFormat     "%w %V %T"
    

    Forwarding

    The directive JkOptions allow you to set many forwarding options which will enable (+) or disable (-) following option. Without any leading signs, options will be enabled.

    The four following options +ForwardURIxxx are mutually exclusive. Exactly one of them is required, a negative sign prefix is not allowed with them. The default value is "ForwardURIProxy" since version 1.2.24. It was "ForwardURICompatUnparsed" in version 1.2.23 and "ForwardURICompat" until version 1.2.22. You can turn the default off by switching on one of the other two options. You should leave this at it's default value, unless you have a very good reason to change it.

    All options are inherited from the global server to virtual hosts. Options that support enabling (plus options) and disabling (minus options), are inherited in the following way:
    options(vhost) = plus_options(global) - minus_options(global) + plus_options(vhost) - minus_options(vhost)

    Using JkOptions ForwardURIProxy, the forwarded URI will be partially reencoded after processing inside Apache and before forwarding to Tomcat. This will be compatible with local URL manipulation by mod_rewrite and with URL encoded session ids.

    JkOptions     +ForwardURIProxy
    

    Using JkOptions ForwardURICompatUnparsed, the forwarded URI will be unparsed. It's spec compliant and secure. It will always forward the original request URI, so rewriting URIs with mod_rewrite and then forwarding the rewritten URI will not work.

    JkOptions     +ForwardURICompatUnparsed
    

    Using JkOptions ForwardURICompat, the forwarded URI will be decoded by Apache. Encoded characters will be decoded and explicit path components like ".." will already be resolved. This is less spec compliant and is not safe if you are using prefix JkMount. This option will allow to rewrite URIs with mod_rewrite before forwarding.

    JkOptions     +ForwardURICompat
    

    Using JkOptions ForwardURIEscaped, the forwarded URI will be the encoded form of the URI used by ForwardURICompat. Explicit path components like ".." will already be resolved. This will not work in combination with URL encoded session IDs, but it will allow to rewrite URIs with mod_rewrite before forwarding.

    JkOptions     +ForwardURIEscaped
    

    JkOptions RejectUnsafeURI will block all URLs, which contain percent signs '%' or backslashes '\' after decoding.

    Most web apps do not use such URLs. Using the option RejectUnsafeURI, you can block several well known URL encoding attacks. By default, this option is not set.

    You can also realise such a check with mod_rewrite, which is more powerful but also slightly more complicated.

    JkOptions     +RejectUnsafeURI
    

    JkOptions CollapseSlashesAll is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions CollapseSlashesUnmount is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions CollapseSlashesNone is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions ForwardDirectories is used in conjunction with DirectoryIndex directive of Apache. As such mod_dir should be available to Apache, statically or dynamically (DSO)

    When DirectoryIndex is configured, Apache will create sub-requests for each of the local-url's specified in the directive, to determine if there is a local file that matches (this is done by stat-ing the file).

    If ForwardDirectories is set to false (default) and Apache doesn't find any files that match, Apache will serve the content of the directory (if directive Options specifies Indexes for that directory) or a 403 Forbidden response (if directive Options doesn't specify Indexes for that directory).

    If ForwardDirectories is set to true and Apache doesn't find any files that match, the request will be forwarded to Tomcat for resolution. This is used in cases when Apache cannot see the index files on the file system for various reasons: Tomcat is running on a different machine, the JSP file has been precompiled etc.

    Note that locally visible files will take precedence over the ones visible only to Tomcat (i.e. if Apache can see the file, that's the one that's going to get served). This is important if there is more then one type of file that Tomcat normally serves - for instance Velocity pages and JSP pages.

    JkOptions     +ForwardDirectories
    

    Setting JkOptions ForwardLocalAddress, you ask mod_jk to send the local address of the Apache HTTP Server instead of remote client address. This can be used by Tomcat remote address valve for allowing connections only from configured Apache servers.

    JkOptions     +ForwardLocalAddress
    

    Setting JkOptions ForwardPhysicalAddress, you ask mod_jk to send the physical peer TCP IP address as the client address. By default mod_jk uses the logical address as provided by the web server. For example the module mod_remoteip sets the logical IP address to the client IP forwarded by proxies in the X-Forwarded-For header.

    JkOptions     +ForwardPhysicalAddress
    

    JkOptions FlushPackets, you ask mod_jk to flush Apache's connection buffer after each AJP packet chunk received from Tomcat. This option can have a strong performance penalty for Apache and Tomcat as writes are performed more often than would normally be required (ie: at the end of each response).

    JkOptions     +FlushPackets
    

    JkOptions FlushHeader, you ask mod_jk to flush Apache's connection buffer after the response headers have been received from Tomcat.

    JkOptions     +FlushHeader
    

    JkOptions DisableReuse, you ask mod_jk to close connections immediately after their use. Normally mod_jk uses persistent connections and pools idle connections to reuse them, when new requests have to be sent to Tomcat.

    Using this option will have a strong performance penalty for Apache and Tomcat. Use this only as a last resort in case of unfixable network problems. If a firewall between Apache and Tomcat silently kills idle connections, try to use the worker attribute socket_keepalive in combination with an appropriate TCP keepalive value in your OS.

    JkOptions     +DisableReuse
    

    JkOptions ForwardKeySize, you ask mod_jk, when using ajp13, to forward also the SSL Key Size as required by Servlet API 2.3. This flag shouldn't be set when servlet engine is Tomcat 3.2.x (off by default).

    JkOptions     +ForwardKeySize
    

    JkOptions ForwardSSLCertChain, you ask mod_jk, when using ajp13, to forward SSL certificate chain (off by default). Mod_jk only passes the SSL_CLIENT_CERT to the AJP connector. This is not a problem with self-signed certificates or certificates directly signed by the root CA certificate. However, there's a large number of certificates signed by an intermediate CA certificate, where this is a significant problem: A servlet will not have the possibility to validate the client certificate on its own. The bug would be fixed by passing on the SSL_CLIENT_CERT_CHAIN to Tomcat via the AJP connector.
    This directive exists only since version 1.2.22.

    JkOptions     +ForwardSSLCertChain
    

    The directive JkEnvVar allows you to forward environment variables from Apache server to Tomcat engine. You can add a default value as a second parameter to the directive. If the default value is not given explicitly, the variable will only be send, if it is set during runtime.
    The variables can be retrieved on the Tomcat side as request attributes via request.getAttribute(attributeName). Note that the variables send via JkEnvVar will not be listed in request.getAttributeNames().
    The variables are inherited from the global server to virtual hosts.

    JkEnvVar     SSL_CLIENT_V_START     undefined
    

    Assigning URLs to Tomcat

    If you have created a custom or local version of mod_jk.conf-local as noted above, you can change settings such as the workers or URL prefix.

    JkMount directive assign specific URLs to Tomcat. In general the structure of a JkMount directive is:

    JkMount [URL prefix] [Worker name]
    # send all requests ending in .jsp to worker1
    JkMount /*.jsp worker1
    # send all requests ending /servlet to worker1
    JkMount /*/servlet/ worker1
    # send all requests jsp requests to files located in /otherworker will go worker2
    JkMount /otherworker/*.jsp worker2
    

    You can use the JkMount directive at the top level or inside <VirtualHost> sections of your httpd.conf file.

    Configuring Apache to serve static web application files

    If the Tomcat Host appBase (webapps) directory is accessible by the Apache HTTP Server, Apache can be configured to serve web application context directory static files instead of passing the request to Tomcat.

    Caution: For security reasons it is strongly recommended that JkMount is used to pass all requests to Tomcat by default and JkUnMount is used to explicitly exclude static content to be served by Apache. It should also be noted that content served by Apache will bypass any security constraints defined in the application's web.xml.

    Use Apache's Alias directive to map a single web application context directory into Apache's document space for a VirtualHost:

    # Static files in the examples webapp are served by Apache
    Alias /examples /vat/tomcat3/webapps/examples
    # All requests go to worker1 by default
    JkMount /* worker1
    # Serve html, jpg and gif using Apache
    JkUnMount /*.html worker1
    JkUnMount /*.jpg  worker1
    JkUnMount /*.gif  worker1
    

    Starting with mod_jk 1.2.6 for Apache 2.x and 1.2.19 for Apache 1.3, it's possible to exclude some URL/URI from jk processing by setting the env var no-jk, for example with the SetEnvIf Directive.

    You could use no-jk env var to fix problem with mod_alias or mod_userdir directive when jk and alias/userdir URLs matches.

    # All URL goes to tomcat except the one containing /home
    <VirtualHost *:80>
        ServerName testxxx.mysys
        DocumentRoot /www/testxxx/htdocs
    
    # Use SetEnvIf to set no-jk when /home/ is encountered
        SetEnvIf Request_URI "/home/*" no-jk
    
    # Now /home will goes to /home/dataxxx/
        Alias /home /home/dataxxx/
    
        <Directory "/home/dataxxx">
            Options Indexes MultiViews
            AllowOverride None
            Require all granted
        </Directory>
    
        JkMount /* myssys-xxx
    
    </VirtualHost>
    

    Use the mod_jk JkAutoAlias directive to map all web application context directories into Apache's document space.

    Attempts to access the WEB-INF or META-INF directories within a web application context or a Web Archive *.war within the Tomcat Host appBase (webapps) directory will fail with an HTTP 403, Access Forbidden

    # Static files in all Tomcat webapp context directories are served by Apache
    JkAutoAlias /var/tomcat3/webapps
    
    # All requests go to worker1 by default
    JkMount /* ajp13
    # Serve html, jpg and gif using Apache
    JkUnMount /*.html ajp13
    JkUnMount /*.jpg  ajp13
    JkUnMount /*.gif  ajp13
    

    If you encoded all your URLs to contain the session id (;jsessionid=...), and you later decide, you want to move part of the content to Apache, you can tell mod_jk to strip off all session ids from URLs for those requests, that do not get forwarded via mod_jk.

    You enable this feature by setting JkStripSession to On. It can be enabled individually for virtual servers. The default value is Off.

    Building mod_jk on Unix

    The mod_jk build use the widely used configure system.

    Prepare your mod_jk configure from subversion

    In case you get source from subversion, ie without an existing configure script, you should have autoconf for configuration and installation.

    To create the mod_jk autoconf script, you will need libtool 1.5.2, automake 1.10 and autoconf 2.59 or newer. The use of more recent versions is encouraged, e.g. for reliable detection of the features of recent version of operating systems.

    Those tools will not be required if you are just using a package downloaded from apache.org, they are only required for developers.

    To create the configure script just type: ./buildconf.sh

    Using configure to build mod_jk

    Here's how to use configure to prepare mod_jk for building, just type:

    ./configure [autoconf arguments] [mod_jk arguments]
    

    You could set CFLAGS and LDFLAGS to add some platform specifics:

    LDFLAGS=-lc ./configure -with-apxs=/home2/local/apache/bin/apxs

    If you want to build mod_jk for different versions of the Apache HTTP Server, like 1.3 or 2.x, you need to go through the full build process for each of them. Please note, that Apache 2.0, 2.2 or 2.4 modules are not binary compatible. You have to compile the module using the Apache version you plan to run it in. The mod_jk build directory used is "apache-2.0" for all 2.x builds. The source code is compatible with Apache HTTP Server 2.0, 2.2 and 2.4.

    • use configure and indicate the correct Apache HTTP Server apxs location (--with-apxs)
    • use make
    • copy the resulting mod_jk.so binary from the apache-1.3 or apache-2.0 subdirectory to the Apache HTTP Server modules location.
    • make clean (to remove all previously compiled object files)
    • Start over with the apxs location for your next Apache HTTP Server version.

    configure arguments

    Apache related parameters
    --with-apxs[=FILE] FILE is the location of the apxs tool. Default is finding apxs in PATH. It builds a shared Apache module. It detects automatically the Apache version. (2.x and 1.3)
    --with-apache=DIR DIR is the path where Apache sources are located. The Apache sources should have been configured before configuring mod_jk. DIR is something like: /home/apache/apache_1.3.19 It builds a static Apache module.
    --enable-EAPI This parameter is needed when using Apache-1.3 and mod_ssl, otherwise you will get the error message: "this module might crash under EAPI!" when loading mod_jk.so in Apache. Not needed when --with-apxs has been used
    --enable-prefork In case you build mod_jk for a multi-threaded Apache HTTP Server 2.x MPM (Multi-Processing Module), some areas of mod_jk code need to be synchronised to make it thread-safe. Because configure can not easily detect, whether your are using a multi-threaded MPM, mod_jk by default is always build thread-safe for Apache HTTP Server 2.x. If you are sure, that your MPM is not multi-threaded, you can use "--enable-prefork" to force the removal of the synchronisation code (thus increasing performance a bit). For instance, the prefork MPM is not multi-threaded. For Apache HTTP Server 1.3 this flag will be set automatically.
    --disable-trace When using log level "trace", mod_jk traces a lot of function calls with "enter" and "exit" log messages. Even if the log level is not "trace", comparing the log levels to decide about logging has some performance impact.
    If you use "--disable-trace", then the trace log code doesn't get compiled into the module binary and you might save some cycles during execution.
    Even with "--disable-trace" logging debug messages with debug log level will still be possible.
    --enable-api-compatibility Only use Apache API functions available in all Apache production releases of the chosen major Apache release branch. This improves binary compatibility of module builds with Apache releases older than the release against mod_jk is build (only between minor Apache versions).
    --enable-flock In case the operating system supports flock system call use this flag to enable this faster locks that are implemented as system call instead emulated by GNU C library.
    However those locks does not work on NFS mounted volumes, so you can use "--enable-flock" during compile time to force the flocks() calls.

    Examples of configure use

    Apache 1.3 and 2.x build ./configure --with-apxs=/usr/sbin/apxs
    make
    cp ./apache-1.3/mod_jk.so /usr/lib/apache
    make clean
    ./configure --with-apxs=/usr/sbin/apxs2
    make
    cp ./apache-2.0/mod_jk.so /usr/lib/apache2

    Building mod_jk for Apache on Windows

    The module was developed using Microsoft Visual C++, so having Visual Studio installed is a prerequisite if you want to perform your own build.

    You can build the source using the IDE GUI, or using a pure commandline build based on nmake. The IDE build currently only supports building 32 Bit binaries. The nmake builds are available for 32 Bit and 64 Bit binaries.

    The common steps for all build procedures are:

    • Set up your build environment for 32 Bits or 64 Bits. The IDE build only supports 32 Bits.
    • Download the sources as a zip file and unpack it.
    • Change directory to the ISAPI redirector source directory.
    • Set your path to the Apache web server directory in your environment.
    Set up 32 or 64 Bit build environment setenv /Release /X86 or (not available for IDE build) setenv /Release /X64 Download tomcat-connectors-xxx-src.zip from https://tomcat.apache.org/download-connectors.cgi and unpack it unzip tomcat-connectors-xxx-src.zip Change directory to the mod_jk source directory. To build mod_jk for the Apache HTTP server 2.0, 2.2 or 2.4, use the "apache-2.0" directory, for the old Apache HTTP server 1.3, the "apache-1.3" directory. cd tomcat-connectors-xxx-src\native\apache-2.0 Set the environment variable "APACHE1_HOME" resp. "APACHE2_HOME" resp. "APACHE22_HOME" resp. "APACHE24_HOME" to the installation path of your Apache web server. set APACHE24_HOME=D:\software\Apache\httpd-2.4.16

    The steps for an IDE build are then:

    • Start Visual Studio using "start mod_jk.dsp"
    • During IDE startup choose "Yes" in all conversion popups.
    • Next choose a Configuration form the dropdown. There are pre-defined configurations for debug and release builds and in the "apache-2.0" directory each of them is available as a configuration to build against the web server versions 2.0, 2.2 and 2.4.
    • Finally choose "Build Solution" in the "Build" menu.
    The resulting file mod_jk.so (and the debug symbol file mod_jk.pdb) is located in the "Debug" resp. "Release" sub directory depending on the build Configuration chosen. For the "apache-2.0" module the directories are named "Debug_20", "Release_20", "Debug_22", "Release_22", "Debug_24" and "Release_24" depending on the chosen build configuration.

    Alternatively the steps for an nmake commandline build are:

    • Set your target architecture to X86 or X64 by editing the "ARCH=" line in the file Makefile.vc.
    • Issue "nmake -f Makefile.vc"
    The resulting file mod_jk.so (and the debug symbol file mod_jk.pdb) is located in the "Debug" resp. "Release" sub directory depending on the build Configuration chosen. For the "apache-2.0" module the directories are named "Debug_20", "Release_20", "Debug_22", "Release_22", "Debug_24" and "Release_24" depending on the chosen build configuration.

    Finally you need to copy the file mod_jk.so to the modules directory of your Apache HTTP server (resp. the libexec directory for the old Apache 1.3).

    For Apache HTTP Server 1.3, ApacheCore.lib is expected to exist before linking mod_jk will succeed.

    Building mod_jk for Apache on System I - i5/OS (OS400)

    Since OS400 V4R5, System I (AS/400) has used Apache 2.0 as their primary web server, replacing the old IBM web server. It's now possible to build mod_jk on System I thanks to the help of the IBM Rochester Labs which has provided information and patches to adapt mod_jk to i5/OS.

    You should have at least Apache 2.0.58 (product 5722DG1), a C Compiler and IFS. Apache 2.0.58 is provided with the most recent set of PTFs for the iSeries Apache server, which can be found at http://www.ibm.com/servers/eserver/iseries/software/http/

    The all latest Apache 2 for i5/OS V5R3 (or V5R4) is now 2.0.58 (as of 2007/04/17). Be sure to have the latest PTFs loaded if you want to make use of jk 1.2.15 and higher. NB: The latest mod_jk known to work on i5/OS V5R3 was 1.2.19.

    New in i5/OS V5R4, UTF is required, also for Apache modules, as such Apache modules do not require translations to/from EBCDIC but works should be done to port mod_jk 1.2.23 (and higher) to V5R4. From the V5R4 Infocenter: As of i5/OS(tm) V5R4, modules must be recompiled with a UTF locale. This creates an environment where locale-dependent C runtime functions assume that string data is encoded in UTF-8. Any hardcoded constants can be encoded in UTF-8 by adding a #pragma convert(1208) statement in the module. Additionally, input data from the client will no longer be converted to EBCDIC but will be passed as-is. Output data sent from the module is not converted either so it must be encoded in ASCII or UTF8 as required. APR and HTTP APIs as of V5R4, expect data in UTF-8. Note that several APIs have additional functions that allow a CCSID to be set to indicate the encoding of the parameters being passed. Conversion functions between UTF-8 and EBCDIC have been added. Be sure to review APIs used by your module to be aware of current changes.

    To configure mod_jk on System I use the CL source provided with the mod_jk source.

    • Get the latest mod_jk source and untar it on a Windows or Unix boxes
    • Create a directory in IFS, ie /home/apache
    • Send the whole jk source directory to System I directory via FTP.
    • Then go to the System I command line:
    Create mod_jk library CRTLIB MOD_JK TEXT(‘Apache mod'jk tomcat connector module') Create service program source file CRTSRCPF MOD_JK/QSRVSRC TEXT(‘Service program source file’) Create the CL build program source file CRTSRCPF FILE(MOD_JK/QCLSRC) TEXT(‘Build program source file’) Edit the service program source file STRSEU MOD_JK/QSRVSRC MOD_JK

    In the edited file, specify that only jk_module should be exported: Columns . . : 1 71 Edit MOD_JK/QSRVSRC SEU==> MOD_JK *************** Beginning of data ************************************* 0001.00 STRPGMEXP PGMLVL(*CURRENT) 0002.00 EXPORT SYMBOL("jk_module") 0003.00 ENDPGMEXP ****************** End of data ****************************************

    You could start to build all the modules of mod_jk (cases for V5R4 or previous releases):

    Copy the CL build program source for i5/OS before V5R4 from IFS CPYFRMSTMF FROMSTMF('/home/apache/jk/native/apache-2.0/bldjk.qclsrc') + TOMBR('/QSYS.LIB/MOD_JK.LIB/QCLSRC.FILE/BLDJK.MBR') MBROPT(*REPLACE) Build the CL build program CRTCLPGM PGM(MOD_JK/BLDJK) SRCFILE(MOD_JK/QCLSRC) TEXT('Apache mod_jk build program') Launch the build CALL MOD_JK/BLDJK
    If the build if successfull, copy the new mod_jk module CRTDUPOBJ OBJ(MOD_JK) FROMLIB(MOD_JK) OBJTYPE(*SRVPGM) TOLIB(QHTTPSVR) NEWOBJ(MOD_JK)
    Copy the CL build program source for i5/OS V5R4 from IFS CPYFRMSTMF FROMSTMF('/home/apache/jk/native/apache-2.0/bldjk54.qclsrc') + TOMBR('/QSYS.LIB/MOD_JK.LIB/QCLSRC.FILE/BLDJK54.MBR') MBROPT(*REPLACE) Build the CL build program for i5/OS V5R4 CRTCLPGM PGM(MOD_JK/BLDJK54) SRCFILE(MOD_JK/QCLSRC) TEXT('Apache mod_jk build program') TGTRLS(*CURRENT) Launch the build for i5/OS V5R4 CALL MOD_JK/BLDJK54
    If the build if successfull, copy the new mod_jk module CRTDUPOBJ OBJ(MOD_JK) FROMLIB(MOD_JK) OBJTYPE(*SRVPGM) TOLIB(QHTTPSVR) NEWOBJ(MOD_JK)

    Next, you should restart your Apache 2.0 instance and enjoy this piece of OpenSource on System I.

    ENDTCPSVR SERVER(*HTTP) HTTPSVR(MYSERVER) STRTCPSVR SERVER(*HTTP) HTTPSVR(MYSERVER)

    Building mod_jk for Apache on MacOS/X

    Mac OS X (10.2.x) build notes:

    Assuming that you are root:

    For Apache 1.3: ./configure --with-apxs=/usr/sbin/apxs cd apache-1.3 make -f Makefile.apxs cp mod_jk.so /etc/libexec/httpd For Apache 2.x: ./configure --with-apxs=/usr/local/apache2/bin/apxs (you should point to the directory where you installed Apache 2.x) cd apache-2.0 make -f Makefile.apxs install

    Getting mod_jk linked statically with Apache

    mod_jk allows to install mod_jk in the Apache source tree to get a statically linked mod_jk. Having mod_jk in the Apache executable brings some small performance improvements. The configure option --with-apache prepare mod_jk to install it in the Apache source tree. The option --with-apache works both for Apache 1.3 and Apache 2.x. The examples below show how to get mod_jk in the Apache process.

    Installation for Apache-2.x

    /home/apache24/httpd-2.4.12 is the directory where the Apache HTTP Server sources are located. ./configure --with-apache=/home/apache24/httpd-2.4.12
    make
    Install the mod_jk library and other files in /home/apache24/httpd-2.4.12/modules: make install
    It is not possible to configure Apache directly because the config.m4 of mod_jk must be added to the configure of httpd-2.x. cd /home/apache24/httpd-2.4.12 sh buildconf configure ... --with-mod_jk make make install

    The enable-jk=share and enable-jk=static are not supported. --with-mod_jk only allow static linking of mod_jk.

    Installation for Apache-1.3

    /home/apache/apache_1.3.27 is the directory where the apache-1.3 sources are located. ./configure --with-apache=/home/apache/apache_1.3.27
    make
    Install the libjk library, mod_jk.c, includes and other files in /home/apache/apache_1.3.27/src/modules/jk: make install
    Configure in the Apache sources: cd /home/apache/apache_1.3.27 configure ... --enable-module=dir --disable-shared=dir \ --activate-module=src/modules/jk/libjk.a \ --disable-shared=jk make make install

    The --enable-shared=jk is also working and builds a dso file.

    Just change the configure in the Apache sources: configure ... --enable-module=dir --enable-shared=dir \ --activate-module=src/modules/jk/libjk.a \ --enable-shared=jk
    tomcat-connectors-1.2.50-src/docs/index.html0000644000000000000020000002605514655113621017254 0ustar rootbin The Apache Tomcat Connectors: mod_jk, ISAPI redirector, NSAPI redirector (1.2.50) - Documentation Overview

    Documentation Overview

    Introduction

    The Apache Tomcat Connectors project is part of the Tomcat project and provides web server plugins to connect web servers with Tomcat and other backends.

    The supported web servers are:

    • the Apache HTTP Server with a plugin (module) named mod_jk.
    • Microsoft IIS with a plugin (extension) named ISAPI redirector (or simply redirector).

    In all cases the plugin uses a special protocol named Apache JServ Protocol or simply AJP to connect to the backend. Backends known to support AJP are Apache Tomcat, Jetty and JBoss. Although there exist 3 versions of the protocol, ajp12, ajp13, ajp14, most installations only use ajp13. The older ajp12 does not use persistent connections and is obsolete, the newer version ajp14 is still experimental. Sometimes ajp13 is called AJP 1.3 or AJPv13, but we will mostly use the name ajp13.

    Most features of the plugins are the same for all web servers. Some details vary on a per web server basis. The documentation and the configuration is split into common parts and web server specific parts.

    down to the more detailed documentation that is available. Each available manual is described in more detail below.

    Headlines

    • JK-1.2.50 released

      The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.50 Stable. This release contains improvements and bug fixes for issues found in previous releases.

      Download the JK 1.2.50 release.

    • Download previous releases from the archives.

    Reference Guide

    • workers.properties

      A Tomcat worker is a Tomcat instance that is waiting to execute servlets on behalf of some web server. For example, we can have a web server such as Apache forwarding servlet requests to a Tomcat process (the worker) running behind it.

      This page contains detailed description of all workers.properties directives.

    • uriworkermap.properties

      The forwarding of requests from the web server to tomcat gets configured by defining mapping rules. The so-called uriworkermap file is a mechanism of defining those rules.

    • Status Worker

      The status worker is a builtin management worker. It displays state information and can also be used to dynamically reconfigure JK.

    • Apache HTTP Server (mod_jk)

      This page contains detailed description of all directives of mod_jk for the Apache HTTP Server.

    • Microsoft IIS (ISAPI redirector)

      This page contains detailed description of all directives of the ISAPI redirector for Microsoft IIS.

    Common HowTo

    • Quick Start

      This page describes the configuration files used by JK on the web server side for the 'impatient'.

    • All about workers

      This page contains an overview about the various aspects of defining and using workers.

    • Timeouts

      This page describes the possible timeout settings you can use.

    • Load Balancing

      This page contains an introduction on load balancing with JK.

    • Reverse Proxy

      This page contains an introduction to reverse proxies, how JK handles this situation and how you can influence the JK proxying behaviour.

    Webserver HowTo

    These pages contain detailed descriptions of how to build and install JK for the various web servers.

    AJP Protocol Reference

    • AJPv13

      This page describes the Apache JServ Protocol version 1.3 (hereafter ajp13).

    • AJPv13 Extension Proposal

      This page describes an extension proposal for ajp13.

    Miscellaneous documentation

    tomcat-connectors-1.2.50-src/docs/miscellaneous/0000755000000000000020000000000014655113620020111 5ustar rootbintomcat-connectors-1.2.50-src/docs/miscellaneous/doccontrib.html0000644000000000000020000003316514655113620023135 0ustar rootbin The Apache Tomcat Connectors - Miscellaneous Documentation (1.2.50) - How to Contribute to the Documentation

    How to Contribute to the Documentation

    Introduction

    This document describes how you can easily contribute to the documentation. I'm going to try to make it easy for everyone to help out with the documentation of Tomcat, more specifically the documentation for the connectors. This is written from a windows user perspective as I believe they will most benefit from it. For people using Unix it should be easy for them to apply these steps. Just substitute Unix syntax where needed.

    The documentation is produced using xml with xsl style sheets. This effectivly seperates the content of the documents from the style, so all that contributers need to worry about the content. It is much easier to use than html.

    It's all really quite simple. Here is what you will need:

    • A recent version of Ant
    • The source code for the connectors from subversion
    • Any ascii text editor

    Getting Started Step by Step

    After you get these tools they are simple to set up.

    STEP 1. Get Ant

    Install Ant. The only advice I have is to choose a simple installation path. Now set an environment variable for ANT_HOME, and then add the location of the Ant/bin directory to your PATH variable. Consult your Operating system documentation for information on how to do this. When you are finished verify that you can run ant from the command line.

    Ant is used to build the documentation, among other things, and it must be able to see a file called build.xml. This file is located in the xdocs directory. In the build.xml file there is a target named all that will be used to build the docs.

    STEP 2. Get the sources

    Get the sources for tomcat-connectors from the git repository. You will need a git client. Install the client of your choice, if you don't already have one.

    You are ready to download the sources now. Change directory to the location where you want your repository to be. For simplicity we will call this your GIT_HOME. Mine is located in C:\build.

    Run the following command to clone the sources for the first time. You should only need to do this once.

    C:\build\>git clone https://github.com/apache/tomcat-connectors tomcat-connectors
    

    You should now be watching all the downloads come in. Now that you have the sources on your machine the hard part is over. From now on, to update your sources all you have to do is cd into any directory in your repository and run the git pull command.

    STEP 3. Test your build environment

    Open a command prompt window and cd to the directory where you downloaded the source. Now cd into the xdocs directory so that Ant can see the build.xml file. Then from a command prompt, run the following:

    C:\build\tomcat-connectors> cd xdocs
    C:\build\tomcat-connectors\xdocs> ant all
    

    .

    You should see the ant compiler messages scrolling by rapidly and then stop with the following:

    [style] Transforming into C:\build\tomcat-connectors\build\docs\news\printer>
    [style] Processing C:\build\tomcat-connectors\xdocs\news\20041100.xml 
    to
    C:\build\tomcat-connectors\build\docs\news/20041100.html
    [style] Loading stylesheet C:\build\tomcat-connectors\xdocs\style.xsl
    [style] Processing C:\build\tomcat-connectors\xdocs\news\20050101.xml 
    to
    C:\build\tomcat-connectors\build\docs\news/20050101.html
    [style] Processing C:\build\tomcat-connectors\xdocs\news\20060101.xml 
    to
    C:\build\tomcat-connectors\build\docs\news/20060101.html
    [style] Transforming into C:\build\tomcat-connectors\build\docs>
    [style] Processing C:\build\tomcat-connectors\xdocs\index.xml 
    to
    C:\build\tomcat-connectors\build\docs\index.html
    [style] Loading stylesheet C:\build\tomcat-connectors\xdocs\style.xsl
     
    BUILD SUCCESSFUL
    Total time: 10 seconds
    C:\build\tomcat-connectors>
    

    All the xml files present in the xdocs directory structure were transformed to html and copied to the GIT_HOME\tomcat-connectors\build\docs directory. Open one of the html files in your browser and see how it looks.

    STEP 4. The editing process.

    I find it easier to use two windows while doing my updates. One I call my build window. I keep this one in the GIT_HOME\tomcat-connectors\xdocs directory and I only run two commands in this window: First I run

    ant clean
    
    Then I run
    ant all
    

    My second window I call my edit window and I keep that one in the GIT_HOME\tomcat-connectors\xdocs directory where I'm doing my edits, diffs and git pulls.

    Before you start editing you should always update your local repository to prevent conflicts.

    C:\build\tomcat-connectors> git pull
    

    Now that your repository is up to date you can begin editing. Find something in the documentation to edit. When you find something remember the name of the file. In your edit window find and edit the xml source file with the same name. After you are done return to the build window, and in the GIT_HOME\tomcat-connectors\xdocs directory run:

    C:\build\tomcat-connectors\xdocs> ant clean
    

    This will delete all the previous html files and make the area ready for updated material. Now to make fresh documents that incorporate your changes run:

    C:\build\tomcat-connectors\xdocs> ant all
    

    Use your browser to view the edits you just made, they will be in the GIT_HOME\tomcat-connectors\build\docs sub-tree. If it looks good and is ready to go, all that is left to do is to create a patch and submit it.

    STEP 5. Creating a patch and submitting it.

    From your edit window cd into the directory that contains the xml file you are working on, and run the git pull command. For example, to produce a diff of the index.xml file and call it patch.txt, you would cd into the directory containing the index.xml file and:

    C:\build\tomcat-connectors\xdocs\>git diff index.xml >  
    patch.txt.
    

    Now that you have your patch you are ready to send it in.

    Patches to the documentation are handled just like a bug report. You should submit your patches to http://issues.apache.org/bugzilla/ and include a good one line subject. If this is your first time to use the bug database then you should read http://issues.apach e.org/bugzilla/bugwritinghelp.html. You will need to create a user account. At the web site paste your patch into the web form and don't forget to describe what it is your patch is for. Sooner or later a someone with commit privileges will review your suggestion.

    Updating Web site

    Only Committers are able to update the web site (http://tomcat.apache.org/connectors-doc/). To do it:

    • Connect to people.apache.org.
    • umask 002
    • Copy the changed files to /www/tomcat.apache.org/connectors-doc/.
    • or use ant from a checkout tomcat/jk/trunk/xdocs repository:
      ant -Dbuild.dir=/www/tomcat.apache.org -Ddist.name=connectors-doc
    • The changes should sync to tomcat.apache.org within seconds.

    Guides and Resources

    tomcat-connectors-1.2.50-src/docs/miscellaneous/faq.html0000644000000000000020000004173714655113620021562 0ustar rootbin The Apache Tomcat Connectors - Miscellaneous Documentation (1.2.50) - Frequently Asked Questions

    Frequently Asked Questions

    General

    General Informations and FAQ about JK

    Where can I get help/support for JK ?

    The primary mechanism for support is through the JK documentation included in the doc directory. Documentation is also available on the Apache Tomcat web site devoted to the Apache Tomcat Connectors Project For additional help, the best resource is the Tomcat Users Discussion list. You should start by searching the mail list archive before you post questions to the list. If you are unable to locate the answer to your question in the archive, you can post questions about JK to the user list for assistance. Make sure that you include the version of your web server, that you are using as well as the platform you are running on and go here to determine how to subscribe to tomcat mailing list.

    I can't find JK anywhere. Where is it?

    Now that JK moved to the tomcat-connectors repository, the source and the binaries for JK can be downloaded from a mirror at the Tomcat Connectors (mod_jk) Downloads page.

    What's the difference between JK and mod_jk ?

    JK is a project covering web servers to Tomcat connectors.

    Apache HTTP Server support is implemented on JK, using a plugin called the mod_jk module.

    Microsoft IIS support is implemented on JK, using a plugin called the ISAPI redirector.

    Where can I get more information ?

    For JK 1.2.x, you should read:

    For more detailed information, have a look at the Reference Guide. You could also try searching the mailing list archives for "JK" or look at the source.

    Which protocol should I use - ajp12, ajp13 or ajp14?

    ajp13 is the standard. The old ajp12 is deprecated and ajp14 is experimental.

    Also ajp13 is supported by all Apache Tomcat versions starting with Tomcat 3.2 and by other servlet engines like Jetty and JBoss.

    I've got a firewall between my web server and Tomcat which drops ajp13 connections after some time

    The ajp13 protocol uses persistant connections where the traffic could be null if there is no request to be sent to Tomcat. Firewalls use to drop inactive connections and will make your web server and Tomcat think the connection is valid.

    Starting with JK 1.2.0, a socket_keepalive property as been added to ajp13 settings, and you should take a look at it in Workers HowTo and workers.properties reference. If nothing else helps, you can try JkOptions +DisableReuse, but this will have strong performance implications.

    Under heavy load, I've got many threads in Tomcat even if my Apache HTTP Server handles much of the load

    Under heavy load, the Apache HTTP Server creates many children to handle the load, which will in turn create many connections to Tomcat to forward the requests they should handle. The Apache HTTP Server will normally kill the children/threads when the load decreases. But if the load is still there and even if only Apache handles the requests, ie static contents, the children are kept and with them all the ajp13 connections, even if they are no more used.

    To close connections after some time of inactivity you can use connection_pool_timeout, for more informations refer to workers.properties reference.

    Apache HTTP Server

    Informations and FAQ about mod_jk and the Apache HTTP Server.

    Whenever I restart Tomcat, Apache locks up!

    The ajp13 protocol keeps an open socket between Tomcat and Apache. Release of mod_jk present in Tomcat Connectors handles the network failure. But with very ancient releases of mod_jk, you may have to restart Apache as well.

    Why do there exist two files mod_jk.so (-eapi ad -noeapi) in download directories for Apache 1.3?

    Many versions of Apache use a modified API, known at Extended API, developed for use with the mod_ssl module. Starting with Apache 2.0 there is no more difference.

    For example, Apache 1.3 present in certains recent Linux distributions include the mod_ssl module.

    So if you got such 'Extended Apache', you need to use mod_jk.so-eapi.

    You should use mod_jk.so-noeapi only for 'Standard Apache' (ie without mod_ssl).

    It's wise to avoid using EAPI modules on STD API Apache or to use standard API modules on EAPI Apache. Allways be sure to have the mod_jk.so which match your version of Apache.

    What's that message about 'garbled DSO ?'

    It's related to Apache EAPI, the message 'mod_jk.so is garbled - perhaps this is not an Apache module DSO ?' just told you, that your're trying to install a mod_jk.so DSO module that was compiled on an Apache using EAPI, like apache-mod_ssl or apache from Redhat distro 6.2/7.0 but your system use the standard Apache with normal API.

    And the message about 'module might crash under EAPI!

    Also related to EAPI, the message '[warn] Loaded DSO /usr/lib/apache/mod_jk.so uses plain Apache 1.3 API, this module might crash under EAPI! (please recompile it with -DEAPI)', the mod_jk.so was compiled under normal Apache with standard API and you try to install the module on an Apache using EAPI.

    APXS is getting an error during the build of mod_jk, like rc=0 or rc=255. I tried all of the steps in the build section, what do I do now ?

    APXS is a Perl script that is created when you build the Apache web server from source. Chances are that if you are getting these errors and you obtained Apache as a binary distribution, that APXS is not configured correctly for your system. Your best bet is to get the Apache source from the Apache HTTP Server homepage and build it yourself. Use the following for a basic build (read the Apache docs for other options):

    [user@host] ~ $ cd /usr/local/src
    [user@host] ~ $ gzip -dc apache_1.3.19.tar.gz|tar xvf -
    [user@host] ~ $ cd apache_1.3.19
    [user@host] ~ $ ./configure --prefix=/usr/local/apache \
                --enable-module=most \
                --enable-shared=max
    [user@host] ~ $ make
    [user@host] ~ $ make install
    

    Note: The above steps assume that you downloaded the Apache source and placed it in your /usr/local/src directory.

    Apache complains about incorrect module version

    Since the Apache API can change between versions, any Apache module contains the Apache API version used to compile the module. This is called the Magic Module Number.

    At start time Apache checks that the version in the module header is compatible with the Apache server. If not it will deny to start and log an error.

    Note that minor versions are forward compatible. If the module was compiled using Apache 2.x.y the resulting binary should work with any other version 2.x.z where z is bigger or equals to y. If you also need compatibility for versions 2.x.z with z smaller than y, use the configure flag --enable-api-compatibility. Note that the module compiled with any 2.x will never be compatible with 2.y for x different from y. In this case you need to recompile the module.

    Does it work for the latest Apache 2.x?

    mod_jk works well with Apache 2.x from 2.0 to 2.4.

    Important parts of the functionality of mod_jk have been reimplemented in the Apache HTTP Server modules mod_proxy_ajp and mod_proxy_balancer. These are part of the standard distribution of Apache 2.2 and 2.4. The new modules do not contain all features of mod_jk, but on the other hand you get the modules automatically with every new Apache release.

    JNI doesn't work with Apache 1.3

    JNI workers have been deprecated. They will likely not work. Do not use them.

    JNI support requires a multi-threaded environment which is not the general case for Apache 1.3. You should verify if Apache 1.3 has been build with thread support and if not you could add the the pthreads library to your httpd.conf file.

    # Add pthread to Apache in httpd.conf
    LoadModule "/usr/lib/libpthreads.so"
    

    Also keep in mind that JNI is suited for multi-threaded servers and you should consider upgrading to Apache 2.x to support JNI.

    JNI report that JVM couldn't be started under Linux

    JNI workers have been deprecated. They will likely not work. Do not use them.

    Under Linux, you should set some environment variables BEFORE launching your Apache HTTP Server:

    export LD_LIBRARY_PATH=$jre/bin:$jre/bin/classic:$LD_LIBRARY_PATH
    

    Also some Linux distributions have enabled a GLIBC feature called 'floating stacks' which may not works with kernel less than 2.4.10 on SMP machines. You should disable floating stacks by exporting an environment variable:

    export LD_ASSUME_KERNEL=2.2.5
    

    You could have to update your service scripts, ie /etc/rc.d/init.d/httpd, to set these env vars before your Apache server starts.

    Mixed errors when building via configure

    configure assume you have some GNU tools already installed and configured for your system, and ad minima libtool.

    Also some systems may have mixed cc and gcc setup which may make you puzzled when trying to link an Apache built with native c compiler with a jk build with gcc.

    In case the make processing doesn't work as expected, you should use a GNU make gmake.

    tomcat-connectors-1.2.50-src/docs/miscellaneous/jkstatustasks.html0000644000000000000020000002653314655113620023726 0ustar rootbin The Apache Tomcat Connectors - Miscellaneous Documentation (1.2.50) - Status Worker Ant Tasks

    Status Worker Ant Tasks

    Introduction

    Since version 1.2.19 the JK release contains additional ant tasks. They can be used to manage the JK web server plugins via the special status worker.

    Manage JK with remote Ant Tasks

    Simple antlib integration

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project name="modjk-status" 
             xmlns:jk="urn:org-apache-jk-status"
             default="status" basedir=".">
    
    	<property name="profile" value=""/>
    	<property file="jkstatus${profile}.properties"/>
    	<property file="jkstatus.properties.default"/>
    
        <path id="jkstatus.classpath">
          <fileset dir="${catalina.home}/bin">
              <include name="commons-logging-api-*.jar"/>
          </fileset>
          <pathelement location="${catalina.home}/server/lib/catalina-ant.jar"/>
          <pathelement location="../dist/tomcat-jkstatus-ant.jar"/>
          <pathelement location="${catalina.home}/server/lib/tomcat-util.jar"/>
        </path>
    
        <typedef resource="org/apache/jk/status/antlib.xml"       
               uri="urn:org-apache-jk-status" classpathref="jkstatus.classpath"/> 
               
        <target name="status" >       
     	    <jk:status url="${jkstatus.url}" 
    	                username="${jkstatus.username}"
    	                password="${jkstatus.password}"
    	                resultproperty="worker"
    	      	        echo="off"
    	                failOnError="off"/>
    	    <echoproperties prefix="worker" />
        </target>
    </project>    
    

    Test Result

    [echoproperties] #Ant properties
    [echoproperties] #Sun Dec 10 20:40:21 CET 2006
    [echoproperties] worker.node01.lbmult=1
    [echoproperties] worker.loadbalancer.lock=Optimistic
    [echoproperties] worker.node02.transferred=0
    [echoproperties] worker.loadbalancer.sticky_session=false
    [echoproperties] worker.node01.distance=0
    [echoproperties] worker.node01.client_errors=0
    [echoproperties] worker.node02.lbmult=1
    [echoproperties] worker.node01.port=7309
    [echoproperties] worker.node01.elected=0
    [echoproperties] worker.loadbalancer.good=2
    [echoproperties] worker.loadbalancer.method=Sessions
    [echoproperties] worker.server.port=2090
    [echoproperties] worker.loadbalancer.map.2.type=Wildchar
    [echoproperties] worker.node02.route=node02
    [echoproperties] worker.node01.route=node01
    [echoproperties] worker.node01.lbvalue=0
    [echoproperties] worker.node01.lbfactor=1
    [echoproperties] worker.node01.max_busy=0
    [echoproperties] worker.node01.busy=0
    [echoproperties] worker.node01.redirect=
    [echoproperties] worker.node02.distance=0
    [echoproperties] worker.loadbalancer.name=loadbalancer
    [echoproperties] worker.loadbalancer.sticky_session_force=false
    [echoproperties] worker.node02.state=N/A
    [echoproperties] worker.node01.state=N/A
    [echoproperties] worker.node01.transferred=0
    [echoproperties] worker.loadbalancer.map.length=2
    [echoproperties] worker.node01.type=ajp13
    [echoproperties] worker.node01.address=127.0.0.1\:7309
    [echoproperties] worker.result.type=OK
    [echoproperties] worker.loadbalancer.member_count=2
    [echoproperties] worker.loadbalancer.map_count=2
    [echoproperties] worker.loadbalancer.mtime_to_maintenance_min=12
    [echoproperties] worker.loadbalancer.mtime_to_maintenance_max=75
    [echoproperties] worker.node02.lbfactor=1
    [echoproperties] worker.node02.max_busy=0
    [echoproperties] worker.jk_version=mod_jk/1.2.21-dev
    [echoproperties] worker.loadbalancer.bad=0
    [echoproperties] worker.node02.redirect=
    [echoproperties] worker.node01.host=localhost
    [echoproperties] worker.node02.activation=ACT
    [echoproperties] worker.loadbalancer.map.1.source=JkMount
    [echoproperties] worker.loadbalancer.retries=2
    [echoproperties] worker.node02.elected=0
    [echoproperties] worker.loadbalancer.map.2.source=JkMount
    [echoproperties] worker.node02.port=7409
    [echoproperties] worker.loadbalancer.length=2
    [echoproperties] worker.node02.lbvalue=0
    [echoproperties] worker.loadbalancer.degraded=0
    [echoproperties] worker.loadbalancer.map.1.type=Wildchar
    [echoproperties] worker.loadbalancer.map.2.uri=/myapps*
    [echoproperties] worker.node02.client_errors=0
    [echoproperties] worker.length=1
    [echoproperties] worker.node01.domain=d20
    [echoproperties] worker.loadbalancer.recover_time=60
    [echoproperties] worker.server.name=localhost
    [echoproperties] worker.node02.domain=
    [echoproperties] worker.result.message=Action finished
    [echoproperties] worker.node02.busy=0
    [echoproperties] worker.node01.readed=0
    [echoproperties] worker.node01.errors=0
    [echoproperties] worker.node02.address=127.0.0.1\:7409
    [echoproperties] worker.node02.readed=0
    [echoproperties] worker.loadbalancer.busy=0
    [echoproperties] worker.web_server=Apache/2.0.59 (Unix) mod_jk/1.2.21-dev
    [echoproperties] worker.node02.errors=0
    [echoproperties] worker.node02.type=ajp13
    [echoproperties] worker.loadbalancer.map.1.uri=/ClusterTest*
    [echoproperties] worker.node01.activation=ACT
    [echoproperties] worker.loadbalancer.max_busy=0
    [echoproperties] worker.loadbalancer.type=lb
    [echoproperties] worker.node02.host=localhost
    

    Update Load Balancer

    <target name="updatelb" >       
    <jk:updateloadbalancer url="${jkstatus.url}" 
                username="${jkstatus.username}"
                password="${jkstatus.password}"
                loadbalancer="loadbalancer"
                method="Busyness"
                retries="2"
                recoverWaitTime="60"
                lock="Optimistic"
                forceStickySession="false"
                stickySession="false"/>
    </target>
    

    Update Worker

    <target name="updatew" >       
    <jk:updateworker url="${jkstatus.url}" 
                username="${jkstatus.username}"
                password="${jkstatus.password}"
                loadbalancer="loadbalancer"
      	        worker="node01"
                lbfactor="2"
                activation="Active"
                redirect=""
                domain=""
                route="node01"
                distance="0"/>
    </target>
    

    Reset Worker

    <target name="reset" >       
    <jk:reset url="${jkstatus.url}" 
                username="${jkstatus.username}"
                password="${jkstatus.password}"
                loadbalancer="loadbalancer"
      	        worker="node01"
                />
    </target>
    

    tomcat-connectors-1.2.50-src/docs/miscellaneous/changelog.html0000644000000000000020000052136514655113620022742 0ustar rootbin The Apache Tomcat Connectors - Miscellaneous Documentation (1.2.50) - Changelog

    Changelog

    Preface

    This is the Changelog for Apache Tomcat Connectors. This changelog does not contain all updates and fixes to the Tomcat connectors (yet). It should contain fixes made only after November 10th 2004, when the new documentation project for JK was started.

    Changes between 1.2.49 and 1.2.50

    Apache

    • Fix: 68117: Fix typo in new libtool flag introduced in 1.2.49 to reduce symbol visibility. Also improve escaping of it in the Makefile. Patch provided by lzsiga@freemail.c3.hu. (rjung)
    • Fix: Improve shared memory handling on non-Windows. (rjung)

    IIS

    • Update: Update PCRE bundled with the ISAPI redirector to 8.45. (rjung)

    Common

    Changes between 1.2.48 and 1.2.49

    Apache

    • Update: Retrieve default request id from mod_unique_id. It can also be taken from an arbitrary environment variable by configuring "JkRequestIdIndicator". (rjung)
    • Fix: 65901: Don't delegate the generatation of the response body to httpd when the status code represents an error if the request used the HEAD method. (markt)
    • Fix: 66005: Only export the main module symbol. Visibility of module internal symbols led to crashes when conflicting with library symbols. Based on a patch provided by Josef ÄŒejka. (rjung)
    • Fix: Remove support for implicit mapping of requests to workers. All mappings must now be explicit. (rjung)

    IIS

    • Update: Set default request id as a GUID. It can also be taken from an arbitrary request header by configuring "request_id_header". (rjung)
    • Fix: Fix non-empty check for the Translate header. (rjung)

    Common

    • Fix: Fix compiler warning when initializing and copying fixed length strings. (rjung)
    • Update: Add a request id to mod_jk log lines. (rjung)
    • Fix: 64878: Enable configure to find the correct sizes for pid_t and pthread_t when building on MacOS. (markt)
    • Fix: Fix Clang 15/16 compatability. Pull request #6 provided by Sam James. (markt)
    • Update: Improve XSS hardening in status worker. (rjung)
    • Update: Add additional bounds and error checking when reading AJP messages. (schultz/markt)

    Docs

    • Update: Remove support for the Netscape / Sun ONE / Oracle iPlanet Web Server as the product has been retired. (markt)
    • Update: Remove links to the old JK2 documentation. The JK2 documentation is still available, it is just no longer linked from the current JK documentation. (markt)
    • Update: Restructure subsections in changelog starting with version 1.2.45. (rjung)

    Changes between 1.2.47 and 1.2.48

    IIS

    • Update: Update the installation how-to to remove windows versions that are no longer supported and to add Windows Server 2019. (markt)

    Changes between 1.2.46 and 1.2.47

    Apache

    • Add: Extend trace level logging of method entry/exit to aid debugging of request mapping issues. (markt)
    • Fix: Fix a bug in the normalization checks that prevented file based requests, such as SSI file includes, from being processed. (markt)
    • Fix: 63214: When using JkAutoAlias, ensure that files that include spaces in their name are accessible. (markt)

    Common

    • Update: Update the documentation to reflect that the source code for the Apache Tomcat Connectors has moved from Subversion to Git. (markt)
    • Fix: 64051: When using set_session_cookie, ensure that an updated session cookie is issued if the load-balancer has to failover to a different worker. (markt)
    • Update: Update config.guess and config.sub from https://git.savannah.gnu.org/git/config.git. (markt)
    • Update: Update release script for migration to git. (rjung)

    Changes between 1.2.45 and 1.2.46

    Apache

    • Fix: 62751: Fix regression in 1.2.44 which resulted in socket_connect_timeout to be interpreted in units of seconds instead of milliseconds on platforms that provide poll(). (rjung)

    Changes between 1.2.44 and 1.2.45

    Apache

    • Update: Update the documentation to note additional limitations of the JkAutoAlias directive. (markt)
    • Fix: Improve path parameter handling so that JkStripSession can remove session IDs that are specified on path parameters in any segment of the URI rather than only the final segment. (markt)

    IIS

    • Fix: Improve path parameter handling so that strip_session can remove session IDs that are specified on path parameters in any segment of the URI rather than only the final segment. (markt)

    Common

    • Fix: 62689: Correct regression in 1.2.44 that broke request handling for OPTIONS * requests. (rjung)
    • Code: Optimize path parameter handling. (rjung)
    • Fix: Improve path parameter parsing so that the session ID specified by the session_path worker property for load-balanced workers can be extracted from a path parameter in any segment of the URI, rather than only from the final segment. (markt)

    Changes between 1.2.43 and 1.2.44

    Native

    • Update: Remove the Novell Netware make files and Netware specific source code since there has not been a supported version of Netware available for over five years. (markt)
    • Update: 57946: Apache: Update the documentation to use httpd 2.4.x style access control directives. (markt)
    • Fix: 58287: Common: Use Local, rather than Global, mutexs on Windows to better support multi-user environments. (markt)
    • Fix: 59897: Apache: Use poll rather than select to avoid the limitations of select triggering an httpd crash. Patch provided by Koen Wilde. (markt)
    • Fix: 60745: ISAPI: Remove the check that rejects requests that contain path segments that match WEB-INF or META-INF as it duplicates a check that Tomcat performs and, because ISAPI does not have visibility of the current context path, it is impossible to implement this check without valid requests being rejected. (markt)
    • Add: Clarify the behvaiour of lb workers when all ajp13 workers fail with particular reference to the role of the retries attribute. (markt)
    • Add: 62408: Add the new load-balancer worker property lb_retries to improve the control over the number of retries. Based on a patch provided by Frederik Nosi. (markt)
    • Fix: Refactor normalisation of request URIs to a common location and align the normalisation implementation for mod_jk with that implemented by Tomcat. (markt)
    • Add: Add a note to the documentation that the CollapseSlashes options are now effectively hard-coded to CollpaseSlashesAll due to the changes made to align normalization with that implemented in Tomcat. (markt)
    • Update: Update PCRE bundled with the ISAPI redirector to 8.42. (rjung)
    • Update: Update config.guess and config.sub from https://git.savannah.gnu.org/git/config.git. (rjung)

    Changes between 1.2.42 and 1.2.43

    Native

    • Fix: 61733: LB: Propagate load factor changes applied by the status worker to a load balancer sub worker correctly to all processes. Based on a patch provided by Jonathan Oddy. (rjung)
    • Fix: ISAPI: Align the make files for 32-bit and 64-bit builds. (markt)
    • Update: Update config.guess and config.sub from http://git.savannah.gnu.org/cgit/config.git. (rjung)
    • Update: Update PCRE bundled with the ISAPI redirector to 8.41. (rjung)
    • Fix: Update the ISAPI redirector installation documentation to reflect the currently supported versions of Windows. (markt)
    • Fix: Align the normalization performed by the ISAPI redirector with that implemented by Tomcat. (markt)

    Changes between 1.2.41 and 1.2.42

    Native

    • Fix: Status: Fix displayed number of bytes read from and written to the backend when an AJP worker is used without a load balancer worker. (rjung)
    • Fix: Apache: Don't try to read remaining request body parts during clean up if reading the request body from the client already failed during earlier processing phases. (rjung)
    • Fix: 57485: Apache: Propagate errors reading the request body from the client to mod_jk so Tomcat sees an error rather than a truncated body. (markt)
    • Fix: 57836: ISAPI: Empty REMOTE_USER should not be translated to "". (rjung)
    • Fix: 58249: Add a note the the documentation that max_packet_size will be aligned to the next multiple of 1024 if a value is specified that is not a multiple of 1024. (markt)
    • Update: 58309: ISAPI: Update bundled pcre from version 5.0 to 8.38. (rjung)
    • Fix: 58286: Fix crash in mod_jk and in the ISAPI Redirector. The crash only happens on Windows when retrieving the jk-status for the HTML format (which is the default format). This regression was introduced by the fix to 54177. (rjung)
    • Fix: 58285: Don't use GCC atomics on platforms, for which GCC doesn't provide an atomics implementation. This regression was introduced by the fix to 44454 and 56703. (rjung)
    • Fix: 58425: Fix regression in 1.2.41 that prevented AJP 1.2 workers from initialising. Note that the AJP 1.2 protocol is deprecated. Patch provided by yagisita. (markt)
    • Fix: 58504: If a background thread is used to perform worker maintenance, ensure that maintenance runs are not skipped. Patch provided by Hiroto Shimizu. (markt)
    • Fix: 58608: ISAPI: Add a new registry option "flush_packets" that allows the flushing behaviour of IIS7+ to be controlled. The default is not to flush. Setting the option to "true" with cause IIS to write data to the client as each AJP packet is received. (markt)
    • Fix: 58813: ISAPI: Correctly release a mutex allowing the plugin to complete initialization. Prior to this fix, the incomplete initialization was causing a hang on shutdown. Patch provided by Matthew Reiter. (markt)
    • Fix: 58895: Correct an off-by-one error in the log messages for the number of attempts made to communicate with the backend server. Patch provided by Hiroto Shimizu. (markt)
    • Fix: 59164: Fix crash on first connection if a host name is specified for the worker that cannot be resolved to an IP address. (markt)
    • Fix: 59184: HTTPD: Avoid segmentation fault if mod_jk is configured with an invalid value for JkShmFile. This causes the server startup to fail. (markt)
    • Fix: Minor code clean-up and optimization. (markt)

    Changes between 1.2.40 and 1.2.41

    Native

    • Fix: AJP, LB: Reduce lock contention during maintenance function. This was observable when using a big number of AJP13 and LB workers, especially in combination with the Apache httpd prefork MPM. (rjung)
    • Fix: 57060: Allow building from outside of source tree. Patch contributed by Petr Sumbera. (rjung)
    • Fix: 56703: Status: Fix inflated counter for current number of backend connections especially when a connection timeout occurred on the backend. (rjung)
    • Fix: 56661: Fix Servlet API getLocalAddr(). Works for Tomcat 6.0.42, 7.0.55 and 8.0.11 and Apache and ISAPI plugins. (rjung)
    • Update: Status: Log old and new values when changing worker attributes. (rjung)
    • Fix: 56667: Status: Fix log message when changing activation state of all members. (rjung)
    • Fix: 56565: Fix IPV6 address resolve on non-dual network stacks. (mturk)
    • Fix: 50511: Reduce log level for "OPTIONS *" requests from warning to debug. (rjung)
    • Fix: Apache: Copy log notes instead of using references to prevent access to memory from closed pool. (rjung)
    • Add: Add option to control handling of multiple adjacent slashes in mount and unmount. New default is collapsing the slashes only in unmount. Configuration is done via new JkOption for Apache ("CollapseSlashesAll", "CollapseSlashesNone" or "CollapseSlashesUnmount") and via property "collapse_slashes" for IIS (values "all", "none", "unmount"). This is the fix for CVE-2014-8111. (rjung)
    • Add: Add more checks for shared memory allocation. (rjung)
    • Add: 56869: Status: Add maximum number of open backend connections to status worker. Patch contributed by Martin Knoblauch. (rjung)
    • Add: 56770: AJP: Add worker name to all log messages. Patch contributed by Martin Knoblauch. (rjung)
    • Fix: 50186: Docs: Clarify relation between "connection_pool_timeout" and "keepAliveTimeout" or "connectionTimeout" in the Tomcat AJP connector configuration. (rjung)
    • Fix: 52334: LB: Calculate worker recovery time based on last recovery attempt time instead of original error time after the first recovery attempt. (rjung)
    • Fix: 54596 part 1: IIS: Fix missing last character when parsing relative file names with no ".." directory components from configuration. (rjung)
    • Fix: 54596 part 2: IIS: Fix using relative file names in config with ".." path segments that go up the directory hierarchy higher than the starting point of the relative file name. (rjung)
    • Fix: Status: Add logging if status worker output was dropped due to insufficient buffer size. (rjung)
    • Fix: Reduce log buffer from 8KB to 1KB. Add logging in case of failed logging and add trailing "..." to lines which were likely truncated. (rjung)
    • Update: Replace fixed allocation of 32 entries for fail_on_status by dynamic allocation. (rjung)
    • Add: Enforce implementation restriction on maximal length "60" of worker attributes "name", "host", "route", "domain", "redirect", "session_cookie", "session_path" and "set_session_cookie". Checks were added to configuration file processing and configuration updates via the status worker. (rjung)
    • Add: 52483: Apache: Add debug logging for result of JkOptions configuration processing. (rjung)
    • Fix: 54177: Status: Use numeric time stamps instead of textual ones to avoid non-well-formed XML output. Textual timestamps are formatted according to locale settings and reencoding them to UTF-8 would be cumbersome. (rjung)
    • Fix: 56618: Status: Use percent decoding when reading query string parameters. For example this fixes editing IPv6 addresses via the status worker if the client encodes ":" as "%3A". Patch contributed by Christopher Schultz. (rjung)
    • Fix: 56452: Fix crash in debug logging for IPv6 adresses. Patch contributed by Christopher Schultz. (rjung)
    • Fix: 34526: Apache: Improve compatibility with mod_deflate request body inflation. An automatic detection of mod_deflate inflation is not implemented. Use the new Apache environment variable JK_IGNORE_CL instead, to let mod_jk ignore an existing Content-Length request header. (rjung)
    • Update: 44454: LB: Add warning to docs about problems with "busyness" load balancing method. (rjung)
    • Fix: 44454: Improve busy counter by using atomics. (rjung)
    • Fix: 56703: Status: Improve connected counter. Use atomics and for mod_jk (Apache) currectly count down connections closed by child processes that are stopped. (rjung)
    • Fix: 44571: Ensure that we return with status 503 if we can not get and endpoint for a worker. (rjung)
    • Fix: Apache: Improve log handling during graceful or normal restart. (rjung)
    • Fix: Don't update last access time of worker connections during optional checking of idle connections using CPing. Updating the time stamp breaks closing idle connections. (rjung)
    • Fix: Adjust linger parameters used during connection shutdown. (rjung)
    • Fix: Fix annoying redefine warnings for the autoconf PACKAGE defines during configure based builds. (rjung)
    • Fix: Status: Use multi-line table headers and fix invalid xml output. (rjung)
    • Fix: 44571: Implement an optional limit on concurrent requests allowed for a worker (attribute "busy_limit"). Original patch contributed by zealot0630 at gmail dot com. (rjung)
    • Fix: Correct log message "all endpoints are disconnected" to "no usable connection found, will create a new one". Tone done from info log level to debug for the common case. (rjung)
    • Add: 57536: AJP: Allow to configure connection source address. This should only be used on multi-homed hosts. The feature is experimental. (rjung)
    • Add: 57540: AJP: Forward name of SSL protocol used for handling the request (SSLv3, TLSv1, TLSv1.1, TLSv1.2). (rjung)

    Changes between 1.2.39 and 1.2.40

    Native

    • Fix: Fix forwarding of chunked requests, which is broken in version 1.2.39. (rjung)
    • Fix: 56352: Fix regression in memory release. (mturk)
    • Fix: Fix status worker display of worker IP address after name or port was changed. (rjung)
    • Update: 56297: Improve key hash function. Copied from APR. (rjung)
    • Fix: 55683: Remove quotes from quoted session cookies. (rjung)
    • Fix: 53542: ISAPI: Fix grammar in 503 error page. (rjung)
    • Fix: 55696: Crash on Mac OS X 10.9 during config parsing. (rjung)

    Changes between 1.2.37 and 1.2.39

    Native

    • Update: Deprecate nt_service from Apache Tomcat Connectors. (mturk)
    • Fix: 56133: Fix possible crash when a request fails during request body transfer to the back end and reply_timeout was set. Patch contributed by Hiroto Shimizu. (rjung)
    • Fix: Fix status worker not updating parameters for all members. (mturk)
    • Fix: 55853: HTTPD: Use the correct API for setting Content-Length. Patch contributed by areese yahoo-inc.com. (rjung)
    • Add: Add IPV6 support for connection to webserver. New directive prefer_ipv6 has been added to control the hostname resolution and preserve backward compatibility. (mturk)
    • Add: Add --disable-sock-cloexec to configure to disable use of SOCK_CLOEXEC (using FD_CLOEXEC + fnctl instead) so built modules will work with Linux kernels prior to 2.6.27. (timw)
    • Update: Clean up config file parsing. Worker names are now restricted to 60 bytes. (rjung)
    • Update: Allow to set a stickyness cookie in case a web framework breaks Tomcat's adding of the routing ID to the end of the JSESSIONID cookie. (rjung)
    • Update: Use max_packet_size also for request body forwarding. (rjung)
    • Update: Apache 2.4: By default forward logical client address as provided by mod_remoteip. When setting JkOptions ForwardPhysicalAddress mod_jk will instead forward the physical peer address. (rjung)
    • Update: Minor documentation improvements. (rjung)

    Changes between 1.2.36 and 1.2.37

    Native

    • Fix: Fix regression which can crash webserver in case worker is defined both as member of load balancer and as standalone worker. (mturk)
    • Fix: Fix core if debug log level is specified and there is no session identifier present. (mturk)

    Changes between 1.2.35 and 1.2.36

    Native

    • Fix: Use named shared memory objects so that we preserve runtime configured data instead of resetting on each child creation. (mturk)
    • Fix: Fix dead-lock caused by not releasing mutex on close. (mturk)
    • Fix: Fix compilation of mod_jk for HTTPD 1.3. (rjung)
    • Fix: 46893: HTTPD 1.3: Apply fix to HTTPD 1.3. It was fixed for HTTPD 2.x already in version 1.2.30. (rjung)
    • Update: HTTPD 1.3: Allow to set path parameter used when doing JkStripSession. This was available for HTTPD 2.x already since mod_jk 1.2.27. (rjung)

    Changes between 1.2.33 and 1.2.35

    Native

    • Fix: HTTPD: Fix crash on unknown worker names. (mturk)
    • Fix: IIS: Fix crash on worker process recycle. (mturk)
    • Fix: 52659: IIS: Fix shared memory corruption. (mturk)
    • Fix: 52921: HTTPD: Fix crash in uri mapping. (mturk)

    Changes between 1.2.32 and 1.2.33

    Native

    • Fix: 52793: AJP: Fix default value of forwarded worker activation state. Contributed by Yoshihito Fukuyama. (rjung)
    • Fix: HTTPD: Improve support for HTTPD 2.4 by using client_* instead of remote_* variables. (rjung)
    • Fix: 52564: Fix building with format checking gcc security hardening cflags. Contributed by Tony Mancill. (rjung)
    • Fix: 52567: Balancer member in recovery state can switch back into error state if it is idle. (rjung)
    • Update: Log error if unable to load URI workermap file, and improve logging of unreadable worker files on IIS. (timw)
    • Update: Remove deprecated JNI worker and build dependency on Java SDK. (mturk)
    • Fix: 51253: Forward WWW-Authenticate header when using server generated error pages (rjung, mturk).
    • Update: 46406: IIS: Support relative paths in configuration. The paths are presumed to be relative from isapi_redirect.dll. (mturk)
    • Fix: 50233: Do not use hard limit on uri size (mturk).
    • Update: IIS: Use Windows Server 2003 SP1, Windows XP SP2 as minimal version supported. (mturk)
    • Fix: 47038: Fix compiler warning when using --enable-flock for configure. (rjung)
    • Add: 51326: URI Map: Add "session_cookie" and "session_path" rule extensions. Contributed by Eiji Takahashi. (rjung)
    • Update: 51333: IIS: Document configuration requirement for 64 Bit environment. (rjung)
    • Add: 51743: HTTPD: Support rule extensions when defining the request worker with an environment variable (e.g. JK_WORKER_NAME). (rjung)
    • Fix: 51769: IIS: Allow URIs which contain "META-INF" or "WEB-INF" as long as they are not path components of the URI. (rjung)
    • Fix: 52056: HTTPD: JK request log does not always log correct response status. Fixed by refactoring JK request log to use the standard request log hook. (rjung)
    • Add: HTTPD: Allow to choose a sticky worker using the environment variable JK_ROUTE. This can be used if sessions and routes are send with the request in a non-standard way. (rjung)
    • Add: URI Map: Add "sticky_ignore" extension attributes to uri worker map. It allows to disable stickyness for individual mounts. (rjung)
    • Add: HTTPD: Allow dynamic disabling of stickyness using the environment variable JK_STICKY_IGNORE. This can be useful to break cookie stickyness for non-sticky requests like login forms. (rjung)
    • Add: LB: New balancing method "Next" to distribute sessions in a round-robin way. (rjung)
    • Add: LB: Add counter for created sessions to status worker and HTTPD notes. It actually counts the number of requests that do not carry a session id. (rjung)
    • Add: URI Map: Add "stateless" extension attributes to uri worker map. This can improve session load balancing. (rjung)
    • Add: HTTPD: Allow dynamic switching of requests to "stateless" using the environment variable JK_STATELESS. (rjung)
    • Update: AJP: Improve logging when request does not fit into an AJP packet. (rjung)

    Changes between 1.2.31 and 1.2.32

    Native

    • Fix: 51417: Fix worker busy detection by querying the worker endpoint. Abandoned connections can leave a worker in busy state without decrementing busy counter. (mturk)
    • Fix: 50339: Fix whitespace trimming when parsing attribute lists. (rjung)
    • Fix: 41263: Support Servlet API getRemotePort(). Works for Tomcat 5.5.28, 6.0.20 and 7.0.0 and Apache and ISAPI plugins. (rjung)
    • Fix: 41923: AJP: Close AJP connection to Tomcat on client write error when recovery_options 4 is specified, aborting the response write on the Tomcat side. (timw)
    • Update: AJP: Cap the lingering bytes that will be read when shutting down an AJP socket at 32k to prevent CPU spikes in the web server when a client aborts on a large response body. Also reduce total linger time to 2s. (timw)
    • Fix: 50839: AJP: Fix 30sec CPU spike due to incorrect counting of lingering bytes causing a busy loop when a client aborts connection during a response write. Fixes regression in 1.2.31. (timw)
    • Add: LB: Forward worker activation state as request attribute "JK_LB_ACTIVATION". Possible values are "ACT" (active), "DIS" (disabled) and "STP" (stopped). (rjung)
    • Fix: HTTPD: Forward WWW-Authenticate from backend when status is 401 and server generated error pages are used. (rjung)
    • Fix: 50363: IIS: Prevent chunk encoding of empty message bodies for 204, 205 and 304 responses. (timw)
    • Fix: 50975: IIS: Fix hanging of Transfer-Encoding: chunked requests when Content-Length header is present in request as well. Also addresses situation where IIS appears to create a Content-Length header for a small chunk encoded request when none was present in the original request. (timw)
    • Fix: 47679: IIS: stop truncation of request headers when ISAPI redirector used as an extension without the corresponding filter installed. (timw)
    • Fix: NSAPI: Use lower case header names for responses. Otherwise the web server might add chunked transfer encoding header in addition to our content length header.
    • Update: Docs: Improve load balancer documentation. (rjung)

    Changes between 1.2.30 and 1.2.31

    Native

    • Fix: 49413: AJP13: Drop flush packets send by the backend after the response has been finished. (rjung)
    • Update: AJP: Log the local and remote socket address. (mturk)
    • Update: Watchdog: Move the maintain workers outside the critical section allowing other threads to use the connection pool during maintenance. (mturk)
    • Update: Common: Add svn revision to init log message. (rjung)
    • Fix: Common: Don't destroy errno during trace logging. (rjung)
    • Update: Apache: Add support for Apache 2.3/2.4. (rjung)
    • Update: Apache: Added version number resource for mod_jk.so on Windows. (timw)
    • Update: 48501: IIS: Added rotatelogs style log rotation to ISAPI Redirector. (timw)
    • Fix: 38895: IIS: Use RAW headers instead of CGI headers by default to prevent conversion of underscores '_' to hyphens '-' in header names. Old behaviour can be enabled by defining USE_CGI_HEADERS. (timw)
    • Fix: 49511: IIS: Do not override IIS log information when subsequent requests on a keep-alive connection are not mapped into the ISAPI Redirector. (timw)
    • Fix: Docs: Document SSLOptions needed for SSL information forwarding. (rjung)
    • Update: Docs: Grammar and style improvements and clarification about serving static content by IIS. Patch provided by André Warnier. (rjung)
    • Fix: Docs: Update subversion paths used in docs. (rjung)

    Changes between 1.2.28 and 1.2.30

    Native

    • Update: Apache: Improve compatibility with Apache 2.3. (rjung)
    • Fix: 46632: Apache: Do not register child cleanup for our pools. (mturk)
    • Fix: 46893: Apache: Log warning only if JkShmSize was actually set in the configuration. (mturk)
    • Update: IIS: Include optional chunking support. Off by default. (mturk)
    • Fix: 48763: IIS: Do not send Content-Length when using chunked encoding or length larger 4GB. (mturk)
    • Fix: 48223: IIS: Propagate correct backend error code to IIS. (rjung)
    • Fix: 47867: IIS: crash during startup, when compiled with VS2008 and workers.properties contains unsupported properties. Patch provided by Indrek Juhani (rjung)
    • Fix: 47628: IIS: Fix deadlock when restarting the Application Pool caused by not releasing the critical section lock. Patch provided by Bret Prucha. (mturk)
    • Fix: IIS/NSAPI: Correct log file flushing after each line. (mturk)
    • Add: NSAPI: Add Microsoft Visual C++ Makefile. (mturk)
    • Update: AJP: Improve socket shutdown handling. (mturk)
    • Update: AJP: Ensure we never reuse a non reusable socket. (mturk)
    • Update: AJP: Tolerate a single excess packet when waiting for cpong. (mturk)
    • Update: AJP: Check protocol correctness more strictly. (mturk)
    • Update: 48410: AJP: Use poll instead select so we can work with more then 1024 sockets. (mturk)
    • Fix: 46503: AJP/Status: Garbage data in worker domain and route. (mturk)
    • Fix: 48276: AJP: When worker contact cannot be resolved mark the worker as disabled instead failing to start the server. (mturk)
    • Fix: 48169: AJP: Improve CGI interoperability by closing all sockets during EXEC. (mturk)
    • Add: Status: Add number of open backend connections to status worker. This feature is experimental, the displayed value might not be accurate. (mturk)
    • Update: 47224: Status: When address gets changed invalidate all opened sockets in the endpoint cache. This will cause new backend connections to get opened using new address. (mturk)
    • Fix: 48305: Status: Do not show "secret" property when doing dump. (mturk)
    • Fix: 45610: Status: Don't accept requests with empty value for sub worker parameter. (rjung)
    • Fix: 45610: Status: Fix erroneous unsetting of sticky_session and sticky_session_force when updating other load balancer attributes via the status worker. (rjung)
    • Fix: 47222: Status: Add ping_timeout to the shared memory and allow dynamic configuration. (mturk)
    • Fix: Status: Remove duplicate "errors" line in property view of AJP13 workers that are part of a load balancer. (rjung)
    • Fix: LB: Fix route logging. (rjung)
    • Update: Logging: Automatically detect size of thread id for logging. (rjung)
    • Update: Logging: Add optional log file locking for Windows when defining JK_LOG_LOCKING. (mturk)
    • Update: Configuration: Update example configuration. (rjung)
    • Update: Docs: Update information about tools needed to create a release. (rjung)
    • Fix: 47983: Docs: Fix typo in example config which breaks startup. (rjung)
    • Update: Build: Force copy of automake files. (rjung)
    • Update: Build: Tomcat code repository structure cleanup reflected in documentation and build script. (rjung, mturk)

    Changes between 1.2.27 and 1.2.28

    Native

    • Add: Apache: Add more environment variables to overwrite request information. Useful in case a proxy is in front of Apache and sends us original request information e.g. via custom headers. (rjung)
    • Update: Apache: No longer preallocate entries for JK request log. (rjung)
    • Fix: 46352: Apache: Fix crash when using SetHandler jakarta-servlet in VHost without any JkMount. Crash due to incorrect initialization of mount extensions. (rjung)
    • Fix: Apache: JkWatchdogInterval had wrong interval calculation causing a 10 times higher watchdog interval then configured. (mturk)
    • Fix: Apache: Activate forwarding of SSL key size by default. (rjung)
    • Fix: 46169: Apache 1.3: Backport use_server_errors mount extension. (rjung)
    • Fix: 46763: Apache 2.0: Survive the log mutex during graceful restart. Patch provided by Eiji Takahashi. (mturk)
    • Fix: 46416: Apache 2.0 on Windows: Include mstcipip.h even if the apr doesn't include it. (mturk)
    • Update: IIS: Update uriworkermap.properties file on a regular interval. This requires both worker_mount_reload and watchdog_interval to be defined. (mturk)
    • Update: IIS: Remove obsolete entries from registry file. (mturk)
    • Fix: 46579: IIS: Use local environment table instead environment variables for setting the JKISAPI_PATH and JKISAPI_NAME. (mturk)
    • Update: LB: Add new property error_escalation_time to fine tune escalation of local errors to global errors. (rjung)
    • Update: LB: If the sticky session affinity mark contains a dot, treat the part before the dot as the domain name. This allows to have full node session affinity with domain failover. (mturk)
    • Fix: LB: make forced recovery work with local error states. (rjung)
    • Fix: LB: Only update error state and error time, if we actually have a new state. (rjung)
    • Fix: LB: Set global worker state to error when we reach max_reply_timeouts, or fail_on_status triggered hard error. (rjung)
    • Update: AJP: Add a new error type JK_AJP_PROTOCOL_ERROR. (mturk)
    • Update: AJP: Allow worker ports lower or equal to 1024. (rjung)
    • Update: AJP: Improve some AJP error log messages. (mturk)
    • Update: Status: Allow changing worker address and port of AJP workers. The address is resolved on next request for that worker. (mturk)
    • Update: Status: Allow update actions to show error messages in the result page. (rjung)
    • Update: Status: Refactor update actions. (rjung)
    • Update: Status: Do not redirect to the show or list page, if an error occured during an action. (rjung)
    • Update: Status: Include error time in display. (rjung)
    • Update: Status: Remove redundant port information from worker display. Rename address column and remove its explanation from the legend. (rjung)
    • Update: Status: Optimize forced uriworkermap.properties reload. (mturk)
    • Fix: Status: Fix crash in text display. (rjung)
    • Fix: Status: Show - Edit - Show always ends in single lb member show, even when started from all members lb show. (rjung)
    • Fix: Status: Wildcards in sub worker names were broken for update actions. (rjung)
    • Fix: Status: Add use_server_errors to map display. (rjung)
    • Update: SHM: Move locking into the data pull and push methods. (rjung)
    • Update: JNI: Deprecate JNI workers. (rjung)
    • Fix: Netware: Missing define for MAX_PATH. Patch by Guenter Knauf. (rjung)
    • Update: Docs: Add a new HowTo page about reverse proxies. (rjung)
    • Update: Docs: Add an explanation of local error states to the timeouts documentation. (rjung)
    • Update: Docs: Clarify relation between socket_timeout and socket_connect_timeout. (rjung)
    • Update: Docs: Clarify IIS URL rewrite feature. (rjung)
    • Fix: 46834,46734: Docs: Fix a couple of missing or broken links. (markt,rjung)
    • Fix: Docs: Add 2008 news to main page and menues. (mturk, rjung)

    Changes between 1.2.26 and 1.2.27

    Native

    • Fix: 46109: Decay reply_timeouts even when lb method is busyness. Also reset reply_timeouts during forced recovery. (rjung)
    • Update: AJP13: Recycle connection if previous request didn't complete. (mturk)
    • Update: Maintain should not run multiple times in parallel. (mturk)
    • Fix: Apache: Fix small memory leak during restart. (mturk)
    • Update: Improve signal handling during socket shutdown. (mturk)
    • Add: URI Map: Add debug dump function for uri worker map. (rjung)
    • Update: Add revision number to version info for non-release builds. (rjung)
    • Add: IIS: Optionally allow chunked encoding for responses. At the moment only usable, if build with ISAPI_ALLOW_CHUNKING defined. Based on patch by Tim Whittington. (rjung)
    • Update: IIS: Optionally use raw headers instead of CGI headers. Fixes problem "underscore=dash" problem in header names. At the moment only available, if build with USE_RAW_HEADERS defined. (rjung)
    • Update: IIS: Optionally improve IIS 5.1 compatibility. At the moment only available, if build with AUTOMATIC_AUTH_NOTIFICATION defined. Based on patch by Tim Whittington. (rjung)
    • Fix: IIS: Fix memory corruption due to parallel initialization by multiple threads. (rjung)
    • Update: Windows: Use non-default socket keepalive interval. (mturk)
    • Add: IIS: Add environment variables JKISAPI_PATH and JKISAPI_NAME. (mturk)
    • Add: Added socket_connect_timeout directive for setting the connect timeout for the socket. This enables to have low connection timeout but higher operational timeouts. (mturk)
    • Fix: AJP13: [CVE-2008-5519] Always send initial POST packet even if the client disconnected after sending request but before providing POST data. In that case or in case the client broke the connection in a middle of read send an zero size packet informing container about broken client connection. (mturk)
    • Add: AJP13: Added connection_acquire_timeout directive for setting the absolute timeout the worker will wait for a free endpoint. (mturk)
    • Update: Apache: Allow to set path parameter used when doing JkStripSession. (mturk)
    • Update: Refactor retries implementation and change semantics of retries attributes. (mturk)
    • Update: Status: Allow showing only a single member for a load balancer. (rjung)
    • Update: Status: Add display of seconds since last statistics reset and access and transfer rates. (rjung)
    • Add: AJP13: Add a configurable retry_interval time. (rjung)
    • Update: Documentation: Enhance description of connection_pool_size. (rjung)
    • Update: IIS: Refactor error page generation. (mturk)
    • Fix: IIS: SERVER_NAME variable can be the same for multiple different server instances if requests are handled according to the ip:port combination. Use INSTANCE_ID variable to which the request belongs instead. (mturk)
    • Add: Allow forwarding server error pages. This can be done on per-uri basis using new use_server_errors extension. (mturk)
    • Add: Added session_cookie and session_path for configuring default session identifiers. (mturk)
    • Update: Use max_packet_size also as TCP send and receive buffer size. (mturk)
    • Update: Apache: Do not allow Apache to start in multi-threaded mode if mod_jk was only build for single threaded server (prefork). (mturk)
    • Fix: 45812: Add done() service method that causes sending EOS bucket for Apache httpd 2.x. This allows filter chain to work properly. (mturk)
    • Add: Added connection_ping_interval, ping_timeout and ping_mode directives. (mturk)
    • Fix: Apache: Use correct ld flags provided by apxs when building module. Prevents some crashes on AIX for httpd 1.3 module. (rjung)
    • Fix: Documentation: "val" attribute numbering in status worker needs to start with 0 instead of 1. (rjung)
    • Update: Documentation: Remove JNI parameters from sample configuration in the workers common howto. (rjung)
    • Fix: 45026: For Apache httpd 2.x add "Unknown Reason" as the reason phrase, if we get an empty one from the backend. Otherwise httpd 2.x returns status 500. (rjung)
    • Fix: Build: Fix Cygwin build. (rjung)
    • Update: Documentation: Add info to docs, that variables sent via JkEnvVar are not listed in request.getAttributeNames(). (rjung)
    • Add: Add watchdog background thread for Apache 2.x and IIS doing internal maintenance (idle connection checks, backend probing). See JkWatchdogInternal (Apache) and watchdog_interval (IIS). (mturk)
    • Update: Change log level of some messages from error to info. (mturk)
    • Fix: Documentation: Fix docs for worker attribute "secret". (rjung)
    • Update: Detect correct plugin name for various web servers via additional preprocessor defines. (rjung)
    • Fix: LB: Do not put loadbalancer node in error state if there is opened channel. This fixes the bug when new connection fails due to busyness, causing opened connections fail stickyness. This brings back per-node busy counter and private state array for each request. We can mark the state as error for failover to work while still operating and reporting node as OK if there are opened working connections. (mturk)
    • Fix: 44738: Fix merging of JkOption ForwardURI* between virtual hosts. Patch contributed by Toshihiro Sasajima. (rjung)
    • Add: URI Map: Add extension attributes to uri worker map. Allowed are reply_timeout, active/disabled/stopped and fail_on_status. Usage currently only implemented for httpd and IIS. (rjung+mturk)
    • Fix: URI Map: Make dynamic reloading atomic and free memory not needed any longer. (rjung)
    • Add: Configure: Don't use post httpd 2.2.0 API functions when building with new --enable-api-compatibility configure switch. (rjung)
    • Fix: Apache: JkAutoAlias does not work in combination with JkMountCopy if there are no JkMount in virtual host. (rjung)
    • Update: LB: Optimize state macros to improve performance. (rjung)
    • Add: Apache: Allow dynamic setting of reply timeout using the environment variable JK_REPLY_TIMEOUT. (rjung)
    • Add: Status: Add manageability for ajp parameters of ajp workers and ajp lb members. (rjung)
    • Update: Status: Change parameter names of update action to make them more easily distinguishable from other parameters. (rjung)
    • Add: Status: Add ajp worker statistics also for workers, that are not lb members. (rjung)
    • Update: AJP: Refactor factories, move ajp13/ajp14 common parts into ajp_factory. (rjung)
    • Update: Status: Only sync shm worker config values of the workers for which we changed values. (rjung)
    • Fix: Status: Set lb_factor instead of distance. (rjung)
    • Update: Status: Minor layout changes, use drop down instead of multiple text links. (rjung)
    • Update: SHM: Use local copies of read mostly attributes of lb sub workers in lb and status worker. (rjung)
    • Update: Status: Add "dump" action to dump our initial configuration. (rjung)
    • Update: Status: Use property table to decide which cmd action uses which output elements. (rjung)
    • Update: Common: Include original configuration map in worker_env to make it available for workers, e.g. the status worker. (rjung)
    • Update: LB: Refactor "route" return for httpd note. Don't use a member of the worker_record, because that's not thread safe. (rjung)
    • Update: Common: Refactor "retries", remove from service and jk_worker, move into ajp worker instead. (rjung)
    • Update: SHM: Use distinct structs for lb and ajp13 in shm. Improves type safety and saves a few bytes. (rjung)
    • Update: SHM: Remove unused attributes. (rjung)
    • Update: SHM: Automatically determine shm size for all web servers. (rjung)
    • Update: SHM: Make open/attach logging consistent for all web servers. (rjung)
    • Update: Status: Include server local time in output. (rjung)
    • Fix: 44116: Fix handling of multiple JSESSIONID cookies. (rjung)
    • Fix: 37850: Use thread safe localtime_r where appropriate. (rjung)
    • Fix: Use thread safe strtok_r on more platforms, especially AIX. (rjung)
    • Update: Status: Improve XSS hardening. (rjung)
    • Update: 35303: Move initialization of service members with defaults from web server specific code to our generic jk_init_ws_service() function. (rjung)
    • Fix: 36385: Add missing prepost CPing/CPong directly after connect in case prepost CPing is used, but no connect CPing. (rjung)
    • Update: 37322: Apache: Enhance robustness of message formating in jk_error_exit(). (rjung)
    • Fix: 44147: Multiple load balancing workers problem. (rjung)

    Changes between 1.2.25 and 1.2.26

    Native

    • Fix: 42003: Allocate memory instead using fixed size from the stack. (mturk)
    • Fix: 43229: Load balancer does not do fail over after reply timeouts. (rjung)
    • Fix: JKStatus: Repair detailed Apache httpd version display. This was broken for httpd version 2.2.4+. (rjung)
    • Update: LB/AJP: Refactoring of jk_connect.c, jk_ajp_common.c, jk_lb_worker.c (rjung)
    • Fix: Configure: Repair broken apxs auto-detection. (rjung)
    • Update: Configure: Remove trace logging from compiled code via new --disable-trace configure switch. (rjung)
    • Update: Common: Maintain idle connections in decreasing (LRU) slot order. (rjung)
    • Update: Apache: Create JK_WORKER_ROUTE and JK_REQUEST_DURATION notes for access log even if no JkRequestLogFormat is set. (rjung)
    • Update: JKStatus: Enhance URI to worker map listing for Apache httpd. We now list maps for all virtual servers and not only the one, in which JKStatus itself was called. (rjung)
    • Update: JKStatus: Enhance URI to worker map listing. Update stale uriworkermap.properties immediately. (rjung)
    • Fix: 43873: Fix small memory leak occuring during httpd restart. (rjung)
    • Update: Common: Allow '*' for the worker name in exclusion rules (resp. JkUnMount) which will override all workers. (rjung)
    • Fix: 42038: Correct overlay of mounts and unmounts for IIS. (rjung)
    • Fix: 43684: Replace JkMountFile by JkMountFileReload in uriworkermap.properties docs. (rjung)
    • Update: Apache: Add new value "All" for JkMountCopy. (rjung)
    • Fix: 43516: Memory leak for Apache httpd module of size 8KB for every virtual host without JK directive after each restart. (rjung)
    • Update: Apache: Cleanup init and destroy of server configuration. (rjung)
    • Update: Apache: Remove global configuration items from per server configuration. (rjung)
    • Update: Apache: Remove unused attributes secret_key and automount/JkAutoMount. (rjung)
    • Update: Cleanup of jk_uri_worker_map. (rjung)
    • Update: Documentation: Small additions to JkShmFile documentation. Contributed by Gerhardus Geldenhuis. (rjung)
    • Fix: AJP13: Ignore flush packets before we received the response headers. (rjung)
    • Fix: Fix crash during startup when using worker configuration inheritance (attribute "reference") and log level debug. (rjung)
    • Fix: AJP13: Match header names exactly against pre defined constants. Avoid possible confusion with custom header names using a standard header name as a prefix. (rjung)
    • Fix: jkstatus: Fix correct parameter validation at JkStatusUpdateTask and JkStatusUpdateLoadbalancerTask ant tasks. Reported by Christian Mittendorf. (pero)

    Changes between 1.2.24 and 1.2.25

    Native

    • Update: IIS: Fix shm shutdown behaviour. (rjung)
    • Update: General: fail_on_status used in a load balancer can optionally do fail over without putting the failed worker in error state. (rjung)
    • Update: NSAPI: Improve build description for Unix. (rjung)
    • Update: NSAPI: Add initialization startup message containing JK version. (rjung)
    • Fix: General: Declare static functions as static. (jim)
    • Update: Documentation: Clarify fail_on_status behaviour. (rjung)
    • Fix: General: Do fail_on_status before returning the response headers. (rjung)
    • Update: NSAPI: Fix shm shutdown behaviour. (rjung)
    • Update: NSAPI: Set return status even if request ended with an error. (rjung)
    • Update: NSAPI: Allow using without shm_file on WIN32 and Netware. (rjung)
    • Fix: NSAPI: Fix Crash of nsapi for log level debug and unset refect_unsafe. (rjung)
    • Update: NSAPI: Improve Solaris and Linux Makefiles for nsapi build. (rjung)
    • Fix: Build: Improve pid_t type detection during configure on Solaris. (rjung)
    • Update: Build: Experimental build support for gcc on WIN32 and Netware. (fuankg)
    • Update: Build: Makefile optimizations for Apache httpd 1.3/Netware . (fuankg)
    • Fix: General: Fix missing flush bug introduced in 1.2.24. (rjung)

    Changes between 1.2.23 and 1.2.24

    Native

    • Update: Documentation: Improved workers.properties description in the reference guide. (rjung)
    • Update: Documentation: Add a HowTo about the various timeouts. rjung)
    • Update: Logging: add milliseconds to the default timestamp format, if we have gettimeofday(). (rjung)
    • Update: Apache: add milliseconds (%Q) and microseconds (%q) as possible JkLogStampFormat conversion specifiers. This does not use strftime(), but needs gettimeofday(). (rjung)
    • Update: IIS & Sun: Log service failures also, if return code is negative. (rjung)
    • Fix: 42849: Abort startup of Apache httpd 1.3 in case mod_jk initialization failed. We already do the same for Apache httpd 2.x. (rjung)
    • Fix: 42849: Refuse to operate with IIS in case the initialization failed. Instead requesting isapi_redirect.dll 500 will be returned to the user. This is as closest as it can get to Apache Httpd where we refuse to start the server in case of fatal initialization errors. (mturk)
    • Fix: Load Balancer: Fix a deadlock in lb worker, which was exposed on Solaris for threaded Apache MPMs. (rjung)
    • Update: Logging: handle LWP IDs as 32 Bit unsigned. Try to make it work, although pthread IDs are opaque. (rjung)
    • Update: JkStatus: Added manipulation of max_reply_timeouts. (rjung)
    • Update: LB, Status: Add feature max_reply_timeouts, to make lb tolerant against occasional long running requests. (rjung)
    • Update: JkStatus: Added OK/IDLE as the successor of N/A. (rjung)
    • Update: Status worker: Renamed runtime states. All states have a major state (OK or ERR) and a substate. Changed the name N/A to OK/IDLE. Added docs about the meaning of the states to the status worker page in the reference guide. No new states have been added to code. (rjung)
    • Update: Common: Add recovery options for recovering idempotent http methods HEAD and GET. (rjung)
    • Fix: Correct documentation for worker attributes retries and recovery_options. (rjung)
    • Fix: Make writing log lines and line endings more atomic. (rjung)
    • Update: Common: Refactored and unified jk_map_read_prop* and jk_map_load_prop* for all use cases. (rjung)
    • Update: Common/Apache/IIS/Netscape: Add an option to check decoded URLs for potentially malicious constructions. (rjung)
    • Update: IIS: Document auth_complete and uri_select. (rjung)
    • Update: Apache/IIS/Netscape: Change the default forwarding encoding to the new proxy method. (jfclere, rjung)
    • Update: Common: Optionally reencode URIs before forwarding to the backend. Based on the URI reencoding done bei httpd mod_proxy. (jfclere, rjung)
    • Update: Common: auto-detect correct print format for pid_t. This fixes at least compiler warnings on Solaris. (rjung)
    • Fix: 42608: Handle Content-length as unsigned 64Bit to allow for huge up- and downloads. (rjung)
    • Update: Apache: Add forwarding uri to debug log. (rjung)
    • Update: Docs: Clarify relation between worker names and jvmRoute for load balancing. (rjung)
    • Fix: Use initial zero timeout for jk_is_socket_connected. The resulting detection is the same but offers a huge performance increase with mod_jk. In most cases the Operating System does not favor the 1 microsecond timeout, but it rather rounds that up to much higher value (frequency of interrupt timer which on most systems defaults to 100Hz). Patch provided by David McLaughlin. (mturk)
    • Update: NSAPI: Check correct log file and shm file configuration during startup. (rjung)
    • Fix: NSAPI: Add support for the general options concerning retries, flushing and connection persistance. (rjung)
    • Fix: NSAPI: fix crashes due to use of mount attribute in workers.properties. Changed initialization order. (rjung)
    • Fix: Improved handling of libtool and discrepancies between CC env variable and CC used during apache build by configure script. (rjung)
    • Fix: Always build with thread support, unless flag --enable-prefork is set during for configure. (rjung)
    • Update: Use snprintf/vsnprintf from ap_snprintf.c for platforms other than Windows, which might lack snprintf/vsnprintf implementations when NOT build for Apache httpd 2.x/APR (e.g. Sub Web Server) or without using configure. (fuankg)
    • Update: Imported ap_snprintf() from Apache 1.3. (fuankg)
    • Fix: Fix incorrect log object cleanup during statup, leading to crashes at least on iSeries. (rjung)
    • Update: Add jk_stat() and jk_file_exists() as wrapper functions. i5/OS V5R4 expects filename in ASCII for fopen but requires them in EBCDIC for stat(). (hgomez)
    • Update: i5/OS (AS/400) V5R4 port where Apache 2.0 modules should now use UTF8. (hgomez)
    • Update: Docs: Add comments on i5/OS build for V5R4 and previous releases. (hgomez)

    Changes between 1.2.22 and 1.2.23

    Native

    • Update: [CVE-2007-0450] and [CVE-2007-1860]: Change the default value of JkOptions to ForwardURICompatUnparsed. The old default value was ForwardURICompat. This should make URL interpretation between Apache httpd and Tomcat consistent (prevent double decoding problems). (rjung)

    Changes between 1.2.21 and 1.2.22

    Native

    • Fix: Refactor line endings logging to make it correct for all platforms and webservers. (mturk)
    • Update: Added command line windows make files. (mturk)
    • Update: Allow fail_on_status directive to be multi line. (mturk)
    • Fix: 42076: Fix name of new option from ForwardCertChain to ForwardSSLCertChain as documented. (rjung)
    • Fix: Docs: Fix a couple of typos, change format of a few tables, fix links to news pages. (rjung)
    • Fix: Fix correct URL for TC 6 examples in new IIS rewrite.properties configuration example file. (rjung)
    • Fix: Add svn properties to several files. (rjung)
    • Update: Add TC 6 examples to uriworkermap.properties in config examples. (rjung)
    • Update: Allow multiple status codes for fail_on_status directive. The status codes can be delimited by space or comma characters. (mturk)
    • Update: IIS. Added pcre like regular expressions for url rewrite rules. (mturk)
    • Fix: 41922: Apache 1.3. Enable JkEnvVar. (mturk)
    • Update: Apache. Add --enable-flock configure parameter for explicit compilation of faster flock() system calls for OS supporting those calls. By default the fcntl system call for locking will be used that is a little bit slower but it can work on NFS mounted volumes as well. (mturk)
    • Fix: 41562: Add Debug logging for read from client in ISAPI Redirector. Contributed by Tim Whittington. (mturk)
    • Update: Apache. Add ForwardSSLCertChain JkOption. Contributed by Patrik Schnellmann. (mturk)
    • Fix: IIS. Do not forbid access to web-inf or meta-inf if there is no mapped worker. This allows to have resource with those names that are outside mapped contexts. (mturk)
    • Update: Apache. Use process id for creating shared memory name and delete shared memory and shared memory lock files on exit. (mturk)
    • Fix: IIS. Fix Keep-Alive regression introduced in 1.2.21. (mturk)
    • Update: Delete unused check for empty init_map during startup. (rjung)
    • Fix: 41770: Fix startup error if no JkWorkersFile is used. (rjung)
    • Update: Use JK_TRUE/JK_FALSE instead of OK/!OK as return values in init_jk(). (rjung)
    • Update: Minor adjustments to apache startup log messages (when to use STDERR, remove deprecated NOERRNO flag, shm warning and warnings for usage of default files). (rjung)
    • Update: Replace APR precompiler directive by httpd mpm_query to detect MPM threading. Add a debug log message about auto-detected pool size. (rjung)
    • Fix: Make MMN check easier to understand and a little more precise (for new ap_get_server_banner()/ap_get_server_description()). We use the new API only for Apache httpd 2.3. This way our binaries are not tightly coupled to a minor 2.0 version, and we don't use ap_get_server_banner() any way. (rjung)
    • Fix: Use the full description string ap_get_server_description() instead of the truncated info from ap_get_server_banner(), because this info gets used internally (status worker display and ajp14 backend communication) and is not send back to the normal user. (rjung)
    • Fix: 41757: Document the "--enable-prefork" flag of configure. (rjung)
    • Update: Enhance log messages for failures when parsing attribute maps. (rjung)
    • Fix: Correct log message during worker initialization, in case remote host could not be resolved. We logged the default host name "localhost" instead of the configured one. (rjung)
    • Fix: 41770: Fix the second part of the bug: local_worker and local_worker_only is missing from the list of deprecated attributes (and not supported either), so prevents the web server from startup. (rjung)

    Changes between 1.2.20 and 1.2.21

    Native

    • Fix: [CVE-2007-0774]: A denial of service and critical remote code execution vulnerability. Caused by buffer overflow in map_uri_to_worker() when URL were longer that 4095 bytes. Reported by ZDI (www.zerodayintiative.com). Please note this issue only affected versions 1.2.19 and 1.2.20 of the Apache Tomcat JK Web Server Connector and not previous versions. Tomcat 5.5.20 and Tomcat 4.1.34 included a vulnerable version in their source packages. Other versions of Tomcat were not affected.
    • Add: Check the worker. parameters and don't start if the parameter is not a valid one. (jfclere)
    • Add: 41439: Allow session IDs to get stripped off URLs of static content in Apache by adding JkStripSession directive (configurable per vhost). (mturk)
    • Add: Change semantics of empty defaults for JkEnvVar variables. Until 1.2.19: not allowed. In 1.2.20: send variables as empty strings, if neither set to non empty in config, nor during runtime. Starting with 1.2.21: If config has no second argument only send variable if set (even when set to empty string) during runtime. Allows good combination with condition attribute in tomcat access log. (rjung)
    • Fix: 41610: Fix incorrect detection of missing Content-Length header leading to duplicate headers. Contributed by Boris Maras. (rjung)
    • Fix: Better build support for SunONE (Netscape/iPlanet) webservers. (jim)
    • Add: Add warning if duplicate map keys are read and are not allowed, e.g. when parsing uriworkermap.properties. (rjung)
    • Fix: Don't concat worker names, if uriworkermap.properties has a duplicate pattern, instead overwrite the worker. (rjung)
    • Fix: Log deprecation message even in duplication case. (rjung)
    • Fix: uriworkermap.properties: Fix off-by-one problem when deleting URL mapping during reloading of uriworkermap.properties. (rjung)
    • Add: 41439: Allow session IDs to get stripped off URLs of static content in IIS (configurable). (rjung)
    • Add: 41333: Refactoring isapi_plugin configuration reading. (rjung)
    • Add: 41332: Add some more errno logging and unify the format. (rjung)
    • Add: JkStatus: Improved logging by adding status worker name to messages. Added messages to the recover worker action. (rjung)
    • Add: JkStatus: Refactoring searching for workers and sub workers. (rjung)
    • Add: 41318: Add configuration to make status worker user name checks case insensitive. (rjung)
    • Add: JkStatus: Add estimated time until next global maintenance to other mime types and adopt jkstatus ant task. (rjung)
    • Add: JkStatus: Show estimated time until next global maintenance. Change displayed time until next recovery to a min/max pair. (rjung)
    • Add: JkStatus: Allow a user of a read/write status worker to switch it to and from read_only mode temporarily. (rjung)
    • Fix: JkStatus: Do not show read/write commands in a read_only status worker. (rjung)
    • Add: JkStatus: Allow lb sub workers in error state to be marked for recovery administratively from the status worker. (rjung)
    • Add: Load Balancer: Do not try to recover multiple times in parallel. Use additional runtime states "PROBE" and "FORCED". (rjung)
    • Fix: JkStatus: Improve data synchronization between different processes. (rjung)
    • Fix: 41381: Fix segfault in feature fail_on_status (wrong order of log arguments). Patch by Juri Haberland. (rjung)
    • Fix: Use correct windows line endings for log file on WIN32 platform. (rjung)

    Changes between 1.2.19 and 1.2.20

    Native

    • Add: JkStatus Ant Task documentation page. (pero/rjung)
    • Add: JkStatus Ant Tasks: Add new tasks for update and reset. (pero)
    • Update: JkStatus Ant Tasks: Update for new xml status format. (pero)
    • Update: Allow integer and string values when setting enumeration/boolean attributes via status worker update action. (rjung)
    • Add: Docs: New reference guide page for status worker. (rjung)
    • Update: Docs: Renaming the config dir to reference and using the title Reference Guide in the docs. (rjung)
    • Update: Added retry_on_status for workers directive. (mturk)
    • Update: Status Worker: Add directive to make property prefix and good/bad rule configurable. (rjung)
    • Update: Status Worker: Omit lb members when att=nosw. (rjung)
    • Update: Status Worker: New command cmd=version for a short version output. (rjung)
    • Update: Status Worker: New output stype mime=prop produces property lists. (rjung)
    • Fix: Apache: Fix incorrect handling of JkEnvVar when Vars are set multiple times. (rjung)
    • Update: Renamed jvm_route to route. Deprecated jvm_route, but still use it as fallback when parsing the worker configuration. (rjung)
    • Update: IIS: Make uriworkermap file reload check interval configurable. (mturk)
    • Update: Apache: Make uriworkermap file reload check interval configurable. (rjung)
    • Update: Status Worker: Add directives for customizing the XML output (ns, xmlns, doctype). (mturk)
    • Add: Docs: New page with description of uriworkermap. (rjung)
    • Update: Docs: Added short description of max_packet_size to worker reference. (rjung)
    • Update: Status Worker: All functions accessible also for xml and txt mime types (list, show, update, reset). (rjung)
    • Update: Status Worker: New global health indicators for load balancers named bad (error, recovering or stopped), degraded (busy or disabled) and good (the rest, active and OK or N/A). (rjung)
    • Update: Status Worker: New edit page, to change one attribute for all members of a load balancer. (rjung)
    • Update: Status Worker: Standard logging for status worker. (rjung)
    • Update: Status Worker: code refactoring. (rjung)
    • Update: Status Worker: New attribute user (list) denies access, if the request user in the sense of remote_user is not in this list. Empty list = no deny (rjung)
    • Update: Status Worker: New attribute read_only disables the parts of the status worker, that change states and configurations. (rjung)
    • Fix: 36121: Don't change main uri when mod_jk serves included uri. (markt)
    • Update: Apache VHosts: Merge JkOptions +base - -base + +vhost - -vhost. (rjung)
    • Update: Apache Docs: Adding requirements, context information, default values and inheritance rules to the Apache config documentation. (rjung)
    • Update: Status Worker: Add source type to status worker, remove the redundant "context" column in the map listing (context=uri). (rjung)
    • Update: uriworkermap: On reload of the file, all old entries from the previous file version get deleted, before the new ones are being read. (rjung)
    • Fix: Keep normal maps and exclusion maps internally separate. Don't treat them as the same when adding a rule. (rjung)
    • Update: Status Worker: Display mapping rules also for non-lb workers and in global view. (rjung)
    • Update: Apache VHosts: Use the vhost log files instead of the main log. (rjung)
    • Update: Apache VHosts: Allow individual timestamp formats by refactoring the formatting method. (rjung)
    • Update: Apache VHosts: Adding all missing config items to the virtual host level. Don't overwrite the settings from the global server, but inherit them in case they are not set in the virtual host. (rjung)
    • Update: Apache: remove unnecessary function names from log messages. (rjung)
    • Update: Apache: add a default log file location and a message, if the default gets used. (rjung)
    • Update: Apache: add missing JK_IS_DEBUG_LEVEL() (rjung)
    • Update: Apache VHosts: Allow JkWorkersFile, JKWorkerProperty, JkShmFile and JkShmFileSize only in global virtual server. (rjung)
    • Update: Add some more jk_close_socket() and reduce log level for some info messages. (rjung)
    • Update: Load Balancer: Added the Sessions strategy. Contributed by Takayuki Kaneko. (rjung)
    • Update: Docs: Minor enhancements and syncing with more recent versions. (rjung)
    • Fix: 40997: Separate uri mappings from their '!' counterpart when checking for duplicates in uriworkermap reloading. (rjung)
    • Fix: 40877: Make sure the shared memory is reset on attach for multiple web server child processes. (mturk)
    • Update: IIS: Added shm_size property to be able to deal with over 64 workers configurations. (mturk)
    • Update: IIS: Increase default thread count to 250, so its the same as Apache Httpd default configuration. (mturk)
    • Fix: 40966: Fix socket descriptor checks on windows. (mturk)
    • Fix: 40965: Initialize missing service parameters. (mturk)
    • Fix: 40938: Fix releasing of rewrite map. Thanks to Chris Adams for spotting that. (mturk)
    • Update: Apache: Added +FlushHeader JkOptions. (mturk)
    • Update: Added explicit flush when AJP body packet size is zero. (mturk)
    • Fix: 40856: Fixing case sensitivity bug in URL mapping. (rjung)
    • Fix: 40793: Documentation: Improvements to Apache HowTo provided by Paul Charles Leddy. (markt)
    • Fix: 40774: Fixing wrong recursion termination. This one restricted the "reference" feature unintentionally to 20 workers. (rjung)
    • Fix: 40716: Adding "reference" feature to IIS and Netscape. (rjung)
    • Fix: Documentation: Corrected SetEnvIf syntax in JK_WORKER_NAME example. (rjung)
    • Fix: Documentation: Added forgotten STATE and ACTIVATION notes for load balancer logging in Apache. (rjung)
    • Update: Apache: Use instdso.sh instead libtool: libtool does not work on HP-UX for example. (jfclere)

    Changes between 1.2.18 and 1.2.19

    Native

    • Update: Docs: Add SetHandler and new env var to Apache config docs. (rjung)
    • Update: Apache 1.3: Backport "no-jk" feature. (rjung)
    • Update: Apache: Add an environment variable to make SetHandler "jakarta-servlet" more useful. The variable is JK_WORKER_NAME, but can be changed by the new directive JkWorkerIndicator. (rjung)
    • Fix: LB: Don't use single worker shortcut, if the single worker is being diabled. (rjung)
    • Fix: Status worker: Add short explanation of activation and error states to legend. (rjung)
    • Fix: Docs: Add meaning of zero timeout values for various timeouts in workers.properties. (rjung)
    • Fix: LB: Cleanup of Mladens forced recovery. (rjung)
    • Fix: LB: Do not change lb_value for recovering workers to max, if we are using BUSYNESS method. (rjung)
    • Fix: Apache: Since 1.2.14 mod_jk failed to detect client abort. (rjung)
    • Fix: Docs: Corrected description of JkEnvVar. (rjung)
    • Fix: Solaris: Detect filio.h in configure to make the new connection detection build on solaris (r432825). (rjung)
    • Update: Add feature to force the recovery of workers that are member of loadbalancer if all the members are in error state. This fixes the time gap where 503 was returned caused by recovery_timeout although the backend was ready to handle the requests. (mturk)
    • Update: Docs: Seperate deprecated directives in their own table. (rjung)
    • Update: Docs: Allow "-" and "_" in worker names. (rjung)
    • Update: Allow multiple lines with attributes "balance_workers" and "mount". (rjung)
    • Fix: Make jk_is_some_property match more precisely. (rjung)
    • Update: JkStatus: Make refresh interval changeable. (rjung)
    • Fix: JkStatus: Adjust display of recover time wrt. global maintenance. (rjung)
    • Update: LB: Resetting worker state from OK to NA, if worker has been idle too long. (rjung)
    • Fix: Avoid compiler warnings concerning the use of lb_*_type arrays. Use functions instead. (rjung)
    • Update: Added %R JkRequestLogFormat option for Apache 1 and Apache 2. (mturk)
    • Update: Allow changing jvm Route from status manager. (mturk)
    • Fix: Do not retun 400 if Tomcat fails in the midle of the post request. Return 500 insted. (mturk)
    • Update: LB: Combine ok/error/recovering/busy runtime states into a single scalar. (rjung)
    • Update: LB: Combine active/disabled/stopped configuration states into a single scalar. (rjung)
    • Update: LB: Add several Apache notes to enable standard logging for load balancer results. (rjung)
    • Update: LB: Reorganisation of the main load balancer service loop. (rjung)
    • Update: Implement hierarchical worker configuration via attribute "reference". (rjung)
    • Update: Log deprecated properties. (rjung)
    • Fix: IIS: Fix simple_rewrite for the cases where the rewritten url is larger then the original one. (mturk)
    • Update: New JkOption "DisableReuse" to disable connection persistence. (jim)
    • Update: LB: Move sessionid retrieval out of get_most_suitable_worker into service. (rjung)
    • Update: Code cleanup for all service methods (use TRACE, JK_LOG_NULL_PARAMS, null pointer checks). (rjung)
    • Update: JKSTATUS: add refresh link. No refresh for updates. Redirect to list view after update. (rjung)
    • Update: Add new hook add_log_items into servers. (rjung)
    • Update: APACHE httpd: Rename apache logging notes. (rjung)
    • Update: LB: Rename lock and method constants. Add constants for defaults. (rjung)
    • Fix: Default log level should be INFO and not DEBUG. Default log level should be the same for all server types. (rjung)
    • Fix: Make rewrite_rule_map and log_level as non mandatory directives for isapi_redirect. (mturk)
    • Fix: 40107: Rewrite is_socket_connected function. Non blocking socket is not used any more. (mturk)
    • Update: Allow building with VS2005 without too many warnings. (mturk)
    • Fix: Decide by MMN, which piped log API we should use. mod_jk 1.2.18 broke compilation with Apache 1.3 pre 1.3.28. (rjung)

    Changes between 1.2.17 and 1.2.18

    Native

    • Fix: Using socklen_t in getsockopt. Also introducing jk_sock_t. (mturk)
    • Update: Allow recovery wait time below 60 seconds (new minimum is 1 second). (mturk)

    Changes between 1.2.16 and JK 1.2.17

    Native

    • Fix: Fix hanging jk status worker when certain attributes are being updated due to double locking. (rjung)
    • Update: Allow JkMount to behave like uriworkermap.properties by parsing pipe symbol as two directive marker. (mturk)

    Changes between 1.2.15 and JK 1.2.16

    Native

    • Update: Added simple rewrite capability for IIS. Although simple it will fulfill most needs. (mturk)
    • Update: Added RECOVER_ABORT_IF_CLIENTERROR recovery_option that closes the connection if client connection is broken during the request. (mturk)
    • Update: Renamed cache_timeout directive to connection_pool_timeout. (mturk)
    • Update: Added connection_pool_minsize directive. (mturk)
    • Update: Deprecate recycle_timeout directive. (mturk)
    • Update: Corrected some HTML syntax bugs in output of status worker. (rjung)
    • Update: Added the refresh=n parameter to the status worker. It will update the display every n seconds. (rjung)
    • Update: Balancer: Add attribute distance to balanced workers to express preferences between workers. (rjung)
    • Update: Balancer: Add attribute jvm_route to balanced workers to be able to use the same target in different balancers. (rjung)
    • Update: Status: Add lb_mult to status. (rjung)
    • Update: Balancer: Make different balancing strategies work in a similar way (use lb_value, use decay during global maintenance, use integer factors for weights. (rjung)
    • Update: Balancer: Improve locking. (rjung)
    • Update: Balancer: Workers start slower after recovering. (rjung)
    • Update: Balancer: Make different balancing strategies work in a similar way (use lb_value, use decay during global maintenance, use integer factors lb_mult for weights). (rjung)
    • Update: Balancer: Move recovery check to global maintenance. (rjung)
    • Update: Balancer: Add global maintenance method, that is called in only one process. (rjung)
    • Update: Extend our use of autoconf to find a 32Bit and a 64Bit unsigned type and their printf formats. (rjung)
    • Update: Logging: piped loggers for JkLogFile and Apache 1.3. (rjung)
    • Update: Logging: Add PID to log lines for each log level apart from REQUEST. (rjung)
    • Update: Logging: flush buffered logs to keep lines in correct order. Output final newline together with log message. (rjung)
    • Update: Reducing shm size. (rjung)
    • Update: Only log removing of old worker, when we actually do it. (rjung)
    • Fix: 37469: Fix shared memory close for forked childs. The shared memory will be closed by the parent process. (mturk)
    • Fix: 37332: Fix potential misuse of buffer length with snprintf functions. (mturk)
    • Fix: 38859: [CVE-2006-7197] Protect mod_jk against buggy or malicious AJP servers in the backend. Patch provided by Ruediger Pluem. (mturk)
    • Fix: 38889: Use worker map sorting depending on the path elements, to comply with Servlet spec. Patch provided by Steve Revilak. (mturk)
    • Update: 36138: Added Busyness lb method. Patch provided by Chris Lamprecht. (mturk)
    • Fix: Fix pessimistic locking mode. The patch correctly handles the burst load, by syncing the access to the shared memory data. (mturk)
    • Fix: 38806: Reclycle worker even if it is disabled. This fixes hot-standby workers in error state. (mturk)
    • Fix: 37167: Allow building with BSD-ish like make. (mturk)
    • Fix: ISAPI plugin (isapi_redirect.dll) did not provide correct request data for IIS to include in the IIS log. (markt)

    Changes between 1.2.14 and 1.2.15

    Native

    • Fix: Fix AJP13 Cookie2 parsing. Cookie2 was always send as Cookie. Patch provided by Andre Gebers. (mturk)
    • Fix: 35862: NSAPI plugin attempts to read freed memory and attempts to dereference a null pointer. Patch provided by Brian Kavanagh. (markt)

    Changes between 1.2.13 and 1.2.14

    Native

    • Fix: Fix lb for worker mpm's with cachesize set to lower number then ThreadsPerChild is. If retries is set to value larger then 3 sleep for 100 ms on each attempt. This enables to tune the connection cache, and serialize incoming connections instead returning busy if connection count is larger then cachesize. (mturk)
    • Fix: 36525: Solaris core dump. (mturk)
    • Fix: 36102: Worker actions do not persist. (mturk)
    • Fix: 35864: Status worker doesn't list workers. Patch provided by Martin Goldhahn. (mturk)
    • Fix: 35809: JkMountCopy don't work for Apache 2.0 Patch provided by Christophe Dubach. (mturk)
    • Fix: 35298: Multiple JK/ISAPI redirectors on a single IIS site are not supported Patch provided by Tim Whittington. (mturk)

    Changes between 1.2.12 and 1.2.13

    Native

    • Fix: 34397: Emergency was handled as Error. (jfclere)
    • Fix: 34474: // in URL were not handled correctly with Apache-1.3. (jfclere)
    • Fix: Use 64 bits int for transferred/read bytes.
    • Update: Added JkOptions +FlushPackets used to optimize memory usage when sending large data. (mturk)
    • Update: Added lock directive for load balancer that allows more acurate load balancing in case of burst load. (mturk)
    • Update: Added worker.maintain directive to allow customizing default 10 second timeout. On busy servers this value needs to be set on higher value. (mturk)
    • Fix: Fix for NetWare compiler to deal with different types between AP13 and AP2 SDKs. (fuankg)
    • Update: Emit much more legible user.dmp crash analysis output for WIN32. (wrowe)
    • Fix: 34558: Fix first failover request. (mturk)

    Changes between 1.2.11 and 1.2.12

    Native

    • Update: Added ForwardLocalAddress JkOptions flag for passing local instead remote address. Useful for remote addr valve. (mturk)
    • Fix: Fix that worker does not get used, when stopped flag is set to true. (pero)
    • Update: Add loadbalance default worker secret attribute to the documentation (pero)

    Changes between 1.2.10 and 1.2.11

    Native

    • Fix: Backport SC_M_JK_STORED from JK2 for passing arbitrary methods instead failing the request. (mturk)
    • Fix: Added missing SEARCH and ACL http methods. (mturk)
    • Update: Add worker secret attribute to the documentation (pero)
    • Update: Add a stopped flag to worker configuration. Set flag to true and the complete traffic to the worker will be stopped. Also update the Ant JkStatusUpdateTask at Tomcat 5.5.10 release. Only usefull in a replicated session cluster.(pero)
    • Update: Added worker maintain function that will maintain all the workers instead just the current one. This enables to recycle the connections on all workers. (mturk)
    • Update: Use shutdown when recycling connections instead hard breaking the socket. (mturk)
    • Update: Add unique directives checking. The directives if unique are now overwritten instead concatenated. (mturk)
    • Update: Allow multiple worker.list directives. (mturk)
    • Fix: 34577: For IIS log original request instead loging the request for ISAPI extension. (mturk)
    • Fix: 34558: Make sure the returned status codes are the same for ajp and lb workers. (mturk)
    • Fix: 34423: Use APR_USE_FLOCK_SERIALIZE for setting log lock on platforms like FreeBSD. Patch provided by Allan Saddi. (mturk)
    • Fix: 33843: Fix obtaining LDFLAGS that were used for building Apache HTTPD. Patch provided by Beat Kneubuehl. (mturk)
    • Fix: 34358: Enable load balancer method configuration. (glenn)
    • Fix: 34357: In some situations Apache 2 mod_jk could segfault when the JkAutoAlias directive is used. (glenn)
    • Update: Add --enable-prefork to the documentation (pero)
    • Update: Update tomcat_trend.pl for new error log string formatting. (glenn)

    Changes between 1.2.8 and 1.2.10

    Native

    • Update: Set default shared memory to 64K instead 1M. (mturk)
    • Fix: Do not mark the worker in error state if headers are larger then AJP13 limit. (mturk)
    • Update: On iSeries you should use the latest PTF for Apache 2.0 (which is now 2.0.52) and ad minima SI17402/SI17061 or cumulative including them. (hgomez)
    • Update: Change the xml status format to xml attribute syntax (pero)
    • Fix: 33248: Fix builds where apxs defines multiple directories for APR includes. (mturk)
    • Fix: 32696: Return 404 instead 403 when WEB-INF is requested to comply with Servlet spec. (mturk)
    • Update: Added ANT task for managing jkstatus. (pero)
    • Update: If socket_timeout is set, check if socket is alive before sending any request to Tomcat. (mturk)
    • Update: Added JkMountFile for Apache web servers. This file can contain uri mappings in the form (/url=worker), and is checked for updates at regular 60 second interval. (mturk)
    • Update: Added status worker for managing worker runtime data using web page. (mturk)
    • Update: Added load balancer method directive that is used for setting the algorithm used for balancing workers. Method can be either Request (default) or Traffic. (mturk)
    • Update: Added shared memory to allow dynamic configuration. Shared memory is needed only for unix platform and web servers having multiple child processes. For Apache web server two new directives has been added (JkShmFile and JkShmSize). (mturk)
    • Update: Added textupdate mode to status worker to handle remote updates from ant tasks.(pero)
    • Fix: 33562: Fix Reply_timeout when recovery_options is larger than 1. Patch provided by Takashi Satou. (mturk)
    • Fix: 33308: Fix segfaults when ForwardDirectories is enabled with Apache 1.3

    Changes between 1.2.7 and 1.2.8

    Native

    • Update: Allow anyone to debug and diagnose stack dumps using windbg or any other debugging tool, and (if they add the .pdb files to their installation) to make sense of dr watson logs. Patch provided by William A. Rowe (wrowe)
    • Fix: Fix in_addr_t usage by using the real struct ignoring typedef. Patch provided by William A. Rowe (wrowe)
    • Fix: Fix url rewriting by restoring the in place uri from which the jsessionid was removed. (mturk)
    • Update: Make load balancer algorithm thread safe by introducing mutex to the load balancer worker. (mturk)
    • Fix: Fix sending error pages for IIS to client by adding Content-Type header using correct api function call. (mturk)
    • Fix: 32696: Prevent IIS from crushing when web-inf url was requested. (mturk)
    • Update: Use default cachesize for servers that support discovering the number of threads per child process. (mturk).
    • Fix: Fix Apache content-length header parsing using case insensitive compare. (billbarker)
    • Fix: Fix parsing AJP headers using case insensitive compare. (mturk)
    • Fix: Use infinite socket timeout if socket_timeout is set to zero or less then zero. (mturk)
    • Update: Change balanced_workers to balance_workers but keep backward compatibility preserving the old directive. (mturk).
    • Fix: Fix ajp initialization for workers with cache_size set to zero. (mturk)
    • Update: 32317: Making mod_jk replication aware (Clustering Support). Patch provided by Rainer Jung. (mturk).
    • Fix: 31132: Core dump when JkLogFile is missing from conf. (mturk)

    Changes between 1.2.6 and 1.2.7

    Native

    • Update: Added new property named recover_time that can be used to change the default 60 second recover time. (mturk)
    • Update: Added custom retries for worker, so we don't depend on default setting. If set to a number grater then 3, it will sleep for 100ms on retry greater then 3 and then try again. (mturk)
    • Update: Added JkWorkerProperty directive that enables omiting workers.properties file. For example: JkWorkerProperty worker.ajp13a.port=8009. (mturk)
    • Fix: Check all JSESSIONID cookies for a valid jvmRoute. If you have multiple Tomcats with overlapping domains, then you can get multiple cookies without a defined order. This will route correctly as long as the different domains don't have any Tomcats in common. (billbarker)
    • Update: Added JkUnMount directive for negative mappings that works as opposite to JkMount directives. It is used for blocking of particular URL or content type. (mturk)
    • Update: Added wildchar match uri mappings. One can now use JkMount to map /app/*/servlet/* or /app?/*/*.jsp. (mturk)
    • Update: Rewrite the logging by adding Trace options. (mturk)
    • Update: Added socket_timeout property that sets the timeout for the socket itself. (mturk)
    • Fix: Changed socket_timeout property to recycle_timeout. This better explains what the directive actually does. (mturk)
    • Fix: Changed the load balancer algorithm. The idea behind this new scheduler is the following: lbfactor is how much we expect this worker to work, or the worker's work quota. lbstatus is how urgent this worker has to work to fulfill its quota of work. We distribute each worker's work quota to the worker, and then look which of them needs to work most urgently (biggest lbstatus). This worker is then selected for work, and its lbstatus reduced by the total work quota we distributed to all workers. Thus the sum of all lbstatus does not change.(*) If some workers are disabled, the others will still be scheduled correctly. (mturk)
    • Fix: Fix iis redirector that was figuring .properties file on each request. (mturk)
    • Fix: Start fixing 64/32 bit compatibility issues. (mturk)

    Changes between 1.2.5 and 1.2.6

    Native

    • Fix: Fix POST Recovery problems in LB mode. (hgomez)
    • Add: Add CPING/CPONG support to avoid problems with hang tomcats. (hgomez)
    • Update: Make POST recovery in LB configurable. (hgomez)
    • Update: Update to Apache License 2.0. (hgomez)
    • Add: For Apache 2.0, when the env var no-jk is present, mod_jk didn't handle request (declined) and as such dont forward requests to tomcats even if URL match. To be used with SetEnvIf or BrowserMatch directives for example to exclude some URL/URI or Browser (hgomez).
    • Fix: Add a fix for iSeries (AS/400) which use XOPEN/Unix98 APIs and need sa_len to be set when calling connect(), it will resolve the error EINVAL in jk_connect. (hgomez)

    Changes between 1.2.4 and 1.2.5

    Native

    • Fix: Fix a thread safe bug when mapping URI's. (billbarker)
    • Fix: Fix a thread safe bug when resolving worker host name when using mod_jk with Apache 2 and the worker MPM. (hgomez)
    • Fix: Remove an unnecessary error message when connections to all load balanced workers fail. (glenn)
    • Fix: When mod_jk cannot connect to a worker include the name of the worker in the error message. This is especially helpful when you are using load balanced workers. (glenn)
    • Fix: Fix problem with mod_jk.log getting opened multiple times for Apache 2. Only one mod_jk.log can be configured. (glenn)
    • Fix: Fix Apache 2 connector so that DirectoryIndex works for an index.jsp page if JkOptions ForwardDirectories was configured. (hgomez)
    • Fix: Fix exposure of JSP source if a //path/to.jsp URL was requested in Apache 1.3 and Apache 2.0 connector. (billbarker)

    Changes between 1.2.3 and 1.2.4

    Native

    • Add: Fix use of libtool for Apache mod_jk builds with more recent versions of Apache 2. (jfclere)
    • Fix: Use reentrant version of strtok() for web server's which use threads. This fixes a thread safe bug under Apache 2 and the worker MPM. (glenn)
    • Fix: Fix the Apache 2 mod_jk hook priority so that mod_jk works well with both mod_alias and mod_dir. (glenn)

    Changes between 1.2.2 and 1.2.3

    Native

    • Add: Add the ability to configure JkLog to pipe its log output to an executable such as Apache rotatelogs or cronolog. Apache 2.0 only. (glenn)
    • Add: Add JkAutoAlias to Apache 2.0. (glenn)
    • Update: Apache 2/1.3, if Tomcat returns an error but not content, let Apache handle processing the error returned by Tomcat. (glenn)
    • Add: Added the load balancer sticky_session property. If set to 0 requests with servlet SESSION ID's can be routed to any Tomcat worker. Default is 1, sessions are sticky. (glenn)
    • Fix: Cleaned up detection and reporting of aborted client connections. This cleanup also makes sure that mod_jk does not pass any requests on to Tomcat if the remote client aborted its connection. (glenn)
    • Fix: Fixed a bug in Apache 2.0 which caused a POST request forwarded to Tomcat to fail if it generated SSI directives which were post processed by mod_include. (glenn)
    • Fix: Fixed a bug in JkRequestLogFormat when printing the request URI that could cause a URI with hex escapes sequences to be formatted wrong. (glenn)

    Changes between 1.2.1 and 1.2.2

    Native

    • Update: tomcat_trend.pl updated script to support changed logging of aborted requests. (glenn)
    • Fix: jk set correctly the content-type in Apache 2.0, making it ready to works with mod_deflate and AddOutputFilterByType. (hgomez)
    • Fix: jk will check result of get_endpoint and handle a failure. This call can fail if the allocation for the endpoint fails because of low memory conditions causing a dereference of NULL when we try and access the endpoint. (mmanders)

    Changes between 1.2.0 and 1.2.1

    Native

    • Fix: 14282: Don't send initial chunk for chunked encoding. (costin)
    • Add: Add perl scripts for analyzing mod_jk logs and generating graphs/reports. (glenn)
    • Fix: Make JK honor the CanonicalHost directive. (hgomez)
    • Fix: Log cleanup. (costin)
    • Fix: Fix typos in jk xdocs/docs. (hgomez)
    • Fix: Add JkRequestLogFormat to Apache 2.0. (hgomez)
    • Fix: Final patches to make JK iSeries compliant. (hgomez)

    JK 2

    JK2 has been put in maintainer mode and no further development will take place. The reason for shutting down JK2 development was the lack of developers interest. Other reason was lack of users interest in adopting JK2, caused by configuration complexity when compared to JK.

    tomcat-connectors-1.2.50-src/docs/miscellaneous/reporttools.html0000644000000000000020000001550014655113620023374 0ustar rootbin The Apache Tomcat Connectors - Miscellaneous Documentation (1.2.50) - Reporting Tools

    Reporting Tools

    Reporting Tools

    The mod_jk source distribution contains two perl scripts in the tools/reports directory which can be used to analyze the mod_jk logs, save statistical data, and generate report graphs.

    tomcat_trend.pl log_dir archive_dir

    Script for analyzing mod_jk.log data when logging tomcat request data using the JkRequestLogFormat Apache mod_jk configuration. Generates statistics for request latency and errors. Archives the generated data to files for later use in long term trend graphs and reports.

    tomcat_reports.pl archive_dir reports_dir

    Script for generating reports and graphs using statistical data generated by the tomcat_trend.pl script. The following graphs are created:

    • tomcat_request.png - Long term trend graph of total number of tomcat requests handled.
    • tomcat_median.png - Long term overall trend graph of tomcat request latency median.
    • tomcat_deviation.png - Long term overall trend graph of tomcat request mean and standard deviation.
    • tomcat_error.png - Long term trend graph of requests rejected by tomcat. Shows requests rejected when tomcat has no request processors available. Can be an indicator that tomcat is overloaded or having other scaling problems.
    • tomcat_client.png - Long term trend graph of requests forward to tomcat which were aborted by the remote client (browser). You will normally see some aborted requests. High numbers of these can be an indicator that tomcat is overloaded or there are requests which have very high latency.

    A great deal of statistical data is generated but at this time only long term trend graphs are being created and no reports. This is only a start. Many more graphs and reports could be generated from the data. Please consider contributing back any new reports or graphs you create. Thanks.

    These perl scripts depend upon the following perl modules and libraries:

    • GD 1.8.x graphics library http://www.boutell.com/gd/
    • GD 1.4.x perl module
    • GD Graph perl module
    • GD TextUtil perl module
    • StatisticsDescriptive perl module

    tomcat-connectors-1.2.50-src/docs/common_howto/0000755000000000000020000000000014655113620017756 5ustar rootbintomcat-connectors-1.2.50-src/docs/common_howto/quick.html0000644000000000000020000002103414655113620021760 0ustar rootbin The Apache Tomcat Connectors - Common HowTo (1.2.50) - Quick Start HowTo

    Quick Start HowTo

    Introduction

    This document describes the configuration files used by JK on the web server side for the 'impatient':

    • workers.properties is a mandatory file used by the web server and which is the same for all JK implementations (mod_jk for the Apache HTTP Server, ISAPI for Microsoft IIS).
    • web server add-ons to be set on the web server side.

    We'll give here minimum servers configuration and an example workers.properties to be able to install and check quickly your configuration.

    Minimum workers.properties

    Here is a minimum workers.properties, using just ajp13 to connect your web server to the Tomcat engine, complete documentation is available in Workers HowTo.

    # Define 1 real worker using ajp13
    worker.list=worker1
    # Set properties for worker1 (ajp13)
    worker.worker1.type=ajp13
    worker.worker1.host=localhost
    worker.worker1.port=8009
    

    Minimum Apache HTTP Server configuration

    Here is some very basic information about Apache configuration, a more complete HowTo for Apache is available.

    You should first have mod_jk.so (unix) or mod_jk.dll (Windows) installed in your Apache module directory (see your Apache documentation to locate it).

    Usual locations for modules directory on Unix:

    • /usr/lib/apache/
    • /usr/lib/apache2/
    • /usr/local/apache/libexec/
    • /usr/local/apache/modules/

    Usual locations for modules directory on Windows:

    • C:\Program Files\Apache Group\Apache\modules\
    • C:\Program Files\Apache Group\Apache2\modules\

    You'll find a link to prebuilt binaries here

    Here is the minimum which should be set in httpd.conf directly or included from another file:

    Usual locations for configuration directory on Unix:

    • /etc/httpd/conf/
    • /etc/httpd2/conf/
    • /usr/local/apache/conf/

    Usual locations for configuration directory on Windows:

    • C:\Program Files\Apache Group\Apache\conf\
    • C:\Program Files\Apache Group\Apache2\conf\

    # Load mod_jk module
    # Update this path to match your modules location
    LoadModule    jk_module  modules/mod_jk.so
    # Declare the module for <IfModule directive> (remove this line for Apache 2.x)
    AddModule     mod_jk.c
    # Where to find workers.properties
    # Update this path to match your conf directory location (put workers.properties next to httpd.conf)
    JkWorkersFile /etc/httpd/conf/workers.properties
    # Where to put jk shared memory
    # Update this path to match your local state directory or logs directory
    JkShmFile     /var/log/httpd/mod_jk.shm
    # Where to put jk logs
    # Update this path to match your logs directory location (put mod_jk.log next to access_log)
    JkLogFile     /var/log/httpd/mod_jk.log
    # Set the jk log level [debug/error/info]
    JkLogLevel    info
    # Select the timestamp log format
    JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
    # Send everything for context /examples to worker named worker1 (ajp13)
    JkMount  /examples/* worker1
    

    Minimum Microsoft IIS configuration

    A separate HowTo for the Microsoft IIS web server is available.

    More information to be added!

    Test your configuration

    (Re)start the web server and browse to the http://localhost/examples/

    tomcat-connectors-1.2.50-src/docs/common_howto/timeouts.html0000644000000000000020000005601214655113620022521 0ustar rootbin The Apache Tomcat Connectors - Common HowTo (1.2.50) - Timeouts HowTo

    Timeouts HowTo

    Introduction

    Setting communication timeouts is very important to improve the communication process. They help to detect problems and stabilise a distributed system. JK can use several different timeout types, which can be individually configured. For historical reasons, all of them are disabled by default. This HowTo explains their use and gives hints how to find appropriate values.

    All timeouts can be configured in the workers.properties file. For a complete reference of all worker configuration items, please consult the worker reference. This page assumes, that you are using at least version 1.2.16 of JK. Dependencies on newer versions will be mentioned where necessary.

    Do not set timeouts to extreme values. Very small timeouts will likely be counterproductive.

    Long Garbage Collection pauses on the backend do not make a good fit with some timeouts. Try to optimise your Java memory and GC settings.

    JK Timeout Attributes

    CPing/CPong

    CPing/CPong is our notion for using small test packets to check the status of backend connections. JK can use such test packets directly after establishing a new backend connection (connect mode) and also directly before each request gets send to a backend (prepost mode). Starting with version 1.2.27 it can also be used when a connection was idle for a long time (interval mode). The maximum waiting time (timeout) for a CPong answer to a CPing and the idle time in interval mode can be configured.

    The test packets will be answered by the backend very fast with a minimal amount of needed processing resources. A positive answer tells us, that the backend can be reached and is actively processing requests. It does not detect, if some context is deployed and working. The benefit of CPing/CPong is a fast detection of a communication problem with the backend. The downside is a slightly increased latency.

    The worker attribute ping_mode can be set to a combination of characters to determine, in which situations test packets are used:

    • C: connect mode, timeout ping_timeout overwritten by connect_timeout
    • P: prepost mode, timeout ping_timeout overwritten by prepost_timeout
    • I: interval mode, timeout ping_timeout, idle time connection_ping_interval
    • A: all modes

    Multiple values must be concatenated without any separator characters. We recommend using all CPing tests. If your application is very latency sensitive, then you should only use the combination of connect and interval mode.

    Activating the CPing probing via ping_mode has been added in version 1.2.27. For older versions only the connect and prepost modes exist and must be activated by explicitely setting connect_timeout and prepost_timeout.

    The worker attribute ping_timeout sets the default wait timeout in milliseconds for CPong for all modes. By default the value is "10000" milliseconds. The value only gets used, if you activate CPing/Cpong probes via ping_mode. The default value should be fine, except if you experience very long Java garbage collection pauses. Depending on your network latency and stability, good custom values often are between 5000 and 15000 milliseconds. You can overwrite the timeout used for connect and prepost mode with connect_timeout and prepost_timeout. Remember: don't use extremely small values.

    The worker attribute connect_timeout sets the wait timeout in milliseconds for CPong during connection establishment. You can use it if you want to overwrite the general timeout set with ping_timeout. To use connect mode CPing, you need to enable it via ping_mode. Since JK usually uses persistent connections, opening new connections is a rare event. We therefore recommend activating connect mode. Depending on your network latency and stability, good values often are between 5000 and 15000 milliseconds. Remember: don't use extremely small values.

    The worker attribute prepost_timeout sets the wait timeout in milliseconds for CPong before request forwarding. You can use it if you want to overwrite the general timeout set with ping_timeout. To use prepost mode CPing, you need to enable it via ping_mode. Activating this type of CPing/CPong adds a small latency to each request. Usually this is small enough and the benefit of CPing/CPong is more important. So in general we also recommend using prepost_timeout. Depending on your network latency and stability, good values often are between 5000 and 10000 milliseconds. Remember: don't use extremely small values.

    Until version 1.2.27 ping_mode and ping_timeout did not exist and to enable connect or prepost mode CPing you had to set connect_timeout respectively prepost_timeout to some reasonable positive value.

    Low-Level TCP Timeouts

    Some platforms allow to set timeouts for all operations on TCP sockets. This is available for Linux and Windows, other platforms do not support this, e.g. Solaris. If your platform supports TCP send and receive timeouts, you can set them using the worker attribute socket_timeout. You can not set the two timeouts to different values.

    JK will accept this attribute even if your platform does not support socket timeouts. In this case setting the attribute will have no effect. By default the value is "0" and the timeout is disabled. You can set the attribute to some seconds value (not: milliseconds). JK will then set the send and the receive timeouts of the backend connections to this value. The timeout is low-level, it is used for each read and write operation on the socket individually.

    Using this attribute will make JK react faster to some types of network problems. Unfortunately socket timeouts have negative side effects, because for most platforms, there is no good way to recover from such a timeout, once it fired. For JK there is no way to decide, if this timeout fired because of real network problems, or only because it didn't receive an answer packet from a backend in time. So remember: don't use extremely small values.

    For the general case of connection establishment you can use socket_connect_timeout. It takes a millisecond value and works on most platforms, even if socket_timeout is not supported. We recommend using socket_connect_timeout because in some network failure situations failure detection during connection establishment can take several minutes due to TCP retransmits. Depending on the quality of your network a timeout somewhere between 1000 and 5000 milliseconds should be fine. Note that socket_timeout is in seconds, and socket_connect_timeout in milliseconds.

    Connection Pools and Idle Timeouts

    JK handles backend connections in a connection pool per web server process. The connections are used in a persistent mode. After a request completed successfully we keep the connection open and wait for the next request to forward. The connection pool is able to grow according to the number of threads that want to forward requests in parallel.

    Most applications have a varying load depending on the hour of the day or the day of the month. Other reasons for a growing connection pool would be temporary slowness of backends, leading to an increasing congestion of the frontends like web servers. Many backends use a dedicated thread for each incoming connection they handle. So usually one wants the connection pool to shrink, if the load diminishes.

    JK allows connections in the pool to get closed after some idle time. This maximum idle time can be configured with the attribute connection_pool_timeout which is given in units of seconds. The default value is "0", which disables closing idle connections.

    We generally recommend values around 10 minutes, so setting connection_pool_timeout to 600 (seconds). If you use this attribute, please also set the attribute keepAliveTimeout (if it is set explicitly) or connectionTimeout in the AJP Connector element of your Tomcat server.xml configuration file to an analogous value. Caution: keepAliveTimeout and connectionTimeout must be given in milliseconds. So if you set JK connection_pool_timeout to 600, you should set Tomcat keepAliveTimeout or connectionTimeout to 600000.

    JK connections do not get closed immediately after the timeout passed. Instead there is an automatic internal maintenance task running every 60 seconds, that checks the idle status of all connections. The 60 seconds interval can be adjusted with the global attribute worker.maintain. We do not recommend to change this value, because it has a lot of side effects. Until version 1.2.26, the maintenance task only runs, if requests get processed. So if your web server has processes that do not receive any requests for a long time, there is no way to close the idle connections in its pool. Starting with version 1.2.27 you can configure an independent watchdog thread when using Apache HTTP Server 2.x with threaded APR or Microsoft IIS.

    The maximum connection pool size can be configured with the attribute connection_pool_size. We generally do not recommend to use this attribute in combination with Apache HTTP Server. For Apache we automatically detect the number of threads per process and set the maximum pool size to this value. For Microsoft IIS we use a default value of 250 (before version 1.2.20: 10). We strongly recommend adjusting this value for IIS to the number of requests one web server process should be able to send to a backend in parallel. You should measure how many connections you need during peak hours without performance problems, and then add some percentage depending on your growth rate etc. Finally you should check, whether your web server processes are able to use at least as many threads, as you configured as the pool size.

    The JK attribute connection_pool_minsize defines, how many idle connections remain when the pool gets shrunken. By default this is half of the maximum pool size.

    Firewall Connection Dropping

    One particular problem with idle connections comes from firewalls, that are often deployed between the web server layer and the backend. Depending on their configuration, they will silently drop connections from their status table if they are idle for to long.

    From the point of view of JK and of the web server, the other side simply doesn't answer any traffic. Since TCP is a reliable protocol it detects the missing TCP ACKs and tries to resend the packets for a relatively long time, typically several minutes. Therefore you should always use connection_pool_timeout and connection_pool_minsize on the JK side and keepAliveTimeout or connectionTimeout on the Tomcat side to prevent idle connection drop.

    Furthermore using the boolean attribute socket_keepalive you can set a standard socket option, that automatically sends TCP keepalive packets after some idle time on each connection. By default this is set to false. If you suspect idle connection drops by firewalls you should set this to true.

    Unfortunately the default intervals and algorithms for these packets are platform specific. You might need to inspect TCP tuning options for your platform on how to control TCP keepalive. Often the default intervals are much longer than the firewall timeouts for idle connections. Nevertheless we recommend talking to your firewall administration and your platform administration in order to make them agree on good configuration values for the firewall and the platform TCP tuning.

    In case none of our recommendations help and you are definitively having problems with idle connection drops, you can disable the use of persistent connections when using JK together with Apache HTTP Server. For this you set "JkOptions +DisableReuse" in your Apache configuration. The amount of performance impact this will have depends on the details of your network and your firewall.

    Reply Timeout

    JK can also use a timeout on request replies. This timeout does not measure the full processing time of the response. Instead it controls, how much time between consecutive response packets is allowed.

    In most cases, this is what one actually wants. Consider for example long running downloads. You would not be able to set an effective global reply timeout, because downloads could last for many minutes. Most applications though have limited processing time before starting to return the response. For those applications you could set an explicit reply timeout. Applications that do not harmonise with reply timeouts are batch type applications, data warehouse and reporting applications which are expected to observe long processing times.

    If JK aborts waiting for a response, because a reply timeout fired, there is no way to stop processing on the backend. Although you free processing resources in your web server, the request will continue to run on the backend - without any way to send back a result once the reply timeout fired.

    JK uses the worker attribute reply_timeout to set reply timeouts. The default value is "0" (timeout disabled) and you can set it to any millisecond value.

    In combination with Apache HTTP Server, you can also set a more flexible reply_timeout using an Apache environment variable. If you set the variable JK_REPLY_TIMEOUT to some integer value, this value will be used instead of the value in the worker configuration. This way you can set reply timeouts more flexible with mod_setenvif and mod_rewrite depending on URI, query string etc. If the environment variable JK_REPLY_TIMEOUT is not set, or is set to a negative value, the default reply timeout of the worker will be used. If JK_REPLY_TIMEOUT contains the value "0", then the reply timeout will be disabled for the request.

    In combination with a load balancing worker, JK will disable a member worker of the load balancer if a reply timeout fires. The worker will then no longer be used until it gets recovered during the next automatic maintenance task. Starting with JK 1.2.24 you can improve this behaviour using max_reply_timeouts. This attribute will allow occasional long running requests without disabling the worker. Only if those requests happen to often, the worker gets disabled by the load balancer.

    Load Balancer Error Detection

    Local and Global Error States

    A load balancer worker does not only have the ability to balance load. It also handles stickyness and failover of requests in case of errors. When a load balancer detects an error on one of its members, it needs to decide, whether the error is serious, or only a temporary error or maybe only related to the actual request that was processed. Temporary errors are called local errors, serious errors will be called global errors.

    If the load balancer decides that a backend should be put into the global error state, then the web server will not send any more requests there. If no session replication is used, this means that all user sessions located on the respective backend are no longer available. The users will be send to another backend and will have to login again. So the global error state is not transparent to the users. The application is still available, but users might loose some work.

    In some cases the decision between local error and global error is easy. For instance if there is an error sending back the response to the client (browser), then it is very unlikely that the backend is broken. So this situation is a typical example of a local error.

    Some situations are harder to decide though. If the load balancer can't establish a new connection to a backend, it could be because of a temporary overload situation (so no more free threads in the backend), or because the backend isn't alive any more. Depending on the details, the right state could either be local error or global error.

    Error Escalation Time

    Until version 1.2.26 most errors were interpreted as global errors. Starting with version 1.2.27 many errors which were previously interpreted as global were switched to being local whenever the backend is still busy. Busy means, that other concurrent requests are send to the same backend (successful or not).

    In many cases there is no perfect way of making the decision between local and global error. The load balancer simply doesn't have enough information. In version 1.2.28 you can now tune, how fast the load balancer switches from local error to global error. If a member of a load balancer stays in local error state for too long, the load balancer will escalate it into global error state.

    The time tolerated in local error state is controlled by the load balancer attribute error_escalation_time (in seconds). The default value is half of recover_time, so unless you changed recover_time the default is 30 seconds.

    Using a smaller value for error_escalation_time will make the load balancer react faster to serious errors, but also carries the risk of more often loosing sessions in not so serious situations. You can lower error_escalation_time down to 0 seconds, which means all local errors which are potentially serious are escalated to global errors immediately.

    Note that without good basic error detection the whole escalation procedure is useless. So you should definitely use socket_connect_timeout and activate CPing/CPong with ping_mode and ping_timeout before thinking about also tuning error_escalation_time.

    tomcat-connectors-1.2.50-src/docs/common_howto/loadbalancers.html0000644000000000000020000003233014655113620023437 0ustar rootbin The Apache Tomcat Connectors - Common HowTo (1.2.50) - Load Balancing HowTo

    Load Balancing HowTo

    Introduction

    A load balancer is a worker that does not directly communicate with Tomcat. Instead it is responsible for the management of several "real" workers, called members or sub workers of the load balancer.

    This management includes:

    • Instantiating the workers in the web server.
    • Using the worker's load balancing factor, perform weighted load balancing (distributing load according to defined strengths of the targets).
    • Keeping requests belonging to the same session executing on the same Tomcat (session stickyness).
    • Identifying failed Tomcat workers, suspending requests to them and instead failing over on other workers managed by the load balancer.
    • Providing status and load metrics for the load balancer itself and all members via the status worker interface.
    • Allowing to dynamically reconfigure load balancing via the status worker interface.

    Workers managed by the same load balancer worker are load balanced (based on their configured balancing factors and current request or session load) and also secured against failure by providing failover to other members of the same load balancer. So a single Tomcat process death will not "kill" the entire site.

    Some of the features provided by a load balancer are even interesting, when only working with a single member worker (where load balancing is not possible).

    Basic Load Balancer Properties

    A worker is configured as a load balancer by setting its worker type to lb.

    The following table specifies some properties used to configure a load balancer worker:

    • balance_workers is a comma separated list of names of the member workers of the load balancer. These workers are typically of type ajp13. The member workers do not need to appear in the worker.list property themselves, adding the load balancer to it suffices.
    • sticky_session specifies whether requests with SESSION ID's should be routed back to the same Tomcat instance that created the session. You can set sticky_session to false when Tomcat is using a session manager which can share session data across multiple instances of Tomcat - or if your application is stateless. By default sticky_session is set to true.
    • lbfactor can be added to each member worker to configure individual strengths for the members. A higher lbfactor will lead to more requests being balanced to that worker. The factors must be given by integers and the load will be distributed proportional to the factors given. Higher factors lead to more requests.
    # The load balancer worker balance1 will distribute
    # load to the members worker1 and worker2
    worker.balance1.type=lb
    worker.balance1.balance_workers=worker1, worker2
    worker.worker1.type=ajp13
    worker.worker1.host=myhost1
    worker.worker1.port=8009
    worker.worker2.type=ajp13
    worker.worker1.host=myhost2
    worker.worker1.port=8009
    
    Session stickyness is not implemented using a tracking table for sessions. Instead each Tomcat instance gets an individual name and adds its name at the end of the session id. When the load balancer sees a session id, it finds the name of the Tomcat instance and sends the request via the correct member worker. For this to work you must set the name of the Tomcat instances as the value of the jvmRoute attribute in the Engine element of each Tomcat's server.xml. The name of the Tomcat needs to be equal to the name of the corresponding load balancer member. In the above example, Tomcat on host "myhost1" needs jvmRoute="worker1", Tomcat on host "myhost2" needs jvmRoute="worker2".

    For a complete reference of all load balancer configuration attributes, please consult the worker reference.

    Advanced Load Balancer Worker Properties

    The load balancer supports complex topologies and failover configurations. Using the member attribute distance you can group members. The load balancer will always send a request to a member of lowest distance. Only when all of those are broken, it will balance to the members of the next higher configured distance. This allows to define priorities between Tomcat instances in different data center locations.

    When working with shared sessions, either by using session replication or a persisting session manager (e.g. via a database), one often splits up the Tomcat farm into replication groups. In case of failure of a member, the load balancer needs to know, which other members share the session. This is configured using the domain attribute. All workers with the same domain are assumed to share the sessions.

    For maintenance purposes you can tell the load balancer to not allow any new sessions on some members, or even not use them at all. This is controlled by the member attribute activation. The value Active allows normal use of a member, disabled will not create new sessions on it, but still allow sticky requests, and stopped will no longer send any requests to the member. Switching the activation from "active" to "disabled" some time before maintenance will drain the sessions on the worker and minimize disruption. Depending on the usage pattern of the application, draining will take from minutes to hours. Switching the worker to stopped immediately before maintenance will reduce logging of false errors by mod_jk.

    Finally you can also configure hot spare workers by using activation set to disabled in combination with the attribute redirect added to the other workers:

    # The advanced router LB worker
    worker.list=router
    worker.router.type=lb
    worker.router.balance_workers=worker1,worker2
    
    # Define the first member worker
    worker.worker1.type=ajp13
    worker.worker1.host=myhost1
    worker.worker1.port=8009
    # Define preferred failover node for worker1
    worker.worker1.redirect=worker2
    
    # Define the second member worker
    worker.worker2.type=ajp13
    worker.worker2.host=myhost2
    worker.worker2.port=8009
    # Disable worker2 for all requests except failover
    worker.worker2.activation=disabled
    

    The redirect flag on worker1 tells the load balancer to redirect the requests to worker2 in case that worker1 has a problem. In all other cases worker2 will not receive any requests, thus acting like a hot standby.

    A final note about setting activation to disabled: The session id coming with a request is send either as part of the request URL (;jsessionid=...) or via a cookie. When using bookmarks or browsers that are running since a long time, it is possible to send a request carrying an old and invalid session id pointing at a disabled member. Since the load balancer does not have a list of valid sessions, it will forward the request to the disabled member. Thus draining takes longer than expected. To handle such cases, you can add a Servlet filter to your web application, which checks the request attribute JK_LB_ACTIVATION. This attribute contains one of the strings "ACT", "DIS" or "STP". If you detect "DIS" and the session for the request is no longer active, delete the session cookie and redirect using a self-referential URL. The redirected request will then no longer carry session information and thus the load balancer will not send it to the disabled worker. The request attribute JK_LB_ACTIVATION has been added in version 1.2.32.

    Status Worker properties

    The status worker does not communicate with Tomcat. Instead it is responsible for the worker management. It is especially useful when combined with load balancer workers.

    # Add the status worker to the worker list
    worker.list=jkstatus
    # Define a 'jkstatus' worker using status
    worker.jkstatus.type=status
    

    Next thing is to mount the requests to the jkstatus worker. For Apache HTTP Servers use:

    # Add the jkstatus mount point
    JkMount /jkmanager/* jkstatus 
    

    To obtain a higher level of security use the:

    # Enable the JK manager access from localhost only
    <Location /jkmanager/>
      JkMount jkstatus
      Require ip 127.0.0.1
    </Location>
    
    tomcat-connectors-1.2.50-src/docs/common_howto/workers.html0000644000000000000020000004412414655113620022345 0ustar rootbin The Apache Tomcat Connectors - Common HowTo (1.2.50) - Workers HowTo

    Workers HowTo

    Introduction

    A Tomcat worker is a Tomcat instance that is waiting to execute servlets on behalf of some web server. For example, we can have a web server such as the Apache HTTP Server forwarding servlet requests to a Tomcat process (the worker) running behind it.

    The scenario described above is a very simple one; in fact one can configure multiple Tomcat workers to serve servlets on behalf of a certain web server. The reasons for such configuration can be:

    • We want different contexts to be served by different Tomcat workers to provide a development environment where all the developers share the same web server but own a Tomcat worker of their own.
    • We want different virtual hosts served by different Tomcat processes to provide a clear separation between sites belonging to different companies.
    • We want to provide load balancing, meaning run multiple Tomcat workers each on a machine of its own and distribute the requests between them.

    There are probably more reasons for having multiple workers but I guess that this list is enough... Tomcat workers are defined in a properties file dubbed workers.properties and this tutorial explains how to work with it.

    This document was originally part of Tomcat: A Minimalistic User's Guide written by Gal Shachor, but has been split off for organisational reasons.

    Defining Workers

    Defining workers to the Tomcat web server plugin can be done using a properties file (a sample file named workers.properties is available in the conf/ directory).

    the file contains entries of the following form:

    worker.list=<a comma separated list of worker names>

    # the list of workers
    worker.list= worker1, worker2
    

    When starting up, the web server plugin will instantiate the workers whose name appears in the worker.list property, these are also the workers to whom you can map requests. The directive can be used multiple times.

    Worker Types

    Each named worker should also have a few entries to provide additional information on his behalf. This information includes the worker's type and other related worker information. Currently the following worker types that exists are (JK 1.2.5):

    TypeDescription
    ajp13This worker knows how to forward requests to out-of-process Tomcat workers using the ajp13 protocol.
    lbThis is a load balancing worker; it knows how to provide flexible load balancing with a certain level of fault-tolerance.
    statusThis is a status worker for managing load balancers.
    ajp12This worker knows how to forward requests to out-of-process Tomcat workers using the ajp12 protocol. It is deprecated
    ajp14This worker knows how to forward requests to out-of-process Tomcat workers using the ajp14 protocol. It is experimental

    Defining workers of a certain type should be done with the following property format:

    worker.worker name.type=<worker type> Where worker name is the name assigned to the worker and the worker type is one of the four types defined in the table (a worker name may only contain any space the characters [a-zA-Z0-9\-_]).

    # Defines a worker named "local" that uses the ajp12 protocol to forward requests to a Tomcat process.
    worker.local.type=ajp12
    # Defines a worker named "remote" that uses the ajp13 protocol to forward requests to a Tomcat process.
    worker.remote.type=ajp13
    # Defines a worker named "loadbalancer" that loadbalances several Tomcat processes transparently.
    worker.loadbalancer.type=lb
    

    Setting Worker Properties

    After defining the workers you can also specify properties for them. Properties can be specified in the following manner:

    worker.<worker name>.<property>=<property value>

    Each worker has a set of properties that you can set as specified in the following subsections:

    ajp12 Worker Properties

    The worker type ajp12 has been deprecated and you should use instead ajp13 instead.

    The ajp12 typed workers forward requests to out-of-process Tomcat workers using the ajp12 protocol over TCP/IP sockets. It does not use persistent connections.

    The ajp12 worker properties are:

    host property sets the host where the Tomcat worker is listening for ajp12 requests.

    port property sets the port where the Tomcat worker is listening for ajp12 requests

    lbfactor property is used when working with a load balancer worker, this is the load balancing factor for the worker. We'll see more on this in the load balancer worker section.

    # worker "worker1" will talk to Tomcat listening on machine www.x.com at port 8007 using 2 lb factor
    worker.worker1.type=ajp12
    worker.worker1.host=www.x.com
    worker.worker1.port=8007
    worker.worker1.lbfactor=2
    

    Note: The default port for ajp12 is 8007

    ajp13 Worker Properties

    The ajp13 typed workers forward requests to out-of-process Tomcat workers using the ajp13 protocol over TCP/IP sockets. The main difference between ajp12 and ajp13 are that:

    • ajp13 is a more binary protocol and it tries to compress some of the request data by coding frequently used strings as small integers.
    • ajp13 reuses open sockets and leaves them open for future requests (remember when you've got a Firewall between your web server and Tomcat).
    • ajp13 has special treatment for SSL information so that the container can implement SSL related methods such as isSecure().

    You should note that ajp13 is the recommended protocol to connect to Tomcat.

    # worker "worker2" will talk to Tomcat listening on machine www2.x.com at port 8009 using 3 lb factor
    worker.worker2.type=ajp13
    worker.worker2.host=www2.x.com
    worker.worker2.port=8009
    worker.worker2.lbfactor=3
    # worker "worker2" uses connections, which will stay no more than 10mn in the connection pool
    worker.worker2.connection_pool_timeout=600
    # worker "worker2" ask operating system to send KEEP-ALIVE signal on the connection
    worker.worker2.socket_keepalive=1
    # mount can be used as an alternative to the JkMount directive
    worker.worker2.mount=/contexta /contexta/* /contextb /contextb/*
    

    Notes: In the ajp13 protocol, the default port is 8009

    lb Worker Properties

    The load balancing worker does not really communicate with Tomcat workers. Instead it is responsible for the management of several "real" workers. This management includes:

    • Instantiating the workers in the web server.
    • Using the worker's load balancing factor, perform weighted round-robin load balancing where a higher lbfactor means stronger machine (that is going to handle proportionally more requests)
    • Keeping requests belonging to the same session executing on the same Tomcat worker (session stickyness).
    • Identifying failed Tomcat workers, suspending requests to them and instead failing over on other workers managed by the lb worker.

    The overall result is that workers managed by the same lb worker are load balanced (based on their lbfactor and current user session) and also fail over so a single Tomcat process death will not "kill" the entire site. The following table specifies some properties that the lb worker can accept:

    • balance_workers is a comma separated list of workers that the load balancer need to manage. As long as these workers should only be used via the load balancer worker, there is no need to also put them into the worker.list property. This directive can be used multiple times for the same load balancer.
    • sticky_session specifies whether requests with SESSION ID's should be routed back to the same Tomcat worker. Set sticky_session to false when Tomcat is using a Session Manager which can persist session data across multiple instances of Tomcat. By default sticky_session is set to true.

    # The worker balance1 while use "real" workers worker1 and worker2
    worker.balance1.balance_workers=worker1, worker2
    

    Status Worker properties

    The status worker does not communicate with Tomcat. Instead it is responsible for the load balancer management.

    # Add the status worker to the worker list
    worker.list=jkstatus
    # Define a 'jkstatus' worker using status
    worker.jkstatus.type=status
    

    Next thing is to mount the requests to the jkstatus worker. For Apache HTTP Servers use:

    # Add the jkstatus mount point
    JkMount /jkmanager/* jkstatus 
    

    To obtain a higher level of security use the:

    # Enable the JK manager access from localhost only
    <Location /jkmanager/>
       JkMount jkstatus
       Require ip 127.0.0.1
    </Location>
    

    Property file macros

    You can define "macros" in the property files. These macros let you define properties and later on use them while constructing other properties.

    # property example, like a network base address
    mynet=194.226.31
    # Using the above macro to simplify the address definitions
    # for a farm of workers.
    worker.node1.host=$(mynet).11
    worker.node2.host=$(mynet).12
    worker.node3.host=$(mynet).13
    

    Hierarchical property configuration

    Workers can reference configurations of other workers. If worker "x" references worker "y", then it inherits all configuration parameters from "y", except for the ones that have explicitly been set for "x".

    # worker toe defines some default settings
    worker.toe.type=ajp13
    worker.toe.socket_keepalive=true
    worker.toe.connect_timeout=10000
    worker.toe.recovery_options=7
    # workers tic and tac inherit those values
    worker.tic.reference=worker.toe
    worker.tac.reference=worker.toe
    

    Please note, that the reference contains the full prefix to the referenced configuration attributes, not only the name of the referenced worker.

    References can be nested with a maximum depth of 20. Be careful to avoid loops!

    Attributes which are allowed multiple times for a single worker can not be merged from a worker and a reference. An attribute is only inherited from a reference, if it is not already set for the referring worker.

    References are especially useful, when configuring load balancers. Try to understand the following two stage references:

    # We only use one load balancer
    worker.list=lb
    # Let's define some defaults
    worker.basic.port=8009
    worker.basic.type=ajp13
    worker.basic.socket_keepalive=true
    worker.basic.connect_timeout=10000
    worker.basic.recovery_options=7
    # And we use them in two groups
    worker.lb1.domain=dom1
    worker.lb1.distance=0
    worker.lb1.reference=worker.basic
    worker.lb2.domain=dom2
    worker.lb2.distance=1
    worker.lb2.reference=worker.basic
    # Now we configure the load balancer
    worker.lb.type=lb
    worker.lb.method=B
    worker.lb.balanced_workers=w11,w12,w21,w22
    worker.w11.host=myhost11
    worker.w11.reference=worker.lb1
    worker.w12.host=myhost12
    worker.w12.reference=worker.lb1
    worker.w21.host=myhost21
    worker.w21.reference=worker.lb2
    worker.w22.host=myhost22
    worker.w22.reference=worker.lb2
    

    A sample worker.properties

    Since coping with worker.properties on your own is not an easy thing to do, a sample worker.properties file is bundled along JK.

    You could also find here a sample workers.properties defining:

    • Two ajp13 workers that use the host localhost and the ports 8109 and 8209
    • An lb worker that load balances over the two ajp13 workers
    # Define 3 workers, 2 real workers using ajp13, and one being a load balancing worker 
    worker.list=node1, node2, lbworker
    # Set properties for node1 (ajp13)
    worker.node1.type=ajp13
    worker.node1.host=localhost
    worker.node1.port=8109
    worker.node1.connection_pool_timeout=600
    worker.node1.socket_keepalive=1
    # Set properties for node2 (ajp13)
    worker.node2.type=ajp13
    worker.node2.host=localhost
    worker.node2.port=8209
    worker.node2.connection_pool_timeout=600
    worker.node2.socket_keepalive=1
    # Set properties for lbworker which uses node1 and node2
    worker.lbworker.type=lb
    worker.lbworker.balance_workers=node1,node2
    
    tomcat-connectors-1.2.50-src/docs/common_howto/proxy.html0000644000000000000020000005250514655113620022034 0ustar rootbin The Apache Tomcat Connectors - Common HowTo (1.2.50) - Reverse Proxy HowTo

    Reverse Proxy HowTo

    Introduction

    The Apache HTTP Server module mod_jk and its ISAPI redirector variant for Microsoft IIS connect the web server to a backend (typically Tomcat) using the AJP protocol. The web server receives an HTTP(S) request and the module forwards the request to the backend. This function is usually called a gateway or a proxy, in the context of HTTP it is called a reverse proxy.

    Typical Problems

    A reverse proxy is not totally transparent to the application on the backend. For instance the host name and port the original client (e.g. browser) needs to talk to belong to the web server and not to the backend, so the reverse proxy talks to a different host name and port. When the application on the backend returns content including self-referential URLs using its own backend address and port, the client will usually not be able to use these URLs.

    Another example is the client IP address, which for the web server is the source IP of the incoming connection, whereas for the backend the connection always comes from the web server. This can be a problem, when the client IP is used by the backend application e.g. for security reasons.

    AJP as a Solution

    Most of these problems are automatically handled by the AJP protocol and the AJP connectors of the backend. The AJP protocol transports this communication metadata and the backend connector presents this metadata whenever the application asks for it using Servlet API methods.

    The following list contains the communication metadata handled by AJP and the ServletRequest/HttpServletRequest API calls which can be used to retrieve them:

    • local name: getLocalName(). This is also equal to getServerName(), unless a Host header is contained in the request. In this case the server name is taken from that header.
    • local IP address: getLocalAddr(). The local IP address was initially not supported. It is available when using version 1.2.41 for Apache or IIS together with Tomcat version at least 6.0.42, 7.0.55 or 8.0.11. For older versions or when using the NSAPI redirector, getLocalAddr() will incorrectly return the same result as getLocalName(). As a workaround you can forward the local IP address by setting JkEnvVar SERVER_ADDR and then either using request.getAttribute("SERVER_ADDR") instead of getLocalAddr() or wrapping the request using a filter and overriding getLocalAddr() with request.getAttribute("SERVER_ADDR").
    • local port: getLocalPort(). This is also equal to getServerPort(), unless a Host header is contained in the request. In this case the server port is taken from that header if it contains an explicit port, or is equal to the default port of the scheme used.
    • client address: getRemoteAddr()
    • client port: getRemotePort(). The remote port was initially not supported. It is available when using version 1.2.32 for Apache or IIS together with Tomcat version at least 5.5.28, 6.0.20 or 7.0.0. For older versions or when using the NSAPI redirector, getRemotePort() will incorrectly return 0 or -1. As a workaround you can forward the remote port by setting JkEnvVar REMOTE_PORT and then either using request.getAttribute("REMOTE_PORT") instead of getRemotePort() or wrapping the request using a filter and overriding getRemotePort() with request.getAttribute("REMOTE_PORT").
    • client host: getRemoteHost()
    • authentication type: getAuthType()
    • remote user: getRemoteUser(), if tomcatAuthentication="false"
    • protocol: getProtocol()
    • HTTP method: getMethod()
    • URI: getRequestURI()
    • HTTPS used: isSecure(), getScheme()
    • query string: getQueryString()
    The following additional SSL-related data will be made available by the Apache HTTP Server and forwarded by mod_jk only if you set SSLOptions +StdEnvVars. For the certificate information you also need to set SSLOptions +ExportCertData.
    • SSL cipher: getAttribute(javax.servlet.request.cipher_suite)
    • SSL key size: getAttribute(javax.servlet.request.key_size). Can be disabled using JkOptions -ForwardKeySize.
    • SSL client certificate: getAttribute(javax.servlet.request.X509Certificate). If you want the whole certificate chain, then you need to also set JkOptions ForwardSSLCertChain. It is likely, that in this case you also need to adjust the maximal AJP packet size using the worker attribute max_packet_size.
    • SSL session ID: getAttribute(javax.servlet.request.ssl_session). This is for Tomcat, it has not yet been standardized.

    Fine Tuning

    In some situations this is not enough though. Assume there is another less clever reverse proxy in front of your web server, for instance an HTTP load balancer or similar device which also serves as an SSL accelerator.

    Then you are sure that all your clients use HTTPS, but your web server doesn't know about that. All it can see is requests coming from the accelerator using plain HTTP.

    Another example would be a simple reverse proxy in front of your web server, so that the client IP address that your web server sees is always the IP address of this reverse proxy, and not of the original client. Often such reverse proxies generate an additional HTTP header, like X-Forwareded-for which contains the original client IP address (or a list of IP addresses, if there are more cascading reverse proxies in front). It would be nice, if we could use the content of such a header as the client IP address to pass to the backend.

    So we might need to manipulate some of the data that AJP sends to the backend. When using mod_jk inside the Apache HTTP Server you can use several Apache environment variables to let mod_jk know, which data it should forward. These environment variables can be set by the configuration directives SetEnv or SetEnvIf, but also in a very flexible way using mod_rewrite (since Apache 2.x it can not only test against environment variables, but also set them).

    The following list contains all environment variables mod_jk checks, before sending data to the backend:

    • JK_LOCAL_NAME: the local name
    • JK_LOCAL_PORT: the local port
    • JK_REMOTE_HOST: the client host
    • JK_REMOTE_ADDR: the client address
    • JK_AUTH_TYPE: the authentication type
    • JK_REMOTE_USER: the remote user
    • HTTPS: On (case-insensitive) to indicate, that HTTPS is used
    • SSL_CIPHER: the SSL cipher
    • SSL_CIPHER_USEKEYSIZE: the SSL key size
    • SSL_CLIENT_CERT: the SSL client certificate
    • SSL_CLIENT_CERT_CHAIN_: prefix of variable names, containing the client cerificate chain
    • SSL_SESSION_ID: the SSL session ID

    Remember: in general you don't need to set them. The module retrieves the data automatically from the web server. Only in case you want to change this data, you can overwrite it by using these variables.

    Some of these variables might also be used by other web server modules. All variables whose name does not begin with "JK" are set directly by the Apache HTTP Server. If you want to change the data, but do not want to negatively influence the behaviour of other modules, you can change the names of all variables mod_jk uses to private ones. For the details see the Apache reference page.

    All variables, that are not SSL-related have only been introduced in version 1.2.27.

    In addition there are two special shortcuts to influence the client IP address that is forwarded. Using JkOptions ForwardLocalAddress you can forward the local IP address of the web server as the client IP address. This can be useful, e.g. when using the Tomcat remote address valve for allowing connections only from registered Apache HTTP Servers. Using JkOptions ForwardPhysicalAddress you always forward the physical peer IP address as the client address. By default mod_jk uses the logical address as provided by the web server. For example the module mod_remoteip sets the logical IP address to the client IP forwarded by proxies in the X-Forwarded-For header.

    Tomcat AJP Connector Settings

    As an alternative to using the environment variables described in the previous section (which do only exist when using Apache), you can also configure Tomcat to overwrite some of the communications data forwarded by mod_jk. The AJP connector in Tomcat's server.xml allows to set the following properties:

    • proxyName: server name as returned by getServerName()
    • proxyPort: server port as returned by getServerPort()
    • scheme: protocol scheme as returned by getScheme()
    • secure: set to "true", if you wish isSecure() to return "true".
    Remember: in general you don't need to set those. AJP automatically handles all cases where the web server running mod_jk knows the right data.

    URL Handling

    URL Rewriting

    Sometimes one want to change path components of the URLs under which an application is available. Especially if a web application is deployed as some context, say /myapp, marketing prefers short URLs, so want the application to be directly available under http://www.mycompany.com/. Although you can deploy the application as the so-called ROOT context, which will be directly available at "/", admins often prefer not to use the ROOT context, e.g. because only one application can be the root context (per host).

    The procedure to change the URLs in the reverse proxy is tedious, because often an application produces self-referential URLs, which then include the path components which you tried to hide to the outside world. Nevertheless, if you absolutely need to do it, here are the steps.

    Case A: You need to make the application available at a simple URL, but it is OK, if users proceed using the more complex URLs, as long as they don't have to type them in. That's the easy case, and if this suffices to you, you're lucky. Use a simply RedirectMatch for the Apache HTTP Server:

    RedirectMatch ^/$ http://www.mycompany.com/myapp/
    

    Your application will then be available under http://www.mycompany.com/, and each visitor will be immediately redirected to the real URL http://www.mycompany.com/myapp/

    Case B: You need to hide path components for all requests going to the application. Here's the recipe for the case, where you want to hide the first path component /myapp. More complex manipulations are left as an exercise to the reader. First the solution for the case of the Apache HTTP Server:

    1. Use mod_rewrite to add /myapp to all requests before forwarding to the backend:

    # Don't forget the PT flag! (pass through)
    RewriteRule ^/(.*) http://www.mycompany.com/myapp/$1 [PT]
    

    2. Use mod_headers to rewrite any HTTP redirects your application might return. Such redirects typically contain the path components you want to hide, because by the HTTP standard, redirects always need to include the full URL, and your application is not aware of the fact, that your clients talk to it via some shortened URL. An HTTP redirect is done with a special response header named Location. We rewrite the Location headers of our responses:

    # Keep protocol, server and port if present,
    # but insert our webapp name before the rest of the URL
    Header edit Location ^([^/]*//[^/]*)?/(.*)$ $1/myapp/$2 
    

    3. Use mod_headers again, to rewrite the paths contained in any cookies, your application might set. Such cookie paths again might contain the path components you want to hide. A cookie is set with the HTTP response header named Set-Cookie. We rewrite the Set-Cookie headers of our responses:

    # Fix the cookie path
    Header edit Set-Cookie "^(.*; Path=/)(.*)" $1/myapp/$2 
    

    3. Some applications might contain hard coded absolute links. In this case check, whether you find a configuration item for your web framework to configure the base URL. If not, your only chance is to parse all response content bodies and do search and replace. This is fragile and very resource intensive. If you really need to do this, you can use mod_proxy_html, mod_substitute or mod_sed for this task.

    If you are using Microsoft IIS as a web server, the ISAPI redirector provides a way of doing the first step with a builtin feature. You define a mapping file for simple prefix changes like this:

    # Add a context prefix to all requests ...
    /=/myapp/
    # ... or change some prefix ...
    /oldapp/=/myapp/
    

    and then put the name of the file in the rewrite_rule_file entry of the registry or your isapi_redirect.properties file. In your uriworkermap.properties file, you still need to map the URLs as they are before rewriting!

    More complex rewrites can be done using the same file, but with regular expressions. A leading tilde sign '~', indicates, that you are using a regular expression:

    # Use a regular expression rewrite
    ~/oldapps([0-9]*)/=/newapps$1/
    

    There is no support for Steps 2 (rewriting redirect responses) or 3 (rewriting cookie paths).

    URL Encoding

    Some types of problems are triggered by the use of encoded URLs (see percent encoding). For the same location there exist a lot of different URLs which are equivalent. The reverse proxy needs to inspect the URL in order to apply its own authentication rules and to decide, to which backend it should send the request (or whether it should handle it itself). Therefore the request URL first is normalized: percent encoded characters are decoded, /./ is replaced by /, /XXX/../ is replaced by / and similar manipulations of the URL are done. After that, the web server might apply rewrite rules to further change the URL in less obvious ways. Finally there is no more way to put the resulting URL in an encoding, which is "similar" to the one which was used for the original URL.

    For historical reasons, there have been several alternatives, how mod_jk and the ISAPI plugin encoded the resulting URL before sending it to the backend. They could be chosen via JkOptions (mod_jk) or uri_select (ISAPI). None of those historical encodings are recommended, because they have either negative functionality implications or pose a security risk. The default encoding since version 1.2.24 is ForwardURIProxy (mod_jk) or proxy (ISAPI) and it is strongly recommended to keep the default and remove all old explicit settings.

    Request Attributes

    You can also add more attributes to any request you are forwarding when using the Apache HTTP Server. For this use the JkEnvVar directive (for details see the Apache reference page). Such request attributes can be retrieved on the Tomcat side via request.getAttribute(attributeName). Note that the names of attributes set via mod_jk will not be listed in request.getAttributeNames()!

    tomcat-connectors-1.2.50-src/docs/news/0000755000000000000020000000000014655113621016223 5ustar rootbintomcat-connectors-1.2.50-src/docs/news/20240101.html0000644000000000000020000001222614655113621020005 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2024 News & Status

    2024 News & Status

    2024 News & Status

    12 August - JK-1.2.50 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.50. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/news/20100101.html0000644000000000000020000001537614655113621020011 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2010 News and Status

    2010 News and Status

    2010 News & Status


    1 November - JK-1.2.31 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.31. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.


    1 March - JK-1.2.30 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.30. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.


    1 March - JK-1.2.29 withdrawn


    Tomcat Connectors 1.2.29 has been withdrawn because of regression inside Microsoft IIS connector.


    26 February - JK-1.2.29 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.29. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/news/20060101.html0000644000000000000020000001645314655113621020013 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2006 News and Status

    2006 News and Status

    2006 News & Status


    10 December - JK-1.2.20 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.20. This is a stable release adding new features and a few bug fixes to version 1.2.19. Furthermore the documentation has been reorganised.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    17 September - JK-1.2.19 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.19. This is a stable release adding some features and a few bug fixes to version 1.2.18. Furthermore the non-functional code trees for isapi and domino have been removed.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    13 July - JK-1.2.18 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.18. This is a stable release adding a few bug fixes to the not released 1.2.17 version.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    JK-1.2.17 not released

    Version 1.2.17 of Tomcat Connectors 1.2.17 has not been released due to a bug in the types chosen for socket arguments.

    Please see the ChangeLog for a full list of changes.


    JK-1.2.16 not released

    Version 1.2.16 of Tomcat Connectors 1.2.16 has not been released due to a bug in the jk status worker. This version adds some features and a few bug fixes to the 1.2.15 version. Furthermore some worker attributes have been deprecated.

    Please see the ChangeLog for a full list of changes.


    tomcat-connectors-1.2.50-src/docs/news/20041100.html0000644000000000000020000002241614655113621020005 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2004 News and Status

    2004 News and Status

    2004 News & Status


    17 December - JK-1.2.8 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.8.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    17 December - JK-1.2.8-rc-1 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.8-rc-1 (Relase Canditate 1).

    We expect it to be ratified as a Stable release when the vote takes place in the next week.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    13 December - JK-1.2.7-beta-3 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.7-beta-3. The release contains a fix to few configuration problems detected with JK-1.2.7-beta-2 version.

    We expect it to be ratified as a Stable release when the vote takes place in the next week.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    7 December - JK-1.2.7-beta-2 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.7-beta-2. The release contains a fix to few compilation problems detected with JK-1.2.7-beta version. This release also introduces a new domain concept clustering support. See 32317 for details.

    We expect it to be ratified as a Stable release when the vote takes place in the next two weeks.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    30 November - JK-1.2.7-beta released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.7-beta. The release contains a significant number of bug fixes and new features.

    We expect it to be ratified as a Stable release when the vote takes place in the next two weeks.

    Please see the ChangeLog for a full list of changes.

    Since release 1.2.7 the socket_timeout property has been renamed to recycle_timeout. The socket_timeout now sets the real timeout for socket operations.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    15 November - JK2 is officially unsupported

    JK2 has been put in maintainer mode and no further development will take place. The reason for shutting down JK2 development was the lack of developers interest. Other reason was lack of users interest in adopting JK2, caused by configuration complexity when compared to JK.

    The latest official JK2 release is 2.0.4.

    JK2 will have it's successor within core Apache2.1/2.2 distribution. We have developed new proxy_ajp that is an addition to the mod_proxy and uses Tomcat's AJP protocol stack. It is developped in httpd-2.1 and integrated in it. We have also developed a new proxy_balancer module for load balancing http and ajp protocol stacks.

    JK will be fully supported for all other web servers. The next JK release is planned for the end of November. Lots of code from JK2 has been ported to JK


    tomcat-connectors-1.2.50-src/docs/news/20150101.html0000644000000000000020000001252414655113621020006 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2015 News & Status

    2015 News & Status

    2015 News & Status

    11 August - JK-1.2.41 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.41. This is a maintenance and security release.

    This release includes the fix for CVE-2014-8111.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/news/20200201.html0000644000000000000020000001222214655113621017776 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2020 News & Status

    2020 News & Status

    2020 News & Status

    6 March - JK-1.2.48 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.48. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/news/20230101.html0000644000000000000020000001223414655113621020003 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2023 News & Status

    2023 News & Status

    2023 News & Status

    11 September - JK-1.2.49 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.49. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/news/20120301.html0000644000000000000020000001766414655113621020017 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2012 News and Status

    2012 News and Status

    2012 News & Status


    31 May - JK-1.2.37 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.37. This is a stable release concentrating mainly on bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    14 May - JK-1.2.36 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.36. This is a stable release concentrating mainly on bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    24 March - JK-1.2.35 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.35. This is a stable release concentrating mainly on bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    19 March - JK-1.2.33 stability issue


    The Apache Tomcat team wishes to draw your attention to stability issues that have been identified with the recent mod_jk 1.2.33 release. If you have not yet upgraded to mod_jk 1.2.33 we recommend that you wait for the mod_jk 1.2.34 release which is currently in progress. If you have upgraded and are experienced issues we recommend that you downgrade to mod_jk 1.2.32 until mod_jk 1.2.34 is available.

    We apologise for any inconvenience.

    13 March - JK-1.2.33 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.33. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/news/20140201.html0000644000000000000020000001404414655113621020005 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2014 News and Status

    2014 News and Status

    2014 News & Status


    15 April - JK-1.2.40 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.40. This is a stable release concentrating mainly on bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    11 March - JK-1.2.39 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.39. This is a stable release containing both bug fixes and few new features like IPV6 support. Note that version 1.2.38 was not released due to some minor issues found in release process.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/news/20050101.html0000644000000000000020000002317114655113621020005 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2005 News and Status

    2005 News and Status

    2005 News & Status


    8 November - JK-1.2.15 released

    The Apache Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.15. This is Stable release and it contains few bug fixes found in 1.2.14 version.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    13 July - JK-1.2.14 released

    The Apache Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.14. This is Stable release and it contains few bug fixes found in 1.2.13 version.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    7 May - JK-1.2.13 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.13. This is development release and contains few bug fixes found in 1.2.12 version.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    7 May - JK-1.2.12 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.12 The release contains a significant number of bug fixes and new features.

    We expect it to be ratified as a Stable release when the vote takes place in the next week.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    29 April - JK-1.2.11 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.11 The release contains a significant number of bug fixes and new features.

    This version has not been released.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    30 March - JK-1.2.10 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.10 The release contains a significant number of bug fixes and new features.

    We expect it to be ratified as a Stable release when the vote takes place in the next two weeks.

    Please see the ChangeLog for a full list of changes.

    Since release 1.2.10 the JkShmFile property has been added for Apache 1.3.x and Apache 2.x web servers on UNIX and LINUX platforms. Load balancer will not work properly if this directive is not present.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    18 March - JK-1.2.9-beta released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.9-beta. The release contains a significant number of bug fixes and new features.

    We expect it to be ratified as a Stable release when the vote takes place in the next two weeks.

    Please see the ChangeLog for a full list of changes.

    Since release 1.2.9 the JkShmFile property has been added for Apache 1.3.x and Apache 2.x web servers on UNIX and LINUX platforms. Load balancer will not work properly if this directive is not present.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    tomcat-connectors-1.2.50-src/docs/news/20180301.html0000644000000000000020000001451214655113621020012 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2018 News & Status

    2018 News & Status

    2018 News & Status

    13 October - JK-1.2.46 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.46. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    1 September - JK-1.2.44 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.44. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    6 March - JK-1.2.43 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.43. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/news/20070301.html0000644000000000000020000001763314655113621020017 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2007 News and Status

    2007 News and Status

    2007 News & Status


    21 December - JK-1.2.26 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.26. This is a stable release adding few new features and some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    7 August - JK-1.2.25 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.25. This is a stable release adding new features and a few bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    27 July - JK-1.2.24 released

    This release has been withdrawn.


    18 May - JK-1.2.23 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.23. This is a stable release adding new features and a few bug fixes to version 1.2.23.

    It fixes an Important vulnerability.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    17 April - JK-1.2.22 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.22. This is a stable release adding new features and a few bug fixes to version 1.2.22.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    1 March - JK-1.2.21 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.21. This is a stable release adding new features and a few bug fixes to version 1.2.20.

    It fixes a Critical vulnerability introduced in version 1.2.19

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    tomcat-connectors-1.2.50-src/docs/news/20090301.html0000644000000000000020000001565014655113621020016 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2009 News and Status

    2009 News and Status

    2009 News & Status


    22 March - JK-1.2.28 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.28. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    The most important new features in this version are:

    Better Error Detection for Load Balancer Workers

    Local and global error states have been improved. You can fine tune the behaviour with the new "error_escalation_time" attribute (see the timeouts documentation).

    Dynamic Address and Port Change Using the Status Worker

    The status worker now allows you to change the address and the port of an AJP13 worker on the fly. You can e.g. provision dummy workers with a port equal to "0", which will be automatically put into stopped mode during startup. Later, when you want to actually use these workers, you set their address and port to the final values.

    Note that already existing connections will go on using the old address and port. This will be improved in future versions.

    New Data in Status Worker Display

    The status worker display now also contains the timestamp of the last worker errors.

    Improved Proxy Flexibility

    You can now overwrite more request metadata before the request gets send to the backend. This is helpful in case there are other reverse proxies in front of your web server. A new documentation page explains this in detail.

    Improved IIS Support

    IIS support has been improved especially when using mutltiple application pools. Furthermore you can now configure the ISAPI plugin to update the uriworkermap.properies file on a regular interval using the watchdog thread.

    JNI Worker Deprecation

    Workers of type jni are broken since a long time. Since there is no more use for them, they have been deprecated now, and will be removed in a future release.

    tomcat-connectors-1.2.50-src/docs/news/20081001.html0000644000000000000020000002613414655113621020012 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2008 News and Status

    2008 News and Status

    2008 News & Status


    28 October - JK-1.2.27 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.27. This is a stable release adding lots of new features and some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    The most important new features in this version are:

    Watchdog Thread for Periodic Tasks

    The connector has to run some periodic tasks independant of request processing. Examples are probing or closing down idle backend connections, adjusting load numbers and recovering workers from error state.

    Before version 1.2.27 these tasks were done inside the request processing loop. When a new request came in and the task was due, the thread handling the request first executed the internal task and then handled the request. If there were no requests coming in, the tasks would not run. If any of the tasks took unexpectedly long, the response time of the request waiting for the finishing of the task went up.

    Starting with this release you can configure a separate watchdog thread inside the web server to run all those tasks independantly of request processing. This new feature is avaliable for the connector when used with Apache httpd 2.x or with Microsoft IIS. To keep the behaviour of the new version consistent with previous releases, this feature is turned off by default. You can activate the watchdog thread via JkWatchdogInterval for Apache or watchdog_interval for IIS.

    Connection Probing

    In previous releases connection probing (checking whether connections still work) could only be done immediately after a new connection was established and directly before sending each request. Since we now have the watchdog thread available, we also added a periodic probing option, which you can activate with the worker attribute ping_mode. This will also be useful as a protection against the infamous firewall idle connection drop.

    The older attributes connect_timeout and prepost_timeout still exist and work the same way they did in previous releases. Since there are now three different probing options, we recommend to migrate your configuration to the newer attributes ping_mode, ping_timeout and connection_ping_interval.

    Mount Extensions

    Usually one defines workers and mounts for the connector. A worker defines a backend we want to talk to and the configuration parameters of the communication, connection pools etc. The mounts define which URIs we want to forward to which worker (so we also call a mount an URI map rule). In version 1.2.27 you can overwrite certain worker parameter per mount.

    One easy to understand example is reply timeouts. Until this release you had to specify a reply timeout for the whole worker. But reply times depend a lot on the type of request. So normally you want to define a general reply timeout and for some special URLs you need to relax the reply timeout, because you know those URLs take much longer to process (like e.g. reporting or other compute intensive tasks).

    Another possible case is the activation status. You might use a load balancer worker to forward requests to certain webapps in a farm of Tomcat nodes. If you wanted to update some webapp on one node, you previously had to stop forwarding requests for all webapps on this Tomcat node. What was not possible until now, was stopping forwarding requests restricted to the webapp and the node you wanted to update.

    Starting with this release, you can add so-called rule extensions to your uriworkermap file to influence worker parameters per mount. This will work for all Apache versions and for IIS. Remember, that the uriworkermap file automatically gets reloaded after changes without web server restart.

    Improved IIS support

    We improved IIS support im various ways. It is now possible to use multiple IIS 6 application pools with the ISAPI redirector.

    Furthermore some improvements were added as compile time features. The most notable one is chunked encoding support, which was a major refactoring and is therefore still considered experimental. You can download binaries with and without chunked encoding support. In future versions, chunked encoding will likely be availabe in all builds.

    Another new feature is an elegant way of configuring error page redirects. All new features are documented on the documentation page about configuring IIS.

    Enhanced Status Worker

    The status worker now can also manage and show statistics for AJP workers that are not part of a load balancer. Other improvements are the new dump action, the integration of the new configuration attributes, showing average request and transfer rates since the last statistics reset and the ability to display only a single member of a load balancer.

    Unfortunately we had to change some request parameters used for the update action of the status worker.

    Miscellaneous Improvements

    Further enhancements are:

    • Configurable session stickyness indicator: cookie name and URL path parameter name can be freely chosen instead of the servlet spec compliant JSESSIONID and ;jsessionid.
    • Automatically determining the size of the shared memory segment needed to accommodate all workers.
    • New connection establishment timeout socket_connect_timeout.
    • New timeout connection_acquire_timeout for acquiring a free connection from the pool.
    • Improved retry handling by adjusting the meaning of the attribute retries for AJP workers and for load balancers and by adding the new retry_interval.
    • Allowing the web server to provide error pages instead of Tomcat.

    tomcat-connectors-1.2.50-src/docs/news/20160901.html0000644000000000000020000001222514655113621020015 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2016 News & Status

    2016 News & Status

    2016 News & Status

    5 October - JK-1.2.42 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.42. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/news/20110701.html0000644000000000000020000001236114655113621020007 0ustar rootbin The Apache Tomcat Connectors - News (1.2.50) - 2011 News and Status

    2011 News and Status

    2011 News & Status


    8 July - JK-1.2.32 released


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.32. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/docs/reference/0000755000000000000020000000000014655113620017204 5ustar rootbintomcat-connectors-1.2.50-src/docs/reference/uriworkermap.html0000644000000000000020000005231714655113620022631 0ustar rootbin The Apache Tomcat Connectors - Reference Guide (1.2.50) - uriworkermap.properties configuration

    uriworkermap.properties configuration

    Introduction

    The forwarding of requests from the web server to tomcat gets configured by defining mapping rules. Such a rule maps requests to workers. The request part of the map is described by a URI pattern, the worker by it's worker name.

    The so-called uriworkermap file is a mechanism of defining rules, which works for all web servers. There exist also other web server specific configuration options for defining rules, which will be mostly discussed on the reference pages for configuring tomcat connectors for the individual web servers.

    The name of the file is usually uriworkermap.properties, although this is configurable in the web server. Please consult the web server specific documentation pages on how to enable the uriworkermap file.

    The main features supported by the uriworkermap file are

    • Support for comments in the rule file.
    • Exact and wildchar matches, shortcuts to map a directory and all including content.
    • Exclusion rules, disabling of rules and rule priorities.
    • Rule extensions, modifying worker behaviour per rule.
    • Virtual host integration: uri mapping rules can be expressed per virtual host. The details are web server specific though.
    • Dynamic reloading: The file gets checked periodically for changes. New versions are automatically reloaded without web server restarts.
    • Integration with the status worker.
    The following sections describe these aspects in more detail.

    Syntax

    Line format

    The file has a line based format. There are no continuation characters, so each rule needs to be defined on a single line. Each rule is a pair consisting of a URI pattern and a worker name, combined by an equals sign '=':

    /myapp=myworker
    
    The URI pattern is case sensitive.

    Comments, white space

    All text after and including the character '#' gets ignored and can be used for comments. Leading and trailing white space gets trimmed around the URI pattern and also around the worker name. The following definitions are all equivalent:

    # This is a white space example
    /myapp=myworker
      /myapp=myworker
    /myapp  =  myworker
    

    URI patterns

    Inside the URI pattern three special characters can be used, '*', '?' and '|'. The character '*' is a wildchar that matches any number of arbitrary characters in the URI, '?' matches exactly one character. Each URI pattern has to start with the character '/', or with '*' or with '?', optionally prefixed by any combination of the modifiers '!' and '-' (see next section).

    # Mapping the URI /myapp1 and everything under /myapp1/:
    /myapp1=myworker-a
    /myapp1/*=myworker-a
    # Mapping all URI which end with a common suffix:
    *.jsp=myworker
    *.do=myworker
    
    Since the first case of mapping a certain location and everything inside it is very common, the character '|' gives a handy shortcut:
    # Mapping the URI /myapp1 and everything under /myapp1/:
    /myapp1|/*=myworker-a
    
    The pattern 'X|Y' is exactly equivalent to the two maps 'X' and 'XY'.

    Exclusion, Disabling and Priorities

    Exclusions and rule disabling

    Exclusion rules allows to define exclusions from URI rules, which would forward requests to tomcat. If the exclusion rule matches, the request will not be forwarded. This is usually used to serve static content by the web server. A rule is an exclusion rule, if it is suffixed with '!':

    # Mapping the URI /myapp and everything under /myapp/:
    /myapp|/*=myworker
    # Exclude the subdirectory static:
    !/myapp/static|/*=myworker
    # Exclude some suffixes:
    !*.html=myworker
    
    An exclusion rule overrides a normal mapping rule only, if the worker names in the normal rule and in the exclusion rule are the same. Starting with version 1.2.26 of JK you can apply an exclusion rule to any worker, by using the star character '*' as the worker name in the exclusion rule. More complex patterns in exclusion worker names are not allowed.
    # Mapping the webapps /myapp1 and /myapp2:
    /myapp1|/*=myworker1
    /myapp2|/*=myworker2
    # Exclude the all subdirectories static for all workers:
    !/*/static|/*=*
    # Exclude some suffixes for all workers:
    !*.html=*
    

    Rule disabling comes into play, if your web server merges rules from various sources, and you want to disable any rule defined previously. Since the uriworkermap file gets reloaded dynamically, you can use this to temporarily disable request forwarding: A rule gets disabled, if it is suffixed with '-':

    # We are not in maintenance.
    # The maintenance rule got defined somewhere else.
    -/*=maintenance
    
    Exclusion rules can get disabled as well, then the rule starts with '-!'.

    Mapping priorities

    The most restrictive URI pattern is applied first. More precisely the URI patterns are sorted by the number of '/' characters in the pattern (highest number first), and rules with equal numbers are sorted by their string length (longest first).

    If both distinctions still do not suffice, then the defining source of the rule is considered. Rules defined in uriworkermap.properties come first, before rules defined by JkMount (for the Apache HTTP Server) and inside workers.properties using the mount attribute.

    All disabled rules are ignored. Exclusion rules are applied after all normal rules have been applied.

    There is no defined behaviour, for the following configuration conflict: using literally the same URI pattern in the same defining source but with different worker targets.

    Rule extensions

    Rule extensions were added in version 1.2.27 and are not available in earlier versions.

    Syntax

    Rule extensions are additional attributes, that can be attached to any rule. They are added at the end of the rule, each extension separated by a semicolon:

    # This is an extension example,
    # setting a reply_timeout of 1 minute
    # only for this mapping.
    /myapp=myworker;reply_timeout=60000
    #
    # This is an example using multiple extensions
    /myapp=myloadbalancer;reply_timeout=60000;stopped=member1
    
    Attributes set via rule extensions always overwrite conflicting configurations in the worker definition file.

    Extension reply_timeout

    The extension reply_timeout sets a reply timeout for a single mapping rule.

    # Setting a reply_timeout of 1 minute
    # only for this mapping.
    /myapp=myworker;reply_timeout=60000
    
    It overrides any reply_timeout defined for the worker. The extension allows to set a reasonable default reply timeout to the worker, and a more relaxed reply timeout to URLs, which are known to start time intensive tasks. For a general description of reply timeouts see the timeouts documentation.

    Extension sticky_ignore

    The extension sticky_ignore will disable session stickyness for a single mapping rule.

    # Disable session stickyness
    # only for this mapping.
    /myapp/loginform.jsp=myworker;sticky_ignore=1
    
    This extension can be useful to optimize load balancing when using cookie based session stickyness. In this case, as long as she keeps her browser open, any request by a user who started a session will be send to the same Tomcat instance, even if he left the part of the application which uses the session. You can for instance set this environment variable when a user requests a login form to ensure, that this initial session request is balanced non-sticky.

    This extension is available since version 1.2.33.

    Extension stateless

    The extension stateless is only useful when using session based load balancing. In this case normally any request which does not come with a session id counts as a new session. If you mark a mapping rule with the stateless extension, then the requests matching the mapping rule will not count as a new session, even if they do not come with a session id.

    # Don't let static content trash our session balancing
    /myapp/static/*=myworker;stateless=1
    
    This extension is available since version 1.2.33.

    Extensions active/disabled/stopped

    The extensions active, disabled, and stopped can be used in a load balancer mapping rule to set selected members of the load balancer into a special activation state.

    # Stop forwarding only for member1 of loadbalancer
    /myapp=myloadbalancer;stopped=member1
    
    Multiple members must be separated by commas or white space:
    # Stop forwarding for member01 and member02 of loadbalancer
    # Disable forwarding for member21 and member22 of loadbalancer
    /myapp=myloadbalancer;stopped=member01,member02;disabled=member21,member22
    
    For the precise meaning of the activation states see the description of activation.

    Extension fail_on_status

    The extension fail_on_status can be used in any rule:

    # Send 503 instead of 404 and 500,
    # and if we get a 503 also set the worker to error
    /myapp=myworker;fail_on_status=-404,-500,503
    
    Multiple status codes must be separated by commas. For the precise meaning of the attribute see the description of fail_on_status.

    Extension use_server_errors

    The extension use_server_errors allows to let the web server send an error page, instead of the backend (e.g. Tomcat) error page. This is useful, if one wants to send customized error pages, but those are not part of all web applications. They can then be put onto the web server.

    The value of use_server_errors is a positive number. Any request send to the backend, that returns with an http status code bigger or equal to use_server_errors, will be answered to the client with the error page of the web server for this status code.

    # Use web server error page for all errors
    /myapp=myworker;use_server_errors=400
    # Use web server error page only for technical errors
    /myotherapp=myworker;use_server_errors=500
    

    Extensions controlling load balancer stickyness

    The extensions

    • session_cookie
    • session_path
    • set_session_cookie
    • session_cookie_path
    allow to define the load balancer worker attributes of the same name per mount. See their descriptions in the worker.properties configuration reference.

    Virtual host integration

    ISAPI redirector for Microsoft IIS

    When using the ISAPI redirector for Microsoft IIS you can restrict individual rules to special virtual hosts by prefixing the URI pattern with the virtual host information. The rules is that the url must be prefixed with the host name.

    # Use www.foo.org as virtual host
    /www.foo.org/myapp/*=myworker
    # Use www.bar.org as virtual host
    /www.bar.org/myapp/*=myworker
    # Normal mapping
    /mysecondapp/*=myworker
    

    Note that /mysecondapp/* will be mapped to all virtual hosts present. In case one needs to prevent the mappings to some particular virtual host then the exclusion rule must be used

    # Make sure the myapp is accessible by all virtual hosts
    /myapp/*=myworker
    # Disable mapping myapp for www.foo.org virtual host
    !/www.foo.org/myapp/*=myworker
    

    mod_jk for Apache HTTP Server

    For the Apache HTTP Server you can define individual uriworkermap files per virtual host. The directive JkMountFile can be used in the main server and in each virtual host. If a virtual host does not use JkMountfile, but JkMountCopy is set to 'On', then it inherits the JkMountFile from the main server. If you want all vhost to inherit mounts from the main server, you can set JkMountCopy to 'All' in the main server.

    Dynamic reloading

    When a request is being processed, tomcat connectors check the file modification time of the uriworkermap file. To keep the performance penalty low, this happens only, if the last check happened at least n seconds ago.

    For the Apache HTTP Server you can configure the interval "n" using the directive JkMountFileReload, for Microsoft IIS you would use the attribute worker_mount_reload. The default value is 60 seconds. A value of "0" turns off the reloading.

    If the file changed, it gets reloaded completely. If there exist rules coming from other sources than the uriworkermap file (e.g. the workers.properties mount attribute or JkMount for the Apache HTTP Server), the new uriworkermap file gets dynamically merged with these ones exactly like when you do a web server restart.

    Until version 1.2.19 reloading behaved slightly differently: it continuously added the full contents of the uriworkermap file to the rule mapping. The merging rules were, that duplicated got eliminated and old rules could be disabled, by defining the rule as disabled in the new file. Rules never got deleted.

    Status worker integration

    The configuration view of the status worker also shows the various mapping rules. After each worker's configuration, the rules are listed, that forward to this worker. The list contains four columns:

    • the name of the virtual server
    • the URI pattern, prefixed with '-' for a disabled pattern and '!' for an exclusion pattern
    • the type of the rule: Exact or Wildchar
    • and the source of the rule definition: 'worker definition' for the workers.properties file (mount attribute), 'JkMount' for the Apache HTTP Server JkMount and it's relatives and finally 'uriworkermap' for the uriworkermap file.

    Note: The following restriction has been removed starting with version 1.2.26.
    For the Apache HTTP Server, there is an important subtlety: the request going to the status worker gets executed in the context of some server (main or virtual). The status worker will only show the mapping rules, that are defined for this server (main or virtual).
    Until version 1.2.25 the list contained three columns:

    • the type of the rule: Exact or Wildchar, eventually prefixed with Disabled or Unmount (for exclusion rules)
    • the URI pattern
    • and the source of the rule definition: 'worker definition' for the workers.properties file (mount attribute), 'JkMount' for the Apache HTTP Server JkMount and it's relatives and finally 'uriworkermap' for the uriworkermap file.

    tomcat-connectors-1.2.50-src/docs/reference/workers.html0000644000000000000020000017411514655113620021577 0ustar rootbin The Apache Tomcat Connectors - Reference Guide (1.2.50) - workers.properties configuration

    workers.properties configuration

    Introduction

    A Tomcat worker is a Tomcat instance that is waiting to execute servlets or any other content on behalf of some web server. For example, we can have a web server such as the Apache HTTP Server forwarding servlet requests to a Tomcat process (the worker) running behind it.

    The scenario described above is a very simple one; in fact one can configure multiple Tomcat workers to serve servlets on behalf of a certain web server. The reasons for such configuration can be:

    • We want different contexts to be served by different Tomcat workers to provide a development environment where all the developers share the same web server but own a Tomcat worker of their own.
    • We want different virtual hosts served by different Tomcat processes to provide a clear separation between sites belonging to different companies.
    • We want to provide load balancing, meaning run multiple Tomcat workers each on a machine of its own and distribute the requests between them.

    There are probably more reasons for having multiple workers but I guess that this list is enough...

    Tomcat workers are defined in a properties file dubbed workers.properties and this tutorial explains how to work with it.

    Configuration File Basics

    Defining workers to the Tomcat web server plugin can be done using a properties file (a sample file named workers.properties is available in the conf/ directory).

    Format, Comments, Whitespace

    The lines in the file define properties. The general format is

    <name>=<value>

    Dots are used as part of the name to represent a configuration hierarchy.

    Invalid directives will be logged during web server startup and prevent the web server from working properly. Some directives have been deprecated. Although they will still work, you should replace them by their successors.

    Some directives are allowed multiple times. This will be explicitly noted in the tables below.

    Whitespace at the beginning and the end of a property name or value gets ignored. Comments can be placed in any line and start with a hash sign '#'. Any line contents behind the hash sign get ignored.

    Boolean properties can be set either using the numbers 0 (false) and 1 (true) as values, or off (false) and on (true) or any other string starting with the letters f (false), n (false), t (true) or y (true). The values are taken case insensitive. In this documentation we will stick to false and true.

    Global Properties

    These directives have global scope.

    Directive Default Description
    worker.listajp13 A comma separated list of workers names that the JK will use. When starting up, the web server plugin will instantiate the workers whose name appears in the worker.list property, these are also the workers to whom you can map requests.

    This directive can be used multiple times.

    worker.maintain60 Worker connection pool maintain interval in seconds. If set to the positive value JK will scan all connections for all workers specified in worker.list directive and check if connections needs to be recycled.

    Furthermore any load balancer does a global maintenance every worker.maintain seconds. During global maintenance load counters are decayed and workers in error are checked for recover_time.

    This feature has been added in jk 1.2.13.

    Worker Properties

    Each worker configuration directive consists of three words separated by a dot:

    worker.<worker name>.<directive>=<value>

    The first word is always worker. The second word is the worker name you can choose. In the case of load balancing, the worker name has an additional meaning. Please consult the Load Balancer HowTo.

    The name of the worker can contain only the alphanumeric characters [a-z][A-Z][0-9][_\-] and is case sensitive.

    Variables, Environment Variables

    You can define and use variables in the workers.properties file. To define a variable you use the syntax:

    <variable_name>=<value>

    Dots are allowed in the variable name, but you have to be careful not to use variable names, that clash with standard directives. Therefore variable names should never start with "worker.".

    To use a variable, you can insert "$(variable_name)" at any place on the value side of a property line. If a variable has not been defined before its use, we will search the process environment for a variable with the same name and use their value.

    Property Inheritance

    Often one wants to use the same property values for various workers. To reduce duplication of configuration lines and to ease the maintenance of the file, you can inherit properties from one worker to another, or even from a template to real workers.

    The directive "reference" allows to copy configurations between workers or worker templates in a hierarchical way. If worker castor sets worker.castor.reference=worker.pollux then it inherits all properties of pollux, except for the ones that are explicitly set for castor.

    Please note, that the value of the directive is not only the name of the referred worker, but the complete prefix including "worker.".

    To use a template worker simply define it like a real worker, but do not add it to the worker.list or as a member to any load balancer. Such a template worker does not have to contain mandatory directives. This approach is especially useful, if one has a lot of balanced workers in a load balancer and these workers share most of their properties. You can set all of these properties in a template worker, e.g. using the prefix "worker.template1", and then simply reference those common properties in all balanced workers.

    References can be used to inherit properties over multiple hops in a hierarchical way. The maximum depth for nesting references is 20. Be careful not to introduce a reference loop!

    This feature has been added in jk 1.2.19.

    List of All Worker Directives

    Mandatory Directives

    Mandatory directives are the one that each worker must contain. Without them the worker will be unavailable or will misbehave. Those directives will be marked with a strong font in the following tables.

    Directive Default Description
    typeajp13 Type of the worker (can be one of ajp12, ajp13, ajp14, jni, lb or status). The type of the worker defines the directives that can be applied to the worker.

    Type ajp13 is the preferred worker type that JK uses for communication between web server and Tomcat. This type of worker uses sockets as communication channel. For detailed description of the ajp13 protocol stack browse to AJPv13 protocol specification. Type lb is used for load balancing workers, type status for status workers.

    Type ajp14 is experimental and not recommended, type ajp12 is obsolete.

    JNI workers are no longer supported and will likely not work. Do not use them.

    Connection Directives

    Connection directives defines the parameters needed to connect and maintain the connections pool of persistent connections between JK and remote Tomcat.

    Directive Default Description
    hostlocalhost Host name or IP address of the backend Tomcat instance. The remote Tomcat must support the AJP13 protocol stack. The host name can have a port number embedded separated by the colon (':') character.
    port8009 Port number of the remote Tomcat instance listening for defined protocol requests. The default value depends on the worker type. For ajp13 workers the default port is 8009, while for ajp14 type of worker that value is 8011.
    source- Name or IP address used for the connection source (outgoing address). It should only be used on multi-homed hosts.

    This feature is experimental and has been added in jk 1.2.41.

    socket_timeout0 Socket timeout in seconds used for the communication channel between JK and remote host. If the remote host does not respond inside the timeout specified, JK will generate an error, and retry again. If set to zero (default) JK will wait for an infinite amount of time on all socket operations.
    socket_connect_timeoutsocket_timeout*1000 Socket connect timeout in milliseconds used for the communication channel between JK and remote host. If the remote host does not respond inside the timeout specified, JK will generate an error, and retry again.

    Note that socket_timeout is in seconds, and socket_connect_timeout in milliseconds, so in absolute terms the default socket_connect_timeout is equal to socket_timeout.

    This feature has been added in jk 1.2.27.

    socket_keepalivefalse This directive should be used when you have a firewall between your web server and the Tomcat engine, who tend to drop inactive connections. This flag will tell the Operating System to send KEEP_ALIVE messages on inactive connections (interval depend on global OS settings, generally 120 minutes), and thus prevent the firewall to cut inactive connections. To enable keepalive set this property value to true.

    The problem with Firewall cutting inactive connections is that sometimes, neither web server or Tomcat have information about the cut and couldn't handle it.

    ping_mode- This flag determines, under which conditions established connections are probed to ensure they are still working. The probe is done with an empty AJP13 packet (CPing) and expects to receive an appropriate answer (CPong) within some timeout.

    The value of the flag can be any combination of the following flags (multiple values are combined without any separators):

    C (connect): If set, the connection will be probed once after connecting to the backend. The timeout can be set by connect_timeout. If it is not set, the value of ping_timeout will be used instead.

    P (prepost): If set, the connection will be probed before sending each request to the backend. The timeout can be set by prepost_timeout. If it is not set, the value of ping_timeout will be used instead.

    I (interval): If set, the connection will be probed during the regular internal maintenance cycle, but only if it is idle longer than connection_ping_interval. The timeout can be set by ping_timeout.

    A If set, all of the above probes will be used.

    This feature has been added in jk 1.2.27. Connect and prepost probing were already available via connect_timeout and prepost_timeout since version jk 1.2.6.

    ping_timeout10000 Timeout in milliseconds used when waiting for the CPong answer of a CPing connection probe. The activation of the probes is done via ping_mode. The timeouts for ping_mode connect and prepost can be overwritten individually via connect_timeout and prepost_timeout.

    For compatibility reasons, CPing/CPong is also used, whenever connect_timeout or prepost_timeout are set, even if ping_mode is empty.

    This feature has been added in jk 1.2.27.

    connection_ping_interval0 / (ping_timeout/1000)*10 When using interval connection probing, connections idle for longer than this interval in seconds are probed by CPing packets whether they still work.

    Interval probing can be activated either by ping_mode, or by setting connection_ping_interval to some value bigger than zero. If you activate interval probing via ping_mode, then the default value of connection_ping_interval is (ping_timeout/1000) * 10. Note that ping_timeout is in milliseconds, and connection_ping_interval in seconds, so in absolute terms the default connection_ping_interval is 10 times ping_timeout.

    This feature has been added in jk 1.2.27.

    connection_pool_sizesee text This defines the number of connections made to the AJP backend that are maintained as a connection pool. It will limit the number of those connection that each web server child process can made.

    Connection pool size property is only used for multi threaded web servers such as the Apache HTTP Server and Microsoft IIS. The connection_pool_size property needs to reflect the number of requests one web server process should be able to send to a backend in parallel. Usually this is the same as the number of threads per web server process. JK will discover this number for the Apache HTTP Server automatically and set the pool size to this value. For IIS the default value is 250 (before version 1.2.20: 10).

    We strongly recommend adjusting this value for IIS to the number of requests one web server process should be able to send to a backend in parallel. You should measure how many connections you need during peak activity without performance problems, and then add some percentage depending on your growth rate. Finally you should check, whether your web server processes are able to use at least as many threads, as you configured as the pool size.

    Do not use connection_pool_size with values higher then 1 on Apache 2.x with prefork MPM or Apache 1.3.x!
    connection_pool_minsize(pool+1)/2 Minimum size of the connection pool that will be maintained.

    Its default value is (connection_pool_size+1)/2.

    Do not use connection_pool_minsize with values higher then 1 on Apache 2.x with prefork MPM or Apache 1.3.x!

    This feature has been added in jk 1.2.16.

    connection_pool_timeout0 Cache timeout property should be used with connection_pool_minsize to specify how many seconds JK should keep an inactive socket in cache before closing it. This property should be used to reduce the number of threads on the Tomcat web server. The default value zero disables the closing (infinite timeout).

    Each child could open an ajp13 connection if it has to forward a request to Tomcat, creating a new ajp13 thread on Tomcat side.

    The problem is that after an ajp13 connection is created, the child won't drop it until killed. And since the web server will keep its childs/threads running to handle high-load, even it the child/thread handle only static contents, you could finish having many unused ajp13 threads on the Tomcat side.

    You should keep this time interval in sync with the keepAliveTimeout attribute (if it is set explicitly) or connectionTimeout attribute of your AJP connector in Tomcat's server.xml. Note however, that the value for mod_jk is given in seconds, the one in server.xml has to use milliseconds.

    connection_acquire_timeoutretries*retry_interval Timeout the worker will wait for a free socket in cache before giving up.

    Its default value is retries * retry_interval.

    This feature has been added in jk 1.2.27.

    lbfactor1 Only used for a member worker of a load balancer.

    The integer number lbfactor (load balancing factor) is how much we expect this worker to work, or the worker's work quota. Load balancing factor is compared with other workers that makes the load balancer. For example if one worker has lbfactor 5 times higher then other worker, then it will receive five times more requests.

    Load Balancing Directives

    Load balancer is a virtual worker that does not really communicate with Tomcat workers. Instead it is responsible for the management of several "real" workers. The worker is supposed to be a load balancer if it's worker type is lb. See worker's type directive.

    Loadbalancer directives define the parameters needed to create the workers that are connecting to a remote cluster of backend Tomcat servers. Each cluster node has to have a worker defined.

    Load balancer management includes:

    • Instantiating the workers in the web server.
    • Using the worker's load balancing factor, perform weighted round-robin load balancing where high lbfactor means stronger machine (that is going to handle more requests)
    • Keeping requests belonging to the same session executing on the same Tomcat worker.
    • Identifying failed Tomcat workers, suspending requests to them and instead fail over on other workers managed by the lb worker.

    The overall result is that workers managed by the same lb worker are load balanced (based on their lbfactor and current user session) and also fail over so a single Tomcat process death will not "kill" the entire site.

    If you want to use session stickiness, you must set different jvmRoute attributes in the Engine element in Tomcat's server.xml. Furthermore the names of the workers which are managed by the balancer have to be equal to the jvmRoute of the Tomcat instance they connect with.

    The restriction on the worker names can be lifted, if you use the route attribute for the workers.

    The following table specifies properties that the lb worker can accept:

    Directive Default Description
    balance_workers- A comma separated list of workers that the load balancer need to manage.

    This directive can be used multiple times for the same load balancer.

    This directive replaces old balanced_workers directive and can be used only with mod_jk versions 1.2.7 and up.

    As long as these workers should only be used via the load balancer worker, there is no need to also put them into the worker.list property.
    sticky_sessiontrue Specifies whether requests with SESSION ID's should be routed back to the same Tomcat worker. If sticky_session is set to true sessions are sticky, otherwise sticky_session is set to false. Set sticky_session to false when Tomcat is using a Session Manager which can persist session data across multiple instances of Tomcat.

    The sticky_session setting can be overwritten using the Apache HTTP Server environment variable JK_STICKY_IGNORE and the worker map extension for sticky_ignore. This has been added in version 1.2.33.

    sticky_session_forcefalse Specifies whether requests with SESSION ID's for workers that are in error state should be rejected. If sticky_session_force is set to true and the worker that matches that SESSION ID is in error state, client will receive 500 (Server Error). If set to false failover on another worker will be issued with losing client session. This directive is used only when you set sticky_session=true.

    This feature has been added in jk 1.2.9.

    methodRequest Specifies what method load balancer is using for electing the best worker. Please note, that session stickiness and perfect load balancing are conflicting targets, especially when the number of sessions is small, or the usage of sessions is extremely varying For huge numbers of sessions this usually is not a problem.

    Some methods note, that they aggregate in a sliding time window. They add up accesses, and on each run of the global maintain method, the load counters get divided by 2. Usually this happens once a minute, depending on the setting of worker.maintain. The value of the load counters can be inspected using the status worker.

    If method is set to R[equest] the balancer will use the number of requests to find the best worker. Accesses will be distributed according to the lbfactor in a sliding time window. This is the default value and should be working well for most applications.

    If method is set to S[ession] the balancer will use the number of sessions to find the best worker. Accesses will be distributed according to the lbfactor in a sliding time window. This method should be used, if sessions are your limiting resource, e.g. when you only have limited memory and your sessions need a lot of memory. Because the balancer does not keep any state, it actually does not know the number of sessions. Instead it counts each request without a session cookie or URL encoding as a new session. This method will neither know, when a session is being invalidated, nor will it correct its load numbers according to session timeouts or worker failover. If you know request URLs, that will be called without a session ID but should not be counted as new sessions, you should add them to the stateless mapping rule extension or set the Apache HTTP Server environment variable JK_STATELESS for them.

    If method is set to N[ext] the balancer will again use the number of sessions to find the best worker. All remarks concerning the Session method apply as well. The difference to the Session method is how the session count is handled in the sliding time window. The Next method does not divide by 2, instead it subtracts the current minimum number. This should effectively result in a round-robin session balancing, thus the name Next. Under high load, the two session balancing methods will result in a similar distribution, but Next will be better if you need to distribute small numbers of sessions.

    If set to T[raffic] the balancer will use the network traffic between JK and Tomcat to find the best worker. Accesses will be distributed according to the lbfactor in a sliding time window. This method should be used, if network to and from the backends is your limiting resource.

    If set to B[usyness] the balancer will pick the worker with the lowest current load, based on how many requests the worker is currently serving. This number is divided by the workers lbfactor, and the lowest value (least busy) worker is picked. This method is especially interesting, if your request take a long time to process, like for a download application. The method is not recommended for general use, because under high load on some hardware architectures the busy counter can become wrong.

    This feature has been added in version 1.2.9. The Session method has been added in version 1.2.20, the Next method in version 1.2.33.

    lockOptimistic Specifies what lock method the load balancer will use for synchronising shared memory runtime data. If lock is set to O[ptimistic] balancer will not use shared memory lock to find the best worker. If set to P[essimistic] balancer will use shared memory lock. The balancer will work more accurately in case of Pessimistic locking, but can slow down the average response time.

    This feature has been added in jk 1.2.13.

    retries2 This directive also exists for normal workers. For those it has a different meaning. When making a request, the load-balancer worker will allocate the request to a member worker. If that member worker is either unable to service the request or fails to service the request, the request will be passed to another member worker until the request is processed, every member worker has attempted to process the request or lb_retries member workers have attempted to process the request.

    If the request remains unprocessed, the load-balancer worker will repeat the above process a maximum of retries times (including the original attempt). Before each retry, the load-balancer worker will pause for a time defined by the retry_interval directive.

    Note that this means that, if all workers fail, there will be a total of worker.retries * min(lb.lb_retries,member worker count) * lb.retries requests before a 504 response is returned to the client. So for an lb worker with four members and a default configuration, if all workers fail there will be a total of 8 requests before a 504 response is returned to the client.

    Until version 1.2.16 the default value was 3.

    lb_retries2 When making a request, the load-balancer worker will allocate the request to a member worker. If that member worker is either unable to service the request or fails to service the request, the request will be passed to another member worker until the request is processed, every member worker has attempted to process the request or lb_retries member workers have attempted to process the request.

    If the request remains unprocessed, the load-balancer worker will repeat the above process a maximum of retries times (including the original attempt). Before each retry, the load-balancer worker will pause for a time defined by the retry_interval directive.

    Note that this means that, if all workers fail, there will be a total of worker.retries * min(lb.lb_retries,member worker count) * lb.retries requests before a 504 response is returned to the client. So for an lb worker with four members and a default configuration, if all workers fail there will be a total of 8 requests before a 504 response is returned to the client.

    This feature has been added in jk 1.2.44. Prior to this feature being added, the load-balancer worker behaved as if lb_retries was equal to the number of member workers.

    Status Worker Directives

    The status worker does not communicate with Tomcat. Instead it is responsible for the load balancer management.

    Directive Default Description
    css- Specifies the url for cascading stylesheet to use.
    read_onlyfalse A status worker with read_only=true will not allow any operations, that change the runtime state or configuration of the other workers. These are edit/update/reset/recover.

    This feature has been added in jk 1.2.20.

    user- It is a list of users which gets compared to the user name authenticated by the web server. If the name is not contained in this list, access is denied. Per default the list is empty and then access is allowed to anybody.

    This directive can be used multiple times.

    This feature has been added in jk 1.2.20.

    user_case_insensitivefalse By default, the user names are matched case sensitively. You can set user_case_insensitive=true to make the comparison case insensitive. This may be especially useful on the Windows platform.

    This feature has been added in jk 1.2.21.

    gooda.o,a.n,a.b,a.r For every load balancer worker, the status worker shows a summary of the state of its members. There are three such states, "good", "bad" and "degraded".

    These states are determined depending on the activation of the members (active, disabled, stopped) and their runtime state (ok, n/a, busy, recovering, probing, forced recovery, error). By default, members are assumed to be "good", if their activation is "active" and their runtime state is not "error".

    You can change this mapping, by assigning a list of values to the attribute "good". Each value gives a possible match for the members, and one match suffices. Each value is either a single character, or two characters combined with a dot ".". The single characters are the first characters in the words "active", "disabled", "stopped", "ok", "na", "busy", "recovering", "error". The additional states "probing" and "forced recovery" are always rated equivalent to "recovering". If a value consists only of a single character, then all members with this activation or runtime state will be assumed good. A combination of an activation and a runtime state concatenated with a dot "." does only apply to a member, that has exactly this activation and state.

    Members of a load balancer will first be matched against the state "bad", if they don't match, the state "good" will be tried, and if they still don't match, their state will be "degraded".

    This directive can be used multiple times.

    This feature has been added in jk 1.2.20.

    bads,e See: "good".

    By default, members are assumed to be "bad", if their activation is "stopped" or their runtime state is "error".

    This directive can be used multiple times.

    This feature has been added in jk 1.2.20.

    prefixworker The prefix, which will be used by the status worker when producing properties output (mime=prop). Each property key will be prefixed by this value.

    This feature has been added in jk 1.2.20.

    nsjk: This directive can be used to customise the XML output from the status worker. If set to - no namespace will be used.

    This feature has been added in jk 1.2.20.

    xmlns- This directive can be used to customise the XML output from the status worker. If set to - no xmlns will be used.

    Default value is set to xmlns:jk="http://tomcat.apache.org"

    This feature has been added in jk 1.2.20.

    doctype- This directive can be used to customise the XML output from the status worker. This value will be inserted to the output xml after the xml header.

    This feature has been added in jk 1.2.20.

    Advanced Worker Directives

    This table lists more advanced configuration options. Most of them only apply to some types of workers. We use the abbreviations AJP for ajp13/ajp14 workers used directly via the workers.list, LB for load balancer workers, and SUB for the workers used indirectly in a load balancer worker as a sub worker or member.

    DirectiveWorker TypeDefaultDescription
    connect_timeoutAJP,SUB0 Connect timeout property told web server to send a PING request on ajp13 connection after connection is established. The parameter is the delay in milliseconds to wait for the PONG reply. The default value zero disables the timeout (infinite timeout).

    This features has been added in jk 1.2.6 to avoid problem with hung Tomcat's and require ajp13 ping/pong support which has been implemented on Tomcat 3.3.2+, 4.1.28+ and 5.0.13+. Disabled by default.

    prepost_timeoutAJP,SUB0 Prepost timeout property told web server to send a PING request on ajp13 connection before forwarding to it a request. The parameter is the delay in milliseconds to wait for the PONG reply. The default value zero disables the timeout (infinite timeout).

    This features has been added in jk 1.2.6 to avoid problem with hung Tomcat's and require ajp13 ping/pong support which has been implemented on Tomcat 3.3.2+, 4.1.28+ and 5.0.13+. Disabled by default.

    reply_timeoutAJP,SUB0 The parameter is the number of milliseconds to wait for success during a read event. So this is not a timeout for the complete answer time of a request, but only for the maximum time between two packets received from Tomcat. Usually the longest pause is between sending the request and getting the first packet of the response.

    If the timeout passes without any data received from Tomcat, the web server will no longer wait for the rest of the response and send an error to the client (browser). Usually this does not mean, that the request is also aborted on the Tomcat backend. If the worker is a member of a load balancer, the load balancer might place the worker into an error state and retry the request on another member. See also max_reply_timeouts, retries and recovery_options.

    By default (value zero) the web server will wait forever which could be an issue for you. If you set a reply_timeout, adjust it carefully if you have long running servlets.

    The reply_timeout can be overwritten using the Apache HTTP Server environment variable JK_REPLY_TIMEOUT and the worker map extension for reply_timeout.

    This features has been added in jk 1.2.6 to avoid problem with hung Tomcat's and works on all servlet engines supporting ajp13. The variable JK_REPLY_TIMEOUT and the worker map extension have been added in version 1.2.27.

    retriesAJP,SUB2 This directive also exists for load balancer workers. For those it has a different meaning. The maximum number of times that the worker will send a request to Tomcat in case of a communication error. Each retry will be done over another connection. The first time already gets counted, so retries=2 means one retry after error. Before a retry, the worker waits for a configurable sleeping time.

    See also the attribute recovery_options for a more fine-grained control of retries and retry_interval for the sleep time configuration.

    Until version 1.2.16 the default value was 3.

    retry_intervalAJP,SUB100 The amount of time in milliseconds the worker sleeps before doing any retry.

    This features has been added in jk 1.2.27.

    recovery_optionsAJP,SUB0 Recovery options influence, how we should handle retries, in case we detect a problem with Tomcat. How often we will retry is controlled by the attribute retries.

    This attribute is a bit mask. The following bits are allowed:
    1: don't recover if Tomcat failed after getting the request
    2: don't recover if Tomcat failed after sending the headers to client
    4: close the connection to Tomcat, if we detect an error when writing back the answer to the client (browser)
    8: always recover requests for HTTP method HEAD (even if Bits 1 or 2 are set)
    16: always recover requests for HTTP method GET (even if Bits 1 or 2 are set)

    This features has been added in jk 1.2.6. Option 4 has been added in version 1.2.16, options 8 and 16 in version 1.2.24.

    fail_on_statusAJP,SUB0 Set this value to the HTTP status code that will cause a worker to fail if returned from Servlet container. Use this directive to deal with cases when the servlet container can temporary return non-200 responses for a short amount of time, e.g during redeployment.

    The error page, headers and status codes of the original response will not be send back to the client. Instead the request will result in a 503 response. If the worker is a member of a load balancer, the member will be put into an error state. Request failover and worker recovery will be handled with the usual load balancer procedures.

    This feature has been added in jk 1.2.20.

    Starting with jk 1.2.22 it is possible to define multiple status codes separated by space or comma characters. For example: worker.xxx.fail_on_status=500,503

    Starting with jk 1.2.25 you can also tell the load balancer to not put a member into an error state, if a response returned with one of the status codes in fail_on_status. This feature gets enabled, by putting a minus sign in front of those status codes. For example: worker.xxx.fail_on_status=-404,-500,503

    busy_limitAJP,SUB0 If set to a positive number, the worker will only be used for a request, if it is currently working on less than this number of concurrent requests.

    Note that this is not related to the Busyness load balancing method.

    This feature is experimental and has been added in jk 1.2.41.

    max_packet_sizeAJP,SUB8192 This attribute sets the maximal AJP packet size in Bytes. It should be a multiple of 1024. Configuration values that are not a multiple of 1024 will be aligned to the next multiple of 1024. The maximum value is 65536. If you change it from the default, you must also change the packetSize attribute of your AJP connector on the Tomcat side! The attribute packetSize is available in Tomcat 6.0.2 onwards.

    Normally it is not necessary to change the maximum packet size. Problems with the default value have been reported when sending certificates or certificate chains.

    This feature has been added in jk 1.2.19.

    prefer_ipv6AJP,SUBfalse When compiled with IPV6 support, this directive forces IPV6 address resolution for host names which have both IPV6 and IPV4 addresses. In case there is no IPV6 address defined for the given hostname this directive in ineffective. This directive will be also ineffective if there is only IPV6 address defined or if IP address is used for "host", either in IPV4 or IPV6 notation.

    This feature has been added in jk 1.2.38.

    secretAJP,SUB,LB- You can set a secret keyword on the Tomcat AJP Connector. Then only requests from workers with the same secret keyword will be accepted.

    Use attribute secret="secret key word" in your Tomcat AJP Connector configuration. (Historical note: the attribute name was requiredSecret in Tomcat 9.0, 8.x, 7.0 versions released earlier than February 2020, request.secret in Tomcat 6.0 and earlier.)

    If you set a secret on a load balancer, all its members will inherit this secret.

    This feature has been added in jk 1.2.12.

    mountAJP,LB- Space delimited list of uri maps the worker should handle. It is only used, if the worker is included in worker.list.

    This directive can be used multiple times for the same worker.

    max_reply_timeoutsLB0 If you use a reply_timeout for the members of a load balancer worker, and you want to tolerate a few requests taking longer than reply_timeout, you can set this attribute to some positive value.

    Long running requests will still time out after reply_timeout milliseconds waiting for data, but the corresponding member worker will only be put into an error state, if more than max_reply_timeouts requests have timed out. More precisely, the counter for those bad requests will be divided by two, whenever the load balancer does its internal maintenance (by default every 60 seconds).

    This features has been added in jk 1.2.24 to make reply_timeout less sensitive for sporadic long running requests.

    recover_timeLB60 The recover time is the time in seconds the load balancer will not try to use a worker, after it went into error state. Only after this time has passed, a worker in error state will be marked as in recovering, so that it will be tried for new requests.

    This interval is not checked every time a request is being processed. Instead it is being checked during global maintenance. The time between two runs of global maintenance is controlled by worker.maintain.

    Do not set recover_time to a very short time unless you understand the implications. Every recovery attempt for a worker in error is done by a real request!

    error_escalation_timeLBrecover_time / 2 Setting a member of a load balancer into an error state is quite serious. E.g. it means that if you need stickyness, all access to the sessions of the respective node is blocked.

    Some types of error detection do not provide a precise information, whether a node is completely broken or not. In those cases an LB will not immediately put the node into the error state. Only when there have been no successful responses for error_escalation_time seconds after such an error, will the node be put into error state.

    This features has been added in jk 1.2.28.

    session_cookieLBJSESSIONID The name of the cookie that contains the routing identifier needed for session stickyness. The routing identifier is everything after a "." character in the value of the cookie.

    This feature has been added in jk 1.2.27.

    session_pathLB;jsessionid The name of the path parameter that contains the routing identifier needed for session stickyness. The routing identifier is everything after a "." character in the value of the path parameter.

    This feature has been added in jk 1.2.27.

    set_session_cookieLBfalse Activates generation of session stickyness cookies. Typically you don't need this.

    Some web frameworks replace Tomcat session management and use a different way of generating session IDs. As a consequence the routing ID added by Tomcat to the end of the session ID is lost and we no longer can do sticky load balancing. As a workaround you can use the following steps:

    • Choose a non-standard cookie name using the "session_cookie" attribute.
    • Activate cookie sending by setting the attribute "set_session_cookie" to true.
    • Set the attribute "session_cookie_path" to the correct application URI, like e.g. "/myapp/".

    The cookie will only be send if the request does not already contain a cookie of the same name, or that cookie does not contain a routing ID which the load balancer can fulfill. Especially after a node failover we will send a new cookie to switch stickyness to the new node.

    This feature has been added in jk 1.2.38.

    session_cookie_pathLB- This attribute is only used if "set_session_cookie" is set to true. See "set_session_cookie" for a description. If the value of "session_cookie_path" is empty (default), then the send cookie will not contain a PATH information.

    This feature has been added in jk 1.2.38.

    activationSUBActive Using this directive, a balanced worker of a load balancer can be configured as disabled or stopped. A disabled worker only gets requests, which belong to sessions for that worker. A stopped worker does not get any requests. Users of a stopped worker will lose their sessions, unless session replication via clustering is used.

    Use d or D to disable and s or S to stop. If this directive is not present the deprecated directives "disabled" or "stopped" are used.

    This flag can be changed at runtime using status worker.

    This feature has been added in jk 1.2.19.

    routeSUBworker name Normally the name of a balanced worker in a load balancer is equal to the jvmRoute of the corresponding Tomcat instance. If you want to include a worker corresponding to a Tomcat instance into several load balancers with different balancing configuration (e.g. disabled, stopped) you can use this attribute.

    Define a separate worker per lb and per Tomcat instance with an arbitrary worker name and set the route attribute of the worker equal to the jvmRoute of the target Tomcat instance.

    If this attribute is left empty, the name of the worker will be used.

    This attribute can be changed at runtime using status worker.

    If the route name contains a period, the part before the first period will be used as domain name, unless domain is set explicitly.

    This feature has been added in jk 1.2.16.
    The automatic domain rule has been added in jk 1.2.20.
    The attribute has been renamed from jvm_route to route in jk 1.2.20.

    distanceSUB0 An integer number to express preferences between the balanced workers of an lb worker. A load balancer will never choose some balanced worker in case there is another usable worker with lower distance.

    Only in case all workers below a given distance are in error, disabled or stopped, workers of a larger distance are eligible for balancing.

    This feature has been added in jk 1.2.16.

    domainSUB- Domain directive can be used only when the worker is a member of the load balancer. Workers that share the same domain name are treated as single worker. If sticky_session is used, then the domain name is used as session route.

    This directive is used for large system with more then 6 Tomcats, to be able to cluster the Tomcats in two groups and thus lowering the session replication transfer between them.

    This feature has been added in jk 1.2.8.

    redirectSUB- Set to the name of the preferred failover worker. If worker matching SESSION ID is in error state then the redirect worker will be used instead. It will be used even if being disabled, thus offering hot standby.

    If you explicitly set a route via the "route" attribute, you must set "redirect" to this route of the preferred failover worker and not to its name.

    This feature has been added in jk 1.2.9.

    Deprecated Worker Directives

    The following directives have been deprecated in the past. We include their documentation in case you need to use an older version of mod_jk. We urge you to update and not use them any more. Please migrate your existing configurations.

    DirectiveSuccessorDefaultDescription
    cachesizeconnection_pool_sizesee text This directive has been deprecated since 1.2.16. Cachesize defines the number of connections made to the AJP backend that are maintained as a connection pool. It will limit the number of those connection that each web server child process can make.

    Cachesize property is used only for multi threaded web servers such as Apache HTTP Server 2.x (all MPMs except prefork) and IIS. The cachesize property should reflect the number of threads per child process. JK will discover the number of threads per child process on the Apache HTTP Server with threaded MPM and set its default value to match the current ThreadsPerChild Apache configuration. For IIS the default value is 10.

    Do not use cachesize with values higher then 1 on Apache 2.x with prefork MPM or Apache 1.3.x!
    cache_timeoutconnection_pool_timeout0 This directive has been deprecated since 1.2.16. Cache timeout property should be used with cachesize to specify how to time JK should keep an open socket in cache before closing it. This property should be used to reduce the number of threads on the Tomcat web server.

    Each child could open an ajp13 connection if it have to forward a request to Tomcat, creating a new ajp13 thread on Tomcat side.

    The problem is that after an ajp13 connection is created, the child won't drop it until killed. And since the web server will keep its childs/threads running to handle high-load, even it the child/thread handle only static contents, you could finish having many unused ajp13 threads on the Tomcat side.

    recycle_timeoutconnection_pool_timeout0 This directive has been deprecated since 1.2.16. The number of seconds that told web server to cut an ajp13 connection after some time of inactivity. When choosing an endpoint for a request and the assigned socket is open, it will be closed if it was not used for the configured time. It's a good way to ensure that there won't too old threads living on Tomcat side, with the extra cost you need to reopen the socket next time a request be forwarded. This property is very similar to cache_timeout but works also in non-cache mode. If set to value zero (default) no recycle will took place.
    balanced_workersbalance_workers- This directive has been deprecated since 1.2.7. A comma separated list of workers that the load balancer need to manage.
    disabledactivationfalse This directive has been deprecated since 1.2.19. If set to true the worker will be disabled if member of load balancer. This flag can be changed at runtime using status worker.

    This feature has been added in jk 1.2.9.

    stoppedactivationfalse This directive has been deprecated since 1.2.19. If set to true the worker will be stopped if member of load balancer. The flag is needed for stop complete traffic of a sticky session worker. It is only useful, when you have a cluster that replicated the sessions. This flag can be changed at runtime using status worker.

    This feature has been added in jk 1.2.11.

    jvm_routerouteworker name This directive has been deprecated since 1.2.20. Normally the name of a balanced worker in a load balancer is equal to the jvmRoute of the corresponding Tomcat instance. If you want to include a worker corresponding to a Tomcat instance into several load balancers with different balancing configuration (e.g. disabled, stopped) you can use this attribute.

    Define a separate worker per lb and per Tomcat instance with an arbitrary worker name and set the jvm_route attribute of the worker equal to the jvmRoute of the target Tomcat instance.

    If this attribute is left empty, the name of the worker will be used.

    This attribute can be changed at runtime using status worker.

    This feature has been added in jk 1.2.16.

    tomcat-connectors-1.2.50-src/docs/reference/status.html0000644000000000000020000006406614655113620021431 0ustar rootbin The Apache Tomcat Connectors - Reference Guide (1.2.50) - Status Worker Reference

    Status Worker Reference

    Introduction

    Tomcat Connectors has a special type of worker, the so-called status worker. The status worker does not forward requests to Tomcat instances. Instead it allows to retrieve status and configuration information at runtime, and furthermore to change many configuration items dynamically. This can be done via a simple embedded web interface.

    The status worker is especially powerful, when used together with load balancing workers.

    This document does not explain the HTML user interface of the status worker. Until now it is very simple, so just go ahead and use it. This doc instead tries to explain the less obvious features of the status worker. We also will give a complete coverage of the various request parameters and their meaning, so that you can include the status worker in your automation scripts.

    The documentation of the status worker starts with jk 1.2.20

    Usage Patterns

    Actions

    The status worker knows about the following actions:

    • list: lists the configurations and runtime information of all configured workers. The output will be grouped by global information first (version data), then load balancer information, after that AJP worker information and finally the legend. For load balancers, there will be a summary part, and after that details for each member worker. For all workers, we also include the URL mappings (forward definitions).
    • show: the same as list, but only shows data for one chosen worker
    • edit: produces a form to edit configuration data for a chosen worker. There is a special subtype of "edit", that makes it easy to change one attribute for all members of a load balancer, e.g. their activation state.
    • update: commit changes made in an edit form. Caution: the changes will not be persisted to the configuration files. As soon as your restart your web server, all changes made through the status worker will be lost! On the other hand, the changes done by the status worker will be applied during runtime without a restart of the web server.
    • reset: reset all runtime statistics for a worker.
    • recover: Mark a member of a load balancer, that is in error state, for immediate recovery.
    • version: only show version information of the web server and the JK software
    • dump: list the original workers configuration. Caution: the dump will only contain the configuration that was used during startup. Any changes applied later by the dynamic management interface of the status worker itself will not be contained in this dump. The dump action has been added in version 1.2.27.

    Output Format

    For most actions you can choose between 4 output formats.

    • HTML: Used interactively with a browser
    • XML: Mostly useful for automation, when your scripting environment is XML friendly. This format has rich structure information, but does not work line based, so you would really like to use it together with XML tools.
    • Properties: This format is a line based format, that conforms to the rules of Java property files. Most structure information is contained in the hierarchical key. For information, that is of configuration nature, the format should produce lines very similar to the ones you can use in workers.properties. It will not produce a complete configuration file!
    • Text: A simple textual output format.
    The "edit" action does only make sense for the HTML output type.

    User Interface Features

    In the HTML view, there is an automatic refresh feature, implemented via the meta refresh option of HTML. Once you start the automatic refresh, the UI will will respect it for all actions except edit, update and maintain. Even if you navigate through one of those, the automatic refresh will start again as soon as you come back to one of the other actions.

    Many parts of the HTML page can be minimised, if they are not interesting for you. There are a couple of "Hide" links, which will collapse parts of the information. The feature exists for the following blocks of information:

    • Legend: Do not show the legend for the information presented in "list" and "show" actions
    • URI mappings: Do not show the URI mapping for the workers
    • Load Balancing Workers: Do not show workers of type "lb"
    • AJP Workers: Do not show workers of type ajp
    • Balancer Members: Do not show detailed information concerning each member of load balancers
    • Load Balancer Configuration: Do not show configuration data for load balancers
    • Load Balancer Summary: Do not show status summary for load balancers
    • AJP Configuration: Do not show configuration data for ajp workers load balancer members
    The last three minimisation features have been added in version 1.2.27.

    Special Considerations concerning URL Maps and Virtual Hosts

    Note: The following restriction has been removed starting with version 1.2.26.

    The Apache module mod_jk makes use of the internal Apache HTTP Server infrastructure concerning virtual hosts. The downside of this is, that the status worker can only show URL maps, for the virtual host it is defined in. It is not able to reach the configuration objects for other virtual hosts. Of course you can define a status worker in any virtual host you are using. All information presented apart from the URL maps will be the same, independent of the virtual host the status worker has been called in.

    Logging

    The status worker will log changes made to the configuration with log level "info" to the usual JK log file. Invalid requests will be logged with log level "warn". If you want to report some broken behaviour, log file content of level "debug" or even "trace" will be useful.

    Configuration

    Basic Configuration

    The basic configuration of a status worker is very similar to that of a usual ajp worker. You need to specify a name for the worker, and the URLs you want to map to it. The first part of the configuration happens in the workers.properties file. We define a worker named mystatus of type status:

    worker.list=mystatus
    worker.mystatus.type=status
    
    Then we define a URL, which should be mapped to this worker, i.e. the URL we use to reach the functionality of the status worker. You can use any method mod_jk supports for the web server of your choice. Possibilities are maps inside uriworkermap.properties, an additional mount attribute in workers.properties, or JkMount for the Apache HTTP Server. Here's an example for a uriworkermap.properties line:
    /private/admin/mystatus=mystatus
    
    The URI pattern is case sensitive.

    As you will learn in the following sections, the status worker is very powerful. You should use the usual authentication and authorisation methods of your web server to secure this URL.

    You can also define multiple instances of the status worker, by using different names and URL mappings. For instance you might want to configure them individually and then allow special groups of people to use them

    Output Customisation

    There are a couple of attributes for the workers.properties entries, which allow to customise various aspects of the output of the status worker.

    The attribute css can be set to the URL of a stylesheet:

    worker.mystatus.css=/private/admin/static/mystatus.css
    
    When writing HTML output, the status worker then includes the line
    <link rel="stylesheet" type="text/css" href="/private/admin/static/mystatus.css" />
    
    There is no sample stylesheet included with the mod_jk release, and by default the attribute css is empty, so no stylesheet reference will be included in the pages. The HTML code of the status worker output pages does not include any class attributes. If you like to contribute a stylesheet or improvements to the HTML layout, please contact us on the tomcat developers list.

    The properties output format can be customised via the attribute prefix. The names of all properties the status worker does output, will begin with this prefix. The default is "worker".

    Several attributes influence the format when writing XML output. The attribute ns allows to set a namespace prefix, that will be used for every status worker+element. The default is "jk:". Setting it to "-" disables the namespace prefix.

    With the attribute xmlns you can map the prefix to a namespace URL. The default value is xmlns:jk="http://tomcat.apache.org". Setting it to "-" disables the output of the URL.

    Finally you can specify an XML document type via the attribute doctype. The specified string will be inserted at the beginning of the document, directly after the xml header. The default is empty.

    Securing Access

    We urge you to use the builtin access control features of your web server to control access to the status worker URLs you have chosen. Nevertheless two configuration attributes of status workers are helpful. The attribute "read_only" disables all features of the status worker, that can be used to change configurations or runtime status of the other workers. A read_only status worker will not allow access to the edit, update, reset or recover actions. The default value is false, ie. read/write. To enable read_only you need to set it to true.

    You could configure two status workers, one has read_only and will be made available to a larger admin group, the other one will be used fully featured, but only by fewer people:

    worker.list=jk-watch
    worker.jk-watch.type=status
    worker.jk-watch.read_only=true
    worker.jk-watch.mount=/user/status/jk
    worker.list=jk-manage
    worker.jk-manage.type=status
    worker.jk-manage.mount=/admin/status/jk
    
    Starting with version 1.2.21, a read/write status worker can also be switched temporarily into read-only mode by the user via a link in the HTML GUI. The user can always switch it back to read/write. Only a status worker configured as read-only via the "read_only" attribute is completely safe from applying any changes.

    The other attribute you can use is user. By default this list is empty, which means no limit on the users. You can set "user" to a comma separated list of user names. If your web server is configured such that it sends the user names with the request, the status worker will check, if the name attached with the request is contained in it's "user" list.

    The user list can be split over multiple occurrences of the "user" attribute.

    By default, the user names are matched case sensitively. Starting with version 1.2.21 you can set the attribute user_case_insensitive to true. Then the comparison will be made case insensitive.

    Service Availability Rating

    For load balancing workers the status worker shows some interesting overview information. It categorises the members of the load balancer into the classes "good", "bad" and degraded". This feature can be combined with external escalation procedures. Depending on your global system design and your operating practises your preferred categorisation might vary.

    The categorisation is based on the activation state of the workers (active, disabled or stopped), which is a pure configuration state, and the runtime state (OK or ERR with possible substates idle, busy, recovering, probing, and forced recovery) which only depends on the runtime situation.

    The runtime substates have the following meaning:

    • OK (idle): This worker didn't receive any request since the last balancer maintenance. By default balancer maintenance runs every 60 seconds. The worker should be OK, but since we didn't have to use it for some time, we can't be sure. This state has been called N/A before version 1.2.24.
    • OK (busy): All connections for this worker are in use for requests.
    • ERROR (recovering): The worker was in error state for some time and is now marked for recovery. The next request suitable for this worker will use it.
    • ERROR (probing): After setting the worker to recovering, we received a request suitable for this worker. This request is now using the worker.
    • ERROR (forced recovery): The worker is in error, but we don't have an alternative worker, so we keep using it.

    By default the status worker groups into "good" all members, that have activation "active" and runtime state not equal to "error" with empty substate. The "bad" group consists of the members, that have either activation "stopped", or are in runtime state "error" with empty substate.

    Workers that fit neither of the two groups, are considered to be "degraded".

    You can define other rules for the grouping into good, bad and degraded. The two attributes "good" and "bad" can be populated by a comma-separated list ob single characters or dot-separated pairs. Each character stands for the first character of one of the possible states "active", "disabled", "stopped", "ok", "idle", "busy", "recovering" and "error". The additional states "probing" and "forced recovery" are always rated equivalent to "recovering". Comma-separated entries will be combined with logical "or", if you combine a configuration and a runtime state with a dot. the are combined with logical "and". So the default value for "good" is "a.o,a.i,a.b,a.r", for "bad" it is "e,s".

    The status worker first tries to match against the "bad" definitions, if this doesn't succeed it tries to match against "good", and finally it chooses "degraded", if no "bad" or "good" match can be found.

    Request Parameters

    This section should help you building automation scripts based on the jk status management interface. This interface is stable in the sense, that we only expect to add further parameters in the future. Existing parameters from previous versions will keep their original semantics. We also expect the output formats XML, Properties and Text to be kept stable. So please use those, if you want to parse status worker output in your automation scripts.

    Actions

    The action is determined by the parameter cmd. It can have the values "list", "show", "edit", "update", "reset", "recover", "version" and "dump". If you omit the cmd parameter, the default "list" will be used. All actions except for "list", "refresh", "version" and "dump" need additional parameters.

    The action "dump" has been added in version 1.2.27.

    Output Format

    The format is determined by the parameter mime. It can have the values "html", "xml", "txt" and "prop". If you omit the mime parameter, the default "html" will be used. The action "edit" (the edit form) does only make sense for "mime=html".

    Worker Selection

    Actions that operate on a single worker need one or two additional parameters to select this worker. The parameter w contains the name of the worker from the worker list. If an action operates on a member (sub worker) of a load balancer, the parameter w contains the name of the load balancer worker, and the additional parameter sw contains the name of the sub worker.

    Automatic Refresh

    During automatic refresh, the parameter re contain the refresh interval in seconds. If you omit this parameter, automatic refresh will be off.

    Hide Options

    The parameter opt contains a bit mask of activated options. The default is 0, so by default no options are activated. The following options exist:

    • 0x0001: hide members of lb workers
    • 0x0002: hide URL maps
    • 0x0004: hide the legend
    • 0x0008: hide load balancer workers
    • 0x0010: hide ajp workers
    • 0x0020: only allow read_only actions for a read/write status worker.
    • 0x0040: hide load balancer configuration
    • 0x0080: hide load balancer status summary
    • 0x0100: hide configuration for ajp and load balancer member workers
    Values 0x0040-0x0100 have been added in version 1.2.27.

    Data Parameters for the standard Update Action

    You can use the edit action with a final click to the update button, to change settings of workers. But you can also make direct calls to the update action. The following request parameters contain the configuration information, you want to change. First the list for load balancer workers:

    • vlr: retries (number)
    • vlt: recover_time (seconds)
    • vlee: error_escalation_time (seconds)
    • vlx: max_reply_timeouts (number)
    • vls: sticky_session (0/f/n/off=off, 1/t/y/on=on; case insensitive)
    • vlf: sticky_session_force (0/f/n/off=off, 1/t/y/on=on; case insensitive)
    • vlm: method (0/r="Requests", 1/t="Traffic", 2/b="Busyness", 3/s="Sessions", 4/s="Next"; case insensitive, only first character is used)
    • vll: lock (0/o="Optimistic", 1/p="Pessimistic"; case insensitive, only first character is used)
    And now the list of parameters you can use to change settings for load balancer members:
    • vwa: activation flag (0/a="active", 1/d="disabled", 2/s="stopped"; case insensitive, only first character is used)
    • vwf: load balancing factor (integer weight)
    • vwn: route for use with sticky sessions (string)
    • vwr: redirect to define simple failover rules (string)
    • vwc: domain to tell JK about your replication design (string)
    • vwd: distance to express preferences (integer)
    Finally the list of parameters you can use to change settings for ajp workers and ajp load balancer members:
    • vahst: host (string)
    • vaprt: port (number)
    • vacpt: connection_pool_timeout (number)
    • vact: connect_timeout (number)
    • vapt: prepost_timeout (number)
    • vart: reply_timeout (number)
    • var: retries (number)
    • varo: recovery_options (number)
    • vabl: busy_limit (number)
    • vamps: max_packet_size (number)
    Note that changing the host name or port will only take effect for new connections. Already established connections to the old address will still be used. Nevertheless this feature is interesting, because you can provision load balancer members with port "0", which will automatically be stopped during startup. Later when you know the final names and ports, you can set them and they will be automatically activated.

    The leading character "v" has been added to the parameters in version 1.2.27. Changing settings for ajp workers has also been introduced in version 1.2.27.

    For the details of all parameters, we refer to the workers.properties Reference.

    Aspect Editing for Load Balancer Members

    You can use the edit action to edit all settings for a load balancer or for a member of a load balancer respectively on one page. If you want to edit one configuration aspect for all members of a load balancer simultaneously, this will be triggered by the parameter att. The value of the parameter indicates, which aspect you want to edit. The list is the same as in the previous section, except for "vahst" and "vaprt": "vwa", "vwf", "vwn", "vwr", "vwc", "vwd", "vacpt", "vact", "vapt", "vart", "var", "varo", "vabl" and "vamps". But here you need to put the name into the parameter att, instead of using it as a request parameter name.

    The values of the common aspect for all the load balancer members will be given in parameters named "val0", "val1", ....

    tomcat-connectors-1.2.50-src/docs/reference/iis.html0000644000000000000020000005042414655113620020663 0ustar rootbin The Apache Tomcat Connectors - Reference Guide (1.2.50) - Configuring the ISAPI redirector for Microsoft IIS

    Configuring the ISAPI redirector for Microsoft IIS

    Requirements

    The Tomcat redirector requires three entities:

    • isapi_redirect.dll - The IIS ISAPI redirector plugin, either obtain a pre-built DLL or build it yourself (see the build section).
    • workers.properties - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). A sample workers.properties can be found under the conf directory.
    • uriworkermap.properties - A file that maps URL-Path patterns to workers. A sample uriworkermap.properties can be found under the conf directory as well.

    The installation includes the following parts:

    • Configuring the ISAPI redirector with a default /examples context and checking that you can serve servlets with IIS.
    • Adding more contexts to the configuration.

    Note that in a 64 Bit environment - at least for IIS 7 - the used IIS Application Pool should have "Enable 32-bit Applications" set to "False". Otherwise the redirector will not be called and returns an http code 404. If you think, the 32bit version of isapi_redirect.dll would do the job instead, you will get an http code 500, because the library is not loadable into a 64 Bit IIS.

    Registry settings

    ISAPI redirector reads configuration from the registry, create a new registry key named:

    "HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0"

    Attributes described below as a "string value representing a boolean" can be set either using the numbers 0 (false) and 1 (true) as values, or off (false) and on (true) or any other string starting with the letters f (false), n (false), t (true) or y (true). The values are taken case insensitive. In this documentation we will stick to false and true.

    Attribute Description
    extension_uri

    A string value pointing to the ISAPI extension /jakarta/isapi_redirect.dll

    log_file

    A value pointing to location where log file will be created. (for example c:\tomcat\logs\isapi.log)
    If one of the log rotation settings (log_rotationtime or log_filesize) are specified then the actual log file name is based on this setting. If the log file name includes any '%' characters, then it is treated as a format string for strftime(3), e.g. c:\tomcat\logs\isapi-%Y-%m-%d-%H_%M_%S.log. Otherwise, the suffix .nnnnnnnnnn is automatically added and is the time in seconds. A full list of format string substitutions can be found in the Apache rotatelogs documentation

    log_level

    A string value for log level (can be debug, info, warn, error or trace).

    This directive was added in version 1.2.31

    log_rotationtime

    The time between log file rotations in seconds. Setting this to 0 (the default) disables log rotation based on time.

    This directive was added in version 1.2.31

    log_filesize

    The maximum log file size in megabytes, after which the log file will be rotated. Setting this to 0 (the default) disables log rotation based on file size.
    The value can have an optional M suffix, i.e. both 5 and 5M will rotate the log file when it grows to 5MB.
    If log_rotationtime is specified, then this setting is ignored.

    worker_file

    A string value which is the full path to workers.properties file (for example c:\tomcat\conf\workers.properties)

    worker_mount_file

    A string value which is the full path to uriworkermap.properties file (for example c:\tomcat\conf\uriworkermap.properties)

    rewrite_rule_file

    A string value which is the full path to rewrite.properties file (for example c:\tomcat\conf\rewrite.properties)

    request_id_header

    A string value which is the name of a request header from which a request id will be extracted that is part of every log line.

    This directive has been added in version 1.2.49

    shm_size

    A DWORD value size of the shared memory. Set this value to be the number of all defined workers * 400. (Set this value only if you have more then 64 workers)

    This directive has been added in version 1.2.20

    Starting with version 1.2.27 the size of the shared memory is determined automatically, even for large numbers of workers. This attribute is not needed any longer.

    worker_mount_reload

    A DWORD value specifying the time in seconds upon which the worker_mount_file will be reloaded.

    This directive has been added in version 1.2.20

    strip_session

    A string value representing a boolean. If it is set to true, URL session suffixes of the form ";jsessionid=..." get stripped of URLs, if the are served locally by the web server.

    The default value is false.

    This directive has been added in version 1.2.21

    auth_complete

    A DWORD value representing "0" or "1". This is needed because of minor incompatibilities with IIS 5.1.

    By default its value is 1, which means we use the SF_NOTIFY_AUTH_COMPLETE event. If you set this to 0, then we use SF_NOTIFY_PREPROC_HEADERS. This might be needed for IIS 5.1 when handling requests using the PUT HTTP method.

    This directive has been added in version 1.2.21

    uri_select

    A string value which influences, how URIs are decoded and re-encoded between IIS and Tomcat. You should leave this at it's default value, unless you have a very good reason to change it.

    If the value is "parsed", the forwarded URI will be decoded and explicit path components like ".." will already be resolved. This is less spec compliant and is not safe if you are using prefix forwarding rules.

    If the value is "unparsed", the forwarded URI will be the original request URI. It's spec compliant and also the safest option. Rewriting the URI and then forwarding the rewritten URI will not work.

    If the value is "escaped", the forwarded URI will be the re-encoded form of the URI used by "parsed". Explicit path components like ".." will already be resolved. This will not work in combination with URL encoded session IDs.

    If the value is "proxy", the forwarded URI will be a partially re-encoded form of the URI used by "parsed". Explicit path components like ".." will already be resolved. and problematic are re-encoded.

    The default value since version 1.2.24 is "proxy". Before it was "parsed".

    reject_unsafe

    A string value representing a boolean. If it is set to true, URLs still containing percent signs '%' or backslashes '\' after decoding will be rejected.

    Most web apps do not use such URLs. By enabling reject_unsafe you can block several well known URL encoding attacks.

    The default value is false.

    This directive has been added in version 1.2.24

    collapse_slashes

    This options is deprecated as of 1.2.44 and will be ignored if used.

    Before version 1.2.41 collapsing was never done. Starting with version 1.2.41 collapsing before looking for unmount matches is the default to prevent easy bypassing of unmount rules. As of 1.2.44, collpasing is always performed before looking for mount or unmount rules.

    This directive has been added in version 1.2.41

    watchdog_interval

    A DWORD value representing the watchdog thread interval in seconds. The workers are maintained periodically by a background thread running periodically every watchdog_interval seconds. Worker maintenance checks for idle connections, corrects load status and is able to detect backend health status.

    The maintenance only happens, if since the last maintenance at least worker.maintain seconds have passed. So setting the watchdog_interval much smaller than worker.maintain is not useful.

    The default value is 0 seconds, meaning the watchdog thread will not be created, and the maintenance is done in combination with normal requests instead.

    This directive has been added in version 1.2.27

    error_page

    A string value representing the error page url redirection when backend returns non-200 response. This directive can be used to customise the error messages returned from backend server.

    The url must point to a valid server url and can contain format string number (%d) that can be used to separate the pages by error number. The redirect url in that case is formatted by replacing %d from error_page to returned error number.

    This directive has been added in version 1.2.27

    enable_chunked_encoding

    A string value representing a boolean. If it is set to true, chunked encoding is supported by the server.

    The default value is false.

    This directive has been added in version 1.2.27. Until version 1.2.30 it was considered experimental and only available when a special build containing chunking support was used. Starting with 1.2.30 it is no longer considered experimental.

    flush_packets

    A string value representing a boolean. If it is set to true, data is flushed immediately to the client as each AJP packet is received. Otherwise, IIS buffers the data and only writes to the client when the buffer is full or the response is complete.

    The default value is false.

    This directive has been added in version 1.2.42

    Using a properties file for configuration

    The ISAPI redirector can read it's configuration from a properties file instead of the registry. This has the advantage that you can use multiple ISAPI redirectors with independent configurations on the same server. The redirector will check for the properties file during initialisation, and use it in preference to the registry if present.

    Create a properties file in the same directory as the ISAPI redirector called isapi_redirect.properties i.e. with the same name as the ISAPI redirector DLL but with a .properties extension. A sample isapi_redirect.properties can be found under the conf directory.

    The property names and values in the properties file are the same as for the registry settings described above. For example:

    # Configuration file for the Tomcat ISAPI Redirector
    
    # The path to the ISAPI Redirector Extension, relative to the website
    # This must be in a virtual directory with execute privileges
    extension_uri=/jakarta/isapi_redirect.dll
    
    # Full path to the log file for the ISAPI Redirector
    log_file=c:\tomcat\logs\isapi_redirect.log
    
    # Log level (debug, info, warn, error or trace)
    log_level=info
    
    # Full path to the workers.properties file
    worker_file=c:\tomcat\conf\workers.properties
    
    # Full path to the uriworkermap.properties file
    worker_mount_file=c:\tomcat\conf\uriworkermap.properties
    

    Notes:

    • Back-slashes - '\' - are not escape characters.
    • Comment lines begin with '#'.

    Starting with version 1.2.27 two environment variables are automatically added to the environment that can be used inside .properties files.

    • JKISAPI_PATH - Full path to the ISAPI Redirector.
    • JKISAPI_NAME - Name of the ISAPI Redirector dll without extension

    # Use the logs in the installation path of ISAPI Redirector
    log_file=$(JKISAPI_PATH)\$(JKISAPI_NAME).log
    

    Log file rotation

    The ISAPI redirector with version 1.2.31 can perform log rotation, with configuration and behaviour similar to the rotatelogs program provided with Apache HTTP Server.

    To configure log rotation, configure a log_file, and one of the log_rotationtime or log_filesize options. If both are specified, the log_rotationtime will take precedence, and log_filesize will be ignored.
    For example, to configure daily rotation of the log file:

    # Configuration file for the Tomcat ISAPI Redirector
    ...
    
    # Full path to the log file for the ISAPI Redirector
    log_file=c:\tomcat\logs\isapi_redirect.%Y-%m-%d.log
    
    # Log level (debug, info, warn, error or trace)
    log_level=info
    
    # Rotate the log file every day
    log_rotationtime=86400
    
    ...
    

    Or to configure rotation of the log file when it reaches 5MB in size:

    # Configuration file for the Tomcat ISAPI Redirector
    ...
    
    # Full path to the log file for the ISAPI Redirector
    log_file=c:\tomcat\logs\isapi_redirect.%Y-%m-%d-%H.log
    
    # Log level (debug, info, warn, error or trace)
    log_level=info
    
    # Rotate the log file at 5 MB
    log_filesize=5M
    
    ...
    

    The log will be rotated whenever the configured limit is reached, but only if the log file name would change. If you configure a log file name with strftime(3) format codes in it, then ensure it specifies the same granularity as the rotation time configured, e.g. %Y-%m-%d if rotating daily (log_rotationtime=86400).
    See the rotatelogs documentation for more examples.

    Using a simple rewrite rules

    The ISAPI redirector with version 1.2.16 can do a simple URL rewriting. Although not as powerful as Apache HTTP Server's mod_rewrite, it allows a simple exchange of request URIs

    The rule is in the form original-url-prefix=forward-url-prefix. For example:

    # Simple rewrite rules, making examples
    # available under shorter URLs
    /jsp/=/examples/jsp/
    /servlets/=/examples/servlets/
    

    You can also use regular expressions, if you prefix the rule with a tilde ~:

    # Complex rewrite rule, prefixing "/examples/"
    # to the first path component of all requests
    ~/([^/]*)=/examples/$1
    

    Note that uriworkermap.properties must use the URLs before rewriting.

    tomcat-connectors-1.2.50-src/docs/reference/apache.html0000644000000000000020000015247514655113620021331 0ustar rootbin The Apache Tomcat Connectors - Reference Guide (1.2.50) - Configuring mod_jk for the Apache HTTP Server

    Configuring mod_jk for the Apache HTTP Server

    Configuration Directives

    Most of the directives are allowed once in the global part of the Apache HTTP Server configuration and once in every <VirtualHost> elements. Exceptions from this rule are explicitly listed in the table below.

    Most values are inherited from the main server to the virtual hosts. Since version 1.2.20 they can be overwritten in the virtual hosts. Exceptions from this rule are again explicitly listed in the table below. See especially JkMountCopy.

    Warning: If Apache and Tomcat are configured to serve content from the same file system location then care must be taken to ensure that Apache is not able to serve inappropriate content such as the contents of the WEB-INF directory or JSP source code.

    This could occur if the Apache DocumentRoot overlaps with a Tomcat Host's appBase or the docBase of any Context. It could also occur when using the Apache Alias directive with a Tomcat Host's appBase or the docBase of any Context.

    Here are the all directives supported by Apache:

    Attribute Description
    JkWorkersFile

    The name of a worker file for the Tomcat servlet containers.
    This directive is only allowed once. It must be put into the global part of the configuration.
    If you don't use the JkWorkerProperty directives, then you must define your workers with a valid JkWorkersFile. There is no default value.

    JkWorkerProperty

    Enables setting worker properties inside Apache configuration file. The syntax is the same as in the JkWorkersFile (usually workers.properties). Simply prefix each line with "JkWorkerProperty" to put it directly into the Apache config files.
    This directive is allowed multiple times. It must be put into the global part of the configuration.
    If you don't use the JkWorkerProperty directives, then you must define your workers with a valid JkWorkersFile. There is no default value.
    This directive is available in jk1.2.7 version and later.

    JkShmFile

    Shared memory file name. Used only on unix platforms. The shm file is used by balancer and status workers.
    This directive is only allowed once. It must be put into the global part of the configuration.
    The default value is logs/jk-runtime-status. It is highly recommended that the shm file be placed on a local drive and not an NFS share.

    The shared memory contains configuration and runtime information for load balancer workers and their members. It is need in order that all Apache children

    • share the same status information for load balancing members (OK, ERROR, ...),
    • share the information about load taken by the individual workers,
    • share the information for the parts of the configuration, which are changeable during runtime by status workers.

    JkShmSize

    Size of the shared memory file name.
    This directive is only allowed once. It must be put into the global part of the configuration.
    The default value depends on the platform. It is usually less than 64KB.

    JkMountFile

    File containing multiple mappings from a context to a Tomcat worker. It is usually called uriworkermap.properties.
    For inheritance rules, see: JkMountCopy.
    There is no default value.

    JkMountFileReload

    This directive configures the reload check interval in seconds. The JkMountFile is checked periodically for changes. A changed file gets reloaded automatically. If you set this directive to "0", reload checking is turned off.
    The default value is 60 seconds.
    This directive has been added in version 1.2.20 of mod_jk.

    JkMount

    A mount point from a context to a Tomcat worker.
    This directive is allowed multiple times. It is allowed in the global configuration and in VirtualHost.
    You can also use it inside Location with a different syntax. Inside Location, one omits the first argument (path), which gets inherited verbatim from the Location argument. Whereas <Location /myapp> matches any URI beginning with "/myapp", any JkMount nested in such a Location block will only match for requests with exact URI /myapp. Therefore nesting JkMount in Location is typically not the right thing to do.
    By default JkMount entries are not inherited from the global server to other VirtualHosts or between VirtualHosts. For the complete inheritance rules, see: JkMountCopy.
    You might append rule extensions to the worker name. The extensions are separated from the worker name by a semicolon ";" using the same syntax as in the uriworkermap.properties file.

    JkUnMount

    An exclusion mount point from a context to a Tomcat worker. All exclusion mounts are checked after mapping a request to a tomcat worker. If the request maps also to an exclusion, it will not be forwarded to tomcat, and instead be served locally.
    This directive is allowed multiple times. It is allowed in the global configuration and in VirtualHost.
    You can also use it inside Location with a different syntax. Inside Location, one omits the first argument (path), which gets inherited verbatim from the Location argument. Whereas <Location /myapp> matches any URI beginning with "/myapp", any JkUnMount nested in such a Location block will only match for requests with exact URI /myapp. Therefore nesting JkUnMount in Location is typically not the right thing to do.
    For inheritance rules, see: JkMountCopy.
    This directive is available in jk1.2.7 version and later.

    JkAutoAlias

    Automatically Alias webapp context directories into the Apache document space.
    Care should be taken to ensure that only static content is served via Apache as a result of using this directive. Any static content served by Apache will bypass any security constraints defined in the application's web.xml.
    For inheritance rules, see: JkMountCopy.
    There is no default value.

    JkMountCopy

    If this directive is set to "On" in some virtual server, the mounts from the global server will be copied to this virtual server, more precisely all mounts defined by JkMount or JkUnMount. The Mounts defined by JkMountFile and JkAutoAlias will only be inherited, if the VirtualHost does not define it's own JkMountFile or JkAutoAlias.
    If you want all vhost to inherit mounts from the main server, you can set JkMountCopy to 'All' in the main server.
    This directive is only allowed inside VirtualHost (with value "On") and in the global server (with value "All").
    The default is Off, so no mounts will be inherited from the global server to any VirtualHost.
    Starting with version 1.2.26 you can also set it to "All" in the global virtual server. This will switch the default to On.

    JkWorkerIndicator

    Name of the Apache environment variable that can be used to set worker names in combination with SetHandler jakarta-servlet.
    This directive is only allowed once per virtual server. It is allowed in the global configuration and in VirtualHost.
    The default value is JK_WORKER_NAME.

    JkWatchdogInterval

    This directive configures the watchdog thread interval in seconds. The workers are maintained periodically by a background thread running periodically every watchdog_interval seconds. Worker maintenance checks for idle connections, corrects load status and is able to detect backend health status.
    The maintenance only happens, if since the last maintenance at least worker.maintain seconds have passed. So setting the JkWatchdogInterval much smaller than worker.maintain is not useful.
    The default value is 0 seconds, meaning the watchdog thread will not be created, and the maintenance is done in combination with normal requests instead.
    This directive is only allowed once. It must be put into the global part of the configuration.
    This directive has been added in version 1.2.27 of mod_jk. It is available only for Apache 2.x and above using APR libraries including thread support.

    JkLogFile

    Full or server relative path to the mod_jk log file. It will also work with pipe, by using a value of the form "| ...".
    The default value is logs/mod_jk.log.
    Pipes are supported for Apache 1.3 only since version 1.2.16. The default value exists only since version 1.2.20.

    JkLogLevel

    The mod_jk log level, can be debug, info, warn error or trace.
    The default value is info.

    JkLogStampFormat

    The mod_jk date log format, using an extended strftime syntax. This format will be used for the time stamps in the JkLogFile. The maximum length of the format is 63 characters.
    Starting with version 1.2.24 of mod_jk you can also use %Q for adding milliseconds to the log and %q for microseconds. These conversion specifiers are an extension to strftime. They will only work on platforms with a gettimeofday() function. You can use %Q and %q only once in the pattern and also not both together in the same pattern.
    The default value is "[%a %b %d %H:%M:%S %Y] " and beginning with version 1.2.24 on platforms with a gettimeofday() function it is "[%a %b %d %H:%M:%S.%Q %Y] ".

    JkRequestLogFormat

    Request log format string. See detailed description below.
    There is no default value. Without defining a value, the request logging is turned off.

    JkExtractSSL

    Turns on SSL processing and information gathering by mod_jk
    The default value is On.
    In order to make SSL data available for mod_jk in Apache, you need to set SSLOptions +StdEnvVars. For the certificate information you also need to add SSLOptions +ExportCertData.

    Specifically, mod_jk will export the following environment variables from Apache to Tomcat under these request attributes as per the Servlet Specification 3.0, section 3.8:

    Env VarRequest Attribute NameTypeExample
    SSL_CIPHER
    (or JkKEYSIZEIndicator)
    javax.servlet.request.cipher_suite java.lang.String DHE-RSA-AES256-SHA
    SSL_CIPHER_USEKEYSIZE
    (or JkKEYSIZEIndicator)
    javax.servlet.request.key_size java.lang.Integer 256
    SSL_SESSION_ID
    (or JkSESSIONIndicator)
    javax.servlet.request.ssl_session java.lang.String 905...32E (a hex string)
    SSL_CLIENT_CERT_CHAIN_n
    (or JkCERTCHAINPrefixn)
    javax.servlet.request.X509Certificate java.security.X509Certificate[] (A chain of certs in ascending order of trust, the first one being ths client's certificate, the second being the signer of that certificate, and so on)

    In addition mod_jk sends the name of the SSL protocol used as a proprietary request attribute named AJP_SSL_PROTOCOL. Modern Tomcat versions will expose this attribute under the name org.apache.tomcat.util.net.secure_protocol_version. This feature has been added in version 1.2.41 of mod_jk. See also JkSSLPROTOCOLIndicator.

    For all other SSL-related variables, use JkEnvVar for each variable you want. Please note that, like JkEnvVar, these variables are available from the request attributes, not as environment variables or as request headers.

    JkRequestIdIndicator

    Name of the Apache environment variable that contains a unique request id. The value of the environment variable will be added to most mod_jk error log lines and allows easy correlation with Apache logs by adding that environment variable there as well.
    The default value is "UNIQUE_ID". Loading the module "mod_unique_id" will automatically provide a unique request id under that name.

    This feature has been added in version 1.2.49 of mod_jk.

    If a request id is sent by the client or another reverse proxy in front via an HTTP request header, one can make this id available for mod_jk by copying it to an environment variable using mod_setenvif:
    SetEnvIf X-REQUEST-ID-HEADER "(.+)" X-REQUEST-ID=$1
    copies the value of the incoming header X-REQUEST-ID-HEADER to the environment variable X-REQUEST-ID. mod_jk can pick it up from there via JkRequestIdIndicator X-REQUEST-ID.

    JkHTTPSIndicator

    Name of the Apache environment variable that contains SSL indication.
    The default value is "HTTPS".

    JkSSLPROTOCOLIndicator

    Name of the Apache environment variable that contains the SSL protocol name.
    The default value is "SSL_PROTOCOL".
    This directive has been added in version 1.2.41 of mod_jk.

    JkCERTSIndicator

    Name of the Apache environment variable that contains SSL client certificates.
    The default value is "SSL_CLIENT_CERT".

    JkCIPHERIndicator

    Name of the Apache environment variable that contains SSL client cipher.
    The default value is "SSL_CIPHER".

    JkCERTCHAINPrefix

    Name of the Apache environment (prefix) that contains SSL client chain certificates.
    The default value is "SSL_CLIENT_CERT_CHAIN_".

    JkSESSIONIndicator

    Name of the Apache environment variable that contains SSL session.
    The default value is "SSL_SESSION_ID".

    JkKEYSIZEIndicator

    Name of the Apache environment variable that contains SSL key size in use.
    The default value is "SSL_CIPHER_USEKEYSIZE".

    JkLocalNameIndicator

    Name of the Apache environment variable which can be used to overwrite the forwarded local name. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_LOCAL_NAME".
    This directive has been added in version 1.2.28 of mod_jk.

    JkIgnoreCLIndicator

    Name of the Apache environment variable which forces to ignore an existing Content-Length request header. This can be used to make mod_jk conpatible with mod_deflate request body inflation (see below).
    The default value is "JK_IGNORE_CL".
    This directive has been added in version 1.2.41 of mod_jk.

    JkLocalAddrIndicator

    Name of the Apache environment variable which can be used to overwrite the forwarded local IP address. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_LOCAL_ADDR".
    This directive has been added in version 1.2.41 of mod_jk.

    JkLocalPortIndicator

    Name of the Apache environment variable which can be used to overwrite the forwarded local port. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_LOCAL_PORT".
    This directive has been added in version 1.2.28 of mod_jk.

    JkRemoteHostIndicator

    Name of the Apache environment variable which can be used to overwrite the forwarded remote (client) host name. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_REMOTE_HOST".
    This directive has been added in version 1.2.28 of mod_jk.

    JkRemoteAddrIndicator

    Name of the Apache environment variable which can be used to overwrite the forwarded remote (client) IP address. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_REMOTE_ADDR".
    This directive has been added in version 1.2.28 of mod_jk.

    JkRemotePortIndicator

    Name of the Apache environment variable which can be used to overwrite the forwarded remote (client) IP address. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_REMOTE_PORT".
    This directive has been added in version 1.2.32 of mod_jk.

    JkRemoteUserIndicator

    Name of the Apache environment variable which can be used to overwrite the forwarded user name. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_REMOTE_USER".
    This directive has been added in version 1.2.28 of mod_jk.

    JkAuthTypeIndicator

    Name of the Apache environment variable which can be used to overwrite the forwarded authentication type. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_AUTH_TYPE".
    This directive has been added in version 1.2.28 of mod_jk.

    JkOptions

    Set one of more options to configure the mod_jk module. See below for details about this directive.
    This directive can be used multiple times per virtual server.
    The default value is "ForwardURIProxy" since version 1.2.24. It was "ForwardURICompatUnparsed" in version 1.2.23 and "ForwardURICompat" until version 1.2.22.

    JkEnvVar

    Adds a name and an optional default value of environment variable that should be sent to servlet-engine as a request attribute. If the default value is not given explicitly, the variable will only be send, if it is set during runtime.
    The default is empty, so no additional variables will be sent.
    This directive can be used multiple times per virtual server. The settings will be merged between the global server and any virtual server.
    You can retrieve the variables on Tomcat as request attributes via request.getAttribute(attributeName). Note that the variables send via JkEnvVar will not be listed in request.getAttributeNames().
    Empty default values are supported since version 1.2.20. Not sending variables with empty defaults and empty runtime value has been introduced in version 1.2.21.

    JkStripSession

    If this directive is set to On in some virtual server, the session IDs ;jsessionid=... will be removed for URLs which are not forwarded but instead are handled by the local server.
    This directive is only allowed inside VirtualHost.
    The default is Off.
    This directive has been introduced in version 1.2.21.
    With version 1.2.27 and later this directive can have optional session ID identifier. If not specified it defaults to ;jsessionid.

    Configuration Directives Types

    We'll discuss here the mod_jk directive types.

    Define workers

    JkWorkersFile specify the location where mod_jk will find the workers definitions. Take a look at Workers documentation for detailed description.

    JkWorkersFile     /etc/httpd/conf/workers.properties
    

    Logging

    JkLogFile specify the location where mod_jk is going to place its log file.

    JkLogFile     /var/log/httpd/mod_jk.log
    

    Since JK 1.2.3 for Apache 2.x and JK 1.2.16 for Apache 1.3 this can also be used for piped logging:

    JkLogFile     "|/usr/bin/rotatelogs /var/log/httpd/mod_jk.log 86400"
    

    JkLogLevel set the log level between:

    • info log will contain standard mod_jk activity (default).
    • warn log will contain non fatal error reports.
    • error log will contain also error reports.
    • debug log will contain all information on mod_jk activity
    • trace log will contain all tracing information on mod_jk activity
    JkLogLevel    info
    

    info should be your default selection for normal operations.

    JkLogStampFormat will configure the date/time format found on mod_jk log file. See above for details.

    JkLogStampFormat "[%Y-%m-%d %H:%M:%S.%Q] "
    

    You can log mod_jk information using the Apache standard module mod_log_config. The module sets several notes in the Apache notes table. Most of them are are only useful in combination with a load balancer worker.

    Attribute Description
    JK_WORKER_NAMEName of the worker selected by the URI mapping
    JK_WORKER_TYPEType of the worker selected by the URI mapping
    JK_WORKER_ROUTEActual worker name selected by the URI mapping (usually a member of the load balancer).
    Before version 1.2.26 only available if JkRequestLogFormat is set.
    JK_REQUEST_DURATIONRequest duration in seconds and microseconds.
    Before version 1.2.26 only available if JkRequestLogFormat is set.
    JK_LB_FIRST_NAMELoad balancer: Name of the first worker tried
    JK_LB_FIRST_TYPELoad balancer: Type of the first worker tried
    JK_LB_FIRST_ACCESSEDLoad balancer: Access count for the first worker tried
    JK_LB_FIRST_SESSIONSLoad balancer: Count of created sessions for the first worker tried
    JK_LB_FIRST_READLoad balancer: Bytes read for the first worker tried
    JK_LB_FIRST_TRANSFERREDLoad balancer: Bytes transferred for the first worker tried
    JK_LB_FIRST_ERRORSLoad balancer: Error count for the first worker tried
    JK_LB_FIRST_BUSYLoad balancer: Busy count for the first worker tried
    JK_LB_FIRST_ACTIVATIONLoad balancer: Activation state for the first worker tried
    JK_LB_FIRST_STATELoad balancer: Error state for the first worker tried
    JK_LB_LAST_NAMELoad balancer: Name of the last worker tried
    JK_LB_LAST_TYPELoad balancer: Type of the last worker tried
    JK_LB_LAST_ACCESSEDLoad balancer: Access count for the last worker tried
    JK_LB_LAST_SESSIONSLoad balancer: Count of created sessions for the last worker tried
    JK_LB_LAST_READLoad balancer: Bytes read for the last worker tried
    JK_LB_LAST_TRANSFERREDLoad balancer: Bytes transferred for the last worker tried
    JK_LB_LAST_ERRORSLoad balancer: Error count for the last worker tried
    JK_LB_LAST_BUSYLoad balancer: Busy count for the last worker tried
    JK_LB_LAST_ACTIVATIONLoad balancer: Activation state for the last worker tried
    JK_LB_LAST_STATELoad balancer: Error state for the last worker tried

    LogFormat     "%h %l %u %t \"%r\" %>s %b %{JK_WORKER_NAME}n %{JK_LB_FIRST_NAME}n \
                   %{JK_LB_FIRST_BUSY}n %{JK_LB_LAST_NAME}n %{JK_LB_LAST_BUSY}n" mod_jk_log
    CustomLog     logs/access_log     mod_jk_log
    

    You can also log a request protocol in the mod_jk log file instead of the access log. This is not recommended and mostly a backward compatibility feature. The directive JkRequestLogFormat will configure the format of this protocol. It gets configured and enabled on a per virtual host basis. To enable request logging for a virtual host just add a JkRequestLogFormat config. The syntax of the format string is similar to the Apache LogFormat command, here is a list of the available request log format options:

    Attribute Description
    %bBytes sent, excluding HTTP headers (CLF format)
    %BBytes sent, excluding HTTP headers
    %HThe request protocol
    %mThe request method
    %pThe canonical Port of the server serving the request
    %qThe query string (prepended with a ? if a query string exists, otherwise an empty string)
    %rFirst line of request
    %sRequest HTTP status code
    %TRequest duration, elapsed time to handle request in seconds '.' micro seconds
    %UThe URL path requested, not including any query string.
    %vThe canonical ServerName of the server serving the request
    %VThe server name according to the UseCanonicalName setting
    %wTomcat worker name
    %RReal worker name

    JkRequestLogFormat     "%w %V %T"
    

    Forwarding

    The directive JkOptions allow you to set many forwarding options which will enable (+) or disable (-) following option. Without any leading signs, options will be enabled.

    The four following options +ForwardURIxxx are mutually exclusive. Exactly one of them is required, a negative sign prefix is not allowed with them. The default value is "ForwardURIProxy" since version 1.2.24. It was "ForwardURICompatUnparsed" in version 1.2.23 and "ForwardURICompat" until version 1.2.22. You can turn the default off by switching on one of the other two options. You should leave this at it's default value, unless you have a very good reason to change it.

    All options are inherited from the global server to virtual hosts. Options that support enabling (plus options) and disabling (minus options), are inherited in the following way:
    options(vhost) = plus_options(global) - minus_options(global) + plus_options(vhost) - minus_options(vhost)

    Using JkOptions ForwardURIProxy, the forwarded URI will be partially reencoded after processing inside Apache and before forwarding to Tomcat. This will be compatible with local URL manipulation by mod_rewrite and with URL encoded session ids.

    JkOptions     +ForwardURIProxy
    

    Using JkOptions ForwardURICompatUnparsed, the forwarded URI will be unparsed. It's spec compliant and secure. It will always forward the original request URI, so rewriting URIs with mod_rewrite and then forwarding the rewritten URI will not work.

    JkOptions     +ForwardURICompatUnparsed
    

    Using JkOptions ForwardURICompat, the forwarded URI will be decoded by Apache. Encoded characters will be decoded and explicit path components like ".." will already be resolved. This is less spec compliant and is not safe if you are using prefix JkMount. This option will allow to rewrite URIs with mod_rewrite before forwarding.

    JkOptions     +ForwardURICompat
    

    Using JkOptions ForwardURIEscaped, the forwarded URI will be the encoded form of the URI used by ForwardURICompat. Explicit path components like ".." will already be resolved. This will not work in combination with URL encoded session IDs, but it will allow to rewrite URIs with mod_rewrite before forwarding.

    JkOptions     +ForwardURIEscaped
    

    JkOptions RejectUnsafeURI will block all URLs, which contain percent signs '%' or backslashes '\' after decoding.

    Most web apps do not use such URLs. Using the option RejectUnsafeURI, you can block several well known URL encoding attacks. By default, this option is not set.

    You can also realise such a check with mod_rewrite, which is more powerful but also slightly more complicated.

    JkOptions     +RejectUnsafeURI
    

    JkOptions CollapseSlashesAll is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions CollapseSlashesUnmount is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions CollapseSlashesNone is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions ForwardDirectories is used in conjunction with DirectoryIndex directive of Apache. As such mod_dir should be available to Apache, statically or dynamically (DSO)

    When DirectoryIndex is configured, Apache will create sub-requests for each of the local-url's specified in the directive, to determine if there is a local file that matches (this is done by stat-ing the file).

    If ForwardDirectories is set to false (default) and Apache doesn't find any files that match, Apache will serve the content of the directory (if directive Options specifies Indexes for that directory) or a 403 Forbidden response (if directive Options doesn't specify Indexes for that directory).

    If ForwardDirectories is set to true and Apache doesn't find any files that match, the request will be forwarded to Tomcat for resolution. This is used in cases when Apache cannot see the index files on the file system for various reasons: Tomcat is running on a different machine, the JSP file has been precompiled etc.

    Note that locally visible files will take precedence over the ones visible only to Tomcat (i.e. if Apache can see the file, that's the one that's going to get served). This is important if there is more then one type of file that Tomcat normally serves - for instance Velocity pages and JSP pages.

    JkOptions     +ForwardDirectories
    

    Setting JkOptions ForwardLocalAddress, you ask mod_jk to send the local address, of the Apache HTTP Server instead remote client address. This can be used by the Tomcat remote address valve for allowing connections only from configured Apache servers.

    JkOptions     +ForwardLocalAddress
    

    Setting JkOptions ForwardPhysicalAddress, you ask mod_jk to send the physical peer TCP IP address as the client address. By default mod_jk uses the logical address as provided by the web server. For example the module mod_remoteip sets the logical IP address to the client IP forwarded by proxies in the X-Forwarded-For header.

    JkOptions     +ForwardPhysicalAddress
    

    JkOptions FlushPackets, you ask mod_jk to flush Apache's connection buffer after each AJP packet chunk received from Tomcat. This option can have a strong performance penalty for Apache and Tomcat as writes are performed more often than would normally be required (ie: at the end of each response).

    JkOptions     +FlushPackets
    

    JkOptions FlushHeader, you ask mod_jk to flush Apache's connection buffer after the response headers have been received from Tomcat.

    JkOptions     +FlushHeader
    

    JkOptions DisableReuse, you ask mod_jk to close connections immediately after their use. Normally mod_jk uses persistent connections and pools idle connections to reuse them, when new requests have to be sent to Tomcat.

    Using this option will have a strong performance penalty for Apache and Tomcat. Use this only as a last resort in case of unfixable network problems. If a firewall between Apache and Tomcat silently kills idle connections, try to use the worker attribute socket_keepalive in combination with an appropriate TCP keepalive value in your OS.

    JkOptions     +DisableReuse
    

    JkOptions ForwardKeySize, you ask mod_jk, when using ajp13, to forward also the SSL Key Size as required by Servlet API 2.3. This flag shouldn't be set when servlet engine is Tomcat 3.2.x (on by default).

    JkOptions     +ForwardKeySize
    

    JkOptions ForwardSSLCertChain, you ask mod_jk, when using ajp13, to forward SSL certificate chain (off by default). Mod_jk only passes the SSL_CLIENT_CERT to the AJP connector. This is not a problem with self-signed certificates or certificates directly signed by the root CA certificate. However, there's a large number of certificates signed by an intermediate CA certificate, where this is a significant problem: A servlet will not have the possibility to validate the client certificate on its own. The bug would be fixed by passing on the SSL_CLIENT_CERT_CHAIN to Tomcat via the AJP connector.
    This directive exists only since version 1.2.22.

    JkOptions     +ForwardSSLCertChain
    

    The directive JkEnvVar allows you to forward environment variables from Apache server to Tomcat engine. You can add a default value as a second parameter to the directive. If the default value is not given explicitly, the variable will only be send, if it is set during runtime.
    The variables can be retrieved on the Tomcat side as request attributes via request.getAttribute(attributeName). Note that the variables send via JkEnvVar will not be listed in request.getAttributeNames().
    The variables are inherited from the global server to virtual hosts.

    JkEnvVar     SSL_CLIENT_V_START     undefined
    

    Assigning URLs to Tomcat

    If you have created a custom or local version of mod_jk.conf-local as noted above, you can change settings such as the workers or URL prefix.

    JkMount directive assign specific URLs to Tomcat. In general the structure of a JkMount directive is:

    JkMount [URL prefix] [Worker name]
    
    # send all requests ending in .jsp to worker1
    JkMount /*.jsp worker1
    # send all requests ending /servlet to worker1
    JkMount /*/servlet/ worker1
    # send all requests jsp requests to files located in /otherworker will go worker2
    JkMount /otherworker/*.jsp worker2
    

    You can use the JkMount directive at the top level or inside <VirtualHost> sections of your httpd.conf file.

    JkUnMount directive acts as an opposite to JkMount and blocks access to a particular URL. The purpose is to be able to filter out the particular content types from mounted context. The following example mounts /servlet/* context, but all .gif files that belongs to that context are not served.

    # send all requests ending with /servlet to worker1
    JkMount /servlet/* worker1
    # do not send requests ending with .gif to worker1
    JkUnMount /servlet/*.gif worker1
    

    JkUnMount takes precedence over JkMount directives, meaning that the JK will first try to mount and then checks, if there is an exclusion defined by a JkUnMount. A JkUnMount overrides a JkMount only, if the worker names in the JkMount and in the JkUnMount are the same.

    The following example will block all .gif files although there is a JkMount for them:

    # do not send requests ending with .gif to worker1
    JkUnMount /*.gif worker1
    # The .gif files will not be mounted cause JkUnMount takes
    # precedence over JkMount directive
    JkMount /servlet/*.gif worker1
    

    Starting with version 1.2.26 of JK you can apply a JkUnMount to any worker, by using the star character '*' as the worker name in the JkUnMount. More complex patterns in JkUnMount worker names are not allowed.

    # Mapping the webapps myapp1 and myapp2:
    /myapp1/*=worker1
    /myapp2/*=worker2
    # Exclude the all subdirectories static for all workers:
    !/*/static/*=*
    # Exclude some suffixes for all workers:
    !*.html=*
    

    JkAutoAlias directive automatically Alias webapp context directories into the Apache document space. It enables Apache to serve a static context while Tomcat serving dynamic context. This directive is used for convenience so that you don't have to put an Apache Alias directive for each application directory inside Tomcat's webapp directory. For security reasons it is strongly recommended that JkMount is used to pass all requests to Tomcat by default and JkUnMount is used to explicitly exclude static content to be served by Apache. It should also be noted that content served by Apache will bypass any security constraints defined in the application's web.xml. The directive only works in the simple case of contexts with a single path element and no version marker. It does not support:

    • the ROOT context (i.e. .../webapps/ROOT)
    • multi-level contexts (e.g. .../webapps/foo#bar)
    • parallel deployment (e.g. .../webapps/foo##v00.05.12)

    # enter the full path to the tomcat webapps directory
    JkAutoAlias /opt/tomcat/webapps
    

    The following example shows how to serve a dynamic context by Tomcat and static using Apache. The webapps directory has to be accessible by Apache.

    # enter the full path to the tomcat webapps directory
    JkAutoAlias /opt/tomcat/webapps
    
    # Mount 'examples' directory. It's physical location
    # is assumed to be in the /opt/tomcat/webapps/examples
    # ajp13w is a worker defined in the workers.properties
    JkMount /examples/* ajp13w
    
    # Unmount desired static content from examples webapp.
    # This content will be served by the Apache directly.
    JkUnMount /*.gif ajp13w
    

    Note that you can have a single JkAutoAlias directive per virtual host inside your httpd.conf

    JkWorkerProperty is a new directive available from JK 1.2.7 version. It is a convenient method for setting directives that are usually set inside workers.propeties file. The parameter for that directive is raw line from workers.properties file.

    # Just like workers.properties but exact line is prefixed
    # with JkWorkerProperty
    
    # Minimal jk configuration
    JkWorkerProperty worker.list=ajp13w
    JkWorkerProperty worker.ajp13w.type=ajp13
    JkWorkerProperty worker.ajp13w.host=localhost
    JkWorkerProperty worker.ajp13w.port=8009   
    

    JkMountFile is a new directive available from JK 1.2.9 version. It is used for dynamic updates of mount points at runtime. When the mount file is changed, JK will reload it's content.

    # Load mount points
    
    JkMountFile conf/uriworkermap.properties
    

    If the mount point uri starts with an exclamation mark '!' it defines an exclusion in the same way JkUnMount does. If the mount point uri starts with minus sign '-' the mount point will only be disabled. A disabled mount can be reenabled by deleting the minus sign and waiting for the JkMountFile to reload. An exclusion can be disabled by prefixing it with a minus sign.

    # Sample uriworkermap.properties file
    
    /examples/*=ajp13w
    # Do not map .gif files
    !/*.gif=ajp13w
    # Make jsp examples initially disabled  
    -/examples/jsp/*=ajp13w
    

    At run time you can change the content of this file. For example removing minus signs will enable the previously disabled uri mappings. You can add any number of new entries at runtime that reflects the newly deployed applications. Apache will reload the file and update the mount points within 60 second interval.

    There is no way to delete entries by dynamic reloading, but you can disable or exclude mappings.

    Using SetHandler and Environment Variables

    Alternatively to the mod_jk specific directives, you can also use SetHandler and environment variables to control, which requests are being forwarded via which worker. This gives you more flexibility, but the results might be more difficult to understand. If you mix both ways of defining the forwards, in general to mod_jk directives will win.

    SetHandler jakarta-servlet forces requests to be handled by mod_jk. You can use SetHandler for example in Location blocks or with Apache 2.2 and later also in RewriteRule.

    In order to control the worker using SetEnvIf or RewriteRule for more complex rules, you can set the environment variable JK_WORKER_NAME to the name of your chosen target worker. This enables you to decide on the chosen worker in a more flexible way, including dependencies on cookie values. This feature has been added in version 1.2.19 of mod_jk. Furthermore you might append rule extensions to the worker name. The extensions are separated from the worker name by a semicolon ";" using the same syntax as in the uriworkermap.properties file. Supporting rule extensions in the worker name has been added in version 1.2.33.

    In order to use another variable than JK_WORKER_NAME, you can set the name of this variable via the JkWorkerIndicator directive.

    You can also define exclusions from mod_jk forwards by setting the environment variable no-jk.

    # Automatically map all encoded urls
    <Location *;jsessionid=>
      SetHandler jakarta-servlet
      SetEnv JK_WORKER_NAME my_worker
    </Location>
    
    # Map all subdirs to workers via naming rule
    # and exclude static content.
    <Location /apps/>
      SetHandler jakarta-servlet
      SetEnvIf REQUEST_URI ^/apps/([^/]*)/ JK_WORKER_NAME=$1
      SetEnvIf REQUEST_URI ^/apps/([^/]*)/static no-jk
    </Location>
    

    Advanced Environment Variables

    Environment variables allow to overwrite the default behaviour of mod_jk depending on request properties like e.g. the request URI, header values or cookie. This can be done using the SetEnvIf or RewriteRule directives.

    The environment variable JK_ROUTE can be set to explicitely choose a member of a load balancer worker. The value must be equal to the route attribute of the member, or if that attribute is not used, equal to the member name. Note that this is only needed if session IDs and routes are encoded in a non standard way in the request. Stickyness using the Java Servlet compliant way of encoding the IDs is supported by default. This is available since version 1.2.33.

    The environment variable JK_REPLY_TIMEOUT can be set to dynamically define a reply timeout. The value must be given in milliseconds. This is available since version 1.2.27.

    The environment variable JK_STICKY_IGNORE can be set to disable session stickyness for individual requests. If the variable is set to an empty string or a nonzero number, session stickyness will be disabled. Setting it to 0 will reset to the behaviour defined by the worker configuration. This is available since version 1.2.33.

    This feature can be useful to optimize load balancing when using cookie based session stickyness. In this case, as long as she keeps her browser open, any request by a user who started a session will be send to the same Tomcat instance, even if he left the part of the application which uses the session. You can for instance set this environment variable when a user requests a login form to ensure, that this initial session request is balanced non-sticky.

    The environment variable JK_STATELESS can be used to improve load balancing for the session based balancing methods Session and Next. In this case normally any request which does not come with a session id counts as a new session. This can be problematic, if for instance static content is retrieved without a session id. If you set the environment variable JK_STATELESS for a request, then the request will not count as a new session, even if it does not come with a session id. This is available since version 1.2.33.

    The environment variable JK_IGNORE_CL can be set to force ignoring the request Content-Length header (if it exists). mod_jk will then stream the request body until the web server indicates that the full body was read. No Content-Length header will be send to the backend. This is available since version 1.2.41.

    This feature can be used to make mod_jk compatible with filters which change the size of the request body. One such filter is mod_deflate when used to inflate the body of a request with gzip encoded body. In this case mod_jk will by default forward a truncated body, because it gets the wrong body size from the web server. Telling mod_jk to ignore the Content-Length header will result in streaming all request body data it can read from the web server to the backend.

    You should only set the JK_IGNORE_CL environment variables for requests that actually need it. Unfortunately there's no way for mod_jk to detect the need automatically.

    tomcat-connectors-1.2.50-src/xdocs/0000755000000000000020000000000014655113617015444 5ustar rootbintomcat-connectors-1.2.50-src/xdocs/ajp/0000755000000000000020000000000014655113617016216 5ustar rootbintomcat-connectors-1.2.50-src/xdocs/ajp/ajpv13a.xml0000644000000000000020000005632214655113617020215 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. AJPv13 danmil@shore.net Jean-Frederic Clere

    The original document was written by Dan Milstein, danmil@shore.net on December 2000. The present document is generated out of an xml file to allow a more easy integration in the Tomcat documentation.

    This describes the Apache JServ Protocol version 1.3 (hereafter ajp13). There is, apparently, no current documentation of how the protocol works. This document is an attempt to remedy that, in order to make life easier for maintainers of JK, and for anyone who wants to port the protocol somewhere (into jakarta 4.x, for example).

    I am not one of the designers of this protocol -- I believe that Gal Shachor was the original designer. Everything in this document is derived from the actual implementation I found in the tomcat 3.x code. I hope it is useful, but I can't make any grand claims to perfect accuracy. I also don't know why certain design decisions were made. Where I was able, I've offered some possible justifications for certain choices, but those are only my guesses. In general, the C code which Shachor wrote is very clean and comprehensible (if almost totally undocumented). I've cleaned up the Java code, and I think it's reasonably readable.

    According to email from Gal Shachor to the jakarta-dev mailing list, the original goals of JK (and thus ajp13) were to extend mod_jserv and ajp12 by (I am only including the goals which relate to communication between the web server and the servlet container):

    • Increasing performance (speed, specifically).
    • Adding support for SSL, so that isSecure() and getScheme() will function correctly within the servlet container. The client certificates and cipher suite will be available to servlets as request attributes.

    The ajp13 protocol is packet-oriented. A binary format was presumably chosen over the more readable plain text for reasons of performance. The web server communicates with the servlet container over TCP connections. To cut down on the expensive process of socket creation, the web server will attempt to maintain persistent TCP connections to the servlet container, and to reuse a connection for multiple request/response cycles.

    Once a connection is assigned to a particular request, it will not be used for any others until the request-handling cycle has terminated. In other words, requests are not multiplexed over connections. This makes for much simpler code at either end of the connection, although it does cause more connections to be open at once.

    Once the web server has opened a connection to the servlet container, the connection can be in one of the following states:

    • Idle
      No request is being handled over this connection.
    • Assigned
      The connecton is handling a specific request.

    Once a connection is assigned to handle a particular request, the basic request informaton (e.g. HTTP headers, etc) is sent over the connection in a highly condensed form (e.g. common strings are encoded as integers). Details of that format are below in Request Packet Structure. If there is a body to the request (content-length > 0), that is sent in a separate packet immediately after.

    At this point, the servlet container is presumably ready to start processing the request. As it does so, it can send the following messages back to the web server:

    • SEND_HEADERS
      Send a set of headers back to the browser.
    • SEND_BODY_CHUNK
      Send a chunk of body data back to the browser.
    • GET_BODY_CHUNK
      Get further data from the request if it hasn't all been transferred yet. This is necessary because the packets have a fixed maximum size and arbitrary amounts of data can be included the body of a request (for uploaded files, for example). (Note: this is unrelated to HTTP chunked tranfer).
    • END_RESPONSE
      Finish the request-handling cycle.

    Each message is accompanied by a differently formatted packet of data. See Response Packet Structures below for details.

    There is a bit of an XDR heritage to this protocol, but it differs in lots of ways (no 4 byte alignment, for example).

    AJP13 uses network byte order for all data types.

    There are four data types in the protocol: bytes, booleans, integers and strings.

    Byte
    A single byte.
    Boolean
    A single byte, 1 = true, 0 = false. Using other non-zero values as true (i.e. C-style) may work in some places, but it won't in others.
    Integer
    A number in the range of 0 to 2^16 (32768). Stored in 2 bytes with the high-order byte first.
    String
    A variable-sized string (length bounded by 2^16). Encoded with the length packed into two bytes first, followed by the string (including the terminating '\0'). Note that the encoded length does not include the trailing '\0' -- it is like strlen. This is a touch confusing on the Java side, which is littered with odd autoincrement statements to skip over these terminators. I believe the reason this was done was to allow the C code to be extra efficient when reading strings which the servlet container is sending back -- with the terminating \0 character, the C code can pass around references into a single buffer, without copying. If the \0 was missing, the C code would have to copy things out in order to get its notion of a string. Note a size of -1 (65535) indicates a null string and no data follow the length in this case.

    According to much of the code, the max packet size is 8 * 1024 bytes (8K). The actual length of the packet is encoded in the header.

    Packets sent from the server to the container begin with 0x1234. Packets sent from the container to the server begin with AB (that's the ASCII code for A followed by the ASCII code for B). After those first two bytes, there is an integer (encoded as above) with the length of the payload. Although this might suggest that the maximum payload could be as large as 2^16, in fact, the code sets the maximum to be 8K.
    Packet Format (Server->Container)
    Byte 0 1 2 3 4...(n+3)
    Contents 0x12 0x34 Data Length (n) Data
    Packet Format (Container->Server)
    Byte 0 1 2 3 4...(n+3)
    Contents A B Data Length (n) Data

    For most packets, the first byte of the payload encodes the type of message. The exception is for request body packets sent from the server to the container -- they are sent with a standard packet header (0x1234 and then length of the packet), but without any prefix code after that (this seems like a mistake to me).

    The web server can send the following messages to the servlet container:
    Code Type of Packet Meaning
    2 Forward Request Begin the request-processing cycle with the following data
    7 Shutdown The web server asks the container to shut itself down.
    8 Ping The web server asks the container to take control (secure login phase).
    10 CPing The web server asks the container to respond quickly with a CPong.
    none Data Size (2 bytes) and corresponding body data.

    To ensure some basic security, the container will only actually do the Shutdown if the request comes from the same machine on which it's hosted.

    The first Data packet is send immediatly after the Forward Request by the web server.

    The servlet container can send the following types of messages to the web server:
    Code Type of Packet Meaning
    3 Send Body Chunk Send a chunk of the body from the servlet container to the web server (and presumably, onto the browser).
    4 Send Headers Send the response headers from the servlet container to the web server (and presumably, onto the browser).
    5 End Response Marks the end of the response (and thus the request-handling cycle).
    6 Get Body Chunk Get further data from the request if it hasn't all been transferred yet.
    9 CPong Reply The reply to a CPing request

    Each of the above messages has a different internal structure, detailed below.

    For messages from the server to the container of type "Forward Request":

    AJP13_FORWARD_REQUEST := prefix_code (byte) 0x02 = JK_AJP13_FORWARD_REQUEST method (byte) protocol (string) req_uri (string) remote_addr (string) remote_host (string) server_name (string) server_port (integer) is_ssl (boolean) num_headers (integer) request_headers *(req_header_name req_header_value) attributes *(attribut_name attribute_value) request_terminator (byte) OxFF

    The request_headers have the following structure:

    req_header_name := sc_req_header_name | (string) [see below for how this is parsed] sc_req_header_name := 0xA0xx (integer) req_header_value := (string)

    The attributes are optional and have the following structure:

    attribute_name := sc_a_name | (sc_a_req_attribute string) attribute_value := (string)

    Not that the all-important header is "content-length', because it determines whether or not the container looks for another packet immediately.

    Detailed description of the elements of Forward Request.

    For all requests, this will be 2. See above for details on other prefix codes.

    The HTTP method, encoded as a single byte:

    Command NameCode
    OPTIONS1
    GET2
    HEAD3
    POST4
    PUT5
    DELETE6
    TRACE7
    PROPFIND8
    PROPPATCH9
    MKCOL10
    COPY11
    MOVE12
    LOCK13
    UNLOCK14
    ACL15
    REPORT16
    VERSION-CONTROL17
    CHECKIN18
    CHECKOUT19
    UNCHECKOUT20
    SEARCH21
    MKWORKSPACE22
    UPDATE23
    LABEL24
    MERGE25
    BASELINE_CONTROL26
    MKACTIVITY27

    These are all fairly self-explanatory. Each of these is required, and will be sent for every request.

    The structure of request_headers is the following: First, the number of headers num_headers is encoded. Then, a series of header name req_header_name / value req_header_value pairs follows. Common header names are encoded as integers, to save space. If the header name is not in the list of basic headers, it is encoded normally (as a string, with prefixed length). The list of common headers sc_req_header_nameand their codes is as follows (all are case-sensitive):

    NameCode valueCode name
    accept0xA001SC_REQ_ACCEPT
    accept-charset0xA002SC_REQ_ACCEPT_CHARSET
    accept-encoding0xA003SC_REQ_ACCEPT_ENCODING
    accept-language0xA004SC_REQ_ACCEPT_LANGUAGE
    authorization0xA005SC_REQ_AUTHORIZATION
    connection0xA006SC_REQ_CONNECTION
    content-type0xA007SC_REQ_CONTENT_TYPE
    content-length0xA008SC_REQ_CONTENT_LENGTH
    cookie0xA009SC_REQ_COOKIE
    cookie20xA00ASC_REQ_COOKIE2
    host0xA00BSC_REQ_HOST
    pragma0xA00CSC_REQ_PRAGMA
    referer0xA00DSC_REQ_REFERER
    user-agent0xA00ESC_REQ_USER_AGENT

    The Java code that reads this grabs the first two-byte integer and if it sees an '0xA0' in the most significant byte, it uses the integer in the second byte as an index into an array of header names. If the first byte is not '0xA0', it assumes that the two-byte integer is the length of a string, which is then read in.

    This works on the assumption that no header names will have length greater than 0x9FFF (==0xA000 - 1), which is perfectly reasonable, though somewhat arbitrary. (If you, like me, started to think about the cookie spec here, and about how long headers can get, fear not -- this limit is on header names not header values. It seems unlikely that unmanageably huge header names will be showing up in the HTTP spec any time soon).

    Note: The content-length header is extremely important. If it is present and non-zero, the container assumes that the request has a body (a POST request, for example), and immediately reads a separate packet off the input stream to get that body.

    The attributes prefixed with a ? (e.g. ?context) are all optional. For each, there is a single byte code to indicate the type of attribute, and then a string to give its value. They can be sent in any order (though the C code always sends them in the order listed below). A special terminating code is sent to signal the end of the list of optional attributes. The list of byte codes is:

    InformationCode ValueNote
    ?context0x01Not currently implemented
    ?servlet_path0x02Not currently implemented
    ?remote_user0x03
    ?auth_type0x04
    ?query_string0x05
    ?route0x06
    ?ssl_cert0x07
    ?ssl_cipher0x08
    ?ssl_session0x09
    ?req_attribute0x0AName (the name of the attribut follows)
    ?ssl_key_size0x0B
    ?secret0x0C
    ?stored_method0x0D
    are_done0xFFrequest_terminator

    The context and servlet_path are not currently set by the C code, and most of the Java code completely ignores whatever is sent over for those fields (and some of it will actually break if a string is sent along after one of those codes). I don't know if this is a bug or an unimplemented feature or just vestigial code, but it's missing from both sides of the connection.

    The remote_user and auth_type presumably refer to HTTP-level authentication, and communicate the remote user's username and the type of authentication used to establish their identity (e.g. Basic, Digest). I'm not clear on why the password isn't also sent, but I don't know HTTP authentication inside and out.

    The query_string, ssl_cert, ssl_cipher, and ssl_session refer to the corresponding pieces of HTTP and HTTPS.

    The route, as I understand it, is used to support sticky sessions -- associating a user's session with a particular Tomcat instance in the presence of multiple, load balancing servers. I don't know the details.

    Beyond this list of basic attributes, any number of other attributes can be sent via the req_attribute code (0x0A). A pair of strings to represent the attribute name and value are sent immediately after each instance of that code. Environment values are passed in via this method.

    Finally, after all the attributes have been sent, the attribute terminator, 0xFF, is sent. This signals both the end of the list of attributes and also then end of the Request Packet.

    For messages which the container can send back to the server. AJP13_SEND_BODY_CHUNK := prefix_code 3 chunk_length (integer) chunk *(byte) AJP13_SEND_HEADERS := prefix_code 4 http_status_code (integer) http_status_msg (string) num_headers (integer) response_headers *(res_header_name header_value) res_header_name := sc_res_header_name | (string) [see below for how this is parsed] sc_res_header_name := 0xA0 (byte) header_value := (string) AJP13_END_RESPONSE := prefix_code 5 reuse (boolean) AJP13_GET_BODY_CHUNK := prefix_code 6 requested_length (integer)

    Details:

    The chunk is basically binary data, and is sent directly back to the browser.

    The status code and message are the usual HTTP things (e.g. "200" and "OK"). The response header names are encoded the same way the request header names are. See above for details about how the the codes are distinguished from the strings. The codes for common headers are:

    NameCode value
    Content-Type0xA001
    Content-Language0xA002
    Content-Length0xA003
    Date0xA004
    Last-Modified0xA005
    Location0xA006
    Set-Cookie0xA007
    Set-Cookie20xA008
    Servlet-Engine0xA009
    Status0xA00A
    WWW-Authenticate0xA00B

    After the code or the string header name, the header value is immediately encoded.

    Signals the end of this request-handling cycle. If the reuse flag is true (anything other than 0 in the actual C code), this TCP connection can now be used to handle new incoming requests. If reuse is false (==0), the connection should be closed.

    The container asks for more data from the request (If the body was too large to fit in the first packet sent over or when the request is chuncked). The server will send a body packet back with an amount of data which is the minimum of the request_length, the maximum send body size (8186 (8 Kbytes - 6)), and the number of bytes actually left to send from the request body.
    If there is no more data in the body (i.e. the servlet container is trying to read past the end of the body), the server will send back an "empty" packet, which is a body packet with a payload length of 0. (0x12,0x34,0x00,0x00)

    What happens if the request headers > max packet size? There is no provision to send a second packet of request headers in case there are more than 8K (I think this is correctly handled for response headers, though I'm not certain). I don't know if there is a way to get more than 8K worth of data into that initial set of request headers, but I'll bet there is (combine long cookies with long ssl information and a lot of environment variables, and you should hit 8K easily). I think the connector would just fail before trying to send any headers in this case, but I'm not certain.

    What about authentication? There doesn't seem to be any authentication of the connection between the web server and the container. This strikes me as potentially dangerous.

    tomcat-connectors-1.2.50-src/xdocs/ajp/project.xml0000644000000000000020000001225614655113617020414 0ustar rootbin The Apache Tomcat Connectors - AJP Protocol Reference The Apache Tomcat Connectors - AJP Protocol Reference tomcat-connectors-1.2.50-src/xdocs/ajp/ajpv13ext.xml0000644000000000000020000005233314655113617020573 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. AJPv13 extensions Proposal Henri Gomez

    This document is a proposal of evolution of the current Apache JServ Protocol version 1.3, also known as ajp13. I'll not cover here the full protocol but only the add-on from ajp13. This nth pass include comments from the tomcat-dev list and misses discovered during developpment.

    ajp13 is a good protocol to link a servlet engine like tomcat to a web server like Apache:

    • use persistent connections to avoid reconnect time at each request
    • encode many http commands to reduce stream size
    • send to servlet engine much info from web server (like SSL certs)

    But ajp13 lacks support for:

    • security between web server and servlet engine. Anybody can connect to an ajp13 port (no login mechanism used) You could connect, for example with telnet, and keep the remote thread up by not sending any data (no timeout in connection)
    • context information passed from servlet engine to web server. Part of the configuration of JK, the web server connector, is to indicate to the web server which URI to handle. The mod_jk JkMount directive, told to web server which URI must be forwarded to servlet engine. A servlet engine already knows which URI it handle and TC 3.3 is allready capable to generate a config file for JK from the list of available contexts.
    • state update of contexts from servlet engine to web server. Big site with farm of Tomcat, like ISP and virtuals hosters, may need to stop a context for admin purposes. In that case the front web server must know that the context is currently down, to eventually relay the request to another Tomcat
    • verify state of connection before sending request. Actually JK send the request to the servlet engine and next wait for the answer. But one of the beauty of the socket API, is you that you could write() to a closed connection without any error reporting, but a read() to a closed connection return you the error code.

    Let's describe here the features and add-on that could be added to AJP13. Since this document is a proposal, a reasonable level of chaos must be expected at first. Be sure that discussion on tomcat list will help clarify points, add features but the current list seems to be a 'minimun vital'

    • Advanced login features at connect time
    • Basic authorisation system, where a shared secret key is present in web server and servlet engine.
    • Basic protocol negociation, just to be sure that if functionnalities are added to AJP13 in the future, current implementations will still works.
    • Clean handling of 'Unknown packets'
    • Extended env vars passed from web-server to servlet engine.
    • Add extra SSL informations needed by Servlet 2.3 API (like SSL_KEY_SIZE)

    1. WEB-SERVER send LOGIN INIT CMD + NEGOCIATION DATA + WEB SERVER INFO
    2. TOMCAT respond with LOGIN SEED CMD + RANDOM DATA
    3. WEB-SERVER calculted the MD5 of RANDOM DATA+SECRET DATA
    4. WEB-SERVER send LOGIN COMP CMD + MD5 (SECRET DATA + RANDOM DATA)
    5. TOMCAT respond with LOGIN STATUS CMD + NEGOCIED DATA + SERVLET ENGINE INFO
    To prevent DOS attack, the servlet engine will wait the LOGIN CMD only 15/30 seconds and reports the timeout exception for admins investigation. The login command will contains basic protocol negociation information like compressing ability, crypto, context info (at start up), context update at run-time (up/down), level of SSL env vars, AJP protocol level supported (level1/level2/level3...) The web server info will contain web server info and connector name (ie Apache 1.3.26 + mod_ssl 2.8.8 + mod_jk 1.2.41 + mod_perl 1.25). The servlet engine will mask the negociation mask with it's own mask (what it can do) and return it when loggin is accepted. This will help having a basic AJP13 implementation (level 1) on a web-server working with a more advanced protocol handler on the servlet engine side or vice-versa. AJP13 was designed to be small and fast and so many SSL informations present in the web-server are not forwarded to the servlet engine. We add here four negociations flags to provide more informations on client SSL data (certs), server SSL datas, crypto used, and misc datas (timeout...).

    +----------------+------------------+-----------------+ | LOGIN INIT CMD | NEGOCIATION DATA | WEB SERVER INFO | +----------------+------------------+-----------------+ +----------------+----------------+ | LOGIN SEED CMD | MD5 of entropy | +----------------+----------------+ +----------------+----------------------------+ | LOGIN COMP CMD | MD5 of RANDOM + SECRET KEY | +----------------+----------------------------+ +-----------+---------------+---------------------+ | LOGOK CMD | NEGOCIED DATA | SERVLET ENGINE INFO | +-----------+---------------+---------------------+ +------------+--------------+ | LOGNOK CMD | FAILURE CODE | +------------+--------------+

    • LOGIN INIT CMD, LOGIN SEED CMD, LOGIN COMP CMD, LOGOK CMD, LOGNOK CMD are 1 byte long.
    • MD5, MD5 of RANDOM + SECRET KEY are 32 chars long.
    • NEGOCIATION DATA, NEGOCIED DATA, FAILURE CODE are 32 bits long.
    • WEB SERVER INFO, SERVLET ENGINE INFO are CString.
    The secret key will be set by a new property in workers.properties: secretkey worker.ajp13.port=8009 worker.ajp13.host=localhost worker.ajp13.type=ajp13 worker.ajp13.secretkey=myverysecretkey

    AJP13 miss a functionality of AJP12, which is shutdown command. A logout will tell servlet engine to shutdown itself. +--------------+----------------------------+ | SHUTDOWN CMD | MD5 of RANDOM + SECRET KEY | +--------------+----------------------------+ +------------+ | SHUTOK CMD | +------------+ +-------------+--------------+ | SHUTNOK CMD | FAILURE CODE | +-------------+--------------+

    • SHUTDOWN CMD, SHUTOK CMD, SHUTNOK CMD are 1 byte long.
    • MD5 of RANDOM + SECRET KEY are 32 chars long.
    • FAILURE CODE is 32 bits long.

    NOTA: While working on AJP13 in JK, I really discovered "JkEnvVar". The following "Extended Env Vars feature" description may not be implemented in extended AJP13 since allready available in original implementation. DESC: Many users will want to see some of their web-server env vars passed to their servlet engine. To reduce the network traffic, the web-servlet will send a table to describing the external vars in a shorter fashion. We'll use there a functionality allready present in AJP13, attributes list: In the AJP13, we've got: AJP13_FORWARD_REQUEST := prefix_code 2 method (byte) protocol (string) req_uri (string) remote_addr (string) remote_host (string) server_name (string) server_port (integer) is_ssl (boolean) num_headers (integer) request_headers *(req_header_name req_header_value) ?context (byte string) ?servlet_path (byte string) ?remote_user (byte string) ?auth_type (byte string) ?query_string (byte string) ?route (byte string) ?ssl_cert (byte string) ?ssl_cipher (byte string) ?ssl_session (byte string) ?attributes *(attribute_name attribute_value) request_terminator (byte) Using short 'web server attribute name' will reduce the network traffic. +-------------------+---------------------------+-------------------------------+----+ | EXTENDED VARS CMD | WEB SERVER ATTRIBUTE NAME | SERVLET ENGINE ATTRIBUTE NAME | ES | +-------------------+---------------------------+-------------------------------+----+ ie: JkExtVars S1 SSL_CLIENT_V_START javax.servlet.request.ssl_start_cert_date JkExtVars S2 SSL_CLIENT_V_END javax.servlet.request.ssl_end_cert_date JkExtVars S3 SSL_SESSION_ID javax.servlet.request.ssl_session_id +-------------------+----+-------------------------------------------+ | EXTENDED VARS CMD | S1 | javax.servlet.request.ssl_start_cert_date | +-------------------+----+-------------------------------------------+ +----+-----------------------------------------+ | S2 | javax.servlet.request.ssl_end_cert_date | +----+-----------------------------------------+ +----+-----------------------------------------+ | S3 | javax.servlet.request.ssl_end_cert_date | +----+-----------------------------------------+ During transmission in extended AJP13 we'll see attributes name containing S1, S2, S3 and attributes values of 2001/01/03, 2002/01/03, 0123AFE56. This example showed the use of extended SSL vars but any 'personal' web-server vars like custom authentification vars could be reused in the servlet engine. The cost will be only some more bytes in the AJP traffic.

    • EXTENDED VARS CMD is 1 byte long.
    • WEB SERVER ATTRIBUTE NAME, SERVLET ENGINE ATTRIBUTE NAME are CString.
    • ES is an empty CString.

    Just after the LOGON PHASE, the web server will ask for the list of contexts and URLs/URIs handled by the servlet engine. It will ease installation in many sites, reduce questions about configuration on tomcat-user list, and be ready for servlet API 2.3. This mode will be activated by a new directive JkAutoMount ie: JkAutoMount examples myworker1 /examples/ If we want to get ALL the contexts handled by the servlet engine, willcard could be used: ie: JkAutoMount * myworker1 * A servlet engine could have many contexts, /examples, /admin, /test. We may want to use only some contexts for a given worker. It was done previously, in Apache HTTP Server for example, by setting by hand the JkMount accordingly in each [virtual] area of Apache. If you web-server support virtual hosting, we'll forward also that information to servlet engine which will only return contexts for that virtual host. In that case the servlet engine will only return the URL/URI matching these particular virtual server (defined in server.xml). This feature will help ISP and big sites which mutualize large farm of Tomcat in load balancing configuration. +-----------------+-------------------+----------+----------+----+ | CONTEXT QRY CMD | VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES | +-----------------+-------------------+----------+----------+----+ +------------------+-------------------+----------+-------------------+----------+---------------+----+ | CONTEXT INFO CMD | VIRTUAL HOST NAME | CONTEXTA | URL1 URL2 URL3 ES | CONTEXTB | URL1 URL2 ... | ES | +------------------+-------------------+----------+-------------------+----------+---------------+----+ We'll discover via context-query, the list of URL/MIMES handled by the remove servlet engine for a list of contextes. In wildcard mode, CONTEXTA will contains just '*'.

    • CONTEXT QRY CMD and CONTEXT INFO CMD are 1 byte long.
    • VIRTUAL HOST NAME is a CString, ie an array of chars terminated by a null byte (/0).
    • An empty string is just a null byte (/0).
    • ES is an empty CString. Indicate end of URI/URLs or end of CONTEXTs.
    NB:
    When VirtualMode is not to be used, the VIRTUAL HOST NAME is '*'. In that case the servlet engine will send all contexts handled.

    Context update are messages caming from the servlet engine each time a context is desactivated/reactivated. The update will be in use when the directive JkUpdateMount. This directive will set the AJP13_CONTEXT_UPDATE_NEG flag. ie: JkUpdateMount myworker1 +--------------------+-------------------+----------+--------+----------+--------+----+ | CONTEXT UPDATE CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES | +--------------------+-------------------+----------+--------+----------+--------+----+

    • CONTEXT UPDATE CMD, STATUS are 1 byte long.
    • VIRTUAL HOST NAME, CONTEXTS are CString.
    • ES is an empty CString. Indicate end of CONTEXTs.
    NB:
    When VirtualMode is not in use, the VIRTUAL HOST NAME is '*'. STATUS is one byte indicating if context is UP/DOWN/INVALID

    This query will be used by the web-server to determine if a given contexts are UP, DOWN or INVALID (and should be removed). +-------------------+--------------------+----------+----------+----+ | CONTEXT STATE CMD | VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES | +-------------------+--------------------+----------+----------+----+ +-------------------------+-------------------+----------+--------+----------+--------+----+ | CONTEXT STATE REPLY CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES | +-------------------------+-------------------+----------+-------------------+--------+----+

    • CONTEXT STATE CMD, CONTEXT STATE REPLY CMD, STATUS are 1 byte long.
    • VIRTUAL HOST NAME, CONTEXTs are CString
    • ES is an empty CString
    NB:
    When VirtualMode is not in use, the VIRTUAL HOST NAME is an empty string.

    Sometimes even with a well negocied protocol, we may be in a situation where one end (web server or servlet engine), will receive a message it couldn't understand. In that case the receiver will send an 'UNKNOW PACKET CMD' with attached the unhandled message. +--------------------+------------------------+-------------------+ | UNKNOWN PACKET CMD | UNHANDLED MESSAGE SIZE | UNHANDLED MESSAGE | +--------------------+------------------------+-------------------+ Depending on the message, the sender will report an error and if possible will try to forward the message to another endpoint.

    • UNKNOWN PACKET CMD is 1 byte long.
    • UNHANDLED MESSAGE SIZE is 16bits long.
    • UNHANDLED MESSAGE is an array of byte (length is contained in UNHANDLED MESSAGE SIZE)
    NB:
    added UNHANDLED MESSAGE SIZE (development)

    NOTA: This fonctionality may never be used, since it may slow up the normal process since requiring on the web-server side an extra IO (read) before forwarding the request..... One of the beauty of socket APIs, is that you could write on a half closed socket. When servlet engine close the socket, the web server will discover it only at the next read() to the socket. Basically, in the AJP13 protocol, the web server send the HTTP HEADER and HTTP BODY (POST by chunk of 8K) to the servlet engine and then try to receive the reply. If the connection was broken the web server will learn it only at receive time. We could use a buffering scheme but what happen when you use the servlet engine for upload operations with more than 8ko of datas ? The hack in the AJP13 protocol is to add some bytes to read after the end of the service: EXAMPLE OF DISCUSSION BETWEEN WEB SERVER AND SERVLET ENGINE AJP HTTP-HEADER (+ HTTP-POST) (WEB->SERVLET) AJP HTTP-REPLY (SERVLET->WEB) AJP END OF DISCUSSION (SERVLET->WEB) ---> AJP STATUS (SERVLET->WEB AJP13) The AJP STATUS will not be read by the servlet engine at the end of the request/response #N but at the begining of the next session. More at that time the web server could also use OS dependants functions (or better APR functions) to determine if there is also more data to read. And that datas could be CONTEXT Updates. This will avoid the web server sending a request to a desactivated context. In that case, if the load balancing is used, it will search for another servlet engine to handle the request. And that feature will help ISP and big sites with farm of tomcat, to updates their servlet engine without any service interruption. +------------+-------------+ | STATUS CMD | STATUS DATA | +------------+-------------+

    • STATUS CMD and STATUS DATA are one byte long.

    The goal of the extended AJP13 protocol is to overcome some of the original AJP13 limitation. An easier configuration, a better support for large site and farm of Tomcat, a simple authentification system and provision for protocol updates. Using the stable ajp13 implementation in JK (native) and in servlet engine (java), it's a reasonable evolution of the well known ajp13.

    Index of Commands and ID to be added in AJP13 Protocol

    Command NameCommand Number
    AJP13_LOGINIT_CMD0x10
    AJP13_LOGSEED_CMD0x11
    AJP13_LOGCOMP_CMD0x12
    AJP13_LOGOK_CMD0x13
    AJP13_LOGNOK_CMD0x14
    AJP13_CONTEXT_QRY_CMD0x15
    AJP13_CONTEXT_INFO_CMD0x16
    AJP13_CONTEXT_UPDATE_CMD0x17
    AJP13_STATUS_CMD0x18
    AJP13_SHUTDOWN_CMD0x19
    AJP13_SHUTOK_CMD0x1A
    AJP13_SHUTNOK_CMD0x1B
    AJP13_CONTEXT_STATE_CMD0x1C
    AJP13_CONTEXT_STATE_REP_CMD0x1D
    AJP13_UNKNOW_PACKET_CMD0x1E

    Command NameNumberDescription
    AJP13_CONTEXT_INFO_NEG0x80000000web-server want context info after login
    AJP13_CONTEXT_UPDATE_NEG0x40000000web-server want context updates
    AJP13_GZIP_STREAM_NEG0x20000000web-server want compressed stream
    AJP13_DES56_STREAM_NEG0x10000000web-server want crypted DES56 stream with secret key
    AJP13_SSL_VSERVER_NEG0x08000000Extended info on server SSL vars
    AJP13_SSL_VCLIENT_NEG0x04000000Extended info on client SSL vars
    AJP13_SSL_VCRYPTO_NEG0x02000000Extended info on crypto SSL vars
    AJP13_SSL_VMISC_NEG0x01000000Extended info on misc SSL vars

    Negociation IDNumberDescription
    AJP13_PROTO_SUPPORT_AJPXX_NEG0x00FF0000mask of protocol supported
    AJP13_PROTO_SUPPORT_AJP13L1_NEG0x00010000communication could use AJP13 Level 1
    AJP13_PROTO_SUPPORT_AJP13L2_NEG0x00020000communication could use AJP13 Level 2
    AJP13_PROTO_SUPPORT_AJP13L3_NEG0x00040000communication could use AJP13 Level 3

    All others flags must be set to 0 since they are reserved for future use.

    Failure IdNumber
    AJP13_BAD_KEY_ERR0xFFFFFFFF
    AJP13_ENGINE_DOWN_ERR0xFFFFFFFE
    AJP13_RETRY_LATER_ERR0xFFFFFFFD
    AJP13_SHUT_AUTHOR_FAILED_ERR0xFFFFFFFC

    Failure IdNumber
    AJP13_CONTEXT_DOWN0x01
    AJP13_CONTEXT_UP0x02
    AJP13_CONTEXT_OK0x03

    tomcat-connectors-1.2.50-src/xdocs/index.xml0000644000000000000020000001703714655113617017305 0ustar rootbin ]> &project; Mladen Turk Rainer Jung Documentation Overview

    The Apache Tomcat Connectors project is part of the Tomcat project and provides web server plugins to connect web servers with Tomcat and other backends.

    The supported web servers are:

    • the Apache HTTP Server with a plugin (module) named mod_jk.
    • Microsoft IIS with a plugin (extension) named ISAPI redirector (or simply redirector).

    In all cases the plugin uses a special protocol named Apache JServ Protocol or simply AJP to connect to the backend. Backends known to support AJP are Apache Tomcat, Jetty and JBoss. Although there exist 3 versions of the protocol, ajp12, ajp13, ajp14, most installations only use ajp13. The older ajp12 does not use persistent connections and is obsolete, the newer version ajp14 is still experimental. Sometimes ajp13 is called AJP 1.3 or AJPv13, but we will mostly use the name ajp13.

    Most features of the plugins are the same for all web servers. Some details vary on a per web server basis. The documentation and the configuration is split into common parts and web server specific parts.

    down to the more detailed documentation that is available. Each available manual is described in more detail below.

    • JK-1.2.50 released

      The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.50 Stable. This release contains improvements and bug fixes for issues found in previous releases.

      Download the JK 1.2.50 release.

    • Download previous releases from the archives.

    • workers.properties

      A Tomcat worker is a Tomcat instance that is waiting to execute servlets on behalf of some web server. For example, we can have a web server such as Apache forwarding servlet requests to a Tomcat process (the worker) running behind it.

      This page contains detailed description of all workers.properties directives.

    • uriworkermap.properties

      The forwarding of requests from the web server to tomcat gets configured by defining mapping rules. The so-called uriworkermap file is a mechanism of defining those rules.

    • Status Worker

      The status worker is a builtin management worker. It displays state information and can also be used to dynamically reconfigure JK.

    • Apache HTTP Server (mod_jk)

      This page contains detailed description of all directives of mod_jk for the Apache HTTP Server.

    • Microsoft IIS (ISAPI redirector)

      This page contains detailed description of all directives of the ISAPI redirector for Microsoft IIS.

    • Quick Start

      This page describes the configuration files used by JK on the web server side for the 'impatient'.

    • All about workers

      This page contains an overview about the various aspects of defining and using workers.

    • Timeouts

      This page describes the possible timeout settings you can use.

    • Load Balancing

      This page contains an introduction on load balancing with JK.

    • Reverse Proxy

      This page contains an introduction to reverse proxies, how JK handles this situation and how you can influence the JK proxying behaviour.

    These pages contain detailed descriptions of how to build and install JK for the various web servers.

    • AJPv13

      This page describes the Apache JServ Protocol version 1.3 (hereafter ajp13).

    • AJPv13 Extension Proposal

      This page describes an extension proposal for ajp13.

    tomcat-connectors-1.2.50-src/xdocs/images/0000755000000000000020000000000014655113617016711 5ustar rootbintomcat-connectors-1.2.50-src/xdocs/images/docs.gif0000644000000000000020000000040514655113617020327 0ustar rootbinGIF89a„ÿÿÿþþþ000ðððààà///111ÀÀÀÏÏÏßßß¿¿¿ÐÐÐýÿþ/10ÎÎÎÞàßÀÀ¾þÿÿ€€€NNN___ááá°°°OOOáßàÿÿý002,Š Ždi–A0ªç(¼p ŸÂ`ß¡Åi ‡àA$&> bX4"Mµ`‘ iƒâ˜è>IŒÁÑìv_’€P6Ó.6ñáF@ࢵњ Bî& Uf}vx…rˆ4lŽxy–˜(Ž ¡-23­³³£³!;tomcat-connectors-1.2.50-src/xdocs/images/tomcat.gif0000644000000000000020000000402214655113617020665 0ustar rootbinGIF89a’\ÄÿÿÿÒ¦)ýÝu" GB4pl^¨”W‹r+’’‘ÓÓÓóóô³´´Ð´bñÑp¸”.!ù,’\ÿ Ždižhª®bQ(l,›LÁ”P®C@>ú³ pxRŽq ¨!Q¼_´7eZ¯%ÃñHH`e í–%ñν¯úJØn_k”¢í(qæ4:Οbc7}" umƒx?"QU„4 uGŠq[^&UŽ‘¤&†–˜_š[ Z'¡‹¥¶Z®[wX†–¹¸¶ÃD•– _ ʺËÄÕ`mǩПV tu“ÍÖç( GÒÈÐd# õö÷ Í¿–ìä˜CGpÄv@3`´‡“@1`¯‚èR¤¨ ¢ÇcÄU^5¥~tT¹Çxw̵ܜç©ÙÖŠYwQ€ Hçí{¦nÍ›3L8nÿþõñ2?À«äänÁ+:Pðy–Õ¿¹²¹ìˆ‡ÏëîOI5§½Î[ŠpŽWáâÇ/³*÷@ý¿)otî²ülÎe˜à-{a ñ:U0/€tÞ$—ˆYÇ/êàa2åY΃”_¯àóë! ƒ¿ÀDà¸ð@f=@y@JÅ׫èL8‘à €Sª ªª…ëgX´çÍÆP:$Pdá>Ú‰¯`D¤áN cBž%1@€PU‡E)úCH¼" ð'ÿ"îm0c¿¶‰¶ð b,„Ô8·^Ñq°sÙ¯À¶¿8’ñ "ŇF.$fR9Œ£þ8 $P!dü ç2€ÜI}YÙ%á?.J2~`[Ðþæ— ¹ßCœ'?IÈa(¿ Àñ é5ñaƒ•ÛËðÊ‚ è´ÔL†I̘Ü—òãZå FJ“¸ˆº,‘%rä˜`™s“àÅ€ð…]“8rôl6¬#ÛL¢*<Ci~ä(¤™fK0D<†rÍ´†)óè2Á0Àï[d<è‘“•¸¤ž!” ¸Œ‚@_þok£$û<²AôÌ£Pþ9J*gè‚×ÿ’t,·¦*ÛLô!=ü­P…+ 4›ß<`VéÑý4t…ɧA¦£)—2Œ&CM™ŽpÖÁb<Í!|:CJÂѡ˘٠Ypš1|ÁV]+P KóTMâxª@êˆþ³¬:G†á3ÜQt5>+Zcœëê þ鎆ÆmË`jÙZÄÅéÊc(aŒjE»!S¸ÛhøÂz°¨ÆÕ¯JªjNrÔKÕ€ë ŠV'æÑê x}H¯€›oå¥åš*$~C¢2§«’.‹„Ìâk³‹¹HeØ 4‡¢‘HV%m‰ÏH8ÐanU]QÚ[+”³g4ŠNç Ø{IP¶D°Õ=¶[Ù!ØÊ´¶ @!»é¦Ã(…S­"gkZNÎ?ØXËÆ”­ ˜B§{É5»£¹?CÈòŽÐÜûÊ@¸GI«ÿ&ÑË_@“ÀŽ‚÷Äw9Éeò¯}#¼† ‡o„:ÝMw9¬×Q®+ ™Š»4b—ˆ±Œgì?µ¹x½ÂÉIœc”!;tomcat-connectors-1.2.50-src/xdocs/images/add.gif0000644000000000000020000000201514655113617020126 0ustar rootbinGIF89açÿÿÿÿþÿþþþÿÿýþÿÿ# ê£aì¥c 4Àn ì£_ÿ¡Iÿ­Uï´r ÿüï5؉Pñ†8ùCÞ˜\Cö¡Qý¡Jÿ­Sý±Yÿ½fôÄ„ ÿüñ1ݘ]ï“@ÿ@ÿžCý¢Iý±[ÿ½dóà æÓµ ÿþô$ ä˜Mÿž>ÿŸAóà õÓ–ûЋðÒ  é£^õ¤Ué²yI+ 8."0000026/%A/ ïЙùщõÑ•î±n÷²díÀ‡>,˜¢×°û ÐÿµØëïЗúÑ‚õÒñÀ~ûÁwìÄ‘ */B—³Û“Âðµ×ò àÇ©5/#äÒ®,-I€†Úžÿ«Êùÿ÷ÿJKšR)£:‰1!zohÅxwì†õ7«»Ô ÿúÿEP*»OÜdÿk2ýwNòhÔ2ÿüÿ FR%³e*ärCß)ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,ò ÀÀƒppÀ€ƒ&dˆ‰ p(£@†0p„(XÀ ÀÈ@ˆP ,\ÀAÃ<|yD#H”0ñàŠ*V°háâà 1d˜øÙaÆ5lÜÀQu :vðèáã B†)’0‚‘#H’(Y¤‰“'P¢HIøa •*V®`É¢e —.Dz òL1c–)c¦ãCgФQ³†M7oàÄ‘3¡EsèÔ±sO={øôé30âÀ~þ $hEQ ,°›7ÆçУG§(@@;tomcat-connectors-1.2.50-src/xdocs/images/tomcat.png0000644000000000000020000001175714655113617020721 0ustar rootbin‰PNG  IHDR’\…™ìJ pHYs  šœ¡IDATxÚí]klSgš~Ì$µF8tdZwŠ I¢¸*jÐv×ÃÄÝ!7 ù12Ùbµ] !™QQ¥iš’’˜N;i ¨3?HÁ!mÂ6ݑԪ¶SŒS"uh(g8ßá;ÇçîããcÖ¯d•Æ·syü¼Ï{ùÞ à ÿxðXUSŬª©bB¡“‹Ç2dVÕT1'ƒAÁãÀˆ=èç…Þ#õ½yðPP(ÄX­ìc›ÿåœ}ìrïGH:<¶ù_æ©Àje\%O2½½ûM &Àn;n­@’úoH ®’'Sny˜ÑÝ…B!Fê˜åŽWO ÍCÞáp˜‰Æf~_sÊóc!¬Y]‡àð0c†ãíëëe–WU31¯Ç §Ã˜¾rEóç3 c±X, Ã0%¯ÏiÎÈEw:ìøumàk¢±¼¸n]ÖÁÔÖº‘iïüàsÏ?óžr=¸¹dØ1å4gôEw—/„×ã}m6ÁÔÖº‘ ôˆ>ÿ/5ÿˆòŠ @ä›si}—R6ʉ2rÑɯ™Ü )0…ÃaCÁÔ××+ "¯Ç wùBöÿ§ÎŸW 1ðÈ*$ÞE'so´ulmŲÈfÄñ‡‡Eݱ–¦Ò¬]¿<X,‹l#×9“soD€÷ö¾7âø¶ú_“|ÓaGÝJ๲»€‹‘놽 £Bš¾ ð»ö§Q5’|ßÛÝ]hmÝ’rãC¡ñ8ñJEïRW’QJ–,Û]S”t)7½½oÆåØhw‡6[¡À9-@HY(4_^U•òwwùBìÙ¼ oø›$ÛZ72Ä=^Œ\Gõ6„>OÕ±"îtØQë]>[ i£õuNÑs`É)ËÖ¾¹Ÿ|ucÌ$%€ÓeI~žHÈ¥éùyÖ¯SH ìT5ê}¹©O¹GyE~òÈ9,vUÊJæãÐè=AÀy=néù9._½ ¸0}p5Æÿ|ÿ,ËrB€r:ì8øEŠK£múÊTVVæd„)ÉŸê¯ÆÑ‘RìØ;hlN‡/4Ö๲»(+™¥‹ðnh=çý»ÏâDОˆòŠ Øl…lØþ |'®ê1$³€‘Oc¸ 㓯~Ìj8:ÜÏ3RŽØú:'êV:pùêmàH›ÍVˆkRXIIš|OR9Ñ®â˜ÊnçÕFØC ˆÄ@ãtØMÃ(y å¹Ër Â/4Ö<4çfj×fÆF\?}ÕÕ5p»kŠæFBÏï)Y²Ä°súumýÉÓ9+=­¬dþÃ$’i% ;‚àH-N&ÿí*±ÇÛZ7â•W;QYYi1 èCS7qhôNÇ$kv-M¥)ù’1›±™è<#)ÎÉàÁøØèL?W‰ÑØ 'aW`E¼téb6t–ÊÍDc3ô Ð?¯ÇÍìÝ0m@¹Ý5EVÄà/¬X_§îýÛ{¾e—¤Æ&Bs邵)`"51-:K‰‘ð [ž³@ ‡ÃÌïuÁUbÅ‹ëÖɾž$ßär5´M„°¼ª ~_3óv`$-—çtØe“BVïK&+½7'M=&ÿìØ;º•hêV:²â~r HË"Û6]œÏ($ïâúé³)¿¢F¾9‡©óçU‰°—«Ä‡ÃšØ‰an$j½+ÍÌu<¦˜‰Æ&Bðûš±¯í±FÂýËWos¢3:o”i3JÿèÍB®+Ç-ù}ÍðÖnÀêÆ–¢ž¾Ã %@$nFwy|pilhȸv MÝD N‡»|Å’ÂúÂô´“HÌâòÕÛ¸0}¹`ÅsewEëk9ÍHÁáaf«ÿ5Ð}Ï´ f˜ŠÙ¡tébMnH6œiSyEÆ&B¸¹ŽDbV‘~ñzÜhi*•}­ÝÅñ|†Ÿ’(ÔròTÉ@&7€fhÔÝõZ[·hf…mík›ÐLI—;€hl&ʼnå„NõWgôæÐ"ž€–h«¥‹H—DŽ—.‘È F ‡Ã iºr:ìØx麖92owwif¦±Ñ#hlhPüzZ³5ùÏ`w‡'E$iD|¯ÄäZlM ¤Ž­-ìÍÖD4˜¶lùOÛÉà ›:ª‚“ÔI\ªÝ«[Ø@46ƒ—¶Áé°cw‡G³!a¸ÚÄãÑ‘(ýCðzÜšXô/Éõ›H}}½ ‰°º»Þ‚Þ"w.œ·fI&3¤$3#ÓwÓ¦p!mFµc¯=-†Rê'³Ø±wBsŸQhê&{$B65,–E6W‰•õßéh"•À¨Ž?=…$]÷zܼ_ô]QíDÚ<Ä´ÊÒÅ D_÷‘OcˆÆfà÷5Ãf+LyŸ‰YŒ|ÃÁc—8©“êjãjy–¹å¸šØˆâ/''MU®H‡aÉ9MþR‘.9:ÅŽ½¢) âzÕ¦2ÄÞÃwµ¡©›øm÷×)¹7§ÃŽÈô]Ýë’º2ŸrD¤QÿìÙq }ÄþýÐè=ì+Wöd-œN!úM©¶! Rúž¥‹̹Àd—%•‘›f Œ“pßß¾3'ÁCꮫ`£¾Ò ÷ú:§ ?:ÅKÛ‡T‰u-ï¡]»|! à†µ¿2ÔFZ;œ;V7¶’ðÒx,Yö1²ÂO m#õ‘f ‘<…Ñô©5Ïuöì¸ xˆ yþ™ïàvýOßÁéÉGñÆäÍ |µ¹œÐÔMö}Fæ¡ÞcÏËh¹Q å—Mô‘Ñô©Æ‚ÃÃL {§ %àYUui¹¸XUu¿Ÿë «4Ôög“ú»ö§5¥ ”–THýíÐè=N±;—šIk¶Ù÷ÕÛûf|xè£y=nóȉgzM™%³8×Ôí._§Ã®XŸñëpÞÚ æ½*Õ¨¦)¥r•Xkt^]›¸Ì#eÏ?óÆ&ÔGoüx¯KpUIKS)*Š¿æ°ˆÛUŒžc ²“œ{“b4ñç“d§º•üGÿ-úP5×ß½ËWŒ?þ/v\ŽR’ëeçO/¹¹Žž>“2ð`Í™ÓaÇ¥ËW3†ø¾¾^Éæ6§ÃŽ¡ÝE¢ Ãg'nô¦ÌNOÎãÜp)’Œvyì#ÆRjŒ”Tàøà V7¶ ýð’¦%Û$OÍdd g8fj½+˜öÎßp\ ß½Dc3øðó¢çŽbÎ{Æ&B¸¿àŸT˪ªûl%þDp\q;ˆP¨NÚRÈ9•WTh!z=n464XæF‚ÿ0­F":©Àz;@WD¢1ZH;v¼Þô¨¤’Ò>ü÷üqßZŽ;ä¿FÌeÐÇC'.•t0†¦n¢É†e¡–¦R¶wH)+ µ«Èµ©<åz£c_XLËH s#A~étëEº,´ªf D{6/ÃÐî"D„!†vaÏæeìüm÷ײ¬BØIL°J™Óag¿‹Ö!r­¬‰Ä,¶÷|‹ªub“”§ú«±¾Î‰SýÕøã¾µ¸¹ŽªuÂöžoU±Ö^'S1Ñ/z5¶ÑŸÅFiû~†'Šå/,ašµä^Ÿ,“¨sQ×n¢qû_Ù›÷åÇòIJ¢a¤X'‘˜åd¥å>—ÿz±æ5‹e‘Íô®Ÿðûš5…™b«rˆº ©­jM­ð&-°J’™GG¢l¤'eÝN±Çp|p0+åÝ\qo¤ÊèP-ºçVåÆÅ†E~g¥–iI\z²•|½ÍV¨¸Ì!Ö Ç d³€(- À+¯>¨ë|ð^—*WFïìãõ¸9šÈÎÚ,%Öµé{œ/mÒT˜Õš> £´·#Efº.š]?§¤T+ñçíÙ¼Œ£m:ߟÏ&Þ”ê$£¯—¤2ÒzX"1‹åkþÌöH}|rÄt}òiþ{åÕNöÚ±µERÕzW0ô!>ˆÈ/ž°S(òƒ)Yé‰âYìÙ¼Œžšüg4ç—”€hCÛgœE¨f\l‘6*++-¤ual"$¸ý íéšÐ;Å¢Q ×ÅØàÃÏWàü­§³záVUÝç€iCÛg‰ÐHÎÎLºHWׯàø!i8fÖ¬®ãè¡¶¦ï5»,:r2ƒë£GiZ@©‘!^D\U€Í #‘nà]ö×¹Í_Qצ;iÝ|R¡w:ì¦ÐO|fZ¾æÏi ðDb6§@¤ ±¡ÁBš¸ýhkÝ("½LéÂl€©ÉF65 Ñî,@¤›k£]­…Ä"³t¢¥ß{ ÑØŒnŸ™)7Gλ}s½*‘š\.HWF".Ž¿òVÏŠü`Ú,43‘(öC½ï¬"W×}à[“Ë5é$‹e‘-нSPÓèmn×L ¦w:ŠY0M„$]]hê&ê}g9LÖÝõVNHW ñÝ}!Åz†´šY„¶Tž‰î…"s–ê}g9€::E“ÿ §Uöøà aí˦ÔHtÆš„ø=ÇáˆÆûç/Òú’õÖ[¸©›Èõ!?2úoz ŸÏiF⃈„ømMß³ÌèÈz1[®.¸ïgœ:âƒ]˜¿}gNJHô^ôN‡mMß§P<]äLLÙ˜¨—«#Íx|f"ì´Õÿš`Uàÿ…k£Ç"“²‡v¡Ãv€Ûk¤Xe%óÙÐX7™-»v«=Çá,£".Û¬ÙŒ‰Ÿµ–+Wðµ=‹H‹Ø¦7Àáï«ti¶™ÀEwä"˜47ÿ“Úš\®èÚ­B„"?à“¯~¬z­€”MŠÕt[mtëL®‚Ij½+رÈb ºv«£žÁ‰à¸îID²AŽÔìm){®ì.þS¦H!Eu¹&Õ@ŠÐ„.ŽÐâƵ¿Buu ¦¯\½o‰Z£³¾ôF‚ÓW®àrä»Ë’È òÈ9M ôtiôü&¢'žLkhq-""$•äGøKy=nEëµÈÄZ°á¡$ÁEoÁn„+ì|?9¡ÞüàÄëqãôøÓƒI1è/¡ñ#3¯Ç ûNÉF,­`Jç—JCŽ|sNÔõÒ®°¶ì+ÝÙŠhG)m™K`R$~ùƒ¯‹ø òûš¡tGÇp8ÌtlmQ-ÄõO–J‹ì P)áf/â*­‹ä@¤e ·Xû‰”ej¤^¡cÊ4¨„$‚ÙÁ$ $9]´vGœQº öRwÖ–vo™œ„Âg+¡§äšðÇëèÅÑ›-›L’@’ÓE4õêÅBË·ÅÌ蕦R JW¨Ó,$MòWùš L’@’ÊeòÄøÛšfBtë*¡ùMZ\ßéÉdÙS* A_s#§å¥$š„’ŽÄ¥eêf*á|=<lôHŠPÏD:!^ c@ ‡Ã ™¥-¤‹ŒúeH ™àƒ‰$ åoíC]ŸÜÀx½´ &³ ’íÒ„Š±tƒ™ƒœäFªa,#]ßïu‰²TºŸÙÀ4Oè¦Ñºˆ²×n²'`Ô^$­­[,Ÿœ,+gþôõõÞçSYYiéé;l‰Lß-êîz‹Óvè@ãö¿¦µb¸kÓö3_\·.ë½LF¢£4±:Ú‡Ÿ¯Dj´ÐUêê„Bt£FàÉi)¡vÒq{´VÍf‘—ÃHôŽÙt§#m'‚ã’{f-jæF¢§ï°åøà ª‘w#×Ùân6­±¡Á2:ö…åËÉIø}Íœ/mBçûóU3é@Æf°fu]F†Ãªb$:ñ(ÕBªÕÙŽHø­Ä–ºJM9|A,…@¶PÊPtuÁé°sö#Yê*EÉ’%g* Ã0)C ÄfWÓ@2ÓØ¹\7í ê…ÆEmÅüR•{'m<™•…aÙœ‘PØÿ°ì¬m6@ Œóu”R@‘ì8ß­óÁå÷5ã•W;u½Àβ‘Üz1H÷î.ȉ†«\5!a®†¡ø E~à4:v켫›W™×Ûûf\N`ç-{Âüøà`Jê`편ªÕËOÏræ““ÏÒ3m`q•<ÉHí$F“y×–» ŦGÚÀR`µjBd^lç6 ô.º[¶ù_Ö$£ëXyS¨×›UüD3éÑۥ렭¼™PZlöïO Hóò·âáåjMqþÂ62¶i‡ØIEND®B`‚tomcat-connectors-1.2.50-src/xdocs/images/fix.gif0000644000000000000020000000053114655113617020165 0ustar rootbinGIF89a¥ÿÿÿþþþŸŸŸ€€€ÀÀÀ°°° OOOÁÁÁŒ{s¢t\ŒN7J<ÿûûÿÿý€¯±°,B“K2ÿ¯¦S .þÿÿþþü3–J2ÿ®—QÿûúÿûôC“K5Q 0ÿ¯˜Qÿûó“K3R R>‰O9è¼±3ÿüûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,~@€ȤrY\2KÁ`*… „BÁ@8 ’M‘H¦NÅ`‘eœŸƒCQh8ˆ$9™`)FCX^B !"K#$C%&'()FaJ‘*+zVB,&-. ¨*/0–Vª1234°B¾ÂþA;tomcat-connectors-1.2.50-src/xdocs/images/asf-logo.svg0000644000000000000020000005000614655113617021142 0ustar rootbin tomcat-connectors-1.2.50-src/xdocs/images/fonts/0000755000000000000020000000000014655113617020042 5ustar rootbintomcat-connectors-1.2.50-src/xdocs/images/fonts/OpenSans600italic.woff0000644000000000000020000005140414655113617024073 0ustar rootbinwOFFS‡\FFTMl\Ú,OS/2ˆ]`¢·Øcmapèh²ŒèÜ™cvt P^¦öfpgm°©´~a¶gasp\ glyfh2‡HøSýõhead:ð46øÈæhhea;$!$[æhmtx;HX9 kern=h# – locaK|®®U¶DPmaxpM, inameML1,²ÁpostP€yò‚léÕprepQüx¬œ%ɉo1ÉcH–ÉíØdxœc`fÑgŠ``eà`ÅjÌÀÀ(¡™/2¤11000q³³1s°01±<``zïÀ  ÔbCÇ`gE…5lòÿDZ8z™"çƒäX‚X·) LÑ >xœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@,A " m ÿ߀xòŸˆêý3åÿë•ÿ¿ü[ñoƒø¿= du€aÆŠS€¬³ GÎ3ìb˜ÅhȰ Ë’"“xœuUÏSÛFÞ "SÊ0Õ!«nìÂ`—t’¶@)lmÉØuÓb 3+èA"&czâ”C¦ñ­ŒHÿ—'r19åÚCÿ‡Ú[9&×ô½•M 3Õkß÷~î÷Þ.jûð Ðû{íÝÖÎO?>ú¡ù}£¾]ó½jå;µµùíÆ7ëk«_õå÷W>/—?+îÉOÝ» syûÎÌôÔäDv|l43bqVÀCF "_‹¤/£z¹$ü…®W.ù²‚ˆà'S”õºd"PÄOtA¡å“,Uj©®-¹-6Ø¥þò¤èóƒ–Æõž \™õ#³Î0‚뢇©Šª>Ôžvc?Äy25Y•ÕãÉr‰%“S¸œÂ,ÊÓ„/nr³°ýõÄbÙiJ‹;õ£ì´´ï9®”K ˜‘žQ±ª cU7!Å •ÎÎERz?ïÛì(\Îud'úYÃH„¾ñˆÇ¿C~–¤KÏþ^ÀCIz>,SÔæîužæû”F ¶ñ†Û‘WÿÞF¢2V°ß0Z‚U¾«]zœrÇ5)jqGýw½#)l'¹\|ê#ÝlGcˆþ»—çÔž`‡]¾ ¶^ÛmÂG­C V¡&º"ønIwÕqó×6;ÿ§fH ’ƒ ».ÑpÞWìèµt* vä\0µ²€’æÕPóñ>izC͵{(±·Í¶Ž!Sht¤ŒŸGÐ;Âéú…#m˜yë¸2žÍ‹µ•ÀØ ¬ªÑ90ZD’Ðë¦Î ¹Ä¶fÞ¦Ÿ+ó³bMbŠãK?¼O» @ Ñõåtö4(*tÌOGbÃN<ÓLX‘§0'+×Ý¥²ü“¶6.7˜« ¼`Å7çJøqè¥%P,ÙÒ—ìÁ»×ÉCá¼xÀ²À#ãù*NYÑuç Ü ž»'B;.¨;H}ÐØ!CK¯3™•=ÝlËfë@¯ I.Sð?#µ“†Á„l!+´åŒhh# j¸• ü…ñBÿl$Ü 4¸• ¡¹Ã†ÖX, ÿØØ‘|+è(Sµ>Œ6F"Æ©Ö7pÓ§\²P-‰Ñ#K¤Ö‡*¼¦P‘Åù¬Ö D\.ÐÐ -e »Ôަ½=†å†óA¯önI7ÈBš˜‹ê¡@dBmÙ¹I.lùZ¬ n Õ"ÎÊf;¦àraå `4Âj5€´Ä»WØx¤ÍŽ¥è0w×)ˆltbÙÖÆï“ßœg”k–5ys¯R.áÕVI$?k%ŠŸµô¥Í˜8ÛÓ·ªa%Hî¡N_ Æ”A-B $A@‘vQÈ{çR1Ö3ÚŒŒü¸Ï™Á²CŒ³Ç}+Åì4QÑ$RÌBM&Õ¨¡u±lŠõ fž„ejrTeÕ„ÊYÓ–“p‚.yÉ›àìEŽOs'A¯]÷y/™PNjÑC •Vx¶ÿ>õþ~‘cèf~1Q…—….6ÿ­ø¢CƒòkÐÀ›ÇÖàËËMl“ÜÄBÆr0)+0%+„o¾•âc„ãˆòyŽî=ìýpš€Cí⑟üéÄöu*ÀK%¶ÿ)ÿ)÷!) ÿÿxœ…\ @SGúŸ™÷òrr‡€\†¢"F ©  —ˆxá]ŠxÑRÄ›ªÕZµVYk­µ–"âQ«õÀ£J]ku]{¹nµZÛí¶®E2ügÞ mûßu©~™ùæ;~ß1ß @ÀØq刚”À×á¡7b¼ÅcœÞZ|ã41Ö Ik„‘Ѷ½Ž3…„ÂŒ†½P庘7.&±05v8<δµíË(‰:ºx ÿCà3fSɯ+ÞM3 ˆ³µFŲy!ö•-ɨhË«)¢f×OHE_Âgmˆìä³þ ؾ X¥òÓ«Y‰\¼ÕÞj™AËp2 Y/Φ‰‰±Zm6›šÿ?}ÑŒbºƒ‰¾ìF­‘¼lŒ¾ÄЦ5±ò,¨Tâ« ›?Zx ¼M }³ð#´,l\ؾðÀÂvEûí¶Ì6fþv/.„õôµí…{p.}íÅß r²¡+ÙdNC¸4ƒ0ïÑ;”šä³7¦e9GO9'íd8½Ö᪠MsúhÕ¦¶¾ªÖîwšµÁFøÖqJh²‡Z¢‚ AÛFEFÇA›ØÇ µ0AÆ’¿±0 ¨×˜?þ=¼6¼eeú¥ü¬íµ?|l®5íZš½|vÆÒòA¸({r™Âéœ ìÿDwíš÷°«}!X=èò7/ªÿò†*áh‚¯µå<‹¿ñ*N›Ü%z¤÷!bk;îsI¢KÀ ø@ÐØÅ¡ ŠâTQäO@  q¯þZ^øqq¼øÕDì„ûÊ™-‚riÐ!j'Q‘j4fh‚Ú?ýW¤±çDeDŽ|jNsÙó/–¬¨ªA§Ÿ9ÃÆÊ#ÇÇŒ‰Ì¡ÿ2¯ª¦ôàüª"Ó¢¯§Ö>woJõ²¸uëŽM{ eó–ê6jDæ²[3——ß™V]µ _ÚúꆷaßM›‰ž:î‹rE­@t` ˆtŠ|MJÖØKѧ¦ £œ¬Õk”Óê¶{Áö5†5yÑÃqDê”ùPm‡ô0>æÈh;9…Û/ÄÚh» ‰µF‹’Ó¡ûã c7NOÆ×ÒÖ¤àG5çâ]o_ÌùæèÎ#/ß›•|wÞ‘V|¯°ô“çO\ifæÌÊUž˜0âñ²zeJmvö¬?/~åŦÏêW.û(›{ÿ|ß­Îq@ê_ˆåýKÚˆ¨oµ žÅ{•àPÄ— HÇÇ¡“ÙA©…Æ  Ui  ¨UZJÿ t\ÅŠ²Ã¡ŽGàÄõ×|ÿ EäóSðqdužµH„ÏC‚&òyƦAÖ‡_…?“˜|¼Ïu ÿŠz¡àèÿKö?…²Ùj.(Ÿœ¸ù4‹ÍZ±´@³]¤eJžƒåxý¾Ö)·ê¡×€ÅfÑ/x½¡5¿2–á /AYÉ™FXø3•CÀ²{‰jK!‚™N¹‹,nŒ2ƒ4êjü ×ÀÅMp!®mBM°W7á•tŽ­øÌ$ï±X [f›¢µ0]R¹¶qú„Ü~ã”{Zá ”‰Vy{5Aê$CæwÜgS‰={ƒÀà{)Òœ^bVŸædýÜÆË«ˆ5… (•¦õÀƒµEDk¢Tlê|çèé“{ ¡ùýÓxîÄ=3ÒsKÞ˜Äü‚?ÆÁ¿‚Žû0þó὿ÆsN×m¾7_ƒrz¶Ÿ M¼-¨šÅ,”rÐð0p€ÑD¬Ÿ —ÚP僢cÒß/…íç˜)›Ø­åûàPrưq[üA C©–¥9ÕbÔÂéNºP˜ZbxÞû@;ŒEÄÕL!œØ yÉ) êL]û„^ð‹†ÊA“r“VM.[ðeù¡ÏÓ÷^ÀÑì&¸çõ—'›4dôΉcí˜yìÌÛø‘[ÁDftïÞ Üa` ¾¾†ÑN__¯ÐÐà4g¨ØKMDØ)<ž+ÿ‹Çd±>ˆx;GÄI™È0*Òh²ó¿=8dãÎí«Z½w4|³3ëRák øûséî+“r“7åL[pmááÙe;> ûî^\såÙÑ_ Œª«¼qxSåè<Ûà]câßãuÛÑNd” :Fd¬}(ÒˆÒœR¥&Xƒ24P£a”bŽ¡b'‘ÏZPÐiô4ÔíD8#Q„‰CÖp1ñöp×3cÂ/â1‰ÁÃ%¶,À†â3ph 1«dµâßÙ%˜×m‘OsC: í@ìãã—îôáÄò4§ø)á-ysæ…âÓ) ±EK#o4*>ôÅüˉÏ×¾ùî;§Ÿ_2á…œ èb8æJ ˜ÕWšwýR3úzÉžÓ«L‰èìUü²F°ë9„‡YDG~‚–¼ *UÏÑN•Ê c‰ =Òœ†?Ô’6²$vN¥)06Á×ø #â#Ž)DÁt>s^…æ³åÙaɳZñ£x®òâöwW~ÿêé«ð/cžOl´9‡B“à‰V¸lð;íƒ]ø·}çÞ©Çß×ýÔâþ)BŸQ0lörÁ¦*‰®¶™q4s¾"‚Ã(Äû.[8ÀIò!†•ègWa³Ûè’±w[÷¶O"žžJÎ[HüØLÀJ´­ã4¾¾}ûzЋÈ_ì4Úéýäqm¼³ ¢S«äCM”ÊÌ' Z>* ÊÐÒ€å#D,tãà_w¼µ`úâ¾vé6œ›7'lZ>RÙê‰= žM/«,µ6n~ñLBú»Ï.<9ýÂ^ا6ióøƒ7Ú¯E¯ŸV0wéÔ¼ôÖÜü±3-aÏO“׉Av^W¡TW •Ae¤ºx-‰yý‰GÉ`—ÙhMžyBˆÇXûsàßÖÌXXvüþ`nÞ‡oZþã¶[ñÄ̪Äüœòú"¦­໵=¯„=„²—m‡²ºûî)š>ûø†™Ëx›¢xÜÆ–<6P¬d¤cœŒJ¯ãÔûta¥Öœ÷­¨'¦% Ý߉ØL…ìÑSF´مݨc;‰%tŽø¬Þ!eœL5Æ)SñX{|ÜZüŸÈ¡i˜i˜0uFç&|¼ùöDçÜ{ð6Vn²þì}>N“±ž#‹Á(¨—BÖ¿=‡ÙëŽÞ„Â;gð^|•?s9<À2?ó¹w°CÍŠ2,„ Ó©„ð%HÞà œ©ÎѳGõ¼Ê™½t9&îàA<§©éw{sÂÞZ)Ý–¡fW ý¬‡V˜sû.Ä™üÞõ·™3¼]˜Ù¡“,Ĥ2Žqš|TÄ$Tì&¡¡ö íÝhß™LQ¸÷”«™±xÆhó¸1iÒÓ¯\zûlÕÞiùJ|J¯85a(<^ónnZƘI9vsü·_[p¦"eþ8\Ï ³d8å­¤#‰Û'jƒ@"èçЉe1juï(VÖ#.N& 7F1½ÃIÁ#«æ´jú†gQÀ‹‡±’ $öî„¶—)„Ez°EØõ„¤v¬FäÎzIÊí«øüÅâérnrÃâšÚ×EŽKÉŸ4:ùù¸ãÞçxßIè÷øÂ¿nÜûŸ{ëWxª/À^Û\¶ìõ™s3+ú8¢˜ô|cO~Êž×Ö¼á&™*/x6<¿æo‹þùãyüò׫þ™½-÷M8è*IO›Û6á;ógšúÚK/ÿ$ÔUµ¯ÒEGˆU(@‡·¦: VÌh¼XÆ]LñÈNj'h$Õ âHÝ6û_ÅŒjö|ÓÛË>~?ÜŒKEGڒѸóÝÈÕ{qàñ,‰¬‰à¡’øZOŠ \O‚à£*(”JCªSÉ(|É–š?DAí|¨eû@¨åQ 27²/o½óêÌ ü)þ“}~õ–¯Ýújã› ž» jÞ»{Ãé IÀ+3¯?"Ùïî…sö?¾±bIñTjǵ$ÿ7›ô¥ %É›–•‹Srmw¶Ô™ñú#™­†&ý!³}ëÏëߨµöxÓéGø»k°èÛëû ãÖ±¸¿}¹édbë0ØÊ! OÜÉ?2@ˆcD¢`")ÐÒ9Mª“cDÚT§HóD~FŽiì `D/pBQðüÆxñ±yP {µŸ}JÖ6ìÝp‹©ÄÿÆ3ÿ.jÆ_¶G퇃.9õø=•y5ÙË‹ÆmNJvâ B¢T'b Œ¤©š§ã6Ý”ÄhþŤ·?‚QŒ$Ìu; >ìƒ%EÈ_ÔÜŠË/áAîµ—ñç ùš°6‚añ®î@Mþ:—„¶Èz\˜ë»"’c9]ì™K:È':äó‹ÀT’_ˆär"9+ò#’Ñþ.¿0’J×ÔÓ­ >´³n%iŒ׿~ö"~Œ¿n…?ι<5÷ÀÎojÜ=«4ßcü\={›a/è%°ùç>/eÂïµ>n„en¹‰Vór#ž aR‰HÆ1P¤ñð#ß© Y•Qkc³¬q}´šœï‡*]õÚèšE,mÊîõÐ4wþ äï6hƒIÐ~_¤é;¥Ã'ð4TFèä@}˜TSD–$øóG8€ ±ØéñȧpË´QÖð‹Q0ì¾Òÿ;<ÍMTÛ–{ýJ'ÿSøuHÄ‘ 'y¡jfÄ<ëvh„lnkßTNye-$é½k ª+q}FøÝƒ\“@瘅dMáœh:y£G1Š“È ø!ò'åÈcC+ýL"Ümò-ðwÈÕI9/1eEà…öˆ91*dHkDµeœ´ÿ‘ÄØ‡ÍâP!ÌÁWn5[¬œ«’=1ÿËöÍdj¶²-…™vlûãa/ÑM²—šž™ñ’¨¤ ”ÔW,\¿Ïr^ÔÜžH¢­ëÓócÇ35í9ISæí:Äì%{#¾˜ÌãªYά¡ÇgKæhŠ`FƦ%¨ Û’†ÁóØÅbüÒ)‚«™•´—Ñ^1õ…Tž_ Ä´¯@1Ä )¤þ¥‚kwbA4 _ÙÒ•ubÝEkÛHúm"3ÆfŽå¬I¸ªDÝÖzscÃêo‚F¥…S2)GK_ÚØÞL6>°â“›Ë™‘íGß:žs#ŒI§ý—õälAVJð”}O ª)œª:À‡8ÿ¥´=l$µ¢Ìue¸„š\ÿ$xúŒ *#Àû³Š€*3¢.Iéb&-cCI°|~ý³*üÌø¡×Úç¸n >ÌZÂÓubõ|ü%v)fE,‰“ ’@‰;®óÖ 4hË„¯4DOYF&Óµ/ŒYfjßjö²qWö?>CÖ»3*Þ®‡H±ÊA >k ¶“`7âLX Xnâ«7ñq®­¡m*9ÇM✵O÷¦ IáþW¯wv¦`Ç<|mu¯Olˆ;×Û ÉNö(½Þ´À¸gm½ÚðÇËÉŒüXè©3M"X¬BÞ­%,‘]̨¨ ªŽÇéÈy£=5ºx%’ý6v$¾$ïAÚ¤'±Qyû• f >¾@È^g6sF¢Y#·””>=hÒÔZ¢l>fóKñËC~µŽc¯Ç½7L¿uC…ªØ)$øõ‡ÎK Är¥¸G’S¬Rê6É Üµ#ÿCÍÛ‡¨«Š5Øì6ÆD,Õ"À£IKX·v÷ê_6L\c‘Å6ÝoÖs;¦gî˜R˜:nsîÝ¥#Á¢Ö¼ñ;h8{bd·æÌØŠÿ»nÊdÊ•ð“ÁéÈ®&ÊK|N 8½ÊDRkÔÍÏS?Õ)É¢¨¸;"Œ'r£„âµ½eŽF˜ro„w„R’»9{}ýêŸåcê'Œ÷r¶.7{;§ÃãÞ·Î¥ù#üÚæØNüxMьנ¸î"Õ‘ÓJdÅW×b9•ÐxpÔ)™ÎîŒ{w’gö³Ûeoí®IZ4i󅹓R–ůÑ}ÚrŽ=9ôHnýv΂~=ÏŒ]:¹Id@âèïðe¼Ä\@ÙI%•%;¥z…>É©ðC·j`„€…–Ú Iè—Ei=•ƒætJ¼}Sïâæ#ZqÎîüºúºŸä™»&ŽwŽ{9‡Ò¸aœòÛý†ÒÜKÇZaÉÙöÄÝPR›7{+þeõ¥.þ˜6")ÑÉpßd®dj5HvªU²ÀN™Ïï2\Rï q„éÑk4‰;e¤€hKÑ[æÀãŸ:¾h¹¹ Jwï:ˆâËahÞÜäu‹v1û×Î(¶Å´?óåùspܱõ5Í­Ás–„ö¿Ÿ™ïscs€ &‘¾ÃG©Kr*ÄßË××?Ùé«""?ÿN¾)yy1B„³kMq¨;º)¡Ml"Ö”š;ر<ìúAýi}¿C{ÊŠ†¦Ä룹m¾ýUïf¬3œÐµ2¸45ÿÜ›a ÙÅÙo}ÐHRËŽZ¬c+ˆŒ, ădGoÿÞ½Äb†¤8ÙžRFlî-î-Ö›-(ÙiQš£F:Í*}ÿ‘N½¿‡Vù8ìkµÒk™0wóS ….…³`È—F*RázÆ}Gc€Ý%‹¶³×Dëw¶"øÃ€"{ωRÕ°‚¿¿ôÕê­©%µ¿^ÌÈÀ©sÌyö/GrçÕÄGHˆŸÅf®4>3úÔ-IoGh€DåS½èì盫§nŽ Ï>Ù:æí³?é¨)MO›9ÙöŒœiI«="-}Řuô.àz ±å À¡PÉt:¢Ê ™žfœ;·1j£iç’òx*·‹tbfÙÜ3áÅ÷‰ïÆø÷×J²Þ*X±Þ°íÌ5×¶]ÇáÄoÛ–¼9ª´pÛK©Å®2ÞFɾ([ÔFbœ˜=¤ÁŒ•A˜9Ló:ó.óó#‰ã ¥7á"ÎZ0¥ggÌD\(%}DTBF|T’õþý{¢âĬ¨è™‘mŸ³™á6¬ã×—“J{€£§C© VYU£UTuª×UWT_©¤ F%yÂî¬ (&w_üxî;Ø[Tµ²wñÃЃ°OêˆèxÂA"oiÇØ3‡ö‰ÓNlÂ] ‘o-‘¯ø9¼‘·ˆc%R”¬D¯š¿Ð3’,”Hˆ¸!SU8špÛÕiT¨µM,›‰ý]áEx%§s­m}^X•µi,DêùXh¤±Óï{ò1ò/< w€Øy(í€1½€ÁÛ¨×P°â€*DI>!Än›­  ºTkêÖºÇ;ÉwË?B$£NN­Yí³æ^váÌ÷Ã&ß«S—Ï~ŸØÁý#zéËì”{ÏU¼ºÚQî*C;'„.{ÔŠƒÑÎÌðZ| ‡±™­ß€.ù¤þ|©ý)¼4¢J®^d$~ ÕÏ~±‚ßiþŒ-k†ÏuÛ]aÇÖΖtÖU~L’ÓO¥‘‘M»£¤XÜå’ö®b ŠLJq^ÁÆ1“&æ¾”ñÆŽ=~[Ñ[gþNÌXX÷ëê9óWüºò#|è½Û-çaêÑ;|¯ë"Áš rF-‰áeÀÛ› Ÿ7±>±?ð÷ˆá]¹½(Ä"T©TØ/åÈÄš¢»0“ûµ÷ëê×ü[>fçd!X6LÌÁ¹ØãýøðeüÚ9æØë¸­;Ròr <ѼBBh—3JÀRniSúlþ}§¶a'¡KK„ògÑkÞá<Åñþ»£äqbIÖÎÜÕ;7üè±cbÞ˜ì—$|íøí4,ôH=3·µù¯pÊ©öÄz(YY8c~´îR—M0+ o*Z3ˆ¼e@%Ó{QSSÇDðlðA Ë˜ÀØþ¶èKÎYJ#ØÃN‘ßP|{ˉúL§k*HLœGÖ áëªF§óA€Ž‘Øèót]Å=QWA²Ýe•!1ŠûŸœxñÕ×'.>£rêçÍg7§®Y22/aÊôœþ0ë÷‡]ÊÍn9tØê Û²R‡'ÙgM"|ä>Ì¢dàGg”j‡—N¡VëH`Vr€ø¤g¤ó¤„‰ Á×Ô“ÖH$ÚÄ´¿EçÇš ÁT ëõ'–mˆ„ ¾·È;b_p£ºÇcRÐ3³3ïz¡b‚ßUß±+ÄYhosí# î{}UJs”ýøYc!Á°B²½«õ&¦*«T~¹Åz¡(Swuv,v‚×´&ã…Û¬7½‘”Kƒ>˜ü§Î°þóW*Kº»Ä5˜ì½hüކ"4õ;êûˆë³¢—ŒèEBj8ZnY¨OùK¥ïÊNÊL¦ µè´´‰oåï…£"æ)†Ûi‹C1õ`èznJÈ×þzxŸU‡+®ZÔù ÈݼxHŸ¢ñš$ß%ÏíT…yŧáã÷‡&_Œ7®}Üd¨]^;äHb&¾4³RÍ…ï {z@›õ(!ðgmvs*~&…ÞXi™hS›àϜꑒÊd/©Ù®þC)ÿ=d²w¥'¥H* ÕjÌ¡¿ãßͤÍÍvŒ¢B^Q¡î£…šè,N,ÏÿÂu>q!›K xîw¨ÃdÙé&Qó½¡É—âëŽe•àßX~ Ï€Q³©¹oÚZú=ÓûõS4˜ c¦»v(”£ÑÈ3d’˜m¥×xa@å{–ï†f¢øBào (bÁÛ¢!%›³ò“rFT>3ucÜ¢´Ôñ¨)vðÉ™¾– ¿ØgNÌ1{øøt ¯F2¶Ÿ»38dx cwîKC~ìŽ`‘F÷ÑÍ{ðd/ÌœXœ?Õ´s¢ìŒ’¸!™%t†œ!X3Pt‰äúÄÞPPoš3úIårõh§\ƸV!íhòf‘ÉNqVÓ5dÖ€é¡Ä(a{ø‹kªno4m7??qxåÄIõN¾H«Ù©û,äâŽ0á¼ÏîÝòð£Quëæ,ëyz¸ˆ÷1:çq„ð:ü¼ tÔBâë«@”æb­R£Lwj|»ÂÕ¶;™@_Loè% ùe' šì6¢w&çøîœº²£}c`Zn0ê'ŒEáí‘¡"Lg{µ ý—èRöá”Vüýþ-ÅËû^9þÝîý0ìèi!þ®… ÖÝB0ÍB¼ß[*Wi =H¬7‹Õv6ÂÀØ-v >vƒ˜¦;±…Æ&±Åjï,HTº:tYEÕ”é3'U-\6thUEÕ„¹ ÆW•W Ý[™Ÿ÷ yù•èÚì „fhܲòe“f>;¡²¢jðàÊŠÊ só–<_P°d)ÕY)‘Uñ0Ôa”)”Š §XÉi´š '´z¥6X‹”Z¥VõœÜ=÷cµü"– 7)+>L‘?&»‘ÿCàe†G®¶ë&ü€ ¢ÿuÓ†4BuþÉtíüÚqrI¶½¼í—_ÈôˆÊÉÃÅ@{˜aV È[+IÈÖ‚O«Ý~M=»ý_xxû?[:~f~áL D²_= ×Ùzôá‚%ÅH§÷é öýnw…ûþ°3ÞÓ‰±»¬óH „Nk¨¿aýêhãÖÄØÚ´ì‰#çVULŸ9åá•ãU[Þ|î¹ô)/̇ùÃÇTÅŽš„ÚWô,‰_õFúŽÀ°áC†E ª+Êß14µüµ†aïŒ6rÀ:ߣ4vèø˜^³† qR9ì!Ö ºÏÏÈ*½”X ?ÂêQž˜=o©÷%Å ˆñŒ5Vu¾• IµˆO±ÚÜ¿…»ÒêŽû\1ñ=0ƒ(`uø‹¼”^Á^¯{1@ Ô*5òR{©C"z°}C´Ýƒ®j[0kÉéU]àÓ™+A>]f5$%dé-´]§amüí"âo¨™úy•¬/ô+_Üòé­ó«–&–¶×^€…‡—Zðî¯àú3‹÷À^o¿Íõ»ñÍwöâ{YÙ–møZOíÛ?ýÛo íø*ýÌ9üúÅóx÷å+0÷Ü^üÕþиç hzç-|ƒ·ƒ b‹Î $ˆªK-«äHØ ? â"âTŸDÄÄœíÌq=òžX¨uíc€?Ï‹â,ó7.–±ECó¦¾"Ž˜0xJæ<Ñù©¹®¬é±öŸ]zóY×±¢×GWœ©©ì0”°æàHÕ!?(I ïá´§h€Z1c~eÀÕµøëW¯Ã#pÙJ|gcÓUwÏÇM¸.¶ Ø8ïÂõ©ð@çÜ!FïÇš‰æ™NTô Ä%ŒQlàA—æú VÐŠŽŽÎ¹AIè%<Û¥w%‘A?¢y›#ÐÜGÙ'¸Šê úªú"KxŸ¾}û„3ò–ÕÉݺ7Ý[mÚ×þ=›émˆ‰1Q–zv]UÿOU3æ»va^#ô†cpVrVnÞØdtã¨[:öù^$ÅŽßgfã©Éq#Q\›ÃéX3wìéÞ,ÓÞ^faê8Ý¢£ãÌ`&È‚ö äUR¦SGÝ>Õz‚îñÓ+V|øáŠœ­9[¦¥$O›:2e»lÅéÓ+V~³9'iÚ´¤”iS…@gDÏð½Ž^¤ÖòÎtÊÜâ*ç"ÊTÁ<›;=57J‡b&¥0*ÑE’ÛkËTÁÈ×öÔS…žºÝìkñ˜aT’änŸkwôž3Ê4h@^IFâ¦Â²•ÖÉóÀ2”RûÕ„ÌäÐþ‘‹£í & Ÿ3;ö‹¦¡~Úýõaôz¥O°âøøÈŒÁJ™±óÒšœHóÄÔb7|†Aaf‘òCÅ˨fMKO9¿oÕÜ%‹r'm˜PàœQž_”¸äçW±rç÷`5Š˶z}DÊðy5‰ñ%ñ sçðy^;{¹íî©3K%îžz´ÝHj&± ¶O\ %ѱýyæmÂÉHšÐz|#É…{мO#—‰ J™^ÉtW½qî´ºo¤º¡³,g88%!nÞ©ð)ßÝ;â#µ}üL«D”@êñ{kµÐŸüøSxýñs&YOs±®â,"¿ý¸mâtÄ´‡%È(€vúÐË5ýé*Úfd›V_;öo—ÿ~ Çíܔ߶26MÛcÈbâÏ›Q <ԪĦ˅»ÿŽD¬÷É; %ðV9¼É*•RÂø+IÌä/+©Óvé‚F2»Mïï^父\™4¼xCD²?*]¤¬Uõ“î-òËêòS(5ó3·ŠCR¦'G’;TJ6Ú "µ—Ø‚tõÇNNR÷ÖÇT¦‰šÛ_†­£Wéúg,£~°›à°„à°7‰a:‡L X‹X…A`ÛÙËt] + óóJQ‘Œ$kÇìE«rþ2ãùðÃ1Sç¦Mf›—œ›»¡zÑù9u²w—­}÷ÅUÖÊ@>s…¹Ác­¢‰”7rudkMK,±kEÂ/æ .[ƒ_mºŽ“qÕè·áà5ˆqaLϦâ„3æÁ|X”Š3(vn"c‹¨Ye×ÐFT¡`ñç@-Ÿ¢S®Ã@zAj’EEQZZ¯¹i+Ú£”ö9FAhÅHEILžIh­¢‹”–1Z ø”`öa5ÊY@ÖEÖ%yúM\Ž0›Ëϳ…;|ÅÀO凼??•‰ŸjSñSm!Oôö'PÕ(:¯; î8m§µ·GJ¶ûÍznFš9kLêÆÑ£Z/8¹ôÍ‚"h)Ê4¬`tBªÞ°oìèôŒ#ÆÛCß›ûööçÊå`á¸IñCÒ§$’ós]â2M(è虇u¸`&5!•J ÂÔQnšý4óÁyÆ`x‚¦Æƒ¦ä 4zý4—ÄÉ]4çA™@ãëûM™8¶‹¦äù!õê%En¾Ån:œóŸÅkµ#Hß=³&6ó3eZ0ÄÑSæê”É §eRZ-äD©F˜¯‚ Ïi' êêÎ1÷Ü“ÖÈßsºgŸhÏ@ôSû³qFÀmL=ÓÎA= òbäïJ[•‰çò“nt ꎂÛPµ«’ÚO-ÖÑy2Âw( Wq‹PoWü,/¿Þn=ü›— ôöî”ÍïhæƒJF§ûSš'Ðh4OÑÄvÑ”‚(^Æ2æç’æókõxÂ_ k‰Džk1+5@WÃñí\÷šsUuOÒá‘p.៟/âm{ `Ûgô÷ï:#?#ÄË!B'˜#Ø`àŸÒÌ'¹&OÓiþ@Ó. 4!!OÑ$wќ׳ù)šØ.šRÐâöµ»eÁF̶–äC>8)‹dzÓN;.¾™f—BƒŠ)d_ÄUÂA0¦ ·@ûb|_X„®A{%¾£èž_ £pëb’ÝÍêØ'jâXRÇ‘ªº¿£G 1 „íå£ÖI9–U*‰B•,ÛËc†Š/ûÜOUñ©ð¥µð  _s ÓEª´@¾õ. Vªœ_³l*/ú`iEMM¡ëÆÚ¯_ðEÛ3Nj]3FU¬þêy÷ÕØMÓv®ºÅnš¶ç…uÇðÞ+9©Lb<Þœco??è$‘?'Ãë`[—邾»1ñw4ó¡¿@ô§4- Y  xŠ&¶‹¦4¸}#,ÌÓ_ù™~­!n|˜"¬¥V dî9©aöÎwKõ©No6Õ)õ–zsîA¾Z ãŸ)Älbmºj¶ÄÍL ¶‰·î¹ž)jh©X¸øü|EÔüŸ0|íåYÅüÌ"&¹[3çb@?‡ï@™ ”Ë#G8å 0$ÙèóÄ-²Gaï¾Ñ‹¶ÃΛ#þÑÅ ô»ª^ŒB®LÂfùðä¡‘ñc} 7 íëãWΚ2#9ôιæÉK–LŸoÍÉLwæ)÷I$~Ô÷(ÖNéÇOc?ùîòÎÚ·^oê“•=iÈþ ñ³s2¤$9ʆZ:$!?2>ùÇǺ–TÎüŒg$rNäcϰ£@ð>µ å?¢™ŸËÓôéóÿд¸x‹åiÑÃ.šóž¦oßßÑÜï¢)í¼GG DQ]{mí¢9w¸£ª›†ø#¡áêØ)ü“›ñ ÎalLvÌ!•ªôÊAU“œ=T*Voî+íK4'%é·» êüM½“Ÿ3çôœšp·ˆÝ ¥³ î©ió“Ã.]£ lý—c ¯è$ãv.eÕks–ö“ƽìgÛY²feg–U6½Û¾|ܶ¢´Qã6Ma^Ÿú¶9øýOu+ËJs?>t_Ÿ·£<.åÕÊæÖ!å ²>}bT¼˜7{'n[=½˜‘ì_;£è™H^ŽXGçQˆŒ’„Ø —uÊ—iãõ”,èû éS:ðñ ™?§é×ï)©MË—¨K¦×¥@SúwAO11ݺ¤÷Ⱦü:§Ýqù„¸¬îÄ z'èA3¿c@#—?A#õ iÁ_ 42™' zÌó#ДbÚ¬â²Ú#.g³-æÌ „hG€HüY. €ñSèõæN½^AÓ¬ ]s6]ƒ˜ú,褴ñáQ\Í7'º­&”À¼ÐÕéì3£Ú~y¥Ë2Ú’®oۀ۵ܨ~°±è¥>œlq[rFþêôiùy«SŠEá}ì[’SVU-lÅ­¸æäçgê¡f{ZÒÖ¬[öøAÅùÒ‰ÏÍ=S6mŽ»ßB°±’÷µ1‚¯™yi<å×X;/³LÁ^Bÿhæ'!‚ÿ?4-ÿù# yÀæòü4çÑÙY‡×@Sú#pGðn¿.÷Ù@VxNß8äbo?­·–¬‡>‹JüÖæKƒ¹û‘®¤Úã}9³×u .66~ø3Ï ëü*šš0vŒHŽsŒÚÝo„>¥­c›Ën$‘&d»$¾ôò7³AÝñ}„S©b‰M°>ßùk|!¾GzÄw!¼3¼5ÏF½ìª_Y<}qYÒZˆÞZ15»²$ç¬=.ÇÂ/:_ÇáÔ>èø_qÃÁÕEk§½v¦:³¨¼$ß¼a1!³Éjî­ ÷q}k$òäï\y½äúÝ„,ÎCæOÓÌ/û½=ê,ïèS.í3Sâ¿LœGGÔu]3é¡ÐÓú³Š`a8]ðSÏðs V’ v)‘Üæ›ì´ÙDò&¹)É©–«úŠh8u‡Sþ—ZÓù“[c݃-†§Â(?ñ;/á¨òÌÝqôâ‚£VþpìïAÇžŠG~Tùú»øþØÊÌ›7¼zNÞ^WÁøµã'æÕ½3 ­œ~ $øƒO†èòó›¿kù¦½ûaÞÔMË_2g‰iàa½˜æ¥¿®n4ß›S®z{ÝÌÉhϳ×Ù0ÎÈwq¯¥m’õàï;L„m±‰Þ¾Ú| lØ–ÔqÕÓw¯Zâÿ(t{=®lv¢ßÒÚÞ“.„Ù/˜_¸­ü‰ŸC¡TJƒ¥V)3W ¥zÚÞ½\ 4º[ âH÷9(óË‹¥¥U/L¶¼zˆ5|p”Í:DtlÚâES§.^8="&&b Ý.Ü5'±_°9¢‡ÔŽÄAD^dG¯*]é–JµÇåÏo¦èèìŠIc‹BTÎ6Äd…JŒë¡Ys¾ú°!½# +Øë!}Bìƒ` ©)j¾å~ö¿…Ù‰jù^6ýO›ûÁÿ0&) ¶œ>í¦Wü8°‹¦‚9…òóÑÒFÀ ßÙ µDkè×FTr!ëÇ7,JcNù¤BÙJüíBÿ¯Œ|ÆÊÏKEôë>&ç1pôqRY$æ™aKEÍ>cñª&@G6øóï7àÜßo0sÿýwÒ¯7@”/æ"ÿ³x71ãÕõ]-–h-aÎèf¤Y‡ “®ÅÝÜž€F¬ÓˆòÌœæÞÉzÞ"åÛöq„çFÇÇ‹à#°FPݧâÔØ;‡ª¥ùï6,í>¤ácü#ô»IŸ€­h7+!Ö"yOJ Òúäã¿[Þ\SR¾{ý”yhÿög=»ýÃ2ò™ P‚Šù»$É{´s|¶ë©ëú …{æãF¼>žâõ&ù(ï‰JÞƒ"þ3î^( ÄÏÕBãփ׹0ÎNÅZg‘Ô€AøèqK ;Ôó; ’P ÊŽÓïbf‡Î[ ERÇЉK¤R1â ¦'_Z 6·˜ø‹aþ;â §„è»E–ÃüRx³eáb|%2¤gÂû¨­¡a%ŠqµÞ\f˸!ؠĸë¢K¤¾ë°rN&Þëg8%¾ÊÀà@$¾s}‘èè«5AšÓ(Ö*ÒZÏ'ÀéØî„‚ÂáκóæšÖ ½ù]`¢(“Ým'?4€ú¯?dÖÏ?«x¶F³ŒøÔÂÚ«–½÷·ÖW+å+{¾œGü5çÕŒ)Ñ¥"t`ïÖaÉÛvmri(dÛ·M跲пŸ½)¤9ÒÿÃt xœc`d```”œU±3žßæ+ƒ<œ|{#Fÿcú'¾…½˜™ƒ $ € ›xœc`d`àèý»H2ücúǾ…!…A”\ˆ›Pxœm’?hSQÅÏ»÷Ë5tplRBÉPB†Á¡‹<Þ$’ÉA$H Ä$HèP2d¥db¥ˆ” %Hè$%H ˆC‘RŠd¥CAD‚ƒHÈõÜÿ„Ò?Î}߻߻ïóE1»$(GKú>N"ËHK+¦…F¤†ÛÞ)NTwUÕ>’UòÙ3uÍn« ¤T‚=1ÛfíKÁ~£Æ©j†”È:¹ãö¸ý*aw¸.»÷8Õ›Ø5Ÿ—ž­Ë2@=’£fˆB©ð¾†@=$ùi_ºôOf?rL>¢.Mîsú†=KHÈ"öÙ×’zf‚RµÏÅGO|;T{¦cQŸJ7uÒúRR‹²‹œì#¥{Ô.I#§ú6.Ëü®þkÚ1ý%·fë+בružÍ>;p=Úgÿ6®ªïôã%}†¼¬IÔvôW{O·xþ¢RðÆêÈî9fÞÛc®ßýñ¯A»=ú”ÿRò:f55Ä+‰#úOï]M×yFoÃÚ93:Gû'òÞ"+xM¿›^Ûú¬òÜ6ûÌ:^5³…'zÓŽBß/Á ©Ì"ÌaŽ0‡9˜UæoáwmQ‹.‹yÂ,˜™Œ§ÓÐ÷K0}úÙ›å0Ï,‡ÿð=Ù9\ÄÍX“óÌ,æqY¸Ìœ†YÔ9'9z·*/9 %/ПYï"åm BÊnæõ THYw8ÿ?ÐREdÉ‚g¦ŠŠ˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€,JžrÜð0Z|”¨ÄÚ6tÈFž¾p¢Ðê(vö&rªà4|¤¸Ü  V † Æ ú F ‚ Ê ê  B „ ® Î ö  & B ^ p Š Ò T ¤ ð6ºö&j˜ªú2l¶.r°ê Nx®Ø&8„¼¼æ*vÀ (޼,l–°¸,>lžÒ4r˜¢Ðð"Ndzâô*>Pš¦¸ÊÜð&:†˜ª¼Îàô ~¢´ÈÚ|Ž ²ÄÖèht†˜ª¼ÎàòhzŒž°ÂÔ  j | Ž   ² Ä!!&!8!’""("\"’"¤"¶"Ð"ì##*#T#x#’#¬#Æ#Ü$$|ÖE</\SxœT=G}³ˆ²–êÀeÝÎ~‰uk„tÉgX—ôÎ4³ »3£ž^–À‘ÿ '$Ä$Hü,ÿ'–g–å75½º[öl#ïª{^×T¿ª®z=nD9"4¿ÛðG¸‚w·°…?n#޾ ¸ƒÏ¢7w±ýð®¶â€Ïà›ÖoŸÅ§mðy\o¿xqçfÀˆß|_vÇ_¹î_Æ'ÝWÌ$êœãÊIV5Žð9VöY ¸Cüp£èEÀ]\‹~ x‹çú+à3ø©õuÀgñEû«€ÏãVûû€·qØþ9à 8ìL¾ˆo;ト+Ý2à˸Ñý÷`‘qxŽç0H¡84ך(AKž¨öšÒªð’c„†½€†Ø¡õ>½ úÍÈ£°G츻žµðÈ÷lf½}nR•j¯UR”Kg³©W/Õh0ô8 wÔý¢ÈfFí®,œö¶È¹õù YÈ™£d0'û„ü3æŽG¥ÉÕÎ+u`ævRÌh{ šÑ-áÂë™ås—ûáK9;rõ8>&†Z#T¸‹Qó¦®Ë€äUbòÔ8ÕS› ©&uwa¹w´õ°§T­ŽöXT…¢×IÅ’W±–jO]…ìm„ÜXÇë­â­Â–¼•¹V‘¤Â¬‰ŸÑVàɆb´tB‰×’ωXçLؼªÑ¨•h‰Xê ›õSöÁ‰o*¯TWÕº;.—­”VÞéÔ̵{¦Š'+µéMB§ËþX' ¹QžÎwÐçÿHþ1·­“&24§'¦Þ—wúý£££Xæ„ÄqRÌûÿŸÖ³ì¥؈v2ú6:Š…sÎFýkh¿,Mj*›å”Y<õsúïK'Œt¡éÝâD¹<‰ë.ï2°¦_³ZßS[>ôˆ)QÀû–TìÑBŠë§Fí–:á#¼ÙQ+ÅâÁ?Wæ8x,UÉøv¶–DEË>¯ÃÆxH™åã'Iœ¬ˆ —õgMUÿÁÞøáÁ¸' lÞ”c]â¿.ü‡×üoª…oˆxœmÐWo€áçt¨R{ï½Wí=Jkï½WrŒžúêÔ^± !®ˆuCì1.{žàÚŽQn9?À›<à•À߸9þ׫¸‰’$+"EQ©Š).M %•RZe•S^URYUUS] 5ÕR[uÕS_ 5ÒXM5Ó\ -µ’®µ6Új§½:ꤳ.ºê¦»zê%Co}dÊÒW?ý 0Ð ƒ 1Ô0Ã0Ò(£1Ö8ãM0Ñ$“M1Õ4ÓÍpÜaëmpÍl´Ã6ûu$”`k(Ñ:»ýôËv{mvÓ{?ìwÌo…þ8ä„{î8i¦l;Íò@Ø]÷=ñÐ#}Œß{î©gN™í»]ño/¼4Çg_m1WÄ< ̗뀨…òòÅ,R`±O–Xf©åVZᲃV[eµ¾øæŠ×N;ãwÞ:뜋.¹å¼ nÛ亮†’BÉ)±ÜHzzFfj´ ägGƒpZN4äÇòÂA$$eÅ‚è?zÞmGxœ5‡;NÃ@Eç1Ž£Tcaþ<ó ;†>Q ãØ„ŸyRœH©è)œ¤4Al‚Úã.{HÁ(XKGºGçößZq@ø„q=„ßóKŸ_E.^ŽEûxrfQ÷Xã^GcÓÐhr©‹iä`G¶©œ É 9Þã%çëä#ùJøzqÔÆózÃŽâCr¥C¶Ü¡mdIAïP€ŸB nn#ŒØ#+Ù73,O64`¯Õ]†éª©oSÕºž*X¨n¶qÿf¢Ì…b4™Ž+€—üy¹d/U§ÙX^žªû:,¯²Ù /Š0œóy¸¡vQýÏïÝý/ßG±tomcat-connectors-1.2.50-src/xdocs/images/fonts/OpenSans400italic.woff0000644000000000000020000005114414655113617024072 0ustar rootbinwOFFRd†pFFTMl\ÚLOS/2ˆ]`¡L¶Žcmapèh²ŒèÜ™cvt PW Àfpgm¨©´~a¶gaspT#glyfd2BI¿ËUhead:¨36ø«Îhhea:Ü!$?þhmtx;XdÝB2kern=# – locaK0®®[°JJmaxpLà ]únameMíEjú postOðyò‚léÕprepQlø T–“ɉo1ÉcHÀÉíØZxœc`fágœÀÀÊÀÁ:‹Õ˜QB3_dHcb```âfccfeabbyÀÀôÞA!(¨Ä †ŽÁÎ Œ kØäÿ‰0´pô2E(00Îɱx°nR@.OT 'xœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@, " þ¿ñä? ÒõgÊÿ×ÿZÿÅý[ñÿ5ƒØ¿= dÕÍÐÈp—aC?CÃL††FF~Ü,æxœuUÏSÛFÞ "SÊ0Õ!«nìÂ`—t’¶@)lmÉØuÓb 3+èA"&czâ”C¦ñ­ŒHÿ—'r19åÚCÿ‡Ú[9&×ô½•M 3Õkß÷~î÷Þ.jûð Ðû{íÝÖÎO?>ú¡ù}£¾]ó½jå;µµùíÆ7ëk«_õå÷W>/—?+îÉOÝ» syûÎÌôÔäDv|l43bqVÀCF "_‹¤/£z¹$ü…®W.ù²‚ˆà'S”õºd"PÄOtA¡å“,Uj©®-¹-6Ø¥þò¤èóƒ–Æõž \™õ#³Î0‚뢇©Šª>Ôžvc?Äy25Y•ÕãÉr‰%“S¸œÂ,ÊÓ„/nr³°ýõÄbÙiJ‹;õ£ì´´ï9®”K ˜‘žQ±ª cU7!Å •ÎÎERz?ïÛì(\Îud'úYÃH„¾ñˆÇ¿C~–¤KÏþ^ÀCIz>,SÔæîužæû”F ¶ñ†Û‘WÿÞF¢2V°ß0Z‚U¾«]zœrÇ5)jqGýw½#)l'¹\|ê#ÝlGcˆþ»—çÔž`‡]¾ ¶^ÛmÂG­C V¡&º"ønIwÕqó×6;ÿ§fH ’ƒ ».ÑpÞWìèµt* vä\0µ²€’æÕPóñ>izC͵{(±·Í¶Ž!Sht¤ŒŸGÐ;Âéú…#m˜yë¸2žÍ‹µ•ÀØ ¬ªÑ90ZD’Ðë¦Î ¹Ä¶fÞ¦Ÿ+ó³bMbŠãK?¼O» @ Ñõåtö4(*tÌOGbÃN<ÓLX‘§0'+×Ý¥²ü“¶6.7˜« ¼`Å7çJøqè¥%P,ÙÒ—ìÁ»×ÉCá¼xÀ²À#ãù*NYÑuç Ü ž»'B;.¨;H}ÐØ!CK¯3™•=ÝlËfë@¯ I.Sð?#µ“†Á„l!+´åŒhh# j¸• ü…ñBÿl$Ü 4¸• ¡¹Ã†ÖX, ÿØØ‘|+è(Sµ>Œ6F"Æ©Ö7pÓ§\²P-‰Ñ#K¤Ö‡*¼¦P‘Åù¬Ö D\.ÐÐ -e »Ôަ½=†å†óA¯önI7ÈBš˜‹ê¡@dBmÙ¹I.lùZ¬ n Õ"ÎÊf;¦àraå `4Âj5€´Ä»WØx¤ÍŽ¥è0w×)ˆltbÙÖÆï“ßœg”k–5ys¯R.áÕVI$?k%ŠŸµô¥Í˜8ÛÓ·ªa%Hî¡N_ Æ”A-B $A@‘vQÈ{çR1Ö3ÚŒŒü¸Ï™Á²CŒ³Ç}+Åì4QÑ$RÌBM&Õ¨¡u±lŠõ fž„ejrTeÕ„ÊYÓ–“p‚.yÉ›àìEŽOs'A¯]÷y/™PNjÑC •Vx¶ÿ>õþ~‘cèf~1Q…—….6ÿ­ø¢CƒòkÐÀ›ÇÖàËËMl“ÜÄBÆr0)+0%+„o¾•âc„ãˆòyŽî=ìýpš€Cí⑟üéÄöu*ÀK%¶ÿ)ÿ)÷!) ÿÿxœ•¼ @”ÕÚ8~λÍÂ0ûÂÃÈ&*Â0Œ¸Àˆì ":ˆˆ,Џ"nˆHd†ˆŠ[fjfFDä‚df–{jV^33óš×¼]o~éµå–2‡ß9ï;,Z}ßÿŸá <óœgßÎó @h÷m*”í P7› EÉZ.g—ëAl(p‹UG‡…•@“Z#£Ìz–3ùR¡èÇ9á5è³qñƒ‡eÄ…[ÙÎÇ7 ™zðhkú$kT|Þ0(p‹ÞKÇaÜ4׎Ñ4ˆ5_Œ i“ƈ¿à—f%SîÛf%³Ž”’|@Þ ;¿×ø³Í ø*•î:•JÈe2èåê*5hhNªÆøb͘F³Ù¬Âÿ÷|CN0ŠŒÎSŒV#ÿe¦ù/ÄÿddÐÛ]¨n¨E—jê£Ç®Ð«ýà /m¨†á5õÕP,ë: ÃòÑ%ºµÕ¢,ØN¾já„ØÒÉW jƒ0½4Hî^Í„qJàÀ 0Üæë+£Cüy¹pœ†“¥Ù=5iv½ÿK£cu ,L¦2‡ªþRCt„Š®åÐd ²ø@³f´DFÅB³HoÑ>ÆàŸàïäP§Õèö[§ÃëÃO.Êz?¥ ¡ú«ƒêƒv.‹]\“·©UÍZ7^<»2!ÞÛ}^ë¦|ø¶ÁðTø¦;?Rí; ³­Š• dë´ÛuYnÔ?*ÕeaÅîEZºï±]ìÌ™ó †ƒ›šñò¢ÂÃ)š£Ü|‡‰¤:w^þ±ÄJxáó¦iB9"Jm‰4h)9Äc‰TóÎ_ÅPø{ôñÉ­LŒqÌÌØÒÑ% ±ÅÙs—·-X¸¨ËWj›9!6p­xÍÄ9ÂOÙÎG©Øl2j[øöJè2cï–Yí/Ü´~/ ßÚDå.ÿ½ªmܦsI{·ÎFŽ}›ùŸ¯ÃÅaÞ|Ù‹Àè µyèÁ*ƒEðÐÁŒo˜Ú¤Ú}³,ÕnÖ^À{‚!ÚM¼ús:­p#¢¬PNaUDFY1'‚‹È)Œ²š9‘ÆijHÝš¹0«¡$æYôúÄÝ Ð§+æ¨G_u\™ñÅ;›Þ=wýx¨¯In)î¼p®bÑ7«[γñ‹æ.*OÊÈ>ÖþØ7îSP‘RZ{sãõ鯯ÛsnG}FeAÖ@´tî{÷ö¡‡{‹²?ø¼Ãû›äE|í¢ài¼— †m‚,t”úùéAš–ØØð¡¥š¥P¥Ô˜¨¬PüʯÔ5C%|†²A zèhA'ÐÛÈ¥Gw>: Æ8¤‡˜fPIAP)i³þüz¼>(«Û@磷¢‡TU Ÿ…ý„i¸J•2µœ'—ƒ'؈héQ€FDà `e5töR¸WŒª:ö–!´ZPƒ–‡°¿¡Zõ+a¨6nF-‹¡×œmïÁug 3fæKÞ!£@‰­ÑbT™UFQe¢´Ö7ÂçÑ’Fªa-\…¯EÕª*šW~´Œþ]CnA÷C(‡w_÷=šöUÛáï`Û}8†œ a¦±ž×¿²“A ݉ÑáC&ÚŠƒXNém§FxGØdÂã›èõ-° Ÿ[½x˜fÀXqŒñ^69å¡rI³«DÐ#ÝNpñ´ãÐ>4Za ½Íäω‚œEPg¤›ºª}á¥é›¦…-š1¶Ùžõáß÷]÷î´‹ÚÛ ÷Li¬^šV¸0:¾|Ûþ—çù|?º(&ç†a™…ãsƒÁ`›vswwK³»»»ú¥ÙE.*,Âáá¸íÆ¿ð¡Y¤óät“?Ÿ#¢0Y¡Ð*|ÓK~þವË~Üó·wòþöìîŽu¾ ¯½°0s[AæÉ;O1«¶_ó“Þ¨®¿°`ÜžpËÎëV5µ¯ÉW¹®è{*“ÎÃòÕÈËi"ÈjØt»D£¡E-H;ŒÏ*ÁÈM|ªƒfÚlŒRkLDDLèÝä=©ŽùÞtÜ©Ïþ…*†Ø&ˆU…Ç0€;è¿u…|#àïUÞŽ&"›L,+€‘§õX;"ƒ«ûNd¢?— oÑ ‘‹¾Ÿ44$ GQÙW7 Gû¯ÞÓúá—ÍuC rROSÛŽ_k&ÒÕ—¼úóâq{¦Ô¶¼ÙÕ-šj{ ¥ˆ ê1-9XO‚¦\ÝX•q¬]¥rcYiš¹y¦ÙÝþ”M¤`ŽÀ9Óähs ä†"ÇF jòç£výâO¡Ïáy)¦øé_ ›ñâï”në¨ÿ®¹ó,lÊk#nYþÐŰåÜM͆õzô%úz\Þé¶WÑ/ÿ´Ï>Vö[ôÔ«wöŒÇ,Ʋã€Þ&e)àFSévš$*2C\†ˆ`; á¾ôROÃ75<º‚==óšýØ×á Âæ©áBLŒ+ä‘f4È\<‘+¶P×?rlèU€¨Ç¨››µ,jdÓôœR¬³ÌGhŸÎ䬛Q5Ön4²n¼¶D¼æþ»¤°Ç~xóí+ xª…ª! ÿ.êj{¡ôùùçÙ¤æ× ß<\ûýºŽ³¨fsçœÙé+ì!•Œôšˆ®­ñß=à ´‰§½º›îLüÇþeÏE—.É©{ ðµ/<ÉñuŽ í8»BÙ¨…ØÙ?XkÈ÷OÅí]™IӞݿé×ÇN.I™bÁöË炟* ³I'UŒ³K•<ò0O{ÓK?Ä=™¦Ð‰×™q¨O{Ðb;[ 2JæÆk°I ŲCc"ÅdD4_ý@ ÔI £ìšIoq訽ðæ&Ôˆ y£e ô¾6W¿Ë2 ŸÇÌaSH.³uÕÐ[»Jè­tNC*X»¸8ÝšáPG÷ÓdôÅå+2‡ÌÈ¿1nTîÇYo®ÛU=Éð?™Iƒ,D¨°yå“‹&ÅL)6ûÖš#Z¶-ýlÑä²ô.ÑbÊ”H¾y݉\ÛkÄÑ` M*’D)ÝFb$Jü'Ô7‚´3§„*ÞÜÃ91dh‚LoÀ<‘94ª»0ù3”N ŒVgòÃÕ’z€1‚Q³þN7õ„\ÓÜ—œVŠçu”×½ðŸ5£«'Ùâéé5©ÝàáwèåÓÐJOß¼þ-:ƒ¶8àèú!Ô®w¤æíÊýþ³‰±ô„ƒèï{Þòü+hÛ€‡]C*ž¿[s‚/ѪïÐCt5»&–ÁÑ…ÇÝ‚îM{jÁ”gàH‘¸ÛÝ€ã˜Ç1®Î¼mrFSìr9ÍÐ"šï¸pâR3ÄíîRL.0º4=)ù€öm?Üšfrc&~ /¡0R®Ps`èÁ·&µãJ‹ÙÿŒ_ ÀD ÖO¡ðKµ+®r¹!Õ.§]ÝRí®ê?~ªž,̘ŒPÓ“‚icÏ7Ü×¾£|)ú¼…CKÐoÛÔ7]~¥‡NlZsíDûOxKý^™ûÅpI¼vÃò’ç¾Ú¼p©`Û›qo Å6éF"‚¤ØµŒ«(Åîªé«¦ˆþˆ¢¬:£xò©†noGÿóêÉ·ÞÍÞ>÷!ºwÝ:½%áEÖ|­¾ñþÍèM¾^0RDê÷2xò`µXœçñ‰œ:ÕÎѬ&ÕΪŸ¨ßB 4ú1@-pÉjÿ†– Ghv²l¨…¾]oŸ‡¯}zöÀ#zzŒæ…Y½Ò%~f\½zãñ|‘{)_÷Ú´œ$ÅÎq¢Ø;ECìoð)“Ê ’üÍчZ¨›~Žó”ÂÛqea;_B¡[ÿê‡[‚-F!ঠZ@Þ;I%ÅaJHµ|>ŽçRJ?Ç}ŒÌñÃK=:ÈÀ:ð&tï\€0..ê» ø§ØÍÓtb3ìq%âl¢!ÐÔ«$ ¦^ØöÕôº~–\¯¸X7vé›è‡mo+ÍG7)äˆNƒFHCWøÞ/Áƒ¶úG\@oû:uÊ-çåæasÓ)v±˜•r4d{ÇmÁç)ß´‹Hþ¾¡‰ãÏ‚æ(+V[ù!Éù lÃçtÀ œÏÀö=ÌÙ§»®cô#¿=D‡ yØg®Õ\qçBz.9o™º~–éì¹zLôkº"Ùº}èðÕn€þñ÷·Ÿ¡›ãûW~[}ªeëÖ¥ÐOhâ]'äP ;î¡O¶ŸG[¿>{ó$œ}ãìÍž˜Á¬â{/ ñ6&Õîâ"âÔ"6DOxÔ#n  1BßÛ¬0«ÐatrÕR¬_˜úå7MýWß6¬{õzä8Îv~àøªs_õ<Â'ÚãäÓ˜l*_¥·RdÀ!ÑÀ(qHT>á†Ê3ü`¤—PÔÇ¿J D¸?)åÙÜñ°þ(:¥Röú÷=¨¾ÎZV?†3¯Ÿ½ùè=ªŸpÖ:ˆ<2Ð6'ÿ«yÔ᡹¤’%¥Ô´,ÅN;eÀ{¦3m!ø©”,ÉU”ÈÙ¡ÀÚZ"<†ÖÝ?riætyËñÏWm¥ò»pôÜ€ö;SùÔq¤ݺsñbSA¸¾5áØülJ_™ŽÖy¥Øu #Ý_ |A‹ËÙÀÞ~(ˆTã}ñ W´>ÐàCÑëÑ÷Ý¥¯&í>°ûØÌ¦-P|µð­©qq{žÍ?ufó l¹|×Û¿u–ç2ªÆ?Ûºðý‡lÔP56~Ô¤¢Å¼­Á2éàs6î= Z„“5¶G"œ¨‰S’Àk%a÷û6¨C¥Fúš*a}·l|e¶éü~ÐÚ$:)ͨúÌ™§’.g°›ÐB1Ž=†­¹hE·ýçßÝ>hýP¿a}Û‡ƒ.²]ÃÑïŽÏOŽ_DÏíª/ͪXõÎyú9SÖ—×›²Ó…ÃÅGBß¼ðÌD›5z¼9ªÞü°ë§ŽÝ­Ó´§× w’yGWÞ©Vì¢ZŒÇ›ÄFáFK¼4RJ×vÆhÁ¡„ÇiЊÌäŒ\ø†¹Û.æÜ“Ñ ö˜V_JÊÙÇÀMB%P’6 ÖuÒ§_Øüz—ºtRÁ®ŸÖÐù]{^ÚòÌ·+éj»·bY_ìÏ&SŒç扸BC“‡Y¢v\A¾G¨ è÷¶ ðý#Ž+T­£†S펋”Ù‘ê” sãc¹G?–— )x%…IC›)wx÷¸£±¬­êÇVêõC× Çm*€^OæEðû›ùÜ‹mRÄPb–I±³4÷Ï逗3™¥ð=¨‘®èZêEow”ùÑ9]EÔ{«™ /7<žGð¡£Ô¡þ;ÄâÂñ¼‘<‹ã: —å¨VÃ:ßÛèÄmt”{ÔøÈˆù¸ƒSæÓs+¨ÁÒ¨º¶íZÏÔ v—bü¥NüØN¨¿›€ŸQu ÚnûÀzôZÖÉÞlüãõn¡BŠ=Žûy CᆃçJÃÛ®&²ç@éúsh0BúꇎœÏkìNæguâguDÔ¼®+>t(:º@*–¹F¯âŒXâýägÐ4YÌz½ªdÔ*¯C¡%̵QGFê^xÃÙçæ3¹8éù ›VÊÈ«ë€G¢(ešD»Lß7:ŽUñv[tƒÙj¦MVgo Ž¢…Xi"'U“».ØeLÍÝzñÁ3 ;Ö> ™öÑ¢ù“KNÏcr §´=>|éΙ¶ÏaÑù.Ï÷`ȦKÚÐׯ-(òÒLS4§Å>ìOhrapnœN¡OÄ}-ðÆ”ý‘&G(Ñ)‡£bïœDÓ?’SÆiÍÒÄj˜Úb¶•L9”߸cõ/~ùg+æÍ,|«D;}R+§}ˆºÛ*çyûzå,}ûúvËÜŠÝ0´å6Ö–ÝŠeÅ×Ô"Y¢]¤š~ÔðT`iôLlzÎÆ |tâË}mu]Ø¢Âùïͬ¯H^³LûåÉaÖæFóKèþ®kƒ=›b:9‰ùÇIðO»È±©HtÀ‹èD®Kì½ÔzB'>÷cÃë9<¡ªæÄD©Ê+c/êlЋ‹÷å5l_÷K`Þdzg¿=“É9örœþû½KÕ%§Ú¿„E'º¼ß‡¦-󾎮¼~›× ῃçߟT´^òD»—‰ÜyI¨ûI¢·¢e{g¸Ï1šDNyÈ!ÖŒ3{Á{‡ÿ¶é×/mCè‚‘YZ[_˜·.rÆ¡¡²ï~JÑ~}ü(´T_Õq1³®yÀÐ ƒLô­£oT•YùY·'ÒÒuœ/¶Þ6½ÌCâ­ÄV¢ÞIv`1Mž}²ê‰´sºgÕ˜b)¡±åõ¥€f‘‰–Ã’„a¶¡éYî·»~jòÚ®à…~¡é£&NñvÿÑýþ´iuúeåÌð1qE¿n×zO«]ó¸óƒvr‡Ö]‹´L:–S0î¸Ç€d[°§ÙŒe%ŠN²3~Zh™Eºà@[’=PL%ÙƒºAIvÝ”’Üë†;rœBMª ƒ ’¸|!ß;… Yï˜ ‹Ú{¦da¸ìàÿÁÏÉL¸3gÒÝ/‡Ü=iõnˆ‹­8ôúý÷Ä7ë^͘>96óþ‘ŒtGêÊg¯Ü¹hÔçdŽ«Œ”•Q1šIžå“ÿám±%#ÄS,×?·âðùæçgn‹ ÉL( õ«~æÄoÚG¿ŒÍ©Y“,Wº/§ÕÏÚ'4gge_ýfŽë!Øž½I®vÑËpÑé±nôJgb&FŒó&ŠŸh u³œîudGS×6ª›íoÖ‹[°ÿª¦O—¼w‹êš A¥TG^ÈÆÊ[;Q§ÍÚ¶³}úÒÒuÏÅ”GFg<Áù²7qÜ”ãH-Q ¨Ã1ýT.ñM¸è›ZÝnùwËb›yÒ˜AÁ‘L2t–”cMÇoGi)oŒC†{}\™è”â'¬‹àrZ)°Øû®Jˆ5¼:Š÷¢_¼'ØÌÙcFòFt‘¹þXÿÖNQzÏI$?Dcy±¼ää&›“K @‹¹¢ÜçS N¼ ¤PS)ù9 ƒÞÿakV+LmM^0˜ £ÜÑ`G%[ŠæqZ´Ïq¯¶?5ã'ù¼,ˆ$ ùV LoÁ¿tÆ­Â6<G ^!Ó¸*€Q¦ â4\¢ÝCƒg*2³ÙI¯½@§ú4f§ò ½:Ä?ì oTǤMعëóß zéÄ·sË–¸ˆ³OÖ4è×µnÔ&¤ŽßQå;‹¨61cÑÍWP“|¡ªdåÂêÅ/¬ŒŸëȧ:JƤ-¼²É@az݉ äÊt„VÍŸØØ¨$äa Ó&e&FHÊ?˜_ÓlhÂçǦ/úûž‚%Å ÕãŠùÎxø€ñf²{ú' "ñYä†=½/#ÀÞ=‰ƒ0²_ZPSuǾY÷ëË}½á7XW=kÎÛSkªJöNa²o>ŠtþãÔ18î *+oÚˆ~µ®itåí¹û Ž/ÑLNO~Ä)[!UH<ÿ?äG9é0ÓQ‘7KZ1k/ÌlÀ™ûøê/þÜ—‹rÝsÍE^º}rßhÇé'ó#–¦‹Ô=t¹®%3˜àãÜñ µ«Ì‡Öé<í:%-I´Óú§û)®ÿµ[POØš„k ŠºyãÜ›/$îNX¾"qáÊÙç_kgÔ°âª)¥IófM­ÛßIØ1pHQFtF|ÊšüßL]í:1aXfìÈìBžßœî{Ôu6xÿUªm2B­Ö%ÙÕ $Ú9}ÿrÚÃMI®ˆƒ@¾9ÂyÑ,".Bl°Úý‹|ªëÕ5mò÷ª ¬Píîת‡WxÔʵU•q¨œ”Œïºj{&6’?¿ ×0yL2®°¼j©›ÂU§ÆòV;OÚHð“ôDÚ±¾ÊŪ'7«›'µ®ô/Úû}ƒ^Vp`êŠ ú L²#ÅÑ´èÛðúãê jcæR{ÈyØÿÕø<á%8Zb#Œ µ¸÷MjYMÂòÍê›W 8öcd/#T5ùTîãÃGŽyÆáKú1VáNK¼5RoO?FŽ‚&…Ðézû1oˆ¿S“&'Ö‘D<ƒnœÝ£sa90¨3€£8¯¹PvqTN^ÆöÊëñé퓚—,;CU8Ú[ò,³¡„šÄÓÑ› †ãyÁ}(£p¡t}}…Îwe¼Œöž„×ï·¶ÃÔ(º«@”…Ò "¸ÝqÇqãýRÍëçV! …;£gïtw˜,%¬>{õ\ÆÂ‚–T©†3•¸™%Oé\‘ŸUaMÇ ÜL@?eMüG(5íj{^·J]\ø¡ÿ6¹÷Ççõëã’쬊“ì$ÙüyGp„¨Ndô¤Ö{;&Qš :»zM×q¬Ot”Ã}VÖ‹‹§Têâ¨UÓ€ìj˜#¢ÃKâí&E𬤰‹# ט¸šép¬S@¾Û×Á#[´Ææ’_e“>Þÿ·Œ¾3sµI^ËK¶¨Ã)Ï £3«"í^Ó55M,‰»V4¦LD.]¢bCÚF$_l _‹y¤¼‘’jqæPÌ®§Ð#šU&Ê»¡Óþ·‹è÷kÇyº=m2/©T« ´†¡2÷PÑCžÙIp(´,X-˜©XÈg,+ô^÷’.\yÉXµV?fÀÞC®å%šd÷å³6«#äã ½ØÎ™•C§\mZ—]‚Žì©^›<ÆUT«¹oŽH¾2ÚßÞˆeYNe2fz®bÔ À­ÑjrYæq1"‚|‰,$7øàD.vüI|‚¹QµëfÛ¦EXkÍEë’—'§åPç"·ÌñðôгnžkôósòÓCÔ2yüζ8D´¿Èuiúvñ vxøÄeל}ŸAñøÄA–ñ£‡FQmo²¡é¹‘QISÌd'Ç“öðÁ6å#“HTcí>niv‰.DÐ]XÛ í±-ÖÄWÄêÞ½³':2•Xú\SÍ?×›–T„Í™‹Û²ç*q[¶ô5íUÿ϶½cÎêZ[$Ák#IwV½!Ø«)†!ö}ûç6öÎúá6wƒ›!Ã.vsSÀ’»mB­H·«ÝzFVÎfÈì,â… #"7便X1&+ŽRtêá­qž»‘x Æ0ý¤Lꊱ+Éó¢%ìcséiì¹ìúqÿƒŽÔ\/Xº­qÈO7j`œFj‘hd”Ì*LS`Ó°”‡A£”IÄ"µ›NÊøêDXͧ">P~Á2M¤5Èj yÇj‘ç’—DAÖ@kO%v'¾6·fÆ‚ŵ¹µ‰‰59µU595ñµM3J6l(™¾Žº\QÀÿ²6§¶¤Lø%¬É¯šÑD`ÈlÔ`™Ýþ £lF©\!k)8µF=ÖNN¡ñÕP B#ƒ:Næ&Œ°2§à´!(T$ñ™Iä܈Äpˆ§áï;~øÞ ]5Âot-zÛ0tÃúñ߷οƚPý®zô+”âšT?áúMJÓ"†ak%άŠS fª2©œnM»ë7äÚõßž9ÅoôÎ×ÈÃÀ`›»»™¬5ÔÄùˆ|$Ù}t"Y’cìMÿ†haÇ ?Йôûr>¹v6xý‹(¬Hò-\ûUŸíûà9ËÆÊé‹Ó—D.™·à»OöU {5½~mñôçà Y¥Å3§ÒÔ¹ÒÄúšñKGŽOO6h\‘mÚÞaI•[ßµÑýÙ¡YCF5ÀñKólƒ–ÇœLx‚çX9}—½ ¤8ÊÊiÛ ¿êÚ×Ðô»æ?7lHƈ Sœ=,l,ù†-2&3<~P°ðBvJºïq¥Øwõ DIq2 VÈ|eP+Õ”L-S{†âzË“éÉqXñSœÛ@Ε‰ÞÚDä§,ŒW‡ŒÉeÕª3©H wfô®êú•+²jãò¢?úÛ7ÇVVŽ,íÚò1Ì;æ|~½qñ3´ûäÌv8¸­|§]Ý׎¾|‡1µo{óÕÐ%^Úûß|þËÈEt˜¼çÚýù'èóŸÁœ3o£Ëo·Ã}ηñvÐJki{×–>$ÒK°=id€ññÀ•.B”_DœêÑXû×91îiÍ1—ðá‚ . »!WÎ¥Œ-|f³~ÔŒ„èèÜjöìŒÇŒŠa©‹Jk®.utì“ðéš|ö$PF·ÐLJ»£Mî*’r€–Ò¬ÊX(ÌñÙ*ç6± FD³ÂË$¸*]m+û6ÀyÙèÎŽ²«T2¬£êpxD7% f´;6 54¿—H»HP ‹ ƒ8ö£…1¬éú™vw܇u8=vw÷ìª9²˜^P`™ lº€Æ2p Œ1 "ób­LÓ»­ŽVõmãjþuhÉŽ*m"¾Ê_ñ7D ÿ§ÂéΩÏÞÞôYYÍ×^A9¹'§NÏ¡®ÿ*g,7¡˜vÑó—£;›ÒcˆlnsZÆÀm}z6KÿÜußHk8ísXWWé<:Ë@†+1ÙA¥TOòìa«&ãâRýƒïÕC+ŸY?áP]]GÙ¬g”geV2Í+㟭8thEæÂŠqY ²ÙŠkF±~mÔÿqe]e,oêÞ'IÉzLÿeR´”ÞJÕ5ÂТFTÝ  ùT*õ+Îy¸nxWªð¥ôzèȇ0O·8×Yz9.éÖ;>3@qùÄà˜93GTošS=sý Ø@¥–~WT81ÌbËÌ).Ë+|µú}Þ¾ª°ÅüŒÏð'^ä¯TªTœ›·¯ gìgø0§ ø ÕÙok±çlѹ»zvõ‚‹rôS§-L1=Ï:g炟12Õô„皇Õ$·®ž••4rTü”Ió§vD‘šNË\£àÓ$doV"ÌÎqfÆ¡Gd¢´ÃŽ~’6“ùyä»ÃuáŸ÷ð½x)®u=H­«–)D…T§÷TP}Ýn¬³l‡Ow:A&¡'7Íö½uþ3_»Ûà&›ÒQ0ß,q1$ï™-ÕPÚ\ùí+ðï_\\’Ÿ±íæ")¹X^gQÓ‰ó—xØ\8±XÎB9b—ƒ0²—EFN%NaRñe”ÙÈt.¸R3á« _ÿ‹Œº¸êßëh³úÑcÈ â·­TÜMç(E@j¨~Æš´à2þN…­VL+Øj?ÁAÓO AV\c]Þ]28Ч=cdqé¨:t¯ RRÄÍ*î\ ¤° 5ñ÷½¸Gãh?.ccyɘÉpÈŠÅD¹WY5ßÝè±ÈÌvvm¤ä3–¸‡ŽËákZKÝÅq–Ìà\;4´«Ô—,.E8[êž%¥ gÊÀFAÝÝ¿µlÕ„-…Ë™^‘žWÁœüðÁÚêŠÓsŸ÷}gí³Ïî_·WÈåPN—ÐÇù8êks-r•:ã(ï¥ý¢¨AÚª ^èT•CÚÊî¢ ´.zì(»ï µYp \FËѼDX "Ð\,ߥ¸JÌb;•Aà2…{Ve Xz¨Dà jºã] 9HS¤r´Xˆ.â0ì ‹a6þ!€À.¤Ú1¬è¥$ €·1ì¿Øs¶â[ö7 àírâ(àÅõy*£~c&ñ;š&›ŠswWšLÞãì&¥R’bWšžâõÈ¡³}•³¡w+“زSîÄï¨õú¢ò©;gägnŒ‹É93±¥ó¹Ï×ÿÈoŽ ‹¢ZVî™’V³qÊt³oíÐÈ7¶-û¼ª`N$‡‘ISÍ<ÂΖ¨\ðôéþ fi¥T² TeqÂŒíS š7·'`†õƒ9 âî ˜&QX/ÌYÿ§xBE½0¥<Ù!šò÷€,ýè¦záÎ`›ªÅýª‚¦î»Á›npžT¸A7 š‚ÿô°î¿×¡#m~R×»T 9 öar¬Z¢æÔ)vކò'o@ÝÈ´*¬ÿ~“ÆM};Nd.À¶8| P*º~šn¥[Ž E”ÒËq¿œŠrÔ4O@ÂFÛK(t³ãŸ8Wïsdòv´iÉÞæ#[§,¡LüÏù½(^žÁN½<æe]]{dõ˜JP-ÀôÉü0§A¢£V?Ð Ó#s úúö“9¿4žÇ5H  p±l\t\?˜ÊîþŒn:¸ÌéîF*}&„§I€)í¶9i2ziÂ:OvîÁ‘™ð`›ÁC$¥Ø dÑJªOµã€âÙo%îÉÎߎÓNð‰ 9¢ÑÞ-¹U›ü67>µ(7¦Qg©s]ŽZ½™ÚÒ·1çèÚŒ¤˜~~‡ˆ·õpÁÖ¡XàÑݽ—G~ˆ—C„ OP"øƒ·÷_ÂTB£ð—0§Á¦ÇezaÂza΂;' ¦|æô½°°>™CÜû†Ó˜*²ÿŒ»8HJ*&·ê$lø™U ("‘û{t¼Úà˜BtÆMC ò©Ëpt!úÚòÑQt,ÚЉ|\ÉUu·±Ãow†àH©ñ5ù `Ýn)vÃ>¹ÂÇ/¯óO¨ð=´Å¹Ä‡»k(l` &2òãvawêãçjç¯.%ËC…;“ëlÁ¯P…P·r.¦Ék·þgs“*Wnë ?ð[DQÑ{sÇ…±dÍhU.½eÊ©œØU–zÎ&~ÁïÀðòæÔã$A×=¦ú'0•8~ð0=.ö'0§ÁÆËë)˜€^˜RpÄé!!ý}•ß áqtƆ Oú½s*‹ßÔ›F¢KµK$œÈ•Iµ»ºrÎ5›'_Ï^˜™6÷ß ËÂÌñúD²ùgÙuå†C¹êê?Ö¬ßK“Õ0tœíìÇ×:÷-ŸË÷5Ý×p“8\K€A6·(]í#“E'ÚeÀg@¢ÝGÿÇ[dAÙ½·ÈÐy‡„ëòDßÉ÷kâ‡À ᆾ•oœQë¢FEŒž`€n¡ÿ8±»càøçN ›m¾vø)æU1e/è†ÄMJˆ™’ã?Ó^õ¼ú1˜Ü;7é§Îeý?>³¶:ºpòÌgâ‡ÅùÏ*óÎÙ¤]!æ…ÅÁ1ì sGZ²“†ÅŽ °¥T¯xt÷ƒv,~σ3bùÇcùs`Ì~ x¤J>ø˜ÊxfàÀÿæôy˜  §aؽ0gÕ‡½Ü Sê¼gGF @–Þ³j{aÎ|-À à„Á>Ša¸IL.ˆí/ÄÙèÜhŽ‘ªFí#G²z«‹ŽPE$Ú=TÊ€Pi(V¥Tßwy)¼ô•ÁyQ&ê¿Dan¨DXbàžXz½ Lãìׂ}xˆç¼>uÉ‹×f-r3Çw饪ft}ÄT×Y—Vìéš5õýªÉc ÷¥ÒW*ކÉÿñK¢v\fÃ¥ç¦iýNÿdÚÔ¶ {_XØy!³®ÙhÞœÖð.¸yÆ’·Ñß÷,(§³?Ø[1oTœPÿ -ÙMÁ²Jò6¬î‘3ÝÁë+YÐûJ^="셹ߦÒÂà ôÌ™~0§?çaBBž‚ù€×©Sú… ¯¨¨>ŽÀwÇs™³‹r¶ª'¦ûú÷ƒ©ì*À¸º>sªÌiô©#•>sœ§G€)E_àÌÙª~9;ÛY€£üiórWè}€˜eh_}p¢]¯Wø*p ¦0öutæ>ƒ® qû£7ø§–œ †‚áXIkÄiú60ÈzÔž¸Ì©•‰±=˜8® ýÞÑyqÕý3_2q)©èá°ðY{§×•ÍÙ5±œn­˜¸af}ùãu´ìÔçïí‚Ú“ÇQª>Ÿ²iöãæ» òÅòÏV,_)ðËdò~7^ð;#/“é =`¼y¹e ö°þ©ŒBfþ_`Nßÿ³xò€±ðô0g¹¿ÀÃëH€)ýpfø>¯]Œiá÷7Üòn%U2ÿäyXÏ3>‘½ ª¾okè­ŽSó,#FFFŽp¾P k×¢/5rxl õ‹ðJf”£º;˜L¦gDž¥V+D 'ñ÷ò6ª´b#\®38!0úþ9ßMy†_ž•á?¯z~ªð‡´Ï~Þ¶¡¨`æœøæŸ7o(-™YƒæÏ~§HEqQk\(ºxÆ[S©ã Öc£«³VÍØ}f싯W;mæ„¶ä¦êÃÐ &GÍà&H ¾Ïßµòº˜$èô%^ïýäü4Le 󄾞†9-BEð4 ¯/¦ÔéQ=Á‚ôLü}#'W8ëÛ§ÎêÙaà´¸¶Àï ¸•ˆ=Un‰v•øþõƒ°èNq½åW°1H*VMß ÷µL ÖHŠ÷Mmxbaú¤’dä!(iw|uÉŸ­2ôðÀó)ðPúüS| ;ð"“,ìÑ(z÷h4f²F„îܱ…°±]A´ÍO©Á ¶ÊdŠ»Œ–z⎡õ)vZ ÕP›bç¹}b ÌÙàõ=bèm󨫦'û°?;ò22{VÑ·>Köå[>_ǃrÊÒµ'!ê×ôr²¶®í]F7ÍŸNÃ¬Ö ëÎ|Ú†ó©ÇÂa`„͇’³²¬•ˆVæ/óÇú‘)½Bج"ö©LŠÕä|À‰hË/¨/‡úœÚêŸ?{÷ìÕªÈÀ€¾ôy=ÌN¸¸ôðW›»^†r{ÚŪ†íè]ôy³´6mMæn5§=ÙÜý竨ÕÕRÿÀ¦½5kÁw'ŽÃŒý·æ,©[üîyœ1ÃM›ÓèØk^nÜGC—eÏ3ì]²phy¹FÿÊqD‘¤]Ȧ¬pËa âD& ûé}!ýëŒè’çgÏY_eØ0y smhcU¢g}mPá qü܈ Âxnpµ¸÷0ÍEá+ “ÄJh‰ŽÌv?™Òo6EòÈ9ê' o,*,®\6µ¸²Äf1Ìlc÷.,/È«X0Íc‰5JxF=“¹Æ„±7° ©;YË %€°S7Îð$C(RRšÔæŠÖLщÁiIcü™õEÃß4.)ÆsÙ£(޹n 5E‡Ô€ÐQ±áùz=UñÇçÿi«?¼²k—FTòg0"y/ÌRú8%柖ÎÏlÐEiÌ”¨–+h«iF×_†2ôÆv¾g«Æð2~wZr€%{ j ƒVµ•bÄÁk'Õ>ŸÀvê'w×ÃÀÿÏÏ5 =ôRžWàÚD´´÷3[ªŒÂ üYœùQÍîÇ¥^*Á¨~I/±¡•®áiU`\2VAè5Ÿ‰è£ØhàhST?Ê©ÁÒ¼Žšè ¯^ôŸ¢ûËa@–ð<-µçÃ[Ÿ‹+Ï‹9¢—[ST¨dê¾Ú5±Næ Ñpä2ÿ…÷¨õô]l{âý𗇦ßúÙæêܼ+ìS¨¶õm¹ ñ{&2j0_¤îä°¢ KÔó¨ëS÷BT\6@uá°¿×Êá=~FªÆ‚¥i²}ïuEá=´h, n+û|€ê²àXXÒxý!w,ÌöyÔƒÇ'^bFõÿ<ˆ\*•ºÉ%ŸËŒ6…«ˆSâQ¢TÒ"ÚÏù¡üêÂgà’]øÌÿ™ Ô¹ÚКPÔl€·ê× 6ç"­=¾˜ã¸ãR”ý*ÜiÅâ|v•=Aš-¤ç.Ÿóòök§½Þ¾Þ”„vóvóV Ýn©]ÓíêþÏ}“%Ý©ySTæþ·Ô¤À!šÿK)ÏóÒo1éÐxœ%Ù»o$gvðÞ@I9˜mÀc›"MK­¨)’Ž4-R-‰lÚÿƒãÍúiÚ»I£_h>Š˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€.L¤ zæú<f†œ®Êà>zÌN¦Ä(~®Úü>Ž :ˆÀö$J’ºÎò  6 n š Ú  Z ˜ ä  6 Z š  â & : V r „ œ æ 2 f ² üFÎ0f–¨:vÂ@ˆÈ"fŽÆî8J”ÆÆð6€Ð:¤Î>|²ÈÐ@R€°â"<z¤®Òò Tj€–äö,@Z¤°ÂÔæú 0D¢´ÆØêþ*†˜ª¼Ðâ¢´ÆØêü€Œž°ÂÔæø ‚”¦¸ÊÜî ~ ¢ ´ Æ Ø!(!:!L!¤""<"n"œ"®"À"Ø"ò##.#V#z#”#²#Ò#è$$€ÖD9/\KxœT=oA};_Ê„BÛ !ŸíT)V%A¡¡ÙÜmΛœï¬½µ"§EÊï  I?‚AK àgÐñn½&v(ðiwߎgÞÌÍ<À½à >Oa=0‹O` ß<®àaP󸊛AÏãIÌo=žÂà‹ÇÓx1ñÆãÜ®Àã9ܯìz<°òÉã„ÕW/âqõ;3ÕYÞŒË^â·ðÁã Fö¸‚çøéq"Øóxwƒ3§ð xïñ4Þ?<žÁ£‰¯ÏáIåŽÇóx]I=^ þåñ"^Vϰ„ËrB!†à’¼K¢9ºè³òÒ«M«À9×2hrÕ•xœmÐWo€áçt¨R{ï½Wí=Jkï½WrŒžúêÔ^± !®ˆuCì1.{žàÚŽQn9?À›<à•À߸9þ׫¸‰’$+"EQ©Š).M %•RZe•S^URYUUS] 5ÕR[uÕS_ 5ÒXM5Ó\ -µ’®µ6Új§½:ꤳ.ºê¦»zê%Co}dÊÒW?ý 0Ð ƒ 1Ô0Ã0Ò(£1Ö8ãM0Ñ$“M1Õ4ÓÍpÜaëmpÍl´Ã6ûu$”`k(Ñ:»ýôËv{mvÓ{?ìwÌo…þ8ä„{î8i¦l;Íò@Ø]÷=ñÐ#}Œß{î©gN™í»]ño/¼4Çg_m1WÄ< ̗뀨…òòÅ,R`±O–Xf©åVZᲃV[eµ¾øæŠ×N;ãwÞ:뜋.¹å¼ nÛ亮†’BÉ)±ÜHzzFfj´ ägGƒpZN4äÇòÂA$$eÅ‚è?zÞmGxœM‹»NÃ@Ew¼N¢Tcˆ°ˆÀópšíXúD)L‚x˜‘âDJEOaSCƒ”&ˆ–¯ðºË_ð!|‚q¨8ÅÕ=ºº£ÏîÑ$âB¦‰d ÃaX†òÚ èÊh2ILƒsc}Êý^M·¦¶¬érªiÚl=½Ë-ìêæ-åP–R^$}úNàäXÓ¡>`_ïñ {ñÂ/tktÚ-øI¼ˆRü×ðêC 6ðQ=¤J™M§¾7¶{»°°²qºÍÑÝܶWVð|1«Þ³·õZŒcÏÒ™‚ÌØÇ¦xAå‹q–çJ-óâYm)T^¨ÿüéþòMº@Ðtomcat-connectors-1.2.50-src/xdocs/images/fonts/OpenSans400.woff0000644000000000000020000005270414655113617022707 0ustar rootbinwOFFUÄŽŒFFTMl\¬yOS/2ˆ]`¡=¿cmapèh²ŒèÜ™cvt PY¢M¤fpgm¬©´~a¶gaspX#glyfh5¿QT¬Á­µhead>(36ù6Úhhea>\$·úhmtx>|X˜wWkern@Œ# – locaN ®®v—cLmaxpPP ]JnamePpã ÞˆrÂpostSTxò‚xéÕprepTÌø C·–¤ɉo1É51‹ÉíØ`xœc`fñcœÀÀÊÀÁ:‹Õ˜QB3_dHcüÈÁÄÄÍÆÆÌÊÂÄÄò€é½ƒB4ƒ3:;3Ö°ÉÿaháèeŠP``œ’cñ`ݤ€\¯·Ÿxœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@, " þ¿ñä? Ô%ügÊÿ·ÿZÿ¿ú·("ñoY€Bu342Üe˜ÁÐÏÐÇ0“¡ƒ¡‘‘Ÿ¡ M=ÿxœuUÏSÛFÞ "SÊ0Õ!«nìÂ`—t’¶@)lmÉØuÓb 3+èA"&czâ”C¦ñ­ŒHÿ—'r19åÚCÿ‡Ú[9&×ô½•M 3Õkß÷~î÷Þ.jûð Ðû{íÝÖÎO?>ú¡ù}£¾]ó½jå;µµùíÆ7ëk«_õå÷W>/—?+îÉOÝ» syûÎÌôÔäDv|l43bqVÀCF "_‹¤/£z¹$ü…®W.ù²‚ˆà'S”õºd"PÄOtA¡å“,Uj©®-¹-6Ø¥þò¤èóƒ–Æõž \™õ#³Î0‚뢇©Šª>Ôžvc?Äy25Y•ÕãÉr‰%“S¸œÂ,ÊÓ„/nr³°ýõÄbÙiJ‹;õ£ì´´ï9®”K ˜‘žQ±ª cU7!Å •ÎÎERz?ïÛì(\Îud'úYÃH„¾ñˆÇ¿C~–¤KÏþ^ÀCIz>,SÔæîužæû”F ¶ñ†Û‘WÿÞF¢2V°ß0Z‚U¾«]zœrÇ5)jqGýw½#)l'¹\|ê#ÝlGcˆþ»—çÔž`‡]¾ ¶^ÛmÂG­C V¡&º"ønIwÕqó×6;ÿ§fH ’ƒ ».ÑpÞWìèµt* vä\0µ²€’æÕPóñ>izC͵{(±·Í¶Ž!Sht¤ŒŸGÐ;Âéú…#m˜yë¸2žÍ‹µ•ÀØ ¬ªÑ90ZD’Ðë¦Î ¹Ä¶fÞ¦Ÿ+ó³bMbŠãK?¼O» @ Ñõåtö4(*tÌOGbÃN<ÓLX‘§0'+×Ý¥²ü“¶6.7˜« ¼`Å7çJøqè¥%P,ÙÒ—ìÁ»×ÉCá¼xÀ²À#ãù*NYÑuç Ü ž»'B;.¨;H}ÐØ!CK¯3™•=ÝlËfë@¯ I.Sð?#µ“†Á„l!+´åŒhh# j¸• ü…ñBÿl$Ü 4¸• ¡¹Ã†ÖX, ÿØØ‘|+è(Sµ>Œ6F"Æ©Ö7pÓ§\²P-‰Ñ#K¤Ö‡*¼¦P‘Åù¬Ö D\.ÐÐ -e »Ôަ½=†å†óA¯önI7ÈBš˜‹ê¡@dBmÙ¹I.lùZ¬ n Õ"ÎÊf;¦àraå `4Âj5€´Ä»WØx¤ÍŽ¥è0w×)ˆltbÙÖÆï“ßœg”k–5ys¯R.áÕVI$?k%ŠŸµô¥Í˜8ÛÓ·ªa%Hî¡N_ Æ”A-B $A@‘vQÈ{çR1Ö3ÚŒŒü¸Ï™Á²CŒ³Ç}+Åì4QÑ$RÌBM&Õ¨¡u±lŠõ fž„ejrTeÕ„ÊYÓ–“p‚.yÉ›àìEŽOs'A¯]÷y/™PNjÑC •Vx¶ÿ>õþ~‘cèf~1Q…—….6ÿ­ø¢CƒòkÐÀ›ÇÖàËËMl“ÜÄBÆr0)+0%+„o¾•âc„ãˆòyŽî=ìýpš€Cí⑟üéÄöu*ÀK%¶ÿ)ÿ)÷!) ÿÿxœ…|`TEúø”W¶÷’Mß,É’ÉfShYZ¡ÅEz“¢ô€ˆˆ€"MZ與†"‡* ""¢"Ç)ÅÃãä8õ< d‡ÿ÷ÞÛM6(÷˲Ù%oÞÌ×Û|óAî]ÇÕü!D‘elT­&g4a¬#:¡_Pç eš-¨0&ËlÁ…fŸÏìËn‹=ÔGs}9»Mð¤¤áâñ¾ _=Ù®(P˜Û ¯á*¿íþK?í‚ãØùŠê v±|I»ƒ“º±ïpfùÒrœ]±¨«þ޳º°‹t!Û;Ÿ•ã}Ò{>®˜‡ëYoé=íÅ@Ñ…÷ª9`AÉ( µFc~¯95ÁÉq6=ïFÈÅ›Õ|›¬T½ ï¤B C†¡w0!#3Þß'ḛ̀ql¼0Î’ñµæHXš}Q¿-XÆÏ瓉 0É&ˆv?%ÍëOÄ>sìÏÍË÷û짘æ5'1>ò°Íá40§ûàðü)w}øJðüËç^™dOîºM[·”ÖŸ½úbÐäQcñÉ%vþãš'iKj>Òyï’…»-‡êùî ÛkYßœasÆ”[±9‰Tì=8/4 AˆGãîÝZóçÙ‘0ÏFÝ-‰×8ZƧ¤´i©ikr|TŸ”©‡WÛl¡mŒ+Õ%ZE8xÉèJh5â§Èˆ/Çlò¤¼,Ø€9–þšçÏM»ïïjìÁ?–>¼k×Ã¥øýk—m^·zÕ\[ZQQVVQQŠÏm\»bãºÕ+^d¬áÓ54“#uu¸—ï®ûææík×oÜn¸ºçÕWþ´çå—÷\¿yûËë7¾£ÉwJA¼á‡¢©÷nñ—øóH 8úÑC¶VJ<™m2[{ i®‡:/ß§ëôYÞÖ†¶|u¥ÑŒŒä,K²º4˜Ì¡¢L¨f9 A,%-n†«Ä NXÁÊš“ Äns¤+Û=ÐmwÂù>"b×€%EßVòÈü1 NÞüˬ×äÁ­6³7–Ö÷ïØâÝ×v]²¯/èêÜÝ­gþý™?Õ\þ·¦ûܽæ=ÜgÄð»[7áÝÝ‚c;WVßYðÞØa#'Öì~eÝăCØìN¯Œb_¯e_˜0ø„°d3p‘l3l‡¥O$[q^±@Š™M„b$zaTÎŽ7Ü£Gñˆ4â F­Wº±(ÊÄXM–|Ÿ¸Zœž4R¾yõÎV­]º}Í&’ÕøÃ}'YÎOß³¼7ëðieÞŽ0¯.2/§™‘Á¨¡œ·ù¼ØDDOžÅŸK¼>‡…è6¯Þ¾tíªvJ³ßX»ÝÇð¹ïž|eËó ó8ƒ`ËÛ6Gy‹zZ«6š8 ÖN¯;¦2 TônN#ß$Jø§:y«¨Å^kj>OɪL¼"–-üuïþíûd‹ðâLÁÆ*'JbG‡â ¬f(.N:4/•Ö‡®séÜ; W-VÄqjž×驨˂ȨÂ*”5$¢úæì™Ùc;fö‘åx ½”Å›–Rçól®{ï…y‹Ø¯ø t©ù Ô`HQ–Ì18Õ)ÈÔÉÇC±#ýsã:ëo;G³_¦Ã9ƒáÞ |…‘©ÀoóA‚xþ”å ßkõ»íø;|eÙn²ÏB?ü1­€N¯¦ý‚j’%\–üˆü‚ÈnèXØ®s—B_× ]»wïÚ¹¸HšÃÎäª,_ÖÃq<¥Äagv[I¯ÉÕеZIžÂ IÐØ{·¸Ö²>:r6 Ò HpÅ¨í½‚j‘{©KÑ¸ÌæRáI!f“Å—cÁòo³ü®õ¿¾õóíŸnÿÒðUÍ®ÚuëjwÕ/X{ÏÃÓð3x{†­f'ÙØ‹ÛÃ+•]¸ ç j0©Va­ŽS‹"V 8Iv ŒxxyXÝí1çæ°èÅ>rn§ÊžûÉ@¼pgY0ÃÞfï4œ)Ós4øÔT°¥.ˆœ1X´"+˜íØ8“¦WÐ$â˜ÞAiêbÎ0béØ;Åzˆ^…Ü`'ìn.µ¡Ïß?¥`Å3¾4zàû·?üç–ÏØ òýJ¼ðÀ†®¬îÐoêîK–²ï?bgTŠŽ ÚÆ ^Ô5Ð"YEQGŠ^h™N§£WÐéÔ¤¦&ö ¦Šs¯ ¦‰ÒR`"DÁ&;¨Dl·qî°“J6›Ü£½0@Loo}aû’ýwÆÉG‡]Žç°¡/¬ÞóÞšg†×=Q1軟Þâ†.;¨rÔ¯¾ø•§Õ¶¬lœŽ5+×/šøTnñ”½#ÉP‘›ÀžXP‡@¢…W¢)¢<µÚ0oá{ÕFÑb¡¢@yí\}ƒì‘u \ªÏ |ó€õå&\y1THí¿Â–hTm3X>.cûqÙ*úEC:¾±²~xQh¦d/~ ±¨] ÉH]6•ÍI¹ø8ÄBH°Û‹vAÐõ ¿#]Ùr8» yRdŠ©LîÑk•B™<Òú[¬fר/ Š?³ÿV=ìÅùärèpêt:÷ïg®3Öo{k_íVœ“Oönd=HÖ™J€+ øê@-P·€'Ö¬uCX"˜iZªNkHèÔ 6jsö Ú\T1ŠØ ºÂf!ˆb½‘;Çi&ê K'ña΀鉸÷Ã%S;÷õݯ:ݤۧ®ÿöÉuö3þnÅÖÕ«ÕËÖ©ø5¼ÇºÒÅ®²Ó{oð »‹û¿÷ú««jK?v`œ"“À×L ©Q« ó<"`$)é ŠQ¢b0P3 –ÑŽqÚpžÕñ «î\ëq —.㟂ڠ>t§1ÍÖŠ&¨ÕT0ÛŒBV[ÁœžœžÜ+˜ž®CºØ>A yú‘ø{/¼ß+Z’s%$I•#1 VÀcãÁñò¤ä½.Zs †}ñÏœóü“ßÍzeýºÚ-o¯[„ÛÍ]1óÅ•³VñçŽîzü@Ïþ™sèÊùcw—õ=8åÅ7ïÖ>¹hÙS#Ö÷l¦=9zðs]:ZwíIf[¹å…5nX¾†7ÔÚVÆ‚®ú~ä}ƒUÙUÜöÈ®^.}¶xü±2ì²áFËñØs¨B§ÁÚ/h05º”ˆ={ÂhÏb†è>3sN´§¡Y¼Xr8DöU°– lD H“^Ï«Õ6«ÖÔ/¨5ÉŽ²Ù*î’6.Ñä8í³`‘v›ü'ù·´L±âÛß~dÖPsˆÇˆ,LŸRÁjÛÕ˜Ko(¢'~¤†qíH|m[ÎŽH4™…Or.z]ÎÕ2v‘pðGµŠãË‚P•ƒgTÉŠör’‹ÆðžEw6 ¥;é êjöXuµbÛ›ÁÄcp·¢J M0YÕPx56ü@áj\Œ+×1÷H6H‚)îÞuZ29Na Á VM´ZQ¼ó¶D¨…©Eb¿` ‡IÓ3h⚉WsÙ’’”H¸qXà 8Gg²î’‘Kz,œÓ¯fDû7?|ëoïgÆt>Ð˜ÙæU®¯˜>£|ìäÔìÅ£Žíé9yÔ¤Ó†¹ÙåHº ðξW,áë!f/‚¬$ÅÓ&ÏÐ^´Å!”n3´ác ¸Ž*³^™I94-³)á„Ì”4Fê²6x#Ja„ÃIí6YÏI O Gì’]Ì· ždÁF wgÁp=Kè Gn7`¦VÕrÝØšWoè¶·»«êÑikÙ¿ÿ|Ú‡»à¬¿>ñ[Ç&†—at÷;|÷çw.X %ý¬!WVÜZ0î¡GFžßÿºçr° ÇË{bÓš7Ø«_± ìÈ€ª ¼Å®¹v½Îv1\ˆy[½b#à‡7ñÇ@¢ À¿DbЪ0/IåDÎd4žA-o0@†8‹”ŸÉ²I¼”œÚ-Õ°OÁ´pëðC¡Cõ{I—•¤ˆ©s{é{ñE–Å»ÓLÀ§Ì>µ—ó¨³`Žƒ7€•JF=iV.Act¹ N4@„ 2ÆcJƒF£\¥Aƒ9Kƒp߃#Œ°Ð»“9ÉÛ9³ó@Z/[ÝLìÂÊ7ÏY¼InÕR܇ýr›‘:S¿mÿ‰;8ûϯþ hß±¯º4…ì껣ݦ.šóDhUè‹êÕKžUôf.ØÖ ²ïH بÁ¦6PgŒõ Z8­4³6Ê@LR€÷`0ÃbkiáË”œ¶ÿÝÄúß6¾»á{“íx}~coI-ïco±›ì+v&]!^‚Ç+ŽT¬î+ñ hÆšA,/ÙF§F²Xy}i§œ¡4(qê÷±.JÇfw2¢ Œ³/æ`³ØJ6ŸÀýñSõ°Öß¹€Ás‘›¬†Íç±E윈SîN‘‚Q,­K…uµR#h4˜C*Ìéô‚ºgP0!|Ï ¡t[ÇH@@¾"¿é¯ iVhÚIªøCëYzMèŠ^Kr±G`ªÂT£½o)KSý+z À/¼ž^Y¦Ý\æßQ¶Y€‡Må"ħââP\OˆÇxÎÜ3¨ãxgÏ o}p<æ6ƒÂGqRVnIÏ¯Þø‡ßocõlÅa<ðÛ¾ßåôaö_ö v㘠«Ø„… SÓðR<úüÈÁ5ìmvƒ}Î>ôà·Üù$™Î¾€K 6]Åq<âõ:íT©x@!r•‹% QºØˆ<„ª>øíã“êX]%ud¨ òñÕdŠÐO—s,ó!H±0E‘+»­4ÑÙ:)¹’ÇÞÎæáqrŽÐkU*ƒQM0Â&™:‘ÄŽ*ñAžî· º¡y=úŒz¬î›·ÊöäT˜oàñ‹áµ¹›2~àÅ$Üx¢ÕHø¯ŽÆ­°O±(£…}˜»ù^è»uudýÙP=9µ$ô –I> U5“bC8Xbuˆø`KÀ2ĦnûÙ:Iøî|³I¹WP‘ä.FÅóÄÀzAo³c™ 9 'Áç,¼ŸôØã°KiÀè3KéÓ2fR¶b„/¨ð%VgP1oÚôIÃPþÐÝRˆL÷í<~çÇ0ߥºŠ µ ØÕ@m4‚a6[´T4ª(£éÒœåá…aÙ4’|/z»á+•ië š "ò"wîóú†“°`»8œZD{(¶_Òƒã”3÷ ª9jì¤Ö?´#nEÒ“QtÎÌg[Ù»’ ÃÃq7ȉGÞúá?¿þòãB;ï`“@ÞÇá1¸šMaÛÙevçà ÈŸ³ÙyŦqãd}· Ü@¬(”FV›†+ j4‚(ZJƒ"îÓøÂ¦òI9EKƾ°­çƱ‹ìÆÞ:<‡´i7~ýþñ³Ç9Ý—ÿ%Bq«w¬Z¦Û%ÓÁ!7©µ€¡°T/ê]=ƒzN´‚1€ä»èt£9ˆ¶&©‡Å?¦Ë×âÁ¿°ëù¤Í·lYVƒKÉÿ PØîƒÏ9„t—RõÚ,j5QM8‡S­- êõ„Rà!¥Z"KÌݤ »L3ÎnâƒÔéÀnâUV`ÅËϲmìÂÍúÝ{Þü‚ mç}x}964™ _½råªge“r 6µ…DÁD+ë1VžKMÓ%R‡쪃£êf… ›8Or$µ…4Â+gKŠ]•ò‹DìLÄaÿøž5,ôɸº½W®þà5vñ¯‡ý÷,ÞPPU}ãO¸êäç]w¥µš?½÷ˆòÜžïíxõ½²µ½g<Ö{ÄCÙåÇ»gЍEÀ‚0>ªRCÄÖ‹ø“ƬV1¦:»ÉÒ:–Í•°l>i½ìCŽ‚î¸`3J ˜MX#bÑj1«(§‡‰ÂXú¢ÕÆl“$C6Šä]ìcö+¼®Õ½÷öïñ‡úÞa_ã亯¡øð»§ŽÐ#°üpïÈ5¥Ø€œ­2ŽR P_¸˜“û€w>ìpæåsºÃ¡v‡~ªÇeíRZ´S*d }_Ú´s‡Œ?Dºbo˜Ï%Õ¨\š¸X»ÁÀ«cÌŠÕŠyñ…wOä™Á²3Iº}Viþð2Vj7»bÏÅŽ¶ìëÝlNý·mq~,Ôck[·Õ£ž^ê|ÚöÜÖ,?ûø¦Ã¯ÑÙ ó6¿³âZ%Á¡¼jdà X8 H€“×ÜH`¨1üƒŒÍIˆ[¦Ôã¬ý1<O:ÈÚ“…¡¹¤ ½Iº†z£0ÝæÈ1RrÀÈñ„©| )ßD;…ÇÒ¤ ØG:âEGXÌ^æ:J®’« óCgI]¬Ô¯a¾"Ù>eœŠˆHä0§ÑòŠUÍbžfu8¹úàæŠ¬T2Ñ·~¥‰U܆UwÇüµì™,ËcrÀ `©¶ªRó„ Ø+Ó Z„ÂQ™ÌòñYv »Ù1áÎò;n >'ˆ/Â5S à}5S+ðï(ñÔ†þ_cÉîñ±c¸!²6E¬¿JD/hÃýk;Ýr}ÙíƒE¯Áâù‡økË”y²‰—óð'Á\ÇÔˆŠ*ÒH9d“„Z%Uãl|`þb[Æ/ÝÔ0–Ü 9壢›î•È5f)3†L4Kòõ â~7 I·±S ÆÕÜjÜÀ +Ä.Zð,¤½±‘j6ö€Äú}`1¨eRç-Ï%OkÅ]É=Qdï~Ð/ÛÑ¡÷nÑóÜ IP@jŠJ›˜èrYTb2¢Mì$Z-²ÛÅA°Š±ÅA޷藾ܑüÏ”š/§±á*¦Ýœš“×QÊdí6-w«Ê_zê¥7ˆõè䧪ÿä{èäˆwßd†Í®=ýÚ[ë¹{3îmºÍŸS1¯Uξ![eÝÆQ¢øÄôACîý`c+Ä&I¨[ Eãtºª£Én=ÒÙ-fX d+Bml}1Q;"‘"•⤠y¥ÐÊ&úòœárŽäȾÏÿýÃgÿÜAç™U«RÍø ®fSÝÆšn»Â~„×§ýÊ— 6¶hÞ˜]KßùöÛ3×.~ö±"ÓÆK¹ÁJ~d¤¦1NA°™`sÜŸñáüÈáÛ@\-[IÈ•ÈØÛì.Vÿ·ß¶Ö¾ü9ìÀKÛ«_˜déX‡­¸UŠs¹# xÿóök eÞº\>ÐÈ4êp'Nd0˜s²Ûb7`XGÕj ‘ÚD­ÅAêx0‰”ZGˆì8}Yþî‘ù™«¸%ݤžþ÷Ëÿþþ³k³ô"W»˜m«Û¸¹nõæMk^ÁiدV;ûõÁÇ»5ë=7Ï\¿ðñgpZ€>V‹Ú’b4N-¥`…ããœÚâ Ó‰Á&ËÐŒXÑYˆ/šl–ì–¼g¾Ý€iŠ º{óþþÅüß>ü>¤çߨýç? ܺ幭Òq™ ·Ä"Vãö×ãO¾Wº6ÍMÿ¾wÃÖWÞ%@ül’MªèØt:+!`6©Ý¡•ЀÓùâ U4RI+äZySˆ(ÎR(+ˆÆüù~“;ìÄ@²Ý¬}÷]<â‘ÊÌá݆=ÓPHÏôêЯõT%Í}¾‡Tð2— ´É@ù¨3šè”é*HÕ%uä³­ØÊ“Œ”ø¤T—¦K×x£ßè/ªÚ÷jRTF•QåÈÈ =‚Æ–E=‚-MŽ6=‚ޏ0ñÙ#· 3Ù#E[¯Äàör!WÚªJTÊnz$6iÜyÎÄ)‚¼9íÏD¹ìsñ­þv";sBé ·¼ÅþÆþqùæ³32 ÝûOüüô€îÌ\³ìâÙIÎL}fЂÿù¹ò®d|Œgj'Tý[gÖ¬<ôÖöÕ£WÇZËüexv?^ÿŽí. ž;1ØýqÚaúÌ[¿<|Ú>©ȺCÊ :o‡ÚáŒ1¨-®8h1iRÛ%SÞ±F´_²XfEˆÍaÍ›+ºí©z±¶V¥É>8ãìYrjÑsÇ> ½ZžÞ¿ ß£o}òKò»e, ¸en–êÊ›Ìz±$¨'F,IƇÑES©ä@£Ê³x@mm}AFËvíZfp%8½ÐŸWPŸsß[ÅlòÜ:ƒZV­V¯R¹b¦’ # 6">æjl³E¬Q ¨)zµÌaí»wíÛ³iEfs-¶õ„k¸kbÇÄ!‘Åš&MM(2ƒF£ÕªŽWqf Ä´&“JEE­•" V.RD¨0LV,ÅHÒ¥&,®ÈˆGžbÝðÕ³lîÜ]»T$»ã(<‹µ-%Âãl¬`k8“?]Y€µ)4ÁTAØ‚dJFl‰ˆá` RÆ ç@O<¨8à±›ÍÚâ¡-Rãv»ÅÅé]`q“\&«ò*»œ¶…7·@ |÷7XD‰D“l8%ÉHvFäCH2sóÚÚ)³¶¬ª]§ÊÚ3ã~ªì£³Ž¾AÎ.\xàÐéó/Ÿ†Nr%5eƒŽýÖÇ’Ì„åൡì@ ²IkS;ì:µÉâj2iŒ׿ÒꌖսÛ%0|G¦ž~O’Õ£ŸÉë>”UììHXS’%Èq­H‘[¬KãKf¢¦f. :Ç¡!~ɰ¢èþn$ûñöšožÆºÛ7°±áÍÝ/½ôê«/¿TKRÙOìÒó˜ü ÜR&ûÝýøoW/]¼¢Øúý`Ï*e¼Ý¨(ìÒr¢¨J²¨,)N‹ŒF{qÐhRUq(¾ÉØ5%IJ+Û{pÖŽ(2H\2øQN[rغÚÅNU nÒ_ÿõÃíÝ5dSÝŠ;lýʇ`…ÜšAeì3öÉÓëGÏ¥~{æÆûç¯*~ `Í—é¥Ä¦u™\ÉîØ8§1!1Ñ¡·ZE°ÿ&=*êÿ—U˜"ý5ͺ@"ùd„|dWÏvÎn¹UoÖV[U÷rƒu›ŒŸïÕs%ç&Έäµt:¬ÓìA¼’×òÖÆ¼¶8è0 TÝ(EY”Ù M›¶¹iÞpÿN³Ä–NÿæÃ¿>Õï`Å‚e“wlœ_ô×ã~µýË‹f>ÙzôŠwªqæÆÚî›Z¶y¸àÑN…ýïµhsÉân¥[u*ð÷x`Lºw‹ìæ‹Ar¤ê…֪ͦ-”‹qj¬&k !`2ŠÀ*1̪ØóÍ‚W…Cv©–éÂöÙ¥,Ãæ –Vå1qã3ØÛ[·ÇØÛC+õâ<½÷#Ëʺÿ“ÍÍ5A¢Ñ.бB®ä;7àÂVQ§ÓX5v‡N¯7©lFY·ÚH-å¾fª#1ˆD$Š6ãÞ Ú/ÖVǨ}g¼w†+ ‚#ú”îYóЀãÉy%V‘ò<kKý&¬Ñéy56Êáº/’{¸åÔÕ—g±ú0ÞΆ¸UfPi+?8À†Ã´3¿éæÇ}HÛ»GP8<0_Ý7a²J¥Í¶œ­·À¦âOxïÃdl¾ƒ:íÝEÝÎe¾KW>9×^†«HŠ‹ø³Àû’@ZŒU­×Ç:ÌDë°ò‰IºWLß Úå²"«©wЃø^÷7 4kWºßÓ1—öAáÃy«ÇïÁ uÇë:nZ9g.®eƒ:—Ò¸»wÏŸ>ýÿø³U}ž^Æ®Ìûbô’V›–gýtmîpà¼ÄŸ9XàœÜv %ôñ(Å€ -Ó“ìöTA$™]-²ææ{ó’—ËwŠ‚‹NÑ+yAÑ›Ÿ–N)]›ˆ PÕ娨Yä¢:;}r!Û ÉR4üÊô ¿ÈqÚœ{¿Ò!e£Ž¨k -Y…ŒÄ—+Q' ЩÈNÛçÅ·Üj··GÐmW›zÕ¨Ijœ¿Û/oÊk• Œ¯É©°¨dQÍÊóø˜„ÃLKô-­¸pjè‹#ü#÷ž1cΦ£5å¥ÿùÉ_Ÿíûvù¢åmŸ¾bQ—ÕϽ’]½ænýiú€êÔ–“ûÏ^šà]èkèP‘ßmýÄAËÓZ½lc絩­{÷hÓ®]fî i#ûŒïh-›üð”Bëh oìç tIÞ³J ²: ²Ä¸ŒÔ®1l~\!*LN=ýþÔ´üü´T?žëOMÍÏOMõóSsÛ´ÉÍÉÎÎ JuˆÑ÷n Ý”=~”9–×ë¤Æ¬¤$›Úèäó ²uI:‚,& ÑYt–¸LÕÇE¼±rFÁܼPi—’C®°Ù]Åò62g±ƒéó¤´òZ8_N K¤…„λxÞÂsÛŽ)~û£/Þzvf»ÇÖ¿‡‡¾/½ßf;?ºÀv¾3~n½wÎxm»¼ûì5γoÓî­Ÿ¶ÅÿðùÅŸ;Ìô±#ò=lçû§XíGð Ób—þ´§ïß&ÉV1µ‘©üÀ; åâBœc‡é&»ã5‹Ë¨‰ª·$ªŸ yWÊ„›)  é wâa©(îé1§Ú|9r5”Øb/6yÓË•kGËœVµ š•M9;rÊcÔ]1bÔØ±ãÎ[å^0~6ëplt}6Ç)õ½rTIëèq$ =JX©F›ÓªÕœ^à F¯’z“³~wr;ÕXÄ©ÊG90K*ŸÏbux)XɾÂI•l7ñâõÝÙN¶£^×ô5ì± |¢ñ(. #˜Ã‚ÈseA^*sGRÇðfšŸK¯nx:C?àªçѽ{‘þi‹€¤fx®Q®TaÉðyòwN Ò¥Wë,N!¿@g‚Ñ«Á¢²-IößJ,V‹õR&1¡9æŠ רxÐd«‡Ê›¤9ŽÿKàÈ¥ÇËF 2èßçöî ‹×b¾vóÝkÿ§È‘;zu^R6'‘Uâ‘l³€ú¿„ß»#@ü)¬y`ýŸîþÄéÛ. Ò먺_¢¬Æ#Öè# ”öVr©K÷î]Âg(R™ K-~)Ò0´`J¤ŽwƒÙ¬¢&”õAN´Ån¬RDš“ó}¢×o¬ñµnݾßCýž8)¿ž]1A=AÕ2/Óo>0Ý kô&¥ø+yo:9` ÂiXbš, D)_”)>ën‡‘O;”¯¬y‹»ò‡Ö’®r´6\¶í]Àï¿#ùöÔ€E::' ð튷±«%oóîf.>ê¼¥ÚäøžšÕ¯î^¿áå{tÜøÁƒÇ?6˜›¼ëðÑ/<´ó)ø™3s¦¼fø“ÝaªUs€ˆH4jἉ zÕ8óÊÝÍvWâ$öU%È*›¾ßÃC»³ñqM_Áôa¹È2yÑ%²!SDrÈ,¢OhBè0R¿N‰‚R¿_òm`ìÕðØ"eì×ÒØ´/Œ“4Ѐ±± nþ,Œ©ü Éw\CʼO„çÍTæ•Îi²Y´r­ÔRê WÙ=8Þï±qé(ëhB‚9--¹_0ÍdÖö š=ͲaC‡4h¤Q>ž&%N…!H~'ÜGef¤o¯³;ºž{ª¬fdûS§î óÆt®ŸÝ¾S—|)Yó=µ¶bB¯>£§¦µ]<üh]ñø`yÖÀC’pæâî]=2žr¿ª8Ý’†ZÈøu½÷6.Gª×‰‰OC™þ?3U)cb<æò(cî“Õ8æ â0Oj㘠(Æhê)i!ò7Ž”1&F…h>"÷ðl>èYQß@+HSÌ©tØÄóvÞ¦¶ ÖžAíÔèáScÒ`òlhj5PrÔÌL9ÿÃʉW_c—%õàÆNKi;N˜²„Øõýä(=:FB×I·»øøL¹57Ü|‰?&%¼æ‚½ÀŸ˜Ód˜Ÿ"DÆWî­“éÖ2LÿÃ2M°¾‰&÷™‰Š”1ö9uï®2&öþ1©c& ‹L[‚Ý´åÁØ­çi¥ÀÞVæá›æy„¾CÔ˜™÷2î‡ùÞ3>jÌ)öeŒ¥iX‹Èð(c&°Âð¸x@·²€×%r–=È1Ûí*N•¸(Šúd‹Ä×Ä â5ü†(rjµ©4¨¦œ½YçnX×î;èÛÔÊ+¥òr;o¸ÛÕ—Ì—È ½s6mÂðCøéƒ¡3ßâ9¬ê8©´ô’겞U³]$j¨a…Æ|‘,ãÙa_ó;>È}‚2mr£ÙЏà6Œ‚ÿn…‡±£ðp<| Û*å…sï½Ãç­ƒ 4בäLäâmñ8\#¯’‚-G¢Û¥w÷ -*ž£&=G]=ƒ´ž]½ÿàr<Ý„ÜJ¥Dî&–+(ÔäÅùŒ¢S:2îµüní˜'? u^Ü:âÉ 'ê'…†OßÿŸ_¼cÈÖ »#m—£—÷Ût?!õ]\¶ö}¶›65ô.—š ÙMôµžr{!ÐUîi“ùSæs±" Ö&Úß?f&º Œ‰{ð˜Sh®2&ùþ1©c&  a]òFÛMnŽ3S¾ÞæA×O}._÷5»ÎÑxýÌ›p?©ñú„¯‘¬ÝíÌŠv7ÁXÕ8æô/ʘ–‘1 §0FöîÒQ.jF|¨…¹mËŵ-Œ‰Ij«E|‡Žq­½­‹ƒ®l.»G° …×Ìq†¯Ã¯2¨Šƒ6ƒ E\äÝþðÑÐûM²¥0•áèæ/§¼A›€ÝwdÍ•†Ê…¬4ë ý•™1ë…—rKÏŒ\ðrºϤÿuUávn­°n »6÷¡S‹^zcßÄ«vo;º‹¾9{©–ˆÏ⬯«”†±tÿ#Ãgÿýr"«ôxצ¹oΛP·~XðÕM£DÕ$§vÛ–ÝŠžOg6©7 hW¬øv\¬ü]êI’ùV¢ðý Ì—ø_î¿>³¯|½Åƒ®ŸúE¾žÞìºÌWåú³¶M|½÷WP¨Qòo‡ýùCÉþÜÜh;^Åω3ó^²2Fß8æžäóûG9Å^QÆXšÆÜ‚1I2AéÌOóò`î½ùÙØ[¨¤ßÊž(7’ÝýåKv‹ûz´ªð<û¡çÍÁC»o{»÷… /ï®ßÂ^{mçk;ˆ}Ë>Æú¯o`a6÷Ù[›¯ê”]Ù³×óg­dÓØ?ÖÔ± ¯>+ÑNîÁuï!E÷ 2U£y4R¦[¹"ŸÈ<Œ}Ðõ™äë)º~JžŸx›]—×W®Ÿùáî—y¢\Ÿ§ÈH›(½‡¸tn·\‰C¾@ŒC£1q„ÃÒ>ŽÕŠE½Kç!±”1ƒîJe±¬¨ ’ð‘Èf‡E›¾£'CûÚçå¶kïËíù$ËŸžý£CÇ¢v…"òSø @0ýÞ1n$·8 ô ¤;“âm6Mü}€«¸10Qw1Žÿ†E$„·Rx›|®äÉý(›¦TL:ënošQQ9b^Û~|±×´—jÉzËê1õ¥W•î”î•}nÀHjPé=«wÕ†ßöŒ%‹üŸ}²kth®ïª$ò>¾Ì» ïß•eÃáÍý×gNm.;÷_?e‘¯{š]—y«\ŸàV´-#Ê®ËûÐòƒ•5”9’­ ÷ÒÈ=o)¨S )Yˆ³™LfÁÜÂcAæ8CMÕ‰ÅAµƒ:A›5Àþ®·GÚg¤Ói„K 7Ó$›sÓðÀ.u.ÿÃg_>¥ãTµµ.Ù½lªÃYki}°û„ýW"펔>E̯B¬Mî ¸#gÓ¿=ƒ÷_¾Ø„Œ³‚Ï„ƒ ΙòîûâJû¾x.ÜAwߌ ŸÛ¾åÏ#JBÚÄF«5éÍ Ÿì6Z æ4"­òD- Ÿå‰ë¤dm:Õ¬#2ú`›’< ‘ÃlΦ 2r~Ñœ&|Bc³7Ø‹x0ŒD !ÐðÐÒ§¡ÛoìÆ¿Ly䮯ð8¼È©$–ÜVv]‘Nµ¸¹ÊÄÈ3tÄ$nJD}ô´NRˆÃ‘še·Ç§ª¸_fKmKˆœÅA´mÚðf­)&…O)"ÞÑÌ3[$ ÛÌ-‡}2¯xÜHoñý9º¹+UñÄ| »:·ÓÅêkì',|·ð|§v'ž9{;äUáÒ¡;¸á®{Ã+/mÜürí:®Ç¼U:’üœí»³p6VAŽÑjÖ´)³Ù/_g³À{“IᥫŸ^üâÓÏ?ßµmÛ.©ý˜»B÷?1H½ò"2µÜ³ië*6¼w.€Bh÷H‡i=X7o¬³ÖñÄÜY«–<<û~ɳéU œù åÊç—ðd˜³µPÙ³:¥n¦¶S˜øƒÌÄÜÆ]ë<ÚzÎØ1OÎ=æéÇ»ø|]:æv挜U9räôYC :v,€·$«Xk}Ï!÷À1.3âu}ëìr÷ƒ¨G7)½mˆT0öH„O$R…ÈgÀÔ–YÞ¯gJŽÏ0R?ýÑ6ú–$g·5ŽÒO宦¶NíÐqv5|´ï4;|F½ÍÂÏŸA„ãïþL9Üøü+þϱbÓX=‰»Éç,‡0¯R#.ò#i°7Oz‘˜ªsŒ,˜Ó%•žt Â:à-úݽÃ\¤^žËˆb:ë՜ɌTT×ø693ôæY}0±; ®1<5'±½>t¹ ÆËX5]kôü&i~µ,ŒÙ¢çM̾Óó‡¡v7>(>ñb†Ìí¢oBÄñ(ûù©Ñ8wˆSºØo¤݆(êC„î äɽ¾Dæq‹KüÄ ‰xœc`d```”œe¤öZ1žßæ+ƒ<œ|{#Fÿ«ü'À¾Ž½Èå``‰o× zxœc`d`àèý»H2ü«üW;Ž(‚®”ÏÀxœm’Od\QÆ¿wïyTUC¤Q1¢²1²ˆ1†¨*í"FeU£bÔbŒQctQ³È2Bd•EDµ»G¨ªÈ¦bÌ¢jÄ(¥«.¢TUU#òúÛIM#Ÿsï¹÷ÜûÎ÷Ý?IF™Æ¶GÛŸEV6ñ<ØBÅÿˆºw„¶)¡HòRÅ2×*ÞoÌ&˜4¶Í¤˜{LH™”È,i“'Ãy…TÝþ4 ÃùS¶†É0ƒ5ÿ*àÏ¡ë¡å÷Ñ•Is~Ìù º&G¦“Gò•ùtÃtƒˆäÐ’Þ0þäZUYÅ5Ö½•w@XÁ¤ì ’&{Ý`»xÁgÌÊ22v+9•o÷•ä±ý€cCZh˜×¸!+˜á± °k‚dC²n‡uÄš—¾Ûk½Íúû<Æ×öÄÁÆ%Ã3"{ˆ¢¨cÅûÎxWû?מãC¢Ú4É”îaÿMþÛ|ðeÓÇ;@ÑÕP{Í ’]Å3—ë CÒ®—_ˆý<ꪷ×ÃMæï[`‘õKA÷È-rÚgî—œ&gê…óaúà“}“K::ö;˜;÷á"ú4ª£8/¾ð¼uSÝ/!øŒ’ó¢õ?ôàõŸO¾Éêÿ|¸ˆ¾3êÅ(ôÂyÆè¼\A+\ç9Þõ«1F#â=Ä„Cßü{L(6O öL渚%ïÊÙ5NÉþ¨—ÍŸxœ%Ù»o$gvðÞ@I9˜mÀc›"MK­¨)’Ž4-R-‰lÚÿƒãÍúiÚ»I£_h>Š˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€2Xà\ÎLf’¾ú&DZ|–ØD¢ä0ް ~´è2Rª2rÎ H ~ ¬ ü . D l œ º ø 0 v ´  V ª Î  * n ž Æ ò0TvŒ¬^šî<|N|ºøh¢ä:ŽÂT’º6pœÞö<vv¨ôF”èŠÀ<ŠÆäìvŒÄâlŒÌüPx²ê,Šœ®ÀÒäð>J\n€’¤¶ÈÚ2DVhzŒžÌ 8 J \ n € ’ Ô!y\×7«ô˜~z\£å íñÝ ^yÖ*évÂZa3¬ck®°Í,Kú’­g:Ï´0*Kú |,ŒvÁ™RS.S¶+RÀ¼KhˆüÂözG&þhÃ/rq1vè:Öe.FkˆVˆ·]°÷ \D2¥fuv–Š­ U?fÍ0üWI{.aá/oI¹#¦=© ܉5ys‚äEÉpU™ÊíV ãšk¯5p—>‚-£ƒKbwyæ¼Æxî;«v ³lÆÕYʯ\¶ÈYì”çC´F;ß{t&ha%=ïŒ*˜`F‹X„>bÙÁ©"Ù@ŒÙ¾dZ&ª0RcTÊ"©Àóp¨U«ÈJ]ð«T»z¢Îš˜rÃjà¼J |GîËv‘4ò”Ü¡<©gL¾ÚhŒF#.Ûd¶sÌ3W®}¢æËˆ‰[ ßB,²ÄbK-·ÌEû­´Â*«}òÅ%/tÊ+o¼vÚç]pÃYçÜ´ÁU×\…CIÉñÜœ´´ôŒ”h~$ˆeEƒHjv4Äây‘ '„3ãAô/¸¬kTxœM‹»NÃ@Ew¼N¢Tcˆ°ˆÀópšíXúD)L‚x˜‘âDJEOaSCƒ”&ˆ–¯ðºË_ð!|‚q¨8ÅÕ=ºº£ÏîÑ$âB¦‰d ÃaX†òÚ èÊh2ILƒsc}Êý^M·¦¶¬érªiÚl=½Ë-ìêæ-åP–R^$}úNàDó¡>`_ïñ {ñÂ/tktÚ-øI¼ˆRü×ðêC 6ðQ=¤J™M§¾7¶{»°°²qºÍÑÝܶWVð|1«Þ³·õZŒcÏÒ™‚ÌØÇ¦xAå‹q–çJ-óâYm)T^¨ÿüéþòq;Atomcat-connectors-1.2.50-src/xdocs/images/fonts/OpenSans700italic.woff0000644000000000000020000005130014655113617024067 0ustar rootbinwOFFRÀ‡ÀFFTMl\Ú¢OS/2ˆ]`¢x¹cmapèh²ŒèÜ™cvt Pb¬gifpgm´´à»s¤ugasph glyft2‰Iì|«„ohead;46øåÂhhea;4!$xËhmtx;XX™þ0kern=l# – locaK€®®s„aÞmaxpM0 VnameMPþ~^ØkÔpostPPyò‚léÕprepQÌôâ¯ɉo1ÉcIÉíØRxœc`fñgÚÃÀÊÀÁ:‹Õ˜QB3_dHcb```âæ`cfeabbyÀÀôÞA!(¨Ä †ŽÁÎ Š kØäÿ‰0´pô2E(00ÎɱınR@.{ö Ìxœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@,q ¢ Õ ÿ߀xòŸˆêý3åÿëùÿŸÿÛÿÿ%ƒÌ¿= dõ”á#£6Ãe†ãŒL@63¼e¸Ï°‰1ä_¢ò#ßxœUÏOGžY 0d¦ê2Û‰]vI•´Jaj{»nZŒAš%=ì‚A¦§œrˆZÉ= ôy›\LN¹öÐÿ!‡öVŽÉ5}oÖ&$R¥®Ö»ó¾÷sÞûv¬î?Ü õîNg»½õÃ÷¾k}Ûlܯµjåµ¹ñõúWk«+_~ñùgw–?-—>)nËý[ó7òîµ¹Ù™é©ìäÄxfÌá¬$€GŒD¾Ë@ÆrIó½Z¹Èz"€¯LQ6’1ˆH@_ñ8…–GïYªÔR]ZrW¬³uJ!üY“bÀ÷Ú׿×d(à®Øu¦h…Y|=lUT­ þ¸g‚käÉÌtUV§Ë%–LÏàrW° %|aƒÛ…³¬%ËÎRZÜiwa«­ƒšçûa¹Ô„9Y³*Vµ!a¢ “6¤8¦ÒÙ©HJ/ÌÙÀeûÑR®+»ñÆbô5c1¿A~ e Ÿü5;?„’¬°DQ[Û—yZoSr/¸R˜W ·#/þy‰‡ÈDÁ}Åh Nø¶öéòêØkcêRÔMdâÁ›þ¾®4I.gØn¶¥1ÄàÍóSêg!¸Q¯…í׷[ðAû¡§P½¼7¥¿âùùK›­ÿR3l 6;ìûÔ†Óbû(@¿­SY°}ï)SËK!8i^Œ4î’¦?Ò\ºGgÛêh™B³+ìøi ý}d×O4éÂÜkÏ—æz^¬.‡ÖV`UÍî±€ñ"6 ½®: oÈŸV˜{¾.O]ZÊPö¨-M{£ö؉ ›aç3œëÎ;Ò•fa›˜ê‘@Í„ú’wµ¹pßÊ—bã=us¤&+[CÁå0 ÃÊ›Àˆîj%ïÙsƒ#ñœ.rÆ2Æ$J[ˆÂÈf×ÈŽ^·Öxöüâ=¡\×Y‹·v*僕Dò“v¢øIgOŸ»Œ‰“ýÔáN5ª„ÉmÔésÁ˜²¨C($(Ò6 Ykï+ÆúV›±€•œY,;Â8;8)榉Š6‘bj2©F¬3ˆeS¬o1{%ŒZ¦¦ÇUVM©œ3ëx 'è)"Ï9cSœ=ËñYî%èµmáï'SÊK-úh¡Ò OvߦÞÝÓÏr ÝìUèBºÌ÷pØøˆ.åç°g¢>6vGƒ7.7pLr ™ÈÁ´<¬ÀŒ¬¾IøfŠO>‰å79º÷qö[À‰µŸ¤øèϸ4© ãþ]þ##2¿ ÿÿxœ…| \”ÅÿÿÌ3ϱ»,{ÃròŠˆ ¬xÀŠÜ"""²Šf’ᙚ©©©y•ššš™j™å]™’_3óg¦Vv§eå×”þ3óìZý¿/ÝCŸyf>ó9ÞŸc>϶^çæ M-ˆt´0rJ¡/‡|¥—¯?Hé†ÔøÃ+ºC«Ñ“Rì‰þ~&Ñ çÿö",q/Ÿ02³x¢+¯^Ggï¾[þHAÖÐGúÀÑ6ô6›_¾{ENB¤ÛO'’©™‹¼¸¨µÇr¸kNæ Mî_9}@ï@H&÷ƒpÐ˦à}|B &hµ~†î§Ó4•ÙˆD•Ìšn7¤¦ÆÇWêív»žý¥/²’d‘èJVúrXäe´#;}I‚ÝaåÕY3â “¿˜r¤î¤è—Ýb€–i§œœ|aòMƒ[<žu ~ƒkéëÌ÷gá<ž¾Î~ÿ= »³·.à«DQ ôsFÅ«£xÑ/:È/h Ëàî#ú¹§Î”+ˆHô#ºšHgëíºÓ±±z@Èeïs*¡Ú$j¡ÕmÓû›Ý`rRJ:´Kþf)Ú†Â8˜Fþ‡|Ó@?“™WÝ»e{¶ëÙå'Îäly_±.²l›]ýôÄô9³2pnza‚Õ–UÝAòCu>TMPÁŒ>{Ÿxí¼vÍÿÌïû*ñyûÈÙØ­ÌMëÖKÃõ‘2{Œ 2@]ë q©p (™ÈÁ’Aœ3 ¤»ÚíÁBºj4AÁbPð“"»2¤Se©´ëéÙE$çg²'’“Ì&ŽjLr’ªO´Bc$¥ÞžH·rÿUNLÑ£ïðÛz|ÑÒÚ·g.XÅ]¾wüWÞ™jËíæˆÉÿó‘ƒ3ž[V}艫ø»¸uUŸ«ªÙ†¯.ß¾îúܦEw‰:µ´5ëèµ——àï—ã¿Rg×à“ûa‘}BaßÒ^ܤ^ãz§Ú+óºU©qQÌΔµ±Ó²…1ë’ Ðqùø Ê%ã|€êM„T6žžÐݨ#Ú®‚zÑÊåÿ [ÿœòã*séÐÿè~¿‹?Æ_A™£µäªÉ*2‡ñòPÇ! ÐëÝÀUßiÅwáï“X…ÊñN÷{ø/ÎÂ͇vŽïvqü|1 h­¢xh’¢Œ’´ÅA‡`DS&Á9¼{ÓíòãÍЈß.…ÅáÞŠcñž<8ÿ¸õNÅ/»á$2_ ¸ÃGñ{Èž¢œ>J òZŽÒŠGÑ{è º‰â+'@H¤ÈcI¶èíz‹ŸEo…—ðr8ñ¬ÅË.q£/ÁIxé%¼’âl]ïÀÙઑŸ@|!4Ê,JÖ#œ¡˜úܵüé7Ì­W·ÃŒ·1pWÍm&2P¼AþOÔßè°H1Éœ:î¸{—Ž!x gÂTB«ú-%*q))À&twtÀÔ@/˜Öµá(lÝF”ö6“/•g`óÇï0^ýíî'xòκ)ŸÂyïÕŽ!û"+£ëL'tM¼•"  ˜‘S(Ù Ûƒ›÷Zc”ãÿ3—Kù õY;_Q8ç¬ùÝ ŸO°&„9µ Ô) ]: ºèdŒp½°ÐkT’- 2Ö‘? ZÖ’ /ï]Pœ•±hÌò§}êЗÅ[àß¹çáŽï•ôØoÈ©GG{iÂÁƒk¾¤ú 4„_Ed]‚nÎd0r© / ð±D…tEI>ú.ŸÀDPè!‡ µäF¬]ä­‘6}¡'%9Ébu°OB¤‡F¾èÝísæ¯Ä?¿{seÉ±Ê ;1^Ø-oûû¥…óÖ5 åƒ^š1÷?SBŸD{ä]—Ÿ˜Ø/ôǃú¾EdÛúáQ㳑h»A‡$(…"—¨4‘$"™ëñv#¡ÔY‘Åhq@ ²[š¬¢y~g:¾”înìŽ8è8º'ôT÷Ј֑ø$ŒÇgaüèÅ–ñwz~jMŸŠŸ¥< &<GÖ ÑN0¹Ìæ B1ß.é~ÞPcêLBX;#ˆË· ®vß§KñÃSNõÙݸ~w]͘ÚqÍÜïl.ËEëÏìß~w~7+ô}hÉÌáÃ-…Üe|_Ò2Ý.#tÌ&º¢‰'2ûšuºˆ"—NgÕ@— ™‰·5?@Œ,%cRìdO$þ“j]¶7ætu °Ë?»6ײ—L8r3ƒ¯;öâ«KnnøôsøöCõý²z×dÁóÁ90ø¹àÛŸÿ²íÈžWð•%X:¸$gHÎôÑÃÆ1]…DN‡ ¿D ßWèB¢LUqžD ,䮹õ@Í1nßù#÷ÔĺdcÈþÌÀ â@„Sã @§A. ù† rùvÜn"Ó;‰é?õDº(âˆÒ Ñã|èÆŒÔó˜é7îìÌ#_Z}±á§>ûV¼<ù ÅäÇF©¬É )(Ÿy` pºdí¨y'“_}üpõ;a—YOoŸöθ–¦¸'† 1aHÞnceÞÓY¹«2 ‰,J ­™L6¯,,T¼™IAâ•]ü?Ê‚8 f*þÔùl÷üB¤‡rfß|æ ÜtcÖ£µ“g¼V×…¯Ý¿åÍå··œ:‡ûö}ØÑ?³÷Ø>9èü=Š ð;êÍš›¶Aó‚Û\Ésƒ†ºòF”T˱$sø:‚‰fЉHYâB:?m‰ËÏ¿ @uøÞ\;’çöiu©¿`kˆÀüœJ4KPéJ\*[ >è qÌwX:Ng3?CwzW¹À< wȳ„¬O5à%2·ß>]â úÄSF¢F23L†~JÈGµä¢ýîznÎ)Ø´þú+>Š¿£û¯›‰,vêäÃ/4W„›/0ïx‚øFc²Å’W ÚOgB¶‹ñÌK— !È©¢I !ðP&CÏþ ””XÃÍq×Ó9àÛ$Œèó+Ö-Åù„Žm­×Ñ †ñÑ “Ó¨%¡=É7ˆ†+µ|§°W'8ìmÅ,ª ëS¼P¯!VG.òcÍÔ'úÍMœ´¬âÛ oœI}ägßμiâˆÌAËòIfR8vå ’Òäi™—ë_qðÜIÃb{gåã%Ã&P ÈzRÑš-'vÛd‚Dg Â'ÕpSƒœ¼ÓçWhð1øt¶¤ Î݈wïnèíä­Œ(6«lL§Í¨=Ì%(Ã_ ˆe:üÈÈNuÁ–Ц÷FG´x|Ö׋Ë&éÄÄ'K–Ìÿuå%Õ>ºž“³þûó)|`TßšrzÚ·?]ćvþß…Fâ «ÝaÅ y q‹sS;¡Ü×ðçÛdÈÞ¸zDk¸¢k߈ÌYŸM8í ÞñÅïø—ÎÝÞ.ö8ÍpïñÛc_uõ͇ê¹Ö¹» ‰¦ñ8µjÄkaK«å%dàIhÉ„ãµd‚çÎ|`t(’ì.Ûvá÷9 §¬ÀlAª®} ¼U8x7“«‚Ãç<Þiú<ÜÀbðd²Îׄ×Zb“áÔ÷Šá:]ø—ZG|¯N§ÑjÍdY¤ (pi ÿæ{™Èî—ÐÈ0/"ï§éúÛÖž†Ïà[îÛ0yߪ3v®ýhû^š¶l^}4B Z<ñú#¿;rØ‚–ÜÉc7]ŸIòÃ6‚FPà2òj©À¥6¶GPިɡ'‚$‘/ ¥IzÖ ¢OŸ›µ`õò÷O~ˆñ·ŸÀНêÔN­^ÈŸÚŒ¿µ}óÜ2ÆBáëq½ïöŠ–uðCˆ%üPßNV . Æ—`è·ä$P×È…Øcxq îC ïY’uØZ.­üâ‰eÏÔ}„l|ès¡ Õ2n-´ZÿRK®Œ'”÷/°< ›3PT’‰„éÔ¦9¡ÀÅ!¨*pÁ¿3Æ^fÓì…Æ´4Ãd”˜‚A?xÙ­E ‹á÷0žïYc-ÛO¨SK×EäùÛÊ ÷M Ç`:a·Ì„{`m¾Û#"P„øCP« ‡Ô¼H8dü[üa!fgðÈ…ŠÅÚ&0£…»ÅÙ7Ï»> »ñ·ŸÁ§ñÿ½_—¿rèºß,[]0<ÿ‰’Ýb7 Œ&¶¥†oüôнÎÝ·áÓoìz)Æzù'leü sê¨ÀU € … ¼µˆx™_Ff"4ãkñ™y8fÝ$Lœ/Ì€ Ü4÷¢{G¹>Þy¹ ž8" Çù$` 7ô€ øæ“qø.æÉ8__ü$<%ƒ'¾@‘¶dêûIÌGÔaþðʲ‚‡f†À(rÿÙ¤ÿââ`·iÆaôÝI^½o/j`uêÔ‡||DD6Ó¶’ôRt§tCHb¢ÓóSðîsõ5ò†Ön€ëàx÷n®(ÛMrwÆiø›;³MßÕ7ÐKöE â!2]2¢•˜AŠÐt/¿´Ý'™È}FèTû(ŒHõHÅë(]”É´RBÓ É1¬d«È1@BÙœ nǧð÷Ë’“÷Iü]Þ'eþ…¬²2Nâ³îæs{ÿ{äÞ ¾¦ åV’Eß‘×éz:æÁ}Z%‚жâÓU«$2@{ŠÈô Þ‰_ùˆÈelò‡a ¯NY |qÄç;Ý$V¿wªqͲS=^KôØS÷Ѹ|xÞ¯C‘ÁcãÍQ÷egÂÚxÇÕV€¯€߀VàþdÆGusgÌ8ùèSh'¾Žû~mY”ðÝøjØ>üþ;+Vï†i'–<ïÁ~ÙŸDØO¬RMM­Öj Z‰BmG«„LÀb¥ûMôçT=–l9šÏ9ñkø³RYêÅ·î qáä½»~ÿ¸ Šž÷ì“@>ݧ„‹S'H=AqIAs‰î•ä'¬¤¢;Áv,Ñbà¿núÏO1^×ôïû>†-£ð4˜û¿ö¾‹ì]ü ŠJ5P @¢öó1¨„¨=öðº9„Ž…>q€ú¢eœ¡pÎòcòLc<ûËm/@ïmFqM).vÏp7 MßðµÃ½‚K`µ–“Ÿ"FJbzŸ0äï\àòçYˆéMÞØ˜,Ý ÚhíæræB¸bƒ¨î¾<ÿðË>œøÐÂGŸ¸¾êâÞšž\Q7c:Üsö÷rhxdH~lßùytö©Iý_žßgXÿ¢ÃÌ®v^œezàïTAƒ„xb’Ô¹Ër‘q‹"× 7c¼Én9ðF~/ä0¦÷/&z¼žÜo&§Ò¤B¼®]…iÙq¬¾D°‰4úIq…õ¦àŸþ®=Žèßù\Ä¡©¥߯·¾>’›žoŸoo\·­¢kì'¸4‰aœ®ÉW$¨#äàƒÌÏÀ‚ª¿Ÿ(qæÂ¸öv›pc´Ùyއ±—ÓУ¬ø\\ÙØxÏ|Òwd¾0Š%ª0#âÍZñ²yËX™|-F"g; < ’˜H®(/fKr ݲðA¼;†‹ Qô/×ÂIPã§cË`>LvÏÀÛü9Ý]¾Î@–þ*éV²ó‡PdoY³üÉÙ_ :g•eËõŽEd3˜ pª>ÇóJ‚¹z9liÇb¤X;¿µ OÆ;9ç è\'À2÷.Ü}káÞvßåDw¬Œ™o“yÓ™ž›*’*JHððŽUÄ•ò¤Dºup*,u¯ž†ÏNûö@c¸¢–î³\<š/Óx”èÉæÃ;9 /ÈòÌOtHÞù%;´:Èç¡õB¼ˆçà˜IBɹ¿DÆ;§àmÂ!’ãøîO•Ó‰´z@(²"ÞOXý®ìÆ9jjÉçf¸ç³ýd“õÖ·æºÔ{9!rùÛâ°p3[N…¡|ðYòÿ-üE´M´Ù¨ÅYP®)B+1ód‹¿mÛŸ3¿ttÈ_Ìz%Ëo%ír‚H^iF½V­•‚r\’s\À_ëG¸Ð^ &Ô mù´Ùî°#+I±mÞüƒåpõŠWžûñÙ‘‹mŠÔïo\×ðóúeÍ*ž93¯Ÿéüû'àØã%EKïm^öòïó®/Ë©|îçÉee”–(Z‰Õ ˆuú«ô*½D Tíü):)„åß^.O׳ɧÓÜÈf•¨Ÿfæ%uLöQÜòWž¹ñÜ‘bEÏïˆ-Å¥ÅÄ* gÇe>Q”ß·ßãýùºÏÂ/~²e©hÂW›¦ŒÊýã©ïæU-ümÊ"7Â#t‹ðˆÅë’/cމ2§Í«Ê<—V×Y³¾ïøùFŒí_ÉWl‹IÊ8úµ*ئ0ø5L?wuÍÓcVt/ÍŸðdùÉÌ÷6hJ3êÊ‹m]4èƒuuÓÖM™Bq-Šàx ÑÙ@âÔè|L&1ÇeÒ©ôñ£ÀØŽßÆ¹ÔB#> ¤VÊô@Bgñ¹ºG*VÇŽÂç¨}ÚºôU¤­½p™[œiŸùÍÇ8A4½uäÓ•ÛŸÏ›À°‚¼-&kª€‰'Ræ¹ðÕª©u°8·½€Cc ˜1bh^AYÅ>÷ ŒFu¥õ,zèž™ÎtßÁ&ŽX?ñ—þ È©Ñúå¹´@qŸæÐi=CmŒëPÒ+'ª’¼ “vÃÿPæYŠiÈN~ç½¼X*’^~ýJÖÒ’XÁW#߬P å2»ô,V°?êI†¨B¢µ° k`(Þ³oz¾Ì¤• ¿žŽîõpk.Þ*šÜù1c€w î²õeÄgø1_F“aX,ß-š¼ãÄóDO£iÅ? ³¯ÅÏÔŠ@©%·%ÊQ›]ÎQ`¢¹]l–vvøf'A *¸+fÿÌRó\|n¡nTŪ®UTÈ£d!ÿò­Ÿ¸œ¯ûfâÔk ƹç01_=ƒãÛäÍoþÆ«[„>ª[½žè–^§Öþt‹ðŠÅÖ<ÛQ§èL¡dl+a5\†òf.ÇeÖéCÚQ&YÛN•£L´ÊìÅ2µ´ÿ´þ«ûOïããÛûŽþ°jÞ:ö ·ÿøã?טyiö9üö›?=ìû™ê[ëA‚ãÈzÔל×iµÁ*ƒ<>Žù»Ž‘{ EÚNlVfDt£æýÜ‚KO·+Ôá¹DÐ¥ßê• {f6 ðø¹ ‡ßÛó]ŸÁ»Äüïý1ÿÚ3?Gx@hÚÀxÝÉã{¾Z]°‚x…Çû<à}©ï¡(Ô@ ­¹?à{üáü²g tnOœö\|ROEî’>Ά<æ|òL#šfÑÀ ¿ké_MÿwóÀð‚ߟýrs>46`z€vÚ´4'ðU @§òó¡ê™ž¨—ÕEwÔ¿ü^QqŽÉ¯GUË‚_Á×ùà/uû^Åj¦YtN3ñë›Èœ‘4oR‡"?¿ l—Ÿ)³]ÈÿÁ¼‰±=ÙsìaóBoÇ´©Ï__Nؘõâæ¢1ùÃgT]>ýáæ‡žšší,›9N:øa˜õNyß±™I™ó+v¾3âB‰=ÖÖ+.]>à -µB œ7jõN“F¯7e»ôZ丄6rhGP€Ž'²*/˃ˆû²³FB ÇõYûüêÅ꺵¡Çž>’ƒñ·uâëµä'ŸNLã‚W”ü|ãºûz˜9Ÿ¬[Kô¾‘€ ?vújõ* eæïë 3䔨=Ѳ°ˆO^—¤Ãqó‚q”ËËþ³py?Ü]Ç 6ßÛÜüõË/TN—÷H ‰_JÖò!9—ɹ´¢ß?å\ð¤# ÆÀ~î­øÝ…Ð'Á¸uÙ\ñ½Íd⦹£ä¹ê n5‘¹X¾ŒJ$ó~ZAÛ¡vCkÆtJŸi¡\OÒ-9>² ’n•¥õù´Ã@ž—xQWоƒ¹*1$Ïÿ´»oà&Q…*»¿&«ßþª)ö[ž p¿äù¢OáÍ{›9ÅóäØã²¯­l_$×RŠñ><Ô*d„ò‚,Ádƒ4—°À™×`ߺ?à(÷~»ž¸žÍ\΂a¡»ÙMlï”ç­#ö¸ŒÉ&ÀéÃû+Ö×ãòõ¸#;ë  ““IÈY<áL:m=4¢‰À"sÜeoà3å©™ÝKR‚ï>þª}Á.è‡÷õ­z8¬u–Ø×I²V{.–í´,ËvQ÷ñ¹˜ƒæbÜÏ-×­\:®³s7bÝÁ}{¹Ã?|àLæ¼Cò°Ñ$O²ÝRsÈh W«U(,\N—ôž|јduPÅJƒ½ D¢䩸k!5,»Sµt˜òáÙ¸Çû÷‰~û’„òAÚŒ¸ï† Öv’úõLÞþ脾éÏ^<†î\të›/4‡*‚&vÍj 1§tþªaFjæþ,’#$.f³¨a½,xúCìz+½¿«1wŽ6P?Õ„sQD/hŸÅ©Ä-±35_¹…O+Ÿ?zÔŒvâ•Lž¶%²rÓ­ xWKO)ÏÌ o‰2+&d©É—íx+ÁŸ^Â)·kÕ†"—RíTIa]\ØþÖ÷ßÒsÃ` Sl"Uú Ó‰4ݲ:d¯ãéZ£9×–IH\úÁ„y ë¿[k9h:¡"y\ÆÜmåÅýŸÊzf‹é?>Øpf~hÞ°AcÿÖ‰¿:\UE²¯¥ls[¾(œ!ôÔYm¦íʀ a  Hm¡Ëp_~Ú!˜òä†%‘98yV‡Ý‘Ѹ£»'-®ê_eЇ±qø¼¡Ëvn©£%<áXwÿ÷ãÞOˆ¹%œ.ý>s`åõ/JŽöÇ-·»>î‹ÿo&>¹`ÞÊïdýqÝœf£.ˆS+…äç.i£Â£Ò£FD5D½Õu3JE+'å&?c’Ãæ0S/å0ÓC|É,ÑŽ2›dsD;¼ø„äC)³W4 «?¬aõìääúå #®+©_ÖÒ\S4¨vÒÀÂZîܘ +’³—ÎvMœPQ¿¬ÞnŸ¹¬¾rÜ€Ú‰…E•eIµ "vãÒœ¢Áh(v‘Ö•ȨUi´šb—¤Õª¡Ÿ¨ðõ1öèŽõ!d§Ê̤%$’‚IôE[*íô…,\¬ƒ,ž²µ„´DµÄãËñä#´Åvì}ƒÆq…n¿Æ…—/“7î'Àu°u è›x‰Z|¼§j@¬^ï±|jû-gqCËYš[˜ˆNòb è’i.k4'tC5JêߎéÆ)•= (›Yׄ5²c° ÷ë™iL´zÄ„.=~<¶kWñŠùÏ zëptRË¥ŸÞõÚCÃ2†O™GÛÓ†ŽNHæî¸VfF>œºêÕ²Ã%Õ±¶êãë¬÷|é@ÿ«ã³Smýº¥®„ÉÃRR†t ѽ†Ð ówøl‘'nš½¾ ÞÎNÎY:ÄÈŠjÏZàâ!æχËK ûf4_SXôHÞP"ÒIyCÙ9j}ëÏb±O‚†) Ç™€ƒÎð¨a–á9ÃUïÉ`‰Tµêpuƒz©z£ú¦ºU-©ÕV{0k5¶XMb›“dhj3W/XBMó?\wâ&oOìdHNâ:ÑÃm´µv\í¸Ø9½æÌ9öåOŸ,YÒÿ±–'?€Ã?: +OÇ[Ï4ãÍGo¡[¶Ã —^Â×·mÅ_oF·–/ž·0<ä½Ô??»Ö’»»'þÞsoüð$Þúq3,?±»u ܲn{Kt`-÷+ªN=A‚§J¥•4à …“Ýû4ñ˜œ EF{Êç÷WÂXL'}¬býèé½EÛú ë\QB\arYÞÃܯÏΚòåô±åqk¿XPýþ´ZV_Éå|¯ õAÐÇæ+’ BœÏ«» P FÉqŠO P>8“¿0¯ÔÖ(ÍÐ(¡(ù#.{ÿ0ÿöGð;¸üþá™Û§¸TØü¾‘Ö§W/üÇÿRæGîŠ&Þ.^&èÔsZÓa-l€¯Ã›PêPÀåÅ{ÄñjÑô¡\cÛŠQá•– ¾¿ÓÇø¨ŽPCu .¢x••´†©EÚÒ vÄò­•›‡U¾TQ±ixå¦ÊCÃúf”ëÛw?‰üßðM•›†•ož>¬"-}øy=|ƒÄ®Z’÷*}Õ>JEžrß 2ïëi¥=<úZñr´ŸÛìém]O±v¢C½¸|KöHÏ:¹¨Ò…ÀoàÇö•Æuì`¤Û!Þ“;êžn…úÚÞ¡vké˜Ñù['Î\ѵjñl8ŒËßviXZ.‹7¤ö~rdvõÃcFе*¸T'|HrD›ÓŒüýµæpó{æfó³`6+ìáZ¥¥ „<­4$Èô´÷´át,ìÐTIAÅ©[ÿYcÿʼnõ³ F%¥5D–—ŒLŠ+S¼äÕ§Öñ·‡N ã-Kç¼ø~nŸžQöM=R;wÎX]QKâ̯ù‹¼ÎS‹G³žZ|ŠÃâGB\+üzàR8°Ûç¥gù[eô=§Q¡5C$Ö ¢ù¨A­‘ÌZÿ` ÊqiüUÞtÌsT eôlÏÆhW\,‚;Ò»—/‹£Ùuƒ8e•}€ITgáO`)Œ›¯ƒ½ûž?ÏßÛ¼ç˜-$c9> æ»gfS>®À-|#«K÷)"Ú@MT€ð$èé†×:ƒÝÂ7nÞöRZÉç_ø™«À-bÑ_{Ýp÷ x9Àp`¯£zñ¾ šËdv‘€Mž†èIlí£Óùú*5¢R‰HNC´Ä‘†Ô'ÈZB›¥þÓA‚<(n[Sš‘ž6&m`ÕÛ⻓Ÿ4ï0GÆ)×ç²3ÐÙ\>wÅÓ#,’5 eK×3^h6¦8HhfãtÍoß. ×9猚ZVÂÅ5£´qƒ^–ma3Áü‚ùj‚S¾{ ¼¯Š¡=íêöt@&Ém„Þ+йãÑyÏ|òÚìøšshQz ¿sÖÙñ«Ÿ9þÇ ý›k_}œÕ*Èåè6Ãõ,§­×y æ ŠïZa P+,^š…›‚$tø¿á»Ú rùƒwàÚ÷ ™<ÄA3x3NxÂác±ÝÐþ•Ée$Éó…& œãŽ“ˆ>̼ ôø…º÷囈3@zr²wì lìd4ɽ¯m,»H€žÓ%ËòžKÆÎ>¤ó"Þ“ÏOQ¹{Ÿ^Sb™—ƒ’ñÿ!V­?{LÌÚ¡ƒË[–›Üi*Ÿ,7!Ò_îl2Ãh£ ²þ&¹£kײַ1Šö65Í¿fÊ0÷™'Ï<¦àJ²v î7{ âãIžæ®œuk^b-Ns¦,›çÚ‡½‘ÅÝŠÅg‹Ü!Q°åëÏa¼îá‘Y¦,×vLûÛ˜©Ð ý÷1ÇÁVyLðƒcJÛÆTƒÝïÜf‹¬'…ÍÓÛc÷3åy¼XíéÏšÆúM$«Ñó÷”&ÂW%¯=Í?2®ÑsoWšd÷&±Ÿ†_ÅŸ—¦É툉Ö[wÜ£‹¶ÍG¶ßñoø’Ðtý<¶Í¶—Å¿¸…à˜I =AWg@´2™c@LŽ‹dÏæl—Á¿{rŽ«û'Òæö–c¹\ð…zìÛötmBõžG¦tB…ŸÜ5;¯[×Ô ýÿûÙ;g=õððäâáÙåS2 R5=Ç~òZyvŸ”¹Q8jÄð½«{!¿Krˆ99vðüÁ;?èókaFrçì´ÜÉ™%gD¦¦å~¯Ï‰·où5òû®~LåÁúED áu&ó1ýÞÌÊô”Óÿp}j»sÿõˆ¶ëÇA+½n»ÿº¦íúI»¿Ëý×ù¶ëô jIzÙ:ÛillsâOyL'ïbodŒx’¯#ˆÚ“èo‰³»)‰¼JŸÙߥMƒj1- ûkƒ{廂uú$zèlÙ. RÅå¸Tþ‹Ç ~v8¸§žÑÛ=n–Û2lëİÞ×2#yÒûÚ¢î?0ó¶KðM5‹ãu5bΚŠå[ü°¤jv¢˜zÐÐu]Å‹o’¤ýTW;.cWÁ›-ësŸÈÏÈÊœžÝM’;)L)½‡/+ðï|Gœ0tiyBÚö…ïœ2«ÆvëüuéïÏüÐPTµð‡ú’ îÖ]Áx‡M´×…ð.[ö¿p~O3˜\se¹¿Êäbí(—Ž×§Æý]n:\?þ »Þùþûù¶ëÕWe™%w+=ÓîÇæ8âñ¹ôy[êsõmxAÏ ‹:Œ™Úê”ǨÛÇè è0æ8þE£º£GScšF|®Þëss ÍsEAì®Àá !‚BCCÅ ­¿t¶‹d¢´ûLžíÒzðN$ê=ýŸìa_bð$½ñgàí©^´k Ñ›ñ>µàª#˧ÎõKÁûƒœ‹ðï~þÕìïW ^ÐM4ü®lbƤ¾²óK/B#»½Ý§pÎÚê ­`Í_xÙÉ/μ ukÓÒÏœ³¢ÅRûöèê÷N4 x÷Êïb67H¶¹XÆˆŽ²)aü*–e¿É.¸ãõq®O-û;& épýøŸìú}óÏbëË×O¶þ]·J˜,äëÕ{Žë`Ï5à2ÅŸdçÁÀîì¸Ñ¾@*’ª¤G%^ôçÒ!Їá{ð ¼ (—±*UzžN:<ö£ïð½íw¯ÉÏÈÈËïÛ·~F¿\úɾtéfAÿ¼ìâBÄ÷0('{P!¥%¶u=?†_A|y(á-ñåA‘aÄ—-ÐñaÙ.þogËí¾<©ƒ/×ÀP£Q¢¡„a/¡3ÇÔ,ž–K› æTe/+ÉÀƒ²`u×cðzŸn?í3HžÿÈÊ «h¯A²‰ã'¤Ôö¤pAÕÎTh OÙ¹/“IY™Â/ϼ>µ]ÿ·ëÇÍìzèý×ù¶ëÕÙzº´Û³|¾Éæ¨×ÐtXÃÛ#!šY/œÊHÒÖ úÝ€÷õŠžî™›$¢QÜê—~µ ±ÒÓ$ñ&ŒËµ+æøåLÍë—›5½¾îüÑ“xåÁ-´OBðé9«vþñÔM‚—Oý2»¬¬v¾öêWØŸ§'©Þä´m=8FÖƒó ŒóôјSš)œ&û´€ g”ÎXà}L ª¡‰æ_j-í W‘^Å#ÿmÝÚÚ³1±ýÙ”¶œL AB´ç11Û­¨êmx6 Å$cÃyž²iI.Ë>’VM;àMm-ïf9SÓE •6¹÷´ùÑKÄZAw ú;c´ø&'šDœhRðÕ'äçéÛ)Çå«cs\¢?;¯•ä¾ò¸O¯ë¤;Iù›ÓÔ@è•+ÍY¢ÚœæîÉû»¥ï˜ùÎå…Pl<;nýŸ¬™ð”C› +¸Çå<š•—Wól>÷LÙóqÏï2 ÈÌðãŸÃ¼½›6uè.ìÖ-›ñý“ÃFAߪ}q*u“D¶ÐÁ_ä«D ÐÍ^ä3K¤ä±Ÿ±FÛDÉJ‚-aÐÌWHh|ÃÅô½I°Ø\"1¹®¬(0uoFʹ€ãLü^%6²gGN¥–Ä•~ˆL÷qe¢·ñD®lHÞ_z »äUÏ>6qá‚ډϽèèÒ%¥{÷.á䄹 µ5³žšg·ÇÅÞ:{‘ùg‹ª[N>d%ŸZSƒ‰3ÍR‚ø +å aÕõÈn+­{bGYlçШ„þÎ^–ðͽ¾LÑ3<²»ÿ® þ¢Åféa‡É[„ÝOy~£`/ÚÍ­ÿÛo$ ’¸÷Ûo=c¤¹ÿ4FŠmS‡såìùfŸ7Á,úƒ´xj´zD4S1vãµacÑaÿ¯[Îã«t|5_ìO †ìFþ1.ŸÜð•«Zh"7œ¶ÿýÛ dþ²êæ¯[šÉhjŸ„>Íï ´oiRÑš‘Å-Se‘?¸TºØÈQî¨T~oxiå(­¼ŽÍ¥!sùð³4"›ëLbÅú‘Û(ç.ÑÉÌñõÞ-÷äɰxž Fl/Té|d?‰Œ´¨¶éλ3î²rô–k‰3<[4_Æ8u&Ìëöãàn®‰!y’Þ©T¥ó üFÑóžÓÞƒK7äùñÓë÷½8e.·»zÏÈyO¼ñÁMMElÌDˆ<Äô!jªb•§¾TTÍDÔD#¦Æô¡ò4{˜¨‰™˜¾ìif*ºœ}çÞ†¨^~¾sÿçüÏ9¾ïÌ ú$(Kóú-zî"’ÇRìe÷=«YôTÕ1EɢŹ¢Z1uµ„J³'gš¬="É›ÏÔ9êõyJÖÉ2Ù°ëUÚÔít Mž•uc¦*ÈOTÜuƒ¤¸Uþ×ð¼@5Çå‚u7‹ FÜ>*Ò¸ÖïœKòþ)»oP“.ºÞºrnöd$cNUÓ|Ó9 ¨[²‚¸^2kRr®ä6å¾Píø6Õ•ñ剩ÉWøê™e|){ÑØK·uiÛ>sb{¸¯¯{¸«ÓÈq®$óx[Ƕ¤Ì¡,˜²n˜/ªo.%ïœQC/Cï ½Cƒ¾ý¡–#ßœ3=Dœw«Åޱ­òé°‡ÞÛšÀŒtÑöÑǬ’,×å‡9q“ا߻Nʘ§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€0N¤|äø:bަ¸Ôê$F‚ØX¬Èt¦Ôô8ˆ >ŒÆü.TœÈÜ  4 P ˆ ¸ ø , v ´ ü  N v ¾ ê  < X l ˆ ¤ ¸ Ò  d š è6~ô.VŒ¾Ò"VŽØ&P–Ò.t ÖJ\¦ââZ¢ø@\¸â^˜Üü~šÒþ4~˜Ø 6X„Ìâø^p‚”¦¸Ê&8J\n€’¤¶$6HZl–ìþ"4F~êú *<NÚæö(:L^pÔäô   $ 6 | Î Þ î þ!! !n!€!”!ò"n"’"Â"ø# ##4#L#d#Š#²#Ú#ú$$H$^$’$öÖE;/\TxœTËnÓ@½ŽÓ—ú@Z!ÄbVUóXÑ.Ú4T•ª"Ѫ«n¦öÔ™Ö±Íx¢(ý–ü;XtÆ-køÖ|ŸÀ™ñ¤MiÊ‚D3>s}çœë;Ç&¢ÇÞ ò¨ü­“vØ£9úæp…æé—Ã>­z/®Ò²÷Þá)Zð~8FàL©@();à)àû»¶þš!ÂY±]͉Å&ö„–#¬[øÍËî`3ñ>PyÇô Ò"i$«±«rؘ,ÛêK,šÆ¤G¸KŠ&rÙ ×PSD` ¡#¡ ô‰5ƒæ˜ÐH¦v%sKÄhÔŒÆHbR‘ÒÎÆÚž¨é_WEçˆetzËÜv™Ù¬!®'6ª0Ç–MÛ)='­Zh#¦ºr}†^+›ÙjG.*Œ®Û# Æ™V<=®ÎYv:rO#ÖãCv"˜±,´P°LY(”渞õ•,"Á${L¶ñõ‘”좑¼Auüö`ÛMÒÐQõI]­óz}0Ü1‡ ¬WÿZ¶ç¶ÁÂú%FnéÀröpPÿ”ÖÃ\D¢q k]ÝCþž= aO¡<»þX»4ˆÍ)oB˜#¯\ÝÜc¾›¸…’`Ú=‰ œQß6WwÛÌyˆ‹»³ÆF.o»;s-خĸ›Ü(¢@d¯B›:´›wìÇÌ1Þ+d*®'eE}o·ÝÙ?èÔLxkI|xœmÐWo€áçt¨R{ï½Wí=Jkï½WrŒžúêÔ^± !®ˆuCì1.{žàÚŽQn9?À›<à•À߸9þ׫¸‰’$+"EQ©Š).M %•RZe•S^URYUUS] 5ÕR[uÕS_ 5ÒXM5Ó\ -µ’®µ6Új§½:ꤳ.ºê¦»zê%Co}dÊÒW?ý 0Ð ƒ 1Ô0Ã0Ò(£1Ö8ãM0Ñ$“M1Õ4ÓÍpÜaëmpÍl´Ã6ûu$”`k(Ñ:»ýôËv{mvÓ{?ìwÌo…þ8ä„{î8i¦l;Íò@Ø]÷=ñÐ#}Œß{î©gN™í»]ño/¼4Çg_m1WÄ< ̗뀨…òòÅ,R`±O–Xf©åVZᲃV[eµ¾øæŠ×N;ãwÞ:뜋.¹å¼ nÛ亮†’BÉ)±ÜHzzFfj´ ägGƒpZN4äÇòÂA$$eÅ‚è?zÞmGxœs˜Ä©è¡ªÀÈ*ïÁ*Çü_>ÀGLÞß7EÞÏ'E^ÍD TÕX%TRø¿<;Ëy6 ¼¯œ|Š£¯¼°±P(+P+‹1P;3#?³=ózff6o·Ón·Ý˜••Bý•eŒ¥CÅŒECùCŒùC×óŸçg2àgdbde4fÍg¨gXÏðžE€±AŒ‘•qã„!ÁÚÚÞ;Øÿyoà ˆÞÀرA5D:Fm`ëØÀ±‘‘±/²µ·—ÁIÖ{ƒQpÄÙHï )@†€ìF1§Èâbmm’ÚÅqÅ% ˜€‰8‘HAxtomcat-connectors-1.2.50-src/xdocs/images/fonts/OpenSans600.woff0000644000000000000020000005411414655113617022706 0ustar rootbinwOFFXL’ÀFFTMl\Ä2OS/2ˆ^`¢ ¸cmapèh²ŒèÜ™cvt P[¦‘4fpgm¬©´~a¶gaspX glyfd8T¸2bhead@h46ù5âhhea@œ$µúhmtx@¼X±ÄPkernBÐ# – locaPä®®Ðó¼ÚmaxpR” R?nameR´Ï‡postUÌxò‚xéÕprepWDx¬›nɉo1ÉLê}ÉíØbxœc`fÉaŠ``eà`ÅjÌÀÀ(¡™/2¤1~c``âfgcæ`abbyÀÀôÞA!šAˆ ƒÖ°ÉÿaháèeŠP``œ’c bݤ€\¢÷oxœc```f€`FXä1‚ù, €´²é:†ÿŒ†ŒÁLǘn1ÝQQRSPR°RpQ(QXóÿ?Xå Š ¨ a   K˜Šÿÿú?ñáßÿßü}ý`ëƒM6>X÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{ŽxœcagðcÝ$KY·±že@,A " m ÿ߀xòŸˆê’ü3åÿÛÕÿ?ý[ñoÐ 2„:À°ƒaÃb†)@ÖY†£ çv1Ìb4dØ36 ÕxœuUÏSÛFÞ "SÊ0Õ!«nìÂ`—t’¶@)lmÉØuÓb 3+èA"&czâ”C¦ñ­ŒHÿ—'r19åÚCÿ‡Ú[9&×ô½•M 3Õkß÷~î÷Þ.jûð Ðû{íÝÖÎO?>ú¡ù}£¾]ó½jå;µµùíÆ7ëk«_õå÷W>/—?+îÉOÝ» syûÎÌôÔäDv|l43bqVÀCF "_‹¤/£z¹$ü…®W.ù²‚ˆà'S”õºd"PÄOtA¡å“,Uj©®-¹-6Ø¥þò¤èóƒ–Æõž \™õ#³Î0‚뢇©Šª>Ôžvc?Äy25Y•ÕãÉr‰%“S¸œÂ,ÊÓ„/nr³°ýõÄbÙiJ‹;õ£ì´´ï9®”K ˜‘žQ±ª cU7!Å •ÎÎERz?ïÛì(\Îud'úYÃH„¾ñˆÇ¿C~–¤KÏþ^ÀCIz>,SÔæîužæû”F ¶ñ†Û‘WÿÞF¢2V°ß0Z‚U¾«]zœrÇ5)jqGýw½#)l'¹\|ê#ÝlGcˆþ»—çÔž`‡]¾ ¶^ÛmÂG­C V¡&º"ønIwÕqó×6;ÿ§fH ’ƒ ».ÑpÞWìèµt* vä\0µ²€’æÕPóñ>izC͵{(±·Í¶Ž!Sht¤ŒŸGÐ;Âéú…#m˜yë¸2žÍ‹µ•ÀØ ¬ªÑ90ZD’Ðë¦Î ¹Ä¶fÞ¦Ÿ+ó³bMbŠãK?¼O» @ Ñõåtö4(*tÌOGbÃN<ÓLX‘§0'+×Ý¥²ü“¶6.7˜« ¼`Å7çJøqè¥%P,ÙÒ—ìÁ»×ÉCá¼xÀ²À#ãù*NYÑuç Ü ž»'B;.¨;H}ÐØ!CK¯3™•=ÝlËfë@¯ I.Sð?#µ“†Á„l!+´åŒhh# j¸• ü…ñBÿl$Ü 4¸• ¡¹Ã†ÖX, ÿØØ‘|+è(Sµ>Œ6F"Æ©Ö7pÓ§\²P-‰Ñ#K¤Ö‡*¼¦P‘Åù¬Ö D\.ÐÐ -e »Ôަ½=†å†óA¯önI7ÈBš˜‹ê¡@dBmÙ¹I.lùZ¬ n Õ"ÎÊf;¦àraå `4Âj5€´Ä»WØx¤ÍŽ¥è0w×)ˆltbÙÖÆï“ßœg”k–5ys¯R.áÕVI$?k%ŠŸµô¥Í˜8ÛÓ·ªa%Hî¡N_ Æ”A-B $A@‘vQÈ{çR1Ö3ÚŒŒü¸Ï™Á²CŒ³Ç}+Åì4QÑ$RÌBM&Õ¨¡u±lŠõ fž„ejrTeÕ„ÊYÓ–“p‚.yÉ›àìEŽOs'A¯]÷y/™PNjÑC •Vx¶ÿ>õþ~‘cèf~1Q…—….6ÿ­ø¢CƒòkÐÀ›ÇÖàËËMl“ÜÄBÆr0)+0%+„o¾•âc„ãˆòyŽî=ìýpš€Cí⑟üéÄöu*ÀK%¶ÿ)ÿ)÷!) ÿÿxœ•||TUöÿ-¯Lï%=L&“BÉ$CËÐB€!"Ë  ˆ"Fˆ¡H¯Ò-‹ˆYDD@D& ²ˆX~ˆèúS°ÅEä‡\þç¾7I&Qw?ÿÃÌλóîéç|ï=÷!‚æÞýï÷ ŠÌ¨EÈ®£%ÄjÁØH¨Qî6ÚQA:Š)°ågZm8ßXYm°—zpN^ ÛåtHÞ”4@oß>ѳwI÷î÷– „`º•ÜRæ‘QrÈ( fÒj$"SŠ g²ùÝáöÊÝ)Ü^x|‹5-ÈøGÜSû ±ð¿W&BÂmq7ŠGÉha¨§&9Á)8´VƒAk3›ô‚Înw¸“dAr Å 1¢(9$‡Æ¹iŒ.¦™G# ؘŒ,–X§Õ¢ÛNu¢ )Øòó33π«ú¦Ðæ†w…D›;_y)Ÿ²³ÕwN¶Ç dÛ½ü•ë±{à þrâ|})ˆMì\É®’[%;Šoãø|v ûJv—Ô”ì(©©E·óoÓ2ömŠ7óWN¨Â[Ù þªbßâÒ›xwà—l¨JChL(ßàp'úZJ‚ zߊD5VÌl-J®ÙVär‡©´eKÉí3H†¾a*¥'8Üa7ÊL·"à.&3 |°qãb,gÒ-g€a…?øSYsH²Ó››æÏMÂn«¿5ÎÍÉ æœ.·œæ·º“°œïyØár[MXð|rî­ç\¹¿ÿ–µŸí›{zOg7\YÝoØNæï>¤¤?>¾â€ëÂy¡è|Ë|Œ§%¼V±p—½ê%¹×ÞŽ¶:±Çæ9m{yÙáxòM~± =Qÿ»ÕÒ ñ4Ò"JB-€ÿ¿…Úd´Lo—ìô‰:dÑY’}-[I™­^ðc¿?ƒ7â׌Øhl•A[Ùd›“bWt\ÀíyȤ€þ D1«þq~]l«Å›"‰Š}çZ<Ù®?ýR‹½»Ûvž3§s[|䥿¯{<û ¾Ù®seeçvøÈÖç×UáІWÙg5Ÿ¡ézf%ÚV®ºòݵ/ñ©Ÿj>f5n}ËŸ¹r姯ð©jê¹Ýü„ëzøÝjñàWüf£þ¡Ö­ÒmNsɃâÓñžæbNÀgÊh)´òÓÔjö'µ²%i{…“„6†âp›ˆãªÎk˜lcVFÝA›iÀ•=ì;.(WQ±êß2Î ˆŒ=~ö¦¤â£]ÚOºÿoE}‡<³÷)V1®d+Ÿýò°nö¾þþüçð ~y× 7à vï_a·…™„&vëÔ§ßÿ{Ïè:½xäÌ3•G‡O\_ºnç«+&ïÂv=t–}û»´¢ôÞÏu„y¼Àã•xáØ‹(ÂãÄ5©!B jdPSÊbø"Œ‰ zª“‘AHà?ͬ 0nø¹Ýb $âtØÜÞ4Rºqå™E«W/8½jÉÂZüÏXÆ,ï­mø=¸o¸o°þ¾:=d$À}]Óûb ‘½y¶Üâ¸l$¸qåé…«V/:ÃoÌ~gm«ÞÆ'oü†Ï½óËRiîIÆ ÉL(>d6±lÔiõZ³EcB¨à˜¢0ήÏ-Úe=öÛ}A‘’ZàŠ¶®úÄÖgÎ|Ç6xñc-${êá ‰ìÔC¸”íx/<ŒŸTæ޾²„£`G­B.‰êtz=ÖP£A‹ . K™CL‰Š@œƒI!€_Ô¬^ü3›Œ—îÆËؤÝdÆ.¼ŽÝÅÆÁ½ †mB?# %…ÌH¤¢F¦!©DúP¢ÜôLD:Ym|õ‚Ðñ¦6³ÿÑ-å»Ïö³‹Øô½B_>Lz’ kgHKõcŸøA[¹g!øðÉ“ªmðœ…ÀOLH/!œÐ~a-7ø:ûF%§¹ÅE=Š{—÷èÓ¯°û½¥ü`2Ô¤ØWBÈ@&楔@(ˆJEܽ©©ö__¸GuL‚Þ­òÅ30¿59lÈ I(6FëìÖÊÔÜ;Lc#¾Ô,Ä›™Õȶaå_«òÿ[ÍšßîüVSkœ9~yùüù3ÉEVÉ–â'ñ$\‰'²Ùl)ûä.ÂDŽ4,3ôoú @ŽyB$h´Æ½ c­„coùŠ,¸Uz¼Öœ  Ë~ †«w—CÓðŽctç+£bÚn|+ò95bM<Ê ÅÉŽ8BLŽx!1Áªë¶Ê$ã¸>a~gà 嫬¹#¬µÀ¹¸#QƒˆìïˆÉ›°;=B~Ïxy|öôû?;fÖãWžúàf÷U¯2²gžùê²'‹FMîØo㘟ìµë¿ßÔ)úòÍZÒP—Pª]ŽÒd£;Ejî§î˜wßpLŒ.55©w8UÖYz‡u ÒÊ2•·(ê”Ü•qMð¤ðüÈÎRÓqn YÉyȲyÕÎìSöÓ¯/ùpø¶ªý'fUà¡O¿wÃSNaÝ¥[BÙ¢·ši\¯­8¹ï¹ÖÙOΙ:áÐõ¡e™]·¬>¨Ô8~ t¼¸tbCE!¿c“^l¢ÅŽÃŽE›"•ذٖl#65ËåÊ ðl4$í¼òˆ”ZV¯Õ“‹áÿx@^ÇÂøã—kG“M—³:MB{ö .`‡qÁ›ô½š"<ñXy硵¿€§‚!@¢Ô6”l¦qNªqÆI‰ÈÚ;ŒärÅö »$ÉÐ;,ýA„ âËœÔ :‹‡KÌÎKŽ˜ô¼„ »È®ÿ¶¸ßGƒžßÊve.Ìyðr«ö3÷ºâÇ÷d¿÷ý¤uöÒX²:’÷ϱ5’d5h+O¥¢®!o¼5EÊ­4ͧs˜LI}Ã&“ƒ¹o˜ÈŽ˜ÞaÇR²U éžl·“ë“"&ˆÀù‰¨¨Û›¢d¶¡äí ÅÅ£¯Vë ™Û¦œø’ÝýòÙïË1›Q9sfñìžëÉD:ÈzÌUÃ~ì¾qî ûm-öÜÜ´âÉå&µ[rX‰× ãP{JȲI‹ˆˆT#£Jú@u¥%>¢NŒé\«¡¿Ö.ŸÝrû%¿«qär!/jƒ‚¡Dª19Ò=Rv–hõxÒÓõ¥ö #Y×7¬oÌ@õo%7pVEÅÀ!;çÖånÊ«Îz&$uœ"9Pº)©ž}x]ß¾‚Ýüægv{Á¦y“o®,¯X6g^âœG±qôã­ú~lÔLñÔ¡¾ž;ààÔ7?ÿàíÇ—ìšøü;wv2½¬ß¼|cÛE´`Ô}9¥]2s§ö¹o·î·Aà'ù¸NS ”`C’úÓ f§9¹oØl¦Nglï°S¦š¾ÑaòÏuŠ-Šá#6»—i¹9Tkóq~TþZc!ȶ°ÍsÛ†ýü£ÞÐîåGŽ|‰ñ—›¾’‘ÇŸš1súænOÐBVÂXŽÇb„mƒJ®Ÿ¿ŒÍëØW7Ÿ_^¾lé°ðÆA*FáyEqÝÅ㺕‡uã69ú…M–úS×#Y2:ÓXsþ˜tV÷ê{èsk9(*åóñܹæ“e‡â 2–$A¦v›€$‹´\¢F*iÍ0­E™6sØÐ!ïE™–Ï­¤TÚ0)^bV²«72éÏn5Ë’Ë‘Iy-p jj˜3-äA·^3Åt"]F¯*ƒ´=©n˜‚»S‹…¬šLz®ÖK.]Â;fàï²*vx(Ã;…ôº‚ë2BñPQA«ÄÒ0$$T6ãLÜO„Ü·&,ï¥Gì–gu ¯2z´¦=J ÞxƒMÚµ«)X$¢4JÿF»–‰‡“Kµ^z®&o†Ye13X)Ðh¹û ¯ä¶4Ô)äñ$Ä#ÙŽLö¡¹_p»¡HµXt½Â!5©_8ÕÞÈ*m ΋6Jîbu53äŽH¶“M8Gë"¾dôôn<8lsïþ§¿?v¥Uxü‚ŸV÷îÞ½MXÙgèØ¢þƒòÒvNz÷•^SÇÝ×cx¿ vxmߢî÷öSìqâÝÒAñ ÊE¨8”Ú9ÚÊ®<“·529\Í[KB}«5;æž{½>=9›¦¥£LÃfòìð>FQ__õ+Îä¯ó)¨F\nêt(ER½)q‚ëe’·‚š%5-Ø0\·9×ÒÁA/>Ô÷Q‡!kù ß¾u®ø­"ר¾C3öò'ìøVœ‡S.ýòÑÿAÙ2ò_xÉ øÞ·ïÔì=l3Í^F¾YöÓœþE}ú|ôÆ?1Ža™1/|ðÜ«˜.ÞÉÞúö%;9h˼ ?€E¼öv³7ØË?`ß5ë6E&ð?±§x¬Í 3I H¦&‚¬1˜e«ÅLŠ!ʈH°DÁóQù D1™¯.`ÓÖØ/ÁÏ‹WÖž[VC¼X ^–µÀœ«‹Ï™ƒ×°qâÛ]Éh¼´ùöæ3W²J°rHÂÈ©fˆrÔ#”æ’ô–¸8³ Ñ›!kb-–X0%‹BGqQsdûN1aO3ÁY_©x=öº2%6R°xã]¸56Îybà öÓoµ¿\»²fá3›Ï²5ë7=/îÙypö6—.ñÕ•Ç¿¢ƒ†M3¸vËšòÄä àO3 .ŸûrP³Öì¤q±vT¶ ©8lˆŠjª?áH¡š1€nn¹5¦™ÿ¬þæ³!;†nÿœbU/ãöŸüëà€ž/ Œ}Áî²_Yµ/ñL'<ûØ3ô„7—ë d&–Ì4 5ˆ«FA ðÉb¥ŠT0‡ÛŸÕ˨¶zš!jú5ÐL,cØ<6ÃCðœæ<»XÈl «÷°§Ù‹Äx碊©`>ZóéQ‡P3ˆ¥:Ä9x$mqX’ Ö‹Ã„b]qÿA3QžÎçð£¼hMÍqÚ®v7ñ×^à ó}6ù$Ëm˜ï6̧E÷€EÂ7P†Lä³™%¬§’D°M³~1 byt•,F¦Â;~¢ùê<|–àiuС˜:Œãµ\ ±kˆ&Î(@$óñêõ–â°^] Rû_×r+x<÷hpn· ®Œœ\ÏAàÏMâæüº„ífëð<úò™þ»výÈ~ùíÊ£sØ9[›’žŠà2</x¢”}~—Ý`?$âþÅΊ¼¡X ˆPù"ŒZÖhDDqýâZfƒ’X‡€¦5 vþ¥vèµkdó/dU-ÀÿÚmd@½ŒñN¯Y÷p„HQRËjÃotøÇgÊØ»£ÙX¼ Æ8^×QY6%äuV]}–¯D»Z]ä ’fdçþýò {ÊyK\p{Ö¿~ª›[L„û™Pn(AoÀˆóuŸÁ$B¼1QHwú(ÝM}»ƲÂa^{,&²«,wɵk#GàEØÂ*¶’5Sj/·…MÄçYÇCêœB<Ì)*kð&KÀ3ÈÙxPœ5 `ôÃ×ÈCâž;î3êo¥Íð[êJ¶éM&£i‰F%Ik¤.'±i©¤—)2Iœä&4×¥ ¥xõÚœ~àæ:ʱç³ëܯ‘ Ñ–^Ñ ÖC8Î~ù¹6H˜*,ºÝ“œ‡úît¨—_%Ðë·[,ˆêdY£Av5h ²Âšú¥×z㨣„çu»"T¤P•XÉ.ÖfiDÓˆSg$b¸(,é´C­&ŸáÆž~„!%WpŸ9ß€Ó À­„bbµÎâ°V æâ0µÿiÜñ¨Ò Eãtñ<ÛÈÞbo²g!3õÂ…xô-ŸúÉ…Ï>ùì"¹×ÿsØ4¶]g?`¶b#v±Õ(,Pðº¤kFz®ätèp\½,Ùd{qXnÑnÂ3¶àQ€`3¡À ØÇìêºkø%lÃÖZÿ¬}Û7¼¸•Ö\¾Áé_Ì5ûé'ŸPäÀ¶(r0CÔ.”, Tr!‹ ’¾1¶8lDü„S ¬¢ jéM옯naO]i*žÓGðPvUûÿRF7Ùêžl>.ú‚BuùB§ä 'Ç6§`qØ_¶²Ø‚ÛeÓ"m/ˆz‡ÞfÐ@‹HM.¨é‚.ÞL:-"ðwn}yÍæŸ»†ŸÅñà‡ßâgÙ/l35=ñø×®Ý'îùøSvíÑÚ¤H±ãÑG ƒSQTë(Ñ&ÚÜHHóÕ@v TÛȨP~ã…¨V ”Ut%¯ò’JgID0°+·n=7úëKç?qää,\üèÃâ£ë}¬Í„e_Sˆ—ý²÷ÿfæ=|éä>ý>\¹÷£ÁGK¸7¿_Q».®ÁÎÆ‚ìdŽOÆT¢Z ¶A‘±C åÔ§z}¡÷ý×X©Ð ^?œá1d7øN;Åg}!«ë5l·YµT45d˜@´Û@À2”Pê 4‹Åb»Eì÷½ Ñ~©ÚKÅ=5}6ÿZ‰›ÕÐ5£ÞÜŽGÑ0Rörx¬n µ Ñ¢° ¥&£–"R›º<Ò¸€ƒpä…—hƒ¹ÅP #7qVLžÆ˜gUêj¦t:“]|² Ìa@H®TÖAB!F1:­s|‚Ñ ,1 bR¢EŒ¡ºx‡j55‰â‘ÿx4â5#TûÔ£Ç;_<Úù{¼I«¹ei#ê2Ì×YÍ;ïÞ8—åÔ·²ýüÓ ¯ßœÿáu:6ÿ³–¡²k6‘/Èç5ÛÏ<{ßG耚­ÓZv‰–*6&€Ù`­Þ×B?iãŠ9äéOÌ{Ê[a3¶àÌ¿Oï†Wý^½â¥ƒ/îõœÛyjÿ¾ÃóA.°Àî!¬.TGuVš˜£/ bbˆ…ÆÄ IrqJMÝ£…ÅQS#x¦ˆN)z ÜIÄ%ƒsÉQУ§5&‹c—°©ú"«M·<3ò•vnzd¾ß$³8k€ÚïÄ¥TŸÍM/î>ìðÞƒì}vñ®x4³Ca·}óQæ˜8·à‰wŒY¼ëé<4úƒÆ”=(”Vx½eù¯Ód¤¥mZuàƒV—-Šw„³:hé{ù‘Ýïå;¤¸tÂýE†Ñîcùüá©*z«‚œ6üÀÉ1/Ff£V«C:·Ë¬³ÛŰݢGXçäIº>—ÕãuGN±q:d¾cÑÌ*L­óÈêEW¯Ìm^ŒW’ªÙO¾þaíEpÿ©Ã.ÈRëã @Àfñ¶Ò³“JB‚¶ÕbL–3e2Lž(Ï’Ÿ—_“¿’¯É²LÌÈ(È2éLT_R¡Ñ <«®^ý½[¨c·nCÝ„Rì+èÚµ }·n|¾»ó™C™Ï€bP—PK»NÁF–ãb]!³%Ù’iékfYfyÞrÖò•Ek¢ Pĸ3©Ùƒ·Ð4EÝÑTÇví¾æê…u”0Gì~Û6áüÄWwÊ£hRå¿@Ù7oJ&TMУPnÒÈ‚ #zDÌRD Ö&Wq› Z(©è\Æ‹æâ>ØÌºà ¬š=[ñÃR´f¾Úøò86WrÔj?Auócž#(r… h…$M"èºh.a.U/Kàc^Tò&ÄÛá;n2XO}©£Îª7'€Á4­ 97„š:gxnm\æÙòÿ`Bnŀܑ/kÝ%¡¸zxÙÓ³®îóZ¿ö º{¯%k×”÷Þ¼:¢lÁ,²mVùëÿ¬½ ”®è;`Géà“gj3ùw¯¾Þ`ß@¯e…bJº:œ@('ÐjÑ›ÿܼÿ‚4Õ¶ŸYÈIÉÞ÷^Êm{çÙÈôŠa«q»æ4€WñuBÙ e”Ë­ƒD¢³Psa˜ºþ¯óm¾\œ‘zšYù¥PÎ~¼µñçÙØqçSs^ »²z.I‡œúáb,ýgkvšÝfxžyLÉûW)<7C¡f1|åNN²ÊVO Õ#“ R¾ l[ŽGñ ©­ èÕI  ¤6¿WÑDÀåä©0ó¨\¾È…5™®ÔÄ&|qö»«ìÖâŠÙ+ŸSéX»8‰µ“:&O­R* —îß²Ûûþ›'ßÚH‘ÐÙèÔ¡P³$‹‹Õ™cÍ)ž¸x·9Ùe°Ùä°Íb@…aCtbˉª`UB•ÒIU—ÅÉÇ@r0À­(/è•ÈÐÕsW?9çè™ï«ÏŽ}©“&îhµ†ÇV½úß™Ý'ßfs@Š3Á_Vï+~?‚?i52 QžW@C! ·!¢³uN¾+È.È.§q®³r¡{kwvÞ’×®îK6_Êt ûVÕJŽz”ß$Ô?ËàþŽÇu(Ê« 06ø”ÃÛ=ì°PMQ´Ñ4Åã<á(‘(jÚH†Qˆ€$`œ.«þâÒ¼£UÚLyhþåãGw¿ñøþ/.x¢=n·ù]NªlyOû´ž«§-}¶ïë=Çå䜢ÆÿÝjò‹X–Ü!”l6Øù‚­Î*¸]FsHk3˜Í¶"ÈŸŠª•n<ހ݄ãSJ4/àion89l¨ë€þ™Ù®µ›KVàvìø}Ûâ_·ºñpÒì€oîªÝy_?•ŽçÀ§Æ ¥P µ ¹±ÕêÐk—“ˆ6­9ESa}éAwQn\Wp«¬>ÐÝCÖ›žzï§±W/ª^Ñ{àÉÓä|í€Y³^ÿøïì¨Ã’E0§¼ØZǼˆÑ‰JÇ‘Y‘€êëꀺ¹0à(ã-lð­¯Û4Ú_ßfƒ„ÒÚòÍ£‹’J~w~ˆ¨Ò¸"êò$"·Ý&hdS|‚N+hMî19 ÝTãÔÆ Ôe“;Pàüš÷Ð4ê%€åÕÙ9–÷ØÙ¨teq]µmSV±öþ/KÚ8$] s&/š39¸¬š$*ÓÙõIµ ¨üêýå=ÞÉ$…µû³Þ¿gæ%â©£@ÔW¥Êúxd&‘`”¢$ë%Þ»¤°Y£wþ¢‡_éŸcK°¡†a[Œç³›ì„›$—$²r\YûMíi1RÑĈžŠÞaN‡NÐhá;Ak\NÁáÔ ³Á ±!’¡ÆXËêQåR ‘ø@Ó_¬m›+Œù+Øù>=s»nëÖ_2oZðY²ñN<{Ùºßp|,Ÿ¿+øþ"˜¿óä×Öa~À{fó…yÎü¯˜Ÿ.ªy‹dÖþJµ—H`5îÞR+©²Í¼ýƒ²¶Ó-ä×ÇØˆIv:HLMJ´b¦³è2ú=DÏR 0@L¬^§"qÞr½ž‘oU+éO.·tàwN¨ÍœÆ!8!>à »9¿òÂ…Éc._.›òÝiœ¼ÿÐýCppÓª=â½¥ì³~Cê)öIi²—¬•Ó•D2Yƒ÷1ÞÇHáë‚Ìú>F³øÂîÝ’å–¹žŸÓÀO’ÂO¼Mp›d™ïÐfɆøxsܬ¸eq¯ÅŠ;'ÅÅÙÁÀíÅOÀ ñCÀ™Ûs†‚¹àÊ9iþÜl…£€b->{ââ°qãf^¾ÂWGg•ϬplZIöâ^ƒ±4cŽÓà?[”Þ+îY¿ƒ}=ºÿ¡ûPû I;!‹ŽG…RÍULµZõ¥a€HV¢¥V)$ñ­)Y*&J‚¤lýóÈÆa²Ä³¼W·˜*W©ë]‘íÆ”4î™=³Ã¨µ§ ¬ ç”·}pE§òþ³Èîö=ç vl{pb²7¨ÖÂsÁ!vC•Z¸yÈ&HÊ'dTÛ×#­Û×í»«=¼JõyxG€]Åž^=‹Š‹‹Šz“¹5ñžž}úöèÖ¿ð»òÌMñ4ØXÏP ÑÑ¥5–!)Q$$¶w DI„X“½wX¿’¡AFg†dsï:®€ÉèÎ.µRé¨&¹9¶ºNjo]WK^œ¾hÓÙ“§þùܺÊ•cW.^¾°×ü¿ýÜN²+ÉÇ{(ÁFˆ§ &Þj§ÑëÝf;ÑZìî)9IÓ7¬1Çb=µ!$ͲÝl3÷ ÛbêÖ„ oãF4¢©‰P%¤ °)x³êY)¦Evy³xóãgð6¥s ¹qçúÈ¡|#ž*ÝÓýâí{îŸqöhÒœGömÇèÀÇ\oS1â…-€üPÁûRL ð­¨5˜€ä8]‹æZÿ@DM²Óg–“ÔP™7©ËvGÇ{NÐtó´tË€"d·ìçY]öÓ‚u¥ÈuhîŒÊÑS¦Œ„·‚‚ŠésGM~2\9½2TõôÐO?=bÈr~üعÓ+ :UN;zÊô‘Ó+:t˜5½bÔ£#çÎ cÔxÂÊÁ?]èþPɪ׺mN9Æ-Ùì¶¾éoOéS»Ýàԙ̦’°l6°S2ÔuûյܫânÔzË{c´8 æzøóæz”?ø†áN7ؤoØw8–}÷5»ŒãÙå±i7i"Y_«Y»aýë7¬%·߈Š=2J }Bè´*P7U)ÊQ‡†^&¬‘ˆÄcRÍÖ­æ[ÅϦܽNH^”òQïP«wZ|kd³cƒ|¹BïŽ÷hÚµ¥±AGvK)I£1÷kpRjpRTùõ‡tU…yÁˆòƒHñ…A—**TwLÔù6‰²{b½{¬¼øÖý[Gu}ô±G&<ýÚšE‹ª?üx^ïwû]m9zÄ’§:ìk3~ñø'žÏëFý%•é÷®«X™ÒrsvÜø¼¾®ÏŽ=\²léKÝßh¨LÏËK ™:"£°ë=Æô“k¹äç ]#V+û‡I!ƒÁ&úccÌÔ©E™MެD¡X_4®öui“[ÊiÓ/€O¡Î6]Ä郃¹¡¶íø{^A[¾3únµÔbŒ ¥¡<ÀˆÍ©93ÙïÖšîdñv6 o—̆dÃój0xñBº×^·­>䇔è (Îú`nŒsÔ†§ƒð–AªMd§ÚêzhùÄÇž|²õ”ÇŽ_øâØÂ§;«™w}Ÿ¿Ž°Íže›Î|§Vmé/¿Â.¾\žÚ.èþ¾tÕsIÎçÿþòÓÿ+\dç”ß°Íïg[?<‹½·]ªz{^©Â¾ª­ì nWù”Uâ °å‡õØãqÇ˲ÕM½)½ÞžÈË‹@“]V?r, øO“ !ÝÒp‚e"mYVå·"çžæ¾É­ÛÍl²/&¢?ì‹A=ôhñ¸ü^lÍ9Û]¸[¸½ƒ³Ãá\e=0ÙTÀD1¨](Q'Š+r:].M\¬Uo’Üf­Óo"…aSýÒÒ;b8‡(îUñ¹ß üZ•ÕÆÏW.¬Þ›bl³lì⾕¯^Å[kTX¾êÞþƒv¥²w¥Žª~'±aºä«Ê9!ΈHÔCÝŒEÆ$šh¯° eÖδÌ}ØkUÏ¿å<Âô‡tìÿ?§?ÿžte5Ò¬ß+hÀvû˜zV‡äã”÷T»C:å¬Õö ÓÈáž&^ÒÐ5MÎGÕ,‹y÷§hu› üœ€ÚmsHo*2›M2‰jÕöF´:"ØÜÎ €]àmìlç`^·¼‚7ú¯kQ2ˆ]ÿÒ¼Àäɸ/vë@ç0>W°{‡Ò§“ÂÏÕðÞ$lÐËZÜLÐ&q£«[$q«Â(Àü`/@û©hÍœ6Ǿ ·@cî·µ ?rNñáãÎBŽãu„/dãç…u¢P“A1¡Ž!ʉ(p"Fröµg×ì|}ýºÌÒgàÀ>ü%ŒÞrðЋ¯ìgëÄ &N?^™³$*gÁœz­@•‰N+™Ì€¼ "OY™ÙQÒÒb¿±¨¾ ¶¾Š——Ux ëÀ6Tá8v¥ —7ë7ÆC‡²’¸†ˆçšöIYâ‹'[²¤¡™ß#«Œ>¦ƒk÷"í”X¡þÍÍåc[ÃØ¢ÈØJuìç|ì£t3Œ•w Š”ûBõ#O)c¡´…÷éªÚ½V M[оA°¬Þø²ét àAŽ+ŠBi )(^¶ÛãSh‹æ‚Ûâ-ñDOãã->_r¿°OmûNiºõ÷‡–oŽx”Ýe^K¹UÝ€·sdRYTZöDLJTUZúÅg¿o9`òÐŽ×`eÁ¸5%#Göê34˜öÆ„C¯ô˜aš7ÉV!³ö8qÔV“vw‚ø¹™J³w¤©¯' ï3 ^ŸO_i`u2zœ˜”ï•þbE¶Í#:Ú«È ;äÖtÌ4Ô翎9~÷wuLLÓ1ëÇŒC‚"‚=uò¿{׿”û´RéaËÕûîó(a}Ô˜iw{4s÷M³7jÌqö‘:ÆÒpˆÆd²B:fû"Bj|¹êù|q¨ÒÓƒº‡|FdÓ¸\ ÌŠ‹uJ²T¶É² ÕZ‹ÃZ*¸5€+§›Emhç« JK8IW{³ÍÄ¡J_øÄ•+ñA|?žSóûã8Àμ@lä¶ŽÍ"O’Yl>Û…–õ8ÉEä*V*¶Ÿ±ý]*¯q ¼*ý£Š<²U¹¢éªxþzÌ4ìÿ¯cŽ£ýê˜Ô¦cŠêÇœ@;Ô1ÍšŽéX?f:ñÅŒˆì1ªÄ&Á$¬ƒ\“2c*ÊZ¾Æœ‰†ñ³±™C"‡o Äk`QŸbûËqîQÎöân3Ù^v œœÇ…³Ø~\8“íaûÊq! QzfÜÝ-žkÀ‹ã¡Nëʬž,8(A‡DÎ,úRÝI®dÁk¶iDÞ_JcwF6=®>f@9ïÅ×nÔ6¾¦Csü˜Ã7N«ïÃýdõÐ%#ð.Ó-u”•Ôî±è“ 5›û^ƒÕµäö[0tù1<ƒ7›–V ^|‚-ÿúéšíyÃéw•´´û‘ËUéuTôsODÏAÕâdßtÌ4ôós-RÇ$5Ó±~Ì8´.â?þèx*PîÓ>2×@õ>¶È}"ýÄ+s¢ÂÏŠŒZ¥¡ØíâíÍHkѨ´´’l@üFI¦¼×» !hF:\¢šêzŒÎ@t—ñ ö»ZuíÚqlÀ–Úä¹ooß´} Õ|sƒ÷üú/æ|rñ¬™êž1ðF¤d@B)>$%ÇšZe “#9CÌ͉õY³2œYÍ ÃYÈê. [w|5ÝõÀu7'‘Fë@i‘ÇOÔÁR¶»9žÊ{w”—‘?lðßZ}úÁÁñm7wy·ÛŒéc»vïš7qÖ¼«_ûôåžsÝÚ&$ÒB‡=Òý¥íNø²ÖvسÇý Ì Þ(ê÷ðƒw¦+Ÿ©â:SúÙ$裫’ߺ¬GÜ3ÛX¹6þäú´âÿ|ýø÷Êõ@£ëâÍúë'¾U®g6¾^]}ÜoHñúöVÕëhÜT?æ=“:¦eÝð]#íÊ ›µšjJ¨Àcv 9.WF®ÓÃqbþ=fOªQÈè„TcŽ«G8''ÕhÍ* ePšÑ’Ó=œÚ¢(œ”êâ= ÊöQzt§Oä­éRŸ‚Dí|&7‡#DŽÄøÂ-o¨²yÔ]Δ4u'¨®ÙÈÊÁUÙ““6è×ßœZ²µçÀs£þ=ê±ÿýçÚ{tØ»oû€W',¾Ðeèá/½}cëËço\N·®l‚ ðTÔ˜iw³›Ž¹ËÇ<5æ8{KcióŒ¨Ðs$’ßá]ÍïÖºü®ôið§@]J7$$ @4{ŒØ¢¹+Öj²ˆn³ÙÁãOr÷°VKÝL}Ýëwâß«‹B|ý»q£u¤Ÿ)ç|ÝÁ4%øƒ.%ØhNÉPÎ~ºs•ý/–¾øôošŽ/ÝøÁ€~ýOûnàuÏÿ²¶rí¼Õ VÏ#Aöû[.‡…w6­™;½]úÊ‚~ +&-fsسÖlynýæ=*ÎPz^?ì§ú¡G‘NB´®Êù•ª¶ð¶¢Ë俺>mâ¾~Ü \Oit]™_½~â®r=©ñõêúëãlª­¤GùøpT-d êóœâQN(ÎeÑñg-Y„ÄÙk7Ú•c¹™+r¡ÎâÊŒ†ÍÊÁÜF§š>§çjׄ:„ºæ·ïR÷NfìÚÅjBÝ‹ zv'uBOÙÝ}B¹°H©RPßPk¥^Hp$ ‡Z/ؤTo“‚!¶0l´PO£~Ÿ¿,¼õCd(R(H¢R84S:–+ž_º;î,ŸÜíé>ók.úðüö[=—<¬æd¬ì™±X×ÏdÍIë:¼8îŸßÿpæâD“FºzU¦8viÅìl&=< /ûˆýÊ[™Ÿ)Ì‚ÄJÆÇoÙå{ÿM\qðí~žU~ƽ߄纞;¡4ºçÎü§=wBiÝù/9^<ƒ( e‘ÙnOŒHeM<ÍÌ6~Rëõ-õT=†lb;‡ZÕÕÇúçDU)ÕŸ§l@š‘6ª 5Mޝù l<{—½„â‚)CiÛÚwI|íeºÃ>üôã+ú—8”ãPcñ<· ?…\ö#HëWö½W@>Õ‡ªåbÈÛ‰¨dF’šáp¤¶¶'ɲ=.UÈÎ2A—á( 22ˆ…fd:sË¢°Y§óóæ9äîF‚.%¸ÔíÞ: ݨlšµ•œ-6óKžµûÙÅ36ŠnÆQ«S>5Y‹Ï±ïÍa7ªÙ÷ØöÛŒ:WÞº„Qm’þ™ eÛ†÷íN÷Ê•K*ç¬XV!ÄN˜¯Çÿ~Òqäο³àô‘ð߾Ÿµe›/ýPs/)xçÈ¡ï:øÁ¢Eó–søF¸@/Cî1ðÝ~­† ?¦b &#ÑÎÊÌŽ;“Ýds(Í/ÉÞܼ ÇåvÒ™Žyü¹CX(8,\èñИޱï=8áp,"x¸ðm'mRžÿÐ2ä2 Ô1nó#ZlÖ&k3µTë |ÝlÈ_.ÖÉ‘ 2¡í*~xö¬ñcçÏmß:³ýC­Û‹Êf•—=PþDYv~~ö¸ ç§ædâMðÓìPŒÍ.kì·Ë‚D=P¡Ÿe_f'öÙ”÷Áõ±tÖFÇXRZƒGÊ^îI .`ÂTÓ²_Ÿž)ý7T–¥—öé‘Ò7¾Üð”pÁ›î²h%ÿwÞZu ¸Ÿ ;È\õLÄ÷±¢ž¹TJãÖ•ÿãX¹al,=Œ§(g`Ü!€˜²¨Õ ¡îé]ꚯ?ÏÆŸ)æ38Êò¶…|ô°ë^7ù.ú-ú÷’ò{I4² ÁïßkØëR}G›sgnë–,îqc×±çc•¯&Ϥâgþ?ŸIE8 Ô¡Ð`â+Á²‘?ÛJo,fÉDtõ,¬_jγ;^ŸÊ–ïË-º~`¥*?ÐÏNcûŸ3 l6šÃ¨Ìaàsè ‚Ù¤£êÓ Þk4‡J­!zŠÂúwxgîÌí@¼ø‚*Eæ+üþéìm¡Èï[ºß?J Yñ5žf~pÆöΩßãmfó÷Ï>eÿ‡…ëʃE„몼+ñ92KÀbí{"ãB™gþl}¿rÎã3æÎ{ì±y¤záò æ¯^¡ØK†*kÕ1!•ˆÀŸ÷!‚kxÂÇvQ£wNá%îÜóçš`1ú‘n2ôÏW³^Øtøé2åìW\H†Ž ©?ú…•ˆ’­>Œ,«©z—ª?úÅŸ3Bz’OÄH‡¬¨c¨™c½,@.~ì6 ð\ÙN•i3“ÙMñÖèÇ>©Û,J߇òÔ§Üœ dÆä“òwÙcxñrvTÊI]MnïÜ9‹t©=³kÄè±y»‡ºa®xðݤPgÕh\É4^ÔYcâSåæ~)1)±$LÍIÉI™I‡’-MrkcÜ1%aucu»í))¨w8E¶›z‡í±MWÅ‘sÁð1»aÎ ²)JOìäiЦ>:$ù½¹nþÍCJëM^òF>ÉZ‚×±!ÜjÙšÊÿfç[¯{š§×¤áìë'Ÿë¿A`UÛ6dýëÙÉŽ§;`Ííõ>_§ wpÒÀ·\ÿ?>Æ xœc`d```”œu莈O<¿ÍWy8ùöFŒþWþO„}{1#HŒyxœc`d`àèý»H2ü+ÿW;Ž(‚®”¡¾xœm“1hQÆ¿{ïw¡d é$C°RBHƒ2ˆ8)ŠˆH()Á¡S:…@é á¦"´]Ú,Î:t :Hpq(¡”"û½[lÈÁïîÿïø¿ï»[Àí%a@£©_¢é®!!§¨zWÈ»#k4Õ rdKJȰWT+H©3¤U’{"ÄÚSÒ"{¤@VÉ òŒdfý‚Y¯62ï £ú B~U7¸iôÝ%4ÜïèË!Ùæó4<…¾ª‘ò´ìFY/ ï—Ð÷vH ݪíUP–cDÝx/cÀ?Å"Uä‚gma[uÑ23S“’ETW§¹pžK—³Oè_œkBÚ¨¨!V¤Že7Œ@m¢¥6§Çrfïÿ©ËÀ®Ì]çþ+”t «ìu$ x'Ë>"Âó靨Ñˈ˾s©~S—3ïyNÒ3ß–ÌQ¨s¶˜ ¬®±ÁYrv½75Át¬p`kC$IÜœ…>îjÆoç#ß?D^/2¿:v½.žGdÞ¯[ßïÁÏNoL6‡9Tm:f﨨Ž{‰Äßl.Ìb›ÅOf›§oÆ÷{ð#سY´ÿ‡|¢ÿmªa(ßPù—Ã]Ìw6°ýÎ<& ›Õfù ÿ-ׯ@:N‘: ·@œWˆT )GÄÒÚV8R=þ=ì:néqˆs§þÌ0ÍŠxœ%Ù»o$gvðÞ@I9˜mÀc›"MK­¨)’Ž4-R-‰lÚÿƒãÍúiÚ»I£_h>Š˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€4ZØVÎLf’Àò BZ|šÜJ¦î<˜¾&†¾ø JrÎX˜ò 2 j ¢ Ô " T j ’ Ì ê 2 n ´ ò J – è @ r È2fЍÊô *ŠÞjÀœÚ\œ´ F†Ú.^¬ð*Z²ì,`°È``’ä<˜îŽÄ@’Îðø‚˜Ð F–¶ü0Rˆ²ì&<RhÈÚìþ"4Žš¬¾Ðâô   * | Ž   ² Ä Ö è!!‚!”!¦!¸!Ê!Ü"&"’"¢"²"Â"Ò"ä"ö#„## #°#À#Ò#ä#ö$$$†$–$¦$¶$Æ$Ö$è%0%˜%¨%º%Ê%Ü%ì&D&V&n&Ò'X'†'À'þ((*(J(j(Œ(¾(î)")B)d)ˆ)¦)æ*\ÖD?/\Šxœ¥”ÑjA†ÿmÛÒ*mñBDd”‚"Í&)""^XÛZ„b¡ñ›éît35Ù]f'ÔôôD¤Ïàµà#ø‚^xç•â¿“©imÑ,3ûíì™ÿœœsf\ Rþ®cÇs€9¼ó<†q|ô\Á•àŽç*悞k˜Þz>…Ùà³çql޽ö<³•Kž§p¡’{žFXùäù4Âê3Ïgp­úÍó &k·=Ïb¢ö˜‘ÕI>u\T%˜ÇKÏcÜýÁsðÅsóAÇs ç‚WžOárðÞó8^ß=OàêØWÏS¸Y¹áyO*Ï=ŸÆ“êyÏgð°úÆó æjW=Ïb¦v+ÐH8,ÇbÉgIŠ!ÇÆYu¸*°Ï±ˆ&Z¼Èk´Éø¶ËÝËdÃ=å,j†!°¢mõžŠE,­Q–ŒN:Vì‹Åf«µ Ö²,é*±œ™<3Òê,å® J) ´)—¢p¤Ð£ð¥» ¹JE[¦…h«žÞʺ\Û¤Q‚> $#Á¦Jú]IX¢Dä$cΆruŽ¿q#p—zÚs‹hR®ˆT+#êâxân_sn5›ÿñG¹0 ŸÈÒqèœã‘2“$ZaëþzýdõR¼>?)*íæ²úÖÕ0v:eŸr-Ãö±šK—Mᬼo¹Uã*PªY÷†½¥·È­”=6|Þaf³9G?û¦(;g”])¬‘±êIóTdÛM#ÓXôä@l)aT¢ « M§"RÆJÞwúF±ŽÊ¶*“Úà䯸P_ÂKã[hðÚuWÈmGE#/:êÑkó[Æîîn(½rDá0Êz—µL{î¬\§$´vMè4{,Ô]ÛA®bUè$eS…Û£ýº«„rUÖ®(]–Âe•—èXÒnøttOùuøµ}Ûu]3‚‚5ê»äÚŽK¹ŒxóoÄA/†ÍßgfäÛd¶sÌ3W®}¢æËˆ‰[ ßB,²ÄbK-·ÌEû­´Â*«}òÅ%/tÊ+o¼vÚç]pÃYçÜ´ÁU×\…CIÉñÜœ´´ôŒ”h~$ˆeEƒHjv4Äây‘ '„3ãAô/¸¬kTxœ5‡;NÃ@Eç1Ž£Tcaþ<ó ;LŸ(…q<„ŸyRœH©è)&=4Hi‚صÇ]ö‚P° –`GºGçößZI@ø„I=„ßó Ÿ_Å.^ŽÅûxrfQ÷8Á½N…M£B“Wx!]”±ƒ¨M àdDœƒà=^p¾N?Ò¯”¯‡Äm<¯7Œá(9$7rÈŽvhY‘ w(@ˆOQ nn#ˆ=°GV°ofX žlhÀ ^Ë», åªYÝJݺžjXèn¶qÿf¢Í…f4™ŽK€—üy¹dOêÓl¬/—ú¾Ë+m6È• ÙšÏà µ•RýÏïÝý†eFútomcat-connectors-1.2.50-src/xdocs/images/fonts/OpenSans700.woff0000644000000000000020000005433414655113617022713 0ustar rootbinwOFFXÜ”ÜFFTMl\¹_"OS/2ˆ^`¢tÁBcmapèh²ŒèÜ™cvt P]ª-”fpgm°´à»s¤ugaspd glyfp8ãWd`û…ŽheadAT46ùC¾hheaAˆ$ÃøhmtxA¨XÌJ°kernC¬# – locaQÀ®®ð æmaxpSp OX÷`ƃþ 4¡¶ãŒl peŒL@‚ ]Ð+,¬lìœ\Ü<¼|ü‚BÂ"¢bâ’RÒ2²rò ŠJÊ*ªjêšZÚ:ºzú†FÆ&¦fæ–VÖ6¶vöŽNÎ.®nîž^Þ>¾~þAÁ!¡aá‘QÑ1±qñ ‰ míÝ“gÌ[¼hɲ¥ËW®^µfíúu6nÞºeÛŽí{vïÝÇP”’šy¡baA6CYCÇ,†b†ôr°ërjVìjLαsk’šZ§>râäÙs§Nïd8ÈpùêÅK@™Ê3çZzš{»ú'Lì›:aÊœ¹³=^ÈÀp¬ ( §K{Žxœcag``Ý$KY·±že@,q@ñj†ÿo@<ùODu‰þ™òÿõ¿þÿþíŠý c p@¨§ ßµ.3lbd²˜á-Ã}†M Œ! È!ÓxœUÏOGžY 0d¦ê2Û‰]vI•´Jaj{»nZŒAš%=ì‚A¦§œrˆZÉ= ôy›\LN¹öÐÿ!‡öVŽÉ5}oÖ&$R¥®Ö»ó¾÷sÞûv¬î?Ü õîNg»½õÃ÷¾k}Ûlܯµjåµ¹ñõúWk«+_~ñùgw–?-—>)nËý[ó7òîµ¹Ù™é©ìäÄxfÌá¬$€GŒD¾Ë@ÆrIó½Z¹Èz"€¯LQ6’1ˆH@_ñ8…–GïYªÔR]ZrW¬³uJ!üY“bÀ÷Ú׿×d(à®Øu¦h…Y|=lUT­ þ¸g‚käÉÌtUV§Ë%–LÏàrW° %|aƒÛ…³¬%ËÎRZÜiwa«­ƒšçûa¹Ô„9Y³*Vµ!a¢ “6¤8¦ÒÙ©HJ/ÌÙÀeûÑR®+»ñÆbô5c1¿A~ e Ÿü5;?„’¬°DQ[Û—yZoSr/¸R˜W ·#/þy‰‡ÈDÁ}Åh Nø¶öéòêØkcêRÔMdâÁ›þ¾®4I.gØn¶¥1ÄàÍóSêg!¸Q¯…í׷[ðAû¡§P½¼7¥¿âùùK›­ÿR3l 6;ìûÔ†Óbû(@¿­SY°}ï)SËK!8i^Œ4î’¦?Ò\ºGgÛêh™B³+ìøi ý}d×O4éÂÜkÏ—æz^¬.‡ÖV`UÍî±€ñ"6 ½®: oÈŸV˜{¾.O]ZÊPö¨-M{£ö؉ ›aç3œëÎ;Ò•fa›˜ê‘@Í„ú’wµ¹pßÊ—bã=us¤&+[CÁå0 ÃÊ›Àˆîj%ïÙsƒ#ñœ.rÆ2Æ$J[ˆÂÈf×ÈŽ^·Öxöüâ=¡\×Y‹·v*僕Dò“v¢øIgOŸ»Œ‰“ýÔáN5ª„ÉmÔésÁ˜²¨C($(Ò6 Ykï+ÆúV›±€•œY,;Â8;8)榉Š6‘bj2©F¬3ˆeS¬o1{%ŒZ¦¦ÇUVM©œ3ëx 'è)"Ï9cSœ=ËñYî%èµmáï'SÊK-úh¡Ò OvߦÞÝÓÏr ÝìUèBºÌ÷pØøˆ.åç°g¢>6vGƒ7.7pLr ™ÈÁ´<¬ÀŒ¬¾IøfŠO>‰å79º÷qö[À‰µŸ¤øèϸ4© ãþ]þ##2¿ ÿÿxœ•| |SUöÿ½ï¾%/ûžtoš.´¥”6M;ek(XjiK[km+BAöUDÀŠˆˆ¨ˆˆ ¢ã BE†q”ap\ ""ƒ ?†_eq\Ap„æöî{Iš"þæó7¦ y·ïž{Öï9÷܇84¿ûs|\Ø2¡Ì€•hµÏ›-X2HAƒ#¨¬,ׂ|+.µø|_Aì%\Tì+t:ì¢7-oºäãéæÑM7ÛÐ8NŽ]9ÕØÔÜ0jL!-'í¤\™CB /!B4"'¸¹ïH¡Ãm?,„¸3¼ñ³ÙÙÜ[ðCØúŽ3³7»OB<v¡”‚ÚÃ5‰)Þ.ËZ£8Þ-¢ÕdÔñZ›ÍîLN’xÑår»í¢–Oõhx.SÉç°á¥uÙˆ¨µe>kii~>,Χ,PýeÅ.X¯Åz½Ÿ@©äq¥6/{û=%ð¶ùˆ½‚¯ÄK¾ÌÇ=YóIí¾ê“U°#¿ {j:kÔž¬ý.”ô^þ{¤ú«èT¼ž½?úê~ŠNaïc_}…à?‚š»WòÃE+JE™¨/z0pCº‹$%Ù bNŽ';9 eiL^‹Ç‡,(¯_NRB†t‹Ç’•Ÿå‘3D}¢+qTÐîõuAA$¢ ^y„ÊÂk5aB͵X‘º¨ÒR哲"fø\X¨|Ãþ©²–m%‡×Ÿ™eIÆ.KV?ì/*.ñûN—ľㄢÌ,G1¶;]~‘þÅÑ•—^¿åÇqÃlýìðÊÏßhyvËþ­5ôøðáÑ™ƒ‡/Ň~·×väP5¹å".ޝ}mÅš¿ØŸ^§mø&`¤§FÎ|àŽœ)?»¸·û–&Ÿ³_TÖ}AüI8ŒddGn”:QHwº\‚ 5#³ÛላËö&{ÍÞ~ù©¹‰™qnÑå&É*¤ß+,+c?ë4¿[he‹|`ësú ýEÞ4QP4Ûoö:3°Û®wÌ+7®0ÿe玭»pð¥?s¯tøŽä.¿ö{-i뺲¸í‹/¿ýúöïWª„Ý]œúÝç_~{¾c2oè>/"X[È¼Í ”æ¼ZœäDZ§ÁfËŠ‹Ï2 #äK–¤B—'Þ©MOÏÏ7ÇÇófsNMÐÌóžê oÃVf´È]Æä[êÎg‹S„[ª˜{©º–¹ò?,?gÁâÒ™PѪ.áâXkãA 6b\” ŒpØ]C°ˆèŠyïüûýçµ#‡½ÿÍ3oĉ#Šðô{ëºÞ]:ñÞ‰t×€aøŽÊÒa5·5³üÓwVîmlúí­ÞüÚAznþë+h÷„eM“㪾ã¸ýƒ›§ö¿aæ7ð³Šß°ÂÂsÌaQÖ : ÅQ¨>Áøº‡[ã (5`Ôiµ„ç‘$™téìïÊ”¿ó…}˜Íl-ñ‰œÃnuy3¹†gž¸²êñµ]^»‘+À2þèå½´ðÒ´äíø³GŒý[#÷†ÃíáÞF˜#ýÚ{c3'y‹­þ".Ëç´r­ÏLRX™Î¢øß€ÿ³xq'mÃË:ñ2ÚÖɵvâé¢NºD]½Œ£ HDŽ× ˆ‚D”@aÔ>ðõ"ñZK<øpÑ=Ÿ MÇî“ÐsX{^å5ÞÆ5q›Aî–?Ã_ñðU¾/,v›ßãÌÅámW®(c•ø…K~g@+é2i Ê6º¯þAIL¤š Q«£Ñ‰Ý˜K†+z–Ðc –C<È€cföìN2ö`2IIí#jÜ+ÞÄ ÞÔBÌ­S|Òà@r¢KȉÉ)NIâ´VmmÐ*q8'ÖÙ4ª¿Q©³©˜Añ-~<„ó+®CÊÂù “±ÃnÄ&ìððu]žõBkßÛëoÞt˶ém›¼òã;G¬Û³‡k;‰ç½¸tæÀæ¦Úʃc«³[wÝ9ñÕ7w¼jThÞ—m™hL ?Í>R"‰‰vÉêãINOî»]nW]PïÆâvkÓ%ƒYkÔ2¡@tC<Ì¿­åV…âÌQ=cØ;†ƒ#–÷¤±ÀÒ‚eäb¿òAYN±§ç]íë_ÝM?¢ÿºðúͶ>ýĶ×gÍÙþÛ¿V®³ú}ìø Kü¬•曆Î߯9~n–r‹'Ï»£éÛàôöþO<þ:Ã7^àõEŽ6TH3IDæ8@›‘dž›Pêm#&I$Š`a>Fys·ªLW‰`ñø1˜¬‡ùu/¸s~Î+ôãÐãÜRœô MÓMF½„óé1œ’¼Ò5åòó¶†Z:M‘+ðØ4% ¦@.„W‰³Û#ÑÄ$»M¶é!ìŽ Æ!$:îÚ Cõ£‚bÒ³¤Ò•°D"³fœ(ÌÚT‘‡1ÔD“’bnÒß®Òé——Öú¸'ÐNÿ}}—¸ÐO ÞÁ¤ýÂÑéåQX—ãÿê´C_Î}M¯Ð³¨ð²è®FHGCѪק¥¡D+²fdšRê‚&“ƒ8âFqDj"õ¢·ÇV•ØÈÂòº ¼`>Õ¡ p(œ (ƒ•xžÙ6"xËïµÊ† ÿûÞ?èåo6ÿ{gž0uBkËò6nÞ‰·™þc·çÛ:õ ½¸§¾³|ñ´Å‹êlQ}Q‰bo»À‰ô 8ÁŸq œ iÀ­®6HÀ¹(ˆœYX 3 úû@ÆþŒËåóq¡“ü+˜ßw•¹6…UÂ!ðPi¨º)m} qËîL‡Ã”œ,›äüþ¢Õêñdgë‘>¡>¨CÞú ŠåŠ%y"sFÄÈ„È3¤ XI ‚H' 30e‰6…G€à_\ÕÇßóð–Õô‹/¾£–¯m›‰yÛÝ“çͳäÄ?GÝ^3q|m«pèͳÿxCó;swu~ø—¶}U£vMûí¾«{šÆM¨6¿|<÷aýðA·öWvCRd^®¬ó ŠC¨,š$Øôz¯Œ)3ËœZ4›‰Ó?*蔈¦.Ö/ÇŠ\8ËEÌL'ý@þ\â5búŠÞš¡,D]_EŸ¤«ïÖ8ö™÷§jô6Ì}ç¬ûbó÷‡.Ž›>¾µåÁ6RAëh“ñ²cÌþß·Tÿø¿ç°e=³÷{¦Þ³¸ŽI=œƒñó”’°YÁ„r›A“9ÎRqcÄF5Ëõ"û}k}O¤#°õÁf˜Åf6Ÿˆ¬³lI²^Ä¢hÓšƒZ3/B¤ÏfÞW¨Æ¬ —±Ilâ·Ç¤DïüÈd\jç:#“):ÝŒó¥àÄD”0 ˜ÅsIÃÐe h°2|=ºÅ&ƒhá1_Ú•BΆ¹‡ñîÕø»ïè~ú¥*ëf¼p RrÊô€rI|¡ŽÇC« _þ­ 5„égÀû™œe7%^:;{Ó—°rhƒC¢P€\*FBB”F›ÌˆÄÍÜŽP#»'~ÇáÁßQójZ¥Ò(vN6A|bú8<–n¸m5X3³LË!¯7©1èµ™´£‚&>"fL,*Å›Š˜a)äMƒ¨ÆçFœ„{åãö†S†kZÿîŒ3W>ú¡õÑq>z²'9¯÷XÝÈ–C‡ïl;°uæ¦ÖUƒÑí1ùú¤îIâAðE¨ ¹Ri©Ýnóû m}lâ‰óäÅAÞêÔ””ðÚÁQµæœ¤>=¸M§-‘D:P{R‹ŠZíŠUeyŨm¹ˆ]±«~pçÌé—8DO*²YÓ!ÈZ1P†™ÇŽÝ6«jnœyú‹¯~ˆõo::ÌU¨~ð‡g? ÿó;À5î©tñÿЫôzË)¼ ŸàÑ{ºÐŽÑ-Zƒ/Ðö÷Ýã1`é‰7ŽcÎ㢮GþòÔóÿ¹¿€þÄfÄ„TˆÏ}%»çã“uº4È M&ÆgŽ« êÍ€~Ìf2ÅWMVä®Â_Çz¿ê!Г͓ªøvy=Qü§~ò¼Žâ·xÒ#‹é™Ë¡Ó¸x×½s/áƒûÑ.a÷«{—m³hS¶¯zÿS2¯vt㡺lüÄÝ`w À_ûp¢‚€[²Ù Q7¸ìÈ‚ªƒ^´BuPk‹5EÈíIýð–XD¯ª¾B—Ô2¡?¾‹gmìÜõº—¾ÜŽKŽ8ÙÚÐ΢?Ÿ£®Ú5ôÔá[^»£+kÈx(Ìj€‹€ße„,ž7 úê @x¤ÓÖXçÁïà3¨%6{¼_ª0ŸN¤÷Ðñø0ž„¥oÓq[—ãw·8§E2 ðDEɬ#pKѲ²JE´ÔfUòîB8ŸpˆÞz@!b·X2aß@;ÛB °«oऻ¸] –`öõ¥Rgp0?eAÈ¥E§l«Ê<1U‰íº~Ê£Ú¸*0›T‹Ò+áKº¾¯ x ®‡×Ä«'Þ|Ï£«ßØÃ¦ëè"ü ž¯¥àÓžüñ2þ_ø©¾’ß®øJó"¼,;Ñh2Ù ˆE;“Ù¬©š‰éW½H4vL+™i*/LZýØ‚%«¸=ôýn9¨Òq¬Å"Ι>cò範. »?WñÔˆŒ&@Tå4ÀÏ ¯u ”`Öjã‰Há%`‹ Gôä/×”>Õ:è°÷zzíU<ŽÎ£—\¿Ê&J_¨§ på¯óJ¨TxåBµL›ËÅky³YëtÄ!- Û&ë‘\Q§×ÛôÄ©SÔ¦'‰Òlv¿WhéÉôb"°ÂA‘˃ñ…Öµ®^ß,ÜŽspòc÷ãªVº¾@òÆO™ÜZ:*ì>uzé¡Rj{œ+Pm«b° üvÄ£´„øxòv=˜ZŸl»é=údÙ•\tñDŽÕ±p:ßï¢Ä±0Z&釳úq2l'1T©S2v%cÞE?£ßìzòÈÍ“fô¿uõƒÖa髹Gç´Îºª¹%ó¦gŽlÀëü«§–×Öä2¼ìÎwìûGqÁ¿ûg6”g.­ßÁèÏd5_‰í^AL#kd‰ðà]øH<ëµ{qÝÜyúÇ×Á{æ(…{½ 6Ö÷²¢Œ€Å‚±]§Ñج2øЦðÒ{a‹]äA}˜V3B‹Ð²†^ø ý‚¾ýýv„‚®ÚÍ—îÇž«ä宥/=÷»í¤Má;Ã>%ål„“e±Z€ÕaÌØc<¥áÚ«ò—+¸”šèËÔŒK±ÍU êjQ²kcÍ‘>c¿PçöÀI¬š¤•Mv›€‘Û-˜ˆ>11))E¯Ó%'Úq›LXÙ ƒ©ÊX®ÓƒS]¥‘¶Â;’Ée±Äàª%ó%6 ÈQ>ˆ•ôwt~^ìo耰ð.øKS̵À'Œ9:m_뛸€rÂ}‹/úB€‚ºþyzséÅrâë:RòÏúÚ¯+Ir„7M o†RuBI–DY+jY¨&¼^§á—!`ñWkQÉV|~iOüR©–¸fÿc¡‰>GwÀkþœÀMx $qµÔÏe‡Nrßs猡\•ž*ö ~^#I`$Ä@‚¬ˆX´T玔V­¥…å`³^`·À ôCš€ëÈXntײÐA.Ÿ¬`k-×üd40¤á1‘$øV«“`*žaP ÁØòjO¡2\]UÊ?~ÎÕw¹·BM||h8wôù£÷»¬ª­¯¦{¸yŠ­$ " d#"Nh›âfÔåq°åæÑDü¯O?¥{Ä+ǯì`÷Ѓ‰•Gjåʦ ÆÑZyi°ÕÃÒ=ô\èL¸VŽ‘æw)ó§ŒXeX¬Ié`­=ꮺ—Ïâõ¾3gð¿hâ¡ñøÏ ±" §á oC®ž°sXDžg»ÉL^3p"RK¢¸06ÓÄaß+/w?Ž/^ˆþ§!»»ª¸e¡6†½ºèRÛ]©î5 –ŘÙkòø=¤¶ëeÒ@÷<ªðWó§È*Ñú‘Ð!)@˜f÷!”ZÕ…øX < ßãt9¸ýe—†ã¦²ü©¾厉ï'¨1­ üï@~¾²—YÈ´ê5z.-ÍíNOÒh¼ú¸‘A½^°ÛMA;à)‰DK/Ó£Û¶í9úÜâÚ±µC` Yص‚,\ÛÐðÎ+ùŸ&Õ ªÏ R;?ø•ŠQÝ®KJ<˜ïo±pÙR*ïÅ<_Ÿ“ãr•x½Cã È€ ¢¡H02(§òàë2‹²¹ª`vvffÙÈ`¦ÙžW´'ÄÖüàS>8/—²¹~xO§§&ã*ÂX‹CR*~ùô` ²Â{“W·ï£›ø.1¥\-üo?ãý¯ž)ÉËßööë{éô£oþsï¢üŠªŠæ;.œÎ_j¥Y glysæ¼ççÌºéæ¦ºöm|Ë3y#oÝuˆé}ËŸ{ú½¿¿°vâCIö1¾ÀÍÙ™Ûæ¾ö¾…¿Ê—UŽ®-ë?ŠÔŒ™:uÌ »Mà›·=8?¡Õe’õ,;M¼ÕÊZÍZ„!—€Ð «[K£Ù6ÛgS’&‹Ý„Õ ~=ºë¾¹ô(.$ó¤t|È­úþåý¡ïÁìÏX9zË߀ޝå9sk r¥,³ü6èLZ'ÝäÊþè>Š"_¡RGeª²¶½ý¦›Úñ6‰°dݺ£®ºø°î6jWîkó͸­`à€S\fÇA3’M,qÓNˆT¯"µ{u ucAÉÞí"‰LX1¿±âÆš¸à£ÙÊ´Ô÷­©‘ß~5{ç^i›]㌟?)ý7¼<ÄPŽQÌF­Á Ñhµ&bßjŒF"jÄE)ð.ëñuá¬>ŒÛKT€¤æöîX°²™Ç'ʽ½Œ1ÀÌÛŽiBhî˜B·ˆöPЃ=Ù^ƒÐÈs;"p@Üø» ‰Œ—ÊÁ޼¨&i·Ù”JTbbBB†A–µÚt›Á`I,À@—Ŭ3%b­CÉìË"=H!ZOŽèIfXQ|.ß̼&ûédߨ—ø•ôhý-ó§Ò£_g[ò¶Ï¼LÈûãÌ·÷Óêo™=‹[µpᎎÐ÷|Ëêš[¶Ô6í?Êbßmz9Â÷m@·Õ+A ¹ƒ`a´2RUJcµ8V‡¯¡MUᦦÃ@ŒïOs÷À&ûý…€ú›ŽìñÓ”ý¡8–û‹z}²Ùâòˆ Ól"#‚¦kY¤—)¼9)°Í¬LÎϛӊ×ÎX¼hÚôÅ‹¦~J»ŸÿéH)üâ Ú·¿ôb{ûÖéEúá*¬y[qÿG镎Màÿv6ˆkÃinQ”´!’Ì’9|(2ì# ThLRJè le‘|±×Þº…¶,¯3Ì0i«ÅΉ$ù]Dì˜m6Ó£—sÓ>>ðé”}§•Èd¢}õ£N:P¬ZÓN?¢ßý‰^~˜¬U?nˆÆ6 uŽÂ³T†Qœ$‰ÄÇÇÅ¥É&“'>ÁeJvê­V‰ù=Ôÿz Vw©3"!=W8";]¾¥’Äö¹YwNf->9?ðéç§>7H“YåGCÁæÎåí»ž¥/ok¿™€XZT׸úçÝøÄàiõª^‘@«™åœUÑ* sQA`è Py˜¢°­ºH/]"æ!Ù® ÿ/У_晊^åçÉôŸÚõ+Bù–=-óP í€9ØÎhŠ)>ÊJ±Û3‘Þž¢OÑ&¹’*‚.3ÑV‰óI~ 3”~¶mãgq=šáûˆ‰íñ&sdÇÅ ‹vŒ¼ùD}{ß飗.,ùòo¼3¶ñ‰ê·¬]¶h®Þ±Ë“ÚÕ§x\z^ifñØ·¬{¡ù“ô~7fè{7£7è-ª!f $ë5&“ͦÕpÅéÒZMÖŠ Ao2 :!L®oo¯þœË(,q(Lõ˰ÏÁªØšÔÍžÛþÚ‹OlkÞiôÁÏx?ó½ñ—°tÒù Ÿ‡>:„Ѱìn3¸{;* ¸9‹Ånwê4‡U6q‚Q0ŽèÁâJ^˧ÞSðXÈëÙæ‚]ó:ÞÇÌîqÁêÚ›àN…æ1³çŒW7‡ó_~Ì«C}vŽi„2-½ŒaÑ0galqÀ©p²œÜW ©8ÆÛi.û{º, }Nâ2ÚÄ·„–-œ>n9צήXì€9’Xÿ¤ÀkÁ$!—‹h‰”˜˜"‰b²K«%‚É” š ø5µ1Ôò«õNé VÉ(ì6@˜~2Šø’¦;¥éëtî¿4%UäSÌãºe¼ÅlÀ¢ÜOû Î¥oãøB×#| µ,ÿ¦zëÍœ;ô•³éö[+¯öÅpÈŒ7ëÞTÒEm¢²5^À‚òtƒV§ÓË"5jt›z×bŒ::˜´ ô%(P1p9Ý€GŸêģ铸n=wž¶s9/}·†N‡:ðºT­á€arr-:»Ýìtò…ÕKˆ]“’bq»S ‰‰žØlЩtƒ>œæ«ûÙÆXÀÜ xWañ`ÌÚ [pX 8“0s¸0#œ²¬íÞû÷]š0Rü×7U­—öaã-c/67hð§ÛÎ’ŠáôÄž4½÷U™ž^AþÙ¶QÍÓÒ|n³hlb `/€f ²|5EgµT‹ìì—=(ÜCJ4°Ž4¶ŽñȬѤÛyÞ›’l4Ú»ƒ|úÿ±mkû‡`¿EiŽÎÌ‚@–ågÝn×à¶9MÃ[/Ny×¼ÏĪÖß®_¼¼mYÞì¹þrÃGà\]Ó4‹>mέNÎúçͤû´n÷RpY|)iPp‹È¢C:b2¹ˆÓd4ŠÚŽ["M#\KWÑÓ0‚Ñjð»fá0 çá¯E/$$p.—–Ó&&ÅÙF5ÆQA$hâà%&ĉL©ôÀÜÜkš&X«i:„ëp›ºZƒ6« —^ÎGÇ;¾³}9KëÞùmíKÞùÊ@| 81¥ý9y蹤ôOßHÉ£ƒå=ªŽ€šªôD6úš¬:N6âNÎmv[­æä½;Î]”ãâ B•©6hu#aÔ5íTj[\OIJ–FÚö”<º'9…e—Xß<4ËLäöìßëoçÕ6âtåSÜGW¿º£fçÎÏ…Ã _‚7íí\½½–v]î;·uMçþC§<4QÞÃožfAfÖÛdÁÏiј–ˆûd»læxN/ ÉáH‘2@‡*þ]‘$ëRê¶¢’¬‹÷%.–J.‰ugIY%™%1˜sOñÒµKÆL2fÉú¥~ÛKn›8¯±mÍ’â£3êêgÍU;‹;>é¶%k—øK–®^œ9mlÛš6Ÿoñš¶['×ÌšY[7s6ãµ¼^ öèDs¿1ZíV‡4\ˆÀiYÖ‰1ǹ‡K´Ú¬ AD0±™´F“±!(™Lzìõ½ú$Ýf¶¬Ò^íád(" åC>‡×ÁÞ?c=¼±‡«Ä K÷ÿôÓOôìþóŸ·é <ˆvCŽï<}~pçã{$ä ˜8QdO™'<‘/¤4ÊĬgd ;$æ’ºŽÑ%]ÇT<;ðÐ1å¡ß ›9Z‹Ë"ýÒPVb¢Ï…\¥Hq±-®  Ç–cÌHÉLqjŒ#ƒü 0׳k£Öm"HÉî*3É)íz¬éCiëc"Ž|DíRûŒxaåàågvoßÛ0|Um}Õ„¹/llRvñÐá'êTìË]÷ÚÃgvâò ?ɵ¬OãºeÏ5¾êë׿ */ðÒŒWoê3¥êÉ?Ž:š]:?«¿/­ê· ›Ü¯48¼¥ÀÈ^»øË¤Cä•þ¸Ô€ÁªgZáŽ3â‘êæTUÅtBeÄvE¹FÊGV ŒÄkë ­© ªÚ†VT tcEYÅÐʲÁ•CÕ³7­ÝçÅá`ß@Ë~¶gNŒ²ÍhËì—éì—ìL..tàx៓f+ŒçcÅl‰õr¹Ÿñ‚`ÞXéZá­;Çš&¹@ ¾Âtvp õ?‘%·O=\ú@éÝ|øééƒëž­šÓÕö>nù€½÷ÑÍ=J7ïl Nܼ'¼°…þkóúù äû'—ѯ’“Þ)½rú“k·  _+C7ÐAÛÿz>À†Åü™ª_ùÜwÜëÂAà° $»%ìr%›%.YJNóš †ΆÀm)¨ì½ÒüB5ì±£3½ºz•gõTŸ•âs8 WÎ@Œ—D® %÷žªùm[ߘ°¤þ¡òòßMX¹Žï—Zœ°†ëš9 0êŒ2?ðŠÔÂÇ–ÑŠ™é7 MµŒÖÔÂoäyÐÈÕô2€>"B$‚^£×› ÌÔ‚ì”Óñ¼^°QæìD´¥4ß×µ£1Òü?…°¨½ÊÎyo!Û4pÉXÂê¯<¯“~]t„‡¹Ÿ°ÏŸÐǸÁøàº…nY€;â{>*}…—!V—!ÅØÖ•D0 D8ÒWé×îáK;»®³—ñôNGwwä „U„xÕI}X+' x ‚„,1€_!š~™Wc0ð^ã5ðú= ·»^£®Q1ªU‰r¿Ä´˜žù¯Ú‹»¯ˆv^OÇìÝ Þ{7¼xõ¯í‡ÂµG¾0¢xäÈÈdJL°êÝL0ïF¡­ˆé¬zHT96´»©eìó·ÞºéÖ5‡Þ –—340†ŸÃ¾Ý<öÖçG\=vHYËXÖ§ Â+8ð]¬cÄm’$Q«Õé1&:ÙbÐëdÐ žCj‹©/¿8Y"É^'n 9uCÛÈYns'¤,‹;éz¦³“åÎ\÷¶ÒW×'`uè1ÀDlq¹ec çpàTe‡¬¬÷ñ ˜ã¥&uo‡~:©´Ÿú ‹×¾µò¹–¥Sð8®j[gk°0³Oó†¥Ëçß¼~þm0ç@®”Û-ÝH²ë8?(ULÕ™E˜™Eìv‡CNô¦eO¤©êÝ‹äÍ qŽhÀQNÝEÏZ„ÏŽ0WÂmÜÞ2ù•7WßÿäâÕ͵³ÇÞT_èËo,8ä©;–læÏ®.1ØgŽZøHÅÛ£§ùý›ŠJ3ÜUùCîûåÞá„d-¯ìÝ ïÝb‘Ä_\âLDÂÕ;ÊpSÑÕü©„÷':ŠŽ†ë˜ÿm,ìf5(Êr¼Õ‰§3Nr™œ S&¢–ç´Ñ2+.ùzÕ·ÕEG*ÞpÙ +EéSÀÇš[î‹ ¾Ì5åÜݶpáÞcõ‚õ7ßܯïÍ¿¥ïŠJšC»øÕ¢´-?àЙ!-†›- 6IMÐ(0˜ÞÁ ‡MÖ]¢a/õxc±Ïï~¾}óÆ¿þ߯¸±´K¬ûùâ³^¹ŠyÖ+1ŸËÆÇ!Ñ!G@f箈Ü$(?rìÊvmSºõÇö…wwR;Þ Ÿ¬¨(à2Xµ ‚ŒÝl6Ø 6ÙÈ£%0Cöå«g%5ȱ $«Ä8o~ê¹Úá câ*Ûk÷&T5_¹o®c›drSÜÆÁî‰J l£2rVŠ—{Ÿ•JfÆq³RÀõ¬T†«¼@„„þµ3pÞ;\~{ömé9ƒ—œSüJ)ÄгCNI "gÁLSRPÌÁSÕ±ö$DBŒoáξö»§ßøÓ Þ¤Þ¡••ee••Cù±¿ßÛñâKû:Ú['Nlm0áš8:£“e­¤á9vÔkô±'òJèÂQ …ÿ5î-TßO…ÀY2.\HùÅo¤«:±“~Ó‰çQ±ç3ç¥à±xìZßó‘ű~‰O»Í™hñÇÈœ…Žsà„-úy6ô’ÿD8HŽÊüþÈØ]×{'ù ÆJ;93ªÆÇÑ0öጟ¢Œ%æð}ß ß7O½/ðj0]HN‚²Ü§"ž–˜˜Àµívcc6J0'p h )Á “E;*hñ^Û‰ÃJ…êj㽺G]⊠–£ÅŠ–;œ>£ô–à¨]ã&ÿÏÔO®Þ¾ú6?îÓ“ûV¬¦¶¹¬´j@Îéßܰ÷¥éÏMH:7E,¥»[í7—æY3Qº²ÆaHÄ Hó'Î)d¢\?ºÞ˜»Ð±ÿ:¦5©c®3.:æ`dŒõÚ1MÑ1S•1Ú]„ó*ƒüÑ1Úð˜ß¬HÅKT©„ûè¥ ¥—Ò†f‰6b¶ oÁZ£3$‡ƒ»™Tµ†ê ^Ëúصf-m²Ò¹Lx+6ötI‡+àdó•VéžýÈfQ¸b©îJ±Re¤wƒë•2ºž¢Žõ´ƒ[ͯጡï9ßÕ$¼h‰Ò~X«êàðÿDŽðÆL„ÌZÄ%)ß+=Þ Ÿû¨òê~Má!¶÷ððÚ1w¡±¿óGcÓÑý£:&îÚû4EÇLíþY‘‡=YtfKÊ}úªôÐEê}ô=÷yÆ|3æ®î1׎éfûB̘ú…:ÆÒ3&÷ù½B:fª2†Ñ£íg¹F¸ç^‘³2ž*Þnu:õX«s葾:hÇÅi v+gaé×'Œ´BGꧬÊdQ{]A²Þ ,>ÖÔš¿2Ü–¯´è¯äù¿~ü·ß.ÃûH×J¤`]ú\㪯.Ò”îPy*Rl  lÇ!¥WáEaØ&ç«v’üëcîÂÿuLÚ¯Žñ^;f\tÌÁȘøkÇ4EÇLUÆ0›Ì ó£¥XÏ›ùŸ’:‘ YÖ”Ry\~aÏ)oæôKd%åïwÐp.xpGÞ:z”_ÏÇyé œ»þy ®Â–7/èn¾„<Ýž6 •])‰v»6‚­7Ý™ì‰3ıæ\âùE'il9{Ç Jj++4a»K9õ#ea§/UíaîxdôæÑX{î'75ï»zâ7øJã”7öp_ø¨¾z2D&¥ŸyèŠéíÃËX›nEÛäeûèƒïÜÉ]ÊûùÇ]óC–,…Jï§"‡ß„噫Ê<Æ7^;æ.lü¯c:ÐFuLêµcš¢c¦*c˜ô‰õŸ½pq¶oPNå‚úÀÔ‚’º~ƒê§Œ»ºŸwè³W™ì”~=Ñr®Äµa/ f‰¹&•ë\¿kÆõ®§F¯wü§›]ïßûº1zý Vùû¬Þ×ùèõ©€½™•ÿÆ¢Zy;£cd«c2#cÀVaŒHùù5 A —nðwjj¡Ý`(,”‹‹3SRäÉriFª×ŸZôûÙqó„_U0ÁlÈ4œ¢ÓRtš‘·"ˆD1¿‚õû)8¶G,jãÖëvŒ©‚Vž3Ãú2³b»#ɨ‹¥|‘V2ÖIÖÓĈÓX»™P°òlåøŽçžßÿý¿ß Ö<ºuÂ[_6¯üwŸÆ(”'<~ÿ{¯z=4tÎ=÷<:ñnÎ{Ê‚_æ¦Ú'N™|k+ërl¼¡¼æƒ‰ËCé·_?yÿÍç³úpñ<˘¥‹&âïÎϾG÷c©õ_+Ôx—©ß³>:E敪N¼¤È,="³k¯ß5ïÿ¾Þ¡Q®g÷¾ÎG¯Oµªò,è‘y÷3`ŒŸ(÷ØŽñ¬vÊâ·%êwÖ€Óø8fÌ]Ý7\;¦ûAs.fLýPcéóŒY£Ð³/ãÙ%Æ["1^éY½ æ¾+0Åq.W¢ !:Âq–ÄD.;Íbé‡Ü|)Ën7çt¦Øí)A€åœ1£"htndàëôZ#&ê›Ø"¾5²™¾#3«Ä©«´4 )‡L]%™Z"ϰaðӺʉÏ=ÛºýÙ'é?º¤ÿ‹ùÓG*4ÃÚ¾h嬋¦-œu÷ìÅS—?ë•¡Õlœ¼š®ûŠ~Eb빯±e<¿yÁcφ&O¿å>¶…ñYíwc6\¯Ú°Oá`\¬<7(¢æKùƒÊ^_äËV§Vk†œ“$”g3HÊ1ë÷ ß+Œi³Œœµ~å„z39ZVU^~cÕС#«Ê‡U²ß\kgçÅꑵ7V4Ô~dMýˆŠúZ…†±Ý»ø üSx{cŠŒ0¦`=GÄ3âÚÆ•ÿ_LQXÌo`íP÷N¶qøÖõÀ%<ÖuÕ†ç–-šŽèéáÌâEÓ¸Ö•7qJë³ØÎ:¤Š¦7>C¯¶TâN×ÖëÑBÓKÀc¥D‘QsŒ_ÀIô¾ÎäÜŽbF(r¾öʈ´Þ÷à£×§æ«–˜”>åcUÿ3X¹GŠ:K¸¯KéÏô°sê)¢èuèÍñ6“ÉlN³ s‚Þ!9iDPv'ðùWºc:º™ÃŽ4u«…,‹ »bZ»ð±ÂÍS|zæà‰ÉFIR{8¿ww‘#õ7+ÝÀä•CZè@ ¢ ﮬíéðŠ®‰®iê'êºûFõ7Ü—¨ìU‡ûM×ïKdá3vRp9AÓ&Š-‡§¦J6Bñ’”n±CjÔ? fÀ²Dë‚…ç“Ø9aìˆ9¯y_çÜn¤E¡¡çt«ÓÕ“ŒF\S‰¥–꺞Ê|,à›ðÁxIk49}½}ÇŽ-Cez—Ë:ü0 áix™QVUrøê—~vXÉ#6gØ–ÎK‹ùy(åBÔŸßßÈ9™™šþý“ìö¢TÆ—èˆËwTóó‘ÙÜ·*h6sFœõˆ ÎŒâ Ðó¼wD¿6ЗþMá=á=•mGÚÙ2‹éŽhxlÇb†ÚG.´Ó¯[ueóåå8s³ßñøÅKØrJë–O{³µþ­«“¢­Œß´Ü#ã}Ü|û3Ï<Š5¯bÎUó,ë"×,Y•Ó…ôÂÝûæ-œÕúñ&ŠO=ÈÀ|;K>PÖpœÑÄÉ÷ 寉yøUX·3³DÉËJÃÉØå ¿­©}êð[ÃðÄ”§+ùS·ÞT[Â[³‹þT¡žïÀüIR%î ï]šD«5Îm2É)2'ËyJE¤%¦r$ÅD(RõØìÙ­˜3óñçŠsrŠû÷Ï)Nྙӗ>0%ÏçËË+*‚õåOòzÑ3âÌ&à qÇémH²Ák–y‰™3ßÇ£üøoݬ´øâÍïª!^eÓƒcñ1(ÖÇRJ ët«ïÊUS•®|^s'û,”û‹×lñd¥)¿ä¯7ÞÛyCаÛÉj}ލßóL3w@æX‹·¹Ê!á×kþæ' ”5˜PFÀ¬ÓkŒ„;[$£ž‡a­þV¨Ð£.È“þÏ«+ø‘ùDN†³Øž¹X}Ø0ÉZI¯<†Í¨%zMu 0¼êðL*áB˜þ-Êúq>«~p ›TNô0DyŽ yNᇥŒ½çPûGb§Èè=E„EøŸ½y~† ð{<ÀôM|6ØŽm7Ûb0È„1;ºA×*Æ?ùÈÊõO=ôð:îüƶ<½¡½]íÓi¿g5òþGx{XЈˆu ò ;«[±±\>¶ÝùÙòÝæ½öÞáº;–DåDŸxá—÷î]Sç6]¿€®è]À0¶rÎ.>ªÁaŽãcÙ)ûÓ2öbnM׉‹$7|ÈN‘‹ž«â~öD²²î« ÙcÄdÄ œÍn”%Y´'¬V"%“T¥4‹l ö´Á`¯Ãë÷øÙ¬Q {f÷SÛº/=ßF׉²ß´„;ûÔS¹¡¡#[šÆÇOw½£Ø {Ó2a/d*E¢ÉÈHLIs&Èz‹%]¢HOÏv%%iúè].Ù-&%'5I²)yI2ìNv'ÛÒ2PL“ÌF›±6h‹>¸­w©×¢Ö}‘2Bl[EyÌŠ%üˆÓð%‡Gr°€ëTŸ!’†²¼~_¦¿~£ð³D¼‹žsáµ´:¾ìÃÆÕÜùêô½ì•wñÜË3ððölÃÝü¡U¾âÍ÷ìü¡´ ÄÚs;]YþW¾Çq _¥xÿÌŸxœc`d```”œõ³žoQ<¿ÍWy8ùöFŒþWþO„}{1#Hæ/xœc`d`àèý»H2ü+ÿWɾ‡(‚®•Êxœm“?hSQÅÏ»÷»ï…¤CAB)ED¤H R¤ˆ„@¦¤H(A$‘ ApÈ ¡ˆC‡t ¥[ åDÔ©Ïœ§.H9[KË0¸%_Ñp“ˆeMjSöдÌñ·BWAl:Ø4ô©üòu k_~úù±®±Äö˜ºŠ"Ƕä9~ÔĘÐÚ~Ç¢½ŒYiÔº÷2óžuŸh¯CB?çy¶óák´ì$Šr”­¡÷Ú¤ÇöϪ>æP$7õ[èCìJè¨ßÁ‹tÈ~ÓNㆮò¸šq—Þ—¼ïgíP™…ÏaÄ[UfðžÞ½¢Æä³*žæð/<ך¯™Å8š…fæÞÑ?ú~Qƒ:3Êaf°Mÿ7¨ëäÐûŸåðzÇFã[ãh>kªÏòºÑÎbOv‚eê'áÝÏ‘`Å,£lû((r‰µÁ}óƒÿ Lœtéq^ïø_£ÇÇxœ%Ù»o$gvðÞ@I9˜mÀc›"MK­¨)’Ž4-R-‰lÚÿƒãÍúiÚ»I£_h>Š˜§Ä‡‚¤Ôƒ$FÁnU×tà@ÿÄFzöëß<(|¬{Ï©s«n×­¯P(ü¦Pø§€ïýÏ? Qô¿…÷ sïþ#àJa1àCõÂßüøÝw?y× ø)Ü€Ÿ½{ð1|7­o9þÂqÕñ—ðkXÇÕ€MØ‚mØ Þ§2<Ãþ¾€/á+ø üÖ™'ðžÁsx ¯à5ü¾†7ðÚ~„?ÁŸá/á¿"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?"þDü‰øñ'âOÄŸˆ?Wø]áuáAaþÝ8à°Ëp%h~Pøèݯ†ób¸÷œÓƒ}8€C8‚c¸/Ã<„G0‘çM8ç·ë»B‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))RR¤¤HI‘’"%EJŠ”))R2Wx/pÍ"8þ;ôÌðw¿ ÷SP5;.Ãç< Ê炞ÎôÌ=³ÿö`àŽà&Îã8“ímÀ÷ B¶÷ E8þû~àzðỿŒáªõ5Çë°n¥›°Û°gNdžœwó®qÞÕÍ»ºyW1ï*æ]ż«˜wó®bÞUÌÓ¿@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍ 4/м@óÍÿîÛ߇çøApo10ÎðÃß"ÞE9å\”sQÎE9å\ ÙfQÓ€KXâÀ–8°Ä%,q`‰KXâÀ–8°îœÝ€œ·ò,Á2\…+ZÎÌŽc¸¼ZƸŒqã2ÆeŒË—1.‡;y–áÂ#˜Èó7=%o–T§¤:%.•T§¤:%Õ)©NIuJªSâd‰“%N–8Yâd‰“%Õ)©NIu>,<øÿÿ X„sá™úPæåü0䜭4`¶`vàDì4`™ò2åeÊË”—)/S^–¿LyK™ò2åeÊË”—)/S^¦¼Ly™òwÔJá·Ž‹Žg÷ÕŠß‘5]QÓ5]QÓ¿/+á×d7à'ÎünÀÏàãp]+á×d†›V¶á¸êøKŒ_;Þ–yÖà.ü7Úꢰ [° ;pÏù=؇8„#8†OÿŒþçð| _Áoà·Î<§ð žÃKx¯á÷ð5¼?¸ºáOðgxKÉø‹3ÿäJÿ 'œ™=­…ý°çB? n̰›°Û°'Ο|2ŒᬾCžï·3†úΰËðcQŸÀOáüÌÃ'pÓú–ã/W ¿†u\ Ø„-؆¸çÌìÃÂçXžÁçð| _Áoà·ðžÂ3x/ἆßÃ×ðþ€ñGøü¾¿8gÂÕiÀ˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|Žùó9æsÌç˜Ï1Ÿc>Ç|^Õ—Võ¥U}iU_ZÕVu€U`UXÕVu€U`Õs·¦û­é{kêµê5;ž÷ß` –áÇ}-Ôk†ŸÂ ø™ÿÎޟ׼?¯…zÍÖ·á¸êøËP…5ïÏk¡³Í¢ê° [° ;pÏ™=؇8„#8†Oq=ƒÏá ø¾‚ßÀoá <…gð^Â+x ¿‡¯á üÁUü‚?ÿyû‹s&ôÏúغ§`ÝS°î)X÷¬»'×Ý“ëîÉu÷äº{rÝ=¹îž\w?ü‹wøÃ»Ç_F0ƒo>²þÈú#¿)ü¦<ò›òÈoÊ£àüì¿·Ž3dzØOµ0‚|pCÎ 97äÜsCÎ 97äÜsCÎ 9ÿ5äü}ÀfðmÀÏåü\ÎÏÿ¹ó+ºAE7¨èÏ~ÅS_ñTVlŠÝ»%vKì–Ø-±[b·Än‰Ý»%vKlu6¯Œà¬gV¹TåR•KU=³Ê«*¯ª¼ªê`U¬ªƒUu°ªVÕÁªü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«ü¬ò³ÊÏ*?«¡¾3…o~å^úʽô•{é+÷Ò¶kÙv-ÛÞô¶½émë?Û2l{CÛ–gÛ{ÚŽ¨Q;¢vDíˆÚµ#jGÔŽ¨—j\ªq©ÆŸjü©¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öšk¯¹öškߥp—Â] w)Ü¥p—Â] w)Ü¥ðß=ËuhÝZ×{ëzoÝZ×ë:pÝZ7ÖM uh]‡¬ëu²®CÖuȺY×!ë&кU7ÖM  44hhÐР¡ACƒ† 44hhÐР¡ACƒ† 44hhÐР¡AC“†& Mš44ihÒФ¡IC“†& Mš44ihÒФ¡IC“†& Mš44ihÒТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´hhÑТ¡EC‹† -Z4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 mÚ4´ihÓЦ¡MC›†6 :4thèÐС¡CC‡† :4thèÐС¡CC‡† :4thèÐС¡CÚú÷°ïaßû‡wOþ=ù÷äß“Oþ=ù÷äß“ù¿dûoøøGØõ´v=­]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼Ù5ovÍ›]óf×¼ÙõÔw=ï=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\}\\\\\\\\\\\\\\\\\\\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\C\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\c\ûfê}3õ¾™zßL½o¦Þ7S÷ÍÔûfê}3õ¾™ú@†d8á@†d8á@†d8”áP†Ce8”áP†Ce8”áP†CŽd8’áH†#Žd8’áH†#Žd8’áH†Ä”˜€¿Ô‰ (Ñs='Ñs='1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€½.Ñë½.Ñë½.Ñë½.1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJL@‰ (1%& Ä”˜€PbJôÛÄ”˜€бï„ǾûNxì~>v'ûNxì;á±ï„ǾûNxì;á±ï„Ǿ>õFýÔõSoËO½-?³þÌú3ëϬ?·þÜúsëÏ­¿°þÂú ë/¬¿´þÒúKë/­¿²þÊú+믬ŸX?±~â ÿÄþ‰7üoø'ÞðO¼áŸˆ={*öTì©ØS±§bOÅžŠ={*öTì™Ø3±gbÏÄž‰={&öLì™Ø3±çbÏÅž‹={.ö\ì¹Øs±çbÏÅ^ˆ½{!öBì…Ø ±b/Ä^ˆ½{)öRì¥ØK±—b/Å^н{)öRì•Ø+±Wb¯Ä^‰½{%öJì•Ø+±×b¯Å^‹½{-öZìµØk±×b¯Å¾±¿Œ`ß¼‘óFÎ9o休óFÎ9o休óFÎ[Sí©áVÿ¿Õÿoõ¢[Sí¾}kj¸Õ½ï0Þa¼Ãx‡ñãÆ;Œwï0Þa¼Çxñã=Æ{Œ÷ï1Þc¼ÇøÆ›ÒŸìÙý¦¾§¾„§vZS;­©ÖÔNkj§5µÓšÚiMí´¦údªO¦vZS}2µÓšê“©ÖTŸL}ýN}ýN}ýN}ýN}ýN}ýNí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©ÖÔNkj§5µÓšÚiMí´¦vZS;­©î—ê~©î—ê~©ÖŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸŒ?2þdüÉø“ñ'ãOÆŸ‰ß‰ß‰ß‰ß‰ibbçwbçwbçwb¦˜ØùØùØùØùØùØùØùØùØùØùØù˜5&v~s5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\r5ÊÕ(W£\¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFS5šªÑT¦j4U£©MÕhªFÓYþ H½€2VÌXÆNf”Â,J`‚ â^ÆlÈòfÂú2\‚® šÞ > € ¸ ô $ z ° Æ ò 2 R ˜ Ô  V ¬ ` † ¼ îJŒÀö6X„œÀnªþT–2pœÚ":–ÒlÂôLŽÊüXžî$pˆØJšôP®ÔRŠZ®ÌÔbz°ê$zžè>x¦Ü0F\rÒäö   , > ž ª ¼ Î à ò!!!(!:!Š!œ!®!À!Ò!ä!ö"&"„"–"¨"º"Ì"Þ# #˜#¨#¸#È#Ø#ê#ü$–$¢$²$Â$Ò$ä$ö%%%,%ª%º%Ê%Ü%ì%ü&&P&®&¾&Ð&à&ò''\'n'†'ö(~(°(æ)()>)T)v)–)¶)ì**N*n*œ*Ì*ê+.+²ÖA=/\Œxœ”»nA†ÿµ›r)B)FJƒP¼¾4@ P.&Šd‰D©h&»“õ&ö®5;–å</@K“†‚†ŽAGMCEÇK ñïì$¶‰¡ÀÖÌ|3{æ?gÏ96€ûÞSx(>O`{XÂ'Ç%TðÍqÞ†ã Ö<åx+ÞkÇóXõ>8^ÀËÒ…ãEÜ-ýt¼Œõò#Ç+ðËï¯Â¯­SÚu©#°KÖ¼ÏÒê§Hà{q›øR…"”FŠ ítuŒ¸Íz£^åÔØûiu•ØMu?ÕÒÄi«/¨§¨"pDÍú*G2!îÐC—Ñc'írÞæãÀš‡œ5/U9nKˆ›‹9 hÁù Ö)“* •UqãKäÄÎ æÜ¨×g6VÅô5àĆ“¹ŒäŽ|ë 'Jg|QÑðš×ŠÕiÅ\°ZÎòÛ9/¢±ÈsÐãªqÁ³g· &m¦„µq=µ§šsdÕŒ »h‘Øz ìIÞ*ÅþœÙÓÖ6äÜ=ËË>ÎBœ )Œ–¡êI}!Ò³ëbË$=9§JhÅ™Qš]'"PÚH®çgaäíù³J<»ëÆEœè'؆64ÞBß¡ýú¼6-8IßR–èÓߪՆá/r@a?H{µÿ—5L{ß&XÙîˆh[tŠo5{,Ô?]›Q_…*‹£„äwLöm[ e«PÔn0‘.Cá¼ÊÛt,iWì¦ïä?í?[¶ÉØ¢í˜d¬ÑÀ&×t”ØîË€‹{²)®{ºé×ÿž™±sßf%âÓîTOÚ8`}[8d›·ì b2#Ö¹Ÿê¨Ö-ÈjíƒÝÖáQ«šðʸ87xœmÐÇoÍÀñÏk_U©½÷Þ«ö¥µ÷Þ«^©ÑW¿çÕ^± !Nĺ{GŒb¯ØÎvì+³Oòý¾üó'[¶ÿyQPH‚DaI IVXŠ"ŠJULq%”TJie”UNyTTIeUTUMu5ÔTKmuÔUO} 4ÔHcM4ÕLs-¤i©•ÖÚh«ö:訓κ誛îzH×S/2õÖG_ýô7À@ƒ 6ÄPà 7ÂH£Œ6ÆXãŒ7ÁD“L6ÅTÓuÐZë\±Ë;ëm³Å‡ %ØJ´ÆNßý°Õn]÷Ö7{ñËO¿pÌ·7]–íf¸'â¶»¹ï‡ÞÜ{ê±'N˜é«ßžyn–>Ûd¶sÌ3W®}¢æËˆ‰[ ßB,²ÄbK-·ÌEû­´Â*«}òÅ%/tÊ+o¼vÚç]pÃYçÜ´ÁU×\…CIÉñÜœ´´ôŒ”h~$ˆeEƒHjv4Äây‘ '„3ãAô/¸¬kTxœsèæTôPU`d•÷`•cþ/à#&ïï›"ïç“"¯f"ªj¬*)ü_žå¿<PÞ×GN>ŇÑÇW^ØX(”¨•Ũ™‘ŸÙžy=33›·Ûi·ÛnÌÊÆJ¡2ÆÒ¡bÆ¢¡‚Œü¡Æü¡ëùÏó3ð323„æ3Ô3¬gxÏÀ"ÀÀØ ÆÈʸƒqÂÆ`mmïìÿƒ¼7pDo`ìØ  "£6°ul`ŠŽØÈÈØÙÚÛËà$ë½Á(8bƒ‚l¤÷† C@v£ƒSdq±6@q\q ˆp ìL@ tomcat-connectors-1.2.50-src/xdocs/images/fonts/fonts.css0000644000000000000020000000362714655113617021715 0ustar rootbin@charset "utf-8"; /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 400; src: local('Open Sans'), local('OpenSans'), url('OpenSans400.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 400; src: local('Open Sans Italic'), local('OpenSans-Italic'), url('OpenSans400italic.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 600; src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('OpenSans600.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 600; src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('OpenSans600italic.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 700; src: local('Open Sans Bold'), local('OpenSans-Bold'), url('OpenSans700.woff') format('woff'); } @font-face { font-family: 'Open Sans'; font-style: italic; font-weight: 700; src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('OpenSans700italic.woff') format('woff'); }tomcat-connectors-1.2.50-src/xdocs/images/cors-flowchart.png0000644000000000000020000025103314655113617022360 0ustar rootbin‰PNG  IHDRÐôk†H+sRGB®ÎégAMA± üa pHYsÃÃÇo¨dÿ¥IDATx^ì½ëw×¹¯ë?`8_ϧ=Æ1>ÿÀùpF clï5Æf¯áE¸íí˜ácƒˆÄ¶Ql#0Ñ Žc.†|àh¯¬cÙ–½l`ËqÌUÁŽ ‡˜‹#ÄErs‘Äý&cÈyTïd¦èVK­VuwuõïùP¼ó³fUWwW=]¼ê¾gûöíóEþá8ÿ]!„"`ïÞ½MMM õõõ54IÒ剤p.xÈ?gwÈ…BQ–\¾|¹¥¥eÑ¢EcÇŽõ†½víÚ/¼3€a f·²(e$ÜBÂ-„B”-x32=yòd4zÛ¶m7nܸ=( `ƒY…¥Ý¥Ž„»@H¸…Bˆò¤©©iêÔ©xóž«°"«3‰›N” î!áB!ÊÞÞÞªªª_ÿú×ÝÝÝ·F«3 S1¡›Z”î!áB!ÊŠC‡¡ÈíííΚG S1!Óº ˆÒAÂ] $ÜB!DùÐÒÒ2kÖ¬ÞØN‡ ™vÛ¶mn3¢Dp ·BQ&´¶¶þô§?½víÚ÷y€i™ü“O>q¥€„»@H¸…Bˆr ££cæÌ™y²mƒÉÙÄÁƒÝ&Eì‘p ·B‘xz{{Qáo¾ùÆ©qÞ`Ó¦MëééqñFÂ] $ÜB!Dâ©®®>pàÀÍ‚°gÏ6÷Ýwß¹m‹#á.n!„"Ùlܸñ—¿ü¥Óá‚ðóŸÿüÃ?¼uë–ÛWâ.Ü6lø?ÿÏÿÓ5ò [a[®‘$ÜBôööîÝ»·©©©¡¡¡®®®&`ÕªU4¹JÑÕ××ç† !D©Áìá‡>sæŒsá‚pâĉiÓ¦:uÊ턈+…ûÑGmmm=ðÚk¯¹ì=÷üßÿ÷ÿ˜ZÂ]@kt…]™¦­B“¸ìÆokÞ}ÿÿü?ÿÅQñÀø‡@`;ÃVhÚ€| áeKWW’]]]=yòd »¾¾Ãþàƒ¾ xûí·i.]º”®±cÇ>÷ÜsÍÍÍúe!DÉÁ‰îÕW_ý®à°ÑÕ«W_¿~Ý퇈% ÷K/½„}>ûì³h(zŠ+“ÇMÉÓ$Þ’m- —um­p—‰8«£àLõ“ŸüÄò’¬kÓ‚7rKZ ì3Û?öÖ䞘mÙ˜Üà!øÏ éH¸E»~j’}ðàA÷;Ńò§?ý©®®ÎÔ¼££ÃM$„±‡×éÓ§6:qâÄîîn·"– ÜÈ.>ú¨kü§ÿôŸX"”)N‰@ã©~0±©9 °ÌÃ2%? &Ü®‚¤Í`°o4S2¶oF¸‹¼wbÛ®`«³¢í€m"èùý› } 0¬iyÀÝÑ‹ôa†„[”‡˜Ÿ{î¹ÎÎN§ÒÃäË/¿¬ªªZºt©îv !âÏÞ½{gÍšå¸àØOá\¹rÅíˆw&÷ò)"X¦·px±¶{ÉfŸŒ°§p³šÌcKŸôýÀ°E?ž|ÊǺü.¥@Ó² KÆñ‰"Ø÷~Hú OÆÆ“& #áeB__ߢE‹ª««1fû]´‘ðñÇO™2¥©©ÉÍ.„±¤®®nýúõœ‹›^¼xñÙ³gÝÞˆø1€p›\ºF³U¯³¤ÓG7­¤ä'?ù ±WaÓYÈtŸÛ„›a†wbKØVLÙYÛä|`LÿÐ;eâì€5‰S> òY‚­ðèüûùÁvLèmßRÆ“xÜ ·(z{{QímÛ¶9_Ž‚ëׯÿú׿^¸p!·!„ˆS¦Lùúë¯M ›~衇¾ýöÛ›7oº1#á‹&: 4Y†e°dTØ 8 “[îǯë„+¿½:[M‹cuÄh± 3¸p‡»2Ù³ßVÊxÈ´Š!ቧ£££ªªª½½Ý™r¤ ñO=õ”ÊK„1„³_eeå;ì èììtíA™°"€&+Z>LEEE[[›kd€صk×åË—Ý>‰˜1€poþÀÑ5B °¬`º†Á~<Šw˜¦×ŸØÍi?Þ“I…½àúÀg6<ÛÌÛ/^Úa÷Ý]ãnR:lÏö9&ú#2«¤#áÉf÷îÝ3gÎ<{ö¬û ´<Àõ†M|ûí·n“B8Î;×™ï÷ßÿÂ… ÑhDÙ¥2€dÏž=›€ñ@0à*L˜"â Kzv`ãÆúáÉØ2€p›•⬮‚¼/Øðô÷ž‰ñN‹_ •š„ »²gÀ$ôÂÖ÷ðx¶Î†è5Ã&¶Œß+}fHÿ™„›ÁäýÑðû#áÂÓÑÑ _»vÍ©qÞøæ›o¸Ì\¼xÑmX!b¦»dÉg¾ÁMk å¶¶¶uëÖ!ÇæÓÐÐÐ`7³ÛÆxá¦×º‚[Þ+̳™gË–-4YÒĪÉ0’ Û;ðî»ï~ûí··ô#8±dáTwôãøÀ˜¤šæÒ´<`Õaï$fŒÅf· fž°ã(âaCÒ™6Ÿ6˜Á—Xõ3l«*!3àg&ñscì#D&ák´±uSÆC¦‡`H¸ER¹|ùree%*ì¤8Ïüå/™5krï6/„Å÷ÅIœùÞ-ܨ6K2ø´eœ M–@3ðí~á5jK’æå6 #À¹a˜ºù·Áüú׿VwlX¸±IsV[Âøñã­Ë ›¼`jñ ô"¸Hmÿ¡Ù«C ·Y5øíÚƒ †1ÄŒ'NÆœ›@0¸pÛÎ÷Ë~PiClû“2¼÷3Ò¥BH¸E"éëë«­­E‚„÷ßÿ—¿ü¥îâ!b‚}E‰3ß@šñcäØÚ,™ ­­¸¿¾{çN ¼gûÀ„Û–fä68<Ìg<öE%7§e·["N ,ÜNi¸öpÐG}ô'?ùIz_i ta±á»ãaX+}6HI²:“¤d+á$1›v°ñáU ÜdüžÛãµ=÷IHYldxŒGÂ-ɪU«ƒ.(÷ºuëÜN!DQ©¯¯÷Ýwù†îp^ŽYbÒ&Í+‚ª‹Ã©63+Z…I6ÂÍ,[¶ á¾zõªÛ-'n!n‘<ººº*++9¹; . gΜy衇ôËjBˆ8ðÎ;ïüÛ¿ýÛõ;Œ?ÞE&Ç>æÄEpòäI–&Ðáá¶a›7of-ægðÃÂsìÀ¿ÿû¿#Üú¢’x"á.n‘<ž{î¹O>ùÄ)p>|ØE1}útpi.3no„¢HØMšøBEE…‹h8pÀ⦦&tlÌò€p`²ŽO›[ÓĹý ~˜Íóúë¯þ&õ{“ñDÂ] $Ü"a:thæÌ™îg…ÈØƒ.Z´ˆ&~Lƺ²áóÏ?=z´k¤±uëV&t.*?üð±cÇnß¾íöI!ŠÁÞ½{Ÿ~úig¾#fgPámqXÖ‡ضm­¿)'î!á £¦¦æÏþ³“ßti&@ŽYvuuél\¸ñøt}ï½÷–-[¦Û9BˆâÂéî±ÇÃt£bùòåý·ÁÇojjr©¡xøá‡÷ï߯?šŒ-î!áI¢··wòäÉN{ïà…Û0E†à®÷zßxãéÓ§[`V®\i]\®¼pkL˜3gN0S?Ö•Â_ÿúׇzèÌ™3ºÉ-„(.S§Nmoowò[pØô#<‚mÃ÷ßïöIÄ wp‹$±qãÆ_þò—}w³k×.´¥Æži“Q£F!è$ hØ„› ¡¡µè"cy›aöìÙtÙ€E‹¤c¿f¬›ÜBˆâÂiêw¿ûó߂æíK¸OŸ>­ñDÂ] $Ü"I<÷ÜsÛ·owÎ{78´÷é~ݾ£Ñ0a ÂlŒI¯Ýá¦iFN` žŽýÖC~ÍXQT:ôÄO\-lúÓO?E¸ÏŸ?ïvHÄ wp‹Ä€æŽ7îòå˦¼éàÇ4‡ö é½~ýz‚­[·ÒîþAw@µý é>|xÚ´i\fô;8Bˆâ2eÊ”'N8. lô¡‡ê¯&Ñ—pÇ wp‹ÄÐÑÑQYYé~k!Ò¼páÂÙ³gд¯‰µ?·÷,@©Y’Va¹nÝ:?’LEE…MÕÖÖF`?ý‰x@—!DÑÙ¸qãâÅ‹.(Æúõë9 ž>}Z·b‹„»@H¸Ebؽ{÷ܹsí†èìì4ö&®œ)°1èõ–-[ˆéófáƒ0iҤÇŸ;wÎíŸB‰ªªª\) lÎþ—tŒ3î!á‰Á~âÁÙîÀ¤½g‰Ÿ={¶kdÀþnòÌ™3nÿ„¢H´¶¶Î›7ϹpAxæ™g8'›p÷Ýwn?Düp ·H ¯½öš³ÝàïggŸ}öÃ?äbãöO!ŠGmmí§Ÿ~êt8Ï|ðÁØ…Ù¶noÇœ{¶oßγ%ò ÇÙòR£«««¥¥Ç‚)S¦þøãyrn¦å¶k×.³m“”nqõõõS¦LA_n%¶¶¶Y³faÞœ¼ÜƒÙÑÒÒ2þ|g»™5jÔ믿îw“)ŸŽýa¥kdà±ÇÛ³g„[+ÚÛÛ§M›öç?ÿùR¤0!ÓzÛîîî¾­Ÿ–,$ÜÂwÖÔÔ¬]»Ö iyðùçŸWUUutt¸£ ²`ïÞ½O?ý´³Ý  ÔãÇwí¯ÎjôÉ“'-8`q6Âýàƒ;vŒ J…±âôéÓÕÕÕï¿ÿ¾“åÃTLxøða³íÞÞ^÷J ·èãÄ;¿üòKç¡åÄßþö7û¿9w,ÄPpŠŸ4iÒµAA”Oœ8aKšû÷ï'æËÕ«W5Ê‚ رc4a&ë6]™èîîF¸íÚãöO!bÃåË—9Ë=õÔS#¼ÕÍêL2þ|û+Ièéé‘m—nÑïO3gÎüæ›oxë–'xÛOúSNg¡˜2eÊÉ“'MyÓ1Õ&X@€@755ýxNnRÎrHáÞ¸qã¼yó¸öœ>}ÚíœBÄ ®2Ÿ~úéŒ3~ö³Ÿ:tèâ0aVduûcãüùóª$)-$ÜåN___MMM[[›©gÙráÂ…ÊÊJLÑ1(õõõÿñÿáœ7 ${üøñ˜´ÝÒ&“â̓÷êÕ«Y²nÿ%ÝÝÝnç„"f Ç(ò‡~øÈ#<ú裿þõ¯÷íÛç„: `ƒYÅ~jÀ8sæÌ%}'I "á.wêêêÞÿý›âæÍ#GŽÌ˜1C'²lØ»wïSO=u5XòÚµk? æ²1mÚ42®;@/¿Y³fÐK’Ïîq'ð#3á ¸õÄ !bN___ooïž={þýßÿ³â~ô£'ëéÓ§“$°Ìĉ@Æþ"Ü8{öì… néJ wYÓÑÑQYYé|Sܼùꫯ®^½ú{UÅeÁ¸qã8û;í ^›:¦Ô–´[×$,X@“C}üøqÄš$—ëò±MB0ˆpþùçÕÕÕv)ÒW”!J‚7n Ý§OŸÞ¿ÿ¶ÄúÀ¶ ,ãÿ,Ò`ðùóç¹H¹)D "á.kjkkwìØñ¸'µGyľ}Ü#‘úúúwÞyÇ™o‘˜7ožýOë™3gÜn !D)pëÖ-NbçÎ3ŸF¸µ¾ ò.\¸~ýº.I @Â]¾´¶¶>ûì³Î4ÅÞ{ï½eË–]¹rÅ&‘ÞÞÞªªªo¾ùÆÜ·ð´µµM›6Í.K/^t»%„¥òp÷õõqéáäF ÿ²KîòeÑ¢E[¶lqš)îpúôé‰'ž={VurCÒÔÔ´|ùr®Eá™gžÙ¸q£ 7OœÛ'!„(An‰„"á.Søô|™C¾Ýñ™yûí·ëëë/p1‰no !€„;ñH¸Ë”¥K—þþ÷¿w‚5·³gÏ^±bÁºuëHVTTXˆÉ¤œ‘>o+2`áÂ…Ö$ ¹eËò7Ížž늜®®®‡z™SUI–,X°àøƒÓá<³|ùòÕ«W›mwwwë÷… @Âx$ÜeJMMÍ_|á3j0c»Ã}ÿý÷Ólkk#C@Ò–ôâÙ @ÉÛH°»×Xµ)8|Éf0cXöΜûð¹ÞÞ^w¼Ä ôõõ=õÔSŸ|ò‰“â¼±víÚùóç{ÛÖ7¦ !’„;ñH¸Ë”©S§vtt8»ŒÓ芊 ³d»9Í̧}Mˆ%Ó…›&ëÒÅ’uQv28zxL^™4iÒáÇϞ=뎗 lxΜ9kÖ¬¹”7–-[¶xñb³màirÛBˆGÂx$ÜeJUUÕ¡C‡L.#Çnc–ÜÙÙiÞŒUƒ•tg#Üèµ­by`¤Í\á¶ ?}ú´;^" 8n¿úÕ¯Ðb'ÈÑqêÔ©§žzê­·Þr®ýí·ø½ÛªB”&á?JnýQòp—)µµµ­­­×óÃøñã-0Ÿ>yò$möÜÔÔd–/_¾yófò ƒCÓKL@óõ×_¯¨¨°U`i3Û`‚<ÑÓÓƒp›Ø¹ã%²ãÖ­[ï¾ûîã?¾cÇ'Ë#æ£>zä‘G¶mÛfÏ\ÑÏ !JŸÞÞÞ©S§®ZµŠË1½wï^š$UИ<$ÜeJ]]ݺuëœ`F ºlAww7bM€+î½Àºˆéª©©! ‰ˆ°ôëô¯ø:¶íc?˜Émdä=zÃ3·sÇK ‡?ÿùÏÕÕÕ?ûÙÏ:tq`íÓ§OŸ7oÞáÇíéàI×!DbàZŒj§€s»n‘ $ÜeÊ;ï¼óoÿöo׊͂׈ ­­­³fÍBïôUÜ9ÃaüðÃùÜò /lß¾Ýtv`Õ}ô¾ŽµïÚµËTzzzôW’Bˆ$ÑÑÑá,û“'OÖm…D"á.Sººº{ì1óË"²)À5bË/¾håÂúO½‘€Ÿ;wîÝwßåÓ˃>ø‹_übÆ ƒÜóþâ‹/Ö¬Y3gΜÿößþÛ¼yóðuólà“ÏåË—õ €BˆäñÜsÏ9×hjjr"YH¸Ë—©S§¶··;Ç!&Nœh5 .\pKäJ__Ÿ[Ž;¶~ýúùóç?òÈ#vQyüñÇ'Mšôä“ONŸ>Ý23fÌX¼x±ÿEãìÙ³¸¸~KR‘T¬€Û¨ªªrY‘8$Üå˪U«Þxã«ânþò—¿ØÏLÂõë×ÝÁ#ãÆ|z9}ú´XøôÓO¹ºlÛ¶-\4â9sæLww÷¥K—TC"„H477s>¬­­um‘D$ÜeM}}ý;#ßãÀÓ¦M3 䣈;L"?paùÝwß©bDQÎôõõMž<¹££ÃµE‘p—5½ÁMîsçÎ9ß,{žyæ_CŒºÃ$òƒ ·B”9]]]µµµîd#á.wZ[[ö³Ÿ]—/¿ýöÛË–-3ÛæCˆ;@"oH¸…¢¥¥¥ººÚ–ÍÍÍ.+‡„[üѬ¯¯wÖY®|òÉ'öÝÛ†no ·¢œéëë«««[´hÑ¥K—nß¾}ãÆ š ,à’äFˆ!áý<ûì³h·©g²sçÎêêêcÇŽ™m_Ñ/‡ ·¢léêêâºóÁ Úa¶mÛöÄO¨¼$yH¸…cùòåË–-ëééá£vY±fÍšY³fyÛ¾xñ¢;""ÏH¸…å‰=zÔYöÝtvvš‹»Ñ"H¸Å?xï½÷žzê©;v8M:HöóÏ?¿xñâ®®.³ísçÎq²s‡Cä ·¢ÜH)#É„ÊK’‡„[ÜÅŸÿüg>XÏ™3gß¾}ý?·P:;;9—=ôÐCëׯ7ÕòœæÜùGÂ-„(+2•‘dBå%IBÂ-R¹~ýúƧM›öè£b¥I2oN[?þøÄ‰W¯^íD;@uÛ…GÂ-„(¬Œ¤½½ýÖp8yò¤ÊK’„[ À÷ßþüù={ö`¥˜7bôàƒ>ùä“=ôqiñ£ýˆ=ǰ‰ÙÿeË–}úé§Î²z{{õ$EgÄEB‘\¬ŒdáÂ…/^t=®_¿þÊ+¯¨¼¤Ô‘p‹Œ ¡h·ýìö±cǶmÛ¶k×.“ÔÈÁ½\5|l`Ï>ìÚwàq¡ÚœÝ£GÂ-„H<¾ŒÄés®¨¼¤Ô‘p‹!à}~õêUÌûÌ™3¦ª>ˆü ·çÔ©S,ñlûeM—{„¢HH¸…É&·2’L¨¼¤¤‘p‹asóæMEG¾Ýëûï¿¿­?ˆŒn!DRaI&T^RºH¸E,{•!zÒ…‰¤««kæÌ™ï¿ÿþ÷ùaëÖ­*/)9$Ü"ȽÊ=éBˆäÑÒÒ‚m···;;Î'Nœ`+*/)!$Ü"ȽÊ=éBˆ$áËH.\¸à¼8Ÿ\»vMå%%„„[ĹW¢']‘ò]F’ •—” n ä^eˆžt!DÁ¸|ùr}}½küýïK–,qQXÉ‘#Gn•—”n ä^eBGGÇ©S§,?éä:äB5{öì¹ï¾û¼g[0B|Éùóçÿƒ«W¯¾üòË*/‰3n $ÜeBooïØ±c«««Ÿ{î9žô†††ÚÚÚ©S§’¤Ë Bˆ¨A¸çÎ;fÌSR/Üõõõ“&Mª¬¬üöÛo-“=¾ŒÄio±Ù²e‹ÊKb‹„[Ä wùPWWÇÓªU«\·Bä„{InMÓ„Û¶fss3ÚÝ?.kŠ[F’ •—Ä ·ˆ(—‹DÒéèè0ÉöLž<¹O¿±/„È'&ÜcÆŒioo7á&&ô÷Ç ILÊH2¡ò’x"á±ër‘(¬žÄÓÔÔä:„"?xá¶›ÙéÂeU·•‘lذá»x£ò’¸!á±ër‘(Z[[Mµ¡ªªÊe…"oxá/ÜVRB—¯-+#ùꫯœÕÆ›ãÇ«¼$>H¸E,@¼\$Ê<Û„ùv)!„È—/_Þ¾}»Åíííþ+qßÌ„•‘,X°àܹsÎgK+W®¨¼$&H¸E,p—ÍÍÍ<éµµµ®-„q¥TÊH2¡ò’8 á±@Â]nôõõMžxð  @²Í°±vš`w²Yúü å+C¢ò’Â#á±@Âx¬€äèѣβ靈³Ó\ÜBˆ‚ƒ"óáñ½‘+7ËŠNk– sÿý÷ïܹÓ5nÜX@†¼el€ 7Mæ¡éøÕmÅþFÀ¦M›t³£`H¸E,p'˜¾»ËH2ÁÙ_å%BˆbÑÒÒ‚}:tÈd47L¸aË–-Èq[[›5=htX”ÏHïÓ`J½nÝ:T›^œ'ál›G­›@Â-b„;©d*#É„ÊK„Æn ði¿§§Çyh®˜p7440•Ýœ¶¼§³³sÔ¨Q   c6ö> ¦Ô+V¬`uoÕ~@ä —.]z饗t³#ßH¸E,p'+#ioo¿5Nž<©ò!DayILš%ºŒ [œÎmºÌ0Ë`ç>& i½¸õºuëx?Àz ¶kDƒÊKò„[Ä w°;F\3.^¼è}:ÒL†'ð·½mŒœÙÈ[’‚žþ&ëöÏ2LFR^"J ·È7¾¼äÀ&»EçÈ‘#*#‰-nQ|0³±cÇFòõÉ"ðÑa•‘„ñÂ=H™m·· Æ&Ð`0o’4Ñkš`÷ÂY(îÃ%çòQŠH¸Eðå%k×®uÎ[¨pX‚͘]ã+V¬ ï@ãÓa{6¥fļIæI¸ÛæQ«¼$ÙH¸E!)by‰ÊHJ ·(}A%âE‹.]ºtûömLÈ ô?þÀ>G›S³ihnxáF©í&72m]aÈ3€‘&L0ùäù.á¶ÕƒRí 4¦ï%¯2BxɽôÒKz±% ·(0áòN,…áøƒÊHJ ·(]]]ÕÕÕ|ð'©0Û¶mÓÿøç›–‘¤`ÊnE –L'Pè^ÇYË»¾%ñuëÖǹ}~ÀU"Aå% FÂ-Š‚//9}ú´“âüÐÛÛ»lÙ2•‘”nQ¬€äèѣβïi3w£E¤Œ¼Œ$OÌž=Ûî‚ÛÍr—Í3*/I*nQ,¬¼äñÇß¿¿³ã¨ùꫯTFRrH¸EAI)#É&¤ò’ȉªŒ$ðYkgZ x¾QyI"‘p‹"ÂU,å%*#)Q$Ü¢pd*#É„ÊK¢åé§ŸþÍo~ã4SÜÍ›o¾ù/ÿò/XšH îu/D‘ðå%§NâƒýÈéééQIé"áÂÊHÚÛÛù ž='OžTyITØž¨J·“ĦM›ìŽ‘n% ·ˆ¾¼dß¾}ΚsåðáÃ*#)i$Ü"ïX%ÃÂ… /^¼h=,®_¿þÊ+¯èü#çbñâÅy­*Ù@Õ7ЬX±ÂövÈ¿ËÌ.c/½ôRøŽQoo¯;X¢”‘p‹˜pûNyÉš5kLsà£>RI©#áùÅ—‘˜=çŒÊK¢Â_,×>ÌDNÿW÷-\H0jÔ(ËŒûZÀÔÔÔ¼þúë47oÞìúFÆÑ£GuÇ(©H¸E¬È¹¼„“’ÊH’„[ä‘ÜÊH2¡ò’¨ðw\Ö­[çÜsdðÔàÄ(Üô2Æ5îà3>ÀªÃìiÂíRׯãÜ6ÿñe$v Ý1Jn7r(/QI’p‹¼àËHøXÿ}t\»vMå%Qaw\æÏŸÏÜIhN,_¾¼¢¢¢¦¦3¦øö?„i&Ofüøñ,Ñe“·{Õ6€.–LB/]4 €$ó„…›1lÑ5rââÅ‹)e$ºc”<$Ü"†„ËK8 ŽÊH†„[DOWW×Ì™3ßÿ}§ÉQ³uëV•—DB´å%v+:ðí7ÒÜÔÔô»Œy6&íÃLºP0Ìnl[Ó¦%èîî¦Ë&Ï•‘” n[ìfÇ/~ñ Î?N®ï†sÝÒ¥KuS aH¸EÄ´´´`ÛíííÎŽóÉ'ØŠÊKFÎÈËK°aìÙߊ|ûÂíuÙb–Œ´U†g{íf|0Íxé ôZ*#)$Ü"΄ËKœeßÁNȺ)<$Ü"2òTF’ •—Dˆ//éîîæÀ „xÇŽ>àš4KìyõêÕgÏže/AÙ¿?mIÆ!0ø@eyðóƒM•<À_|QwŒÊ ·ˆ9–—¨Œ$ÁH¸E4仌$*/‰ _^rðàAg©Ù^7¦ûÕ9]¸±jòÖÛÔÔD™¦kÓ¦M6ÿ&›Ðqš,YL¸YÒ ÆöövÝ1*7$Ü¢$ðå%*#I6nVFräȤ­ð¨¼$*Âå%ÎUKŸ7êŽQ"á¥W±æææ±cÇê¦@²‘p‹áËHÓߢpõêÕ—_~yÊK¢`$å%±Be$匄[”·oßæk§)ÐMDRáîêêjiii˜2e /²Ò‚}®¯¯gçùHzèÐ!÷¨Ê_Fâ´·ØlÙ²Eå%‘ÀÁ´ò’¶¶6>Ì”"*#)s8W»HˆR€Wìµk×NŸ>­›I¥pœ­ZµjjÀ¢E‹L¸=ʻҢ³³síÚµì|]]]uuõäÉ“ vïÞígÙPÜ2’L¨¼$*x©[yISS“sØÒáã?VI™#᥅^±‰§Â}êÔ) Ï~ûí·±UÓÖÄÐÓÓƒÞÕÖÖ"ß{÷îu¹¨\¾|¹¾¾Þ5þþ÷%K–¸("¬ŒdÁ‚çÎû.~\¹rEå%QáËKΞ=ëd6Þ Ö*# }¥…^±‰'ïÂùM™2eÛ¶m·’N[[Û¬Y³0ï¢{Þž={î»ï>ïÙÄD‚•‘lذÁém\QyITÜ,ò•‘ôE”zÅ&ž< 7ÞYSS³víZ'¤åÁçŸ^UUU\ÏC¸çÎ;fÌS/Ü|ø™4iRee%"b™ábe$_}õ•ImÌ9~ü¸ÊK"áv)”—¨ŒD„‘¾ˆÒB¯ØÄ“/áÆ8ñÎ/¿üÒ4´¬øÛßþV]]y»cQpî%¸5MnlÛšÍÍÍhwÿ¸áó2’L¨¼$B¬¼äùçŸ?sæ 6>ðšT‰HAú"J‹ôW¬ÿoj—‰Š%/ÂÝÛÛ;sæÌo¾ùÆý6IùqíÚµŸþô§þóŸÝ),&ÜcÆŒioo7á&&ô÷ÇdI©”‘dBå%QáËK8`²[tŽ9¢2‘Ž„[”靨ÊÊÊÆÆFl;,ߢD‰^¸ûúújjjÚÚÚœ{–+.\àÝ‚ªºãR@¼pÛÍìtáVU·•‘>|˜g6B<è¢èdÎcÇŽ©¼$|yÉÚµk󕑈LH¸Ei‘þŠå„fwÇü=2»¦ÛV:NS.^*D/Üuuuï¿ÿ>~6qâÄà‹Úú Çaæ¢/¼ðãaÆ 4¿þúëéÓ§‡3`Mضm›el Kk¦`ûsæÌq©¡`»°–ÃÅî½¾˜Á 7xá¶’º|mÉà©VFÒÛÛkÚšÜE}}&LpÑP¬_¿~Ñ¢E| aV’Öë±ïŽt™64zôhÜË5Òà‰PyIT½¼De$bp$Ü¢´ðËÅzîܹvAooo·rP®ã4MÄ9ûõ±'báîèèàõkîÞ½ûñú;jÔ( R` #]#!¶µð]Ì›€1o¼ñ†eˆÍ°M‚‰mfVyõÕW Rf3Â+2Õ€–Ÿ‚í¿ÅÙŒÏ{µzõêï¿ÿÞ ‚€Pnß¾ÝbÞ“¾ö‹Oüo³,³2’t N!ì¾<. ?’ƒlJÍæˆ·nÝjùÁðN63dñ0›7oVyI$ðònnn~üñÇ÷ïßÏK®|õÕW*#)üñä3ØéÓ§­Ö—¦¦¦>úÈ5„ˆ% 7'7ÿ?Ò\¾í~6XR··K‹ˆ…»¶¶vÇŽ\ù>ÿüóE‹¡P‡¢‰`Y²ÿNfz„û’g ½†ô`` vï¾c$nMà“¬nwIW®\i™tø”Þ”=a'-ö;CÌž°$&É’ØŠ±ey i6D Ìo]œýyä6qûömwŒJìËHx°.º£Ñ8:IŽuÙ3aK¶ÛÛÖeÀ¼9 ³ñÀ1ºfϞ̈́Àš,ÃÏk1ǹ¢¡PyIT„ËKœ çŸ?üá*#éðÚø§ú'¬eܸqÿßÿ÷ÿTWW[òøñãnœ±d@ᆰpÏ;wOç=K666÷²D±ˆR¸[[[Ÿ}öYMî 6àC4M£#3QïÍ>c“q&× `IžÉ}o¿ M˜€uY3LÊVÀglOˆÙÃs¶«á=± ²}NyP`³±iÀ$~]xï½÷–-[V*ÿÙYF†ƒ`GˆÉø9XyŽŒeRèjó6l«0Mbiò4}!Šmˆ˜ny¶B=\›U^¾¼„—ýFœ7xUðVR‰ÈÄsÏ=‡µ¤ƒy»BÄ^¨.º/Üœñìo± ¹¹™SâöíÛ-iD̉R¸ -[¶˜e" 4 Ì·ÌMmigiªjk®Á$6áØŠøV¸×6d7›Ã08EÄSö$¼]ëJÏø=ñ]~ÛzÉ0øu ™8qâ™3gâ“»««ë‰'žÀ_od ÖE7nðð-˜={6yš;î¿ÿþ… ZW’á¼´¥eüËWTT¬X±‚¦mÈ÷†W›6mRyI$ ¼De$"þûÿï&Ùžú§âõ㺅ˆ+¼V]t7ᢠ»¿ dÉ« Ç"þD&Ü}}}“&Mòw7wíÚ…€ØíI ‰Ø–`7> è"¶¤Á_Àlþî¦a[­~NÕ³a¬öÀ5Rö„¥ßŠu¥gßîD¾ËOb‚­°uˤ0sæÌO?ý4Ó­8¯‹ŠJKK öÉÇg£Ù‘.ÜdÖ­[G`–ôÜ@”MŽÃ´µµ…EÙ|:]¸FACCƒåmCÖK³p¶Í£VyÉÈÉky‰ÊHD–¬ZµÊ<ÛóÜsϹ>!b ¯U‰„™pïÞ½{îܹN0C Ȯ¹)>j÷¤1T+3 I2\r€TÑËL†%G†ÀK°n’Vû˰¸¯`·1䑸”=I×k$˜€>Ó?ûÝÂÍT6M’dlyšž·Þz«®®îÌ™3î`ÝaïÞ½ÕÕÕS¦Lqí"ÁZIOOóÐ¬á ¸èŽ#Ç<|T˜&*LÌäoN§@žL`Òœ.ÜLÅ00ç¶ Y/ÁH„.]ºôÒK/©¼$|yÉ©S§8°#‡×¤ÊHİàDaª ÿý¿ÿw—"~ôööVUUñ)±µµ•—+J@@“$]nH ‘ 7/‘7ß|Ó)L@ØÞÚÚÚ|€¡PÖš)žG/Ipí;k¥d,`][=Ó ð›NÙ?ž¤6Àgü† <˜ØçŒ³oß¾3fà 7oÞ´Ã…ŽørC$Ò’E!‡2’0þP€àþ°Ø³–]ý‡,tÐüàà÷p|°vËx)gi½Aú®ÝÈ •—D…//áeï¬9W>¬21\þøÇ?Ú©¸0¹¬±¤®®Î½XCèu›H"î¥K—þþ÷¿wò"î©}衇ÐâòåËõõõî]PDÉË­Œ¤À¬[·Ï^¸p!Ú]QQá²y@å%QáËKÖ¬Ycêœ}ô‘ÊHDnØ·”L˜0Áµ…ˆ+\wÌ<“'OîëësÝ"AD&Ü555_|ñ…3‘ï"´ûw¿ûݸqãìMå)J%ÃHÊHŠÂλÿc$Oày*/‰ŠœËKxMªŒDŒ„ãÇsjýãÿèÚBĘ”o×ijjr"YD&ÜS§N僚Ó‘Æ„ þÇÿøîýðþßüæ7nçÄݼùæ›O=õ”{e‹Cy‰ÊHÀZZZ¸p¸SRé0eÊ”úúzv1:tè{TBäŠpUUU.+GdÂÍ«$æ• ÅåÁäMUSSãÞUw;v¬;‚…¥«««ºº:çÒí³iÓ&«dPC$„ËK.…ÊH žm†°.Z´(ðí†/¿ü’WHiÁËríÚµì<Úm¿­³téÒÝ»w»Ç)ÄðÁ L ð—‰#2á®­­å…r= 8°páB–ÖÜ`q,_¾¼»»Û5ŠDOOÂm±wï^ÿÖ2ŠõÇÈ}}}‹/ŽOUɖ׊àÏ,Sÿ8u„\ êI• ú;ñ¨°ò’_üâU'×wÛkQI"á}Ä“‹g#©Î[“ç?þ˜+ 'vi·Èææfd€W‘k‹$™p×ÕÕ­[·Î æÈ¸ÿþû›šš¸Ð ¾üm!Á믿ôÃXqüøñ,Ož<É3s}a[É+G}ä‘GL#ìpmܸqòäÉ&ÜEþ¿,€8Ü´ÞLã‰Yø©)ªK¾ŒÄlTÉü‹-\^¢2’¤rùòåçž{În”FZ|ùå—V`鎂Y€<ûì³úcýd™pwuu=öØcN0G@EEÅ=÷Ü3~üxÄ×ÌÛ„{õêÕ4,™€$ȱgºˆY`SŒ¤«¦¦†€9O“ui¢Y ð[!Ãê,›šš‚U#ãÅ_´»w===îxÝ¡··7’lÿã?þ|öÐ470ætá¶ç…§€¥5-扠iÿ#A“'bÀñô2’eØÑ¡»»›U\#W¾”2U2ä_^ÂG)•‘$•S§NUWWÿéOrZNpjš5kÖþðw,„l›¦˜W=9w‚‰L¸aêÔ©íííÎ1G€°úuûî;Üx˜91ÆŒŠ™pÓ?ÆCÆûy ßô[áµNÀê¬Ò?":&Nœxøða|Õp+~DR^‚1sôxR€K©"c½aifK’VdÏñp<Ëôj"³‰.*#)öb;v¬~"A*++Oœ8ñ}¹Âiÿç?ÿùöíÛÝ"fÛVYÚÑÑñä“O^¼xѺDˆR¸W­ZõÆo\1xX803&@¼>ûì3 À¬Ž.’4ûW¸z•ÌêÕ«-6è²µü<Ó¦Mc“[3e+áÙ"á/ù VgJÁYجX2òòŒ9å7MŽpð\õƒ[cÏ“g˜-ÏÓ‘^Ob#]#'TFR\x±=ðÀîÐëà'‹ÚÚZÞYÎ=óƅב)_`؇™3g¶··»ƒ"DfÛŸþ9çCãèÑ£?ùÉOä܉$Jáîíí}øá‡¹p:ÓÌ3`xöêŒ1¯]»¶D@X‘±m,Íâ3)Âmø&AÊVülûöíc9ræÍ›÷ᇢ§OŸæíäVŒá:aå%Ènpƒ~p ýÿ0Ø!=qâÇÓ2<Ðkuó555ާ™ò¿žÉà‹/¾¨J†Èillä`Z\__?äÿ"Ü<¼/tð“Oýš5kn‡W_}õðáî‘5/°âôéÓ]*Àò®°aƉlÈ2 °ŒÉ$–yã7,ãÇpQ³Ìpùæ›o¸Zqzq‡Fˆé¶mȹ“J” œjßyç.Ÿ#áÞ{ï ˜Xðƒüàµ×^Óì(ÍÖÖV‚`~fÍše½,IÀò6ÏÆÉÛMnšäS¶âg#o+Ž„°-³ºsçιÃ{¸TXyÉÁƒMR³cNnLiæ¨M–A·‰5Ÿ‘À„{ÀñézM2¥X?KÚÛÛUF’'+++ 8È“&M²ä Ü.I¡££ƒ×€éfö ¶»wïv¬a- øúë¯-cø¼m=ÚÆX·öŽN`IÄš%ümÛ6´ÛÆÉY¸ÏË–-#pHˆ€L¶mȹIÄÂm7¹1Kç›eÏ3Ï<ƒâ›Ø•–Õñž÷å%ÎUKž •‘ä•1cưD¹¬zó&F¾í?ÖI›”ƒ„;yàŸ|ò çºa±hÑ"̃΄”ß%?jÔ(°2`Μ9ÖK@’µÀÖ¢É täƒõú¡É×ðÓBWWlÀ³Ùº ·eFW®‰|áŒêŽ‘({·mCÎ<"nhmmýÙÏ~vY\¾üöÛo/[¶ÌÄ®„no‡IyI¬PIa°›Üþö6þÍ¡æ½`"~ß}÷“±^ w°ÛÛÎ4‡~Œ|*Ì©̉QÞ­[·àĘ1Ã1¾Ý¿¢3KbÖ"ß?. ¬×àÇ{lIÖb]°ø1ïPÀn-ƒ[@†Þ††KöööZÀ2ðêþm-¿Šå-ÚV÷0ýµ˜.ؘíàÁƒÃúõë}WÎÌ;wãÆÒ&1,Û6ä܉!_ uuuË–-ëéé¹Tf¬Y³fÖ¬YÞ¶/Äø»·‡…//9{ö¬“ÙxƒX«Œ¤ðxᶸ¹¹™fcc#M–|­¬¬´î$Ágò™3g:Á&æÍ ÷ôéÓ}L/~ì3&Ö~­Ù³gÓÅ?&¬ÑöÌò$m$“Ð$I`zí­Ú6±råJ¿ÊÖ­[ãw#°vNž|qK”%9ض!çNynøÿø§žzjÇŽNE“b÷üóÏsbíêê2Ã;wîïw8JŸ*/QI±! ‡ÝJJL¸éò1H¸“Ä;ï¼ó›ßüæFNðÞ´€‹;wî´|ÈwvvZ†µlÅðZ¶¢ŸÐã» &IÉ„·b± `¤%ÇKGGÇ#<ÂÛùvÇK”fÛ·r…+šœ»Ôɯpãš_|ñEuuõœ9söíÛÇk%©pR®««{衇֯_Ø]?çÏŸO’m<¢ø——¨Œ¤$p' >M½ûî»N0ÅÝðàÁäDtéÒ%w¼D91BÛ6äÜ¥N~…Û¸råÊÆ§M›öè£b¥I2ïŽŽŽÆÆÆÇ|âĉ«W¯6·3üM¾Dbå%Ï?ÿü™3gx~ãùsçTFR*H¸“ÄsÏ=÷Ç?þÑ ¦Hcܸqœ”8¹ã%ʆHlÛs—4…nèëëëííݳgVŠys¡åãþ“O>ùÐC—?úÑØs ›˜ý_¶lÙ§Ÿ~jngpJ-‡ÿ7ôå%0Ù-:GŽQI Á;ÈE¢ô©©©ùâ‹/œ]Š4~øáýû÷Ÿ9sÆ/QÔÕÕ}ðÁΗ£@Î]ºH¸ N:™Ÿõ·mÛþOÿR ìùáÇ]ûœI»»»¯_¿îmàËKÖ®]뜷x¨Œ¤äp' ÷à˜ps^rÇK” ¯¿þº‰r„ȹK”‚ ·ñý÷ߣG½½½fE€ªº¨4á±ðˆx\î–E//QI‰"áNK—.ýðï‹ ðj·³Âä™H4y²mCÎ]ŠA¸Søî»ïnÞ¼é¥û¬Z•—<þøãû÷ïïÿòòÕW_©Œ¤D‘p'‰U«V½ùæ›Î.seáÂ…÷Œ?þäÉ“.¢»»»©©É5r…ÉÁâššÛ"nnVTTØ€Hà¼4qâD–§NJÞ_Ò‹tòjÛ†œ»ä(¾p‹d./q.œþð‡?¨Œ¤t‘p' >r¿øâ‹×FÆ‚ vìØA°|ùr”×’`I °a‹Oœ8‘xhòùßòaV¯^mÛ$›6m²­œ={vÔ¨Q¶"X3*¾üòKÎTœ ôUÜå€Ùö÷ùGÎ]ZH¸E”øò®+NŠóCooï²eËTFRÒH¸“Ä©S§~øa'˜¹â…›̉YÒd‰ [ì{f-°.š Ý®ömØ`n¦e~Ÿ÷‚îDÅï~÷»_ÿúל¦0{w¼DB)˜mrîBÂ-"¦å%*#Iî„Q]]ýå—_:ÇÌ Ó{›I%Àž—/_Vá…Ûgšššúµ=wƒI6mÚä'¡‹ØºlÎZæôlËò‘ðØcíÙ³‡3Õ¹sçÜÁI¤À¶mȹK ·ˆž¼–—¨Œ$1H¸Æ;ï¼ó¿ÿ÷ÿv¿>•ðgŸ}væÌô÷øñãd즵+ÓK— ¦Ë2äÃ]–!|{%™Iȯ^½šûöí£‹ØzÉØ šlÎ5F>d?3 4ÝÁ‰ƒ×ÿoû[gÁ…EÎ]H¸E¾ðå%§N²Ÿ¾!===*#Iî„ÑÛÛû裞={ÖD30`庺ºY³f ¾øwÐÙOت‡+ÜÌcMff]6mO›6ͺl6ïÜÌ`.¶ðÜxñÅí¿ãNŸ>­[IeãÆ¿úÕ¯œÿ9wü‘p‹<âËKöíÛç¬9W>¬2’ÐÕÕ…–Ynò®!J–¦¦¦åË—÷[gNÌŸ?¿µµÕâ{ï½—åš5k~ðƒØnN#d¬I€7ÒÌZ`y °y˜,éa?ÒfcùÚk¯Ñ$¶&KšH¹9sàÀvÏNYþ•/FÑmÛsÇ ·È/¾¼„ §sçáóÑG©Œ$àcÇŽ­®®~î¹ç†ÚÚÚ©S§’”Ž$€¾¾¾)S¦üõ¯u¾YöÌ›7ïÃ?´³ÖõrúY´ò!&¶mȹ㌄[‚œËKTF’<êêêPíV­ZåºE‰³wïÞgžy†Oî¯.ʘµk×rÞó'.w€D‚À¶ùË_ÞŒGŽ‘sÇ ·(œ†[^¢2’DÒÑÑá,û“'OîëësÝ¢ôA4—/_\Ù³gOuuuWW—»tâJÞ¶wïÞ¸n¶¼ð _ýµÅÃ]7äÜñDÂ- G¸¼„sÁ਌$ÁX=‰§©©Éuˆ¤ðòË/ÿö·¿uîY~ì߿ڴi‡¶s×¥K—ÜqIÁÛöo¼1jÔ(žk“Ý!aäĉ-F»Y÷ÕW_µf„ȹcˆ„[+/ùÅ/~ÁuÈÜ:…îîî¥K—ªŒ$Á´¶¶:×~પ*—ÉâÿïÿýüóÏóæµÿ°*ìf·m}÷vòhiiY¸p¡©-öü /LŸ>Ýšø7O½94>M@ƺ C8=z´5Á¬b÷¿YÒ»mÛ6ëbÚp“€¦ Ç9wÜp‹"À¹À——˜d{ì¸ÊHžmÂ|»”H¨çüãO>ùÄ©hÒéêêâ3Ƽyó|% §¯Û·o»Ã!ÁîÝ»þóŸ_½z• Žkºì¥yÔ¨QÈ·é/ITž3gŽõ¦`k¡ìvƒœa¬Ë*¶ú† ˜Š^†±iãå4ŽƒYÿœ;VH¸Eq°¼De$埸°íÚÚZ× W˜5kÖ“O>ùÅ_¸÷yéì쬫«{衇֯_ïN^Á½m¾Fض™e„;èéï2Ÿ Ã[ÃjK0f3òð0VGµ]#r†1Kq2vK;ƒmÑbsÇ ·(&¾¼ääÉ“*#)+úúú&Ož¬ïÞ.®_¿Ž‹ðYúG?úVºcÇ“ÔÀ ¸±±‘ÏêÕ«ým¸¤ºíÄȆmp_àÙ·%/Íè2–€%[2 ’í×µµÂÂm+ºF°!Æ[ÒÌž%ëš©ûøüùó6† X¯9wLp‹"Ãé ¹¹yìØ±*#)+P“ÚÚZ w™ÀÛüܹsû÷ïÇJ«««xàÿößþžúÐC…E¥üž³\¶lºãÎ\ÝÝÝ7nÜp\$lûÙgŸ½rå ×&ãСCx°k|÷ºì—°uëÖéÓ§[Ìé΂0ŒäMañ„ ÏlŸþ9Mb¿:ë2lÑ¢E+W® Æ~GÓVdÉŠá8耯¾úJÎ]t$Ü¢øÜ¾}›K—»X©Œ¤ hiiÁºlÉÇ-—I§¯¯¯··÷ôéÓ¼ÍÑ<õÓO?µw}´ ÿõ¿þW–®)|l`ÏYºvˆ³gÏ^»vÍ=Z‘ ÒmÞxã /Á0gÎ,9l½X2M p©; ë^ÇaÆ ŒÁ¶m<3“dBkÚÆ[“­0Þb‚pl#DÎ]t$Ü" Ü\¨¸«Œ$Ù \uuu\Z.]ºÄ­7nÐ\°`ÁåË—Ý‘tø8ÍÛüܹsÎR¿ýöÌ™3.ŠˆÇ{ŒS K×Î3ÝÝݼ€oÞ¼é¡HÚv)"ç..n ¸:ºH$—®®®êêê>øÕ³mÛ¶'žxBå%å žŠ ¸Fôöör>1ˆ]6j¾ÿþ{ýZS9°wïÞŸþô§ °mCÎ]D$Ü"pit‘H(V@rôèQgÙwÓÙÙi.îF ‘+?þñͶØe…>³fͲ"éÄ ç.n ¸4ºH$Ž”2’L¨¼DŒœðím#7¹E²I¤mrî¢ á±€ë¢‹D²ÈTF’ •—ˆ‘¾½mè&·ÈÛ¶!ç.<n ¸.ºH$+#ioo¿5Nž<©ò‘é·· ÝäÃÛ~úé§yÙôõõmݺuQð•|]]]4#a×®]&Lp¶ÅV ¡¡Á¥òÏáÇåÜ…DÂ-bE‰DÀÙ¼®®náÂ…œÍG‡ëׯ¿òÊ+*/Ã"ýö¶¡›Ü‰‡E}}½küýïK–,qÑð Û6ú;zôhœ›`úôéý–:˜ôÁƒ]#7ÓºF™Ù³g³d+YnhXØg×!ç.$n ¸(ºH”>¾ŒÄés®¨¼DdÝÞþçþççŸ~ÅŠÄ,aâĉÿôOÿ¤›ÜÉfÏž=÷ÝwŸ÷lb †KضaÔ¨Q>6Ö¯_|çuÿ—aÓÄ’-ƒÑÒ$É*$ È£étØH?l@á¶.` l[lCx3yëµ›îäm ¢¬3ÆŒŸ} &ÃC 9wq‘p‹X áN ¹•‘dBå%"K¾üò˰U§œR$ÜÉáž;wî˜1cìÿļp×××Oš4©²²òÛo¿µÌ à¯3gÎô†®Åˆ,0ÒºXšþâµè5]d,@ ‰™„Ù%É0“P¸ébÉ ÿ( 8¥aŒ7î‹/¾pÚ8L¸ñcD™¦—Wò,nÓqßkFKlu?˜&`äÖ –É$Ü6ÀÏÀ0KØVl*[Ýo:Óx?`„pqî[·n¹·™n 8'ºHÄ+#9|øp_üè pA9vìØÿüŸÿ3·òlì“¡îæææp^ÄR„‡ÞO?ýtOð{éÃIÅY V7|»Ú2ŒÍJ¸ív¸a3æü€ð ,ÁJDh®[·Žf&áNOL08€ÕÕÕ»víâ ,çÎ ·ˆº:Æ<ÕÊH}ôQÓÖt¦OŸî¢ >xðà„€Ñ£G[°hÑ"kZ†Ëž ëׯwk¶b“ƒÅCrï½÷æV^bVmµO&Üö;Ì3`M”ˆ:¥ˆ0¹97’jâËI µ Ë«ùw¿ÒîܹeËòv®c)ºLÀºæÇ4;;;­¤„&òn–6› ÉZÌc{EÓJJè —”„ÇÛæ€1ö@†…·mN€€s»#+²FÂ-b®ŽqÀÊH̉¹x˜³¦îB©9§Ç6c[…ù³uëVK ®+„§[kóæÍÃ-/A¸YÚ9™p[5”õÚ_&X,â‰N)"…¯¾új¸ÎÍ`“i@j}`“à²fƸ/M,–˜ñ†ÙZ °‘–l˜&Kâ™ÁÆÓk±_ad¼a§Œ÷û È·ípö°nŠm÷Ýwî°Š¬‘p‹X «cÑI)#1EFŽ Àß`ë2†%ÜN«Ìž=Û–ä üíó`³ý“¼çž{ˆÙ †ÙýrÛ^qE±¦_׿$é5ýرcÃúön.-ØvºpÓ+áŽ9:¥ˆt¼s_/W6oÞ¼|ùr×ÈÙvTH¸E,ÐÕ±ˆà£VF®6Óe™~CÚ\ÖÀh³nº˜Š1]]]–¿:ÞLÀ4c¶æúõëM£½:›pÐÅ´¬ôô{9k±ÀÌ~-¸|ùröå%&Ü€dãú¾¤„ ¹¹™ÀzElÑ)E ˆœ{Xȶ#DÂ-b®ŽÅý}â‰'W÷‡wÀeYî *ÞùûúŒpi`8ûM‹mH©Dˆ-ðsÚ$,$KûC%?Òæ!°a¶´.û_ZÃ2~-ϦM›²)/illtQè[w¶oßÜæv_¹#âŒN)"rî,‘mG‹„[Ä]‹BKK ö9à×Ó†­Úª]#'á¯&“pÓ´FO&á¶??ò]ì*̾҅°mµ~'Ùè”"AÎ=$Ó¦M“mGˆ„[Ä] Lß2.9ÎCïÆ ØJ;***°XËC„Û&°ØË³·–$cÂm]ì'Ikr`ZšÌ9 pÃ¥K—^z饾½D” :¥ˆÁ‰Ð¹8à¢,Öàt8ï¹ènržvÀ 9‹VWWïß¿_¶!n tu,$™ÊHÂXí§]NÇ)u áf¦¸’Å)]&·ÀðmÚ°&Á€Ó†G‚ f™i»F–å%¢Ñ)E ÉÛ;.õ9áX<8 c°käĨQ£X¾`#û}HÁ& Ù3lÛÝÝݲíHp‹X «cÁ¤Œ¤ QyIRÑ)EdÃHœÛ«já…;¨„;Ŷ{{{¿ÿþ{w°ÄÈp‹X «c²Œ¤ôsQLgÕªUn„È'.\X¼xñüùó9É: >veüøñ4S„ÛîF“a¹yófšŒôyLYÚ0‹ÉÓdZ– 7]Ë—/wásñâÅ”2ŽÀ•+WÜq‰€3‰‹„&)ß[’T<˜ro[wòŠ„[“ªª*“lÏäÉ“}‰È7–—˜¾ýáfÉE‹Û6#·<± 6 çÓ—F¥¦™~‡Û2¬åÚÃGe$e' 1|pî§žzêìÙ³WJ[[›l»ÀH¸E1imm5Ïö ^®O„–— Ç(2 (Üa]fŒ-éeÉ0Ÿ›%ôÏä`¥~å1.>*#)8™¸HˆœH°s˶‹‚„[™ÚÚZSm¨ªªrYQX|yÉpÿ!ö§<;îüiœfÏž-Ꮎ¼¤­­Í­K •‘”9n-Ù8÷´iÓfÍšÅrüøñ4S„ÛJìȰܴi“Ýœöy¬šYÚ0‹É3Ìædžtá^»v­mnRlûܹs·oßvL ·(2---ÕÕÕ¶Dò\V_^ÒÔÔäÎÙ¥ÃǬ2’2GÂ-"ÇœûÌ™3W†âÞ{ïe9?À7ðƒغ7nD‘-Ã’Ø¿öÚk¸õš5kü°cÇŽY/´¶¶Zla¼kdàÓO?•mÇ ·(}}}uuu‹-ºtéïÿ7nÐäcýåË—ÝQl|yI©ü>b­2n‘wntE†…Û–cl‰@³dëšX³„þY‚<,o])ÂÍe@¶$Ü¢8ðþ¯®®þàƒxó‡Ù¶mÛO<¡ò’øPBå%*# ·Èƒ8·Wê…]>vìÁš5kì¶t]]Á¬Y³¬˜ÄÄÚßá6¿Ã¦»h >þøcÙv|p‹"`$G5ÉN¡³³Ó\Üņ'%þå%*#a$Ü"drn¤]öêœ"ÜvÛzͼYÒµqãFƒ[Ò†ù4s’‚áf-›*®¡óæÍ“mÇ ·(()e$™PyI ±ò’çŸ>›ÆBÂ…De$" ·È+Ù×sl×·ó!ȶ〄[ŽLe$™PyIÜðå%pçõbsäÈ•‘ˆt$Ü"ßÄÖ¹Slûüùó\OÝN‹â!áÂÊHÚÛÛo ‡“'Oª¼$Vpâ¶ò’µk׺³{ñP‰È„„[€:wŠm_¸pÁí«(6n‘w¬ŒdáÂ…/^4ׯ_å•WT^+Š^^¢218nQ̹OŸ>ͪèȶ㌄[ä_Fâô9WT^7¬¼äñÇß¿¿;Ù ®p*#ƒ#á#&Î-ÛŽ9n‘Gr+#É„ÊKâF¸¼ÄòóÏþ𕑈!‘p‹BRtç~ûí·eÛ1GÂ-ò‚/#ámÿ}t\»vMå%q×—äûbÓÛÛ»lÙ2•‘ˆlp‹SDçþío˹ÑΊ ÛŽ'n=]]]3gÎ|ÿý÷&GÍÖ­[U^+ P^¢21,$Ü¢ðʱí_ÿú×î´(ÛŽ1n1---Øv{{»³ãüpâÄ ¶¢ò’ø×ò•‘ˆá"áE¡ÀÎbÛ/^tû!⇄[DFžÊH2¡ò’âËKN:u) zzzTF"r@Â-ŠEÁœ;Ŷ9aº=±DÂ-¢!ße$™PyIÜðå%ûöí3iΙÇ«ŒD䆄[sî¨î; ˆl»äp‹°2’#GŽ […Gå%q×—¬Y³Æ® 9ðÑG©ŒD䌄[—¼:·l»‘p‹áËH!ç¿ÅàêÕ«/¿ü²ÊKbEÎå%*##GÂ-ŠNžœ›Ó£l»)‚pwuuµ´´4L™2…ÓbiÁ>××׳óÍÍ͇rª,ñe$N{‹Í–-[T^+xR†[^¢2 œ«]$DñˆÜ¹_xá…ð鑌ےˆ=…nälÕªUS-ZdÂ}ôèÑÛ¥FggçÚµkÙùºººêêêÉ“'ìÞ½Û=β¡¸e$™PyIÜà-ãËK.…ÊHDTH¸ELˆÐ¹±íwß}×eÛ¥F!„›×†g¿ýöÛØªikbèééAïjkk‘ï½{÷ºÇ\T._¾\__ïÿû’%K\VF²`Á‚sçÎ}?®\¹¢ò’¸aå%¿øÅ/¸H8¹¾›îîî¥K—ªŒDD…„[ćHœ;Ŷuz,9ò.ܘߔ)S¶mÛv+é´µµÍš5 ó.ºçíÙ³ç¾ûîóžMlA$XɆ œÞÆ•—Ä›¡ògÙw°[à*#"á±b„ÎbÛW¯^uóŠÒ!ÂwÖÔÔ¬]»Ö iyðùçŸWUU×óî¹sçŽ3ÆÔß 7~&MšTYYÉÛÕ2ÃÅÊH8q˜ÔÆœãÇ«¼$Vܨ¼De$"H¸EÜàÒùä“OrŠs羬‘m'ƒ| 7Ɖw~ùå—¦¡eÅßþö·êêjÌÛ‹‚ƒp/ À­išpcÛÖlnnF»ûÇ ‡˜—‘dBå%1Ä——œì¢»¹àŃ}¨¬¬DUÝq) ^¸ífvºp«ªÛÊH8Ú<³¥Ë±cÇT^+nß¾¹ËˆÊHDÔH¸ElÉÆ¹Í¶?üðC;C‚l»Ô‰^¸ëêê†ûÅÌÓ§OwÑp=zôîÝ»Á”Õ_p€ 6L xõÕW-ÃËø‘Lb™7ÞxÃ2~LÎ?éräÈ‘3f¾˜Á 7xá¶’º|mÉà©VFÒÛÛkÚZÒðD¨¼$¯466rU°˜—ÙÇ%ºvíÚéÓ§UF""GÂ-âÌàÎm¶½qãÆÀ´û‘m'€ˆ…»££™s¾™5H­‹†ƒ 7Á×_m£_·CÂm3ÒÆX·öŽN`IÛ†1xÛ¶mh·!3’ßPDñW¯^ýý÷ß»TíÛ·[ÜÞÞŽúXŒ!â¾98VF²~ýz³Õİyóf•—ä ^`öYŽW]6' %ùC¯.s29wºm_¿~Ý­#J™ˆ…»¶¶vÇŽV8›=&L`yèÐ!@yñ]2£F ú¿[0gÎë% IðùçŸÛZ4‰É‹- Öë‡&c\#ÀO h%lÀ³Ùº ·eFÂéÓ§yä¶rûömwŒJd”‘dBå%ùÃþ<í¶|˜71òM@“$±ÿ)‘Èzu‰ø“îÜé¶}ãÆ 7Z”8Q wkkë³Ï>ëLs8xcF…Ϙ£¼[·n%À‰qVè}ǘI²Šy¶o°VX¸Ãz ~¼ÇÏÆZ¬ –GëIšú„÷Þ{oÙ²e¥òŸæøh’ÊH2¡ò’=qâÄ3gÎÄÿ&7÷‰'žX¿~=oòr`Ó¦M*/‰¬Únoï¹óL@@®"6RJ$ò‡^]¢T0ç>yò¤l;ÙD&Ü}}}“&MÊí¶(ŽËr×®]Ø­e` È`Ï –´ù­—.VñkùUL¸-&·Õ=ŒÄ,-¦Ë¶nK`¶ƒZ اïÊ™™3g~úé§™nr³3.**---Ø'ŸjLFËl›G­ò’ñ߇ÃÒb°’ÀÅIZSJ$ò‡^]¢„À¹ÇŽ+ÛN6‘ ÷îÝ»çÎës˜ "ÜÓ§O÷1½ø±Ï¤÷ìÙ³ébÉlaáÆž@ž¤dš$ L¯½UÛ&V®\éWÙºu+cünäÀ[o½UWWwæÌw°î°wïÞêêê)S¦¸v‘`­Œ¤§§Ç4Ô³eË–ô¤§¢¢¢³³“€åÂŽžu…!ï¢Ì ®bçÎ<®1¶Q ,cø¼AÌœ°nÝ:— qéÒ¥—^zIå%Qá…Ûâææfš4Yr+ƒoË¡)%ùC¯.QZðŠu®-ÛN(‘ ÷ªU«Þ|óM3˜áÒÖÖ–`]€OyÜÎ2®e+¦;¢ï2˜$%ÞŠÅ6À„ÒšäÀ¾}ûf̘Á»èæÍ›v¸N:õÜsÏñ$Õ’Eað2T5ÓG^n¼™O#4I†*6À3 …sÃÇÜÃW¬XáCѯÕX§lÂç {yU°Ÿ–IGå%QþB@^óVRbÂM—¿BDŽ^]¢´àk5¨\\J$‹È„{éÒ¥¿ÿýïÍ]D HíC=„|\ºt A;úEûE”¼!ËHÐVnŒv„ a‹E‹ÍŒSî›Ô¢Ý$éBvÍËÑëþ›ÌÁ$¸/½@/#É7ÿ¶Áò0˜}`Ìá¶ÈŠ@à×" —¥åS¸ÿþû]4*/)0¼ø]$DÔèÕ%J ½bOdÂ]SSóÅ_8sið^B»÷»ß7Ž8LQ*)# ƒ¶"ܨ°©ª¿ß&å¶1#Y…%Ök²nȰ:„˜f Êý“Ó»eË[¥ý»a°‰¸æÙÌcsÚ$Öd RN/SYÞʘ}ŠÍ§£ò’B‹ßEBD^]¢´Ð+6ñD&ÜS§NíèèpÚ"ÒÀÿÇÿøý~ðþßüæ7nç2ƒ¶š4³ÿ) ëÉ$ܶ"xáFîI2Í~S&÷ž2@[ŠF†n?ƒÏ{h²¢k Å›o¾ùÔSO¹W¶È¼]$DÔèÕ%J ½bOdÂ]UUUn_p1,|ðÁÖÖÖššš~Û 1vìXw KWWWuuõ߈§zoFX½õ†!þóG¯×)ÂgvÇ:Pâ¡…`’mñº XÜÛ$Öô3ø¼gÅŠ¶Ý!Ù´iÓŒ3víÚuþüù[·n¹ã%ò¯ 5zu‰ÒB¯ØÄ™p×ÖÖ"”×Å@ôôô Üý{üí·{÷îåÃI¿kß¡··×ÄÂÒ××·xñâÁ«JÐVì–(µ•j¸Ž0y+ ©¸óG“dR„›¥yp¸ü:áÆÑé²j ðol“XÞF"Öì å=ìUøSÁ€X=ɼyóŽ;fOV±žš2¿‹„ˆ½ºDi‘þŠ]²d‰‹‚¿8w‘(Y":DÊ f® IèŒ?þäÉ“.bóæÍp\ar°¸¦¦Æ¶øúë¯û.ßŒŠ£G>òÈ#æpv¸6nÜ8yòä~Ý~àÝ»w[²ðܼy³¹¹ÙþnÒíëÝpÀ»»» ³]HÓò)·þ¸-_¾ÜVò,9ªè5 å<‰¬ŒadxX: öclClÅ6d“øu Àæ·ŒÁ ƒ¿rxŽf̘ñÖ[oÙÓ|Ìøî»ïÜ‘y ý#DTèÕ%J‹ôWleeecèû,)J—È„ûwÞù·û·k#cÁ‚;vì @Ð2Kž8qbÿþý3,&Ÿ€´Œ_+ÌêÕ«M©‰7mÚd[9{öì¨Q£lEöÁDEkkë¬Y³p¸ðWq÷ßù=nܸE‹¹T1¸}û6¶kŽüóÒ »anŽÿ€Ÿ¦Šˆ/#1ÕÕ“)‘Èzu‰Ò"ýË•h̘1¶„æææI“&!âÖDÇiÊÅK…È„»««ë±Çs‚™+^¸½X#ÄPSSÃFÚ€˜.‚þu®]CŽY‹ñ€R³ÄêìîuXÇŒ÷iVa°Ï{Aë~$¼øâ‹vë´§§Ç¯;ôöö655¹Fñ¸páÂâÅ‹çÏŸÏ: œ{áÂ…ÛXÙöÅ‹SÊH8™~TD‹”H佺Di1à+·ž;w®)u{{;zM°gÏš&â\¶ú‡ŠØ™pÃÔ©Sy8ÇÌ /Íæ»¸2±u Äý~çwºp{K&ƒÅ„Ç ¾iÓ¦°p›ßƒMb÷¿™™a–„‰'>|˜w^ëVü²¼$y¨Œ¤¸H‰DþЫK”¾b¹*Ýwß}£Ýv?,©ÛÛ¥E”½jÕª7ÞxãêÀ€?ûì³3gΠ¿Ç'Æ}1`ƒ|àÏ l0]0˜‘á.Ë„“LÈ$äíø¾}ûè"¶^Û¢ÅlÈO>rþò—¿`uæsÈ·;X±¤0å%1Ae$EGJ$ò‡^]¢´ÈôŠ ÷ܹs÷pÁ²dcc£/81'Jáîíí}øá‡±gšÃ6Q®««›5kŒ[—øsŽÂí}™Y—M`ÛÓ¦M³®æiþí-að_|ñE•‘)‘Èzu‰ÒbHáæR…[›p777_¾|yûöí–´"æD)ÜP__ÿÎ;ïà.¹äµ¶¶Z|ï½÷²DŽðƒØnš7n¤‰%û.k²ëBÿšW®0Øæ '=ûöí³Ù€Õ‰Y¾öÚkè—o29½H¹™`÷©ûöܹsî0Å_^rðàAg©I¡½½]e$EäÔ©SþËÃò®!Ĉ‘p‹Ò"Ó+6\4‚a÷”,YB@3‹ø±pÛMnÌÒùfÙóÌ3Ïð!ÁÄ®´¬.\^â\µôá¹PIqá1vìØšššU«VqihhàSzUUI/âBŒ ·(-ôŠM< 7´¶¶þìg?»,._~ûí·—-[fbWB··Ã$¦¼De$ñ¡®®ŽKK ø·ë" xQ¹HˆR@¯ØÄ½p¢Y__דּ\ùä“Ofß½m”nÑ‚//ikkse饆ÊHbEGGGàØÿ`òäÉ}}}®[ˆ(àuå"!âÊîÝ»[[[-¿bIññDžÈ‹püyóÐnçžåÇÎ;«««ýÍÔR¿“êËKšššœÃ–ü±ÊHâÆsÏ=˜¶#_E/¯+ W¬ÄnòäÉ555¼bYM•Ø%’| 7ÔÕÕ-[¶¬§§çR™±fÍšY³fyÛŽówo _^röìY'³ñ±VI¹qi©­­um!"…W—‹„ˆ7*±+ò+ÜÆ•àû³§M›öè£b¥I2o>›666>þøã'N\½zµ“»€Ë—/»ÇŸD¬¼äùçŸ?sæ Ïo|8wîœÊHJ‚¾¾¾É“'ë»·Ež@\\$D¼Q‰]™Pá.®½½½{öì±wäUõàƒ>ùä“=ô½ÈJˆýèGì9†MÌþ/[¶ìÓO?5·30¼røÿ _^ràÀ“Ý¢säÈ•‘” |"}öÙg“ý¹TÎÏ."ö¨Ä®(p7nÜ@€Ì„Ž;¶mÛ¶ðúGHWWZï ©£… ìùáÇ]ûgΜéîî¾~ýº{´e€//Y»v­sÞâ¡2’Ï®©©Ù¸q#K9·ÈnQB¨Ä®(¨pßÿ=zÔÛÛë´(PUEÄêÕ«yí¦Ôxä ˆÇåa™Qôò•‘”fÛVLÂòÉ'Ÿ¼xñ¢u nQB¨Ä®(‚p§ðÝwßݼyÓ5¢À^¸œmóú§¾ì³jg͹røða•‘”\TfÍšÕÞÞ~k80^Î-Fˆ„[Ä–lnCp“s'ŒäwoooتSζîbÁ‰ÃÊKÖ¬YãÜyø|ôÑG*#)9r³mCÎ-Fˆ„[Ä“ìÿÓ+]UU'C·¦(q’öG“mcEÎå%*#)QFbÛ†œ[Œ]D ÉÞ¶ .‚Œ—s' ·(9”—¨Œ¤D¹mrn‘3ºˆ¸1\Û6¸²ÖW_}åf%‹„[ξ¼‹•‘”(QÙ¶!繡K€ˆ#91rd]9w©#á…ÆÊK~ñ‹_àÐZ§ÒÝݽtéR•‘”"ÑÚ¶!ç9 K€ˆ#?1r”s—:nQÂå%cÿ»®2’RÄ_T¾9·.ºˆ˜ÕmN€rî’FÂ-ŠÃ€å%*#)]ògÛ†œ[ ]Dˆö?ý8ʹK ·(&¾¼ääÉ“*#)]òmÛ†œ[d.¢èDkÛ'Àêêê;v¸mˆÒAÂ-ŠŒ•—Œ;Ve$%JalÛs‹,Ñ%@—|ضqýúõŸÿüçrî’CÂ-ŠÏíÛ·y¾œk«Œ¤¤(¤m¥èÜUUU¼ÂË©{Ìņq‘'¶m˜söÙgn{¢p‹XÀóuíÚµÓ§O«Œ¤„(¼m%çܼ¼û¿P· ˆÏ‰W—Q, sbäŠ)ç.-$Ü"èù*9ì¢räÈ‘›Å€í–s—•pûí·ÝÝÝî‘RDQ(äm9wi!á±@ÏWiQ\Û6JȹËM¸Á=òâ¡SŠ(<…ÿO?9w !á±`ÈçkÉ’%.úûßëëë]$ŠAlÛ(ç–p]D)¼mæÜüãÝ~ˆ¸"á±`È竲²²±±‘ÛË·(0ñ±m£$œ›—·û[§¤#áåI±lÛ0çþýïïöFÄ ·ˆC>_\ÂÇŒC`KÀ¼'Mšäå7E>à¢R]]ýÖ[o9Û1_ýõ o¼ñ†K… ï¢Û\# þÎ=,áæ,^¼Ø5BLÉOœ8ñ‹/¾p€Lë ·(CŠkÛž_ýêW~ø¡Û'?$Ü"dó|UVVÎ;×”Û&¶€ g:ñ8\铊]TÖ¯_? çÞ‹± “o–“&M"£ÛÛyÅ.*_}õÕ矾hÑ¢ï¾ûnëÖ­&L@”‰=H3I–Ä]]] &ÃJ† õ’ 4YZo–¬b]¬î'' ÃTl4Xµ-’¹Ÿ„}‹­sK¸ymðÁ'Ntí[·~üãÓdiÂÍ#µfºp§¬ëGÐdušH¹uÙ´ÖõÍ7ßX“ŽûgnQV؉1>%vðË_þRÎO$Ü¢8 Ú“'O7n\mmmCCÏKŒjÊ”)cÇŽíííuãî&,Ü{,dÈ»†ˆoÛx­nüøÜ¹sh1±A!&@šW®\ÉHÆ!=z4y䨛7¶‡16“& cL¬™Ü&aë~ØŠåm7ØÃx:7/owj(>Œéð ,CóÍ7ßüë_ÿJæ…^°.<›Ï«¼l¤¯k#Y—Á¯¾ú*M’Ù¬‹ü… l0+¾ÿþûýëÜ ·(r¶íóçÏ»(?ȹ㉄[¦¦&ž¦tV­ZåF¤á…·®¬¬4áÞ¾};'>–\æ%Ü‘¶mðÂCX¸¦×îF{ÏSg¼™U,ŸI¸Í¶Á ÷† îþAwV´8*çÿoI}}=Á5r‚WµÒ¡xæ™gLˆ}Àk>èù¾¿Ôý…h¯e²nx$„0­MhÖÎx</§7³´aÁzCÃ#•p‹rÀÛ¶}Ðuª›áñÄ)” rî"áÅ$ý'¯'OžìëLÒ kÎMìên1Úm½"Rl¼pÃÖ­[Ñ8»i h1rÌ«$1{¶®°£Ý6±Ý7l Éáf6¦õ¥#ýºY¸!çFC­T øþ”à…í„t(Ø.`àAe¬ËÄ7¬ÑÞ¡!eÝðH°ŒÅÖÅÐKþõ¯ýñüꫯ†ã .Ø03$‡æaV´ØÖ²{Û¬H° ø^¯â¡s›U[…’ ·}‡›´|öðÚvÀA _‰GÍ…œñbë% ‰ÓôÅ Áª©ëÚH°¤94]Ä)_ÈH’˜)ñpá‘J¸E‚I±mÞtvšÓši1ªmïDßÅ›Ô+u –G¬ímHÓÔœ©üê†ÃÛ“<ïP“rÇé¬^½ZÎ$Ü¢Ètttðd­­­.+Š •§Ÿ~]닚ٳg744¸Fvp[¿~ý®]»¸Ì¸l°ÿ9;7ÂÍÒ~nÉ„Ûj–¬×þ~Àâlàµí®~I‡G*áI%Ŷ“Mí‹M_2vohÛ½ç…f-Ö%` ¿.°ºMh0ØT¬E†˜À,ßÇœôˆ X¯œû·¿ý­{ ¢xH¸EñYºt)ÏWmm­k‹¢’?Û†áÚ6tuu­ nœøÕ³mÛ¶'žxBå%…Älã3ϰعsçý÷ßOÀ’Ø’#aa€k ‡,w€ÇXçætä¬ÿnx »[·n%nhhÈæ? ü‡œÁaLú'Ù³g#ÜþïVmL–f‰„[$†DÚ¶ñÑGɹ „[+ 9zô¨³ì»éìì4w£E>–m¯[·cÃnYÒLnò6`Ë–-<6ÌX`3?°µl#,Ü6Œ$Mb¿¢ Àm­Q£Fe#ÜPçÎ$Ü<œ•+WºFúkÐqÜbœØD™˜Ë’˜äôà'6ˆíȱÿ"0™&C’ YúfàÛN¸™ßf`Nš,í“ÚN®_¿~Èÿp‹d`Û6pnÞÎîÑŠ‚ á…Kr¸Œ$ˆ‘ÊK Àpïm÷ôôX€ã"¸&ʾ‰ó­X±‚&ªíó,19¤°-¥ÃÅ+**È3[xuòaáf X%Ãl~¿![y²n(¼sgnS^×ðÊKÌC³ÒvkïÇ@Æœ˜¥Y2Ðk7ÎSföcl€ŒñÚÆÖãlyó{–CÞƒ—p‹`'Æá–Øeoç”OÚEá÷¿ÿ½œ»H¸EáÈTF’ •—ä•áÚ¶awRMp!lÌÞ›-Ã’Áxmö†% Ô¬Î$`Ãh+¥–” è¬k›£éç·a~ëá®,)°s"ÜfÌ©‹Áõ6 Ö•ž®š`1ÇÙÆ°äh‡¹_—Ñh®ñ$ l° ü´þN6Þ³Œ'@l€MÈÌÁØT$Ü¢ÔI±m^í¼òÁ>I¦·F˜ðÛͰŒm+åœ Ì9à§e9w!‘p‹ae$ííí·†ÃÉ“'U^’r³m®ëÖ­#0ÁõÊkMz·lÙ tMÒŒÙnftvv¢Ý\ºl˜aƒÁLÚb o÷Ôm€·j†ŽÛÖÃ]Ù¹sŸ:uÊEip:r[½…Ýì÷øCaÇ“¥Œþ¦d |Héµ#“r@lÇ lc†&ì?Øbû°D²«"á%Mºm{öŒ¹zyµÿ, »,ÆŒ=»ÆÝ]>? pÛ§Ü”®ðT`MÛ¨-S Þ"± cr›?9wÁp‹¼Ã[º®®Ž 6rãRN:u÷îÝ®"“p{n‡‹ÇŽõÚáIžO/þƒ>±˜:ûŒ%FÒŽ!™”b‡Ñ5‚^/å~,YÝ6mÃÐn6ÁäŒ!ðŸ¦AÂ-Šç´úúz×}wþ°H±mT5E‹ o“éÓ§óF³&ÆóFãBL€ÅX –AÜnzmfV! iM`{ƒ³ kš3ÆÖe¯Àv¦í1ÚÍ*`ùtpî_üâî@ˆü áù…sÝ¢vúœ+*/‰ŠœmÛÀ½p5_ÌMì—`ræ›àÓ–„~Ñ ¡oú™ ’¬•²Æøa ð›È›ËÕ¸qã8óÔÔÔ¤¼Pnzÿô&'¥iI l@8cÐô¿–>bÀä4ý˜ð&ü †o¦ä3!áEaÏž=÷ÝwŸ÷lb ²'Ŷ!]‹‘`ÖbºY–ëׯ§é­7ìÁ^pIö¿0`>= p#Ät‘·{Ò~¶¸råJ¿iÿçá AøãI¶M6ÆâÙ¼yó¿þ뿸Ã!ò€„[ä‘ÜÊH2¡ò’‘3BÛN$:7—4Î<ÆÒ¥K¹4Zž¦ÛXÒá‘J¸EáA¸çÎ;fÌNq4½p×××Oš4©²²rð×dºmƒ9«k„µý5o[/AzÂó„…›i26G§I`þm éé³¥lˆ8¼ 'öŸÀ¤ßÆXh†Ù±cÎÍ»Ø5n‘x÷ZÉ… ¾Žk×®©¼$gdÛ™ˆÊ¹¹RræñŒ;– ‡Øm)éðH%Ü¢ð ÜKpkš&ÜØ¶5›››Ñîþq1 mH­/ÝÆhy;‡oZÛMå°õZ>%cI»Ù¼~ýzf`ë2ÈØ`<غXÚnÃoÚßáFšmßPÖ ßác ‚}q;3rî¼"áÑÃ;æÌ™ï¿ÿ¾Óä¨á,£ò’à¢òÅ_˜‰82ÿò/ÿÂy#r&OžÌÒm&éðH%Ü¢ð˜pŒ3¦½½Ý„›˜|Ðß[Âà·!vá€ÚÚ_8 îßÕ´j«…Ћû ÐôótuwÄÖeñƒÓÖÖfÓ¿±à¯;,oM„›¦ öÄÖ%ðcl¼ý} [ܲe‹5ÉÎgŸ}&çÎn1---Ø6§|:åQŒ?žå믿î²w àÀ׸ò®‘F¸Q ·( ØóöíÛ-nooǰ-nllDÄ}ÓSº¶]0pî'Ÿ|òÒ¥Kî‰#á`e$G޹Y T^2\¼s;Kº›“'Ozå"¶¤7%þZÓ 9à´Ò$ï·ÎûÉiЬeÍð[7<>/_¾œ#ÓÿÀ‚fÉSÀ£  —Âÿ¤ÐôÔf0üÑ —¦±ƒã± ý˜ô655ÙŠl…'zÈz$Ü"æÈ¶‡*Ú_ä-g$Ü"w|‰ÓÞb³eË•—dÏ€ÎNy Lnš¨f®F¾»»› Cq8`],YÅOHÌœá­`{`±áW1×ôIóo›Ÿ%™ô,m€Ÿ–Œm4Lä¶=8œŽ®¥ÁŽíرÃ5®]ãã¢Ác´Œ °$MŽ0M O“Ã{öìY?¬…»a€-Oœ8acõêÕLe1ëîß¿?}£wî¦7®\¹¢ò’ìй›šš°U»aL‘åìO@#xýNyÓYš–´›Óæ¾¶Š÷Ýp ¶•“'O2‰Ý&Û¨ ßÀ6üüéw¸ ¿nàÛwámn3c‹Ïž=ËAÀ§õ½Ë}i2’Àn-é¾>ï0±¶˜Ù8Œ³î€eÇXúUߨGÂ-âIn÷¶ÃÂÍkž3‰Å>0hvvvºÆmmm4Ãã-c±öÕÚ`c8Y¥ü½8ï5–érQ@J3}»át®=LäÜ#GÂ-†‡•‘lذÁì6¶¨¼${ÂΊ§l+Ì è¿YTT[Ó2,1c2\|†¦é²5mbNúÀE…¼yyx+dÂk…W±›¬d€¦ŸŸÕ-“2€¥­øv¿pûŶa@á¿ó,ñ`2a÷%Ô’!CL¯w_f1дƒÃxš,íP‡ KèµìÍôÚ*6fÿþýCnÔ#á1$çJ’táFj 8«ÐeÒì›,iòÞš¼YÌw‰gÏžMÒ¾1‰<à"Å’µÈ{ÿöØ0û-š)Û[—$ó0 e»)ãÉØ„Œ ¦Ï9÷‘p‹a`e$ø™ImÌ9~ü¸ÊK²Äœ»»»ÛyS8ƒ§h'qÅ]Ql8]ÍÔö³Ï>#8sæ ±%ó O«k×®ÅÅ-Άø÷¸qãØ!€Cn?²ËI5LdV»mºlÀ.w7˜-C@™¶ß¤f°¥Ýf^±b…ïJ‡a=A)¶Í“i»(5¤o7e<Ûúá0âÜ#ùu°rFÂ@ø4þÚQÿs#!æe$™PyIödãÜé÷59‰»(ÞѶӑÒá³úNM6˜y€Y³fÙ§M›æRÙÁ#µ#ì¹1 çü «­‰,K ˜.y¤™Øò6 <ž1œ$m¼Ý]‹/½ ðÇü0?-Ø<¶]f#fÍôíÃÿ1>< güÿrþ”s瀄;ìÙ³ç¾ûîóž=àOÚ‹R)#ÉñU^’ YÞç.9ŠkÛ0á.-$Ü"žäæÜت‹Òî^d-ü·n`—Â[ñ¤wÊvqhðÁ w¸ ¿ŸF[ZËxÛ¶78gQwdEÖH¸Â=wîÜ1cÆØm]/Üõõõ“&Mª¬¬ÖåÐÊH>Ü7bx¯ºèn<袼qìØ1•—dCòœ»è¶ n!ŠŽÜ†åÜa&F[Mm‰Áj²iÚÍf ILÆ’Œ· 24½I¯X±Âò–øa Hßî–-[l4ͼS¶›2ž MHL—ÅY’nÛ…?‹& wA¸—àÖ4M¸±mk677£Ýýã†båÊ•óæÍ[°`ï.ç­#ƒ3KÞü`côèÑ™\¹ö–¸ÆP0’ì+>Rˆ‰mC$Â]àÃaß¾}Ó¦Ms<#á1Ç;÷õrž²)KdÛ"áN ^¸ífvºpYÕme$555æÁÓ§OŸ0aKÓVX¿~=D™¥Kõõ-Z´håÊ•ÓÅ’^Æxš&ÜŒ±a tù°p“a[6Øþl€­B“ôS“$`X0¼ÿ?éhnݺ՚ `•{˜¤ÊK†„ËÒSO=…^»Z€µ®‚'ËEi òWwØö€³!ÐàƒræÌ™M›6?~œ­àÜ.ÀžÇç:‰pÏpáÐÚÚúƒüÀ5òŒ„[Ä9w–ȶ£EÂ@¼pƒn+)¡Ë×– ’jßFÂ[ æ8.ù0ôZ@,îê겑­Ù9–~sh¦K2UŠpÓd?clpÊ*~*¿ –¶Q„;7½¦iØÀåË—õí%C’îÜûÐ\ŽKËs`-ÀzyýXlxNé•ï¾Xšcî¿y[WG@W¿nÂm[±$¤Oî¡ËV1beÛ¡p¿àRW®sL,>vìXpë,³qãFVY³fîðxòŒd€5#AÂ-J‚ýû÷ãÜ/^tj)ÒmGŽ„; ‘Û·o·¸½½ÝE`cc#"î›é ªO<ñÄúõë­rkað]Bv›9¥êË’˜–1P¨ÎÎN_"¶nÝ:Æš füQõ_cd1Ø0`13Ø$髨T4}WxüŠ+,oc¬×ŸSyÉà¤8w` pn–Ÿ}öÙøñãͧ9°,§M›†ÌqTqè`x?™ºˆéš5k³±¤ÉTp GKK öþ-.<Õ{pø[‡£µ¯"éÇŽËZ6Ò~éŠ lÃ,ûyáBß )“x-Nù]€ôUl*š)›HÁöŠ ½ÛæQ«¼dÂÎm*l^‹æbxÖäÀ²¤ Aç?¤‹§Ì±ôñãljm°mÅÜÚno#å6ÂkdLÊ!†¶ Q ·yöŸþô'\yïÞ½,‰­É’.^Ï÷Þ{/12mI>ž%‚΀‘p‹bpçæüã¢aRQQa?Ä!¶3Ý–1rÞÖ N¶'$Üâe$¼Íœ‡ ©ˆ,škåf´or’ À®Œ—“1K6G·º[—.–ýŽè/IF2Á€Â tÙx›Ó¯bÛeßèõ› ¦×Æû='ƒsûÙRæ¥K—^zé%>ºàŽˆ¸ïÜ ÷ßáædM`K4—gÁ|×îR‡+³é¢iê>lÉŒa‰mÛŠØ?xÀ;ÜÖ o‹ dZ lW7»}Nà»dÛCÂ]¾ôõõ-^¼˜wo«JV¬X‘åÖfß4âÙàQp)¨'™7oÞ±cÇü©Ç,q7qpîR±mp Q*|øá‡æÜæ¦PQQ±ÿ~ HŠìájbæZ/™ôñdhöO8ºåm˜‡v#ÍÃìwþÄÂÉ‘pôèÑ3f¼õÖ[vÞ_§žA(®s—mƒ„[ˆ‚Ë¢¿Ï`dÛFÂ]îܾ}ÛÆ5×­[çÜ3W싇¼@§˜t¸9êΙpûï92˜'}]Эù˜ž28|‰w@õ$Ù`Îáïf [,­ë„„[ˆÒ"ñÎ-Û.<nÑÏ… /^<þüžž'¡Ãü[ÿtÿieŠŒO,\¸$1î¹ç‹Éû‘æëôBʺִL $S|}X )e$+W®¸ã"†¢ðÎ]r¶ åó7Ü>ø =/î‘ Q²àÜ\íËþÆÙÿjA‚‘p ÇÈËKn>4 Áv×Ùº)øJÿÍ›7£×6’%0ÀºÐqÀ¹½U#Ù˃ï+µ,}—aëÍ •‘DB!»mÛcû\0Ð_÷˜…(eéܲíb!áÿ`„å%^£ÍªÁ„›%¬š|JI · ¶.LšŒî2È0À5†ÊH"¤0Î]Ò¶ ì¿íya(¢póHÝc¢ÄyçwV¬Xá\µô‘m ·HÅ——tww»j¯ì@£-@¬-@‘wÜù-Ë~¤ X`_rd]5Áב².Kšv?Ûº Nþë†ðÅ_TI´äÛ¹Kݶ Âí"!ÄXàŒu8Øu€KžeF×ÖÏ>ûÌ5®^µ_ç%¹oß>—Ùvq‘p‹ðå%t–šéÂM€›FƒÙ³Åûƒ 7•kÛšŒ±&æmãIºFÖ´··«Œ$OäϹeÛ9 á"*rsn»®D%Ü\ ÃÂ}üøq–k×®åâh™Am ·˜py‰sÕÒgãÆ*#É+æÜ§N²ßŒfÓu"$ÜBDÈoûÛ!ÛÜh¦ ÷¬Y³èµ$clÞL>èïÀ²®®Îƒ}ûöÑœ6mZŠp¬NÞ52 ÛŽn19——Ä •‘Œh[¶3n!¢eHçöm†øö?„i^½z5VM6Q¦iè%ƶ½vÛêæÙöó)ÂÍDܦ̈́l;&H¸Åøò’¶¶6÷ö-5TFR`¢rnÙöHp 9æÜý?¾•×^{mþüù÷Þ{/1XÓ–pìØ±üà¶´»×ø·-I"ܬȒ®ÖÖVfãiZl0€Ù\c Jë7Â’„[ //ijjr[:|üñÇ*#)<#wnÙö‘p ‘qn„xÍš58ñàÂmVM€R3iFÓ‰-É’&“˜[³´¼uYÒƒ£»h dÛ±BÂ-²Å——œ={ÖÉl¼A¬UFRDFâܲí‘#á"OÔÕÕ½óÎ;&µaPj.7èò€ÂX³"ÆŒ%3†ÌÆqh’6Æì™.‚~Ýnme€uáå6-I2ætQ²í¸!áà„ÊKTFrsnÙv$H¸…È/¼ðÂ|àÜöø1†ƒ5͘M»·¶Öš˜1]ûöí³$ȃ•‹'f³Ù`yÝl;†H¸Åð(‰ò•‘ćá:·l;*$ÜBä•;ȶ㉄[ä‚•—<ÿüó)Ÿ¶‹Î¹sçTF7pî'Ÿ|’çââP0F׉¨pžªª*{YÁCv¾,Y´hQÜœ[¶[$Ü"G|yÉܽØ9rDe$ñ$ç¦W׉A†\$ Es½Ìbåܲí8#á¹ãËKÖ®]ëÞîÅCe$1gpç&¯ëD´È„ Çœ³bYÁCæ ÛÝÝíAYbÎí~·xèycŽ„[Œ”¢——¨Œ¤TÈäÜdtˆ wá)[áwÊ•¢;·l;þH¸EXyÉã?¾ÿ~÷î/8œÊHJˆtç&Öu"H¸ „»œù×ý×­[·º+Sa‘m—n œy}y‰;äŸ?üá*#)9ÂÎÍR׉zô¨®ùCÂ]x8æ|à/+$Üa ïܲíBÂ-"¦å%*#I<‰ÿüÏÿ¬ëDþpžH„û®°xñb|óÍ7)Šˆ„;…7n̹eÛ¥…„[DÏí|–—¨Œ$1øKµ®ù@Â]x†%ÜHó}÷݇=»öÐëÃf˜‹&Nœè×3fÌüc‹‹‚„;Â8·l»äp‹|áËK†ûËÞ™èééQIœilläI±¸¾¾žK‚Å™àRÍâÌ™3ºNä wá–p#Êvk4ú«¯¾ |Û%¿øâ‹‹/†…› ’m1ã‘oß4à¢;ºÆ­[Äa¿LéÊ ÷€xçvW¯¨Ñ/ò–"n‘G|yɾ}ûÜy"W>¬2’˜ƒpWVV´··Oš4É’ƒ #Ì+:¼…‡cþ}ÖŒ=úÂ… ,­ùæ›o£àèõ /¼`žyæ–dlŒÁÉÐzYË––±U°pÆØ„4™“.’Û`ºØ ™pWÿÃD‰ü9·l»D‘p‹üâËKÖ¬YãÎÃç£>RII0fÌ–h÷öíÛ 0ob䛀&Ib“ræÞ“½p›(˜`Àø7yTØ ™"ÜVaÉêLBàW1ü„îb6V±u 2ýë_]c˜H¸ç~òÉ'ÿüç?»+YȶK ·(9——¨Œ¤´°›Üþö6þÍSvùòeq®ëÄd¬WF˜Wtx OöÂ"ÿøÇ?F¬- ã­š¤Ç2 7ÒLÞ†™1[ìºï^ËÆ°-¿¹÷ßßnr›²[ÞÆØ]ðlpW1œ{äÿÇkȶK ·(9”—pPIÉÁuÝnoïÙ³‡xIM\xm¤Œ0¯èðž,…9Fv¿¸ƒ™1»Íìïp›gºÃM﫯¾j3° q¦;Ü,Sº<áûÜ `*×È ÷p-ûÉO~2rç–m—:nQ8Âå%Á †ÊHJ”1cÆàÖ,-+)\œ¤5e„yE‡·ðpÌofr+)1á¦ËÇ #Ì+:¼…GÂ- œ9·]첄c+ÛNnQ,/QIY!#Ì+:¼…GÂ-‡Ëܰœ›+ÛN nQL|yÉÉ“'UFRnÈóŠoáá˜ãCe…„{¸ ÑÓ§Oïèè0¥Žªl;IH¸E‘¹”—Œ;Ve$册0¯èð ·È†¿ýío?ùÉOwn©l;aH¸Eñ¹}û¶?kƒÊHÊa^Ñá-ÈóŠoá\¸í{ú-Z„õ¨ÈédãÇL®qœ~Ô¨Q~+~ IËD…„;g¾ùæ››ƒ)ÛN$n $eˆžô¼¢Ã[x8æ}À€±m×èëâX¦këÖ­fáLùlV1“öcL¸S6ÍTŒ$Ï´¶"Û¥!‘psî£G^¸páoû›l;ÁH¸E,R–,Yâ¢àëœ]$Ja^Ñá-<ƒ·W^Žkw¯Á<Øß~6NÉ Á´91àÇ6-Ðd[‹1&Ð fù~ŒM˜¾i›“< ñ¬Åæ>?g&$Ü#Çœ{ïÞ½²íd#á±`H9¨¬¬ ÿxŠ%EI##Ì+:¼…‡c~#¸/.ë÷ßÿÎ;}Ì÷õMëJϰ´ÁÀœ ïÐÓÓãt™1lŽ¥Í`]Öô³Y̲¢¢bË–-¬²"À’düŠ™pGÎýÏÿüϲíd#á±`H9à4fÌ[æ=iÒ$/ßᦈ?2¼¢Ã[xn@vQX‚ÎÎÎuëÖ¡Åæ²¸¯¹x6 $±j³ät'ö€™ÃclÂôMÛç’ìÛ²d6 .Ü}}}.CÁ‘ij9’²í¤"á± 9¨¬¬œ;w®)5¶Ml™öövñLç}Cd„yE‡·ðṗD[["k“Á˜ÃM‚``Þ2˜±õú ëÁJý~LÓîI[Ø`×3Ìa-˧l|LÀZ–ràÛ©'Þ7ÖÔÔ¸†ÈŽä÷ßæÌÙvR‘p‹XpN¿ï¾û,F¯M¾YNš4‰Œno—§Nêííµ8ü¤“ïèèp Ù¼§D´ṗ– <äáFµ§L™B¾¡¡Á¥Dè ›x$Ü"dy® wccãžË_p"â ¶=vìØšššU«VÙ%¹¾¾¾ªªŠ¤q º~޹óв‡ì…Û«¶±wï^;,"8b. EÂ-bA–ç/ܸuee¥ ÷öíÛ/_¾Ì’“¾„;þÔÕÕ—ã»À¿]·ˆŽª‹D¡à˜;-xÈœxß}÷ݰj§NrÇEdGÌEwÿŸm½¾›«ô‘p‹X~®ð ç¦ vsÅb´ÛzEléèè.Çÿ`òäÉúãªÈáÀºH ޹óв‡üÐCõ¿ EUU•;ÜÉ‚‡æ¢;軹†„[Ä‚ôsH0Ï=÷\pét455¹X‰BÁ1wZ6ð÷ïß?þüþwòÝäé73»(Y¤?.ÿ¶þn›››'Mš„ˆ[×/•n ’zÒÚÚÚAHêýª¢Ã±u‘(óëƒròäÉ;w²tí¡XàÙÑà!Æï¢&‡/ôzéÒ¥ýoé;䩆›™]”,|\áïæjoo·oسg¾›«äp‹XÔs¨ÈžÝM~àäÛ¥D¤è=Ux8æÎCâõ×_¿ÿþû.\ˆæf©Ñ ×”ŠŠ óø¦K†5j”‹îÀxöÇ5r…‡lÂmG ¬Ýyúà fvQ²ðqq`ý_.¡Ýv?,©ÛÛ¥…„[Ä‚¤žCE&š››yÒkkk][DÞS…‡cî<4»íîîF‹IzŸFÇÃnÍššš°.3Ðܼy3Mb&gÁ’,Y—d°Æ?„ÛÏÃä6ÒÃl¬bsúæà÷ãyÈaá6L»§L™âÚ‘’Ôv¦Çî¹sçÚWøÞ¨ïæ*$Ü"Hʾ¾¾É“'ë»·ó‡ÞS…‡cî<4 ³g×@‘ÇÑz]F£­Æƒ‘d°dî”¶.M´ÉZ¦È¶ 3ìܹӦ¢iÂMlšÎFi†1Agff[`30Ørºphw>¾ë3©/ìLË 7·6ánnnÖws•n $1ÁWz$Œ2¬çQ»H Žùµ ,p\yÓ¦Mû÷ï'Þ`rlcl­ô¶ôÒ3ÀŠ«W¯¦‹ØæÄ¿!è&a3˜ÜŸ8qÂud€‡øváʈ“úÂÎô¸ÂE#vAÉïã Ç"þH¸E,ÄžˆÛI¤ _`zO޹óÐ4_üÕ5¼"³Ä†M”—/_N&E¸Ód#ÜlŽ{ 7˜‚ãÓÖô`ç¶Š-Éðy€xpAç!K¸#AoØÄ#á±@皘Àá5Y˜tww»ÇYè=Ux8æÎCåµ[Ú'Nœ°jSd >{ö¬uYÓFVTT˜û¦\¸‰ÉÐL¹Ãm«³u[+Œ­H`w¸ms,S>'¤`ï, ÷ÈÑ6ñH¸E,й&&ðD8EM…ׂ¢£÷Táá˜;»…l#Ó,­Ëê7€$MtÙšè²ÝÒNà×¥7<ÀÆ[†1€=³¤I/KšÁ4ý;@3 .NžÁØ63ø-¸QøwVR_ØzÃ& ·ˆ:×Äž§¨É¢ðZPtôž*<ó«eFáßYI}aë ›x$Ü"è\x"n%‘ÂkAÑÑ{ªðṗ– …g%é…ÝÛÛ[UUÕÜܼwï^K Y]]/xÅEÂ-bä &ðD8EM…ׂ¢£÷Táá˜;- ÿÎJØ û¹çžã¥P__ïºE‚p‹XÀ)ÆE¢¨ðD8EM<®kAÑÑ{ªðṗ– …g%ì…ÝÚÚÊ# 3vìXÝÞN$n 8˸Hžˆï“«ÀZPtôž*<ó+eFáßYÉ{aOž<™åÑíí¤"á±€³Œ‹DQá‰pŠš,x\Ö‚¢£÷Táá˜;šiÓ¦;vÌ5†Ikkëøñã]#j ÿÎJÞ »¡¡eèöv‚‘p‹XÀ‰ÆE¢¨ðD8E”/¾øÂE!^ p€‰'ºè.\8|ø°kWµ èè=Ux8æÎC#eÍš57Áüùóëêê,™=¹­•%…g%ï…aó  ÝÞN0n 8ѸHž§¨™yóÍ7ï»ï¾to~!À5æ¢;üøÇ?NOWµ èè=Ux8æÎC#]†3gÎØc;vlÖÐq`˜%mFZÞd=Oþ•ȶýé¤no' ·ˆ’ƒ˜Àqs(&NœˆXOŸ>ݵoÞ|ã7^}õÕ9sæ§ùõ×_lÛ¶mÔ¨Q6À3zôhVd¼k߼Ɋ¾É*¬ˆÊ[Ó¦µÂÍ”®!)¼½§ Çür> {ÖÞ½{ÿô§?Ý{ï½ø4ñüzIþà? øáHÁÔ©S?þøãþ5óFáßY‰|aÛŸNêöv²‘p‹X 9ˆ <NQ3€L#Ͷ<Û½F—mÀ† H¦7cŒO£ì–a¤ 7° ÍÝ»w›Ê[Ò“d$F~þüùpL34…ׂ¢£÷Táá˜;Íén=`·$æm]ù£ðﬤ¾°§L™¢ÛÛÉFÂ-bä &ðD8Eͦ X/ÊKà­ÛzYZ&E¸Qg»{m²NlA/¶m±uÑ 0u°ÞpŒsÛ0kf¢ðZPtôž*<sç¡ùÁ4š`Há&6‚!y¤ðï¬D¾°»ººž}öÙŽŽ×IDÂ-Šg––––¾¾>k†Ï¡{÷î=tèkˆÂÂñÝ  ¿0aÂ[’Áª­kQËø.ƒ&«ÁÊ•+?ÿüs&q}ÁÌd,&`ŒMÅHK¾ñƌٰaC8Þºu« ³1™(¼DzIÌá˜;ͯ¼òŠ/)ñÂýñÇÿð‡?$3uêTK0’ ]§OŸ¶ay¢ðï¬ä½°¹VWWoÛ¶å{ï½ÇùÊuˆd!áÅÕžþ•˜vWWWuuõ|€j‡Ù¶mÛŒ3¾üòË[·n¹¡"H¸E1©ªªâìfòäɾÎDž§¨É‚ÇU`-(:ó×ÕÕ-\¸#æ3cLµm€Œ”UÌÚ­ÐÅòˆ8ËLu/nQ0NŸ>m/¶BR\áæ!»ŸòúÂÆ­çÎkJÝÞÞŽ^ìÙ³‡€¦‰8·è tuuÍœ9óý÷ßwš5[·nUyIÉ!áÅaÙzâ‰'T^R,†nÚSgoÃ`]éÀŒMŽÁJSl]üØwað^å-°1~°Ÿ–^VñîŽ[`K›0ż%Ü"Ù”ÏÓ×GÊ)â¾ûî³í¶ûÙ`É,oo·´´`Ûº³ãüpâÄ ¶¢ò’BÂ-Š€ þ#[¸¸- HŠpã¾àÞ¡í¦u؃³nüØ;tOOK Ï`ºÌžmXÂ÷¶×­[G‰ÇÂY—¤­ÂÌÁX‡„[$ wT„…{îܹ{ü©£±±Ñœ¤“§2’L¨¼¤´p‹‚’RF’ Iå%E‹Ùõ'OžÄƒ_ýu–«ËñãÇ/_¾œÇµ<ÖkƒÉòÀæÇ>N655Ùx?ÆØ¼y33»FÐ˦m Ø*ÌÆêÖ¤—LMM 1“³ºíg°öH¸E²‘pG…nN¸µ wss3£íÛ·[Ò¤àËHn–-[¶¨¼¤$HŽpófØÀ%¹!„%O:åÆ‰â‘©Œ$*/)<) ¨mÿÝé… ½Î"ܾÙÝÝMÓò$-°á àÄ4Á\™1¬k]@/¸Æõ뼋Ñhã7á÷Ä´ŒÅ> ·H6î¨`Øý%K–Ð Ç)XÉ‘#Gœ•—”¥-ÜHöÆ-Z4vìØqãÆÕÔ××;×°ä”)Sx—p!—|+#ÉíG¶T^R0x›8EM<. ·H0åótÇí‘ú2’óçÏ;ÿ-W¯^}ùå—U^gJR¸ñìæææÚÚZ${éÒ¥Û¶m»qㆻ):(_~ù%:Ž|WUUáâ2ïÂàÏGGð#[*/) îÄ á.+$ÜE¡Xe$™PyIœ)1áFÝÞyçŒûüóÏGŸ£G"Ü6Ooo¯›]ä_Fböœ3*/) \Ì®% ·H6îÂUÉôéÓ]*/‰-¥$Ü7nD‘W­Z5øßÛ D9‘oÝ=͹•‘dBå%@Â$Üe…„»ØÛ.X°àܹsxí™0a‚‹"âÊ•+*/‰!¥!܇ªªªZºtiOO3åè¸|­ïÔ©Sz·=1b|I>~dKå%ùCÂ$Üe…„»`XɆ œÞŽîE‹õ+jtò­ò’¸QÂÝÒÒ2kÖ¬¨î’f¢»»ûW¿úÕ¯ýk·U1|Y›Óä¨Ùºu«ÊKò³«ƒrüøq>ðÀêÕ«]*y…Øà¹2mÚ46 Ÿ}ö[Ù·oIâñãÇÛ€Á‘p‹d#á. VFòÕW_9«“ìQ£FY3B8aª¼$>Ä]¸W­Zeßöå¼8Ϭ]»ö™gžÑÝÓ‘`ç£ÂüÈ–ÊK"gpáÆ›¹*ð6Át1`> »Ž; háȱùqΰE6çƒûï¿ß6y×ÕÕC†@Â-’„;ßD[FÆ„û7Þ=z4KKF…ÊKâC|…›÷sÏ=÷öÛo;.Ÿþùÿú_ÿ«¬.ÌQ‘§2’L\SyI\¸ÇòºÆÕ«È7KÜ—$]Ç7-2<;8:½@/#ÉOño^6$YÅòX»­k½À°À„›4ýæ†DÂ-’„;¯ØÛ®_¿žË\ä Ü.êë›>}ú®]»\#:6oÞ¬ò’¢SáF¡xqúé§Î­ ˉ'*++ÛÛÛÝÞˆ,ÈwI&T^-ƒ ·¶ñýì³ÏX"¾dlM¤ùÌ™3tÑDôâß¶Jÿúw°ûâæÙ8·õ"èAç]0'yf#p©ìp‹d#áÎöß¶‡vö5&ܨvCCÃèÑ£0Ãf‰ötuuY2\¾|Yå%E$ŽÂ]__ÏÕÚ™oñhkk«®®æRívK ïaÎG1ù‘-N‹*/!ƒ 7B¼qãF׸ãÍéÂ:ãÜx3odšƒ 7¶m3¼öÚk~@8Ž—„[$˜òyº öHóZFRDT^R,b'ÜÍÍͯ¼òŠsÞb³uëV> ¸wãËHœö›-[¶¨¼d„p13Cƹñc”±&iºl̤Qmºl>ŒÑ\¸÷íÛGþÌ™3v‡›€ùÍÂ݈,`]“ûLH¸E²‘pGK¾ËHŠ‹ÊKŠB¼„{ïÞ½?ýéO¯^½ê*üû¿ÿûï~÷»Û·o»]w(nI&T^2B¸˜]”?þØš÷…eø„|úôi‹É³üáˆþþéO¢ XCæa*2Œ±9ûgšÖ› lnðñn‘l$ÜQZIOOÏäréÒ¥—^zIå%…$FÂÍ«üá‡æ¹wê*++¿üòK·—¥zQ__ïÿû’%K\v>*zI&T^2†îl¸÷Þ{M¸§NJà²EEÂ-’„;ºººžxâ‰õë×;-M:›6mRyIÁˆ‘p744¬^½ÚISœØ³gOuu5×l·£±‡¾ï¾û¼g[ VFálå •—äF$ÂÍaå•WæÏŸ¿wï^—*6n‘l$Ü#§¥¥…«Æ¡C‡œ–===+V¬paÂéšG­ò’áîíí}øá‡cULæç?ÿù‡~X*/G„{îܹcÆŒÁ3hzᮯ¯Ÿ4iReeeÎÚae$ÑþÈVþ°ÙRyɰˆD¸cˆ„[$ ÷H(JICCƒ‹îfçÎ÷ßÿ„ X®[·ÎeÅVqAp£*/) qn\ð½÷Þs¢?PÌiÓ¦;wÎín¼A¸—àÖ4M¸9ÂÖlnnF»ûÇ >ŠüG¶òÊ•àG¶T^’=\Ì8ù& ·H6Œµ ³³3%â¶¶6³ôã z€"‡göcÂyŸô¤ÌO¼p§ïOxÝðä)¨¼$ßÄB¸y¹ã‚¸‘³¤XòË_þòÝwß%p;cL¸ ÆŒÓÞÞnÂML>èï-È’R)#É„ÊK²GÂ$ÜeBUUÏõ¸qã\;éDû¼Œ„kÇ„ .\ØÐЖÚQ£F±$?{ö슊 C†4Iú‘~Œ5íÖ52‰¬kkaÆ4‰m]ƒ^†ÙH°mÙlŒ'o›2¬kSÙ$$ioV÷íŸ: •—ä•Xw]]]¾eî\€k¤P.Z´È52püøñGy¤»»ÛítŒñÂm7³Ó…{XUݹ};Rž~++Ü´} ’ÊK†DÂ$ÜeB¹=ÑQ=^® C–‘¬X±[µ8“p‡3,m6ò¬‹×ú¬k~ìe—Øn6ãÄ>Éœ`±AÓìX%}Ú‰m0r^”°uëVš–Ï|z¥ž3gÎo¼á™yì±ÇpÖëׯ»ýŽ+^¸Á ·•”ÐåkK†ÄŸü‘­éÓ§»(õë×s´ ø$Ã0{âüÏX“^…¼ÿ™/›2;°=;žá@v¨­Ë2À·ãì“<;&Ê^-¶ÕýSiÐäe@O´ ök±´yÀœÛâL¨¼d$܉A–TRþNOtÎp9xùå—çÏŸÅ^ˆåË—¨©©¡‰­Z“€& K`¼þúëdpeb?üx›ßµ.[ñf njj"OÆOB&På…¶ Më‚Ödu– `+~M–¶9? KØÞ¦Ã©ÒêI¸Jr¶ä°|§bîè(¾pO:•§ÖLhÐ5¼ÊT ì*Ms8ë%0í¶&a  —‘¶® ³ÀÌŒXš%‡dÒ¤IhèÕ«WÝÞ'ã e$aì8³Ìtôü17RüØ?eá.‹m-{Š=¶],ù(e­eÏãªíQyI&$܉A–T89WUU½óÎ;‡¢iOô©S§ZZZ81ê–äpÙ¶m›ýݤ³Î¬ñëá²å¢äèÑ£3fÌxë­·ìT©z’È)²pcH=ö˜“ ,@ª¼O³ääÞÒ¼„y]³1½ä™ìªW½lÀÒx9ž+‘ï.<œw²ù/6à²äÓ3—9éX2ŒŒ\#ô'6üù.‹m-ž Ë °.–Ö´ 6ë…+V¤¬2$›6mRyI QÕGÆ|Ю"îq–ëô';Lªli/woi^Ý`>gÌk#} –§!ôGÄÙðî»ï.[¶ìôéÓ·oßv!) þíHé˜pv„]ã)G»¢¢‚aá ÿ¬YlS1ŒgÇ’VÖF@— 7S±Jx~ ÉF]#;ì[T^’‚¹i¾Á\T@Ü#,8¼.‰£÷ÿoï]¿£ªò}ýþGÎ+áo8CåÅ}F³Ï¶#ûgëa B¶’ ‘á­ºÁÆB· rØ4 Ú±•€€´¢6[î`D.AmBB¸ÊM”ý{²>3³WªR•º×ªUßçÅßyY—9×Zs=µ2SÕÝ=tèÐÀ±ÿ 9öz;gôB-Íô’¸rÙ¦‘”Š2 wKK gÚ¹Ojp,t ÙÒ’œL„c#“] *:ð‰Ù”’”dŸ¹.¹(¹L]BðùÁÈߎ”Œ¼™ÎD‹½L'@¾Î—c­ÆŸ5Å:Sòu,É71‚Š=z Ú5“·œ ú$›^†”ÁE¥‚v¹Vt¯‹Œ8’ü’Û^oçOÎÓK*›FRJÊ,Ü‹/^¹r¥Ÿ´ _˜–)ëB½#ú@uäÙT“O‡k’©|±eŽÿ¿É°œ¯Y³fäÈ‘4ÇeUYM# £~¦éL^’щ—î]1p¦?S uÙ‹’á¢àöä³T5åç†M/)=(‚‹Œ"`Ýo^rÛëíBá§—\;­­­6¤””Y¸gÏžý׿þÕ)OAÑ+ðôpGKd·âƒ>ÈÕyùòeŽÿìÙ³ÍÍÍ~ÔÓ¿°TÙN#‰76½¤Äp˸È(Ö½±'ü’Û^o?½¤««ËÉif|öÙg. 1/À% ÊæÍ›§œì,5ÆŒã¢Os‰¾8p r‰ìÙ°aª­ï tYÐÖÖfÓHÊB™…{ôèÑÇw²S!Œ1bþüùO=õTbW,þÈVu²råÊ'žxÂ]£FÑà:t‘Q¬{«½ä¶×ÛE"Ûé%K—.õ’O{áFŽ 6oÞTéj¸²Þ‹ËžUÓo‡Ll*aÝ0™ ·M#)#eîqãÆUÜ|†ûî»ïË/¿|óÍ7{¼5ÄСC]«*Æ‘ d«Ú`DÓxdŸû‹ w‹Œ"`Ý[ tww×ÔÔØëíâ‘Õô’Aƒ±D—G I94È­½CCcc#u(%¦tذaÄÚŽ2µ EcÆŒ ¯™¿á¶i$e§ÌÂ=uêÔO?ýÔ™NÉÑ·adÅ•+W~õ«_q±ž={vß¾}|`dÛQY£ãÈÌ™3¹½+tVIþÿ(™€æ“øñì1VT¸e\dëÞÒ“ðDˆ1´Ôµ¹:Ðô’C‡]K ¢ì¢k×p<˜enO›vâÄ ’X¸+PÅáR¿mÛÆà Xúú¢!À%RcÓH¢@ùÿiò½÷ÞsßO“1[¶lárg É“cÇŽ¹¨—/¾øÂE‘¡Ê…4½ä…^8wîœ7"\¸pÁ¦‘D“2 7 Á»wïv>;þ‹u„Œ™œÎÎN-½F£nH»@¸©OM’>ð53äÒ¥K÷Ýwm¹ˆ¹¬]b‡Ÿ^Ò•ålù6àOŠÀ¡—_,ê¿ÀÈw>IÎ¥œ&å„Qåð–=¬å¢,Iøv$ I1>¡‘ÅŒ°¨X÷–ž¬„±>|¸K„2dH‚a<ØE½,\¸pìØ±.QL¸…¦—¾„§—8W-þÏ e!ü#[Â^”3¢bÝ[z²nŒùرc,•ļ‹‚^K¸1r’Hy‚pëÕ8õ© _g]Å*•Öƒ¶ÉSLÉ„8[L¸Ã”}z‰M#©Ê/Ü0zôè¶¶6gµ†éèÑ£\ͱœÀÝ/9O/I­—Ö%Ʀ‘D3¢bÝ[zèóŸ2cûöícÇŽ%¸÷Þ{¿ýö[,©$ܾ19zåÊ•ZÅ×d² ›õElV•ÛJØlV˜p'³mÛ¶Ç{ìÀWK ÀlIE á^¾|ùâÅ‹ÕF•Ý»w븳îЫ?½dÀÙŠ,6$šðÌ6ŠGMMëh£TÐíNH~õÕW1c‚3fHˆAÆL&('ÁŒ©€Ik‚pMW&Ÿ¤^ckû˜:|=sÔ ‹{zh©ÆR×r#ÀO/q.\|>øà›FR)DB¸¹hFýÝwß9?Š$ÜEü1×´ÿÉêÁO/ÙöG¶¢IxZ›°g¶‹ #d.Üx°D°Þ£GJˆ™FǧL™¢œ°CcØTЊT¸»â¾•à ÃZì"9ÎîTøé%¨‚œ¸HtwwÏ™3Ǧ‘T‘nÀäæÍ›LFŠ"[·nmjjÒørùòewÐU†Ÿ^Ò™âG¶¢bmÓH¢Œ ·3¸¤ogÀŠ+}ôQ—¸}Û ÷“O>I>Áž={Μ93hÐ Lzøðá®êíÛT`u—¸}›"jJÁ)b;ÚI*x;WR«ká8ØX˜p§§ØÓKlI%áæCáÃ?üí·ßJp£ÆØ±cõŠôܹsÕ|Y3ÎVÊô›FMNœ8áÿFîƒîÞ½Û% £2ÉP¸Ñ#p‰Û·1f%ñlÜב/ó q‚+©š¾ˆC8Ibê'ÄÙbÂ= š^²nݺ+…æý÷ß·i$•HT„¶oßþ /Hp#ÅúõëgΜ©Á¥j_o{*bz‰M#‰,7êšššúúz‚††ÎÔ¿þë¿Sä*Fe’¡pÇîLðÓKΞ=ëd9?Ðk›FR¹DH¸gðÞ½{çFƒsçÎ5êhðå$Äè¦;ÖêFÓK¢ÿ#[’ÈwÇmD€1cÆð´N€{ßFÅ•ì„4îÐR °®åFj4½dÿþýΚs ÿÙÖÞ"UÑn>N˜0áÌ™3nšR˜2eJkk«®oó¶0Œ¹š^ÙÙ{A>úè£À±ÿÉ/ùKî5Wl 3N5@K5ƺ–iÉz‰M#‰Ñn8|øðO<ÑÝÝ-ß-/óæÍ[ºt©†•ÎÎN{½€Ÿ^µÙö ²üÛ¿ý[`ÚŽçŸÞF%ÃÅì„4îÐR ³®åÆ@ä<½Ä¦‘Ä†È 7|øá‡\”ÎyËGxê6—øíXÿ–{>”}z‰M#©8/^˜vÿò/ÿâr £Âáz––Œ—^zÉE©Q­ÊÉZªÁÖµÜÈ ?½ärfè•–M#‰Qnxíµ×Þxã g¾åàoû[CCC{{»®ò7n¸#3ú£ŒÓKlI…‚g¾ý¿o—e׳|4™'Ÿ|òÞ€xÀe¥9F¶\"5ƒ rQíË%zë Ý™Øy†ÐR·®åFÆøé%ΩScÓHbFD…^~ùåææf÷7•ÒÂU^__ï_—âßԄ§—èCK ÿÈ–°•ÂŒ3xf#.m•—ô­þÀt}ôQÅŒW / r@±üX±òAIÖò12­ Œ´eWRu6>Œ„ L¸óœ;wîoû[:ÐÉu_ºººfÏžmÓHbFt…V­ZÅ'õB}ŸN†,Z´ˆ«œ¡'LzΑ~zI‰d ì@eÁIüå/ùÑG¹´aT>©„NÐYü&OžLIT˜€–7n<|ø0– ä`Æ41ùT 2IÙ3EÁöþ žMM-•£:=º¬B>ø]³Ô±ÈÂÙ8;"Hƒ wþ¤š^bÓHâJ¤…ûÎ;<¹"‘*§ÃÅc{úé§_ýu]åpáÂûGÉlÑô’RþÈØ €Šƒgüã?~üøq—6ŒÊ'•p'h1¿dß  Â$Q^y?–p÷T \W¬ÌdᦎÞmû]„…;y×,—/_.•×1ø i0á.œŽ„é%6$ÆDZ¸vU[[»zõjçÅÅáoû{yï½÷4ˆ—¾;#KŠ:½Ä¦‘Ä€íÛ·×××kÉÇ3—kNáÖ[dá­h©0„‹’s€€¤YJ¦‘l½WŽÖ%À¤}e&ïÕf]Ì›$E,¥Ýd‚¶Œ w¡ 35½äÔ©S6$ÞT€pWÞœ9s~ó›ßlÙ²EŸ Èþýûüñ†††½{÷jk×®¹}¹â§—éG¶À^T<]š››yÌsBù`vóæM’Ó¦M㣔«a Ê%̘1c¦OŸ®øÐ¡C§OŸ¾çž{”Ô fJUa×®]*JζCe†>e"ÓA‰ƒRê° cÌdªŽ6˜¼krT“%«øá‡Ay:Ò ·ÝÎÙ²mÛ¶¡C‡ö;¤­­M`).2*Ênà£ÞÑ£G›šš{ì±Ï>ûÌÉr~?~œ•µµµ\ëºÊ¡³³'p{5òÃO/)øl½¨8ÚÛÛëëëÿò—¿ Úa¸'L˜`ÓKŒJ'•p.+¯’Èn8)&@”•ƒõRAö¬@ֵ˷ß~›œá¦(¬Ë* 7A®½C0þü„ ¦"•p·¶¶Ú¯Ææ]zýúõŽŽŽð[$ {ðàÁþÏ€Ä ŒJ¤b„øÀ‡%üñÇÜÏÿïÿý¿… fþe–ax®¯ZµêñÇðÁ7nܨQC\ºtÉ&'tJÓK õ#[¦‘Tš@òõ×_K²8}ú´\ÜÕ6Œ $pÇŒdáFµ~øaò›››]–‘ t‹B ÜuuuC† QÒ w[[Û¬Y³0%Š ’„[ܾ}ûÂ… \…¯¿þzmmío~ó›Ù³gïØ±#½|#ÙŸ}ö«<úè£xöœ9sÂoµmÚëÒâ‘óô›F¦‘¤‚§x¼§—Œ7ŽgjUA“]㫚,=´T2­öª-öìÙ£Þ0²‚®sQT±Æ¹Y’”p·´´ à555QT4*€ÊnÁ#¼»»›»ýÀo½õVCCò­»¥~üñÇ'NœÈ”‰d×××/\¸0ü–T°›CRr˜^bÓHb@ªi$©ˆñô"U ÕÖdÚë„4îÐRäµk׆U[pË»î0²®sQ ÷Õ«W1l–î#F¯ 6ɤ‚¨Tá8Ü?ü€„uttHÈ¥Þ¼yóC=Ä2á5¶‡úzQÊܶŒâƒNùé%îO©±i$1@ÓHÚÚÚ8q™sêÔ©XN/áªÕMæÎíêêr]wh¯Ò¸CK|ðA–Ѥÿ´Âa»(„„›€eSS“ôZ¯·ƒòžX}*[¸=<¤±ç .tww#ÓK—.åÚe)Q“޳¤”:Ô¤¾[Ó(9š^’ùlM#©84dúôéœÐÀ¢³ãƯ¼òJ̦—0(9­h²na×q‡ö:!;´ôÀ/¾ø"AgÏžuÝQ>8 Uý³nÀ­%ܘ·2)1bDPhT1î0<éGŽɵ˅ÈÓš$ÏoWfDƒðôI¶'áG¶À¦‘T~‰ì9gb6½„AÉyhÕ@“u».ˆ;´—ÏŠý|Sß®S§N¹tò]¢+À%Š@ž;õg½ž={6IϾ}û\w”ÃE•C¿ÇÜÖÖ¶hÑ"Å<4½^×ÕÕCøKˆCáÞ°aCp×÷@ìrˆÁÃ8yz‰M#‰¹M#IEœ¦—0"IC«š¬ÙuAÜ¡½NHCp ßsÏ=Ó§O'X¶l™+èe̘1. Áà \¢ä¹Ó„3ÖîåË—+³Œp.ª*ñ˜¬ˆ›pû×Û‚˜WfD?½$áG¶À¦‘TÜkšFÂiý©p\¿~=ÓK‘ÜLjª&ëvv]wh¯Ò¨í¼yówuu 4ˆ¯eÐãf!ö N@ή]»¨v0@™ªÉRÕ¥dúuUgË–-JŠ„:™ï”šlÊv2ýžYi÷èÑ£]º|px.ª*ñ˜¬ˆ›p3LpÕ†!Ç•‘DÓKÂ?²6¤âhooŸ8qâ»ï¾ë4¹ÐlݺµÒ§—09̓… ^M‹'&Ç%>úè£p…òB“uG».ˆ;´× i¶çž{îÁnY6 Óõ NÜØØÈ‹"i1O)Ê®ü`2Ù«P_›¥š+¤Y™ªCN†;eJ nêK$Í™E»ËþÙ˜ÃsQåP‰ÇldE¬„;áõ¶°—ÜÑ'ü§g°i$ÇöíÛ±í¶¶6gÇÅáäÉ“ì¥r§—p‘KC3aÊ”)C† q‰d~ñÅ.ñóÏÄáj¨v89xð`>ǺD9ð÷µë‚¸C{¯'¼º(µýì³ÏXnÞ¼Y9ª€Ú’O@Ëi¾´¢bqàÀ¥K—’Ï­Þ ðm$Ãêðz*%¼'âg–ÃsQåP‰ÇldE¬„›é\²ÉïjQ…ÓÄ ÞÑ÷WmèS¤i$©à"©Üé%\äÎC3o>|øG}äÒ?ÿ|ìØ±ï¾û.,Ü Â=3@1ª=vìX6¢¤ðë‚6è}‹ œL(Êše-+8Ç»Do’e‚ sU£¿ä766* ¾«•©@eòI²Í1cÆ©R×WpNššp—…J/28@RîëK!¼Šwb½áV&„cZ[ rV;õî’Q‰ÇldE|„»»»;üÒ+áÚ­ô·Š=6ÖTšFòÕW_Ý.•8½„‹Üyè@àÁt/äXÞ”ôä ÜTÐç–¾(Œ_Ÿ¿ „7¾HªM}¯×rqÅ9@“£¬e‡ö:!í ‹Ú‚7o9.¯)2Œšƒ/U¿ VaÉíl¾ç·+ HùZ‘d&;¥Épµd"~f+ñR‰ÇldEÜþiÒc×neaç«‚ðÓH.^¼èü·\»vmîܹ¸B¥|œæ"w:ƒž@°råJ Û[/’,I†‹Â ÍzKí_iûU a-b ¾V!‡%9a§'ùV‚`½¡ÉQÖ²‚C{¹,scРAçÎ#àæe›œwñ3[‰”JP¢ã*G›ÀâÅ‹]±#L¸H0àù1bÄŽ;V­ZUWW§L£4hÉ;ï¼óc!ؽ{÷K/½¤xÁ‚+V¬Pœ?™^2+€™2dˆ2 ¹óЪ&GYË íý¡:ˆø™ð¯8Ú0öã!qńۈž/lç&`©Q¾­­ 1’…™á¤Q(4䨱cÎjóÆ ·æ3P¸áĉùO/‘gs9ñéN9‹-R ľ(s¸È‡V 49°2î,6lØÎ;]"^ p‰"ñ3;à%R<ÿüó°gƒýrHL1á6"A&ç Õö¯·[ZZHîÝ»—$1ã>’D’X•üÑ4’iÓ¦]¸pÁùl! wam[`yN/AµQjÿz›€ O—œ’Ĺ ·;Ī&GYË í•æÃÝwßmÂ'™å+G«$Ô'Ð*J„ˆŸÙL(‘Ïæ˜ùvYFì0á6"A†ç R€ô455Í g3ô×ÕÕ餑'šFrôèÑ[EàóÏ?dz ðl–“'O&'()0ß|óMÎÓKäÖ,¹êt¥ùY%ÄTÈÖ6¸È‡¦àÈ‘#|q‰ñ裲Y—Þ‘êË*49°2î,@¸eÌ«–+òÉ' ÈÔRI–Ä|¶dE„;¹þ]wÝ…p“$.?³>P¢CKK Ç|xÁ‚<ð†Ê/\¹M/ñ­X«K/´äóž¯!\äÎCûƒ~ CôÊ¿_EN€:O>ù¤K¤†­%KüŠ+ ä÷¢:@ œBA“+3áμYrÜ3A$oV€:“[#ÐH95I*Têû $âg6ÃJt`°9rdžÿðmDn#dx¾Â/°õ>vìØÁ¸¯wÅFöhÉÆe«±aË–-ÙN/áêòß ¨ÙÛ ÿP 8+¸ÈÝ%±|ùòä[·nÅ¿Y*Éy!Ög`üX öc8‰¾š¯Ffï÷¨:@ 6Hý Â_ìû£JOĵ¬àÐ^'¤y,ܸ59À5 ª°dÉ’T®®P@"~f3| D‡³gÏN:•óåÒF1á6"¯²SÔi$e'Ÿé%…‚‹ÜMp‚ÂNž<!F‚)B  „cÒ䨂rˆ ¨,EFšQdé8EÉ­:^¯U|>{áx¨Ìޤïì—˜€%ÛïYs "®e‡ö^Éù4Á _ýµràÏþó—_~I?›4iÕî¿ÿþ¹sç~ðÁÉõ©€p÷l÷ÊЍ£8O"~f+ë²gÏžqãÆmÛ¶­¾¾¾šÿïßOdþaM¸H`竌 FÅžF®æ:½¤Pp‘»CIBÊë8´‚Ç«T6 *JÎÌX ø±ê°ä̲Õ‘@ãè²|Õí®gýÞ­‘#Å'_EZj•ô× M޲–Úë„4¸JñiH¾•\²d‰b‚žzÕï·>AP«‡pœ?³…} „+Û‰dÂgשS§Ò¥wîܹyó¦†ârQå…³F'Ä5šp‘ÀÎW¹hooŸ0aÂÆë«Í›7çÿã8¹ÁEî"‰1cÆÌŸ?ß%ph§OŸ¾çž{víÚÅR9*JÎéŠÙ¦ê°üðÃ}9€Ck©êøÊ,ƒ ÜDü*Úõß~ûm­lo:ùAÝþ¡ÉQÖ²‚C{壱'âg¶€ýÛ´ñìÿ(°jT›»ÌyY/Û¶mcŒbdvõªΚë‚x¡›¥««Ë„Ûˆv¾ÊÂöíÛÙ9âü¨:À¶iué§—p‘»#HmEjqkŇ’ã’DÄñÚ°§nV‘ Ÿ?^¥,©ö -»Dã7H&« ì:6Kä€: Ÿ Ò 'Mdµ¬àÐ^'¤q'âg¶€„»®®Îÿ;¾nýòÚªœ¾!…Æ·{÷n'e}a( tÓ¦M®vuÀYsíþf1á6"¯s«w‰Ôªìð€Áçdœ™€8b.‘=Ãþð‡büévöìÙ­­­.Ñ.r·ûþЛcP»h`BÒ·—L(ö9€+Ÿ ’d-ÖU`Ìa]žPnÄçÖäK¸[ZZôEFMMM9üÿ4«×××ÿý÷?§æÆ¿ÿýï÷»ß1V»ÕâgÍ)j¼ð7‹ · ì|•’rM#Áçúu5½7•)føöÔ¿ŽT;…bL/Á¶¹˜~øádí&ßí¸jðO×q‡ö:!;?³ž‹òFÂÍ's}=¨„{Dð;ǪÕ$½éxå•WðigÖiÙ´iÓØ±c«dz gÍ5;^ø›Å„Ûˆv¾JÆ€ÓHÂ/Aõ–ÈôIJ•T:žË{èÐ!’É4É|½S÷{¡4¬Î”úU”ãk vDuüZá ä³’:ž„&Sðé%ÝÝÝ\Ì"A»Éq{­h²ž4® âíuBw"~f9<å„›€eSS“ô:á{ú ÈÙ³gëëëmœˆeÆ©S§XkÛ¶mn+ñ…³æÚ/üÍbÂmD;_% “i$c‚ÿÞÃV©~‹ì'ûR©} ø®:å+‡",Y+Nž<™|­¢É l“Ê~ƒß ™=ûèůâuY{¤HÛ×T9\$*°}ð;íÙt|z s¯ÝÄn—UMÖ“F={h¯Ò¸ñ3Ëá¹(o¼pn-áÖïP:"³Ÿ7Þ³gO]ðíþ?eÏ¥K—çÎïé%œ5§¨ñÂß,&ÜF$°óU&MšôÚk¯9Jnêõ·_á&“À)x²« àWñ²ëWïE+*~•CÁø± (ðÛWNr-©à7ësÒ³råÊ_ÿú×\‡EífévV5Ðd=iÜ%wjjj‚³î»ï¾(ŸYŽÐEyƒ"û_5Öo`)Æž‰!ü¥©X¾|ùSO=…7;ƒÎ‰wß}wB¬¿½„³æš/h—nn#Øù*ŒÔõõõNÝæÙ€¤¾ýöÛòWef(Üa»U…„û½èå´ÇWcÉöµeM )NUA™áœ4lÞ¼yüøñŸþùÅ‹þùg×_¹ÂÅœÀìٳϞ=KàöW5Ðd=i\×TjrÉð\\›#}â¢r£ïþ[¶l™“¯ü@î'NœøÉ'Ÿ¸­Ç Κkg¼ðw¨ · ì|•†[·nÍœ93ͬ’ÓÁÿâÁتŸ]­‰$5Q„R½¢&c&@š©F¦4Ç•F‡}×Çá½°½ÒOJ! Ä:T­â·^S”\Á¯K5Õ o-Í'yæ™g¾ùæ‰ÝÝÝ®³r"<‡¤Ú*"y#-äP]"8¬â™Ño}2Ù”Kô2/À%r…&«WÕUBGG‡Z]|'—ZêÚ1è••ãÇ×ÕÕñIÞ™W!¸téÒsÏ=÷ꫯÆoz gÍ5254ÿèÑ£.bøðá.  Îرc]¢2óü#Cnø;Ô„Ûˆv¾JÆíÛ·[ZZô“N‹B466 ™)ÉRB†¼ú Aõ¸2Eª£%A[KᆠÈ_¶lYÂ^X* ÄÉ«€”Ä•“PÁ¯ë}Ñï”8¯¿þzüøño½õ–FCÀÝüñG×S9¡o)°j 2ÝŽûƒ#ç8ù@'ûæ§GŸ%\"5lÍŸ‚S§N)ö°6å½pa˜8qâ»ï¾ël«˜\¼xñ¹çž{ã7ܾ ŠÿÞCÇѳæ–4÷É'Ÿyø"LW±*PÔÙÙIÌ*¸o¿”T çàÍ@2á ·V'“œžÚ!´¢TÛÖvRáŸ4® Œ"`ƒg2%ë“«W¯bœúî?>‚:ÃÊïpò¼PÌd›Çö$|¡ûË–-sGVPíU½¯·¹‹‡ Bcq&%÷îÝÛÒÒ¢ÊùÃYS£ú…æ?ù䓊åÓ4\L c¦½G@å°pSíwÞQ¬í° M’>§ë¼©÷ôfo‘J€6¨¶ ú™à‡An£<?~|çÎ.Ñ÷|QÄP—0JÅíÞé%‡vº”ýúVÍ¥õ°œa³ÃÒ¿XM ­­­\ÓHÂp‘»êZ¤¦Éž ”¾ÕêUžë>‰š'W èY-xq® *õ9è2IbêÏ›7¿SÅ  õ*Eǩϲg‹Ã†iû©ðO×F°‡]2%ëŒ÷BIù*»Ê<kÄ 19„ÏË¥Ç+cž•à?þÈà0iÒ¤BM/A¯¬ûϦ™´”)ÿVÍ‚ÀYsÍèú$ÜRQ¦—XzE& XµÏr\Ôûºš@몈>W¬:X»’Ô÷1E¬Þø€øaЄÛ(·nÝ9rdMMÍÔ©S—/_ÎùbÉýðÃ:´àÓÑŒLO/qÆ4Œï. ÆÉü’᱄¥¹DöèÅjgg§‰; ­­­eœF†‹üZ•áŸ4® Œ"`»dJÖ'ÍÍÍÿóþÏ3gΠËR1mžÉ“'“ÉRIJõ;_7n$I |’àóCKrü*lù#“íÃã’ö¬¬å7þÊ+¯`Æûöís‡˜ú){˜5kÖˆ#Xª`V ÷5;Ò´“‚ÀYsŠ/ü0hÂm” 6pš’Y¼x±«a”ƒ¬¦—èm¨^‘bÒšˆì…[ïbÃòÝ|c†rX…úT@£ÉWÿzUEáuÃh Dz¢0$ ×¶óЪ&«ç]E€Nv‘ÑK úÇŶ¸*åÇÝÝÝbA!&@”,X@@ò59>|ø0ù dØê|þùçXµ­E ±V’jT‚ðÆ'MšTé%^¸wìØ¡¹%¾£‡ ⢼á¬M~4á6Êɸqã8SaFŽÉêŠ2á§—:tÈ©S åYnÞ¼ùĉxðþýû{t{Ú4’dªH àd~úé§Ä¬Ë‹TS™,ÉohhPÀ¦‚Çúõë)ª­­uéDdI.owpUMVç».0Šì"£—b÷‰¾ûoãÆrbžYx0„…ÐhJõ6š¤Wj©3ÞÌ*J²ô¥Buzl:X×ç° ûíW¸ƒZ®Á›o¾ÙÔÔtõêUwÐ9~­—Ü@ÀMícWœ7œ55!føaЄÛ(';wîäL…Ù°aƒ+3ÊŠŸ^ÂqöÔòcÀ¹1c’ØsàÛ=–¬WÔª ’Ý’3Ibլ˒¨H‰µ»D 6mÚ‘i$a¸¼ÝñU 4YýïºÀ(t²‹Œ^ŠÚ'{‚ïþ;zô(.%'–WmݺÙÕKk@‹‘c*Lž<9• Ý*%Öq¡Ê=6ÝW¸Ù›Eâ5“ÄWHÞ8|öÙg<ò#¹;ôhÃYÓaÇ ? špefêÔ©œ,1nÜ8—kD?½¤³³Ó9T_äÇh±ÞUëíun÷z¶^i+†Ì…›Éå{ØÑþýû]" Ä:RÓHÂp…s$UMÖYp]`:ÙEF/Åëü¸©©‰QåfÀ®]»¦OŸN@>™cÆŒ!GEóçÏGŽOŸ>«ƒ›ŠßTúdR‡øí·ß&ÿÃ?¤ˆ|Ö%“µ.h-¶F™l?\!yãâìÙ³&LX½zµk@¹ioowQœ5wÐñƒ&ÜF™9~ü8'K„¿·Äˆ駗ȇ †oÞ¼™$Š,á>wšðPeÐ<i´Ö~Ee²µÚÚÚÝþôS6¢:¹OÈñDpI®pç¡…†þwQöði \¢ÐÐd×F “]dôRŒ>Ñwÿ½ùæ›N£aPdôñE»•/”‰þªŽÌXùRvŠ• TëÑçÐvÈѺ µnÔœI‚¯¼ñ0¯½öÚ³Ï>›çô’‚ÐØØ8zôè~¿2œ³æ·šF»h‘>“ ž2. ¡ÎT¬6,ß^rÃ&ÜFù™={6狱̥ˆ‘fz ŠÌ«&hnn^¿~½<[NÜãÝÓ¦%ø±Ÿ–­¥`E’,ýt‚ž•§M O‡To¸£9$ ¹óЂÂ'$€í¦g”™9¹­•!þIãºÀ(ö°K¦à}rüøñºº:>ÿ;‡*“'ONpôA%ÜcÆŒ!p¹ðÑGÑ„²O/immåìæM¯ºÜ2ݱÐ3|A‚ h¬ËM ~|èÐ!—HM¿Â;@±ÿ ÄÒ„{`h¡‹ŒÈÓÝÝ=tèЄ{ψš^ò / ÔΧ¢Á… ";$ ƒ’¸°ÔÖÖbÌ<Æîºë.ä›`ݺu(8&M@ÝB5bP@kST¼×ÛàŸ4® Œ"`»d Û'ú_{{»¨Â‘­mÃéÓ§ç/Î31Ëh¤I“Ö¯_ïV®^½ÊÙñÌž=PIw hq«z>` Ô WÑ|\QŽÞî“É*dOßR¤Ï$dúj,ÜTVõj²p‡wÍ) rÏjÁ¤ >'Ú¥aЄÛ(?úS]þÚe¤ÇO/9xð SªróÕW_EyI%.ò"ÑÑÑq÷Ýw/Y²„‡&þä“O”I@…`æÈ‹ûöí»ÿþûI’© ¨ø'ë£ØÃ.™BõÉ­à»ÿþð‡?\¹rÅÙS…CC,XPÞé%C‡åyHâ».ÜQ&M¶T˜†w|×Û°4ëe ‘£·&f#ÄX2™T£²œ;Y¸©Ãö¥Ý$„;y×Ú‚ŸLŸß/´Kà ·Qf¸Í[[[Y–q02ÄO/Y¿~½sÞòýi$a”¸Â‹G‚[÷› x¶‚»îºKuЇÒ¸.0Š€=ì’©©©¡[ò‡í¼öÚkΛbÄÚµkýë_»FFƒ‘#G²tÇןpãÊÒeÀ°Ue¸(9¼^'è²êèe¹ò¥ì~ïÚ j’íš%+bç0þ|L]SçU“@•íÒ0hÂm”É~"ËÇüòåË*2¢LÙ§—TÊ4’0 JÒÐ"‘¡p744ÜqªS<ü“ÆuQìaW<ÚÛÛëëë7nÜèÔ)üõ¯Õ{ FѲ¼žxøá‡¹hàGŽ!p‡ðZ.«øàeÃá¢äðÛÑ‹jŸCMàÁ.“Ó3_ä0iòS ·v-Û&Fâƒõþ9TÓC»4 špeƒç1·Ù×_}§âÿøÿ0ç®Ê8½¤‚¦‘„aP’†‰ûï¿ßO)e¢×°iÓ&½ØF²¥à°nÝ:Õ)þIãºÀ(ö°+*·nÝÒW£2ÈÜȆaÆI¿\V~à‚. ²}ذaƒËJ M˜5kmñï)üüéRÂëA¾ý·“‘t€èuò–-[xÐHi)”$ÐË–-ëêêò9Êœ7o5Ù¥ä$ô$Ûa㊩ †w‘¼k`#lYu|f¿Ð.õ¶ ·Qx'ض0ç® 8_~z‰«|ðÁ4$ ƒÒ•bòå—_¾ð ôp¹W® ”*“¥rÂuŠ„Ò¸.0Š€=승Àpç*0 ÒÛXæô+ܧNb‰bö[fß¾}Œœk×®Õ- eyOÑÞÞÎ 555ø«Ë Ók/è¯ÔYÍļÃI4š†+0cJ•r5É—m±‘ÔfYú˜€­Q ´ki´”Ù/´KnÂm”´©_󾆥…Ÿ^ÒÑÑ!'.ÝÝÝsæÌ©¬i$a”œ‡V þIãºÀ(ö°+<˜ôráí·ßv•ÖÕóª¹÷es²póÔ£TzçÕ-°µžúÈ¢Œ“óÕ€R’¬›^©ÓkýÊ•+ëëë÷îÝ«û·ËòžbñâÅC‡eÉî²záJv‡/ü0hÂm”n³4¶-̹+ ½zì±Ç8¸qá9vìX%N# àä<´jðO×F°‡]Éð¿¼ÛÕÕu= ̘åÉ“'1c ø³’HóÒ¥K xüM›6 «f©jcÆŒ!`¹yófò©@RQ©ÐÙÙIR›M†ý²Š6’Ì÷ß?eÊ”æææöövÝŒŒœ×®]sM*9<)Ξ=ë}áJvŠ/ü0hÂm”Ìi@󾆥§¬xÓK>¨Øi$a”œ‡V þIãºÀ(ö°+%~zÉáÇ҆ÐÏuõ+Ü^—1rr´$‰ˆ+ðK9KŠ gµÐ ‚T>™;wÖÖÖ¶¶¶ê6„îînšà1¸’ÝqÇ ? šp¥sÊж…9wÅá§—œ={Ö9W~œ?¾¢§‘„aPâb®*ü“ÆuQìaWbx6ùé%N©på 6`Øé…[/­ TÞ¼ycÆŒÁ˜ÑkekE’™7[`›.âOúSCCÃÑ£Gu#*ïš=¸’Ý¡Ç ? šp%Ûææokkû9¨oÎ]Yøé%û÷ï—4ç ŠJŸF†AIZ=ø'ë£ØÃ®,$O/AˆOž<‰.÷+Üø4fLRzMNcc#E¸òæÍ›YE™,© É—£Ý©„›íPÓ%N:5a„×_]wp7oÞt‡U¸’]â…M¸R›m sîŠÃ¿Z·nsçìyÿý÷c0$ ƒ’4´zðO×F°‡]¹ðÓK:tíÚ5¬-Ƙdssó¹’ÊQ%Oœ8AR±€ $ $ׯ_OÌÒ¯˜›Ý¿¿K\»¶iÓ¦ÚÚÚ?þX·twwWÄÈÉ•ìÚ‚„ž CçƒK„ ²‹ò€K,éd:V甤Ž$(? špE'󾆥HÎÓKâ4$ ƒ’4´zðO×F°‡]ñ/6lØàôª|\¼x‘!7¥dö¢°wöËRfÏñô»Çdü0hÂm—üm[˜sW"9L/‰Ù4’0…ú¹é â¾ûîÓIt]`úÙEF™ðÓK:;;d•œC‡á‚á¯Ùîêêºuë–;ÄJ€+Ù5& ž È®K/õñ œ›¥X@K©¹^?(i&VÒÃfÉ¡¾þ Á•Ô;lAÕÈ!_°5jføzh—Έ ·QD eÛœ» O/ ^z¦#~ÓH’q +!~¸/#®ñF°‡]H˜^RbÖ¬YÃÈþší ý'מ$‚éÿÜO?ýÿf9hÐ ô!V”ƒX«þ]wÝåK «ˆÖÖVЍFÑ›o¾‰s“ãÊ „ ·Q\¼mÿTh̹+”ðôI¶GO©XN#‰6Æ;¿‘Âÿï *ì„«hìÝ»wÔ¨Qá¯Ùfäd¤u‡Ri¤nÚˆ »D ÐF¿ÂÝ3ç#˜R¢üôÂÍFPse²$‡-°.™ªPL¸"R<ÛæÜJ¿ÓKªaIy±Á0ÞØù~zÉÁƒsÅ‹3r†¿f›á”1ÖD’F¸'FšõÆŒ“…{ÿþýª¦˜üôš³5l^o¸y0±Yÿv<¤ø.‘n£XÛ¶…9wåâ§—œ:uªJ¦‘” ãßž^Â3±°œ9sæ±Ç[¸p¡†MèììŒþ×lW²ka ^yå©óñãÇIvtt£¢M½Œ=ú“Äš|*ûR‚ð*Àv¨@ªMK%]qfhi0á6Š×V l[˜sW.z4tèP›FRl0Œ7v~#‹Ÿ^‚ÌɽògëÖ­£F Í6#g<þ$8 p®,áFï¿ÿ~—[nL¸ÂÃ…U2󾆥Ë;wü06¤xØ`oìüFÿ¿+~åLww÷œ9sšššüŸáÊ•+nO•W²kjlÚ´éÅ_\²d‰KGÿ¤3á6 WU‰m[˜sW.ܤׯ_ïèè°i$EÅÃxcç7âdzɱcÇjkkÃìì쬬¯Ù®d×ÚxA»tÊL¸À%…mõÕW|š/=ìל»±›´4X?Ç;¿Ÿ^’í/ïºuë°íð×l_¸p!~äJv Ž´KgÍ„ÛÈ—òÚ¶0ç®Dì&- ÖÏñÆÎo¥À£Ê5ªs±ÀÎqtL=ü5Ûqý“ W²kv¼ ]:w&ÜF^DÁ¶…9wDØ»w¯‹þû¿ÛÚÚ\Ôv“–ëçxcç·‚5ªÓ±Ôüýﯭ­Ý¸q£t °mvn[±ƒ+Ùµ<^Ð.>n#w¢cÛœ; <¸©©Iñ!CÂþ€Ý¤¥Áú9ÞØù­8üå]X¶l^~àÀ¹YÑ_³= \Éj{Ì ]:ƒ&ÜFŽlÚ´©¾¾^¶½-@Ö; >úè™3gϘ1ÃÇÁœ»ì ÙÀà¢XÂMrQ@PÅa7ii°~Ž7v~+žV©~y÷ôéÓ?þxsss i=tuu]¿~Ý­_¸’]Ä Ú¥óhÂmäÂÕ«Wï¹çž7JsñfPœžwÞyáV|ôèÑ{ï½÷É'ŸT²P˜s——#F¬ZµŠ%±„›†€§ ùªv“–ëçxcç·B O/‘™ÁŽ;FµmÛ6)œ?þ§Ÿ~rëÄ®d× ñ‚véTšpY£™$»wïþ1à¥ìù`©ü+VT‘X óÆ¿qn%ê“IÌHDLIÖ oŠ€äÖ­[‰“÷rìØ1sîr!ÕfÉ“C½hÑ¢Y³fùR?ÉÄnÒÒ`ýoìüV4~zÉéÓ§›››y¶Æõk¶„+Y†3h—Φ ·‘²mŒÁE¬Y‚|÷Â… 2`òñcDY2ÝÞÞhp"*E©µA $Ü”"ô¬K)[“İ#Ÿd©öbÎ].$ÜØ6„ÛöÂ]WWgÂ]b¬ŸãßJçv0½døðáK—.•™Aü¾f{@jjj¸˜ãÇ}÷ݧsjÂmd·mŒñÅqby“‰þzÿ&™ðk!ÍiQÿIDATâ9 jh’ Á Aƒ‚’ØføÍ7±vÁ’mJ²eçà÷‚Isî² áÜú¿øz-ù&‡ëǦ””ëçxcç7ܹs‡G•´ º»»«ö—w]î•n#S¶ x-Zìc:‡ýÐâ°:{¨I>® RíôÂíåÞeõÎ*Qì÷’PÇœ»ôàÙ _ðl–ijfÍ"†––•‚ݤ¥Áú9ÞØù öË»@vZ\J/Ü´Ë„ÛȈÛ|׫mn÷ÎôhooǃIj† É~…;¬×È7ÆÌZlm².™¬…Á³–”Jå8räKVI¿0çŽ,v“–ëçxcç×0²¥,w ·10ɶ h®fn(ͱ–“ìÑð—^R†©éÁDÍÛV}’ÊT2¨Òó[IÜÚiÞ¶âä½x̹£‰Ý¤¥Áú9ÞØù5Œl1á.$6 l{Ò¤IG½UÉpüæÜQàĉŠÃ7éÁƒùœæFA±Á0ÞØù5Œl1á.$6„xض0çŽ7÷fMMM}}=ACCÃøñãÿõ_ÿ•˜"WÉ((6Æ;¿†‘-e¹kL¸ãI[[›‹þû¿ý·°eKœl[˜sG1cÆp{&€»b£Ðн.2âˆ_ÃÈ–²Ü5&Ü1Ãâö óË_þ’ëÍ…†v‘GìüF¶”å®1áŽ!w]]ÿÂc/Ümmm³fÍZµj•’i(ªmw¸D90ç.;ÿöoÿÆêyþùç]QèaqÄίadKYîî‚p#Ö8·~ÞOÂÝÒÒ¢Ÿýkjjòß”Ü/aÛ~4ø­u–‡–­¦§½½ÝE©Ñ—ЏDÀ‚àgÛ!!¿P$¼9wyY¼x1w¨ø—ù—k:ÙEF±ókÙR–»Æ„;†H¸ñf ›¥„{Ĉä«BšI&aÛ¾÷Þ{Qa‚­[·nܸ10Õt|þùç¬â©In’¬K€Ù'ŽJÛcÎ]^ðlnR£ÔÔÔ¸N7â§ØE†adFYîî"á&`ÙÔÔ$½Öëí ¼'V€lûÈ‘#7oÞüðÃxàÏ®]»ôNŸ>MÎ=÷Ü3yòd-I’?hÐ –ŠÉ$yèСåË—“¤Ú˜1c(š@à!ÉÆ ¨©:ZHRÊêÚÑüùóÉ!f Ôa 1‡§˜Õà¾6†–šs—‹3fp“rŽ\Ú0Œœ0á6Œl1á.$&ÜŠqk 7æ­LJGŒö!lÛ¬Å8k‚#²Ê¡ë•÷T rüê>“µX7yË$1i@¿¼Ê«ˆ€–Ú[кì:(ï©@ëʧß~ûmÕ!GÀ¯žŒ9w¹àzã&ýè£\Ú0Œœ0á6Œl1á.$Õ<µµµ-Z´HqKK‹×뺺:bi H°mHpVðŽ ˜1Ëë‚pA8f³Aïy¼Ÿ&‰.Sªš¬Â–UJ@¿#­K°k–@}–ú0@Làõ]CŽò{ÖìÅœ»,´··:ôøñã.mFNÔÔÔð¼3*›eWJÊ2Ñ΄ÛèǶ!¬¹pþüyŸD^ÑV‚ë‚pÛñ™¸òüùó½4{Hª2ŠO…ð*b@áæx>üðCåxü¬0©0ç.1Û·o¯¯¯×Ò¥aFÕbÒ{L¸«~m[è}0‚K€cÃ$ñWÙm‚õž>}š qØq‰YW+’$PIUÖìö«Uô6Z»fé·¯ djGAÏvƒ—å ³—pkÝd#cÎ]nݺÕÜÜüÒK/]¹råÎ;ô<ÉiÓ¦qº†aÕAGG‡‹’¤%\dÄîª&m‹CÁÌl–á¤æi€Wê„ áA¦¯|>@±'}5­ÞÛ”R‡süºÔ Ö賺b NØi2æÜŦ½½½¾¾þ/ù ªfÛ¶m&L°é%†aT<‚ÿýßÿý­·ÞB¯%-$ÇŒcï ⇠wõ2 mG°psîâ¡ $_ýµ³ì¾ðyI.îj†aT ¿&ÆïŠaÂ]¥T¢mCÏ»ñ^Tç‰9wÁI˜F’ :ߦ—†QU„ÌsâÄ WlÄˆØ ·ýãvzèŸ/¾øBŠi$@ÏàÜ?ÿü³»˜Œ_º|*@E@® $»ººnâaÆ)S¤ÚÂÁƒ]âÆ âpØ pJ†ëk;”*™ŒÙv¡ÈmI*8qrw·õJ†§©SÑê€öênrí7 #ú×I{½oL¸tΡ"¾Ø°„uË–-þ·fpY•/[¶ u&‡€LÕܰa+Ccc#9Á†{ì\I 7æ­|‘f ,•T,S×Áhƒ\ŸLj²Lpta¶]ü4’K—.ýT8®_¿é%&܆a¤âÿïÿm¯·ã ·ÑC*ç–pãИ+IäçF[É'– “#ëU>«¨>I2‘u–$üyóæù ú7Ü ¤ÙAXšµº?–ýÖgÉN•“€ÙvAhooŸ8qâ»ï¾ë4¹ÐlݺµÒ§—  î½}u`ÂmÂø9eÊ”#Gޏ´GL¸ G¿Î-á&@X‘cY,Ky0 ÚàëxáVŽªiIb•‚rR ·*ø-PMûŽ{V¬Õý®SÕ÷0Û.Û·oǶÛÚÚœ‡“'O²—Ê^bÂmF2š†·mÛ¶ÆÆÆ5kÖ¸\#v˜pÿ$Ù¹‘T‰ï˜`v‡^K^ýKe—Ú]NxÃÍF€ÕI¦yÃj ¯¥€­éØ’ßp ’:¶0fÛùS¤i$©¨èé%&܆a„ÑøéìæÍ›‹/njjâaäjTñø¥‚4¿?`Âmô!Á¹‘T‰ïÁƒ½ã6Œ|I­^!Kv©Iq,÷ê2¥x¶¯Ü³‰À€•$PN˜·ÀÉf©Õ5iÄgö[?A¸Í¶ó§ØÓHRQ¡ÓK‹]ªÚ«›Ëµß0Œ©~l÷îÝHÛž={\½ªÃE•LšV˜p‰È¹»ºº®ÇZg¶'šFòÕW_Ý.•8½Ä„Û0 ¡i$_ýµ³ì¾œ?~êÔ©o¼ñÆ­[·Ü U#†k%£qÇp­ aÂmôC¼Ûl;Oü4’‹/:ÿ-×®]›;wnM/1á6 ßþ(ØêÕ«y···»5ãNœ„»ßqÏ„Û蟸:·Ùvžøi$N{Ë͇~X)ÓKL¸ £ÊñÓHœSÄ¡C‡¨¿mÛ6·~¬1á6ª—ø9·Ùvž„§‘ìÙ³GÊ›9>úèÑ£G]"^ p‰$*ez ±;â ¸xñb¿}•ЇÄä¸DÀŒ3Μ9£8‡sT@L¸ #Œ¦‘dû£`—/_ž>}úï~÷»ØO/aÄpm®dL¸‰“s›mçCÂ4”nРAi$¸_î½÷Þ܉—èN/áq袾qþd%Üh4=ì!ú˜—ü{øðáŠs;GÄ„Û0„?sþ6§>ø`ìØ±ýCbÂmT;ÅvîÍ›7ãIpòäI—U̶óAÓHÞyç:M¼€ê)IÑ… ,X°uëV’,9¢¢+V(êSä«[&éë( Ê¡ˆä“O>Éî|_Ÿý’£"(Èô’Y\'C† QfAÈJ¸é+œ›–ºt𚟤îmÛ¶ñ!„ wø“‰âp©Vñ/ȵAÅdRD%USoÊY†‹2Ç„Û0€1JÓðœ;çŠþ”·~ýz·ÝØaÂm=ÎýÄOtvv^+ 'Nœ`yÏ=÷¸¬BÑ›m猦‘p HjÇòX“$–ü!Ó€,’Ï“F5EB5•H©©À’¤´RIIç Aƒ°êäúÚ Eè~Ï~ü‘k)ÿé%òl´{ÕªUÊ!X´h‘b öE™“¹pÓd~]MKñcÄ÷¿ø­>ÔT'å³¶*³®¦ K¸"ª©ˆ˜’H6¶­µÈïÙh6˜p†ÆÏBý(Øõë×.\øÔSOUâ #†kg—.]bs‰ \.  Îرc]¢2Kó3„ÛÈ—¢:·(’p›mçŒþ :mÚ4¯³ÉFs 03/¾»wï&À}A9,1c  Õ(BìÈ”Zu°jŸô™©ê³Aü[u±dËŠPŸ:Të·¾ß`¿|óÍ79O/‘[°dLæu÷¼öV)1úRÓ¡pcØ2]ðfL‡ ¹´š$™òcò©¬ ¨¾b#V¡2Ii7k©Â‘#GØ”Š€Lå³dEeB¿{I ·Qhü,Á‚!ÇìˆÑØí8°mý¥îY–á¹s$÷$åE‚Ã5¬/+úN±Ó<·wÞy‡Ç9ÄÊa ÁJêlÛ¶ W’~]Lš ²YU P‘*û¤ŸM§µ8’`«é0á6 F1œ{Ú´iŸ~ú©K³íÜÀS5Ä+u˜´·^ظq#ºFù$ñ6P#ÔòåË‹äj¬‹ÕOR HrúTÊvú­ï7˜Š«W¯æ6½Ä ·b­®1T˦¦&_!C2n¥ù$‚Æâ¾ ô¾á*U’n¡¾jz¨Îä9ÁZZ…g ±ß ¶F}%Qsê+&@ñk YaÂmTŒ9áos*|ä‘GvîÜéŽ Pmÿz›Û–q½Æ¹ë”dÄkiiQåbJ¸ý?¢ðLa‰£ËAÉm ·þ…€¥êx””=„×­.(bd @¾÷o•{ÛVT§Ø„Û($wnýߤK³íÜÀ®&NœˆCËVó„ÊEåfË–-ÙN/á©ã¿P³·A"г‚ØPu`ÂmT?ù˜ªœ%ƒäÏ>ûì+¯¼ÂMç%'ÐëÁƒë†Å³â0lP¦ü[5‹D*áFQj 1'7Ï ˜€¥ÄZ Ëáu±öðº ÕùTS¹5΂“é+°q2UÇ»x&ÜF‘sŸ;wî‡BP[[»nÝ:—ÈŽÊl;ÒO#ɖÇOž<Ù%"@>ÓK … ·aÄŸ<%ÁùþWæ úcÇŽEúÝån­`Ö¬Y#FŒè™H×ûeMÜÈ(8™ªP 1\cB,Hšb·5ø’3ô'8*S¡§jÕüçmGóIÒQ|P¡²¦Ø‘ï‹Tª´Aå°ÕOƒ ·Qx ëÜ…Âl;p£ôÓHâAÎÓK … ·aÄ.õ~¿Í)Œ0˜œõOL…·Àl9qâNœÏk/Ü;vìðÄ ßÂC úÓ ô+ÜHpò;Ä—€¥Wä k§Ø‘ã¢Þþ&к*¢Ÿ¯þ ߟ#êû˜"Vo<&ÜFQˆšs›mçÃÊ„ 6nÜx³:ؼysþ?Ž“&܆3?3™FâÕú¸4ä,ÜÀspîܹÏ=÷\n¯Â/°õ’¸‹}슋@¿Â]q˜pÅ":Îm¶Û·oÇ>9âl´:À¶iué§—0»#¨L¸x“ù4¼AÁ×.yüÛSÜš˜œÉ“'“C’€¤*¨þòåË•Lø7ôTìØ±ã‘Ga`wZ!˜pÆDÁ¹Í¶³…AY=þ¼ó£âÃÃEÙ3?À%òæÊ•+øÃŠ1½äìÙ³ô­Kô%•pï p‰1f̘C‡¹DIí\V‘1á6âŠ?3™†Çƒ ‡v‰¾¼ ÙÃ.+øwóÁ—2¡Ý üêôéèèàÃÀêÕ«ÝWŒîè+n£¸”׹Ͷ³…!»,ÓH ä¢$ÄÓ§O»DLp‰QŒé% ¸?üðòå˹]V/ý ÷=÷ÜCÛy²¸¬´ð©ãí·ßv‰Ô°µ±&G}.«È˜p±„ñ—ÍüÛœúnLúà—­äÜà «fåS-xÁÝS?ý¡&ðÚk¯Mš4)y,Š&&܆‘rn>U_--ìÑl;+òœFr(¡—uóæ‡~ˆÆyc¦I2•$_I/ܬ~]}þüytL½n×êáí9Ê ¯˜°ß(Æôž‘Œ¹C‡={6Ïf—ÛŸp£Úɯíic¸Qè5ÍôÕPs ‹T$ˆ:-Y¸yZ»(À×TÀ.:SI–Jú“¨dBå~1á6âGnã'CŸ¿Y帹‹‰¹‰€$K•‚¿yUÊ­MŽŠrà‹/¾xä‘GöìÙãaL¸ #SJïÜfÛYÁXÿ4’cd‘˜) O”އ þG@’ ÄäPŸ€¤„[–‰±ùà ¦ˆPSÏ’ÔTðûõù={ íWÕr àÓK8HÆ\ÏÔ©Sõ´#v»ìÅñÐFu¢uÔ¡ídÒLzŒ%T=@œÜiJj›‚µÈu;IöºlœLêpä”j;äSLD’ìH¥ Ò4=O{ucª[ £¢ÉgüÔÅ-¦;‹¤î,eêþ" HzÍÍÅZä•YQ‚íeÜÔÔ´páBšàS>ø¬’ê0’GHi™ ‡º‘þÑ+Œ0É9’fÜ3á6 I)Ûl;[&MšôÚk¯¹Q!Wü3€qÚG z$èABR)]°ªóËY Þî„ñÏVWa vÛg; ûUQά\¹ò׿þ5ce‘=z4K·³^ „𫬰 +G•ƒnèÓÿÜiêO$,UDŽÖųIò £¦¶@¿)­èL‡$!Њ@i°U×óÔ!N~>Ñ^Ý›îú3ŒŠ%ÿixrGPRw ô]¥º‰ü­D‘J!X5/õ\»v-MÿÍ­,´´´Œ9’§Ã€“îüÆ7ÆC—›jº(5t£î»`Lóã°?fKšqÏ„Û(0¥qn³í`¨¥ÓòœºÝ£lI­L™ÉÀ!LA°ê?ýR#©^— ’l0(VÉÛIدŠrcóæÍãÇçrºxñâÏ?ÿìú+W6lØÀ˜¦±±ñÈ‘#n½Ð„°§†Ÿtí ç¨Õj/A¸(¹Ó”îÿäGu”™¼)¦tBŒ3Fõz^Ÿ ’Ÿˆ´W·§ëèLbómN4¡®®nÓ¦M®a倇u0(0éÎé;ÈdyêÔ)2ÃEÐiª "á+Ѻښ6*Ò)ð}®þ¨”„4=ŸæÁcAA¦áEµk×u]$Lºc¨—Η k _* çè•rìMZ¯¼[h-eêI•úM¥~à_–C‡1Z‘jÜ3á6Š…œûìÙ³|¤.lÍl;îܹƒmãš|ŽwrT}øi$º–  óI¸&‡ºxñb>º¬^ˆÝ¾#Ï !.Q8Òª­­-Ô ºxøá‡Â$OºÃ}Þ"3F1Rù˜ezáVŽ7e²M/ÜXrѯÀ•‰C“O¼œÊÚÉ1Á×Ô9*¿—`ÿüî&A+R{&ÜF)¬s›m–K—.Íœ9óÅ_dÄqŠT\¾|9a =ðÃ?¸~ÉãÇs¡ºD_ˆÝDŒ„—å…"̓Ç0*…[·n1V0bð rJUÞæÔ1òHïú%}©” MX°`ASSSgÐå#ƒ'aÒ;ðZýôÔ©S6l@Êé1’4vXðç>*ôÔ»qCzÝoéÿôÊɧTE‚ͪ2›õ[Pà·£€Ã`#óæÍã`‚Zý@+Ô·jTn£¸ʹͶ‹AžÓK*‘"M#É„„ÇIìIóà1Œ ‚qò?ÿó?'MšÄÅì.îüÀ %p ùCõæ€/õà‹ Õ0¿eË–ižžËJÁéÓ§iÂÒ¥KuWZúÇh{{;# 8é.(ñЦµµ•gºKôÅ„Û0 CnÎm¶]2üô’Ç;cŠº'¿›àÑŒsSO›6‘JEht¸ˆÛ’>`IÌ* j$})èîóÂP9Õxøý÷ß3¤¿þúëºÃNõCe'`IÌ˜æ· óV)°q–Ü›ùW‚:Tv‰`ɤI“.\¨»Ð÷ÈN# !`´Ñ¸”9ê—È ¡.‘=&ÜF´HïÜä›m—?½„G…H’à AáIC´ x00rÈíTSEè2™<$¨¯a” hXjk¾²ß ‡ X»KôǦM›"2$LøqB衎Jèê °$Õª uSÕ÷îØÂÛQýôûAõþë‡7˜€ ·{ôO<ñÄwß}—âêfÌ–Ý»w3ºnÛ¶M·D|I˜4ÂÍ “jœIExìÊŠ4cZ&˜p‘#•s“c¶üô’ÎÎN7œ„àÃØ$”ÃC‚LÙ0c–òY‡‡?ÿ\Ñ䇿æf* ‰= òÕ“c¬â¢$ëHM# Ã@Ì‘zÀE?üp÷Ýwïܹ“å›o¾Id®[·Žfãµô?ÒÔ‡»îºKÐ|u¬K÷¢«~úýŠ zÿõYú &`ÂmTþÿÇÿønÊ}T ³bÅŠ<==ªû®\¹â޲H%Üt‹>Þû?£ñt I&E$×ÓÞž Ô¡™>ŸÕ‰ýv´ø¿úÍJ¸ꓯUÒ¿î1á6¢H²s›mG4ÓKŒP: ›7o>wî\#O›FÌD)cPªjŒYJ2fP€‘‹"Öbܤ¥À|eŠ’…[ÛO&‚ÓH¤n,–Kí‘8 iÆ=n£œ„›¥Ùv4I3½„A 'fILà3¤0f4Ú—&Mô†á—ªrB)K½ÃC¾‹BDsI˜ðã„g†‹‚žî" “‡0Ê+ŸX^K’ç I2Iö[Ÿ€%ð !¦¦’aXÑçûúé÷«­±ôÇ®Þ GÞéÿ2á6ª ÿº=KÆÞ½{GÅÝªÛ *hIF פ¾ÈwéUŒ?aáf ÒÛð/@9ÔaE–”*“€$EÊ´–ꤩï+¤'͸gÂm”9÷×_m¶q4½ä…^Èðq’áð”?.\ˆì4’0©'q%̓Ç0b š‹øN˜0áàÁƒî6(2kÖ¬?~|åN# Óï‰ã»(5н|øGµ%ÙT`‰ó¬½2*÷n-aÿþýä“dS$S wr}b‚ô˜p‘çþ?ÿçÿ˜mG?½$“ÇIsï‹Û¢òÕW_EyIâ«Õ„ ·Qè7mÚä©âÀèúÌ3ÏÌ™3GwtvvÞ¼yÓDÒï‰æîÛ·Oñ’%KFýÊ+¯°”O“yüøqê|€@«&ø äS€%H²’x6ëÔf)eÙo}í…î¿ÿ~ÖUœ€ ·uü5j¶qüô’õë×»¿|DInè.÷~cà… ÜhUPöîÝ[[[ûÞ{ïéƒóçÏWâ4’0ýŽ’fZLKÜF|ÉäAØõ‹ªÄJvttPŸEV5 4¥Š•mÜvB}JÙTP±Oœ€ ·u¸Fñl>²›mWÙN/)8•2$Œ ·aTþÏœ9ãn‰±zõêúúúèþüÞíµ’Ép„D²%Ü,\nd0á6¢ר‹Œ !«é%…¥‚¦‘„1á6ŒªÂcà®]»Ü]‘/¼ðœ9sÚÛÛusuuuݸqÃí¯Âaĸ’K–,¡>øà—Ž&ÜFÔ1á®DÂÓKÜ¡ø0ÈVÐ4’0™?Nâ ·aÀ¹à—/_\9pàC߯u[Aww÷O?ýävSùÄc„4á6¢Î€Â½wï^õ²ã§—¤šÓV(xºÌ™3§²¦‘„1á6ŒêDßøôÓOŸ={ÖÝY²nÝ:l›gŸî)¸|ùò;wÜb ·a”‚…{Ĉ;vì XµjU]]2ˆ é%=öØœšcÇŽUâ4’0&܆Qµè$÷ïßïîÌ` {á…fΜ駑sýúu·ÝaÂm¥`@áÆ¶qn–º”ÛÚÚfÍš% 2ÃI£ÄuzIåN# cÂmU޾1ðý÷ßw7É@P¿¶¶6<Û¾}û¶Û\¼`ĸ\ù˜pQg@áTÛ¿Þnii!¹wï^’Ä\ÜC† !I¬ÊFYðÓKrþËi<]*zI˜x5ת&ÜF$à2uQZ¼pãÙ‹-R|õêU€ˆ»È(79O/‰Ó4’0\äî‰ZÐ^>×~Ã0ú¢o \¶l™»g._N~ÑÀ@ãi$ɸf?(•מ&ÜF$ÈP¸Ã/°õ>vìØÁÅ­wÅFÈazI̦‘„‰Çû›ÌIó¦Ç0 á¿1ðôéÓ³gÏNxÑpíÚ5W¯jèèèPó‹ã’‹Š ­pí aÂmDnñ"<½Ä½ÃIMü¦‘$ãVBJöŒI…k¹aý¡o :th,_4DŠòš† · L¸ã¦—üö·¿åAâäº/]]]Éowb0$™¢¾¿é—ò w¿oz ÃH |Ÿ†_4´µµ)€½ö£oùaÂm&Üñ'<½ÄYv/znowŠ„Ý\†}¸OoܸÁÔð‹ {ðàÁþëný1¹aÂmæUA¿ÓKªaIy±›Ë0¢O¿÷)Â]WWç¿ À ·~÷mÕªUJbÂmæU„Ÿ^rêÔ©*™FR^ìæ2Œè“J¸kœ[ß ániiAÁ)jjj¢(¨hd„ ·a˜Tš^bÿ$Tìæ2Œè“F¸¯^½Ša³”p~eYl’IV˜p†9AÕqçÎNºsm›FRLìæ2ŒèSSS3nÜ8—èEÂMÀ²©©Iz­×ÛA¹ýôDv˜p†9A|ðOÿ}2œôëׯ'ü“Qpìæ2ŒŠ ùVõ ¸µ„[¿²L@éûqål0á6 s‚øÀ#çâð›˜d줗ëgÈ&áŸI†„[õÖ­[mmmþ7•[ZZ¼^ûß}KÿRÃHÀ„Û0Ì â’ ÿ~îÄ 7IþÉ!줗ëgÈ&ÝÝÝ­­­2o«?~œÑáVÒ(&܆aNFŒ±jÕ*–Änl› ¥¥…|U;é¥ÁúÙ0" bÍê9r¤‚„×FA c]TL¸HPÞÛÀ( Rm–;vìpóäðÓÉ÷“L줗ëgÈ,ÝÝÝC‡å& Cù®†Q8è[•n#”÷60 ˆ„Û&pcÛ^¸ëêêL¸KŒõ³aD™„—Ü`¯·‹}ë¢r`ÂmD‚òÞF‘pný‹_ü½–|“£o“U)ØI/ Öφe^rÛëíâA÷º¨˜p‘ ¼·Q@ü/ŸýãÿÀ³õß“³fÍ"†––•‚ôÒ`ýl'ü’Û^oº×EåÀ„Ûˆå½ Œ²`'½4X?FÄñ/¹íõvQ1á6 s‚jÄNzi°~6Œè£—Üöz»¨˜p†9A5b'½4X?Fôéî©±×ÛEÅ„Û0Ì ª;é¥ÁúÙ0¢O{{ûÔ©S9âÒF0á6 s‚jÄNzi°~6ŒˆÓÚÚZ__¿mÛ¶ÆÆÆ5kÖ¸\£Ð˜pÕÈñãÇ÷ìÙã}o>èÛ§ü¸ÒÝÝí¯8|ÒÉç¼»„QPL¸ #²\½zuvÀ•+WîܹsóæÍÅ‹755ÙÜ’b`ÂmT#X×È€E‹-_¾œÛ€%Œ=ÚþM;Æpfkjjxº„OúóÏ?o'½x˜p™0nÜ8.•J‡V¸öTGŽ©¯¯ß´iªf÷îÝ4$üNÊ(\!.*&ÜFÙØ°aƒ†Èø|ïjq¤¹¹ÙévÒ‹Ýë"ÃH ׉ӽ$®\¹2sæL—1bĈ¿ÿýï.0xð`õòÑG-\¸Ð%ŠO]íkÖ¬ill<}ú´;ô¾œ?~êÔ©o¼ñ†ÿ“ ‘?å½còg_@kkkò¿|DŽyÍš5jÂÕ«W]“" G뤵/è/* H3d.Üøqx]|=\„› l $ÖðÑG±â±cÇÂ1PG™ÉЊœ…ÛÆ¹ Xj ,-Z„%å=ÉY³fIʳbûöíü¡C‡œ;çÊÉ“''Nœ¸~ýz·]#K¸<\TL¸òÓÝÝ=tèPûà^Uè{!í¤—€ò>crƒËGá£xMMMc1žá&êVŸ|òÉâŋյeÆ gÏžuíŒ\'NëBpÐe—øé§{ï½÷Ûo¿E”ß}÷Ý•+Wà¾G%Ÿ`ÆŒ个?ý„@¿ú꫊Y‹:¾&ë³e*hEU 6Î*Ô¹téÒØ±cÉ ÇÚ`*òn@µýëm6‚â£×8wSS“’{÷îmiiQåLàJæÒ>}:Çï1?®_¿¾pá§žz*âŸß¢‰ ·Q0Xè­ŸåË—ÿþ÷¿×W2+3š¤ê‡g¡µµ•3R‰¯G­Ë ] !®UÕ â¢J€k1áá‡~饗6mÚ¤_‰ _~ù%öFë°¨r\'ÎéBpKüô*Œ(ŠŒ+S$$ŸY¸j–©¤jz'6HÌÖ”Ô©C¬ †ãôЊÀ·snôšÏ Z3…ycØ Lù·jfÂñãÇÙÂ|à®p|þùçŒr6¸eKyCn£¤9r„QŒ‘¿¸")7Êä4räHžI;wîäìV6Š Ÿ‚lý gþ猬^½úæÍ›Î*„Ó§OërBÚhˆ~j‡§¸kg•QAÂÍýÎà°páÂlÿ«¬âà³-eô‹ÎøÖ¯pWy 7àÖ fÍš5bÄ– Y%lÖ´“ásãĉOžûÊ+¯Ø Ìô˜p1äøñã£G^½zõ€?]›-Ÿ|ò [®Â‰‡¡™O/Ë–-s=[MpYNŸ>}éÒ¥®/bMÄ…{Ñ¢EëÖ­sîY­|÷Ýwµµµh“ë”r`ÂÝÝÝ|ŒgHq \Þyç±cÇÚïÀ§Á„ÛˆÛ·ogè)ÞKSlé÷¿ÿýÂ… ÝþŒœÀ¶·nÝêøUÉo¼±råJ×ñ%ÊÂÝÒÒ2wî\çJÕÍÞ½{®]»æº¦äp8qË—^ziÁ‚HžË*ƒ rQö”E¸wîÜùÈ#<ñľèؽ{÷< œ¬X±b…‹~ü‘î哘6è!ÓETPδiÓþïÿý¿ùË_Ü‘}1á6bÅâÅ‹§OŸ^ðÛɬ_¿~Ê”)Wí»HsbùòåË–-sâYÅ<÷ÜsHƒë”˜Yáîîî~衇Jðe•«¯¾Ši1¸¹*-Ù 7‡zï½÷rû<úè£.7-Øç‘#G\"5$Ü·nÝjnn~öÙgÿþ÷¿ÓO>ù¤CŒp“©œ¬k:[`;‚žqQEt>ÕX…€äÝwßý /0²ÙÃ1n#><ÿüóùütm¶|þùç?þ¸ +Ù²sçN†c÷¯n°½ººº¯¾úÊuM‰¬pk2‰;FðEo>ø`GG‡ë Ò’­p#.\p‰€wÞyí,\I¹¸tœLVAI TDMŠÈ$ÆP{¶R9ÂÝÞÞÎè±qãF´›6`ÀÄ áæ ås&Ož¬6SSk±òƒòž €š.ºu‹-°ÅôŒ.ò«h×;vìxä‘Gìk0á6bBYæb:tè?þã?nܸáÂFä‡zˆG»{ÈW=»víjhh [\ÅŽh ·^oÿðÃN”Œ€W_}uéÒ¥t‹ë¦Âu[F„UR>|˜N+©"´€ä‚ ðQŠH._¾œ@El„S$“ú'ù Z™%î––lû›o¾Ñ~ÕdšÉÇ ‚ç wBÕWJª±”†…›Rm¨•pèøä6qâÄÕ«W»#6L¸xÐÚÚúûßÿÞYpiùàƒ¦OŸ^®¿ÃV6là¡îïFÀ³Ï>ûÞ{ïq-¹>ŠÑîÅ‹¿õÖ[î½ IÇçóð;w\O•Š<…[v¨車Ïñ•½ ú"ðéM]9ª#wÌœ÷Õ«W9°¹sçh§$M&ظq£¼oxrµDŽ©kTé|Ö¾Ó p³ðñF9âµ×^›4ilÜÑW7&ÜFÅsäÈ‘†††ëׯˀKÏÂ… W®\YúGTÅÁâ‘G)ý·VEœcÇŽ•ý;"ŠG4…{ôèÑþí fâĉüqé_rg%Ü RLÅòEŸ#k$ð‚è‹ÀoÇ¿÷U5S 3¥ØÂÍî®®nË–-nè²÷]¼Èñ‡[áwÛØ9õõn[™ò]Ôתú<\^%¿ÿýï û{öìqm¨bL¸Ê†‘¨ìS0þO?ýÔ“‘‚ÖÖÖßýîwN3²×S1"‚ÂÝÞÞŽ8èKd}þyøm_&0 ¥73½Dt‰,GáH´¯„WŒ™ CUœFwDæë­·š››Q]gõ¥xßÏur3èÀ1cÆìÚµëÃ?$8tèÐ=÷ÜCòí·ß& Âô2•#¿<þ¼/Ræüùó©ÃF(%­TQ¤nN·‹rbÍš5&L`#ng½„X­Pà Oh#F™Ä¬N~ÏʽPßE7oªW'ôL¸(¼J2ôySSÓÂ… ¹À\cÒ²oß>Å n£²™={ö|à´·|œ]ÇÇ¹ÆÆÆ~/Zß:A¹ÕÀpQB$(b-eŠp5JU z&\^%k×®Õת$üeÆÒeÅ n£‚9~üx]]”·ìèÿ'wpF_虚š?ï¯è²"Ûw °:ZÃóOÛa™ðöq@xfpä,‰(¿_29Úo¾ùfÔ¨Q<§ûýg*¤yJEœ ÷¢E‹xö; è‹÷]DVâ-M±2Á6ÏG;°=êËù€IRGf,¨æ [ÛQPgåƒÖõ›¢¦@µ½H Öâ’÷«ÃÖÒRæó“¡Â}÷ÝÇ¥xåÊúêìÙ³ÈâСC9P¼_ðfãî*ZøvpsÛ¶¶¶Ö××=÷¿rþãÀž={yä‘/¾øÂí£’Ñ”˜M›6¹¶õ’p™ñÃÄ šæ¢r`ÂmäÅóÏ?ÿ·¿ýM”/;>ø C­MæîMMMnÜMzE7 T–L°Ìüu]¿ Uò¶ÃÖð"¢üôÈ–°¶Ã*àÊúC{q‰ÔŒ1âèÑ£ sgõnŒg¶KW å}Æô Ÿµ6oÞìú½/n|T—×9\!\~Ää«ç]È¡È_úë<5ýêZ*GpIP“øk%19ä³)¬—:@&{ÔUJ9ª£íxö+ùÖº\®á½£jiœûW¿úÞ'Ÿ|ÂøÏ?)Þ?6îv_ÉÐ {÷îå¶­©© úÌqüøq×ÔŒAÙùpȰé_$Ç>ÈÍš5‹ëójðºûöíK¸Ìè75?~Ð:•n#wvîÜùì³Ï:ÛþóŸçÌ™S–/ÕŠ>­­­Œ³s‘¼A±@)Èñ™ÁÃC¸äyƒ"ëÁƒ1°$ÉZ Ü^g•Z °ŠpoJõ½ŽHqØ/±ŽÇo‡€|rÈWeÁFØ>PÁW¦¦r”Ô^zÚjQ2uuuŸÿ¤E_%¼[¼x±ú°)ï3¦_S½/Ä\QR–\$½°²Ôy×’|àbà‚Ñ5Z%PM¾«íøkLø¤TŸÀoAÇì‚ø-ø:ž„ý*N^×—Ç›òSâÿ÷ÿýÿþïÿ®k¯”¸ÝW2´büøñjNþ ž ,p›Žk×®}ì±ÇÆçšZ”÷³„ ·‘;èÈœêFT{äÈ‘'Ož´—ÜÉ ,o¾ù¦FÛcÅ"¦^k°’z}ˆÓ°ŠäÆÛ9á·z>_E,©äËTä7…þRŸR­ˆ:ÕóÒZÇCMbj²–öÅ‘øO¡’CÀ6©F@R{I®–@SS’ý_ÿõ_ÉïÆÈwXpü.Š i„› €%§^§ŒóÈù2Éáô©”+¨@¦*èÂt-I*Vø¤|M¿m¸ Ã[ ˆ«W±HØ/¥!+j™¼—`«)…û¡‡¢ ºüÂè­d1`ãn÷• ­à©ôâ‹/½Õ‡º®½½ÇÜÆÝÖãÂG}T[[ûyðßÉO=õ”ë ^°p×~£ ˜p9ÒÝÝÚ:ÏÓ¦Mc|ÔôG# éŸÞââÿ(Nà… Ù|N‚dø|PKåË™T~S +úr<’fð›b ¾ŽÇçøí€^f+©½ô[-ÌóÏ?è¸gNŒˆàˆ5¥äF 6LçèÔ©Sœ²yóæ)§««‹å²e˨C>¥ÔQýàÜN'à:马ΉÆì•ÏFÈQèªOà·À–•#|M`›\ŸŠ9– û §g¿:€ä½ø ý¢)%ÿøÇ?¾üòË„wERâv_<˜”ZÑ3ƒûÿ8{öììÙ³ƒ>sä0¥nݺ5sæL+úãÞ€$|Ë. žŒ ,hjjúæ›oÔQ<Ê÷íÛ¾Ìb<¥¤¼˜p9ÒÒÒ2wî\£¨±eË–gžy¦££Ã^r'þO5ü ü`Ðã_±L×çÈä á/Á*òù "–Úø7Üà7•°¢j*ЫAÀ›Éñû"I‘b¡j~;ZËWR{I®–À¬Y³/^Üï»1û Û¢KÑ)R_¼È¢ÈrYrp_àÖV±4Ž`Æ TåôÔÖòu€R¿e HIøú(2õ‰Aë®O2¼®%$P¾¶Ã‡rˆ)e×~]¿—àx݉;ýÓ$ƒ˜þ…·µµuäÈ‘º‹úO“îrBÝå½-t¯¹¬’@+ä‘jTX»sþ§ÉÛ·oó¼›0aÂ×_ív“‚|ÚËç¢lÐeÆNu#¤‡AxÒ¤IK—.Uö½ß…¾ÌâúO“åÅ„ÛÈ‘È~Á#ÅðáÃÛÛÛ_ܱkÖ¬ùÓŸþ¤‘ZƒÊèaÉø«€À?BX‡süBEzãH’­©ˆmj•ü¦€Vô;e þðØ,ËðÓˆXîE¿–¶ã·F»(3¡ëÊ~¢mÛ¶ñ:sæL»1·®B KñºÑ‡Ö×"‹®¿‚÷¬|Ô¬©©)ê׺;!'ôAEŸ‘@7¿×J­L²Ï×J»yf¹töܹsG_×øÞ{ï¹=õG>íÍM¸ãØ€ûå£ÇÿñÇ«àÂ… _Êä/³¸~-`y1á6rÛ’{2üs‘BætéÒ%w¸F@kðO“nôMzEç“ ¯ ýË9ò)åêsH²’2W=tYª™=[ Ð|áë+Õ÷¥ ¾Š€8ùPY‚? –ýV£‚rÄ#<²wï^žC\BtWøÝXss³úÐ(|¦·`}Y±b××aòoßtww/Z´È% ×¹»ráãÎòÚGnÆ îVbKê33w·îA}r&ÈZÈd??|CïKäÏ”_|‘QôòåËn}Q{ÕR}ö §gœ FE’†z•@¾Vñ­ @L—ºDðdª¦'ÜóýÂçÛ††?Ò|µ½d¯Š ·‘ ú~÷—øè±víÚ9sættt¸Ã5Ž92aÂ÷T7’¸ï¾ûô@úé§Ÿ\—õj÷È‘#eáF¡=zt[[›ëz#7©^Cæi‡Ù‚ªº#Ȟ͛7ãÐhßÉ“'|@ dO½ëש¶4ÑT>IÀòÀA•¼H#ÜáöíÛ|6;vl¿W/íÅ›;ÈñB{iuP«‡i¾ß´"¯Æ^(ò$‡.¢>A=>l5]º/ßÿ=WÔ믿®n®®.ÍÊ‚ ·‘ |üýÃþàô¶/çÏŸÞkdôÿšûvðU»$YT&aÎî€0*=óÌ3Œ,6¬$PSSÃhëFb#ÄîÝ»ëëë¹f0ìäÙÿd–Ø~bÏâÅ‹W¬XqÍèËwß}7|øðÀ‹þQ¼/$é—|„5œ7oÎG€G’n-Uô0Qê ”ª w ‹i¶[¸ñáðáÃãÇommu{í%ÜR 4K5Š|ºˆ–$É”»‡ º«O5P} 7*(öõ=TvQ k£F O#aë÷·½Œ`ÂmäË•+W:½íËôàŸÕôÿjþ¿6CŒ ›€%æ AIT&½‚ïß¿ŸÑÁ¥ÄO¬è3{öl>,¹ÁØ1þ|ó\3ö‡‘ÒÀƒÿ¡‡ºxñ¢3M#À_‡þKK ÈG¸Ãú(Ad‰ Ê8 L ‚¼M$¦±È¥*äI „[ð!á™gžyùå—/]ºäöB¸•´]¯ö{z*è %A5é–ðkìð«°¢K¨?“Y²dI}}}x‰=Ë‹ ·‘ xÛ_ÿúW§·}A¸õzÛ¿·–F1 N}Ÿ.ÕbT™@¥rôÓÁÏ©,~ðB¥ZQßt^±_ÚÛÛõ““6;;wòpÏv#ò‡Ø5SJ-Z´fÍšŒ^¾ýö[.}! >纩T ªîfȤ¹¶¶Ö%®]C÷ïßÏòÓe644`ŠJBss3Ãø‰'¨C€e*?OJ&ÜpûöíÿüÏÿœ0a‚Ÿ^’,Ü4YoýkFú ¥fI52Ož19QŸÊZWI†¤œj¾T«OÒ¯Øïü¡aצ$3nÜ8>½¸§“°mÛ¶¦¦&=™¸x\OEF/¹/\¸à|³êA¤0*]‡$]7•Šœ…û\€K\»†C“Ĺ•ôü[±ðÉ„ü|(¥pÃÏ?ÿüå—_Ž?ž1Dn¯rˆÃ¢"uš>r°ô”£:ï“_SìÞ½›Ï?úÂ%aÓH"‚ ·‘ £G>~ü¸Ô6<-F¬Y&ü<™ziÍR™òlôèöôéè J1l’¾È—ÍûœTŒ1âèÑ£]]]îˆ^ô’[xCŒ;öóÏ?çÉd_ß^bZZZ^~ùewª®À††½Þ.ËÀ•³pGŠ ·@ùÄ>þü²O‘Z±bE}}=Ï>uØoÀEn#ÆwäÈç¶}A‘åÄ",Ü“ûþJs¿ÂM@M)»f˜ä ÜúÆ ›Û/œ¾ƒºç|Õ³fÍš9sæØÃ©\,\¸põêÕW«›'NÔÖÖúé¶7Êñ¨ª»%*™²7üøãÈîOkÖ¬a³i$ÑÇ„ÛÈ…åË—/Y²Äém¡Á³ñi‚®ÞŸÏ–={öè;•ûÜI¬ZµjΜ9RÏ*ÛFòü;!ûÿÚò‚e¾úꫜ‘o¾ùF&{pëÕ«W‡U‰‹°Ä_Uu÷F1á¾{å•W\¢”]¸áÖ­[‹/ž0a·ß~뤸8ð€{æ™güŒ8èìì¼iÿöUL¸\Hø‘ð‚£Øþ}v¶¼÷Þ{/¾ø"£4wÄF¬]»ö‰'ž8{ö¬S€ªÅAt¼móÑÎþüZv8œ‘Q£F577Ÿ>}úr¬yçwh)ª¤ÿ’«2Ú6d.ÜŸ|ò ¬ï¿ÿ~Å™@ý»ï¾Û%Š@„4½D?:ãì¸ÐìÝ»·¶¶–‡Ú \B6ŽEn#öíÛ7iÒ$÷ŸÑcÉ’%ú Ò .¸#6R°k×.Fí?üЩh ×Š~& ¶}ûöm×F¹A–.]úàƒþö·¿ÅJ9ANQcÁgŸ}ÆÇ Z‡°ê{ß#UÙU)gá 4I]½züøñpHBªúÀ“Ŭ®8+""Ü¢£££¡¡á7ÞpW8Äêëë×W—Û«UL¸‰ò„ûoy³1(Nœ8ÑÔÔôè£bÄ×™3gŽÿ:³írãÆï¾ûnãÆXÝ}÷Ý÷xÀŒ3ødˆNUÜV|øWh ’Älj°';wr-/+­dn@°ädá^²dÉý÷ßO¾^x¿òÊ+£GF7UŠ@(©œ„ú*R>5Yül¡êXתrsëÖ­?þñO<ñÄ™3gÜ!æÿ /„ÿ6 Æ-ãögDn#G"û#á§Nòÿ1ùƒý\fðTøâ‹/°ßüæ7ÍÍÍÄNQcÁ–-[еáÇóP»Žý#”áæÅ-8MÛÖ®]린 .¨¼×—ÂòÞ{ï½þúëj‚ÿ˜'hÝ•+W¢s¢ªúЀ ÙwÝuZ ²d2YjrÚ¤I“æÎTì|êcÏþóŸI²ì·>Iž®\aã_ýµâl‰šp§˜àÛµk—³æ\aø?~<ŸEÕF(ï¼#+L¸Ù¾};úâ¾4JlذaæÌ™Œl$Êž /^d@GkÓyn!ß?þ8Ÿ^ˆ+ 9 Ù$›ššÐµðñŸ;wÎ>ŒU7oÞä#n*ù†®®.…‚ ž‹¤H6Ÿ –Évýúõ¨}Ø£œ´úˆûXí>øàò“¯:,ÓÔgƒ~›_~ù%™Þ¿³‚V¨Ÿ]«"Ÿèêëëó™^²~ýúð\8àÖ°o2­ L¸¹uëÖ¯ýë²ÿ°V2O<ñĶàWmy0»c52æÇìîî–Ü ßz3W¤—ÅÃyX²Mã©l/¶+Ncp»¬BÀGމ¥±$v¹…&ø_îl?Êó—ònÿÆZxÃV€=/Y²„dònn1iÒ$m!«·Ý‘nàøãÿøä“O†ž çÏŸ§sfΜé‡brøÌæ¶kT&ÜFî<ÿüó847"|÷Ýw>ø F%Æ)w F– 7?üðÃ… 4¸Ã¹sç\T™àÙ—/_¶™ŽF6l@ѱ˭Jèž XðñÇã>¾ÿþû Ö®]‹C/¬ïÿ¯ÿú/*(&“:ä¨ófÙo}¿Mò©Æ²­­mîܹªŸ!´B·¼kUÄ`hå¡9jÔ¨¿ÿýï’é9zôhmmmx ¶mÿyR‰˜p¹süøñ±cÇ:ÕóçÏ÷þñÇÝùq+À%*‡Ÿ~ú‰Ã¶'“‘ .½ÞE}É}è'­• ­ÐøïZIÚÛÛÇŸÉ/=½ûî»Ø¶M#‰&ÜF^,Z´hÍš5?Dƒƒ26iT²ù$†a¤'üz[TóKnš/g­hh…®UQåæÍ›óçÏúé§9Twè}á6cÆŒ_|ÑO#!Ǧ‘T4&ÜF^tww?ôÐC.\pÎ[Vžyæÿ+6yÀ0Œ4$¼ÞÕü’»¦¦ÆõB%sß}÷éàZa~þùçM›6ÕÖÖ&+Ô‘#GÆ¿víZµ°mûc]¥cÂmäKD^r‡_oó1ÀœaF$¿ÞU>“[Ch pí‰<ß|óM}}ýªU«œk_¾üþûïcÛú) qéÒ%›FL¸|¹uë–~òÊ}wQ9èèè_’ÍÞ6 # z½ ‹-Z¾|9ž½fÍ‚qãÆUóKnð_¿XÑРמJÉþÃþðôÓOŸ>}zöìÙÏ<óŒÿÊöóçÏ_+è×òeÄ„Û(gÏž}ì±Ç õKZ90eÊ”ÖÖVPösî†a¤§½½}ß¾}.L_vQ0šÙŸÈŒóÓO?ñ:tè[o½¥`Ûý¾¹ÿ~}·hA8}útssó¨Q£üw”²#ûñ-Ã0òÁ„ÛˆY 7àÖnÌ[™”Ž1"(4"‡ ·Q,nß¾½uëÖÚÚÚ3f ÊN™s¥««ëõ×_Gµ—.]*Õû/IÃ0òDŽۈ™\‡mmm‹-RÜÒÒâõº®®ŽÂ_hD n£ˆüüóÏÝÝÝk×®}ðÁÑî÷ßov1Ÿ}öYss3[X¸p¡ÿ9`Ëö €†aä ·ì:Œ7&ÜFѹuë~Œv?óÌ3¿úÕ¯ž~úéuëÖ¥ŸjrüøqìG¿ï¾ûêëë—.]zôèQy6tvvÚ’†Q(LtŒ(`×a¼1á6JÄõë×Ï;‡.¿÷Þ{3gά­­epG}ôñÊ|ðÁ±s=üJØBš/(5 ÃÈÆFù°ë0Þ˜p%í¾téRGG‡3èüãóÏ?ßÂåöåìÙ³/^¼víÚ;w܆ Ã0 „‰Žì:Œ7&ÜFy¸uëÖåË—»»»%ßa÷9”RÇf†QTLtŒ(`×a¼1á6"ÁÏ?ÿŒ‚ ûWHÃ0J‰‰Žì:Œ7&܆aFUSSSƒëFyá:tW¤GL¸ Ã0 Ã0 £hü÷ÿÿïm4ûHo»ìIEND®B`‚tomcat-connectors-1.2.50-src/xdocs/images/void.gif0000644000000000000020000000005314655113617020337 0ustar rootbinGIF89a€ÿÿÿÿÿÿ!ù ,L;tomcat-connectors-1.2.50-src/xdocs/images/update.gif0000644000000000000020000000116314655113617020663 0ustar rootbinGIF89aÆÿÿÿþþþþÿÿ???>>>??=@@@=?>>@?*EVe¹èO¿ÿB±ø?®ö2£é-Ÿæ“Ù‹Ñ ƒÄz²%sšJbòÿÿÿÿý*FT1¢èIaooopno@>?¯¯¯ïïïðîïðððÏÏÏ¿¿¿°°°    ÿþÿÍÒÎÂή¿¯®¾±©Â¬2 ›Ä¢5E:®®®ÏÑлÀº¡¯¢“­’~ nod|d$,#}&Y¿\/t1 /%¾ÐIJϹ¤Í«›Ð¦“Π¿7ˆÐ‘u܃XÊjtÜ…”Þ¡*¼Á»¡®¤•®™~ ‡m’sk‰q$**w/؆4q5 / ÁϯÀ°±¿°°¾¯¬Á® -¯ÍµÐÐв®­«¡Ÿ#ÐÎÏÏÏÑÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,Ø€‚‚ƒƒ†Šƒ…‹Ž’••Ž Š¢¤§©«®Š¼½¾ŽÅÆ !ÂÄ"#$%Ô&Öƒ''ÃÅ()*++*,-./‰†0123456789:;<=>é(?@ABCˆ1rI%K XǤ‰“'P¢H™B¥Š•+ùqû€K–,Z¶péâE Dˆ(9û͘0aÄ\S4`Ì2dDèÔùEÄa0YZiR¤IH%M:(;tomcat-connectors-1.2.50-src/xdocs/images/code.gif0000644000000000000020000000061214655113617020311 0ustar rootbinGIF89a¥ÿÿÿþþþ000ðððààà///111ÀÀÀVVãssä]]êÏÏÏßßß¿¿¿––Î..ô¢¢ÚŠŠßEEï••êJJôýÿþ/10ÎÎÎddñ||í¸¸ÔÇÇã22øÆÇãÀÀ¾þÿÿ€€ÔKKõ@@退€NNN___ÈÈäûkkÛø««Å°°°OOO°®ç––Ìÿÿý002‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”‘¥”,¯@€pH,‹ÀPy žÐ(ô(X¯‚–P8‡0"‘P, Üp< 7Zm¬†#’³dBHSgxg ~E eh tE† “T—q›o”D–g† ¦F }’ °§B† !g"»±u#$%&' ()*+½N,+-.ÛÓÔH//#+°ÝÞM00RSêððàðA;tomcat-connectors-1.2.50-src/xdocs/images/printer.gif0000644000000000000020000000066614655113617021073 0ustar rootbinGIF89a ÄÿÿÿÿÿÞßÞÖ×ÖÎÏÎÎ1ÆÇƵ¶µ¥¦¥œžœ”–”„†„sqscžcacÿ0œÀÀÀ!ù, ÿ $ŽdI.¨©®ê2¦l\º3-³4Õw[ê"C$Ò›‰€$a‘”HØ$HåRÒ”äv#i±:0<Ú×Ë8@±¢ê©/‹áA G†¬ä~rt^ yD"nxz €r…(Š‹# ‰ yo“‡B~ š‹4TAp‡¸ª««‹ˆ¯ ”±””ˆ¹o¼« qÁǸˆoɪšjDÁ’“T‰^Îkp¼ÌŒ í” ÎåçÙC# ë íàûòòÐK6„'ÑŠù/ß< †¨2ØhÂbþ)8oˆ½û—Àa5ï3™Pi1‘Æ’Cò½a¹â c ‘猦Œ!à¼ì è³ÈyrÊ+:EÂK)6]É4F;tomcat-connectors-1.2.50-src/xdocs/images/jakarta-logo.gif0000644000000000000020000002061014655113617021752 0ustar rootbinGIF89aù0ç:5:[Q,‡{Dß:³«N¿JñÉ[£%·.•#Ñ;Td-ð×\‡*÷T@™5Mðá]~ &æSI÷|J†2Em¡/èàbîîî¶V:NÈ‘v_ "v8:\I’ˆI®¦bK>–T=çÎbÐEöòŠ[]_¶ivŠ•N &‘hk<5¸±[ÚÙÙ:Jf.Y¸xP.--c*]î3t2¡–YbF2}FöööÝBvh7˜Œf= Sö£Q¢,F¶®jÈĈÜ,Tˤ„îæj¢‚IZxY;>¥´ºfed¥:o{ƒÁ=Y6ÊEîÒfúúúL#4Rm>>>c&`Ú$Ako“pQ§šeÝ9Xv6S{oFááà/ IÎvЇGC7$2 DlùhF 08¤*["4” *ʦ¦ÒÒв²°h6M¯o^’~^¼)Qž%DŽ-Oª Rö›WÌixì<Ž":è5R4g‡ a–¤¬TTUºº†•S„ÚÊj––•€[_MXIJJöHAn0ééè¡D3µÄÈþþþi"^®¢jƒ?qË´˜vP‚`lpìxJÎʘb 2‰œ¦‚*Q¥H” \Ö>*0’&R°W~ 2Í(Vö1¹›‘õ4>´®n.UuDvljh¼SQ5W{(9ï»ZK)PrSoèiMvvvò>àÍ˦¦¥³AKN 6’fV¶Œxòòòî~Ftt¯gb0"5h7ie,<‡HgÎ~††|N| f~>F”T[$%a:dÄ»¼¶¶Š·|y€€º¤”ÐÌÆ†1p a` N{c_ô$>u¢`…††n[Arrr¬®¯?TiDvhú‹KïµTX"b AP&&&μ}ù3žžê)Ju*UY8e¾J„$`!þ+Thanks to Brian.Ewins@i-documentsystems.com,ù0þ H° Áå4\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠôè…ÍÈ“(Sª\ɲ¥Ë—0c†œá¥¢—‰^¤xL¦ÏŸ@ƒ J´¨LCePô”¨¤'"ikñ1Ó‹…TOª‹ÆuiVƒÇ¸FS÷µ,A b£a5›Ò‹KâElR.Qº=kí¨¡¾VjîyÑH >¶«(^¼8QÑ@–cìÊècº¥dر¡ŠÝ0¨ÂRÃM/³@Žê¬˜O4“'_ˆPS¤¡7S›%3ŸÊ _¨P²&ŠgJö&²U @Œ5ê©Ñ©1@øð½X‹xàìïRþù]ˆeÑšQ†þŽ'Åõ£YŽBò2{ÑÀCz™í>¤ýôl€oêHÁÐ]å ¢Ä#*çÉP³CsÈàa!¡pÓ 7ÜÒŠWÝI!☉hàc‘é¤CA/Äó‚ÉöÝgDý—|ßÕ6|¤­4fvdß}˜‘’!£D“$wÙØ]<½a&@1º´F<“ìÍ#{4ˆ@ùÔ…PœC—\’F…Ôa u0AŒ,E胈_ýHÐcU "^ (Zý8[]5Ò‡’!é4Š#¡ñÈR4Šzd_ÝtSŽ ¢UÙÝž•v·Š¢Í ñÁÇ$“ðÑ¥4þ‰¬áÌpØp@þ@Å `áWàQidÃ+ô|‚9àüUVztÙ(Ï`¶D":”À‹®@D÷™gÐ,äêfˆ4ÝÄ#A³\éJ7ÒăêAƒn:k¬ëä ®¸¢£A%M9鬑³ýÛn<ïÆ;¯@’T.¹éÐ"º®¤ó°@W<‹ð!Z1»"_Ǥó.Ç0É}Uˆ(P9³×±ÄëŽÀ«Hóo"R[².'ðÀ3dÃݤS›Ì0rÉw²¶˜€‚rR ‡ (LÂe"­XbIöÌf=ÈQf—ÜÑ\dƒGuܸÉÌþ†Ü0ã‰\FQ ¨ã%B"iêp­†`öóAñˆ¦Íl§3›"óG‘g"† 9²@ÿy1¹hBœÜáÇyDÒÌ+ Žttƒ…=bƒÒ·­ì²—¿þÍÉ 'š2¬¤ŠÆ1†”MÅ®ŒFÄ40½¨  M€£0‡q a½èE)̦¿P$cš`ÄÎAÒ Àá—hÎ%žêàáá  °9}N>Á“ÖQÁD„æ[«ë¤AB¨ lÑp cÔè9HÙe6a¡<ņ2àRÏz”@PXñP4^¡htäÔ1DR€ÐÜ ƒ :ÊUó;KXB Õ ™½Ð ‰[¡C˜ˆ­!ш=ƒÅ\áDÌø®‹õ”ÞQ¹Vž‚Õ¨Õ[—žÅÿØ¡y X¨>Ì@€ˆ#¨„~Œ£É…ðh ]° µi8þ€l ÿ銂ôÕž€V0C$G8Žeã¦'™¤Nu) ¨ Å膟ŠFp‡…Å ˆY²·jc4PãD¸åá²}³Ù ¹9̬â`j5È«EXÊR4ÊYÈ,ë :uwÝ+ˆ ÁUjŽS}\áƒ)wˆNÌ– íÍé@¤†™ƒ6±ë…°hÞ+Ù¸ìdNÂ,½VAáÙ`ÒpÅhWÌyà"m6z! ~¤müØ#Û@R”é PduaÕ 6¸‡*È LÄB N I³ÓžbkÖkóþ$¼zK»P­Øl¼âWˆN4Égþ‰\Å@.æ\92LÚ¤ÌU0¥h`Ÿifw\lãß*a‚Ðõ ^°%‘öŠÄ¬å¨ñ² R-ÌU±cai8ÑLšÍq»Qâ~Î`óà@8ð jø`ãÀB°Œ`°Öΰ%ô7‡9|@¶P8@ Sƒ¼ÂWG&‡² ì­oàÈ ¹„:TÊ•LÍvÈv1™½‘sÂQCBEü&¢Îr†¯ìB=öœ•H¨,HUKØßËÀ¹à¢Ç]ÂA,¾ìbAÄÍíz¢»|T'¿£'ê³Ä¥Äâ>`Às`ޏ8.2ŠGFô‚µg›ÕþΠ Røªw@išLq7V¼ãw«A x¢­ˆ²YôM$D=ÍMœ\¼<šn¤ÌÞ_¹Ó{îÙð!IPWÒX"‚ØÚ½ ®8úžë+BòZi6BD<ªNh:TF#Ë: t6F1ƒpÅÆžˆUˆæZ¶ ³¦eWgD=êd±O¼•ŽvQ»¢{pÅ#š°Y!,!ÚÐs禱TØàÀP ãf‚Ö§G™p‡ÇaþcyuÀ‰A~€2…À!îñŠW8¡jhµ‹²åF#UïMÏôTgDlÃüæ½;N#þÈóS|®—AT,úÀþéBæ×{ëÁ·˜Eã 2–»wóÏà3ƒ‚ðŸv¾/ÉØÝÒ osÃW÷Œ%¨à¡(Ѓ0†0 y ’·û0«¦j‡ã ßpZÉ Ô`ÇÁ0Âc{t¡²Çv ` ¬€,¹p—PÕ‘d2 ‹° ÆÐ 9W€DQ`%TÛ–26Õ7 5cî±tæ–Tô^ôï—DÁ‡kQg|FN91Vnݶ9™v…mwv˜Z/|æ—svt×]à'%æsæTôAñÇ÷8µab¸/° ¬òªòÐ;a Xà4þ˜ gep óðýPq7߉H@ ãPò #W¹ÀQp)… +À.øð`d5` $  ` að D,è S¿¹w ê`ƒååéc=&4‡¢mzD¨Ô{]5Ø#à^!Ðs^\ˆ€3F¯BjÝ wûõ„Ô„Œa…mïÆiuwT,Ä„mµn@$Tß&0"ˆåIGxäØfO£CŒ\VpàHý€Gö` Ê€GzÀD6PþGVmÀ )Ui`Ë€@vp´Çµx¾ PÖ ɇD¸Aa(VõsœSºÁY ¥0ò”¢‘M%&n¦¢3U0XjíV)X©•àÁu=‚Œí—ÄÑ :µQ†£ÔOU 1óÅYfw|Åt—l·BÑ@Oâ$ýQ–U@Eéq|Ó— ‡˜³Q}y†la+ñ ®¢(Ð%5¡Ð ³b ŒÐ Í@ òÓ yB €¬Vqщ_à§SP½ gÀ6õ€»Æ‚„¦àe6ð“ÜÃvd°ŠN€7}sáþP‹°‚¶·»Ð£Dñƒq|81F÷Ñ÷˜À‡Xî–pú§…Í':°•ßjDtwëÒž³¡o㑘씳 yúö}kf ŠFÀG˜Vè÷8ÞètCsE®3Ú<IFÕ ^`JP  2 **npùp¤Prà –àY Ô€ ûР ó  8Z—X >ÀHP ‚¼– ¯Åbr&à |tæ`Ôaœxp9`.Xrà ¬@p‚÷ ddPúÐ#‘>œyau1FlÀBP9`w ãUh@Ó *{„þ[¨]gVÏà)qÉÔ‹ú¸B|jo>5¡@CO a,T•qTzY³@D=R`3 Ij…¹‡ù;‚™Œñ†!épfð ÁdÅ g( #Ÿ ˜˜õV¡¢“ð&: 4’xpÓ L¤0sÀ,€£µ€ y0>Ó00Ѐã hkfã ÁP Éà’²»6+À ‚¹àceò 6ŠGÆÈ'$çЮü°}ó ²'YžP‘ s,±]³ M)·±F±_ª¨Á87a ûªDS2éÇ8š~ñ° R2³3;†2c·þ}šmvš±ç¦IëI&;²l±k€²{Ô5P@à?cpõ  ¢àš4P Õ Š0¥@$e°Óµ¬6 ÕÀq¤…S6s`cÀZÙ H—@š [p¶’&p#ï   õ@RàrPx÷ Sd@@c°¸á=¸Žû¸Qi˜A±;X2Ä!­PD[™`!p$Œ­VµÔµH€ ²é£˜¡€X‹É ø ŒÀQTP µÐ ü0¤˜ b« ›pº¢+ p¾`lÙÂÒ Ì@W@èþP‹¹` –ðÈ Y@×° /ð@)Ѹ•{¾èk93ÀYs‰¾("ÇàÇ0´/ˆ¥50xÐŒà Îð´ÕàP[ ¢À ˜ˆœ¥pj>0 X°Zz —84p²ÅfS‘,Ðk|t=¦+¦  éʉ'•Rc w³!Ÿð›½ÀQm mÚ°G–ÄP¾¥ê¾8Üpêù|9¼Ï"¶`qPgðÕqG†ÿàš ¨ÀÀ:ú‘˜àºêƒ ¨€ ºicÕ r  e…à :†Œ°Z–Pº°¶erâ‚[@qsôq¹{hà¹edL@]þa¾=<ÈŸ¢žBP„ŒÄ@¬ !pP¯à‚z@ þðPÅ:*ÅÿÀ‚ ó`ÀÐh¬‹µ¬… ²[ /Ö›æ  úc¨ð´0°½l“ p RÞ0 “8ã` và[¹Àº’Räpnà5øÃ5DC¹‰Í_1 2 ÍÒ씇€ôpÕA p¢œ`µ`6k|‘¢°»º[  µþ;Õ€ ó0 ‰DÚàf¯6 IZVð<4ð€ò  (i\à»p› ¼ ‰` p2!¼Œp¸@ Ö` ûÐjð¦Ú4%ŠÈ×<Ò$]Òq dþ÷ Í.ç‚™°ÕàÀõÐkü­–ÀÍpÎP‹ ® ®Ù ,4 €¡ŒDÀp hÓ Õ@GÁy¬¢c+Üì?6ГXq>` Äö›¬ÕcÀ Ÿ ,3• ÷ð5À Ö Äpíp Q '€°&×z½×E0„pôÀ àDÀ ,P™`çÉsà ¸v»6êZzÀæ0ö€É\[ ó`óУ›æ-J} Zûóy² ·;rJk T’à¡°¯€ œ¹°7|ó[°Ñ[¾ $À?ð×p ] CC Ò|þ=ÝÔmÒ†° ´Pù  „à ÷ðàù[a2£õ0Áv~ÀÙö& Π] 0 Ó,@Êpˆû VÌJjf@Xà»fi@ !9‰æðcS‰ã0i°H¦Pzô$LVJÙ7p•!Ý'QŽz[²*è8T/¾ê`$ Ñ˜#aÍî‹âîÛ8)@ Y¸Œ°d‘Ü cPà68ÍqcP¤ÀÞ*έ®•ß6 ,PåëlŠ  Ø fðß÷!¥`X; ¯6;6H‰¸°Èvd‚ÀÍk&‡pÊR‹þá âP7•`ë`= A`k@žQù¥t~Vœ Ú€°U€\ñõ›.–sÍŽî¾lÐé(a ìP±P~Ps°Õq þ`—p9@@ ¯9@lO¾´T>~°´šcö XP Õ  Ðßµ0@1@· ÔG]ÚÞ2¹0¥Ø0  (Õ Љ7F ¹`Ø¿)€â è°FÀ 7à < ³ê{é3é$1•*ð#Ñ 6Ÿ.Íú~¾BÀÌ*q  à @ô@ v !LÞ '5Š&ð@ð‚ðJ ›þü°cçM ÿ€kŠÐksÀÓÕº`£¸€ Iêf ðŒ bp o±ª¼£ Øž 90Ê0xDwpÂÕ±Gp À• ë°)ÐQÀ •Ðîëpk)ép Rãs¡šÉÁôhÙ :@3Àð<÷ á x9y¿:À2tBK ÅДo4Å0U€t-‘á«À€"¯aÝ€}bö‘£ ø«@¹^ ³ A(ú‰¿ø¿UŠ*¦:öR“…`á'so(âìÆ°Ïð9RPe ® õG„4‹À@„€@þps3ÄÕ¬Íñ&Õ±·Í1³^z& š +¡À¶9 ´ª¹å,ð¸ ?\Ð< xôÓ ›0€ V@¨€ Ñ~  y™)S@Aî ²'8xœÇ£„„8… „¸ Tª´H /‰<~R$È*Bø¬I€È5BF¥‹'¤BÒ¥3R!Ý^Sd7³Fz¬òâh¢Aé–z”’ŽO´‘(Ò½XƒbÆÈnT¡4Rš´c/\¹s”€hB=êàfGR^¾8VÅÓ‘«Ø¬y1*ÀÈtf\4X䨲gÝ‚¤-Þšr«D–äó¢°º‘êf¼þЯ̾!©œ/ÀJ‘F¹Œw¹ àrr¦[RZ÷î£^NÑqC‚$FjÔȆî½pðàyÇ„«ÏñdsžÊ¥KÎ3‘¦@& @isà@=Ršø±ç£Y³qh,9K–‡Ã~0šYP™<¾á€š/QfTæÙgLn1˜2 °Â2„pgàÁ#@ ‹v@ñ."‡\ám)8óH°.‹«*ŽÚÉ(¤, I CÒ‘i$R$)ˆÔ­›Qø2¤¨¡–Œ†Ýfè&-j)tk²È9R©ÒÑæ#)ÊÀò(*EbÌéÅQþ ¤!uLDy‚ENóÒ#ž9Š:¹ò(>Òü²Ñ¥|\C˜7®ùá‡Åœ36G¥–^zQ†zQ*¹šº€fÛ1ìâˆ.Ä a‘­ú_ƒ?ª‚Q¨ºþ£ŠºÅE—…5‰½¸ ¿ÎÒ`(ž¶:ê¬%؈§'+?þ7é… 6Î")ˆ†6ŸÚàh¨ÿÈ{ðŘ䥂ODó4€hŒ¢€÷ãþ&(‚Y~$ñ¢Œ—ˆý΂K9†8@CFp@ ôVƒy!àÐÛª:Ñ ¸ÕàÈ0Ž& 7~8q¨Ž©:Nàä¸Äs®°‰ñ4à§ëE3`xîРzÀÎC,tËɰÁvEŽÿØÃ8¨ˆ½@t„DÁ#BÀ) á€ÜÀƒ†Bð»âÕo$ òpd>C}éHíKD󔉩 AÊÑP<6ƒÜ© Ò«B=²“™$€˜"-É— LQ Í>±=’x’üJ9~F0&¬Lüê’™@šàDÕØ—^З#yÁ "þ‰7°ª<¨ÄM±B ŒpÇŽƒŽ;0C¡¸T €p½­ÐDhÕŒS&\¡UÊ`%œ•.êÌÅÆamn68ÇxLð„9Ô£¦àEP¸ ë@ XG±¯­P”u©‚4F"…npo|¸¼Y]2’¼,åà’ ¦<d/TÙ *wâRàÉtcÚ¤G8É›60I S(v$FÍô”"Ä+ÿ‡¥V&¢“#É,ÞÔ#PÔ©-mÔ@" !@m‚e é/Åú|AÂèZ°_ЃÌ0ÅÙ±ƒ* £òŧìþº®0p7M•¬šðg=<`‡nâáõ8@.Æ™œgq Àƒ©Î-î ÁB€Jdà ACê‚!XТÉKD4¡ƒ©’4jR¨-OÓ¡)«Úƒj"^=?% MG4À'½´|V…J[ßÚt)MÚWnÑ !dÏUÈi'§@ÒÀ”c À ¤0 (ÕLÒ¥.P9‹2ŒÂ(^(.ñX™Ó* 'Rx*©z\¸¢»‰˜Å –Ôš[B%|Hw¯’Àv¬6©!z PÁ^Ü!³5„h tó‡@:èñŠþ\ÊgëÄâ`V –m3¸1d˜b;¦è&,Ïñx€Cf9¶p7Sˆ#E@%Bà ð` Èx‘­ò«ŽÂ’6(V¬‚BùMÄNÑ®Ajì·!)ƒvAR†2/¥u‰ ´½'}de©j(ÔQ›R ©GA¡*´écì¥Gž1¡GÚ2K˜4ª\EËwM"ñxP†L[4§‰ …é#-X$¦ÕçIcmITHÊ¡Q ›7î>ñ†]„:±8Bòcz„a8d8DÞj`xL‡䈱[õÃÂÜágÈñ vþ¯HÃs ˆ*H@fñ€LÜ Øri+‰nרuyÔÇ–§5/xÕ‡*Í3t`ƒ·H ¤n¤Ð¾YT¼4:ðx<ª°q¾\<ã“Ôs£Ö{òGi å~ôtH´Qçƒ×üKÁlE$ޱ†n£N‡) Í: */ border-collapse: separate; } th { text-align: left; } main { /* Remove this once all IEs support
    element */ display: block; } /* Layout */ #wrapper { min-width: 400px; } #header { border-bottom: 1px solid #bbb; } @media not print { #header { box-shadow: 0 0 7px #aaa; } } #header > div { padding-left: 15px; padding-right: 15px; /* Work-around for old browsers: */ background-color: #F8F3E4; background: linear-gradient(to bottom, #ffffff -10%, #F8F3E4 100%); position: relative; } #header .logo { float: left; padding-top: 10px; min-width: 190px; } #header .logo img{ /* To avoid that the Font Descender being added to the parent div's height */ vertical-align: middle; } #header .asfLogo { float: right; position: relative; top: 8px; } #header h1 { margin-top: 0.6em; margin-bottom: 0; } #header .versionInfo { font-size: 13pt; margin-bottom: 1em; } #middle { display: table; table-layout: fixed; margin: 0; width: 100%; } #middle > div { display: table-row; } #middle > div > div { display: table-cell; vertical-align: top; } #mainLeft { width: 190px; } #mainLeft > div { margin-top: -1px; /* to overwrite border of element above */ padding-left: 16px; padding-right: 14px; padding-top: 6px; padding-bottom: 15px; background-color: #F8F3E4; border-right: 1px solid #bbb; border-bottom: 1px solid #bbb; font-size: 10pt; border-bottom-right-radius: 20px; box-shadow: 0 0 5px #aaa; } #mainLeft h2 { margin-bottom: 0.2em; font-size: 1.2em; } #mainLeft ul { padding: 0; margin: 0; list-style-type: none; } #mainLeft ul a { text-indent: -0.6em; padding-left: 1.4em; display: block; text-decoration: none; color: #444; } #mainLeft ul a:hover { color: #000; background-color: #D1c9b9; } #mainRight { padding-left: 14px; padding-right: 20px; } #footer { margin-top: 30px; padding-top: 20px; padding-bottom: 20px; padding-left: 20px; padding-right: 20px; border-top: 1px solid #ccc; color: #444; text-align: center; /* font-style: italic; */ font-size: 9pt; } /* Content */ #content div.text { padding-left: 1em; padding-left: 1em; } #content h3, #content h4, #content h5, #content h6 { padding-left: 5px; padding-right: 5px; background-color: #eaeaea; } @media not print { #content h3, #content h4, #content h5, #content h6 { border: 1px solid #ccc; border-radius: 4px; } } #content h4, #content h5, #content h6 { background-color: #f6f6f6; } code { background-color: rgb(224,255,255); } div.codeBox pre code, code.attributeName, code.propertyName, code.noHighlight, .noHighlight code { background-color: transparent; } div.codeBox { overflow: auto; margin: 1em 0; } div.codeBox pre { margin: 0; padding: 4px; border: 1px solid #999; border-radius: 5px; background-color: #eff8ff; display: table; /* To prevent
    s from taking the complete available width. */
      /*
      When it is officially supported, use the following CSS instead of display: table
      to prevent big 
    s from exceeding the browser window:
      max-width: available;
      width: min-content;
      */
    }
    
    div.codeBox pre.wrap {
      white-space: pre-wrap;
    }
    
    
    table.defaultTable tr, table.detail-table tr {
        border: 1px solid #CCC;
    }
    
    table.defaultTable tr:nth-child(even), table.detail-table tr:nth-child(even) {
        background-color: #FAFBFF;
    }
    
    table.defaultTable tr:nth-child(odd), table.detail-table tr:nth-child(odd) {
        background-color: #EEEFFF;
    }
    
    table.defaultTable th, table.detail-table th {
      background-color: #88b;
      color: #fff;
    }
    
    table.defaultTable th, table.defaultTable td, table.detail-table th, table.detail-table td {
      padding: 5px 8px;
    }
    
    
    p.notice {
      border: 1px solid rgb(255, 0, 0);
      background-color: rgb(238, 238, 238);
      color: rgb(0, 51, 102);
      padding: 0.5em;
      margin: 1em 2em 1em 1em;
    }
    
    
    /* Changelog-Styles */
    
    ul.changelog {
      padding-left: 1em;
      list-style-type: none;
    }
    
    ul.changelog  li{
      padding-top: 5px;
      padding-bottom: 5px;
    }
    
    ul.changelog img {
      vertical-align: middle
    }
    
    
    /* Printer-only Styles */
    @media print {
        .noPrint { display: none; }
        #middle > div > div#mainLeft { display: none; }
        a { color: inherit; text-decoration: none; }
    }
    
    /* Fix for Comments section which contains a 

    */ #comments_thread h1, #comments_thread h2, #comments_thread h3, #comments_thread h4, #comments_thread h5, #comments_thread h6 { border: none; background-color: transparent; }tomcat-connectors-1.2.50-src/xdocs/images/design.gif0000644000000000000020000000114014655113617020645 0ustar rootbinGIF89aÆÿÿÿþþþþÿÿ???>>>??=@@@=?>>@?*EVe¹èO¿ÿB±ø?®ö2£é-Ÿæ“Ù‹Ñ ƒÄz²%sšJbòÿÿÿÿý*FT1¢èIaooopno@>?¯¯¯ïïïðîïðððÏÏÏ¿¿¿°°°   «¡ŸÿþÿÍÒÎÂή¿¯®¾±©Â¬‘¥”®®®ÏÑлÀº¡¯¢“­’~ nod|dSkS#}&¾ÐIJϹ¤Í«›Ð¦“Π¿ˆÐ‘u܃¼Á»¡®¤•®™~ ‡m’sk‰q*w/ÁϯÀ°±¿°°¾¯¬Á®ÐÐв®­ÐÎÏÏÏÑ,Å€‚‚ƒƒ†Šƒ…‹Ž’••Ž Š¢¤§©«®Š¼½¾ŽÅÆ !ÂÄ"#$%%&&̃''ÃÅ()*++*,-ØŠ./012345667ç†Ã(89:;<=>>?ê 2 H!Cˆ‘gD  nPA‚$‰’%æ!¢äŒI4M¬]æÄÉ“'"R¦d"Â!¥˜,ɬ4)Ò¤›’lâ;tomcat-connectors-1.2.50-src/xdocs/tomcat-docs.xsl0000644000000000000020000004605614655113617020424 0ustar rootbin project.xml <xsl:value-of select="$project/title"/> (<xsl:value-of select="$version"/>) - <xsl:value-of select="properties/title"/>

  •         
              wrap
            
            
          
    Attribute Description
    Directive Default Description
    -
    Directive Worker Type Default Description
    ? -
    Directive Successor Default Description
    - -
    Property Description
    /images/add.gif
  • Add:
  • /images/update.gif
  • Update:
  • /images/design.gif
  • Design:
  • /images/docs.gif
  • Docs:
  • /images/fix.gif
  • Fix:
  • /images/code.gif
  • Code:
  • # r
    tomcat-connectors-1.2.50-src/xdocs/project.xml0000644000000000000020000001204314655113617017634 0ustar rootbin The Apache Tomcat Connectors: mod_jk, ISAPI redirector, NSAPI redirector The Apache Tomcat Connectors tomcat-connectors-1.2.50-src/xdocs/webserver_howto/0000755000000000000020000000000014655113617020670 5ustar rootbintomcat-connectors-1.2.50-src/xdocs/webserver_howto/project.xml0000644000000000000020000001223414655113617023062 0ustar rootbin The Apache Tomcat Connectors - Web Server HowTo The Apache Tomcat Connectors - Web Server HowTo tomcat-connectors-1.2.50-src/xdocs/webserver_howto/apache.xml0000644000000000000020000012274714655113617022650 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Apache HTTP Server HowTo Henri Gomez Gal Shachor

    This document explains how to connect Tomcat to the popular open source web server, Apache HTTP Server. You can use the connection module mod_jk with any supported version of Apache and any supported version of Tomcat.

    It is recommended that you also read the Workers HowTo document to learn how to setup the working entities between your web server and Tomcat Engines. For more detailed configuration information consult the Reference Guide for workers.properties, uriworkermap and Apache.

    Warning: If Apache and Tomcat are configured to serve content from the same file system location then care must be taken to ensure that Apache is not able to serve inappropriate content such as the contents of the WEB-INF directory or JSP source code. This could occur if the Apache DocumentRoot overlaps with a Tomcat Host's appBase or the docBase of any Context. It could also occur when using the Apache Alias directive with a Tomcat Host's appBase or the docBase of any Context.

    This document was originally part of Tomcat: A Minimalistic User's Guide written by Gal Shachor, but has been split off for organisational reasons.

    ${tomcat_home} is the root directory of tomcat. Your Tomcat installation should have the following subdirectories:

    • ${tomcat_home}\conf - Where you can place various configuration files
    • ${tomcat_home}\webapps - Containing example applications
    • ${tomcat_home}\bin - Where you place web server plugins

    In all the examples in this document ${tomcat_home} will be /var/tomcat3. A worker is defined to be a tomcat process that accepts work from the Apache server.

    The mod_jk module is supported for:

    • All currently supported versions of Apache Web Server (httpd)
    • Any operating system supported by Apache Web Server
    • All currently supported versions of Tomcat

    The mod_jk module may work with older, unsupported versions of Apache Web Server and/or Tomcat but such configurations are not supported.

    The mod_jk module uses the AJP protocol to send requests to the Tomcat containers. The AJP version used is ajp13. All current versions Tomcat support the ajp13 protocol. Others servlet engines such as Jetty and JBoss also support the ajp13 protocol.

    The ajp12 protocol has been deprecated and you should no longer use it. The ajp14 protocol is considered experimental.

    In a nutshell a web server is waiting for client HTTP requests. When these requests arrive the server does whatever is needed to serve the requests by providing the necessary content.

    Adding a servlet container may somewhat change this behaviour. Now the web server needs also to perform the following:

    • Load the servlet container adaptor library and initialise it (prior to serving requests).
    • When a request arrives, it needs to check and see if a certain request belongs to a servlet, if so it needs to let the adaptor take the request and handle it.

    The adaptor on the other hand needs to know what requests it is going to serve, usually based on some pattern in the request URL, and to where to direct these requests.

    Things are even more complex when the user wants to set a configuration that uses virtual hosts, or when they want multiple developers to work on the same web server but on different servlet container JVMs. We will cover these two cases in the advanced sections.

    mod_jk can be obtained in two formats - binary and source. Depending on the platform you are running your web server on, a binary version of mod_jk may be available.

    It is recommended to use the binary version if one is available. If the binary is not available, follow the instructions given in the below "Building mod_jk" sections for building mod_jk from source. The mod_jk source can be downloaded from a mirror here

    The binaries for mod_jk are now available for several platforms. The binaries are located in subdirectories by platform.

    For some platforms, such as Windows, this is the typical way of obtaining mod_jk since most Windows systems do not have C compilers.

    For others, the binary distribution of mod_jk offers simpler installation.

    For example JK 1.2.x can be downloaded from a mirror here (look for JK 1.2 Binary Releases). The "JK 1.2 Binary Releases" link contains binary version for a variety of operating systems for both Apache 1.3 and Apache 2.x.

    mod_jk requires two entities:

    • mod_jk.xxx - The Apache HTTP Server module, depending on your operating system, it will be mod_jk.so, mod_jk.nlm or MOD_JK.SRVPGM (see the build section).
    • workers.properties - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). A sample workers.properties can be found under the conf directory in the source download.

    Also as with other Apache modules, mod_jk should be first installed on the modules directory of your Apache HTTP Server, ie: /usr/lib/apache and you should update your httpd.conf file.

    If you've previously configured Apache to use mod_jserv, remove any ApJServMount directives from your httpd.conf.

    If you're including tomcat-apache.conf or tomcat.conf, you'll want to remove them as well - they are specific to mod_jserv.

    The mod_jserv configuration directives are not compatible with mod_jk !

    Tomcat auto-configure is deprecated and has been removed in Tomcat 7 and later.

    The auto-configure works only for a single Tomcat running on the same machine where the Apache HTTP Server is running. The simplest way to configure Apache HTTP Server to use mod_jk is to turn on the Apache HTTP Server auto-configure setting in Tomcat and put the following include directive at the end of your Apache httpd.conf file (make sure you replace $TOMCAT_HOME with the correct path for your Tomcat installation:

    # To be added at the end of your httpd.conf Include $TOMCAT_HOME/conf/jk/mod_jk.conf-auto

    Note: this file may also be generated as $TOMCAT_HOME/conf/auto/mod_jk.conf

    This will tell the Apache HTTP Server to use directives in the mod_jk.conf-auto file in the Apache configuration. This file is created by enabling the Apache auto-configuration by creating your workers.properties file at $TOMCAT_HOME/conf/jk/workers.properties and adding the listener to the Engine element in the server.xml file as per the following example. Please note that this example is specific to Tomcat 5.x, unlike other sections of this document which also apply to previous Tomcat branches.

    ... <Engine ...> ... <Listener className="org.apache.jk.config.ApacheConfig" modJk="/path/to/mod_jk.so" /> ... </Engine> ...

    Then restart Tomcat and mod_jk.conf should be generated. For more information on this topic, please refer to the API documentation at the Tomcat docs website.

    You should use custom configuration when:

    • You couldn't use mod_jk.conf-auto since Tomcat engine isn't on the same machine that your Apache web server, ie when you have an Apache in front of a Tomcat Farm.
    • Another case for custom configuration is when your Apache is in front of many different Tomcat engines, each one having it's own configuration, a general case in ISP hosting
    • Also most Apache web masters will retain custom configuration to be able to tune the settings to their real needs.

    Here is a simple configuration:

    # Load mod_jk module LoadModule jk_module modules/mod_jk.so # Add the module (activate this lne for Apache 1.3) # AddModule mod_jk.c # Where to find workers.properties JkWorkersFile /etc/httpd/conf/workers.properties # Where to put jk shared memory JkShmFile /var/log/httpd/mod_jk.shm # Where to put jk logs JkLogFile /var/log/httpd/mod_jk.log # Set the jk log level [debug/error/info] JkLogLevel info # Send requests for context /examples to worker named worker1 JkMount /examples/* worker1

    We'll discuss here the mod_jk directives and details behind them

    JkWorkersFile specify the location where mod_jk will find the workers definitions. JkWorkersFile /etc/httpd/conf/workers.properties

    JkLogFile specify the location where mod_jk is going to place its log file.

    JkLogFile /var/log/httpd/mod_jk.log

    Since JK 1.2.3 for Apache 2.x and JK 1.2.16 for Apache 1.3 this can also be used for piped logging:

    JkLogFile "|/usr/bin/rotatelogs /var/log/httpd/mod_jk.log 86400"

    JkLogLevel set the log level between:

    • info log will contains standard mod_jk activity (default).
    • error log will contains also error reports.
    • debug log will contains all information on mod_jk activity
    JkLogLevel info

    info should be your default selection for normal operations.

    JkLogStampFormat will configure the date/time format found on mod_jk logfile. See the mod_jk Apache HTTP Server reference for details.

    JkLogStampFormat "[%y-%m-%d %H:%M:%S.%Q] "

    You can log mod_jk information using the Apache standard module mod_log_config. The module sets several notes in the Apache notes table. Most of them are are only useful in combination with a load balancer worker. See the mod_jk Apache HTTP Server reference for details.

    LogFormat "%h %l %u %t \"%r\" %>s %b %{JK_WORKER_NAME}n %{JK_LB_FIRST_NAME}n \ %{JK_LB_FIRST_BUSY}n %{JK_LB_LAST_NAME}n %{JK_LB_LAST_BUSY}n" mod_jk_log CustomLog logs/access_log mod_jk_log

    You can also log a request protocol in the mod_jk log file instead of the access log. This is not recommended and mostly a backward compatibility feature. The directive JkRequestLogFormat will configure the format of this protocol. It gets configured and enabled on a per virtual host basis. See the mod_jk Apache HTTP Server reference for details.

    JkRequestLogFormat "%w %V %T"

    The directive JkOptions allow you to set many forwarding options which will enable (+) or disable (-) following option. Without any leading signs, options will be enabled.

    The four following options +ForwardURIxxx are mutually exclusive. Exactly one of them is required, a negative sign prefix is not allowed with them. The default value is "ForwardURIProxy" since version 1.2.24. It was "ForwardURICompatUnparsed" in version 1.2.23 and "ForwardURICompat" until version 1.2.22. You can turn the default off by switching on one of the other two options. You should leave this at it's default value, unless you have a very good reason to change it.

    All options are inherited from the global server to virtual hosts. Options that support enabling (plus options) and disabling (minus options), are inherited in the following way:
    options(vhost) = plus_options(global) - minus_options(global) + plus_options(vhost) - minus_options(vhost)

    Using JkOptions ForwardURIProxy, the forwarded URI will be partially reencoded after processing inside Apache and before forwarding to Tomcat. This will be compatible with local URL manipulation by mod_rewrite and with URL encoded session ids. JkOptions +ForwardURIProxy

    Using JkOptions ForwardURICompatUnparsed, the forwarded URI will be unparsed. It's spec compliant and secure. It will always forward the original request URI, so rewriting URIs with mod_rewrite and then forwarding the rewritten URI will not work. JkOptions +ForwardURICompatUnparsed

    Using JkOptions ForwardURICompat, the forwarded URI will be decoded by Apache. Encoded characters will be decoded and explicit path components like ".." will already be resolved. This is less spec compliant and is not safe if you are using prefix JkMount. This option will allow to rewrite URIs with mod_rewrite before forwarding. JkOptions +ForwardURICompat

    Using JkOptions ForwardURIEscaped, the forwarded URI will be the encoded form of the URI used by ForwardURICompat. Explicit path components like ".." will already be resolved. This will not work in combination with URL encoded session IDs, but it will allow to rewrite URIs with mod_rewrite before forwarding. JkOptions +ForwardURIEscaped

    JkOptions RejectUnsafeURI will block all URLs, which contain percent signs '%' or backslashes '\' after decoding.

    Most web apps do not use such URLs. Using the option RejectUnsafeURI, you can block several well known URL encoding attacks. By default, this option is not set.

    You can also realise such a check with mod_rewrite, which is more powerful but also slightly more complicated. JkOptions +RejectUnsafeURI

    JkOptions CollapseSlashesAll is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions CollapseSlashesUnmount is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions CollapseSlashesNone is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions ForwardDirectories is used in conjunction with DirectoryIndex directive of Apache. As such mod_dir should be available to Apache, statically or dynamically (DSO)

    When DirectoryIndex is configured, Apache will create sub-requests for each of the local-url's specified in the directive, to determine if there is a local file that matches (this is done by stat-ing the file).

    If ForwardDirectories is set to false (default) and Apache doesn't find any files that match, Apache will serve the content of the directory (if directive Options specifies Indexes for that directory) or a 403 Forbidden response (if directive Options doesn't specify Indexes for that directory).

    If ForwardDirectories is set to true and Apache doesn't find any files that match, the request will be forwarded to Tomcat for resolution. This is used in cases when Apache cannot see the index files on the file system for various reasons: Tomcat is running on a different machine, the JSP file has been precompiled etc.

    Note that locally visible files will take precedence over the ones visible only to Tomcat (i.e. if Apache can see the file, that's the one that's going to get served). This is important if there is more then one type of file that Tomcat normally serves - for instance Velocity pages and JSP pages. JkOptions +ForwardDirectories

    Setting JkOptions ForwardLocalAddress, you ask mod_jk to send the local address of the Apache HTTP Server instead of remote client address. This can be used by Tomcat remote address valve for allowing connections only from configured Apache servers. JkOptions +ForwardLocalAddress

    Setting JkOptions ForwardPhysicalAddress, you ask mod_jk to send the physical peer TCP IP address as the client address. By default mod_jk uses the logical address as provided by the web server. For example the module mod_remoteip sets the logical IP address to the client IP forwarded by proxies in the X-Forwarded-For header. JkOptions +ForwardPhysicalAddress

    JkOptions FlushPackets, you ask mod_jk to flush Apache's connection buffer after each AJP packet chunk received from Tomcat. This option can have a strong performance penalty for Apache and Tomcat as writes are performed more often than would normally be required (ie: at the end of each response). JkOptions +FlushPackets

    JkOptions FlushHeader, you ask mod_jk to flush Apache's connection buffer after the response headers have been received from Tomcat. JkOptions +FlushHeader

    JkOptions DisableReuse, you ask mod_jk to close connections immediately after their use. Normally mod_jk uses persistent connections and pools idle connections to reuse them, when new requests have to be sent to Tomcat.

    Using this option will have a strong performance penalty for Apache and Tomcat. Use this only as a last resort in case of unfixable network problems. If a firewall between Apache and Tomcat silently kills idle connections, try to use the worker attribute socket_keepalive in combination with an appropriate TCP keepalive value in your OS. JkOptions +DisableReuse

    JkOptions ForwardKeySize, you ask mod_jk, when using ajp13, to forward also the SSL Key Size as required by Servlet API 2.3. This flag shouldn't be set when servlet engine is Tomcat 3.2.x (off by default). JkOptions +ForwardKeySize

    JkOptions ForwardSSLCertChain, you ask mod_jk, when using ajp13, to forward SSL certificate chain (off by default). Mod_jk only passes the SSL_CLIENT_CERT to the AJP connector. This is not a problem with self-signed certificates or certificates directly signed by the root CA certificate. However, there's a large number of certificates signed by an intermediate CA certificate, where this is a significant problem: A servlet will not have the possibility to validate the client certificate on its own. The bug would be fixed by passing on the SSL_CLIENT_CERT_CHAIN to Tomcat via the AJP connector.
    This directive exists only since version 1.2.22. JkOptions +ForwardSSLCertChain

    The directive JkEnvVar allows you to forward environment variables from Apache server to Tomcat engine. You can add a default value as a second parameter to the directive. If the default value is not given explicitly, the variable will only be send, if it is set during runtime.
    The variables can be retrieved on the Tomcat side as request attributes via request.getAttribute(attributeName). Note that the variables send via JkEnvVar will not be listed in request.getAttributeNames().
    The variables are inherited from the global server to virtual hosts. JkEnvVar SSL_CLIENT_V_START undefined

    If you have created a custom or local version of mod_jk.conf-local as noted above, you can change settings such as the workers or URL prefix.

    JkMount directive assign specific URLs to Tomcat. In general the structure of a JkMount directive is:

    JkMount [URL prefix] [Worker name] # send all requests ending in .jsp to worker1 JkMount /*.jsp worker1 # send all requests ending /servlet to worker1 JkMount /*/servlet/ worker1 # send all requests jsp requests to files located in /otherworker will go worker2 JkMount /otherworker/*.jsp worker2

    You can use the JkMount directive at the top level or inside <VirtualHost> sections of your httpd.conf file.

    If the Tomcat Host appBase (webapps) directory is accessible by the Apache HTTP Server, Apache can be configured to serve web application context directory static files instead of passing the request to Tomcat.

    Caution: For security reasons it is strongly recommended that JkMount is used to pass all requests to Tomcat by default and JkUnMount is used to explicitly exclude static content to be served by Apache. It should also be noted that content served by Apache will bypass any security constraints defined in the application's web.xml.

    Use Apache's Alias directive to map a single web application context directory into Apache's document space for a VirtualHost:

    # Static files in the examples webapp are served by Apache Alias /examples /vat/tomcat3/webapps/examples # All requests go to worker1 by default JkMount /* worker1 # Serve html, jpg and gif using Apache JkUnMount /*.html worker1 JkUnMount /*.jpg worker1 JkUnMount /*.gif worker1

    Starting with mod_jk 1.2.6 for Apache 2.x and 1.2.19 for Apache 1.3, it's possible to exclude some URL/URI from jk processing by setting the env var no-jk, for example with the SetEnvIf Directive.

    You could use no-jk env var to fix problem with mod_alias or mod_userdir directive when jk and alias/userdir URLs matches.

    # All URL goes to tomcat except the one containing /home <VirtualHost *:80> ServerName testxxx.mysys DocumentRoot /www/testxxx/htdocs # Use SetEnvIf to set no-jk when /home/ is encountered SetEnvIf Request_URI "/home/*" no-jk # Now /home will goes to /home/dataxxx/ Alias /home /home/dataxxx/ <Directory "/home/dataxxx"> Options Indexes MultiViews AllowOverride None Require all granted </Directory> JkMount /* myssys-xxx </VirtualHost>

    Use the mod_jk JkAutoAlias directive to map all web application context directories into Apache's document space.

    Attempts to access the WEB-INF or META-INF directories within a web application context or a Web Archive *.war within the Tomcat Host appBase (webapps) directory will fail with an HTTP 403, Access Forbidden

    # Static files in all Tomcat webapp context directories are served by Apache JkAutoAlias /var/tomcat3/webapps # All requests go to worker1 by default JkMount /* ajp13 # Serve html, jpg and gif using Apache JkUnMount /*.html ajp13 JkUnMount /*.jpg ajp13 JkUnMount /*.gif ajp13

    If you encoded all your URLs to contain the session id (;jsessionid=...), and you later decide, you want to move part of the content to Apache, you can tell mod_jk to strip off all session ids from URLs for those requests, that do not get forwarded via mod_jk.

    You enable this feature by setting JkStripSession to On. It can be enabled individually for virtual servers. The default value is Off.

    The mod_jk build use the widely used configure system.

    In case you get source from subversion, ie without an existing configure script, you should have autoconf for configuration and installation.

    To create the mod_jk autoconf script, you will need libtool 1.5.2, automake 1.10 and autoconf 2.59 or newer. The use of more recent versions is encouraged, e.g. for reliable detection of the features of recent version of operating systems.

    Those tools will not be required if you are just using a package downloaded from apache.org, they are only required for developers.

    To create the configure script just type: ./buildconf.sh

    Here's how to use configure to prepare mod_jk for building, just type: ./configure [autoconf arguments] [mod_jk arguments]

    You could set CFLAGS and LDFLAGS to add some platform specifics:

    LDFLAGS=-lc ./configure -with-apxs=/home2/local/apache/bin/apxs

    If you want to build mod_jk for different versions of the Apache HTTP Server, like 1.3 or 2.x, you need to go through the full build process for each of them. Please note, that Apache 2.0, 2.2 or 2.4 modules are not binary compatible. You have to compile the module using the Apache version you plan to run it in. The mod_jk build directory used is "apache-2.0" for all 2.x builds. The source code is compatible with Apache HTTP Server 2.0, 2.2 and 2.4.

    • use configure and indicate the correct Apache HTTP Server apxs location (--with-apxs)
    • use make
    • copy the resulting mod_jk.so binary from the apache-1.3 or apache-2.0 subdirectory to the Apache HTTP Server modules location.
    • make clean (to remove all previously compiled object files)
    • Start over with the apxs location for your next Apache HTTP Server version.

    Apache related parameters
    --with-apxs[=FILE] FILE is the location of the apxs tool. Default is finding apxs in PATH. It builds a shared Apache module. It detects automatically the Apache version. (2.x and 1.3)
    --with-apache=DIR DIR is the path where Apache sources are located. The Apache sources should have been configured before configuring mod_jk. DIR is something like: /home/apache/apache_1.3.19 It builds a static Apache module.
    --enable-EAPI This parameter is needed when using Apache-1.3 and mod_ssl, otherwise you will get the error message: "this module might crash under EAPI!" when loading mod_jk.so in Apache. Not needed when --with-apxs has been used
    --enable-prefork In case you build mod_jk for a multi-threaded Apache HTTP Server 2.x MPM (Multi-Processing Module), some areas of mod_jk code need to be synchronised to make it thread-safe. Because configure can not easily detect, whether your are using a multi-threaded MPM, mod_jk by default is always build thread-safe for Apache HTTP Server 2.x. If you are sure, that your MPM is not multi-threaded, you can use "--enable-prefork" to force the removal of the synchronisation code (thus increasing performance a bit). For instance, the prefork MPM is not multi-threaded. For Apache HTTP Server 1.3 this flag will be set automatically.
    --disable-trace When using log level "trace", mod_jk traces a lot of function calls with "enter" and "exit" log messages. Even if the log level is not "trace", comparing the log levels to decide about logging has some performance impact.
    If you use "--disable-trace", then the trace log code doesn't get compiled into the module binary and you might save some cycles during execution.
    Even with "--disable-trace" logging debug messages with debug log level will still be possible.
    --enable-api-compatibility Only use Apache API functions available in all Apache production releases of the chosen major Apache release branch. This improves binary compatibility of module builds with Apache releases older than the release against mod_jk is build (only between minor Apache versions).
    --enable-flock In case the operating system supports flock system call use this flag to enable this faster locks that are implemented as system call instead emulated by GNU C library.
    However those locks does not work on NFS mounted volumes, so you can use "--enable-flock" during compile time to force the flocks() calls.

    Apache 1.3 and 2.x build ./configure --with-apxs=/usr/sbin/apxs
    make
    cp ./apache-1.3/mod_jk.so /usr/lib/apache
    make clean
    ./configure --with-apxs=/usr/sbin/apxs2
    make
    cp ./apache-2.0/mod_jk.so /usr/lib/apache2

    The module was developed using Microsoft Visual C++, so having Visual Studio installed is a prerequisite if you want to perform your own build.

    You can build the source using the IDE GUI, or using a pure commandline build based on nmake. The IDE build currently only supports building 32 Bit binaries. The nmake builds are available for 32 Bit and 64 Bit binaries.

    The common steps for all build procedures are:

    • Set up your build environment for 32 Bits or 64 Bits. The IDE build only supports 32 Bits.
    • Download the sources as a zip file and unpack it.
    • Change directory to the ISAPI redirector source directory.
    • Set your path to the Apache web server directory in your environment.
    Set up 32 or 64 Bit build environment setenv /Release /X86 or (not available for IDE build) setenv /Release /X64 Download tomcat-connectors-xxx-src.zip from https://tomcat.apache.org/download-connectors.cgi and unpack it unzip tomcat-connectors-xxx-src.zip Change directory to the mod_jk source directory. To build mod_jk for the Apache HTTP server 2.0, 2.2 or 2.4, use the "apache-2.0" directory, for the old Apache HTTP server 1.3, the "apache-1.3" directory. cd tomcat-connectors-xxx-src\native\apache-2.0 Set the environment variable "APACHE1_HOME" resp. "APACHE2_HOME" resp. "APACHE22_HOME" resp. "APACHE24_HOME" to the installation path of your Apache web server. set APACHE24_HOME=D:\software\Apache\httpd-2.4.16

    The steps for an IDE build are then:

    • Start Visual Studio using "start mod_jk.dsp"
    • During IDE startup choose "Yes" in all conversion popups.
    • Next choose a Configuration form the dropdown. There are pre-defined configurations for debug and release builds and in the "apache-2.0" directory each of them is available as a configuration to build against the web server versions 2.0, 2.2 and 2.4.
    • Finally choose "Build Solution" in the "Build" menu.
    The resulting file mod_jk.so (and the debug symbol file mod_jk.pdb) is located in the "Debug" resp. "Release" sub directory depending on the build Configuration chosen. For the "apache-2.0" module the directories are named "Debug_20", "Release_20", "Debug_22", "Release_22", "Debug_24" and "Release_24" depending on the chosen build configuration.

    Alternatively the steps for an nmake commandline build are:

    • Set your target architecture to X86 or X64 by editing the "ARCH=" line in the file Makefile.vc.
    • Issue "nmake -f Makefile.vc"
    The resulting file mod_jk.so (and the debug symbol file mod_jk.pdb) is located in the "Debug" resp. "Release" sub directory depending on the build Configuration chosen. For the "apache-2.0" module the directories are named "Debug_20", "Release_20", "Debug_22", "Release_22", "Debug_24" and "Release_24" depending on the chosen build configuration.

    Finally you need to copy the file mod_jk.so to the modules directory of your Apache HTTP server (resp. the libexec directory for the old Apache 1.3).

    For Apache HTTP Server 1.3, ApacheCore.lib is expected to exist before linking mod_jk will succeed.

    Since OS400 V4R5, System I (AS/400) has used Apache 2.0 as their primary web server, replacing the old IBM web server. It's now possible to build mod_jk on System I thanks to the help of the IBM Rochester Labs which has provided information and patches to adapt mod_jk to i5/OS.

    You should have at least Apache 2.0.58 (product 5722DG1), a C Compiler and IFS. Apache 2.0.58 is provided with the most recent set of PTFs for the iSeries Apache server, which can be found at http://www.ibm.com/servers/eserver/iseries/software/http/

    The all latest Apache 2 for i5/OS V5R3 (or V5R4) is now 2.0.58 (as of 2007/04/17). Be sure to have the latest PTFs loaded if you want to make use of jk 1.2.15 and higher. NB: The latest mod_jk known to work on i5/OS V5R3 was 1.2.19.

    New in i5/OS V5R4, UTF is required, also for Apache modules, as such Apache modules do not require translations to/from EBCDIC but works should be done to port mod_jk 1.2.23 (and higher) to V5R4. From the V5R4 Infocenter: As of i5/OS(tm) V5R4, modules must be recompiled with a UTF locale. This creates an environment where locale-dependent C runtime functions assume that string data is encoded in UTF-8. Any hardcoded constants can be encoded in UTF-8 by adding a #pragma convert(1208) statement in the module. Additionally, input data from the client will no longer be converted to EBCDIC but will be passed as-is. Output data sent from the module is not converted either so it must be encoded in ASCII or UTF8 as required. APR and HTTP APIs as of V5R4, expect data in UTF-8. Note that several APIs have additional functions that allow a CCSID to be set to indicate the encoding of the parameters being passed. Conversion functions between UTF-8 and EBCDIC have been added. Be sure to review APIs used by your module to be aware of current changes.

    To configure mod_jk on System I use the CL source provided with the mod_jk source.

    • Get the latest mod_jk source and untar it on a Windows or Unix boxes
    • Create a directory in IFS, ie /home/apache
    • Send the whole jk source directory to System I directory via FTP.
    • Then go to the System I command line:
    Create mod_jk library CRTLIB MOD_JK TEXT(‘Apache mod'jk tomcat connector module') Create service program source file CRTSRCPF MOD_JK/QSRVSRC TEXT(‘Service program source file’) Create the CL build program source file CRTSRCPF FILE(MOD_JK/QCLSRC) TEXT(‘Build program source file’) Edit the service program source file STRSEU MOD_JK/QSRVSRC MOD_JK

    In the edited file, specify that only jk_module should be exported: Columns . . : 1 71 Edit MOD_JK/QSRVSRC SEU==> MOD_JK *************** Beginning of data ************************************* 0001.00 STRPGMEXP PGMLVL(*CURRENT) 0002.00 EXPORT SYMBOL("jk_module") 0003.00 ENDPGMEXP ****************** End of data ****************************************

    You could start to build all the modules of mod_jk (cases for V5R4 or previous releases):

    Copy the CL build program source for i5/OS before V5R4 from IFS CPYFRMSTMF FROMSTMF('/home/apache/jk/native/apache-2.0/bldjk.qclsrc') + TOMBR('/QSYS.LIB/MOD_JK.LIB/QCLSRC.FILE/BLDJK.MBR') MBROPT(*REPLACE) Build the CL build program CRTCLPGM PGM(MOD_JK/BLDJK) SRCFILE(MOD_JK/QCLSRC) TEXT('Apache mod_jk build program') Launch the build CALL MOD_JK/BLDJK
    If the build if successfull, copy the new mod_jk module CRTDUPOBJ OBJ(MOD_JK) FROMLIB(MOD_JK) OBJTYPE(*SRVPGM) TOLIB(QHTTPSVR) NEWOBJ(MOD_JK)
    Copy the CL build program source for i5/OS V5R4 from IFS CPYFRMSTMF FROMSTMF('/home/apache/jk/native/apache-2.0/bldjk54.qclsrc') + TOMBR('/QSYS.LIB/MOD_JK.LIB/QCLSRC.FILE/BLDJK54.MBR') MBROPT(*REPLACE) Build the CL build program for i5/OS V5R4 CRTCLPGM PGM(MOD_JK/BLDJK54) SRCFILE(MOD_JK/QCLSRC) TEXT('Apache mod_jk build program') TGTRLS(*CURRENT) Launch the build for i5/OS V5R4 CALL MOD_JK/BLDJK54
    If the build if successfull, copy the new mod_jk module CRTDUPOBJ OBJ(MOD_JK) FROMLIB(MOD_JK) OBJTYPE(*SRVPGM) TOLIB(QHTTPSVR) NEWOBJ(MOD_JK)

    Next, you should restart your Apache 2.0 instance and enjoy this piece of OpenSource on System I.

    ENDTCPSVR SERVER(*HTTP) HTTPSVR(MYSERVER) STRTCPSVR SERVER(*HTTP) HTTPSVR(MYSERVER)

    Mac OS X (10.2.x) build notes:

    Assuming that you are root:

    For Apache 1.3: ./configure --with-apxs=/usr/sbin/apxs cd apache-1.3 make -f Makefile.apxs cp mod_jk.so /etc/libexec/httpd For Apache 2.x: ./configure --with-apxs=/usr/local/apache2/bin/apxs (you should point to the directory where you installed Apache 2.x) cd apache-2.0 make -f Makefile.apxs install

    mod_jk allows to install mod_jk in the Apache source tree to get a statically linked mod_jk. Having mod_jk in the Apache executable brings some small performance improvements. The configure option --with-apache prepare mod_jk to install it in the Apache source tree. The option --with-apache works both for Apache 1.3 and Apache 2.x. The examples below show how to get mod_jk in the Apache process.

    /home/apache24/httpd-2.4.12 is the directory where the Apache HTTP Server sources are located. ./configure --with-apache=/home/apache24/httpd-2.4.12
    make
    Install the mod_jk library and other files in /home/apache24/httpd-2.4.12/modules: make install
    It is not possible to configure Apache directly because the config.m4 of mod_jk must be added to the configure of httpd-2.x. cd /home/apache24/httpd-2.4.12 sh buildconf configure ... --with-mod_jk make make install

    The enable-jk=share and enable-jk=static are not supported. --with-mod_jk only allow static linking of mod_jk.

    /home/apache/apache_1.3.27 is the directory where the apache-1.3 sources are located. ./configure --with-apache=/home/apache/apache_1.3.27
    make
    Install the libjk library, mod_jk.c, includes and other files in /home/apache/apache_1.3.27/src/modules/jk: make install
    Configure in the Apache sources: cd /home/apache/apache_1.3.27 configure ... --enable-module=dir --disable-shared=dir \ --activate-module=src/modules/jk/libjk.a \ --disable-shared=jk make make install

    The --enable-shared=jk is also working and builds a dso file.

    Just change the configure in the Apache sources: configure ... --enable-module=dir --enable-shared=dir \ --activate-module=src/modules/jk/libjk.a \ --enable-shared=jk
    tomcat-connectors-1.2.50-src/xdocs/webserver_howto/iis.xml0000644000000000000020000006005614655113617022205 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ISAPI redirector for Micrsoft IIS HowTo Henri Gomez Gal Shachor Yoav Shapira

    This document explains how to set up the ISAPI redirector for IIS to cooperate with Tomcat.

    Normally IIS can not execute Servlets and Java Server Pages (JSPs). Configuring IIS to use the ISAPI redirector plugin will let IIS send servlet and JSP requests to Tomcat (and this way, serve them to clients).

    It is recommended that you also read the Workers HowTo document to learn how to setup the working entities between your web server and Tomcat Engines. For more detailed configuration information consult the Reference Guide for workers.properties, uriworkermap and IIS.

    ${tomcat_home} is the root directory of tomcat. Your Tomcat installation should have the following subdirectories:

    • ${tomcat_home}\conf - Where you can place various configuration files
    • ${tomcat_home}\webapps - Containing example applications
    • ${tomcat_home}\bin - Where you place web server plugins

    In all the examples in this document ${tomcat_home} will be c:\tomcat. A worker is defined to be a tomcat process that accepts work from the IIS server.

    The IIS to Tomcat redirector is supported for:

    • IIS running on any currently supported version of Windows
    • All currently supported versions of Tomcat

    The redirector may work with IIS running on older, unsupported versions of Windows and/or Tomcat but such configurations are not supported.

    The redirector uses the AJP protocol to send requests to the Tomcat containers. The AJP version used is ajp13. All current versions Tomcat support the ajp13 protocol. Others servlet engines such as Jetty and JBoss also support the ajp13 protocol.

    The ajp12 protocol has been deprecated and you should no longer use it. The ajp14 protocol is considered experimental.

    1. The ISAPI redirector is a Microsoft IIS plugin (filter + extension). IIS loads the redirector plugin and calls its filter function for each in-coming request.
    2. The filter then tests the request URL against a list of URI-paths held inside uriworkermap.properties. If the current request matches one of the entries in the list of URI-paths, the filter transfers the request to the extension.
    3. The extension collects the request parameters and forwards them to the appropriate worker using the defined protocol like ajp13.
    4. The extension collects the response from the worker and returns it to the browser.

    Pre-built versions of the ISAPI redirector plugin, isapi_redirect.dll, for 32-bit and 64-bit environments are available from the Apache Tomcat Connectors Downloads page. You can also build a copy locally from the Tomcat Connectors source distribution. The ISAPI redirector requires three entities:

    • isapi_redirect.dll - The ISAPI redirector for Microsoft IIS plugin, either obtain a pre-built DLL or build it yourself (see the build section).
    • workers.properties - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). A sample workers.properties can be found under the conf directory.
    • uriworkermap.properties - A file that maps URL-Path patterns to workers. A sample uriworkermap.properties can be found under the conf directory as well.

    The installation includes the following parts:

    • Configuring the ISAPI redirector with a default /examples context and checking that you can serve servlets with IIS.
    • Adding more contexts to the configuration.

    These instructions have been written based on Windows Server 2012 R2 and tested with all supported Windows operating systems up to Windows 11 / Windows Server 2022.

    These installation instructions have been tested with a default installation of IIS plus ISAPI Extensions and Filters on a clean, fully patched OS installation with Tomcat 9 installed in C:\Program Files\Apache Software Foundation\Tomcat 9.0. This is referred to as ${tomcat_home} for the remainder of this document.

    1. Create a directory ${tomcat_home}\isapi
    2. Allow the IIS process to create the ISAPI redirector log file. Modify the path as necessary if the log file is to be written to a different directory. Enter the following at a command prompt: >icacls "C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi" /grant "IIS APPPOOL\DefaultAppPool":(OI)(CI)M On client operating systems with User Account Control (UAC) enabled, the command prompt must be opened using Run as administrator for the above command to complete successfully.
    3. Download the appropriate (32-bit or 64-bit) isapi_redirect.dll for your operating system and place it in ${tomcat_home}\isapi
    4. Set the premissions for isapi_redirect.dll. On Windows Server 2019 it appears to be necessary to explicitly set the permissions for this dll. Enter the following at a command prompt: >icacls "C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi\isapi_redirect.dll" /grant "Everyone":RX
    5. Create ${tomcat_home}\isapi\isapi_redirect.properties file to configure the ISAPI redirctor. Configuration can also be performed via registry settings - see below. The contents of this file should be: extension_uri=/jakarta/isapi_redirect.dll log_file=C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi\isapi_redirect.log log_level=info worker_file=C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi\workers.properties worker_mount_file=C:\Program Files\Apache Software Foundation\Tomcat 9.0\isapi\uriworkermap.properties Be careful so that Windows does not add a .txt extension to the file.
    6. Create ${tomcat_home}\isapi\workers.properties file to configure the Tomcat instances that requests will be passed to. For a single Tomcat instance on the local machine the contents of this file should be: worker.list=tomcat01 worker.tomcat01.type=ajp13 worker.tomcat01.host=localhost worker.tomcat01.port=8009
    7. Create ${tomcat_home}\isapi\uriworkermap.properties file to configure which requests will be passed to Tomcat. To expose the examples web application the contents of this file should be: /examples/*=tomcat01
    8. Using the IIS management console, add a new virtual directory to your IIS web site. In a clean install, this will be the Default Web Site. The name of the virtual directory must be jakarta. Its physical path should be the directory where you placed isapi_redirect.dll.
    9. Select the newly created virtual directory in the management console and then double-click Handler Mappings. Select the (currently disabled) ISAPI-dll entry and then click Edit Feature Permissions in the action pane. In the dialog box that opens, select Execute so all three permissions are selected. Click OK and ISAPI-dll should now be in the enabled state.
    10. Again using the IIS management console, add the ISAPI redirector as a filter to your web site. Select your web site and then double-click ISAPI Filters. From the action pane, click Add.... For the filter name use tomcat and the executable should be the full path to isapi_redirect.dll. Once configured, click OK.
    11. Still using the IIS management console, configure the ISAPI redirector as allowed. Select your server (not the web site) and then double-click on ISAPI and CGI Restrictions. From the action pane, click Add.... Select the isapi_redirect.dll, add a descripion (e.g. tomcat) and select the Allow extension path to execute and then click OK.
    12. Restart IIS (stop + start the IIS service).

    That's all, you should now start Tomcat and ask IIS to serve you the /examples context. Try http://localhost/examples/ for example and execute some of the Servlet or JSP examples.

    If this does not work successfully, refer to the Troubleshooting section below for help on correcting the problem.

    If the IIS access logs show entries such as /jakarta/isapi_redirect.dll rather than /examples/servlets then this can be corrected via the IIS management console. Select your server (not the web site) and then double-click on Modules. In the Actions pane, click View Ordered List..., select the IsapiFilterModule and move it up until it is above the HttpLoggingModule.

    As an alternative to using the isapi_redirector.properties file, the ISAPI redirector may be configured via the registry. To do this, follow these steps:

    1. In the registry, create a new registry key named "HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0"
    2. Add a string value with the name extension_uri and a value of /jakarta/isapi_redirect.dll
    3. Add a string value with the name log_file and a value pointing to where you want your log file to be (for example c:\tomcat\logs\isapi.log).
    4. Add a string value with the name log_level and a value for your log level (can be debug, info, error or emerg).
    5. Add a string value with the name worker_file and a value which is the full path to your workers.properties file (for example c:\tomcat\conf\workers.properties)
    6. Add a string value with the name worker_mount_file and a value which is the full path to your uriworkermap.properties file (for example c:\tomcat\conf\uriworkermap.properties)

    In a 64-bit environment the IIS Application Pool should have "Enable 32-bit Applications" set to "False". To check this, select Application Pools in the IIS management console, then right-click on the pool you are using and select Set Application Pool Defaults.... Enable 32-bit Applications may be found in the General section. If this is not configured correctly, the redirector will not be called and IIS will return an HTTP code 404.

    You must use the 64-bit version of the ISAPI redirector on 64-bit operating systems. If you attempt to use the 32-bit version, you will get an HTTP code 500 for every request because the library is not loadable into a 64-bit IIS.

    The examples context is useful for verifying your installation, but you will also need to add your own contexts. Adding a new context requires two operations:

    1. Adding the context to Tomcat (not discussed here).
    2. Adding the context to the ISAPI redirector.

    Adding a context to the ISAPI redirector is simple, all you need to do is to edit your uriworkermap.properties and to add a line that looks like:

    /context/*=worker_name

    Workers and their name are defined in workers.properties. As an example, if you want to add a context named "shop", to be served by the worker named "tomcat01" the line that you should add to uriworkermap.properties will be:

    /shop/*=tomcat01 After saving uriworkermap.properties restart IIS and it will serve the new context.

    The above should be all you need for IIS to pass through to Tomcat any request for any URI which corresponds to a Tomcat context (webapp).

    If your website is very busy (more than 100 requests/second, or more than 100 simultaneous client connections), it might sometimes be desirable to have IIS serve static content (html, gif, jpeg etc.) directly, even if these files are part of a context served by Tomcat. Allowing IIS to serve such files directly may avoid the small overhead consisting of passing the request to Tomcat via the redirector, and may free up Tomcat somewhat, by using it only to process requests that only Tomcat can handle (e.g. requests to JSP pages and java servlets).

    For example, consider the html and gif files in the examples context: you could serve these files directly with IIS; there is no need to serve them from the Tomcat process.

    However, you should be very careful when you implement the following configuration style, because by doing so you are in fact providing a "back-door" to IIS, and allowing it to serve files out of a Tomcat context without Tomcat's knowledge, thus bypassing any security restrictions which Tomcat itself and the Tomcat context (webapp) may place on those files.

    Making IIS serve static files that are part of the Tomcat contexts requires the following:

    1. Configuring IIS to know about the Tomcat contexts
    2. Configuring the redirector to leave the static files for IIS

    Adding a Tomcat context to IIS requires the addition of a new IIS virtual directory that covers the Tomcat context. For example adding a /example IIS virtual directory that covers the c:\tomcat\webapps\examples directory.

    Configuring the redirector is somewhat harder, you will need to specify the exact URL-Path pattern(s) which you want Tomcat to handle (usually only JSP files and servlets). This requires a change to the uriworkermap.properties: For the examples context it requires to replace the following line /examples/*=tomcat01 with the following two lines /examples/*.jsp=tomcat01 /examples/servlet/*=tomcat01

    As you can see the second configuration is more explicit, it actually instruct the redirector to redirect only requests to resources under /examples/servlet/ and resources under /examples/ whose name ends with .jsp.

    You can even be more explicit and provide lines such as: /example/servlets/chat=tomcat01

    that instructs the redirector to redirect all requests whose URL-path matches the leading string "/example/servlets/chat" to the worker named tomcat01.

    Once again, be aware that by allowing IIS to access the content of your Tomcat context directly, you are potentially bypassing Tomcat's protection of that content. You should thus make sure to protect this content at the IIS level if needed, by using the corresponding IIS management console functions.

    In particular, each servlet application (context) has a special directory named WEB-INF, which contains sensitive configuration data and Java classes, and which should always be kept hidden from web users. Using the IIS management console it is possible to protect the WEB-INF directory from user access, but considering that this is a general requirement, and considering that it is easy to forget to implement this protection at the IIS level, the ISAPI redirector plugin does it automatically for you, and it will reject any request which contains WEB-INF in its URL path. It will also reject any request which contains META-INF in its URL path.

    Sometimes you may want to serve different contexts with different Tomcat processes (for example to spread the load among different machines). To achieve such a goal you will need to define several workers and assign each context to its own worker.

    Defining additional workers is done in the workers.properties file. This file includes two types of entries:

    # An entry that lists all the workers defined worker.list=worker1, worker2 # Entries that define the host and port associated with each of these workers worker.worker1.host=localhost worker.worker1.port=8009 worker.worker1.type=ajp13 worker.worker2.host=otherhost worker.worker2.port=8009 worker.worker2.type=ajp13

    The above example defined two workers, now we can use these workers to serve two different contexts each with its own worker: example uriworkermap.properties fragment /examples/*=worker1 /webpages/*=worker2

    As you can see the examples context is served by worker1 while the webpages context is served by worker2.

    More information on using and configuring workers in the Workers HowTo and in the worker.properties configuration reference.

    To build the ISAPI redirector you will need Mladen's Custom Microsoft Compiler. The remainder of this document assumes this installed to c:\cmsc.

    The steps to build the ISAPI redirector are:

    • Download the sources as a zip file and unpack it.
    • Change directory to the ISAPI redirector source directory.
    • c:\cmsc\setenv.bat x86 nmake -f Makefile.vc c:\cmsc\setenv.bat x64 nmake -f Makefile.vc

    The resulting file isapi_redirect.dll (and the debug symbol file isapi_redirect.pdb) is located in the "x86_RELEASE" or "x64_RELEASE" sub directory.

    It is easy to have the ISAPI redirector not work the first time you try to install it.

    If this happens to you, here are some steps to follow to try to correct the problem.

    These steps aren't guaranteed to cover all possible problems, but they should help find the typical mistakes.

    If you make any corrections during these steps, restart the IIS service as described above in the last step of the installation, then retry the step.

    Note: These steps are based on the configuration used in the installation instructions that proxies requests for the examples web application to a single Tomcat instance. It is also assumed that the "/examples" context works correctly if you access Tomcat directly.

    Delete (or move elsewhere) the ISAPI redirector log file if present.

    Start the IIS service and Tomcat.

    Check for the presence of the ISAPI redirector log file at the specified location. If not found, that indicates that the ISAPI redirector has not started correctly. This is usually caused by incorrect configuration settings.

    • Check your configuration carefully against the installation instructions, particularly the location, name and contents of the ${tomcat_home}\isapi\isapi_redirect.properties file.
    • If using the registry based configuration, check the path, name and values of the registry keys. Registry names are not case sensitive.
    • Check that the directory specified for the log file exists and that the file permissions have been configured as per the installation instructions.
    If the above are set correctly, the ISAPI redirector should be able to create the log file.

    Invoke the URL http://localhost/examples/ in your browser. Case is important in URLs. The characters following "localhost" in the URL must be lower case. If the page fails to appear, stop the IIS service (required to view the IIS log file). Then examine the last line in the IIS log file in found in C:\inetpub\logs\LogFiles\W3SVC1:

    If the last line contains: GET "/examples/ HTTP/1.1" 404 then the ISAPI redirector is not recognising that it should be handling requests for the "/examples" context.

    If the last line contains something like: GET "/jakarta/isapi_redirect.dll HTTP1.1" then the ISAPI redirector is recognising that it should handle the request, but is not successful at getting Tomcat to service the request.

    Check the following:

    • Check your configuration carefully against the installation instructions, particularly the name of the virtual directory and the location, name and contents of the ${tomcat_home}\isapi\uriworkermap.properties and ${tomcat_home}\isapi\workers.properties files.
    • If these are set correctly, the ISAPI redirector should recognise that it should handle requests for the "/examples" context.

    If the browser shows a 503 error page then the ISAPI redirector is recognising that it should handle the request but is not receiving a timely response from Tomcat. Check the following:

    • Check your configuration carefully against the installation instructions, particularly the location, name and ${tomcat_home}\isapi\workers.properties file.
    • Check the AJP connector configuration in Tomcta matches the configuration in the ${tomcat_home}\isapi\workers.properties file.

    If the browser shows a 500 error page then an internal error has occurred within IIS or the ISAPI redirector when trying to serve the request. There should be a textual description of the error towards the top of the page and an 8-digit hex error code towards the end of the page. The last four digits should be the standard windows error code associated with the problem.

    A common cause of 500 errors is Windows creating configuration files with hidden ".txt" file extensions that are not shown in Windows Explorer. Even if file extensions are shown for other files, double check to make sure that Windows Explorer is configured to show file extensions for all files.

    If the error message is Calling GetFilterVersion on ISAPI filter "...isapi_redirect.dll" failed and the code is 0x8007047e then the code translates to an error code 0x047e or 1150 which is "The specified program requires a newer version of Windows". Together these indicate that the initialisation of the ISAPI redirector failed because the configuration could not be read - either from ${tomcat_home}\isapi\isapi_redirect.properties of from the registry. Check the name location and contents of the ${tomcat_home}\isapi\isapi_redirect.properties file or the registry keys as appropriate.

    If the above settings are correct, the index.html page should appear in your browser. You should also be able to click the links to execute some Servlet or JSP examples.

    tomcat-connectors-1.2.50-src/xdocs/build.xml0000644000000000000020000002015614655113617017271 0ustar rootbin tomcat-connectors-1.2.50-src/xdocs/miscellaneous/0000755000000000000020000000000014655113617020307 5ustar rootbintomcat-connectors-1.2.50-src/xdocs/miscellaneous/project.xml0000644000000000000020000001227614655113617022507 0ustar rootbin The Apache Tomcat Connectors - Miscellaneous Documentation The Apache Tomcat Connectors - Miscellaneous Documentation tomcat-connectors-1.2.50-src/xdocs/miscellaneous/doccontrib.xml0000644000000000000020000002265714655113617023173 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. How to Contribute to the Documentation Robert Sowders

    This document describes how you can easily contribute to the documentation. I'm going to try to make it easy for everyone to help out with the documentation of Tomcat, more specifically the documentation for the connectors. This is written from a windows user perspective as I believe they will most benefit from it. For people using Unix it should be easy for them to apply these steps. Just substitute Unix syntax where needed.

    The documentation is produced using xml with xsl style sheets. This effectivly seperates the content of the documents from the style, so all that contributers need to worry about the content. It is much easier to use than html.

    It's all really quite simple. Here is what you will need:

    • A recent version of Ant
    • The source code for the connectors from subversion
    • Any ascii text editor

    After you get these tools they are simple to set up.

    Install Ant. The only advice I have is to choose a simple installation path. Now set an environment variable for ANT_HOME, and then add the location of the Ant/bin directory to your PATH variable. Consult your Operating system documentation for information on how to do this. When you are finished verify that you can run ant from the command line.

    Ant is used to build the documentation, among other things, and it must be able to see a file called build.xml. This file is located in the xdocs directory. In the build.xml file there is a target named all that will be used to build the docs.

    Get the sources for tomcat-connectors from the git repository. You will need a git client. Install the client of your choice, if you don't already have one.

    You are ready to download the sources now. Change directory to the location where you want your repository to be. For simplicity we will call this your GIT_HOME. Mine is located in C:\build.

    Run the following command to clone the sources for the first time. You should only need to do this once. C:\build\>git clone https://github.com/apache/tomcat-connectors tomcat-connectors

    You should now be watching all the downloads come in. Now that you have the sources on your machine the hard part is over. From now on, to update your sources all you have to do is cd into any directory in your repository and run the git pull command.

    Open a command prompt window and cd to the directory where you downloaded the source. Now cd into the xdocs directory so that Ant can see the build.xml file. Then from a command prompt, run the following: C:\build\tomcat-connectors> cd xdocs C:\build\tomcat-connectors\xdocs> ant all

    .

    You should see the ant compiler messages scrolling by rapidly and then stop with the following: [style] Transforming into C:\build\tomcat-connectors\build\docs\news\printer> [style] Processing C:\build\tomcat-connectors\xdocs\news\20041100.xml to C:\build\tomcat-connectors\build\docs\news/20041100.html [style] Loading stylesheet C:\build\tomcat-connectors\xdocs\style.xsl [style] Processing C:\build\tomcat-connectors\xdocs\news\20050101.xml to C:\build\tomcat-connectors\build\docs\news/20050101.html [style] Processing C:\build\tomcat-connectors\xdocs\news\20060101.xml to C:\build\tomcat-connectors\build\docs\news/20060101.html [style] Transforming into C:\build\tomcat-connectors\build\docs> [style] Processing C:\build\tomcat-connectors\xdocs\index.xml to C:\build\tomcat-connectors\build\docs\index.html [style] Loading stylesheet C:\build\tomcat-connectors\xdocs\style.xsl BUILD SUCCESSFUL Total time: 10 seconds C:\build\tomcat-connectors>

    All the xml files present in the xdocs directory structure were transformed to html and copied to the GIT_HOME\tomcat-connectors\build\docs directory. Open one of the html files in your browser and see how it looks.

    I find it easier to use two windows while doing my updates. One I call my build window. I keep this one in the GIT_HOME\tomcat-connectors\xdocs directory and I only run two commands in this window: First I run ant clean Then I run ant all

    My second window I call my edit window and I keep that one in the GIT_HOME\tomcat-connectors\xdocs directory where I'm doing my edits, diffs and git pulls.

    Before you start editing you should always update your local repository to prevent conflicts. C:\build\tomcat-connectors> git pull

    Now that your repository is up to date you can begin editing. Find something in the documentation to edit. When you find something remember the name of the file. In your edit window find and edit the xml source file with the same name. After you are done return to the build window, and in the GIT_HOME\tomcat-connectors\xdocs directory run: C:\build\tomcat-connectors\xdocs> ant clean

    This will delete all the previous html files and make the area ready for updated material. Now to make fresh documents that incorporate your changes run: C:\build\tomcat-connectors\xdocs> ant all

    Use your browser to view the edits you just made, they will be in the GIT_HOME\tomcat-connectors\build\docs sub-tree. If it looks good and is ready to go, all that is left to do is to create a patch and submit it.

    From your edit window cd into the directory that contains the xml file you are working on, and run the git pull command. For example, to produce a diff of the index.xml file and call it patch.txt, you would cd into the directory containing the index.xml file and: C:\build\tomcat-connectors\xdocs\>git diff index.xml > patch.txt.

    Now that you have your patch you are ready to send it in.

    Patches to the documentation are handled just like a bug report. You should submit your patches to http://issues.apache.org/bugzilla/ and include a good one line subject. If this is your first time to use the bug database then you should read http://issues.apach e.org/bugzilla/bugwritinghelp.html. You will need to create a user account. At the web site paste your patch into the web form and don't forget to describe what it is your patch is for. Sooner or later a someone with commit privileges will review your suggestion.

    Only Committers are able to update the web site (http://tomcat.apache.org/connectors-doc/). To do it:

    • Connect to people.apache.org.
    • umask 002
    • Copy the changed files to /www/tomcat.apache.org/connectors-doc/.
    • or use ant from a checkout tomcat/jk/trunk/xdocs repository:
      ant -Dbuild.dir=/www/tomcat.apache.org -Ddist.name=connectors-doc
    • The changes should sync to tomcat.apache.org within seconds.

    A little help to get you started if you need it

    tomcat-connectors-1.2.50-src/xdocs/miscellaneous/faq.xml0000644000000000000020000002746514655113617021616 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Frequently Asked Questions Henri Gomez

    General Informations and FAQ about JK

    The primary mechanism for support is through the JK documentation included in the doc directory. Documentation is also available on the Apache Tomcat web site devoted to the Apache Tomcat Connectors Project For additional help, the best resource is the Tomcat Users Discussion list. You should start by searching the mail list archive before you post questions to the list. If you are unable to locate the answer to your question in the archive, you can post questions about JK to the user list for assistance. Make sure that you include the version of your web server, that you are using as well as the platform you are running on and go here to determine how to subscribe to tomcat mailing list.

    Now that JK moved to the tomcat-connectors repository, the source and the binaries for JK can be downloaded from a mirror at the Tomcat Connectors (mod_jk) Downloads page.

    JK is a project covering web servers to Tomcat connectors.

    Apache HTTP Server support is implemented on JK, using a plugin called the mod_jk module.

    Microsoft IIS support is implemented on JK, using a plugin called the ISAPI redirector.

    For JK 1.2.x, you should read:

    For more detailed information, have a look at the Reference Guide. You could also try searching the mailing list archives for "JK" or look at the source.

    ajp13 is the standard. The old ajp12 is deprecated and ajp14 is experimental.

    Also ajp13 is supported by all Apache Tomcat versions starting with Tomcat 3.2 and by other servlet engines like Jetty and JBoss.

    The ajp13 protocol uses persistant connections where the traffic could be null if there is no request to be sent to Tomcat. Firewalls use to drop inactive connections and will make your web server and Tomcat think the connection is valid.

    Starting with JK 1.2.0, a socket_keepalive property as been added to ajp13 settings, and you should take a look at it in Workers HowTo and workers.properties reference. If nothing else helps, you can try JkOptions +DisableReuse, but this will have strong performance implications.

    Under heavy load, the Apache HTTP Server creates many children to handle the load, which will in turn create many connections to Tomcat to forward the requests they should handle. The Apache HTTP Server will normally kill the children/threads when the load decreases. But if the load is still there and even if only Apache handles the requests, ie static contents, the children are kept and with them all the ajp13 connections, even if they are no more used.

    To close connections after some time of inactivity you can use connection_pool_timeout, for more informations refer to workers.properties reference.

    Informations and FAQ about mod_jk and the Apache HTTP Server.

    The ajp13 protocol keeps an open socket between Tomcat and Apache. Release of mod_jk present in Tomcat Connectors handles the network failure. But with very ancient releases of mod_jk, you may have to restart Apache as well.

    Many versions of Apache use a modified API, known at Extended API, developed for use with the mod_ssl module. Starting with Apache 2.0 there is no more difference.

    For example, Apache 1.3 present in certains recent Linux distributions include the mod_ssl module.

    So if you got such 'Extended Apache', you need to use mod_jk.so-eapi.

    You should use mod_jk.so-noeapi only for 'Standard Apache' (ie without mod_ssl).

    It's wise to avoid using EAPI modules on STD API Apache or to use standard API modules on EAPI Apache. Allways be sure to have the mod_jk.so which match your version of Apache.

    It's related to Apache EAPI, the message 'mod_jk.so is garbled - perhaps this is not an Apache module DSO ?' just told you, that your're trying to install a mod_jk.so DSO module that was compiled on an Apache using EAPI, like apache-mod_ssl or apache from Redhat distro 6.2/7.0 but your system use the standard Apache with normal API.

    Also related to EAPI, the message '[warn] Loaded DSO /usr/lib/apache/mod_jk.so uses plain Apache 1.3 API, this module might crash under EAPI! (please recompile it with -DEAPI)', the mod_jk.so was compiled under normal Apache with standard API and you try to install the module on an Apache using EAPI.

    APXS is a Perl script that is created when you build the Apache web server from source. Chances are that if you are getting these errors and you obtained Apache as a binary distribution, that APXS is not configured correctly for your system. Your best bet is to get the Apache source from the Apache HTTP Server homepage and build it yourself. Use the following for a basic build (read the Apache docs for other options): [user@host] ~ $ cd /usr/local/src [user@host] ~ $ gzip -dc apache_1.3.19.tar.gz|tar xvf - [user@host] ~ $ cd apache_1.3.19 [user@host] ~ $ ./configure --prefix=/usr/local/apache \ --enable-module=most \ --enable-shared=max [user@host] ~ $ make [user@host] ~ $ make install

    Note: The above steps assume that you downloaded the Apache source and placed it in your /usr/local/src directory.

    Since the Apache API can change between versions, any Apache module contains the Apache API version used to compile the module. This is called the Magic Module Number.

    At start time Apache checks that the version in the module header is compatible with the Apache server. If not it will deny to start and log an error.

    Note that minor versions are forward compatible. If the module was compiled using Apache 2.x.y the resulting binary should work with any other version 2.x.z where z is bigger or equals to y. If you also need compatibility for versions 2.x.z with z smaller than y, use the configure flag --enable-api-compatibility. Note that the module compiled with any 2.x will never be compatible with 2.y for x different from y. In this case you need to recompile the module.

    mod_jk works well with Apache 2.x from 2.0 to 2.4.

    Important parts of the functionality of mod_jk have been reimplemented in the Apache HTTP Server modules mod_proxy_ajp and mod_proxy_balancer. These are part of the standard distribution of Apache 2.2 and 2.4. The new modules do not contain all features of mod_jk, but on the other hand you get the modules automatically with every new Apache release.

    JNI workers have been deprecated. They will likely not work. Do not use them.

    JNI support requires a multi-threaded environment which is not the general case for Apache 1.3. You should verify if Apache 1.3 has been build with thread support and if not you could add the the pthreads library to your httpd.conf file.

    # Add pthread to Apache in httpd.conf LoadModule "/usr/lib/libpthreads.so"

    Also keep in mind that JNI is suited for multi-threaded servers and you should consider upgrading to Apache 2.x to support JNI.

    JNI workers have been deprecated. They will likely not work. Do not use them.

    Under Linux, you should set some environment variables BEFORE launching your Apache HTTP Server:

    export LD_LIBRARY_PATH=$jre/bin:$jre/bin/classic:$LD_LIBRARY_PATH

    Also some Linux distributions have enabled a GLIBC feature called 'floating stacks' which may not works with kernel less than 2.4.10 on SMP machines. You should disable floating stacks by exporting an environment variable:

    export LD_ASSUME_KERNEL=2.2.5

    You could have to update your service scripts, ie /etc/rc.d/init.d/httpd, to set these env vars before your Apache server starts.

    configure assume you have some GNU tools already installed and configured for your system, and ad minima libtool.

    Also some systems may have mixed cc and gcc setup which may make you puzzled when trying to link an Apache built with native c compiler with a jk build with gcc.

    In case the make processing doesn't work as expected, you should use a GNU make gmake.

    tomcat-connectors-1.2.50-src/xdocs/miscellaneous/jkstatustasks.xml0000644000000000000020000001666314655113617023763 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Status Worker Ant Tasks Peter Rossbach

    Since version 1.2.19 the JK release contains additional ant tasks. They can be used to manage the JK web server plugins via the special status worker.

    <?xml version="1.0" encoding="UTF-8"?> <project name="modjk-status" xmlns:jk="urn:org-apache-jk-status" default="status" basedir="."> <property name="profile" value=""/> <property file="jkstatus${profile}.properties"/> <property file="jkstatus.properties.default"/> <path id="jkstatus.classpath"> <fileset dir="${catalina.home}/bin"> <include name="commons-logging-api-*.jar"/> </fileset> <pathelement location="${catalina.home}/server/lib/catalina-ant.jar"/> <pathelement location="../dist/tomcat-jkstatus-ant.jar"/> <pathelement location="${catalina.home}/server/lib/tomcat-util.jar"/> </path> <typedef resource="org/apache/jk/status/antlib.xml" uri="urn:org-apache-jk-status" classpathref="jkstatus.classpath"/> <target name="status" > <jk:status url="${jkstatus.url}" username="${jkstatus.username}" password="${jkstatus.password}" resultproperty="worker" echo="off" failOnError="off"/> <echoproperties prefix="worker" /> </target> </project>

    [echoproperties] #Ant properties [echoproperties] #Sun Dec 10 20:40:21 CET 2006 [echoproperties] worker.node01.lbmult=1 [echoproperties] worker.loadbalancer.lock=Optimistic [echoproperties] worker.node02.transferred=0 [echoproperties] worker.loadbalancer.sticky_session=false [echoproperties] worker.node01.distance=0 [echoproperties] worker.node01.client_errors=0 [echoproperties] worker.node02.lbmult=1 [echoproperties] worker.node01.port=7309 [echoproperties] worker.node01.elected=0 [echoproperties] worker.loadbalancer.good=2 [echoproperties] worker.loadbalancer.method=Sessions [echoproperties] worker.server.port=2090 [echoproperties] worker.loadbalancer.map.2.type=Wildchar [echoproperties] worker.node02.route=node02 [echoproperties] worker.node01.route=node01 [echoproperties] worker.node01.lbvalue=0 [echoproperties] worker.node01.lbfactor=1 [echoproperties] worker.node01.max_busy=0 [echoproperties] worker.node01.busy=0 [echoproperties] worker.node01.redirect= [echoproperties] worker.node02.distance=0 [echoproperties] worker.loadbalancer.name=loadbalancer [echoproperties] worker.loadbalancer.sticky_session_force=false [echoproperties] worker.node02.state=N/A [echoproperties] worker.node01.state=N/A [echoproperties] worker.node01.transferred=0 [echoproperties] worker.loadbalancer.map.length=2 [echoproperties] worker.node01.type=ajp13 [echoproperties] worker.node01.address=127.0.0.1\:7309 [echoproperties] worker.result.type=OK [echoproperties] worker.loadbalancer.member_count=2 [echoproperties] worker.loadbalancer.map_count=2 [echoproperties] worker.loadbalancer.mtime_to_maintenance_min=12 [echoproperties] worker.loadbalancer.mtime_to_maintenance_max=75 [echoproperties] worker.node02.lbfactor=1 [echoproperties] worker.node02.max_busy=0 [echoproperties] worker.jk_version=mod_jk/1.2.21-dev [echoproperties] worker.loadbalancer.bad=0 [echoproperties] worker.node02.redirect= [echoproperties] worker.node01.host=localhost [echoproperties] worker.node02.activation=ACT [echoproperties] worker.loadbalancer.map.1.source=JkMount [echoproperties] worker.loadbalancer.retries=2 [echoproperties] worker.node02.elected=0 [echoproperties] worker.loadbalancer.map.2.source=JkMount [echoproperties] worker.node02.port=7409 [echoproperties] worker.loadbalancer.length=2 [echoproperties] worker.node02.lbvalue=0 [echoproperties] worker.loadbalancer.degraded=0 [echoproperties] worker.loadbalancer.map.1.type=Wildchar [echoproperties] worker.loadbalancer.map.2.uri=/myapps* [echoproperties] worker.node02.client_errors=0 [echoproperties] worker.length=1 [echoproperties] worker.node01.domain=d20 [echoproperties] worker.loadbalancer.recover_time=60 [echoproperties] worker.server.name=localhost [echoproperties] worker.node02.domain= [echoproperties] worker.result.message=Action finished [echoproperties] worker.node02.busy=0 [echoproperties] worker.node01.readed=0 [echoproperties] worker.node01.errors=0 [echoproperties] worker.node02.address=127.0.0.1\:7409 [echoproperties] worker.node02.readed=0 [echoproperties] worker.loadbalancer.busy=0 [echoproperties] worker.web_server=Apache/2.0.59 (Unix) mod_jk/1.2.21-dev [echoproperties] worker.node02.errors=0 [echoproperties] worker.node02.type=ajp13 [echoproperties] worker.loadbalancer.map.1.uri=/ClusterTest* [echoproperties] worker.node01.activation=ACT [echoproperties] worker.loadbalancer.max_busy=0 [echoproperties] worker.loadbalancer.type=lb [echoproperties] worker.node02.host=localhost

    <target name="updatelb" > <jk:updateloadbalancer url="${jkstatus.url}" username="${jkstatus.username}" password="${jkstatus.password}" loadbalancer="loadbalancer" method="Busyness" retries="2" recoverWaitTime="60" lock="Optimistic" forceStickySession="false" stickySession="false"/> </target>

    <target name="updatew" > <jk:updateworker url="${jkstatus.url}" username="${jkstatus.username}" password="${jkstatus.password}" loadbalancer="loadbalancer" worker="node01" lbfactor="2" activation="Active" redirect="" domain="" route="node01" distance="0"/> </target>

    <target name="reset" > <jk:reset url="${jkstatus.url}" username="${jkstatus.username}" password="${jkstatus.password}" loadbalancer="loadbalancer" worker="node01" /> </target>

    tomcat-connectors-1.2.50-src/xdocs/miscellaneous/reporttools.xml0000644000000000000020000000656014655113617023434 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Reporting Tools Glenn Nielsen

    The mod_jk source distribution contains two perl scripts in the tools/reports directory which can be used to analyze the mod_jk logs, save statistical data, and generate report graphs.

    tomcat_trend.pl log_dir archive_dir

    Script for analyzing mod_jk.log data when logging tomcat request data using the JkRequestLogFormat Apache mod_jk configuration. Generates statistics for request latency and errors. Archives the generated data to files for later use in long term trend graphs and reports.

    tomcat_reports.pl archive_dir reports_dir

    Script for generating reports and graphs using statistical data generated by the tomcat_trend.pl script. The following graphs are created:

    • tomcat_request.png - Long term trend graph of total number of tomcat requests handled.
    • tomcat_median.png - Long term overall trend graph of tomcat request latency median.
    • tomcat_deviation.png - Long term overall trend graph of tomcat request mean and standard deviation.
    • tomcat_error.png - Long term trend graph of requests rejected by tomcat. Shows requests rejected when tomcat has no request processors available. Can be an indicator that tomcat is overloaded or having other scaling problems.
    • tomcat_client.png - Long term trend graph of requests forward to tomcat which were aborted by the remote client (browser). You will normally see some aborted requests. High numbers of these can be an indicator that tomcat is overloaded or there are requests which have very high latency.

    A great deal of statistical data is generated but at this time only long term trend graphs are being created and no reports. This is only a start. Many more graphs and reports could be generated from the data. Please consider contributing back any new reports or graphs you create. Thanks.

    These perl scripts depend upon the following perl modules and libraries:

    • GD 1.8.x graphics library http://www.boutell.com/gd/
    • GD 1.4.x perl module
    • GD Graph perl module
    • GD TextUtil perl module
    • StatisticsDescriptive perl module

    tomcat-connectors-1.2.50-src/xdocs/miscellaneous/changelog.xml0000644000000000000020000034236314655113617022773 0ustar rootbin ]> &project; Mladen Turk Rainer Jung Henri Gomez Tim Whittington Changelog

    This is the Changelog for Apache Tomcat Connectors. This changelog does not contain all updates and fixes to the Tomcat connectors (yet). It should contain fixes made only after November 10th 2004, when the new documentation project for JK was started.

    68117: Fix typo in new libtool flag introduced in 1.2.49 to reduce symbol visibility. Also improve escaping of it in the Makefile. Patch provided by lzsiga@freemail.c3.hu. (rjung) Improve shared memory handling on non-Windows. (rjung) Update PCRE bundled with the ISAPI redirector to 8.45. (rjung) 8: Fix compilation on musl. Patch provided by conrad+github@kostecki.com. (rjung) Update config.guess and config.sub from https://git.savannah.gnu.org/git/config.git. (rjung)
    Retrieve default request id from mod_unique_id. It can also be taken from an arbitrary environment variable by configuring "JkRequestIdIndicator". (rjung) 65901: Don't delegate the generatation of the response body to httpd when the status code represents an error if the request used the HEAD method. (markt) 66005: Only export the main module symbol. Visibility of module internal symbols led to crashes when conflicting with library symbols. Based on a patch provided by Josef ÄŒejka. (rjung) Remove support for implicit mapping of requests to workers. All mappings must now be explicit. (rjung) Set default request id as a GUID. It can also be taken from an arbitrary request header by configuring "request_id_header". (rjung) Fix non-empty check for the Translate header. (rjung) Fix compiler warning when initializing and copying fixed length strings. (rjung) Add a request id to mod_jk log lines. (rjung) 64878: Enable configure to find the correct sizes for pid_t and pthread_t when building on MacOS. (markt) Fix Clang 15/16 compatability. Pull request 6 provided by Sam James. (markt) Improve XSS hardening in status worker. (rjung) Add additional bounds and error checking when reading AJP messages. (schultz/markt) Remove support for the Netscape / Sun ONE / Oracle iPlanet Web Server as the product has been retired. (markt) Remove links to the old JK2 documentation. The JK2 documentation is still available, it is just no longer linked from the current JK documentation. (markt) Restructure subsections in changelog starting with version 1.2.45. (rjung)
    Update the installation how-to to remove windows versions that are no longer supported and to add Windows Server 2019. (markt)
    Extend trace level logging of method entry/exit to aid debugging of request mapping issues. (markt) Fix a bug in the normalization checks that prevented file based requests, such as SSI file includes, from being processed. (markt) 63214: When using JkAutoAlias, ensure that files that include spaces in their name are accessible. (markt) Update the documentation to reflect that the source code for the Apache Tomcat Connectors has moved from Subversion to Git. (markt) 64051: When using set_session_cookie, ensure that an updated session cookie is issued if the load-balancer has to failover to a different worker. (markt) Update config.guess and config.sub from https://git.savannah.gnu.org/git/config.git. (markt) Update release script for migration to git. (rjung)
    62751: Fix regression in 1.2.44 which resulted in socket_connect_timeout to be interpreted in units of seconds instead of milliseconds on platforms that provide poll(). (rjung)
    Update the documentation to note additional limitations of the JkAutoAlias directive. (markt) Improve path parameter handling so that JkStripSession can remove session IDs that are specified on path parameters in any segment of the URI rather than only the final segment. (markt) Improve path parameter handling so that strip_session can remove session IDs that are specified on path parameters in any segment of the URI rather than only the final segment. (markt) 62689: Correct regression in 1.2.44 that broke request handling for OPTIONS * requests. (rjung) Optimize path parameter handling. (rjung) Improve path parameter parsing so that the session ID specified by the session_path worker property for load-balanced workers can be extracted from a path parameter in any segment of the URI, rather than only from the final segment. (markt)
    Remove the Novell Netware make files and Netware specific source code since there has not been a supported version of Netware available for over five years. (markt) 57946: Apache: Update the documentation to use httpd 2.4.x style access control directives. (markt) 58287: Common: Use Local, rather than Global, mutexs on Windows to better support multi-user environments. (markt) 59897: Apache: Use poll rather than select to avoid the limitations of select triggering an httpd crash. Patch provided by Koen Wilde. (markt) 60745: ISAPI: Remove the check that rejects requests that contain path segments that match WEB-INF or META-INF as it duplicates a check that Tomcat performs and, because ISAPI does not have visibility of the current context path, it is impossible to implement this check without valid requests being rejected. (markt) Clarify the behvaiour of lb workers when all ajp13 workers fail with particular reference to the role of the retries attribute. (markt) 62408: Add the new load-balancer worker property lb_retries to improve the control over the number of retries. Based on a patch provided by Frederik Nosi. (markt) Refactor normalisation of request URIs to a common location and align the normalisation implementation for mod_jk with that implemented by Tomcat. (markt) Add a note to the documentation that the CollapseSlashes options are now effectively hard-coded to CollpaseSlashesAll due to the changes made to align normalization with that implemented in Tomcat. (markt) Update PCRE bundled with the ISAPI redirector to 8.42. (rjung) Update config.guess and config.sub from https://git.savannah.gnu.org/git/config.git. (rjung)
    61733: LB: Propagate load factor changes applied by the status worker to a load balancer sub worker correctly to all processes. Based on a patch provided by Jonathan Oddy. (rjung) ISAPI: Align the make files for 32-bit and 64-bit builds. (markt) Update config.guess and config.sub from http://git.savannah.gnu.org/cgit/config.git. (rjung) Update PCRE bundled with the ISAPI redirector to 8.41. (rjung) Update the ISAPI redirector installation documentation to reflect the currently supported versions of Windows. (markt) Align the normalization performed by the ISAPI redirector with that implemented by Tomcat. (markt)
    Status: Fix displayed number of bytes read from and written to the backend when an AJP worker is used without a load balancer worker. (rjung) Apache: Don't try to read remaining request body parts during clean up if reading the request body from the client already failed during earlier processing phases. (rjung) 57485: Apache: Propagate errors reading the request body from the client to mod_jk so Tomcat sees an error rather than a truncated body. (markt) 57836: ISAPI: Empty REMOTE_USER should not be translated to "". (rjung) 58249: Add a note the the documentation that max_packet_size will be aligned to the next multiple of 1024 if a value is specified that is not a multiple of 1024. (markt) 58309: ISAPI: Update bundled pcre from version 5.0 to 8.38. (rjung) 58286: Fix crash in mod_jk and in the ISAPI Redirector. The crash only happens on Windows when retrieving the jk-status for the HTML format (which is the default format). This regression was introduced by the fix to 54177. (rjung) 58285: Don't use GCC atomics on platforms, for which GCC doesn't provide an atomics implementation. This regression was introduced by the fix to 44454 and 56703. (rjung) 58425: Fix regression in 1.2.41 that prevented AJP 1.2 workers from initialising. Note that the AJP 1.2 protocol is deprecated. Patch provided by yagisita. (markt) 58504: If a background thread is used to perform worker maintenance, ensure that maintenance runs are not skipped. Patch provided by Hiroto Shimizu. (markt) 58608: ISAPI: Add a new registry option "flush_packets" that allows the flushing behaviour of IIS7+ to be controlled. The default is not to flush. Setting the option to "true" with cause IIS to write data to the client as each AJP packet is received. (markt) 58813: ISAPI: Correctly release a mutex allowing the plugin to complete initialization. Prior to this fix, the incomplete initialization was causing a hang on shutdown. Patch provided by Matthew Reiter. (markt) 58895: Correct an off-by-one error in the log messages for the number of attempts made to communicate with the backend server. Patch provided by Hiroto Shimizu. (markt) 59164: Fix crash on first connection if a host name is specified for the worker that cannot be resolved to an IP address. (markt) 59184: HTTPD: Avoid segmentation fault if mod_jk is configured with an invalid value for JkShmFile. This causes the server startup to fail. (markt) Minor code clean-up and optimization. (markt)
    AJP, LB: Reduce lock contention during maintenance function. This was observable when using a big number of AJP13 and LB workers, especially in combination with the Apache httpd prefork MPM. (rjung) 57060: Allow building from outside of source tree. Patch contributed by Petr Sumbera. (rjung) 56703: Status: Fix inflated counter for current number of backend connections especially when a connection timeout occurred on the backend. (rjung) 56661: Fix Servlet API getLocalAddr(). Works for Tomcat 6.0.42, 7.0.55 and 8.0.11 and Apache and ISAPI plugins. (rjung) Status: Log old and new values when changing worker attributes. (rjung) 56667: Status: Fix log message when changing activation state of all members. (rjung) 56565: Fix IPV6 address resolve on non-dual network stacks. (mturk) 50511: Reduce log level for "OPTIONS *" requests from warning to debug. (rjung) Apache: Copy log notes instead of using references to prevent access to memory from closed pool. (rjung) Add option to control handling of multiple adjacent slashes in mount and unmount. New default is collapsing the slashes only in unmount. Configuration is done via new JkOption for Apache ("CollapseSlashesAll", "CollapseSlashesNone" or "CollapseSlashesUnmount") and via property "collapse_slashes" for IIS (values "all", "none", "unmount"). This is the fix for CVE-2014-8111. (rjung) Add more checks for shared memory allocation. (rjung) 56869: Status: Add maximum number of open backend connections to status worker. Patch contributed by Martin Knoblauch. (rjung) 56770: AJP: Add worker name to all log messages. Patch contributed by Martin Knoblauch. (rjung) 50186: Docs: Clarify relation between "connection_pool_timeout" and "keepAliveTimeout" or "connectionTimeout" in the Tomcat AJP connector configuration. (rjung) 52334: LB: Calculate worker recovery time based on last recovery attempt time instead of original error time after the first recovery attempt. (rjung) 54596 part 1: IIS: Fix missing last character when parsing relative file names with no ".." directory components from configuration. (rjung) 54596 part 2: IIS: Fix using relative file names in config with ".." path segments that go up the directory hierarchy higher than the starting point of the relative file name. (rjung) Status: Add logging if status worker output was dropped due to insufficient buffer size. (rjung) Reduce log buffer from 8KB to 1KB. Add logging in case of failed logging and add trailing "..." to lines which were likely truncated. (rjung) Replace fixed allocation of 32 entries for fail_on_status by dynamic allocation. (rjung) Enforce implementation restriction on maximal length "60" of worker attributes "name", "host", "route", "domain", "redirect", "session_cookie", "session_path" and "set_session_cookie". Checks were added to configuration file processing and configuration updates via the status worker. (rjung) 52483: Apache: Add debug logging for result of JkOptions configuration processing. (rjung) 54177: Status: Use numeric time stamps instead of textual ones to avoid non-well-formed XML output. Textual timestamps are formatted according to locale settings and reencoding them to UTF-8 would be cumbersome. (rjung) 56618: Status: Use percent decoding when reading query string parameters. For example this fixes editing IPv6 addresses via the status worker if the client encodes ":" as "%3A". Patch contributed by Christopher Schultz. (rjung) 56452: Fix crash in debug logging for IPv6 adresses. Patch contributed by Christopher Schultz. (rjung) 34526: Apache: Improve compatibility with mod_deflate request body inflation. An automatic detection of mod_deflate inflation is not implemented. Use the new Apache environment variable JK_IGNORE_CL instead, to let mod_jk ignore an existing Content-Length request header. (rjung) 44454: LB: Add warning to docs about problems with "busyness" load balancing method. (rjung) 44454: Improve busy counter by using atomics. (rjung) 56703: Status: Improve connected counter. Use atomics and for mod_jk (Apache) currectly count down connections closed by child processes that are stopped. (rjung) 44571: Ensure that we return with status 503 if we can not get and endpoint for a worker. (rjung) Apache: Improve log handling during graceful or normal restart. (rjung) Don't update last access time of worker connections during optional checking of idle connections using CPing. Updating the time stamp breaks closing idle connections. (rjung) Adjust linger parameters used during connection shutdown. (rjung) Fix annoying redefine warnings for the autoconf PACKAGE defines during configure based builds. (rjung) Status: Use multi-line table headers and fix invalid xml output. (rjung) 44571: Implement an optional limit on concurrent requests allowed for a worker (attribute "busy_limit"). Original patch contributed by zealot0630 at gmail dot com. (rjung) Correct log message "all endpoints are disconnected" to "no usable connection found, will create a new one". Tone done from info log level to debug for the common case. (rjung) 57536: AJP: Allow to configure connection source address. This should only be used on multi-homed hosts. The feature is experimental. (rjung) 57540: AJP: Forward name of SSL protocol used for handling the request (SSLv3, TLSv1, TLSv1.1, TLSv1.2). (rjung)
    Fix forwarding of chunked requests, which is broken in version 1.2.39. (rjung) 56352: Fix regression in memory release. (mturk) Fix status worker display of worker IP address after name or port was changed. (rjung) 56297: Improve key hash function. Copied from APR. (rjung) 55683: Remove quotes from quoted session cookies. (rjung) 53542: ISAPI: Fix grammar in 503 error page. (rjung) 55696: Crash on Mac OS X 10.9 during config parsing. (rjung)
    Deprecate nt_service from Apache Tomcat Connectors. (mturk) 56133: Fix possible crash when a request fails during request body transfer to the back end and reply_timeout was set. Patch contributed by Hiroto Shimizu. (rjung) Fix status worker not updating parameters for all members. (mturk) 55853: HTTPD: Use the correct API for setting Content-Length. Patch contributed by areese yahoo-inc.com. (rjung) Add IPV6 support for connection to webserver. New directive prefer_ipv6 has been added to control the hostname resolution and preserve backward compatibility. (mturk) Add --disable-sock-cloexec to configure to disable use of SOCK_CLOEXEC (using FD_CLOEXEC + fnctl instead) so built modules will work with Linux kernels prior to 2.6.27. (timw) Clean up config file parsing. Worker names are now restricted to 60 bytes. (rjung) Allow to set a stickyness cookie in case a web framework breaks Tomcat's adding of the routing ID to the end of the JSESSIONID cookie. (rjung) Use max_packet_size also for request body forwarding. (rjung) Apache 2.4: By default forward logical client address as provided by mod_remoteip. When setting JkOptions ForwardPhysicalAddress mod_jk will instead forward the physical peer address. (rjung) Minor documentation improvements. (rjung)
    Fix regression which can crash webserver in case worker is defined both as member of load balancer and as standalone worker. (mturk) Fix core if debug log level is specified and there is no session identifier present. (mturk)
    Use named shared memory objects so that we preserve runtime configured data instead of resetting on each child creation. (mturk) Fix dead-lock caused by not releasing mutex on close. (mturk) Fix compilation of mod_jk for HTTPD 1.3. (rjung) 46893: HTTPD 1.3: Apply fix to HTTPD 1.3. It was fixed for HTTPD 2.x already in version 1.2.30. (rjung) HTTPD 1.3: Allow to set path parameter used when doing JkStripSession. This was available for HTTPD 2.x already since mod_jk 1.2.27. (rjung)
    HTTPD: Fix crash on unknown worker names. (mturk) IIS: Fix crash on worker process recycle. (mturk) 52659: IIS: Fix shared memory corruption. (mturk) 52921: HTTPD: Fix crash in uri mapping. (mturk)
    52793: AJP: Fix default value of forwarded worker activation state. Contributed by Yoshihito Fukuyama. (rjung) HTTPD: Improve support for HTTPD 2.4 by using client_* instead of remote_* variables. (rjung) 52564: Fix building with format checking gcc security hardening cflags. Contributed by Tony Mancill. (rjung) 52567: Balancer member in recovery state can switch back into error state if it is idle. (rjung) Log error if unable to load URI workermap file, and improve logging of unreadable worker files on IIS. (timw) Remove deprecated JNI worker and build dependency on Java SDK. (mturk) 51253: Forward WWW-Authenticate header when using server generated error pages (rjung, mturk). 46406: IIS: Support relative paths in configuration. The paths are presumed to be relative from isapi_redirect.dll. (mturk) 50233: Do not use hard limit on uri size (mturk). IIS: Use Windows Server 2003 SP1, Windows XP SP2 as minimal version supported. (mturk) 47038: Fix compiler warning when using --enable-flock for configure. (rjung) 51326: URI Map: Add "session_cookie" and "session_path" rule extensions. Contributed by Eiji Takahashi. (rjung) 51333: IIS: Document configuration requirement for 64 Bit environment. (rjung) 51743: HTTPD: Support rule extensions when defining the request worker with an environment variable (e.g. JK_WORKER_NAME). (rjung) 51769: IIS: Allow URIs which contain "META-INF" or "WEB-INF" as long as they are not path components of the URI. (rjung) 52056: HTTPD: JK request log does not always log correct response status. Fixed by refactoring JK request log to use the standard request log hook. (rjung) HTTPD: Allow to choose a sticky worker using the environment variable JK_ROUTE. This can be used if sessions and routes are send with the request in a non-standard way. (rjung) URI Map: Add "sticky_ignore" extension attributes to uri worker map. It allows to disable stickyness for individual mounts. (rjung) HTTPD: Allow dynamic disabling of stickyness using the environment variable JK_STICKY_IGNORE. This can be useful to break cookie stickyness for non-sticky requests like login forms. (rjung) LB: New balancing method "Next" to distribute sessions in a round-robin way. (rjung) LB: Add counter for created sessions to status worker and HTTPD notes. It actually counts the number of requests that do not carry a session id. (rjung) URI Map: Add "stateless" extension attributes to uri worker map. This can improve session load balancing. (rjung) HTTPD: Allow dynamic switching of requests to "stateless" using the environment variable JK_STATELESS. (rjung) AJP: Improve logging when request does not fit into an AJP packet. (rjung)
    51417: Fix worker busy detection by querying the worker endpoint. Abandoned connections can leave a worker in busy state without decrementing busy counter. (mturk) 50339: Fix whitespace trimming when parsing attribute lists. (rjung) 41263: Support Servlet API getRemotePort(). Works for Tomcat 5.5.28, 6.0.20 and 7.0.0 and Apache and ISAPI plugins. (rjung) 41923: AJP: Close AJP connection to Tomcat on client write error when recovery_options 4 is specified, aborting the response write on the Tomcat side. (timw) AJP: Cap the lingering bytes that will be read when shutting down an AJP socket at 32k to prevent CPU spikes in the web server when a client aborts on a large response body. Also reduce total linger time to 2s. (timw) 50839: AJP: Fix 30sec CPU spike due to incorrect counting of lingering bytes causing a busy loop when a client aborts connection during a response write. Fixes regression in 1.2.31. (timw) LB: Forward worker activation state as request attribute "JK_LB_ACTIVATION". Possible values are "ACT" (active), "DIS" (disabled) and "STP" (stopped). (rjung) HTTPD: Forward WWW-Authenticate from backend when status is 401 and server generated error pages are used. (rjung) 50363: IIS: Prevent chunk encoding of empty message bodies for 204, 205 and 304 responses. (timw) 50975: IIS: Fix hanging of Transfer-Encoding: chunked requests when Content-Length header is present in request as well. Also addresses situation where IIS appears to create a Content-Length header for a small chunk encoded request when none was present in the original request. (timw) 47679: IIS: stop truncation of request headers when ISAPI redirector used as an extension without the corresponding filter installed. (timw) NSAPI: Use lower case header names for responses. Otherwise the web server might add chunked transfer encoding header in addition to our content length header. Docs: Improve load balancer documentation. (rjung)
    49413: AJP13: Drop flush packets send by the backend after the response has been finished. (rjung) AJP: Log the local and remote socket address. (mturk) Watchdog: Move the maintain workers outside the critical section allowing other threads to use the connection pool during maintenance. (mturk) Common: Add svn revision to init log message. (rjung) Common: Don't destroy errno during trace logging. (rjung) Apache: Add support for Apache 2.3/2.4. (rjung) Apache: Added version number resource for mod_jk.so on Windows. (timw) 48501: IIS: Added rotatelogs style log rotation to ISAPI Redirector. (timw) 38895: IIS: Use RAW headers instead of CGI headers by default to prevent conversion of underscores '_' to hyphens '-' in header names. Old behaviour can be enabled by defining USE_CGI_HEADERS. (timw) 49511: IIS: Do not override IIS log information when subsequent requests on a keep-alive connection are not mapped into the ISAPI Redirector. (timw) Docs: Document SSLOptions needed for SSL information forwarding. (rjung) Docs: Grammar and style improvements and clarification about serving static content by IIS. Patch provided by André Warnier. (rjung) Docs: Update subversion paths used in docs. (rjung)
    Apache: Improve compatibility with Apache 2.3. (rjung) 46632: Apache: Do not register child cleanup for our pools. (mturk) 46893: Apache: Log warning only if JkShmSize was actually set in the configuration. (mturk) IIS: Include optional chunking support. Off by default. (mturk) 48763: IIS: Do not send Content-Length when using chunked encoding or length larger 4GB. (mturk) 48223: IIS: Propagate correct backend error code to IIS. (rjung) 47867: IIS: crash during startup, when compiled with VS2008 and workers.properties contains unsupported properties. Patch provided by Indrek Juhani (rjung) 47628: IIS: Fix deadlock when restarting the Application Pool caused by not releasing the critical section lock. Patch provided by Bret Prucha. (mturk) IIS/NSAPI: Correct log file flushing after each line. (mturk) NSAPI: Add Microsoft Visual C++ Makefile. (mturk) AJP: Improve socket shutdown handling. (mturk) AJP: Ensure we never reuse a non reusable socket. (mturk) AJP: Tolerate a single excess packet when waiting for cpong. (mturk) AJP: Check protocol correctness more strictly. (mturk) 48410: AJP: Use poll instead select so we can work with more then 1024 sockets. (mturk) 46503: AJP/Status: Garbage data in worker domain and route. (mturk) 48276: AJP: When worker contact cannot be resolved mark the worker as disabled instead failing to start the server. (mturk) 48169: AJP: Improve CGI interoperability by closing all sockets during EXEC. (mturk) Status: Add number of open backend connections to status worker. This feature is experimental, the displayed value might not be accurate. (mturk) 47224: Status: When address gets changed invalidate all opened sockets in the endpoint cache. This will cause new backend connections to get opened using new address. (mturk) 48305: Status: Do not show "secret" property when doing dump. (mturk) 45610: Status: Don't accept requests with empty value for sub worker parameter. (rjung) 45610: Status: Fix erroneous unsetting of sticky_session and sticky_session_force when updating other load balancer attributes via the status worker. (rjung) 47222: Status: Add ping_timeout to the shared memory and allow dynamic configuration. (mturk) Status: Remove duplicate "errors" line in property view of AJP13 workers that are part of a load balancer. (rjung) LB: Fix route logging. (rjung) Logging: Automatically detect size of thread id for logging. (rjung) Logging: Add optional log file locking for Windows when defining JK_LOG_LOCKING. (mturk) Configuration: Update example configuration. (rjung) Docs: Update information about tools needed to create a release. (rjung) 47983: Docs: Fix typo in example config which breaks startup. (rjung) Build: Force copy of automake files. (rjung) Build: Tomcat code repository structure cleanup reflected in documentation and build script. (rjung, mturk)
    Apache: Add more environment variables to overwrite request information. Useful in case a proxy is in front of Apache and sends us original request information e.g. via custom headers. (rjung) Apache: No longer preallocate entries for JK request log. (rjung) 46352: Apache: Fix crash when using SetHandler jakarta-servlet in VHost without any JkMount. Crash due to incorrect initialization of mount extensions. (rjung) Apache: JkWatchdogInterval had wrong interval calculation causing a 10 times higher watchdog interval then configured. (mturk) Apache: Activate forwarding of SSL key size by default. (rjung) 46169: Apache 1.3: Backport use_server_errors mount extension. (rjung) 46763: Apache 2.0: Survive the log mutex during graceful restart. Patch provided by Eiji Takahashi. (mturk) 46416: Apache 2.0 on Windows: Include mstcipip.h even if the apr doesn't include it. (mturk) IIS: Update uriworkermap.properties file on a regular interval. This requires both worker_mount_reload and watchdog_interval to be defined. (mturk) IIS: Remove obsolete entries from registry file. (mturk) 46579: IIS: Use local environment table instead environment variables for setting the JKISAPI_PATH and JKISAPI_NAME. (mturk) LB: Add new property error_escalation_time to fine tune escalation of local errors to global errors. (rjung) LB: If the sticky session affinity mark contains a dot, treat the part before the dot as the domain name. This allows to have full node session affinity with domain failover. (mturk) LB: make forced recovery work with local error states. (rjung) LB: Only update error state and error time, if we actually have a new state. (rjung) LB: Set global worker state to error when we reach max_reply_timeouts, or fail_on_status triggered hard error. (rjung) AJP: Add a new error type JK_AJP_PROTOCOL_ERROR. (mturk) AJP: Allow worker ports lower or equal to 1024. (rjung) AJP: Improve some AJP error log messages. (mturk) Status: Allow changing worker address and port of AJP workers. The address is resolved on next request for that worker. (mturk) Status: Allow update actions to show error messages in the result page. (rjung) Status: Refactor update actions. (rjung) Status: Do not redirect to the show or list page, if an error occured during an action. (rjung) Status: Include error time in display. (rjung) Status: Remove redundant port information from worker display. Rename address column and remove its explanation from the legend. (rjung) Status: Optimize forced uriworkermap.properties reload. (mturk) Status: Fix crash in text display. (rjung) Status: Show - Edit - Show always ends in single lb member show, even when started from all members lb show. (rjung) Status: Wildcards in sub worker names were broken for update actions. (rjung) Status: Add use_server_errors to map display. (rjung) SHM: Move locking into the data pull and push methods. (rjung) JNI: Deprecate JNI workers. (rjung) Netware: Missing define for MAX_PATH. Patch by Guenter Knauf. (rjung) Docs: Add a new HowTo page about reverse proxies. (rjung) Docs: Add an explanation of local error states to the timeouts documentation. (rjung) Docs: Clarify relation between socket_timeout and socket_connect_timeout. (rjung) Docs: Clarify IIS URL rewrite feature. (rjung) 46834,46734: Docs: Fix a couple of missing or broken links. (markt,rjung) Docs: Add 2008 news to main page and menues. (mturk, rjung)
    46109: Decay reply_timeouts even when lb method is busyness. Also reset reply_timeouts during forced recovery. (rjung) AJP13: Recycle connection if previous request didn't complete. (mturk) Maintain should not run multiple times in parallel. (mturk) Apache: Fix small memory leak during restart. (mturk) Improve signal handling during socket shutdown. (mturk) URI Map: Add debug dump function for uri worker map. (rjung) Add revision number to version info for non-release builds. (rjung) IIS: Optionally allow chunked encoding for responses. At the moment only usable, if build with ISAPI_ALLOW_CHUNKING defined. Based on patch by Tim Whittington. (rjung) IIS: Optionally use raw headers instead of CGI headers. Fixes problem "underscore=dash" problem in header names. At the moment only available, if build with USE_RAW_HEADERS defined. (rjung) IIS: Optionally improve IIS 5.1 compatibility. At the moment only available, if build with AUTOMATIC_AUTH_NOTIFICATION defined. Based on patch by Tim Whittington. (rjung) IIS: Fix memory corruption due to parallel initialization by multiple threads. (rjung) Windows: Use non-default socket keepalive interval. (mturk) IIS: Add environment variables JKISAPI_PATH and JKISAPI_NAME. (mturk) Added socket_connect_timeout directive for setting the connect timeout for the socket. This enables to have low connection timeout but higher operational timeouts. (mturk) AJP13: [CVE-2008-5519] Always send initial POST packet even if the client disconnected after sending request but before providing POST data. In that case or in case the client broke the connection in a middle of read send an zero size packet informing container about broken client connection. (mturk) AJP13: Added connection_acquire_timeout directive for setting the absolute timeout the worker will wait for a free endpoint. (mturk) Apache: Allow to set path parameter used when doing JkStripSession. (mturk) Refactor retries implementation and change semantics of retries attributes. (mturk) Status: Allow showing only a single member for a load balancer. (rjung) Status: Add display of seconds since last statistics reset and access and transfer rates. (rjung) AJP13: Add a configurable retry_interval time. (rjung) Documentation: Enhance description of connection_pool_size. (rjung) IIS: Refactor error page generation. (mturk) IIS: SERVER_NAME variable can be the same for multiple different server instances if requests are handled according to the ip:port combination. Use INSTANCE_ID variable to which the request belongs instead. (mturk) Allow forwarding server error pages. This can be done on per-uri basis using new use_server_errors extension. (mturk) Added session_cookie and session_path for configuring default session identifiers. (mturk) Use max_packet_size also as TCP send and receive buffer size. (mturk) Apache: Do not allow Apache to start in multi-threaded mode if mod_jk was only build for single threaded server (prefork). (mturk) 45812: Add done() service method that causes sending EOS bucket for Apache httpd 2.x. This allows filter chain to work properly. (mturk) Added connection_ping_interval, ping_timeout and ping_mode directives. (mturk) Apache: Use correct ld flags provided by apxs when building module. Prevents some crashes on AIX for httpd 1.3 module. (rjung) Documentation: "val" attribute numbering in status worker needs to start with 0 instead of 1. (rjung) Documentation: Remove JNI parameters from sample configuration in the workers common howto. (rjung) 45026: For Apache httpd 2.x add "Unknown Reason" as the reason phrase, if we get an empty one from the backend. Otherwise httpd 2.x returns status 500. (rjung) Build: Fix Cygwin build. (rjung) Documentation: Add info to docs, that variables sent via JkEnvVar are not listed in request.getAttributeNames(). (rjung) Add watchdog background thread for Apache 2.x and IIS doing internal maintenance (idle connection checks, backend probing). See JkWatchdogInternal (Apache) and watchdog_interval (IIS). (mturk) Change log level of some messages from error to info. (mturk) Documentation: Fix docs for worker attribute "secret". (rjung) Detect correct plugin name for various web servers via additional preprocessor defines. (rjung) LB: Do not put loadbalancer node in error state if there is opened channel. This fixes the bug when new connection fails due to busyness, causing opened connections fail stickyness. This brings back per-node busy counter and private state array for each request. We can mark the state as error for failover to work while still operating and reporting node as OK if there are opened working connections. (mturk) 44738: Fix merging of JkOption ForwardURI* between virtual hosts. Patch contributed by Toshihiro Sasajima. (rjung) URI Map: Add extension attributes to uri worker map. Allowed are reply_timeout, active/disabled/stopped and fail_on_status. Usage currently only implemented for httpd and IIS. (rjung+mturk) URI Map: Make dynamic reloading atomic and free memory not needed any longer. (rjung) Configure: Don't use post httpd 2.2.0 API functions when building with new --enable-api-compatibility configure switch. (rjung) Apache: JkAutoAlias does not work in combination with JkMountCopy if there are no JkMount in virtual host. (rjung) LB: Optimize state macros to improve performance. (rjung) Apache: Allow dynamic setting of reply timeout using the environment variable JK_REPLY_TIMEOUT. (rjung) Status: Add manageability for ajp parameters of ajp workers and ajp lb members. (rjung) Status: Change parameter names of update action to make them more easily distinguishable from other parameters. (rjung) Status: Add ajp worker statistics also for workers, that are not lb members. (rjung) AJP: Refactor factories, move ajp13/ajp14 common parts into ajp_factory. (rjung) Status: Only sync shm worker config values of the workers for which we changed values. (rjung) Status: Set lb_factor instead of distance. (rjung) Status: Minor layout changes, use drop down instead of multiple text links. (rjung) SHM: Use local copies of read mostly attributes of lb sub workers in lb and status worker. (rjung) Status: Add "dump" action to dump our initial configuration. (rjung) Status: Use property table to decide which cmd action uses which output elements. (rjung) Common: Include original configuration map in worker_env to make it available for workers, e.g. the status worker. (rjung) LB: Refactor "route" return for httpd note. Don't use a member of the worker_record, because that's not thread safe. (rjung) Common: Refactor "retries", remove from service and jk_worker, move into ajp worker instead. (rjung) SHM: Use distinct structs for lb and ajp13 in shm. Improves type safety and saves a few bytes. (rjung) SHM: Remove unused attributes. (rjung) SHM: Automatically determine shm size for all web servers. (rjung) SHM: Make open/attach logging consistent for all web servers. (rjung) Status: Include server local time in output. (rjung) 44116: Fix handling of multiple JSESSIONID cookies. (rjung) 37850: Use thread safe localtime_r where appropriate. (rjung) Use thread safe strtok_r on more platforms, especially AIX. (rjung) Status: Improve XSS hardening. (rjung) 35303: Move initialization of service members with defaults from web server specific code to our generic jk_init_ws_service() function. (rjung) 36385: Add missing prepost CPing/CPong directly after connect in case prepost CPing is used, but no connect CPing. (rjung) 37322: Apache: Enhance robustness of message formating in jk_error_exit(). (rjung) 44147: Multiple load balancing workers problem. (rjung)
    42003: Allocate memory instead using fixed size from the stack. (mturk) 43229: Load balancer does not do fail over after reply timeouts. (rjung) JKStatus: Repair detailed Apache httpd version display. This was broken for httpd version 2.2.4+. (rjung) LB/AJP: Refactoring of jk_connect.c, jk_ajp_common.c, jk_lb_worker.c (rjung) Configure: Repair broken apxs auto-detection. (rjung) Configure: Remove trace logging from compiled code via new --disable-trace configure switch. (rjung) Common: Maintain idle connections in decreasing (LRU) slot order. (rjung) Apache: Create JK_WORKER_ROUTE and JK_REQUEST_DURATION notes for access log even if no JkRequestLogFormat is set. (rjung) JKStatus: Enhance URI to worker map listing for Apache httpd. We now list maps for all virtual servers and not only the one, in which JKStatus itself was called. (rjung) JKStatus: Enhance URI to worker map listing. Update stale uriworkermap.properties immediately. (rjung) 43873: Fix small memory leak occuring during httpd restart. (rjung) Common: Allow '*' for the worker name in exclusion rules (resp. JkUnMount) which will override all workers. (rjung) 42038: Correct overlay of mounts and unmounts for IIS. (rjung) 43684: Replace JkMountFile by JkMountFileReload in uriworkermap.properties docs. (rjung) Apache: Add new value "All" for JkMountCopy. (rjung) 43516: Memory leak for Apache httpd module of size 8KB for every virtual host without JK directive after each restart. (rjung) Apache: Cleanup init and destroy of server configuration. (rjung) Apache: Remove global configuration items from per server configuration. (rjung) Apache: Remove unused attributes secret_key and automount/JkAutoMount. (rjung) Cleanup of jk_uri_worker_map. (rjung) Documentation: Small additions to JkShmFile documentation. Contributed by Gerhardus Geldenhuis. (rjung) AJP13: Ignore flush packets before we received the response headers. (rjung) Fix crash during startup when using worker configuration inheritance (attribute "reference") and log level debug. (rjung) AJP13: Match header names exactly against pre defined constants. Avoid possible confusion with custom header names using a standard header name as a prefix. (rjung) jkstatus: Fix correct parameter validation at JkStatusUpdateTask and JkStatusUpdateLoadbalancerTask ant tasks. Reported by Christian Mittendorf. (pero)
    IIS: Fix shm shutdown behaviour. (rjung) General: fail_on_status used in a load balancer can optionally do fail over without putting the failed worker in error state. (rjung) NSAPI: Improve build description for Unix. (rjung) NSAPI: Add initialization startup message containing JK version. (rjung) General: Declare static functions as static. (jim) Documentation: Clarify fail_on_status behaviour. (rjung) General: Do fail_on_status before returning the response headers. (rjung) NSAPI: Fix shm shutdown behaviour. (rjung) NSAPI: Set return status even if request ended with an error. (rjung) NSAPI: Allow using without shm_file on WIN32 and Netware. (rjung) NSAPI: Fix Crash of nsapi for log level debug and unset refect_unsafe. (rjung) NSAPI: Improve Solaris and Linux Makefiles for nsapi build. (rjung) Build: Improve pid_t type detection during configure on Solaris. (rjung) Build: Experimental build support for gcc on WIN32 and Netware. (fuankg) Build: Makefile optimizations for Apache httpd 1.3/Netware . (fuankg) General: Fix missing flush bug introduced in 1.2.24. (rjung)
    Documentation: Improved workers.properties description in the reference guide. (rjung) Documentation: Add a HowTo about the various timeouts. rjung) Logging: add milliseconds to the default timestamp format, if we have gettimeofday(). (rjung) Apache: add milliseconds (%Q) and microseconds (%q) as possible JkLogStampFormat conversion specifiers. This does not use strftime(), but needs gettimeofday(). (rjung) IIS & Sun: Log service failures also, if return code is negative. (rjung) 42849: Abort startup of Apache httpd 1.3 in case mod_jk initialization failed. We already do the same for Apache httpd 2.x. (rjung) 42849: Refuse to operate with IIS in case the initialization failed. Instead requesting isapi_redirect.dll 500 will be returned to the user. This is as closest as it can get to Apache Httpd where we refuse to start the server in case of fatal initialization errors. (mturk) Load Balancer: Fix a deadlock in lb worker, which was exposed on Solaris for threaded Apache MPMs. (rjung) Logging: handle LWP IDs as 32 Bit unsigned. Try to make it work, although pthread IDs are opaque. (rjung) JkStatus: Added manipulation of max_reply_timeouts. (rjung) LB, Status: Add feature max_reply_timeouts, to make lb tolerant against occasional long running requests. (rjung) JkStatus: Added OK/IDLE as the successor of N/A. (rjung) Status worker: Renamed runtime states. All states have a major state (OK or ERR) and a substate. Changed the name N/A to OK/IDLE. Added docs about the meaning of the states to the status worker page in the reference guide. No new states have been added to code. (rjung) Common: Add recovery options for recovering idempotent http methods HEAD and GET. (rjung) Correct documentation for worker attributes retries and recovery_options. (rjung) Make writing log lines and line endings more atomic. (rjung) Common: Refactored and unified jk_map_read_prop* and jk_map_load_prop* for all use cases. (rjung) Common/Apache/IIS/Netscape: Add an option to check decoded URLs for potentially malicious constructions. (rjung) IIS: Document auth_complete and uri_select. (rjung) Apache/IIS/Netscape: Change the default forwarding encoding to the new proxy method. (jfclere, rjung) Common: Optionally reencode URIs before forwarding to the backend. Based on the URI reencoding done bei httpd mod_proxy. (jfclere, rjung) Common: auto-detect correct print format for pid_t. This fixes at least compiler warnings on Solaris. (rjung) 42608: Handle Content-length as unsigned 64Bit to allow for huge up- and downloads. (rjung) Apache: Add forwarding uri to debug log. (rjung) Docs: Clarify relation between worker names and jvmRoute for load balancing. (rjung) Use initial zero timeout for jk_is_socket_connected. The resulting detection is the same but offers a huge performance increase with mod_jk. In most cases the Operating System does not favor the 1 microsecond timeout, but it rather rounds that up to much higher value (frequency of interrupt timer which on most systems defaults to 100Hz). Patch provided by David McLaughlin. (mturk) NSAPI: Check correct log file and shm file configuration during startup. (rjung) NSAPI: Add support for the general options concerning retries, flushing and connection persistance. (rjung) NSAPI: fix crashes due to use of mount attribute in workers.properties. Changed initialization order. (rjung) Improved handling of libtool and discrepancies between CC env variable and CC used during apache build by configure script. (rjung) Always build with thread support, unless flag --enable-prefork is set during for configure. (rjung) Use snprintf/vsnprintf from ap_snprintf.c for platforms other than Windows, which might lack snprintf/vsnprintf implementations when NOT build for Apache httpd 2.x/APR (e.g. Sub Web Server) or without using configure. (fuankg) Imported ap_snprintf() from Apache 1.3. (fuankg) Fix incorrect log object cleanup during statup, leading to crashes at least on iSeries. (rjung) Add jk_stat() and jk_file_exists() as wrapper functions. i5/OS V5R4 expects filename in ASCII for fopen but requires them in EBCDIC for stat(). (hgomez) i5/OS (AS/400) V5R4 port where Apache 2.0 modules should now use UTF8. (hgomez) Docs: Add comments on i5/OS build for V5R4 and previous releases. (hgomez)
    [CVE-2007-0450] and [CVE-2007-1860]: Change the default value of JkOptions to ForwardURICompatUnparsed. The old default value was ForwardURICompat. This should make URL interpretation between Apache httpd and Tomcat consistent (prevent double decoding problems). (rjung)
    Refactor line endings logging to make it correct for all platforms and webservers. (mturk) Added command line windows make files. (mturk) Allow fail_on_status directive to be multi line. (mturk) 42076: Fix name of new option from ForwardCertChain to ForwardSSLCertChain as documented. (rjung) Docs: Fix a couple of typos, change format of a few tables, fix links to news pages. (rjung) Fix correct URL for TC 6 examples in new IIS rewrite.properties configuration example file. (rjung) Add svn properties to several files. (rjung) Add TC 6 examples to uriworkermap.properties in config examples. (rjung) Allow multiple status codes for fail_on_status directive. The status codes can be delimited by space or comma characters. (mturk) IIS. Added pcre like regular expressions for url rewrite rules. (mturk) 41922: Apache 1.3. Enable JkEnvVar. (mturk) Apache. Add --enable-flock configure parameter for explicit compilation of faster flock() system calls for OS supporting those calls. By default the fcntl system call for locking will be used that is a little bit slower but it can work on NFS mounted volumes as well. (mturk) 41562: Add Debug logging for read from client in ISAPI Redirector. Contributed by Tim Whittington. (mturk) Apache. Add ForwardSSLCertChain JkOption. Contributed by Patrik Schnellmann. (mturk) IIS. Do not forbid access to web-inf or meta-inf if there is no mapped worker. This allows to have resource with those names that are outside mapped contexts. (mturk) Apache. Use process id for creating shared memory name and delete shared memory and shared memory lock files on exit. (mturk) IIS. Fix Keep-Alive regression introduced in 1.2.21. (mturk) Delete unused check for empty init_map during startup. (rjung) 41770: Fix startup error if no JkWorkersFile is used. (rjung) Use JK_TRUE/JK_FALSE instead of OK/!OK as return values in init_jk(). (rjung) Minor adjustments to apache startup log messages (when to use STDERR, remove deprecated NOERRNO flag, shm warning and warnings for usage of default files). (rjung) Replace APR precompiler directive by httpd mpm_query to detect MPM threading. Add a debug log message about auto-detected pool size. (rjung) Make MMN check easier to understand and a little more precise (for new ap_get_server_banner()/ap_get_server_description()). We use the new API only for Apache httpd 2.3. This way our binaries are not tightly coupled to a minor 2.0 version, and we don't use ap_get_server_banner() any way. (rjung) Use the full description string ap_get_server_description() instead of the truncated info from ap_get_server_banner(), because this info gets used internally (status worker display and ajp14 backend communication) and is not send back to the normal user. (rjung) 41757: Document the "--enable-prefork" flag of configure. (rjung) Enhance log messages for failures when parsing attribute maps. (rjung) Correct log message during worker initialization, in case remote host could not be resolved. We logged the default host name "localhost" instead of the configured one. (rjung) 41770: Fix the second part of the bug: local_worker and local_worker_only is missing from the list of deprecated attributes (and not supported either), so prevents the web server from startup. (rjung)
    [CVE-2007-0774]: A denial of service and critical remote code execution vulnerability. Caused by buffer overflow in map_uri_to_worker() when URL were longer that 4095 bytes. Reported by ZDI (www.zerodayintiative.com). Please note this issue only affected versions 1.2.19 and 1.2.20 of the Apache Tomcat JK Web Server Connector and not previous versions. Tomcat 5.5.20 and Tomcat 4.1.34 included a vulnerable version in their source packages. Other versions of Tomcat were not affected. Check the worker. parameters and don't start if the parameter is not a valid one. (jfclere) 41439: Allow session IDs to get stripped off URLs of static content in Apache by adding JkStripSession directive (configurable per vhost). (mturk) Change semantics of empty defaults for JkEnvVar variables. Until 1.2.19: not allowed. In 1.2.20: send variables as empty strings, if neither set to non empty in config, nor during runtime. Starting with 1.2.21: If config has no second argument only send variable if set (even when set to empty string) during runtime. Allows good combination with condition attribute in tomcat access log. (rjung) 41610: Fix incorrect detection of missing Content-Length header leading to duplicate headers. Contributed by Boris Maras. (rjung) Better build support for SunONE (Netscape/iPlanet) webservers. (jim) Add warning if duplicate map keys are read and are not allowed, e.g. when parsing uriworkermap.properties. (rjung) Don't concat worker names, if uriworkermap.properties has a duplicate pattern, instead overwrite the worker. (rjung) Log deprecation message even in duplication case. (rjung) uriworkermap.properties: Fix off-by-one problem when deleting URL mapping during reloading of uriworkermap.properties. (rjung) 41439: Allow session IDs to get stripped off URLs of static content in IIS (configurable). (rjung) 41333: Refactoring isapi_plugin configuration reading. (rjung) 41332: Add some more errno logging and unify the format. (rjung) JkStatus: Improved logging by adding status worker name to messages. Added messages to the recover worker action. (rjung) JkStatus: Refactoring searching for workers and sub workers. (rjung) 41318: Add configuration to make status worker user name checks case insensitive. (rjung) JkStatus: Add estimated time until next global maintenance to other mime types and adopt jkstatus ant task. (rjung) JkStatus: Show estimated time until next global maintenance. Change displayed time until next recovery to a min/max pair. (rjung) JkStatus: Allow a user of a read/write status worker to switch it to and from read_only mode temporarily. (rjung) JkStatus: Do not show read/write commands in a read_only status worker. (rjung) JkStatus: Allow lb sub workers in error state to be marked for recovery administratively from the status worker. (rjung) Load Balancer: Do not try to recover multiple times in parallel. Use additional runtime states "PROBE" and "FORCED". (rjung) JkStatus: Improve data synchronization between different processes. (rjung) 41381: Fix segfault in feature fail_on_status (wrong order of log arguments). Patch by Juri Haberland. (rjung) Use correct windows line endings for log file on WIN32 platform. (rjung)
    JkStatus Ant Task documentation page. (pero/rjung) JkStatus Ant Tasks: Add new tasks for update and reset. (pero) JkStatus Ant Tasks: Update for new xml status format. (pero) Allow integer and string values when setting enumeration/boolean attributes via status worker update action. (rjung) Docs: New reference guide page for status worker. (rjung) Docs: Renaming the config dir to reference and using the title Reference Guide in the docs. (rjung) Added retry_on_status for workers directive. (mturk) Status Worker: Add directive to make property prefix and good/bad rule configurable. (rjung) Status Worker: Omit lb members when att=nosw. (rjung) Status Worker: New command cmd=version for a short version output. (rjung) Status Worker: New output stype mime=prop produces property lists. (rjung) Apache: Fix incorrect handling of JkEnvVar when Vars are set multiple times. (rjung) Renamed jvm_route to route. Deprecated jvm_route, but still use it as fallback when parsing the worker configuration. (rjung) IIS: Make uriworkermap file reload check interval configurable. (mturk) Apache: Make uriworkermap file reload check interval configurable. (rjung) Status Worker: Add directives for customizing the XML output (ns, xmlns, doctype). (mturk) Docs: New page with description of uriworkermap. (rjung) Docs: Added short description of max_packet_size to worker reference. (rjung) Status Worker: All functions accessible also for xml and txt mime types (list, show, update, reset). (rjung) Status Worker: New global health indicators for load balancers named bad (error, recovering or stopped), degraded (busy or disabled) and good (the rest, active and OK or N/A). (rjung) Status Worker: New edit page, to change one attribute for all members of a load balancer. (rjung) Status Worker: Standard logging for status worker. (rjung) Status Worker: code refactoring. (rjung) Status Worker: New attribute user (list) denies access, if the request user in the sense of remote_user is not in this list. Empty list = no deny (rjung) Status Worker: New attribute read_only disables the parts of the status worker, that change states and configurations. (rjung) 36121: Don't change main uri when mod_jk serves included uri. (markt) Apache VHosts: Merge JkOptions +base - -base + +vhost - -vhost. (rjung) Apache Docs: Adding requirements, context information, default values and inheritance rules to the Apache config documentation. (rjung) Status Worker: Add source type to status worker, remove the redundant "context" column in the map listing (context=uri). (rjung) uriworkermap: On reload of the file, all old entries from the previous file version get deleted, before the new ones are being read. (rjung) Keep normal maps and exclusion maps internally separate. Don't treat them as the same when adding a rule. (rjung) Status Worker: Display mapping rules also for non-lb workers and in global view. (rjung) Apache VHosts: Use the vhost log files instead of the main log. (rjung) Apache VHosts: Allow individual timestamp formats by refactoring the formatting method. (rjung) Apache VHosts: Adding all missing config items to the virtual host level. Don't overwrite the settings from the global server, but inherit them in case they are not set in the virtual host. (rjung) Apache: remove unnecessary function names from log messages. (rjung) Apache: add a default log file location and a message, if the default gets used. (rjung) Apache: add missing JK_IS_DEBUG_LEVEL() (rjung) Apache VHosts: Allow JkWorkersFile, JKWorkerProperty, JkShmFile and JkShmFileSize only in global virtual server. (rjung) Add some more jk_close_socket() and reduce log level for some info messages. (rjung) Load Balancer: Added the Sessions strategy. Contributed by Takayuki Kaneko. (rjung) Docs: Minor enhancements and syncing with more recent versions. (rjung) 40997: Separate uri mappings from their '!' counterpart when checking for duplicates in uriworkermap reloading. (rjung) 40877: Make sure the shared memory is reset on attach for multiple web server child processes. (mturk) IIS: Added shm_size property to be able to deal with over 64 workers configurations. (mturk) IIS: Increase default thread count to 250, so its the same as Apache Httpd default configuration. (mturk) 40966: Fix socket descriptor checks on windows. (mturk) 40965: Initialize missing service parameters. (mturk) 40938: Fix releasing of rewrite map. Thanks to Chris Adams for spotting that. (mturk) Apache: Added +FlushHeader JkOptions. (mturk) Added explicit flush when AJP body packet size is zero. (mturk) 40856: Fixing case sensitivity bug in URL mapping. (rjung) 40793: Documentation: Improvements to Apache HowTo provided by Paul Charles Leddy. (markt) 40774: Fixing wrong recursion termination. This one restricted the "reference" feature unintentionally to 20 workers. (rjung) 40716: Adding "reference" feature to IIS and Netscape. (rjung) Documentation: Corrected SetEnvIf syntax in JK_WORKER_NAME example. (rjung) Documentation: Added forgotten STATE and ACTIVATION notes for load balancer logging in Apache. (rjung) Apache: Use instdso.sh instead libtool: libtool does not work on HP-UX for example. (jfclere)
    Docs: Add SetHandler and new env var to Apache config docs. (rjung) Apache 1.3: Backport "no-jk" feature. (rjung) Apache: Add an environment variable to make SetHandler "jakarta-servlet" more useful. The variable is JK_WORKER_NAME, but can be changed by the new directive JkWorkerIndicator. (rjung) LB: Don't use single worker shortcut, if the single worker is being diabled. (rjung) Status worker: Add short explanation of activation and error states to legend. (rjung) Docs: Add meaning of zero timeout values for various timeouts in workers.properties. (rjung) LB: Cleanup of Mladens forced recovery. (rjung) LB: Do not change lb_value for recovering workers to max, if we are using BUSYNESS method. (rjung) Apache: Since 1.2.14 mod_jk failed to detect client abort. (rjung) Docs: Corrected description of JkEnvVar. (rjung) Solaris: Detect filio.h in configure to make the new connection detection build on solaris (r432825). (rjung) Add feature to force the recovery of workers that are member of loadbalancer if all the members are in error state. This fixes the time gap where 503 was returned caused by recovery_timeout although the backend was ready to handle the requests. (mturk) Docs: Seperate deprecated directives in their own table. (rjung) Docs: Allow "-" and "_" in worker names. (rjung) Allow multiple lines with attributes "balance_workers" and "mount". (rjung) Make jk_is_some_property match more precisely. (rjung) JkStatus: Make refresh interval changeable. (rjung) JkStatus: Adjust display of recover time wrt. global maintenance. (rjung) LB: Resetting worker state from OK to NA, if worker has been idle too long. (rjung) Avoid compiler warnings concerning the use of lb_*_type arrays. Use functions instead. (rjung) Added %R JkRequestLogFormat option for Apache 1 and Apache 2. (mturk) Allow changing jvm Route from status manager. (mturk) Do not retun 400 if Tomcat fails in the midle of the post request. Return 500 insted. (mturk) LB: Combine ok/error/recovering/busy runtime states into a single scalar. (rjung) LB: Combine active/disabled/stopped configuration states into a single scalar. (rjung) LB: Add several Apache notes to enable standard logging for load balancer results. (rjung) LB: Reorganisation of the main load balancer service loop. (rjung) Implement hierarchical worker configuration via attribute "reference". (rjung) Log deprecated properties. (rjung) IIS: Fix simple_rewrite for the cases where the rewritten url is larger then the original one. (mturk) New JkOption "DisableReuse" to disable connection persistence. (jim) LB: Move sessionid retrieval out of get_most_suitable_worker into service. (rjung) Code cleanup for all service methods (use TRACE, JK_LOG_NULL_PARAMS, null pointer checks). (rjung) JKSTATUS: add refresh link. No refresh for updates. Redirect to list view after update. (rjung) Add new hook add_log_items into servers. (rjung) APACHE httpd: Rename apache logging notes. (rjung) LB: Rename lock and method constants. Add constants for defaults. (rjung) Default log level should be INFO and not DEBUG. Default log level should be the same for all server types. (rjung) Make rewrite_rule_map and log_level as non mandatory directives for isapi_redirect. (mturk) 40107: Rewrite is_socket_connected function. Non blocking socket is not used any more. (mturk) Allow building with VS2005 without too many warnings. (mturk) Decide by MMN, which piped log API we should use. mod_jk 1.2.18 broke compilation with Apache 1.3 pre 1.3.28. (rjung)
    Using socklen_t in getsockopt. Also introducing jk_sock_t. (mturk) Allow recovery wait time below 60 seconds (new minimum is 1 second). (mturk)
    Fix hanging jk status worker when certain attributes are being updated due to double locking. (rjung) Allow JkMount to behave like uriworkermap.properties by parsing pipe symbol as two directive marker. (mturk)
    Added simple rewrite capability for IIS. Although simple it will fulfill most needs. (mturk) Added RECOVER_ABORT_IF_CLIENTERROR recovery_option that closes the connection if client connection is broken during the request. (mturk) Renamed cache_timeout directive to connection_pool_timeout. (mturk) Added connection_pool_minsize directive. (mturk) Deprecate recycle_timeout directive. (mturk) Corrected some HTML syntax bugs in output of status worker. (rjung) Added the refresh=n parameter to the status worker. It will update the display every n seconds. (rjung) Balancer: Add attribute distance to balanced workers to express preferences between workers. (rjung) Balancer: Add attribute jvm_route to balanced workers to be able to use the same target in different balancers. (rjung) Status: Add lb_mult to status. (rjung) Balancer: Make different balancing strategies work in a similar way (use lb_value, use decay during global maintenance, use integer factors for weights. (rjung) Balancer: Improve locking. (rjung) Balancer: Workers start slower after recovering. (rjung) Balancer: Make different balancing strategies work in a similar way (use lb_value, use decay during global maintenance, use integer factors lb_mult for weights). (rjung) Balancer: Move recovery check to global maintenance. (rjung) Balancer: Add global maintenance method, that is called in only one process. (rjung) Extend our use of autoconf to find a 32Bit and a 64Bit unsigned type and their printf formats. (rjung) Logging: piped loggers for JkLogFile and Apache 1.3. (rjung) Logging: Add PID to log lines for each log level apart from REQUEST. (rjung) Logging: flush buffered logs to keep lines in correct order. Output final newline together with log message. (rjung) Reducing shm size. (rjung) Only log removing of old worker, when we actually do it. (rjung) 37469: Fix shared memory close for forked childs. The shared memory will be closed by the parent process. (mturk) 37332: Fix potential misuse of buffer length with snprintf functions. (mturk) 38859: [CVE-2006-7197] Protect mod_jk against buggy or malicious AJP servers in the backend. Patch provided by Ruediger Pluem. (mturk) 38889: Use worker map sorting depending on the path elements, to comply with Servlet spec. Patch provided by Steve Revilak. (mturk) 36138: Added Busyness lb method. Patch provided by Chris Lamprecht. (mturk) Fix pessimistic locking mode. The patch correctly handles the burst load, by syncing the access to the shared memory data. (mturk) 38806: Reclycle worker even if it is disabled. This fixes hot-standby workers in error state. (mturk) 37167: Allow building with BSD-ish like make. (mturk) ISAPI plugin (isapi_redirect.dll) did not provide correct request data for IIS to include in the IIS log. (markt)
    Fix AJP13 Cookie2 parsing. Cookie2 was always send as Cookie. Patch provided by Andre Gebers. (mturk) 35862: NSAPI plugin attempts to read freed memory and attempts to dereference a null pointer. Patch provided by Brian Kavanagh. (markt)
    Fix lb for worker mpm's with cachesize set to lower number then ThreadsPerChild is. If retries is set to value larger then 3 sleep for 100 ms on each attempt. This enables to tune the connection cache, and serialize incoming connections instead returning busy if connection count is larger then cachesize. (mturk) 36525: Solaris core dump. (mturk) 36102: Worker actions do not persist. (mturk) 35864: Status worker doesn't list workers. Patch provided by Martin Goldhahn. (mturk) 35809: JkMountCopy don't work for Apache 2.0 Patch provided by Christophe Dubach. (mturk) 35298: Multiple JK/ISAPI redirectors on a single IIS site are not supported Patch provided by Tim Whittington. (mturk)
    34397: Emergency was handled as Error. (jfclere) 34474: // in URL were not handled correctly with Apache-1.3. (jfclere) Use 64 bits int for transferred/read bytes. Added JkOptions +FlushPackets used to optimize memory usage when sending large data. (mturk) Added lock directive for load balancer that allows more acurate load balancing in case of burst load. (mturk) Added worker.maintain directive to allow customizing default 10 second timeout. On busy servers this value needs to be set on higher value. (mturk) Fix for NetWare compiler to deal with different types between AP13 and AP2 SDKs. (fuankg) Emit much more legible user.dmp crash analysis output for WIN32. (wrowe) 34558: Fix first failover request. (mturk)
    Added ForwardLocalAddress JkOptions flag for passing local instead remote address. Useful for remote addr valve. (mturk) Fix that worker does not get used, when stopped flag is set to true. (pero) Add loadbalance default worker secret attribute to the documentation (pero)
    Backport SC_M_JK_STORED from JK2 for passing arbitrary methods instead failing the request. (mturk) Added missing SEARCH and ACL http methods. (mturk) Add worker secret attribute to the documentation (pero) Add a stopped flag to worker configuration. Set flag to true and the complete traffic to the worker will be stopped. Also update the Ant JkStatusUpdateTask at Tomcat 5.5.10 release. Only usefull in a replicated session cluster.(pero) Added worker maintain function that will maintain all the workers instead just the current one. This enables to recycle the connections on all workers. (mturk) Use shutdown when recycling connections instead hard breaking the socket. (mturk) Add unique directives checking. The directives if unique are now overwritten instead concatenated. (mturk) Allow multiple worker.list directives. (mturk) 34577: For IIS log original request instead loging the request for ISAPI extension. (mturk) 34558: Make sure the returned status codes are the same for ajp and lb workers. (mturk) 34423: Use APR_USE_FLOCK_SERIALIZE for setting log lock on platforms like FreeBSD. Patch provided by Allan Saddi. (mturk) 33843: Fix obtaining LDFLAGS that were used for building Apache HTTPD. Patch provided by Beat Kneubuehl. (mturk) 34358: Enable load balancer method configuration. (glenn) 34357: In some situations Apache 2 mod_jk could segfault when the JkAutoAlias directive is used. (glenn) Add --enable-prefork to the documentation (pero) Update tomcat_trend.pl for new error log string formatting. (glenn)
    Set default shared memory to 64K instead 1M. (mturk) Do not mark the worker in error state if headers are larger then AJP13 limit. (mturk) On iSeries you should use the latest PTF for Apache 2.0 (which is now 2.0.52) and ad minima SI17402/SI17061 or cumulative including them. (hgomez) Change the xml status format to xml attribute syntax (pero) 33248: Fix builds where apxs defines multiple directories for APR includes. (mturk) 32696: Return 404 instead 403 when WEB-INF is requested to comply with Servlet spec. (mturk) Added ANT task for managing jkstatus. (pero) If socket_timeout is set, check if socket is alive before sending any request to Tomcat. (mturk) Added JkMountFile for Apache web servers. This file can contain uri mappings in the form (/url=worker), and is checked for updates at regular 60 second interval. (mturk) Added status worker for managing worker runtime data using web page. (mturk) Added load balancer method directive that is used for setting the algorithm used for balancing workers. Method can be either Request (default) or Traffic. (mturk) Added shared memory to allow dynamic configuration. Shared memory is needed only for unix platform and web servers having multiple child processes. For Apache web server two new directives has been added (JkShmFile and JkShmSize). (mturk) Added textupdate mode to status worker to handle remote updates from ant tasks.(pero) 33562: Fix Reply_timeout when recovery_options is larger than 1. Patch provided by Takashi Satou. (mturk) 33308: Fix segfaults when ForwardDirectories is enabled with Apache 1.3
    Allow anyone to debug and diagnose stack dumps using windbg or any other debugging tool, and (if they add the .pdb files to their installation) to make sense of dr watson logs. Patch provided by William A. Rowe (wrowe) Fix in_addr_t usage by using the real struct ignoring typedef. Patch provided by William A. Rowe (wrowe) Fix url rewriting by restoring the in place uri from which the jsessionid was removed. (mturk) Make load balancer algorithm thread safe by introducing mutex to the load balancer worker. (mturk) Fix sending error pages for IIS to client by adding Content-Type header using correct api function call. (mturk) 32696: Prevent IIS from crushing when web-inf url was requested. (mturk) Use default cachesize for servers that support discovering the number of threads per child process. (mturk). Fix Apache content-length header parsing using case insensitive compare. (billbarker) Fix parsing AJP headers using case insensitive compare. (mturk) Use infinite socket timeout if socket_timeout is set to zero or less then zero. (mturk) Change balanced_workers to balance_workers but keep backward compatibility preserving the old directive. (mturk). Fix ajp initialization for workers with cache_size set to zero. (mturk) 32317: Making mod_jk replication aware (Clustering Support). Patch provided by Rainer Jung. (mturk). 31132: Core dump when JkLogFile is missing from conf. (mturk)
    Added new property named recover_time that can be used to change the default 60 second recover time. (mturk) Added custom retries for worker, so we don't depend on default setting. If set to a number grater then 3, it will sleep for 100ms on retry greater then 3 and then try again. (mturk) Added JkWorkerProperty directive that enables omiting workers.properties file. For example: JkWorkerProperty worker.ajp13a.port=8009. (mturk) Check all JSESSIONID cookies for a valid jvmRoute. If you have multiple Tomcats with overlapping domains, then you can get multiple cookies without a defined order. This will route correctly as long as the different domains don't have any Tomcats in common. (billbarker) Added JkUnMount directive for negative mappings that works as opposite to JkMount directives. It is used for blocking of particular URL or content type. (mturk) Added wildchar match uri mappings. One can now use JkMount to map /app/*/servlet/* or /app?/*/*.jsp. (mturk) Rewrite the logging by adding Trace options. (mturk) Added socket_timeout property that sets the timeout for the socket itself. (mturk) Changed socket_timeout property to recycle_timeout. This better explains what the directive actually does. (mturk) Changed the load balancer algorithm. The idea behind this new scheduler is the following: lbfactor is how much we expect this worker to work, or the worker's work quota. lbstatus is how urgent this worker has to work to fulfill its quota of work. We distribute each worker's work quota to the worker, and then look which of them needs to work most urgently (biggest lbstatus). This worker is then selected for work, and its lbstatus reduced by the total work quota we distributed to all workers. Thus the sum of all lbstatus does not change.(*) If some workers are disabled, the others will still be scheduled correctly. (mturk) Fix iis redirector that was figuring .properties file on each request. (mturk) Start fixing 64/32 bit compatibility issues. (mturk)
    Fix POST Recovery problems in LB mode. (hgomez) Add CPING/CPONG support to avoid problems with hang tomcats. (hgomez) Make POST recovery in LB configurable. (hgomez) Update to Apache License 2.0. (hgomez) For Apache 2.0, when the env var no-jk is present, mod_jk didn't handle request (declined) and as such dont forward requests to tomcats even if URL match. To be used with SetEnvIf or BrowserMatch directives for example to exclude some URL/URI or Browser (hgomez). Add a fix for iSeries (AS/400) which use XOPEN/Unix98 APIs and need sa_len to be set when calling connect(), it will resolve the error EINVAL in jk_connect. (hgomez)
    Fix a thread safe bug when mapping URI's. (billbarker) Fix a thread safe bug when resolving worker host name when using mod_jk with Apache 2 and the worker MPM. (hgomez) Remove an unnecessary error message when connections to all load balanced workers fail. (glenn) When mod_jk cannot connect to a worker include the name of the worker in the error message. This is especially helpful when you are using load balanced workers. (glenn) Fix problem with mod_jk.log getting opened multiple times for Apache 2. Only one mod_jk.log can be configured. (glenn) Fix Apache 2 connector so that DirectoryIndex works for an index.jsp page if JkOptions ForwardDirectories was configured. (hgomez) Fix exposure of JSP source if a //path/to.jsp URL was requested in Apache 1.3 and Apache 2.0 connector. (billbarker)
    Fix use of libtool for Apache mod_jk builds with more recent versions of Apache 2. (jfclere) Use reentrant version of strtok() for web server's which use threads. This fixes a thread safe bug under Apache 2 and the worker MPM. (glenn) Fix the Apache 2 mod_jk hook priority so that mod_jk works well with both mod_alias and mod_dir. (glenn)
    Add the ability to configure JkLog to pipe its log output to an executable such as Apache rotatelogs or cronolog. Apache 2.0 only. (glenn) Add JkAutoAlias to Apache 2.0. (glenn) Apache 2/1.3, if Tomcat returns an error but not content, let Apache handle processing the error returned by Tomcat. (glenn) Added the load balancer sticky_session property. If set to 0 requests with servlet SESSION ID's can be routed to any Tomcat worker. Default is 1, sessions are sticky. (glenn) Cleaned up detection and reporting of aborted client connections. This cleanup also makes sure that mod_jk does not pass any requests on to Tomcat if the remote client aborted its connection. (glenn) Fixed a bug in Apache 2.0 which caused a POST request forwarded to Tomcat to fail if it generated SSI directives which were post processed by mod_include. (glenn) Fixed a bug in JkRequestLogFormat when printing the request URI that could cause a URI with hex escapes sequences to be formatted wrong. (glenn)
    tomcat_trend.pl updated script to support changed logging of aborted requests. (glenn) jk set correctly the content-type in Apache 2.0, making it ready to works with mod_deflate and AddOutputFilterByType. (hgomez) jk will check result of get_endpoint and handle a failure. This call can fail if the allocation for the endpoint fails because of low memory conditions causing a dereference of NULL when we try and access the endpoint. (mmanders)
    14282: Don't send initial chunk for chunked encoding. (costin) Add perl scripts for analyzing mod_jk logs and generating graphs/reports. (glenn) Make JK honor the CanonicalHost directive. (hgomez) Log cleanup. (costin) Fix typos in jk xdocs/docs. (hgomez) Add JkRequestLogFormat to Apache 2.0. (hgomez) Final patches to make JK iSeries compliant. (hgomez)

    JK2 has been put in maintainer mode and no further development will take place. The reason for shutting down JK2 development was the lack of developers interest. Other reason was lack of users interest in adopting JK2, caused by configuration complexity when compared to JK.

    tomcat-connectors-1.2.50-src/xdocs/common_howto/0000755000000000000020000000000014655113617020154 5ustar rootbintomcat-connectors-1.2.50-src/xdocs/common_howto/loadbalancers.xml0000644000000000000020000002271214655113617023474 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Load Balancing HowTo Mladen Turk

    A load balancer is a worker that does not directly communicate with Tomcat. Instead it is responsible for the management of several "real" workers, called members or sub workers of the load balancer.

    This management includes:

    • Instantiating the workers in the web server.
    • Using the worker's load balancing factor, perform weighted load balancing (distributing load according to defined strengths of the targets).
    • Keeping requests belonging to the same session executing on the same Tomcat (session stickyness).
    • Identifying failed Tomcat workers, suspending requests to them and instead failing over on other workers managed by the load balancer.
    • Providing status and load metrics for the load balancer itself and all members via the status worker interface.
    • Allowing to dynamically reconfigure load balancing via the status worker interface.

    Workers managed by the same load balancer worker are load balanced (based on their configured balancing factors and current request or session load) and also secured against failure by providing failover to other members of the same load balancer. So a single Tomcat process death will not "kill" the entire site.

    Some of the features provided by a load balancer are even interesting, when only working with a single member worker (where load balancing is not possible).

    A worker is configured as a load balancer by setting its worker type to lb.

    The following table specifies some properties used to configure a load balancer worker:

    • balance_workers is a comma separated list of names of the member workers of the load balancer. These workers are typically of type ajp13. The member workers do not need to appear in the worker.list property themselves, adding the load balancer to it suffices.
    • sticky_session specifies whether requests with SESSION ID's should be routed back to the same Tomcat instance that created the session. You can set sticky_session to false when Tomcat is using a session manager which can share session data across multiple instances of Tomcat - or if your application is stateless. By default sticky_session is set to true.
    • lbfactor can be added to each member worker to configure individual strengths for the members. A higher lbfactor will lead to more requests being balanced to that worker. The factors must be given by integers and the load will be distributed proportional to the factors given. Higher factors lead to more requests.
    # The load balancer worker balance1 will distribute # load to the members worker1 and worker2 worker.balance1.type=lb worker.balance1.balance_workers=worker1, worker2 worker.worker1.type=ajp13 worker.worker1.host=myhost1 worker.worker1.port=8009 worker.worker2.type=ajp13 worker.worker1.host=myhost2 worker.worker1.port=8009 Session stickyness is not implemented using a tracking table for sessions. Instead each Tomcat instance gets an individual name and adds its name at the end of the session id. When the load balancer sees a session id, it finds the name of the Tomcat instance and sends the request via the correct member worker. For this to work you must set the name of the Tomcat instances as the value of the jvmRoute attribute in the Engine element of each Tomcat's server.xml. The name of the Tomcat needs to be equal to the name of the corresponding load balancer member. In the above example, Tomcat on host "myhost1" needs jvmRoute="worker1", Tomcat on host "myhost2" needs jvmRoute="worker2".

    For a complete reference of all load balancer configuration attributes, please consult the worker reference.

    The load balancer supports complex topologies and failover configurations. Using the member attribute distance you can group members. The load balancer will always send a request to a member of lowest distance. Only when all of those are broken, it will balance to the members of the next higher configured distance. This allows to define priorities between Tomcat instances in different data center locations.

    When working with shared sessions, either by using session replication or a persisting session manager (e.g. via a database), one often splits up the Tomcat farm into replication groups. In case of failure of a member, the load balancer needs to know, which other members share the session. This is configured using the domain attribute. All workers with the same domain are assumed to share the sessions.

    For maintenance purposes you can tell the load balancer to not allow any new sessions on some members, or even not use them at all. This is controlled by the member attribute activation. The value Active allows normal use of a member, disabled will not create new sessions on it, but still allow sticky requests, and stopped will no longer send any requests to the member. Switching the activation from "active" to "disabled" some time before maintenance will drain the sessions on the worker and minimize disruption. Depending on the usage pattern of the application, draining will take from minutes to hours. Switching the worker to stopped immediately before maintenance will reduce logging of false errors by mod_jk.

    Finally you can also configure hot spare workers by using activation set to disabled in combination with the attribute redirect added to the other workers:

    # The advanced router LB worker worker.list=router worker.router.type=lb worker.router.balance_workers=worker1,worker2 # Define the first member worker worker.worker1.type=ajp13 worker.worker1.host=myhost1 worker.worker1.port=8009 # Define preferred failover node for worker1 worker.worker1.redirect=worker2 # Define the second member worker worker.worker2.type=ajp13 worker.worker2.host=myhost2 worker.worker2.port=8009 # Disable worker2 for all requests except failover worker.worker2.activation=disabled

    The redirect flag on worker1 tells the load balancer to redirect the requests to worker2 in case that worker1 has a problem. In all other cases worker2 will not receive any requests, thus acting like a hot standby.

    A final note about setting activation to disabled: The session id coming with a request is send either as part of the request URL (;jsessionid=...) or via a cookie. When using bookmarks or browsers that are running since a long time, it is possible to send a request carrying an old and invalid session id pointing at a disabled member. Since the load balancer does not have a list of valid sessions, it will forward the request to the disabled member. Thus draining takes longer than expected. To handle such cases, you can add a Servlet filter to your web application, which checks the request attribute JK_LB_ACTIVATION. This attribute contains one of the strings "ACT", "DIS" or "STP". If you detect "DIS" and the session for the request is no longer active, delete the session cookie and redirect using a self-referential URL. The redirected request will then no longer carry session information and thus the load balancer will not send it to the disabled worker. The request attribute JK_LB_ACTIVATION has been added in version 1.2.32.

    The status worker does not communicate with Tomcat. Instead it is responsible for the worker management. It is especially useful when combined with load balancer workers.

    # Add the status worker to the worker list worker.list=jkstatus # Define a 'jkstatus' worker using status worker.jkstatus.type=status

    Next thing is to mount the requests to the jkstatus worker. For Apache HTTP Servers use:

    # Add the jkstatus mount point JkMount /jkmanager/* jkstatus

    To obtain a higher level of security use the:

    # Enable the JK manager access from localhost only <Location /jkmanager/> JkMount jkstatus Require ip 127.0.0.1 </Location>
    tomcat-connectors-1.2.50-src/xdocs/common_howto/project.xml0000644000000000000020000001222014655113617022341 0ustar rootbin The Apache Tomcat Connectors - Common HowTo The Apache Tomcat Connectors - Common HowTo tomcat-connectors-1.2.50-src/xdocs/common_howto/proxy.xml0000644000000000000020000004271514655113617022070 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Reverse Proxy HowTo Rainer Jung

    The Apache HTTP Server module mod_jk and its ISAPI redirector variant for Microsoft IIS connect the web server to a backend (typically Tomcat) using the AJP protocol. The web server receives an HTTP(S) request and the module forwards the request to the backend. This function is usually called a gateway or a proxy, in the context of HTTP it is called a reverse proxy.

    A reverse proxy is not totally transparent to the application on the backend. For instance the host name and port the original client (e.g. browser) needs to talk to belong to the web server and not to the backend, so the reverse proxy talks to a different host name and port. When the application on the backend returns content including self-referential URLs using its own backend address and port, the client will usually not be able to use these URLs.

    Another example is the client IP address, which for the web server is the source IP of the incoming connection, whereas for the backend the connection always comes from the web server. This can be a problem, when the client IP is used by the backend application e.g. for security reasons.

    Most of these problems are automatically handled by the AJP protocol and the AJP connectors of the backend. The AJP protocol transports this communication metadata and the backend connector presents this metadata whenever the application asks for it using Servlet API methods.

    The following list contains the communication metadata handled by AJP and the ServletRequest/HttpServletRequest API calls which can be used to retrieve them:

    • local name: getLocalName(). This is also equal to getServerName(), unless a Host header is contained in the request. In this case the server name is taken from that header.
    • local IP address: getLocalAddr(). The local IP address was initially not supported. It is available when using version 1.2.41 for Apache or IIS together with Tomcat version at least 6.0.42, 7.0.55 or 8.0.11. For older versions or when using the NSAPI redirector, getLocalAddr() will incorrectly return the same result as getLocalName(). As a workaround you can forward the local IP address by setting JkEnvVar SERVER_ADDR and then either using request.getAttribute("SERVER_ADDR") instead of getLocalAddr() or wrapping the request using a filter and overriding getLocalAddr() with request.getAttribute("SERVER_ADDR").
    • local port: getLocalPort(). This is also equal to getServerPort(), unless a Host header is contained in the request. In this case the server port is taken from that header if it contains an explicit port, or is equal to the default port of the scheme used.
    • client address: getRemoteAddr()
    • client port: getRemotePort(). The remote port was initially not supported. It is available when using version 1.2.32 for Apache or IIS together with Tomcat version at least 5.5.28, 6.0.20 or 7.0.0. For older versions or when using the NSAPI redirector, getRemotePort() will incorrectly return 0 or -1. As a workaround you can forward the remote port by setting JkEnvVar REMOTE_PORT and then either using request.getAttribute("REMOTE_PORT") instead of getRemotePort() or wrapping the request using a filter and overriding getRemotePort() with request.getAttribute("REMOTE_PORT").
    • client host: getRemoteHost()
    • authentication type: getAuthType()
    • remote user: getRemoteUser(), if tomcatAuthentication="false"
    • protocol: getProtocol()
    • HTTP method: getMethod()
    • URI: getRequestURI()
    • HTTPS used: isSecure(), getScheme()
    • query string: getQueryString()
    The following additional SSL-related data will be made available by the Apache HTTP Server and forwarded by mod_jk only if you set SSLOptions +StdEnvVars. For the certificate information you also need to set SSLOptions +ExportCertData.
    • SSL cipher: getAttribute(javax.servlet.request.cipher_suite)
    • SSL key size: getAttribute(javax.servlet.request.key_size). Can be disabled using JkOptions -ForwardKeySize.
    • SSL client certificate: getAttribute(javax.servlet.request.X509Certificate). If you want the whole certificate chain, then you need to also set JkOptions ForwardSSLCertChain. It is likely, that in this case you also need to adjust the maximal AJP packet size using the worker attribute max_packet_size.
    • SSL session ID: getAttribute(javax.servlet.request.ssl_session). This is for Tomcat, it has not yet been standardized.

    In some situations this is not enough though. Assume there is another less clever reverse proxy in front of your web server, for instance an HTTP load balancer or similar device which also serves as an SSL accelerator.

    Then you are sure that all your clients use HTTPS, but your web server doesn't know about that. All it can see is requests coming from the accelerator using plain HTTP.

    Another example would be a simple reverse proxy in front of your web server, so that the client IP address that your web server sees is always the IP address of this reverse proxy, and not of the original client. Often such reverse proxies generate an additional HTTP header, like X-Forwareded-for which contains the original client IP address (or a list of IP addresses, if there are more cascading reverse proxies in front). It would be nice, if we could use the content of such a header as the client IP address to pass to the backend.

    So we might need to manipulate some of the data that AJP sends to the backend. When using mod_jk inside the Apache HTTP Server you can use several Apache environment variables to let mod_jk know, which data it should forward. These environment variables can be set by the configuration directives SetEnv or SetEnvIf, but also in a very flexible way using mod_rewrite (since Apache 2.x it can not only test against environment variables, but also set them).

    The following list contains all environment variables mod_jk checks, before sending data to the backend:

    • JK_LOCAL_NAME: the local name
    • JK_LOCAL_PORT: the local port
    • JK_REMOTE_HOST: the client host
    • JK_REMOTE_ADDR: the client address
    • JK_AUTH_TYPE: the authentication type
    • JK_REMOTE_USER: the remote user
    • HTTPS: On (case-insensitive) to indicate, that HTTPS is used
    • SSL_CIPHER: the SSL cipher
    • SSL_CIPHER_USEKEYSIZE: the SSL key size
    • SSL_CLIENT_CERT: the SSL client certificate
    • SSL_CLIENT_CERT_CHAIN_: prefix of variable names, containing the client cerificate chain
    • SSL_SESSION_ID: the SSL session ID

    Remember: in general you don't need to set them. The module retrieves the data automatically from the web server. Only in case you want to change this data, you can overwrite it by using these variables.

    Some of these variables might also be used by other web server modules. All variables whose name does not begin with "JK" are set directly by the Apache HTTP Server. If you want to change the data, but do not want to negatively influence the behaviour of other modules, you can change the names of all variables mod_jk uses to private ones. For the details see the Apache reference page.

    All variables, that are not SSL-related have only been introduced in version 1.2.27.

    In addition there are two special shortcuts to influence the client IP address that is forwarded. Using JkOptions ForwardLocalAddress you can forward the local IP address of the web server as the client IP address. This can be useful, e.g. when using the Tomcat remote address valve for allowing connections only from registered Apache HTTP Servers. Using JkOptions ForwardPhysicalAddress you always forward the physical peer IP address as the client address. By default mod_jk uses the logical address as provided by the web server. For example the module mod_remoteip sets the logical IP address to the client IP forwarded by proxies in the X-Forwarded-For header.

    As an alternative to using the environment variables described in the previous section (which do only exist when using Apache), you can also configure Tomcat to overwrite some of the communications data forwarded by mod_jk. The AJP connector in Tomcat's server.xml allows to set the following properties:

    • proxyName: server name as returned by getServerName()
    • proxyPort: server port as returned by getServerPort()
    • scheme: protocol scheme as returned by getScheme()
    • secure: set to "true", if you wish isSecure() to return "true".
    Remember: in general you don't need to set those. AJP automatically handles all cases where the web server running mod_jk knows the right data.

    Sometimes one want to change path components of the URLs under which an application is available. Especially if a web application is deployed as some context, say /myapp, marketing prefers short URLs, so want the application to be directly available under http://www.mycompany.com/. Although you can deploy the application as the so-called ROOT context, which will be directly available at "/", admins often prefer not to use the ROOT context, e.g. because only one application can be the root context (per host).

    The procedure to change the URLs in the reverse proxy is tedious, because often an application produces self-referential URLs, which then include the path components which you tried to hide to the outside world. Nevertheless, if you absolutely need to do it, here are the steps.

    Case A: You need to make the application available at a simple URL, but it is OK, if users proceed using the more complex URLs, as long as they don't have to type them in. That's the easy case, and if this suffices to you, you're lucky. Use a simply RedirectMatch for the Apache HTTP Server:

    RedirectMatch ^/$ http://www.mycompany.com/myapp/

    Your application will then be available under http://www.mycompany.com/, and each visitor will be immediately redirected to the real URL http://www.mycompany.com/myapp/

    Case B: You need to hide path components for all requests going to the application. Here's the recipe for the case, where you want to hide the first path component /myapp. More complex manipulations are left as an exercise to the reader. First the solution for the case of the Apache HTTP Server:

    1. Use mod_rewrite to add /myapp to all requests before forwarding to the backend:

    # Don't forget the PT flag! (pass through) RewriteRule ^/(.*) http://www.mycompany.com/myapp/$1 [PT]

    2. Use mod_headers to rewrite any HTTP redirects your application might return. Such redirects typically contain the path components you want to hide, because by the HTTP standard, redirects always need to include the full URL, and your application is not aware of the fact, that your clients talk to it via some shortened URL. An HTTP redirect is done with a special response header named Location. We rewrite the Location headers of our responses:

    # Keep protocol, server and port if present, # but insert our webapp name before the rest of the URL Header edit Location ^([^/]*//[^/]*)?/(.*)$ $1/myapp/$2

    3. Use mod_headers again, to rewrite the paths contained in any cookies, your application might set. Such cookie paths again might contain the path components you want to hide. A cookie is set with the HTTP response header named Set-Cookie. We rewrite the Set-Cookie headers of our responses:

    # Fix the cookie path Header edit Set-Cookie "^(.*; Path=/)(.*)" $1/myapp/$2

    3. Some applications might contain hard coded absolute links. In this case check, whether you find a configuration item for your web framework to configure the base URL. If not, your only chance is to parse all response content bodies and do search and replace. This is fragile and very resource intensive. If you really need to do this, you can use mod_proxy_html, mod_substitute or mod_sed for this task.

    If you are using Microsoft IIS as a web server, the ISAPI redirector provides a way of doing the first step with a builtin feature. You define a mapping file for simple prefix changes like this:

    # Add a context prefix to all requests ... /=/myapp/ # ... or change some prefix ... /oldapp/=/myapp/

    and then put the name of the file in the rewrite_rule_file entry of the registry or your isapi_redirect.properties file. In your uriworkermap.properties file, you still need to map the URLs as they are before rewriting!

    More complex rewrites can be done using the same file, but with regular expressions. A leading tilde sign '~', indicates, that you are using a regular expression:

    # Use a regular expression rewrite ~/oldapps([0-9]*)/=/newapps$1/

    There is no support for Steps 2 (rewriting redirect responses) or 3 (rewriting cookie paths).

    Some types of problems are triggered by the use of encoded URLs (see percent encoding). For the same location there exist a lot of different URLs which are equivalent. The reverse proxy needs to inspect the URL in order to apply its own authentication rules and to decide, to which backend it should send the request (or whether it should handle it itself). Therefore the request URL first is normalized: percent encoded characters are decoded, /./ is replaced by /, /XXX/../ is replaced by / and similar manipulations of the URL are done. After that, the web server might apply rewrite rules to further change the URL in less obvious ways. Finally there is no more way to put the resulting URL in an encoding, which is "similar" to the one which was used for the original URL.

    For historical reasons, there have been several alternatives, how mod_jk and the ISAPI plugin encoded the resulting URL before sending it to the backend. They could be chosen via JkOptions (mod_jk) or uri_select (ISAPI). None of those historical encodings are recommended, because they have either negative functionality implications or pose a security risk. The default encoding since version 1.2.24 is ForwardURIProxy (mod_jk) or proxy (ISAPI) and it is strongly recommended to keep the default and remove all old explicit settings.

    You can also add more attributes to any request you are forwarding when using the Apache HTTP Server. For this use the JkEnvVar directive (for details see the Apache reference page). Such request attributes can be retrieved on the Tomcat side via request.getAttribute(attributeName). Note that the names of attributes set via mod_jk will not be listed in request.getAttributeNames()!

    tomcat-connectors-1.2.50-src/xdocs/common_howto/timeouts.xml0000644000000000000020000004622314655113617022556 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Timeouts HowTo Rainer Jung

    Setting communication timeouts is very important to improve the communication process. They help to detect problems and stabilise a distributed system. JK can use several different timeout types, which can be individually configured. For historical reasons, all of them are disabled by default. This HowTo explains their use and gives hints how to find appropriate values.

    All timeouts can be configured in the workers.properties file. For a complete reference of all worker configuration items, please consult the worker reference. This page assumes, that you are using at least version 1.2.16 of JK. Dependencies on newer versions will be mentioned where necessary.

    Do not set timeouts to extreme values. Very small timeouts will likely be counterproductive.

    Long Garbage Collection pauses on the backend do not make a good fit with some timeouts. Try to optimise your Java memory and GC settings.

    CPing/CPong is our notion for using small test packets to check the status of backend connections. JK can use such test packets directly after establishing a new backend connection (connect mode) and also directly before each request gets send to a backend (prepost mode). Starting with version 1.2.27 it can also be used when a connection was idle for a long time (interval mode). The maximum waiting time (timeout) for a CPong answer to a CPing and the idle time in interval mode can be configured.

    The test packets will be answered by the backend very fast with a minimal amount of needed processing resources. A positive answer tells us, that the backend can be reached and is actively processing requests. It does not detect, if some context is deployed and working. The benefit of CPing/CPong is a fast detection of a communication problem with the backend. The downside is a slightly increased latency.

    The worker attribute ping_mode can be set to a combination of characters to determine, in which situations test packets are used:

    • C: connect mode, timeout ping_timeout overwritten by connect_timeout
    • P: prepost mode, timeout ping_timeout overwritten by prepost_timeout
    • I: interval mode, timeout ping_timeout, idle time connection_ping_interval
    • A: all modes

    Multiple values must be concatenated without any separator characters. We recommend using all CPing tests. If your application is very latency sensitive, then you should only use the combination of connect and interval mode.

    Activating the CPing probing via ping_mode has been added in version 1.2.27. For older versions only the connect and prepost modes exist and must be activated by explicitely setting connect_timeout and prepost_timeout.

    The worker attribute ping_timeout sets the default wait timeout in milliseconds for CPong for all modes. By default the value is "10000" milliseconds. The value only gets used, if you activate CPing/Cpong probes via ping_mode. The default value should be fine, except if you experience very long Java garbage collection pauses. Depending on your network latency and stability, good custom values often are between 5000 and 15000 milliseconds. You can overwrite the timeout used for connect and prepost mode with connect_timeout and prepost_timeout. Remember: don't use extremely small values.

    The worker attribute connect_timeout sets the wait timeout in milliseconds for CPong during connection establishment. You can use it if you want to overwrite the general timeout set with ping_timeout. To use connect mode CPing, you need to enable it via ping_mode. Since JK usually uses persistent connections, opening new connections is a rare event. We therefore recommend activating connect mode. Depending on your network latency and stability, good values often are between 5000 and 15000 milliseconds. Remember: don't use extremely small values.

    The worker attribute prepost_timeout sets the wait timeout in milliseconds for CPong before request forwarding. You can use it if you want to overwrite the general timeout set with ping_timeout. To use prepost mode CPing, you need to enable it via ping_mode. Activating this type of CPing/CPong adds a small latency to each request. Usually this is small enough and the benefit of CPing/CPong is more important. So in general we also recommend using prepost_timeout. Depending on your network latency and stability, good values often are between 5000 and 10000 milliseconds. Remember: don't use extremely small values.

    Until version 1.2.27 ping_mode and ping_timeout did not exist and to enable connect or prepost mode CPing you had to set connect_timeout respectively prepost_timeout to some reasonable positive value.

    Some platforms allow to set timeouts for all operations on TCP sockets. This is available for Linux and Windows, other platforms do not support this, e.g. Solaris. If your platform supports TCP send and receive timeouts, you can set them using the worker attribute socket_timeout. You can not set the two timeouts to different values.

    JK will accept this attribute even if your platform does not support socket timeouts. In this case setting the attribute will have no effect. By default the value is "0" and the timeout is disabled. You can set the attribute to some seconds value (not: milliseconds). JK will then set the send and the receive timeouts of the backend connections to this value. The timeout is low-level, it is used for each read and write operation on the socket individually.

    Using this attribute will make JK react faster to some types of network problems. Unfortunately socket timeouts have negative side effects, because for most platforms, there is no good way to recover from such a timeout, once it fired. For JK there is no way to decide, if this timeout fired because of real network problems, or only because it didn't receive an answer packet from a backend in time. So remember: don't use extremely small values.

    For the general case of connection establishment you can use socket_connect_timeout. It takes a millisecond value and works on most platforms, even if socket_timeout is not supported. We recommend using socket_connect_timeout because in some network failure situations failure detection during connection establishment can take several minutes due to TCP retransmits. Depending on the quality of your network a timeout somewhere between 1000 and 5000 milliseconds should be fine. Note that socket_timeout is in seconds, and socket_connect_timeout in milliseconds.

    JK handles backend connections in a connection pool per web server process. The connections are used in a persistent mode. After a request completed successfully we keep the connection open and wait for the next request to forward. The connection pool is able to grow according to the number of threads that want to forward requests in parallel.

    Most applications have a varying load depending on the hour of the day or the day of the month. Other reasons for a growing connection pool would be temporary slowness of backends, leading to an increasing congestion of the frontends like web servers. Many backends use a dedicated thread for each incoming connection they handle. So usually one wants the connection pool to shrink, if the load diminishes.

    JK allows connections in the pool to get closed after some idle time. This maximum idle time can be configured with the attribute connection_pool_timeout which is given in units of seconds. The default value is "0", which disables closing idle connections.

    We generally recommend values around 10 minutes, so setting connection_pool_timeout to 600 (seconds). If you use this attribute, please also set the attribute keepAliveTimeout (if it is set explicitly) or connectionTimeout in the AJP Connector element of your Tomcat server.xml configuration file to an analogous value. Caution: keepAliveTimeout and connectionTimeout must be given in milliseconds. So if you set JK connection_pool_timeout to 600, you should set Tomcat keepAliveTimeout or connectionTimeout to 600000.

    JK connections do not get closed immediately after the timeout passed. Instead there is an automatic internal maintenance task running every 60 seconds, that checks the idle status of all connections. The 60 seconds interval can be adjusted with the global attribute worker.maintain. We do not recommend to change this value, because it has a lot of side effects. Until version 1.2.26, the maintenance task only runs, if requests get processed. So if your web server has processes that do not receive any requests for a long time, there is no way to close the idle connections in its pool. Starting with version 1.2.27 you can configure an independent watchdog thread when using Apache HTTP Server 2.x with threaded APR or Microsoft IIS.

    The maximum connection pool size can be configured with the attribute connection_pool_size. We generally do not recommend to use this attribute in combination with Apache HTTP Server. For Apache we automatically detect the number of threads per process and set the maximum pool size to this value. For Microsoft IIS we use a default value of 250 (before version 1.2.20: 10). We strongly recommend adjusting this value for IIS to the number of requests one web server process should be able to send to a backend in parallel. You should measure how many connections you need during peak hours without performance problems, and then add some percentage depending on your growth rate etc. Finally you should check, whether your web server processes are able to use at least as many threads, as you configured as the pool size.

    The JK attribute connection_pool_minsize defines, how many idle connections remain when the pool gets shrunken. By default this is half of the maximum pool size.

    One particular problem with idle connections comes from firewalls, that are often deployed between the web server layer and the backend. Depending on their configuration, they will silently drop connections from their status table if they are idle for to long.

    From the point of view of JK and of the web server, the other side simply doesn't answer any traffic. Since TCP is a reliable protocol it detects the missing TCP ACKs and tries to resend the packets for a relatively long time, typically several minutes. Therefore you should always use connection_pool_timeout and connection_pool_minsize on the JK side and keepAliveTimeout or connectionTimeout on the Tomcat side to prevent idle connection drop.

    Furthermore using the boolean attribute socket_keepalive you can set a standard socket option, that automatically sends TCP keepalive packets after some idle time on each connection. By default this is set to false. If you suspect idle connection drops by firewalls you should set this to true.

    Unfortunately the default intervals and algorithms for these packets are platform specific. You might need to inspect TCP tuning options for your platform on how to control TCP keepalive. Often the default intervals are much longer than the firewall timeouts for idle connections. Nevertheless we recommend talking to your firewall administration and your platform administration in order to make them agree on good configuration values for the firewall and the platform TCP tuning.

    In case none of our recommendations help and you are definitively having problems with idle connection drops, you can disable the use of persistent connections when using JK together with Apache HTTP Server. For this you set "JkOptions +DisableReuse" in your Apache configuration. The amount of performance impact this will have depends on the details of your network and your firewall.

    JK can also use a timeout on request replies. This timeout does not measure the full processing time of the response. Instead it controls, how much time between consecutive response packets is allowed.

    In most cases, this is what one actually wants. Consider for example long running downloads. You would not be able to set an effective global reply timeout, because downloads could last for many minutes. Most applications though have limited processing time before starting to return the response. For those applications you could set an explicit reply timeout. Applications that do not harmonise with reply timeouts are batch type applications, data warehouse and reporting applications which are expected to observe long processing times.

    If JK aborts waiting for a response, because a reply timeout fired, there is no way to stop processing on the backend. Although you free processing resources in your web server, the request will continue to run on the backend - without any way to send back a result once the reply timeout fired.

    JK uses the worker attribute reply_timeout to set reply timeouts. The default value is "0" (timeout disabled) and you can set it to any millisecond value.

    In combination with Apache HTTP Server, you can also set a more flexible reply_timeout using an Apache environment variable. If you set the variable JK_REPLY_TIMEOUT to some integer value, this value will be used instead of the value in the worker configuration. This way you can set reply timeouts more flexible with mod_setenvif and mod_rewrite depending on URI, query string etc. If the environment variable JK_REPLY_TIMEOUT is not set, or is set to a negative value, the default reply timeout of the worker will be used. If JK_REPLY_TIMEOUT contains the value "0", then the reply timeout will be disabled for the request.

    In combination with a load balancing worker, JK will disable a member worker of the load balancer if a reply timeout fires. The worker will then no longer be used until it gets recovered during the next automatic maintenance task. Starting with JK 1.2.24 you can improve this behaviour using max_reply_timeouts. This attribute will allow occasional long running requests without disabling the worker. Only if those requests happen to often, the worker gets disabled by the load balancer.

    A load balancer worker does not only have the ability to balance load. It also handles stickyness and failover of requests in case of errors. When a load balancer detects an error on one of its members, it needs to decide, whether the error is serious, or only a temporary error or maybe only related to the actual request that was processed. Temporary errors are called local errors, serious errors will be called global errors.

    If the load balancer decides that a backend should be put into the global error state, then the web server will not send any more requests there. If no session replication is used, this means that all user sessions located on the respective backend are no longer available. The users will be send to another backend and will have to login again. So the global error state is not transparent to the users. The application is still available, but users might loose some work.

    In some cases the decision between local error and global error is easy. For instance if there is an error sending back the response to the client (browser), then it is very unlikely that the backend is broken. So this situation is a typical example of a local error.

    Some situations are harder to decide though. If the load balancer can't establish a new connection to a backend, it could be because of a temporary overload situation (so no more free threads in the backend), or because the backend isn't alive any more. Depending on the details, the right state could either be local error or global error.

    Until version 1.2.26 most errors were interpreted as global errors. Starting with version 1.2.27 many errors which were previously interpreted as global were switched to being local whenever the backend is still busy. Busy means, that other concurrent requests are send to the same backend (successful or not).

    In many cases there is no perfect way of making the decision between local and global error. The load balancer simply doesn't have enough information. In version 1.2.28 you can now tune, how fast the load balancer switches from local error to global error. If a member of a load balancer stays in local error state for too long, the load balancer will escalate it into global error state.

    The time tolerated in local error state is controlled by the load balancer attribute error_escalation_time (in seconds). The default value is half of recover_time, so unless you changed recover_time the default is 30 seconds.

    Using a smaller value for error_escalation_time will make the load balancer react faster to serious errors, but also carries the risk of more often loosing sessions in not so serious situations. You can lower error_escalation_time down to 0 seconds, which means all local errors which are potentially serious are escalated to global errors immediately.

    Note that without good basic error detection the whole escalation procedure is useless. So you should definitely use socket_connect_timeout and activate CPing/CPong with ping_mode and ping_timeout before thinking about also tuning error_escalation_time.

    tomcat-connectors-1.2.50-src/xdocs/common_howto/quick.xml0000644000000000000020000001162514655113617022017 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Quick Start HowTo Henri Gomez

    This document describes the configuration files used by JK on the web server side for the 'impatient':

    • workers.properties is a mandatory file used by the web server and which is the same for all JK implementations (mod_jk for the Apache HTTP Server, ISAPI for Microsoft IIS).
    • web server add-ons to be set on the web server side.

    We'll give here minimum servers configuration and an example workers.properties to be able to install and check quickly your configuration.

    Here is a minimum workers.properties, using just ajp13 to connect your web server to the Tomcat engine, complete documentation is available in Workers HowTo.

    # Define 1 real worker using ajp13 worker.list=worker1 # Set properties for worker1 (ajp13) worker.worker1.type=ajp13 worker.worker1.host=localhost worker.worker1.port=8009

    Here is some very basic information about Apache configuration, a more complete HowTo for Apache is available.

    You should first have mod_jk.so (unix) or mod_jk.dll (Windows) installed in your Apache module directory (see your Apache documentation to locate it).

    Usual locations for modules directory on Unix:

    • /usr/lib/apache/
    • /usr/lib/apache2/
    • /usr/local/apache/libexec/
    • /usr/local/apache/modules/

    Usual locations for modules directory on Windows:

    • C:\Program Files\Apache Group\Apache\modules\
    • C:\Program Files\Apache Group\Apache2\modules\

    You'll find a link to prebuilt binaries here

    Here is the minimum which should be set in httpd.conf directly or included from another file:

    Usual locations for configuration directory on Unix:

    • /etc/httpd/conf/
    • /etc/httpd2/conf/
    • /usr/local/apache/conf/

    Usual locations for configuration directory on Windows:

    • C:\Program Files\Apache Group\Apache\conf\
    • C:\Program Files\Apache Group\Apache2\conf\

    # Load mod_jk module # Update this path to match your modules location LoadModule jk_module modules/mod_jk.so # Declare the module for <IfModule directive> (remove this line for Apache 2.x) AddModule mod_jk.c # Where to find workers.properties # Update this path to match your conf directory location (put workers.properties next to httpd.conf) JkWorkersFile /etc/httpd/conf/workers.properties # Where to put jk shared memory # Update this path to match your local state directory or logs directory JkShmFile /var/log/httpd/mod_jk.shm # Where to put jk logs # Update this path to match your logs directory location (put mod_jk.log next to access_log) JkLogFile /var/log/httpd/mod_jk.log # Set the jk log level [debug/error/info] JkLogLevel info # Select the timestamp log format JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " # Send everything for context /examples to worker named worker1 (ajp13) JkMount /examples/* worker1

    A separate HowTo for the Microsoft IIS web server is available.

    More information to be added!

    (Re)start the web server and browse to the http://localhost/examples/

    tomcat-connectors-1.2.50-src/xdocs/common_howto/workers.xml0000644000000000000020000003350314655113617022376 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Workers HowTo Henri Gomez Gal Shachor Mladen Turk

    A Tomcat worker is a Tomcat instance that is waiting to execute servlets on behalf of some web server. For example, we can have a web server such as the Apache HTTP Server forwarding servlet requests to a Tomcat process (the worker) running behind it.

    The scenario described above is a very simple one; in fact one can configure multiple Tomcat workers to serve servlets on behalf of a certain web server. The reasons for such configuration can be:

    • We want different contexts to be served by different Tomcat workers to provide a development environment where all the developers share the same web server but own a Tomcat worker of their own.
    • We want different virtual hosts served by different Tomcat processes to provide a clear separation between sites belonging to different companies.
    • We want to provide load balancing, meaning run multiple Tomcat workers each on a machine of its own and distribute the requests between them.

    There are probably more reasons for having multiple workers but I guess that this list is enough... Tomcat workers are defined in a properties file dubbed workers.properties and this tutorial explains how to work with it.

    This document was originally part of Tomcat: A Minimalistic User's Guide written by Gal Shachor, but has been split off for organisational reasons.

    Defining workers to the Tomcat web server plugin can be done using a properties file (a sample file named workers.properties is available in the conf/ directory).

    the file contains entries of the following form:

    worker.list=<a comma separated list of worker names>

    # the list of workers worker.list= worker1, worker2

    When starting up, the web server plugin will instantiate the workers whose name appears in the worker.list property, these are also the workers to whom you can map requests. The directive can be used multiple times.

    Each named worker should also have a few entries to provide additional information on his behalf. This information includes the worker's type and other related worker information. Currently the following worker types that exists are (JK 1.2.5):

    TypeDescription
    ajp13This worker knows how to forward requests to out-of-process Tomcat workers using the ajp13 protocol.
    lbThis is a load balancing worker; it knows how to provide flexible load balancing with a certain level of fault-tolerance.
    statusThis is a status worker for managing load balancers.
    ajp12This worker knows how to forward requests to out-of-process Tomcat workers using the ajp12 protocol. It is deprecated
    ajp14This worker knows how to forward requests to out-of-process Tomcat workers using the ajp14 protocol. It is experimental

    Defining workers of a certain type should be done with the following property format:

    worker.worker name.type=<worker type> Where worker name is the name assigned to the worker and the worker type is one of the four types defined in the table (a worker name may only contain any space the characters [a-zA-Z0-9\-_]).

    # Defines a worker named "local" that uses the ajp12 protocol to forward requests to a Tomcat process. worker.local.type=ajp12 # Defines a worker named "remote" that uses the ajp13 protocol to forward requests to a Tomcat process. worker.remote.type=ajp13 # Defines a worker named "loadbalancer" that loadbalances several Tomcat processes transparently. worker.loadbalancer.type=lb

    After defining the workers you can also specify properties for them. Properties can be specified in the following manner:

    worker.<worker name>.<property>=<property value>

    Each worker has a set of properties that you can set as specified in the following subsections:

    The worker type ajp12 has been deprecated and you should use instead ajp13 instead.

    The ajp12 typed workers forward requests to out-of-process Tomcat workers using the ajp12 protocol over TCP/IP sockets. It does not use persistent connections.

    The ajp12 worker properties are:

    host property sets the host where the Tomcat worker is listening for ajp12 requests.

    port property sets the port where the Tomcat worker is listening for ajp12 requests

    lbfactor property is used when working with a load balancer worker, this is the load balancing factor for the worker. We'll see more on this in the load balancer worker section.

    # worker "worker1" will talk to Tomcat listening on machine www.x.com at port 8007 using 2 lb factor worker.worker1.type=ajp12 worker.worker1.host=www.x.com worker.worker1.port=8007 worker.worker1.lbfactor=2

    Note: The default port for ajp12 is 8007

    The ajp13 typed workers forward requests to out-of-process Tomcat workers using the ajp13 protocol over TCP/IP sockets. The main difference between ajp12 and ajp13 are that:

    • ajp13 is a more binary protocol and it tries to compress some of the request data by coding frequently used strings as small integers.
    • ajp13 reuses open sockets and leaves them open for future requests (remember when you've got a Firewall between your web server and Tomcat).
    • ajp13 has special treatment for SSL information so that the container can implement SSL related methods such as isSecure().

    You should note that ajp13 is the recommended protocol to connect to Tomcat.

    # worker "worker2" will talk to Tomcat listening on machine www2.x.com at port 8009 using 3 lb factor worker.worker2.type=ajp13 worker.worker2.host=www2.x.com worker.worker2.port=8009 worker.worker2.lbfactor=3 # worker "worker2" uses connections, which will stay no more than 10mn in the connection pool worker.worker2.connection_pool_timeout=600 # worker "worker2" ask operating system to send KEEP-ALIVE signal on the connection worker.worker2.socket_keepalive=1 # mount can be used as an alternative to the JkMount directive worker.worker2.mount=/contexta /contexta/* /contextb /contextb/*

    Notes: In the ajp13 protocol, the default port is 8009

    The load balancing worker does not really communicate with Tomcat workers. Instead it is responsible for the management of several "real" workers. This management includes:

    • Instantiating the workers in the web server.
    • Using the worker's load balancing factor, perform weighted round-robin load balancing where a higher lbfactor means stronger machine (that is going to handle proportionally more requests)
    • Keeping requests belonging to the same session executing on the same Tomcat worker (session stickyness).
    • Identifying failed Tomcat workers, suspending requests to them and instead failing over on other workers managed by the lb worker.

    The overall result is that workers managed by the same lb worker are load balanced (based on their lbfactor and current user session) and also fail over so a single Tomcat process death will not "kill" the entire site. The following table specifies some properties that the lb worker can accept:

    • balance_workers is a comma separated list of workers that the load balancer need to manage. As long as these workers should only be used via the load balancer worker, there is no need to also put them into the worker.list property. This directive can be used multiple times for the same load balancer.
    • sticky_session specifies whether requests with SESSION ID's should be routed back to the same Tomcat worker. Set sticky_session to false when Tomcat is using a Session Manager which can persist session data across multiple instances of Tomcat. By default sticky_session is set to true.

    # The worker balance1 while use "real" workers worker1 and worker2 worker.balance1.balance_workers=worker1, worker2

    The status worker does not communicate with Tomcat. Instead it is responsible for the load balancer management.

    # Add the status worker to the worker list worker.list=jkstatus # Define a 'jkstatus' worker using status worker.jkstatus.type=status

    Next thing is to mount the requests to the jkstatus worker. For Apache HTTP Servers use:

    # Add the jkstatus mount point JkMount /jkmanager/* jkstatus

    To obtain a higher level of security use the:

    # Enable the JK manager access from localhost only <Location /jkmanager/> JkMount jkstatus Require ip 127.0.0.1 </Location>

    You can define "macros" in the property files. These macros let you define properties and later on use them while constructing other properties.

    # property example, like a network base address mynet=194.226.31 # Using the above macro to simplify the address definitions # for a farm of workers. worker.node1.host=$(mynet).11 worker.node2.host=$(mynet).12 worker.node3.host=$(mynet).13

    Workers can reference configurations of other workers. If worker "x" references worker "y", then it inherits all configuration parameters from "y", except for the ones that have explicitly been set for "x".

    # worker toe defines some default settings worker.toe.type=ajp13 worker.toe.socket_keepalive=true worker.toe.connect_timeout=10000 worker.toe.recovery_options=7 # workers tic and tac inherit those values worker.tic.reference=worker.toe worker.tac.reference=worker.toe

    Please note, that the reference contains the full prefix to the referenced configuration attributes, not only the name of the referenced worker.

    References can be nested with a maximum depth of 20. Be careful to avoid loops!

    Attributes which are allowed multiple times for a single worker can not be merged from a worker and a reference. An attribute is only inherited from a reference, if it is not already set for the referring worker.

    References are especially useful, when configuring load balancers. Try to understand the following two stage references:

    # We only use one load balancer worker.list=lb # Let's define some defaults worker.basic.port=8009 worker.basic.type=ajp13 worker.basic.socket_keepalive=true worker.basic.connect_timeout=10000 worker.basic.recovery_options=7 # And we use them in two groups worker.lb1.domain=dom1 worker.lb1.distance=0 worker.lb1.reference=worker.basic worker.lb2.domain=dom2 worker.lb2.distance=1 worker.lb2.reference=worker.basic # Now we configure the load balancer worker.lb.type=lb worker.lb.method=B worker.lb.balanced_workers=w11,w12,w21,w22 worker.w11.host=myhost11 worker.w11.reference=worker.lb1 worker.w12.host=myhost12 worker.w12.reference=worker.lb1 worker.w21.host=myhost21 worker.w21.reference=worker.lb2 worker.w22.host=myhost22 worker.w22.reference=worker.lb2

    Since coping with worker.properties on your own is not an easy thing to do, a sample worker.properties file is bundled along JK.

    You could also find here a sample workers.properties defining:

    • Two ajp13 workers that use the host localhost and the ports 8109 and 8209
    • An lb worker that load balances over the two ajp13 workers
    # Define 3 workers, 2 real workers using ajp13, and one being a load balancing worker worker.list=node1, node2, lbworker # Set properties for node1 (ajp13) worker.node1.type=ajp13 worker.node1.host=localhost worker.node1.port=8109 worker.node1.connection_pool_timeout=600 worker.node1.socket_keepalive=1 # Set properties for node2 (ajp13) worker.node2.type=ajp13 worker.node2.host=localhost worker.node2.port=8209 worker.node2.connection_pool_timeout=600 worker.node2.socket_keepalive=1 # Set properties for lbworker which uses node1 and node2 worker.lbworker.type=lb worker.lbworker.balance_workers=node1,node2
    tomcat-connectors-1.2.50-src/xdocs/empty.xml0000644000000000000020000000241014655113617017321 0ustar rootbin ]> &project; Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Empty template Developer Name

    This is a generic template for JK documentation. Please fill in the url and title tags, as well as author tags.

    tomcat-connectors-1.2.50-src/xdocs/news/0000755000000000000020000000000014655113617016420 5ustar rootbintomcat-connectors-1.2.50-src/xdocs/news/20090301.xml0000644000000000000020000000672214655113617020047 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2009 News and Status


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.28. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    The most important new features in this version are:

    Better Error Detection for Load Balancer Workers

    Local and global error states have been improved. You can fine tune the behaviour with the new "error_escalation_time" attribute (see the timeouts documentation).

    Dynamic Address and Port Change Using the Status Worker

    The status worker now allows you to change the address and the port of an AJP13 worker on the fly. You can e.g. provision dummy workers with a port equal to "0", which will be automatically put into stopped mode during startup. Later, when you want to actually use these workers, you set their address and port to the final values.

    Note that already existing connections will go on using the old address and port. This will be improved in future versions.

    New Data in Status Worker Display

    The status worker display now also contains the timestamp of the last worker errors.

    Improved Proxy Flexibility

    You can now overwrite more request metadata before the request gets send to the backend. This is helpful in case there are other reverse proxies in front of your web server. A new documentation page explains this in detail.

    Improved IIS Support

    IIS support has been improved especially when using mutltiple application pools. Furthermore you can now configure the ISAPI plugin to update the uriworkermap.properies file on a regular interval using the watchdog thread.

    JNI Worker Deprecation

    Workers of type jni are broken since a long time. Since there is no more use for them, they have been deprecated now, and will be removed in a future release.

    tomcat-connectors-1.2.50-src/xdocs/news/project.xml0000644000000000000020000001217014655113617020611 0ustar rootbin The Apache Tomcat Connectors - News The Apache Tomcat Connectors - News tomcat-connectors-1.2.50-src/xdocs/news/20041100.xml0000644000000000000020000001373614655113617020043 0ustar rootbin ]> &project; Apache Jakarta Project 2004 News and Status

    17 December - JK-1.2.8 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.8.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    17 December - JK-1.2.8-rc-1 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.8-rc-1 (Relase Canditate 1).

    We expect it to be ratified as a Stable release when the vote takes place in the next week.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    13 December - JK-1.2.7-beta-3 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.7-beta-3. The release contains a fix to few configuration problems detected with JK-1.2.7-beta-2 version.

    We expect it to be ratified as a Stable release when the vote takes place in the next week.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    7 December - JK-1.2.7-beta-2 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.7-beta-2. The release contains a fix to few compilation problems detected with JK-1.2.7-beta version. This release also introduces a new domain concept clustering support. See 32317 for details.

    We expect it to be ratified as a Stable release when the vote takes place in the next two weeks.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    30 November - JK-1.2.7-beta released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.7-beta. The release contains a significant number of bug fixes and new features.

    We expect it to be ratified as a Stable release when the vote takes place in the next two weeks.

    Please see the ChangeLog for a full list of changes.

    Since release 1.2.7 the socket_timeout property has been renamed to recycle_timeout. The socket_timeout now sets the real timeout for socket operations.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    15 November - JK2 is officially unsupported

    JK2 has been put in maintainer mode and no further development will take place. The reason for shutting down JK2 development was the lack of developers interest. Other reason was lack of users interest in adopting JK2, caused by configuration complexity when compared to JK.

    The latest official JK2 release is 2.0.4.

    JK2 will have it's successor within core Apache2.1/2.2 distribution. We have developed new proxy_ajp that is an addition to the mod_proxy and uses Tomcat's AJP protocol stack. It is developped in httpd-2.1 and integrated in it. We have also developed a new proxy_balancer module for load balancing http and ajp protocol stacks.

    JK will be fully supported for all other web servers. The next JK release is planned for the end of November. Lots of code from JK2 has been ported to JK


    tomcat-connectors-1.2.50-src/xdocs/news/20100101.xml0000644000000000000020000000615614655113617020036 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2010 News and Status


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.31. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.



    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.30. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.



    Tomcat Connectors 1.2.29 has been withdrawn because of regression inside Microsoft IIS connector.



    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.29. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/news/20060101.xml0000644000000000000020000000773014655113617020042 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2006 News and Status

    10 December - JK-1.2.20 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.20. This is a stable release adding new features and a few bug fixes to version 1.2.19. Furthermore the documentation has been reorganised.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    17 September - JK-1.2.19 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.19. This is a stable release adding some features and a few bug fixes to version 1.2.18. Furthermore the non-functional code trees for isapi and domino have been removed.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    13 July - JK-1.2.18 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.18. This is a stable release adding a few bug fixes to the not released 1.2.17 version.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    JK-1.2.17 not released

    Version 1.2.17 of Tomcat Connectors 1.2.17 has not been released due to a bug in the types chosen for socket arguments.

    Please see the ChangeLog for a full list of changes.


    JK-1.2.16 not released

    Version 1.2.16 of Tomcat Connectors 1.2.16 has not been released due to a bug in the jk status worker. This version adds some features and a few bug fixes to the 1.2.15 version. Furthermore some worker attributes have been deprecated.

    Please see the ChangeLog for a full list of changes.


    tomcat-connectors-1.2.50-src/xdocs/news/20050101.xml0000644000000000000020000001461514655113617020041 0ustar rootbin ]> &project; Apache Jakarta Project 2005 News and Status

    8 November - JK-1.2.15 released

    The Apache Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.15. This is Stable release and it contains few bug fixes found in 1.2.14 version.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    13 July - JK-1.2.14 released

    The Apache Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.14. This is Stable release and it contains few bug fixes found in 1.2.13 version.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    7 May - JK-1.2.13 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.13. This is development release and contains few bug fixes found in 1.2.12 version.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    7 May - JK-1.2.12 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.12 The release contains a significant number of bug fixes and new features.

    We expect it to be ratified as a Stable release when the vote takes place in the next week.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    29 April - JK-1.2.11 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.11 The release contains a significant number of bug fixes and new features.

    This version has not been released.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    30 March - JK-1.2.10 released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.10 The release contains a significant number of bug fixes and new features.

    We expect it to be ratified as a Stable release when the vote takes place in the next two weeks.

    Please see the ChangeLog for a full list of changes.

    Since release 1.2.10 the JkShmFile property has been added for Apache 1.3.x and Apache 2.x web servers on UNIX and LINUX platforms. Load balancer will not work properly if this directive is not present.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    18 March - JK-1.2.9-beta released

    The Apache Jakarta Tomcat team is proud to announce the immediate availability of Jakarta Tomcat Connectors 1.2.9-beta. The release contains a significant number of bug fixes and new features.

    We expect it to be ratified as a Stable release when the vote takes place in the next two weeks.

    Please see the ChangeLog for a full list of changes.

    Since release 1.2.9 the JkShmFile property has been added for Apache 1.3.x and Apache 2.x web servers on UNIX and LINUX platforms. Load balancer will not work properly if this directive is not present.

    If you find any bugs during testing this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    tomcat-connectors-1.2.50-src/xdocs/news/20160901.xml0000644000000000000020000000327014655113617020046 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2016 News & Status

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.42. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/news/20140201.xml0000644000000000000020000000501714655113617020036 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2014 News and Status


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.40. This is a stable release concentrating mainly on bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.39. This is a stable release containing both bug fixes and few new features like IPV6 support. Note that version 1.2.38 was not released due to some minor issues found in release process.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/news/20240101.xml0000644000000000000020000000327114655113617020036 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2024 News & Status

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.50. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/news/20150101.xml0000644000000000000020000000357614655113617020046 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2015 News & Status

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.41. This is a maintenance and security release.

    This release includes the fix for CVE-2014-8111.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/news/20230101.xml0000644000000000000020000000327414655113617020040 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2023 News & Status

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.49. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/news/20180301.xml0000644000000000000020000000535014655113617020043 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2018 News & Status

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.46. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.44. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.43. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/news/20070301.xml0000644000000000000020000001112414655113617020035 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2007 News and Status

    21 December - JK-1.2.26 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.26. This is a stable release adding few new features and some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    7 August - JK-1.2.25 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.25. This is a stable release adding new features and a few bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    27 July - JK-1.2.24 released

    This release has been withdrawn.


    18 May - JK-1.2.23 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.23. This is a stable release adding new features and a few bug fixes to version 1.2.23.

    It fixes an Important vulnerability.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    17 April - JK-1.2.22 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.22. This is a stable release adding new features and a few bug fixes to version 1.2.22.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    1 March - JK-1.2.21 released

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.21. This is a stable release adding new features and a few bug fixes to version 1.2.20.

    It fixes a Critical vulnerability introduced in version 1.2.19

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report. When entering bug select Native:JK Component.


    tomcat-connectors-1.2.50-src/xdocs/news/20081001.xml0000644000000000000020000001720414655113617020041 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2008 News and Status


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.27. This is a stable release adding lots of new features and some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    The most important new features in this version are:

    Watchdog Thread for Periodic Tasks

    The connector has to run some periodic tasks independant of request processing. Examples are probing or closing down idle backend connections, adjusting load numbers and recovering workers from error state.

    Before version 1.2.27 these tasks were done inside the request processing loop. When a new request came in and the task was due, the thread handling the request first executed the internal task and then handled the request. If there were no requests coming in, the tasks would not run. If any of the tasks took unexpectedly long, the response time of the request waiting for the finishing of the task went up.

    Starting with this release you can configure a separate watchdog thread inside the web server to run all those tasks independantly of request processing. This new feature is avaliable for the connector when used with Apache httpd 2.x or with Microsoft IIS. To keep the behaviour of the new version consistent with previous releases, this feature is turned off by default. You can activate the watchdog thread via JkWatchdogInterval for Apache or watchdog_interval for IIS.

    Connection Probing

    In previous releases connection probing (checking whether connections still work) could only be done immediately after a new connection was established and directly before sending each request. Since we now have the watchdog thread available, we also added a periodic probing option, which you can activate with the worker attribute ping_mode. This will also be useful as a protection against the infamous firewall idle connection drop.

    The older attributes connect_timeout and prepost_timeout still exist and work the same way they did in previous releases. Since there are now three different probing options, we recommend to migrate your configuration to the newer attributes ping_mode, ping_timeout and connection_ping_interval.

    Mount Extensions

    Usually one defines workers and mounts for the connector. A worker defines a backend we want to talk to and the configuration parameters of the communication, connection pools etc. The mounts define which URIs we want to forward to which worker (so we also call a mount an URI map rule). In version 1.2.27 you can overwrite certain worker parameter per mount.

    One easy to understand example is reply timeouts. Until this release you had to specify a reply timeout for the whole worker. But reply times depend a lot on the type of request. So normally you want to define a general reply timeout and for some special URLs you need to relax the reply timeout, because you know those URLs take much longer to process (like e.g. reporting or other compute intensive tasks).

    Another possible case is the activation status. You might use a load balancer worker to forward requests to certain webapps in a farm of Tomcat nodes. If you wanted to update some webapp on one node, you previously had to stop forwarding requests for all webapps on this Tomcat node. What was not possible until now, was stopping forwarding requests restricted to the webapp and the node you wanted to update.

    Starting with this release, you can add so-called rule extensions to your uriworkermap file to influence worker parameters per mount. This will work for all Apache versions and for IIS. Remember, that the uriworkermap file automatically gets reloaded after changes without web server restart.

    Improved IIS support

    We improved IIS support im various ways. It is now possible to use multiple IIS 6 application pools with the ISAPI redirector.

    Furthermore some improvements were added as compile time features. The most notable one is chunked encoding support, which was a major refactoring and is therefore still considered experimental. You can download binaries with and without chunked encoding support. In future versions, chunked encoding will likely be availabe in all builds.

    Another new feature is an elegant way of configuring error page redirects. All new features are documented on the documentation page about configuring IIS.

    Enhanced Status Worker

    The status worker now can also manage and show statistics for AJP workers that are not part of a load balancer. Other improvements are the new dump action, the integration of the new configuration attributes, showing average request and transfer rates since the last statistics reset and the ability to display only a single member of a load balancer.

    Unfortunately we had to change some request parameters used for the update action of the status worker.

    Miscellaneous Improvements

    Further enhancements are:

    • Configurable session stickyness indicator: cookie name and URL path parameter name can be freely chosen instead of the servlet spec compliant JSESSIONID and ;jsessionid.
    • Automatically determining the size of the shared memory segment needed to accommodate all workers.
    • New connection establishment timeout socket_connect_timeout.
    • New timeout connection_acquire_timeout for acquiring a free connection from the pool.
    • Improved retry handling by adjusting the meaning of the attribute retries for AJP workers and for load balancers and by adding the new retry_interval.
    • Allowing the web server to provide error pages instead of Tomcat.

    tomcat-connectors-1.2.50-src/xdocs/news/20200201.xml0000644000000000000020000000326714655113617020040 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2020 News & Status

    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.48. This is a maintenance release.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/news/20120301.xml0000644000000000000020000001034014655113617020030 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2012 News and Status


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.37. This is a stable release concentrating mainly on bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.36. This is a stable release concentrating mainly on bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.35. This is a stable release concentrating mainly on bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.


    The Apache Tomcat team wishes to draw your attention to stability issues that have been identified with the recent mod_jk 1.2.33 release. If you have not yet upgraded to mod_jk 1.2.33 we recommend that you wait for the mod_jk 1.2.34 release which is currently in progress. If you have upgraded and are experienced issues we recommend that you downgrade to mod_jk 1.2.32 until mod_jk 1.2.34 is available.

    We apologise for any inconvenience.


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.33. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/news/20110701.xml0000644000000000000020000000343614655113617020043 0ustar rootbin ]> &project; Apache Tomcat Connectors Project 2011 News and Status


    The Apache Tomcat team is proud to announce the immediate availability of Tomcat Connectors 1.2.32. This is a stable release concentrating mainly on some bug fixes.

    Please see the ChangeLog for a full list of changes.

    If you find any bugs while using this release, please fill in the Bugzilla Bug Report.

    tomcat-connectors-1.2.50-src/xdocs/reference/0000755000000000000020000000000014655113617017402 5ustar rootbintomcat-connectors-1.2.50-src/xdocs/reference/status.xml0000644000000000000020000005267414655113617021465 0ustar rootbin ]> &project; Rainer Jung Status Worker Reference

    Tomcat Connectors has a special type of worker, the so-called status worker. The status worker does not forward requests to Tomcat instances. Instead it allows to retrieve status and configuration information at runtime, and furthermore to change many configuration items dynamically. This can be done via a simple embedded web interface.

    The status worker is especially powerful, when used together with load balancing workers.

    This document does not explain the HTML user interface of the status worker. Until now it is very simple, so just go ahead and use it. This doc instead tries to explain the less obvious features of the status worker. We also will give a complete coverage of the various request parameters and their meaning, so that you can include the status worker in your automation scripts.

    The documentation of the status worker starts with jk 1.2.20

    The status worker knows about the following actions:

    • list: lists the configurations and runtime information of all configured workers. The output will be grouped by global information first (version data), then load balancer information, after that AJP worker information and finally the legend. For load balancers, there will be a summary part, and after that details for each member worker. For all workers, we also include the URL mappings (forward definitions).
    • show: the same as list, but only shows data for one chosen worker
    • edit: produces a form to edit configuration data for a chosen worker. There is a special subtype of "edit", that makes it easy to change one attribute for all members of a load balancer, e.g. their activation state.
    • update: commit changes made in an edit form. Caution: the changes will not be persisted to the configuration files. As soon as your restart your web server, all changes made through the status worker will be lost! On the other hand, the changes done by the status worker will be applied during runtime without a restart of the web server.
    • reset: reset all runtime statistics for a worker.
    • recover: Mark a member of a load balancer, that is in error state, for immediate recovery.
    • version: only show version information of the web server and the JK software
    • dump: list the original workers configuration. Caution: the dump will only contain the configuration that was used during startup. Any changes applied later by the dynamic management interface of the status worker itself will not be contained in this dump. The dump action has been added in version 1.2.27.

    For most actions you can choose between 4 output formats.

    • HTML: Used interactively with a browser
    • XML: Mostly useful for automation, when your scripting environment is XML friendly. This format has rich structure information, but does not work line based, so you would really like to use it together with XML tools.
    • Properties: This format is a line based format, that conforms to the rules of Java property files. Most structure information is contained in the hierarchical key. For information, that is of configuration nature, the format should produce lines very similar to the ones you can use in workers.properties. It will not produce a complete configuration file!
    • Text: A simple textual output format.
    The "edit" action does only make sense for the HTML output type.

    In the HTML view, there is an automatic refresh feature, implemented via the meta refresh option of HTML. Once you start the automatic refresh, the UI will will respect it for all actions except edit, update and maintain. Even if you navigate through one of those, the automatic refresh will start again as soon as you come back to one of the other actions.

    Many parts of the HTML page can be minimised, if they are not interesting for you. There are a couple of "Hide" links, which will collapse parts of the information. The feature exists for the following blocks of information:

    • Legend: Do not show the legend for the information presented in "list" and "show" actions
    • URI mappings: Do not show the URI mapping for the workers
    • Load Balancing Workers: Do not show workers of type "lb"
    • AJP Workers: Do not show workers of type ajp
    • Balancer Members: Do not show detailed information concerning each member of load balancers
    • Load Balancer Configuration: Do not show configuration data for load balancers
    • Load Balancer Summary: Do not show status summary for load balancers
    • AJP Configuration: Do not show configuration data for ajp workers load balancer members
    The last three minimisation features have been added in version 1.2.27.

    Note: The following restriction has been removed starting with version 1.2.26.

    The Apache module mod_jk makes use of the internal Apache HTTP Server infrastructure concerning virtual hosts. The downside of this is, that the status worker can only show URL maps, for the virtual host it is defined in. It is not able to reach the configuration objects for other virtual hosts. Of course you can define a status worker in any virtual host you are using. All information presented apart from the URL maps will be the same, independent of the virtual host the status worker has been called in.

    The status worker will log changes made to the configuration with log level "info" to the usual JK log file. Invalid requests will be logged with log level "warn". If you want to report some broken behaviour, log file content of level "debug" or even "trace" will be useful.

    The basic configuration of a status worker is very similar to that of a usual ajp worker. You need to specify a name for the worker, and the URLs you want to map to it. The first part of the configuration happens in the workers.properties file. We define a worker named mystatus of type status: worker.list=mystatus worker.mystatus.type=status Then we define a URL, which should be mapped to this worker, i.e. the URL we use to reach the functionality of the status worker. You can use any method mod_jk supports for the web server of your choice. Possibilities are maps inside uriworkermap.properties, an additional mount attribute in workers.properties, or JkMount for the Apache HTTP Server. Here's an example for a uriworkermap.properties line: /private/admin/mystatus=mystatus The URI pattern is case sensitive.

    As you will learn in the following sections, the status worker is very powerful. You should use the usual authentication and authorisation methods of your web server to secure this URL.

    You can also define multiple instances of the status worker, by using different names and URL mappings. For instance you might want to configure them individually and then allow special groups of people to use them

    There are a couple of attributes for the workers.properties entries, which allow to customise various aspects of the output of the status worker.

    The attribute css can be set to the URL of a stylesheet: worker.mystatus.css=/private/admin/static/mystatus.css When writing HTML output, the status worker then includes the line <link rel="stylesheet" type="text/css" href="/private/admin/static/mystatus.css" /> There is no sample stylesheet included with the mod_jk release, and by default the attribute css is empty, so no stylesheet reference will be included in the pages. The HTML code of the status worker output pages does not include any class attributes. If you like to contribute a stylesheet or improvements to the HTML layout, please contact us on the tomcat developers list.

    The properties output format can be customised via the attribute prefix. The names of all properties the status worker does output, will begin with this prefix. The default is "worker".

    Several attributes influence the format when writing XML output. The attribute ns allows to set a namespace prefix, that will be used for every status worker+element. The default is "jk:". Setting it to "-" disables the namespace prefix.

    With the attribute xmlns you can map the prefix to a namespace URL. The default value is xmlns:jk="http://tomcat.apache.org". Setting it to "-" disables the output of the URL.

    Finally you can specify an XML document type via the attribute doctype. The specified string will be inserted at the beginning of the document, directly after the xml header. The default is empty.

    We urge you to use the builtin access control features of your web server to control access to the status worker URLs you have chosen. Nevertheless two configuration attributes of status workers are helpful. The attribute "read_only" disables all features of the status worker, that can be used to change configurations or runtime status of the other workers. A read_only status worker will not allow access to the edit, update, reset or recover actions. The default value is false, ie. read/write. To enable read_only you need to set it to true.

    You could configure two status workers, one has read_only and will be made available to a larger admin group, the other one will be used fully featured, but only by fewer people: worker.list=jk-watch worker.jk-watch.type=status worker.jk-watch.read_only=true worker.jk-watch.mount=/user/status/jk worker.list=jk-manage worker.jk-manage.type=status worker.jk-manage.mount=/admin/status/jk Starting with version 1.2.21, a read/write status worker can also be switched temporarily into read-only mode by the user via a link in the HTML GUI. The user can always switch it back to read/write. Only a status worker configured as read-only via the "read_only" attribute is completely safe from applying any changes.

    The other attribute you can use is user. By default this list is empty, which means no limit on the users. You can set "user" to a comma separated list of user names. If your web server is configured such that it sends the user names with the request, the status worker will check, if the name attached with the request is contained in it's "user" list.

    The user list can be split over multiple occurrences of the "user" attribute.

    By default, the user names are matched case sensitively. Starting with version 1.2.21 you can set the attribute user_case_insensitive to true. Then the comparison will be made case insensitive.

    For load balancing workers the status worker shows some interesting overview information. It categorises the members of the load balancer into the classes "good", "bad" and degraded". This feature can be combined with external escalation procedures. Depending on your global system design and your operating practises your preferred categorisation might vary.

    The categorisation is based on the activation state of the workers (active, disabled or stopped), which is a pure configuration state, and the runtime state (OK or ERR with possible substates idle, busy, recovering, probing, and forced recovery) which only depends on the runtime situation.

    The runtime substates have the following meaning:

    • OK (idle): This worker didn't receive any request since the last balancer maintenance. By default balancer maintenance runs every 60 seconds. The worker should be OK, but since we didn't have to use it for some time, we can't be sure. This state has been called N/A before version 1.2.24.
    • OK (busy): All connections for this worker are in use for requests.
    • ERROR (recovering): The worker was in error state for some time and is now marked for recovery. The next request suitable for this worker will use it.
    • ERROR (probing): After setting the worker to recovering, we received a request suitable for this worker. This request is now using the worker.
    • ERROR (forced recovery): The worker is in error, but we don't have an alternative worker, so we keep using it.

    By default the status worker groups into "good" all members, that have activation "active" and runtime state not equal to "error" with empty substate. The "bad" group consists of the members, that have either activation "stopped", or are in runtime state "error" with empty substate.

    Workers that fit neither of the two groups, are considered to be "degraded".

    You can define other rules for the grouping into good, bad and degraded. The two attributes "good" and "bad" can be populated by a comma-separated list ob single characters or dot-separated pairs. Each character stands for the first character of one of the possible states "active", "disabled", "stopped", "ok", "idle", "busy", "recovering" and "error". The additional states "probing" and "forced recovery" are always rated equivalent to "recovering". Comma-separated entries will be combined with logical "or", if you combine a configuration and a runtime state with a dot. the are combined with logical "and". So the default value for "good" is "a.o,a.i,a.b,a.r", for "bad" it is "e,s".

    The status worker first tries to match against the "bad" definitions, if this doesn't succeed it tries to match against "good", and finally it chooses "degraded", if no "bad" or "good" match can be found.

    This section should help you building automation scripts based on the jk status management interface. This interface is stable in the sense, that we only expect to add further parameters in the future. Existing parameters from previous versions will keep their original semantics. We also expect the output formats XML, Properties and Text to be kept stable. So please use those, if you want to parse status worker output in your automation scripts.

    The action is determined by the parameter cmd. It can have the values "list", "show", "edit", "update", "reset", "recover", "version" and "dump". If you omit the cmd parameter, the default "list" will be used. All actions except for "list", "refresh", "version" and "dump" need additional parameters.

    The action "dump" has been added in version 1.2.27.

    The format is determined by the parameter mime. It can have the values "html", "xml", "txt" and "prop". If you omit the mime parameter, the default "html" will be used. The action "edit" (the edit form) does only make sense for "mime=html".

    Actions that operate on a single worker need one or two additional parameters to select this worker. The parameter w contains the name of the worker from the worker list. If an action operates on a member (sub worker) of a load balancer, the parameter w contains the name of the load balancer worker, and the additional parameter sw contains the name of the sub worker.

    During automatic refresh, the parameter re contain the refresh interval in seconds. If you omit this parameter, automatic refresh will be off.

    The parameter opt contains a bit mask of activated options. The default is 0, so by default no options are activated. The following options exist:

    • 0x0001: hide members of lb workers
    • 0x0002: hide URL maps
    • 0x0004: hide the legend
    • 0x0008: hide load balancer workers
    • 0x0010: hide ajp workers
    • 0x0020: only allow read_only actions for a read/write status worker.
    • 0x0040: hide load balancer configuration
    • 0x0080: hide load balancer status summary
    • 0x0100: hide configuration for ajp and load balancer member workers
    Values 0x0040-0x0100 have been added in version 1.2.27.

    You can use the edit action with a final click to the update button, to change settings of workers. But you can also make direct calls to the update action. The following request parameters contain the configuration information, you want to change. First the list for load balancer workers:

    • vlr: retries (number)
    • vlt: recover_time (seconds)
    • vlee: error_escalation_time (seconds)
    • vlx: max_reply_timeouts (number)
    • vls: sticky_session (0/f/n/off=off, 1/t/y/on=on; case insensitive)
    • vlf: sticky_session_force (0/f/n/off=off, 1/t/y/on=on; case insensitive)
    • vlm: method (0/r="Requests", 1/t="Traffic", 2/b="Busyness", 3/s="Sessions", 4/s="Next"; case insensitive, only first character is used)
    • vll: lock (0/o="Optimistic", 1/p="Pessimistic"; case insensitive, only first character is used)
    And now the list of parameters you can use to change settings for load balancer members:
    • vwa: activation flag (0/a="active", 1/d="disabled", 2/s="stopped"; case insensitive, only first character is used)
    • vwf: load balancing factor (integer weight)
    • vwn: route for use with sticky sessions (string)
    • vwr: redirect to define simple failover rules (string)
    • vwc: domain to tell JK about your replication design (string)
    • vwd: distance to express preferences (integer)
    Finally the list of parameters you can use to change settings for ajp workers and ajp load balancer members:
    • vahst: host (string)
    • vaprt: port (number)
    • vacpt: connection_pool_timeout (number)
    • vact: connect_timeout (number)
    • vapt: prepost_timeout (number)
    • vart: reply_timeout (number)
    • var: retries (number)
    • varo: recovery_options (number)
    • vabl: busy_limit (number)
    • vamps: max_packet_size (number)
    Note that changing the host name or port will only take effect for new connections. Already established connections to the old address will still be used. Nevertheless this feature is interesting, because you can provision load balancer members with port "0", which will automatically be stopped during startup. Later when you know the final names and ports, you can set them and they will be automatically activated.

    The leading character "v" has been added to the parameters in version 1.2.27. Changing settings for ajp workers has also been introduced in version 1.2.27.

    For the details of all parameters, we refer to the workers.properties Reference.

    You can use the edit action to edit all settings for a load balancer or for a member of a load balancer respectively on one page. If you want to edit one configuration aspect for all members of a load balancer simultaneously, this will be triggered by the parameter att. The value of the parameter indicates, which aspect you want to edit. The list is the same as in the previous section, except for "vahst" and "vaprt": "vwa", "vwf", "vwn", "vwr", "vwc", "vwd", "vacpt", "vact", "vapt", "vart", "var", "varo", "vabl" and "vamps". But here you need to put the name into the parameter att, instead of using it as a request parameter name.

    The values of the common aspect for all the load balancer members will be given in parameters named "val0", "val1", ....

    tomcat-connectors-1.2.50-src/xdocs/reference/project.xml0000644000000000000020000001223114655113617021571 0ustar rootbin The Apache Tomcat Connectors - Reference Guide The Apache Tomcat Connectors - Reference Guide tomcat-connectors-1.2.50-src/xdocs/reference/apache.xml0000644000000000000020000013670314655113617021357 0ustar rootbin ]> &project; Mladen Turk Configuring mod_jk for the Apache HTTP Server

    Most of the directives are allowed once in the global part of the Apache HTTP Server configuration and once in every <VirtualHost> elements. Exceptions from this rule are explicitly listed in the table below.

    Most values are inherited from the main server to the virtual hosts. Since version 1.2.20 they can be overwritten in the virtual hosts. Exceptions from this rule are again explicitly listed in the table below. See especially JkMountCopy.

    Warning: If Apache and Tomcat are configured to serve content from the same file system location then care must be taken to ensure that Apache is not able to serve inappropriate content such as the contents of the WEB-INF directory or JSP source code.

    This could occur if the Apache DocumentRoot overlaps with a Tomcat Host's appBase or the docBase of any Context. It could also occur when using the Apache Alias directive with a Tomcat Host's appBase or the docBase of any Context.

    Here are the all directives supported by Apache:

    The name of a worker file for the Tomcat servlet containers.
    This directive is only allowed once. It must be put into the global part of the configuration.
    If you don't use the JkWorkerProperty directives, then you must define your workers with a valid JkWorkersFile. There is no default value.

    Enables setting worker properties inside Apache configuration file. The syntax is the same as in the JkWorkersFile (usually workers.properties). Simply prefix each line with "JkWorkerProperty" to put it directly into the Apache config files.
    This directive is allowed multiple times. It must be put into the global part of the configuration.
    If you don't use the JkWorkerProperty directives, then you must define your workers with a valid JkWorkersFile. There is no default value.
    This directive is available in jk1.2.7 version and later.

    Shared memory file name. Used only on unix platforms. The shm file is used by balancer and status workers.
    This directive is only allowed once. It must be put into the global part of the configuration.
    The default value is logs/jk-runtime-status. It is highly recommended that the shm file be placed on a local drive and not an NFS share.

    The shared memory contains configuration and runtime information for load balancer workers and their members. It is need in order that all Apache children

    • share the same status information for load balancing members (OK, ERROR, ...),
    • share the information about load taken by the individual workers,
    • share the information for the parts of the configuration, which are changeable during runtime by status workers.

    Size of the shared memory file name.
    This directive is only allowed once. It must be put into the global part of the configuration.
    The default value depends on the platform. It is usually less than 64KB.

    Starting with version 1.2.27 the size of the shared memory is determined automatically, even for large numbers of workers. This attribute is not needed any longer.

    File containing multiple mappings from a context to a Tomcat worker. It is usually called uriworkermap.properties.
    For inheritance rules, see: JkMountCopy.
    There is no default value.

    This directive configures the reload check interval in seconds. The JkMountFile is checked periodically for changes. A changed file gets reloaded automatically. If you set this directive to "0", reload checking is turned off.
    The default value is 60 seconds.
    This directive has been added in version 1.2.20 of mod_jk.

    A mount point from a context to a Tomcat worker.
    This directive is allowed multiple times. It is allowed in the global configuration and in VirtualHost.
    You can also use it inside Location with a different syntax. Inside Location, one omits the first argument (path), which gets inherited verbatim from the Location argument. Whereas <Location /myapp> matches any URI beginning with "/myapp", any JkMount nested in such a Location block will only match for requests with exact URI /myapp. Therefore nesting JkMount in Location is typically not the right thing to do.
    By default JkMount entries are not inherited from the global server to other VirtualHosts or between VirtualHosts. For the complete inheritance rules, see: JkMountCopy.
    You might append rule extensions to the worker name. The extensions are separated from the worker name by a semicolon ";" using the same syntax as in the uriworkermap.properties file.

    An exclusion mount point from a context to a Tomcat worker. All exclusion mounts are checked after mapping a request to a tomcat worker. If the request maps also to an exclusion, it will not be forwarded to tomcat, and instead be served locally.
    This directive is allowed multiple times. It is allowed in the global configuration and in VirtualHost.
    You can also use it inside Location with a different syntax. Inside Location, one omits the first argument (path), which gets inherited verbatim from the Location argument. Whereas <Location /myapp> matches any URI beginning with "/myapp", any JkUnMount nested in such a Location block will only match for requests with exact URI /myapp. Therefore nesting JkUnMount in Location is typically not the right thing to do.
    For inheritance rules, see: JkMountCopy.
    This directive is available in jk1.2.7 version and later.

    Automatically Alias webapp context directories into the Apache document space.
    Care should be taken to ensure that only static content is served via Apache as a result of using this directive. Any static content served by Apache will bypass any security constraints defined in the application's web.xml.
    For inheritance rules, see: JkMountCopy.
    There is no default value.

    If this directive is set to "On" in some virtual server, the mounts from the global server will be copied to this virtual server, more precisely all mounts defined by JkMount or JkUnMount. The Mounts defined by JkMountFile and JkAutoAlias will only be inherited, if the VirtualHost does not define it's own JkMountFile or JkAutoAlias.
    If you want all vhost to inherit mounts from the main server, you can set JkMountCopy to 'All' in the main server.
    This directive is only allowed inside VirtualHost (with value "On") and in the global server (with value "All").
    The default is Off, so no mounts will be inherited from the global server to any VirtualHost.
    Starting with version 1.2.26 you can also set it to "All" in the global virtual server. This will switch the default to On.

    Name of the Apache environment variable that can be used to set worker names in combination with SetHandler jakarta-servlet.
    This directive is only allowed once per virtual server. It is allowed in the global configuration and in VirtualHost.
    The default value is JK_WORKER_NAME.

    This directive configures the watchdog thread interval in seconds. The workers are maintained periodically by a background thread running periodically every watchdog_interval seconds. Worker maintenance checks for idle connections, corrects load status and is able to detect backend health status.
    The maintenance only happens, if since the last maintenance at least worker.maintain seconds have passed. So setting the JkWatchdogInterval much smaller than worker.maintain is not useful.
    The default value is 0 seconds, meaning the watchdog thread will not be created, and the maintenance is done in combination with normal requests instead.
    This directive is only allowed once. It must be put into the global part of the configuration.
    This directive has been added in version 1.2.27 of mod_jk. It is available only for Apache 2.x and above using APR libraries including thread support.

    Full or server relative path to the mod_jk log file. It will also work with pipe, by using a value of the form "| ...".
    The default value is logs/mod_jk.log.
    Pipes are supported for Apache 1.3 only since version 1.2.16. The default value exists only since version 1.2.20.

    The mod_jk log level, can be debug, info, warn error or trace.
    The default value is info.

    The mod_jk date log format, using an extended strftime syntax. This format will be used for the time stamps in the JkLogFile. The maximum length of the format is 63 characters.
    Starting with version 1.2.24 of mod_jk you can also use %Q for adding milliseconds to the log and %q for microseconds. These conversion specifiers are an extension to strftime. They will only work on platforms with a gettimeofday() function. You can use %Q and %q only once in the pattern and also not both together in the same pattern.
    The default value is "[%a %b %d %H:%M:%S %Y] " and beginning with version 1.2.24 on platforms with a gettimeofday() function it is "[%a %b %d %H:%M:%S.%Q %Y] ".

    Request log format string. See detailed description below.
    There is no default value. Without defining a value, the request logging is turned off.

    Turns on SSL processing and information gathering by mod_jk
    The default value is On.
    In order to make SSL data available for mod_jk in Apache, you need to set SSLOptions +StdEnvVars. For the certificate information you also need to add SSLOptions +ExportCertData.

    Specifically, mod_jk will export the following environment variables from Apache to Tomcat under these request attributes as per the Servlet Specification 3.0, section 3.8:

    Env VarRequest Attribute NameTypeExample
    SSL_CIPHER
    (or JkKEYSIZEIndicator)
    javax.servlet.request.cipher_suite java.lang.String DHE-RSA-AES256-SHA
    SSL_CIPHER_USEKEYSIZE
    (or JkKEYSIZEIndicator)
    javax.servlet.request.key_size java.lang.Integer 256
    SSL_SESSION_ID
    (or JkSESSIONIndicator)
    javax.servlet.request.ssl_session java.lang.String 905...32E (a hex string)
    SSL_CLIENT_CERT_CHAIN_n
    (or JkCERTCHAINPrefixn)
    javax.servlet.request.X509Certificate java.security.X509Certificate[] (A chain of certs in ascending order of trust, the first one being ths client's certificate, the second being the signer of that certificate, and so on)

    In addition mod_jk sends the name of the SSL protocol used as a proprietary request attribute named AJP_SSL_PROTOCOL. Modern Tomcat versions will expose this attribute under the name org.apache.tomcat.util.net.secure_protocol_version. This feature has been added in version 1.2.41 of mod_jk. See also JkSSLPROTOCOLIndicator.

    For all other SSL-related variables, use JkEnvVar for each variable you want. Please note that, like JkEnvVar, these variables are available from the request attributes, not as environment variables or as request headers.

    Name of the Apache environment variable that contains a unique request id. The value of the environment variable will be added to most mod_jk error log lines and allows easy correlation with Apache logs by adding that environment variable there as well.
    The default value is "UNIQUE_ID". Loading the module "mod_unique_id" will automatically provide a unique request id under that name.

    This feature has been added in version 1.2.49 of mod_jk.

    If a request id is sent by the client or another reverse proxy in front via an HTTP request header, one can make this id available for mod_jk by copying it to an environment variable using mod_setenvif:
    SetEnvIf X-REQUEST-ID-HEADER "(.+)" X-REQUEST-ID=$1
    copies the value of the incoming header X-REQUEST-ID-HEADER to the environment variable X-REQUEST-ID. mod_jk can pick it up from there via JkRequestIdIndicator X-REQUEST-ID.

    Name of the Apache environment variable that contains SSL indication.
    The default value is "HTTPS".

    Name of the Apache environment variable that contains the SSL protocol name.
    The default value is "SSL_PROTOCOL".
    This directive has been added in version 1.2.41 of mod_jk.

    Name of the Apache environment variable that contains SSL client certificates.
    The default value is "SSL_CLIENT_CERT".

    Name of the Apache environment variable that contains SSL client cipher.
    The default value is "SSL_CIPHER".

    Name of the Apache environment (prefix) that contains SSL client chain certificates.
    The default value is "SSL_CLIENT_CERT_CHAIN_".

    Name of the Apache environment variable that contains SSL session.
    The default value is "SSL_SESSION_ID".

    Name of the Apache environment variable that contains SSL key size in use.
    The default value is "SSL_CIPHER_USEKEYSIZE".

    Name of the Apache environment variable which can be used to overwrite the forwarded local name. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_LOCAL_NAME".
    This directive has been added in version 1.2.28 of mod_jk.

    Name of the Apache environment variable which forces to ignore an existing Content-Length request header. This can be used to make mod_jk conpatible with mod_deflate request body inflation (see below).
    The default value is "JK_IGNORE_CL".
    This directive has been added in version 1.2.41 of mod_jk.

    Name of the Apache environment variable which can be used to overwrite the forwarded local IP address. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_LOCAL_ADDR".
    This directive has been added in version 1.2.41 of mod_jk.

    Name of the Apache environment variable which can be used to overwrite the forwarded local port. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_LOCAL_PORT".
    This directive has been added in version 1.2.28 of mod_jk.

    Name of the Apache environment variable which can be used to overwrite the forwarded remote (client) host name. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_REMOTE_HOST".
    This directive has been added in version 1.2.28 of mod_jk.

    Name of the Apache environment variable which can be used to overwrite the forwarded remote (client) IP address. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_REMOTE_ADDR".
    This directive has been added in version 1.2.28 of mod_jk.

    Name of the Apache environment variable which can be used to overwrite the forwarded remote (client) IP address. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_REMOTE_PORT".
    This directive has been added in version 1.2.32 of mod_jk.

    Name of the Apache environment variable which can be used to overwrite the forwarded user name. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_REMOTE_USER".
    This directive has been added in version 1.2.28 of mod_jk.

    Name of the Apache environment variable which can be used to overwrite the forwarded authentication type. Use this only if you need to adjust the data (see the proxy documentation).
    The default value is "JK_AUTH_TYPE".
    This directive has been added in version 1.2.28 of mod_jk.

    Set one of more options to configure the mod_jk module. See below for details about this directive.
    This directive can be used multiple times per virtual server.
    The default value is "ForwardURIProxy" since version 1.2.24. It was "ForwardURICompatUnparsed" in version 1.2.23 and "ForwardURICompat" until version 1.2.22.

    Adds a name and an optional default value of environment variable that should be sent to servlet-engine as a request attribute. If the default value is not given explicitly, the variable will only be send, if it is set during runtime.
    The default is empty, so no additional variables will be sent.
    This directive can be used multiple times per virtual server. The settings will be merged between the global server and any virtual server.
    You can retrieve the variables on Tomcat as request attributes via request.getAttribute(attributeName). Note that the variables send via JkEnvVar will not be listed in request.getAttributeNames().
    Empty default values are supported since version 1.2.20. Not sending variables with empty defaults and empty runtime value has been introduced in version 1.2.21.

    If this directive is set to On in some virtual server, the session IDs ;jsessionid=... will be removed for URLs which are not forwarded but instead are handled by the local server.
    This directive is only allowed inside VirtualHost.
    The default is Off.
    This directive has been introduced in version 1.2.21.
    With version 1.2.27 and later this directive can have optional session ID identifier. If not specified it defaults to ;jsessionid.

    We'll discuss here the mod_jk directive types.

    JkWorkersFile specify the location where mod_jk will find the workers definitions. Take a look at Workers documentation for detailed description. JkWorkersFile /etc/httpd/conf/workers.properties

    JkLogFile specify the location where mod_jk is going to place its log file.

    JkLogFile /var/log/httpd/mod_jk.log

    Since JK 1.2.3 for Apache 2.x and JK 1.2.16 for Apache 1.3 this can also be used for piped logging:

    JkLogFile "|/usr/bin/rotatelogs /var/log/httpd/mod_jk.log 86400"

    JkLogLevel set the log level between:

    • info log will contain standard mod_jk activity (default).
    • warn log will contain non fatal error reports.
    • error log will contain also error reports.
    • debug log will contain all information on mod_jk activity
    • trace log will contain all tracing information on mod_jk activity
    JkLogLevel info

    info should be your default selection for normal operations.

    JkLogStampFormat will configure the date/time format found on mod_jk log file. See above for details.

    JkLogStampFormat "[%Y-%m-%d %H:%M:%S.%Q] "

    You can log mod_jk information using the Apache standard module mod_log_config. The module sets several notes in the Apache notes table. Most of them are are only useful in combination with a load balancer worker.

    Name of the worker selected by the URI mapping Type of the worker selected by the URI mapping Actual worker name selected by the URI mapping (usually a member of the load balancer).
    Before version 1.2.26 only available if JkRequestLogFormat is set.
    Request duration in seconds and microseconds.
    Before version 1.2.26 only available if JkRequestLogFormat is set.
    Load balancer: Name of the first worker tried Load balancer: Type of the first worker tried Load balancer: Access count for the first worker tried Load balancer: Count of created sessions for the first worker tried Load balancer: Bytes read for the first worker tried Load balancer: Bytes transferred for the first worker tried Load balancer: Error count for the first worker tried Load balancer: Busy count for the first worker tried Load balancer: Activation state for the first worker tried Load balancer: Error state for the first worker tried Load balancer: Name of the last worker tried Load balancer: Type of the last worker tried Load balancer: Access count for the last worker tried Load balancer: Count of created sessions for the last worker tried Load balancer: Bytes read for the last worker tried Load balancer: Bytes transferred for the last worker tried Load balancer: Error count for the last worker tried Load balancer: Busy count for the last worker tried Load balancer: Activation state for the last worker tried Load balancer: Error state for the last worker tried
    LogFormat "%h %l %u %t \"%r\" %>s %b %{JK_WORKER_NAME}n %{JK_LB_FIRST_NAME}n \ %{JK_LB_FIRST_BUSY}n %{JK_LB_LAST_NAME}n %{JK_LB_LAST_BUSY}n" mod_jk_log CustomLog logs/access_log mod_jk_log

    You can also log a request protocol in the mod_jk log file instead of the access log. This is not recommended and mostly a backward compatibility feature. The directive JkRequestLogFormat will configure the format of this protocol. It gets configured and enabled on a per virtual host basis. To enable request logging for a virtual host just add a JkRequestLogFormat config. The syntax of the format string is similar to the Apache LogFormat command, here is a list of the available request log format options:

    Bytes sent, excluding HTTP headers (CLF format) Bytes sent, excluding HTTP headers The request protocol The request method The canonical Port of the server serving the request The query string (prepended with a ? if a query string exists, otherwise an empty string) First line of request Request HTTP status code Request duration, elapsed time to handle request in seconds '.' micro seconds The URL path requested, not including any query string. The canonical ServerName of the server serving the request The server name according to the UseCanonicalName setting Tomcat worker name Real worker name JkRequestLogFormat "%w %V %T"

    The directive JkOptions allow you to set many forwarding options which will enable (+) or disable (-) following option. Without any leading signs, options will be enabled.

    The four following options +ForwardURIxxx are mutually exclusive. Exactly one of them is required, a negative sign prefix is not allowed with them. The default value is "ForwardURIProxy" since version 1.2.24. It was "ForwardURICompatUnparsed" in version 1.2.23 and "ForwardURICompat" until version 1.2.22. You can turn the default off by switching on one of the other two options. You should leave this at it's default value, unless you have a very good reason to change it.

    All options are inherited from the global server to virtual hosts. Options that support enabling (plus options) and disabling (minus options), are inherited in the following way:
    options(vhost) = plus_options(global) - minus_options(global) + plus_options(vhost) - minus_options(vhost)

    Using JkOptions ForwardURIProxy, the forwarded URI will be partially reencoded after processing inside Apache and before forwarding to Tomcat. This will be compatible with local URL manipulation by mod_rewrite and with URL encoded session ids. JkOptions +ForwardURIProxy

    Using JkOptions ForwardURICompatUnparsed, the forwarded URI will be unparsed. It's spec compliant and secure. It will always forward the original request URI, so rewriting URIs with mod_rewrite and then forwarding the rewritten URI will not work. JkOptions +ForwardURICompatUnparsed

    Using JkOptions ForwardURICompat, the forwarded URI will be decoded by Apache. Encoded characters will be decoded and explicit path components like ".." will already be resolved. This is less spec compliant and is not safe if you are using prefix JkMount. This option will allow to rewrite URIs with mod_rewrite before forwarding. JkOptions +ForwardURICompat

    Using JkOptions ForwardURIEscaped, the forwarded URI will be the encoded form of the URI used by ForwardURICompat. Explicit path components like ".." will already be resolved. This will not work in combination with URL encoded session IDs, but it will allow to rewrite URIs with mod_rewrite before forwarding. JkOptions +ForwardURIEscaped

    JkOptions RejectUnsafeURI will block all URLs, which contain percent signs '%' or backslashes '\' after decoding.

    Most web apps do not use such URLs. Using the option RejectUnsafeURI, you can block several well known URL encoding attacks. By default, this option is not set.

    You can also realise such a check with mod_rewrite, which is more powerful but also slightly more complicated. JkOptions +RejectUnsafeURI

    JkOptions CollapseSlashesAll is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions CollapseSlashesUnmount is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions CollapseSlashesNone is deprecated as of 1.2.44 and will be ignored if used.

    JkOptions ForwardDirectories is used in conjunction with DirectoryIndex directive of Apache. As such mod_dir should be available to Apache, statically or dynamically (DSO)

    When DirectoryIndex is configured, Apache will create sub-requests for each of the local-url's specified in the directive, to determine if there is a local file that matches (this is done by stat-ing the file).

    If ForwardDirectories is set to false (default) and Apache doesn't find any files that match, Apache will serve the content of the directory (if directive Options specifies Indexes for that directory) or a 403 Forbidden response (if directive Options doesn't specify Indexes for that directory).

    If ForwardDirectories is set to true and Apache doesn't find any files that match, the request will be forwarded to Tomcat for resolution. This is used in cases when Apache cannot see the index files on the file system for various reasons: Tomcat is running on a different machine, the JSP file has been precompiled etc.

    Note that locally visible files will take precedence over the ones visible only to Tomcat (i.e. if Apache can see the file, that's the one that's going to get served). This is important if there is more then one type of file that Tomcat normally serves - for instance Velocity pages and JSP pages. JkOptions +ForwardDirectories

    Setting JkOptions ForwardLocalAddress, you ask mod_jk to send the local address, of the Apache HTTP Server instead remote client address. This can be used by the Tomcat remote address valve for allowing connections only from configured Apache servers. JkOptions +ForwardLocalAddress

    Setting JkOptions ForwardPhysicalAddress, you ask mod_jk to send the physical peer TCP IP address as the client address. By default mod_jk uses the logical address as provided by the web server. For example the module mod_remoteip sets the logical IP address to the client IP forwarded by proxies in the X-Forwarded-For header. JkOptions +ForwardPhysicalAddress

    JkOptions FlushPackets, you ask mod_jk to flush Apache's connection buffer after each AJP packet chunk received from Tomcat. This option can have a strong performance penalty for Apache and Tomcat as writes are performed more often than would normally be required (ie: at the end of each response). JkOptions +FlushPackets

    JkOptions FlushHeader, you ask mod_jk to flush Apache's connection buffer after the response headers have been received from Tomcat. JkOptions +FlushHeader

    JkOptions DisableReuse, you ask mod_jk to close connections immediately after their use. Normally mod_jk uses persistent connections and pools idle connections to reuse them, when new requests have to be sent to Tomcat.

    Using this option will have a strong performance penalty for Apache and Tomcat. Use this only as a last resort in case of unfixable network problems. If a firewall between Apache and Tomcat silently kills idle connections, try to use the worker attribute socket_keepalive in combination with an appropriate TCP keepalive value in your OS. JkOptions +DisableReuse

    JkOptions ForwardKeySize, you ask mod_jk, when using ajp13, to forward also the SSL Key Size as required by Servlet API 2.3. This flag shouldn't be set when servlet engine is Tomcat 3.2.x (on by default). JkOptions +ForwardKeySize

    JkOptions ForwardSSLCertChain, you ask mod_jk, when using ajp13, to forward SSL certificate chain (off by default). Mod_jk only passes the SSL_CLIENT_CERT to the AJP connector. This is not a problem with self-signed certificates or certificates directly signed by the root CA certificate. However, there's a large number of certificates signed by an intermediate CA certificate, where this is a significant problem: A servlet will not have the possibility to validate the client certificate on its own. The bug would be fixed by passing on the SSL_CLIENT_CERT_CHAIN to Tomcat via the AJP connector.
    This directive exists only since version 1.2.22. JkOptions +ForwardSSLCertChain

    The directive JkEnvVar allows you to forward environment variables from Apache server to Tomcat engine. You can add a default value as a second parameter to the directive. If the default value is not given explicitly, the variable will only be send, if it is set during runtime.
    The variables can be retrieved on the Tomcat side as request attributes via request.getAttribute(attributeName). Note that the variables send via JkEnvVar will not be listed in request.getAttributeNames().
    The variables are inherited from the global server to virtual hosts. JkEnvVar SSL_CLIENT_V_START undefined

    If you have created a custom or local version of mod_jk.conf-local as noted above, you can change settings such as the workers or URL prefix.

    JkMount directive assign specific URLs to Tomcat. In general the structure of a JkMount directive is:

    JkMount [URL prefix] [Worker name] # send all requests ending in .jsp to worker1 JkMount /*.jsp worker1 # send all requests ending /servlet to worker1 JkMount /*/servlet/ worker1 # send all requests jsp requests to files located in /otherworker will go worker2 JkMount /otherworker/*.jsp worker2

    You can use the JkMount directive at the top level or inside <VirtualHost> sections of your httpd.conf file.

    JkUnMount directive acts as an opposite to JkMount and blocks access to a particular URL. The purpose is to be able to filter out the particular content types from mounted context. The following example mounts /servlet/* context, but all .gif files that belongs to that context are not served.

    # send all requests ending with /servlet to worker1 JkMount /servlet/* worker1 # do not send requests ending with .gif to worker1 JkUnMount /servlet/*.gif worker1

    JkUnMount takes precedence over JkMount directives, meaning that the JK will first try to mount and then checks, if there is an exclusion defined by a JkUnMount. A JkUnMount overrides a JkMount only, if the worker names in the JkMount and in the JkUnMount are the same.

    The following example will block all .gif files although there is a JkMount for them:

    # do not send requests ending with .gif to worker1 JkUnMount /*.gif worker1 # The .gif files will not be mounted cause JkUnMount takes # precedence over JkMount directive JkMount /servlet/*.gif worker1

    Starting with version 1.2.26 of JK you can apply a JkUnMount to any worker, by using the star character '*' as the worker name in the JkUnMount. More complex patterns in JkUnMount worker names are not allowed.

    # Mapping the webapps myapp1 and myapp2: /myapp1/*=worker1 /myapp2/*=worker2 # Exclude the all subdirectories static for all workers: !/*/static/*=* # Exclude some suffixes for all workers: !*.html=*

    JkAutoAlias directive automatically Alias webapp context directories into the Apache document space. It enables Apache to serve a static context while Tomcat serving dynamic context. This directive is used for convenience so that you don't have to put an Apache Alias directive for each application directory inside Tomcat's webapp directory. For security reasons it is strongly recommended that JkMount is used to pass all requests to Tomcat by default and JkUnMount is used to explicitly exclude static content to be served by Apache. It should also be noted that content served by Apache will bypass any security constraints defined in the application's web.xml. The directive only works in the simple case of contexts with a single path element and no version marker. It does not support:

    • the ROOT context (i.e. .../webapps/ROOT)
    • multi-level contexts (e.g. .../webapps/foo#bar)
    • parallel deployment (e.g. .../webapps/foo##v00.05.12)

    # enter the full path to the tomcat webapps directory JkAutoAlias /opt/tomcat/webapps

    The following example shows how to serve a dynamic context by Tomcat and static using Apache. The webapps directory has to be accessible by Apache.

    # enter the full path to the tomcat webapps directory JkAutoAlias /opt/tomcat/webapps # Mount 'examples' directory. It's physical location # is assumed to be in the /opt/tomcat/webapps/examples # ajp13w is a worker defined in the workers.properties JkMount /examples/* ajp13w # Unmount desired static content from examples webapp. # This content will be served by the Apache directly. JkUnMount /*.gif ajp13w

    Note that you can have a single JkAutoAlias directive per virtual host inside your httpd.conf

    JkWorkerProperty is a new directive available from JK 1.2.7 version. It is a convenient method for setting directives that are usually set inside workers.propeties file. The parameter for that directive is raw line from workers.properties file.

    # Just like workers.properties but exact line is prefixed # with JkWorkerProperty # Minimal jk configuration JkWorkerProperty worker.list=ajp13w JkWorkerProperty worker.ajp13w.type=ajp13 JkWorkerProperty worker.ajp13w.host=localhost JkWorkerProperty worker.ajp13w.port=8009

    JkMountFile is a new directive available from JK 1.2.9 version. It is used for dynamic updates of mount points at runtime. When the mount file is changed, JK will reload it's content.

    # Load mount points JkMountFile conf/uriworkermap.properties

    If the mount point uri starts with an exclamation mark '!' it defines an exclusion in the same way JkUnMount does. If the mount point uri starts with minus sign '-' the mount point will only be disabled. A disabled mount can be reenabled by deleting the minus sign and waiting for the JkMountFile to reload. An exclusion can be disabled by prefixing it with a minus sign.

    # Sample uriworkermap.properties file /examples/*=ajp13w # Do not map .gif files !/*.gif=ajp13w # Make jsp examples initially disabled -/examples/jsp/*=ajp13w

    At run time you can change the content of this file. For example removing minus signs will enable the previously disabled uri mappings. You can add any number of new entries at runtime that reflects the newly deployed applications. Apache will reload the file and update the mount points within 60 second interval.

    There is no way to delete entries by dynamic reloading, but you can disable or exclude mappings.

    Alternatively to the mod_jk specific directives, you can also use SetHandler and environment variables to control, which requests are being forwarded via which worker. This gives you more flexibility, but the results might be more difficult to understand. If you mix both ways of defining the forwards, in general to mod_jk directives will win.

    SetHandler jakarta-servlet forces requests to be handled by mod_jk. You can use SetHandler for example in Location blocks or with Apache 2.2 and later also in RewriteRule.

    In order to control the worker using SetEnvIf or RewriteRule for more complex rules, you can set the environment variable JK_WORKER_NAME to the name of your chosen target worker. This enables you to decide on the chosen worker in a more flexible way, including dependencies on cookie values. This feature has been added in version 1.2.19 of mod_jk. Furthermore you might append rule extensions to the worker name. The extensions are separated from the worker name by a semicolon ";" using the same syntax as in the uriworkermap.properties file. Supporting rule extensions in the worker name has been added in version 1.2.33.

    In order to use another variable than JK_WORKER_NAME, you can set the name of this variable via the JkWorkerIndicator directive.

    You can also define exclusions from mod_jk forwards by setting the environment variable no-jk.

    # Automatically map all encoded urls <Location *;jsessionid=> SetHandler jakarta-servlet SetEnv JK_WORKER_NAME my_worker </Location> # Map all subdirs to workers via naming rule # and exclude static content. <Location /apps/> SetHandler jakarta-servlet SetEnvIf REQUEST_URI ^/apps/([^/]*)/ JK_WORKER_NAME=$1 SetEnvIf REQUEST_URI ^/apps/([^/]*)/static no-jk </Location>

    Environment variables allow to overwrite the default behaviour of mod_jk depending on request properties like e.g. the request URI, header values or cookie. This can be done using the SetEnvIf or RewriteRule directives.

    The environment variable JK_ROUTE can be set to explicitely choose a member of a load balancer worker. The value must be equal to the route attribute of the member, or if that attribute is not used, equal to the member name. Note that this is only needed if session IDs and routes are encoded in a non standard way in the request. Stickyness using the Java Servlet compliant way of encoding the IDs is supported by default. This is available since version 1.2.33.

    The environment variable JK_REPLY_TIMEOUT can be set to dynamically define a reply timeout. The value must be given in milliseconds. This is available since version 1.2.27.

    The environment variable JK_STICKY_IGNORE can be set to disable session stickyness for individual requests. If the variable is set to an empty string or a nonzero number, session stickyness will be disabled. Setting it to 0 will reset to the behaviour defined by the worker configuration. This is available since version 1.2.33.

    This feature can be useful to optimize load balancing when using cookie based session stickyness. In this case, as long as she keeps her browser open, any request by a user who started a session will be send to the same Tomcat instance, even if he left the part of the application which uses the session. You can for instance set this environment variable when a user requests a login form to ensure, that this initial session request is balanced non-sticky.

    The environment variable JK_STATELESS can be used to improve load balancing for the session based balancing methods Session and Next. In this case normally any request which does not come with a session id counts as a new session. This can be problematic, if for instance static content is retrieved without a session id. If you set the environment variable JK_STATELESS for a request, then the request will not count as a new session, even if it does not come with a session id. This is available since version 1.2.33.

    The environment variable JK_IGNORE_CL can be set to force ignoring the request Content-Length header (if it exists). mod_jk will then stream the request body until the web server indicates that the full body was read. No Content-Length header will be send to the backend. This is available since version 1.2.41.

    This feature can be used to make mod_jk compatible with filters which change the size of the request body. One such filter is mod_deflate when used to inflate the body of a request with gzip encoded body. In this case mod_jk will by default forward a truncated body, because it gets the wrong body size from the web server. Telling mod_jk to ignore the Content-Length header will result in streaming all request body data it can read from the web server to the backend.

    You should only set the JK_IGNORE_CL environment variables for requests that actually need it. Unfortunately there's no way for mod_jk to detect the need automatically.

    tomcat-connectors-1.2.50-src/xdocs/reference/uriworkermap.xml0000644000000000000020000004025114655113617022655 0ustar rootbin ]> &project; Rainer Jung Mladen Turk uriworkermap.properties configuration

    The forwarding of requests from the web server to tomcat gets configured by defining mapping rules. Such a rule maps requests to workers. The request part of the map is described by a URI pattern, the worker by it's worker name.

    The so-called uriworkermap file is a mechanism of defining rules, which works for all web servers. There exist also other web server specific configuration options for defining rules, which will be mostly discussed on the reference pages for configuring tomcat connectors for the individual web servers.

    The name of the file is usually uriworkermap.properties, although this is configurable in the web server. Please consult the web server specific documentation pages on how to enable the uriworkermap file.

    The main features supported by the uriworkermap file are

    • Support for comments in the rule file.
    • Exact and wildchar matches, shortcuts to map a directory and all including content.
    • Exclusion rules, disabling of rules and rule priorities.
    • Rule extensions, modifying worker behaviour per rule.
    • Virtual host integration: uri mapping rules can be expressed per virtual host. The details are web server specific though.
    • Dynamic reloading: The file gets checked periodically for changes. New versions are automatically reloaded without web server restarts.
    • Integration with the status worker.
    The following sections describe these aspects in more detail.

    The file has a line based format. There are no continuation characters, so each rule needs to be defined on a single line. Each rule is a pair consisting of a URI pattern and a worker name, combined by an equals sign '=': /myapp=myworker The URI pattern is case sensitive.

    All text after and including the character '#' gets ignored and can be used for comments. Leading and trailing white space gets trimmed around the URI pattern and also around the worker name. The following definitions are all equivalent: # This is a white space example /myapp=myworker /myapp=myworker /myapp = myworker

    Inside the URI pattern three special characters can be used, '*', '?' and '|'. The character '*' is a wildchar that matches any number of arbitrary characters in the URI, '?' matches exactly one character. Each URI pattern has to start with the character '/', or with '*' or with '?', optionally prefixed by any combination of the modifiers '!' and '-' (see next section). # Mapping the URI /myapp1 and everything under /myapp1/: /myapp1=myworker-a /myapp1/*=myworker-a # Mapping all URI which end with a common suffix: *.jsp=myworker *.do=myworker Since the first case of mapping a certain location and everything inside it is very common, the character '|' gives a handy shortcut: # Mapping the URI /myapp1 and everything under /myapp1/: /myapp1|/*=myworker-a The pattern 'X|Y' is exactly equivalent to the two maps 'X' and 'XY'.

    Exclusion rules allows to define exclusions from URI rules, which would forward requests to tomcat. If the exclusion rule matches, the request will not be forwarded. This is usually used to serve static content by the web server. A rule is an exclusion rule, if it is suffixed with '!': # Mapping the URI /myapp and everything under /myapp/: /myapp|/*=myworker # Exclude the subdirectory static: !/myapp/static|/*=myworker # Exclude some suffixes: !*.html=myworker An exclusion rule overrides a normal mapping rule only, if the worker names in the normal rule and in the exclusion rule are the same. Starting with version 1.2.26 of JK you can apply an exclusion rule to any worker, by using the star character '*' as the worker name in the exclusion rule. More complex patterns in exclusion worker names are not allowed. # Mapping the webapps /myapp1 and /myapp2: /myapp1|/*=myworker1 /myapp2|/*=myworker2 # Exclude the all subdirectories static for all workers: !/*/static|/*=* # Exclude some suffixes for all workers: !*.html=*

    Rule disabling comes into play, if your web server merges rules from various sources, and you want to disable any rule defined previously. Since the uriworkermap file gets reloaded dynamically, you can use this to temporarily disable request forwarding: A rule gets disabled, if it is suffixed with '-': # We are not in maintenance. # The maintenance rule got defined somewhere else. -/*=maintenance Exclusion rules can get disabled as well, then the rule starts with '-!'.

    The most restrictive URI pattern is applied first. More precisely the URI patterns are sorted by the number of '/' characters in the pattern (highest number first), and rules with equal numbers are sorted by their string length (longest first).

    If both distinctions still do not suffice, then the defining source of the rule is considered. Rules defined in uriworkermap.properties come first, before rules defined by JkMount (for the Apache HTTP Server) and inside workers.properties using the mount attribute.

    All disabled rules are ignored. Exclusion rules are applied after all normal rules have been applied.

    There is no defined behaviour, for the following configuration conflict: using literally the same URI pattern in the same defining source but with different worker targets.

    Rule extensions were added in version 1.2.27 and are not available in earlier versions.

    Rule extensions are additional attributes, that can be attached to any rule. They are added at the end of the rule, each extension separated by a semicolon: # This is an extension example, # setting a reply_timeout of 1 minute # only for this mapping. /myapp=myworker;reply_timeout=60000 # # This is an example using multiple extensions /myapp=myloadbalancer;reply_timeout=60000;stopped=member1 Attributes set via rule extensions always overwrite conflicting configurations in the worker definition file.

    The extension reply_timeout sets a reply timeout for a single mapping rule. # Setting a reply_timeout of 1 minute # only for this mapping. /myapp=myworker;reply_timeout=60000 It overrides any reply_timeout defined for the worker. The extension allows to set a reasonable default reply timeout to the worker, and a more relaxed reply timeout to URLs, which are known to start time intensive tasks. For a general description of reply timeouts see the timeouts documentation.

    The extension sticky_ignore will disable session stickyness for a single mapping rule. # Disable session stickyness # only for this mapping. /myapp/loginform.jsp=myworker;sticky_ignore=1 This extension can be useful to optimize load balancing when using cookie based session stickyness. In this case, as long as she keeps her browser open, any request by a user who started a session will be send to the same Tomcat instance, even if he left the part of the application which uses the session. You can for instance set this environment variable when a user requests a login form to ensure, that this initial session request is balanced non-sticky.

    This extension is available since version 1.2.33.

    The extension stateless is only useful when using session based load balancing. In this case normally any request which does not come with a session id counts as a new session. If you mark a mapping rule with the stateless extension, then the requests matching the mapping rule will not count as a new session, even if they do not come with a session id. # Don't let static content trash our session balancing /myapp/static/*=myworker;stateless=1 This extension is available since version 1.2.33.

    The extensions active, disabled, and stopped can be used in a load balancer mapping rule to set selected members of the load balancer into a special activation state. # Stop forwarding only for member1 of loadbalancer /myapp=myloadbalancer;stopped=member1 Multiple members must be separated by commas or white space: # Stop forwarding for member01 and member02 of loadbalancer # Disable forwarding for member21 and member22 of loadbalancer /myapp=myloadbalancer;stopped=member01,member02;disabled=member21,member22 For the precise meaning of the activation states see the description of activation.

    The extension fail_on_status can be used in any rule: # Send 503 instead of 404 and 500, # and if we get a 503 also set the worker to error /myapp=myworker;fail_on_status=-404,-500,503 Multiple status codes must be separated by commas. For the precise meaning of the attribute see the description of fail_on_status.

    The extension use_server_errors allows to let the web server send an error page, instead of the backend (e.g. Tomcat) error page. This is useful, if one wants to send customized error pages, but those are not part of all web applications. They can then be put onto the web server.

    The value of use_server_errors is a positive number. Any request send to the backend, that returns with an http status code bigger or equal to use_server_errors, will be answered to the client with the error page of the web server for this status code. # Use web server error page for all errors /myapp=myworker;use_server_errors=400 # Use web server error page only for technical errors /myotherapp=myworker;use_server_errors=500

    The extensions

    • session_cookie
    • session_path
    • set_session_cookie
    • session_cookie_path
    allow to define the load balancer worker attributes of the same name per mount. See their descriptions in the worker.properties configuration reference.

    When using the ISAPI redirector for Microsoft IIS you can restrict individual rules to special virtual hosts by prefixing the URI pattern with the virtual host information. The rules is that the url must be prefixed with the host name. # Use www.foo.org as virtual host /www.foo.org/myapp/*=myworker # Use www.bar.org as virtual host /www.bar.org/myapp/*=myworker # Normal mapping /mysecondapp/*=myworker

    Note that /mysecondapp/* will be mapped to all virtual hosts present. In case one needs to prevent the mappings to some particular virtual host then the exclusion rule must be used # Make sure the myapp is accessible by all virtual hosts /myapp/*=myworker # Disable mapping myapp for www.foo.org virtual host !/www.foo.org/myapp/*=myworker

    For the Apache HTTP Server you can define individual uriworkermap files per virtual host. The directive JkMountFile can be used in the main server and in each virtual host. If a virtual host does not use JkMountfile, but JkMountCopy is set to 'On', then it inherits the JkMountFile from the main server. If you want all vhost to inherit mounts from the main server, you can set JkMountCopy to 'All' in the main server.

    When a request is being processed, tomcat connectors check the file modification time of the uriworkermap file. To keep the performance penalty low, this happens only, if the last check happened at least n seconds ago.

    For the Apache HTTP Server you can configure the interval "n" using the directive JkMountFileReload, for Microsoft IIS you would use the attribute worker_mount_reload. The default value is 60 seconds. A value of "0" turns off the reloading.

    If the file changed, it gets reloaded completely. If there exist rules coming from other sources than the uriworkermap file (e.g. the workers.properties mount attribute or JkMount for the Apache HTTP Server), the new uriworkermap file gets dynamically merged with these ones exactly like when you do a web server restart.

    Until version 1.2.19 reloading behaved slightly differently: it continuously added the full contents of the uriworkermap file to the rule mapping. The merging rules were, that duplicated got eliminated and old rules could be disabled, by defining the rule as disabled in the new file. Rules never got deleted.

    The configuration view of the status worker also shows the various mapping rules. After each worker's configuration, the rules are listed, that forward to this worker. The list contains four columns:

    • the name of the virtual server
    • the URI pattern, prefixed with '-' for a disabled pattern and '!' for an exclusion pattern
    • the type of the rule: Exact or Wildchar
    • and the source of the rule definition: 'worker definition' for the workers.properties file (mount attribute), 'JkMount' for the Apache HTTP Server JkMount and it's relatives and finally 'uriworkermap' for the uriworkermap file.

    Note: The following restriction has been removed starting with version 1.2.26.
    For the Apache HTTP Server, there is an important subtlety: the request going to the status worker gets executed in the context of some server (main or virtual). The status worker will only show the mapping rules, that are defined for this server (main or virtual).
    Until version 1.2.25 the list contained three columns:

    • the type of the rule: Exact or Wildchar, eventually prefixed with Disabled or Unmount (for exclusion rules)
    • the URI pattern
    • and the source of the rule definition: 'worker definition' for the workers.properties file (mount attribute), 'JkMount' for the Apache HTTP Server JkMount and it's relatives and finally 'uriworkermap' for the uriworkermap file.

    tomcat-connectors-1.2.50-src/xdocs/reference/iis.xml0000644000000000000020000004010214655113617020705 0ustar rootbin ]> &project; Mladen Turk Configuring the ISAPI redirector for Microsoft IIS

    The Tomcat redirector requires three entities:

    • isapi_redirect.dll - The IIS ISAPI redirector plugin, either obtain a pre-built DLL or build it yourself (see the build section).
    • workers.properties - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). A sample workers.properties can be found under the conf directory.
    • uriworkermap.properties - A file that maps URL-Path patterns to workers. A sample uriworkermap.properties can be found under the conf directory as well.

    The installation includes the following parts:

    • Configuring the ISAPI redirector with a default /examples context and checking that you can serve servlets with IIS.
    • Adding more contexts to the configuration.

    Note that in a 64 Bit environment - at least for IIS 7 - the used IIS Application Pool should have "Enable 32-bit Applications" set to "False". Otherwise the redirector will not be called and returns an http code 404. If you think, the 32bit version of isapi_redirect.dll would do the job instead, you will get an http code 500, because the library is not loadable into a 64 Bit IIS.

    ISAPI redirector reads configuration from the registry, create a new registry key named:

    "HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0"

    Attributes described below as a "string value representing a boolean" can be set either using the numbers 0 (false) and 1 (true) as values, or off (false) and on (true) or any other string starting with the letters f (false), n (false), t (true) or y (true). The values are taken case insensitive. In this documentation we will stick to false and true.

    A string value pointing to the ISAPI extension /jakarta/isapi_redirect.dll

    A value pointing to location where log file will be created. (for example c:\tomcat\logs\isapi.log)
    If one of the log rotation settings (log_rotationtime or log_filesize) are specified then the actual log file name is based on this setting. If the log file name includes any '%' characters, then it is treated as a format string for strftime(3), e.g. c:\tomcat\logs\isapi-%Y-%m-%d-%H_%M_%S.log. Otherwise, the suffix .nnnnnnnnnn is automatically added and is the time in seconds. A full list of format string substitutions can be found in the Apache rotatelogs documentation

    A string value for log level (can be debug, info, warn, error or trace).

    This directive was added in version 1.2.31

    The time between log file rotations in seconds. Setting this to 0 (the default) disables log rotation based on time.

    This directive was added in version 1.2.31

    The maximum log file size in megabytes, after which the log file will be rotated. Setting this to 0 (the default) disables log rotation based on file size.
    The value can have an optional M suffix, i.e. both 5 and 5M will rotate the log file when it grows to 5MB.
    If log_rotationtime is specified, then this setting is ignored.

    A string value which is the full path to workers.properties file (for example c:\tomcat\conf\workers.properties)

    A string value which is the full path to uriworkermap.properties file (for example c:\tomcat\conf\uriworkermap.properties)

    A string value which is the full path to rewrite.properties file (for example c:\tomcat\conf\rewrite.properties)

    A string value which is the name of a request header from which a request id will be extracted that is part of every log line.

    This directive has been added in version 1.2.49

    A DWORD value size of the shared memory. Set this value to be the number of all defined workers * 400. (Set this value only if you have more then 64 workers)

    This directive has been added in version 1.2.20

    Starting with version 1.2.27 the size of the shared memory is determined automatically, even for large numbers of workers. This attribute is not needed any longer.

    A DWORD value specifying the time in seconds upon which the worker_mount_file will be reloaded.

    This directive has been added in version 1.2.20

    A string value representing a boolean. If it is set to true, URL session suffixes of the form ";jsessionid=..." get stripped of URLs, if the are served locally by the web server.

    The default value is false.

    This directive has been added in version 1.2.21

    A DWORD value representing "0" or "1". This is needed because of minor incompatibilities with IIS 5.1.

    By default its value is 1, which means we use the SF_NOTIFY_AUTH_COMPLETE event. If you set this to 0, then we use SF_NOTIFY_PREPROC_HEADERS. This might be needed for IIS 5.1 when handling requests using the PUT HTTP method.

    This directive has been added in version 1.2.21

    A string value which influences, how URIs are decoded and re-encoded between IIS and Tomcat. You should leave this at it's default value, unless you have a very good reason to change it.

    If the value is "parsed", the forwarded URI will be decoded and explicit path components like ".." will already be resolved. This is less spec compliant and is not safe if you are using prefix forwarding rules.

    If the value is "unparsed", the forwarded URI will be the original request URI. It's spec compliant and also the safest option. Rewriting the URI and then forwarding the rewritten URI will not work.

    If the value is "escaped", the forwarded URI will be the re-encoded form of the URI used by "parsed". Explicit path components like ".." will already be resolved. This will not work in combination with URL encoded session IDs.

    If the value is "proxy", the forwarded URI will be a partially re-encoded form of the URI used by "parsed". Explicit path components like ".." will already be resolved. and problematic are re-encoded.

    The default value since version 1.2.24 is "proxy". Before it was "parsed".

    A string value representing a boolean. If it is set to true, URLs still containing percent signs '%' or backslashes '\' after decoding will be rejected.

    Most web apps do not use such URLs. By enabling reject_unsafe you can block several well known URL encoding attacks.

    The default value is false.

    This directive has been added in version 1.2.24

    This options is deprecated as of 1.2.44 and will be ignored if used.

    Before version 1.2.41 collapsing was never done. Starting with version 1.2.41 collapsing before looking for unmount matches is the default to prevent easy bypassing of unmount rules. As of 1.2.44, collpasing is always performed before looking for mount or unmount rules.

    This directive has been added in version 1.2.41

    A DWORD value representing the watchdog thread interval in seconds. The workers are maintained periodically by a background thread running periodically every watchdog_interval seconds. Worker maintenance checks for idle connections, corrects load status and is able to detect backend health status.

    The maintenance only happens, if since the last maintenance at least worker.maintain seconds have passed. So setting the watchdog_interval much smaller than worker.maintain is not useful.

    The default value is 0 seconds, meaning the watchdog thread will not be created, and the maintenance is done in combination with normal requests instead.

    This directive has been added in version 1.2.27

    A string value representing the error page url redirection when backend returns non-200 response. This directive can be used to customise the error messages returned from backend server.

    The url must point to a valid server url and can contain format string number (%d) that can be used to separate the pages by error number. The redirect url in that case is formatted by replacing %d from error_page to returned error number.

    This directive has been added in version 1.2.27

    A string value representing a boolean. If it is set to true, chunked encoding is supported by the server.

    The default value is false.

    This directive has been added in version 1.2.27. Until version 1.2.30 it was considered experimental and only available when a special build containing chunking support was used. Starting with 1.2.30 it is no longer considered experimental.

    A string value representing a boolean. If it is set to true, data is flushed immediately to the client as each AJP packet is received. Otherwise, IIS buffers the data and only writes to the client when the buffer is full or the response is complete.

    The default value is false.

    This directive has been added in version 1.2.42

    The ISAPI redirector can read it's configuration from a properties file instead of the registry. This has the advantage that you can use multiple ISAPI redirectors with independent configurations on the same server. The redirector will check for the properties file during initialisation, and use it in preference to the registry if present.

    Create a properties file in the same directory as the ISAPI redirector called isapi_redirect.properties i.e. with the same name as the ISAPI redirector DLL but with a .properties extension. A sample isapi_redirect.properties can be found under the conf directory.

    The property names and values in the properties file are the same as for the registry settings described above. For example:

    # Configuration file for the Tomcat ISAPI Redirector # The path to the ISAPI Redirector Extension, relative to the website # This must be in a virtual directory with execute privileges extension_uri=/jakarta/isapi_redirect.dll # Full path to the log file for the ISAPI Redirector log_file=c:\tomcat\logs\isapi_redirect.log # Log level (debug, info, warn, error or trace) log_level=info # Full path to the workers.properties file worker_file=c:\tomcat\conf\workers.properties # Full path to the uriworkermap.properties file worker_mount_file=c:\tomcat\conf\uriworkermap.properties

    Notes:

    • Back-slashes - '\' - are not escape characters.
    • Comment lines begin with '#'.

    Starting with version 1.2.27 two environment variables are automatically added to the environment that can be used inside .properties files.

    • JKISAPI_PATH - Full path to the ISAPI Redirector.
    • JKISAPI_NAME - Name of the ISAPI Redirector dll without extension

    # Use the logs in the installation path of ISAPI Redirector log_file=$(JKISAPI_PATH)\$(JKISAPI_NAME).log

    The ISAPI redirector with version 1.2.31 can perform log rotation, with configuration and behaviour similar to the rotatelogs program provided with Apache HTTP Server.

    To configure log rotation, configure a log_file, and one of the log_rotationtime or log_filesize options. If both are specified, the log_rotationtime will take precedence, and log_filesize will be ignored.
    For example, to configure daily rotation of the log file:

    # Configuration file for the Tomcat ISAPI Redirector ... # Full path to the log file for the ISAPI Redirector log_file=c:\tomcat\logs\isapi_redirect.%Y-%m-%d.log # Log level (debug, info, warn, error or trace) log_level=info # Rotate the log file every day log_rotationtime=86400 ...

    Or to configure rotation of the log file when it reaches 5MB in size:

    # Configuration file for the Tomcat ISAPI Redirector ... # Full path to the log file for the ISAPI Redirector log_file=c:\tomcat\logs\isapi_redirect.%Y-%m-%d-%H.log # Log level (debug, info, warn, error or trace) log_level=info # Rotate the log file at 5 MB log_filesize=5M ...

    The log will be rotated whenever the configured limit is reached, but only if the log file name would change. If you configure a log file name with strftime(3) format codes in it, then ensure it specifies the same granularity as the rotation time configured, e.g. %Y-%m-%d if rotating daily (log_rotationtime=86400).
    See the rotatelogs documentation for more examples.

    The ISAPI redirector with version 1.2.16 can do a simple URL rewriting. Although not as powerful as Apache HTTP Server's mod_rewrite, it allows a simple exchange of request URIs

    The rule is in the form original-url-prefix=forward-url-prefix. For example:

    # Simple rewrite rules, making examples # available under shorter URLs /jsp/=/examples/jsp/ /servlets/=/examples/servlets/

    You can also use regular expressions, if you prefix the rule with a tilde ~:

    # Complex rewrite rule, prefixing "/examples/" # to the first path component of all requests ~/([^/]*)=/examples/$1

    Note that uriworkermap.properties must use the URLs before rewriting.

    tomcat-connectors-1.2.50-src/xdocs/reference/workers.xml0000644000000000000020000015362714655113617021636 0ustar rootbin ]> &project; Mladen Turk workers.properties configuration

    A Tomcat worker is a Tomcat instance that is waiting to execute servlets or any other content on behalf of some web server. For example, we can have a web server such as the Apache HTTP Server forwarding servlet requests to a Tomcat process (the worker) running behind it.

    The scenario described above is a very simple one; in fact one can configure multiple Tomcat workers to serve servlets on behalf of a certain web server. The reasons for such configuration can be:

    • We want different contexts to be served by different Tomcat workers to provide a development environment where all the developers share the same web server but own a Tomcat worker of their own.
    • We want different virtual hosts served by different Tomcat processes to provide a clear separation between sites belonging to different companies.
    • We want to provide load balancing, meaning run multiple Tomcat workers each on a machine of its own and distribute the requests between them.

    There are probably more reasons for having multiple workers but I guess that this list is enough...

    Tomcat workers are defined in a properties file dubbed workers.properties and this tutorial explains how to work with it.

    Defining workers to the Tomcat web server plugin can be done using a properties file (a sample file named workers.properties is available in the conf/ directory).

    The lines in the file define properties. The general format is

    <name>=<value>

    Dots are used as part of the name to represent a configuration hierarchy.

    Invalid directives will be logged during web server startup and prevent the web server from working properly. Some directives have been deprecated. Although they will still work, you should replace them by their successors.

    Some directives are allowed multiple times. This will be explicitly noted in the tables below.

    Whitespace at the beginning and the end of a property name or value gets ignored. Comments can be placed in any line and start with a hash sign '#'. Any line contents behind the hash sign get ignored.

    Boolean properties can be set either using the numbers 0 (false) and 1 (true) as values, or off (false) and on (true) or any other string starting with the letters f (false), n (false), t (true) or y (true). The values are taken case insensitive. In this documentation we will stick to false and true.

    These directives have global scope.

    A comma separated list of workers names that the JK will use. When starting up, the web server plugin will instantiate the workers whose name appears in the worker.list property, these are also the workers to whom you can map requests.

    This directive can be used multiple times.

    Worker connection pool maintain interval in seconds. If set to the positive value JK will scan all connections for all workers specified in worker.list directive and check if connections needs to be recycled.

    Furthermore any load balancer does a global maintenance every worker.maintain seconds. During global maintenance load counters are decayed and workers in error are checked for recover_time.

    This feature has been added in jk 1.2.13.

    Each worker configuration directive consists of three words separated by a dot:

    worker.<worker name>.<directive>=<value>

    The first word is always worker. The second word is the worker name you can choose. In the case of load balancing, the worker name has an additional meaning. Please consult the Load Balancer HowTo.

    The name of the worker can contain only the alphanumeric characters [a-z][A-Z][0-9][_\-] and is case sensitive.

    You can define and use variables in the workers.properties file. To define a variable you use the syntax:

    <variable_name>=<value>

    Dots are allowed in the variable name, but you have to be careful not to use variable names, that clash with standard directives. Therefore variable names should never start with "worker.".

    To use a variable, you can insert "$(variable_name)" at any place on the value side of a property line. If a variable has not been defined before its use, we will search the process environment for a variable with the same name and use their value.

    Often one wants to use the same property values for various workers. To reduce duplication of configuration lines and to ease the maintenance of the file, you can inherit properties from one worker to another, or even from a template to real workers.

    The directive "reference" allows to copy configurations between workers or worker templates in a hierarchical way. If worker castor sets worker.castor.reference=worker.pollux then it inherits all properties of pollux, except for the ones that are explicitly set for castor.

    Please note, that the value of the directive is not only the name of the referred worker, but the complete prefix including "worker.".

    To use a template worker simply define it like a real worker, but do not add it to the worker.list or as a member to any load balancer. Such a template worker does not have to contain mandatory directives. This approach is especially useful, if one has a lot of balanced workers in a load balancer and these workers share most of their properties. You can set all of these properties in a template worker, e.g. using the prefix "worker.template1", and then simply reference those common properties in all balanced workers.

    References can be used to inherit properties over multiple hops in a hierarchical way. The maximum depth for nesting references is 20. Be careful not to introduce a reference loop!

    This feature has been added in jk 1.2.19.

    Mandatory directives are the one that each worker must contain. Without them the worker will be unavailable or will misbehave. Those directives will be marked with a strong font in the following tables.

    Type of the worker (can be one of ajp12, ajp13, ajp14, jni, lb or status). The type of the worker defines the directives that can be applied to the worker.

    Type ajp13 is the preferred worker type that JK uses for communication between web server and Tomcat. This type of worker uses sockets as communication channel. For detailed description of the ajp13 protocol stack browse to AJPv13 protocol specification. Type lb is used for load balancing workers, type status for status workers.

    Type ajp14 is experimental and not recommended, type ajp12 is obsolete.

    JNI workers are no longer supported and will likely not work. Do not use them.

    Connection directives defines the parameters needed to connect and maintain the connections pool of persistent connections between JK and remote Tomcat.

    Host name or IP address of the backend Tomcat instance. The remote Tomcat must support the AJP13 protocol stack. The host name can have a port number embedded separated by the colon (':') character. Port number of the remote Tomcat instance listening for defined protocol requests. The default value depends on the worker type. For ajp13 workers the default port is 8009, while for ajp14 type of worker that value is 8011. Name or IP address used for the connection source (outgoing address). It should only be used on multi-homed hosts.

    This feature is experimental and has been added in jk 1.2.41.

    Socket timeout in seconds used for the communication channel between JK and remote host. If the remote host does not respond inside the timeout specified, JK will generate an error, and retry again. If set to zero (default) JK will wait for an infinite amount of time on all socket operations. Socket connect timeout in milliseconds used for the communication channel between JK and remote host. If the remote host does not respond inside the timeout specified, JK will generate an error, and retry again.

    Note that socket_timeout is in seconds, and socket_connect_timeout in milliseconds, so in absolute terms the default socket_connect_timeout is equal to socket_timeout.

    This feature has been added in jk 1.2.27.

    This directive should be used when you have a firewall between your web server and the Tomcat engine, who tend to drop inactive connections. This flag will tell the Operating System to send KEEP_ALIVE messages on inactive connections (interval depend on global OS settings, generally 120 minutes), and thus prevent the firewall to cut inactive connections. To enable keepalive set this property value to true.

    The problem with Firewall cutting inactive connections is that sometimes, neither web server or Tomcat have information about the cut and couldn't handle it.

    This flag determines, under which conditions established connections are probed to ensure they are still working. The probe is done with an empty AJP13 packet (CPing) and expects to receive an appropriate answer (CPong) within some timeout.

    The value of the flag can be any combination of the following flags (multiple values are combined without any separators):

    C (connect): If set, the connection will be probed once after connecting to the backend. The timeout can be set by connect_timeout. If it is not set, the value of ping_timeout will be used instead.

    P (prepost): If set, the connection will be probed before sending each request to the backend. The timeout can be set by prepost_timeout. If it is not set, the value of ping_timeout will be used instead.

    I (interval): If set, the connection will be probed during the regular internal maintenance cycle, but only if it is idle longer than connection_ping_interval. The timeout can be set by ping_timeout.

    A If set, all of the above probes will be used.

    This feature has been added in jk 1.2.27. Connect and prepost probing were already available via connect_timeout and prepost_timeout since version jk 1.2.6.

    Timeout in milliseconds used when waiting for the CPong answer of a CPing connection probe. The activation of the probes is done via ping_mode. The timeouts for ping_mode connect and prepost can be overwritten individually via connect_timeout and prepost_timeout.

    For compatibility reasons, CPing/CPong is also used, whenever connect_timeout or prepost_timeout are set, even if ping_mode is empty.

    This feature has been added in jk 1.2.27.

    The usage depend on the ping_mode flags used. directive connection_ping_interval was not set, the value of (ping_timeout/1000) * 10 will be used as connection_ping_interval value. When using interval connection probing, connections idle for longer than this interval in seconds are probed by CPing packets whether they still work.

    Interval probing can be activated either by ping_mode, or by setting connection_ping_interval to some value bigger than zero. If you activate interval probing via ping_mode, then the default value of connection_ping_interval is (ping_timeout/1000) * 10. Note that ping_timeout is in milliseconds, and connection_ping_interval in seconds, so in absolute terms the default connection_ping_interval is 10 times ping_timeout.

    This feature has been added in jk 1.2.27.

    This defines the number of connections made to the AJP backend that are maintained as a connection pool. It will limit the number of those connection that each web server child process can made.

    Connection pool size property is only used for multi threaded web servers such as the Apache HTTP Server and Microsoft IIS. The connection_pool_size property needs to reflect the number of requests one web server process should be able to send to a backend in parallel. Usually this is the same as the number of threads per web server process. JK will discover this number for the Apache HTTP Server automatically and set the pool size to this value. For IIS the default value is 250 (before version 1.2.20: 10).

    We strongly recommend adjusting this value for IIS to the number of requests one web server process should be able to send to a backend in parallel. You should measure how many connections you need during peak activity without performance problems, and then add some percentage depending on your growth rate. Finally you should check, whether your web server processes are able to use at least as many threads, as you configured as the pool size.

    Do not use connection_pool_size with values higher then 1 on Apache 2.x with prefork MPM or Apache 1.3.x!
    Minimum size of the connection pool that will be maintained.

    Its default value is (connection_pool_size+1)/2.

    Do not use connection_pool_minsize with values higher then 1 on Apache 2.x with prefork MPM or Apache 1.3.x!

    This feature has been added in jk 1.2.16.

    Cache timeout property should be used with connection_pool_minsize to specify how many seconds JK should keep an inactive socket in cache before closing it. This property should be used to reduce the number of threads on the Tomcat web server. The default value zero disables the closing (infinite timeout).

    Each child could open an ajp13 connection if it has to forward a request to Tomcat, creating a new ajp13 thread on Tomcat side.

    The problem is that after an ajp13 connection is created, the child won't drop it until killed. And since the web server will keep its childs/threads running to handle high-load, even it the child/thread handle only static contents, you could finish having many unused ajp13 threads on the Tomcat side.

    You should keep this time interval in sync with the keepAliveTimeout attribute (if it is set explicitly) or connectionTimeout attribute of your AJP connector in Tomcat's server.xml. Note however, that the value for mod_jk is given in seconds, the one in server.xml has to use milliseconds.

    Timeout the worker will wait for a free socket in cache before giving up.

    Its default value is retries * retry_interval.

    This feature has been added in jk 1.2.27.

    Only used for a member worker of a load balancer.

    The integer number lbfactor (load balancing factor) is how much we expect this worker to work, or the worker's work quota. Load balancing factor is compared with other workers that makes the load balancer. For example if one worker has lbfactor 5 times higher then other worker, then it will receive five times more requests.

    Load balancer is a virtual worker that does not really communicate with Tomcat workers. Instead it is responsible for the management of several "real" workers. The worker is supposed to be a load balancer if it's worker type is lb. See worker's type directive.

    Loadbalancer directives define the parameters needed to create the workers that are connecting to a remote cluster of backend Tomcat servers. Each cluster node has to have a worker defined.

    Load balancer management includes:

    • Instantiating the workers in the web server.
    • Using the worker's load balancing factor, perform weighted round-robin load balancing where high lbfactor means stronger machine (that is going to handle more requests)
    • Keeping requests belonging to the same session executing on the same Tomcat worker.
    • Identifying failed Tomcat workers, suspending requests to them and instead fail over on other workers managed by the lb worker.

    The overall result is that workers managed by the same lb worker are load balanced (based on their lbfactor and current user session) and also fail over so a single Tomcat process death will not "kill" the entire site.

    If you want to use session stickiness, you must set different jvmRoute attributes in the Engine element in Tomcat's server.xml. Furthermore the names of the workers which are managed by the balancer have to be equal to the jvmRoute of the Tomcat instance they connect with.

    The restriction on the worker names can be lifted, if you use the route attribute for the workers.

    The following table specifies properties that the lb worker can accept:

    A comma separated list of workers that the load balancer need to manage.

    This directive can be used multiple times for the same load balancer.

    This directive replaces old balanced_workers directive and can be used only with mod_jk versions 1.2.7 and up.

    As long as these workers should only be used via the load balancer worker, there is no need to also put them into the worker.list property.
    Specifies whether requests with SESSION ID's should be routed back to the same Tomcat worker. If sticky_session is set to true sessions are sticky, otherwise sticky_session is set to false. Set sticky_session to false when Tomcat is using a Session Manager which can persist session data across multiple instances of Tomcat.

    The sticky_session setting can be overwritten using the Apache HTTP Server environment variable JK_STICKY_IGNORE and the worker map extension for sticky_ignore. This has been added in version 1.2.33.

    Specifies whether requests with SESSION ID's for workers that are in error state should be rejected. If sticky_session_force is set to true and the worker that matches that SESSION ID is in error state, client will receive 500 (Server Error). If set to false failover on another worker will be issued with losing client session. This directive is used only when you set sticky_session=true.

    This feature has been added in jk 1.2.9.

    Specifies what method load balancer is using for electing the best worker. Please note, that session stickiness and perfect load balancing are conflicting targets, especially when the number of sessions is small, or the usage of sessions is extremely varying For huge numbers of sessions this usually is not a problem.

    Some methods note, that they aggregate in a sliding time window. They add up accesses, and on each run of the global maintain method, the load counters get divided by 2. Usually this happens once a minute, depending on the setting of worker.maintain. The value of the load counters can be inspected using the status worker.

    If method is set to R[equest] the balancer will use the number of requests to find the best worker. Accesses will be distributed according to the lbfactor in a sliding time window. This is the default value and should be working well for most applications.

    If method is set to S[ession] the balancer will use the number of sessions to find the best worker. Accesses will be distributed according to the lbfactor in a sliding time window. This method should be used, if sessions are your limiting resource, e.g. when you only have limited memory and your sessions need a lot of memory. Because the balancer does not keep any state, it actually does not know the number of sessions. Instead it counts each request without a session cookie or URL encoding as a new session. This method will neither know, when a session is being invalidated, nor will it correct its load numbers according to session timeouts or worker failover. If you know request URLs, that will be called without a session ID but should not be counted as new sessions, you should add them to the stateless mapping rule extension or set the Apache HTTP Server environment variable JK_STATELESS for them.

    If method is set to N[ext] the balancer will again use the number of sessions to find the best worker. All remarks concerning the Session method apply as well. The difference to the Session method is how the session count is handled in the sliding time window. The Next method does not divide by 2, instead it subtracts the current minimum number. This should effectively result in a round-robin session balancing, thus the name Next. Under high load, the two session balancing methods will result in a similar distribution, but Next will be better if you need to distribute small numbers of sessions.

    If set to T[raffic] the balancer will use the network traffic between JK and Tomcat to find the best worker. Accesses will be distributed according to the lbfactor in a sliding time window. This method should be used, if network to and from the backends is your limiting resource.

    If set to B[usyness] the balancer will pick the worker with the lowest current load, based on how many requests the worker is currently serving. This number is divided by the workers lbfactor, and the lowest value (least busy) worker is picked. This method is especially interesting, if your request take a long time to process, like for a download application. The method is not recommended for general use, because under high load on some hardware architectures the busy counter can become wrong.

    This feature has been added in version 1.2.9. The Session method has been added in version 1.2.20, the Next method in version 1.2.33.

    Specifies what lock method the load balancer will use for synchronising shared memory runtime data. If lock is set to O[ptimistic] balancer will not use shared memory lock to find the best worker. If set to P[essimistic] balancer will use shared memory lock. The balancer will work more accurately in case of Pessimistic locking, but can slow down the average response time.

    This feature has been added in jk 1.2.13.

    This directive also exists for normal workers. For those it has a different meaning. When making a request, the load-balancer worker will allocate the request to a member worker. If that member worker is either unable to service the request or fails to service the request, the request will be passed to another member worker until the request is processed, every member worker has attempted to process the request or lb_retries member workers have attempted to process the request.

    If the request remains unprocessed, the load-balancer worker will repeat the above process a maximum of retries times (including the original attempt). Before each retry, the load-balancer worker will pause for a time defined by the retry_interval directive.

    Note that this means that, if all workers fail, there will be a total of worker.retries * min(lb.lb_retries,member worker count) * lb.retries requests before a 504 response is returned to the client. So for an lb worker with four members and a default configuration, if all workers fail there will be a total of 8 requests before a 504 response is returned to the client.

    Until version 1.2.16 the default value was 3.

    When making a request, the load-balancer worker will allocate the request to a member worker. If that member worker is either unable to service the request or fails to service the request, the request will be passed to another member worker until the request is processed, every member worker has attempted to process the request or lb_retries member workers have attempted to process the request.

    If the request remains unprocessed, the load-balancer worker will repeat the above process a maximum of retries times (including the original attempt). Before each retry, the load-balancer worker will pause for a time defined by the retry_interval directive.

    Note that this means that, if all workers fail, there will be a total of worker.retries * min(lb.lb_retries,member worker count) * lb.retries requests before a 504 response is returned to the client. So for an lb worker with four members and a default configuration, if all workers fail there will be a total of 8 requests before a 504 response is returned to the client.

    This feature has been added in jk 1.2.44. Prior to this feature being added, the load-balancer worker behaved as if lb_retries was equal to the number of member workers.

    The status worker does not communicate with Tomcat. Instead it is responsible for the load balancer management.

    Specifies the url for cascading stylesheet to use. A status worker with read_only=true will not allow any operations, that change the runtime state or configuration of the other workers. These are edit/update/reset/recover.

    This feature has been added in jk 1.2.20.

    It is a list of users which gets compared to the user name authenticated by the web server. If the name is not contained in this list, access is denied. Per default the list is empty and then access is allowed to anybody.

    This directive can be used multiple times.

    This feature has been added in jk 1.2.20.

    By default, the user names are matched case sensitively. You can set user_case_insensitive=true to make the comparison case insensitive. This may be especially useful on the Windows platform.

    This feature has been added in jk 1.2.21.

    For every load balancer worker, the status worker shows a summary of the state of its members. There are three such states, "good", "bad" and "degraded".

    These states are determined depending on the activation of the members (active, disabled, stopped) and their runtime state (ok, n/a, busy, recovering, probing, forced recovery, error). By default, members are assumed to be "good", if their activation is "active" and their runtime state is not "error".

    You can change this mapping, by assigning a list of values to the attribute "good". Each value gives a possible match for the members, and one match suffices. Each value is either a single character, or two characters combined with a dot ".". The single characters are the first characters in the words "active", "disabled", "stopped", "ok", "na", "busy", "recovering", "error". The additional states "probing" and "forced recovery" are always rated equivalent to "recovering". If a value consists only of a single character, then all members with this activation or runtime state will be assumed good. A combination of an activation and a runtime state concatenated with a dot "." does only apply to a member, that has exactly this activation and state.

    Members of a load balancer will first be matched against the state "bad", if they don't match, the state "good" will be tried, and if they still don't match, their state will be "degraded".

    This directive can be used multiple times.

    This feature has been added in jk 1.2.20.

    See: "good".

    By default, members are assumed to be "bad", if their activation is "stopped" or their runtime state is "error".

    This directive can be used multiple times.

    This feature has been added in jk 1.2.20.

    The prefix, which will be used by the status worker when producing properties output (mime=prop). Each property key will be prefixed by this value.

    This feature has been added in jk 1.2.20.

    This directive can be used to customise the XML output from the status worker. If set to - no namespace will be used.

    This feature has been added in jk 1.2.20.

    This directive can be used to customise the XML output from the status worker. If set to - no xmlns will be used.

    Default value is set to xmlns:jk="http://tomcat.apache.org"

    This feature has been added in jk 1.2.20.

    This directive can be used to customise the XML output from the status worker. This value will be inserted to the output xml after the xml header.

    This feature has been added in jk 1.2.20.

    This table lists more advanced configuration options. Most of them only apply to some types of workers. We use the abbreviations AJP for ajp13/ajp14 workers used directly via the workers.list, LB for load balancer workers, and SUB for the workers used indirectly in a load balancer worker as a sub worker or member.

    Connect timeout property told web server to send a PING request on ajp13 connection after connection is established. The parameter is the delay in milliseconds to wait for the PONG reply. The default value zero disables the timeout (infinite timeout).

    This features has been added in jk 1.2.6 to avoid problem with hung Tomcat's and require ajp13 ping/pong support which has been implemented on Tomcat 3.3.2+, 4.1.28+ and 5.0.13+. Disabled by default.

    Prepost timeout property told web server to send a PING request on ajp13 connection before forwarding to it a request. The parameter is the delay in milliseconds to wait for the PONG reply. The default value zero disables the timeout (infinite timeout).

    This features has been added in jk 1.2.6 to avoid problem with hung Tomcat's and require ajp13 ping/pong support which has been implemented on Tomcat 3.3.2+, 4.1.28+ and 5.0.13+. Disabled by default.

    The parameter is the number of milliseconds to wait for success during a read event. So this is not a timeout for the complete answer time of a request, but only for the maximum time between two packets received from Tomcat. Usually the longest pause is between sending the request and getting the first packet of the response.

    If the timeout passes without any data received from Tomcat, the web server will no longer wait for the rest of the response and send an error to the client (browser). Usually this does not mean, that the request is also aborted on the Tomcat backend. If the worker is a member of a load balancer, the load balancer might place the worker into an error state and retry the request on another member. See also max_reply_timeouts, retries and recovery_options.

    By default (value zero) the web server will wait forever which could be an issue for you. If you set a reply_timeout, adjust it carefully if you have long running servlets.

    The reply_timeout can be overwritten using the Apache HTTP Server environment variable JK_REPLY_TIMEOUT and the worker map extension for reply_timeout.

    This features has been added in jk 1.2.6 to avoid problem with hung Tomcat's and works on all servlet engines supporting ajp13. The variable JK_REPLY_TIMEOUT and the worker map extension have been added in version 1.2.27.

    This directive also exists for load balancer workers. For those it has a different meaning. The maximum number of times that the worker will send a request to Tomcat in case of a communication error. Each retry will be done over another connection. The first time already gets counted, so retries=2 means one retry after error. Before a retry, the worker waits for a configurable sleeping time.

    See also the attribute recovery_options for a more fine-grained control of retries and retry_interval for the sleep time configuration.

    Until version 1.2.16 the default value was 3.

    The amount of time in milliseconds the worker sleeps before doing any retry.

    This features has been added in jk 1.2.27.

    Recovery options influence, how we should handle retries, in case we detect a problem with Tomcat. How often we will retry is controlled by the attribute retries.

    This attribute is a bit mask. The following bits are allowed:
    1: don't recover if Tomcat failed after getting the request
    2: don't recover if Tomcat failed after sending the headers to client
    4: close the connection to Tomcat, if we detect an error when writing back the answer to the client (browser)
    8: always recover requests for HTTP method HEAD (even if Bits 1 or 2 are set)
    16: always recover requests for HTTP method GET (even if Bits 1 or 2 are set)

    This features has been added in jk 1.2.6. Option 4 has been added in version 1.2.16, options 8 and 16 in version 1.2.24.

    Set this value to the HTTP status code that will cause a worker to fail if returned from Servlet container. Use this directive to deal with cases when the servlet container can temporary return non-200 responses for a short amount of time, e.g during redeployment.

    The error page, headers and status codes of the original response will not be send back to the client. Instead the request will result in a 503 response. If the worker is a member of a load balancer, the member will be put into an error state. Request failover and worker recovery will be handled with the usual load balancer procedures.

    This feature has been added in jk 1.2.20.

    Starting with jk 1.2.22 it is possible to define multiple status codes separated by space or comma characters. For example: worker.xxx.fail_on_status=500,503

    Starting with jk 1.2.25 you can also tell the load balancer to not put a member into an error state, if a response returned with one of the status codes in fail_on_status. This feature gets enabled, by putting a minus sign in front of those status codes. For example: worker.xxx.fail_on_status=-404,-500,503

    If set to a positive number, the worker will only be used for a request, if it is currently working on less than this number of concurrent requests.

    Note that this is not related to the Busyness load balancing method.

    This feature is experimental and has been added in jk 1.2.41.

    This attribute sets the maximal AJP packet size in Bytes. It should be a multiple of 1024. Configuration values that are not a multiple of 1024 will be aligned to the next multiple of 1024. The maximum value is 65536. If you change it from the default, you must also change the packetSize attribute of your AJP connector on the Tomcat side! The attribute packetSize is available in Tomcat 6.0.2 onwards.

    Normally it is not necessary to change the maximum packet size. Problems with the default value have been reported when sending certificates or certificate chains.

    This feature has been added in jk 1.2.19.

    When compiled with IPV6 support, this directive forces IPV6 address resolution for host names which have both IPV6 and IPV4 addresses. In case there is no IPV6 address defined for the given hostname this directive in ineffective. This directive will be also ineffective if there is only IPV6 address defined or if IP address is used for "host", either in IPV4 or IPV6 notation.

    This feature has been added in jk 1.2.38.

    You can set a secret keyword on the Tomcat AJP Connector. Then only requests from workers with the same secret keyword will be accepted.

    Use attribute secret="secret key word" in your Tomcat AJP Connector configuration. (Historical note: the attribute name was requiredSecret in Tomcat 9.0, 8.x, 7.0 versions released earlier than February 2020, request.secret in Tomcat 6.0 and earlier.)

    If you set a secret on a load balancer, all its members will inherit this secret.

    This feature has been added in jk 1.2.12.

    Space delimited list of uri maps the worker should handle. It is only used, if the worker is included in worker.list.

    This directive can be used multiple times for the same worker.

    If you use a reply_timeout for the members of a load balancer worker, and you want to tolerate a few requests taking longer than reply_timeout, you can set this attribute to some positive value.

    Long running requests will still time out after reply_timeout milliseconds waiting for data, but the corresponding member worker will only be put into an error state, if more than max_reply_timeouts requests have timed out. More precisely, the counter for those bad requests will be divided by two, whenever the load balancer does its internal maintenance (by default every 60 seconds).

    This features has been added in jk 1.2.24 to make reply_timeout less sensitive for sporadic long running requests.

    The recover time is the time in seconds the load balancer will not try to use a worker, after it went into error state. Only after this time has passed, a worker in error state will be marked as in recovering, so that it will be tried for new requests.

    This interval is not checked every time a request is being processed. Instead it is being checked during global maintenance. The time between two runs of global maintenance is controlled by worker.maintain.

    Do not set recover_time to a very short time unless you understand the implications. Every recovery attempt for a worker in error is done by a real request!

    Setting a member of a load balancer into an error state is quite serious. E.g. it means that if you need stickyness, all access to the sessions of the respective node is blocked.

    Some types of error detection do not provide a precise information, whether a node is completely broken or not. In those cases an LB will not immediately put the node into the error state. Only when there have been no successful responses for error_escalation_time seconds after such an error, will the node be put into error state.

    This features has been added in jk 1.2.28.

    The name of the cookie that contains the routing identifier needed for session stickyness. The routing identifier is everything after a "." character in the value of the cookie.

    This feature has been added in jk 1.2.27.

    The name of the path parameter that contains the routing identifier needed for session stickyness. The routing identifier is everything after a "." character in the value of the path parameter.

    This feature has been added in jk 1.2.27.

    Activates generation of session stickyness cookies. Typically you don't need this.

    Some web frameworks replace Tomcat session management and use a different way of generating session IDs. As a consequence the routing ID added by Tomcat to the end of the session ID is lost and we no longer can do sticky load balancing. As a workaround you can use the following steps:

    • Choose a non-standard cookie name using the "session_cookie" attribute.
    • Activate cookie sending by setting the attribute "set_session_cookie" to true.
    • Set the attribute "session_cookie_path" to the correct application URI, like e.g. "/myapp/".

    The cookie will only be send if the request does not already contain a cookie of the same name, or that cookie does not contain a routing ID which the load balancer can fulfill. Especially after a node failover we will send a new cookie to switch stickyness to the new node.

    This feature has been added in jk 1.2.38.

    This attribute is only used if "set_session_cookie" is set to true. See "set_session_cookie" for a description. If the value of "session_cookie_path" is empty (default), then the send cookie will not contain a PATH information.

    This feature has been added in jk 1.2.38.

    Using this directive, a balanced worker of a load balancer can be configured as disabled or stopped. A disabled worker only gets requests, which belong to sessions for that worker. A stopped worker does not get any requests. Users of a stopped worker will lose their sessions, unless session replication via clustering is used.

    Use d or D to disable and s or S to stop. If this directive is not present the deprecated directives "disabled" or "stopped" are used.

    This flag can be changed at runtime using status worker.

    This feature has been added in jk 1.2.19.

    Normally the name of a balanced worker in a load balancer is equal to the jvmRoute of the corresponding Tomcat instance. If you want to include a worker corresponding to a Tomcat instance into several load balancers with different balancing configuration (e.g. disabled, stopped) you can use this attribute.

    Define a separate worker per lb and per Tomcat instance with an arbitrary worker name and set the route attribute of the worker equal to the jvmRoute of the target Tomcat instance.

    If this attribute is left empty, the name of the worker will be used.

    This attribute can be changed at runtime using status worker.

    If the route name contains a period, the part before the first period will be used as domain name, unless domain is set explicitly.

    This feature has been added in jk 1.2.16.
    The automatic domain rule has been added in jk 1.2.20.
    The attribute has been renamed from jvm_route to route in jk 1.2.20.

    An integer number to express preferences between the balanced workers of an lb worker. A load balancer will never choose some balanced worker in case there is another usable worker with lower distance.

    Only in case all workers below a given distance are in error, disabled or stopped, workers of a larger distance are eligible for balancing.

    This feature has been added in jk 1.2.16.

    Domain directive can be used only when the worker is a member of the load balancer. Workers that share the same domain name are treated as single worker. If sticky_session is used, then the domain name is used as session route.

    This directive is used for large system with more then 6 Tomcats, to be able to cluster the Tomcats in two groups and thus lowering the session replication transfer between them.

    This feature has been added in jk 1.2.8.

    Set to the name of the preferred failover worker. If worker matching SESSION ID is in error state then the redirect worker will be used instead. It will be used even if being disabled, thus offering hot standby.

    If you explicitly set a route via the "route" attribute, you must set "redirect" to this route of the preferred failover worker and not to its name.

    This feature has been added in jk 1.2.9.

    The following directives have been deprecated in the past. We include their documentation in case you need to use an older version of mod_jk. We urge you to update and not use them any more. Please migrate your existing configurations.

    This directive has been deprecated since 1.2.16. Cachesize defines the number of connections made to the AJP backend that are maintained as a connection pool. It will limit the number of those connection that each web server child process can make.

    Cachesize property is used only for multi threaded web servers such as Apache HTTP Server 2.x (all MPMs except prefork) and IIS. The cachesize property should reflect the number of threads per child process. JK will discover the number of threads per child process on the Apache HTTP Server with threaded MPM and set its default value to match the current ThreadsPerChild Apache configuration. For IIS the default value is 10.

    Do not use cachesize with values higher then 1 on Apache 2.x with prefork MPM or Apache 1.3.x!
    This directive has been deprecated since 1.2.16. Cache timeout property should be used with cachesize to specify how to time JK should keep an open socket in cache before closing it. This property should be used to reduce the number of threads on the Tomcat web server.

    Each child could open an ajp13 connection if it have to forward a request to Tomcat, creating a new ajp13 thread on Tomcat side.

    The problem is that after an ajp13 connection is created, the child won't drop it until killed. And since the web server will keep its childs/threads running to handle high-load, even it the child/thread handle only static contents, you could finish having many unused ajp13 threads on the Tomcat side.

    This directive has been deprecated since 1.2.16. The number of seconds that told web server to cut an ajp13 connection after some time of inactivity. When choosing an endpoint for a request and the assigned socket is open, it will be closed if it was not used for the configured time. It's a good way to ensure that there won't too old threads living on Tomcat side, with the extra cost you need to reopen the socket next time a request be forwarded. This property is very similar to cache_timeout but works also in non-cache mode. If set to value zero (default) no recycle will took place. This directive has been deprecated since 1.2.7. A comma separated list of workers that the load balancer need to manage. This directive has been deprecated since 1.2.19. If set to true the worker will be disabled if member of load balancer. This flag can be changed at runtime using status worker.

    This feature has been added in jk 1.2.9.

    This directive has been deprecated since 1.2.19. If set to true the worker will be stopped if member of load balancer. The flag is needed for stop complete traffic of a sticky session worker. It is only useful, when you have a cluster that replicated the sessions. This flag can be changed at runtime using status worker.

    This feature has been added in jk 1.2.11.

    This directive has been deprecated since 1.2.20. Normally the name of a balanced worker in a load balancer is equal to the jvmRoute of the corresponding Tomcat instance. If you want to include a worker corresponding to a Tomcat instance into several load balancers with different balancing configuration (e.g. disabled, stopped) you can use this attribute.

    Define a separate worker per lb and per Tomcat instance with an arbitrary worker name and set the jvm_route attribute of the worker equal to the jvmRoute of the target Tomcat instance.

    If this attribute is left empty, the name of the worker will be used.

    This attribute can be changed at runtime using status worker.

    This feature has been added in jk 1.2.16.