Rserve/0000755000175100001440000000000014531324156011542 5ustar hornikusersRserve/NAMESPACE0000644000175100001440000000034714531234224012761 0ustar hornikusersexport(Rserve, self.ctrlEval, self.ctrlSource, self.oobSend, self.oobMessage, run.Rserve, ocap, Rserve.eval, Rserve.context, resolve.ocap, ulog) if (.Platform$OS.type == "windows") { importFrom("utils", "shortPathName") } Rserve/LICENSE0000644000175100001440000004072614531234224012554 0ustar hornikusers [Summary: GPL-2 with OpenSSL linking exception] Rserve Copyright (C) 2002-2013 Simon Urbanek 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; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL project's "OpenSSL" library (or with modified versions of it that use the same license as the "OpenSSL" library - see http://www.openssl.org/), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. Full text of GPL-2 follows: GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Rserve/tools/0000755000175100001440000000000014531234224012676 5ustar hornikusersRserve/tools/config.sub0000755000175100001440000010264414531234224014670 0ustar hornikusers#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2020 Free Software Foundation, Inc. timestamp='2020-11-07' # 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/gitweb/?p=config.git;a=blob_plain;f=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. 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-2020 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 # shellcheck disable=SC2162 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 nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova*) 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 ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) 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 ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; 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 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; 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 case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; 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/-.*//') ;; *-*) # shellcheck disable=SC2162 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 caes, or perhaps split kernel-os, or else just # set os. 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|') ;; *-*) # shellcheck disable=SC2162 IFS="-" read kernel os <&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 in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* ) ;; uclinux-uclibc* ) ;; -dietlibc* | -newlib* | -musl* | -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 ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS 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*) 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" 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: Rserve/tools/config.guess0000755000175100001440000013761314531234224015231 0ustar hornikusers#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2020 Free Software Foundation, Inc. timestamp='2020-11-07' # 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/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . 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-2020 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 # 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 { 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 c89 c99 ; 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/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else #include #ifdef __DEFINED_va_list LIBC=musl #else LIBC=gnu #endif #endif EOF eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g')" ;; 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". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \ "/sbin/$sysctl" 2>/dev/null || \ "/usr/sbin/$sysctl" 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. echo "$machine-${os}${release}${abi-}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//') echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//') echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//') echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" exit ;; *:MidnightBSD:*:*) echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" exit ;; *:OS108:*:*) echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:Sortix:*:*) echo "$UNAME_MACHINE"-unknown-sortix exit ;; *:Twizzler:*:*) echo "$UNAME_MACHINE"-unknown-twizzler exit ;; *:Redox:*:*) echo "$UNAME_MACHINE"-unknown-redox exit ;; mips:OSF1:*.*) echo mips-dec-osf1 exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}') ;; *5.*) UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}') ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1) case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "$( (/bin/universe) 2>/dev/null)" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case $(/usr/bin/uname -p) in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; 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 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; sun4*:SunOS:*:*) case "$(/usr/bin/arch -k)" in Series*|S4*) UNAME_RELEASE=$(uname -v) ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')" exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null) test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case "$(/bin/arch)" in sun3) echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) 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; } echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=$(/usr/bin/uname -p) if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then echo m88k-dg-dgux"$UNAME_RELEASE" else echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'$(uname -s)'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=$(/usr/bin/oslevel) else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[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 echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') case "$UNAME_MACHINE" in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if 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 echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//') echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) 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; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then echo "$UNAME_MACHINE"-unknown-osf1mk else echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz) FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/') echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///') FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/') echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; 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 echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi else echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo ${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf fi exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=$(/usr/bin/uname -p) case "$UNAME_PROCESSOR" in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" exit ;; i*:CYGWIN*:*) echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) case "$UNAME_MACHINE" in x86) echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; i*:UWIN*:*) echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-pc-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; *:GNU:*:*) # the GNU system echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo "$UNAME_RELEASE"|sed -e 's,/.*$,,')" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC" exit ;; *:Minix:*:*) echo "$UNAME_MACHINE"-unknown-minix exit ;; aarch64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; 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 echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; e2k:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; k1om:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; 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 eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI')" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-"$LIBC" exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) set_cc_for_build LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_X32 >/dev/null then LIBCABI="$LIBC"x32 fi fi echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI" exit ;; xtensa*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; i*86:*:4.*:*) UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//') if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case $(/bin/uname -X | grep "^Machine") in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=$(sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //')) (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming 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. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; 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*:*) echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=$( (uname -p) 2>/dev/null) echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then echo mips-nec-sysv"$UNAME_RELEASE" else echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux"$UNAME_RELEASE" exit ;; SX-ACE:SUPER-UX:*:*) echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; arm64:Darwin:*:*) echo aarch64-apple-darwin"$UNAME_RELEASE" exit ;; *: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 echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=$(uname -p) if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-*:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk"$UNAME_RELEASE" exit ;; NSR-*:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk"$UNAME_RELEASE" exit ;; NSV-*:NONSTOP_KERNEL:*:*) echo nsv-tandem-nsk"$UNAME_RELEASE" exit ;; NSX-*:NONSTOP_KERNEL:*:*) echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. # shellcheck disable=SC2154 if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')" exit ;; *:*VMS:*:*) UNAME_MACHINE=$( (uname -p) 2>/dev/null) case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ .*$//')" exit ;; i*86:rdos:*:*) echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; *:Unleashed:*:*) echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE" exit ;; esac # 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 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: Rserve/tools/m4/0000755000175100001440000000000014531234224013216 5ustar hornikusersRserve/tools/m4/ax_pthread.m40000644000175100001440000003360314531234224015604 0ustar hornikusers# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # Updated to work around issues in RedHat by Simon Urbanek # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # Copyright (c) 2015 Simon Urbanek # # 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 . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 21 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac # Clang doesn't consider unrecognized options an error unless we specify # -Werror. We throw in some extra Clang-specific options to ensure that # this doesn't happen for GCC, which also accepts -Werror. AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) save_CFLAGS="$CFLAGS" ax_pthread_extra_flags="-Werror" CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], [AC_MSG_RESULT([yes])], [ax_pthread_extra_flags= AC_MSG_RESULT([no])]) CFLAGS="$save_CFLAGS" if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. # NOTE: RedHat is broken and requires an explicit # inclusion of pthread_atfork in the test otherwise it # will appear to work without -pthread even though it doesn't. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include static void routine(void *a) { a = 0; } static void atfork_null() { } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_atfork(atfork_null, atfork_null, atfork_null); pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT([$attr_name]) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else # TODO: What about Clang on Solaris? flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT([$flag]) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], [ax_cv_PTHREAD_PRIO_INHERIT], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: compile with *_r variant if test "x$GCC" != xyes; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" AC_SUBST([PTHREAD_LIBS]) AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD Rserve/man/0000755000175100001440000000000014531234224012311 5ustar hornikusersRserve/man/Rserv.Rd0000644000175100001440000000524314531234224013705 0ustar hornikusers\name{Rserve} \title{Server providing R functionality to applications via TCP/IP or local unix sockets} \alias{Rserve} \usage{ # R CMD Rserve [] Rserve(debug = FALSE, port, args = NULL, quote=(length(args) > 1), wait, ...) } \description{ Starts Rserve in daemon mode (unix only). Any additional parameters not related to Rserve will be passed straight to the underlying R. For configuration, usage and command line parameters please consult the online documentation at http://www.rforge.net/Rserve. Use \code{R CMD Rserve --help} for a brief help. The \code{Rserve} function is provided for convenience only. On Windows the \code{Rserve()} function sets up the \code{PATH} to include the current R.DLL so that Rserve can be run. } \arguments{ \item{debug}{determines whether regular Rserve or debug version of Rserve (\code{Rserve.dbg}) should be started.} \item{port}{port used by Rserve to listen for connections. If not specified, it will be taken from the configuration file (if present) or default to 6311} \item{args}{further arguments passed to Rserve (as a string that will be passed to the \code{system} command - see \code{quote} below).} \item{quote}{logical, if \code{TRUE} then arguments are quoted, otherwise they are just joined with spaces} \item{wait}{wait argument for the \code{\link{system}} call. It defaults to \code{FALSE} on Windows and \code{TRUE} elsewhere.} \item{\dots}{other arguments to be passes to \code{\link{system}}.} } \details{ Rserve is not just a package, but an application. It is provided as a R package for convenience only. For details see http://www.rforge.net/Rserve } \note{ \code{R CMD Rserve} will only work on unix when installed from \emph{sources} and with sufficient permissions to have write-rights in \code{$R_HOME/bin}. Binary installations have no way to write in \code{$R_HOME/bin} and thus \code{Rserve()} function described above is the only reliable way to start \code{Rserve} in that case. Java developers may want to see the \code{StartRserve} class in \code{java/Rserve/test} examples for easy way to start \code{Rserve} from Java. Rserve can be compiled with TLS/SSL support based on OpenSSL. Therefore the following statements may be true if Rserve binaries are shipped together with OpenSSL: This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/). This product includes cryptographic software written by Eric Young (eay@cryptsoft.com). This product includes software written by Tim Hudson (tjh@cryptsoft.com). They are not true otherwise. } \seealso{\code{\link{run.Rserve}}} \author{Simon Urbanek} \keyword{interface} Rserve/man/ulog.Rd0000644000175100001440000000210014531234224013537 0ustar hornikusers\name{ulog} \title{Micro Logging} \alias{ulog} \usage{ ulog(...) } \description{ \code{ulog} logs the supplied message using the \code{ulog} facility which typically corresponsed to syslog. See \code{ulog} Rserve configuration for the various endpoints supported by ulog (local, UDP/TCP remote, ...). This function is guaranteed to be silent regardless of the ulog setting and is intended to have minimal performance impact. Note: if Rserve is compiled with \code{-DULOG_STDERR} (also implied in the debug build) then ulog messages are also emitted on \code{stderr} with \code{"ULOG: "} prefix. Please note that this \code{ulog} function is governed by the Rserve settings, and NOT the \code{ulog} package settings. The latter is a general port of the \code{ulog} logging facility to R, while \code{Rserve::ulog} is specific to to the Rserve process. } \arguments{ \item{...}{message to log} } \value{ The logged string constructed from the message, invisibly } \examples{ ulog("INFO: My application started") } \author{Simon Urbanek} \keyword{interface} Rserve/man/self.Rd0000644000175100001440000000454014531234224013534 0ustar hornikusers\name{self} \title{Functions usable for R code run inside Rserve} \alias{self.ctrlEval} \alias{self.ctrlSource} \alias{self.oobSend} \alias{self.oobMessage} \usage{ self.ctrlEval(expr) self.ctrlSource(file) self.oobSend(what, code = 0L) self.oobMessage(what, code = 0L) } \description{ The following functions can only be used inside Rserve, they cannot be used in stand-alone R. They interact with special features of Rserve. All commands below will succeed only if Rserve has been started with \code{r-control enable} configuration setting for security reasons. \code{self.ctrlEval} issues a control command to the Rserve parent instance that evaluates the given expression in the server. The expression is only queued for evaluation which will happen asynchronously in the server (see \code{RSserverEval} in \code{RSclient} package for details). Note that the current session is unaffected by the command. \code{self.ctrlSource} issues a control command to the Rserve parent instance to source the given file in the server, see \code{RSserverSource} in the \code{RSclient} package for details. \code{self.oobSend} sends a out-of-band (OOB) message with the encoded content of \code{what} to the client connected to this session. The OOB facility must be enabled in the Rserve configuration (using \code{oob enable}) and the client must support OOB messages for this to be meaningful. This facility is not used by Rserve itself, it is offered to specialized applications (e.g. \code{Cairo} supports asynchronous notification of web clients using WebSockets-QAP1 tunnel to dynamically update graphics on the web during evaluation). \code{self.oobMessage} is like \code{self.oobSend} except that it waits for a response and returns the response. } \arguments{ \item{expr}{R expression to evaluate remotely} \item{file}{path to a file that will be sourced into the main instance} \item{what}{object to include as the payload fo the message} \item{code}{user-defined message code that will be ORed with the \code{OOB_SEND}/\code{OOB_MSG} message code} } \value{ \code{oobMessage} returns data contained in the response message. All other functions return \code{TRUE} (invisibly). } \examples{ \dontrun{ self.ctrlEval("a <- rnorm(10)") self.oobSend(list("url","http://foo/bar")) } } \author{Simon Urbanek} \keyword{interface} Rserve/man/Rserve.eval.Rd0000644000175100001440000001002314531234224014770 0ustar hornikusers\name{Rserve.eval} \alias{Rserve.eval} \title{Evaluate expressions in a REPL-like fashion} \description{ \code{Rserve.eval} evaluates a given expression in a way that is very close to the behavior on the console Read/Evaluate/Print Loop (REPL). Among other things this means printing the result of each expression if visible. The function is guaranteed to not raise an error and in case of an error it returns an object of class \code{Rserve-eval-error} with details including the error and the stack trace. } \usage{ Rserve.eval(what, where = .GlobalEnv, last.value = FALSE, exp.value = FALSE, context = NULL, handlers = list(error=.save.condition)) } \arguments{ \item{what}{expressions to evaluate} \item{where}{environment to evaluate in} \item{last.value}{logical, if \code{TRUE} then the result of the evaluation is returned, otherwise the evaluation is only performed for its side-efects and returns \code{TRUE} instead.} \item{exp.value}{logical, it \code{TRUE} then an error object will include the actual expression that triggered the error, otherwise it will only store the index of the expression in \code{what}.} \item{context}{optional object that will be used as the Rserve context for the duration of the evaluation (see \code{\link{Rserve.context}}).} \item{handlers}{optional named list of calling handlers to register for the duration of the evaluation. The default is to register an \code{error} handlers which stores the error condition so it can be reported in the result - see below.} } \details{ If \code{what} contains one or more expressions, they are evaluated one by one while printing the result of each if visible. Upon error subsequent expressions are not evaluated. If \code{what} is not an expression then the only a single evaluation of \code{what} is performed and the result is not printed. The main purpose of this function is to implement console front-ends where the front-end uses \code{parse()} + \code{Rserve.eval()} to simulate the action of a GUI. Because the function returns in all circumstances it allows clients to rely on a well-define messaging behavior. } \value{ If the evaluation triggered an error, the result is an object of class \code{Rserve-eval-error} with components: \item{error}{character, error message} \item{traceback}{list of contexts in the traceback} \item{expression}{if \code{what} contains multiple expressions then this will be either an index to the expression that caused the error (\code{exp.value=FALSE}) or the actual expression (otherwise).} \item{context}{current Rserve context, \code{NULL} if none has been set} \item{condition}{if any condition has been saved via \code{.save.condition} (which is the default) then on error the captured condition object is stored here, \code{NULL} otherwise} If the evaluation finished without an error then the result is either \code{TRUE} if \code{last.value=FALSE} or the value of the last expression otherwise. } \note{ Rserve versions up to 1.8-10 did not include the \code{condition} component, no calling handlers were registered and there was no \code{condition} component in the result. To replicate that behavior or if you don't need that information, you can set \code{handlers=NULL} which removes the overhead of adding calling handlers. No error checking is performed on the \code{handlers} parameter, so make sure it is avalid, named list of functions, otherwise an error will occur at evaluation time. } \author{ Simon Urbanek } \examples{ g <- function() stop("foo") f <- function() g() (Rserve.eval(expression(f()))) (Rserve.eval(parse(text="1:5\n1+1"))) (Rserve.eval(quote(1+1), last.value=TRUE)) error_with_condition = function(object = NULL) { cond = errorCondition("this is a custom error with condition", object = object, class = "CustomError") stop(cond) } str(Rserve.eval(quote(error_with_condition("hello")), last.value = TRUE)) } \keyword{manip} Rserve/man/run.Rserve.Rd0000644000175100001440000000273214531234224014655 0ustar hornikusers\name{run.Rserve} \alias{run.Rserve} \title{ Start Rserve within the current R process. } \description{ \code{run.Rserve} makes the current R process into an Rserve instance. Rserve takes over until it is shut down or receives a user interrupt signal. The main difference between \code{\link{Rserve}} and \code{run.Rserve} is that \code{Rserve} starts a new process, whereas \code{run.Rserve} turns the current R session into Rserve. This is only possible if there are no UI elements or other parts that could interfere with the prepation of \code{Rserve}. } \usage{ run.Rserve(..., config.file = "/etc/Rserve.conf") } %- maybe also 'usage' for other objects documented here. \arguments{ \item{\dots}{ all named arguments are treated as entries that would be otherwise present in the configuration file. So argument \code{foo="bar"} has the same meaning as \code{foo bar} in the configuration file. The only exception is that logical values can be used instead of \code{enable}/\code{disable}. Some settings such as \code{uid} are not relevant and thus ignored. } \item{config.file}{ path of the configuration file to load in the Rserve. It will be loaded before the above settings and is optional, i.e. if the file is not present or readable it will be ignored. } } %\details{ %} \value{ Returns \code{TRUE} after the Rserve was shut down. } %\references{ %} \author{Simon Urbanek} \seealso{ \code{\link{Rserve}} } \keyword{interface} Rserve/man/ocap.Rd0000644000175100001440000000302714531234224013524 0ustar hornikusers\name{ocap} \title{Object Capability (OCAP) Functions} \alias{ocap} \alias{resolve.ocap} \alias{Rserve.context} \usage{ ocap(fun, name = deparse(substitute(fun))) resolve.ocap(ocap) Rserve.context(what) } \description{ The following functions are only meaningful when used by code that is run inside Rserve in object-capability (OCAP) mode. See \href{https://github.com/s-u/Rserve/wiki/OCAP-mode}{Rserve Wiki} for details. \code{ocap} registers a function as a capability and returns the reference. \code{resolve.ocap} takes a capability reference and returns the function representing the capability. \code{Rserve.context} retrieves or sets the current context for out-of-band (OOB) messages (see also \code{\link{Rserve.eval}} for specifying contexts during evaluation). } \arguments{ \item{fun}{function to register} \item{name}{description of the function, only for informational and logging purposes} \item{ocap}{reference previously obtained by a call to \code{ocap}} \item{what}{if present, sets the context to the supplied value. If missing, the function returns the current context} } \value{ \code{ocap} returns the new capability reference, it will be an object of the class \code{"OCref"}. \code{resolve.ocap} returns the function corresponding to the reference or \code{NULL} if the reference does not exist. It will raise an error if \code{ocap} is not a valid \code{"OCref"} object. \code{Rserve.context} returns the current context } %\examples{ %} \author{Simon Urbanek} \keyword{interface} Rserve/DESCRIPTION0000644000175100001440000000171614531324156013255 0ustar hornikusersPackage: Rserve Version: 1.8-13 Title: Binary R server Author: Simon Urbanek Maintainer: Simon Urbanek Depends: R (>= 1.5.0) Suggests: RSclient SystemRequirements: libR, GNU make Description: Rserve acts as a socket server (TCP/IP or local sockets) which allows binary requests to be sent to R. Every connection has a separate workspace and working directory. Client-side implementations are available for popular languages such as C/C++ and Java, allowing any application to use facilities of R without the need of linking to R code. Rserve supports remote connection, user authentication and file transfer. A simple R client is included in this package as well. License: GPL-2 | file LICENSE URL: http://www.rforge.net/Rserve/ Biarch: true NeedsCompilation: yes Packaged: 2023-11-28 00:47:19 UTC; rforge Repository: CRAN Date/Publication: 2023-11-28 08:44:30 UTC Rserve/configure.ac0000644000175100001440000002025014531234224014023 0ustar hornikusers# Process this file with autoconf to produce a configure script. AC_INIT([Rserve],[1.8],[Simon.Urbanek@r-project.org]) AC_CONFIG_SRCDIR([src/Rserv.c]) AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_AUX_DIR([tools]) AC_CONFIG_MACRO_DIRS([tools/m4]) # find R home and set CC/CFLAGS : ${R_HOME=`R RHOME`} if test -z "${R_HOME}"; then echo "could not determine R_HOME" exit 1 fi AC_ARG_WITH([server], AS_HELP_STRING(--with-server,[compile Rserve server (default is @<:@yes@:>@). Given that this is the main functionality of Rserve, the only reason to disable the server is to configure R or C++ client separately.]), [with_server=$withval], [with_server=yes]) AC_ARG_WITH([client], AS_HELP_STRING(--with-client,[compile additional C/C++ Rserve client (default is @<:@no@:>@). The client can be always compiled manually regardless of this setting.]), [with_client=$withval], [with_client=no]) AC_ARG_WITH([proxy], AS_HELP_STRING(--with-proxy,[compile WebSockets/QAP proxy (default is @<:@yes@:>@).]), [with_proxy=$withval], [with_proxy=yes]) AC_ARG_ENABLE([ipv6], [AS_HELP_STRING([--enable-ipv6],[enable the use of IPv6 protocol. @<:@no@:>@])], [want_ipv6="${enableval}"], [want_ipv6=no]) RLD=`${R_HOME}/bin/R CMD config --ldflags 2>/dev/null` has_R_shlib=no if test -n "$RLD"; then has_R_shlib=yes fi AC_ARG_ENABLE([threads], [AS_HELP_STRING([--enable-threads],[enable the use of threads in code than may benefit from it. Currently, it is only used in stdout/err forwarding, it does not enable the threaded server. @<:@auto@:>@])], [want_threads="${enableval}"], [want_threads=auto]) AC_MSG_CHECKING([whether to compile the server]) if test "${with_server}" = yes; then AC_MSG_RESULT(yes) if test "${has_R_shlib}" = no; then AC_MSG_ERROR([R was configured without --enable-R-shlib or --enable-R-static-lib *** Rserve requires R (shared or static) library. *** *** Please install R library or compile R with either --enable-R-shlib *** *** or --enable-R-static-lib support *** Alternatively use --without-server if you wish to build only Rserve client. ]) fi else AC_MSG_RESULT(no) fi AC_MSG_CHECKING([whether to compile the client]) if test "${with_client}" = yes; then AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi AM_CONDITIONAL(WITH_SERVER, [test "x${with_server}" = xyes]) AM_CONDITIONAL(WITH_CLIENT, [test "x${with_client}" = xyes]) AM_CONDITIONAL(WITH_PROXY, [test "x${with_proxy}" = xyes]) CC=`${R_HOME}/bin/R CMD config CC`; CXX=`${R_HOME}/bin/R CMD config CXX`; R_CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS`; LDFLAGS=`${R_HOME}/bin/R CMD config LDFLAGS`; CPPFLAGS="${CPPFLAGS} ${PKG_CPPFLAGS} ${R_CPPFLAGS}" CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS` CXXFLAGS=`${R_HOME}/bin/R CMD config CXXFLAGS` RINC=`${R_HOME}/bin/R CMD config --cppflags` LIBS="${LIBS} ${PKG_LIBS}" AC_SUBST(R_HOME) AC_SUBST(RINC) AC_SUBST(RLD) AC_ARG_VAR([OPENSSL_INCLUDES],[optional path to the include directory for OpenSSL headers]) AC_ARG_VAR([PKG_CPPFLAGS],[additional pre-processor flags]) AC_ARG_VAR([PKG_LIBS],[additional linker library flags]) if test "x${OPENSSL_INCLUDES}" != x; then CPPFLAGS="${CPPFLAGS} -I${OPENSSL_INCLUDES}" fi # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([limits.h string.h memory.h sys/time.h unistd.h]) AC_CHECK_HEADERS([sys/stat.h sys/types.h sys/socket.h sys/un.h netinet/in.h netinet/tcp.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_BIGENDIAN(AC_DEFINE(BS_BIG_ENDIAN, 1, [Defined if the platform is big-endian]), AC_DEFINE(BS_LITTLE_ENDIAN, 1, [Defined if the platform is little-endian]), [ AC_MSG_RESULT(endianness unknown - will rely solely on compiler macros) AC_MSG_CHECKING([whether compiler sets endianness macros]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #if defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN_ || defined __BIG_ENDIAN__ || defined _BIG_ENDIAN_ #define BS_OK 1 #else cannot determine compiler's endianness #endif ])],[AC_MSG_RESULT(yes)],[ AC_MSG_RESULT(no) AC_MSG_ERROR([Cannot determine endianness neither from the compiler nor using a test. Try adding -D_BIG_ENDIAN_ or -D_LITTLE_ENDIAN_ to PKG_CPPFLAGS. ])]) ]) AC_CHECK_SIZEOF(size_t) # Checks for library functions. AC_FUNC_FORK # NOTE: autoconf claims this must be void and thus is not needed AC_CACHE_CHECK([return type of signal handlers],[ac_cv_type_signal],[AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([#include #include ], [return *(signal (0, 0)) (0) == 1;])], [ac_cv_type_signal=int], [ac_cv_type_signal=void])]) AC_DEFINE_UNQUOTED([RETSIGTYPE],[$ac_cv_type_signal],[Define as the return type of signal handlers (`int' or `void').]) AC_CHECK_FUNCS([memset mkdir rmdir select socket srandomdev]) # Check whether we can use crypt (and if we do if it's in the crypt library) AC_SEARCH_LIBS(crypt, crypt, [AC_DEFINE(HAS_CRYPT, 1, [If defined Rserve supports unix crypt password encryption.])]) AC_CHECK_HEADERS([crypt.h]) # socket related stuff - indroduced first due to Solaris # socklen_t - note that we don't try to find an equivalent! # we'll use BSD-style int in case this one isn't defined. # that should be fine for all major platforms. AC_CHECK_TYPE(socklen_t,, AC_DEFINE(socklen_t, int, [Define to `int' if neither nor define.]), [ #include #include ]) # connect may need -lsocket and/or -lnsl (e.g. on Solaris) AC_CHECK_FUNCS(connect) if test x"$ac_cv_func_connect" = x"no"; then case "$LIBS" in *-lnsl*) ;; *) AC_CHECK_LIB(nsl_s, printf) ;; esac case "$LIBS" in *-lnsl*) ;; *) AC_CHECK_LIB(nsl, printf) ;; esac case "$LIBS" in *-lsocket*) ;; *) AC_CHECK_LIB(socket, connect) ;; esac case "$LIBS" in *-linet*) ;; *) AC_CHECK_LIB(inet, connect) ;; esac dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value dnl has been cached. if test x"$ac_cv_lib_socket_connect" = x"yes" || test x"$ac_cv_lib_inet_connect" = x"yes"; then # ac_cv_func_connect=yes # don't! it would cause AC_CHECK_FUNC to succeed next time configure is run AC_DEFINE(HAVE_CONNECT, 1, [ ]) fi fi # IPv6 have_ipv6=no AC_MSG_CHECKING([whether to enable IPv6]) if test "$want_ipv6" = yes; then AC_MSG_RESULT([yes]) AC_MSG_CHECKING([for working IPv6 sockets]) AC_LINK_IFELSE([AC_LANG_SOURCE([ #include #include int main(void) { struct sockaddr_in6 sin; int i = socket(PF_INET6, SOCK_STREAM, 0); sin.sin6_family = AF_INET6; sin.sin6_addr = in6addr_any; return 0; } ])],[AC_MSG_RESULT(yes) have_ipv6=yes],[AC_MSG_RESULT(no)]) else AC_MSG_RESULT([no]) fi if test "$have_ipv6" = yes; then AC_DEFINE(HAVE_IPV6, 1, [IPv6 support present and enabled]) fi # on some platforms libR expects dl code in the binary AC_CHECK_LIB(dl, dlopen) # check RSA/crypto AC_CHECK_HEADER([openssl/rsa.h], [AC_SEARCH_LIBS(RSA_generate_key, [crypto ssl openssl], [AC_DEFINE(HAVE_RSA, 1, [RSA crypto support])])]) # check SSL support AC_CHECK_HEADER([openssl/ssl.h], [AC_SEARCH_LIBS(SSL_CTX_load_verify_locations, [ssl openssl], [AC_DEFINE(HAVE_TLS, 1, [TLS/SSL support])])]) # check threads AC_MSG_CHECKING([whether threads are desired]) if test "$want_threads" != no; then AC_MSG_RESULT([yes]) AX_PTHREAD([ LIBS="$PTHREAD_LIBS $LIBS" ## we don't want to mess with CFLAGS so we (ab)use CPPFLAGS CPPFLAGS="$CPPFLAGS $PTHREAD_CFLAGS" ## and we ignore PTHREAD_CC since we have to use R's settings with_threads=yes AC_MSG_CHECKING([for working threads support]) AC_MSG_RESULT([yes]) ], [ AC_MSG_CHECKING([for working threads support]) AC_MSG_RESULT([no]) if test "$want_threads" = yes; then AC_MSG_ERROR([Threads were requested, but no working threads support was found]) fi with_threads=no ]) else AC_MSG_RESULT([no]) with_threads=no fi AC_SUBST(PTHREAD_CFLAGS) if test x"$with_threads" = xyes; then AC_DEFINE(WITH_THREADS, 1, [set if threads can be used]) fi AC_CONFIG_FILES([src/Makevars]) AC_CONFIG_FILES([src/client/cxx/Makefile]) AC_OUTPUT Rserve/src/0000755000175100001440000000000014531234224012325 5ustar hornikusersRserve/src/tls.h0000644000175100001440000000132214531234224013276 0ustar hornikusers#ifndef TLS_H__ #define TLS_H__ #include "RSserver.h" typedef struct tls tls_t; /* for set_tls_verify() */ #define TLS_NONE 0 /* default */ #define TLS_REQUIRE 1 /* in case shared tls is not set, it will be set to new_tls (which can be NULL) */ tls_t *shared_tls(tls_t *new_tls); tls_t *new_tls(void); int set_tls_pk(tls_t *tls, const char *fn); int set_tls_cert(tls_t *tls, const char *fn); int set_tls_ca(tls_t *tls, const char *fn_ca, const char *path_ca); int set_tls_verify(tls_t *tls, int verify); void free_tls(tls_t *tls); int add_tls(args_t *c, tls_t *tls, int server); void copy_tls(args_t *src, args_t *dst); void close_tls(args_t *c); int verify_peer_tls(args_t *c, char *cn, int len); #endif Rserve/src/install.libs.R0000644000175100001440000000146514531234224015054 0ustar hornikuserslibarch <- if (nzchar(R_ARCH)) paste("libs", R_ARCH, sep='') else "libs" dest <- file.path(R_PACKAGE_DIR, libarch) ## the last two on unix are for compatibility only files <- if (WINDOWS) c("Rserve.exe", "Rserve_d.exe", "forward.exe") else c("Rserve","Rserve.dbg","forward") files <- c(files, paste("Rserve",SHLIB_EXT,sep='')) ## all files are optional in case the package is built without the server files <- files[file.exists(files)] if (length(files)) { dir.create(dest, recursive = TRUE, showWarnings = FALSE) file.copy(files, dest, overwrite = TRUE) if (length(grep("^darwin", R.version$os))) { message('generating debug symbols (dSYM)') dylib <- Sys.glob(paste(dest, "/*", SHLIB_EXT, sep='')) if (length(dylib)) for (file in dylib) try(system(paste("dsymutil ", file, sep='')), silent=TRUE) } } Rserve/src/websockets.h0000644000175100001440000000210314531234224014643 0ustar hornikusers#ifndef WEBSOCKETS_H__ #define WEBSOCKETS_H__ #include "RSserver.h" #define WS_PROT_QAP 0x01 #define WS_PROT_TEXT 0x02 /* NOTE: this is not the same as SRV_TLS! It is annoying, but WS needs to chain TLS futher down, if SRC_TLS is set then QAP will be tunneled through TLS but we need to wrap WS around it first */ #define WS_TLS 0x08 /* WARNING: HTTP uses 0x10 and 0x20 */ #define WS_PROT_ALL (WS_PROT_QAP | WS_PROT_TEXT) server_t *create_WS_server(int port, int protocols); /* upgrade HTTP connection to WS - assumes that the HTTP server has parsed the request already only WS 13+ handshake is supported by this function */ void WS13_upgrade(args_t *arg, const char *key, const char *protocol, const char *version); /* flags used in args_t.flags */ #define F_INFRAME 0x010 #define F_MASK 0x020 #define F_IN_BIN 0x040 #define F_OUT_BIN 0x080 #define SET_F_FT(X, FT) X = (((X) & 0xfff) | (((FT) & 15) << 12)) #define GET_F_FT(X) (((X) >> 12) & 15) #define GET_MASK_ID(X) ((X) & 3) #define SET_F_MASK(X, M) X = (((X) & 0xfffc) | F_MASK | ((M) & 3)) #endif Rserve/src/RSserver.h0000644000175100001440000000563514531234224014262 0ustar hornikusers#ifndef RS_SERVER_H__ #define RS_SERVER_H__ #include "Rsrv.h" /* this is a voluntary standart flag to request TLS support */ #define SRV_TLS 0x0800 /* these flags are global and respected by the default socket server */ #define SRV_IPV6 0x1000 /* use IPv6 */ #define SRV_LOCAL 0x4000 /* bind to local loopback interface only */ #define SRV_KEEPALIVE 0x8000 /* enable keep-alive - note that this is really a client option sice inheritance is not guaranteed */ typedef struct args args_t; typedef void (*work_fn_t)(void *par); /* 0 = success, <0 = error */ typedef int (*send_fn_t)(args_t *arg, int rsp, size_t len, const void *buf); typedef ssize_t (*buf_fn_t) (args_t *arg, void *buf, size_t len); typedef ssize_t (*cbuf_fn_t) (args_t *arg, const void *buf, size_t len); typedef int (*fork_fn_t) (args_t *arg); /* definition of a server */ typedef struct server { int ss; /* server socket */ int unix_socket; /* 0 = TCP/IP, 1 = unix socket */ int flags; /* optional server-specific flags */ work_fn_t connected; /* function called for each new connection */ work_fn_t fin; /* optional finalization function */ send_fn_t send_resp; /* send response */ cbuf_fn_t send; /* direct send */ buf_fn_t recv; /* direct receive */ fork_fn_t fork; /* fork */ struct server *parent;/* parent server - used only by multi-layer servers */ } server_t; /* this flag can be passed to create_server for an IP socket to modify the behavior */ #define LSM_IP_LOCAL 1 /* bind to loopback address only */ #define LSM_IPV6 2 /* use IPv6 (if available) */ server_t *create_server(int port, const char *localSocketName, int localSocketMode, int flags); void accepted_server(server_t *srv, int cs); /* performs additional tasks on client socket (eg SO_KEEPALIVE) */ int add_server(server_t *srv); int rm_server(server_t *srv); /* server stacks */ typedef struct server_stack server_stack_t; server_stack_t* create_server_stack(void); void push_server(server_stack_t *s, server_t *srv); int server_stack_size(server_stack_t *s); void release_server_stack(server_stack_t *s); /* some generic implementations */ void server_fin(void *x); ssize_t server_recv(args_t *arg, void *buf, size_t len); ssize_t server_send(args_t *arg, const void *buf, size_t len); void stop_server_loop(void); void serverLoop(void); /* helper function that prepares the process just like Rserve internal impleemntation - forking when desired, establishing pipes, setting see, uid/gid, cwd etc. returns 0 for the child */ int Rserve_prepare_child(args_t *arg); /* this one is called by the former to close all server sockets in the child */ void close_all_srv_sockets(void); #endif /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/base64.c0000644000175100001440000000324014531234224013554 0ustar hornikusersvoid base64encode(const unsigned char *src, int len, char *dst); int base64decode(const char *src, void *dst, int max_len); static const char *b64tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* dst must be at least (len + 2) / 3 * 4 + 1 bytes long and will be NUL terminated when done */ void base64encode(const unsigned char *src, int len, char *dst) { while (len > 0) { *(dst++) = b64tab[src[0] >> 2]; *(dst++) = b64tab[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)]; *(dst++) = (len > 1) ? b64tab[((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)] : '='; *(dst++) = (len > 2) ? b64tab[src[2] & 0x3f] : '='; src += 3; len -= 3; } *dst = 0; } static unsigned int val(const char **src) { while (1) { char c = **src; if (c) src[0]++; else return 0x10000; if (c >= 'A' && c <= 'Z') return c - 'A'; if (c >= 'a' && c <= 'z') return c - 'a' + 26; if (c >= '0' && c <= '9') return c - '0' + 52; if (c == '+') return 62; if (c == '/') return 63; if (c == '=') return 0x10000; /* we loop as to skip any blanks, newlines etc. */ } } /* returns the decoded length or -1 if max_len was not enough */ int base64decode(const char *src, void *dst, int max_len) { unsigned char *t = (unsigned char*) dst, *end = t + max_len; while (*src && t < end) { unsigned int v = val(&src); if (v > 64) break; *t = v << 2; v = val(&src); *t |= v >> 4; if (v < 64) { if (++t == end) return -1; *t = v << 4; v = val(&src); *t |= v >> 2; if (v < 64) { if (++t == end) return -1; *t = v << 6; v = val(&src); *t |= v & 0x3f; if (v < 64) t++; } } } return (int) (t - (unsigned char*) dst); } Rserve/src/md5.c0000644000175100001440000002076614531234224013171 0ustar hornikusers/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ /* Brutally hacked by John Walker back from ANSI C to K&R (no prototypes) to maintain the tradition that Netfone will compile with Sun's original "cc". Modified to work better with autoconf and added md5hash convenience function (Simon Urbanek, 2005/09/30) $Id$ */ #ifndef NO_CONFIG_H #include "config.h" #endif #ifdef HAVE_MEMORY_H #include /* for memcpy() */ #else #include #endif #include "md5.h" #ifdef SWAPEND #define HIGHFIRST #endif #ifndef HIGHFIRST #define byteReverse(buf, len) /* Nothing */ #else /* * Note: this code is harmless on little-endian machines. */ void byteReverse(unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } #endif /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len) { uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memcpy(p, buf, len); return; } memcpy(p, buf, t); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(unsigned char digest[16],struct MD5Context *ctx) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1]; MD5Transform(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform(uint32 buf[4], uint32 in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } static unsigned char m5hash[16]; /* the hash must hold 16 bytes */ unsigned char *md5hash(const void *buf, int len, unsigned char hash[16]) { struct MD5Context ctx; if (!hash) hash=m5hash; MD5Init(&ctx); MD5Update(&ctx, buf, len); MD5Final(hash, &ctx); return hash; } Rserve/src/sha1.h0000644000175100001440000000015414531234224013332 0ustar hornikusers#ifndef SHA1_H__ #define SHA1_H__ void sha1hash(const char *buf, int len, unsigned char hash[20]); #endif Rserve/src/Rsrv.h0000644000175100001440000004614014531234224013437 0ustar hornikusers/* * Rsrv.h : constants and macros for Rserve client/server architecture * Copyright (C) 2002-22 Simon Urbanek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; version 2.1 of the License * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Note: This header file is licensed under LGPL to allow other * programs to use it under LGPL. Rserve itself is licensed under GPL. * * $Id$ */ /* external defines: MAIN - should be defined in just one file that will contain the fn definitions and variables */ #ifndef __RSRV_H__ #define __RSRV_H__ #ifndef NO_CONFIG_H #include "config.h" #endif #define RSRV_VER 0x01080d /* Rserve v1.8-13 */ #define default_Rsrv_port 6311 /* Rserve communication is done over any reliable connection-oriented protocol (usually TCP/IP or local sockets). After the connection is established, the server sends 32 bytes of ID-string defining the capabilities of the server. Each attribute of the ID-string is 4 bytes long and is meant to be user-readable (i.e. don't use special characters), and it's a good idea to make "\r\n\r\n" the last attribute the ID string must be of the form: [0] "Rsrv" - R-server ID signature [4] "0100" - version of the R server [8] "QAP1" - protocol used for communication (here Quad Attributes Packets v1) [12] any additional attributes follow. \r\n and '-' are ignored. optional attributes (in any order; it is legitimate to put dummy attributes, like "----" or " " between attributes): "R151" - version of R (here 1.5.1) "ARpt" - authorization required (here "pt"=plain text, "uc"=unix crypt, "m5"=MD5) connection will be closed if the first packet is not CMD_login. if more AR.. methods are specified, then client is free to use the one he supports (usually the most secure) "K***" - key if encoded authentification is challenged (*** is the key) for unix crypt the first two letters of the key are the salt required by the server */ /* QAP1 transport protocol header structure all int and double entries throughout the transfer are in Intel-endianess format: int=0x12345678 -> char[4]=(0x78,0x56,x34,0x12) functions/macros for converting from native to protocol format are available below Please note also that all values muse be quad-aligned, i.e. the length must be divisible by 4. This is automatically assured for int/double etc., but care must be taken when using strings and byte streams. */ struct phdr { /* always 16 bytes */ int cmd; /* command */ int len; /* length of the packet minus header (ergo -16) */ int msg_id; /* message id (since 1.8) [WAS:data offset behind header (ergo usually 0)] */ int res; /* high 32-bit of the packet length (since 0103 and supported on 64-bit platforms only) aka "lenhi", but the name was not changed to maintain compatibility */ }; /* each entry in the data section (aka parameter list) is preceded by 4 bytes: 1 byte : parameter type 3 bytes: length parameter list may be terminated by 0/0/0/0 but doesn't have to since "len" field specifies the packet length sufficiently (hint: best method for parsing is to allocate len+4 bytes, set the last 4 bytes to 0 and trverse list of parameters until (int)0 occurs since 0102: if the 7-th bit (0x40) in parameter type is set then the length is encoded in 7 bytes enlarging the header by 4 bytes. */ /* macros for handling the first int - split/combine (24-bit version only!) */ #define PAR_TYPE(X) ((X) & 255) #define PAR_LEN(X) (((unsigned int)(X)) >> 8) #define PAR_LENGTH PAR_LEN #define SET_PAR(TY,LEN) ((((unsigned int) (LEN) & 0xffffff) << 8) | ((TY) & 255)) #define CMD_STAT(X) (((X) >> 24)&127) /* returns the stat code of the response */ #define SET_STAT(X,s) ((X) | (((s) & 127) << 24)) /* sets the stat code */ #define CMD_RESP 0x10000 /* all responses have this flag set */ #define RESP_OK (CMD_RESP|0x0001) /* command succeeded; returned parameters depend on the command issued */ #define RESP_ERR (CMD_RESP|0x0002) /* command failed, check stats code attached string may describe the error */ #define CMD_OOB 0x20000 /* out-of-band data - i.e. unsolicited messages */ #define OOB_SEND (CMD_OOB | 0x1000) /* OOB send - unsolicited SEXP sent from the R instance to the client. 12 LSB are reserved for application-specific code */ #define OOB_MSG (CMD_OOB | 0x2000) /* OOB message - unsolicited message sent from the R instance to the client requiring a response. 12 LSB are reserved for application-specific code */ #define IS_OOB_SEND(X) (((X) & 0x0ffff000) == OOB_SEND) #define IS_OOB_MSG(X) (((X) & 0x0ffff000) == OOB_MSG) #define OOB_USR_CODE(X) ((X) & 0xfff) /* flag for create_server: Use QAP object-cap mode */ #define SRV_QAP_OC 0x40 /* mask of all flags that are relevant to QAP (so they can be passed through) */ #define SRV_QAP_FLAGS (SRV_QAP_OC) /* stat codes; 0-0x3f are reserved for program specific codes - e.g. for R connection they correspond to the stat of Parse command. the following codes are returned by the Rserv itself codes <0 denote Rerror as provided by R_tryEval */ #define ERR_auth_failed 0x41 /* auth.failed or auth.requested but no login came. in case of authentification failure due to name/pwd mismatch, server may send CMD_accessDenied instead */ #define ERR_conn_broken 0x42 /* connection closed or broken packet killed it */ #define ERR_inv_cmd 0x43 /* unsupported/invalid command */ #define ERR_inv_par 0x44 /* some parameters are invalid */ #define ERR_Rerror 0x45 /* R-error occured, usually followed by connection shutdown */ #define ERR_IOerror 0x46 /* I/O error */ #define ERR_notOpen 0x47 /* attempt to perform fileRead/Write on closed file */ #define ERR_accessDenied 0x48 /* this answer is also valid on CMD_login; otherwise it's sent if the server deosn;t allow the user to issue the specified command. (e.g. some server admins may block file I/O operations for some users) */ #define ERR_unsupportedCmd 0x49 /* unsupported command */ #define ERR_unknownCmd 0x4a /* unknown command - the difference between unsupported and unknown is that unsupported commands are known to the server but for some reasons (e.g. platform dependent) it's not supported. unknown commands are simply not recognized by the server at all. */ /* The following ERR_.. exist since 1.23/0.1-6 */ #define ERR_data_overflow 0x4b /* incoming packet is too big. currently there is a limit as of the size of an incoming packet. */ #define ERR_object_too_big 0x4c /* the requested object is too big to be transported in that way. If received after CMD_eval then the evaluation itself was successful. optional parameter is the size of the object */ /* since 1.29/0.1-9 */ #define ERR_out_of_mem 0x4d /* out of memory. the connection is usually closed after this error was sent */ /* since 0.6-0 */ #define ERR_ctrl_closed 0x4e /* control pipe to the master process is closed or broken */ /* since 0.4-0 */ #define ERR_session_busy 0x50 /* session is still busy */ #define ERR_detach_failed 0x51 /* unable to detach seesion (cannot determine peer IP or problems creating a listening socket for resume) */ /* since 1.7 */ #define ERR_disabled 0x61 /* feature is disabled */ #define ERR_unavailable 0x62 /* feature is not present in this build */ #define ERR_cryptError 0x63 /* crypto-system error */ #define ERR_securityClose 0x64 /* server-initiated close due to security violation (too many attempts, excessive timeout etc.) */ /* availiable commands */ #define CMD_login 0x001 /* "name\npwd" : - */ #define CMD_voidEval 0x002 /* string : - */ #define CMD_eval 0x003 /* string | encoded SEXP : encoded SEXP */ #define CMD_shutdown 0x004 /* [admin-pwd] : - */ /* security/encryption - all since 1.7-0 */ #define CMD_switch 0x005 /* string (protocol) : - */ #define CMD_keyReq 0x006 /* string (request) : bytestream (key) */ #define CMD_secLogin 0x007 /* bytestream (encrypted auth) : - */ #define CMD_OCcall 0x00f /* SEXP : SEXP -- it is the only command supported in object-capability mode and it requires that the SEXP is a language construct with OC reference in the first position */ #define CMD_OCinit 0x434f7352 /* SEXP -- 'RsOC' - command sent from the server in OC mode with the packet of initial capabilities. */ /* file I/O routines. server may answe */ #define CMD_openFile 0x010 /* fn : - */ #define CMD_createFile 0x011 /* fn : - */ #define CMD_closeFile 0x012 /* - : - */ #define CMD_readFile 0x013 /* [int size] : data... ; if size not present, server is free to choose any value - usually it uses the size of its static buffer */ #define CMD_writeFile 0x014 /* data : - */ #define CMD_removeFile 0x015 /* fn : - */ /* object manipulation */ #define CMD_setSEXP 0x020 /* string(name), REXP : - */ #define CMD_assignSEXP 0x021 /* string(name), REXP : - ; same as setSEXP except that the name is parsed */ /* session management (since 0.4-0) */ #define CMD_detachSession 0x030 /* : session key */ #define CMD_detachedVoidEval 0x031 /* string : session key; doesn't */ #define CMD_attachSession 0x032 /* session key : - */ /* control commands (since 0.6-0) - passed on to the master process */ /* Note: currently all control commands are asychronous, i.e. RESP_OK indicates that the command was enqueued in the master pipe, but there is no guarantee that it will be processed. Moreover non-forked connections (e.g. the default debug setup) don't process any control commands until the current client connection is closed so the connection issuing the control command will never see its result. */ #define CMD_ctrl 0x40 /* -- not a command - just a constant -- */ #define CMD_ctrlEval 0x42 /* string : - */ #define CMD_ctrlSource 0x45 /* string : - */ #define CMD_ctrlShutdown 0x44 /* - : - */ /* 'internal' commands (since 0.1-9) */ #define CMD_setBufferSize 0x081 /* [int sendBufSize] this commad allow clients to request bigger buffer sizes if large data is to be transported from Rserve to the client. (incoming buffer is resized automatically) */ #define CMD_setEncoding 0x082 /* string (one of "native","latin1","utf8") : -; since 0.5-3 */ /* special commands - the payload of packages with this mask does not contain defined parameters */ #define CMD_SPECIAL_MASK 0xf0 #define CMD_serEval 0xf5 /* serialized eval - the packets are raw serialized data without data header */ #define CMD_serAssign 0xf6 /* serialized assign - serialized list with [[1]]=name, [[2]]=value */ #define CMD_serEEval 0xf7 /* serialized expression eval - like serEval with one additional evaluation round */ /* data types for the transport protocol (QAP1) do NOT confuse with XT_.. values. */ #define DT_INT 1 /* int */ #define DT_CHAR 2 /* char */ #define DT_DOUBLE 3 /* double */ #define DT_STRING 4 /* 0 terminted string */ #define DT_BYTESTREAM 5 /* stream of bytes (unlike DT_STRING may contain 0) */ #define DT_SEXP 10 /* encoded SEXP */ #define DT_ARRAY 11 /* array of objects (i.e. first 4 bytes specify how many subsequent objects are part of the array; 0 is legitimate) */ #define DT_CUSTOM 32 /* custom types not defined in the protocol but used by applications */ #define DT_LARGE 64 /* new in 0102: if this flag is set then the length of the object is coded as 56-bit integer enlarging the header by 4 bytes */ /* XpressionTypes REXP - R expressions are packed in the same way as command parameters transport format of the encoded Xpressions: [0] int type/len (1 byte type, 3 bytes len - same as SET_PAR) [4] REXP attr (if bit 8 in type is set) [4/8] data .. */ #define XT_NULL 0 /* P data: [0] */ #define XT_INT 1 /* - data: [4]int */ #define XT_DOUBLE 2 /* - data: [8]double */ #define XT_STR 3 /* P data: [n]char null-term. strg. */ #define XT_LANG 4 /* - data: same as XT_LIST */ #define XT_SYM 5 /* - data: [n]char symbol name */ #define XT_BOOL 6 /* - data: [1]byte boolean (1=TRUE, 0=FALSE, 2=NA) */ #define XT_S4 7 /* P data: [0] */ #define XT_VECTOR 16 /* P data: [?]REXP,REXP,.. */ #define XT_LIST 17 /* - X head, X vals, X tag (since 0.1-5) */ #define XT_CLOS 18 /* P X formals, X body (closure; since 0.1-5) */ #define XT_SYMNAME 19 /* s same as XT_STR (since 0.5) */ #define XT_LIST_NOTAG 20 /* s same as XT_VECTOR (since 0.5) */ #define XT_LIST_TAG 21 /* P X tag, X val, Y tag, Y val, ... (since 0.5) */ #define XT_LANG_NOTAG 22 /* s same as XT_LIST_NOTAG (since 0.5) */ #define XT_LANG_TAG 23 /* s same as XT_LIST_TAG (since 0.5) */ #define XT_VECTOR_EXP 26 /* s same as XT_VECTOR (since 0.5) */ #define XT_VECTOR_STR 27 /* - same as XT_VECTOR (since 0.5 but unused, use XT_ARRAY_STR instead) */ #define XT_ARRAY_INT 32 /* P data: [n*4]int,int,.. */ #define XT_ARRAY_DOUBLE 33 /* P data: [n*8]double,double,.. */ #define XT_ARRAY_STR 34 /* P data: string,string,.. (string=byte,byte,...,0) padded with '\01' */ #define XT_ARRAY_BOOL_UA 35 /* - data: [n]byte,byte,.. (unaligned! NOT supported anymore) */ #define XT_ARRAY_BOOL 36 /* P data: int(n),byte,byte,... */ #define XT_RAW 37 /* P data: int(n),byte,byte,... */ #define XT_ARRAY_CPLX 38 /* P data: [n*16]double,double,... (Re,Im,Re,Im,...) */ #define XT_UNKNOWN 48 /* P data: [4]int - SEXP type (as from TYPEOF(x)) */ /* | +--- interesting flags for client implementations: P = primary type s = secondary type - its decoding is identical to a primary type and thus the client doesn't need to decode it separately. - = deprecated/removed. if a client doesn't need to support old Rserve versions, those can be safely skipped. Total primary: 4 trivial types (NULL, STR, S4, UNKNOWN) + 6 array types + 3 recursive types */ #define XT_LARGE 64 /* new in 0102: if this flag is set then the length of the object is coded as 56-bit integer enlarging the header by 4 bytes */ #define XT_HAS_ATTR 128 /* flag; if set, the following REXP is the attribute */ /* the use of attributes and vectors results in recursive storage of REXPs */ #define BOOL_TRUE 1 #define BOOL_FALSE 0 #define BOOL_NA 2 #define GET_XT(X) ((X)&63) #define GET_DT(X) ((X)&63) #define HAS_ATTR(X) (((X)&XT_HAS_ATTR)>0) #define IS_LARGE(X) (((X)&XT_LARGE)>0) #if defined sun && ! defined ALIGN_DOUBLES #define ALIGN_DOUBLES #endif #ifndef SIZEOF_SIZE_T #include /* defines SIZEOF_SIZE_T in case we missed it */ #endif #include /* for ptrdiff_t, which is required by C99 */ #include /* not directly used but for fixed-size int types */ #include /* s/size_t */ /* long vectors - we don't want to mandate Rinternals.h here so we use the minimal definition. By now size_t and ptrdiff_t should be ubiquitous so no more special cases */ typedef ssize_t rlen_t; /* we really need an unsigned type for safety in places where R is not involved */ typedef size_t urlen_t; /* this is used for alignment/masking */ #if ( SIZEOF_SIZE_T > 4 ) #define rlen_max ((rlen_t) 0x7fffffffffffffff) #else #define rlen_max ((rlen_t) 0x7fffffff) #endif /* functions/macros to convert native endianess of int/double for transport currently ony PPC style and Intel style are supported */ /* Since 0.4-5 we no longer use configure-time endianness tests to allow cross-compilation. Either BS_xx_ENDIAN constant is defined by configure and thus should be relied upon only if the compiler contants don't work */ #if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN_ #define SWAPEND 1 #elif defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN_ || defined BS_LITTLE_ENDIAN /* #undef SWAPEND */ #elif defined BS_BIG_ENDIAN #define SWAPEND 1 #elif __ia64__ || __i386__ || __x86_64__ /* take a guess based on the architecture (Intel-like) */ #define __LITTLE_ENDIAN__ 1 #elif __ppc__ || __ppc64__ /* any ppc */ #define __BIG_ENDIAN__ 1 #define SWAPEND 1 #elif ! defined Win32 /* Windows is little-endian is most cases, anywhere else we're stuck */ #error "Cannot determine endianness. Make sure config.h is included or __{BIG|LITTLE}_ENDIAN__ is defined ." #endif /* FIXME: all the mess below needs more efficient implementation - the current one is so messy to work around alignment problems on some platforms like Sun and HP 9000 */ #ifdef SWAPEND /* swap endianness - for PPC and co. */ #ifdef MAIN unsigned int itop(unsigned int i) { char b[4]; b[0]=((char*)&i)[3]; b[3]=((char*)&i)[0]; b[1]=((char*)&i)[2]; b[2]=((char*)&i)[1]; return *((unsigned int*)b); } double dtop(double i) { char b[8]; b[0]=((char*)&i)[7]; b[1]=((char*)&i)[6]; b[2]=((char*)&i)[5]; b[3]=((char*)&i)[4]; b[7]=((char*)&i)[0]; b[6]=((char*)&i)[1]; b[5]=((char*)&i)[2]; b[4]=((char*)&i)[3]; return *((double*)b); } void fixdcpy(void *t,void *s) { int i=0; while (i<8) { ((char*)t)[7-i]=((char*)s)[i]; i++; } } #else extern unsigned int itop(unsigned int i); extern double dtop(double i); extern void fixdcpy(void *t,void *s); #endif #define ptoi(X) itop(X) /* itop*itop=id */ #define ptod(X) dtop(X) #else #define itop(X) (X) #define ptoi(X) (X) #define dtop(X) (X) #define ptod(X) (X) #define fixdcpy(T,S) ((double*)(T))[0]=((double*)(S))[0]; #define NATIVE_COPY 1 #endif #ifndef HAVE_CONFIG_H /* this tiny function can be used to make sure that the endianess is correct (it is not included if the package was configured with autoconf since then it should be fine anyway) */ #ifdef MAIN int isByteSexOk(void) { int i; i=itop(0x12345678); return (*((char*)&i)==0x78); } #else extern int isByteSexOk(void); #endif #else #define isByteSexOk 1 #endif /* STANDALONE_RSERVE takes precedence over RSERVE_PKG */ #if defined STANDALONE_RSERVE && defined RSERVE_PKG #undef RSERVE_PKG #endif #endif /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/tls.c0000644000175100001440000000724614531234224013304 0ustar hornikusers#ifndef NO_CONFIG_H #include "config.h" #endif #include "tls.h" #ifdef HAVE_TLS #ifndef OPENSSL_SUPPRESS_DEPRECATED #define OPENSSL_SUPPRESS_DEPRECATED 1 #endif #include #ifdef RSERV_DEBUG #include #endif struct tls { SSL_CTX *ctx; const SSL_METHOD *method; }; static int first_tls = 1; static tls_t *tls; tls_t *shared_tls(tls_t *new_tls) { if (!tls) tls = new_tls; return tls; } tls_t *new_tls(void) { tls_t *t = (tls_t*) calloc(1, sizeof(tls_t)); if (first_tls) { SSL_library_init(); #ifdef RSERV_DEBUG SSL_load_error_strings(); #endif first_tls = 0; tls = t; } t->method = SSLv23_server_method(); t->ctx = SSL_CTX_new(t->method); return t; } int set_tls_pk(tls_t *tls, const char *fn) { return SSL_CTX_use_PrivateKey_file(tls->ctx, fn, SSL_FILETYPE_PEM); } int set_tls_cert(tls_t *tls, const char *fn) { return SSL_CTX_use_certificate_file(tls->ctx, fn, SSL_FILETYPE_PEM); } int set_tls_ca(tls_t *tls, const char *fn_ca, const char *path_ca) { return SSL_CTX_load_verify_locations(tls->ctx, fn_ca, path_ca); } int set_tls_verify(tls_t *tls, int verify) { SSL_CTX_set_verify(tls->ctx, verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, 0); return 1; } struct args { server_t *srv; /* server that instantiated this connection */ int s; int ss; int msg_id; SSL *ssl; void *res2; }; static ssize_t tls_recv(args_t *c, void *buf, size_t len) { return SSL_read(c->ssl, buf, len); } static ssize_t tls_send(args_t *c, const void *buf, size_t len) { return SSL_write(c->ssl, buf, len); } int add_tls(args_t *c, tls_t *tls, int server) { c->ssl = SSL_new(tls->ctx); c->srv->send = tls_send; c->srv->recv = tls_recv; SSL_set_fd(c->ssl, c->s); if (server) return SSL_accept(c->ssl); else return SSL_connect(c->ssl); } void copy_tls(args_t *src, args_t *dst) { dst->ssl = src->ssl; dst->s = src->s; dst->srv->send = src->srv->send; dst->srv->recv = src->srv->recv; } void close_tls(args_t *c) { if (c->ssl) { SSL_shutdown(c->ssl); SSL_free(c->ssl); c->ssl = 0; } } void free_tls(tls_t *tls) { } /* if cn is present, len > 0 and there is a cert then the common name is copied to cn and terminated. It may be truncated if len is too short. Return values: 0 = present but verification failed 1 = present and verification successful -1 = absent */ int verify_peer_tls(args_t *c, char *cn, int len) { X509 *peer; if ((peer = SSL_get_peer_certificate(c->ssl))) { if (cn && len > 0) { X509_NAME *sn = X509_get_subject_name(peer); X509_NAME_get_text_by_NID(sn, NID_commonName, cn, len); fprintf(stderr, "INFO: peer cert common name: \"%s\"\n", cn); } X509_free(peer); if (SSL_get_verify_result(c->ssl) == X509_V_OK) { fprintf(stderr, "INFO: peer cert present and OK\n"); return 1; } else { fprintf(stderr, "INFO: peer cert present, but verification FAILED\n"); return 0; } } fprintf(stderr, "INFO: peer nas NO cert\n"); return -1; } #else /* no SSL/TLS support, ignore everything, fail on everything */ tls_t *shared_tls(tls_t *new_tls) { return 0; } tls_t *new_tls(void) { return 0; } int set_tls_pk(tls_t *tls, const char *fn) { return -1; } int set_tls_cert(tls_t *tls, const char *fn) { return -1; } int set_tls_ca(tls_t *tls, const char *fn_ca, const char *path_ca) { return -1; } int set_tls_verify(tls_t *tls, int verify) { return -1; } void free_tls(tls_t *tls) { } int add_tls(args_t *c, tls_t *tls, int server) { return -1; } void copy_tls(args_t *src, args_t *dst) { } void close_tls(args_t *c) { } int verify_peer_tls(args_t *c, char *cn, int len) { return -1; } #endif Rserve/src/ulog.c0000644000175100001440000001250314531234224013440 0ustar hornikusers/* UDP logger (C)Copyright 2002-2013 Simon Urbanek This logger can be used either via simple ulog(...) call in the printf format, or the message can be constructed incerementally via ulog_begin() ulog_add(...); [ulog_add(...); ...] ulog_end() calls. ulog_end() commences the transfer. Internal state, sockets etc. may be cached after the first use. */ #define DEFAULT_ULOG_PORT 514 #ifndef NO_CONFIG_H #include "config.h" #endif #include "ulog.h" /* FIXME: now that we support UDP/TCP we could make this work on Windows ... */ #ifndef WIN32 #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H # include #endif #include #include #include #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif static int ulog_sock = -1; static char *ulog_path; static int ulog_dcol, ulog_port = 0; static char hn[512]; static char buf[4096]; static char ts[64]; static unsigned int buf_pos; #ifdef ULOG_MICROTIME static double time0, timeN; #endif static char *app_name = "unknown"; static char *sstrdup(const char *s, const char *dflt) { char *c; if (!s) return 0; c = strdup(s); return (char*) (c ? c : dflt); } void ulog_set_app_name(const char *name) { app_name = sstrdup(name, "out-of-memory"); } void ulog_set_path(const char *path) { ulog_path = sstrdup(path, 0); } int ulog_enabled(void) { return (ulog_path) ? 1 : 0; } void ulog_begin(void) { if (!ulog_path) return; if (ulog_sock == -1) { /* first-time user */ int u_family = AF_LOCAL; int u_sock = SOCK_DGRAM; gethostname(hn, sizeof(hn)); if (!strncmp(ulog_path, "udp://", 6) || !strncmp(ulog_path, "tcp://", 6)) { const char *c; u_family = AF_INET; if (ulog_path[0] == 't') u_sock = SOCK_STREAM; c = strchr(ulog_path + 6, ':'); ulog_port = DEFAULT_ULOG_PORT; if (c) { ulog_dcol = (int) (c - ulog_path); ulog_port = atoi(c + 1); if (ulog_port < 1) ulog_port = DEFAULT_ULOG_PORT; } /* FIXME: we don't resolve host names - only IPs are supported for now */ } #ifdef RSERV_DEBUG fprintf(stderr, "ULOG: begin %s %s port=%d\n", (u_family == AF_INET) ? "INET" : "UNIX", (u_sock == SOCK_DGRAM) ? "DGRAM" : "STREAM", ulog_port); #endif ulog_sock = socket(u_family, u_sock, 0); if (ulog_sock == -1) return; #if defined O_NONBLOCK && defined F_SETFL { /* try to use non-blocking socket where available */ int flags = fcntl(ulog_sock, F_GETFL, 0); if (flags != -1) fcntl(ulog_sock, F_SETFL, flags | O_NONBLOCK); } #endif } { struct tm *stm; time_t now = time(0); stm = gmtime(&now); strftime (ts, sizeof(ts), "%Y-%m-%dT%H:%M:%SZ", stm); #ifdef ULOG_MICROTIME { /* this is useful for profiling but breaks the syslog standard */ struct timeval tv; double t; gettimeofday(&tv, 0); t = ((double) tv.tv_sec) + (((double) tv.tv_usec) / 1000000.0); if (time0 < 1.0) timeN = time0 = t; snprintf(ts + strlen(ts), sizeof(ts), "[%.4f/%.4f]", t - time0, t - timeN); timeN = t; } #endif } /* FIXME: we could cache user/group/pid and show the former in textual form ... */ /* This format is compatible with the syslog format (RFC5424) with hard-coded facility (3) and severity (6) */ snprintf(buf, sizeof(buf), "<30>1 %s %s %s %ld %d/%d - ", ts, hn, app_name, (long) getpid(), (int) getuid(), (int) getgid()); buf_pos = strlen(buf); } void ulog_add(const char *format, ...) { va_list(ap); va_start(ap, format); if (buf_pos) { vsnprintf(buf + buf_pos, sizeof(buf) - buf_pos, format, ap); buf_pos += strlen(buf + buf_pos); } va_end(ap); } void ulog_end(void) { #if defined (RSERV_DEBUG) || defined (ULOG_STDERR) buf[buf_pos] = 0; fprintf(stderr, "ULOG: %s\n", buf); #endif if (ulog_sock != -1) { if (ulog_port) { struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(ulog_port); ulog_path[ulog_dcol] = 0; sa.sin_addr.s_addr = inet_addr(ulog_path + 6); ulog_path[ulog_dcol] = ':'; /* we probably don't even need this ... */ sendto(ulog_sock, buf, buf_pos, 0, (struct sockaddr*) &sa, sizeof(sa)); } else { struct sockaddr_un sa; if (!buf_pos) return; memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_LOCAL; strcpy(sa.sun_path, ulog_path); /* FIXME: check possible overflow? */ sendto(ulog_sock, buf, buf_pos, 0, (struct sockaddr*) &sa, sizeof(sa)); } } buf_pos = 0; } void ulog_reset(void) { if (ulog_sock != -1) close(ulog_sock); ulog_sock = -1; } void ulog(const char *format, ...) { va_list(ap); va_start(ap, format); ulog_begin(); #if defined (RSERV_DEBUG) || defined (ULOG_STDERR) /* in case ulog_begin did not start a line */ if (!buf_pos) { *buf = ' '; buf_pos = 1; } #endif if (buf_pos) { vsnprintf(buf + buf_pos, sizeof(buf) - buf_pos, format, ap); buf_pos += strlen(buf + buf_pos); ulog_end(); } va_end(ap); } #else void ulog_set_path(const char *path) { } void ulog_set_app_name(const char *name) { } void ulog_begin(void) {} void ulog_add(const char *format, ...) { } void ulog_end(void) {} void ulog(const char *format, ...) { } void ulog_reset(void) {} #endif Rserve/src/qap_decode.c0000644000175100001440000001720714531234224014564 0ustar hornikusers#include "qap_decode.h" #include #include #define decode_to_SEXP QAP_decode /* string encoding handling */ #if (R_VERSION < R_Version(2,8,0)) || (defined DISABLE_ENCODING) #define mkRChar(X) mkChar(X) #else #define USE_ENCODING 1 extern cetype_t string_encoding; #define mkRChar(X) mkCharCE((X), string_encoding) #endif /* this is only used in debugging output for down-casing pointers to long on Windows as intermediate step */ #ifdef WIN64 typedef unsigned long long temp_ptr_int_t; #else typedef unsigned long temp_ptr_int_t; #endif /* this is the representation of NAs in strings. We chose 0xff since that should never occur in UTF-8 strings. If 0xff occurs in the beginning of a string anyway, it will be doubled to avoid misrepresentation. */ static const unsigned char NaStringRepresentation[2] = { 255, 0 }; /* decode_toSEXP is used to decode SEXPs from binary form and create corresponding objects in R. UPC is a pointer to a counter of UNPROTECT calls which will be necessary after we're done. The buffer position is advanced to the point where the SEXP ends (more precisely it points to the next stored SEXP). */ SEXP decode_to_SEXP(unsigned int **buf) { unsigned int *b = *buf, *pab = *buf; char *c, *cc; SEXP val = 0, vatt = 0; int ty = PAR_TYPE(ptoi(*b)); rlen_t ln = PAR_LEN(ptoi(*b)); rlen_t i, l; if (IS_LARGE(ty)) { ty ^= XT_LARGE; b++; ln |= ((rlen_t) (unsigned int) ptoi(*b)) << 24; } #ifdef RSERV_DEBUG printf("decode: type=%d, len=%ld\n", ty, (long)ln); #endif b++; pab = b; /* pre-attr b */ if (ty & XT_HAS_ATTR) { #ifdef RSERV_DEBUG printf(" - has attributes\n"); #endif *buf = b; vatt = PROTECT(decode_to_SEXP(buf)); b = *buf; ty = ty ^ XT_HAS_ATTR; #ifdef RSERV_DEBUG printf(" - returned from attributes(@%p)\n", (void*)*buf); #endif ln -= (((char*)b) - ((char*)pab)); /* adjust length */ } /* b = beginning of the SEXP data (after attrs) pab = beginning before attrs (=just behind the heaer) ln = length of th SEX payload (w/o attr) */ switch(ty) { case XT_NULL: val = R_NilValue; *buf = b; break; case XT_INT: case XT_ARRAY_INT: l = ln / 4; val = allocVector(INTSXP, l); #ifdef NATIVE_COPY memcpy(INTEGER(val), b, l * sizeof(int)); b += l; #else i = 0; while (i < l) { INTEGER(val)[i] = ptoi(*b); i++; b++; } #endif *buf = b; break; case XT_ARRAY_BOOL: { int vl = ptoi(*(b++)); char *cb = (char*) b; val = allocVector(LGLSXP, vl); i = 0; while (i < vl) { LOGICAL(val)[i] = (cb[i] == 1) ? TRUE : ((cb[i] == 0) ? FALSE : NA_LOGICAL); i++; } while ((i & 3) != 0) i++; b = (unsigned int*) (cb + i); } *buf = b; break; case XT_DOUBLE: case XT_ARRAY_DOUBLE: l = ln / 8; val = allocVector(REALSXP, l); #ifdef NATIVE_COPY memcpy(REAL(val), b, sizeof(double) * l); b += l * 2; #else i = 0; while (i < l) { fixdcpy(REAL(val) + i, b); b += 2; i++; } #endif *buf = b; break; case XT_ARRAY_CPLX: l = ln / 16; val = allocVector(CPLXSXP, l); #ifdef NATIVE_COPY memcpy(COMPLEX(val), b, sizeof(Rcomplex) * l); b += l * 4; #else i = 0; while (i < l) { fixdcpy(&(COMPLEX(val)[i].r),b); b+=2; fixdcpy(&(COMPLEX(val)[i].i),b); b+=2; i++; } #endif *buf = b; break; case XT_ARRAY_STR: { /* count the number of elements */ char *sen = (c = (char*)(b)) + ln; i = 0; while (c < sen) { if (!*c) i++; c++; } /* protect so we can alloc CHARSXPs */ val = PROTECT(allocVector(STRSXP, i)); i = 0; cc = c = (char*)b; while (c < sen) { SEXP sx; if (!*c) { if ((unsigned char)cc[0] == NaStringRepresentation[0]) { if ((unsigned char)cc[1] == NaStringRepresentation[1]) sx = R_NaString; else sx = mkRChar(cc + 1); } else sx = mkRChar(cc); SET_STRING_ELT(val, i, sx); i++; cc = c + 1; } c++; } UNPROTECT(1); } *buf = (unsigned int*)((char*)b + ln); break; case XT_RAW: i = ptoi(*b); val = allocVector(RAWSXP, i); memcpy(RAW(val), (b + 1), i); *buf = (unsigned int*)((char*)b + ln); break; case XT_VECTOR: case XT_VECTOR_EXP: { unsigned char *ie = (unsigned char*) b + ln; rlen_t n = 0; SEXP vr = PROTECT(CONS(R_NilValue, R_NilValue)); SEXP tail = vr; *buf = b; while ((unsigned char*)*buf < ie) { SEXP v = decode_to_SEXP(buf); /* CONS() protects its arguments if GC is needed so v is safe */ SEXP ne = CONS(v, R_NilValue); SETCDR(tail, ne); tail = ne; n++; } #ifdef RSERV_DEBUG printf(" vector (%s), %ld elements\n", (ty == XT_VECTOR) ? "generic" : ((ty == XT_VECTOR_EXP) ? "expression" : "string"), (long) n); #endif val = PROTECT(allocVector((ty==XT_VECTOR) ? VECSXP : ((ty == XT_VECTOR_EXP) ? EXPRSXP : STRSXP), n)); n = 0; while (CDR(vr) != R_NilValue) { vr = CDR(vr); SET_VECTOR_ELT(val, n++, CAR(vr)); } #ifdef RSERV_DEBUG printf(" end of vector %lx/%lx\n", (unsigned long) ((temp_ptr_int_t) *buf), (unsigned long) ((temp_ptr_int_t) ie)); #endif UNPROTECT(2); /* val and vr */ break; } case XT_STR: case XT_SYMNAME: /* i=ptoi(*b); b++; */ #ifdef RSERV_DEBUG printf(" string/symbol(%d) '%s'\n", ty, (char*)b); #endif { char *c = (char*) b; if (ty == XT_STR) { val = mkRChar(c); } else val = install(c); } *buf = (unsigned int*)((char*)b + ln); break; case XT_S4: val = Rf_allocS4Object(); break; case XT_LIST_NOTAG: case XT_LIST_TAG: case XT_LANG_NOTAG: case XT_LANG_TAG: { SEXP vnext = R_NilValue, vtail = 0; unsigned char *ie = (unsigned char*) b + ln; val = R_NilValue; *buf = b; while ((unsigned char*)*buf < ie) { #ifdef RSERV_DEBUG printf(" el %08lx of %08lx\n", (unsigned long) ((temp_ptr_int_t) *buf), (unsigned long) ((temp_ptr_int_t) ie)); #endif SEXP el = PROTECT(decode_to_SEXP(buf)); SEXP ea = R_NilValue; if (ty == XT_LANG_TAG || ty==XT_LIST_TAG) { #ifdef RSERV_DEBUG printf(" tag %08lx of %08lx\n", (unsigned long) ((temp_ptr_int_t) *buf), (unsigned long) ((temp_ptr_int_t) ie)); #endif ea = decode_to_SEXP(buf); if (ea != R_NilValue) PROTECT(ea); } if (ty == XT_LANG_TAG || ty == XT_LANG_NOTAG) vnext = LCONS(el, R_NilValue); else vnext = CONS(el, R_NilValue); PROTECT(vnext); if (ea != R_NilValue) SET_TAG(vnext, ea); if (vtail) { SETCDR(vtail, vnext); UNPROTECT((ea == R_NilValue) ? 2 : 3); } else { UNPROTECT((ea == R_NilValue) ? 2 : 3); val = vnext; PROTECT(val); /* protect the root */ } vtail = vnext; } if (vtail) UNPROTECT(1); break; } default: REprintf("Rserve SEXP parsing: unsupported type %d\n", ty); val = R_NilValue; *buf = (unsigned int*)((char*)b + ln); } if (vatt) { /* if vatt contains "class" we have to set the object bit [we could use classgets(vec,kls) instead] */ SEXP head = vatt; int has_class = 0; PROTECT(val); SET_ATTRIB(val, vatt); while (head != R_NilValue) { if (TAG(head) == R_ClassSymbol) { has_class = 1; break; } head = CDR(head); } if (has_class) /* if it has a class slot, we have to set the object bit */ SET_OBJECT(val, 1); #ifdef SET_S4_OBJECT /* FIXME: we have currently no way of knowing whether an object derived from a non-S4 type is actually S4 object. Hence we can only flag "pure" S4 objects */ if (TYPEOF(val) == S4SXP) SET_S4_OBJECT(val); #endif UNPROTECT(2); /* vatt + val */ } /* NOTE: val is NOT protected - this guarantees that recursion doesn't fill up the stack */ return val; } Rserve/src/date.c0000644000175100001440000000753114531234224013414 0ustar hornikusers/* utilities to parse valid HTTP times and to generate RFC 822/1123 date (C)Copyright 2014,21 Simon Urbanek License: BSD */ /* -- interface -- */ char *posix2http(double ts); /* Note: returned buffer is static */ double http2posix(const char *c); /* -- implementation -- */ #include #include #include #include #include static const char *c_wkd[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char *c_mon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char date_buf[64]; char *posix2http(double ts) { time_t t = (time_t) ts; struct tm *tm = gmtime(&t); if (!tm) return 0; snprintf(date_buf, sizeof(date_buf), "%s, %02d %s %d %02d:%02d:%02d GMT", c_wkd[tm->tm_wday], tm->tm_mday, c_mon[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); return date_buf; } static int lookup(const char *c, const char **where, int n) { int i; for (i = 0; i < n; i++) if (!memcmp(c, where[i], 3)) return i; return -1; } static double parse_hms(const char **c_ptr) { int h,m,s; const char *c = *c_ptr; while (*c == ' ') c++; h = atoi(c); while (*c >= '0' && *c <= '9') c++; if (*c != ':') return -1.0; c++; m = atoi(c); while (*c >= '0' && *c <= '9') c++; if (*c != ':') return -1.0; c++; s = atoi(c); while (*c >= '0' && *c <= '9') c++; *c_ptr = c; return (double) (s + (m * 60) + (h *3600)); } /* start of each month in seconds */ static const int cml[] = { 0, 0, 2678400, 5097600, 7776000, 10368000, 13046400, 15638400, 18316800, 20995200, 23587200, 26265600, 28857600, 31536000 }; typedef int64_t time_int_t; static double day2posix(int day, int month, int year) { double ts; /* check input ranges */ if (year < 1970 || year > 2199 || month < 1 || month > 12 || day < 1 || day > 31) return 0.0; year -= 1970; /* adjust for all leap years prior to the current one */ ts = ((time_int_t)((year + 1) / 4)) * (time_int_t) 86400; if (year > 130) /* 2100 is an exception - not a leap year */ ts -= 86400; ts += ((time_int_t) year) * ((time_int_t) 31536000); /* month */ ts += cml[month]; if (month > 2 && (year & 3) == 2 && year != 130 /* 2100 again */) ts += 86400; /* day */ ts += (day - 1) * 86400; return ts; } double http2posix(const char *c) { int mon, day, year; double hms; /* skip weekday */ while (*c && *c != ' ') c++; if (!*c) return 0.0; while (*c == ' ') c++; /* this is now one of "01-Jan 2000", "01-Jan-00" or "Jan 1" */ if (*c < '0' || *c > '9') { /* non-digit so it's either asctime() or invalid */ if ((mon = lookup(c, c_mon, 12)) < 0) return 0.0; mon++; while (*c && *c != ' ') c++; while (*c == ' ') c++; if (!*c) return 0.0; day = atoi(c); while (*c && *c != ' ') c++; if (!*c) return 0.0; if ((hms = parse_hms(&c)) < 0.0) return 0.0; while (*c == ' ') c++; if (!*c) return 0.0; year = atoi(c); } else { /* RFC 822/1123 or RFC 850/1036 - both can be parsed the same way if we ignore the the difference between ' ' and '-' and adjust year */ day = atoi(c); while (*c >= '0' && *c <= '9') c++; while (*c == '-' || *c ==' ') c++; if ((mon = lookup(c, c_mon, 12)) < 0) return 0.0; mon++; while (*c && (*c < '0' || *c > '9')) c++; if (!*c) return 0.0; year = atoi(c); /* RFC 850/1036 doesn't say how to interpret two-digit years, so we assume 70..99 are 1970..1999 and 00..69 are 2000..2069 */ if (year < 70) year += 2000; else if (year < 100) year += 1900; while (*c && *c != ' ') c++; if (!*c || (hms = parse_hms(&c)) < 0.0) return 0.0; } /* ok, we got hms and day/month/year - assemble it to POSIX */ return hms + day2posix(day, mon, year); } Rserve/src/ioc.c0000644000175100001440000001221514531234224013244 0ustar hornikusers/* threaded buffering of stdout/err to pass back to a synchronous process (C)Copyright 2014 Simon Urbanek License any of: BSD, GPL-2, GPL-3 */ #ifndef NO_CONFIG_H #include "config.h" #endif #if defined WITH_THREADS || ! defined WIN32 #include #include #include #include #include #include static int stdoutFD, stderrFD, triggerFD; static volatile unsigned int head, tail; static unsigned int alloc; static char *buf; static volatile int ioc_active = 0; pthread_mutex_t buffer_mux = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t trigger_mux = PTHREAD_MUTEX_INITIALIZER; void ulog(const char *format, ...); static void *feed_thread(void *whichFD) { int ta = 1024*1024, fd = stdoutFD; char *thb = (char*) malloc(ta + 8); unsigned int *h = (unsigned int*) thb, mask = 0; if (!thb) return 0; if (whichFD == &stderrFD) { fd = stderrFD; mask = 0x80000000; } ulog("feed_thread started, mask=0x%x\n", mask); while (ioc_active) { int n = read(fd, thb + 4, ta), dst; ulog("feed_thread n = %d\n", n); if (n == -1 && errno != EINTR) break; pthread_mutex_lock(&buffer_mux); dst = tail; tail = (tail + n + 4) & (alloc - 1); *h = n | mask; n += 4; if (tail < dst) { memcpy(buf + dst, thb, alloc - dst); n -= alloc - dst; memcpy(buf, thb + alloc - dst, n); } else memcpy(buf + dst, thb, n); ulog("feed_thread: tail = %d\n", tail); pthread_mutex_unlock(&buffer_mux); pthread_mutex_unlock(&trigger_mux); } close(fd); return 0; } static void *read_thread(void *dummy) { ulog("read_thread started\n"); while (ioc_active) { volatile int head0, tail0; /* lock just to get a consistent state */ pthread_mutex_lock(&buffer_mux); head0 = head; tail0 = tail; pthread_mutex_unlock(&buffer_mux); /* if there is nothing to do, lock so we get notified */ if (head0 == tail0) { pthread_mutex_lock(&trigger_mux); continue; } ulog("read_thread: [%d/%d]\n", head0, tail0); if (head0 > tail0) { while (head0 < alloc) { int n = write(triggerFD, buf + head0, alloc - head0); if (n > 0 && n < alloc - head0) { pthread_mutex_lock(&buffer_mux); head0 += n; if (head0 >= alloc) head0 -= alloc; head = head0; pthread_mutex_unlock(&buffer_mux); continue; } if (n < 0 && errno != EINTR) { ulog("ERROR: lost output pipe, aborting\n"); close(triggerFD); return 0; } } head0 = 0; } while (head0 < tail0) { int n = write(triggerFD, buf + head0, tail0 - head0); if (n > 0 && n < tail0 - head0) { pthread_mutex_lock(&buffer_mux); head0 += n; head = head0; pthread_mutex_unlock(&buffer_mux); continue; } if (n < 0 && errno != EINTR) { ulog("ERROR: lost output pipe, aborting\n"); close(triggerFD); return 0; } head0 += n; } pthread_mutex_lock(&buffer_mux); head = tail0; pthread_mutex_unlock(&buffer_mux); /* we don't unlock the trigger mutex since that's how the feed threads wake us up */ } return 0; } #include static int readFD; /* on fork() remove all forwarding from the children */ static void atfork_prepare(void) { } static void atfork_parent(void) { } static void atfork_child(void) { ioc_active = 0; close(stdoutFD); close(stderrFD); close(triggerFD); } int ioc_setup(void) { int pfd[2]; pthread_t thread; pthread_attr_t thread_attr; alloc = 1024*1024; buf = malloc(alloc); if (!buf) Rf_error("cannot allocate buffer"); if (pipe(pfd)) return 0; dup2(pfd[1], STDOUT_FILENO); close(pfd[1]); stdoutFD = pfd[0]; if (pipe(pfd)) return 0; dup2(pfd[1], STDERR_FILENO); close(pfd[1]); stderrFD = pfd[0]; if (pipe(pfd)) return 0; triggerFD = pfd[1]; ioc_active = 1; pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); pthread_create(&thread, &thread_attr, feed_thread, &stdoutFD); #if defined RSERV_DEBUG || defined ULOG_STDERR ulog("NOTE: cannot forward stderr in debug builds since it would cause infinite recursion"); #else pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); pthread_create(&thread, &thread_attr, feed_thread, &stderrFD); #endif pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); pthread_create(&thread, &thread_attr, read_thread, 0); pthread_atfork(atfork_prepare, atfork_parent, atfork_child); ulog("setup done, fd = %d\n", pfd[0]); return (readFD = pfd[0]); } SEXP ioc_read(int *type) { SEXP res; unsigned int h; int n = read(readFD, &h, sizeof(h)); if (n != sizeof(h)) Rf_error("failed to read header"); ulog("header = 0x%x\n", h); if (type) type[0] = (h & 0x80000000) ? 1 : 0; h &= 0x7fffffff; res = Rf_allocVector(RAWSXP, h); n = read(readFD, RAW(res), h); if (n != h) Rf_error("read error (n=%d)", n); return res; } #else #include int ioc_setup(void) { return 0; } SEXP ioc_read(int *type) { Rf_error("I/O redirection or threads not supported on this platform"); return R_NilValue; } #endif Rserve/src/RSserver.c0000644000175100001440000001254214531234224014250 0ustar hornikusers#include "RSserver.h" #include "rserr.h" #define SOCK_ERRORS #ifndef LISTENQ #define LISTENQ 32 #endif #include #ifdef unix #include /* needed for unix sockets */ #endif #include #include /* AF_LOCAL is the POSIX version of AF_UNIX - we need this e.g. for AIX */ #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif /* keep track of all bound server sockets so they can be easily all closed after fork this is important for two reasons: so ports don't get stuck bound after the server has been shut down but children are still around, and so that a rogue child cannot impersonate the server after the server has been shut down (since the port may have been bound at higher privileges than the child may have at this point) */ #define MAX_SRVS 512 static int active_srv_sockets[MAX_SRVS]; static void add_active_srv_socket(int s) { int i = 0; while (active_srv_sockets[i] && i < MAX_SRVS) { if (active_srv_sockets[i] == s) return; i++; } if (i < MAX_SRVS) active_srv_sockets[i] = s; } static void rm_active_srv_socket(int s) { int i = 0; while (i < MAX_SRVS) { if (active_srv_sockets[i] == s) { active_srv_sockets[i] = 0; break; } i++; } } /* this is typically used after fork in the child process */ void close_all_srv_sockets(void) { int i = 0; while (i < MAX_SRVS) { if (active_srv_sockets[i]) closesocket(active_srv_sockets[i]); i++; } } /* provides client socket from accept() to the server so that it can modify the socket as needed according to the server flags */ void accepted_server(server_t *srv, int cs) { #ifdef SO_KEEPALIVE /* if keep-alive is enabled and supported - try to set it */ if (srv->flags & SRV_KEEPALIVE) { int ka = 1; setsockopt(cs, SOL_SOCKET, SO_KEEPALIVE, (const char *) &ka, sizeof(ka)); } #endif } server_t *create_server(int port, const char *localSocketName, int localSocketMode, int flags) { server_t *srv; SAIN ssa; int reuse, ss; #ifdef HAVE_IPV6 struct sockaddr_in6 ssa6; #endif #ifdef unix struct sockaddr_un lusa; #endif #ifdef RSERV_DEBUG printf(" - create_server(port = %d, socket = %s, mode = %d, flags = 0x%x)\n", port, localSocketName ? localSocketName : "", localSocketMode, flags); #endif initsocks(); if (localSocketName) { #ifndef unix RSEprintf("ERROR: Local sockets are not supported on non-unix systems.\n"); return 0; #else ss = FCF("open socket", socket(AF_LOCAL, SOCK_STREAM, 0)); memset(&lusa, 0, sizeof(lusa)); lusa.sun_family = AF_LOCAL; if (strlen(localSocketName) > sizeof(lusa.sun_path) - 2) { RSEprintf("ERROR: Local socket name is too long for this system.\n"); return 0; } strcpy(lusa.sun_path, localSocketName); remove(localSocketName); /* remove existing if possible */ #endif } else #ifdef HAVE_IPV6 ss = FCF("open socket", socket((flags & SRV_IPV6) ? AF_INET6 : AF_INET, SOCK_STREAM, 0)); #else ss = FCF("open socket", socket(AF_INET, SOCK_STREAM, 0)); #endif srv = (server_t*) calloc(1, sizeof(server_t)); if (!srv) { RSEprintf("ERROR: cannot allocate memory for server structure\n"); return 0; } srv->ss = ss; srv->unix_socket = localSocketName ? 1 : 0; srv->flags = flags; srv->parent = 0; reuse = 1; /* enable socket address reusage */ setsockopt(ss, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)); #ifdef unix if (localSocketName) { FCF("bind", bind(ss, (SA*) &lusa, sizeof(lusa))); if (localSocketMode) chmod(localSocketName, localSocketMode); } else { #endif #ifdef HAVE_IPV6 if (flags & SRV_IPV6) { memset(&ssa6, 0, sizeof(ssa6)); ssa6.sin6_family = AF_INET6; ssa6.sin6_port = htons(port); ssa6.sin6_addr = (flags & SRV_LOCAL) ? in6addr_loopback : in6addr_any; FCF("bind", bind(ss, (struct sockaddr*) &ssa6, sizeof(ssa6))); } else { #endif memset(&ssa, 0, sizeof(ssa)); ssa.sin_family = AF_INET; ssa.sin_port = htons(port); ssa.sin_addr.s_addr = htonl((flags & SRV_LOCAL) ? INADDR_LOOPBACK : INADDR_ANY); FCF("bind", bind(ss, (struct sockaddr*) &ssa, sizeof(ssa))); #ifdef HAVE_IPV6 } /* if (flags & SRV_IPV6) else */ #endif #ifdef unix } /* if (localSocketName) else */ #endif add_active_srv_socket(ss); FCF("listen", listen(ss, LISTENQ)); return srv; } void server_fin(void *x) { server_t *srv = (server_t*) x; if (srv) { closesocket(srv->ss); if (srv->ss != -1) rm_active_srv_socket(srv->ss); } } #define NSPS 16 struct server_stack { server_stack_t *prev, *next; int ns; server_t *srv[NSPS]; }; server_stack_t* create_server_stack(void) { server_stack_t *s = (server_stack_t*) malloc(sizeof(server_stack_t)); s->prev = s->next = 0; s->ns = 0; return s; } void push_server(server_stack_t *s, server_t *srv) { while (s->ns >= NSPS && s->next) s = s->next; if (s->ns >= NSPS) { server_stack_t *ns = create_server_stack(); ns->prev = s; s = s->next = ns; } s->srv[s->ns++] = srv; } void release_server_stack(server_stack_t *s) { while (s && s->next) s = s->next; while (s) { int i = s->ns; while (i-- > 0) { rm_server(s->srv[i]); free(s->srv[i]); } s->ns = 0; s = s->prev; } } int server_stack_size(server_stack_t *s) { int n = 0; while (s) { n += s->ns; s = s->next; } return n; } /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/utils.c0000644000175100001440000001315014531234224013631 0ustar hornikusers#define USE_RINTERNALS 1 #include #include #include /* string encoding handling */ #if (R_VERSION < R_Version(2,8,0)) || (defined DISABLE_ENCODING) #define mkRChar(X) mkChar(X) #else #define USE_ENCODING 1 /* in Rserv.c */ extern cetype_t string_encoding; /* default is native */ #define mkRChar(X) mkCharCE((X), string_encoding) #endif extern Rboolean R_Visible; /* this is really convoluted - we want to be guaranteed to not leave the call on one hand, but on the other hand R_ToplevelExec() removes the context which also removes the traceback. So the trick is to use R_ExecWithCleanup() to add another layer where we stash the traceback before R_ToplevelExec() blows it away. It would be really just one extra line in R sources, but what can you do ... R_ToplevelExec(Rserve_eval_) -> R_ExecWithCleanup(Rserve_eval_do -> eval) */ typedef struct rs_eval { SEXP what, rho, ctx_obj, last, traceback, handlers; int exp; } rs_eval_t; static SEXP last_condition; SEXP Rserve_set_last_condition(SEXP sCond) { if (last_condition && last_condition != R_NilValue) R_ReleaseObject(last_condition); if (!sCond || sCond == R_NilValue) last_condition = 0; else { last_condition = sCond; R_PreserveObject(last_condition); } return R_NilValue; } static SEXP Rserve_eval_do(void *arg) { rs_eval_t *e = (rs_eval_t*) arg; SEXP what = e->what, rho = e->rho, x; int i, n; /* add calling handlers to catch error conditions so we can report them - see #154 */ if (e->handlers) { SEXP sInternal = Rf_install(".Internal"); SEXP addCondHands = Rf_install(".addCondHands"); SEXP ach = PROTECT(lang2(sInternal, lang6(addCondHands, Rf_getAttrib(e->handlers, R_NamesSymbol), e->handlers, rho, R_NilValue, PROTECT(Rf_ScalarLogical(1))))); eval(ach, rho); UNPROTECT(2); } if (TYPEOF(what) == EXPRSXP) { n = LENGTH(what); for (i = 0; i < n; i++) { e->exp = i; x = eval(VECTOR_ELT(what, i), rho); if (i == n - 1) { R_PreserveObject(x); e->last = x; } if (R_Visible) PrintValue(x); } } else { e->exp = -1; x = eval(what, rho); R_PreserveObject(x); /* intentionally we don't print if it is not an expression vector */ e->last = x; } return R_NilValue; } /* it's really stupid becasue R has R_GetTraceback() but we have to jump through eval() just because it's hidden so we can't access it ... */ static SEXP R_GetTraceback(int skip) { SEXP d_int = install(".Internal"), tb = install("traceback"), sSkip = PROTECT(ScalarInteger(skip)); SEXP what = PROTECT(lang2(d_int, lang2(tb, sSkip))); SEXP res = eval(what, R_GlobalEnv); UNPROTECT(2); return res; } static void Rserve_eval_cleanup(void *arg) { rs_eval_t *e = (rs_eval_t*) arg; SEXP tb = R_GetTraceback(0); if (tb && tb != R_NilValue) R_PreserveObject((e->traceback = tb)); } static void Rserve_eval_(void *arg) { R_ExecWithCleanup(Rserve_eval_do, arg, Rserve_eval_cleanup, arg); } static SEXP RS_current_context; static int RS_current_context_is_protected; SEXP Rserve_get_context(void) { return RS_current_context ? RS_current_context : R_NilValue; } SEXP Rserve_set_context(SEXP sObj) { if (!sObj) sObj = R_NilValue; if (RS_current_context == sObj) return sObj; if (RS_current_context != R_NilValue && RS_current_context_is_protected) R_ReleaseObject(RS_current_context); RS_current_context = sObj; RS_current_context_is_protected = 0; if (RS_current_context != R_NilValue) { R_PreserveObject(RS_current_context); RS_current_context_is_protected = 1; } return RS_current_context; } SEXP Rserve_eval(SEXP what, SEXP rho, SEXP retLast, SEXP retExp, SEXP ctxObj, SEXP sHandlers) { int need_last = asInteger(retLast), exp_value = asInteger(retExp); rs_eval_t e = { what, rho, 0, 0, 0, 0, 0 }; SEXP saved_context = RS_current_context; int saved_context_is_protected = RS_current_context_is_protected; if (ctxObj != R_NilValue) { RS_current_context = ctxObj; /* this is transient so no protection */ RS_current_context_is_protected = 0; } e.ctx_obj = RS_current_context; if (sHandlers != R_NilValue) e.handlers = sHandlers; Rserve_set_last_condition(0); if (!R_ToplevelExec(Rserve_eval_, &e)) { RS_current_context = saved_context; RS_current_context_is_protected = saved_context_is_protected; SEXP res = PROTECT(mkNamed(VECSXP, (const char*[]) { "error", "traceback", "expression", "context", "condition", "" })); SET_VECTOR_ELT(res, 1, e.traceback ? e.traceback : R_NilValue); const char *errmsg = R_curErrorBuf(); SET_VECTOR_ELT(res, 0, errmsg ? mkString(errmsg) : R_NilValue); if (exp_value) SET_VECTOR_ELT(res, 2, (e.exp == -1) ? what : VECTOR_ELT(what, e.exp)); else SET_VECTOR_ELT(res, 2, ScalarInteger(e.exp < 0 ? NA_INTEGER : (e.exp + 1))); SET_VECTOR_ELT(res, 3, e.ctx_obj ? e.ctx_obj : R_NilValue); SET_VECTOR_ELT(res, 4, last_condition ? last_condition : R_NilValue); setAttrib(res, R_ClassSymbol, mkString("Rserve-eval-error")); UNPROTECT(1); return res; } RS_current_context = saved_context; RS_current_context_is_protected = saved_context_is_protected; if (need_last) { if (e.last) { R_ReleaseObject(e.last); return e.last; } return R_NilValue; } return ScalarLogical(TRUE); } Rserve/src/include/0000755000175100001440000000000014531234224013750 5ustar hornikusersRserve/src/include/Win32/0000755000175100001440000000000014531234224014652 5ustar hornikusersRserve/src/include/Win32/config.h0000644000175100001440000000344014531234224016271 0ustar hornikusers/* config.h for Windows This file is based on a config.h as generated by configure run on a MinGW gcc system. Most of it is not used, because many parts of Rserve have its own Win32 code, but it may become handy at some later point. Last update: Rserve 0.4-5, R 2.4.0, MinGW gcc 3.4.5 */ /* Defined if the platform is little-endian */ #define BS_LITTLE_ENDIAN 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #define HAVE_MALLOC 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the `memset' function. */ #define HAVE_MEMSET 1 /* Define to 1 if you have the `mkdir' function. */ #define HAVE_MKDIR 1 /* Define to 1 if you have the `rmdir' function. */ #define HAVE_RMDIR 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to 1 if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* CRAN has OpenSSL so we can use TLS */ #define HAVE_TLS 1 Rserve/src/include/Win32/Startup.h0000644000175100001440000000547414531234224016477 0ustar hornikusers/* * R : A Computer Language for Statistical Data Analysis * Copyright (C) 1999-2003 The R Development Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef STARTUP_H_ #define STARTUP_H_ #include /* TRUE/FALSE */ #ifdef Win32 typedef int (*blah1) (char *, char *, int, int); typedef void (*blah2) (char *, int); typedef void (*blah3) (); typedef void (*blah4) (char *); typedef int (*blah5) (char *); typedef void (*blah6) (int); typedef enum {RGui, RTerm, LinkDLL} UImode; #endif /* Startup Actions */ typedef enum { SA_NORESTORE,/* = 0 */ SA_RESTORE, SA_DEFAULT,/* was === SA_RESTORE */ SA_NOSAVE, SA_SAVE, SA_SAVEASK, SA_SUICIDE } SA_TYPE; typedef struct { Rboolean R_Quiet; Rboolean R_Slave; Rboolean R_Interactive; Rboolean R_Verbose; Rboolean LoadSiteFile; Rboolean LoadInitFile; Rboolean DebugInitFile; SA_TYPE RestoreAction; SA_TYPE SaveAction; unsigned long vsize; unsigned long nsize; unsigned long max_vsize; unsigned long max_nsize; unsigned long ppsize; int NoRenviron; /* Permanent copy of the command line arguments and the number of them passed to the application. These are populated via the routine R_set_command_line_arguments() called from R_common_command_line(). */ int NumCommandLineArgs; char **CommandLineArgs; #ifdef Win32 char *rhome; /* R_HOME */ char *home; /* HOME */ blah1 ReadConsole; blah2 WriteConsole; blah3 CallBack; blah4 message; blah5 yesnocancel; blah6 busy; UImode CharacterMode; Rboolean DebugMenuitem; #endif } structRstart; typedef structRstart *Rstart; void R_DefParams(Rstart); void R_SetParams(Rstart); void R_SetWin32(Rstart); void R_SizeFromEnv(Rstart); void R_common_command_line(int *, char **, Rstart); void R_set_command_line_arguments(int argc, char **argv, Rstart Rp); void setup_Rmainloop(void); /* originally from Defn.h : */ void R_CleanUp(SA_TYPE, int, int); void R_StartUp(void); FILE *R_OpenInitFile(void); FILE *R_OpenSysInitFile(void); FILE *R_OpenSiteFile(void); #endif Rserve/src/include/Win32/psignal.h0000644000175100001440000001410014531234224016454 0ustar hornikusers/***************************************************************************** * * * signal.h * * * * Freely redistributable and modifiable. Use at your own risk. * * * * Copyright 1994-1999 The Downhill Project * * http://www.ede.com/free/u2nt * * * *****************************************************************************/ /* Original version taken at Changes (g.m.): 10.06.1999: Made self contained - Changed some names 11.06.1999: Added 'sigsetjmp' and 'siglongjmp' 12.06.1999: Added pause and sigsuspend (require a version (also a non POSIX one) of sleep; if your system don't have it define DONT_HAVE_SLEEP) 27/06/1999: (BDR) convert sigsetjmp and siglongjmp macros to (,,) 12/07/1999: (BDR) fix sigsetjmp macro to set saved_mask */ #ifndef _PSIGNAL_H_ #define _PSIGNAL_H_ #include #include #include #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt */ #define SIGQUIT 3 /* quit */ #define SIGILL 4 /* illegal instruction (not reset when caught) */ #define SIGTRAP 5 /* trace trap (not reset when caught) */ #define SIGEMT 7 /* EMT instruction */ #define SIGFPE 8 /* floating point exception */ #define SIGKILL 9 /* kill (cannot be caught or ignored) */ #define SIGBUS 10 /* bus error */ #define SIGSEGV 11 /* segmentation violation */ #define SIGSYS 12 /* bad argument to system call */ #define SIGPIPE 13 /* write on a pipe with no one to read it */ #define SIGALRM 14 /* alarm clock */ #define SIGTERM 15 /* software termination signal from kill */ #define SIGURG 16 /* urgent condition on IO channel */ #define SIGSTOP 17 /* sendable stop signal not from tty */ #define SIGTSTP 18 /* stop signal from tty */ #define SIGCONT 19 /* continue a stopped process */ #define SIGCHLD 20 /* to parent on child stop or exit */ #define SIGCLD 20 /* System V name for SIGCHLD */ #define SIGBREAK 21 /* to readers pgrp upon background tty read */ #define SIGABRT 22 /* used by abort */ #define SIGIO 23 /* input/output possible signal */ #define SIGPOLL SIGIO /* System V name for SIGIO */ #define SIGXCPU 24 /* exceeded CPU time limit */ #define SIGXFSZ 25 /* exceeded file size limit */ #define SIGVTALRM 26 /* virtual time alarm */ #define SIGPROF 27 /* profiling time alarm */ #define SIGWINCH 28 /* window changed */ #define SIGLOST 29 /* resource lost (eg, record-lock lost) */ #define SIGUSR1 30 /* user defined signal 1 */ #define SIGUSR2 31 /* user defined signal 2 */ #define NSIG 32 /* signal 0 implied */ #ifndef RC_INVOKED /* * A pointer to a signal handler function. A signal handler takes a * single int, which is the signal it handles. */ typedef void (*sighandler_t)(int nSig); #ifndef _SIGSET_T_ #define _SIGSET_T_ typedef int sigset_t; #endif /* Not _SIGSET_T_ */ /* * These are special values of signal handler pointers which are * used to send a signal to the default handler (SIG_DFL), ignore * the signal (SIG_IGN), or indicate an error return (SIG_ERR). */ #define SIG_DFL ((sighandler_t) 0) #define SIG_IGN ((sighandler_t) 1) #define SIG_ERR ((sighandler_t) -1) #ifdef __cplusplus extern "C" { #endif /* Signal mask actions ===================================================== */ #define SIG_BLOCK 0 #define SIG_UNBLOCK 1 #define SIG_SETMASK 2 /* Signal flag actions ===================================================== */ #define SA_NOCLDSTOP 1 #define SA_RESETHAND 2 /* Struct stuff **************************************************************/struct sigaction { void (*sa_handler)(int); sigset_t sa_mask; int sa_flags; }; typedef struct { jmp_buf jmpbuf; /* Calling environment. */ int mask_was_saved; /* Saved the signal mask? */ sigset_t saved_mask; /* Saved signal mask. */ } sigjmp_buf[1]; /* Prototype stuff ***********************************************************/ unsigned long sigsetmask(unsigned long signal_Block_MaskNew); unsigned long sigblock(unsigned long signal_Block_MaskNew); int sighold(int signal_Number); int sigrelse(int signal_Number); int sigaction(int signal_Number,struct sigaction* sigaction_Info, struct sigaction* signaction_InfoOld); int sigaddset(sigset_t* sigset_Info,int signal_Number); int sigdelset(sigset_t* sigset_Info,int signal_Number); int sigemptyset(sigset_t* sigset_Info); int sigfillset(sigset_t* sigset_Info); int sigismember(sigset_t* sigset_Info,int signal_Number); int sigpending(sigset_t* sigset_Info); int sigprocmask(int mask_Function,sigset_t* sigset_Info, sigset_t* sigset_InfoOld); sighandler_t signal(int signal_Number, sighandler_t); void raise(int); int pause(void); int sigsuspend(sigset_t* sigset_Info); /* Re-mapped functions ===================================================== */ #define sigmask(signal_Index) (1<<(signal_Index-1)) /* This must be a macro, since we want setjmp working in the calling environment */ /* #define sigsetjmp(jb, sm) (\ sm?sigprocmask(SIG_SETMASK,NULL,&jb->saved_mask):0,\ jb->mask_was_saved=sm,\ setjmp(jb->jmpbuf)) we only currently use the case sm=0, so avoid compiler warnings by */ #define sigsetjmp(jb, sm) (jb->mask_was_saved=0, setjmp(jb->jmpbuf)) /* We can transform this in a function but ... */ #define siglongjmp(jb, val) (((jb->mask_was_saved)?\ sigprocmask(SIG_SETMASK, &jb->saved_mask, 0):0),\ longjmp(jb->jmpbuf, val)) #ifdef __cplusplus } #endif #endif /* Not RC_INVOKED */ #endif /* Not _PSIGNAL_H_ */ Rserve/src/include/sbthread.h0000644000175100001440000000653514531234224015726 0ustar hornikusers/*****************************************************************\ * sbthread - system-independent basic threads * * (C)Copyright 2001 Simon Urbanek * *---------------------------------------------------------------* * Supported platforms: unix w pthread, Win32 * \*****************************************************************/ #ifndef __SBTHREAD_H__ #define __SBTHREAD_H__ #ifdef unix /* begin unix (pthread) implementation */ #include #define decl_sbthread void * #define sbthread_result(A) (void *)(A) #define sbthread_mutex pthread_mutex_t sbthread_mutex *sbthread_create_mutex() { pthread_mutex_t lm=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t *m=(pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); memcpy(m,&lm,sizeof(pthread_mutex_t)); return m; }; #define sbthread_lock_mutex(M) pthread_mutex_lock(M); #define sbthread_unlock_mutex(M) pthread_mutex_unlock(M); void sbthread_destroy_mutex(sbthread_mutex *m) { pthread_mutex_destroy(m); free(m); }; int sbthread_create(void * (thr)(void *), void *par) { pthread_t Thread; pthread_attr_t ThreadAttr; pthread_attr_init(&ThreadAttr); pthread_attr_setdetachstate(&ThreadAttr,PTHREAD_CREATE_DETACHED); return pthread_create(&Thread,&ThreadAttr,*thr,par); }; #else /* end of unix, begin of Win32 */ #include #define decl_sbthread DWORD WINAPI #define sbthread_result(A) (DWORD)(A) #define sbthread_mutex char #ifndef sleep /* this has nothing to do with threads, but may be usefull */ #define sleep(A) Sleep((A)*1000) #endif unsigned int sbthread_mutex_counter=1; sbthread_mutex *sbthread_create_mutex(void) { char mtxn[64],*c; unsigned int i,j; HANDLE m; strcpy(mtxn,"sbthread_mutex"); /* this isn't really thread-safe, but creating more mutexes at exactly the same time by different threads on an SMP machine is ... let's say inprobable. moreover ++ might be atomic. creating yet another mutex for this single operation seems to me as an overkill. but if you need 100% thread-safe code, feel free to implement it here ;) */ sbthread_mutex_counter++; i=15; j=sbthread_mutex_counter; while (j>0) { mtxn[i]=65+(j&15); i++; j>>=4; }; mtxn[i]=0; i++; m=CreateMutex(0,0,mtxn); if (!m) return 0; memcpy(&mtxn[i],&m,sizeof(m)); i+=sizeof(m)*2+1; c=(char*)malloc(i); memcpy(c,mtxn,i); /* content: name\0[createHANDLE][ownershipHANDLE] */ return c; }; int sbthread_lock_mutex(sbthread_mutex *m) { HANDLE h; int i; h=OpenMutex(MUTEX_ALL_ACCESS,0,m); if (!h) return 0; if (WaitForSingleObject(h,INFINITE)==WAIT_FAILED) return 0; i=strlen(m); i+=sizeof(h)+1; memcpy(&m[i],&h,sizeof(h)); return 1; }; int sbthread_unlock_mutex(sbthread_mutex *m) { HANDLE h; int i; i=strlen(m); i+=sizeof(h)+1; memcpy(&h,&m[i],sizeof(h)); if (!h) return 0; memset(&m[i],0,sizeof(h)); ReleaseMutex(h); CloseHandle(h); return 1; }; void sbthread_destroy_mutex(sbthread_mutex *m) { HANDLE h; int i; i=strlen(m); i+=sizeof(h)+1; memcpy(&h,&m[i],sizeof(h)); if (h) return; // oh, mutex is still in use memcpy(&h,&m[i-sizeof(h)],sizeof(h)); CloseHandle(h); free(m); }; int sbthread_create(LPTHREAD_START_ROUTINE sa, void *par) { DWORD tid; return CreateThread(0,0,sa,par,0,&tid); }; #endif /* Windows implementation */ #endif /* __SBTHREAD_H__ */ Rserve/src/include/Parse.h0000644000175100001440000000047414531234224015200 0ustar hornikusers/* This is a fall-back for R versions that don't have R_ext/Parse.h (R versions before 2.1.0) */ #ifndef R_EXT_PARSE_H_ #define R_EXT_PARSE_H_ typedef enum { PARSE_NULL, PARSE_OK, PARSE_INCOMPLETE, PARSE_ERROR, PARSE_EOF } ParseStatus; SEXP R_ParseVector(SEXP, int, ParseStatus *); #endif Rserve/src/include/sisocks.h0000644000175100001440000001706114531234224015604 0ustar hornikusers/* system independent sockets (basically for unix and Win) * Copyright (C) 2000,1 Simon Urbanek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; version 2.1 of the License * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * conditional defines: MAIN should be defined in just one file that will contain the fn definitions and variables USE_SNPRINTF emulate snprintf on Win platforms (you will lose the security which is provided under unix of course) SOCK_ERRORS include error code handling and checking functions */ #ifndef __SISOCKS_H__ #define __SISOCKS_H__ #if defined __GNUC__ && !defined unix && !defined Win32 /* MacOS X hack (gcc on any platform should behave as unix - except for Win32, where we need to keep using winsock) */ #define unix #endif #if defined STANDALONE_RSERVE && defined RSERVE_PKG #undef RSERVE_PKG #endif #if defined SOCK_ERRORS || defined USE_SNPRINTF #include #endif #include #ifdef unix #include #include #include #include #include #include #include #define sockerrno errno #define SOCKET int #define INVALID_SOCKET (-1) #define closesocket(A) close(A) #else #define windows #include #include #include #include #define inet_aton(A,B) (0, B.s_addr=inet_addr(A)) #define sockerrno WSAGetLastError() #ifndef ECONNREFUSED #define ECONNREFUSED WSAECONNREFUSED #endif #ifndef EADDRINUSE #define EADDRINUSE WSAEADDRINUSE #endif #ifndef ENOTSOCK #define ENOTSOCK WSAENOTSOCK #endif #ifndef EISCONN #define EISCONN WSAEISCONN #endif #ifndef ETIMEDOUT #define ETIMEDOUT WSAETIMEDOUT #endif #ifndef ENETUNREACH #define ENETUNREACH WSAENETUNREACH #endif #ifndef EINPROGRESS #define EINPROGRESS WSAEINPROGRESS #endif #ifndef EALREADY #define EALREADY WSAEALREADY #endif #ifndef EOPNOTSUPP #define EOPNOTSUPP WSAEOPNOTSUPP #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK #endif #ifndef WIN64 #ifndef EAFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #endif #ifndef EBADF #define EBADF WSAEBADF #endif #ifndef EINVAL #define EINVAL WSAEINVAL #endif #ifndef EFAULT #define EFAULT WSAEFAULT #endif #ifndef EACCES #define EACCES WSAEACCES #endif #endif #ifdef USE_SNPRINTF #ifdef MAIN int snprintf(char *buf, int len, char *fmt, ...) { va_list argptr; int cnt; va_start(argptr, fmt); cnt = vsprintf(buf, fmt, argptr); va_end(argptr); return(cnt); } #else extern int snprintf(char *buf, int len, char *fmt, ...); #endif #endif #endif #define SA struct sockaddr #define SAIN struct sockaddr_in #ifdef windows #ifdef MAIN int initsocks(void) { WSADATA dt; /* initialize WinSock 1.1 */ return (WSAStartup(0x0101,&dt))?-1:0; } #else extern int initsocks(void); #endif #define donesocks() WSACleanup() #else /* no stupid stuff necessary for unix */ #define initsocks() #define donesocks() #endif #ifdef SOCK_ERRORS #ifdef MAIN int suppmode=0; int socklasterr; FILE *sockerrlog=0; /* copy error description to buf or set *buf=0 if none */ int sockerrorchecks(char *buf, int blen, int res) { *buf=0; if (res==-1) { switch(sockerrno) { case EBADF: strncpy(buf,"bad descriptor",blen); break; case EINVAL: strncpy(buf,"already in use",blen); break; case EACCES: strncpy(buf,"access denied",blen); break; case ENOTSOCK: strncpy(buf,"descriptor is not a socket",blen); break; case EOPNOTSUPP: strncpy(buf,"operation not supported",blen); break; case EFAULT: strncpy(buf,"fault",blen); break; case EWOULDBLOCK: strncpy(buf,"operation would block",blen); break; case EISCONN: strncpy(buf,"is already connected",blen); break; case ECONNREFUSED: strncpy(buf,"connection refused",blen); break; case ETIMEDOUT: strncpy(buf,"operation timed out",blen); break; case ENETUNREACH: strncpy(buf,"network is unreachable",blen); break; case EADDRINUSE: strncpy(buf,"address already in use",blen); break; case EINPROGRESS: strncpy(buf,"in progress",blen); break; case EALREADY: strncpy(buf,"previous connect request not completed yet",blen); break; #ifdef unix default: snprintf(buf,blen,"unknown socket error %d",sockerrno); #else default: sprintf(buf,"unknown socket error %d",sockerrno); #endif } } return res; } #ifdef RSERVE_PKG /* use error instead of exit */ #include int sockerrorcheck(char *sn, int rtb, int res) { if ((signed int)res == -1) { char sock_err_buf[72]; sockerrorchecks(sock_err_buf, sizeof(sock_err_buf), res); if (rtb) Rf_error("%s socket error #%d (%s)", sn, (int) sockerrno, sock_err_buf); else Rf_warning("%s socket error #%d (%s)", sn, (int) sockerrno, sock_err_buf); } return res; } #else /* check socket error and add to log file if necessary */ int sockerrorcheck(char *sn, int rtb, int res) { if (!sockerrlog) sockerrlog=stderr; if ((signed int)res==-1) { if (socklasterr==sockerrno) { suppmode++; } else { if (suppmode>0) { fprintf(sockerrlog,"##> REP: (last error has been repeated %d times.)\n",suppmode); suppmode=0; } fprintf(sockerrlog,"##> SOCK_ERROR: %s error #%d",sn,sockerrno); switch(sockerrno) { case EBADF: fprintf(sockerrlog,"(bad descriptor)"); break; case EINVAL: fprintf(sockerrlog,"(already in use)"); break; case EACCES: fprintf(sockerrlog,"(access denied)"); break; case ENOTSOCK: fprintf(sockerrlog,"(descriptor is not a socket)"); break; case EOPNOTSUPP: fprintf(sockerrlog,"(operation not supported)"); break; case EFAULT: fprintf(sockerrlog,"(fault)"); break; case EWOULDBLOCK: fprintf(sockerrlog,"(operation would block)"); break; case EISCONN: fprintf(sockerrlog,"(is already connected)"); break; case ECONNREFUSED: fprintf(sockerrlog,"(connection refused)"); break; case ETIMEDOUT: fprintf(sockerrlog,"(operation timed out)"); break; case ENETUNREACH: fprintf(sockerrlog,"(network is unreachable)"); break; case EADDRINUSE: fprintf(sockerrlog,"(address already in use)"); break; case EINPROGRESS: fprintf(sockerrlog,"(in progress)"); break; case EALREADY: fprintf(sockerrlog,"(previous connect request not completed yet)"); break; default: fprintf(sockerrlog,"(?)"); } fprintf(sockerrlog,"\n"); fflush(sockerrlog); socklasterr=sockerrno; } if (rtb) exit(1); } return res; } #endif #else extern int suppmode; extern int socklasterr; extern FILE *sockerrlog; int sockerrorchecks(char *buf, int blen, int res); int sockerrorcheck(char *sn, int rtb, int res); #endif #define FCF(X,F) sockerrorcheck(X,1,F) #define CF(X,F) sockerrorcheck(X,0,F) #endif #ifdef MAIN struct sockaddr *build_sin(struct sockaddr_in *sa,char *ip,int port) { memset(sa,0,sizeof(struct sockaddr_in)); sa->sin_family=AF_INET; sa->sin_port=htons(port); sa->sin_addr.s_addr=(ip)?inet_addr(ip):htonl(INADDR_ANY); return (struct sockaddr*)sa; } #else struct sockaddr *build_sin(struct sockaddr_in *sa,char *ip,int port); #endif #endif /* __SISOCKS_H__ */ Rserve/src/oc.c0000644000175100001440000000763614531234224013106 0ustar hornikusers#include #include "oc.h" #include "sha1.h" #ifndef NO_CONFIG_H #include "config.h" #endif #ifdef HAVE_TLS #include #endif #ifndef HAVE_SRANDOMDEV /* the fall-back is to use time and pid so we need those extra headers */ #include #include #endif static SEXP oc_env; SEXP oc_resolve(const char *ref) { SEXP val; if (!oc_env) return R_NilValue; val = findVarInFrame(oc_env, install(ref)); if (val == R_UnboundValue) val = R_NilValue; return val; } /* this is where we generate tokens. The current apporach is to generate good random 168-bits and encode them using slightly modified base-64 encoding into a string. If we can't get good random bits, we generate more pseudo-random bytes and run SHA1 on it. The result is almost a valid identifier except that it can start with a number. */ static int rand_inited; static const char b64map[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_."; /* currently we use 21 bytes = 168 bits --> 28 bytes encoded */ #define MAX_OC_TOKEN_LEN 31 /* this is used to create multi-tier OCAPs if needed (0=no prefix, default) */ char Rserve_oc_prefix; static void oc_new(char *dst) { int have_hash = 0, i; unsigned char hash[21]; #ifdef HAVE_TLS #if OPENSSL_VERSION_NUMBER < 0x10100000L if (RAND_bytes(hash, 21) == 1 || RAND_pseudo_bytes(hash, 21)) have_hash = 1; #else /* OpenSSL 1.1+ doesn't support pseudo-bytes fall-back, so don't try - have to use random() instead ... */ if (RAND_bytes(hash, 21) == 1) have_hash = 1; #endif #endif if (!have_hash) { /* should only be used if TLS is not available or it fails */ unsigned char rbuf[64]; if (!rand_inited) { #ifdef HAVE_SRANDOMDEV srandomdev(); #else #ifdef Win32 srand(time(NULL) ^ (getpid() << 12)); #else /* fall back -- mix of time and pid is the best we can do ... */ srandom(time(NULL) ^ (getpid() << 12)); #endif #endif rand_inited = 1; } #ifdef Win32 for (i = 0; i < sizeof(rbuf); i++) rbuf[i] = rand(); #else for (i = 0; i < sizeof(rbuf); i++) rbuf[i] = random(); #endif /* we use random -> SHA1 .. is it an overkill? */ sha1hash((const char*)rbuf, sizeof(rbuf) - 1, hash); /* the last byte is the hold-out byte -- just because SHA gives only 160 bits */ hash[20] = rbuf[sizeof(rbuf) - 1]; } if (Rserve_oc_prefix) *(dst++) = Rserve_oc_prefix; for (i = 0; i < 21; i += 3) { *(dst++) = b64map[hash[i] & 63]; *(dst++) = b64map[((hash[i] >> 6) | (hash[i + 1] << 2)) & 63]; *(dst++) = b64map[((hash[i + 1] >> 4) | (hash[i + 2] << 4)) & 63]; *(dst++) = b64map[hash[i + 2] >> 2]; } *dst = 0; } char *oc_register(SEXP what, char *dst, int len, const char *name) { SEXP x; if (len <= MAX_OC_TOKEN_LEN) return NULL; if (!oc_env) { SEXP env = eval(PROTECT(lang3(install("new.env"), ScalarLogical(TRUE), R_EmptyEnv)), R_GlobalEnv); UNPROTECT(1); if (TYPEOF(env) != ENVSXP) return NULL; oc_env = env; R_PreserveObject(oc_env); } x = PROTECT(CONS(what, R_NilValue)); if (name) SET_TAG(x, install(name)); oc_new(dst); Rf_defineVar(install(dst), x, oc_env); UNPROTECT(1); return dst; } /* --- R-side API --- */ /* NOTE: if you change the signature, you *have* to change the registration and declaration in standalone.c !! */ SEXP Rserve_oc_register(SEXP what, SEXP sName) { const char *name = 0; char token[MAX_OC_TOKEN_LEN + 1]; SEXP res; if (TYPEOF(sName) == STRSXP && LENGTH(sName) > 0) name = CHAR(STRING_ELT(sName, 0)); if (!oc_register(what, token, sizeof(token), name)) Rf_error("Cannot create OC reference registry"); res = PROTECT(mkString(token)); setAttrib(res, R_ClassSymbol, mkString("OCref")); UNPROTECT(1); return res; } SEXP Rserve_oc_resolve(SEXP what) { if (!inherits(what, "OCref") || TYPEOF(what) != STRSXP || LENGTH(what) != 1) Rf_error("invalid OCref"); return CAR(oc_resolve(CHAR(STRING_ELT(what, 0)))); } Rserve/src/winembed.c0000644000175100001440000001725514531234224014275 0ustar hornikusers/* * R : A Computer Language for Statistical Data Analysis * Copyright (C) 1998--2002 R Development Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef WIN32 /* based on rtest.c implements Rf_initEmbeddedR which is missing in the Windows-version of R shared library */ /* 27/03/2000 win32-api needs this */ #define NONAMELESSUNION #include #include #include #include #include "Rversion.h" #if R_VERSION < 0x2010 #include "Startup.h" #else #include #include #endif /* flag governing interactivity - from Rserv.c */ extern int Rsrv_interactive; /* I didn't actually check if 2.10.x is really the point where initEmbedded was introduced but it makes pretty much all this file obsolete */ #if R_VERSION > R_Version(2,10,0) __declspec(dllimport) int R_Interactive; int Rf_initEmbeddedR(int argc, char **argv) { Rf_initialize_R(argc, argv); R_Interactive = Rsrv_interactive; setup_Rmainloop(); return 0; } #else /* otherwise we have to do all this manually ... */ /* for signal-handling code */ #include "psignal.h" /* one way to allow user interrupts: called in ProcessEvents */ #if defined _MSC_VER || defined WIN64 __declspec(dllimport) int UserBreak; #else #define UserBreak (*_imp__UserBreak) extern int UserBreak; #endif /* calls into the R DLL */ extern char *getDLLVersion(); extern void R_DefParams(Rstart); extern void R_SetParams(Rstart); extern void setup_term_ui(void); extern void ProcessEvents(void); extern void end_Rmainloop(void), R_ReplDLLinit(void); extern int R_ReplDLLdo1(); extern void run_Rmainloop(void); #ifndef YES #define YES 1 #endif #ifndef NO #define NO -1 #endif #ifndef CANCEL #define CANCEL 0 #endif /* simple input, simple output */ /* This version blocks all events: a real one needs to call ProcessEvents frequently. See rterm.c and ../system.c for one approach using a separate thread for input */ int myReadConsole(const char *prompt, char *buf, int len, int addtohistory) { fputs(prompt, stdout); fflush(stdout); if(fgets(buf, len, stdin)) return 1; else return 0; } void myWriteConsole(const char *buf, int len) { printf("%s", buf); } void myCallBack() { /* called during i/o, eval, graphics in ProcessEvents */ } void myBusy(int which) { /* set a busy cursor ... if which = 1, unset if which = 0 */ } void myMessage(const char *s) { if (!s) return; myWriteConsole(s, strlen(s)); } int myYesNoCancel(const char *s) { char ss[128]; char a[3]; snprintf(ss, sizeof(ss)-1, "%s [y/n/c]: ", s); myReadConsole(ss, a, 3, 0); switch (a[0]) { case 'y': case 'Y': return YES; case 'n': case 'N': return NO; default: return CANCEL; } } static void my_onintr(int sig) { UserBreak = 1; } static char Rversion[25], RUser[MAX_PATH], RHome[MAX_PATH]; static int dir_exists(const char* dn) { DWORD att = GetFileAttributes(dn); /* this actually needs Win2k or higher but I suppose that's ok these days ... */ return (att != INVALID_FILE_ATTRIBUTES && ((att & FILE_ATTRIBUTE_DIRECTORY) != 0 || att == FILE_ATTRIBUTE_NORMAL)); /* the last one is weird, but according to MS docs it can happen any we cannot tell whether it's a file or a directory */ } static char tmpbuf[8192]; int Rf_initEmbeddedR(int argc, char **argv) { structRstart rp; Rstart Rp = &rp; char *p; char rhb[MAX_PATH+10]; DWORD t,s=MAX_PATH; HKEY k; const char *arch = 0; const char *path_suf = 0; snprintf(Rversion, sizeof(Rversion)-1, "%s.%s", R_MAJOR, R_MINOR); { char *c = Rversion, *d = Rversion; while (*c) { if (*c=='.') d=c; c++; }; *d=0; } #ifdef RSERV_DEBUG printf("Windows: Rf_initEmbeddedR; compiled as %s.%s, DLL is %s\n", R_MAJOR, R_MINOR, getDLLVersion()); #endif if(strncmp(Rversion, getDLLVersion(), strlen(Rversion)) != 0) { fprintf(stderr, "Error: R.DLL version (%s) does not match (%s.%s)\n", getDLLVersion(), R_MAJOR, R_MINOR); return -1; } R_DefParams(Rp); if(getenv("R_HOME")) { strcpy(RHome, getenv("R_HOME")); } else { /* fetch R_HOME from the registry */ /* try HKCU first such that users can override the system setting */ if (RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\R-core\\R", 0, KEY_QUERY_VALUE, &k) != ERROR_SUCCESS || RegQueryValueEx(k, "InstallPath", 0, &t, (LPVOID)RHome, &s) != ERROR_SUCCESS || !dir_exists(RHome)) { /* then try HKLM where teh system-wide installs would be */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\R-core\\R", 0, KEY_QUERY_VALUE, &k) != ERROR_SUCCESS || RegQueryValueEx(k, "InstallPath", 0, &t, (LPVOID)RHome, &s) != ERROR_SUCCESS) { fprintf(stderr, "R_HOME must be set or R properly installed (\\Software\\R-core\\R\\InstallPath registry entry must exist).\n"); return -2; } } snprintf(rhb, sizeof(rhb)-1, "R_HOME=%s",RHome); putenv(rhb); } /* on Win32 this should set R_Home (in R_SetParams) as well */ Rp->rhome = RHome; #ifdef RSERV_DEBUG printf("R_HOME: %s\n", RHome); #endif /* check for multi-arch R */ if (!getenv("R_ARCH")) { strcpy(tmpbuf, RHome); #ifdef WIN64 strcat(tmpbuf, "\\bin\\x64\\R.dll"); arch = "R_ARCH=/x64"; #else strcat(tmpbuf, "\\bin\\i386\\R.dll"); arch = "R_ARCH=/i386"; #endif if (GetFileAttributes(tmpbuf) != -1) { /* muti-arch R, DLL found */ putenv(arch); #ifdef RSERV_DEBUG printf("Multi-architecture R found, setting %s\n", arch); #endif } else arch = 0; } if (!arch) { strcpy(tmpbuf, RHome); strcat(tmpbuf, "\\bin\\R.dll"); if (GetFileAttributes(tmpbuf) == -1) printf("WARNING: cannot find R DDL at %s\n check your R installation or make sure PATH is set accordingly\n"); } /* * try R_USER then HOME then working directory */ if (getenv("R_USER")) { strcpy(RUser, getenv("R_USER")); } else if (getenv("HOME")) { strcpy(RUser, getenv("HOME")); } else if (getenv("HOMEDIR")) { strcpy(RUser, getenv("HOMEDIR")); strcat(RUser, getenv("HOMEPATH")); } else GetCurrentDirectory(MAX_PATH, RUser); p = RUser + (strlen(RUser) - 1); if (*p == '/' || *p == '\\') *p = '\0'; Rp->home = RUser; Rp->CharacterMode = LinkDLL; Rp->ReadConsole = myReadConsole; Rp->WriteConsole = myWriteConsole; Rp->CallBack = myCallBack; #if R_VERSION < 0x2010 Rp->message = myMessage; Rp->yesnocancel = myYesNoCancel; Rp->busy = myBusy; #else Rp->ShowMessage = myMessage; Rp->YesNoCancel = myYesNoCancel; Rp->Busy = myBusy; #endif Rp->R_Quiet = TRUE; Rp->R_Interactive = Rsrv_interactive; Rp->RestoreAction = SA_RESTORE; Rp->SaveAction = SA_NOSAVE; #if R_VERSION < 0x2000 Rp->CommandLineArgs = NULL; Rp->NumCommandLineArgs = 0; #endif /* Rp->nsize = 300000; Rp->vsize = 6e6; */ R_SetParams(Rp); /* so R_ShowMessage is set */ R_SizeFromEnv(Rp); R_SetParams(Rp); FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); signal(SIGBREAK, my_onintr); setup_term_ui(); setup_Rmainloop(); return 0; } #endif #else #include #endif Rserve/src/bsdcmpt.h0000644000175100001440000000140314531234224014130 0ustar hornikusers#ifndef BSD_CMPT_H__ #define BSD_CMPT_H__ /* Implementation of BSD-specific pieces used in the proxy that are missing on other platforms. Curretnly we only used it on OS X but we should add a cfg check for other BSD variants. */ #include #ifdef __APPLE__ #define MTIME(X) (X).st_mtimespec.tv_sec #else #define MTIME(X) (X).st_mtime /* not part of Linux/POSIX so implement it ... */ static const char *strnstr(const char *haystack, const char *needle, size_t len) { const char *eohs = haystack + len; size_t nl = strlen(needle); while (eohs - haystack >= nl && (haystack = memchr(haystack, needle[0], eohs - haystack))) if (!memcmp(haystack, needle, nl)) return haystack; else haystack++; return 0; } #endif #endif Rserve/src/http.c0000644000175100001440000011454014531234224013455 0ustar hornikusers#include "RSserver.h" #include "tls.h" #include "http.h" #include "websockets.h" /* for connection upgrade */ #include "rserr.h" #include #include #include #include #include "bsdcmpt.h" #include /* size of the line buffer for each worker (request and header only) * requests that have longer headers will be rejected with 413 * Note that cookies can be quite big and some browsers send them * in one line, so this should not be too small */ #define LINE_BUF_SIZE 32768 /* debug output - change the DBG(X) X to enable debugging output */ #ifdef RSERV_DEBUG #define DBG(X) X #else #define DBG(X) #endif /* --- httpd --- */ #define PART_REQUEST 0 #define PART_HEADER 1 #define PART_BODY 2 #define METHOD_POST 1 #define METHOD_GET 2 #define METHOD_HEAD 3 #define METHOD_OTHER 8 /* for custom requests only */ /* attributes of a connection/worker */ #define CONNECTION_CLOSE 0x0001 /* Connection: close response behavior is requested */ #define HOST_HEADER 0x0002 /* headers contained Host: header (required for HTTP/1.1) */ #define HTTP_1_0 0x0004 /* the client requested HTTP/1.0 */ #define CONTENT_LENGTH 0x0008 /* Content-length: was specified in the headers */ #define THREAD_OWNED 0x0010 /* the worker is owned by a thread and cannot removed */ #define THREAD_DISPOSE 0x0020 /* the thread should dispose of the worker */ #define CONTENT_TYPE 0x0040 /* message has a specific content type set */ #define CONTENT_FORM_UENC 0x0080 /* message content type is application/x-www-form-urlencoded */ #define WS_UPGRADE 0x0100 /* upgrade to WebSockets protocol */ struct buffer { struct buffer *next, *prev; int size, length; char data[1]; }; #ifdef unix #include /* needed for unix sockets */ #endif struct args { server_t *srv; /* server that instantiated this connection */ SOCKET s; SOCKET ss; int msg_id; void *res1, *res2; /* the following entries are not populated by Rserve but can be used by server implemetations */ char *buf, *sbuf; int ver, bp, bl, sp, sl, flags; size_t l1, l2; /* The following fields are informational, populated by Rserve */ SAIN sa; int ucix; #ifdef unix struct sockaddr_un su; #endif char *line_buf; /* line buffer (used for request and headers) */ char *url, *body; /* URL and request body */ char *content_type; /* content type (if set) */ unsigned int line_pos, body_pos; /* positions in the buffers */ long content_length; /* desired content length */ char part, method; /* request part, method */ int attr; /* connection attributes */ char *ws_protocol, *ws_version, *ws_key; struct buffer *headers; /* buffer holding header lines */ }; #define IS_HTTP_1_1(C) (((C)->attr & HTTP_1_0) == 0) /* returns the HTTP/x.x string for a given connection - we support 1.0 and 1.1 only */ #define HTTP_SIG(C) (IS_HTTP_1_1(C) ? "HTTP/1.1" : "HTTP/1.0") #ifndef USE_RINTERNALS #define USE_RINTERNALS #include #endif /* free buffers starting from the tail(!!) */ static void free_buffer(struct buffer *buf) { if (!buf) return; if (buf->prev) free_buffer(buf->prev); free(buf); } /* allocate a new buffer */ static struct buffer *alloc_buffer(int size, struct buffer *parent) { struct buffer *buf = (struct buffer*) malloc(sizeof(struct buffer) + size); if (!buf) return buf; buf->next = 0; buf->prev = parent; if (parent) parent->next = buf; buf->size = size; buf->length = 0; return buf; } /* convert doubly-linked buffers into one big raw vector */ static SEXP collect_buffers(struct buffer *buf) { SEXP res; char *dst; int len = 0; if (!buf) return allocVector(RAWSXP, 0); while (buf->prev) { /* count the total length and find the root */ len += buf->length; buf = buf->prev; } res = allocVector(RAWSXP, len + buf->length); dst = (char*) RAW(res); while (buf) { memcpy(dst, buf->data, buf->length); dst += buf->length; buf = buf->next; } return res; } /* convert doubly-linked buffers into one big string, caller must free, may return NULL */ static char *collect_buffers_c(struct buffer *buf) { char *res, *dst; int len = 0; if (!buf) return 0; while (buf->prev) { /* count the total length and find the root */ len += buf->length; buf = buf->prev; } res = malloc(len + buf->length + 1); if (!res) return res; dst = res; while (buf) { memcpy(dst, buf->data, buf->length); dst += buf->length; buf = buf->next; } *dst = 0; /* terminate */ return res; } static void free_args(args_t *c) { DBG(printf("finalizing worker %p\n", (void*) c)); if (c->url) { free(c->url); c->url = NULL; } if (c->line_buf) { free(c->line_buf); c->line_buf = NULL; } if (c->body) { free(c->body); c->body = NULL; } if (c->content_type) { free(c->content_type); c->content_type = NULL; } if (c->headers) { free_buffer(c->headers); c->headers = NULL; } if (c->ws_key) { free(c->ws_key); c->ws_key = NULL; } if (c->ws_protocol) { free(c->ws_protocol); c->ws_protocol = NULL; } if (c->ws_version) { free(c->ws_version); c->ws_version = NULL; } if (c->s != INVALID_SOCKET) { closesocket(c->s); c->s = INVALID_SOCKET; } } static int send_response(args_t *c, const char *buf, unsigned int len) { server_t *srv = c->srv; unsigned int i = 0; /* we have to tell R to ignore SIGPIPE otherwise it can raise an error and get us into deep trouble */ while (i < len) { int n = srv->send(c, buf + i, len - i); if (n < 1) { return -1; } i += n; } return 0; } /* sends HTTP/x.x plus the text (which should be of the form " XXX ...") */ static int send_http_response(args_t *c, const char *text) { char buf[96]; server_t *srv = c->srv; const char *s = HTTP_SIG(c); int l = strlen(text), res; /* reduce the number of packets by sending the payload en-block from buf */ if (l < sizeof(buf) - 10) { strcpy(buf, s); strcpy(buf + 8, text); return send_response(c, buf, l + 8); } res = srv->send(c, s, 8); if (res < 8) return -1; return send_response(c, text, strlen(text)); } /* decode URI in place (decoding never expands) */ static void uri_decode(char *s) { char *t = s; while (*s) { if (*s == '+') { /* + -> SPC */ *(t++) = ' '; s++; } else if (*s == '%') { unsigned char ec = 0; s++; if (*s >= '0' && *s <= '9') ec |= ((unsigned char)(*s - '0')) << 4; else if (*s >= 'a' && *s <= 'f') ec |= ((unsigned char)(*s - 'a' + 10)) << 4; else if (*s >= 'A' && *s <= 'F') ec |= ((unsigned char)(*s - 'A' + 10)) << 4; if (*s) s++; if (*s >= '0' && *s <= '9') ec |= (unsigned char)(*s - '0'); else if (*s >= 'a' && *s <= 'f') ec |= (unsigned char)(*s - 'a' + 10); else if (*s >= 'A' && *s <= 'F') ec |= (unsigned char)(*s - 'A' + 10); if (*s) s++; *(t++) = (char) ec; } else *(t++) = *(s++); } *t = 0; } /* parse a query string into a named character vector - must NOT be * URI decoded */ static SEXP parse_query(char *query) { int parts = 0; SEXP res, names; char *s = query, *key = 0, *value = query, *t = query; while (*s) { if (*s == '&') parts++; s++; } parts++; res = PROTECT(allocVector(STRSXP, parts)); names = PROTECT(allocVector(STRSXP, parts)); s = query; parts = 0; while (1) { if (*s == '=' && !key) { /* first '=' in a part */ key = value; *(t++) = 0; value = t; s++; } else if (*s == '&' || !*s) { /* next part */ int last_entry = !*s; *(t++) = 0; if (!key) key = ""; SET_STRING_ELT(names, parts, mkChar(key)); SET_STRING_ELT(res, parts, mkChar(value)); parts++; if (last_entry) break; key = 0; value = t; s++; } else if (*s == '+') { /* + -> SPC */ *(t++) = ' '; s++; } else if (*s == '%') { /* we cannot use uri_decode becasue we need &/= *before* decoding */ unsigned char ec = 0; s++; if (*s >= '0' && *s <= '9') ec |= ((unsigned char)(*s - '0')) << 4; else if (*s >= 'a' && *s <= 'f') ec |= ((unsigned char)(*s - 'a' + 10)) << 4; else if (*s >= 'A' && *s <= 'F') ec |= ((unsigned char)(*s - 'A' + 10)) << 4; if (*s) s++; if (*s >= '0' && *s <= '9') ec |= (unsigned char)(*s - '0'); else if (*s >= 'a' && *s <= 'f') ec |= (unsigned char)(*s - 'a' + 10); else if (*s >= 'A' && *s <= 'F') ec |= (unsigned char)(*s - 'A' + 10); if (*s) s++; *(t++) = (char) ec; } else *(t++) = *(s++); } setAttrib(res, R_NamesSymbol, names); UNPROTECT(2); return res; } static SEXP R_ContentTypeName; /* create an object representing the request body. It is NULL if the body is empty (or zero length). * In the case of a URL encoded form it will have the same shape as the query string (named string vector). * In all other cases it will be a raw vector with a "content-type" attribute (if specified in the headers) */ static SEXP parse_request_body(args_t *c) { if (!c || !c->body) return R_NilValue; if ((c->attr & CONTENT_FORM_UENC) && !(c->srv->flags & HTTP_RAW_BODY)) { /* URL encoded form - return parsed form */ c->body[c->content_length] = 0; /* the body is guaranteed to have an extra byte for the termination */ return parse_query(c->body); } else { /* something else - pass it as a raw vector */ SEXP res = PROTECT(Rf_allocVector(RAWSXP, c->content_length)); if (c->content_length) memcpy(RAW(res), c->body, c->content_length); if (c->content_type) { /* attach the content type so it can be interpreted */ if (!R_ContentTypeName) R_ContentTypeName = install("content-type"); setAttrib(res, R_ContentTypeName, mkString(c->content_type)); } UNPROTECT(1); return res; } } /* finalize a request - essentially for HTTP/1.0 it means that * we have to close the connection */ static void fin_request(args_t *c) { if (!IS_HTTP_1_1(c)) c->attr |= CONNECTION_CLOSE; } static SEXP s_http_request_fn; static void http_set_request_fn(SEXP sFn) { s_http_request_fn = sFn ? sFn : install(".http.request"); } /* API */ SEXP Rserve_set_http_request_fn(SEXP sFn) { http_set_request_fn((sFn == R_NilValue) ? 0 : sFn); return s_http_request_fn; } #define HSF_STOP 1 /* stop if prefix matches */ #define HSF_PRECOMPRESSED 2 /* use pre-compressed .gz files */ typedef struct http_static { struct http_static *next; char *prefix, *path, *index; int prefix_len; int flags; } http_static; static http_static *http_statics; SEXP Rserve_http_add_static(SEXP sPrefix, SEXP sPath, SEXP sIndex, SEXP sFlags) { int n = 1; http_static *h, *hl; if (TYPEOF(sPrefix) != STRSXP || LENGTH(sPrefix) != 1) Rf_error("Invalid prefix, must be a string"); if (TYPEOF(sPath) != STRSXP || LENGTH(sPath) != 1) Rf_error("Invalid path, must be a string"); if (!((TYPEOF(sIndex) == STRSXP && LENGTH(sPath) == 1) || sIndex == R_NilValue)) Rf_error("Invalid index, must be NULL or a string"); h = (http_static*) malloc(sizeof(http_static)); if (!h) Rf_error("Cannot allocate structure."); h->next = 0; h->prefix = strdup(CHAR(STRING_ELT(sPrefix, 0))); h->path = strdup(CHAR(STRING_ELT(sPath, 0))); h->index = (sIndex == R_NilValue) ? 0 : strdup(CHAR(STRING_ELT(sIndex, 0))); h->prefix_len = strlen(h->prefix); h->flags = Rf_asInteger(sFlags); if (!http_statics) { http_statics = h; } else { hl = http_statics; n++; while (hl->next) { n++; hl = hl->next; } hl->next = h; } return Rf_ScalarInteger(n); } static char http_tmp[512]; /* 0 = ok, sent -1 = failure during transmission, have to close -2 = file cannot be read (nothing sent) */ static int http_send_file(args_t *c, const char *fn, size_t fsz, int size_valid, const char *preamble) { char *fbuf; char buf[64]; FILE *f = fopen(fn, "rb"); if (!f) return -2; /* FIXME: on Windows this is limited to 2Gb */ if (!size_valid) { fseek(f, 0, SEEK_END); fsz = (size_t) ftell(f); fseek(f, 0, SEEK_SET); } if (preamble) send_http_response(c, preamble); snprintf(buf, sizeof(buf), "\r\nContent-length: %llu\r\n\r\n", (unsigned long long) fsz); send_response(c, buf, strlen(buf)); #define HTTP_SEND_FILE_CHUNK (1024*1024) if (fsz && c->method != METHOD_HEAD) { fbuf = (char*) malloc(HTTP_SEND_FILE_CHUNK); if (fbuf) { while (fsz > 0 && !feof(f)) { int rd = (fsz > HTTP_SEND_FILE_CHUNK) ? HTTP_SEND_FILE_CHUNK : fsz; if (fread(fbuf, 1, rd, f) != rd) { free(fbuf); fclose(f); return -1; } send_response(c, fbuf, rd); fsz -= rd; } free(fbuf); } else { /* allocation error - get out */ fclose(f); return -1; } } fclose(f); return 0; } /* returns a pointer to the beginning of a value for a given header field or NULL if not present. */ static const char *get_header(const char *headers, const char *name) { const char *c = headers, *e; int name_len = strlen(name); if (!c) return 0; while (*c && (e = strchr(c, '\n'))) { const char *v = strchr(c, ':'); if (v && (v < e) && (v - c == name_len)) { int i; for (i = 0; i < name_len; i++) if ((name[i] & 0xdf) != (c[i] & 0xdf)) break; if (i == name_len) { v++; while (*v == '\t' || *v == ' ') v++; return v; } } while (*e == '\n' || *e == '\t') e++; c = e; } return 0; } static const char *infer_content_type(const char *fn) { const char *x = fn ? strrchr(fn, '.') : 0; char ext[8]; /* lower-case version of the extension */ int i = 0; if (!x) return "application/octet-stream"; x++; while (i < 7 && *x) { ext[i++] = (*x >= 'A' && *x <= 'Z') ? (*x | 0x20) : *x; x++; } ext[i] = 0; if (!strcmp(ext, "svg")) return "image/svg+xml"; if (!strcmp(ext, "js")) return "application/javascript"; if (!strcmp(ext, "css")) return "text/css"; if (!strcmp(ext, "html")) return "text/html"; if (!strcmp(ext, "txt")) return "text/plain"; if (!strcmp(ext, "png")) return "image/png"; if (!strcmp(ext, "jpeg") || !strcmp(ext, "jpg")) return "image/jpeg"; if (!strcmp(ext, "md")) return "text/markdown"; if (!strcmp(ext, "json")) return "application/json"; return "application/octet-stream"; } /* removes .. and . segments, control characters. non-ASCII characters are retained */ static void sanitize_path(char *path) { char *src = path, *dst = path; int pos = 0; DBG(fprintf(stderr, "path: '%s' sanitizing\n", path)); while (*src) { if (!pos) { if (src[0] == '.') { /* .. */ if (src[1] == '.' && (!src[2] || src[2] == '/')) { src += 2; continue; } /* . (harmless, but we still remove it) */ if (!src[1] || src[1] == '/') { src++; continue; } } } if (*src == '/') { if (pos) { /* not a repeated / */ *(dst++) = *(src++); pos = 0; } else /* repeated, just ignore */ src++; continue; } pos++; if (*src >= 32) *(dst++) = *(src++); } *dst = 0; DBG(fprintf(stderr, " '%s'\n", path)); } /* from date.c */ char *posix2http(double ts); /* Note: returned buffer is static */ double http2posix(const char *c); /* process a request by calling the httpd() function in R */ static void process_request(args_t *c) { const char *ct = "text/html"; char *query = 0, *s; SEXP sHeaders = R_NilValue; int code = 200; DBG(Rprintf("process request for %p\n", (void*) c)); if (!c || !c->url) return; /* if there is not enough to process, bail out */ if ((c->attr & WS_UPGRADE) && (c->srv->flags & HTTP_WS_UPGRADE)) { WS13_upgrade(c, c->ws_key, c->ws_protocol, c->ws_version); /* the WS swtich messes up args since it replaces it with its own version so we can't go back to serving - just bail out (NOTE: only works when forked!) */ exit(0); } s = c->url; while (*s && *s != '?') s++; /* find the query part */ if (*s) { *(s++) = 0; query = s; } if (!s_http_request_fn) s_http_request_fn = install(".http.request"); uri_decode(c->url); /* decode the path part */ /* it would be nice if we could re-use the code from forward.c, but for now they are separate. FIXME: move the forward static handling into an http handler, make the R API call another handler and then replace the code here with the handler code from forward.c */ if (http_statics) { http_static *hs = http_statics; while (hs) { //fprintf(stderr, "match '%s' and '%s'\n", c->url, hs->prefix); if (!strncmp(hs->prefix, c->url, hs->prefix_len)) { struct stat st; const char *fn = c->url + hs->prefix_len; int found = 0; if (strlen(fn) + strlen(hs->path) + (hs->index ? strlen(hs->index) : 0) + 7 > sizeof(http_tmp)) { send_http_response(c, " 414 Path too long\r\nContent-type: text/plain\r\nContent-length: 14\r\n\r\nPath too long\n"); fin_request(c); return; } strcpy(http_tmp, hs->path); strcat(http_tmp, fn); sanitize_path(http_tmp); if (!stat(http_tmp, &st)) { /* path exists */ if (st.st_mode & S_IFDIR) { /* if it is a directory, we only accept it if index exists */ if (hs->index) { strcat(http_tmp, hs->index); //fprintf(stderr, " - try '%s'\n", http_tmp); if (!stat(http_tmp, &st)) found = 1; } } else if (st.st_mode & S_IFREG) /* otherwise we only accept regular files */ found = 1; } if (!found) { //fprintf(stderr, " - '%s' not found\n", http_tmp); if (hs->flags & HSF_STOP) { send_http_response(c, " 404 Not found\r\nContent-type: text/plain\r\nContent-length: 10\r\n\r\nNot found\n"); fin_request(c); return; } } else { /* file found */ int not_modified = 0; /* check for conditional GET */ if (c->headers) { char *h = collect_buffers_c(c->headers); const char *if_mod = get_header(h, "if-modified-since"); if (if_mod) { double since = http2posix(if_mod); if (since >= MTIME(st)) not_modified = 1; } free(h); } if (not_modified) { send_http_response(c, " 304 Not modified\r\nCache-Control: no-cache\r\n\r\n"); } else { char buf[196]; double ts = (double) time(0); snprintf(buf, sizeof(buf), " 200 OK\r\nCache-Control: no-cache\r\nContent-type: %s\r\nLast-Modified: %s", infer_content_type(http_tmp), posix2http((MTIME(st) > ts) ? ts : MTIME(st))); int res = http_send_file(c, http_tmp, (size_t) st.st_size, 1, buf); if (res == -2) { /* cannot open */ send_http_response(c, " 403 Forbidden\r\nContent-Type: text/plain\r\nContent-length: 10\r\n\r\nForbidden\n"); } if (res == -1) /* transfer error */ c->attr |= CONNECTION_CLOSE; } /* all paths here sent the response */ fin_request(c); return; } } hs = hs->next; } } { /* construct "try(httpd(url, query, body, headers), silent=TRUE)" */ SEXP sTrue = PROTECT(ScalarLogical(TRUE)); SEXP sBody = PROTECT(parse_request_body(c)); SEXP sQuery = PROTECT(query ? parse_query(query) : R_NilValue); SEXP sReqHeaders = PROTECT(c->headers ? collect_buffers(c->headers) : R_NilValue); SEXP sArgs = PROTECT(list4(mkString(c->url), sQuery, sBody, sReqHeaders)); SEXP sTry = install("try"); SEXP y, x = PROTECT(lang3(sTry, LCONS(s_http_request_fn, sArgs), sTrue)); SET_TAG(CDR(CDR(x)), install("silent")); DBG(Rprintf("eval(try(.http.request('%s'),silent=TRUE))\n", c->url)); /* evaluate the above in the global namespace */ x = PROTECT(eval(x, R_GlobalEnv)); /* the result is expected to have one of the following forms: a) character vector of length 1 => error (possibly from try), will create 500 response b) list(payload[, content-type[, headers[, status code]]]) payload: can be a character vector of length one or a raw vector. if the character vector is named "file" then the content of a file of that name is the payload content-type: must be a character vector of length one or NULL (if present, else default is "text/html") headers: must be a character vector - the elements will have CRLF appended and neither Content-type nor Content-length may be used status code: must be an integer if present (default is 200) */ if (TYPEOF(x) == STRSXP && LENGTH(x) > 0) { /* string means there was an error */ const char *s = CHAR(STRING_ELT(x, 0)); send_http_response(c, " 500 Evaluation error\r\nConnection: close\r\nContent-type: text/plain\r\n\r\n"); DBG(Rprintf("respond with 500 and content: %s\n", s)); if (c->method != METHOD_HEAD) send_response(c, s, strlen(s)); c->attr |= CONNECTION_CLOSE; /* force close */ UNPROTECT(7); return; } if (TYPEOF(x) == VECSXP && LENGTH(x) > 0) { /* a list (generic vector) can be a real payload */ SEXP xNames = getAttrib(x, R_NamesSymbol); if (LENGTH(x) > 1) { SEXP sCT = VECTOR_ELT(x, 1); /* second element is content type if present */ if (TYPEOF(sCT) == STRSXP && LENGTH(sCT) > 0) ct = CHAR(STRING_ELT(sCT, 0)); if (LENGTH(x) > 2) { /* third element is headers vector */ sHeaders = VECTOR_ELT(x, 2); if (TYPEOF(sHeaders) != STRSXP) sHeaders = R_NilValue; if (LENGTH(x) > 3) /* fourth element is HTTP code */ code = asInteger(VECTOR_ELT(x, 3)); } } y = VECTOR_ELT(x, 0); if (TYPEOF(y) == STRSXP && LENGTH(y) > 0) { char buf[64]; int is_tmp = 0; const char *cs = CHAR(STRING_ELT(y, 0)), *fn = 0; if (code == 200) send_http_response(c, " 200 OK\r\nContent-type: "); else { snprintf(buf, sizeof(buf)-1, "%s %d Code %d\r\nContent-type: ", HTTP_SIG(c), code, code); send_response(c, buf, strlen(buf)); } send_response(c, ct, strlen(ct)); if (sHeaders != R_NilValue) { unsigned int i = 0, n = LENGTH(sHeaders); for (; i < n; i++) { const char *hs = CHAR(STRING_ELT(sHeaders, i)); if (*hs) { /* headers must be non-empty */ send_response(c, "\r\n", 2); send_response(c, hs, strlen(hs)); } } } /* special content - a file: either list(file="") or list(tmpfile="") the latter will be deleted once served */ if (TYPEOF(xNames) == STRSXP && LENGTH(xNames) > 0 && (!strcmp(CHAR(STRING_ELT(xNames, 0)), "file") || (is_tmp = !strcmp(CHAR(STRING_ELT(xNames, 0)), "tmpfile")))) fn = cs; if (fn) { int res = http_send_file(c, fn, 0, 0, 0); if (res == -2) { /* cannot open */ send_response(c, "\r\nContent-length: 0\r\n\r\n", 23); UNPROTECT(7); fin_request(c); return; } else if (res) { /* force close since the transfer failed */ c->attr |= CONNECTION_CLOSE; } if (is_tmp) unlink(fn); UNPROTECT(7); fin_request(c); return; } snprintf(buf, sizeof(buf)-1, "\r\nContent-length: %u\r\n\r\n", (unsigned int) strlen(cs)); send_response(c, buf, strlen(buf)); if (c->method != METHOD_HEAD) send_response(c, cs, strlen(cs)); UNPROTECT(7); fin_request(c); return; } if (TYPEOF(y) == RAWSXP) { char buf[64]; Rbyte *cs = RAW(y); if (code == 200) send_http_response(c, " 200 OK\r\nContent-type: "); else { snprintf(buf, sizeof(buf)-1, "%s %d Code %d\r\nContent-type: ", HTTP_SIG(c), code, code); send_response(c, buf, strlen(buf)); } send_response(c, ct, strlen(ct)); if (sHeaders != R_NilValue) { unsigned int i = 0, n = LENGTH(sHeaders); for (; i < n; i++) { const char *hs = CHAR(STRING_ELT(sHeaders, i)); send_response(c, "\r\n", 2); send_response(c, hs, strlen(hs)); } } snprintf(buf, sizeof(buf)-1, "\r\nContent-length: %u\r\n\r\n", LENGTH(y)); send_response(c, buf, strlen(buf)); if (c->method != METHOD_HEAD) send_response(c, (char*) cs, LENGTH(y)); UNPROTECT(7); fin_request(c); return; } } UNPROTECT(7); } send_http_response(c, " 500 Invalid response from R\r\nConnection: close\r\nContent-type: text/plain\r\n\r\nServer error: invalid response from R\r\n"); c->attr |= CONNECTION_CLOSE; /* force close */ } static void http_close(args_t *arg) { closesocket(arg->s); arg->s = -1; } /* this function is called to fetch new data from the client * connection socket and process it */ static void http_input_iteration(args_t *c) { int n; server_t *srv = c->srv; DBG(printf("worker_input_handler, data=%p\n", (void*) c)); if (!c) return; DBG(printf("input handler for worker %p (sock=%d, part=%d, method=%d, line_pos=%d)\n", (void*) c, (int)c->s, (int)c->part, (int)c->method, (int)c->line_pos)); /* FIXME: there is one edge case that is not caught on unix: if * recv reads two or more full requests into the line buffer then * this function exits after the first one, but input handlers may * not trigger, because there may be no further data. It is not * trivial to fix, because just checking for a full line at the * beginning and not calling recv won't trigger a new input * handler. However, under normal circumstance this should not * happen, because clients should wait for the response and even * if they don't it's unlikely that both requests get combined * into one packet. */ if (c->part < PART_BODY) { char *s = c->line_buf; n = srv->recv(c, c->line_buf + c->line_pos, LINE_BUF_SIZE - c->line_pos - 1); DBG(printf("[recv n=%d, line_pos=%d, part=%d]\n", n, c->line_pos, (int)c->part)); if (n < 0) { /* error, scrape this worker */ http_close(c); return; } if (n == 0) { /* connection closed -> try to process and then remove */ process_request(c); http_close(c); return; } c->line_pos += n; c->line_buf[c->line_pos] = 0; DBG(printf("in buffer: {%s}\n", c->line_buf)); while (*s) { /* ok, we have genuine data in the line buffer */ if (s[0] == '\n' || (s[0] == '\r' && s[1] == '\n')) { /* single, empty line - end of headers */ /* --- check request validity --- */ DBG(printf(" end of request, moving to body\n")); if (!(c->attr & HTTP_1_0) && !(c->attr & HOST_HEADER)) { /* HTTP/1.1 mandates Host: header */ send_http_response(c, " 400 Bad Request (Host: missing)\r\nConnection: close\r\n\r\n"); http_close(c); return; } if (c->attr & CONTENT_LENGTH && c->content_length) { if (c->content_length < 0 || /* we are parsing signed so negative numbers are bad */ c->content_length > 2147483640 || /* R will currently have issues with body around 2Gb or more, so better to not go there */ !(c->body = (char*) malloc(c->content_length + 1 /* allocate an extra termination byte */ ))) { send_http_response(c, " 413 Request Entity Too Large (request body too big)\r\nConnection: close\r\n\r\n"); http_close(c); return; } } c->body_pos = 0; c->part = PART_BODY; if (s[0] == '\r') s++; s++; /* move the body part to the beginning of the buffer */ c->line_pos -= s - c->line_buf; memmove(c->line_buf, s, c->line_pos); /* GET/HEAD or no content length mean no body */ if (c->method == METHOD_GET || c->method == METHOD_HEAD || !(c->attr & CONTENT_LENGTH) || c->content_length == 0) { if ((c->attr & CONTENT_LENGTH) && c->content_length > 0) { send_http_response(c, " 400 Bad Request (GET/HEAD with body)\r\n\r\n"); http_close(c); return; } process_request(c); if (c->attr & CONNECTION_CLOSE) { http_close(c); return; } /* keep-alive - reset the worker so it can process a new request */ if (c->url) { free(c->url); c->url = NULL; } if (c->body) { free(c->body); c->body = NULL; } if (c->content_type) { free(c->content_type); c->content_type = NULL; } if (c->headers) { free_buffer(c->headers); c->headers = NULL; } if (c->ws_key) { free(c->ws_key); c->ws_key = NULL; } if (c->ws_protocol) { free(c->ws_protocol); c->ws_protocol = NULL; } if (c->ws_version) { free(c->ws_version); c->ws_version = NULL; } c->body_pos = 0; c->method = 0; c->part = PART_REQUEST; c->attr = 0; c->content_length = 0; return; } /* copy body content (as far as available) */ c->body_pos = (c->content_length < c->line_pos) ? c->content_length : c->line_pos; if (c->body_pos) { memcpy(c->body, c->line_buf, c->body_pos); c->line_pos -= c->body_pos; /* NOTE: we are NOT moving the buffer since non-zero left-over causes connection close */ } /* POST will continue into the BODY part */ break; } { char *bol = s; while (*s && *s != '\r' && *s != '\n') s++; if (!*s) { /* incomplete line */ if (bol == c->line_buf) { if (c->line_pos < LINE_BUF_SIZE) /* one, incomplete line, but the buffer is not full yet, just return */ return; /* the buffer is full yet the line is incomplete - we're in trouble */ send_http_response(c, " 413 Request entity too large\r\nConnection: close\r\n\r\n"); http_close(c); return; } /* move the line to the begining of the buffer for later requests */ c->line_pos -= bol - c->line_buf; memmove(c->line_buf, bol, c->line_pos); return; } else { /* complete line, great! */ if (*s == '\r') *(s++) = 0; if (*s == '\n') *(s++) = 0; DBG(printf("complete line: {%s}\n", bol)); if (c->part == PART_REQUEST) { /* --- process request line --- */ unsigned int rll = strlen(bol); /* request line length */ char *url = strchr(bol, ' '); if (!url || rll < 14 || strncmp(bol + rll - 9, " HTTP/1.", 8)) { /* each request must have at least 14 characters [GET / HTTP/1.0] and have HTTP/1.x */ send_response(c, "HTTP/1.0 400 Bad Request\r\n\r\n", 28); http_close(c); return; } url++; if (!strncmp(bol + rll - 3, "1.0", 3)) c->attr |= HTTP_1_0; if (!strncmp(bol, "GET ", 4)) c->method = METHOD_GET; if (!strncmp(bol, "POST ", 5)) c->method = METHOD_POST; if (!strncmp(bol, "HEAD ", 5)) c->method = METHOD_HEAD; { char *mend = url - 1; /* we generate a header with the method so it can be passed to the handler */ if (!c->headers) c->headers = alloc_buffer(1024, NULL); /* make sure it fits */ if (c->headers->size - c->headers->length >= 18 + (mend - bol)) { if (!c->method) c->method = METHOD_OTHER; /* add "Request-Method: xxx" */ memcpy(c->headers->data + c->headers->length, "Request-Method: ", 16); c->headers->length += 16; memcpy(c->headers->data + c->headers->length, bol, mend - bol); c->headers->length += mend - bol; c->headers->data[c->headers->length++] = '\n'; } } if (!c->method) { send_http_response(c, " 501 Invalid or unimplemented method\r\n\r\n"); http_close(c); return; } bol[strlen(bol) - 9] = 0; c->url = strdup(url); c->part = PART_HEADER; DBG(printf("parsed request, method=%d, URL='%s'\n", (int)c->method, c->url)); } else if (c->part == PART_HEADER) { /* --- process headers --- */ char *k = bol; if (!c->headers) c->headers = alloc_buffer(1024, NULL); if (c->headers) { /* record the header line in the buffer */ int l = strlen(bol); if (l) { /* this should be really always true */ if (c->headers->length + l + 1 > c->headers->size) { /* not enough space? */ int fits = c->headers->size - c->headers->length; int needs = 2048; if (fits) { memcpy(c->headers->data + c->headers->length, bol, fits); c->headers->length += fits; } while (l + 1 - fits >= needs) needs <<= 1; if (alloc_buffer(needs, c->headers)) { c->headers = c->headers->next; memcpy(c->headers->data, bol + fits, l - fits); c->headers->length = l - fits; c->headers->data[c->headers->length++] = '\n'; } } else { memcpy(c->headers->data + c->headers->length, bol, l); c->headers->length += l; c->headers->data[c->headers->length++] = '\n'; } } } /* lower-case all header names */ while (*k && *k != ':') { if (*k >= 'A' && *k <= 'Z') *k |= 0x20; k++; } if (*k == ':') { *(k++) = 0; while (*k == ' ' || *k == '\t') k++; DBG(printf("header '%s' => '%s'\n", bol, k)); if (!strcmp(bol, "upgrade") && !strcmp(k, "websocket")) c->attr |= WS_UPGRADE; if (!strcmp(bol, "content-length")) { c->attr |= CONTENT_LENGTH; c->content_length = atol(k); } if (!strcmp(bol, "content-type")) { char *l = k; /* change the content type to lower case, however, stop at ; since training content may be case-sensitive such as multipart-boundary (see #149) */ while (*l && *l != ';') { if (*l >= 'A' && *l <= 'Z') *l |= 0x20; l++; } c->attr |= CONTENT_TYPE; if (c->content_type) free(c->content_type); c->content_type = strdup(k); if (!strncmp(k, "application/x-www-form-urlencoded", 33)) c->attr |= CONTENT_FORM_UENC; } if (!strcmp(bol, "host")) c->attr |= HOST_HEADER; if (!strcmp(bol, "connection")) { char *l = k; while (*l) { if (*l >= 'A' && *l <= 'Z') *l |= 0x20; l++; } if (!strncmp(k, "close", 5)) c->attr |= CONNECTION_CLOSE; } if (!strcmp(bol, "sec-websocket-key")) { if (c->ws_key) free(c->ws_key); c->ws_key = strdup(k); } if (!strcmp(bol, "sec-websocket-protocol")) { if (c->ws_protocol) free(c->ws_protocol); c->ws_protocol = strdup(k); } if (!strcmp(bol, "sec-websocket-version")) { if (c->ws_version) free(c->ws_version); c->ws_version = strdup(k); } DBG(Rprintf(" [attr = %x]\n", c->attr)); } } } } } if (c->part < PART_BODY) { /* we end here if we processed a buffer of exactly one line */ c->line_pos = 0; return; } } if (c->part == PART_BODY && c->body) { /* BODY - this branch always returns */ if (c->body_pos < c->content_length) { /* need to receive more ? */ DBG(printf("BODY: body_pos=%d, content_length=%ld\n", c->body_pos, c->content_length)); n = srv->recv(c, c->body + c->body_pos, c->content_length - c->body_pos); DBG(printf(" [recv n=%d - had %u of %lu]\n", n, c->body_pos, c->content_length)); c->line_pos = 0; if (n < 0) { /* error, scrap this worker */ http_close(c); return; } if (n == 0) { /* connection closed -> try to process and then remove */ process_request(c); http_close(c); return; } c->body_pos += n; } if (c->body_pos == c->content_length) { /* yay! we got the whole body */ process_request(c); if (c->attr & CONNECTION_CLOSE || c->line_pos) { /* we have to close the connection if there was a double-hit */ http_close(c); return; } /* keep-alive - reset the worker so it can process a new request */ if (c->url) { free(c->url); c->url = NULL; } if (c->body) { free(c->body); c->body = NULL; } if (c->content_type) { free(c->content_type); c->content_type = NULL; } if (c->headers) { free_buffer(c->headers); c->headers = NULL; } if (c->ws_key) { free(c->ws_key); c->ws_key = NULL; } if (c->ws_protocol) { free(c->ws_protocol); c->ws_protocol = NULL; } if (c->ws_version) { free(c->ws_version); c->ws_version = NULL; } c->line_pos = 0; c->body_pos = 0; c->method = 0; c->part = PART_REQUEST; c->attr = 0; c->content_length = 0; return; } } /* we enter here only if recv was used to leave the headers with no body */ if (c->part == PART_BODY && !c->body) { char *s = c->line_buf; if (c->line_pos > 0) { if ((s[0] != '\r' || s[1] != '\n') && (s[0] != '\n')) { send_http_response(c, " 411 length is required for non-empty body\r\nConnection: close\r\n\r\n"); http_close(c); return; } /* empty body, good */ process_request(c); if (c->attr & CONNECTION_CLOSE) { http_close(c); return; } else { /* keep-alive */ int sh = 1; if (s[0] == '\r') sh++; if (c->line_pos <= sh) c->line_pos = 0; else { /* shift the remaining buffer */ memmove(c->line_buf, c->line_buf + sh, c->line_pos - sh); c->line_pos -= sh; } /* keep-alive - reset the worker so it can process a new request */ if (c->url) { free(c->url); c->url = NULL; } if (c->body) { free(c->body); c->body = NULL; } if (c->content_type) { free(c->content_type); c->content_type = NULL; } if (c->headers) { free_buffer(c->headers); c->headers = NULL; } if (c->ws_key) { free(c->ws_key); c->ws_key = NULL; } if (c->ws_protocol) { free(c->ws_protocol); c->ws_protocol = NULL; } if (c->ws_version) { free(c->ws_version); c->ws_version = NULL; } c->body_pos = 0; c->method = 0; c->part = PART_REQUEST; c->attr = 0; c->content_length = 0; return; } } n = srv->recv(c, c->line_buf + c->line_pos, LINE_BUF_SIZE - c->line_pos - 1); if (n < 0) { /* error, scrap this worker */ http_close(c); return; } if (n == 0) { /* connection closed -> try to process and then remove */ process_request(c); http_close(c); return; } if ((s[0] != '\r' || s[1] != '\n') && (s[0] != '\n')) { send_http_response(c, " 411 length is required for non-empty body\r\nConnection: close\r\n\r\n"); http_close(c); return; } } } /* from Rserve.c */ int check_tls_client(int verify, const char *cn); static void HTTP_connected(void *parg) { args_t *arg = (args_t*) parg; if (Rserve_prepare_child(arg) != 0) { /* parent or error */ free(arg); return; } if (!(arg->line_buf = (char*) malloc(LINE_BUF_SIZE))) { RSEprintf("ERROR: unable to allocate line buffer\n"); free(arg); return; } if ((arg->srv->flags & SRV_TLS) && shared_tls(0)) { char cn[256]; add_tls(arg, shared_tls(0), 1); if (check_tls_client(verify_peer_tls(arg, cn, 256), cn)) { close_tls(arg); closesocket(arg->s); free_args(arg); return; } } while (arg->s != -1) http_input_iteration(arg); free_args(arg); } server_t *create_HTTP_server(int port, int flags) { server_t *srv = create_server(port, 0, 0, flags); #ifdef RSERV_DEBUG fprintf(stderr, "create_HTTP_server(port = %d, flags=0x%x)\n", port, flags); #endif if (srv) { srv->connected = HTTP_connected; /* srv->send_resp = */ srv->recv = server_recv; srv->send = server_send; srv->fin = server_fin; add_server(srv); return srv; } return 0; } /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/sha1.c0000644000175100001440000002616714531234224013341 0ustar hornikusers/* * sha1.c * * Description: * This file implements the Secure Hashing Algorithm 1 as * defined in FIPS PUB 180-1 published April 17, 1995. * * The SHA-1, produces a 160-bit message digest for a given * data stream. It should take about 2**n steps to find a * message with the same digest as a given message and * 2**(n/2) to find any two messages with the same digest, * when n is the digest size in bits. Therefore, this * algorithm can serve as a means of providing a * "fingerprint" for a message. * * Portability Issues: * SHA-1 is defined in terms of 32-bit "words". This code * uses (included via "sha1.h" to define 32 and 8 * bit unsigned integer types. If your C compiler does not * support 32 bit unsigned integers, this code is not * appropriate. * * Caveats: * SHA-1 is designed to work with messages less than 2^64 bits * long. Although SHA-1 allows a message digest to be generated * for messages of any number of bits less than 2^64, this * implementation only works with messages with a length that is * a multiple of the size of an 8-bit character. * */ #include enum { shaSuccess = 0, shaNull, /* Null pointer parameter */ shaInputTooLong, /* input data too long */ shaStateError /* called Input after Result */ }; #define SHA1HashSize 20 /* * This structure will hold context information for the SHA-1 * hashing operation */ typedef struct SHA1Context { uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ uint32_t Length_Low; /* Message length in bits */ uint32_t Length_High; /* Message length in bits */ /* Index into message block array */ int_least16_t Message_Block_Index; uint8_t Message_Block[64]; /* 512-bit message blocks */ int Computed; /* Is the digest computed? */ int Corrupted; /* Is the message digest corrupted? */ } SHA1Context; /* * Define the SHA1 circular left shift macro */ #define SHA1CircularShift(bits,word) \ (((word) << (bits)) | ((word) >> (32-(bits)))) /* Local Function Prototyptes */ static void SHA1PadMessage(SHA1Context *); static void SHA1ProcessMessageBlock(SHA1Context *); /* * SHA1Reset * * Description: * This function will initialize the SHA1Context in preparation * for computing a new SHA1 message digest. * * Parameters: * context: [in/out] * The context to reset. * * Returns: * sha Error Code. * */ static int SHA1Reset(SHA1Context *context) { if (!context) { return shaNull; } context->Length_Low = 0; context->Length_High = 0; context->Message_Block_Index = 0; context->Intermediate_Hash[0] = 0x67452301; context->Intermediate_Hash[1] = 0xEFCDAB89; context->Intermediate_Hash[2] = 0x98BADCFE; context->Intermediate_Hash[3] = 0x10325476; context->Intermediate_Hash[4] = 0xC3D2E1F0; context->Computed = 0; context->Corrupted = 0; return shaSuccess; } /* * SHA1Result * * Description: * This function will return the 160-bit message digest into the * Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 19th element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA-1 hash. * Message_Digest: [out] * Where the digest is returned. * * Returns: * sha Error Code. * */ static int SHA1Result( SHA1Context *context, uint8_t Message_Digest[SHA1HashSize]) { int i; if (!context || !Message_Digest) { return shaNull; } if (context->Corrupted) { return context->Corrupted; } if (!context->Computed) { SHA1PadMessage(context); for(i=0; i<64; ++i) { /* message may be sensitive, clear it out */ context->Message_Block[i] = 0; } context->Length_Low = 0; /* and clear length */ context->Length_High = 0; context->Computed = 1; } for(i = 0; i < SHA1HashSize; ++i) { Message_Digest[i] = context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ); } return shaSuccess; } /* * SHA1Input * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. * */ static int SHA1Input( SHA1Context *context, const uint8_t *message_array, unsigned length) { if (!length) { return shaSuccess; } if (!context || !message_array) { return shaNull; } if (context->Computed) { context->Corrupted = shaStateError; return shaStateError; } if (context->Corrupted) { return context->Corrupted; } while(length-- && !context->Corrupted) { context->Message_Block[context->Message_Block_Index++] = (*message_array & 0xFF); context->Length_Low += 8; if (context->Length_Low == 0) { context->Length_High++; if (context->Length_High == 0) { /* Message is too long */ context->Corrupted = 1; } } if (context->Message_Block_Index == 64) { SHA1ProcessMessageBlock(context); } message_array++; } return shaSuccess; } /* * SHA1ProcessMessageBlock * * Description: * This function will process the next 512 bits of the message * stored in the Message_Block array. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * Many of the variable names in this code, especially the * single character names, were used because those were the * names used in the publication. * * */ static void SHA1ProcessMessageBlock(SHA1Context *context) { const uint32_t K[] = { /* Constants defined in SHA-1 */ 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; int t; /* Loop counter */ uint32_t temp; /* Temporary word value */ uint32_t W[80]; /* Word sequence */ uint32_t A, B, C, D, E; /* Word buffers */ /* * Initialize the first 16 words in the array W */ for(t = 0; t < 16; t++) { W[t] = context->Message_Block[t * 4] << 24; W[t] |= context->Message_Block[t * 4 + 1] << 16; W[t] |= context->Message_Block[t * 4 + 2] << 8; W[t] |= context->Message_Block[t * 4 + 3]; } for(t = 16; t < 80; t++) { W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); } A = context->Intermediate_Hash[0]; B = context->Intermediate_Hash[1]; C = context->Intermediate_Hash[2]; D = context->Intermediate_Hash[3]; E = context->Intermediate_Hash[4]; for(t = 0; t < 20; t++) { temp = SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; E = D; D = C; C = SHA1CircularShift(30,B); B = A; A = temp; } for(t = 20; t < 40; t++) { temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; E = D; D = C; C = SHA1CircularShift(30,B); B = A; A = temp; } for(t = 40; t < 60; t++) { temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; E = D; D = C; C = SHA1CircularShift(30,B); B = A; A = temp; } for(t = 60; t < 80; t++) { temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; E = D; D = C; C = SHA1CircularShift(30,B); B = A; A = temp; } context->Intermediate_Hash[0] += A; context->Intermediate_Hash[1] += B; context->Intermediate_Hash[2] += C; context->Intermediate_Hash[3] += D; context->Intermediate_Hash[4] += E; context->Message_Block_Index = 0; } /* * SHA1PadMessage * * Description: * According to the standard, the message must be padded to an even * 512 bits. The first padding bit must be a '1'. The last 64 * bits represent the length of the original message. All bits in * between should be 0. This function will pad the message * according to those rules by filling the Message_Block array * accordingly. It will also call the ProcessMessageBlock function * provided appropriately. When it returns, it can be assumed that * the message digest has been computed. * * Parameters: * context: [in/out] * The context to pad * ProcessMessageBlock: [in] * The appropriate SHA*ProcessMessageBlock function * Returns: * Nothing. * */ static void SHA1PadMessage(SHA1Context *context) { /* * Check to see if the current message block is too small to hold * the initial padding bits and length. If so, we will pad the * block, process it, and then continue padding into a second * block. */ if (context->Message_Block_Index > 55) { context->Message_Block[context->Message_Block_Index++] = 0x80; while(context->Message_Block_Index < 64) { context->Message_Block[context->Message_Block_Index++] = 0; } SHA1ProcessMessageBlock(context); while(context->Message_Block_Index < 56) { context->Message_Block[context->Message_Block_Index++] = 0; } } else { context->Message_Block[context->Message_Block_Index++] = 0x80; while(context->Message_Block_Index < 56) { context->Message_Block[context->Message_Block_Index++] = 0; } } /* * Store the message length as the last 8 octets */ context->Message_Block[56] = context->Length_High >> 24; context->Message_Block[57] = context->Length_High >> 16; context->Message_Block[58] = context->Length_High >> 8; context->Message_Block[59] = context->Length_High; context->Message_Block[60] = context->Length_Low >> 24; context->Message_Block[61] = context->Length_Low >> 16; context->Message_Block[62] = context->Length_Low >> 8; context->Message_Block[63] = context->Length_Low; SHA1ProcessMessageBlock(context); } void sha1hash(const char *buf, int len, unsigned char hash[20]) { SHA1Context sha; SHA1Reset(&sha); SHA1Input(&sha, (const unsigned char *) buf, len); SHA1Result(&sha, hash); } Rserve/src/client/0000755000175100001440000000000014531234224013603 5ustar hornikusersRserve/src/client/README.txt0000644000175100001440000000110014531234224015271 0ustar hornikusersThis directory contains various Rserve clients: cxx - minimal C++ client java - Java client based on the REngine API. This is the actively developed Java client as it is more flexible and consistent than the older JRclient. It supports multiple back-ends such as Rserve or JRI. php - minimal PHP client and example code that can be used to run FastRWeb via PHP instead of CGI NOTE: a more complete PHP client written by Clement Turbelin based on this minimal version is available from http://code.google.com/p/rserve-php Rserve/src/client/cxx/0000755000175100001440000000000014531234224014405 5ustar hornikusersRserve/src/client/cxx/rcons.cc0000644000175100001440000000542514531234224016046 0ustar hornikusers/* * Simple console that uses C++ interface to Rserve * Copyright (C) 2004 Simon Urbanek, All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License * * 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 Leser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ */ #include using std::cout; #define MAIN // we are the main program, we need to define this #define SOCK_ERRORS // we will use verbose socket errors #include "Rconnection.h" #ifdef READLINE #include #include #endif #ifdef READLINE char *c=0; #else char c[1024]; #endif int main(int argc, char **argv) { initsocks(); // this is needed for Win32 - it does noting on unix Rconnection *rc = new Rconnection(); int i=rc->connect(); if (i) { char msg[128]; sockerrorchecks(msg, 128, -1); printf("unable to connect (result=%d, socket:%s).\n", i, msg); return i; } printf("connected. Type \"q\" to quit.\n"); do { #ifdef READLINE c=readline("Rcli> "); if (c && *c) add_history(c); #else printf("Rcli> "); c[1023]=0; fgets(c,1023,stdin); char *rq=c; while(*rq && rq-c<1023) { if (*rq=='\n') *rq=0; rq++; } #endif if (!strcmp(c,"q") || !strcmp(c,"quit") || !strcmp(c,"exit")) { cout << "ok, you got enough, right? leaving.\n"; break; } int res=0; if (!strcmp(c,"shutdown")) { // this is a demo of low-level commands being send via "request" Rmessage *msg=new Rmessage(); cout << "performing shutdown.\n"; res=rc->request(msg,CMD_shutdown); delete(msg); } else if (*c) { // this is a regular "eval" demo Rexp *xp=rc->eval(c, &res); if (xp) { cout << "type=" << xp->type << ", len=" << xp->len << ", result:" << *xp << "\n"; if (xp->attr) cout << "attributes: " << *xp->attr << "\n"; delete(xp); } else cout << "eval failed with result " << res << "\n"; } if (res) { cout << "request failed with error code " << res << "\n"; break; } } while (1); delete(rc); return 0; } Rserve/src/client/cxx/Rconnection.cc0000644000175100001440000006273714531234224017214 0ustar hornikusers/* * C++ Interface to Rserve * Copyright (C) 2004-8 Simon Urbanek, All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License * * 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 Leser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Although this code is licensed under LGPL v2.1, we strongly encourage * everyone modifying this software to contribute back any improvements and * bugfixes to the project for the benefit all other users. Thank you. * * $Id$ */ /* external defines: SWAPEND - needs to be defined for platforms with inverse endianess related to Intel see also SOCK_ERROR, MAIN and other defines in sisocks.h */ /* locally generated status error and return codes: -1 - operation failed (e.g. connect failed) -2 - handhake failed -3 - invalid ID string -4 - protocol not supported -5 - not connected -6 - - unused - -7 - remote connection close -8 - malformed packet -9 - send error -10 - out of memory -11 - operation is unsupported (e.g. unix login while crypt is not linked) -12 - eval didn't return a SEXP (possibly the server is too old/buggy or crashed) -13 - message requires 64-bit sizes but this binary is linked as 32-bit */ #include "Rconnection.h" #include #include "sisocks.h" #ifdef unix #include #include #else #define AF_LOCAL -1 #endif #if defined HAVE_NETINET_TCP_H && defined HAVE_NETINET_IN_H #define CAN_TCP_NODELAY #include #include #endif #ifdef Win32 #define CAN_TCP_NODELAY #endif #include "Rsrv.h" #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif // NOTE: 0103 compatibility has not been established! use at your own risk! static const char *myID = "Rsrv0103QAP1"; /* this client supports up to protocol version 0103 */ #define IS_LIST_TYPE_(TYPE) ((TYPE) == XT_LIST || (TYPE) == XT_LIST_NOTAG || (TYPE) == XT_LIST_TAG) #define IS_SYMBOL_TYPE_(TYPE) ((TYPE) == XT_SYM || (TYPE) == XT_SYMNAME) static Rexp *new_parsed_Rexp(unsigned int *d, Rmessage *msg) { int type=ptoi(*d)&0x3f; #ifdef DEBUG_CXX printf("new_parsed_Rexp(%p, %p) type=%d\n", d, msg, type); #endif if (type==XT_ARRAY_INT || type==XT_INT) return new Rinteger(d,msg); if (type==XT_ARRAY_DOUBLE || type==XT_DOUBLE) return new Rdouble(d,msg); if (IS_LIST_TYPE_(type)) return new Rlist(d,msg); if (type==XT_VECTOR) return new Rvector(d,msg); if (type==XT_STR) return new Rstring(d,msg); if (type==XT_SYM || type==XT_SYMNAME) return new Rsymbol(d,msg); if (type==XT_ARRAY_STR) return new Rstrings(d,msg); return new Rexp(d,msg); } static Rexp *new_parsed_Rexp_from_Msg(Rmessage *msg) { int hl=1; unsigned int *hp=msg->par[0]; Rsize_t plen=hp[0]>>8; if ((hp[0]&DT_LARGE)>0) { hl++; plen|=((Rsize_t)hp[1])<<24; } return new_parsed_Rexp(hp+hl,msg); } Rmessage::Rmessage() { complete=0; data=0; len=0; } Rmessage::Rmessage(int cmd) { memset(&head,0,sizeof(head)); head.cmd = cmd; data=0; len=0; complete=1; } Rmessage::Rmessage(int cmd, const char *txt) { memset(&head,0,sizeof(head)); int tl=strlen(txt)+1; if ((tl&3)>0) tl=(tl+4)&0xffffc; // allign the text len=tl+4; // message length is tl + 4 (short format only) head.cmd=cmd; head.len=len; data=(char*)malloc(tl+16); memset(data,0,tl+16); *((int*)data)=itop(SET_PAR(DT_STRING,tl)); strcpy(data+4,txt); complete=1; } Rmessage::Rmessage(int cmd, const void *buf, int dlen, int raw_data) { memset(&head,0,sizeof(head)); len=(raw_data)?dlen:(dlen+4); head.cmd=cmd; head.len=len; data=(char*)malloc(len); memcpy(data, (raw_data)?buf:((char*)buf+4), dlen); if (!raw_data) *((int*)data)=itop(SET_PAR(DT_BYTESTREAM,dlen)); complete=1; } Rmessage::Rmessage(int cmd, int i) { memset(&head,0,sizeof(head)); len=8; // DT_INT+len (4) + payload-1xINT (4) head.cmd=cmd; head.len=len; data=(char*)malloc(8); *((int*)data)=itop(SET_PAR(DT_INT,4)); ((int*)data)[1]=itop(i); complete=1; } Rmessage::~Rmessage() { if(data) free(data); complete=0; } int Rmessage::read(int s) { complete=0; int n=recv(s,(char*)&head,sizeof(head),0); if (n!=sizeof(head)) { closesocket(s); s=-1; return (n==0)?-7:-8; } Rsize_t i = len = (unsigned int) (head.len = ptoi(head.len)); head.cmd = ptoi(head.cmd); head.msg_id = ptoi(head.msg_id); head.res = ptoi(head.res); #ifdef __LP64__ if (head.res) { /* process high bits of the length */ unsigned int len_lo = (unsigned int) head.len, len_hi = (unsigned int) head.res; len = (Rsize_t) (((unsigned long) len_lo) | (((unsigned long) len_hi) << 32)); i = len; } #else if (head.res) return -13; // 64-bit packet, but only 32-bit long is supported #endif if (i>0) { data=(char*) malloc(i); if (!data) { closesocket(s); s=-1; return -10; // out of memory } char *dp=data; while(i>0 && (n=recv(s,(char*)dp,i,0))>0) { dp+=n; i-=n; } if (i>0) { closesocket(s); s=-1; return -8; } } parse(); complete=1; return 0; } void Rmessage::parse() { pars=0; if (len<4) return; char *c=data, *eop=c+len; while (c>8; if ((p1&DT_LARGE)>0) { hs+=4; unsigned int p2=ptoi(pp[1]); len|=((Rsize_t)p2)<<24; } #ifdef DEBUG_CXX printf(" par %d: %d length %ld\n", pars, p1&0x3f, (long) len); #endif par[pars++]=(unsigned int*)c; c+=hs; c+=len; if (pars>15) break; // max 16 pars } } int Rmessage::send(int s) { int failed=0; head.cmd=itop(head.cmd); head.len=itop(head.len); head.msg_id=itop(head.msg_id); head.res=itop(head.res); if (::send(s,(char*)&head,sizeof(head),0)!=sizeof(head)) failed=-1; if (!failed && len>0 && (Rsize_t)::send(s,data,len,0)!=len) failed=-1; head.cmd=ptoi(head.cmd); head.len=ptoi(head.len); head.msg_id=ptoi(head.msg_id); head.res=ptoi(head.res); return failed; } Rexp::Rexp(Rmessage *msg) { #ifdef DEBUG_CXX printf("new Rexp@%x\n", this); #endif master=0; rcount=0; attr=0; attribs=0; this->msg=msg; int hl=1; unsigned int *hp=msg->par[0]; Rsize_t plen=hp[0]>>8; if ((hp[0]&DT_LARGE)>0) { hl++; plen|=((Rsize_t)hp[1])<<24; } next=parse(hp+hl); } Rexp::Rexp(unsigned int *pos, Rmessage *msg) { #ifdef DEBUG_CXX printf("new Rexp@%x\n", this); #endif attr=0; master=0; this->msg=msg; rcount=0; attribs=0; next=parse(pos); } Rexp::Rexp(int type, const char *data, Rsize_t len, Rexp *attr) { this->attr=attr; master=this; rcount=0; attribs=0; this->type=type; this->msg=0; if (len>0) { #ifdef DEBUG_CXX fprintf(stderr, "Rexp::Rexp %p: allocating %lu bytes\n", this, (unsigned long) len); #endif this->data=(char*) malloc(len); memcpy(this->data, data, len); this->len=len; } else this->len=0; next=(char*)data+this->len; } Rexp::~Rexp() { #ifdef DEBUG_CXX printf("releasing Rexp@%p\n", this); #endif if (attr) delete(attr); attr=0; if (master) { if (master==this) { free(data); len=0; } else master->rcount--; master=0; } if (msg) { if (rcount>0) fprintf(stderr, "WARNING! Rexp master %lx delete requested, but %d object(s) are using our memory - refusing to free, leaking...\n", (long)this, rcount); else delete(msg); } msg=0; } void Rexp::set_master(Rexp *m) { if (master) master->rcount--; master=m; if (m) m->rcount++; } char *Rexp::parse(unsigned int *pos) { // plen is not used this->pos=pos; int hl=1; unsigned int p1=ptoi(pos[0]); len=p1>>8; if ((p1&XT_LARGE)>0) { hl++; len|=((Rsize_t)(ptoi(pos[1])))<<24; } data=(char*)(pos+hl); if (p1&XT_HAS_ATTR) { attr=new_parsed_Rexp((unsigned int*)data, 0); len-=attr->next-data; data=attr->next; if (master || msg) attr->set_master(master?master:this); } type=p1&0x3f; #ifdef DEBUG_CXX printf("Rexp(type=%d, len=%d, attr=%p)\n", type, len, attr); #endif return data+len; } void Rexp::store(char *buf) { int hl=4; unsigned int *i = (unsigned int*)buf; i[0]=SET_PAR(type, len); i[0]=itop(i[0]); if (len>0x7fffff) { buf[0]|=XT_LARGE; i[1]=itop(len>>24); hl+=4; } memcpy(buf+hl, data, len); } Rexp *Rexp::attribute(const char *name) { return (attr && IS_LIST_TYPE_(attr->type)) ? ((Rlist*)attr)->entryByTagName(name) : 0; } const char **Rexp::attributeNames() { if (!attr || !IS_LIST_TYPE_(attr->type)) return 0; if (attribs == 0) { // let us cache attribute names Rlist *l = (Rlist*) attr; while (l && (IS_LIST_TYPE_(l->type))) { if (l->tag && IS_SYMBOL_TYPE_(l->tag->type)) attribs++; l = l->tail; } attrnames = (const char**) malloc(sizeof(char*)*(attribs+1)); l = (Rlist*) attr; while (l && IS_LIST_TYPE_(l->type)) { if (l->tag && IS_SYMBOL_TYPE_(l->tag->type)) attrnames[attribs++] = ((Rsymbol*)l->tag)->symbolName(); l = l->tail; } attrnames[attribs] = 0; } return attrnames; } void Rinteger::fix_content() { if (len<0 || !data) return; #ifdef SWAPEND int *i = (int*) data; int *j = (int*) (data+len); while (inext; if (ptrnext; if (ptrtype!=XT_LIST) { // if tail is not a list, then something is wrong - just delete it delete(tail); tail=0; } } } } } else if (type == XT_LIST_NOTAG) { /* new style list w/o tags */ Rlist *lt = this; int n = 0; while (ptr < eod) { Rexp *h = new_parsed_Rexp((unsigned int*) ptr, 0); if (!h) break; if (n) lt = lt->tail = new Rlist(type, h, 0, h->next, msg); else lt->head = h; n++; ptr = h->next; } } else if (type == XT_LIST_TAG) { /* new style list with tags */ Rlist *lt = this; int n = 0; while (ptr < eod) { Rexp *h = new_parsed_Rexp((unsigned int*) ptr, 0); #ifdef DEBUG_CXX printf(" LIST_TAG: n=%d, ptr=%p, h=%p\n", n, ptr, h); #endif if (!h) break; ptr = h->next; Rexp *t = new_parsed_Rexp((unsigned int*) ptr, 0); #ifdef DEBUG_CXX printf(" tag=%p (ptr=%p)\n", t, ptr); #endif if (!t) break; if (n) lt = lt->tail = new Rlist(type, h, t, t->next, msg); else { lt->head = h; lt->tag = t; } ptr = t->next; n++; } next = ptr; } #ifdef DEBUG_CXX printf(" end of list %p, ptr=%p\n", this, ptr); #endif } Rvector::~Rvector() { int i=0; while(itype==XT_STR) sc++; i++; } if (sc==0) return 0; strs=(char**)malloc(sizeof(char*)*(sc+1)); i=0; sc=0; while (itype==XT_STR) strs[sc++]=((Rstring*)cont[i])->string(); i++; } strs[sc]=0; return strs; } int Rvector::indexOf(Rexp *exp) { int i=0; while (itype==XT_STR && !strcmp(((Rstring*)cont[i])->string(),str)) return i; i++; } return -1; } int Rstrings::indexOfString(const char *str) { unsigned int i = 0; while (i < nel) { if (cont[i] && !strcmp(cont[i], str)) return i; i++; } return -1; } Rexp* Rvector::byName(const char *name) { /* here we are not using IS_LIST_TYPE_() because XT_LIST_NOTAG is guaranteed to not match */ if (count < 1 || !attr || (attr->type!=XT_LIST && attr->type != XT_LIST_TAG)) return 0; Rexp *e = ((Rlist*) attr)->head; if (((Rlist*) attr)->tag) e = ((Rlist*) attr)->entryByTagName("names"); if (!e || (e->type!=XT_VECTOR && e->type!=XT_ARRAY_STR && e->type!=XT_STR)) return 0; if (e->type == XT_VECTOR) { int pos = ((Rvector*)e)->indexOfString(name); if (pos>-1 && postype == XT_ARRAY_STR) { int pos = ((Rstrings*)e)->indexOfString(name); if (pos>-1 && posstring(),name)) return cont[0]; } return 0; } void Rvector::fix_content() { char *ptr = data; char *eod = data+len; capacity=16; cont=(Rexp**) malloc(sizeof(Rexp*)*capacity); while (ptrnext; else break; count++; } } Rconnection::Rconnection(const char *host, int port) { if (!host) host = "127.0.0.1"; this->host = strdup(host); this->port = port; family = (port==-1) ? AF_LOCAL : AF_INET; s = -1; auth = 0; salt[0] = '.'; salt[1] = '.'; session_key = 0; } Rconnection::Rconnection(Rsession *session) { const char *sHost = session->host(); if (!sHost) sHost="127.0.0.1"; this->host = strdup(sHost); this->port = session->port(); family = AF_INET; s = -1; auth = 0; salt[0]='.'; salt[1]='.'; session_key = (char*) malloc(32); memcpy(session_key, session->key(), 32); } Rconnection::~Rconnection() { if (host) free(host); host = 0; if (s != -1) closesocket(s); s = -1; } int Rconnection::connect() { #ifdef unix struct sockaddr_un sau; #endif SAIN sai; char IDstring[33]; if (family==AF_INET) { memset(&sai,0,sizeof(sai)); build_sin(&sai,host,port); } else { #ifdef unix memset(&sau,0,sizeof(sau)); sau.sun_family=AF_LOCAL; strcpy(sau.sun_path,host); // FIXME: possible overflow! #else return -11; // unsupported #endif } IDstring[32]=0; int i; s=socket(family,SOCK_STREAM,0); if (family==AF_INET) { #ifdef CAN_TCP_NODELAY int opt=1; setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*) &opt, sizeof(opt)); #endif i=::connect(s,(SA*)&sai,sizeof(sai)); } #ifdef unix else i=::connect(s,(SA*)&sau,sizeof(sau)); #endif if (i==-1) { closesocket(s); s=-1; return -1; // connect failed } if (session_key) { // resume a session int n = send(s, session_key, 32, 0); if (n != 32) { closesocket(s); s = -1; return -2; // handshake failed (session key send error) } Rmessage *msg = new Rmessage(); int q = msg->read(s); delete msg; return q; } int n=recv(s,IDstring,32,0); if (n!=32) { closesocket(s); s=-1; return -2; // handshake failed (no IDstring) } if (strncmp(IDstring,myID,4)) { closesocket(s); s=-1; return -3; // invalid IDstring } if (strncmp(IDstring+8,myID+8,4) || strncmp(IDstring+4,myID+4,4)>0) { closesocket(s); s=-1; return -4; // protocol not supported } { int i=12; while (i<32) { if (!strncmp(IDstring+i, "ARuc", 4)) auth|=A_required|A_crypt; if (!strncmp(IDstring+i, "ARpt", 4)) auth|=A_required|A_plain; if (IDstring[i]=='K') { salt[0]=IDstring[i+1]; salt[1]=IDstring[i+2]; } i+=4; } } return 0; } int Rconnection::disconnect() { if (s>-1) { closesocket(s); s=-1; } return 0; } /**--- low-level functions --*/ int Rconnection::request(Rmessage *msg, int cmd, int len, void *par) { struct phdr ph; if (s==-1) return -5; // not connected memset(&ph,0,sizeof(ph)); ph.len=itop(len); ph.cmd=itop(cmd); if (send(s,(char*)&ph,sizeof(ph),0)!=sizeof(ph)) { closesocket(s); s=-1; return -9; } if (len>0 && send(s,(char*)par,len,0)!=len) { closesocket(s); s=-1; return -9; } return msg->read(s); } int Rconnection::request(Rmessage *targetMsg, Rmessage *contents) { if (s==-1) return -5; // not connected if (contents->send(s)) { closesocket(s); s=-1; return -9; // send error } return targetMsg->read(s); } /** --- high-level functions -- */ int Rconnection::shutdown(const char *key) { Rmessage *msg = new Rmessage(); Rmessage *cm = key?new Rmessage(CMD_shutdown, key):new Rmessage(CMD_shutdown); int res = request(msg, cm); delete cm; delete msg; return res; } int Rconnection::assign(const char *symbol, Rexp *exp) { Rmessage *msg=new Rmessage(); Rmessage *cm=new Rmessage(CMD_setSEXP); int tl=strlen(symbol)+1; if (tl&3) tl=(tl+4)&0xfffc; Rsize_t xl=exp->storageSize(); Rsize_t hl=4+tl+4; if (xl>0x7fffff) hl+=4; cm->data=(char*) malloc(hl+xl); cm->head.len=cm->len=hl+xl; ((unsigned int*)cm->data)[0]=SET_PAR(DT_STRING, tl); ((unsigned int*)cm->data)[0]=itop(((unsigned int*)cm->data)[0]); strcpy(cm->data+4, symbol); ((unsigned int*)(cm->data+4+tl))[0]=SET_PAR((Rsize_t) ((xl>0x7fffff)?(DT_SEXP|DT_LARGE):DT_SEXP), (Rsize_t) xl); ((unsigned int*)(cm->data+4+tl))[0]=itop(((unsigned int*)(cm->data+4+tl))[0]); if (xl>0x7fffff) ((unsigned int*)(cm->data+4+tl))[1]=itop(xl>>24); exp->store(cm->data+hl); int res=request(msg,cm); delete (cm); if (res) { delete(msg); return res; } if (!res) res = CMD_STAT(msg->command()); delete(msg); return res; } int Rconnection::voidEval(const char *cmd) { int status=0; eval(cmd, &status, 1); return status; } Rexp *Rconnection::eval(const char *cmd, int *status, int opt) { /* opt = 1 -> void eval */ Rmessage *msg=new Rmessage(); Rmessage *cmdMessage=new Rmessage((opt&1)?CMD_voidEval:CMD_eval, cmd); int res=request(msg,cmdMessage); delete (cmdMessage); if (opt&1 && !res) { if (status) *status=0; // we should put response code here delete(msg); return 0; } if ((opt & 1) == 0 && !res && (msg->pars!=1 || (ptoi(msg->par[0][0])&0x3f)!=DT_SEXP)) { delete(msg); if (status) *status=-12; // returned object is not SEXP return 0; } if (res) { delete(msg); if (status) *status=res; return 0; } if (status) *status=0; return new_parsed_Rexp_from_Msg(msg); } /** detached eval (aka detached void eval) initiates eval and detaches the session. * @param cmd command to evaluate. If NULL equivalent to simple detach() * @param status optional status to be reported (zero on success) * @return object describintg he session. * Note that the caller is responsible for freeing the object if not needed. */ Rsession *Rconnection::detachedEval(const char *cmd, int *status) { Rmessage *msg = new Rmessage(); Rmessage *cmdMessage = cmd ? new Rmessage(CMD_detachedVoidEval, cmd) : new Rmessage(CMD_detachSession); int res = request(msg, cmdMessage); delete cmdMessage; if (res) { if (status) *status = res; delete msg; return 0; } if (msg->pars != 2 || PAR_TYPE(ptoi(msg->par[0][0])) != DT_INT || PAR_LEN(ptoi(msg->par[0][0])) != sizeof(int) || PAR_TYPE(ptoi(msg->par[1][0])) != DT_BYTESTREAM || PAR_LEN(ptoi(msg->par[1][0])) != 32) { // invalid contents if (status) *status = -12; delete msg; return 0; } Rsession *session = new Rsession(host, ptoi(msg->par[0][1]), (const char*) (msg->par[1] + 1)); delete msg; if (status) *status=0; return session; } Rsession *Rconnection::detach(int *status) { return detachedEval(0, status); } int Rconnection::openFile(const char *fn) { Rmessage *msg=new Rmessage(); Rmessage *cmdMessage=new Rmessage(CMD_openFile, fn); int res=request(msg,cmdMessage); delete (cmdMessage); if (!res) res=CMD_STAT(msg->command()); delete (msg); return res; } int Rconnection::createFile(const char *fn) { Rmessage *msg=new Rmessage(); Rmessage *cmdMessage=new Rmessage(CMD_createFile, fn); int res=request(msg,cmdMessage); delete (cmdMessage); if (!res) res=CMD_STAT(msg->command()); delete (msg); return res; } int Rconnection::readFile(char *buf, unsigned int len) { Rmessage *msg=new Rmessage(); Rmessage *cmdMessage=new Rmessage(CMD_readFile, len); int res=request(msg,cmdMessage); delete(cmdMessage); if (!res) { // FIXME: Rserve up to 0.4-0 actually sends buggy response - it ommits DT_BYTESTREAM header! if (msg->len > len) { // we're in trouble here - techincally we should not get this delete(msg); return CERR_malformed_packet; } if (msg->len > 0) memcpy(buf, msg->data, msg->len); int rl = msg->len; delete(msg); return rl; } delete(msg); return CERR_io_error; } int Rconnection::writeFile(const char *buf, unsigned int len) { Rmessage *msg=new Rmessage(); Rmessage *cmdMessage=new Rmessage(CMD_writeFile, buf, len); int res=request(msg,cmdMessage); delete(cmdMessage); if (!res && msg->command()==RESP_OK) { delete(msg); return 0; } delete(msg); // FIXME: this is not really true ... return (res==0)?CERR_io_error:res; } int Rconnection::closeFile() { Rmessage *msg=new Rmessage(); Rmessage *cmdMessage=new Rmessage(CMD_closeFile); int res=request(msg,cmdMessage); delete(cmdMessage); if (!res && msg->command()==RESP_OK) { delete(msg); return 0; } delete(msg); // FIXME: this is not really true ... return (res==0)?CERR_io_error:res; } int Rconnection::removeFile(const char *fn) { Rmessage *msg=new Rmessage(); Rmessage *cmdMessage=new Rmessage(CMD_removeFile, fn); int res=request(msg,cmdMessage); delete (cmdMessage); if (!res) res=CMD_STAT(msg->command()); delete (msg); return res; } int Rconnection::login(const char *user, const char *pwd) { char *authbuf, *c; if (!(auth&A_required)) return 0; authbuf=(char*) malloc(strlen(user)+strlen(pwd)+22); strcpy(authbuf, user); c=authbuf+strlen(user); *c='\n'; c++; strcpy(c,pwd); #ifdef unix if (auth&A_crypt) strcpy(c,crypt(pwd,salt)); #else if (!(auth&A_plain)) { free(authbuf); return CERR_auth_unsupported; } #endif Rmessage *msg=new Rmessage(); Rmessage *cmdMessage=new Rmessage(CMD_login, authbuf); int res=request(msg,cmdMessage); delete (cmdMessage); if (!res) res=CMD_STAT(msg->command()); delete (msg); free(authbuf); return res; } #ifdef CMD_ctrl /* server control methods */ int serverEval(const char *cmd); int serverSource(const char *fn); int serverShutdown(); int Rconnection::serverEval(const char *cmd) { Rmessage *msg = new Rmessage(); /* result message */ Rmessage *cmdMessage = new Rmessage(CMD_ctrlEval, cmd); /* request message */ int res = request(msg, cmdMessage); delete (cmdMessage); if (!res) res = CMD_STAT(msg->command()); delete (msg); return res; } int Rconnection::serverSource(const char *fn) { Rmessage *msg = new Rmessage(); /* result message */ Rmessage *cmdMessage = new Rmessage(CMD_ctrlSource, fn); /* request message */ int res = request(msg, cmdMessage); delete (cmdMessage); if (!res) res = CMD_STAT(msg->command()); delete (msg); return res; } int Rconnection::serverShutdown() { Rmessage *msg = new Rmessage(); /* result message */ Rmessage *cmdMessage = new Rmessage(CMD_ctrlShutdown); /* request message */ int res = request(msg, cmdMessage); delete (cmdMessage); if (!res) res = CMD_STAT(msg->command()); delete (msg); return res; } #endif Rserve/src/client/cxx/Rsrv.h0000644000175100001440000004614014531234224015517 0ustar hornikusers/* * Rsrv.h : constants and macros for Rserve client/server architecture * Copyright (C) 2002-22 Simon Urbanek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; version 2.1 of the License * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Note: This header file is licensed under LGPL to allow other * programs to use it under LGPL. Rserve itself is licensed under GPL. * * $Id$ */ /* external defines: MAIN - should be defined in just one file that will contain the fn definitions and variables */ #ifndef __RSRV_H__ #define __RSRV_H__ #ifndef NO_CONFIG_H #include "config.h" #endif #define RSRV_VER 0x01080d /* Rserve v1.8-13 */ #define default_Rsrv_port 6311 /* Rserve communication is done over any reliable connection-oriented protocol (usually TCP/IP or local sockets). After the connection is established, the server sends 32 bytes of ID-string defining the capabilities of the server. Each attribute of the ID-string is 4 bytes long and is meant to be user-readable (i.e. don't use special characters), and it's a good idea to make "\r\n\r\n" the last attribute the ID string must be of the form: [0] "Rsrv" - R-server ID signature [4] "0100" - version of the R server [8] "QAP1" - protocol used for communication (here Quad Attributes Packets v1) [12] any additional attributes follow. \r\n and '-' are ignored. optional attributes (in any order; it is legitimate to put dummy attributes, like "----" or " " between attributes): "R151" - version of R (here 1.5.1) "ARpt" - authorization required (here "pt"=plain text, "uc"=unix crypt, "m5"=MD5) connection will be closed if the first packet is not CMD_login. if more AR.. methods are specified, then client is free to use the one he supports (usually the most secure) "K***" - key if encoded authentification is challenged (*** is the key) for unix crypt the first two letters of the key are the salt required by the server */ /* QAP1 transport protocol header structure all int and double entries throughout the transfer are in Intel-endianess format: int=0x12345678 -> char[4]=(0x78,0x56,x34,0x12) functions/macros for converting from native to protocol format are available below Please note also that all values muse be quad-aligned, i.e. the length must be divisible by 4. This is automatically assured for int/double etc., but care must be taken when using strings and byte streams. */ struct phdr { /* always 16 bytes */ int cmd; /* command */ int len; /* length of the packet minus header (ergo -16) */ int msg_id; /* message id (since 1.8) [WAS:data offset behind header (ergo usually 0)] */ int res; /* high 32-bit of the packet length (since 0103 and supported on 64-bit platforms only) aka "lenhi", but the name was not changed to maintain compatibility */ }; /* each entry in the data section (aka parameter list) is preceded by 4 bytes: 1 byte : parameter type 3 bytes: length parameter list may be terminated by 0/0/0/0 but doesn't have to since "len" field specifies the packet length sufficiently (hint: best method for parsing is to allocate len+4 bytes, set the last 4 bytes to 0 and trverse list of parameters until (int)0 occurs since 0102: if the 7-th bit (0x40) in parameter type is set then the length is encoded in 7 bytes enlarging the header by 4 bytes. */ /* macros for handling the first int - split/combine (24-bit version only!) */ #define PAR_TYPE(X) ((X) & 255) #define PAR_LEN(X) (((unsigned int)(X)) >> 8) #define PAR_LENGTH PAR_LEN #define SET_PAR(TY,LEN) ((((unsigned int) (LEN) & 0xffffff) << 8) | ((TY) & 255)) #define CMD_STAT(X) (((X) >> 24)&127) /* returns the stat code of the response */ #define SET_STAT(X,s) ((X) | (((s) & 127) << 24)) /* sets the stat code */ #define CMD_RESP 0x10000 /* all responses have this flag set */ #define RESP_OK (CMD_RESP|0x0001) /* command succeeded; returned parameters depend on the command issued */ #define RESP_ERR (CMD_RESP|0x0002) /* command failed, check stats code attached string may describe the error */ #define CMD_OOB 0x20000 /* out-of-band data - i.e. unsolicited messages */ #define OOB_SEND (CMD_OOB | 0x1000) /* OOB send - unsolicited SEXP sent from the R instance to the client. 12 LSB are reserved for application-specific code */ #define OOB_MSG (CMD_OOB | 0x2000) /* OOB message - unsolicited message sent from the R instance to the client requiring a response. 12 LSB are reserved for application-specific code */ #define IS_OOB_SEND(X) (((X) & 0x0ffff000) == OOB_SEND) #define IS_OOB_MSG(X) (((X) & 0x0ffff000) == OOB_MSG) #define OOB_USR_CODE(X) ((X) & 0xfff) /* flag for create_server: Use QAP object-cap mode */ #define SRV_QAP_OC 0x40 /* mask of all flags that are relevant to QAP (so they can be passed through) */ #define SRV_QAP_FLAGS (SRV_QAP_OC) /* stat codes; 0-0x3f are reserved for program specific codes - e.g. for R connection they correspond to the stat of Parse command. the following codes are returned by the Rserv itself codes <0 denote Rerror as provided by R_tryEval */ #define ERR_auth_failed 0x41 /* auth.failed or auth.requested but no login came. in case of authentification failure due to name/pwd mismatch, server may send CMD_accessDenied instead */ #define ERR_conn_broken 0x42 /* connection closed or broken packet killed it */ #define ERR_inv_cmd 0x43 /* unsupported/invalid command */ #define ERR_inv_par 0x44 /* some parameters are invalid */ #define ERR_Rerror 0x45 /* R-error occured, usually followed by connection shutdown */ #define ERR_IOerror 0x46 /* I/O error */ #define ERR_notOpen 0x47 /* attempt to perform fileRead/Write on closed file */ #define ERR_accessDenied 0x48 /* this answer is also valid on CMD_login; otherwise it's sent if the server deosn;t allow the user to issue the specified command. (e.g. some server admins may block file I/O operations for some users) */ #define ERR_unsupportedCmd 0x49 /* unsupported command */ #define ERR_unknownCmd 0x4a /* unknown command - the difference between unsupported and unknown is that unsupported commands are known to the server but for some reasons (e.g. platform dependent) it's not supported. unknown commands are simply not recognized by the server at all. */ /* The following ERR_.. exist since 1.23/0.1-6 */ #define ERR_data_overflow 0x4b /* incoming packet is too big. currently there is a limit as of the size of an incoming packet. */ #define ERR_object_too_big 0x4c /* the requested object is too big to be transported in that way. If received after CMD_eval then the evaluation itself was successful. optional parameter is the size of the object */ /* since 1.29/0.1-9 */ #define ERR_out_of_mem 0x4d /* out of memory. the connection is usually closed after this error was sent */ /* since 0.6-0 */ #define ERR_ctrl_closed 0x4e /* control pipe to the master process is closed or broken */ /* since 0.4-0 */ #define ERR_session_busy 0x50 /* session is still busy */ #define ERR_detach_failed 0x51 /* unable to detach seesion (cannot determine peer IP or problems creating a listening socket for resume) */ /* since 1.7 */ #define ERR_disabled 0x61 /* feature is disabled */ #define ERR_unavailable 0x62 /* feature is not present in this build */ #define ERR_cryptError 0x63 /* crypto-system error */ #define ERR_securityClose 0x64 /* server-initiated close due to security violation (too many attempts, excessive timeout etc.) */ /* availiable commands */ #define CMD_login 0x001 /* "name\npwd" : - */ #define CMD_voidEval 0x002 /* string : - */ #define CMD_eval 0x003 /* string | encoded SEXP : encoded SEXP */ #define CMD_shutdown 0x004 /* [admin-pwd] : - */ /* security/encryption - all since 1.7-0 */ #define CMD_switch 0x005 /* string (protocol) : - */ #define CMD_keyReq 0x006 /* string (request) : bytestream (key) */ #define CMD_secLogin 0x007 /* bytestream (encrypted auth) : - */ #define CMD_OCcall 0x00f /* SEXP : SEXP -- it is the only command supported in object-capability mode and it requires that the SEXP is a language construct with OC reference in the first position */ #define CMD_OCinit 0x434f7352 /* SEXP -- 'RsOC' - command sent from the server in OC mode with the packet of initial capabilities. */ /* file I/O routines. server may answe */ #define CMD_openFile 0x010 /* fn : - */ #define CMD_createFile 0x011 /* fn : - */ #define CMD_closeFile 0x012 /* - : - */ #define CMD_readFile 0x013 /* [int size] : data... ; if size not present, server is free to choose any value - usually it uses the size of its static buffer */ #define CMD_writeFile 0x014 /* data : - */ #define CMD_removeFile 0x015 /* fn : - */ /* object manipulation */ #define CMD_setSEXP 0x020 /* string(name), REXP : - */ #define CMD_assignSEXP 0x021 /* string(name), REXP : - ; same as setSEXP except that the name is parsed */ /* session management (since 0.4-0) */ #define CMD_detachSession 0x030 /* : session key */ #define CMD_detachedVoidEval 0x031 /* string : session key; doesn't */ #define CMD_attachSession 0x032 /* session key : - */ /* control commands (since 0.6-0) - passed on to the master process */ /* Note: currently all control commands are asychronous, i.e. RESP_OK indicates that the command was enqueued in the master pipe, but there is no guarantee that it will be processed. Moreover non-forked connections (e.g. the default debug setup) don't process any control commands until the current client connection is closed so the connection issuing the control command will never see its result. */ #define CMD_ctrl 0x40 /* -- not a command - just a constant -- */ #define CMD_ctrlEval 0x42 /* string : - */ #define CMD_ctrlSource 0x45 /* string : - */ #define CMD_ctrlShutdown 0x44 /* - : - */ /* 'internal' commands (since 0.1-9) */ #define CMD_setBufferSize 0x081 /* [int sendBufSize] this commad allow clients to request bigger buffer sizes if large data is to be transported from Rserve to the client. (incoming buffer is resized automatically) */ #define CMD_setEncoding 0x082 /* string (one of "native","latin1","utf8") : -; since 0.5-3 */ /* special commands - the payload of packages with this mask does not contain defined parameters */ #define CMD_SPECIAL_MASK 0xf0 #define CMD_serEval 0xf5 /* serialized eval - the packets are raw serialized data without data header */ #define CMD_serAssign 0xf6 /* serialized assign - serialized list with [[1]]=name, [[2]]=value */ #define CMD_serEEval 0xf7 /* serialized expression eval - like serEval with one additional evaluation round */ /* data types for the transport protocol (QAP1) do NOT confuse with XT_.. values. */ #define DT_INT 1 /* int */ #define DT_CHAR 2 /* char */ #define DT_DOUBLE 3 /* double */ #define DT_STRING 4 /* 0 terminted string */ #define DT_BYTESTREAM 5 /* stream of bytes (unlike DT_STRING may contain 0) */ #define DT_SEXP 10 /* encoded SEXP */ #define DT_ARRAY 11 /* array of objects (i.e. first 4 bytes specify how many subsequent objects are part of the array; 0 is legitimate) */ #define DT_CUSTOM 32 /* custom types not defined in the protocol but used by applications */ #define DT_LARGE 64 /* new in 0102: if this flag is set then the length of the object is coded as 56-bit integer enlarging the header by 4 bytes */ /* XpressionTypes REXP - R expressions are packed in the same way as command parameters transport format of the encoded Xpressions: [0] int type/len (1 byte type, 3 bytes len - same as SET_PAR) [4] REXP attr (if bit 8 in type is set) [4/8] data .. */ #define XT_NULL 0 /* P data: [0] */ #define XT_INT 1 /* - data: [4]int */ #define XT_DOUBLE 2 /* - data: [8]double */ #define XT_STR 3 /* P data: [n]char null-term. strg. */ #define XT_LANG 4 /* - data: same as XT_LIST */ #define XT_SYM 5 /* - data: [n]char symbol name */ #define XT_BOOL 6 /* - data: [1]byte boolean (1=TRUE, 0=FALSE, 2=NA) */ #define XT_S4 7 /* P data: [0] */ #define XT_VECTOR 16 /* P data: [?]REXP,REXP,.. */ #define XT_LIST 17 /* - X head, X vals, X tag (since 0.1-5) */ #define XT_CLOS 18 /* P X formals, X body (closure; since 0.1-5) */ #define XT_SYMNAME 19 /* s same as XT_STR (since 0.5) */ #define XT_LIST_NOTAG 20 /* s same as XT_VECTOR (since 0.5) */ #define XT_LIST_TAG 21 /* P X tag, X val, Y tag, Y val, ... (since 0.5) */ #define XT_LANG_NOTAG 22 /* s same as XT_LIST_NOTAG (since 0.5) */ #define XT_LANG_TAG 23 /* s same as XT_LIST_TAG (since 0.5) */ #define XT_VECTOR_EXP 26 /* s same as XT_VECTOR (since 0.5) */ #define XT_VECTOR_STR 27 /* - same as XT_VECTOR (since 0.5 but unused, use XT_ARRAY_STR instead) */ #define XT_ARRAY_INT 32 /* P data: [n*4]int,int,.. */ #define XT_ARRAY_DOUBLE 33 /* P data: [n*8]double,double,.. */ #define XT_ARRAY_STR 34 /* P data: string,string,.. (string=byte,byte,...,0) padded with '\01' */ #define XT_ARRAY_BOOL_UA 35 /* - data: [n]byte,byte,.. (unaligned! NOT supported anymore) */ #define XT_ARRAY_BOOL 36 /* P data: int(n),byte,byte,... */ #define XT_RAW 37 /* P data: int(n),byte,byte,... */ #define XT_ARRAY_CPLX 38 /* P data: [n*16]double,double,... (Re,Im,Re,Im,...) */ #define XT_UNKNOWN 48 /* P data: [4]int - SEXP type (as from TYPEOF(x)) */ /* | +--- interesting flags for client implementations: P = primary type s = secondary type - its decoding is identical to a primary type and thus the client doesn't need to decode it separately. - = deprecated/removed. if a client doesn't need to support old Rserve versions, those can be safely skipped. Total primary: 4 trivial types (NULL, STR, S4, UNKNOWN) + 6 array types + 3 recursive types */ #define XT_LARGE 64 /* new in 0102: if this flag is set then the length of the object is coded as 56-bit integer enlarging the header by 4 bytes */ #define XT_HAS_ATTR 128 /* flag; if set, the following REXP is the attribute */ /* the use of attributes and vectors results in recursive storage of REXPs */ #define BOOL_TRUE 1 #define BOOL_FALSE 0 #define BOOL_NA 2 #define GET_XT(X) ((X)&63) #define GET_DT(X) ((X)&63) #define HAS_ATTR(X) (((X)&XT_HAS_ATTR)>0) #define IS_LARGE(X) (((X)&XT_LARGE)>0) #if defined sun && ! defined ALIGN_DOUBLES #define ALIGN_DOUBLES #endif #ifndef SIZEOF_SIZE_T #include /* defines SIZEOF_SIZE_T in case we missed it */ #endif #include /* for ptrdiff_t, which is required by C99 */ #include /* not directly used but for fixed-size int types */ #include /* s/size_t */ /* long vectors - we don't want to mandate Rinternals.h here so we use the minimal definition. By now size_t and ptrdiff_t should be ubiquitous so no more special cases */ typedef ssize_t rlen_t; /* we really need an unsigned type for safety in places where R is not involved */ typedef size_t urlen_t; /* this is used for alignment/masking */ #if ( SIZEOF_SIZE_T > 4 ) #define rlen_max ((rlen_t) 0x7fffffffffffffff) #else #define rlen_max ((rlen_t) 0x7fffffff) #endif /* functions/macros to convert native endianess of int/double for transport currently ony PPC style and Intel style are supported */ /* Since 0.4-5 we no longer use configure-time endianness tests to allow cross-compilation. Either BS_xx_ENDIAN constant is defined by configure and thus should be relied upon only if the compiler contants don't work */ #if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN_ #define SWAPEND 1 #elif defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN_ || defined BS_LITTLE_ENDIAN /* #undef SWAPEND */ #elif defined BS_BIG_ENDIAN #define SWAPEND 1 #elif __ia64__ || __i386__ || __x86_64__ /* take a guess based on the architecture (Intel-like) */ #define __LITTLE_ENDIAN__ 1 #elif __ppc__ || __ppc64__ /* any ppc */ #define __BIG_ENDIAN__ 1 #define SWAPEND 1 #elif ! defined Win32 /* Windows is little-endian is most cases, anywhere else we're stuck */ #error "Cannot determine endianness. Make sure config.h is included or __{BIG|LITTLE}_ENDIAN__ is defined ." #endif /* FIXME: all the mess below needs more efficient implementation - the current one is so messy to work around alignment problems on some platforms like Sun and HP 9000 */ #ifdef SWAPEND /* swap endianness - for PPC and co. */ #ifdef MAIN unsigned int itop(unsigned int i) { char b[4]; b[0]=((char*)&i)[3]; b[3]=((char*)&i)[0]; b[1]=((char*)&i)[2]; b[2]=((char*)&i)[1]; return *((unsigned int*)b); } double dtop(double i) { char b[8]; b[0]=((char*)&i)[7]; b[1]=((char*)&i)[6]; b[2]=((char*)&i)[5]; b[3]=((char*)&i)[4]; b[7]=((char*)&i)[0]; b[6]=((char*)&i)[1]; b[5]=((char*)&i)[2]; b[4]=((char*)&i)[3]; return *((double*)b); } void fixdcpy(void *t,void *s) { int i=0; while (i<8) { ((char*)t)[7-i]=((char*)s)[i]; i++; } } #else extern unsigned int itop(unsigned int i); extern double dtop(double i); extern void fixdcpy(void *t,void *s); #endif #define ptoi(X) itop(X) /* itop*itop=id */ #define ptod(X) dtop(X) #else #define itop(X) (X) #define ptoi(X) (X) #define dtop(X) (X) #define ptod(X) (X) #define fixdcpy(T,S) ((double*)(T))[0]=((double*)(S))[0]; #define NATIVE_COPY 1 #endif #ifndef HAVE_CONFIG_H /* this tiny function can be used to make sure that the endianess is correct (it is not included if the package was configured with autoconf since then it should be fine anyway) */ #ifdef MAIN int isByteSexOk(void) { int i; i=itop(0x12345678); return (*((char*)&i)==0x78); } #else extern int isByteSexOk(void); #endif #else #define isByteSexOk 1 #endif /* STANDALONE_RSERVE takes precedence over RSERVE_PKG */ #if defined STANDALONE_RSERVE && defined RSERVE_PKG #undef RSERVE_PKG #endif #endif /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/client/cxx/Makefile.in0000644000175100001440000000044614531234224016456 0ustar hornikusers# Makefile for C++ Rserve clients. # # $Id$ SRC = $(wildcard *.cc) OBJ = $(SRC:%.cc=%.o) DST = demo1 rcons rsdown LIBS+=@LIBS@ CPPFLAGS+=-DHAVE_CONFIG_H all: $(DST) $(OBJ) %: Rconnection.o %.o $(CXX) $^ -o $@ $(LIBS) debug: $(MAKE) CXXFLAGS=-g all clean: rm -rf *~ *.o \#* .\#* $(DST) Rserve/src/client/cxx/Rconnection.h0000644000175100001440000003225214531234224017043 0ustar hornikusers/* * C++ Interface to Rserve * Copyright (C) 2004-8 Simon Urbanek, All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License * * 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 Leser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Although this code is licensed under LGPL v2.1, we strongly encourage * everyone modifying this software to contribute back any improvements and * bugfixes to the project for the benefit all other users. Thank you. * * $Id$ */ /* external defines: SWAPEND - needs to be defined for platforms with inverse endianess related to Intel MAIN - should be defined in just one file that will contain the fn definitions and variables (this is inherited from Rsrv.h and sisocks.h) */ #ifndef __RCONNECTION_H__ #define __RCONNECTION_H__ #if defined __GNUC__ && !defined unix && !defined Win32 && !defined WIN32 #define unix #endif #include #include #include "sisocks.h" #include "Rsrv.h" #ifdef __LP64__ typedef long Rsize_t; #else typedef int Rsize_t; #endif //=== Rconnection error codes #define CERR_connect_failed -1 #define CERR_handshake_failed -2 #define CERR_invalid_id -3 #define CERR_protocol_not_supp -4 #define CERR_not_connected -5 #define CERR_peer_closed -7 #define CERR_malformed_packet -8 #define CERR_send_error -9 #define CERR_out_of_mem -10 #define CERR_not_supported -11 #define CERR_io_error -12 // this one is custom - authentication method required by // the server is not supported in this client #define CERR_auth_unsupported -20 #define A_required 0x001 #define A_crypt 0x002 #define A_plain 0x004 //===================================== Rmessage ---- QAP1 storage class Rmessage { public: struct phdr head; char *data; Rsize_t len; int complete; // the following is avaliable only for parsed messages (max 16 pars) int pars; unsigned int *par[16]; Rmessage(); Rmessage(int cmd); // 0 data Rmessage(int cmd, const char *txt); // DT_STRING data Rmessage(int cmd, int i); // DT_INT data (1 entry) Rmessage(int cmd, const void *buf, int len, int raw_data=0); // raw data or DT_BYTESTREAM virtual ~Rmessage(); int command() { return complete?head.cmd:-1; } Rsize_t length() { return complete?head.len:-1; } int is_complete() { return complete; } int read(int s); void parse(); int send(int s); }; //===================================== Rexp --- basis for all SEXPs class Rexp { public: Rmessage *msg; unsigned int *pos; Rsize_t len; Rexp *attr; int type; /* memory manegement for data/len: - content is in a message and this Rexp is the master of that message: master=0; msg=; - content is in a message, but this Rexp is not the master master=; msg=0 - content is all self-allocated with no message associated master=this; msg=0 */ char *data, *next; protected: // the next two are only cached if requested, no direct access allowed int attribs; const char **attrnames; Rexp *master; // if this is set then this Rexp allocated the memory for us, so we are not supposed to free anything; if this is set to "this" then the content is self-allocated, including any data int rcount; // reference count - only for a master - it counts how many children still exist public: Rexp(Rmessage *msg); Rexp(unsigned int *pos, Rmessage *msg=0); Rexp(int type, const char *data=0, Rsize_t len=0, Rexp *attr=0); virtual ~Rexp(); void set_master(Rexp *m); char *parse(unsigned int *pos); virtual Rsize_t storageSize() { return len+((len>0x7fffff)?8:4); } virtual void store(char *buf); Rexp *attribute(const char *name); const char **attributeNames(); virtual Rsize_t length() { return len; } friend std::ostream& operator<< (std::ostream& os, const Rexp& exp) { return ((Rexp&)exp).os_print(os); } friend std::ostream& operator<< (std::ostream& os, const Rexp* exp) { return ((Rexp*)exp)->os_print(os); } virtual std::ostream& os_print(std::ostream& os) { return os << "Rexp[type=" << type << ",len=" << len <<"]"; } }; //===================================== Rint --- XT_INT/XT_ARRAY_INT class Rinteger : public Rexp { public: Rinteger(Rmessage *msg) : Rexp(msg) { fix_content(); } Rinteger(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg) { fix_content(); } Rinteger(int *array, int count) : Rexp(XT_ARRAY_INT, (char*)array, count*sizeof(int)) { fix_content(); } int *intArray() { return (int*) data; } int intAt(int pos) { return (pos>=0 && (unsigned)pos=0 && (unsigned)pos= nel) ? 0 : cont[i]; } char *string() { return stringAt(0); } virtual Rsize_t length() { return nel; } unsigned int count() { return nel; } int indexOfString(const char *str); virtual std::ostream& os_print (std::ostream& os) { return os << "char*[" << nel <<"]\"" << string() <<"\".."; } private: void decode() { char *c = (char*) data; unsigned int i = 0; nel = 0; while (i < len) { if (!c[i]) nel++; i++; } if (nel) { i = 0; cont = (char**) malloc(sizeof(char*)*nel); while (i < nel) { cont[i] = strdup(c); while (*c) c++; c++; i++; } } else cont = 0; } }; //===================================== Rstring --- XT_STR class Rstring : public Rexp { public: Rstring(Rmessage *msg) : Rexp(msg) {} Rstring(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg) {} Rstring(const char *str) : Rexp(XT_STR, str, strlen(str)+1) {} char *string() { return (char*) data; } virtual std::ostream& os_print (std::ostream& os) { return os << "\"" << string() <<"\""; } }; //===================================== Rlist --- XT_LIST (CONS lists) class Rlist : public Rexp { public: Rexp *head, *tag; Rlist *tail; Rlist(Rmessage *msg) : Rexp(msg) { head=tag=0; tail=0; fix_content(); } Rlist(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg) { head=tag=0; tail=0; fix_content(); } /* this is a sort of special constructor that allows to create a Rlist based solely on its content. This is necessary since 0.5 because each LISTSXP is no longer represented by its own encoded SEXP but they are packed in one content list instead */ Rlist(int type, Rexp *head, Rexp *tag, char *next, Rmessage *imsg) : Rexp(type, 0, 0, 0) { this->head = head; this->tag = tag; tail = 0; this->next = next; this->msg = imsg; master = 0; } virtual ~Rlist(); Rexp *entryByTagName(const char *tagName) { if (tag && (tag->type==XT_SYM || tag->type==XT_SYMNAME) && !strcmp(((Rsymbol*)tag)->symbolName(),tagName)) return head; if (tail) return tail->entryByTagName(tagName); return 0; } virtual std::ostream& os_print (std::ostream& os) { os << "Rlist[tag="; if (tag) os << *tag; else os << ""; os << ",head="; if (head) os << *head; else os << ""; if (tail) os << ",tail=" << *tail; return os << "]"; } private: void fix_content(); }; //===================================== Rvector --- XT_VECTOR (general lists) class Rvector : public Rexp { protected: Rexp **cont; int count; // cached char **strs; public: Rvector(Rmessage *msg) : Rexp(msg) { cont=0; count=0; strs=0; fix_content(); } Rvector(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg) { cont=0; count=0; strs=0; fix_content(); } virtual ~Rvector(); char **strings(); int indexOf(Rexp *exp); int indexOfString(const char *str); virtual Rsize_t length() { return (Rsize_t) count; } char *stringAt(int i) { if (i < 0 || i >= count || !cont[i] || cont[i]->type != XT_STR) return 0; return ((Rstring*)cont[i])->string(); } Rexp *elementAt(int i) { return (i < 0 || i >= count || !cont[i]) ? 0 : cont[i]; } Rexp* byName(const char *name); virtual std::ostream& os_print (std::ostream& os) { os << "Rvector[count=" << count << ":"; int i=0; while (i] [-p ] [-s ] [-P ] [-h] \n\n", av[0]); return 0; } if (host_name) { if (port > 1) rc = new Rconnection(host_name, port); else rc = new Rconnection(host_name); } else if (sock_name) { rc = new Rconnection(sock_name, -1); } else { rc = new Rconnection(); } i = rc->connect(); if (i) { char buf[1024]; sockerrorchecks(buf, 1024, -1); fprintf(stderr, "ERROR: unable to connect (result=%d, socket:%s).\n", i, buf); } else rc->shutdown(pwd); delete rc; return 0; } Rserve/src/client/cxx/demo1.cc0000644000175100001440000001010214531234224015713 0ustar hornikusers/* * Small demo to illustrate the use of the C++ interface to Rserve * Copyright (C) 2004 Simon Urbanek, All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License * * 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 Leser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ */ #include using std::cout; #define MAIN // we are the main program, we need to define this #define SOCK_ERRORS // we will use verbose socket errors #include "sisocks.h" #include "Rconnection.h" // this is just a very silly example to show how the C++ API works ... int main(int argc, char **argv) { initsocks(); // this is needed for Win32 - it does nothing on unix Rconnection *rc = new Rconnection(); int i=rc->connect(); if (i) { char msg[128]; sockerrorchecks(msg, 128, -1); printf("unable to connect (result=%d, socket:%s).\n", i, msg); return i; } double d[6] = { 1.5, 2.4, 5.6, -1.2, 0.6, 1.7 }; // assign the above contents to the variable "a" in R Rdouble *rd = new Rdouble(d, 6); rc->assign("a", rd); delete rd; // create a 2 x 3 matrix named "b" and calculate b * t(b) matrix product Rdouble *x = (Rdouble*) rc->eval("b<-matrix(a,2); b%*%t(b)"); if (x) { // if everything was fine, we have the result cout << x << "\n"; // just for fun - let's get the matrix dimensionality Rinteger *dim = (Rinteger*) x->attribute("dim"); if (dim) cout << dim->intAt(0) << " by " << dim->intAt(1) << " matrix\n"; // and print the contents of the matrix (unformatted) double *d = x->doubleArray(); int i=0, ct = x->length(); while (i < ct) { cout << d[i++] << " "; } cout << "\n"; // finally dispose of the object delete x; } // integer constant assignment test int ia[6] = { 1, 4, 6, 3, 5 , 2 }; Rinteger *ri = new Rinteger(ia, 6); rc->assign("i", ri); delete ri; // let's get the whole iris data Rvector *iris = (Rvector*) rc->eval("data(iris); iris"); if (!iris) { cout << "oops! couldn't get iris data\n"; delete rc; return 0; } // now let's just get the sepal width - this a cheap operation, no talking to Rserve, because we have all the data already Rdouble *sw = (Rdouble*) iris->byName("Sepal.Width"); double *swd = sw->doubleArray(); // and print it ... { int i=0, ct=sw->length(); while (i #include ], [return *(signal (0, 0)) (0) == 1;])], [ac_cv_type_signal=int], [ac_cv_type_signal=void])]) AC_DEFINE_UNQUOTED([RETSIGTYPE],[$ac_cv_type_signal],[Define as the return type of signal handlers (`int' or `void').]) AC_CHECK_FUNCS([memset mkdir rmdir select socket]) # Check whether we can use crypt (and if we do if it's in the crypt library) AC_SEARCH_LIBS(crypt, crypt, [AC_DEFINE(HAS_CRYPT, 1, [If defined Rserve supports unix crypt password encryption.])]) AC_CHECK_HEADERS([crypt.h]) # socket related stuff - indroduced first due to Solaris # socklen_t - note that we don't try to find an equivalent! # we'll use BSD-style int in case this one isn't defined. # that should be fine for all major platforms. AC_CHECK_TYPE(socklen_t,, AC_DEFINE(socklen_t, int, [Define to `int' if neither nor define.]), [ #include #include ]) # connect may need -lsocket and/or -lnsl (e.g. on Solaris) AC_CHECK_FUNCS(connect) if test x"$ac_cv_func_connect" = x"no"; then case "$LIBS" in *-lnsl*) ;; *) AC_CHECK_LIB(nsl_s, printf) ;; esac case "$LIBS" in *-lnsl*) ;; *) AC_CHECK_LIB(nsl, printf) ;; esac case "$LIBS" in *-lsocket*) ;; *) AC_CHECK_LIB(socket, connect) ;; esac case "$LIBS" in *-linet*) ;; *) AC_CHECK_LIB(inet, connect) ;; esac dnl We can't just call AC_CHECK_FUNCS(connect) here, because the value dnl has been cached. if test x"$ac_cv_lib_socket_connect" = x"yes" || test x"$ac_cv_lib_inet_connect" = x"yes"; then # ac_cv_func_connect=yes # don't! it would cause AC_CHECK_FUNC to succeed next time configure is run AC_DEFINE(HAVE_CONNECT, 1, [ ]) fi fi # on some platforms libR expects dl code in the binary AC_CHECK_LIB(dl, dlopen) AC_CONFIG_FILES([Makefile]) AC_OUTPUT Rserve/src/client/cxx/sisocks.h0000644000175100001440000001706114531234224016241 0ustar hornikusers/* system independent sockets (basically for unix and Win) * Copyright (C) 2000,1 Simon Urbanek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; version 2.1 of the License * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * conditional defines: MAIN should be defined in just one file that will contain the fn definitions and variables USE_SNPRINTF emulate snprintf on Win platforms (you will lose the security which is provided under unix of course) SOCK_ERRORS include error code handling and checking functions */ #ifndef __SISOCKS_H__ #define __SISOCKS_H__ #if defined __GNUC__ && !defined unix && !defined Win32 /* MacOS X hack (gcc on any platform should behave as unix - except for Win32, where we need to keep using winsock) */ #define unix #endif #if defined STANDALONE_RSERVE && defined RSERVE_PKG #undef RSERVE_PKG #endif #if defined SOCK_ERRORS || defined USE_SNPRINTF #include #endif #include #ifdef unix #include #include #include #include #include #include #include #define sockerrno errno #define SOCKET int #define INVALID_SOCKET (-1) #define closesocket(A) close(A) #else #define windows #include #include #include #include #define inet_aton(A,B) (0, B.s_addr=inet_addr(A)) #define sockerrno WSAGetLastError() #ifndef ECONNREFUSED #define ECONNREFUSED WSAECONNREFUSED #endif #ifndef EADDRINUSE #define EADDRINUSE WSAEADDRINUSE #endif #ifndef ENOTSOCK #define ENOTSOCK WSAENOTSOCK #endif #ifndef EISCONN #define EISCONN WSAEISCONN #endif #ifndef ETIMEDOUT #define ETIMEDOUT WSAETIMEDOUT #endif #ifndef ENETUNREACH #define ENETUNREACH WSAENETUNREACH #endif #ifndef EINPROGRESS #define EINPROGRESS WSAEINPROGRESS #endif #ifndef EALREADY #define EALREADY WSAEALREADY #endif #ifndef EOPNOTSUPP #define EOPNOTSUPP WSAEOPNOTSUPP #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK #endif #ifndef WIN64 #ifndef EAFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #endif #ifndef EBADF #define EBADF WSAEBADF #endif #ifndef EINVAL #define EINVAL WSAEINVAL #endif #ifndef EFAULT #define EFAULT WSAEFAULT #endif #ifndef EACCES #define EACCES WSAEACCES #endif #endif #ifdef USE_SNPRINTF #ifdef MAIN int snprintf(char *buf, int len, char *fmt, ...) { va_list argptr; int cnt; va_start(argptr, fmt); cnt = vsprintf(buf, fmt, argptr); va_end(argptr); return(cnt); } #else extern int snprintf(char *buf, int len, char *fmt, ...); #endif #endif #endif #define SA struct sockaddr #define SAIN struct sockaddr_in #ifdef windows #ifdef MAIN int initsocks(void) { WSADATA dt; /* initialize WinSock 1.1 */ return (WSAStartup(0x0101,&dt))?-1:0; } #else extern int initsocks(void); #endif #define donesocks() WSACleanup() #else /* no stupid stuff necessary for unix */ #define initsocks() #define donesocks() #endif #ifdef SOCK_ERRORS #ifdef MAIN int suppmode=0; int socklasterr; FILE *sockerrlog=0; /* copy error description to buf or set *buf=0 if none */ int sockerrorchecks(char *buf, int blen, int res) { *buf=0; if (res==-1) { switch(sockerrno) { case EBADF: strncpy(buf,"bad descriptor",blen); break; case EINVAL: strncpy(buf,"already in use",blen); break; case EACCES: strncpy(buf,"access denied",blen); break; case ENOTSOCK: strncpy(buf,"descriptor is not a socket",blen); break; case EOPNOTSUPP: strncpy(buf,"operation not supported",blen); break; case EFAULT: strncpy(buf,"fault",blen); break; case EWOULDBLOCK: strncpy(buf,"operation would block",blen); break; case EISCONN: strncpy(buf,"is already connected",blen); break; case ECONNREFUSED: strncpy(buf,"connection refused",blen); break; case ETIMEDOUT: strncpy(buf,"operation timed out",blen); break; case ENETUNREACH: strncpy(buf,"network is unreachable",blen); break; case EADDRINUSE: strncpy(buf,"address already in use",blen); break; case EINPROGRESS: strncpy(buf,"in progress",blen); break; case EALREADY: strncpy(buf,"previous connect request not completed yet",blen); break; #ifdef unix default: snprintf(buf,blen,"unknown socket error %d",sockerrno); #else default: sprintf(buf,"unknown socket error %d",sockerrno); #endif } } return res; } #ifdef RSERVE_PKG /* use error instead of exit */ #include int sockerrorcheck(char *sn, int rtb, int res) { if ((signed int)res == -1) { char sock_err_buf[72]; sockerrorchecks(sock_err_buf, sizeof(sock_err_buf), res); if (rtb) Rf_error("%s socket error #%d (%s)", sn, (int) sockerrno, sock_err_buf); else Rf_warning("%s socket error #%d (%s)", sn, (int) sockerrno, sock_err_buf); } return res; } #else /* check socket error and add to log file if necessary */ int sockerrorcheck(char *sn, int rtb, int res) { if (!sockerrlog) sockerrlog=stderr; if ((signed int)res==-1) { if (socklasterr==sockerrno) { suppmode++; } else { if (suppmode>0) { fprintf(sockerrlog,"##> REP: (last error has been repeated %d times.)\n",suppmode); suppmode=0; } fprintf(sockerrlog,"##> SOCK_ERROR: %s error #%d",sn,sockerrno); switch(sockerrno) { case EBADF: fprintf(sockerrlog,"(bad descriptor)"); break; case EINVAL: fprintf(sockerrlog,"(already in use)"); break; case EACCES: fprintf(sockerrlog,"(access denied)"); break; case ENOTSOCK: fprintf(sockerrlog,"(descriptor is not a socket)"); break; case EOPNOTSUPP: fprintf(sockerrlog,"(operation not supported)"); break; case EFAULT: fprintf(sockerrlog,"(fault)"); break; case EWOULDBLOCK: fprintf(sockerrlog,"(operation would block)"); break; case EISCONN: fprintf(sockerrlog,"(is already connected)"); break; case ECONNREFUSED: fprintf(sockerrlog,"(connection refused)"); break; case ETIMEDOUT: fprintf(sockerrlog,"(operation timed out)"); break; case ENETUNREACH: fprintf(sockerrlog,"(network is unreachable)"); break; case EADDRINUSE: fprintf(sockerrlog,"(address already in use)"); break; case EINPROGRESS: fprintf(sockerrlog,"(in progress)"); break; case EALREADY: fprintf(sockerrlog,"(previous connect request not completed yet)"); break; default: fprintf(sockerrlog,"(?)"); } fprintf(sockerrlog,"\n"); fflush(sockerrlog); socklasterr=sockerrno; } if (rtb) exit(1); } return res; } #endif #else extern int suppmode; extern int socklasterr; extern FILE *sockerrlog; int sockerrorchecks(char *buf, int blen, int res); int sockerrorcheck(char *sn, int rtb, int res); #endif #define FCF(X,F) sockerrorcheck(X,1,F) #define CF(X,F) sockerrorcheck(X,0,F) #endif #ifdef MAIN struct sockaddr *build_sin(struct sockaddr_in *sa,char *ip,int port) { memset(sa,0,sizeof(struct sockaddr_in)); sa->sin_family=AF_INET; sa->sin_port=htons(port); sa->sin_addr.s_addr=(ip)?inet_addr(ip):htonl(INADDR_ANY); return (struct sockaddr*)sa; } #else struct sockaddr *build_sin(struct sockaddr_in *sa,char *ip,int port); #endif #endif /* __SISOCKS_H__ */ Rserve/src/client/cxx/COPYING0000644000175100001440000006350414531234224015450 0ustar hornikusers GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! Rserve/src/client/cxx/config.h.in0000644000175100001440000001040114531234224016424 0ustar hornikusers/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* Defined if the platform is big-endian */ #undef BS_BIG_ENDIAN /* Defined if the platform is little-endian */ #undef BS_LITTLE_ENDIAN /* If defined Rserve supports unix crypt password encryption. */ #undef HAS_CRYPT /* */ #undef HAVE_CONNECT /* Define to 1 if you have the header file. */ #undef HAVE_CRYPT_H /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the `inet' library (-linet). */ #undef HAVE_LIBINET /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL /* Define to 1 if you have the `nsl_s' library (-lnsl_s). */ #undef HAVE_LIBNSL_S /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_TCP_H /* Define to 1 if you have the `rmdir' function. */ #undef HAVE_RMDIR /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* 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_SOCKET_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_TIME_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_SYS_UN_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* 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 /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* 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 WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to `int' if neither nor define. */ #undef socklen_t /* Define as `fork' if `vfork' does not work. */ #undef vfork Rserve/src/client/cxx/rcmd.cc0000644000175100001440000000761614531234224015653 0ustar hornikusers/* * Small demo to illustrate the use of the C++ interface to Rserve * Copyright (C) 2004 Simon Urbanek, All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License * * 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 Leser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ */ #define MAIN // we are the main program, we need to define this #define SOCK_ERRORS // we will use verbose socket errors #include "sisocks.h" #include "Rconnection.h" char buf[1024]; int main(int ac, char **av) { initsocks(); // this is needed for Win32 - it does nothing on unix Rconnection *rc = 0; int port = -1, help = 0, do_cd = 1; const char *sock_name = 0; const char *host_name = 0; const char *pwd = 0; const char *user = 0; const char *wd = 0; int i = 1; while (i < ac) { if (av[i][0] == '-') { switch (av[i][1]) { case 'h': help = 1; break; case 'H': if (++i < ac) host_name = av[i]; break; case 'u': if (++i < ac) user = av[i]; break; case 'p': if (++i < ac) port = atoi(av[i]); break; case 'P': if (++i < ac) pwd = av[i]; else pwd = getpass("password: "); break; case 's': if (++i < ac) sock_name = av[i]; break; case 'w': if (++i < ac) wd = av[i]; break; case 'n': do_cd = 0; break; case 'c': i++; } } i++; } if (wd) do_cd = 1; if (help) { printf("\n Usage: %s [-H ] [-c ] [-w ] [-n] [-p ] [-s ] [-u ] [-P ] [-h] [ [...]]\n\n", av[0]); return 0; } if (host_name) { if (port > 1) rc = new Rconnection(host_name, port); else rc = new Rconnection(host_name); } else if (sock_name) { rc = new Rconnection(sock_name, -1); } else { rc = new Rconnection(); } buf[1023]=0; i = rc->connect(); if (i) { sockerrorchecks(buf, 1023, -1); fprintf(stderr, "unable to connect (result=%d, socket:%s).\n", i, buf); return i; } if (user) { if (!pwd) pwd = ""; i = rc->login(user, pwd); if (i) { fprintf(stderr, "login failed (result=%d)\n", i); return i; } } if (do_cd) { char *es, *d; const char *c; if (!wd) wd = strdup(getwd(buf)); d = es = (char*) malloc(strlen(wd) * 2 + 14); c = wd; strcpy(d, "setwd(\""); d += 7; while (*c) { if (*c == '\"' || *c == '\\' || *c == '\'') (d++)[0] = '\\'; if (*c == '\n' || *c == '\r') (d++)[0] = ' '; else (d++)[0] = (c++)[0]; } strcpy(d, "\")"); rc->voidEval(es); free(es); } i = 1; // source all files specified at the command line and print the output while (i < ac) { if (av[i][0] == '-') { switch(av[i][1]) { /* skip options that have extra argument */ case 'c': if (++i < ac) { snprintf(buf, 1023, "try(paste(capture.output(%s),collapse='\\n'))", av[i]); Rstring *str = (Rstring*) rc->eval(buf); puts(str->string()); delete str; } break; case 'p': case 'P': case 's': case 'H': case 'u': case 'w': i++; } } else { snprintf(buf, 1023, "try(paste(capture.output(source(\"%s\")),collapse='\\n'))", av[i]); Rstring *str = (Rstring*) rc->eval(buf); puts(str->string()); delete str; } i++; } // dispose of the connection object - this implicitly closes the connection delete rc; return 0; } Rserve/src/client/cxx/ReadMe.txt0000644000175100001440000000536414531234224016313 0ustar hornikusersThis directory contains a sample C++ client for Rserve You can compile this client without R. Just run "configure" in the Rserve directory, a corresponding Makefile will be automatically generated. Win32: There is no configure for Windows, but there is a special Makefile.win to build it - use "make -f Makefile.win" - it requires MinGW (or compatible) and GNU make. This C++ interface is experimental and does not come in form of a library, it is left to the user to build one or just use it in static form. Rconnection.h and Rconnection.cc is all that's needed. This directory also contains two little examples: * demo1.cc This (rather silly) example demonstrates the basic use of the API, such as assigning contents, evaluating expressions and fetching various parts of the data. * rcons.cc A very simple console to Rserve. It uses the os_print method to print the results and its attributes. It is helpful if you want to understand how R and Rserve stores various expressions. * rcmd.cc This program "sources" all files specified on the command line into a Rserve session and prints its output. It is something like a 'fast' version of R CMD BATCH. It's very simple, so look at the code if you want a more sophisticated behavior. The entire C++ interface handles only the most basic types such as lists, vectors, doubles, integers and strings. Look at the sources to see how to implement other types if necessary (although there isn't too much missing, maybe logical vectors ...). A word about the memory allocation of the objects here: in most cases the memory is allocated by the Rmessage object that receives the evaluated expression for R. All further Rexp objects are just pointers inside that message. For convenience there is one "main" Rexp, which knows about the message and automaically deallocates it upon its own destruction. This means that from user's point of view there is always only *one* object which can be deleted, namely the one returned by 'eval'. The user should *never* delete any object obtained indirectly from another Rexp. Complex Rexps, such as Rvector always return direct pointers to their content. This applies also to pointer to other types obtained from Rexp such as doubleArray of Rdouble. You should always copy this content if you plan to make modifications. This approach was taken to provide very fast access to all objects returned from Rserve. Usually noting needs to be copied - this is imporant, because the objects could be quite large. Please feel free to contribute to this project. I don't use this C++ interface myself, therefore it is left to the users to extend it further. All low-level handling is implemented, therefore it is much easier to add high-level functionality. see also: http://www.rosuda.org/Rserve/ Simon Urbanek, Sept 2004 Rserve/src/client/cxx/Makefile.win0000755000175100001440000000063414531234224016647 0ustar hornikusers# Makefile for C++ Rserve clients - Win32 version # # $Id$ SRC = $(wildcard *.cc) OBJ = $(SRC:%.cc=%.o) DST = demo1 rcons CXXFLAGS+=-I../include -I../include/Win32 -I.. -I. -DWin32 LIBS+=-lwsock32 linkRL= all: $(DST) demo1: Rconnection.o demo1.o $(CXX) $^ -o $@ $(LIBS) rcons: Rconnection.o rcons.o $(CXX) $^ -o $@ $(LIBS) $(linkRL) debug: CXXFLAGS=-g $(MAKE) all clean: rm -rf *~ *.o \#* .\#* $(DST) Rserve/src/client/cxx/configure0000755000175100001440000053606014531234227016331 0ustar hornikusers#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for Rserve-cxx-client 0.1. # # Report bugs to . # # # 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" 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 and $0: Simon.Urbanek@r-project.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'" 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='Rserve-cxx-client' PACKAGE_TARNAME='rserve-cxx-client' PACKAGE_VERSION='0.1' PACKAGE_STRING='Rserve-cxx-client 0.1' PACKAGE_BUGREPORT='Simon.Urbanek@r-project.org' PACKAGE_URL='' ac_unique_file="Rconnection.cc" # 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_func_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS ac_ct_CXX CXXFLAGS CXX OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC 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' ac_subst_files='' ac_user_opts=' enable_option_checking ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC' # 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 Rserve-cxx-client 0.1 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/rserve-cxx-client] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Rserve-cxx-client 0.1:";; esac cat <<\_ACEOF 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 CXX C++ compiler command CXXFLAGS C++ compiler flags Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _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 Rserve-cxx-client configure 0.1 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_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_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_cxx_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_cxx_try_compile # 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_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_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { 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 eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop eval "$3=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 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_type # 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_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_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Rserve-cxx-client $as_me 0.1, 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; } " # Test code for whether the C++ compiler supports C++98 (global declarations) ac_cxx_conftest_cxx98_globals=' // Does the compiler advertise C++98 conformance? #if !defined __cplusplus || __cplusplus < 199711L # error "Compiler does not advertise C++98 conformance" #endif // These inclusions are to reject old compilers that // lack the unsuffixed header files. #include #include // and are *not* freestanding headers in C++98. extern void assert (int); namespace std { extern int strcmp (const char *, const char *); } // Namespaces, exceptions, and templates were all added after "C++ 2.0". using std::exception; using std::strcmp; namespace { void test_exception_syntax() { try { throw "test"; } catch (const char *s) { // Extra parentheses suppress a warning when building autoconf itself, // due to lint rules shared with more typical C programs. assert (!(strcmp) (s, "test")); } } template struct test_template { T const val; explicit test_template(T t) : val(t) {} template T add(U u) { return static_cast(u) + val; } }; } // anonymous namespace ' # Test code for whether the C++ compiler supports C++98 (body of main) ac_cxx_conftest_cxx98_main=' assert (argc); assert (! argv[0]); { test_exception_syntax (); test_template tt (2.0); assert (tt.add (4) == 6.0); assert (true && !false); } ' # Test code for whether the C++ compiler supports C++11 (global declarations) ac_cxx_conftest_cxx11_globals=' // Does the compiler advertise C++ 2011 conformance? #if !defined __cplusplus || __cplusplus < 201103L # error "Compiler does not advertise C++11 conformance" #endif namespace cxx11test { constexpr int get_val() { return 20; } struct testinit { int i; double d; }; class delegate { public: delegate(int n) : n(n) {} delegate(): delegate(2354) {} virtual int getval() { return this->n; }; protected: int n; }; class overridden : public delegate { public: overridden(int n): delegate(n) {} virtual int getval() override final { return this->n * 2; } }; class nocopy { public: nocopy(int i): i(i) {} nocopy() = default; nocopy(const nocopy&) = delete; nocopy & operator=(const nocopy&) = delete; private: int i; }; // for testing lambda expressions template Ret eval(Fn f, Ret v) { return f(v); } // for testing variadic templates and trailing return types template auto sum(V first) -> V { return first; } template auto sum(V first, Args... rest) -> V { return first + sum(rest...); } } ' # Test code for whether the C++ compiler supports C++11 (body of main) ac_cxx_conftest_cxx11_main=' { // Test auto and decltype auto a1 = 6538; auto a2 = 48573953.4; auto a3 = "String literal"; int total = 0; for (auto i = a3; *i; ++i) { total += *i; } decltype(a2) a4 = 34895.034; } { // Test constexpr short sa[cxx11test::get_val()] = { 0 }; } { // Test initializer lists cxx11test::testinit il = { 4323, 435234.23544 }; } { // Test range-based for int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; for (auto &x : array) { x += 23; } } { // Test lambda expressions using cxx11test::eval; assert (eval ([](int x) { return x*2; }, 21) == 42); double d = 2.0; assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); assert (d == 5.0); assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); assert (d == 5.0); } { // Test use of variadic templates using cxx11test::sum; auto a = sum(1); auto b = sum(1, 2); auto c = sum(1.0, 2.0, 3.0); } { // Test constructor delegation cxx11test::delegate d1; cxx11test::delegate d2(); cxx11test::delegate d3(45); } { // Test override and final cxx11test::overridden o1(55464); } { // Test nullptr char *c = nullptr; } { // Test template brackets test_template<::test_template> v(test_template(12)); } { // Unicode literals char const *utf8 = u8"UTF-8 string \u2500"; char16_t const *utf16 = u"UTF-8 string \u2500"; char32_t const *utf32 = U"UTF-32 string \u2500"; } ' # Test code for whether the C compiler supports C++11 (complete). ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} ${ac_cxx_conftest_cxx11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_main} ${ac_cxx_conftest_cxx11_main} return ok; } " # Test code for whether the C compiler supports C++98 (complete). ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} int main (int argc, char **argv) { int ok = 0; ${ac_cxx_conftest_cxx98_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" as_fn_append ac_header_c_list " vfork.h vfork_h HAVE_VFORK_H" as_fn_append ac_func_c_list " fork HAVE_FORK" as_fn_append ac_func_c_list " vfork HAVE_VFORK" # 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 config.h" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { 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=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ 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_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS 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_CXX="$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 CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 printf "%s\n" "$CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ 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_CXX+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS 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_CXX="$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_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 printf "%s\n" "$ac_ct_CXX" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" 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 CXX=$ac_ct_CXX fi fi fi fi # 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; 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 { 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_cxx_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_cxx_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_cxx_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+y} ac_save_CXXFLAGS=$CXXFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 printf %s "checking whether $CXX accepts -g... " >&6; } if test ${ac_cv_prog_cxx_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes else $as_nop CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : else $as_nop ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_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_cxx_werror_flag=$ac_save_cxx_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_prog_cxx_stdcxx=no if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } if test ${ac_cv_prog_cxx_11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx11_program _ACEOF for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx11" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx11" = 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_cxx_cxx11" = 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_cxx_cxx11" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx11" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 ac_prog_cxx_stdcxx=cxx11 fi fi if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } if test ${ac_cv_prog_cxx_98+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cxx_98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_cxx_conftest_cxx98_program _ACEOF for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA do CXX="$ac_save_CXX $ac_arg" if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_cxx98=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cxx_cxx98" != "xno" && break done rm -f conftest.$ac_ext CXX=$ac_save_CXX fi if test "x$ac_cv_prog_cxx_cxx98" = 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_cxx_cxx98" = 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_cxx_cxx98" >&5 printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } CXX="$CXX $ac_cv_prog_cxx_cxx98" fi ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 ac_prog_cxx_stdcxx=cxx98 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 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 printf %s "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if test ${ac_cv_header_sys_wait_h+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main (void) { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_header_sys_wait_h=yes else $as_nop ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 printf "%s\n" "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi 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" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = xyes then : printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "memory.h" "ac_cv_header_memory_h" "$ac_includes_default" if test "x$ac_cv_header_memory_h" = xyes then : printf "%s\n" "#define HAVE_MEMORY_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" if test "x$ac_cv_header_sys_time_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes then : printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/stat.h" "ac_cv_header_sys_stat_h" "$ac_includes_default" if test "x$ac_cv_header_sys_stat_h" = xyes then : printf "%s\n" "#define HAVE_SYS_STAT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" if test "x$ac_cv_header_sys_types_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" if test "x$ac_cv_header_sys_socket_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default" if test "x$ac_cv_header_sys_un_h" = xyes then : printf "%s\n" "#define HAVE_SYS_UN_H 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" "netinet/tcp.h" "ac_cv_header_netinet_tcp_h" "$ac_includes_default" if test "x$ac_cv_header_netinet_tcp_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_TCP_H 1" >>confdefs.h fi # Checks for typedefs, structures, and compiler characteristics. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 printf %s "checking for an ANSI C-conforming const... " >&6; } if test ${ac_cv_c_const+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* IBM XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* IBM XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_const=yes else $as_nop ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 printf "%s\n" "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then printf "%s\n" "#define const /**/" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 printf %s "checking whether byte ordering is bigendian... " >&6; } if test ${ac_cv_c_bigendian+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO" then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no 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 if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no 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 if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ unsigned short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; unsigned short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } unsigned short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; unsigned short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main (void) { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_c_bigendian=no else $as_nop ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 printf "%s\n" "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) printf "%s\n" "#define BS_BIG_ENDIAN 1" >>confdefs.h ;; #( no) printf "%s\n" "#define BS_LITTLE_ENDIAN 1" >>confdefs.h ;; #( universal) printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: endianness unknown - will rely solely on compiler macros" >&5 printf "%s\n" "endianness unknown - will rely solely on compiler macros" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether compiler sets endianness macros" >&5 printf %s "checking whether compiler sets endianness macros... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN_ || defined __BIG_ENDIAN__ || defined _BIG_ENDIAN_ #define BS_OK 1 #else cannot determine compiler's endianness #endif _ACEOF if ac_fn_c_try_compile "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Cannot determine endianness neither from the compiler nor using a test. Try adding -D_BIG_ENDIAN_ or -D_LITTLE_ENDIAN_ to PKG_CPPFLAGS. " "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac # Checks for library functions. ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default " if test "x$ac_cv_type_pid_t" = xyes then : else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined _WIN64 && !defined __CYGWIN__ LLP64 #endif int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_pid_type='int' else $as_nop ac_pid_type='__int64' fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h fi ac_func= for ac_item in $ac_func_c_list do if test $ac_func; then ac_fn_c_check_func "$LINENO" $ac_func ac_cv_func_$ac_func if eval test \"x\$ac_cv_func_$ac_func\" = xyes; then echo "#define $ac_item 1" >> confdefs.h fi ac_func= else ac_func=$ac_item fi done if test "x$ac_cv_func_fork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 printf %s "checking for working fork... " >&6; } if test ${ac_cv_func_fork_works+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_func_fork_works=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_fork_works=yes else $as_nop ac_cv_func_fork_works=no 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_func_fork_works" >&5 printf "%s\n" "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 printf %s "checking for working vfork... " >&6; } if test ${ac_cv_func_vfork_works+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_func_vfork_works=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #include #ifdef HAVE_VFORK_H # include #endif static void do_nothing (int sig) { (void) sig; } /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void sparc_address_test (int arg) { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main (void) { pid_t parent = getpid (); pid_t child; sparc_address_test (0); /* On Solaris 2.4, changes by the child to the signal handler also munge signal handlers in the parent. To detect this, start by putting the parent's handler in a known state. */ signal (SIGTERM, SIG_DFL); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* Alter the child's signal handler. */ if (signal (SIGTERM, do_nothing) != SIG_DFL) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child munge the parent's signal handler? */ || signal (SIGTERM, SIG_DFL) != SIG_DFL /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_vfork_works=yes else $as_nop ac_cv_func_vfork_works=no 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_func_vfork_works" >&5 printf "%s\n" "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_VFORK 1" >>confdefs.h else printf "%s\n" "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_FORK 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 printf %s "checking return type of signal handlers... " >&6; } if test ${ac_cv_type_signal+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_type_signal=int else $as_nop ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 printf "%s\n" "$ac_cv_type_signal" >&6; } printf "%s\n" "#define RETSIGTYPE $ac_cv_type_signal" >>confdefs.h ac_fn_c_check_func "$LINENO" "memset" "ac_cv_func_memset" if test "x$ac_cv_func_memset" = xyes then : printf "%s\n" "#define HAVE_MEMSET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mkdir" "ac_cv_func_mkdir" if test "x$ac_cv_func_mkdir" = xyes then : printf "%s\n" "#define HAVE_MKDIR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "rmdir" "ac_cv_func_rmdir" if test "x$ac_cv_func_rmdir" = xyes then : printf "%s\n" "#define HAVE_RMDIR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "select" "ac_cv_func_select" if test "x$ac_cv_func_select" = xyes then : printf "%s\n" "#define HAVE_SELECT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" if test "x$ac_cv_func_socket" = xyes then : printf "%s\n" "#define HAVE_SOCKET 1" >>confdefs.h fi # Check whether we can use crypt (and if we do if it's in the crypt library) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing crypt" >&5 printf %s "checking for library containing crypt... " >&6; } if test ${ac_cv_search_crypt+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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 crypt (); int main (void) { return crypt (); ; return 0; } _ACEOF for ac_lib in '' crypt do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_crypt=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_crypt+y} then : break fi done if test ${ac_cv_search_crypt+y} then : else $as_nop ac_cv_search_crypt=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt" >&5 printf "%s\n" "$ac_cv_search_crypt" >&6; } ac_res=$ac_cv_search_crypt if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" printf "%s\n" "#define HAS_CRYPT 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "crypt.h" "ac_cv_header_crypt_h" "$ac_includes_default" if test "x$ac_cv_header_crypt_h" = xyes then : printf "%s\n" "#define HAVE_CRYPT_H 1" >>confdefs.h fi # socket related stuff - indroduced first due to Solaris # socklen_t - note that we don't try to find an equivalent! # we'll use BSD-style int in case this one isn't defined. # that should be fine for all major platforms. ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" " #include #include " if test "x$ac_cv_type_socklen_t" = xyes then : else $as_nop printf "%s\n" "#define socklen_t int" >>confdefs.h fi # connect may need -lsocket and/or -lnsl (e.g. on Solaris) ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes then : printf "%s\n" "#define HAVE_CONNECT 1" >>confdefs.h fi if test x"$ac_cv_func_connect" = x"no"; then case "$LIBS" in *-lnsl*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for printf in -lnsl_s" >&5 printf %s "checking for printf in -lnsl_s... " >&6; } if test ${ac_cv_lib_nsl_s_printf+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl_s $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 printf (); int main (void) { return printf (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_nsl_s_printf=yes else $as_nop ac_cv_lib_nsl_s_printf=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_nsl_s_printf" >&5 printf "%s\n" "$ac_cv_lib_nsl_s_printf" >&6; } if test "x$ac_cv_lib_nsl_s_printf" = xyes then : printf "%s\n" "#define HAVE_LIBNSL_S 1" >>confdefs.h LIBS="-lnsl_s $LIBS" fi ;; esac case "$LIBS" in *-lnsl*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for printf in -lnsl" >&5 printf %s "checking for printf in -lnsl... " >&6; } if test ${ac_cv_lib_nsl_printf+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $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 printf (); int main (void) { return printf (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_nsl_printf=yes else $as_nop ac_cv_lib_nsl_printf=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_nsl_printf" >&5 printf "%s\n" "$ac_cv_lib_nsl_printf" >&6; } if test "x$ac_cv_lib_nsl_printf" = xyes then : printf "%s\n" "#define HAVE_LIBNSL 1" >>confdefs.h LIBS="-lnsl $LIBS" fi ;; esac case "$LIBS" in *-lsocket*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 printf %s "checking for connect in -lsocket... " >&6; } if test ${ac_cv_lib_socket_connect+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 connect (); int main (void) { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_socket_connect=yes else $as_nop ac_cv_lib_socket_connect=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_connect" >&5 printf "%s\n" "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = xyes then : printf "%s\n" "#define HAVE_LIBSOCKET 1" >>confdefs.h LIBS="-lsocket $LIBS" fi ;; esac case "$LIBS" in *-linet*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for connect in -linet" >&5 printf %s "checking for connect in -linet... " >&6; } if test ${ac_cv_lib_inet_connect+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-linet $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 connect (); int main (void) { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_inet_connect=yes else $as_nop ac_cv_lib_inet_connect=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_inet_connect" >&5 printf "%s\n" "$ac_cv_lib_inet_connect" >&6; } if test "x$ac_cv_lib_inet_connect" = xyes then : printf "%s\n" "#define HAVE_LIBINET 1" >>confdefs.h LIBS="-linet $LIBS" fi ;; esac if test x"$ac_cv_lib_socket_connect" = x"yes" || test x"$ac_cv_lib_inet_connect" = x"yes"; then # ac_cv_func_connect=yes # don't! it would cause AC_CHECK_FUNC to succeed next time configure is run printf "%s\n" "#define HAVE_CONNECT 1" >>confdefs.h fi fi # on some platforms libR expects dl code in the binary { 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 : printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h LIBS="-ldl $LIBS" fi ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { 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 : "${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 Rserve-cxx-client $as_me 0.1, 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" _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 Report bugs to ." _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="\\ Rserve-cxx-client config.status 0.1 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' 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 _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 "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) 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 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 " 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 # _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 $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 ;; 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 Rserve/src/client/java/0000755000175100001440000000000014531234227014527 5ustar hornikusersRserve/src/client/java/REXPDouble.java0000644000175100001440000000556014531234224017306 0ustar hornikuserspackage org.rosuda.REngine; /** REXPDouble represents a vector of double precision floating point values. */ public class REXPDouble extends REXPVector { private double[] payload; /** NA real value as defined in R. Note: it can NOT be used in comparisons, you must use {@link #isNA(double)} instead. */ public static final double NA = Double.longBitsToDouble(0x7ff00000000007a2L); /** Java screws up the bits in NA real values, so we cannot compare to the real bits used by R (0x7ff00000000007a2L) but use this value which is obtained by passing the bits through Java's double type */ static final long NA_bits = Double.doubleToRawLongBits(Double.longBitsToDouble(0x7ff00000000007a2L)); /** checks whether a given double value is a NA representation in R. Note that NA is NaN but not all NaNs are NA. */ public static boolean isNA(double value) { /* on OS X i386 the MSB of the fraction is set even though R doesn't set it. Although this is technically a good idea (to make it a QNaN) it's not what R does and thus makes the comparison tricky */ return (Double.doubleToRawLongBits(value) & 0xfff7ffffffffffffL) == (NA_bits & 0xfff7ffffffffffffL); } /** create real vector of the length 1 with the given value as its first (and only) element */ public REXPDouble(double load) { super(); payload=new double[] { load }; } public REXPDouble(double[] load) { super(); payload=(load==null)?new double[0]:load; } public REXPDouble(double[] load, REXPList attr) { super(attr); payload=(load==null)?new double[0]:load; } public int length() { return payload.length; } public Object asNativeJavaObject() { return payload; } /** return true */ public boolean isNumeric() { return true; } /** returns the values represented by this vector */ public double[] asDoubles() { return payload; } /** converts the values of this vector into integers by cast */ public int[] asIntegers() { int[] a = new int[payload.length]; int i = 0; while (i < payload.length) { a[i] = (int) payload[i]; i++; } return a; } /** converts the values of this vector into strings */ public String[] asStrings() { String[] s = new String[payload.length]; int i = 0; while (i < payload.length) { s[i] = ""+payload[i]; i++; } return s; } /** returns a boolean vector of the same length as this vector with true for NA values and false for any other values (including NaNs) */ public boolean[] isNA() { boolean a[] = new boolean[payload.length]; int i = 0; while (i < a.length) { a[i] = isNA(payload[i]); i++; } return a; } public String toDebugString() { StringBuffer sb = new StringBuffer(super.toDebugString()+"{"); int i = 0; while (i < payload.length && i < maxDebugItems) { if (i>0) sb.append(","); sb.append(payload[i]); i++; } if (i < payload.length) sb.append(",.."); return sb.toString()+"}"; } } Rserve/src/client/java/REngine.java0000644000175100001440000003024214531234224016717 0ustar hornikuserspackage org.rosuda.REngine; import java.lang.reflect.Method; /** REngine is an abstract base class for all implementations of R engines. Subclasses can implement interfaces to R in many different ways. Clients should always use methods this class instead of its direct subclasses in order to maintian compatibility with any R engine implementation. The canonical way of obtaining a new engine is to call {@link #engineForClass}. All subclasses must implement createEngine() method. */ public abstract class REngine { /** last created engine or null if there is none */ protected static REngine lastEngine = null; /** this is the designated constructor for REngine classes. It uses reflection to call createEngine method on the given REngine class. @param klass fully qualified class-name of a REngine implementation @return REngine implementation or null if createEngine invokation failed */ public static REngine engineForClass(String klass) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, java.lang.reflect.InvocationTargetException { Class cl=Class.forName(klass); if (cl==null) throw(new ClassNotFoundException("can't find engine class "+klass)); Method m=cl.getMethod("createEngine",(Class[])null); Object o=m.invoke(null,(Object[])null); return lastEngine=(REngine)o; } /** This is the extended constructor for REngine classes. It uses reflection to call createEngine method on the given REngine class with some additional control over the engine. Note that not all engines may support the extended version. @param klass fully qualified class-name of a REngine implementation @param args arguments to pass to R for initialization @param callbacks delegate for REngine callbacks or null if callbacks won't be serviced (engine may not support callbacks) @param runREPL if true then REPL will be started (if supported by the engine) @return REngine implementation or null if createEngine invokation failed */ public static REngine engineForClass(String klass, String[] args, REngineCallbacks callbacks, boolean runREPL) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, java.lang.reflect.InvocationTargetException { Class cl = Class.forName(klass); if (cl == null) throw new ClassNotFoundException("can't find engine class " + klass); Method m = cl.getMethod("createEngine", new Class[] { String[].class, REngineCallbacks.class, Boolean.TYPE }); Object o = m.invoke(null, new Object[] { args, callbacks, Boolean.valueOf(runREPL) }); return lastEngine = (REngine)o; } /** retrieve the last created engine @return last created engine or null if no engine was created yet */ public static REngine getLastEngine() { return lastEngine; } /** parse a string into an expression vector @param text string to parse @param resolve resolve the resulting REXP (true) or just return a reference (false) @return parsed expression */ public abstract REXP parse(String text, boolean resolve) throws REngineException; /** evaluate an expression vector @param what an expression (or vector of such) to evaluate @param where environment to evaluate in (use null for the global environemnt and/or if environments are not supported by the engine) @param resolve resolve the resulting REXP or just return a reference @return the result of the evaluation of the last expression */ public abstract REXP eval(REXP what, REXP where, boolean resolve) throws REngineException, REXPMismatchException; /** assign into an environment @param symbol symbol name @param value value to assign @param env environment to assign to (use null for the global environemnt and/or if environments are not supported by the engine) */ public abstract void assign(String symbol, REXP value, REXP env) throws REngineException, REXPMismatchException; /** get a value from an environment @param symbol symbol name @param env environment (use null for the global environemnt and/or if environments are not supported by the engine) @param resolve resolve the resulting REXP or just return a reference @return value */ public abstract REXP get(String symbol, REXP env, boolean resolve) throws REngineException, REXPMismatchException; /** fetch the contents of the given reference. The resulting REXP may never be REXPReference. The engine should raise a {@link #REngineException} exception if {@link #supportsReferences()} returns false. @param ref reference to resolve @return resolved reference */ public abstract REXP resolveReference(REXP ref) throws REngineException, REXPMismatchException; /** create a reference by pushing local data to R and returning a reference to the data. If ref is a reference it is returned as-is. The engine should raise a {@link #REngineException} exception if {@link #supportsReferences()} returns false. @param value to create reference to @return reference to the value */ public abstract REXP createReference(REXP value) throws REngineException, REXPMismatchException; /** removes reference from the R side. This method is called automatically by the finalizer of REXPReference and should never be called directly. @param ref reference to finalize */ public abstract void finalizeReference(REXP ref) throws REngineException, REXPMismatchException; /** get the parent environemnt of an environemnt @param env environment to query @param resolve whether to resolve the resulting environment reference @return parent environemnt of env */ public abstract REXP getParentEnvironment(REXP env, boolean resolve) throws REngineException, REXPMismatchException; /** create a new environemnt @param parent parent environment @param resolve whether to resolve the reference to the environemnt (usually false since the returned environment will be empty) @return resulting environment */ public abstract REXP newEnvironment(REXP parent, boolean resolve) throws REngineException, REXPMismatchException; /** convenince method equivalent to eval(parse(text, false), where, resolve); @param text to parse (see {@link #parse}) @param where environment to evaluate in (see {@link #eval}) @param resolve whether to resolve the resulting reference or not (see {@link #eval}) @return result */ public REXP parseAndEval(String text, REXP where, boolean resolve) throws REngineException, REXPMismatchException { REXP p = parse(text, false); return eval(p, where, resolve); } /** convenince method equivalent to eval(parse(cmd, false), null, true); @param cmd expression to parse (see {@link #parse}) @return result */ public REXP parseAndEval(String cmd) throws REngineException, REXPMismatchException { return parseAndEval(cmd, null, true); }; /** performs a close operation on engines that support it. The engine may not be used after close() returned true. This operation is optional and will always return false if not implemented. @return true if the close opetaion was successful, false otherwise. */ public boolean close() { return false; } //--- capabilities --- /** check whether this engine supports references to R objects @return true if this engine supports references, false/code> otherwise */ public boolean supportsReferences() { return false; } /** check whether this engine supports handing of environments (if not, {@link #eval} and {@link #assign} only support the global environment denoted by null). @return true if this engine supports environments, false/code> otherwise */ public boolean supportsEnvironments() { return false; } /** check whether this engine supports REPL (Read-Evaluate-Print-Loop) and corresponding callbacks. @return true if this engine supports REPL, false/code> otherwise */ public boolean supportsREPL() { return false; } /** check whether this engine supports locking ({@link #lock}, {@link #tryLock} and {@link #unlock}). @return true if this engine supports REPL, false/code> otherwise */ public boolean supportsLocking() { return false; } //--- convenience methods --- (the REXPMismatchException catches should be no-ops since the value type is guaranteed in the call to assign) /** convenience method equivalent to assign(symbol, new REXPDouble(d), null) (see {@link #assign(String, REXP, REXP)}) @param symbol symbol name to assign to @param d values to assign */ public void assign(String symbol, double[] d) throws REngineException { try { assign(symbol, new REXPDouble(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,double[]): "+e)); } } /** convenience method equivalent to assign(symbol, new REXPInteger(d), null) (see {@link #assign(String, REXP, REXP)}) @param symbol symbol name to assign to @param d values to assign */ public void assign(String symbol, int[] d) throws REngineException { try { assign(symbol, new REXPInteger(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,int[]): "+e)); } } /** convenience method equivalent to assign(symbol, new REXPString(d), null) (see {@link #assign(String, REXP, REXP)}) @param symbol symbol name to assign to @param d values to assign */ public void assign(String symbol, String[] d) throws REngineException { try { assign(symbol, new REXPString(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,String[]): "+e)); } } /** convenience method equivalent to assign(symbol, new REXPRaw(d), null) (see {@link #assign(String, REXP, REXP)}) @param symbol symbol name to assign to @param d values to assign */ public void assign(String symbol, byte[] d) throws REngineException { try { assign(symbol, new REXPRaw(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,byte[]): "+e)); } } /** convenience method equivalent to assign(symbol, new REXPString(d), null) (see {@link #assign(String, REXP, REXP)}) @param symbol symbol name to assign to @param d value to assign */ public void assign(String symbol, String d) throws REngineException { try { assign(symbol, new REXPString(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,String[]): "+e)); } } /** convenience method equivalent to assign(symbol, value, null) (see {@link #assign(String, REXP, REXP)}) @param symbol symbol name to assign to @param value values to assign */ public void assign(String symbol, REXP value) throws REngineException, REXPMismatchException { assign(symbol, value, null); } //--- locking API --- /** attempts to obtain a lock for this R engine synchronously (without waiting for it).
Note: check for {@link #supportsLocking()} before relying on this capability. If not implemented, always returns 0. @return 0 if the lock could not be obtained (R engine is busy) and some other value otherwise -- the returned value must be used in a matching call to {@link #unlock(int)}. */ public synchronized int tryLock() { return 0; } /** obtains a lock for this R engine, waiting until it becomes available.
Note: check for {@link #supportsLocking()} before relying on this capability. If not implemented, always returns 0. @return value that must be passed to {@link #unlock} in order to release the lock */ public synchronized int lock() { return 0; } /** releases a lock previously obtained by {@link #lock()} or {@link #tryLock()}.
Note: check for {@link #supportsLocking()} before relying on this capability. If not implemented, has no effect. @param lockValue value returned by {@link #lock()} or {@link #tryLock()}. */ public synchronized void unlock(int lockValue) {} public String toString() { return super.toString()+((lastEngine==this)?"{last}":""); } public REXP wrap(Object o){ return REXPWrapper.wrap(o); } } Rserve/src/client/java/REXPReference.java0000644000175100001440000000730314531234224017767 0ustar hornikuserspackage org.rosuda.REngine; /** this class represents a reference (proxy) to an R object.

The reference semantics works by calling {@link #resolve()} (which in turn uses {@link REngine#resolveReference(REXP)} on itself) whenever any methods are accessed. The implementation is not finalized yat and may change as we approach the JRI interface which is more ameanable to reference-style access. Subclasses are free to implement more efficient implementations. */ public class REXPReference extends REXP { /** engine which will be used to resolve the reference */ protected REngine eng; /** an opaque (optional) handle */ protected Object handle; /** resolved (cached) object */ protected REXP resolvedValue; /** create an external REXP reference using given engine and handle. The handle value is just an (optional) identifier not used by the implementation directly. */ public REXPReference(REngine eng, Object handle) { super(); this.eng = eng; this.handle = handle; } /** shortcut for REXPReference(eng, new Long(handle)) that is used by native code */ REXPReference(REngine eng, long handle) { this(eng, Long.valueOf(handle)); } /** resolve the external REXP reference into an actual REXP object. In addition, the value (if not null) will be cached for subsequent calls to resolve until invalidate is called. */ public REXP resolve() { if (resolvedValue != null) return resolvedValue; try { resolvedValue = eng.resolveReference(this); return resolvedValue; } catch (REXPMismatchException me) { // this should never happen since we are REXPReference } catch(REngineException ee) { // FIXME: what to we do? } return null; } /** invalidates any cached representation of the reference */ public void invalidate() { resolvedValue = null; } /** finalization that notifies the engine when a reference gets collected */ protected void finalize() throws Throwable { try { eng.finalizeReference(this); } finally { super.finalize(); } } // type checks public boolean isString() { return resolve().isString(); } public boolean isNumeric() { return resolve().isNumeric(); } public boolean isInteger() { return resolve().isInteger(); } public boolean isNull() { return resolve().isNull(); } public boolean isFactor() { return resolve().isFactor(); } public boolean isList() { return resolve().isList(); } public boolean isLogical() { return resolve().isLogical(); } public boolean isEnvironment() { return resolve().isEnvironment(); } public boolean isLanguage() { return resolve().isLanguage(); } public boolean isSymbol() { return resolve().isSymbol(); } public boolean isVector() { return resolve().isVector(); } public boolean isRaw() { return resolve().isRaw(); } public boolean isComplex() { return resolve().isComplex(); } public boolean isRecursive() { return resolve().isRecursive(); } public boolean isReference() { return true; } // basic accessor methods public String[] asStrings() throws REXPMismatchException { return resolve().asStrings(); } public int[] asIntegers() throws REXPMismatchException { return resolve().asIntegers(); } public double[] asDoubles() throws REXPMismatchException { return resolve().asDoubles(); } public RList asList() throws REXPMismatchException { return resolve().asList(); } public RFactor asFactor() throws REXPMismatchException { return resolve().asFactor(); } public int length() throws REXPMismatchException { return resolve().length(); } public REXPList _attr() { return resolve()._attr(); } public Object getHandle() { return handle; } public REngine getEngine() { return eng; } public String toString() { return super.toString()+"{eng="+eng+",h="+handle+"}"; } } Rserve/src/client/java/REXPString.java0000644000175100001440000000270214531234224017335 0ustar hornikuserspackage org.rosuda.REngine; /** REXPString represents a character vector in R. */ public class REXPString extends REXPVector { /** payload */ private String[] payload; /** create a new character vector of the length one * @param load first (and only) element of the vector */ public REXPString(String load) { super(); payload=new String[] { load }; } /** create a new character vector * @param load string elements of the vector */ public REXPString(String[] load) { super(); payload=(load==null)?new String[0]:load; } /** create a new character vector with attributes * @param load string elements of the vector * @param attr attributes */ public REXPString(String[] load, REXPList attr) { super(attr); payload=(load==null)?new String[0]:load; } public int length() { return payload.length; } public boolean isString() { return true; } public Object asNativeJavaObject() { return payload; } public String[] asStrings() { return payload; } public boolean[] isNA() { boolean a[] = new boolean[payload.length]; int i = 0; while (i < a.length) { a[i] = (payload[i]==null); i++; } return a; } public String toDebugString() { StringBuffer sb = new StringBuffer(super.toDebugString()+"{"); int i = 0; while (i < payload.length && i < maxDebugItems) { if (i>0) sb.append(","); sb.append("\""+payload[i]+"\""); i++; } if (i < payload.length) sb.append(",.."); return sb.toString()+"}"; } } Rserve/src/client/java/JRI/0000755000175100001440000000000014531234224015150 5ustar hornikusersRserve/src/client/java/JRI/JRIEngine.java0000644000175100001440000010121014531234224017560 0ustar hornikusers// JRIEngine - REngine-based interface to JRI // Copyright(c) 2009 Simon Urbanek // // Currently it uses low-level calls from org.rosuda.JRI.Rengine, but // all REXP representations are created based on the org.rosuda.REngine API package org.rosuda.REngine.JRI; import org.rosuda.JRI.Rengine; import org.rosuda.JRI.Mutex; import org.rosuda.JRI.RMainLoopCallbacks; import org.rosuda.REngine.*; /** JRIEngine is a REngine implementation using JRI (Java/R Interface).

Note that at most one JRI instance can exist in a given JVM process, because R does not support multiple threads. JRIEngine itself is thread-safe, so it is possible to invoke its methods from any thread. However, this is achieved by serializing all entries into R, so be aware of possible deadlock conditions if your R code calls back into Java (JRIEngine is re-entrant from the same thread so deadlock issues can arise only with multiple threads inteacting thorugh R). */ public class JRIEngine extends REngine implements RMainLoopCallbacks { // internal R types as defined in Rinternals.h static final int NILSXP = 0; /* nil = NULL */ static final int SYMSXP = 1; /* symbols */ static final int LISTSXP = 2; /* lists of dotted pairs */ static final int CLOSXP = 3; /* closures */ static final int ENVSXP = 4; /* environments */ static final int PROMSXP = 5; /* promises: [un]evaluated closure arguments */ static final int LANGSXP = 6; /* language constructs */ static final int SPECIALSXP = 7; /* special forms */ static final int BUILTINSXP = 8; /* builtin non-special forms */ static final int CHARSXP = 9; /* "scalar" string type (internal only) */ static final int LGLSXP = 10; /* logical vectors */ static final int INTSXP = 13; /* integer vectors */ static final int REALSXP = 14; /* real variables */ static final int CPLXSXP = 15; /* complex variables */ static final int STRSXP = 16; /* string vectors */ static final int DOTSXP = 17; /* dot-dot-dot object */ static final int ANYSXP = 18; /* make "any" args work */ static final int VECSXP = 19; /* generic vectors */ static final int EXPRSXP = 20; /* expressions vectors */ static final int BCODESXP = 21; /* byte code */ static final int EXTPTRSXP = 22; /* external pointer */ static final int WEAKREFSXP = 23; /* weak reference */ static final int RAWSXP = 24; /* raw bytes */ static final int S4SXP = 25; /* S4 object */ /** minimal JRI API version that is required by this class in order to work properly (currently API 1.10, corresponding to JRI 0.5-1 or higher) */ static public final long requiredAPIversion = 0x010a; /** currently running JRIEngine - there can be only one and we store it here. Essentially if it is null then R was not initialized. */ static JRIEngine jriEngine = null; /** reference to the underlying low-level JRI (RNI) engine */ Rengine rni = null; /** event loop callbacks associated with this engine. */ REngineCallbacks callbacks = null; /** mutex synchronizing access to R through JRIEngine.

NOTE: only access through this class is synchronized. Any other access (e.g. using RNI directly) is NOT. */ Mutex rniMutex = null; // cached pointers of special objects in R long R_UnboundValue, R_NilValue; /** special, global references */ public REXPReference globalEnv, emptyEnv, baseEnv, nullValueRef; /** canonical NULL object */ public REXPNull nullValue; /** class used for wrapping raw pointers such that they are adequately protected and released according to the lifespan of the Java object */ class JRIPointer { long ptr; JRIPointer(long ptr, boolean preserve) { this.ptr = ptr; if (preserve && ptr != 0 && ptr != R_NilValue) { boolean obtainedLock = rniMutex.safeLock(); // this will inherently wait for R to become ready try { rni.rniPreserve(ptr); } finally { if (obtainedLock) rniMutex.unlock(); } } } protected void finalize() throws Throwable { try { if (ptr != 0 && ptr != R_NilValue) { boolean obtainedLock = rniMutex.safeLock(); try { rni.rniRelease(ptr); } finally { if (obtainedLock) rniMutex.unlock(); } } } finally { super.finalize(); } } long pointer() { return ptr; } } /** factory method called by engineForClass @return new or current engine (new if there is none, current otherwise since R allows only one engine at any time) */ public static REngine createEngine() throws REngineException { // there can only be one JRI engine in a process if (jriEngine == null) jriEngine = new JRIEngine(); return jriEngine; } public static REngine createEngine(String[] args, REngineCallbacks callbacks, boolean runREPL) throws REngineException { if (jriEngine != null) throw new REngineException(jriEngine, "engine already running - cannot use extended constructor on a running instance"); return jriEngine = new JRIEngine(args, callbacks, runREPL); } public Rengine getRni() { return rni; } /** default constructor - this constructor is also used via createEngine factory call and implies --no-save R argument, no callbacks and no REPL.

This is equivalent to JRIEngine(new String[] { "--no-save" }, null, false) */ public JRIEngine() throws REngineException { this(new String[] { "--no-save" }, (REngineCallbacks) null, false); } /** create JRIEngine with specified R command line arguments, no callbacks and no REPL.

This is equivalent to JRIEngine(args, null, false) */ public JRIEngine(String args[]) throws REngineException { this(args, (REngineCallbacks) null, false); } /** creates a JRI engine with specified delegate for callbacks (JRI compatibility mode ONLY!). The event loop is started if callbacks in not null. * @param args arguments to pass to R (note that R usually requires something like --no-save!) * @param callbacks delegate class to process event loop callback from R or null if no event loop is desired **/ public JRIEngine(String args[], RMainLoopCallbacks callbacks) throws REngineException { this(args, callbacks, (callbacks == null) ? false : true); } /** creates a JRI engine with specified delegate for callbacks * @param args arguments to pass to R (note that R usually requires something like --no-save!) * @param callback delegate class to process callbacks from R or null if no callbacks are desired * @param runREPL if set to true then the event loop (REPL) will be started, otherwise the engine is in direct operation mode. */ public JRIEngine(String args[], REngineCallbacks callbacks, boolean runREPL) throws REngineException { // if Rengine hasn't been able to load the native JRI library in its static // initializer, throw an exception if (!Rengine.jriLoaded) throw new REngineException (null, "Cannot load JRI native library"); if (Rengine.getVersion() < requiredAPIversion) throw new REngineException(null, "JRI API version is too old, update rJava/JRI to match the REngine API"); this.callbacks = callbacks; // the default modus operandi is without event loop and with --no-save option rni = new Rengine(args, runREPL, (callbacks == null) ? null : this); rniMutex = rni.getRsync(); boolean obtainedLock = rniMutex.safeLock(); // this will inherently wait for R to become ready try { if (!rni.waitForR()) throw(new REngineException(this, "Unable to initialize R")); if (rni.rniGetVersion() < requiredAPIversion) throw(new REngineException(this, "JRI API version is too old, update rJava/JRI to match the REngine API")); globalEnv = new REXPReference(this, Long.valueOf(rni.rniSpecialObject(Rengine.SO_GlobalEnv))); nullValueRef = new REXPReference(this, Long.valueOf(R_NilValue = rni.rniSpecialObject(Rengine.SO_NilValue))); emptyEnv = new REXPReference(this, Long.valueOf(rni.rniSpecialObject(Rengine.SO_EmptyEnv))); baseEnv = new REXPReference(this, Long.valueOf(rni.rniSpecialObject(Rengine.SO_BaseEnv))); nullValue = new REXPNull(); R_UnboundValue = rni.rniSpecialObject(Rengine.SO_UnboundValue); } finally { if (obtainedLock) rniMutex.unlock(); } // register ourself as the main and last engine lastEngine = this; if (jriEngine == null) jriEngine = this; } /** creates a JRI engine with specified delegate for callbacks (JRI compatibility mode ONLY! Will be deprecated soon!) * @param args arguments to pass to R (note that R usually requires something like --no-save!) * @param callback delegate class to process callbacks from R or null if no callbacks are desired * @param runREPL if set to true then the event loop (REPL) will be started, otherwise the engine is in direct operation mode. */ public JRIEngine(String args[], RMainLoopCallbacks callbacks, boolean runREPL) throws REngineException { // if Rengine hasn't been able to load the native JRI library in its static // initializer, throw an exception if (!Rengine.jriLoaded) throw new REngineException (null, "Cannot load JRI native library"); if (Rengine.getVersion() < requiredAPIversion) throw new REngineException(null, "JRI API version is too old, update rJava/JRI to match the REngine API"); // the default modus operandi is without event loop and with --no-save option rni = new Rengine(args, runREPL, callbacks); rniMutex = rni.getRsync(); boolean obtainedLock = rniMutex.safeLock(); // this will inherently wait for R to become ready try { if (!rni.waitForR()) throw(new REngineException(this, "Unable to initialize R")); if (rni.rniGetVersion() < requiredAPIversion) throw(new REngineException(this, "JRI API version is too old, update rJava/JRI to match the REngine API")); globalEnv = new REXPReference(this, Long.valueOf(rni.rniSpecialObject(Rengine.SO_GlobalEnv))); nullValueRef = new REXPReference(this, Long.valueOf(R_NilValue = rni.rniSpecialObject(Rengine.SO_NilValue))); emptyEnv = new REXPReference(this, Long.valueOf(rni.rniSpecialObject(Rengine.SO_EmptyEnv))); baseEnv = new REXPReference(this, Long.valueOf(rni.rniSpecialObject(Rengine.SO_BaseEnv))); nullValue = new REXPNull(); R_UnboundValue = rni.rniSpecialObject(Rengine.SO_UnboundValue); } finally { if (obtainedLock) rniMutex.unlock(); } // register ourself as the main and last engine lastEngine = this; if (jriEngine == null) jriEngine = this; } /** WARNING: legacy fallback for hooking from R into an existing Rengine - do NOT use for creating a new Rengine - it will go away eventually */ public JRIEngine(Rengine eng) throws REngineException { // if Rengine hasn't been able to load the native JRI library in its static // initializer, throw an exception if (!Rengine.jriLoaded) throw new REngineException (null, "Cannot load JRI native library"); rni = eng; if (rni.rniGetVersion() < 0x109) throw(new REngineException(this, "R JRI engine is too old - RNI API 1.9 (JRI 0.5) or newer is required")); rniMutex = rni.getRsync(); boolean obtainedLock = rniMutex.safeLock(); try { globalEnv = new REXPReference(this, Long.valueOf(rni.rniSpecialObject(Rengine.SO_GlobalEnv))); nullValueRef = new REXPReference(this, Long.valueOf(R_NilValue = rni.rniSpecialObject(Rengine.SO_NilValue))); emptyEnv = new REXPReference(this, Long.valueOf(rni.rniSpecialObject(Rengine.SO_EmptyEnv))); baseEnv = new REXPReference(this, Long.valueOf(rni.rniSpecialObject(Rengine.SO_BaseEnv))); nullValue = new REXPNull(); R_UnboundValue = rni.rniSpecialObject(Rengine.SO_UnboundValue); } finally { if (obtainedLock) rniMutex.unlock(); } // register ourself as the main and last engine lastEngine = this; if (jriEngine == null) jriEngine = this; } public REXP parse(String text, boolean resolve) throws REngineException { REXP ref = null; boolean obtainedLock = rniMutex.safeLock(); try { long pr = rni.rniParse(text, -1); if (pr == 0 || pr == R_NilValue) throw(new REngineException(this, "Parse error")); rni.rniPreserve(pr); ref = new REXPReference(this, Long.valueOf(pr)); if (resolve) try { ref = resolveReference(ref); } catch (REXPMismatchException me) { }; } finally { if (obtainedLock) rniMutex.unlock(); } return ref; } public REXP eval(REXP what, REXP where, boolean resolve) throws REngineException, REXPMismatchException { REXP ref = null; long rho = 0; if (where != null && !where.isReference()) { if (!where.isEnvironment() || ((REXPEnvironment)where).getHandle() == null) throw(new REXPMismatchException(where, "environment")); else rho = ((JRIPointer)((REXPEnvironment)where).getHandle()).pointer(); } else if (where != null) rho = ((Long)((REXPReference)where).getHandle()).longValue(); if (what == null) throw(new REngineException(this, "null object to evaluate")); if (!what.isReference()) { if (what.isExpression() || what.isLanguage()) what = createReference(what); else throw(new REXPMismatchException(where, "reference, expression or language")); } boolean obtainedLock = rniMutex.safeLock(); try { long pr = rni.rniEval(((Long)((REXPReference)what).getHandle()).longValue(), rho); if (pr == 0) // rniEval() signals error by passing 0 throw new REngineEvalException(this, "error during evaluation", REngineEvalException.ERROR) ; rni.rniPreserve(pr); ref = new REXPReference(this, Long.valueOf(pr)); if (resolve) ref = resolveReference(ref); } finally { if (obtainedLock) rniMutex.unlock(); } return ref; } public void assign(String symbol, REXP value, REXP env) throws REngineException, REXPMismatchException { long rho = 0; if (env != null && !env.isReference()) { if (!env.isEnvironment() || ((REXPEnvironment)env).getHandle() == null) throw(new REXPMismatchException(env, "environment")); else rho = ((JRIPointer)((REXPEnvironment)env).getHandle()).pointer(); } else if (env != null) rho = ((Long)((REXPReference)env).getHandle()).longValue(); if (value == null) value = nullValueRef; if (!value.isReference()) value = createReference(value); // if value is not a reference, we have to create one boolean obtainedLock = rniMutex.safeLock(), succeeded = false; try { succeeded = rni.rniAssign(symbol, ((Long)((REXPReference)value).getHandle()).longValue(), rho); } finally { if (obtainedLock) rniMutex.unlock(); } if (!succeeded) throw new REngineException(this, "assign failed (probably locked binding"); } public REXP get(String symbol, REXP env, boolean resolve) throws REngineException, REXPMismatchException { REXP ref = null; long rho = 0; if (env != null && !env.isReference()) { if (!env.isEnvironment() || ((REXPEnvironment)env).getHandle() == null) throw(new REXPMismatchException(env, "environment")); else rho = ((JRIPointer)((REXPEnvironment)env).getHandle()).pointer(); } else if (env != null) rho = ((Long)((REXPReference)env).getHandle()).longValue(); boolean obtainedLock = rniMutex.safeLock(); try { long pr = rni.rniFindVar(symbol, rho); if (pr == R_UnboundValue || pr == 0) return null; rni.rniPreserve(pr); ref = new REXPReference(this, Long.valueOf(pr)); if (resolve) try { ref = resolveReference(ref); } catch (REXPMismatchException me) { }; } finally { if (obtainedLock) rniMutex.unlock(); } return ref; } public REXP resolveReference(REXP ref) throws REngineException, REXPMismatchException { REXP res = null; if (ref == null) throw(new REngineException(this, "resolveReference called on NULL input")); if (!ref.isReference()) throw(new REXPMismatchException(ref, "reference")); long ptr = ((Long)((REXPReference)ref).getHandle()).longValue(); if (ptr == 0) return nullValue; return resolvePointer(ptr); } /** * Turn an R pointer (long) into a REXP object. * * This is the actual implementation of resolveReference but it works directly on the long pointers to be more efficient when performing recursive de-referencing */ REXP resolvePointer(long ptr) throws REngineException, REXPMismatchException { if (ptr == 0) return nullValue; REXP res = null; boolean obtainedLock = rniMutex.safeLock(); try { int xt = rni.rniExpType(ptr); String an[] = rni.rniGetAttrNames(ptr); REXPList attrs = null; if (an != null && an.length > 0) { // are there attributes? Then we need to resolve them first // we allow special handling for Java references so we need the class and jobj long jobj = 0; String oclass = null; RList attl = new RList(); for (int i = 0; i < an.length; i++) { long aptr = rni.rniGetAttr(ptr, an[i]); if (aptr != 0 && aptr != R_NilValue) { if (an[i].equals("jobj")) jobj = aptr; REXP av = resolvePointer(aptr); if (av != null && av != nullValue) { attl.put(an[i], av); if (an[i].equals("class") && av.isString()) oclass = av.asString(); } } } if (attl.size() > 0) attrs = new REXPList(attl); // FIXME: in general, we could allow arbitrary convertors here ... // Note that the jobj hack is only needed because we don't support EXTPTRSXP conversion // (for a good reason - we can't separate the PTR from the R object so the only way it can // live is as a reference and we don't want resolvePointer to ever return REXPReference as // that could trigger infinite recursions), but if we did, we could allow post-processing // based on the class attribute on the converted REXP.. (better, we can leverage REXPUnknown // and pass the ptr to the convertor so it can pull things like EXTPTR via rni) if (jobj != 0 && oclass != null && (oclass.equals("jobjRef") || oclass.equals("jarrayRef") || oclass.equals("jrectRef"))) return new REXPJavaReference(rni.rniXrefToJava(jobj), attrs); } switch (xt) { case NILSXP: return nullValue; case STRSXP: String[] s = rni.rniGetStringArray(ptr); res = new REXPString(s, attrs); break; case INTSXP: if (rni.rniInherits(ptr, "factor")) { long levx = rni.rniGetAttr(ptr, "levels"); if (levx != 0) { String[] levels = null; // we're using low-level calls here (FIXME?) int rlt = rni.rniExpType(levx); if (rlt == STRSXP) { levels = rni.rniGetStringArray(levx); int[] ids = rni.rniGetIntArray(ptr); res = new REXPFactor(ids, levels, attrs); } } } // if it's not a factor, then we use int[] instead if (res == null) res = new REXPInteger(rni.rniGetIntArray(ptr), attrs); break; case REALSXP: res = new REXPDouble(rni.rniGetDoubleArray(ptr), attrs); break; case LGLSXP: { int ba[] = rni.rniGetBoolArrayI(ptr); byte b[] = new byte[ba.length]; for (int i = 0; i < ba.length; i++) b[i] = (ba[i] == 0 || ba[i] == 1) ? (byte) ba[i] : REXPLogical.NA; res = new REXPLogical(b, attrs); } break; case VECSXP: { long l[] = rni.rniGetVector(ptr); REXP rl[] = new REXP[l.length]; long na = rni.rniGetAttr(ptr, "names"); String[] names = null; if (na != 0 && rni.rniExpType(na) == STRSXP) names = rni.rniGetStringArray(na); for (int i = 0; i < l.length; i++) rl[i] = resolvePointer(l[i]); RList list = (names == null) ? new RList(rl) : new RList(rl, names); res = new REXPGenericVector(list, attrs); } break; case RAWSXP: res = new REXPRaw(rni.rniGetRawArray(ptr), attrs); break; case LISTSXP: case LANGSXP: { RList l = new RList(); // we need to plow through the list iteratively - the recursion occurs at the value level long cdr = ptr; while (cdr != 0 && cdr != R_NilValue) { long car = rni.rniCAR(cdr); long tag = rni.rniTAG(cdr); String name = null; if (rni.rniExpType(tag) == SYMSXP) name = rni.rniGetSymbolName(tag); REXP val = resolvePointer(car); if (name == null) l.add(val); else l.put(name, val); cdr = rni.rniCDR(cdr); } res = (xt == LANGSXP) ? new REXPLanguage(l, attrs) : new REXPList(l, attrs); } break; case SYMSXP: res = new REXPSymbol(rni.rniGetSymbolName(ptr)); break; case ENVSXP: if (ptr != 0) rni.rniPreserve(ptr); res = new REXPEnvironment(this, new JRIPointer(ptr, false)); break; case S4SXP: res = new REXPS4(attrs); break; default: res = new REXPUnknown(xt, attrs); break; } } finally { if (obtainedLock) rniMutex.unlock(); } return res; } public REXP createReference(REXP value) throws REngineException, REXPMismatchException { if (value == null) throw(new REngineException(this, "createReference from a NULL value")); if (value.isReference()) return value; long ptr = createReferencePointer(value); if (ptr == 0) return null; boolean obtainedLock = rniMutex.safeLock(); try { rni.rniPreserve(ptr); } finally { if (obtainedLock) rniMutex.unlock(); } return new REXPReference(this, Long.valueOf(ptr)); } /** * Create an R object, returning its pointer, from an REXP java object. * * @param value * @return long R pointer * @throws REngineException if any of the RNI calls fails * @throws REXPMismatchException only if some internal inconsistency happens. The internal logic should prevent invalid access to valid objects. */ long createReferencePointer(REXP value) throws REngineException, REXPMismatchException { if (value.isReference()) { // if it's reference, return the handle if it's from this engine REXPReference vref = (REXPReference) value; if (vref.getEngine() != this) throw new REXPMismatchException(value, "reference (cross-engine reference is invalid)"); return ((Long)vref.getHandle()).longValue(); } boolean obtainedLock = rniMutex.safeLock(); int upp = 0; try { long ptr = 0; if (value.isNull()) // NULL cannot have attributes, hence get out right away return R_NilValue; else if (value.isLogical()) { int v[] = value.asIntegers(); for (int i = 0; i < v.length; i++) v[i] = (v[i] < 0) ? 2 : ((v[i] == 0) ? 0 : 1); // convert to logical NAs as used by R ptr = rni.rniPutBoolArrayI(v); } else if (value.isInteger()) ptr = rni.rniPutIntArray(value.asIntegers()); else if (value.isRaw()) ptr = rni.rniPutRawArray(value.asBytes()); else if (value.isNumeric()) ptr = rni.rniPutDoubleArray(value.asDoubles()); else if (value.isString()) ptr = rni.rniPutStringArray(value.asStrings()); else if (value.isEnvironment()) { JRIPointer l = (JRIPointer) ((REXPEnvironment)value).getHandle(); if (l == null) { // no associated reference, create a new environemnt long p = rni.rniParse("new.env(parent=baseenv())", 1); ptr = rni.rniEval(p, 0); /* TODO: should we handle REngineEvalException.ERROR and REngineEvalException.INVALID_INPUT here, for completeness */ } else ptr = l.pointer(); } else if (value.isPairList()) { // LISTSXP / LANGSXP boolean lang = value.isLanguage(); RList rl = value.asList(); ptr = R_NilValue; int j = rl.size(); if (j == 0) ptr = rni.rniCons(R_NilValue, 0, 0, lang); else // we are in a somewhat unfortunate situation because we cannot append to the list (RNI has no rniSetCDR!) so we have to use Preserve and bulild the list backwards which may be a bit slower ... for (int i = j - 1; i >= 0; i--) { REXP v = rl.at(i); String n = rl.keyAt(i); long sn = 0; if (n != null) sn = rni.rniInstallSymbol(n); long vptr = createReferencePointer(v); if (vptr == 0) vptr = R_NilValue; long ent = rni.rniCons(vptr, ptr, sn, (i == 0) && lang); /* only the head should be LANGSXP I think - verify ... */ rni.rniPreserve(ent); // preserve current head rni.rniRelease(ptr); // release previous head (since it's part of the new one already) ptr = ent; } } else if (value.isList()) { // VECSXP int init_upp = upp; RList rl = value.asList(); long xl[] = new long[rl.size()]; for (int i = 0; i < xl.length; i++) { REXP rv = rl.at(i); if (rv == null || rv.isNull()) xl[i] = R_NilValue; else { long lv = createReferencePointer(rv); if (lv != 0 && lv != R_NilValue) { rni.rniProtect(lv); upp++; } else lv = R_NilValue; xl[i] = lv; } } ptr = rni.rniPutVector(xl); if (init_upp > upp) { rni.rniUnprotect(upp - init_upp); upp = init_upp; } } else if (value.isSymbol()) return rni.rniInstallSymbol(value.asString()); // symbols need no attribute handling, hence get out right away else if (value instanceof REXPJavaReference) { // we wrap Java references by calling new("jobjRef", ...) Object jval = ((REXPJavaReference)value).getObject(); long jobj = rni.rniJavaToXref(jval); rni.rniProtect(jobj); long jobj_sym = rni.rniInstallSymbol("jobj"); long jclass_sym = rni.rniInstallSymbol("jclass"); String clname = "java/lang/Object"; if (jval != null) { clname = jval.getClass().getName(); clname = clname.replace('.', '/'); } long jclass = rni.rniPutString(clname); rni.rniProtect(jclass); long jobjRef = rni.rniPutString("jobjRef"); rni.rniProtect(jobjRef); long ro = rni.rniEval(rni.rniLCons(rni.rniInstallSymbol("new"), rni.rniCons(jobjRef, rni.rniCons(jobj, rni.rniCons(jclass, R_NilValue, jclass_sym, false), jobj_sym, false)) ), 0); rni.rniUnprotect(3); ptr = ro; } if (ptr == R_NilValue) return ptr; if (ptr != 0) { REXPList att = value._attr(); if (att == null || !att.isPairList()) return ptr; // no valid attributes? the we're done RList al = att.asList(); if (al == null || al.size() < 1 || !al.isNamed()) return ptr; // again - no valid list, get out rni.rniProtect(ptr); // symbols and other exotic creatures are already out by now, so it's ok to protect upp++; for (int i = 0; i < al.size(); i++) { REXP v = al.at(i); String n = al.keyAt(i); if (n != null) { long vptr = createReferencePointer(v); if (vptr != 0 && vptr != R_NilValue) rni.rniSetAttr(ptr, n, vptr); } } return ptr; } } finally { if (upp > 0) rni.rniUnprotect(upp); if (obtainedLock) rniMutex.unlock(); } // we fall thgough here if the object cannot be handled or something went wrong return 0; } public void finalizeReference(REXP ref) throws REngineException, REXPMismatchException { if (ref != null && ref.isReference()) { long ptr = ((Long)((REXPReference)ref).getHandle()).longValue(); boolean obtainedLock = rniMutex.safeLock(); try { rni.rniRelease(ptr); } finally { if (obtainedLock) rniMutex.unlock(); } } } public REXP getParentEnvironment(REXP env, boolean resolve) throws REngineException, REXPMismatchException { REXP ref = null; long rho = 0; if (env != null && !env.isReference()) { if (!env.isEnvironment() || ((REXPEnvironment)env).getHandle() == null) throw(new REXPMismatchException(env, "environment")); else rho = ((JRIPointer)((REXPEnvironment)env).getHandle()).pointer(); } else if (env != null) rho = ((Long)((REXPReference)env).getHandle()).longValue(); boolean obtainedLock = rniMutex.safeLock(); try { long pr = rni.rniParentEnv(rho); if (pr == 0 || pr == R_NilValue) return null; // this should never happen, really rni.rniPreserve(pr); ref = new REXPReference(this, Long.valueOf(pr)); if (resolve) ref = resolveReference(ref); } finally { if (obtainedLock) rniMutex.unlock(); } return ref; } public REXP newEnvironment(REXP parent, boolean resolve) throws REXPMismatchException, REngineException { REXP ref = null; boolean obtainedLock = rniMutex.safeLock(); try { long rho = 0; if (parent != null && !parent.isReference()) { if (!parent.isEnvironment() || ((REXPEnvironment)parent).getHandle() == null) throw(new REXPMismatchException(parent, "environment")); else rho = ((JRIPointer)((REXPEnvironment)parent).getHandle()).pointer(); } else if (parent != null) rho = ((Long)((REXPReference)parent).getHandle()).longValue(); if (rho == 0) rho = ((Long)((REXPReference)globalEnv).getHandle()).longValue(); long p = rni.rniEval(rni.rniLCons(rni.rniInstallSymbol("new.env"), rni.rniCons(rho, R_NilValue, rni.rniInstallSymbol("parent"), false)), 0); /* TODO: should we handle REngineEvalException.INVALID_INPUT and REngineEvalException.ERROR here, for completeness */ if (p != 0) rni.rniPreserve(p); ref = new REXPReference(this, Long.valueOf(p)); if (resolve) ref = resolveReference(ref); } finally { if (obtainedLock) rniMutex.unlock(); } return ref; } public boolean close() { if (rni == null) return false; rni.end(); return true; } /** attempts to obtain a lock for this R engine synchronously (without waiting for it). @return 0 if the lock could not be obtained (R is busy) and some other value otherwise (1 = lock obtained, 2 = the current thread already holds a lock) -- the returned value must be used in a matching call to {@link #unlock(int)}. */ public synchronized int tryLock() { int res = rniMutex.tryLock(); return (res == 1) ? 0 : ((res == -1) ? 2 : 1); } /** obains a lock for this R engine, waiting until it becomes available. @return value that must be passed to {@link #unlock} in order to release the lock */ public synchronized int lock() { return rniMutex.safeLock() ? 1 : 2; } /** releases a lock previously obtained by {@link #lock()} or {@link #tryLock()}. @param lockValue value returned by {@link #lock()} or {@link #tryLock()}. */ public synchronized void unlock(int lockValue) { if (lockValue == 1) rniMutex.unlock(); } public boolean supportsReferences() { return true; } public boolean supportsEnvironments() { return true; } // public boolean supportsREPL() { return true; } public boolean supportsLocking() { return true; } /** * creates a jobjRef reference in R via rJava.
Important: rJava must be loaded and intialized in R (e.g. via eval("{library(rJava);.jinit()}",false), otherwise this will fail. Requires rJava 0.4-13 or higher! * * @param o object to push to R * * @return unresolved REXPReference of the newly created jobjRef object * or null upon failure */ public REXPReference createRJavaRef(Object o) throws REngineException { /* precaution */ if( o == null ){ return null ; } /* call Rengine api and make REXPReference from the result */ REXPReference ref = null ; boolean obtainedLock = rniMutex.safeLock(); try { org.rosuda.JRI.REXP rx = rni.createRJavaRef( o ); if( rx == null){ throw new REngineException( this, "Could not push java Object to R" ) ; } else{ long p = rx.xp; rni.rniPreserve(p) ; ref = new REXPReference( this, Long.valueOf(p) ) ; } } finally { if (obtainedLock) rniMutex.unlock(); } return ref ; } /** JRI callbacks forwarding */ public void rWriteConsole (Rengine re, String text, int oType) { if (callbacks != null && callbacks instanceof REngineOutputInterface) ((REngineOutputInterface)callbacks).RWriteConsole(this, text, oType); } public void rBusy (Rengine re, int which) { if (callbacks != null && callbacks instanceof REngineUIInterface) ((REngineUIInterface)callbacks).RBusyState(this, which); } public synchronized String rReadConsole (Rengine re, String prompt, int addToHistory) { if (callbacks != null && callbacks instanceof REngineInputInterface) return ((REngineInputInterface)callbacks).RReadConsole(this, prompt, addToHistory); try { wait(); } catch (Exception e) {} return ""; } public void rShowMessage (Rengine re, String message) { if (callbacks != null && callbacks instanceof REngineOutputInterface) ((REngineOutputInterface)callbacks).RShowMessage(this, message); } public String rChooseFile (Rengine re, int newFile) { if (callbacks != null && callbacks instanceof REngineUIInterface) return ((REngineUIInterface)callbacks).RChooseFile(this, (newFile == 0)); return null; } public void rFlushConsole (Rengine re) { if (callbacks != null && callbacks instanceof REngineOutputInterface) ((REngineOutputInterface)callbacks).RFlushConsole(this); } public void rSaveHistory (Rengine re, String filename) { if (callbacks != null && callbacks instanceof REngineConsoleHistoryInterface) ((REngineConsoleHistoryInterface)callbacks).RSaveHistory(this, filename); } public void rLoadHistory (Rengine re, String filename) { if (callbacks != null && callbacks instanceof REngineConsoleHistoryInterface) ((REngineConsoleHistoryInterface)callbacks).RLoadHistory(this, filename); } } Rserve/src/client/java/JRI/Makefile0000644000175100001440000000130314531234227016610 0ustar hornikusers## there are two ways to compile JRIEngine - either use ## already installed REngine and JRI and then just ## compile JRIEngine against those jars or use this ## Makefile with all org sources checked out ## in which case the JRIEngine.jar will implicitly ## contain org.rosuda.JRI classes as well ## However, that requires both: ## org/rosuda/JRI ## org/rosuda/REngine JRI_MAIN_SRC=$(wildcard ../../*.java) JRIENGINE_SRC=JRIEngine.java JAVAC=javac JAR=jar JFLAGS=-source 1.6 -target 1.6 all: JRIEngine.jar JRIEngine.jar: $(JRI_MAIN_SRC) $(JRIENGINE_SRC) rm -rf org $(JAVAC) $(JFLAGS) -classpath ../REngine.jar -d . $^ $(JAR) fc $@ org clean: rm -rf org *~ JRIEngine.jar *.class make -C test clean Rserve/src/client/java/JRI/test/0000755000175100001440000000000014531234224016127 5ustar hornikusersRserve/src/client/java/JRI/test/RTest.java0000644000175100001440000004134414531234224020041 0ustar hornikusersimport org.rosuda.REngine.*; class TestException extends Exception { public TestException(String msg) { super(msg); } } // This is the same test as in Rserve but it's using JRI instead public class RTest { public static void main(String[] args) { try { // the simple initialization is done using // REngine eng = REngine.engineForClass("org.rosuda.REngine.JRI.JRIEngine"); // but the one below allows us to see all output from R via REngineStdOutput() // However, it won't succeed if the engine doesn't support callbacks, so be prepared to fall back REngine eng = REngine.engineForClass("org.rosuda.REngine.JRI.JRIEngine", args, new REngineStdOutput(), false); if (args.length > 0 && args[0].equals("--debug")) { // --debug waits for so a debugger can be attached System.out.println("R Version: " + eng.parseAndEval("R.version.string").asString()); System.out.println("ok, connected, press to continue\n"); System.in.read(); } { System.out.println("* Test string and list retrieval"); RList l = eng.parseAndEval("{d=data.frame(\"huhu\",c(11:20)); lapply(d,as.character)}").asList(); int cols = l.size(); int rows = l.at(0).length(); String[][] s = new String[cols][]; for (int i=0; i { .env <- new.env(); .env$x <- 2 }" ); System.out.println( " env = eng.get(\".env\", null, false ) " ); System.out.print( " parseAndEval( \"x+1\", env, true)" ); if( !( x instanceof REXPDouble ) || x.asDouble() != 3.0 ) throw new TestException("eval within environment failed") ; System.out.println( " == 3.0 : ok" ); System.out.println("PASSED"); } /* SU: wrap() tests removed since they didn't even compile ... */ { System.out.println("* Test generation of exceptions"); /* parse exceptions */ String cmd = "rnorm(10))" ; // syntax error System.out.println(" eng.parse(\"rnorm(10))\", false ) -> REngineException( \"Parse Error\" ) " ) ; boolean ok = false; try{ eng.parse( cmd, false ) ; } catch( REngineException e){ ok = true ; } if( !ok ){ throw new TestException( "parse did not generate an exception on syntax error" ) ; } System.out.println(" eng.parseAndEval(\"rnorm(10))\" ) -> REngineException( \"Parse Error\" ) " ) ; ok = false; try{ eng.parseAndEval( cmd ) ; } catch( REngineException e){ ok = true ; } if( !ok ){ throw new TestException( "parseAndEval did not generate an exception on syntax error" ) ; } /* eval exceptions */ cmd = "rnorm(5); stop('error'); rnorm(2)" ; System.out.print(" " + cmd ) ; ok = false; try{ eng.parseAndEval( cmd ) ; } catch( REngineException e){ if( e instanceof REngineEvalException ){ ok = true ; } } if( !ok ){ throw new TestException( "error in R did not generate REngineEvalException" ) ; } System.out.println( " -> REngineEvalException : ok" ) ; System.out.println("PASSED"); } { System.out.println("* Test creation of references to java objects"); if (!((REXPLogical)eng.parseAndEval("require(rJava)")).isTRUE()[0]) { System.out.println(" - rJava is not available, skipping test\n"); } else if (!(eng instanceof org.rosuda.REngine.JRI.JRIEngine)) { System.out.println(" - the used engine is not JRIEngine, skipping test\n"); } else { /* try to use rJava before it is initialized */ System.out.print(" checking that rJava generate error if not yet loaded" ) ; boolean error = false; try{ eng.parseAndEval( "p <- .jnew( 'java/awt/Point' ) " ) ; } catch( REngineException e){ error = true ; } if( !error ){ throw new TestException( "rJava not initiliazed, but did not generate error" ) ; } System.out.println( " : ok" ) ; eng.parseAndEval(".jinit()"); REXPReference ref = ((org.rosuda.REngine.JRI.JRIEngine)eng).createRJavaRef( null ); if( ref != null ){ throw new TestException( "null object should create null REXPReference" ) ; } System.out.println(" eng.createRJavaRef(null) -> null : ok" ) ; System.out.println( " pushing a java.awt.Point to R " ) ; java.awt.Point p = new java.awt.Point( 10, 10) ; ref = ((org.rosuda.REngine.JRI.JRIEngine)eng).createRJavaRef( p ); eng.assign( "p", ref ) ; String cmd = "exists('p') && inherits( p, 'jobjRef') && .jclass(p) == 'java.awt.Point' " ; System.out.println( " test if the object was pushed correctly " ) ; boolean ok = ((REXPLogical)eng.parseAndEval( cmd )).isTRUE()[0] ; if( !ok ){ throw new TestException( "could not push java object to R" ) ; } System.out.println( " R> " + cmd + " : ok " ) ; eng.parseAndEval( ".jcall( p, 'V', 'move', 20L, 20L )" ) ; System.out.println(" manipulate the object " ) ; if( p.x != 20 || p.y != 20 ){ throw new TestException( "not modified the java object with R" ) ; } System.out.println(" R> .jcall( p, 'V', 'move', 20L, 20L ) -> p.x == 20 ,p.y == 20 : ok " ) ; /* bug #126, use of .jfield with guess of the return class using reflection */ System.out.print(" using .jfield with reflection (bug #126)" ) ; eng.parseAndEval( ".jfield( p, , 'x')" ) ; /* used to crash the jvm; (not really - the code in the bgu just forgot to init rJava) */ System.out.println(" : ok " ) ; System.out.println("PASSED"); } } /* setEncoding is Rserve's extension - with JRI you have to use UTF-8 locale so this test will fail unless run in UTF-8 { // string encoding test (will work with Rserve 0.5-3 and higher only) System.out.println("* Test string encoding support ..."); String t = "ã²ã‚‰ãŒãª"; // hiragana (literally, in hiragana ;)) eng.setStringEncoding("utf8"); // -- Just in case the console is not UTF-8 don't display it //System.out.println(" unicode text: "+t); eng.assign("s", t); REXP x = eng.parseAndEval("nchar(s)"); System.out.println(" nchar = " + x); if (x == null || !x.isInteger() || x.asInteger() != 4) throw new TestException("UTF-8 encoding string length test failed"); // we cannot really test any other encoding .. System.out.println("PASSED"); } */ eng.close(); // close the engine connection System.out.println("Done."); } catch (REXPMismatchException me) { // some type is different from what you (the programmer) expected System.err.println("Type mismatch: "+me); me.printStackTrace(); System.exit(1); } catch (REngineException ee) { // something went wring in the engine System.err.println("REngine exception: "+ee); ee.printStackTrace(); System.exit(1); } catch (ClassNotFoundException cnfe) { // class not found is thrown by engineForClass System.err.println("Cannot find JRIEngine class - please fix your class path!\n"+cnfe); System.exit(1); } catch (Exception e) { // some other exception ... System.err.println("Exception: "+e); e.printStackTrace(); System.exit(1); } } } Rserve/src/client/java/JRI/test/Makefile0000644000175100001440000000122014531234227017565 0ustar hornikusers## NOTE: the tests require rJava to be installed in the current R ## since they also test the JRI/rJava connectivity CP=../../REngine.jar:../JRIEngine.jar:$(RJAVA)/java/boot:$(RJAVA)/jri/JRI.jar JFLAGS=-source 1.6 -target 1.6 RJAVA=$(shell echo "cat(system.file(package='rJava'))"|R --slave --no-save) JRI=$(shell if test -e ../../../JRI/src/JRI.jar; then echo ../../../JRI/src; else echo $(RJAVA)/jri; fi) JRT=-Djava.library.path=$(JRI):. JAVAC=javac JAVA=java all: run RTest.class: RTest.java $(JAVAC) $(JFLAGS) -classpath $(CP) $^ run: RTest.class R CMD $(JAVA) -cp $(CP):. $(JRT) RTest clean: rm -rf org *.class *~ .PHONY: run clean Rserve/src/client/java/JRI/package-info.java0000644000175100001440000000035014531234224020335 0ustar hornikusers/** * REngine-based interface to JRI * *

* Currently it uses low-level calls from org.rosuda.JRI.Rengine, but * all REXP representations are created based on the org.rosuda.REngine API */ package org.rosuda.REngine.JRI ; Rserve/src/client/java/REXPLogical.java0000644000175100001440000001251714531234224017446 0ustar hornikuserspackage org.rosuda.REngine; /** REXPLogical represents a vector of logical values (TRUE, FALSE or NA). Unlike Java's boolean type R's logicals support NA values therefore either of {@link #isTRUE()}, {@link #isFALSE()} or {@link #isNA()} must be used to convert logicals to boolean values. */ public class REXPLogical extends REXPVector { protected byte[] payload; /** NA integer value as defined in R. Unlike its real equivalent this one can be used in comparisons, although {@link #isNA(int) } is provided for consistency. */ static final int NA_internal = -2147483648; /** NA boolean value as used in REXPLogical implementation. This differs from the value used in R since R uses int data type and we use byte. Unlike its real equivalent this one can be used in comparisons, although {@link #isNA(byte) } is provided for consistency. */ public static final byte NA = -128; public static final byte TRUE = 1; public static final byte FALSE = 0; public static boolean isNA(byte value) { return (value == NA); } /** create logical vector of the length 1 with the given value as its first (and only) element */ public REXPLogical(boolean load) { super(); payload = new byte[] { load ? TRUE : FALSE }; } /** create logical vector of the length 1 with the given value as its first (and only) element */ public REXPLogical(byte load) { super(); payload = new byte[] { load }; } /** create logical vector with the payload specified by load */ public REXPLogical(byte[] load) { super(); payload = (load==null) ? new byte[0]:load; } /** create logical vector with the payload specified by load */ public REXPLogical(boolean[] load) { super(); payload = new byte[(load == null) ? 0 : load.length]; if (load != null) for (int i = 0; i < load.length; i++) payload[i] = load[i] ? TRUE : FALSE; } /** create integer vector with the payload specified by load and attributes attr */ public REXPLogical(byte[] load, REXPList attr) { super(attr); payload = (load==null) ? new byte[0] : load; } /** create integer vector with the payload specified by load and attributes attr */ public REXPLogical(boolean[] load, REXPList attr) { super(attr); payload = new byte[(load == null) ? 0 : load.length]; if (load != null) for (int i = 0; i < load.length; i++) payload[i] = load[i] ? TRUE : FALSE; } public int length() { return payload.length; } public boolean isLogical() { return true; } public Object asNativeJavaObject() { return payload; } public int[] asIntegers() { int p[] = new int[payload.length]; for (int i = 0; i < payload.length; i++) // map bytes to integers including NA representation p[i] = (payload[i] == NA) ? REXPInteger.NA : ((payload[i] == FALSE) ? 0 : 1); return p; } public byte[] asBytes() { return payload; } /** returns the contents of this vector as doubles */ public double[] asDoubles() { double[] d = new double[payload.length]; for (int i = 0; i < payload.length; i++) d[i] = (payload[i] == NA) ? REXPDouble.NA : ((payload[i] == FALSE) ? 0.0 : 1.0); return d; } /** returns the contents of this vector as strings */ public String[] asStrings() { String[] s = new String[payload.length]; for (int i = 0; i < payload.length; i++) s[i] = (payload[i] == NA) ? "NA" : ((payload[i] == FALSE) ? "FALSE" : "TRUE"); return s; } public boolean[] isNA() { boolean a[] = new boolean[payload.length]; int i = 0; while (i < a.length) { a[i] = (payload[i] == NA); i++; } return a; } /** returns a boolean array of the same langth as the receiver with true for TRUE values and false for FALSE and NA values. @return boolean array */ public boolean[] isTRUE() { boolean a[] = new boolean[payload.length]; int i = 0; while (i < a.length) { a[i] = (payload[i] != NA && payload[i] != FALSE); i++; } return a; } /** returns a boolean array of the same langth as the receiver with true for FALSE values and false for TRUE and NA values. @return boolean array */ public boolean[] isFALSE() { boolean a[] = new boolean[payload.length]; int i = 0; while (i < a.length) { a[i] = (payload[i] == FALSE); i++; } return a; } /** returns a boolean array of the same langth as the receiver with true for TRUE values and false for FALSE and NA values. @return boolean array @deprecated replaced by {@link #isTRUE()} for consistency with R nomenclature. */ public boolean[] isTrue() { return isTRUE(); } /** returns a boolean array of the same langth as the receiver with true for FALSE values and false for TRUE and NA values. @return boolean array @deprecated replaced by {@link #isTRUE()} for consistency with R nomenclature. */ public boolean[] isFalse() { return isFALSE(); } public String toDebugString() { StringBuffer sb = new StringBuffer(super.toDebugString()+"{"); int i = 0; while (i < payload.length && i < maxDebugItems) { if (i>0) sb.append(","); sb.append((payload[i] == NA) ? "NA" : ((payload[i] == FALSE) ? "FALSE" : "TRUE")); i++; } if (i < payload.length) sb.append(",.."); return sb.toString()+"}"; } } Rserve/src/client/java/LICENSE0000644000175100001440000000140214531234224015526 0ustar hornikusersREngine - Java interface to R Copyright (C) 2004,5,6,7 Simon Urbanek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Rserve/src/client/java/REngineOutputInterface.java0000644000175100001440000000143514531234224021763 0ustar hornikuserspackage org.rosuda.REngine; /** interface defining delegate methods used by {@link REngine} to forward output callbacks from R. */ public interface REngineOutputInterface { /** called when R prints output to the console. * @param eng calling engine * @param text text to display in the console * @param oType output type (0=regular, 1=error/warning) */ public void RWriteConsole(REngine eng, String text, int oType); /** called when R wants to show a warning/error message box (not console-related). * @param eng calling engine * @param text text to display in the message */ public void RShowMessage(REngine eng, String text); /** called by R to flush (display) any pending console output. * @param eng calling engine */ public void RFlushConsole(REngine eng); } Rserve/src/client/java/pom.xml0000644000175100001440000001016114531234224016040 0ustar hornikusers 4.0.0 org.rosuda.REngine REngine REngine Java interface to R REngine API to access R from Java in a backend-independent way. 2.1.1-SNAPSHOT http://github.com/s-u/REngine UTF-8 LGPL v2.1 https://www.gnu.org/licenses/lgpl-2.1.txt Simon Urbanek simon.urbanek@R-project.org scm:git:https://github.com/s-u/REngine.git scm:git:git@github.com:s-u/REngine.git https://github.com/s-u/REngine junit junit 4.13.1 test exec-maven-plugin org.codehaus.mojo 1.3.2 create mvn structure generate-sources exec ${basedir}/mkmvn.sh org.apache.maven.plugins maven-compiler-plugin 3.2 ${target.version} ${target.version} target-1.4 true 1.4 target-1.6 [9,12) 1.6 target-1.7 [12,20) 1.7 release org.apache.maven.plugins maven-gpg-plugin 1.6 sign-artifacts verify sign org.apache.maven.plugins maven-javadoc-plugin 2.10.2 attach-javadocs jar org.apache.maven.plugins maven-source-plugin 2.4 attach-sources jar-no-fork ossrh https://oss.sonatype.org/content/repositories/snapshots ossrh https://oss.sonatype.org/service/local/staging/deploy/maven2/ Rserve/src/client/java/REXPS4.java0000644000175100001440000000027414531234224016357 0ustar hornikuserspackage org.rosuda.REngine; /** S4 REXP is a completely vanilla REXP */ public class REXPS4 extends REXP { public REXPS4() { super(); } public REXPS4(REXPList attr) { super(attr); } } Rserve/src/client/java/REXPJavaReference.java0000644000175100001440000000164214531234224020571 0ustar hornikuserspackage org.rosuda.REngine; /** REXPJavaReference is a reference to a Java object that has been resolved from is R wrapper. Note that not all engines support references. */ public class REXPJavaReference extends REXP { /** the referenced Java object */ Object object; /** creates a new Java reference R object * @param o Java object referenced by the REXP */ public REXPJavaReference(Object o) { super(); this.object = o; } /** creates a new Java reference R object * @param o Java object referenced by the REXP * @param attr attributes (of the R wrapper) */ public REXPJavaReference(Object o, REXPList attr) { super(attr); this.object = o; } /** returns the Java object referenced by this REXP * @return Java object */ public Object getObject() { return object; } public Object asNativeJavaObject() { return object; } public String toString() { return super.toString() + "[" + object + "]"; } } Rserve/src/client/java/REXPWrapper.java0000644000175100001440000001614414531234224017514 0ustar hornikuserspackage org.rosuda.REngine ; /** * Utility class to wrap an Object into a REXP object. * * This facilitates wrapping native java objects and arrays * into REXP objects that can be pushed to R * * @author Romain Francois */ public class REXPWrapper { /* various classes */ private static Class byte_ARRAY ; private static Class short_ARRAY ; private static Class int_ARRAY ; private static Class long_ARRAY ; private static Class float_ARRAY ; private static Class double_ARRAY ; private static Class boolean_ARRAY ; private static Class String_ARRAY ; private static Class Byte_ARRAY ; private static Class Short_ARRAY; private static Class Integer_ARRAY ; private static Class Long_ARRAY ; private static Class Float_ARRAY ; private static Class Double_ARRAY ; private static Class Boolean_ARRAY ; static{ try{ byte_ARRAY = Class.forName("[B") ; short_ARRAY = Class.forName("[S" ); int_ARRAY = Class.forName("[I" ); long_ARRAY = (new long[1]).getClass() ; /* FIXME */ float_ARRAY = Class.forName("[F" ) ; double_ARRAY = Class.forName("[D" ); boolean_ARRAY = Class.forName("[Z" ) ; String_ARRAY = Class.forName( "[Ljava.lang.String;") ; Byte_ARRAY = Class.forName( "[Ljava.lang.Byte;" ) ; Short_ARRAY = Class.forName( "[Ljava.lang.Short;" ) ; Integer_ARRAY = Class.forName( "[Ljava.lang.Integer;" ) ; Long_ARRAY = Class.forName( "[Ljava.lang.Long;" ) ; Float_ARRAY = Class.forName( "[Ljava.lang.Float;" ) ; Double_ARRAY = Class.forName( "[Ljava.lang.Double;" ) ; Boolean_ARRAY = Class.forName( "[Ljava.lang.Boolean;" ) ; } catch( Exception e){ // should never happen e.printStackTrace(); System.err.println( "problem while initiating the classes" ) ; } } /** * Wraps an Object into a REXP * *

Conversion :

* *
    *
  • Byte (byte) : REXPRaw
  • *
  • Short (short) : REXPInteger
  • *
  • Integer (int) : REXPInteger
  • *
  • Long (long) : REXPInteger
  • *
  • Float (float) : REXPDouble
  • *
  • Double (double) : REXPDouble
  • *
  • Boolean (boolean) : REXPLogical
  • *
  • --
  • *
  • String : REXPString
  • *
  • String[] : REXPString
  • *
  • --
  • *
  • byte[] or Byte[] : REXPRaw
  • *
  • short[] or Short[] : REXPInteger
  • *
  • int[] or Integer[] : REXPInteger
  • *
  • long[] or Long[] : REXPInteger
  • *
  • float[] or Float[] : REXPDouble
  • *
  • double[] or Double[] : REXPDouble
  • *
  • boolean[] or Boolean[]: REXPLogical
  • *
  • --
  • *
  • null for anything else
  • *
* * @param o object to wrap * @return REXP object that represents o or null if the conversion is not possible */ public static REXP wrap( Object o ) { /* nothing to do in that case */ if( o instanceof REXP){ return (REXP)o; } Class clazz = o.getClass() ; /* primitives */ if( clazz == Byte.class ){ byte[] load = new byte[1]; load[0] = ((Byte)o).byteValue() ; return new REXPRaw( load ); } if( clazz == Short.class ){ return new REXPInteger( ((Short)o).intValue() ) ; } if( clazz == Integer.class ){ return new REXPInteger( ((Integer)o).intValue() ) ; } if( clazz == Long.class ){ return new REXPInteger( ((Long)o).intValue() ) ; } if( clazz == Float.class ){ return new REXPDouble( ((Float)o).doubleValue() ) ; } if( clazz == Double.class ){ return new REXPDouble( ((Double)o).doubleValue() ) ; } if( clazz == Boolean.class ){ return new REXPLogical( ((Boolean)o).booleanValue() ) ; } /* Strings -> REXPString */ if( clazz == String.class ){ return new REXPString( (String)o ) ; } if( clazz == String_ARRAY ){ /* String[] */ return new REXPString( (String[])o ); } /* array of byte or Bytes -> REXPRaw */ if( clazz == byte_ARRAY ){ /* byte[] */ return new REXPRaw( (byte[])o ) ; } if( clazz == Byte_ARRAY ){ /* Byte[] */ Byte[] b = (Byte[])o; int n = b.length ; byte[] bytes = new byte[b.length]; for( int i=0; i REXPInteger */ if( clazz == short_ARRAY ){ /* short[] */ short[] shorts = (short[])o ; int[] ints = new int[ shorts.length ]; int n = ints.length; for( int i=0; i REXPInteger */ if( clazz == int_ARRAY ){ /* int[] */ return new REXPInteger( (int[])o ) ; } if( clazz == Integer_ARRAY ){ /* Integer[] */ Integer[] integers = (Integer[])o; int n = integers.length ; int[] ints = new int[integers.length]; for( int i=0; i REXPInteger */ if( clazz == long_ARRAY ){ /* long[] */ long[] longs = (long[])o; int n = longs.length ; int[] ints = new int[longs.length]; for( int i=0; i REXPDouble */ if( clazz == float_ARRAY ){ /* float[] */ float[] floats = (float[])o; int n = floats.length ; double[] doubles = new double[floats.length]; for( int i=0; i REXPDouble */ if(clazz == double_ARRAY ) { /* double[] */ return new REXPDouble( (double[])o ) ; } if( clazz == Double_ARRAY ){ /* Double[] */ Double[] doubles = (Double[])o; double n = doubles.length ; double[] d = new double[doubles.length]; for( int i=0; i REXPLogical */ if( clazz == boolean_ARRAY ){ /* boolean[] */ return new REXPLogical( (boolean[])o ) ; } if( clazz == Boolean_ARRAY ){ /* Boolean[] */ Boolean[] booleans = (Boolean[])o; int n = booleans.length ; boolean[] b = new boolean[booleans.length]; for( int i=0; i All lists (dotted-pair lists, language lists, expressions and vectors) are regarded as named generic vectors. Note: This implementation has changed radically in Rserve 0.5! This class inofficially implements the Map interface. Unfortunately a conflict in the Java iterface classes Map and List doesn't allow us to implement both officially. Most prominently the Map 'remove' method had to be renamed to removeByKey. @version $Id$ */ public class RList extends Vector implements List { public Vector names; /** constructs an empty list */ public RList() { super(); names=null; } /** constructs an initialized, unnamed list * @param contents - an array of {@link REXP}s to use as contents of this list */ public RList(REXP[] contents) { super(contents.length); int i=0; while (i0) { this.names=new Vector(names.length); int i = 0; while (i < names.length) this.names.add(names[i++]); while (this.names.size()0) { this.names=new Vector(names.length); int i = 0; while (i < names.length) this.names.add(names[i++]); while (this.names.size()0) { this.names=new Vector(names); while (this.names.size()true
if this list is named, false otherwise */ public boolean isNamed() { return names!=null; } /** get xpression given a key @param v key @return value which corresponds to the given key or null if the list is unnamed or key not found */ public REXP at(String v) { if (names==null) return null; int i = names.indexOf(v); if (i < 0) return null; return (REXP)elementAt(i); } /** get element at the specified position @param i index @return value at the index or null if the index is out of bounds */ public REXP at(int i) { return (i>=0 && inull
is the list is unnamed or the index is out of range */ public String keyAt(int i) { return (names==null || i<0 || i>=names.size())?null:(String)names.get(i); } /** set key at the given index. Using this method automatically makes the list a named one even if the key is null. Out of range operations are undefined (currently no-ops) @param i index @param value key name */ public void setKeyAt(int i, String value) { if (i < 0) return; if (names==null) names = new Vector(); if (names.size() < size()) names.setSize(size()); if (i < size()) names.set(i, value); } /** returns all keys of the list * @return array containing all keys or null if list unnamed */ public String[] keys() { if (names==null) return null; int i = 0; String k[] = new String[names.size()]; while (i < k.length) { k[i] = keyAt(i); i++; }; return k; } // --- overrides that sync names public void add(int index, Object element) { super.add(index, element); if (names==null) return; names.add(index, null); } public boolean add(Object element) { super.add(element); if (names != null) names.add(null); return true; } public boolean addAll(Collection c) { boolean ch = super.addAll(c); if (names==null) return ch; int l = size(); while (names.size() 0) names.add(index, null); return ch; } public void clear() { super.clear(); names=null; } public Object clone() { return new RList(this, names); } public Object remove(int index) { Object o = super.remove(index); if (names != null) { names.remove(index); if (size()==0) names=null; } return o; } public boolean remove(Object elem) { int i = indexOf(elem); if (i<0) return false; remove(i); if (size()==0) names=null; return true; } public boolean removeAll(Collection c) { if (names==null) return super.removeAll(c); boolean changed=false; Iterator it = c.iterator(); while (it.hasNext()) changed|=remove(it.next()); return changed; } public boolean retainAll(Collection c) { if (names==null) return super.retainAll(c); boolean rm[] = new boolean[size()]; boolean changed=false; int i = 0; while (i0) { i--; if (rm[i]) remove(i); } return changed; } // --- old API mapping public void removeAllElements() { clear(); } public void insertElementAt(Object obj, int index) { add(index, obj); } public void addElement(Object obj) { add(obj); } public void removeElementAt(int index) { remove(index); } public boolean removeElement(Object obj) { return remove(obj); } // --- Map interface public boolean containsKey(Object key) { return (names==null)?false:names.contains(key); } public boolean containsValue(Object value) { return contains(value); } /** NOTE: THIS IS UNIMPLEMENTED and always returns null! Due to the fact that R lists are not proper maps we canot maintain a set-view of the list */ public Set entrySet() { return null; } public Object get(Object key) { return at((String)key); } /** Note: sinde RList is not really a Map, the returned set is only an approximation as it cannot reference duplicate or null names that may exist in the list */ public Set keySet() { if (names==null) return null; return new HashSet(names); } public Object put(Object key, Object value) { if (key==null) { add(value); return null; } if (names != null) { int p = names.indexOf(key); if (p >= 0) return super.set(p, value); } int i = size(); super.add(value); if (names==null) names = new Vector(i+1); while (names.size() < i) names.add(null); names.add(key); return null; } public void putAll(Map t) { if (t==null) return; // NOTE: this if branch is dead since RList cannot inherit from Map if (t instanceof RList) { // we need some more sophistication for RLists as they may have null-names which we append RList l = (RList) t; if (names==null) { addAll(l); return; } int n = l.size(); int i = 0; while (i < n) { String key = l.keyAt(i); if (key==null) add(l.at(i)); else put(key, l.at(i)); i++; } } else { Set ks = t.keySet(); Iterator i = ks.iterator(); while (i.hasNext()) { Object key = i.next(); put(key, t.get(key)); } } } public void putAll(RList t) { if (t == null) return; RList l = (RList) t; if (names==null) { addAll(l); return; } int n = l.size(); int i = 0; while (i < n) { String key = l.keyAt(i); if (key == null) add(l.at(i)); else put(key, l.at(i)); i++; } } public Object removeByKey(Object key) { if (names==null) return null; int i = names.indexOf(key); if (i<0) return null; Object o = elementAt(i); removeElementAt(i); names.removeElementAt(i); return o; } public Collection values() { return this; } // other public String toString() { return "RList"+super.toString()+"{"+(isNamed()?"named,":"")+size()+"}"; } } Rserve/src/client/java/REXPList.java0000644000175100001440000000417014531234224017003 0ustar hornikuserspackage org.rosuda.REngine; /** Represents a pairlist in R. Unlike the actual internal R implementation this one does not use CAR/CDR/TAG linked representation but a @link{RList} object. */ public class REXPList extends REXPVector { private RList payload; /* create a new pairlist with the contents of a named R list and no attributes. @param list named list with the contents */ public REXPList(RList list) { super(); payload=(list==null)?new RList():list; } /* create a new pairlist with the contents of a named R list and attributes. @param list named list with the contents @param attr attributes */ public REXPList(RList list, REXPList attr) { super(attr); payload=(list==null)?new RList():list; } /* create a pairlist containing just one pair comprising of one value and one name. This is a convenience constructor most commonly used to create attribute pairlists. @param value of the element in the pairlist (must not be null) @param name of the element in the pairlist (must not be null) */ public REXPList(REXP value, String name) { super(); payload = new RList(new REXP[] { value }, new String[] { name }); } public Object asNativeJavaObject() throws REXPMismatchException { // since REXPGenericVector does the hard work, we just cheat and use it in turn REXPGenericVector v = new REXPGenericVector(payload); return v.asNativeJavaObject(); } public int length() { return payload.size(); } public boolean isList() { return true; } public boolean isPairList() { return true; } public boolean isRecursive() { return true; } public RList asList() { return payload; } public String toString() { return super.toString()+(asList().isNamed()?"named":""); } public String toDebugString() { StringBuffer sb = new StringBuffer(super.toDebugString()+"{"); int i = 0; while (i < payload.size() && i < maxDebugItems) { if (i>0) sb.append(",\n"); String name = payload.keyAt(i); if (name!=null) sb.append(name+"="); sb.append(payload.at(i).toDebugString()); i++; } if (i < payload.size()) sb.append(",.."); return sb.toString()+"}"; } } Rserve/src/client/java/REngineEvalException.java0000644000175100001440000000235014531234224021405 0ustar hornikuserspackage org.rosuda.REngine ; /** * Exception thrown when an error occurs during eval. * *

* This class is a placeholder and should be extended when more information * can be extracted from R (call stack, etc ... ) *

*/ public class REngineEvalException extends REngineException { /** * Value returned by the rniEval native method when the input passed to eval * is invalid */ public static final int INVALID_INPUT = -1 ; /** * Value returned by the rniEval native method when an error occured during * eval (stop, ...) */ public static final int ERROR = -2 ; /** * Type of eval error */ protected int type ; /** * Constructor * * @param eng associated REngine * @param message error message * @param type type of error (ERROR or INVALID_INPUT) */ public REngineEvalException( REngine eng, String message, int type ){ super( eng, message ); this.type = type ; } /** * Constructor using ERROR type * * @param eng associated REngine * @param message error message */ public REngineEvalException( REngine eng, String message){ this( eng, message, ERROR ); } /** * @return the type of error (ERROR or INVALID_INPUT) */ public int getType(){ return type ; } } Rserve/src/client/java/REngineUIInterface.java0000644000175100001440000000146514531234224021003 0ustar hornikuserspackage org.rosuda.REngine; /** interface defining delegate methods used by {@link REngine} to forward user interface callbacks from R. */ public interface REngineUIInterface { /** called when the busy state of R changes - usual response is to change the shape of the cursor * @param eng calling engine * @param state busy state of R (0 = not busy) */ public void RBusyState (REngine eng, int state); /** called when R wants the user to choose a file. * @param eng calling engine * @param newFile if true then the user can specify a non-existing file to be created, otherwise an existing file must be selected. * @return full path and name of the selected file or null if the selection was cancelled. */ public String RChooseFile (REngine eng, boolean newFile); } Rserve/src/client/java/REXPGenericVector.java0000644000175100001440000000574314531234224020636 0ustar hornikuserspackage org.rosuda.REngine; import java.util.Vector; import java.util.HashMap; /** REXPGenericVector represents a generic vector in R. Its elements can be typically of any {@link REXP} type. */ public class REXPGenericVector extends REXPVector { /** payload */ private RList payload; /** creates a new generic vector from a list. If the list is named, the "names" attribute is created automatically from it. * @param list list to create the vector from */ public REXPGenericVector(RList list) { super(); payload=(list==null)?new RList():list; // automatically generate 'names' attribute if (payload.isNamed()) attr = new REXPList( new RList(new REXP[] { new REXPString(payload.keys()) }, new String[] { "names" })); } /** creates a new generic vector from a list. Note that the names in the list are ignored as they are expected to be defined by the attributes parameter. * @param list list to create the vector from (names are ignored - use {@link #REXPGenericVector(RList)} or the "names" attribute for named lists * @param attr attributes */ public REXPGenericVector(RList list, REXPList attr) { super(attr); payload=(list==null)?new RList():list; } /* generic vectors are converted either to a Map (if it is a named vector and there are no duplicate names) or a Vector. The contained elements are converted using asNativeJavaObject recursively. */ public Object asNativeJavaObject() throws REXPMismatchException { // we need to convert the inside as well int n = payload.size(); // named list -> map but only if // a) all names are present // b) there are no duplicates in the names if (payload.isNamed()) { String[] names = payload.keys(); if (names.length == n) { HashMap map = new HashMap(); boolean valid = true; for (int i = 0; i < n; i++) { if (map.containsKey(names[i])) { valid = false; break; } Object value = payload.elementAt(i); if (value != null) value = ((REXP) value).asNativeJavaObject(); map.put(names[i], value); } if (valid) return map; } } // otherwise drop names and use just a vector Vector v = new Vector(); for (int i = 0; i < n; i++) { Object value = payload.elementAt(i); if (value != null) value = ((REXP) value).asNativeJavaObject(); v.addElement(value); } return v; } public int length() { return payload.size(); } public boolean isList() { return true; } public boolean isRecursive() { return true; } public RList asList() { return payload; } public String toString() { return super.toString()+(asList().isNamed()?"named":""); } public String toDebugString() { StringBuffer sb = new StringBuffer(super.toDebugString()+"{"); int i = 0; while (i < payload.size() && i < maxDebugItems) { if (i>0) sb.append(",\n"); sb.append(payload.at(i).toDebugString()); i++; } if (i < payload.size()) sb.append(",.."); return sb.toString()+"}"; } } Rserve/src/client/java/REXP.java0000644000175100001440000003676314531234224016164 0ustar hornikuserspackage org.rosuda.REngine; /** Basic class representing an object of any type in R. Each type in R in represented by a specific subclass.

This class defines basic accessor methods (asXXX), type check methods (isXXX), gives access to attributes ({@link #getAttribute}, {@link #hasAttribute}) as well as several convenience methods. If a given method is not applicable to a particular type, it will throw the {@link REXPMismatchException} exception.

This root class will throw on any accessor call and returns false for all type methods. This allows subclasses to override accessor and type methods selectively. */ public class REXP { /** attribute list. This attribute should never be accessed directly. */ protected REXPList attr; /** public root contrsuctor, same as new REXP(null) */ public REXP() { } /** public root constructor @param attr attribute list object (can be null */ public REXP(REXPList attr) { this.attr=attr; } // type checks /** check whether the REXP object is a character vector (string) @return true if the receiver is a character vector, false otherwise */ public boolean isString() { return false; } /** check whether the REXP object is a numeric vector @return true if the receiver is a numeric vector, false otherwise */ public boolean isNumeric() { return false; } /** check whether the REXP object is an integer vector @return true if the receiver is an integer vector, false otherwise */ public boolean isInteger() { return false; } /** check whether the REXP object is NULL @return true if the receiver is NULL, false otherwise */ public boolean isNull() { return false; } /** check whether the REXP object is a factor @return true if the receiver is a factor, false otherwise */ public boolean isFactor() { return false; } /** check whether the REXP object is a list (either generic vector or a pairlist - i.e. {@link #asList()} will succeed) @return true if the receiver is a generic vector or a pair-list, false otherwise */ public boolean isList() { return false; } /** check whether the REXP object is a pair-list @return true if the receiver is a pair-list, false otherwise */ public boolean isPairList() { return false; } /** check whether the REXP object is a logical vector @return true if the receiver is a logical vector, false otherwise */ public boolean isLogical() { return false; } /** check whether the REXP object is an environment @return true if the receiver is an environment, false otherwise */ public boolean isEnvironment() { return false; } /** check whether the REXP object is a language object @return true if the receiver is a language object, false otherwise */ public boolean isLanguage() { return false; } /** check whether the REXP object is an expression vector @return true if the receiver is an expression vector, false otherwise */ public boolean isExpression() { return false; } /** check whether the REXP object is a symbol @return true if the receiver is a symbol, false otherwise */ public boolean isSymbol() { return false; } /** check whether the REXP object is a vector @return true if the receiver is a vector, false otherwise */ public boolean isVector() { return false; } /** check whether the REXP object is a raw vector @return true if the receiver is a raw vector, false otherwise */ public boolean isRaw() { return false; } /** check whether the REXP object is a complex vector @return true if the receiver is a complex vector, false otherwise */ public boolean isComplex() { return false; } /** check whether the REXP object is a recursive obejct @return true if the receiver is a recursive object, false otherwise */ public boolean isRecursive() { return false; } /** check whether the REXP object is a reference to an R object @return true if the receiver is a reference, false otherwise */ public boolean isReference() { return false; } // basic accessor methods /** returns the contents as an array of Strings (if supported by the represented object) */ public String[] asStrings() throws REXPMismatchException { throw new REXPMismatchException(this, "String"); } /** returns the contents as an array of integers (if supported by the represented object) */ public int[] asIntegers() throws REXPMismatchException { throw new REXPMismatchException(this, "int"); } /** returns the contents as an array of doubles (if supported by the represented object) */ public double[] asDoubles() throws REXPMismatchException { throw new REXPMismatchException(this, "double"); } /** returns the contents as an array of bytes (if supported by the represented object) */ public byte[] asBytes() throws REXPMismatchException { throw new REXPMismatchException(this, "byte"); } /** returns the contents as a (named) list (if supported by the represented object) */ public RList asList() throws REXPMismatchException { throw new REXPMismatchException(this, "list"); } /** returns the contents as a factor (if supported by the represented object) */ public RFactor asFactor() throws REXPMismatchException { throw new REXPMismatchException(this, "factor"); } /** attempt to represent the REXP by a native Java object and return it. Note that this may lead to loss of information (e.g., factors may be returned as a string array) and attributes are ignored. Not all R types can be converted to native Java objects. Also note that R has no concept of scalars, so vectors of length 1 will always be returned as an arrays (i.e., int[1] and not Integer). */ public Object asNativeJavaObject() throws REXPMismatchException { throw new REXPMismatchException(this, "native Java Object"); } /** returns the length of a vector object. Note that we use R semantics here, i.e. a matrix will have a length of m * n since it is represented by a single vector (see {@link #dim} for retrieving matrix and multidimentional-array dimensions). * @return length (number of elements) in a vector object * @throws REXPMismatchException if this is not a vector object */ public int length() throws REXPMismatchException { throw new REXPMismatchException(this, "vector"); } /** returns a boolean vector of the same length as this vector with true for NA values and false for any other values * @return a boolean vector of the same length as this vector with true for NA values and false for any other values * @throws REXPMismatchException if this is not a vector object */ public boolean[] isNA() throws REXPMismatchException { throw new REXPMismatchException(this, "vector"); } // convenience accessor methods /** convenience method corresponding to asIntegers()[0] @return first entry returned by {@link #asInteger} */ public int asInteger() throws REXPMismatchException { int[] i = asIntegers(); return i[0]; } /** convenience method corresponding to asDoubles()[0] @return first entry returned by {@link #asDoubles} */ public double asDouble() throws REXPMismatchException { double[] d = asDoubles(); return d[0]; } /** convenience method corresponding to asStrings()[0] @return first entry returned by {@link #asStrings} */ public String asString() throws REXPMismatchException { String[] s = asStrings(); return s[0]; } // methods common to all REXPs /** retrieve an attribute of the given name from this object * @param name attribute name * @return attribute value or null if the attribute does not exist */ public REXP getAttribute(String name) { final REXPList a = _attr(); if (a==null || !a.isList()) return null; return a.asList().at(name); } /** checks whether this obejct has a given attribute * @param name attribute name * @return true if the attribute exists, false otherwise */ public boolean hasAttribute(String name) { final REXPList a = _attr(); return (a!=null && a.isList() && a.asList().at(name)!=null); } // helper methods common to all REXPs /** returns dimensions of the object (as determined by the "dim" attribute) * @return an array of integers with corresponding dimensions or null if the object has no dimension attribute */ public int[] dim() { try { return hasAttribute("dim")?_attr().asList().at("dim").asIntegers():null; } catch (REXPMismatchException me) { } return null; } /** determines whether this object inherits from a given class in the same fashion as the inherits() function in R does (i.e. ignoring S4 inheritance) * @param klass class name * @return true if this object is of the class klass, false otherwise */ public boolean inherits(String klass) { if (!hasAttribute("class")) return false; try { String c[] = getAttribute("class").asStrings(); if (c != null) { int i = 0; while (i < c.length) { if (c[i]!=null && c[i].equals(klass)) return true; i++; } } } catch (REXPMismatchException me) { } return false; } /** this method allows a limited access to object's attributes - {@link #getAttribute} should be used instead to access specific attributes!. Note that the {@link #attr} attribute should never be used directly incase the REXP implements a lazy access (e.g. via a reference) @return list of attributes or null if the object has no attributes */ public REXPList _attr() { return attr; } /** returns a string description of the object @return string describing the object - it can be of an arbitrary form and used only for debugging (do not confuse with {@link #asString()} for accessing string REXPs) */ public String toString() { return super.toString()+((attr!=null)?"+":""); } /** returns representation that it useful for debugging (e.g. it includes attributes and may include vector values -- see {@link #maxDebugItems}) @return extended description of the obejct -- it may include vector values */ public String toDebugString() { return (attr!=null)?(("<"+attr.toDebugString()+">")+super.toString()):super.toString(); } //======= complex convenience methods /** returns the content of the REXP as a matrix of doubles (2D-array: m[rows][cols]). This is the same form as used by popular math packages for Java, such as JAMA. This means that following leads to desired results:
Matrix m=new Matrix(c.eval("matrix(c(1,2,3,4,5,6),2,3)").asDoubleMatrix());
@return 2D array of doubles in the form double[rows][cols] or null if the contents is no 2-dimensional matrix of doubles */ public double[][] asDoubleMatrix() throws REXPMismatchException { double[] ct = asDoubles(); REXP dim = getAttribute("dim"); if (dim == null) throw new REXPMismatchException(this, "matrix (dim attribute missing)"); int[] ds = dim.asIntegers(); if (ds.length != 2) throw new REXPMismatchException(this, "matrix (wrong dimensionality)"); int m = ds[0], n = ds[1]; double[][] r = new double[m][n]; // R stores matrices as matrix(c(1,2,3,4),2,2) = col1:(1,2), col2:(3,4) // we need to copy everything, since we create 2d array from 1d array int k = 0; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) r[j][i] = ct[k++]; return r; } /** creates a REXP that represents a double matrix in R based on matrix of doubles (2D-array: m[rows][cols]). This is the same form as used by popular math packages for Java, such as JAMA. The result of this function can be used in {@link REngine.assign} to store a matrix in R. @param matrix array double[rows][colums] containing the matrix to convert into a REXP. If matrix is null or either of the dimensions is 0 then the resulting matrix will have the dimensions 0 x 0 (Note: Java cannot represent 0 x n matrices for n > 0, so special matrices with one dimension of 0 can only be created by setting dimensions directly). @return REXPDouble with "dim" attribute which constitutes a matrix in R */ public static REXP createDoubleMatrix(double[][] matrix) { int m = 0, n = 0; double a[]; if (matrix != null && matrix.length != 0 && matrix[0].length != 0) { m = matrix.length; n = matrix[0].length; a = new double[m * n]; int k = 0; for (int j = 0; j < n; j++) for (int i = 0; i < m; i++) a[k++] = matrix[i][j]; } else a = new double[0]; return new REXPDouble(a, new REXPList( new RList( new REXP[] { new REXPInteger(new int[] { m, n }) }, new String[] { "dim" }) ) ); } //======= tools /** creates a data frame object from a list object using integer row names * @param l a (named) list of vectors ({@link REXPVector} subclasses), each element corresponds to a column and all elements must have the same length * @return a data frame object * @throws REXPMismatchException if the list is empty or any of the elements is not a vector */ public static REXP createDataFrame(RList l) throws REXPMismatchException { if (l == null || l.size() < 1) throw new REXPMismatchException(new REXPList(l), "data frame (must have dim>0)"); if (!(l.at(0) instanceof REXPVector)) throw new REXPMismatchException(new REXPList(l), "data frame (contents must be vectors)"); REXPVector fe = (REXPVector) l.at(0); return new REXPGenericVector(l, new REXPList( new RList( new REXP[] { new REXPString("data.frame"), new REXPString(l.keys()), new REXPInteger(new int[] { REXPInteger.NA, -fe.length() }) }, new String[] { "class", "names", "row.names" }))); } public static REXP asCall(REXP what, REXP[] args) { RList l = new RList(); l.add(what); for (int i = 0; i < args.length; i++) l.add(args[i]); return new REXPLanguage(l); } public static REXP asCall(String name, REXP[] args) { return asCall(new REXPSymbol(name), args); } public static REXP asCall(String name, REXP arg1) { return new REXPLanguage(new RList(new REXP[] { new REXPSymbol(name), arg1 })); } public static REXP asCall(String name, REXP arg1, REXP arg2) { return new REXPLanguage(new RList(new REXP[] { new REXPSymbol(name), arg1, arg2 })); } public static REXP asCall(String name, REXP arg1, REXP arg2, REXP arg3) { return new REXPLanguage(new RList(new REXP[] { new REXPSymbol(name), arg1, arg2, arg3 })); } public static REXP asCall(REXP what, REXP arg1) { return new REXPLanguage(new RList(new REXP[] { what, arg1 })); } public static REXP asCall(REXP what, REXP arg1, REXP arg2) { return new REXPLanguage(new RList(new REXP[] { what, arg1, arg2 })); } public static REXP asCall(REXP what, REXP arg1, REXP arg2, REXP arg3) { return new REXPLanguage(new RList(new REXP[] { what, arg1, arg2, arg3 })); } /** specifies how many items of a vector or list will be displayed in {@link #toDebugString} */ public static int maxDebugItems = 32; } Rserve/src/client/java/REngineException.java0000644000175100001440000000240014531234224020571 0ustar hornikusers// REngine - generic Java/R API // // Copyright (C) 2006 Simon Urbanek // --- for licensing information see LICENSE file in the original JRclient distribution --- // // RSrvException.java // // Created by Simon Urbanek on Wed Jun 21 2006. // // $Id$ // package org.rosuda.REngine; /** REngineException is a generic exception that can be thrown by methods invoked on an R engine. */ public class REngineException extends Exception { /** engine associated with this exception */ protected REngine engine; /** creates an R engine exception @param engine engine associated with this exception @param msg message describing the cause @param cause original cause if this is a chained exception */ public REngineException(REngine engine, String msg, Throwable cause) { super(msg, cause); this.engine = engine; } /** creates an R engine exception @param engine engine associated with this exception @param msg message describing the cause */ public REngineException(REngine engine, String msg) { super(msg); this.engine = engine; } /** returns the engine associated with this exception @return engine associated with this exception */ public REngine getEngine() { return engine; } } Rserve/src/client/java/REngineCallbacks.java0000644000175100001440000000025714531234224020522 0ustar hornikuserspackage org.rosuda.REngine; /** REngineCallbacks is a virtual interface that poses as a superclass of all callback delegate classes. */ public interface REngineCallbacks { } Rserve/src/client/java/REngineConsoleHistoryInterface.java0000644000175100001440000000117214531234224023445 0ustar hornikuserspackage org.rosuda.REngine; /** interface defining delegate methods used by {@link REngine} to forward console history callbacks from R. */ public interface REngineConsoleHistoryInterface { /** called when R wants to save the history content. * @param eng calling engine * @param filename name of the file to save command history to */ public void RSaveHistory (REngine eng, String filename); /** called when R wants to load the history content. * @param eng calling engine * @param filename name of the file to load the command history from */ public void RLoadHistory (REngine eng, String filename); } Rserve/src/client/java/MutableREXP.java0000644000175100001440000000016214531234224017456 0ustar hornikuserspackage org.rosuda.REngine; public interface MutableREXP { public void setAttribute(String name, REXP value); } Rserve/src/client/java/REXPVector.java0000644000175100001440000000165614531234224017340 0ustar hornikuserspackage org.rosuda.REngine; /** abstract class representing all vectors in R */ public abstract class REXPVector extends REXP { public REXPVector() { super(); } public REXPVector(REXPList attr) { super(attr); } /** returns the length of the vector (i.e. the number of elements) * @return length of the vector */ public abstract int length(); public boolean isVector() { return true; } /** returns a boolean vector of the same length as this vector with true for NA values and false for any other values * @return a boolean vector of the same length as this vector with true for NA values and false for any other values */ public boolean[] isNA() { boolean a[] = new boolean[length()]; return a; } public String toString() { return super.toString()+"["+length()+"]"; } public String toDebugString() { return super.toDebugString()+"["+length()+"]"; } } Rserve/src/client/java/REXPSymbol.java0000644000175100001440000000134214531234224017333 0ustar hornikuserspackage org.rosuda.REngine; /** REXPSymbol represents a symbol in R. */ public class REXPSymbol extends REXP { /** name of the symbol */ private String name; /** create a new symbol of the given name */ public REXPSymbol(String name) { super(); this.name=(name==null)?"":name; } public boolean isSymbol() { return true; } /** returns the name of the symbol * @return name of the symbol */ public String asString() { return name; } public String[] asStrings() { return new String[] { name }; } public String toString() { return getClass().getName()+"["+name+"]"; } public String toDebugString() { return super.toDebugString()+"["+name+"]"; } public Object asNativeJavaObject() { return name; } } Rserve/src/client/java/Makefile0000644000175100001440000000212114531234227016163 0ustar hornikusersRENG_SRC=$(wildcard *.java) RSRV_SRC=$(wildcard Rserve/*.java) $(wildcard Rserve/protocol/*.java) JRI_SRC=$(wildcard JRI/*.java) TARGETS=REngine.jar Rserve.jar all: $(TARGETS) JAVAC=javac JAVADOC=javadoc JDFLAGS=-author -version -breakiterator -link http://java.sun.com/j2se/1.4.2/docs/api/ JFLAGS+=-source 1.6 -target 1.6 REngine.jar: $(RENG_SRC) @rm -rf org $(JAVAC) -d . $(JFLAGS) $(RENG_SRC) jar fc $@ org rm -rf org Rserve.jar: $(RSRV_SRC) REngine.jar @rm -rf org $(JAVAC) -d . -cp REngine.jar $(RSRV_SRC) jar fc $@ org rm -rf org clean: rm -rf org *~ $(TARGETS) doc make -C Rserve clean make -C JRI clean test: make -C Rserve test rc: Rserve.jar Rserve/test/jt.java make -C Rserve/test jt doc: $(RENG_SRC) $(RSRV_SRC) $(JRI_SRC) rm -rf $@ mkdir $@ $(JAVADOC) -d $@ $(JDFLAGS) $^ mvn.pkg: mvn -B clean package install && (cd Rserve && mvn -B clean package) mvn.sign: mvn clean verify install -P release && (cd Rserve && mvn clean verify -P release ) mvn.deploy: mvn clean deploy install -P release && (cd Rserve && mvn clean deploy -P release ) .PHONY: clean all test Rserve/src/client/java/REXPEnvironment.java0000644000175100001440000000654414531234224020403 0ustar hornikuserspackage org.rosuda.REngine; // environments are like REXPReferences except that they cannot be resolved /** REXPEnvironment represents an environment in R. Very much like {@link org.rosuda.REngine.REXPReference} this is a proxy object to the actual object on the R side. It provides methods for accessing the content of the environment. The actual implementation may vary by the back-end used and not all engines support environments. Check {@link org.rosuda.REngine.REngine.supportsEnvironments()} for the given engine. Environments are specific for a given engine, they cannot be passed across engines. */ public class REXPEnvironment extends REXP { /** engine associated with this environment */ REngine eng; /** transparent handle that can be used by the engine to indentify the environment. It is not used by REngine API itself. */ Object handle; /** create a new environemnt reference - this constructor should never be used directly, use {@link REngine.newEnvironment()} instead. * @param eng engine responsible for this environment * @param handle handle used by the engine to identify this environment */ public REXPEnvironment(REngine eng, Object handle) { super(); this.eng = eng; this.handle = handle; } public boolean isEnvironment() { return true; } /** returns the handle used to identify this environemnt in the engine - for internal use by engine implementations only * @return handle of this environment */ public Object getHandle() { return handle; } /** get a value from this environment * @param name name of the value * @param resolve if false returns a reference to the object, if false the reference is resolved * @return value corresponding to the symbol name or possibly null if the value is unbound (the latter is currently engine-specific) */ public REXP get(String name, boolean resolve) throws REngineException { try { return eng.get(name, this, resolve); } catch (REXPMismatchException e) { // this should never happen because this is always guaranteed to be REXPEnv throw(new REngineException(eng, "REXPMismatchException:"+e+" in get()")); } } /** get a value from this environment - equavalent to get(name, true). * @param name name of the value * @return value (see {@link #get(String,boolean)}) */ public REXP get(String name) throws REngineException { return get(name, true); } /** assigns a value to a given symbol name * @param name symbol name * @param value value */ public void assign(String name, REXP value) throws REngineException, REXPMismatchException { eng.assign(name, value, this); } /** returns the parent environment or a reference to it * @param resolve if true returns the environemnt, otherwise a reference. * @return parent environemnt (or a reference to it) */ public REXP parent(boolean resolve) throws REngineException { try { return eng.getParentEnvironment(this, resolve); } catch (REXPMismatchException e) { // this should never happen because this is always guaranteed to be REXPEnv throw(new REngineException(eng, "REXPMismatchException:"+e+" in parent()")); } } /** returns the parent environment. This is equivalent to parent(true). * @return parent environemnt */ public REXPEnvironment parent() throws REngineException { return (REXPEnvironment) parent(true); } } Rserve/src/client/java/REXPMismatchException.java0000644000175100001440000000360614531234224021517 0ustar hornikusers// REngine - generic Java/R API // // Copyright (C) 2007,2008 Simon Urbanek // --- for licensing information see LICENSE file in the distribution --- // // REXPMismatch.java // // Created by Simon Urbanek on 2007/05/03 // // $Id: REngineException.java 2555 2006-06-21 20:36:42Z urbaneks $ // package org.rosuda.REngine; /** This exception is thrown whenever the operation requested is not supported by the given R object type, e.g. using asStrings on an S4 object. Most {@link REXP} methods throw this exception. Previous R/Java interfaces were silently returning null in those cases, but using exceptions helps to write more robust code. */ public class REXPMismatchException extends Exception { REXP sender; String access; /** primary constructor. The exception message will be formed as "attempt to access <REXP-class> as <access-string>" * @param sender R object that triggered this exception (cannot be null!) * @param access assumed type of the access that was requested. It should be a simple name of the assumed type (e.g. "vector"). The type name can be based on R semantics beyond basic types reflected by REXP classes. In cases where certain assertions were not satisfied, the string should be of the form "type (assertion)" (e.g. "data frame (must have dim>0)"). */ public REXPMismatchException(REXP sender, String access) { super("attempt to access "+sender.getClass().getName()+" as "+access); this.sender = sender; this.access = access; } /** retrieve the exception sender/origin * @return REXP object that triggered the exception */ public REXP getSender() { return sender; } /** get the assumed access type that was violated by the sender. * @return string describing the access type. See {@link #REXPMismatchException} for details. */ public String getAccess() { return access; } } Rserve/src/client/java/mkmvn.sh0000755000175100001440000000033314531234224016212 0ustar hornikusers#!/bin/sh BASE="$1" if [ -z "$BASE" ]; then BASE="`pwd`"; fi rm -rf "$BASE/src/main" mkdir -p "$BASE/src/main/java/org/rosuda/REngine" (cd "$BASE/src/main/java/org/rosuda/REngine" && ln -s ../../../../../../*.java .) Rserve/src/client/java/Rserve/0000755000175100001440000000000014531234227015775 5ustar hornikusersRserve/src/client/java/Rserve/pom.xml0000644000175100001440000001124414531234224017311 0ustar hornikusers 4.0.0 org.rosuda.REngine Rserve Rserve client back-end for REngine Rserve client back-end implementation for REngine to access R from Java via Rserve. 1.8.2-SNAPSHOT http://github.com/s-u/REngine UTF-8 LGPL v2.1 https://www.gnu.org/licenses/lgpl-2.1.txt Simon Urbanek simon.urbanek@R-project.org scm:git:https://github.com/s-u/REngine.git scm:git:git@github.com:s-u/REngine.git https://github.com/s-u/REngine/tree/master/Rserve org.rosuda.REngine REngine 2.1.1-SNAPSHOT junit junit 4.13.1 test org.slf4j slf4j-api 1.7.5 test org.slf4j slf4j-simple 1.7.5 test exec-maven-plugin org.codehaus.mojo 1.3.2 create mvn structure generate-sources exec ${basedir}/mkmvn.sh org.apache.maven.plugins maven-compiler-plugin 3.2 ${target.version} ${target.version} target-1.5 true 1.5 target-1.6 [9,12) 1.6 target-1.7 [12,20) 1.7 release org.apache.maven.plugins maven-gpg-plugin 1.6 sign-artifacts verify sign org.apache.maven.plugins maven-javadoc-plugin 2.10.2 attach-javadocs jar org.apache.maven.plugins maven-source-plugin 2.4 attach-sources jar-no-fork ossrh https://oss.sonatype.org/content/repositories/snapshots ossrh https://oss.sonatype.org/service/local/staging/deploy/maven2/ Rserve/src/client/java/Rserve/RserveException.java0000644000175100001440000000563114531234224021767 0ustar hornikusers// JRclient library - client interface to Rserve, see http://www.rosuda.org/Rserve/ // Copyright (C) 2004 Simon Urbanek // --- for licensing information see LICENSE file in the original JRclient distribution --- // // RserveException.java // // Created by Simon Urbanek on Mon Aug 18 2003. // // $Id$ // package org.rosuda.REngine.Rserve; import org.rosuda.REngine.Rserve.protocol.RPacket; import org.rosuda.REngine.Rserve.protocol.RTalk; import org.rosuda.REngine.REngineException; public class RserveException extends REngineException { protected String err; protected int reqReturnCode; public String getRequestErrorDescription() { return getRequestErrorDescription(reqReturnCode); } public String getRequestErrorDescription(int code) { switch(code) { case 0: return "no error"; case 2: return "R parser: input incomplete"; case 3: return "R parser: syntax error"; case RTalk.ERR_auth_failed: return "authorization failed"; case RTalk.ERR_conn_broken: return "connection broken"; case RTalk.ERR_inv_cmd: return "invalid command"; case RTalk.ERR_inv_par: return "invalid parameter"; case RTalk.ERR_IOerror: return "I/O error on the server"; case RTalk.ERR_not_open: return "connection is not open"; case RTalk.ERR_access_denied: return "access denied (local to the server)"; case RTalk.ERR_unsupported_cmd: return "unsupported command"; case RTalk.ERR_unknown_cmd: return "unknown command"; case RTalk.ERR_data_overflow: return "data overflow, incoming data too big"; case RTalk.ERR_object_too_big: return "evaluation successful, but returned object is too big to transport"; case RTalk.ERR_out_of_mem: return "FATAL: Rserve ran out of memory, closing connection"; case RTalk.ERR_session_busy: return "session is busy"; case RTalk.ERR_detach_failed: return "session detach failed"; case RTalk.ERR_ctrl_closed: return "control pipe to master process is closed/broken"; } return "error code: "+code; } public String getMessage() { return super.getMessage() + ((reqReturnCode != -1) ? ", request status: " + getRequestErrorDescription() : ""); } public RserveException(RConnection c, String msg) { this(c,msg,-1); } public RserveException(RConnection c, String msg, Throwable cause) { super(c, msg, cause); reqReturnCode = -1; if (c != null) c.lastError = getMessage(); } public RserveException(RConnection c, String msg, int requestReturnCode) { super(c, msg); reqReturnCode = requestReturnCode; if (c != null) c.lastError = getMessage(); } public RserveException(RConnection c, String msg, RPacket p) { this(c, msg, (p == null) ? -1 : p.getStat()); } public int getRequestReturnCode() { return reqReturnCode; } } Rserve/src/client/java/Rserve/protocol/0000755000175100001440000000000014531234224017633 5ustar hornikusersRserve/src/client/java/Rserve/protocol/jcrypt.java0000644000175100001440000005731614531234224022025 0ustar hornikuserspackage org.rosuda.REngine.Rserve.protocol; /**************************************************************************** * jcrypt.java * * Java-based implementation of the unix crypt command * * Based upon C source code written by Eric Young, eay@psych.uq.oz.au * ****************************************************************************/ public class jcrypt { private static final int ITERATIONS = 16; private static final int con_salt[] = { 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, }; private static final boolean shifts2[] = { false, false, true, true, true, true, true, true, false, true, true, true, true, true, true, false }; private static final int skb[][] = { { /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ 0x00000000, 0x00000010, 0x20000000, 0x20000010, 0x00010000, 0x00010010, 0x20010000, 0x20010010, 0x00000800, 0x00000810, 0x20000800, 0x20000810, 0x00010800, 0x00010810, 0x20010800, 0x20010810, 0x00000020, 0x00000030, 0x20000020, 0x20000030, 0x00010020, 0x00010030, 0x20010020, 0x20010030, 0x00000820, 0x00000830, 0x20000820, 0x20000830, 0x00010820, 0x00010830, 0x20010820, 0x20010830, 0x00080000, 0x00080010, 0x20080000, 0x20080010, 0x00090000, 0x00090010, 0x20090000, 0x20090010, 0x00080800, 0x00080810, 0x20080800, 0x20080810, 0x00090800, 0x00090810, 0x20090800, 0x20090810, 0x00080020, 0x00080030, 0x20080020, 0x20080030, 0x00090020, 0x00090030, 0x20090020, 0x20090030, 0x00080820, 0x00080830, 0x20080820, 0x20080830, 0x00090820, 0x00090830, 0x20090820, 0x20090830, }, { /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */ 0x00000000, 0x02000000, 0x00002000, 0x02002000, 0x00200000, 0x02200000, 0x00202000, 0x02202000, 0x00000004, 0x02000004, 0x00002004, 0x02002004, 0x00200004, 0x02200004, 0x00202004, 0x02202004, 0x00000400, 0x02000400, 0x00002400, 0x02002400, 0x00200400, 0x02200400, 0x00202400, 0x02202400, 0x00000404, 0x02000404, 0x00002404, 0x02002404, 0x00200404, 0x02200404, 0x00202404, 0x02202404, 0x10000000, 0x12000000, 0x10002000, 0x12002000, 0x10200000, 0x12200000, 0x10202000, 0x12202000, 0x10000004, 0x12000004, 0x10002004, 0x12002004, 0x10200004, 0x12200004, 0x10202004, 0x12202004, 0x10000400, 0x12000400, 0x10002400, 0x12002400, 0x10200400, 0x12200400, 0x10202400, 0x12202400, 0x10000404, 0x12000404, 0x10002404, 0x12002404, 0x10200404, 0x12200404, 0x10202404, 0x12202404, }, { /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */ 0x00000000, 0x00000001, 0x00040000, 0x00040001, 0x01000000, 0x01000001, 0x01040000, 0x01040001, 0x00000002, 0x00000003, 0x00040002, 0x00040003, 0x01000002, 0x01000003, 0x01040002, 0x01040003, 0x00000200, 0x00000201, 0x00040200, 0x00040201, 0x01000200, 0x01000201, 0x01040200, 0x01040201, 0x00000202, 0x00000203, 0x00040202, 0x00040203, 0x01000202, 0x01000203, 0x01040202, 0x01040203, 0x08000000, 0x08000001, 0x08040000, 0x08040001, 0x09000000, 0x09000001, 0x09040000, 0x09040001, 0x08000002, 0x08000003, 0x08040002, 0x08040003, 0x09000002, 0x09000003, 0x09040002, 0x09040003, 0x08000200, 0x08000201, 0x08040200, 0x08040201, 0x09000200, 0x09000201, 0x09040200, 0x09040201, 0x08000202, 0x08000203, 0x08040202, 0x08040203, 0x09000202, 0x09000203, 0x09040202, 0x09040203, }, { /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */ 0x00000000, 0x00100000, 0x00000100, 0x00100100, 0x00000008, 0x00100008, 0x00000108, 0x00100108, 0x00001000, 0x00101000, 0x00001100, 0x00101100, 0x00001008, 0x00101008, 0x00001108, 0x00101108, 0x04000000, 0x04100000, 0x04000100, 0x04100100, 0x04000008, 0x04100008, 0x04000108, 0x04100108, 0x04001000, 0x04101000, 0x04001100, 0x04101100, 0x04001008, 0x04101008, 0x04001108, 0x04101108, 0x00020000, 0x00120000, 0x00020100, 0x00120100, 0x00020008, 0x00120008, 0x00020108, 0x00120108, 0x00021000, 0x00121000, 0x00021100, 0x00121100, 0x00021008, 0x00121008, 0x00021108, 0x00121108, 0x04020000, 0x04120000, 0x04020100, 0x04120100, 0x04020008, 0x04120008, 0x04020108, 0x04120108, 0x04021000, 0x04121000, 0x04021100, 0x04121100, 0x04021008, 0x04121008, 0x04021108, 0x04121108, }, { /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ 0x00000000, 0x10000000, 0x00010000, 0x10010000, 0x00000004, 0x10000004, 0x00010004, 0x10010004, 0x20000000, 0x30000000, 0x20010000, 0x30010000, 0x20000004, 0x30000004, 0x20010004, 0x30010004, 0x00100000, 0x10100000, 0x00110000, 0x10110000, 0x00100004, 0x10100004, 0x00110004, 0x10110004, 0x20100000, 0x30100000, 0x20110000, 0x30110000, 0x20100004, 0x30100004, 0x20110004, 0x30110004, 0x00001000, 0x10001000, 0x00011000, 0x10011000, 0x00001004, 0x10001004, 0x00011004, 0x10011004, 0x20001000, 0x30001000, 0x20011000, 0x30011000, 0x20001004, 0x30001004, 0x20011004, 0x30011004, 0x00101000, 0x10101000, 0x00111000, 0x10111000, 0x00101004, 0x10101004, 0x00111004, 0x10111004, 0x20101000, 0x30101000, 0x20111000, 0x30111000, 0x20101004, 0x30101004, 0x20111004, 0x30111004, }, { /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */ 0x00000000, 0x08000000, 0x00000008, 0x08000008, 0x00000400, 0x08000400, 0x00000408, 0x08000408, 0x00020000, 0x08020000, 0x00020008, 0x08020008, 0x00020400, 0x08020400, 0x00020408, 0x08020408, 0x00000001, 0x08000001, 0x00000009, 0x08000009, 0x00000401, 0x08000401, 0x00000409, 0x08000409, 0x00020001, 0x08020001, 0x00020009, 0x08020009, 0x00020401, 0x08020401, 0x00020409, 0x08020409, 0x02000000, 0x0A000000, 0x02000008, 0x0A000008, 0x02000400, 0x0A000400, 0x02000408, 0x0A000408, 0x02020000, 0x0A020000, 0x02020008, 0x0A020008, 0x02020400, 0x0A020400, 0x02020408, 0x0A020408, 0x02000001, 0x0A000001, 0x02000009, 0x0A000009, 0x02000401, 0x0A000401, 0x02000409, 0x0A000409, 0x02020001, 0x0A020001, 0x02020009, 0x0A020009, 0x02020401, 0x0A020401, 0x02020409, 0x0A020409, }, { /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */ 0x00000000, 0x00000100, 0x00080000, 0x00080100, 0x01000000, 0x01000100, 0x01080000, 0x01080100, 0x00000010, 0x00000110, 0x00080010, 0x00080110, 0x01000010, 0x01000110, 0x01080010, 0x01080110, 0x00200000, 0x00200100, 0x00280000, 0x00280100, 0x01200000, 0x01200100, 0x01280000, 0x01280100, 0x00200010, 0x00200110, 0x00280010, 0x00280110, 0x01200010, 0x01200110, 0x01280010, 0x01280110, 0x00000200, 0x00000300, 0x00080200, 0x00080300, 0x01000200, 0x01000300, 0x01080200, 0x01080300, 0x00000210, 0x00000310, 0x00080210, 0x00080310, 0x01000210, 0x01000310, 0x01080210, 0x01080310, 0x00200200, 0x00200300, 0x00280200, 0x00280300, 0x01200200, 0x01200300, 0x01280200, 0x01280300, 0x00200210, 0x00200310, 0x00280210, 0x00280310, 0x01200210, 0x01200310, 0x01280210, 0x01280310, }, { /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000002, 0x04000002, 0x00040002, 0x04040002, 0x00002000, 0x04002000, 0x00042000, 0x04042000, 0x00002002, 0x04002002, 0x00042002, 0x04042002, 0x00000020, 0x04000020, 0x00040020, 0x04040020, 0x00000022, 0x04000022, 0x00040022, 0x04040022, 0x00002020, 0x04002020, 0x00042020, 0x04042020, 0x00002022, 0x04002022, 0x00042022, 0x04042022, 0x00000800, 0x04000800, 0x00040800, 0x04040800, 0x00000802, 0x04000802, 0x00040802, 0x04040802, 0x00002800, 0x04002800, 0x00042800, 0x04042800, 0x00002802, 0x04002802, 0x00042802, 0x04042802, 0x00000820, 0x04000820, 0x00040820, 0x04040820, 0x00000822, 0x04000822, 0x00040822, 0x04040822, 0x00002820, 0x04002820, 0x00042820, 0x04042820, 0x00002822, 0x04002822, 0x00042822, 0x04042822, }, }; private static final int SPtrans[][] = { { /* nibble 0 */ 0x00820200, 0x00020000, 0x80800000, 0x80820200, 0x00800000, 0x80020200, 0x80020000, 0x80800000, 0x80020200, 0x00820200, 0x00820000, 0x80000200, 0x80800200, 0x00800000, 0x00000000, 0x80020000, 0x00020000, 0x80000000, 0x00800200, 0x00020200, 0x80820200, 0x00820000, 0x80000200, 0x00800200, 0x80000000, 0x00000200, 0x00020200, 0x80820000, 0x00000200, 0x80800200, 0x80820000, 0x00000000, 0x00000000, 0x80820200, 0x00800200, 0x80020000, 0x00820200, 0x00020000, 0x80000200, 0x00800200, 0x80820000, 0x00000200, 0x00020200, 0x80800000, 0x80020200, 0x80000000, 0x80800000, 0x00820000, 0x80820200, 0x00020200, 0x00820000, 0x80800200, 0x00800000, 0x80000200, 0x80020000, 0x00000000, 0x00020000, 0x00800000, 0x80800200, 0x00820200, 0x80000000, 0x80820000, 0x00000200, 0x80020200, }, { /* nibble 1 */ 0x10042004, 0x00000000, 0x00042000, 0x10040000, 0x10000004, 0x00002004, 0x10002000, 0x00042000, 0x00002000, 0x10040004, 0x00000004, 0x10002000, 0x00040004, 0x10042000, 0x10040000, 0x00000004, 0x00040000, 0x10002004, 0x10040004, 0x00002000, 0x00042004, 0x10000000, 0x00000000, 0x00040004, 0x10002004, 0x00042004, 0x10042000, 0x10000004, 0x10000000, 0x00040000, 0x00002004, 0x10042004, 0x00040004, 0x10042000, 0x10002000, 0x00042004, 0x10042004, 0x00040004, 0x10000004, 0x00000000, 0x10000000, 0x00002004, 0x00040000, 0x10040004, 0x00002000, 0x10000000, 0x00042004, 0x10002004, 0x10042000, 0x00002000, 0x00000000, 0x10000004, 0x00000004, 0x10042004, 0x00042000, 0x10040000, 0x10040004, 0x00040000, 0x00002004, 0x10002000, 0x10002004, 0x00000004, 0x10040000, 0x00042000, }, { /* nibble 2 */ 0x41000000, 0x01010040, 0x00000040, 0x41000040, 0x40010000, 0x01000000, 0x41000040, 0x00010040, 0x01000040, 0x00010000, 0x01010000, 0x40000000, 0x41010040, 0x40000040, 0x40000000, 0x41010000, 0x00000000, 0x40010000, 0x01010040, 0x00000040, 0x40000040, 0x41010040, 0x00010000, 0x41000000, 0x41010000, 0x01000040, 0x40010040, 0x01010000, 0x00010040, 0x00000000, 0x01000000, 0x40010040, 0x01010040, 0x00000040, 0x40000000, 0x00010000, 0x40000040, 0x40010000, 0x01010000, 0x41000040, 0x00000000, 0x01010040, 0x00010040, 0x41010000, 0x40010000, 0x01000000, 0x41010040, 0x40000000, 0x40010040, 0x41000000, 0x01000000, 0x41010040, 0x00010000, 0x01000040, 0x41000040, 0x00010040, 0x01000040, 0x00000000, 0x41010000, 0x40000040, 0x41000000, 0x40010040, 0x00000040, 0x01010000, }, { /* nibble 3 */ 0x00100402, 0x04000400, 0x00000002, 0x04100402, 0x00000000, 0x04100000, 0x04000402, 0x00100002, 0x04100400, 0x04000002, 0x04000000, 0x00000402, 0x04000002, 0x00100402, 0x00100000, 0x04000000, 0x04100002, 0x00100400, 0x00000400, 0x00000002, 0x00100400, 0x04000402, 0x04100000, 0x00000400, 0x00000402, 0x00000000, 0x00100002, 0x04100400, 0x04000400, 0x04100002, 0x04100402, 0x00100000, 0x04100002, 0x00000402, 0x00100000, 0x04000002, 0x00100400, 0x04000400, 0x00000002, 0x04100000, 0x04000402, 0x00000000, 0x00000400, 0x00100002, 0x00000000, 0x04100002, 0x04100400, 0x00000400, 0x04000000, 0x04100402, 0x00100402, 0x00100000, 0x04100402, 0x00000002, 0x04000400, 0x00100402, 0x00100002, 0x00100400, 0x04100000, 0x04000402, 0x00000402, 0x04000000, 0x04000002, 0x04100400, }, { /* nibble 4 */ 0x02000000, 0x00004000, 0x00000100, 0x02004108, 0x02004008, 0x02000100, 0x00004108, 0x02004000, 0x00004000, 0x00000008, 0x02000008, 0x00004100, 0x02000108, 0x02004008, 0x02004100, 0x00000000, 0x00004100, 0x02000000, 0x00004008, 0x00000108, 0x02000100, 0x00004108, 0x00000000, 0x02000008, 0x00000008, 0x02000108, 0x02004108, 0x00004008, 0x02004000, 0x00000100, 0x00000108, 0x02004100, 0x02004100, 0x02000108, 0x00004008, 0x02004000, 0x00004000, 0x00000008, 0x02000008, 0x02000100, 0x02000000, 0x00004100, 0x02004108, 0x00000000, 0x00004108, 0x02000000, 0x00000100, 0x00004008, 0x02000108, 0x00000100, 0x00000000, 0x02004108, 0x02004008, 0x02004100, 0x00000108, 0x00004000, 0x00004100, 0x02004008, 0x02000100, 0x00000108, 0x00000008, 0x00004108, 0x02004000, 0x02000008, }, { /* nibble 5 */ 0x20000010, 0x00080010, 0x00000000, 0x20080800, 0x00080010, 0x00000800, 0x20000810, 0x00080000, 0x00000810, 0x20080810, 0x00080800, 0x20000000, 0x20000800, 0x20000010, 0x20080000, 0x00080810, 0x00080000, 0x20000810, 0x20080010, 0x00000000, 0x00000800, 0x00000010, 0x20080800, 0x20080010, 0x20080810, 0x20080000, 0x20000000, 0x00000810, 0x00000010, 0x00080800, 0x00080810, 0x20000800, 0x00000810, 0x20000000, 0x20000800, 0x00080810, 0x20080800, 0x00080010, 0x00000000, 0x20000800, 0x20000000, 0x00000800, 0x20080010, 0x00080000, 0x00080010, 0x20080810, 0x00080800, 0x00000010, 0x20080810, 0x00080800, 0x00080000, 0x20000810, 0x20000010, 0x20080000, 0x00080810, 0x00000000, 0x00000800, 0x20000010, 0x20000810, 0x20080800, 0x20080000, 0x00000810, 0x00000010, 0x20080010, }, { /* nibble 6 */ 0x00001000, 0x00000080, 0x00400080, 0x00400001, 0x00401081, 0x00001001, 0x00001080, 0x00000000, 0x00400000, 0x00400081, 0x00000081, 0x00401000, 0x00000001, 0x00401080, 0x00401000, 0x00000081, 0x00400081, 0x00001000, 0x00001001, 0x00401081, 0x00000000, 0x00400080, 0x00400001, 0x00001080, 0x00401001, 0x00001081, 0x00401080, 0x00000001, 0x00001081, 0x00401001, 0x00000080, 0x00400000, 0x00001081, 0x00401000, 0x00401001, 0x00000081, 0x00001000, 0x00000080, 0x00400000, 0x00401001, 0x00400081, 0x00001081, 0x00001080, 0x00000000, 0x00000080, 0x00400001, 0x00000001, 0x00400080, 0x00000000, 0x00400081, 0x00400080, 0x00001080, 0x00000081, 0x00001000, 0x00401081, 0x00400000, 0x00401080, 0x00000001, 0x00001001, 0x00401081, 0x00400001, 0x00401080, 0x00401000, 0x00001001, }, { /* nibble 7 */ 0x08200020, 0x08208000, 0x00008020, 0x00000000, 0x08008000, 0x00200020, 0x08200000, 0x08208020, 0x00000020, 0x08000000, 0x00208000, 0x00008020, 0x00208020, 0x08008020, 0x08000020, 0x08200000, 0x00008000, 0x00208020, 0x00200020, 0x08008000, 0x08208020, 0x08000020, 0x00000000, 0x00208000, 0x08000000, 0x00200000, 0x08008020, 0x08200020, 0x00200000, 0x00008000, 0x08208000, 0x00000020, 0x00200000, 0x00008000, 0x08000020, 0x08208020, 0x00008020, 0x08000000, 0x00000000, 0x00208000, 0x08200020, 0x08008020, 0x08008000, 0x00200020, 0x08208000, 0x00000020, 0x00200020, 0x08008000, 0x08208020, 0x00200000, 0x08200000, 0x08000020, 0x00208000, 0x00008020, 0x08008020, 0x08200000, 0x00000020, 0x08208000, 0x00208020, 0x00000000, 0x08000000, 0x08200020, 0x00008000, 0x00208020 } }; private static final int cov_2char[] = { 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A }; private static final int byteToUnsigned(byte b) { int value = (int)b; return(value >= 0 ? value : value + 256); } private static int fourBytesToInt(byte b[], int offset) { int value; value = byteToUnsigned(b[offset++]); value |= (byteToUnsigned(b[offset++]) << 8); value |= (byteToUnsigned(b[offset++]) << 16); value |= (byteToUnsigned(b[offset++]) << 24); return(value); } private static final void intToFourBytes(int iValue, byte b[], int offset) { b[offset++] = (byte)((iValue) & 0xff); b[offset++] = (byte)((iValue >>> 8 ) & 0xff); b[offset++] = (byte)((iValue >>> 16) & 0xff); b[offset++] = (byte)((iValue >>> 24) & 0xff); } private static final void PERM_OP(int a, int b, int n, int m, int results[]) { int t; t = ((a >>> n) ^ b) & m; a ^= t << n; b ^= t; results[0] = a; results[1] = b; } private static final int HPERM_OP(int a, int n, int m) { int t; t = ((a << (16 - n)) ^ a) & m; a = a ^ t ^ (t >>> (16 - n)); return(a); } private static int [] des_set_key(byte key[]) { int schedule[] = new int[ITERATIONS * 2]; int c = fourBytesToInt(key, 0); int d = fourBytesToInt(key, 4); int results[] = new int[2]; PERM_OP(d, c, 4, 0x0f0f0f0f, results); d = results[0]; c = results[1]; c = HPERM_OP(c, -2, 0xcccc0000); d = HPERM_OP(d, -2, 0xcccc0000); PERM_OP(d, c, 1, 0x55555555, results); d = results[0]; c = results[1]; PERM_OP(c, d, 8, 0x00ff00ff, results); c = results[0]; d = results[1]; PERM_OP(d, c, 1, 0x55555555, results); d = results[0]; c = results[1]; d = (((d & 0x000000ff) << 16) | (d & 0x0000ff00) | ((d & 0x00ff0000) >>> 16) | ((c & 0xf0000000) >>> 4)); c &= 0x0fffffff; int s, t; int j = 0; for(int i = 0; i < ITERATIONS; i ++) { if(shifts2[i]) { c = (c >>> 2) | (c << 26); d = (d >>> 2) | (d << 26); } else { c = (c >>> 1) | (c << 27); d = (d >>> 1) | (d << 27); } c &= 0x0fffffff; d &= 0x0fffffff; s = skb[0][ (c ) & 0x3f ]| skb[1][((c >>> 6) & 0x03) | ((c >>> 7) & 0x3c)]| skb[2][((c >>> 13) & 0x0f) | ((c >>> 14) & 0x30)]| skb[3][((c >>> 20) & 0x01) | ((c >>> 21) & 0x06) | ((c >>> 22) & 0x38)]; t = skb[4][ (d ) & 0x3f ]| skb[5][((d >>> 7) & 0x03) | ((d >>> 8) & 0x3c)]| skb[6][ (d >>>15) & 0x3f ]| skb[7][((d >>>21) & 0x0f) | ((d >>> 22) & 0x30)]; schedule[j++] = ((t << 16) | (s & 0x0000ffff)) & 0xffffffff; s = ((s >>> 16) | (t & 0xffff0000)); s = (s << 4) | (s >>> 28); schedule[j++] = s & 0xffffffff; } return(schedule); } private static final int D_ENCRYPT ( int L, int R, int S, int E0, int E1, int s[] ) { int t, u, v; v = R ^ (R >>> 16); u = v & E0; v = v & E1; u = (u ^ (u << 16)) ^ R ^ s[S]; t = (v ^ (v << 16)) ^ R ^ s[S + 1]; t = (t >>> 4) | (t << 28); L ^= SPtrans[1][(t ) & 0x3f] | SPtrans[3][(t >>> 8) & 0x3f] | SPtrans[5][(t >>> 16) & 0x3f] | SPtrans[7][(t >>> 24) & 0x3f] | SPtrans[0][(u ) & 0x3f] | SPtrans[2][(u >>> 8) & 0x3f] | SPtrans[4][(u >>> 16) & 0x3f] | SPtrans[6][(u >>> 24) & 0x3f]; return(L); } private static final int [] body(int schedule[], int Eswap0, int Eswap1) { int left = 0; int right = 0; int t = 0; for(int j = 0; j < 25; j ++) { for(int i = 0; i < ITERATIONS * 2; i += 4) { left = D_ENCRYPT(left, right, i, Eswap0, Eswap1, schedule); right = D_ENCRYPT(right, left, i + 2, Eswap0, Eswap1, schedule); } t = left; left = right; right = t; } t = right; right = (left >>> 1) | (left << 31); left = (t >>> 1) | (t << 31); left &= 0xffffffff; right &= 0xffffffff; int results[] = new int[2]; PERM_OP(right, left, 1, 0x55555555, results); right = results[0]; left = results[1]; PERM_OP(left, right, 8, 0x00ff00ff, results); left = results[0]; right = results[1]; PERM_OP(right, left, 2, 0x33333333, results); right = results[0]; left = results[1]; PERM_OP(left, right, 16, 0x0000ffff, results); left = results[0]; right = results[1]; PERM_OP(right, left, 4, 0x0f0f0f0f, results); right = results[0]; left = results[1]; int out[] = new int[2]; out[0] = left; out[1] = right; return(out); } public static final String crypt(String salt, String original) { while(salt.length() < 2) salt += "A"; StringBuffer buffer = new StringBuffer(" "); char charZero = salt.charAt(0); char charOne = salt.charAt(1); buffer.setCharAt(0, charZero); buffer.setCharAt(1, charOne); int Eswap0 = con_salt[(int)charZero]; int Eswap1 = con_salt[(int)charOne] << 4; byte key[] = new byte[8]; for(int i = 0; i < key.length; i ++) key[i] = (byte)0; for(int i = 0; i < key.length && i < original.length(); i ++) { int iChar = (int)original.charAt(i); key[i] = (byte)(iChar << 1); } int schedule[] = des_set_key(key); int out[] = body(schedule, Eswap0, Eswap1); byte b[] = new byte[9]; intToFourBytes(out[0], b, 0); intToFourBytes(out[1], b, 4); b[8] = 0; for(int i = 2, y = 0, u = 0x80; i < 13; i ++) { for(int j = 0, c = 0; j < 6; j ++) { c <<= 1; if(((int)b[y] & u) != 0) c |= 1; u >>>= 1; if(u == 0) { y++; u = 0x80; } buffer.setCharAt(i, (char)cov_2char[c]); } } return(buffer.toString()); } } Rserve/src/client/java/Rserve/protocol/RPacket.java0000644000175100001440000000272014531234224022030 0ustar hornikuserspackage org.rosuda.REngine.Rserve.protocol; import org.rosuda.REngine.Rserve.protocol.RTalk; // JRclient library - client interface to Rserve, see http://www.rosuda.org/Rserve/ // Copyright (C) 2004 Simon Urbanek // --- for licensing information see LICENSE file in the original JRclient distribution --- /** small class encapsulating packets from/to Rserv @version $Id$ */ public class RPacket { int cmd; byte[] cont; /** construct new packet @param Rcmd command @param Rcont content */ public RPacket(int Rcmd, byte[] Rcont) { cmd=Rcmd; cont=Rcont; } /** get command @return command */ public int getCmd() { return cmd; } /** check if last response was an OOB message (send or msg) */ public boolean isOOB() { return ((cmd & 0xf0000) == RTalk.CMD_OOB); } /** check last response for RESP_OK @return true if last response was OK */ public boolean isOk() { return ((cmd&15)==1); } /** check last response for RESP_ERR @return true if last response was ERROR */ public boolean isError() { return ((cmd&15)==2); } /** get status code of last response @return status code returned on last response */ public int getStat() { return ((cmd>>24)&127); } /** get content @return inner package content */ public byte[] getCont() { return cont; } public String toString() { return "RPacket[cmd="+cmd+",len="+((cont==null)?"":(""+cont.length))+"]"; } } Rserve/src/client/java/Rserve/protocol/REXPFactory.java0000644000175100001440000005546314531234224022621 0ustar hornikuserspackage org.rosuda.REngine.Rserve.protocol; // JRclient library - client interface to Rserve, see http://www.rosuda.org/Rserve/ // Copyright (C) 2004-8 Simon Urbanek // --- for licensing information see LICENSE file in the original JRclient distribution --- import java.util.*; import org.rosuda.REngine.*; import org.rosuda.REngine.Rserve.*; /** representation of R-eXpressions in Java @version $Id$ */ public class REXPFactory { /** xpression type: NULL */ public static final int XT_NULL=0; /** xpression type: integer */ public static final int XT_INT=1; /** xpression type: double */ public static final int XT_DOUBLE=2; /** xpression type: String */ public static final int XT_STR=3; /** xpression type: language construct (currently content is same as list) */ public static final int XT_LANG=4; /** xpression type: symbol (content is symbol name: String) */ public static final int XT_SYM=5; /** xpression type: RBool */ public static final int XT_BOOL=6; /** xpression type: S4 object @since Rserve 0.5 */ public static final int XT_S4=7; /** xpression type: generic vector (RList) */ public static final int XT_VECTOR=16; /** xpression type: dotted-pair list (RList) */ public static final int XT_LIST=17; /** xpression type: closure (there is no java class for that type (yet?). currently the body of the closure is stored in the content part of the REXP. Please note that this may change in the future!) */ public static final int XT_CLOS=18; /** xpression type: symbol name @since Rserve 0.5 */ public static final int XT_SYMNAME=19; /** xpression type: dotted-pair list (w/o tags) @since Rserve 0.5 */ public static final int XT_LIST_NOTAG=20; /** xpression type: dotted-pair list (w tags) @since Rserve 0.5 */ public static final int XT_LIST_TAG=21; /** xpression type: language list (w/o tags) @since Rserve 0.5 */ public static final int XT_LANG_NOTAG=22; /** xpression type: language list (w tags) @since Rserve 0.5 */ public static final int XT_LANG_TAG=23; /** xpression type: expression vector */ public static final int XT_VECTOR_EXP=26; /** xpression type: string vector */ public static final int XT_VECTOR_STR=27; /** xpression type: int[] */ public static final int XT_ARRAY_INT=32; /** xpression type: double[] */ public static final int XT_ARRAY_DOUBLE=33; /** xpression type: String[] (currently not used, Vector is used instead) */ public static final int XT_ARRAY_STR=34; /** internal use only! this constant should never appear in a REXP */ public static final int XT_ARRAY_BOOL_UA=35; /** xpression type: RBool[] */ public static final int XT_ARRAY_BOOL=36; /** xpression type: raw (byte[]) @since Rserve 0.4-? */ public static final int XT_RAW=37; /** xpression type: Complex[] @since Rserve 0.5 */ public static final int XT_ARRAY_CPLX=38; /** xpression type: unknown; no assumptions can be made about the content */ public static final int XT_UNKNOWN=48; /** xpression type: RFactor; this XT is internally generated (ergo is does not come from Rsrv.h) to support RFactor class which is built from XT_ARRAY_INT */ public static final int XT_FACTOR=127; /** used for transport only - has attribute */ private static final int XT_HAS_ATTR=128; int type; REXPFactory attr; REXP cont; RList rootList; public REXP getREXP() { return cont; } public REXPList getAttr() { return (attr==null)?null:(REXPList)attr.cont; } public REXPFactory() { } public REXPFactory(REXP r) throws REXPMismatchException { if (r == null) r=new REXPNull(); REXPList a = r._attr(); cont = r; if (a != null) attr = new REXPFactory(a); if (r instanceof REXPNull) { type=XT_NULL; } else if (r instanceof REXPList) { RList l = r.asList(); type = l.isNamed()?XT_LIST_TAG:XT_LIST_NOTAG; if (r instanceof REXPLanguage) type = (type==XT_LIST_TAG)?XT_LANG_TAG:XT_LANG_NOTAG; } else if (r instanceof REXPGenericVector) { type = XT_VECTOR; // FIXME: may have to adjust names attr } else if (r instanceof REXPS4) { type = XT_S4; } else if (r instanceof REXPInteger) { // this includes factor - FIXME: do we need speacial handling? type = XT_ARRAY_INT; } else if (r instanceof REXPDouble) { type = XT_ARRAY_DOUBLE; } else if (r instanceof REXPString) { type = XT_ARRAY_STR; } else if (r instanceof REXPSymbol) { type = XT_SYMNAME; } else if (r instanceof REXPRaw) { type = XT_RAW; } else if (r instanceof REXPLogical) { type = XT_ARRAY_BOOL; } else { // throw new REXPMismatchException(r, "decode"); System.err.println("*** REXPFactory unable to interpret "+r); } } /** parses byte buffer for binary representation of xpressions - read one xpression slot (descends recursively for aggregated xpressions such as lists, vectors etc.) @param buf buffer containing the binary representation @param o offset in the buffer to start at @return position just behind the parsed xpression. Can be use for successive calls to {@link #parseREXP} if more than one expression is stored in the binary array. */ public int parseREXP(byte[] buf, int o) throws REXPMismatchException { int xl = RTalk.getLen(buf,o); boolean hasAtt = ((buf[o]&128)!=0); boolean isLong = ((buf[o]&64)!=0); int xt = (int)(buf[o]&63); //System.out.println("parseREXP: type="+xt+", len="+xl+", hasAtt="+hasAtt+", isLong="+isLong); if (isLong) o+=4; o+=4; int eox=o+xl; type=xt; attr=new REXPFactory(); cont=null; if (hasAtt) o = attr.parseREXP(buf, o); if (xt==XT_NULL) { cont = new REXPNull(getAttr()); return o; } if (xt==XT_DOUBLE) { long lr = RTalk.getLong(buf,o); double[] d = new double[] { Double.longBitsToDouble(lr) }; o+=8; if (o!=eox) { System.err.println("Warning: double SEXP size mismatch\n"); o=eox; } cont = new REXPDouble(d, getAttr()); return o; } if (xt==XT_ARRAY_DOUBLE) { int as=(eox-o)/8,i=0; double[] d=new double[as]; while (o 0) { c = 0; i = o; while (o < eox) { if (buf[o] == 0) { try { if (buf[i] == -1) { /* if the first byte is 0xff (-1 in signed char) then it either needs to be skipped (doubling) or there is an NA value */ if (buf[i + 1] == 0) s[c] = null; /* NA */ else s[c] = new String(buf, i + 1, o - i - 1, RConnection.transferCharset); } else s[c] = new String(buf, i, o - i, RConnection.transferCharset); } catch (java.io.UnsupportedEncodingException ex) { s[c]=""; } c++; i = o + 1; } o++; } } cont = new REXPString(s, getAttr()); return o; } if (xt==XT_VECTOR_STR) { Vector v=new Vector(); while(oPlease note that currently only XT_[ARRAY_]INT, XT_[ARRAY_]DOUBLE and XT_[ARRAY_]STR are supported! All other types will return 4 which is the size of the header. @return length of the REXP including headers (4 or 8 bytes)*/ public int getBinaryLength() throws REXPMismatchException { int l=0; int rxt = type; if (type==XT_LIST || type==XT_LIST_TAG || type==XT_LIST_NOTAG) rxt=(cont.asList()!=null && cont.asList().isNamed())?XT_LIST_TAG:XT_LIST_NOTAG; //System.out.print("len["+xtName(type)+"/"+xtName(rxt)+"] "); if (type==XT_VECTOR_STR) rxt=XT_ARRAY_STR; // VECTOR_STR is broken right now /* if (type==XT_VECTOR && cont.asList()!=null && cont.asList().isNamed()) setAttribute("names",new REXPString(cont.asList().keys())); */ boolean hasAttr = false; REXPList a = getAttr(); RList al = null; if (a!=null) al = a.asList(); if (al != null && al.size()>0) hasAttr=true; if (hasAttr) l+=attr.getBinaryLength(); switch (rxt) { case XT_NULL: case XT_S4: break; case XT_INT: l+=4; break; case XT_DOUBLE: l+=8; break; case XT_RAW: l+=4 + cont.asBytes().length; if ((l&3)>0) l=l-(l&3)+4; break; case XT_STR: case XT_SYMNAME: l+=(cont==null)?1:(cont.asString().length()+1); if ((l&3)>0) l=l-(l&3)+4; break; case XT_ARRAY_INT: l+=cont.asIntegers().length*4; break; case XT_ARRAY_DOUBLE: l+=cont.asDoubles().length*8; break; case XT_ARRAY_CPLX: l+=cont.asDoubles().length*8; break; case XT_ARRAY_BOOL: l += cont.asBytes().length + 4; if ((l & 3) > 0) l = l - (l & 3) + 4; break; case XT_LIST_TAG: case XT_LIST_NOTAG: case XT_LANG_TAG: case XT_LANG_NOTAG: case XT_LIST: case XT_VECTOR: { final RList lst = cont.asList(); int i=0; while (i0) l=l-(l&3)+4; // System.out.println("TAG length: "+(l-pl)); } i++; } if ((l&3)>0) l=l-(l&3)+4; break; } case XT_ARRAY_STR: { String sa[] = cont.asStrings(); int i=0; while (i < sa.length) { if (sa[i] != null) { try { byte b[] = sa[i].getBytes(RConnection.transferCharset); if (b.length > 0) { if (b[0] == -1) l++; l += b.length; } b = null; } catch (java.io.UnsupportedEncodingException uex) { // FIXME: we should so something ... so far we hope noone's gonna mess with the encoding } } else l++; // NA = -1 l++; i++; } if ((l&3)>0) l=l-(l&3)+4; break; } } // switch if (l>0xfffff0) l+=4; // large data need 4 more bytes // System.out.println("len:"+(l+4)+" "+xtName(rxt)+"/"+xtName(type)+" "+cont); return l+4; // add the header } /** Stores the REXP in its binary (ready-to-send) representation including header into a buffer and returns the index of the byte behind the REXP.

Please note that currently only XT_[ARRAY_]INT, XT_[ARRAY_]DOUBLE and XT_[ARRAY_]STR are supported! All other types will be stored as SEXP of the length 0 without any contents. @param buf buffer to store the REXP binary into @param off offset of the first byte where to store the REXP @return the offset of the first byte behind the stored REXP */ public int getBinaryRepresentation(byte[] buf, int off) throws REXPMismatchException { int myl=getBinaryLength(); boolean isLarge=(myl>0xfffff0); boolean hasAttr = false; final REXPList a = getAttr(); RList al = null; if (a != null) al = a.asList(); if (al != null && al.size()>0) hasAttr=true; int rxt=type, ooff=off; if (type==XT_VECTOR_STR) rxt=XT_ARRAY_STR; // VECTOR_STR is broken right now if (type==XT_LIST || type==XT_LIST_TAG || type==XT_LIST_NOTAG) rxt=(cont.asList()!=null && cont.asList().isNamed())?XT_LIST_TAG:XT_LIST_NOTAG; // System.out.println("@"+off+": "+xtName(rxt)+"/"+xtName(type)+" "+cont+" ("+myl+"/"+buf.length+") att="+hasAttr); RTalk.setHdr(rxt|(hasAttr?XT_HAS_ATTR:0),myl-(isLarge?8:4),buf,off); off+=(isLarge?8:4); if (hasAttr) off=attr.getBinaryRepresentation(buf, off); switch (rxt) { case XT_S4: case XT_NULL: break; case XT_INT: RTalk.setInt(cont.asInteger(),buf,off); break; case XT_DOUBLE: RTalk.setLong(Double.doubleToRawLongBits(cont.asDouble()),buf,off); break; case XT_ARRAY_INT: { int ia[]=cont.asIntegers(); int i=0, io=off; while(i 0) { for(int i =0; i < ba.length; i++) buf[io++] = (byte) ( (ba[i] == REXPLogical.NA) ? 2 : ((ba[i] == REXPLogical.FALSE) ? 0 : 1) ); while ((io & 3) != 0) buf[io++] = 3; } break; } case XT_ARRAY_DOUBLE: { double da[]=cont.asDoubles(); int i=0, io=off; while(i 0) { if (b[0] == -1) /* if the first entry happens to be -1 then we need to double it so it doesn't get confused with NAs */ buf[io++] = -1; System.arraycopy(b, 0, buf, io, b.length); io += b.length; } b = null; } catch (java.io.UnsupportedEncodingException uex) { // FIXME: we should so something ... so far we hope noone's gonna mess with the encoding } } else buf[io++] = -1; /* NAs are stored as 0xff (-1 in signed bytes) */ buf[io++] = 0; i++; } i = io - off; while ((i & 3) != 0) { buf[io++] = 1; i++; } // padding if necessary.. break; } case XT_LIST_TAG: case XT_LIST_NOTAG: case XT_LANG_TAG: case XT_LANG_NOTAG: case XT_LIST: case XT_VECTOR: case XT_VECTOR_EXP: { int io = off; final RList lst = cont.asList(); if (lst != null) { int i=0; while (i @"+off+", len "+b.length+" (cont "+buf.length+") \""+s+"\""); System.arraycopy(b,0,buf,io,b.length); io+=b.length; b=null; } catch (java.io.UnsupportedEncodingException uex) { // FIXME: we should so something ... so far we hope noone's gonna mess with the encoding } buf[io++]=0; while ((io&3)!=0) buf[io++]=0; // padding if necessary.. return io; } /** returns human-readable name of the xpression type as string. Arrays are denoted by a trailing asterisk (*). @param xt xpression type @return name of the xpression type */ public static String xtName(int xt) { if (xt==XT_NULL) return "NULL"; if (xt==XT_INT) return "INT"; if (xt==XT_STR) return "STRING"; if (xt==XT_DOUBLE) return "REAL"; if (xt==XT_BOOL) return "BOOL"; if (xt==XT_ARRAY_INT) return "INT*"; if (xt==XT_ARRAY_STR) return "STRING*"; if (xt==XT_ARRAY_DOUBLE) return "REAL*"; if (xt==XT_ARRAY_BOOL) return "BOOL*"; if (xt==XT_ARRAY_CPLX) return "COMPLEX*"; if (xt==XT_SYM) return "SYMBOL"; if (xt==XT_SYMNAME) return "SYMNAME"; if (xt==XT_LANG) return "LANG"; if (xt==XT_LIST) return "LIST"; if (xt==XT_LIST_TAG) return "LIST+T"; if (xt==XT_LIST_NOTAG) return "LIST/T"; if (xt==XT_LANG_TAG) return "LANG+T"; if (xt==XT_LANG_NOTAG) return "LANG/T"; if (xt==XT_CLOS) return "CLOS"; if (xt==XT_RAW) return "RAW"; if (xt==XT_S4) return "S4"; if (xt==XT_VECTOR) return "VECTOR"; if (xt==XT_VECTOR_STR) return "STRING[]"; if (xt==XT_VECTOR_EXP) return "EXPR[]"; if (xt==XT_FACTOR) return "FACTOR"; if (xt==XT_UNKNOWN) return "UNKNOWN"; return ""; } } Rserve/src/client/java/Rserve/protocol/RTalk.java0000644000175100001440000003012314531234224021512 0ustar hornikuserspackage org.rosuda.REngine.Rserve.protocol; // JRclient library - client interface to Rserve, see http://www.rosuda.org/Rserve/ // Copyright (C) 2004 Simon Urbanek // --- for licensing information see LICENSE file in the original JRclient distribution --- import java.util.*; import java.io.*; import java.net.*; import org.rosuda.REngine.Rserve.RConnection; import org.rosuda.REngine.Rserve.protocol.REXPFactory; import org.rosuda.REngine.REXP; /** This class encapsulates the QAP1 protocol used by Rserv. it is independent of the underying protocol(s), therefore RTalk can be used over any transport layer

The current implementation supports long (0.3+/0102) data format only up to 32-bit and only for incoming packets.

@version $Id$ */ public class RTalk { public static final int DT_INT=1; public static final int DT_CHAR=2; public static final int DT_DOUBLE=3; public static final int DT_STRING=4; public static final int DT_BYTESTREAM=5; public static final int DT_SEXP=10; public static final int DT_ARRAY=11; /** this is a flag saying that the contents is large (>0xfffff0) and hence uses 56-bit length field */ public static final int DT_LARGE=64; public static final int CMD_login=0x001; public static final int CMD_voidEval=0x002; public static final int CMD_eval=0x003; public static final int CMD_shutdown=0x004; /** OCAP call, only valid in OCAP mode, since Rserve 1.8 */ public static final int CMD_OCcall = 0x00f; /** not a command but rather payload sent by the server in OCAP mode */ public static final int CMD_OCinit = 0x434f7352; /* RsOC in ASCII */ public static final int CMD_openFile=0x010; public static final int CMD_createFile=0x011; public static final int CMD_closeFile=0x012; public static final int CMD_readFile=0x013; public static final int CMD_writeFile=0x014; public static final int CMD_removeFile=0x015; public static final int CMD_setSEXP=0x020; public static final int CMD_assignSEXP=0x021; public static final int CMD_setBufferSize=0x081; public static final int CMD_setEncoding=0x082; public static final int CMD_detachSession=0x030; public static final int CMD_detachedVoidEval=0x031; public static final int CMD_attachSession=0x032; // control commands since 0.6-0 public static final int CMD_ctrlEval=0x42; public static final int CMD_ctrlSource=0x45; public static final int CMD_ctrlShutdown=0x44; // errors as returned by Rserve public static final int ERR_auth_failed=0x41; public static final int ERR_conn_broken=0x42; public static final int ERR_inv_cmd=0x43; public static final int ERR_inv_par=0x44; public static final int ERR_Rerror=0x45; public static final int ERR_IOerror=0x46; public static final int ERR_not_open=0x47; public static final int ERR_access_denied=0x48; public static final int ERR_unsupported_cmd=0x49; public static final int ERR_unknown_cmd=0x4a; public static final int ERR_data_overflow=0x4b; public static final int ERR_object_too_big=0x4c; public static final int ERR_out_of_mem=0x4d; public static final int ERR_ctrl_closed=0x4e; public static final int ERR_session_busy=0x50; public static final int ERR_detach_failed=0x51; /** since 1.7 */ public static final int ERR_disabled = 0x61; public static final int ERR_unavailable = 0x62; public static final int ERR_cryptError = 0x63; public static final int ERR_securityClose = 0x64; public static final int CMD_RESP = 0x10000; /* response bit */ public static final int RESP_OK = 0x10001; public static final int RESP_ERR = 0x10002; public static final int CMD_OOB = 0x20000; /* OOB command, low 12 bits are app-specific */ public static final int OOB_SEND = 0x21000; public static final int OOB_MSG = 0x22000; InputStream is; OutputStream os; /** constructor; parameters specify the streams @param sis socket input stream @param sos socket output stream */ public RTalk(InputStream sis, OutputStream sos) { is=sis; os=sos; } /** writes bit-wise int to a byte buffer at specified position in Intel-endian form @param v value to be written @param buf buffer @param o offset in the buffer to start at. An int takes always 4 bytes */ public static void setInt(int v, byte[] buf, int o) { buf[o]=(byte)(v&255); o++; buf[o]=(byte)((v&0xff00)>>8); o++; buf[o]=(byte)((v&0xff0000)>>16); o++; buf[o]=(byte)((v&0xff000000)>>24); } /** writes cmd/resp/type byte + 3/7 bytes len into a byte buffer at specified offset. @param ty type/cmd/resp byte @param len length @param buf buffer @param o offset @return offset in buf just after the header. Please note that since Rserve 0.3 the header can be either 4 or 8 bytes long, depending on the len parameter. */ public static int setHdr(int ty, int len, byte[] buf, int o) { buf[o]=(byte)((ty&255)|((len>0xfffff0)?DT_LARGE:0)); o++; buf[o]=(byte)(len&255); o++; buf[o]=(byte)((len&0xff00)>>8); o++; buf[o]=(byte)((len&0xff0000)>>16); o++; if (len>0xfffff0) { // for large data we need to set the next 4 bytes as well buf[o]=(byte)((len&0xff000000)>>24); o++; buf[o]=0; o++; // since len is int, we get 32-bits only buf[o]=0; o++; buf[o]=0; o++; } return o; } /** creates a new header according to the type and length of the parameter @param ty type/cmd/resp byte @param len length */ public static byte[] newHdr(int ty, int len) { byte[] hdr=new byte[(len>0xfffff0)?8:4]; setHdr(ty,len,hdr,0); return hdr; } /** converts bit-wise stored int in Intel-endian form into Java int @param buf buffer containg the representation @param o offset where to start (4 bytes will be used) @return the int value. no bounds checking is done so you need to make sure that the buffer is big enough */ public static int getInt(byte[] buf, int o) { return ((buf[o]&255)|((buf[o+1]&255)<<8)|((buf[o+2]&255)<<16)|((buf[o+3]&255)<<24)); } /** converts bit-wise stored length from a header. "long" format is supported up to 32-bit @param buf buffer @param o offset of the header (length is at o+1) @return length */ public static int getLen(byte[] buf, int o) { return ((buf[o]&64)>0)? // "long" format; still - we support 32-bit only ((buf[o+1]&255)|((buf[o+2]&255)<<8)|((buf[o+3]&255)<<16)|((buf[o+4]&255)<<24)) : ((buf[o+1]&255)|((buf[o+2]&255)<<8)|((buf[o+3]&255)<<16)); } /** converts bit-wise Intel-endian format into long @param buf buffer @param o offset (8 bytes will be used) @return long value */ public static long getLong(byte[] buf, int o) { long low=((long)getInt(buf,o))&0xffffffffL; long hi=((long)getInt(buf,o+4))&0xffffffffL; hi<<=32; hi|=low; return hi; } public static void setLong(long l, byte[] buf, int o) { setInt((int)(l&0xffffffffL),buf,o); setInt((int)(l>>32),buf,o+4); } /** sends a request with no attached parameters @param cmd command @return returned packet or null if something went wrong */ public RPacket request(int cmd) { byte[] d = new byte[0]; return request(cmd,d); } /** sends a request with attached parameters @param cmd command @param cont contents - parameters @return returned packet or null if something went wrong */ public RPacket request(int cmd, byte[] cont) { return request(cmd,null,cont,0,(cont==null)?0:cont.length); } /** read the response. Return null on error (FIXME: need to use exceptions) */ public RPacket response() { return response(null); } /** read the response. If header is null then is it read from the socket otherwise the provided header is used instead of reading it. Note that if provided, the header aray must have at least 16 bytes and it must at most contain one message */ public RPacket response(byte[] header) { try { if (header == null) { header = new byte[16]; int n = is.read(header); if (n != 16) return null; } int rep = getInt(header, 0); int rl = getInt(header, 4); if (rl > 0) { byte[] ct = new byte[rl]; int n = 0; if (header.length > 16) { n = header.length - 16; System.arraycopy(header, 16, ct, 0, n); } while (n < rl) { int rd = is.read(ct, n, rl - n); n += rd; } return new RPacket(rep, ct); } return new RPacket(rep, null); } catch(Exception e) { e.printStackTrace(); return null; } } /** sends a request with attached prefix and parameters. Both prefix and cont can be null. Effectively request(a,b,null) and request(a,null,b) are equivalent. @param cmd command - a special command of -1 prevents request from sending anything @param prefix - this content is sent *before* cont. It is provided to save memory copy operations where a small header precedes a large data chunk (usually prefix conatins the parameter header and cont contains the actual data). @param cont contents @param offset offset in cont where to start sending (if <0 then 0 is assumed, if >cont.length then no cont is sent) @param len number of bytes in cont to send (it is clipped to the length of cont if necessary) @return returned packet or null if something went wrong */ public RPacket request(int cmd, byte[] prefix, byte[] cont, int offset, int len) { if (cont!=null) { if (offset>=cont.length) { cont=null; len=0; } else if (len>cont.length-offset) len=cont.length-offset; } if (offset<0) offset=0; if (len<0) len=0; int contlen=(cont==null)?0:len; if (prefix!=null && prefix.length>0) contlen+=prefix.length; byte[] hdr=new byte[16]; setInt(cmd,hdr,0); setInt(contlen,hdr,4); for(int i=8;i<16;i++) hdr[i]=0; try { if (cmd!=-1) { os.write(hdr); if (prefix!=null && prefix.length>0) os.write(prefix); if (cont!=null && cont.length>0) os.write(cont,offset,len); } return response(); } catch(Exception e) { e.printStackTrace(); return null; } } /** sends a request with one string parameter attached @param cmd command @param par parameter - length and DT_STRING will be prepended @return returned packet or null if something went wrong */ public RPacket request(int cmd, String par) { try { byte[] b=par.getBytes(RConnection.transferCharset); int sl=b.length+1; if ((sl&3)>0) sl=(sl&0xfffffc)+4; // make sure the length is divisible by 4 byte[] rq=new byte[sl+5]; int i; for(i=0;iDT_SEXP payload) @param cmd command @param object REXP to send @return returned packet or null if something went wrong */ public RPacket request(int cmd, REXP object) { try { REXPFactory r = new REXPFactory(object); int rl = r.getBinaryLength(); byte[] rq = new byte[rl + ((rl > 0xfffff0) ? 8 : 4)]; setHdr(RTalk.DT_SEXP, rl, rq, 0); r.getBinaryRepresentation(rq, (rl > 0xfffff0) ? 8 : 4); return request(cmd, rq); } catch (Exception e) { e.printStackTrace(); } return null; } /** sends a request with one string parameter attached @param cmd command @param par parameter of the type DT_INT @return returned packet or null if something went wrong */ public RPacket request(int cmd, int par) { try { byte[] rq=new byte[8]; setInt(par,rq,4); setHdr(DT_INT,4,rq,0); return request(cmd,rq); } catch (Exception e) { }; return null; } } Rserve/src/client/java/Rserve/OOBInterface.java0000644000175100001440000000031514531234224021074 0ustar hornikuserspackage org.rosuda.REngine.Rserve; import org.rosuda.REngine.REXP; public interface OOBInterface { public void oobSend(int code, REXP message); public REXP oobMessage(int code, REXP message); } Rserve/src/client/java/Rserve/Makefile0000644000175100001440000000075014531234227017437 0ustar hornikusersRENG_SRC=$(wildcard ../*.java) RSRV_SRC=$(wildcard *.java) $(wildcard protocol/*.java) TARGETS=Rserve.jar all: $(TARGETS) JAVAC=javac JFLAGS=-encoding utf8 -source 1.6 -target 1.6 ../REngine.jar: $(RENG_SRC) make -C .. REngine.jar Rserve.jar: $(RSRV_SRC) ../REngine.jar @rm -rf org $(JAVAC) $(JFLAGS) -d . -cp ../REngine.jar $(RSRV_SRC) jar fc $@ org rm -rf org clean: rm -rf org *~ protocol/*~ $(TARGETS) make -C test clean test: make -C test test .PHONY: clean all test Rserve/src/client/java/Rserve/RFileInputStream.java0000644000175100001440000000711514531234224022036 0ustar hornikuserspackage org.rosuda.REngine.Rserve; // JRclient library - client interface to Rserve, see http://www.rosuda.org/Rserve/ // Copyright (C) 2004 Simon Urbanek // --- for licensing information see LICENSE file in the original JRclient distribution --- import java.io.*; import org.rosuda.REngine.*; import org.rosuda.REngine.Rserve.protocol.*; /** RFileInputStream is an {@link InputStream} to transfer files from Rserve server to the client. It is used very much like a {@link FileInputStream}. Currently mark and seek is not supported. The current implementation is also "one-shot" only, that means the file can be read only once. @version $Id$ */ public class RFileInputStream extends InputStream { /** RTalk class to use for communication with the Rserve */ RTalk rt; /** set to true when {@link #close} was called. Any subsequent read requests on closed stream result in an {@link IOException} or error result */ boolean closed; /** set to true once EOF is reached - or more specifically the first time remore fread returns OK and 0 bytes */ boolean eof; /** tries to open file on the R server, using specified {@link RTalk} object and filename. Be aware that the filename has to be specified in host format (which is usually unix). In general you should not use directories since Rserve provides an own directory for every connection. Future Rserve servers may even strip all directory navigation characters for security purposes. Therefore only filenames without path specification are considered valid, the behavior in respect to absolute paths in filenames is undefined. */ RFileInputStream(RTalk rti, String fn) throws IOException { rt=rti; RPacket rp=rt.request(RTalk.CMD_openFile,fn); if (rp==null || !rp.isOk()) throw new IOException((rp==null)?"Connection to Rserve failed":("Request return code: "+rp.getStat())); closed=false; eof=false; } /** reads one byte from the file. This function should be avoided, since {@link RFileInputStream} provides no buffering. This means that each call to this function leads to a complete packet exchange between the server and the client. Use {@link #read(byte[],int,int)} instead whenever possible. In fact this function calls #read(b,0,1). @return -1 on any failure, or the acquired byte (0..255) on success */ public int read() throws IOException { byte[] b=new byte[1]; if (read(b,0,1)<1) return -1; return b[0]; } /** Reads specified number of bytes (or less) from the remote file. @param b buffer to store the read bytes @param off offset where to strat filling the buffer @param len maximal number of bytes to read @return number of bytes read or -1 if EOF reached */ public int read(byte[] b, int off, int len) throws IOException { if (closed) throw new IOException("File is not open"); if (eof) return -1; RPacket rp=rt.request(RTalk.CMD_readFile,len); if (rp==null || !rp.isOk()) throw new IOException((rp==null)?"Connection to Rserve failed":("Request return code: "+rp.getStat())); byte[] rd=rp.getCont(); if (rd==null) { eof=true; return -1; }; int i=0; while(iRFileOutputStream is an {@link OutputStream} to transfer files from the client to Rserve server. It is used very much like a {@link FileOutputStream}. Currently mark and seek is not supported. The current implementation is also "one-shot" only, that means the file can be written only once. @version $Id$ */ public class RFileOutputStream extends OutputStream { /** RTalk class to use for communication with the Rserve */ RTalk rt; /** set to true when {@link #close} was called. Any subsequent read requests on closed stream result in an {@link IOException} or error result */ boolean closed; /** tries to create a file on the R server, using specified {@link RTalk} object and filename. Be aware that the filename has to be specified in host format (which is usually unix). In general you should not use directories since Rserve provides an own directory for every connection. Future Rserve servers may even strip all directory navigation characters for security purposes. Therefore only filenames without path specification are considered valid, the behavior in respect to absolute paths in filenames is undefined. @param rti RTalk object for communication with Rserve @param fb filename of the file to create (existing file will be overwritten) */ RFileOutputStream(RTalk rti, String fn) throws IOException { rt=rti; RPacket rp=rt.request(RTalk.CMD_createFile,fn); if (rp==null || !rp.isOk()) throw new IOException((rp==null)?"Connection to Rserve failed":("Request return code: "+rp.getStat())); closed=false; } /** writes one byte to the file. This function should be avoided, since {@link RFileOutputStream} provides no buffering. This means that each call to this function leads to a complete packet exchange between the server and the client. Use {@link #write(byte[])} instead whenever possible. In fact this function calls write(b,0,1). @param b byte to write */ public void write(int b) throws IOException { byte[] ba=new byte[1]; write(ba,0,1); } /** writes the content of b into the file. This methods is equivalent to calling write(b,0,b.length). @param b content to write */ public void write(byte b[]) throws IOException { write(b,0,b.length); } /** Writes specified number of bytes to the remote file. @param b buffer containing the bytes to write @param off offset where to start @param len number of bytes to write */ public void write(byte[] b, int off, int len) throws IOException { if (closed) throw new IOException("File is not open"); if (len<0) len=0; boolean isLarge=(len>0xfffff0); byte[] hdr=RTalk.newHdr(RTalk.DT_BYTESTREAM,len); RPacket rp=rt.request(RTalk.CMD_writeFile,hdr,b,off,len); if (rp==null || !rp.isOk()) throw new IOException((rp==null)?"Connection to Rserve failed":("Request return code: "+rp.getStat())); } /** close stream - is not related to the actual RConnection, calling close does not close the RConnection. */ public void close() throws IOException { RPacket rp=rt.request(RTalk.CMD_closeFile,(byte[])null); if (rp==null || !rp.isOk()) throw new IOException((rp==null)?"Connection to Rserve failed":("Request return code: "+rp.getStat())); closed=true; } /** currently (Rserve 0.3) there is no way to force flush on the remote side, hence this function is noop. Future versions of Rserve may support this feature though. At any rate, it is safe to call it. */ public void flush() { } } Rserve/src/client/java/Rserve/src/0000755000175100001440000000000014531234224016561 5ustar hornikusersRserve/src/client/java/Rserve/src/test/0000755000175100001440000000000014531234224017540 5ustar hornikusersRserve/src/client/java/Rserve/src/test/java/0000755000175100001440000000000014531234224020461 5ustar hornikusersRserve/src/client/java/Rserve/src/test/java/org/0000755000175100001440000000000014531234224021250 5ustar hornikusersRserve/src/client/java/Rserve/src/test/java/org/rosuda/0000755000175100001440000000000014531234224022545 5ustar hornikusersRserve/src/client/java/Rserve/src/test/java/org/rosuda/rserve/0000755000175100001440000000000014531234224024053 5ustar hornikusersRserve/src/client/java/Rserve/src/test/java/org/rosuda/rserve/RserveTest.java0000644000175100001440000003545314531234224027036 0ustar hornikuserspackage org.rosuda.REngine.Rserve; import org.junit.After; import org.junit.AfterClass; import org.junit.Assume; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.rosuda.REngine.REXP; import org.rosuda.REngine.REXPDouble; import org.rosuda.REngine.REXPFactor; import org.rosuda.REngine.REXPGenericVector; import org.rosuda.REngine.REXPInteger; import org.rosuda.REngine.REXPList; import org.rosuda.REngine.REXPLogical; import org.rosuda.REngine.REXPMismatchException; import org.rosuda.REngine.REXPRaw; import org.rosuda.REngine.REXPString; import org.rosuda.REngine.REngine; import org.rosuda.REngine.REngineException; import org.rosuda.REngine.RFactor; import org.rosuda.REngine.RList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author cemmersb */ public class RserveTest { /** * Provides some detailed output on test execution. */ private static final Logger LOGGER = LoggerFactory.getLogger(RserveTest.class); /** * Connection object to establish communication to Rserve. */ private RConnection connection = null; /** * Backend agnostic object providing an abstraction to RConnection. */ private REngine engine = null; @BeforeClass static public void startUpRserve() throws RserveException { if (!org.rosuda.REngine.Rserve.StartRserve.checkLocalRserve()) fail("cannot start local Rserve for tests"); } @Before public void createConnection() throws RserveException { connection = new RConnection(); engine = (REngine) connection; } @Test public void versionStringTest() throws RserveException, REXPMismatchException { final String versionString = connection.eval("R.version$version.string").asString(); LOGGER.debug(versionString); assertNotNull(versionString); assertTrue(versionString.contains("R version")); } @Test public void stringAndListRetrievalTest() throws RserveException, REXPMismatchException { final RList list = connection.eval("{d=data.frame(\"huhu\",c(11:20)); lapply(d,as.character)}").asList(); LOGGER.debug(list.toString()); assertNotNull(list); for (Object object : list) { if (object instanceof REXPString) { REXPString rexpString = (REXPString) object; // Check if 10 elements have been received within the REXPString object assertNotNull(rexpString); assertEquals(10, rexpString.length()); // Check the value of the objects if (object.equals(list.firstElement())) { String[] value = rexpString.asStrings(); for (String string : value) { assertNotNull(string); assertEquals("huhu", string); } } else if (object.equals(list.lastElement())) { String[] numbers = rexpString.asStrings(); for (String string : numbers) { assertNotNull(string); assertTrue(11 <= Integer.parseInt(string) && Integer.parseInt(string) <= 20); } } else { // Fail if there are more than first and last element as result fail("There are more elements than expected within the RList object."); } } else { // Fail if the response is other than REXPString fail("Could not find object of instance REXPString."); } } } @Test public void doubleVectorNaNaNSupportTest() throws REngineException, REXPMismatchException { final double r_na = REXPDouble.NA; double x[] = {1.0, 0.5, r_na, Double.NaN, 3.5}; connection.assign("x", x); // Check of Na/NaN can be assigned and retrieved final String nas = connection.eval("paste(capture.output(print(x)),collapse='\\n')").asString(); assertNotNull(nas); assertEquals("[1] 1.0 0.5 NA NaN 3.5", nas); // Check of Na/NaN can be pulled final REXP rexp = connection.eval("c(2.2, NA_real_, NaN)"); assertNotNull(rexp); assertTrue(rexp.isNumeric()); assertFalse(rexp.isInteger()); // Check if NA/NaN can be pulled final boolean nal[] = rexp.isNA(); assertNotNull(nal); assertTrue(nal.length == 3); assertFalse(nal[0]); assertTrue(nal[1]); assertFalse(nal[2]); // Check of NA/NAN can be pulled x = rexp.asDoubles(); assertNotNull(x); assertTrue(x.length == 3); assertTrue(Double.isNaN(x[2])); assertFalse(REXPDouble.isNA(x[2])); assertTrue(REXPDouble.isNA(x[1])); } @Test public void assignListsAndVectorsTest() throws RserveException, REXPMismatchException, REngineException { // Initialize REXP container final REXPInteger rexpInteger = new REXPInteger(new int[]{0, 1, 2, 3}); final REXPDouble rexpDouble = new REXPDouble(new double[]{0.5, 1.2, 2.3, 3.0}); // Assign REXP container to RList final RList list = new RList(); list.put("a", rexpInteger); list.put("b", rexpDouble); // Variables to assign List, Vector and DataFrame final String[] vars = {"x", "y", "z"}; // Assign all three varaiables connection.assign(vars[0], new REXPList(list)); connection.assign(vars[1], new REXPGenericVector(list)); connection.assign(vars[2], REXP.createDataFrame(list)); // Evaluate result for all assignments for (String var : vars) { checkListAndVectorsRexpResult(var, list, rexpInteger, rexpDouble); } } private void checkListAndVectorsRexpResult(String var, RList list, REXPInteger rexpInteger, REXPDouble rexpDouble) throws REXPMismatchException, REngineException { REXP rexp = connection.parseAndEval("x"); assertNotNull(rexp); assertEquals(list.names, rexp.asList().names); try { REXPInteger a = (REXPInteger) rexp.asList().get("a"); REXPDouble b = (REXPDouble) rexp.asList().get("b"); // Check of the result for a corresponds to rexpInteger length assertTrue(a.length() == rexpInteger.length()); assertTrue(b.length() == rexpDouble.length()); // Iterate and check values for (int i = 0; i < rexpInteger.length(); i++) { assertEquals(rexpInteger.asIntegers()[i], a.asIntegers()[i]); } } catch (ClassCastException exception) { LOGGER.error(exception.getMessage()); fail("Could not cast object to the required type."); } } @Test public void logicalsSupportTest() throws RserveException, REngineException, REXPMismatchException { final REXPLogical rexpLogical = new REXPLogical(new boolean[]{true, false, true}); connection.assign("b", rexpLogical); REXP rexp = connection.parseAndEval("b"); assertNotNull(rexp); assertTrue(rexp.isLogical()); assertEquals(rexpLogical.length(), rexp.length()); try { final boolean[] result = ((REXPLogical) rexp).isTRUE(); assertTrue(result[0]); assertFalse(result[1]); assertTrue(result[2]); } catch (ClassCastException exception) { LOGGER.error(exception.getMessage()); fail("Could not cast REXP to REPLogical."); } rexp = connection.parseAndEval("c(TRUE,FALSE,NA)"); assertNotNull(rexp); assertTrue(rexp.isLogical()); assertEquals(rexpLogical.length(), rexp.length()); // Check result values of rexp.isTRUE() boolean result1[] = ((REXPLogical) rexp).isTRUE(); assertTrue(result1[0]); assertFalse(result1[1]); assertFalse(result1[2]); // Check result values of rexp.isFALSE() boolean result2[] = ((REXPLogical) rexp).isFALSE(); assertFalse(result2[0]); assertTrue(result2[1]); assertFalse(result2[2]); // Check result values of rexp.isNA() boolean result3[] = ((REXPLogical) rexp).isNA(); assertFalse(result3[0]); assertFalse(result3[1]); assertTrue(result3[2]); } @Test public void s3ObjectFunctionalityTest() throws REngineException, REXPMismatchException { final REXPInteger rexpInteger = new REXPInteger(new int[]{0, 1, 2, 3}); final REXPDouble rexpDouble = new REXPDouble(new double[]{0.5, 1.2, 2.3, 3.0}); final RList list = new RList(); list.put("a", rexpInteger); list.put("b", rexpDouble); connection.assign("z", REXP.createDataFrame(list)); final REXP rexp = connection.parseAndEval("z[2,2]"); assertNotNull(rexp); assertTrue(rexp.length() == 1); assertTrue(rexp.asDouble() == 1.2); } @Test public void dataFramePassThroughTest() throws REngineException, REXPMismatchException { final REXP dataFrame = connection.parseAndEval("{data(iris); iris}"); connection.assign("df", dataFrame); final REXP rexp = connection.eval("identical(df, iris)"); assertNotNull(rexp); assertTrue(rexp.isLogical()); assertTrue(rexp.length() == 1); assertTrue(((REXPLogical) rexp).isTRUE()[0]); } @Test public void factorSupportTest() throws REngineException, REXPMismatchException { REXP factor = connection.parseAndEval("factor(paste('F',as.integer(runif(20)*5),sep=''))"); assertNotNull(factor); assertTrue(factor.isFactor()); factor = connection.parseAndEval("factor('foo')"); assertNotNull(factor); assertTrue(factor.isFactor()); assertEquals("foo", factor.asFactor().at(0)); connection.assign("f", new REXPFactor(new RFactor(new String[]{"foo", "bar", "foo", "foo", null, "bar"}))); factor = connection.parseAndEval("f"); assertNotNull(factor); assertTrue(factor.isFactor()); factor = connection.parseAndEval("as.factor(c(1,'a','b',1,'b'))"); assertNotNull(factor); assertTrue(factor.isFactor()); } @Test public void lowessTest() throws RserveException, REXPMismatchException, REngineException { final double x[] = connection.eval("rnorm(100)").asDoubles(); final double y[] = connection.eval("rnorm(100)").asDoubles(); connection.assign("x", x); connection.assign("y", y); final RList list = connection.parseAndEval("lowess(x,y)").asList(); assertNotNull(list); assertEquals(x.length, list.at("x").asDoubles().length); assertEquals(y.length, list.at("y").asDoubles().length); } @Test public void multiLineExpressionTest() throws RserveException, REXPMismatchException { final REXP rexp = connection.eval("{ a=1:10\nb=11:20\nmean(b-a) }\n"); assertNotNull(rexp); assertEquals(10, rexp.asInteger()); } @Test public void matrixTest() throws REngineException, REXPMismatchException { final int m = 100; final int n = 100; // Initialize matrix and assign to R environment final double[] matrix = new double[m * n]; int counter = 0; while (counter < m * n) { matrix[counter++] = counter / 100; } connection.assign("m1", matrix); connection.voidEval("m1 <- matrix(m1," + m + "," + n + ")"); // Initialize second matrix and assign to R environment double[][] matrix2 = new double[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { matrix2[i][j] = matrix[i + j * m]; } } connection.assign("m2", REXP.createDoubleMatrix(matrix2)); // Evaluate result final REXP rexp = connection.eval("identical(m1,m2)"); assertNotNull(rexp); assertTrue(rexp.asInteger() == 1); } @Test public void rawVectorSerializationTest() throws RserveException, REXPMismatchException { final byte[] bytes = connection.eval("serialize(ls, NULL, ascii=FALSE)").asBytes(); assertNotNull(bytes); connection.assign("r", new REXPRaw(bytes)); String[] result = connection.eval("unserialize(r)()").asStrings(); assertNotNull(result); assertEquals("r", result[0]); } @Test public void vectorNAHandlingTest() throws REngineException, REXPMismatchException { engine.assign("s", new String[]{"foo", "", null, "NA"}); final int nas[] = engine.parseAndEval("is.na(s)").asIntegers(); assertNotNull(nas); assertEquals(4, nas.length); assertEquals(REXPLogical.FALSE, nas[0]); assertEquals(REXPLogical.FALSE, nas[1]); assertEquals(REXPLogical.TRUE, nas[2]); assertEquals(REXPLogical.FALSE, nas[3]); final String[] result = engine.parseAndEval("c('foo', '', NA, 'NA')").asStrings(); assertNotNull(result); assertEquals(4, result.length); assertNotNull(result[0]); assertNotNull(result[1]); assertEquals("", result[1]); assertNull(result[2]); assertNotNull(result[3]); final REXP rexp = engine.parseAndEval("identical(s, c('foo', '', NA, 'NA'))"); assertNotNull(rexp); assertEquals(REXPLogical.TRUE, rexp.asInteger()); boolean na[] = engine.parseAndEval("s").isNA(); assertNotNull(na); assertEquals(4, na.length); assertFalse(na[0]); assertFalse(na[1]); assertTrue(na[2]); assertFalse(na[3]); } @Test public void encodingSupportTest() throws RserveException, REngineException, REXPMismatchException { // hiragana (literally, in hiragana ;)) final String testString = "ã²ã‚‰ãŒãª"; connection.setStringEncoding("utf8"); connection.assign("s", testString); final REXP rexp = connection.parseAndEval("nchar(s)"); assertNotNull(rexp); assertTrue(rexp.isInteger()); assertEquals(4, rexp.asInteger()); } @Test public void controlCommandTest() throws RserveException, REXPMismatchException { final String key = "rn" + Math.random(); boolean hasCtrl = true; try { connection.serverEval("xXx<-'" + key + "'"); } catch (RserveException re) { // we expect ERR_ctrl_closed if CTRL is disabled, or ERR_unsupported_cmd if this // version has no CTRL command support, so we take that as OK if (re.getRequestReturnCode() == org.rosuda.REngine.Rserve.protocol.RTalk.ERR_ctrl_closed || re.getRequestReturnCode() == org.rosuda.REngine.Rserve.protocol.RTalk.ERR_unsupported_cmd) hasCtrl = false; else // anything else is a fail fail("serverEval failed with "+ re); } Assume.assumeTrue(hasCtrl); // Reconnect connection.close(); engine = (REngine) (connection = new RConnection()); final REXP rexp = connection.eval("xXx"); assertNotNull(rexp); assertTrue(rexp.isString()); assertEquals(1, rexp.length()); assertEquals(key, rexp.asString()); } @After public void closeConnection() { engine.close(); } @AfterClass public static void tearDownRserve() { try { // connect so we can control RConnection connection = new RConnection(); // first use CTRL - it will fail in most cases (sinnce CTRL is likely not enabled) // but is the most reliable try { connection.serverShutdown(); } catch (RserveException e1) { } // this will work on older Rserve versions, may not work on new ones try { connection.shutdown(); } catch (RserveException e2) { } // finally, close the connection connection.close(); } catch (REngineException e3) { } // if this fails, that's ok - nothing to shutdown } } Rserve/src/client/java/Rserve/mkmvn.sh0000755000175100001440000000055314531234224017464 0ustar hornikusers#!/bin/sh BASE="$1" if [ -z "$BASE" ]; then BASE="`pwd`"; fi rm -rf "$BASE/src/main" mkdir -p "$BASE/src/main/java/org/rosuda/REngine/Rserve/protocol" (cd "$BASE/src/main/java/org/rosuda/REngine/Rserve" && ln -s ../../../../../../../*.java .) && \ (cd "$BASE/src/main/java/org/rosuda/REngine/Rserve/protocol" && ln -s ../../../../../../../../protocol/*.java .) Rserve/src/client/java/Rserve/test/0000755000175100001440000000000014531234224016751 5ustar hornikusersRserve/src/client/java/Rserve/test/test.java0000644000175100001440000003417114531234224020601 0ustar hornikusersimport org.rosuda.REngine.*; import org.rosuda.REngine.Rserve.*; class TestException extends Exception { public TestException(String msg) { super(msg); } } public class test { public static void main(String[] args) { try { RConnection c = new RConnection(); // REngine is the backend-agnostic API -- using eng instead of c makes sure that we don't use Rserve extensions inadvertently REngine eng = (REngine) c; System.out.println(">>" + c.eval("R.version$version.string").asString() + "<<"); { System.out.println("* Test string and list retrieval"); RList l = c.eval("{d=data.frame(\"huhu\",c(11:20)); lapply(d,as.character)}").asList(); int cols = l.size(); int rows = l.at(0).length(); String[][] s = new String[cols][]; for (int i=0; i0)?args[0]:"127.0.0.1"); // if Cairo is installed, we can get much nicer graphics, so try to load it if (c.parseAndEval("suppressWarnings(require('Cairo',quietly=TRUE))").asInteger()>0) device="CairoJPEG"; // great, we can use Cairo device else System.out.println("(consider installing Cairo package for better bitmap output)"); // we are careful here - not all R binaries support jpeg // so we rather capture any failures REXP xp = c.parseAndEval("try("+device+"('test.jpg',quality=90))"); if (xp.inherits("try-error")) { // if the result is of the class try-error then there was a problem System.err.println("Can't open "+device+" graphics device:\n"+xp.asString()); // this is analogous to 'warnings', but for us it's sufficient to get just the 1st warning REXP w = c.eval("if (exists('last.warning') && length(last.warning)>0) names(last.warning)[1] else 0"); if (w.isString()) System.err.println(w.asString()); return; } // ok, so the device should be fine - let's plot - replace this by any plotting code you desire ... c.parseAndEval("data(iris); attach(iris); plot(Sepal.Length, Petal.Length, col=unclass(Species)); dev.off()"); // There is no I/O API in REngine because it's actually more efficient to use R for this // we limit the file size to 1MB which should be sufficient and we delete the file as well xp = c.parseAndEval("r=readBin('test.jpg','raw',1024*1024); unlink('test.jpg'); r"); // now this is pretty boring AWT stuff - create an image from the data and display it ... Image img = Toolkit.getDefaultToolkit().createImage(xp.asBytes()); Frame f = new Frame("Test image"); f.add(new PlotDemo(img)); f.addWindowListener(new WindowAdapter() { // just so we can close the window public void windowClosing(WindowEvent e) { System.exit(0); } }); f.pack(); f.setVisible(true); // close RConnection, we're done c.close(); } catch (RserveException rse) { // RserveException (transport layer - e.g. Rserve is not running) System.out.println(rse); } catch (REXPMismatchException mme) { // REXP mismatch exception (we got something we didn't think we get) System.out.println(mme); mme.printStackTrace(); } catch(Exception e) { // something else System.out.println("Something went wrong, but it's not the Rserve: " +e.getMessage()); e.printStackTrace(); } } Image img; public PlotDemo(Image img) { this.img=img; MediaTracker mediaTracker = new MediaTracker(this); mediaTracker.addImage(img, 0); try { mediaTracker.waitForID(0); } catch (InterruptedException ie) { System.err.println(ie); System.exit(1); } setSize(img.getWidth(null), img.getHeight(null)); } public void paint(Graphics g) { g.drawImage(img, 0, 0, null); } } Rserve/src/client/java/Rserve/test/jt.java0000644000175100001440000000205314531234224020231 0ustar hornikusersimport java.io.*; import org.rosuda.REngine.*; import org.rosuda.REngine.Rserve.*; public class jt { public static void main(String[] args) { try { RConnection c = new RConnection((args.length>0)?args[0]:"127.0.0.1"); BufferedReader ir=new BufferedReader(new InputStreamReader(System.in)); String s=null; System.out.print("> "); while ((s=ir.readLine()).length() > 0) { if (s.equals("shutdown")) { System.out.println("Sending shutdown request"); c.shutdown(); System.out.println("Shutdown successful. Quitting console."); return; } else { REXP rx = c.parseAndEval(s); System.out.println("result(debug): "+rx.toDebugString()); } System.out.print("> "); } } catch (RserveException rse) { System.out.println(rse); /* } catch (REXPMismatchException mme) { System.out.println(mme); mme.printStackTrace(); */ } catch (Exception e) { e.printStackTrace(); } } } Rserve/src/client/java/Rserve/test/Makefile0000644000175100001440000000213114531234227020411 0ustar hornikusersJAVA=java JAVAC=javac JFLAGS+=-encoding utf8 -source 1.6 -target 1.6 all: test PlotDemo.class StartRserve.class ../Rserve.jar: ../../REngine.jar $(MAKE) -C .. Rserve.jar ../../REngine.jar: $(MAKE) -C ../.. REngine.jar test: test.class ../Rserve.jar ../../REngine.jar $(JAVA) -cp ../Rserve.jar:../../REngine.jar:. test test.class: test.java ../Rserve.jar ../../REngine.jar $(JAVAC) $(JFLAGS) -d . -cp ../Rserve.jar:../../REngine.jar:. test.java PlotDemo.class: PlotDemo.java ../Rserve.jar ../../REngine.jar $(JAVAC) $(JFLAGS) -d . -cp ../Rserve.jar:../../REngine.jar:. $< PlotDemo: PlotDemo.class ../Rserve.jar ../../REngine.jar $(JAVA) -cp ../Rserve.jar:../../REngine.jar:. $@ jt: jt.class ../Rserve.jar ../../REngine.jar $(JAVA) -cp ../Rserve.jar:../../REngine.jar:. $@ jt.class: jt.java ../Rserve.jar ../../REngine.jar $(JAVAC) $(JFLAGS) -d . -cp ../Rserve.jar:../../REngine.jar:. jt.java StartRserve.class: StartRserve.java ../Rserve.jar ../../REngine.jar $(JAVAC) $(JFLAGS) -d . -cp ../Rserve.jar:../../REngine.jar:. StartRserve.java clean: rm -rf org *~ *.class .PHONY: test all clean Rserve/src/client/java/Rserve/test/StartRserve.java0000644000175100001440000001535314531234224022107 0ustar hornikusersimport java.io.*; import java.util.*; import org.rosuda.REngine.Rserve.RConnection; /** helper class that consumes output of a process. In addition, it filter output of the REG command on Windows to look for InstallPath registry entry which specifies the location of R. */ class StreamHog extends Thread { InputStream is; boolean capture; String installPath; StreamHog(InputStream is, boolean capture) { this.is = is; this.capture = capture; start(); } public String getInstallPath() { return installPath; } public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = null; while ( (line = br.readLine()) != null) { if (capture) { // we are supposed to capture the output from REG command int i = line.indexOf("InstallPath"); if (i >= 0) { String s = line.substring(i + 11).trim(); int j = s.indexOf("REG_SZ"); if (j >= 0) s = s.substring(j + 6).trim(); installPath = s; System.out.println("R InstallPath = "+s); } } else System.out.println("Rserve>" + line); } } catch (IOException e) { e.printStackTrace(); } } } /** simple class that start Rserve locally if it's not running already - see mainly checkLocalRserve method. It spits out quite some debugging outout of the console, so feel free to modify it for your application if desired.

Important: All applications should shutdown every Rserve that they started! Never leave Rserve running if you started it after your application quits since it may pose a security risk. Inform the user if you started an Rserve instance. */ public class StartRserve { /** shortcut to launchRserve(cmd, "--no-save --slave", "--no-save --slave", false) */ public static boolean launchRserve(String cmd) { return launchRserve(cmd, "--no-save --slave","--no-save --slave",false); } /** attempt to start Rserve. Note: parameters are not quoted, so avoid using any quotes in arguments @param cmd command necessary to start R @param rargs arguments are are to be passed to R @param rsrvargs arguments to be passed to Rserve @return true if Rserve is running or was successfully started, false otherwise. */ public static boolean launchRserve(String cmd, String rargs, String rsrvargs, boolean debug) { try { Process p; boolean isWindows = false; String osname = System.getProperty("os.name"); if (osname != null && osname.length() >= 7 && osname.substring(0,7).equals("Windows")) { isWindows = true; /* Windows startup */ p = Runtime.getRuntime().exec("\""+cmd+"\" -e \"library(Rserve);Rserve("+(debug?"TRUE":"FALSE")+",args='"+rsrvargs+"')\" "+rargs); } else /* unix startup */ p = Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", "echo 'library(Rserve);Rserve("+(debug?"TRUE":"FALSE")+",args=\""+rsrvargs+"\")'|"+cmd+" "+rargs }); System.out.println("waiting for Rserve to start ... ("+p+")"); // we need to fetch the output - some platforms will die if you don't ... StreamHog errorHog = new StreamHog(p.getErrorStream(), false); StreamHog outputHog = new StreamHog(p.getInputStream(), false); if (!isWindows) /* on Windows the process will never return, so we cannot wait */ p.waitFor(); System.out.println("call terminated, let us try to connect ..."); } catch (Exception x) { System.out.println("failed to start Rserve process with "+x.getMessage()); return false; } int attempts = 5; /* try up to 5 times before giving up. We can be conservative here, because at this point the process execution itself was successful and the start up is usually asynchronous */ while (attempts > 0) { try { RConnection c = new RConnection(); System.out.println("Rserve is running."); c.close(); return true; } catch (Exception e2) { System.out.println("Try failed with: "+e2.getMessage()); } /* a safety sleep just in case the start up is delayed or asynchronous */ try { Thread.sleep(500); } catch (InterruptedException ix) { }; attempts--; } return false; } /** checks whether Rserve is running and if that's not the case it attempts to start it using the defaults for the platform where it is run on. This method is meant to be set-and-forget and cover most default setups. For special setups you may get more control over R with <launchRserve instead. */ public static boolean checkLocalRserve() { if (isRserveRunning()) return true; String osname = System.getProperty("os.name"); if (osname != null && osname.length() >= 7 && osname.substring(0,7).equals("Windows")) { System.out.println("Windows: query registry to find where R is installed ..."); String installPath = null; try { Process rp = Runtime.getRuntime().exec("reg query HKLM\\Software\\R-core\\R"); StreamHog regHog = new StreamHog(rp.getInputStream(), true); rp.waitFor(); regHog.join(); installPath = regHog.getInstallPath(); } catch (Exception rge) { System.out.println("ERROR: unable to run REG to find the location of R: "+rge); return false; } if (installPath == null) { System.out.println("ERROR: canot find path to R. Make sure reg is available and R was installed with registry settings."); return false; } return launchRserve(installPath+"\\bin\\R.exe"); } return (launchRserve("R") || /* try some common unix locations of R */ ((new File("/Library/Frameworks/R.framework/Resources/bin/R")).exists() && launchRserve("/Library/Frameworks/R.framework/Resources/bin/R")) || ((new File("/usr/local/lib/R/bin/R")).exists() && launchRserve("/usr/local/lib/R/bin/R")) || ((new File("/usr/lib/R/bin/R")).exists() && launchRserve("/usr/lib/R/bin/R")) || ((new File("/usr/local/bin/R")).exists() && launchRserve("/usr/local/bin/R")) || ((new File("/sw/bin/R")).exists() && launchRserve("/sw/bin/R")) || ((new File("/usr/common/bin/R")).exists() && launchRserve("/usr/common/bin/R")) || ((new File("/opt/bin/R")).exists() && launchRserve("/opt/bin/R")) ); } /** check whether Rserve is currently running (on local machine and default port). @return true if local Rserve instance is running, false otherwise */ public static boolean isRserveRunning() { try { RConnection c = new RConnection(); System.out.println("Rserve is running."); c.close(); return true; } catch (Exception e) { System.out.println("First connect try failed with: "+e.getMessage()); } return false; } /** just a demo main method which starts Rserve and shuts it down again */ public static void main(String[] args) { System.out.println("result="+checkLocalRserve()); try { RConnection c=new RConnection(); c.shutdown(); } catch (Exception x) {}; } } Rserve/src/client/java/Rserve/RSession.java0000644000175100001440000000230714531234224020404 0ustar hornikuserspackage org.rosuda.REngine.Rserve; import org.rosuda.REngine.Rserve.protocol.RPacket; import org.rosuda.REngine.Rserve.protocol.RTalk; public class RSession implements java.io.Serializable { // serial version UID should only change if method signatures change // significantly enough that previous versions cannot be used with // current versions private static final long serialVersionUID = -7048099825974875604l; String host; int port; byte[] key; transient RPacket attachPacket=null; // response on session attach int rsrvVersion; protected RSession() { // default no-args constructor for serialization } RSession(RConnection c, RPacket p) throws RserveException { this.host=c.host; this.rsrvVersion=c.rsrvVersion; byte[] ct = p.getCont(); if (ct==null || ct.length!=32+3*4) throw new RserveException(c, "Invalid response to session detach request."); this.port = RTalk.getInt(ct, 4); this.key=new byte[32]; System.arraycopy(ct, 12, this.key, 0, 32); } /** attach/resume this session */ public RConnection attach() throws RserveException { RConnection c = new RConnection(this); attachPacket = c.rt.request(-1); return c; } } Rserve/src/client/java/Rserve/StartRserve.java0000644000175100001440000001675514531234224021137 0ustar hornikuserspackage org.rosuda.REngine.Rserve; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * helper class that consumes output of a process. In addition, it filters output * of the REG command on Windows to look for InstallPath registry entry which * specifies the location of R. */ class StreamHog extends Thread { InputStream is; boolean capture; String installPath; StreamHog(InputStream is, boolean capture) { this.is = is; this.capture = capture; start(); } public String getInstallPath() { return installPath; } public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = null; while ((line = br.readLine()) != null) { if (capture) { // we are supposed to capture the output from REG command int i = line.indexOf("InstallPath"); if (i >= 0) { String s = line.substring(i + 11).trim(); int j = s.indexOf("REG_SZ"); if (j >= 0) { s = s.substring(j + 6).trim(); } installPath = s; System.out.println("StartRserve: R InstallPath = " + s); } } else { System.out.println("StartRserve: Rserve>" + line); } } } catch (IOException e) { e.printStackTrace(); } } } /** * simple class that start Rserve locally if it's not running already - see * mainly checkLocalRserve method. It spits out quite some * debugging outout of the console, so feel free to modify it for your * application if desired.

* Important: All applications should shutdown every Rserve that they * started! Never leave Rserve running if you started it after your application * quits since it may pose a security risk. Inform the user if you started an * Rserve instance. */ public class StartRserve { /** * shortcut to * launchRserve(cmd, "--no-save --slave", "--no-save --slave", false) */ public static boolean launchRserve(String cmd) { return launchRserve(cmd, "--no-save --slave", "--no-save --slave", false); } /** * attempt to start Rserve. Note: parameters are not quoted, so avoid * using any quotes in arguments * * @param cmd command necessary to start R * @param rargs arguments are are to be passed to R * @param rsrvargs arguments to be passed to Rserve * @return true if Rserve is running or was successfully started, * false otherwise. */ public static boolean launchRserve(String cmd, String rargs, String rsrvargs, boolean debug) { try { Process p; boolean isWindows = false; String osname = System.getProperty("os.name"); if (osname != null && osname.length() >= 7 && osname.substring(0, 7).equals("Windows")) { isWindows = true; /* Windows startup */ p = Runtime.getRuntime().exec("\"" + cmd + "\" -e \"library(Rserve);Rserve(" + (debug ? "TRUE" : "FALSE") + ",args='" + rsrvargs + "')\" " + rargs); } else /* unix startup */ { p = Runtime.getRuntime().exec(new String[]{ "/bin/sh", "-c", "echo 'library(Rserve);Rserve(" + (debug ? "TRUE" : "FALSE") + ",args=\"" + rsrvargs + "\")'|" + cmd + " " + rargs }); } System.out.println("StartRserve: waiting for Rserve to start ... (" + p + ")"); // we need to fetch the output - some platforms will die if you don't ... StreamHog errorHog = new StreamHog(p.getErrorStream(), false); StreamHog outputHog = new StreamHog(p.getInputStream(), false); if (!isWindows) /* on Windows the process will never return, so we cannot wait */ { p.waitFor(); } System.out.println("StartRserve: call terminated, let us try to connect ..."); } catch (Exception x) { System.out.println("StartRserve: failed to start Rserve process with " + x.getMessage()); return false; } int attempts = 5; /* try up to 5 times before giving up. We can be conservative here, because at this point the process execution itself was successful and the start up is usually asynchronous */ while (attempts > 0) { try { RConnection c = new RConnection(); c.close(); return true; } catch (Exception e2) { System.out.println("StartRserve: Try failed with: " + e2.getMessage()); } /* a safety sleep just in case the start up is delayed or asynchronous */ try { Thread.sleep(500); } catch (InterruptedException ix) { }; attempts--; } return false; } /** * checks whether Rserve is running and if that's not the case it attempts to * start it using the defaults for the platform where it is run on. This * method is meant to be set-and-forget and cover most default setups. For * special setups you may get more control over R with * <launchRserve instead. */ public static boolean checkLocalRserve() { if (isRserveRunning()) { return true; } String osname = System.getProperty("os.name"); if (osname != null && osname.length() >= 7 && osname.substring(0, 7).equals("Windows")) { System.out.println("StartRserve: Windows: query registry to find where R is installed ..."); String installPath = null; try { Process rp = Runtime.getRuntime().exec("reg query HKLM\\Software\\R-core\\R"); StreamHog regHog = new StreamHog(rp.getInputStream(), true); rp.waitFor(); regHog.join(); installPath = regHog.getInstallPath(); } catch (Exception rge) { System.out.println("ERROR: unable to run REG to find the location of R: " + rge); return false; } if (installPath == null) { System.out.println("ERROR: canot find path to R. Make sure reg is available and R was installed with registry settings."); return false; } return launchRserve(installPath + "\\bin\\R.exe"); } return (launchRserve("R") || /* try some common unix locations of R */ ((new File("/Library/Frameworks/R.framework/Resources/bin/R")).exists() && launchRserve("/Library/Frameworks/R.framework/Resources/bin/R")) || ((new File("/usr/local/lib/R/bin/R")).exists() && launchRserve("/usr/local/lib/R/bin/R")) || ((new File("/usr/lib/R/bin/R")).exists() && launchRserve("/usr/lib/R/bin/R")) || ((new File("/usr/local/bin/R")).exists() && launchRserve("/usr/local/bin/R")) || ((new File("/sw/bin/R")).exists() && launchRserve("/sw/bin/R")) || ((new File("/usr/common/bin/R")).exists() && launchRserve("/usr/common/bin/R")) || ((new File("/opt/bin/R")).exists() && launchRserve("/opt/bin/R"))); } /** * check whether Rserve is currently running (on local machine and default * port). * * @return true if local Rserve instance is running, * false otherwise */ public static boolean isRserveRunning() { try { RConnection c = new RConnection(); c.close(); return true; } catch (Exception e) { System.out.println("StartRserve: first connect try failed with: " + e.getMessage()); } return false; } /** * just a demo main method which starts Rserve and shuts it down again */ public static void main(String[] args) { System.out.println("result=" + checkLocalRserve()); try { RConnection c = new RConnection(); c.shutdown(); } catch (Exception x) { }; } } Rserve/src/client/java/Rserve/package-info.java0000644000175100001440000000017514531234224021164 0ustar hornikusers/** * REngine-based interface to Rserve */ package org.rosuda.REngine.Rserve ; Rserve/src/client/java/Rserve/Rserve.jar0000644000175100001440000010604314531234227017745 0ustar hornikusersPKé|W META-INF/þÊPKPKé|WMETA-INF/MANIFEST.MFóMÌËLK-.Ñ K-*ÎÌϳR0Ô3àår.JM,IMÑuª Eô M4\R“2ó4y¹x¹PK¸o67PK é|Worg/PK é|W org/rosuda/PK é|Worg/rosuda/REngine/PK é|Worg/rosuda/REngine/Rserve/PKé|W,org/rosuda/REngine/Rserve/OOBInterface.class}½ Â@„g£&þ4ú¶¢‚• P"Äö’¬!!ÜÁæá,|J¼tê4³ß ìóuX`  O´NbVa< wÚäÂh{ˤ8nT^(v~>¬f'Bß‘{¶VæLXþƒ^ÜH¬o&åmQ¹‘Q­Cues‘)ÏKYKÂä[ײ©Y|Ò„aËJª\DIÉéÕ'<4òÚ„Ú€ó|—¸G›Ý7PK¢Ÿ(©PKé|W+org/rosuda/REngine/Rserve/StartRserve.classWùw×þžÏX ÆljÖ‰I°ll«!Z±$l0¶Êbã6ËcIFš³`œ„6¤;´IšÅ$!KIœÅiKÚÈ.IÚR ¤û~NèÐzòSO[÷¾É–Œ Ñ‘Þ›÷½ûîòÞwï<]ûï…÷¬Ã_ØEDˆ‰@Å`Õˆó&!"Éû¡â°€Tó¸xš÷š]DFĆ“c´1,☈÷‹x@ă|æx9©HÄ .û°ˆ/ðe<"àd=x4€Õø ú*o¾&âë¾!â›Ôã[NÐ…7§E|ÛçÃ>à;xLÀã<‚'D|WÄ“\ÑS¼yZÄ3"FEœá³ÏŠxNÀó"ΰ/ðæE/‰xYÄ÷DœñŠˆWEŒ‰x˿ν|ƒ|SÀ¸€·Ê6'µ¤µ•Áª?ÀàÛ®¨ :’šºÇN÷«F·ÒŸ"DJ)¶KDMÕ8JêPÇrT §-¤ßTßË)¤—/žße)±ÃJƱ)àû~ à‡ •±„;ܡǔTÞr—V,Hš.µ5ôPi%©1T‡•p té¶S[“<¨J2hX®†f..a/ö1,ljÒô&S9ªÊMMfŠz ]ØÏ èf³¦¤É·óÞÆ$üïHÈb‚æ&µ}Ø”0‰w%\ÀÃ’¹>l³“©Õ``µ~‚‹ +jå&U®M%û Å ¹ÎÔorûÔÝßÂào½»£‹z¡Q1âæ–:š¨«¯•%¼‡÷%|€ŸR4s‘t¸?©…̓§)F¶ÔXB—ënh+§¼–”×Ö×=H^Ê\÷Ï$ü—š ¶+"+I‹ŒÈƒº!»˜lé²ÉEäææf9Äüé¨pYÂ\eX­ñ°¡›ö€޶hqbYØ]Ë]V•ô.=.áC\ãñ‘„_ò§_á†E¶‰)ÙRtRS,u QN©–l›²eŒp'bº¦©1Ç †E³ÛÒr,¦f¬¤N¹½Hß B|˜õ?OÆÐcªiÊÃI+A;ñk¼ÏpÛCˆnwí’ ¿Á!†•EVºÉ»œ%®1" ø­„ßá÷$8ëd›Fv†âšñWBW×R¤.Ç·ˆ|ÄVI³¡Æ“fniJN¨†*Gå¤)'5Š+Å ;[Âes«vµwtöuéƒÖ°b¨}Ѧ˜Î; À> ä¯o‰F÷F#²­ñ¬äÚ [“£-;g Y UNQrrOe}P&a†XnYLÑtË•Ë(´´(Ú,w*‡UÙ´É?î yHá'SŽ…$£Ä®B¯˜ ÐT-Î<“" ôÁû¢Íê1'E»‰nQ*VÎn&õ°›æáp‡Ëøp«AÉ;¬‡Íp´y0?GUÓ© ¦“.QN¾«þÄ·¼:l›F˜G— SÞ„£®e›;QrdsPyØÎ?/t¦cz:­ky,Ö3V~ÐXÌɤaZ3T¶ær‡²ÕPM;em‘ЋC<Ùþ,á/¼|Ý„¢Š ÆÞþ!²B>ÎBTR­dšÄ•(¥E’ûÜ4)®@#¦¥¦æÅU‹æ3ªa0¬)õÚ(¥½,¥jq+áÔù6ÚFÓî7s5­:ÔÖVzzÄVR朗“™ór /3QU… •ä`®EÉdTm€¡éùš+è´P´ô|Ù]*é XJU¸îÿ(Îm'-•|‹•õê6_UGžùûHÖrkê¦9±äwä&±,*¡†—ᣔvƒ×?½]+h‡[ C7òK–äw‚tµi{Ö¥šPɉ޼š,ó—M«n¸gØI!+q:C,¥›ÅDîNÐ :=¿™RÕ íyh·s¯ÒùµÀUìT•} §W™zŒj qfy¨÷¦‡k&l‹ª­†[èµÇ¹©•ñ뵟§Ñ êõþ† °óü"‡hN؆r^r¢µð9h !è z¼“ðŽÏ‘osä÷»òž -'Þ þ oþHYMÙeÄjʲ(«^BOM™·RÈBŠY”¢Í·Á?‰ÀæõL@ ÎÏ¢¢~ÁÔ¬…¬ƒ?¸CAjùÃ"jÖÒ/‹ÅYTE|cè&eQÝã .éêñ?ÕÕãÏ«¬¹^ÓÒ¼¦eysËgUve±"â{+ó V^ãËBÞ’7Z;…Õ=»Õ;Û"B~¸ÆŠUþ3(ç㺃¤'¢c¸µHiCNéLµÞqqƒ¯Êw;¦ÐH2M?‹æƒ¾ñˆ¿`e˜¯ô®\ŒOObEñŸôMM_¤CòÒ!T²E¨g›Yë¤>Å fãxœÃ»+©í!¹^pˆnù}t×þ"t܇ÓèÇõІ¿#Ž ÿ É<b"R¬ÒœfUÐØ:èl=ް0ÙfجGY;†Éâ1¶#,…ãÌÀ ²üÆÃì8ýé8@–?BÅ4ÑSPí~‰’ÔÂ#à €yÓÄ§ëæ¼î=®šFÝõó~gþú²©(+!dk ¥ô8rïN«é;MÛã+VS/ÿ¶Ÿâî`~b<½ÖÜ `Ó”1>êÛ'±~~߸“í —qª!—'ŠRÀæù #ë 7§;9¡ˆ¡k|ħ=œHMYl¤ßg;ưª³€Ÿs¹,çI´ö æs…g”“â\ nr 3‰ÍãÁ-ÔžÁ¹)lí Þ9»²¸{ó‚w:ð)Þ6 osࣼ}ÞîÀ÷:ðŽYx‡ïrà–Y¸ÅowàÖY¸Õ—:ðÎ<¼ ¸“àQ”Û>b3]ípÃR—½–S{ŠŠÍiˆô´¡ÓŸê'HòIlÁSا©æ=CÅi”Ö>O«ÏÇŸ…ç0Œ³x/༈Gñ2!çð^Á%¼Š¿a ÿÄk¬¯3o³ßd»iþ€S+ÄiòÀã²Á!òùÿBõÊjç㽋.üœ+Ÿå/’͹”nopº½àw¹5¨°8k*°`&Þ¥)0A±Nb>Þ¥™ ¨¤mÄEÇ/*Å{ɲýÊa×všl{¨o,°ÕFF&±;‹ö|sÜê ãÄ+_ÇyZ»ŒR«aŽåK„^¦ÿôWhîCš½Šµ¸æXàâ–iá½4ôà¾ÿPK”-I* àPK é|W#org/rosuda/REngine/Rserve/protocol/PKé|W.org/rosuda/REngine/Rserve/protocol/RTalk.class•˜y|TÕÇÏÍ,o2È#d€ÉDp˜L‹F´d²À$¢¸4™Ì<’d^œyˆZ«­µ‹U»×B¥ØX— M«mµµ­]Ýênݪ¶Ÿþë‚éïÜy3yÆøù?òæ~Ͻ÷ܳÜ{î{yâã‡Çˆh½ç¦ÓéÁBrÑa~±“ d÷Æÿ§Ð¨}GùqÌ)„ããLñãa~çÇ 7ý‚ÆÜôKú·QèQ7•Ò¯ú›æÐoÝô=ÎßñèßÒô7ÝKäe>RèOnª 'ùñg~üE¡¿ r6vt†[;‰°  z2mD“ÆÖh_Fƒ±$)Ѱ¡.ÂX ¨ØØva}s lYA{G$ܺžvh ~[G„Mu-,tdµ´7]¼™Ñ-Ȭ‹Dê¶1e¹¹.²^*] ¥ -}zO")ÈÃíA=oŒöa(£&›²'Ý›1âú. t3¶5Ä¢}}¬¦8/I$†­¡-1§èZr]¢Oz¨ šÉ²XJ‹ZN:‹ƒÁÒ>=–˜Ó12ž“Í6îJ%&f—š:SZ¿>˜—zIƒ5#‰Js`4Nô$sÒ‚f™ë3Û·k©öÄ•RÃ>AÅfGS2¦ÇÉ_kŽkF4ÖÛ®A™žäŽe‚J':´øV3ˆÜ·Üœ5&MZaz3R}¹Áõ¹ AÖ®gR1iN“ 5/5³ÀòF˜Ù‰tF3Foçö(ܳ¸ÎÇôd²³;¥ïÔ³"–$’ƒ±~9¨Á"ˆ¦B¦ˆ–Jé)³+Ü&‰G¯ƒ­,Jê†L*ËÖÃ1¹z,§à{2‘]ƒ ÙÜ‘I¦3zÊÐâ¹Uæi™äÎ$œÈ‰7šªâQ#Ú‰L¦¶÷黸c“ îлwh1£ÓÐõÎî„ÌE3"%{2°h{g¿ÖÏÒ–œëˆTvOIý­ ‹ÓÙèwvgÒC,ßœ[WæÍÂ-¦¿ñD:ÚmÊ¢yÛ£ƒÈrw›†ÄRCFS.`1SsZ‹e°c‡Ø+ÒÔŽ=(pòIávgÛ&FÔ—DLfF!PäÙj«·Qv¡‰ÞÚVy6sK;ŠBA%OH¤y›wÀÆš„^NdŒv'©5:utÎÉw¶e k¯s Ÿß - L9êyK¶ ²7èq áiN$µÖL·–êàð@%NP8iÀÊ@øÒú0eц8ö˜+–2®‡íˆÿΖ耜¦Ðß0,©í’ܶäR g©Ë0§±¤™7·Â =Ù“ëÃ~RÒ9‘Øh.­¤´+2Z*já%Ízª§&¥§3ñhM¤)‰¨ÕDÒZjP«Hé†Óûj"›a—f 8ËÙiÎq¥´ô*½Æ!æÜei/w6›W§ëZ] œMm_4ÙSƒ´¢Ü­ž–…þ.hÔL5ÅvºÚþÁþOÛw¶bò5ˆtDûv.e¿ûܰS¬"‘Œ¦†PëzŒ^px=7/h¨4ZÒˆ²m´o¥§ãªYE>ZHgàRXį”´|¦…à%‚«,W[x)¸ÆÂËÀË-¼¼ÒÂgÏž´~í¤õÏ™´þ¹“Ö?ÏÂìÏj ¯Ÿoá ÀŸ³ðZp…ëÁ n7Yxx½…7€ÃÞÞdáfp‹…[ÁmÞ Þbá¸ÝÂà -¼|‘…/o³ð%àK-|ør Ü9i~—…£àîIóc“ôÇ-¬·[¸Ükáx‡…w‚û,ÜNZXXø pÊÂi°aá xлÀ»-<¾ÒÂW¯¶ðÀ{,| x¯…÷¯µðÁ×Yøzð—,üeð þ øF ü5 O\:ü¥É÷¡ïºÏoj0F~?’V¡‚`èÙîçÏAú6ž3e÷²#´3ÚB¾„ÌÉ—AʽgUÍ/›Eã{n@ ]bߣº®Ì“cªNs:4±Ââá4yø2<€€¯D  ùâ3Wzcìøí •Ë•ü%Ê!r©k‡ÉnÛ Õ6*÷›&ÈvÞ„,åL° 9s1ËLCäÛ§Êï‘d ƒäæ2™ªEHÑJ¤¨©YÔ\ˆ”\†”ÄŠÿäx|ñ—àóX(ôC”J~ŠqùÁœ•Ø¥D|ˆãVH·ÑL/ÍxúL÷\pO9áj)ó‡lǨð¢ÐHÞ¤lZn¡bdr.&ó²*(âÏi~W05®‡ÆNsп’ÃôÛ»dCuíÞô;LPœ&ÌÛ½÷ž|rœüy éÇy¥7™J» T]»g?ÕæÕN¨tYUJýÊ„þaZ| S&P"“? +îDŽ æ§9×t³Ç·ÓAÓ¸ uâwIÐŒÜ×—RÑ5u¼vαϱ«•CüS¹Ÿ÷æ}Í®òуHõaÜG ú'tÈT}.úyļ VtC¨üͨP+¯B‹õϘ|h‚¦‡‘ãÞ‹³ZÎDŸüGˆ ™ úC£4s$?Ñ-û–yTN6'uÃ'ùˆ _„l¡ÇI± “#46JÅ{"›«'dd–SÁ8Íà­çâ-Gn8xÛ“˜;ób|öñ»¹^T²2gPŒ’:2i;<)ÇÞ•+Ö ¤7T=N>U=áj¦‚ªQšuþ|U=@1R…íë>¿JÁó‚òý´¹ü„k•ÝVë¨SÕCäåŸ8HU}v›×qŒJ¼ŽòƒTÁz|v´½Žø(Í®uz^gW­cxüµãTºm¾Ï~”¼#²)¸Õ‚`Î#Ù3„ó:õdPþîBÑåßl .A‹è)Dùi$ø$þYšGÏaôóTI/ ñ/â ¿„âø2^(^Á À«¸È_ÃÅû:.Ó77qñ¼…jø64¿Íï¢2¼‡jðóü;ÊÆñjÂÑ•±•‡ž*ß'÷8,ÈŠ â92Ëw›‘Ü‹ 1¬ú1ZèµWÝNE¢q¦R¯£zÌk"·ü­uxí·‘ÓV‹ðÈ_Gµ¹)¼ŽZgè1*í'·×ëªurVV)~Ÿ‚<Ìð:} 21CuÕº¼.U=HÅ>ÅëBÑs‰áñÿù Ð DÞæSFi4©¬©ˆ%ï<˜VZ A1 ª½X~”|ÁQ*Yåò¹²ñ¸ãðä⽕¼x¾ï> Ùô!®§“x±ú/gãüÿ?ڌݷUÐåÂFš°ÓÕÂIû…‹n…ž›‰"3舘IGE1ªŒu9yf«Š¢Ô‰h–8Ió8ÖPIEic.¼÷˜›ú=ÀU=@þQšßZ=fïBíNÔ0×^R¾G‘ìêB¸6ì7gõØA*õaÛ)]Õ^çʎ뜈ѻ^§×~fe嶬ð¿Š×îsÈ:ôû|¬[«sñ ¼¸ôæã± ‚DŽžŸfŠùT!Êi±8–‰JZß:±€6ˆÓ“3¨K,¢^±˜âLêK¤Ï Éq’*ØÑ“äæŸ¹¥ã4+wªïØX?77–Ë,Š[ŽSŶÐQ:-«dWáõÄU#ÝVÝy?ªá µ”Lé[¯¥9ßó+¨P¬¤bq-gÓRQKõâÚ(Î¥MâÀ" `‹°ÈXä,òQù‹Ð|€Eh>À"4@–@G4‚$ d2j0€ ‚ˆPƒA_ƒ¾}Q‚LCF èkÐ× /JiÈ\xsáÍ…7Þ% K@–€Ì…_Ì(¨@*ŠÀž={(!‚d È% s‹‹X\Äâ"–d È% Sãb5@¹(,ªÀ¢ê¹1;P¦hQ(êá ÉP*”‡@Y´LÁ…Læ}€s`0ÃÄâ òQùS>ŒÂž{ì9°çÀž{ì9°çÀž{ì9°çÀž{ì9°gK«Šƒ’)àñ ZÖ®:X-ÈH…ÑÃD÷x8Eæ@æ@FÊP)B¨!T €*VÆø)M`”uPE!Z €­@• „J•™A<æRd%@• „JB¥¡R¸ ÙEnP ãì2Q2•Р…z˜N„j(k”(A†V• #HÊ¢EF“¼9\r#.“¿I€ß$ÀÀo`QI€AI€A,I€QìˆÀ  $À  $À  $Àp@åj$;‰©Q%™Åò@ Ë¿†L…h̓ýNO9Ž’â’Œ×¦ý¨*V`Š*”« Õ:ب.)ÞbP•ar"‹yŸÑª¥ÞHoiAéÅôéEƒŠôBe1d½-fª”Íx6 ¨” Vƒ*/èr’,ƼïhT{ÕÅä­W(Õzíå(± %, ½­–²1$ÊÜpœdjœJjœ'+dHödŠ[Ci€nÒ‹›ÕZ%—÷/[½¸yßik(+–kU¾txh÷ÈÀÐÈ;ö ’"6wóðІÝ;Fhò®'¥øîó·oÙ݆êÙüî 7®ç¦5«Fv íÖ*±yø’ m›ÏØ¥U¬kûÐö‘RÊ7žAËîÒá-ƒZU®Ø>4xÚž‹6 îêØ´ƒ$›ö ö¯Ú½}ÛÐàÒÌ/iDTkF6_¸r`ç½­Ã{v-!ÝÝýÃˇ(¬X~ý’åЬØ>4Ò?|â‘f (¿Mä5¾jÙê•úVQhùåô³ž¥îÉGÅ1ˆa¤lËàî »G6\8¸Ol7®_74D‰6,;méêu«úiìØ ÌPgÓðÒuóëa#ݼkßN mA~Å— ´îÚÖºfd×ö¡mo–4¾Y7äÄíÚ¼£4vÉ5ôT›OÜŽ(»€Í· WÊäÌ””©3õZ5ïÚÖºkx÷ž-­«— m£n]½{p×%ƒ­;w oÞÑ*]S¦ÁLO™¼iL™&Óœ2“MuÊdLMÊÔZM!eÖ¢Éo mÉží;¶ îJ™3ÍY4m§Ì:Có êÍz[·ýåáñ?w}ÊœcÎM™ó̆”I›ª”™ef§ÌÓ–23Ì̔ɚ*z8f°oÓƒ›yþ-y\I;‡¶œÏ3Œ?6°sçàM Ùo1úoëÒuÒx 19)ÿ¤h•~+‹4J1LõÅ#˜³Ë—ÒT¡ ´´$Šæ—/m jõªI_©êw‘?Ê’¿ä-FÚìhíþÜX1Z“Žf÷îï¬MG÷weœHM_ÆqjûŽY­¾¾J%ôh©ü Jë«U¾FMÕ&Ë”X%Ë °ÇÐßjŠ´vËÞšýÙ±žšÜþj£û;kŽKžX_«ÊôuªJ’†ŸrC¬˜½ô xý¸ß†‡“+š"÷(§»)NØ=œìprÙ¸Í8÷¨…ÚÒC¡¶tgík>i¸Ý¹R¡'—uüĵrÖõ“G…ݾ¥bÃJÌæü²±ñœŸ¢òèxÖ/‹Ž÷dýбîH1)ºi×ÚƒºêªL»íתêlt4kkh䢣9znVé¬CÂZRA,äzÑ¡ª-kµPÉ¡Rl46–µñQÛ56Þ2NÂ( ËGm%I+Fm¡$‘tÒ¨CÂô¨gmÕ¨]€Æb”šãm¹’M—Jq²IO~Ì&uÏÙÊQ¨pêiøÈÁ û(ÆšÓñqŽÑ0¤£¾76nÆúÒQˆtÌ÷ÇÈO:§›¥rI9J:\}ókÏ6åhÎ]IK‚Ò7ª¨þ,Ñý9å雈ò[è¤ùyšž_TíúVÕ¥¿¬NÔ·©U”áëõ!5¨¿ª†õjŸ¾[}LM]¯«ôêý u»þ–ºW[=¨¿«ÖßSꪧôCêiýc]Ô?×o×é«õãúý¤þ‚~Jß©Ð÷é_s¾ç”3¡nT‰¸i‰«™ZPl´’4x¯¨§i.Ó†PšË/Ë,T÷×ÖÒCïÙ”*ñ´›vƨOÇidö×îÏD³-ûYî8IKÇâ4X6»—F³æ œ6ª1-A E÷‹ª=Z%B¨^}´i#g¥råc=ã¨×3†z©çë®7CúYzAxNUèç)…_P3ôŸiqxQ-Ó/©ûô¿éñio’Ç×_ ”ÇåÀ¿"=‘¢)F#x ›9¨¨Ž‡ª†\ÚIÇk³M÷¨I=i'—ŽG7J­èˆ;7O<‘£iâô¤£Té›'¾™vŠQNƒ©4(N:êŒÒ ¢rOÎŒ‘3Vtã12†¬Œ!+c‘–¢“‰!UÓ'ðq¤dÆÉEýô[)[ß{ e,oP†Óx&Éõeâ¤BxlþŽ)ŒÇk´gL¨(Þé€íÓ«]ÖÄè°Wó©Ümª×$ÕRS¦N¢ö•¦BNÛàzz‰ßJà´ýí¤Ímm|ã&£ÞgjÕÇMV¤mîK4Þ÷˜:õÚÇ6 êqÚ‡~O›Ãs´`ÿÃ4ó¼ÍbÞ–©8OZü(õ*­Æ¯¨™¯¨J•1ífniñ,*\q(]lºKUEªšûÔäuw«jªfü‚»Tí©7Oõu³J}ßœNL¯Q¿5kÕ‹æLõw³NMÐá2jÎÑeæ[C¸ÊÖžn³„«mŽpBØo§®µ!á¶ŽðL[Ox–FHÃEx¶N¸žuÎasYç<ÖÙÀ:YgÀÎ Üdgn¶yÂ-¶‘pÐ6nµÍ„Ûì,ÂóílÂí¶…ðÛJx¡-î°s/²m„C¶pØÎ%Üiç^l‹„»ì|ÂÝváˆ]H¸Çv^b; ßf»÷ÚnÂ}¶‡ðR»ˆð2Ð8 x;` ðŽHߪÎÚÃMã~šÆýë¢NÿºýÆé×¥_‹ŠE ë Mc”’€2@ P¨TFúïP•Ö½_Í\±½GÒôE}˜OÃ÷i4\ƒó1qƒáz®Bžx.ÈNúš2C“ò14å>†¦ÂÇÐTúË”x†i²aªö\tÈx.zÔø´Zƒ–õ1h9ƒ6ÅÇ Mõ1h¡ß‹ò#‡ü%H")²È?iä/Cù'"‘ü“IþÉH%9rÉ?É䟊lòW ü•È'ÿ4$”߇ŒòW!¥üÓ‘Sþj$•¿Yå÷#«üµÈ*ÿ d•&²Ê? Yå¯CVùg#­üõH+ÿ¤•.ÒÊ?iåoè[C#”#qà… $ €„M a3“°…I HÏ„¿ x¡Ãlc Îg ¶30‚Ïiž¿x ŠI¸ˆIb†™„LÂÅL‚³8ð&a7“0Â$ìa.aÞÆ$ìeö1 —2 —1 £LÂÛ™„1&áLÂ8“p9“°ŸIx'“p€I¸‚I¸’Ix“ðn&á=LÂ{™„÷1 ïg®b>À$|Iø“p5“p “ða&á#LÂG™„1 '¢ÇHpŸׂ‚ë@ÁõLÁ'™‚O¬²‰çÀ LÀ§™€Ï072™€Ï2† ðŒæ,øð_LÀMLÀÍLÀ-LÀç™c8 ï þ˜€/2·2_b¾ÌÜÆ|… ¸ 8ÄÜÁ|• ¸“ ¸‹ ¸› ¸‡ øp/pp˜ ¸Ÿ x€ ø:ð &à›LÀ·˜€o3ßaþ› x ø.ð=&àûLÀ˜€21?b~ÌÐ8(L 4N žÅpL4N 3#ÃÌ@ãÌ4 Æ©¡)ÐxÖæ@ãÜ0+Ð88Ì46Ë–@ãÑ[=›éÂÜœhì“mÆFÙhìls­r^ ±WÍr~ ç kó„µ¢°6_X[ ¬-Ö:„µNa­‹XscVƒ(²€X¢ 3Î[€èÎ"Çâ1qâz™¸„¸ÅBÜ!n©w‚‡ •ÇÊãÕÆç#"±†-v’çha [m•ç$„µ“…µåÂÚ)ÂÚ©ÂÚ am¥°vš°Ö'¬­â¤Ú(¤.¤­ÒÖp^íÎú…³µÂÙÂÙ™ÂÙYÂÙ:áìlál½pvŽpv®p†M¹è BÚF!m@HÛ$¤mÒ¶iƒBÚV!m›v¾¶]H»@H»PHÛ!¤]$¤ iö¸•½(Î3DÛð‘Ý'Ð;%Ý.Ö°)»|ÚNxZÎa‹…µÝÂÚˆ°¶GX»DX{§Û&I·½’nû„¸K%Ý.âF%ÝÞ.Ä qïâÆ…¸Ë…¸ýBÜ;…¸BÜBÜ•œn¼ïÕy%̽K˜{73w“0÷aî½Âöô¼gðT^Ä sïæ®æ> Ì}P˜û0wµ0w0÷aaî#ÂÜG…¹ sæ>!Ì]+Ì]'Ì]/Ì}R˜û”0wƒ0÷iaî3ÂÜ`îøUòÑ#§†@ÓÆ2oØüc|@ Ú°ë»|¸C¶a÷Oú&!ûÊ w‹÷y!{éè/ q· q8Lâ÷âíËÂÛmÂNÕ^ o· o‡„7œ ²^X/¼}Ux»Sx»‹ysKËäÝÂÛ=ÂÎ žk„¸{…¸û„¸ÃL\^IÊÝ/Ä= Äáü0ËË!îBÜ7…8œ$ ræ'â¾-Ä}GˆÃ™b®çÖ q qßâpºXàåC!îûBÜ„8>gxùz!î!!îGBÜûÖÜÿtsÜÛO ƒ´ FýSˆcG Ê$þL’ïçÂ"ö«’0ÁÁâ/„Å_JúýJXÄEî ¤³å…–8|T8|L8|\’ï'Bâ/„Ä_ ‰Iò¡CFr©F:‰O0‰,̉Ï)"<îZAÌÖ‹¡iFƒD=£™!®fŠF^ 4ŠÕ&qÕ,ÏæˆPÖ>é9WÆ`žÄR”ç‹÷âc¡¨tˆûNQéâȺÅe½q} Ã%ªƒs9sÀ5cµÒjŒïLã|séÊej‚/!“|9YÆ/Ó)¾^-‡%J§%œNx²ÜÍc>_uÊW1æ7ƒ*¾ØœÌ­Õl9ÃjØr­¸Ì²jŽ]NaÓSÙe(Íu¬[Ï¢iÜÜÀV§óë†|šàÆ<+6Šÿ&öÙÌ1ÎbÍÙì¿…Ý´²ËKæ°¤5Ûùiæò³ÎãH‹ìQN by!·v°f'GÒÅšÝn›^Dî½Tñû¾ã©q>'¼ÊyóΛ×À…Õœ7û | 4®MŸ8’žÂ›NYÀ÷v)‡“†/æ*DT) 6(Ýïñí‚/föQú6ľq°ÃÍdqXðå^Ƴ—sâ°áZ8ÉŠ(' S8|¤ÍsÃmu@½¨L“8$€éÒa†t˜)*y‰±Qº7I¥ÄaõÙ\ h•x hž#ÛDÔ.çŠÃyâ°(:_.'YC2¢Ð%.ºE¡GaT޽LÆÁnd¢`ÌÄJßëƒk§À Ýb‘{'Ã÷Nüf”àÛÏd`Ê„/\e¥“ÆÊ…1\?UJgb ·Pž¨øb8`/´Ò±á´t(­tl¸š½dø%ºFÌÖr¼t¾Û$„ÁêŽÞNåÈBn©“–z±9M<4HœÓÙª¤“øÉ‹ÑFqÑ$a5K³Äøl6Þ"²VÑ(ˆÙ9ì±M´]<ÎÃóÄcQ Ï•V^¢Øn‡ŒH'_r`ÝL<Á"´ÓT láÛ˜ƒOcQ|à‰áÃXßÅ\þ,ãÏbqþ,æòg±Kòg±2þ,–²X"Ê-¹Âb騴¸g²×LžÅ¥’oq™X,“,–…´EúWY,#“-.ª-î2×G5·Gµ—GY‹[£œÅ2Å®a^pYZÜÕY\Õ[ÜM³¸(j°¸'šnqM4Ãâîg¦Åxæ-n~-.~š,î}š-®}fÙmL.}Z,î|Z-®| 7>s,.|Ú,î{Ú->¶ÌµøØ2ÏâJ§hq£3ßîbpy³Ðâî¦Ãâê¦Óâæ¦Ëââ¦Ûâ@ßcqa³È^Úw‡šþ†ÿ1§¬ùžjˆdT“¬Ì­Ó›¨u>ÿg€ÿPKË„bª6PKé|W0org/rosuda/REngine/Rserve/protocol/RPacket.classR]OÓP~N[Ö2 ùFAüèê Šà!#hHPÌFLtñ¢lÍR(íÒu\h‚Å;n¸ÀD Ñ„[”úž®ƒ0²Ä^<ç=ïyÎóž÷éûûÏs³XNBƒÑ‰^<à‘dL‹ø:“$0˜|}Èá‘‚YÌñݼ‚'2žÊxÆ –öÊ lA*ù^È s ‰EÇsÂe ôõb.óŽNWý²ÍÚp<ûM}oÛ¶¬m—2‰Š®r QÏJ‡SÛÜÌE» Ý…Ð*í¾¶ª1Y¢Ó]Ù©­PD·‰6¢Õè’žáoPB¿ŽWaè×3;Ö¾eº–W1ÙÏ’¿”ì—WWóo©šÎp®ŠA¼Pч~70À ûAÅ üZ½l™ù5¯B˜ùšìÛf5ðC¿ä»f~Ëré}ƒ­ÅruÇ-ÛÁe‰"Ù¶¤b‹–¨ï¬k{KÜ9¯îºäTÜÅ=²ö#ƒñ?¥ éËâ›Û;véjªi ùK%aU«¶GæOë× ºîYÜÆؾÞþ“4TMM7ü# ;"¦I ‘Ö”qfŒž@0²'¿QŠa„°':îƒD"=$Á0бøò8­d:ŒïŽ.®$¢ä0á8nÆÔyªÃ³§jÒ–ø Y:„$E¯¼¼7†[\Bz…«O\HÌŽ\":Ú)L4R‘Âd[…Žv w®*ܾèx*V芆>¥¿´ö­N‘Âu‹Äãj–&,¦~&§yöÕOÈïÏ h§Hò:§èÒÔF,þ¢|÷!Fšœž8N¤S¤h§¥ (Öá¯üyÞ¥•Ât¼oR‘ë¼aøb_K€¦,Ȭ7|’YE³e¶6nôg®il]ã Õ­tð¸ÛÆœÈêkiñmˆ5à×Y‘+‚Á¦ñvìÔq +ø>ÞBö 4aT?–˜:ÐíU×äkmÕñN¼‹NY“­¿‰°­ø+ÂÎ3ü©ã6슽Ês,¦ßàݬÞ=É}+ +t¸cEJïÅKt¼?¿Å.»ñ~–ôÂÈ~V4óÀŽü#Ôq;ÒñAÜAÇßP -ÔØ”gÂß!Œî'n­AŠá•òÃìÔN|$,3jûÑŽŒáVþQš-¹d=G½VrŠ¥±?¦âã:>=Œì¢-mÌÖÌ[hmkn¶„üõ%º`=MåS`öÝ:>‰O1t-‚¾½OÙZK(³ÕP—¼ô¼û¼- ¬×X̲¶-°Ò¨oò×gò…Z`Ÿ½:|Î>~÷éø CÏâs:>¿çíó‚Ž/ÂW:îÇ:¾„/ëðmX|…ùþ€¯êø¾®ãø¦Žă:ü¾¤«ÏLÚ$Ê8h¿Q2QZ>—z+KЍWæ„"æÐehR ²1™[¦S«Íª˜¿ ¬dI‹¨™_̃T+«¢áœqCù1p“ò €è¹a€{dNÐH)JP‡PÅL–h*S‰¥Ë¨#˜˜9 Íi¥+t}Nk3ÝI)öÛ<+VѪ#dÇX‡ùÖ&ŒZe±t6ŠùCWaòÒî¿~½æ$Ôk[n&BНÕLX¼1‰pÊÒØÊ×l½q—ŸÝ×oh ù×ÁßBÝeẀà[Ýï[3•'jnöhü¸ì.òŸuY1|ê ü–þ'ã×BÁð9LÉ0#H@C²°™±¦gh¸(ÆÊœx³WûšV“µ”ÐPòC9fze8–År2Wd}Í„êÌ~Þ ßµ®¦ gG¡Öê`¸KÎ>s m€aÙKgÿâ$ÄTü‹Lvã:¨ 6o@ÈÀí¥t•ò@6·”³cš¦ô§¾P¬mp’ÜÚ×^VÅ~›¯©õ„… o³Ù‹×à3à±8•4€ð‹Êk­áô…AK%ÉWÏG£¹,;m­N¾…#§²`àÝbLþ‹šÉ|W‘V­þÐ<ÿ†"ÒdPö@I3gõ¤nI“Ÿ×l@/𖆳H5,â­ñ3wF4k 1îÖYÁ¦&ê¦5u³lO v¦Œ}Ì*©~˜¬Tf„Z|Öóü-³VrMB–$ ´Ð>T1ü0)ûÿ³¤ègõFÄYÙ¿|¼Õ*}!Lõµoù[ùˆáðNé—YH9|­VvnKÝnF«k¶%?öY²­6÷‡Æ™9Ñ Ž£15yöŒzÚZvi©Qï3Fj¦G_Í6È‹Œ£QtY:ÉfÆ[¤Ä¾Ì c¬ëlŽujk8ü©Ùg 4¸‘ßÀ7ÁÍ€p ¿ÅÀ­„ß…ÿšðÛ£ðN·Dáw~g~á[£ðm„wEá¿!üî(üÂïÂï#ü·Qx7á÷Gá¾= ðQøC„ÿ. ˜ðQø#„?…?FøãQø„÷Dá»ß…?IøSQøÂ÷FáO¾/ †ðg£ðç> ÿ=á/Dá/¾? ?@øKQøË¯Dá /¶üÌÆ¶ÑR¹m´”™Ó×N¼”}Ò÷O„eP‹ü”–ó8àNãqîÏü”ftÖЗª0‹uªÅ:ˆXÅP±â¤Ï‚´Ó˜¾oìÙð¿Âp–ª Q󖠬Ȝ»@~$2§ƒÆœ2,3Ø?$œØ…N=21%0{îpî[Í.Js{@Ÿ“ûàØý³´š±»ÀþˆÜçÀÖ Îé ptû„Jpñ;ËsÆõ€Þ šËÝ 6W 15®RsȇËÝE¤T& 2ÆÞIÔøNÐs\.¿†ðW üBÂ]žiàM„'x–ŸCx’3ð2“ <ÙÀ§žbà# |,ánaàÞGaÐH%{'yz lHïod<qøFBßåä¤Zpܰ‚vEä@=œ~8΃™Ð%°C#œ « VÅЗÁ¸t΃tn›é¼Oç§…ö}+íãí¿6ÚOki!ÖÑ‚¬‡¿ÃøŠfü7lÂxØl,òjHꥉ… š GÁCKß ƒA6ûUyÿÖKkÛ¿—Çá’Ø¤# D‚õ7>âW`bü ýþ ›{$~9U_ñÚÖ\ïnR˜ë”íu‚*wƒ,åËÔášÙ‡ÛŸqQ¾â¦m¢t™þófÔæ«9n…Ünl¥]0”vRÒörËæVÏ%ÇgNw+[ %‡waNdíZYôîp+¶.(äù‡OÑä½j4HÛ #* BóºÕmOk™4’–έN§á‰5‡)`”%À•Õ ݪ·Þ¥5åkR¾Ý­íU 4ønðxn»!…’È;v÷ê<úd‚•.¨”÷j5^] y4iR'$r#o;µ®öjé®ñhæÈlÙ!Ð?ˆTRj·“§cNcHÞËXݰ®Z#×ëqHÜ·rˆMÊwºǾ»!‹ôwÒ¤ÉFK³: i;œdÇGæäŽ¾É FtÑ"›só5Z!còÇ.¹Éµ9R¾ÃíðØ áv·Ãέ!œî`á¦[H¾½¿|¹ ¦È{욣¢@#.WÄc È}ezfô°™jd¡ÖB /Tno,^¥/ûdŒ·V‰·O³pÓyIzà”g›È˜îqî‡<¾r<Θ”4¹Ní„ Ò3Ÿ¼åÑ{`Š©ìi$ϵ9_¡ÈE2($0¶¨+âÓ±aŸŽì‚I±}jº*%⪂ð°”m0˜÷6H¤f¹˜šÔ.xÅ:+Z°ï©L³üÑ€N>9,À™ë±›½;éÛÓ·@¼Òy³ÀI4Úy€öªÃ£3wƒ‹0§…Ï\ÜÝÛ™ÓO§ä=1¼ˆØ÷€Á‹Ù¢ÈzÌŠZÓD: nEí‚R¾F>œMÓæXÆ<³åühMÀ¶Ù{ $Ÿ}?ÛR}Æâ“hø¡Àã°Ìu•WÔaÚÊf›àôNZ4ÏGÆ4¾渵N˜Ìö%v› aË”nHbSûzŠx[ÑÞšmä2=’Ö…cöÀ\RøŒÍÐ%+bHd 4KéÒîÞ¿ö¹çLk»;uGxoΣ½¹îŠF ìÈÎ/í˺½Š*ë$Û©uòJöÀ|ÚÕú¾§¡¼À!åǹã1£AÏBÙ]ÕGçæïì|Ò̱ Ю6LáÅ=«Æã4í­47>‚W‘ýÝpºÅ𯬦Œ]P‘Ê#Nè® ïóa]°›–ßKgÚήJÎuÛéOÚÒû}‡F:}åÖ ÝÝÚV¸Ðd4\ÚL‘u Ô÷$Ñ©•k©C'Ã4¬ê†|ö@yAñºíõrý£°p,"¢'ŠÈ¤A'Ÿ)iIMî•kóí”»{o m™ÙÑ5aÝÓ»àâþ ="öBO2Öúß­µGë³ÙD{_|ÌáÔ£¹=°ôY(¯2Âêç¦öþJ(æžKî‚ ¼ùZ®[£°ìrk¬ŒÝpà7ÄÓcÁ2ÍS#†{Ýš7lwŸÄnBŒÉ5'²ì‚s jRU_Fª›7µy”5š —ÂÁÇÄÖKÆ›Â'?‰²¾0<¡ ¼Äº¼Æ’¦*µQ¼R‰ž`]þ¾0)<T¶‚6·ÒufÆæÝ’Ø!$ÁéJ»òšò&,VïQ¿V¿¥ÍHå¤íð%å7—S}¤Â•0®‚<¸¦P’V× ¸ ”ØÝH‰ÜM”ÝLÉØ­ÐNEÚTœÝBÅÙ¯©(»‹Š²û¨»Ÿ '©ÛCE×óTl½NÅÖÛTd½OEÖ!âø’Š«o‰ë?TH‡íˆ°“à!L‡1vâ(x§Â£Xa<Ž á \=è‡]¸žÄU°χ½¸žÆv؇×À3x=<‹»á9|žÇ?À x^Ä÷`?~ðSx ¿‚—…^ƒáb ¼*ráuq ¼! áMQ•pP,·D-¼-êàÏÂïŠ&xO¬ƒ÷Å&ø@\ Šká#qüEÜ‹;áq/|*ºá3±‰Çà ñüC¼_ŠÏá+q¾–¾#¯+Ùà{)~†Â¿¥QðiüWš‡¥|øQš G¤Yð“T G¥Ep\¢J[ºQê@!]‹’t3ÊÒmh“¶¢"í@Uz5émtH‡Ð)ý ué¿'+/Âyºä±˜(OÆ$y ¦È§ã y¦Ê¥8X^€y)¦ÉçÒnÀ ¹‡Èëq¨|1fÊ×á0ùV.ß#ä{p”üŽ–âùÌ‘ÿйòw8Ö&á8›†lœhŒ“lY8Ù6OµMÀ|Ûi8ÅVŒ§ÙJðtÛ<,°UáTÛ",´5á ÛFœiÛ„E¶ë±ØökœeÛŠ³m÷a‰í!œc{ϰ}€¥¶¿á™¶pž"a™¢à|%Ë•‘X¡LÃJ!V*%X¥ÌÃ…Ê \¤4âb%€K”Ö(ñl¥ÏQ®ÄeÊx®²k•]¸By ýÊ›X§Äzå=—ft 9±#.=<³jɃ#yðµNŠ”¯ºUÝã%wC­Gq«=ÐX ¥{4ÒK%½8ÓàTÒn®¿!MJÏ·›œ«¨þG9Ýã0 ª7Jp†çëP)5ºÓè[Û§ÃjS‡)(›Ãr'FKéP¬æ$gßVH႞²O¥‘ÔÛW; ´n2>ÜÇÿñ<»yâûæ‘Ò“šîe9]­ÝAkwˆ­°Øz`ú å€{éX< *îƒaø ás0_‚ ºçâ+°„îúz|Zñ5X‡¯ÃÅøŽÅƒ˜‡oá©ø6NÅ?a ¾‹­øéñÞ‚â}øöà_ˆú9A‡ðcü¿Äàø¥pâÿˆDüJ¤à×"ÿ)2ñ1 ¿Eøƒ˜ÿsñßb >üIÔãQÑ„ÇD{ÅÅÄÅMBˆÛ…Lv¨b«°‰.jïšø­°‹„C<,tñ¬p‰—E’ñˆõ-Œî'Ø.l¶Œy° pÔC ?O!&%¸\Ç8®N%¯„" ÜÉ/bhŒ$˜–iÄåiô+7†*±É4üGH0n—¡ÅgtýŒ£(h뛣û†}†WËB#n­_Hû"ü’¦,¦éâ)½•bP}aï‹ð#š”o3“‚´90)˜TºŸJXÕLŠœÏOÉ£0 5Õ5Ì(¨cÄÆá'ù•¶N°'B;+ÒžÁïqš‹6µ¬Ös–¾f±7ª«v:sGÞëÓÝÚv#*Ьð8’~÷ÓïAú=Eý»LZøÇ´h|Àßtë÷‚5~ú ¿h¾ÆÃ«t¢–ÒïA ÿ/ÁWu ¯é ›ÕÜ-âLôüÝÐÂ=­Ýø“å¸zvzóuóy ?ã×´'ŽÏuë4²C—»{Yá­ÀáÍg®\·“IN™à­ø¨Dƒuãmnl®1–Dè“\í´^6㉅°- JäSùÆêÇA·S¹¨×™üJuwïwVL=A…–:§°â¬Qk‡®u÷~шÕa;i#ñ«á¾ÝÓÞpÄë'êX½£µ‚^œ'Ž‚ÞhOœôœ4))ª 'hüœÅmm¾Žqd"lf+™ïw¸uo=¿U’yp»I’MÒ?½ùŽðUàä÷¸ ¦ãœÆ}pŽÇéÖù> e€nýÓDAœq'ÄÑËEs€*iÍ|úÒø*“ÉF9jŒ^EÕh«áê.Ò7×òƤÝZì¶g¡ù6ñ¦x+š©@+¥ ”6á…$‘n1ÒÅP"2!GdA³ÄpX FÀj1®£á!‘ {¨ôzEä`HŒÃub<^.òðv1CA¶[LƇũø{1_Óð 1ß…ø˜Ÿˆ™”‹D‚˜)Ü¢XŒgˆ ¢Tä‹3E¡˜'гĹ¢R4Š*ºDªÅ:±D´‹q¹8[\'–’öË( ŸK!x¹xDÔŠ'…O¼(Vˆ×D=ÙÕ Þ~ñ'jß% ‹Uâ ±ZüS¬ÿÉ.6HºØ(¹ÅRš¸PÊ›¤Ñâ"i‚Ø,Šv©B\,-—HÅ¥Ò&Ñ!µ‹Ë¤KÅ5Ò âz#Y¿ò(Ý£4½<ÑÙªÍ!á¸ÓèÀ2âpœÈCy­0ƒyLÒÀ£$BÎ:™LJæñ‰Ç!žR{¤9ÝÈ–?e‘é÷óAÊ)>¿Ä±9$£9ê`Îÿ Ï?$Ë€?ãzf"q$ó…2  b1ï5Ž2ê”ãŒL9ÊúW ñþÈ—“У®;ÿÿfÖ¿n'©6jg=JÒ’ùé…c­Ó-{d)'Ã#ó1榶 d~Þ–s2:$:¸|Vã,¤»÷‡ :${Œ‰$.ãìüfPÅ-`·Ñ ¹2D' [`”¸ ƈ; —‰bS áD`0بœÉâ‰ú”ïXÓ8THöÿÀW¦Þ¸•fàÃ<š¶…ônÛ™&SÚ•´vgšÂíºi6n×ïLsÈd`#ø€€,.$`›ÅÀE;Ó4n7SG2í;ÓTn/¦ŽD.!ÀÍÀ¥¤0ÐA@*—0ˆË Hbà F2p%†œ«p1ð+¸èHºš€4®!`3×0ëv†Ÿ³®ï´´¨Kº€ðöý“o€ö(ˆnòóý €T±†Š![ì€SÄC…~GQèa(;a¡x–‰Gá<ñÄã°N<íTÄ\E×èMb7Ü!ž„{ÅS¥ö@Ø Ïˆ§á%±þ(ž÷ųð7ñœ±N^ªwéO3þTͬ?Z›¯ íþù¿PK[ÆÃF ë4PKé|W1org/rosuda/REngine/Rserve/RFileOutputStream.class•TßSUþnv³» K iM mZ¥.Ù„mÑV¤4 ?PKñÁmØâJº›n6­ÿŠŽŽ}vƆŽuªOuÆÿ_qϽ Ruh²÷×9÷ž{¾ï|sÿxñó3ã¸GV §qYÅ•8$ŒÇñ&ÞVñކ«*®Å¡ÁÒð.ßã®÷ùl‚w“q(˜âg?ˆS7­áº„Vë/e†w7Tø8«âCs ‘ dÈ–ü`Û üzc˶ÊsÞ¶ë9V¹î«ø¡_ñ«VyÝ®îL2(•ª_w¶ØmZL¹žN3\7Ž£ô•ýÀ¶ª¶·m­…ëmOŽ~Ê Ïú[ÃÉ\nÜ»ãëö*Yz×B»²³d×ÄZżŠâs_WœZèú^!ú0pCÚ*E*jlø¨ÒXl[DÒ ’!Vw«ú—cÍogÞåפÊ|\i„µFHi9ö½1ž§Žs0uœÁYã¸u, ¨ãc,2œh]ß*®ü—2ÃÙYßóœ _dB?ÓŽ’¹kS Dí`7C…†[Ýr†²s¿áÔÃLà„ÀËTˆ´‰ŒŽ–t,c…ÏVuÜD™'¾¦cÃ:.a”¡ã˸õŒç‡¿æx:Öñ O•(‰løì3óÕ 1ÄÜCwÐÜ× €DvòV©Ò)R Ú0nÅ#ôr,±µƒ‘de·¾²#ŠÏ%k×;‘œ7Ž ü æ)Šºí>;Š C$¶ÿÙ®…þô¤qx#í8*ª…â9¶¨ØŠAêÝ,0\5Š›¡å×~…Ÿ{­3¸@ïFš¢5=ø4D½BíΓ'C³?!Ó(ewÁ²æcD²?!ÒןkB^Î?G<ßDô[dŸBÙÈÿ-¡>Bú)´]Äñ&zȯ7ÑÛĉ]œü5+=FßâÞ â•ú,Ý`"†’ÈÓÍc˜‡…E\ÆEò.Bn‘QVqZ…¤â •ÞB´ w™"ÎÓ×Â@—Cj;h%a„Ê Ê©]Â[9²I4êò/ÚR6'ÉMôó$™Hò„ðMОIô`ª+†Ñ‰1B6Nf,kJæ³âÂQ ‡{¶ëðhçðß´æLDnß7èål&œ°á‡§¾‡*?‚,]“µá'HNDE’é¨94ÜÄÀ„’Vž£'­ˆräx€´Ò©Ç™—ëÁw¼TýZ\¤ü8Ûýô´ b‰ˆ[¦ª¬èUz1nâ>Ê¢KÐú£±ö#LEŠn¡ª <ÅXÇÆË±@_ ©Ã>©í;T‘,]Ø&䇛óe‚ý†Tƒ%“gî Ά㠞ë:e¾H^²[%yß&„úh¯¹fµ¶æø¤ó}ÓiIß š¾›,“B3I yÜа ƒß­h¸‰[xAÃ(Nh8ɇ3H1Ä8Çdµ‘t½ éÕ—C-j(á6õ5Ç—$Œùv¦½*íf¸;ëåðΪ;úݤÎ:äCÙï2e˜7¬}üq su‹‘Q¥jce=l;5j׉9éÂ9x –"›øv¯CêPP’1"C”qZ¦dt õ„côí ѳ!v7h%Òœ%Ùƒ®3tP—éÅšÒJÞL‹R qé"ÂfZÌn¾F{8”.KÉç1€ !:¬Ã=¥SÝÒìÅ8ÇŸI»ØCôs±âƒ¡O0ðŸª:x¢…¡I—^à.…ÂNð\]ÚVöØneyÆ.iù21Ñ#/¡š),lŠ£‰¨yþCéÑDô=’ˆfK?FÙãοÞ!5MBsDè ¹bžhäˆâ¾ÆU”±ˆo©¸|zÝýD áÄ-ô (m®óxýˆ„’3¶Ý úïÊvH•=q±çh#Ná66²G9éí¦üºÝ”¥PŸ8û Ã-ͧÉxéã¥÷3^z¯ñH‘ØŽçêf‘~%¢}›hÞ IMCjC)iBè!¾ÜX¯Bb7ô†¥&ÂS&ÿPK*È(ÜPKé|W/org/rosuda/REngine/Rserve/RserveException.class¥V sU=›–f‚…í(²@Á4m‰XÅZ Ú– -´ øÞ$Ûti²7샇EFFGGÔYFhG|ŽŽøýþ g¬çn’6BUÄÌœ{wï½ßwÎý¾ïÞÍ÷Üþ Àc8߈x:ÆæÃ*FTŒª8¨bLŸŠC*«˜PqDÅQ“*¦TSq\Å 'U¤£˜Ž¡3*NÉþ´lž•Í™vᬊç¤óçU¼ ûåàKòél#öâeùúJ ƒ0¢ÈD‘UPg:ŽmòœqÁH ;ŸšöËÎïS°Î1ϧMÏwìQ‘3( 6åM/mž÷M×sá4ݬc•£ ÂYûÜó„T6÷?”ý½aɞȊB*}‚ñ5½Ppžy[Ijm¾ëÝÌxlZøNÖ·d&ZÊžÆ.eÍ0ç»%}ÝHÆÑƒ”Õº) ƒ¥’ÖK†Ãõƒºe—|mVKÓ££¶•I÷²í—ªV-†ïÍ ÇzÕþõYƒ¼Lù†ìòžõŒ#æM–[“e_0 VN§Û¢aËUÕú6Š$¢Ãö‰Ôñ²s¶Þœ©‡[àL[OËÕmáé¢$ï0²Y–›ž3mËÌ鉂ÈÝ5ÖÝ š}ÛõK%áxf„&ßž·ÅE{e¤+gx†.h4[{Ëa`¦ôpÜBÏXLˆIé~y×® ˜õ ½z†‘s¬FdÎQ°T[± U9†íJ úLJg†'õrštNè‚öbV/šEá\îÕ³áJò•½S³K²J2¾{™'³:’3yç–Ó¢™çˆ‚^²J¦ä..£¬³²ÂˆÑ$0s©j’Úï.Ðß*äL'Ž~Ì)ˆ—3“eÁ êqX8'›ù8 èczy7õrÿaqê®gx¾+öÈH'²)Æa#!ŸD% )èþ‡óó×f¾W[[îkV­¿{' vÞ×!e©¬r[(HÞÿI #ï…£Ä e"ú«\i÷ UbÍ+µsµ«veZõDuOã«_=åþþoB£ò‘P°ç?:•öQÞJüxØÆÏ×.~=#¨Ç#Hð©^Þ8ìU(²ØöñmW°(ИLÞ„²€HÀ»Ù6„íáòTy¹’çòGÛ|ò÷ ¡¡ü{-¤^'êˆ7ˆaâ-b„¸FŒï‰÷‰qB2">$ Äñq„ø„8J|NL_SÄ×Ä1â'âñ-q’øA« ´ú@[h  45Ð-hk-hëí¡@k ´õ¶!д@k´–àc´ž]D›Ö¾€ŽÍ ظ€MA¸#‹4ZØnÆtâ*¶àM<Œ·±ï@ÇuñlÇ ìÀMta‘¡¿ÍàÊÀÁÐÅÀßaè¿cdàf$eD £Ûü;®Dîù1Ü{–sT`8e**“‹ À™°ÈUtV…wʱlaGí×°F{¸ü¸²rJûCê6DD­KR¢”áK”ÿ¶x!âñ s«F¦RMöôF±õÆrqÄÂT?‰(B‹'*ghQÏ~#-ú¡'#· ôÜÁÚJÛv Ûo,‹ÑÂ…ûèbˆ—Ò~tà@(¬Ê_ê)*н”%B– Ë)ª’ÆdYÄŽä–!æÎG°–å×ÎÒ“$Í’¤½†D©P3úŒÁP…u‹Ìû52¹ïÝu²ÝrøPKèë}‘ PKé|W(org/rosuda/REngine/Rserve/RSession.class•TÝnE=ã8{³Nܤô‡Ÿ`Ú¦¬×v¶´I $M`‹›;TõjãŒÜMÜ]³»ŽW<ϕ궢¨ÜqÁ+!gÖVQ[dKžùf¾ù¾sÎìÙýã¯_ž¸ˆÛŽã½<æq1Y\ÒÑ%-ëhÙ€÷%>Èá²>4ð>Ö™=¬¸‚«Ÿ,øTW}¦¬I¬K\“Ø(Æ*ò½ÎŽŠb? n»×ÄuÂzĉ$;^§§&¸°ðýŸ›ûUì½0NæêûÞ¡çt¼ í4“ÈÚ+ÌuÈ9á L¨#ÌÝ5ÓK¯uï–×:PÌVëaÔv¢0îíyNc#hûrdq¨œn&a+ì8ÁiöœŽâèpÈN`jÕüä*û[宇{J`¶Î[½û»*Úöv;ÜÙ±F 4¨-P­„WþXhRËÁ ¯›IlJ”ŒoZª«Æä8Ð+P¶Êc²`‡fØ‹ZjÓ×ì ¦Šµà%}É&ÎaÑÄ;8câ ¼iâ,L|Ž/ˆ0¢}:=ç%PqƒC¯ãï•"wIT•’°pJ{JSfê랊“% éJ\7ñ%ê&ÞÒ€o£$qÃÄn ,Ž¥K·¹eâ+4L4±-pfDÙP2ù¯³nîÀñtËfjVÿÛÁS¶Çx²­Rc”µÊÚ—«c{ä«k'Xã€o{:‚ЮFž²î®¹e÷Í£8Q÷ò^yG­°Ë÷ƶê/_Šû[®&òîHÃkM)gôÛieyMœ¶”CG8–;Êͯ¼,ôë<¿\¯a ¯ãN2>ÅOZ§9ÒÈÐ?Z+é.Žßi—§ë³éþ²Úü¬<Ï•ÍZÁÙ°Cآ̮xgxDÌ¢ˆ<1Á:‹çuÝO˜ä>Ð|^gWb¢¬ž'û˜ª>‚ܪý£ö¬Xý3O‘»S™Ë?†ñ›]“O0݇iK¿æú(ÔŠ¦ý…‰bé f¤‚4%Ls<9$p Ç(ó4…/Pj™b—)õ W”Ú Ø2OŸ@æoY‰y‰Y [¢By¨2—¥°ÿ5vȸL‰ñ³w(¥X×ôeaŽ’*?¿tçHc‘7qþ…vNJøÂ?PK ŒO_PKé|W)org/rosuda/REngine/Rserve/StreamHog.classuTmSW~n²ÙM–0!@ÄHªUò&kñ¥-mQPl"4¡/‰}qI.qÛ°›Ùì:¶3m‡CýÐ~ñkí”0Sfú±üEúAÛs7AÓÌä¹wϹç¹ç9çÌ}úò¯¿Ìàk˜ŽàtT‚wÄnFÁE—T(¸¬BÆï†ñžŠÞ0+`.Œ«ÌcAÁ*Žc:ŒÅú‘€E×p=Œ%Ë*ÆqCÁM+ ³Í/|kÜ7tÓÖW¬–ç–]‡ JÍh¹žÃX•aÀ´Ú®Ñl®î=†h7¦iX L«AòUÓ2݆Dº/e5óƒtÍ®åPÁ´ømokƒ;ëÆF“,ƒ î®ôÞ1’Îô»%èxaZ+»Fí»¢Ñò9ÜbP˶çÔø²)8‡É︥6wîóiÁ¥á42N"©á&5|,>Sx‹aôUÊ‹Þæ&wx½Ä:wHM-]Ÿ`+(j¸)*R «XÓð JÊÂ)—–n|S®*X×ð)(û±×Õ-zfÓ¿2Ù“÷lª”ê¡Mͧ4|Ž/4T0¥ ªá¾¤bðWêDì ÷Õ¥5ÞrMÛÒð2 gl§¡;vÛ«ziÉjP?ônœÞÕxÓnPs\¿GÖúS7m†P[ÜÎ0Þ¿ñ¢U±CW·x¾5,(Å(и™V?XݤL¿Ù÷ Mk¤ím´÷oŒ§WúN‡D›­£9~ßv9™‚¶çöûE»l´ZÜ"uçû]þ†i¿SvíWUˆõ¡&]-ñÕ´þGa¨Õ=O£¼î5Nóx‚^ HUˆM«¿Ò¬î{Nã ަݾ%–ÝËævÈžÜA0Ûô„Ì g G"„8"ô5ˆ1Dé1`8‡©}¢$­ŒÖPöO„~?•}ãa™îQ–#:™¬¿íA®ìA©PH`á]D ¬˜ë@­ÿÁOd >Ä|t m!¹b>9ç5É{ ¡MK)D@(ÝXE¬ RÖj[ -  Ø´ m Mj’‚uÁ}q7pEP(**ê8à¾ŽŽŽƒÎúÎâÌÿÏè(Nÿï¼÷’&iÚigDî}ïÞsÎ=÷ìç…×þõÌóD4•£±j'52ít'Û3ñ4H‡ ƒUÎ’9[§ 92äÊ0D†<\2 µÓh¦òp•Ý*°SÛ5>Fæ‘vÊå|ye§!<:“–²G†cÑ#ñ*š c…q';ãíTÌd¥@ö&ÊZ¡<ÉS±Æ%*— Ì$;Oæ)Oµó4ž.Çk+ì|Ÿ®q¥¼Œ×¸J¨Wk¼Xã%rôR;½Ï5×ÊAu/Sy¹ +dý Wj¼JåÕvZÎvΔá,•רiŸ­q½Ìù{åJ rlcuuÚM2ø4^«r³Æ-ûeaP^/C ƒ²¿¢ Rœ4ˆ[9(»!¼z@ªMVÎÑ8¬qD㨜Ú.áþ•ÏNçóù*_`§ ù|/:›4¾Hæ‹5¾DãKåÖ—i|¹¯à+5¾Jã«5¾Fãk5¾Nã¨|½Æ›í´™oÐøF¾Iä‘/+7Ëë5¾Eå[ít;ß&ï·k|‡Ê[˜2ÞHt~8 3åV®ónðN xƒÍ“j£a°ù$&Ž0åA_tRm¨q½/ŠõÌÆP0èkŒúš³ŠIñÐeúC“*‚míQñy[¬„°94¾¹¸=š¸«zÛ£-5¾s˜4yªëhóf“S^—¼þàœ@ ´QŽÊ8Ý×zá(Sae(Ü<)Š´7y'ÕÌ6ûƒ¾I5_xƒoR[8 5†“jê¼õ8ÃÑèmó6øþ¨ß^Üiq矱 ¡PSAÔ/.¯F}áµÞFlþÈâ¹s–0YZB0fi ÙѰ7Yë Ïmñ†#>¬hsêÎn“ë0 ž F¢Þ`t¹7ÐîË@L c¿1ÜÑ•wfŽ„7,÷…#þPl³üAôd0X0q9N™j‚œ²+ÁXu{kƒ/\çm`Å>ÿÜF_[8¢‘‚žJì¡iÖ+dcB_¯©õE„DY:ýE\õ6®¯ò¶™Lçô°1³An6SQ¿õ!hšHÊÐÉО„W— L–À¬ðG[ŒU¦™=!ûw•·âȵþ 7à?wq6û¢µŽë*ƒ=[¡ˆOƒÇS0±+Ô6„üMó7x*ß fcoó|[K7³Izí»ðæ61G!Vã‹´ÁJÀѾÄÛíLK¼†fúàÛâa¦’~óg Ù¼`¯9¨Û_Äô&¬5zCÉÓÓ³/¤{?T廘JÓ×+-95Ôæ .ð‹Íž:PZb`Tùn¸k#ž£>ƒäœÿ„dJ8µ‡}­¡ &A-ÒÒm m„ds"b–Á¦òöµJµº©Z N“Ké[úióƒ¡&Ì0Ö@¨Y"UA¿²J÷Ö&Ó:Ç÷bÚ=lq?2·;d}¾¦JãXœ¨²;7åbšìd×)†çë6ç0^jCíáFÜ-Ë| Àª~z¯êË8«{7¯^7ú$èÐ9™l2_8#ì“ð€(õiçÍa_$Øà«ñÁd|Ak¶a¯ +9±Ð—°6²õLº›¬ƒvуzHÐ?¢Gô(=æ Çi·ƒöÈÆ=´ÍAïгLCºõÏÛLû8JŸ`‡¥j¼¼ÝhòÁiÆÌõƒ¡¨GO;ž¶°oƒ?Ôñ4Æy-ó8øÞæàíô7ß‹ð=!|?IBÛ))ÑÁ÷ñN½F¯C˜1ò=£gpu¾ŸpЇô‘ƒw1$±ƒîsðCü°ƒvÒýHÈ&,Àãy"zØ*ó Ðô·œ&¤ò#~”ƒ©é!³±ö„}>ÿÁÓäzË<*?îàݼÇA¯Ð«L“yƒM‘ïzŸg­ðMeß¹mzøñL›êièˆú"žŸâ+ö4ƒK‘Ïrà“¸oª e}¯ƒ÷q'"i j5ï秘NìyŠìz$Ãy£ía_üÐbOC{Ôd,Œ¹ŽñøQ‚…R•Ÿvð3BpQO‚u->à<í0Ý ·F=1qy¢-Þ ?tðc§|.³dJZA´ÛÛ¤r±Êµ›R|vb±§Â…<¡` Ã#„„àœš¶¨>µ7:ø?ëàçx«ÊÏ;ø ¿Àtl¢z"È?¢œˆ‘<ë}¢zeñéâï¢.¬î6(½µ°;øE~ÉÁ?–ÝìXd2- xÕ¼‘wÀ¸ì{|Ý🇄ÊO|ˆ3Õ$r‹Û7 Öi†ôD[æ©EÔñDѧx¦LžØmA¢Ëµ¡ö`iD=:.1•öǺAw·1 w8ø~ÕÁ¯Ñ{½8@«ü‘Vo´±% üº„”üØ|A$á?l–z"íA¾D î…¯óü¦ƒßâ·EØï@ F5â¸Xç¶,‰I¬RHˆD%íÝÛŸ¹söä ¯)6¦‰¨õbœªÛŽñ¤#,}§]Žpõ®ƒß# ?¥·U~ßÁðÏ$Ò|SFùvUí¸N y°á øáLA˜rØ×,aÜ™?âŸ3Šá  ¨lç ‚÷`{iÙ“p[Vc¨µÕ«k×8H’aìÝIþ˜ ÉO§¨"uB ã ÍéVàXÃ8±®õA½oÿ«Laé`dE$Rzw »tð).«'–É4¼Gm·á=j˸¬¾¤?J/Qùˆƒ?ãϬ·¿% ÞÄ¥ q:ÃôÎÙõMÙlf”Xõ™Ó]Æa†$Ö†ñUWr‰_›Öãô9ÑÜ ùyšB¾HpBÔc*Á ^‡)î|0»¶RÑïzAòu—/ð…h ,VÞ¥ ¡oÕƒ~N •_;èú ‘µRáX†þ?¿—ØQÛÑÚ Hó‚ÐýÕñ²º%3™Fô~w(kuyŸÆ—Ú*Bm½0«|ä[Ñâ¡Ú¼mh°šzë {©u¤@AQ…hím–¶'2ö™–öùA£»nKÓÔ$¬Ôµ„C%0_/`ÓumÕ¡y¾€·CÚ(½ÿÑÂñ†zrÁêò¾z =5ŠX\ Áo!ºXÏÓã{Z6@“vxlJ?kwR¨¤—k IŽ;b‚Z¬r±Šäb¨ˆLo8ìíh µA"…‰Ú[ܰ2>©"Í’þÍidAE_šõŸkP¨ëcÎŒ´7DL£ZP‘æHã³f+ÜÖWêåÛ®žÓ½*Ÿš¥ÔÖôŽ®Bz[c‹7æö'ù$¦™^¼úÜ‹ §—4HÇ’FwÑü½‹î–ß0äÆ>o§{õÍ¿>£õ×çÌõ]ô >?d¾?lâÿˆÑçGé1}~œvëóî îI?SºÌnÚ‡w¦N<+´ïO%¼?Mù0çIX;@Ïbí9¼§ ¼Ù s9gø®ý¤ìц‘_hí€!šŠ¦ÑADÇ~ÁÄ>N~ù ‹Ò#Ÿñ”¥ ¿h"ÚüÈ£äý”‘Š[N*ÍMÀ%ྔ€«è¸œQ”wp+Rplàò5dÅ¢7 ÷“¥÷‘µ0cÙdPeÈ”Á.ƒdpÈ0X†,ÙÈ.ÜK¶-ØßKÎNÊ‘uç.šPf9@CV ¼•ûÉ•;´“†¹-4s'¹Ý–ý4â`É!\²—Ž©Ä0r¶qhÑ>Ê/¹F Ñ+‹Fî'O™Åmæ±…nKÉ~Ó“öØt´÷àr3påJÊ¥ëagbVtl |Œ•D.4™GY4 Ž?n쌠1t MÀS1¢)ä•jšG‹A«XKð¶”Ú¨–¢TG´Œ6Ñ ºŒÎ «i%NZMwÐY°ø58Ó‹Sφ×ÓÔ@/ãÔQdë1‹JšJdz R´P¥Ü±ƒý2¦ÆOL †zÄ0.ûÄ"SE'mBÈ §vŸàt̰¹lrËz·Õ…Gµ@eª[ÍR[ÉóÔ­p(KÜÝðdÇ~¹¾on`Èt«4×yúvxž[µØ@>y¹Í²«kÛ.[f5=ϸ‹`(Ô}Ðm=¸‹f‹v‹÷Ò¼ §§“æ÷0Œi à M¶æ.BtØ›³ÂíFÁ%×P ­§\žÁóyÞo Ÿ)°Ñá-˜«âP²)W¯LWNˆ;õHRD?•Ͱñ@ëfP»>xB?D$¼Ž+œö6œpθ§lkoô=ȱ;aý÷#Å<@o"¯¿ƒ(ø3äñ‘Á‰üýía+=Éy´—gP'ϧý|=͵ô ¯¡¢gùzŽï£çy7ägè~‘^äCô¿N/ó;tˆ?¦Ã|„^áßÐküz¿¥çàéïâVo)Vz[ñÐ;ÊXzOOï+Óqßèe&n}¤ÔÓÇŠ>QÖÓ/ô@ k$¶tQYhƒØ¬ÒL,ù;:Õ6ö(•!hc5—‡œx”2ø(•bÁ2ä[rý“¬å* éBT°%᫦åÊQ–ÈjR{•‡À¦CöRy8 ;©bE·utGŸ\=`V>CXûœ²éWØy‹Þ6)äc bf㉣ÙôÅßc|‡Þ5A—™Ñr¸Xä¡ä”`y¤2ã'±=fCõáOˆïãÁÎWXû«.>•”¬¸¥÷Òp3xw 7_cÜç&4;•ñaüi¼ÂºÂÌ…UݹÌq8 NÓCV¬¦ÃH Í=Ýð–Nª¬*>DƒÛ«¶eRä¶ø ^Æo ÓÌb¹Yr´Fs8S¿¥2²ìGi‚Jï'©ð˜¶ÁÜ}À­é“9ç”Þ¹³ w[)Û@Y¢3w€–®,ÄSMµn%»ãÜŽ‘ÔÂ9à6Ü¡p¨9ì¢*J+xÉÃuΑ%Æù ¤"ðCúȬ12!mQð³ÁVmµd›vÒ\u¶äû6*•ù´m4>)"ÕIDÊ@¤Ÿ–»¬;¨ê ÛÉæÔf—‡®å0D„æ(tÚŽ’äz•/„B6A§Ñ'|1ýŽ/^/Õu9†gÙsŽ’z:*ú9bu”Æaþ–œßÒ Å>(Åc?3t¥,4=vx¯º’؉»µW£òÛ0Ãb:°ӆ˦º¨Íe©wYr7î$¼(5áGqoŽé`ª”»1Ïûƒáy)þªûšîuN»Ë‚=›áv%ò˜rB';PwìÐÝ1¹À=Ï(pÏJ(p!37âÛ°öO1Ê,ï_#Èû×ñ„Pƒz…øZèú:èúz$‚ÍTÀ7о‘fòM´ˆo¦zøÆ…|+ÝÌ·Ñ]|;ô{JÊ-ô6o¥OùNú‚ï¢/ùnúšï¡ox›®ÛûE·]TÚí§GTd½:D†é‚:Óì(ÌßËúìÎë¢Ê좃Á¡—˃PéÄb‚ ÞŽèa}ñª$óú•aì‹”ñahð:_úGGÑ~º ¥ã]qä_ãïoè·=‘/Œ!oJE~, ùwñJ-j&ÌY}C’*Óf¥+Ì8P»¹“Æñ~æ§ÓâÐÔ´øûøW½0°å"e}òý¸²œ%qrIQNž'σ“`f/R)¿”ÈI^*'ÿC09Ù`–ˆ'÷ÉI]2úêNº´ºÜ”$qsYIn^7¯ƒ›7i<¿ESùíDn†§róE\Gí¦Žfÿn.íEI—§SÒ0ó˜ùœŽã_Áû~Ḛ̀Tf¾ŒÕ.‰ß?‹ÑG_‘ò ‡¿D™÷ÇÜ?šïFœ,µ“b4ë–=½^( ØKö“ó·ÒùxÈ´l§æA‡Qšå^)ßЀcI­ã¢ø)º*^ÒIÊ’g1’ÐÚ[SZ{½«2X¸ZÊY#¹õ8¢ø¿¤}Aé ‹é2´c@¶GâÜÊ„þNÿƒ†òרo¾†þ‰ç[äÃïh.Ìz­þ]€´B@Qè0Zê }޶úïŠMצ‡Ú`»6\ÏuïWHƒû-yô†ØxKÒÓŸÐ3:¾Ñ4¸Óû “MO´%føk‹âížjªôv¨8¥R”¥ &·’Ec•l*UœT¦äÐ<%—*”!‰íP^J;ÄèjÓu¤¶”ŽTñ«´ j*èhŒ¥¿¥µ¦ÄQe,Æÿ{敦 ªûTy¿ÝëÒ¸ª2²*„¬Šh†RLåJI¢«¤ºêÿ 4¶Ïï%lü /ÓÁËñàeSN ÉÊÌ>cûßã±=bÆö“úæe^úà~}šà®œ VN+§Â„æÐ$¥<‘W*+ÿ@ b°2ÖŒ`ƒÐfоa?Ýx0Eˋ⨛õöò3€}€ƒa½t¨×[@ŒYÝ›„®T…à½Ýh¡7 Uã$Óv¡fšÏ†ºÍê¶é%œÛâ¶%Ä*6DÕ†JᦺÕC”+E\•°!ñnխаR~~9/]¿Ž[Ð-´uÉ­wÄ‹´“Ño“R WAÀÕ”¯,¦e)MUjèD¥–ª”::CYF­ÊrºDYA›•3èVe%íPVÑNeµ®ˆ‡hP–=«K~MÑë ”KGXJ&b„-걪Èòh³H‹/£¤’_¤´¤4»±Úl±JŽ€€@1Âæ³.³tCHa¶*IÙÿ¤oM;©7û³ ):-„mÞ¼[ä‹%‘éEš·r¶þ1nˆ)EýK ROÙJ¹”F¦4Å>ÄeÏ—Oމç~Bߙ続畤ž ÿ¼u¹z½G?Û…6*v¶þ‘BiÅÙ!œ¦áJPΡB%¢ó QFö"ð“ÄÄÑøå›±&L”æo1q›Îĺ],úŽbœ¾%I º ùÐy² ÎÒ(ey”‹â2¨N•Á÷±ÞX÷Q¥ÛGoKã£W%¡þk ¨×%¡vÉRQ7'¢â?%}P¹) êÍI¨A½-UcKükô(=Q*wë“töžd,cD‡ ÛþPK ЗWW¾<PKé|W META-INF/þÊPKé|W¸o67=META-INF/MANIFEST.MFPK é|Wµorg/PK é|W ×org/rosuda/PK é|Worg/rosuda/REngine/PK é|W1org/rosuda/REngine/Rserve/PKé|W¢Ÿ(©,iorg/rosuda/REngine/Rserve/OOBInterface.classPKé|W”-I* à+lorg/rosuda/REngine/Rserve/StartRserve.classPK é|W#ï org/rosuda/REngine/Rserve/protocol/PKé|W?¬É" ".0 org/rosuda/REngine/Rserve/protocol/RTalk.classPKé|WË„bª6/šorg/rosuda/REngine/Rserve/protocol/jcrypt.classPKé|W²,÷†¢0¡5org/rosuda/REngine/Rserve/protocol/RPacket.classPKé|W[ÆÃF ë44…8org/rosuda/REngine/Rserve/protocol/REXPFactory.classPKé|Wn7before connecting to the Rserve in case later Rserves will provide a possibility of setting the encoding during the handshake. */ public static String transferCharset="UTF-8"; /** authorization type: plain text */ public static final int AT_plain = 0; /** authorization type: unix crypt */ public static final int AT_crypt = 1; /** version of the server (as reported in IDstring just after Rsrv) */ protected int rsrvVersion; /** make a new local connection on default port (6311) */ public RConnection() throws RserveException { this("127.0.0.1",6311); } /** make a new connection to specified host on default port (6311) @param host host name/IP */ public RConnection(String host) throws RserveException { this(host,6311); } /** make a new connection to specified host and given port. * Make sure you check {@link #isConnected} to ensure the connection was successfully created. * @param host host name/IP * @param port TCP port */ public RConnection(String host, int port) throws RserveException { this(host, port, null); } /** restore a connection based on a previously detached session * @param session detached session object */ RConnection(RSession session) throws RserveException { this(null, 0, session); } RConnection(String host, int port, RSession session) throws RserveException { try { if (connected) s.close(); s = null; } catch (Exception e) { throw new RserveException(this, "Cannot close previous connection: " + e.getMessage(), e); } if (session != null) { host = session.host; port = session.port; } connected = false; this.host = host; this.port = port; try { Socket ss = new Socket(host,port); // disable Nagle's algorithm since we really want immediate replies ss.setTcpNoDelay(true); initWithSocket(ss, session); } catch (Exception sce) { throw new RserveException(this, "Cannot connect: "+sce.getMessage(), sce); } } /** create a connection based on a previously obtained socket. This constructor allows the use of other communication protocols than TCP/IP (if a Socket implementation exists) or tunneling through other protocols that expose socket insteface (such as SSL). @param sock connected socket */ public RConnection(Socket sock) throws RserveException { this.host = null; this.port = 0; try { if (connected) s.close(); connected = false; s = null; } catch (Exception e) { throw new RserveException(this, "Cannot close previous connection: " + e.getMessage(), e); } initWithSocket(sock, null); } /** set OOB callbacks, i.e. an object that will handle OOB_SEND and OOB_MSG packets in OCAP mode @param callbacks object implementing the OOB interface */ public void setOOB(OOBInterface callbacks) { oob = callbacks; } /** initialization in OCAP mode, assumes all communication variables are setup already, expected to be called by initWithSocket */ private void initOCAP(Socket sock, byte[] header) throws RserveException { /* there is no version in OCAP but 103 is assumed since that is the earliest version that supports OCAPs */ rsrvVersion = 103; isOCAP = true; connected = true; RPacket rp = rt.response(header); capabilities = parseEvalResponse(rp); } private void initWithSocket(Socket sock, RSession session) throws RserveException { s = sock; try { is = s.getInputStream(); os = s.getOutputStream(); } catch (Exception gse) { throw new RserveException(this, "Cannot get io stream: " + gse.getMessage(), gse); } rt = new RTalk(is,os); if (session==null) { byte[] IDs=new byte[32]; int n=-1; try { n=is.read(IDs); } catch (Exception sre) { throw new RserveException(this, "Error while receiving data: "+sre.getMessage(), sre); } try { /* is this OCAP mode ? */ if (n >= 16 && IDs[0] == 0x52 && IDs[1] == 0x73 && IDs[2] == 0x4f && IDs[3] == 0x43) { /* it is possible that the buffering doesn't work out and the first packet is <32 bytes, in which case we have to re-wrap the array to have the correct length */ if (n < 32) { byte[] header = new byte[n]; System.arraycopy(IDs, 0, header, 0, n); IDs = header; } initOCAP(sock, IDs); return; } if (n!=32) { throw new RserveException(this,"Handshake failed: expected 32 bytes header, got "+n); } String ids = new String(IDs); /* regular Rserve mode? */ if (ids.substring(0,4).compareTo("Rsrv")!=0) throw new RserveException(this, "Handshake failed: Rsrv signature expected, but received \""+ids+"\" instead."); try { rsrvVersion=Integer.parseInt(ids.substring(4,8)); } catch (Exception px) {} // we support (knowingly) up to 103 if (rsrvVersion > 103) throw new RserveException(this, "Handshake failed: The server uses more recent protocol than this client."); if (ids.substring(8,12).compareTo("QAP1")!=0) throw new RserveException(this, "Handshake failed: unupported transfer protocol ("+ids.substring(8,12)+"), I talk only QAP1."); for (int i=12; i<32; i+=4) { String attr=ids.substring(i,i+4); if (attr.compareTo("ARpt")==0) { if (!authReq) { // this method is only fallback when no other was specified authReq=true; authType=AT_plain; } authPlainAllowed = true; } if (attr.compareTo("ARuc")==0) { authReq=true; authType=AT_crypt; } if (attr.charAt(0)=='K') { Key=attr.substring(1,3); } } } catch (RserveException innerX) { try { s.close(); } catch (Exception ex01) {}; is=null; os=null; s=null; throw innerX; } } else { // we have a session to take care of try { os.write(session.key,0,32); } catch (Exception sre) { throw new RserveException(this, "Error while sending session key: " + sre.getMessage(), sre); } rsrvVersion = session.rsrvVersion; } connected=true; lastError="OK"; } public void finalize() { close(); is=null; os=null; } /** get server version as reported during the handshake. @return server version as integer (Rsrv0100 will return 100) */ public int getServerVersion() { return rsrvVersion; } /** closes current connection */ public boolean close() { try { if (s != null) s.close(); connected = false; return true; } catch(Exception e) { }; return false; } /** Returns capabilities received from the server on connect. For non-OCAP mode this always returns null */ public REXP capabilities() { return capabilities; } /** Check whether this connection is to Rserve in OCAP mode. Note that callOC is the only command allowed in OCAP mode. @return true if this connection is in OCAP mode, false otherwise. */ public boolean isOCAP() { return isOCAP; } /** evaluates the given command, but does not fetch the result (useful for assignment operations) @param cmd command/expression string */ public void voidEval(String cmd) throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); RPacket rp=rt.request(RTalk.CMD_voidEval,cmd+"\n"); if (rp!=null && rp.isOk()) return; throw new RserveException(this,"voidEval failed",rp); } /** evaluates the given command, detaches the session (see @link{detach()}) and closes connection while the command is being evaluted (requires Rserve 0.4+). Note that a session cannot be attached again until the commad was successfully processed. Techincally the session is put into listening mode while the command is being evaluated but accept is called only after the command was evaluated. One commonly used techique to monitor detached working sessions is to use second connection to poll the status (e.g. create a temporary file and return the full path before detaching thus allowing new connections to read it). @param cmd command/expression string @return session object that can be use to attach back to the session once the command completed */ public RSession voidEvalDetach(String cmd) throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); RPacket rp=rt.request(RTalk.CMD_detachedVoidEval,cmd+"\n"); if (rp==null || !rp.isOk()) throw new RserveException(this,"detached void eval failed",rp); RSession s = new RSession(this, rp); close(); return s; } REXP parseEvalResponse(RPacket rp) throws RserveException { int rxo=0; byte[] pc=rp.getCont(); if (rsrvVersion>100) { /* since 0101 eval responds correctly by using DT_SEXP type/len header which is 4 bytes long */ rxo=4; /* we should check parameter type (should be DT_SEXP) and fail if it's not */ if (pc[0]!=RTalk.DT_SEXP && pc[0]!=(RTalk.DT_SEXP|RTalk.DT_LARGE)) throw new RserveException(this,"Error while processing eval output: SEXP (type "+RTalk.DT_SEXP+") expected but found result type "+pc[0]+"."); if (pc[0]==(RTalk.DT_SEXP|RTalk.DT_LARGE)) rxo=8; // large data need skip of 8 bytes /* warning: we are not checking or using the length - we assume that only the one SEXP is returned. This is true for the current CMD_eval implementation, but may not be in the future. */ } if (pc.length>rxo) { try { REXPFactory rx=new REXPFactory(); rx.parseREXP(pc, rxo); return rx.getREXP(); } catch (REXPMismatchException me) { me.printStackTrace(); throw new RserveException(this, "Error when parsing response: " + me.getMessage(), me); } } return null; } /** evaluates the given command and retrieves the result @param cmd command/expression string @return R-xpression or null if an error occured */ public REXP eval(String cmd) throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); RPacket rp=rt.request(RTalk.CMD_eval,cmd+"\n"); if (rp!=null && rp.isOk()) return parseEvalResponse(rp); throw new RserveException(this,"eval failed",rp); } /** assign a string value to a symbol in R. The symbol is created if it doesn't exist already. @param sym symbol name. Currently assign uses CMD_setSEXP command of Rserve, i.e. the symbol value is NOT parsed. It is the responsibility of the user to make sure that the symbol name is valid in R (recall the difference between a symbol and an expression!). In fact R will always create the symbol, but it may not be accessible (examples: "bar\nfoo" or "bar$foo"). @param ct contents */ public void assign(String sym, String ct) throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); try { byte[] symn = sym.getBytes(transferCharset); byte[] ctn = ct.getBytes(transferCharset); int sl = symn.length + 1; int cl = ctn.length + 1; if ((sl & 3) > 0) sl = (sl & 0xfffffc) + 4; // make sure the symbol length is divisible by 4 if ((cl & 3) > 0) cl = (cl & 0xfffffc) + 4; // make sure the content length is divisible by 4 byte[] rq=new byte[sl + 4 + cl + 4]; int ic; for (ic = 0;ic < symn.length; ic++) rq[ic + 4] = symn[ic]; while (ic < sl) { rq[ic + 4] = 0; ic++; } for (ic = 0; ic < ctn.length; ic++) rq[ic + sl + 8] = ctn[ic]; while (ic < cl) { rq[ic + sl + 8] = 0; ic++; } RTalk.setHdr(RTalk.DT_STRING, sl, rq, 0); RTalk.setHdr(RTalk.DT_STRING, cl, rq, sl + 4); RPacket rp = rt.request(RTalk.CMD_setSEXP, rq); if (rp !=null && rp.isOk()) return; throw new RserveException(this, "assign failed", rp); } catch(java.io.UnsupportedEncodingException e) { throw new RserveException(this, "unsupported encoding in assign(String,String)", e); } } public REXP callOCAP(REXP call) throws RserveException { if (!connected || rt == null) throw new RserveException(this, "Not connected"); if (!isOCAP) throw new RserveException(this, "callOCAP is only available in OCAP mode"); RPacket rp = rt.request(RTalk.CMD_OCcall, call); /* process any OOB messages */ while (rp != null && rp.isOOB()) { REXP payload = parseEvalResponse(rp); if ((rp.getCmd() & 0xff000) == RTalk.OOB_SEND) { if (oob != null) oob.oobSend(rp.getCmd() & 0xfff, payload); rp = rt.response(); } else if ((rp.getCmd() & 0xff000) == RTalk.OOB_MSG) { if (oob == null) throw new RserveException(this, "OOB_MSG received, but no OOB listener registered", rp); REXP res = oob.oobMessage(rp.getCmd() & 0xfff, payload); if (res == null) throw new RserveException(this, "OOB_MSG callback returned null", rp); // FIXME: we don't have official documentation for this - what is the // correct response to OOB_MSG? rserve-js uses cmd | RESP_OK/RESP_ERR // but that mangles low two bits of the OOB code // Rserve itself doesn't care so it is technically undefined // The most senstible thing to do is to just copy the cmd since // the recieving end knows that this is a msg response rp = rt.request(rp.getCmd(), res); } else throw new RserveException(this, "Unsupported OOB command received", rp); } if (rp == null || !rp.isOk()) throw new RserveException(this,"callOCAP failed", rp); return parseEvalResponse(rp); } /** assign a content of a REXP to a symbol in R. The symbol is created if it doesn't exist already. * @param sym symbol name. Currently assign uses CMD_setSEXP command of Rserve, i.e. the symbol value is NOT parsed. It is the responsibility of the user to make sure that the symbol name is valid in R (recall the difference between a symbol and an expression!). In fact R will always create the symbol, but it may not be accessible (examples: "bar\nfoo" or "bar$foo"). * @param rexp contents */ public void assign(String sym, REXP rexp) throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); try { REXPFactory r = new REXPFactory(rexp); int rl = r.getBinaryLength(); byte[] symn = sym.getBytes(transferCharset); int sl = symn.length+1; if ((sl&3)>0) sl=(sl&0xfffffc)+4; // make sure the symbol length is divisible by 4 byte[] rq=new byte[sl+rl+((rl>0xfffff0)?12:8)]; int ic; for(ic=0;ic0xfffff0)?12:8)); RPacket rp=rt.request(RTalk.CMD_setSEXP,rq); if (rp!=null && rp.isOk()) return; throw new RserveException(this,"assign failed",rp); } catch(java.io.UnsupportedEncodingException e) { throw new RserveException(this, "unsupported encoding in assign(String,REXP)", e); } catch (REXPMismatchException me) { throw new RserveException(this, "Error creating binary representation: "+me.getMessage(), me); } } /** open a file on the Rserve for reading @param fn file name. should not contain any path delimiters, since Rserve may restrict the access to local working directory. @return input stream to be used for reading. Note that the stream is read-once only, there is no support for seek or rewind. */ public RFileInputStream openFile(String fn) throws IOException { return new RFileInputStream(rt,fn); } /** create a file on the Rserve for writing @param fn file name. should not contain any path delimiters, since Rserve may restrict the access to local working directory. @return output stream to be used for writinging. Note that the stream is write-once only, there is no support for seek or rewind. */ public RFileOutputStream createFile(String fn) throws IOException { return new RFileOutputStream(rt,fn); } /** remove a file on the Rserve @param fn file name. should not contain any path delimiters, since Rserve may restrict the access to local working directory. */ public void removeFile(String fn) throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); RPacket rp=rt.request(RTalk.CMD_removeFile,fn); if (rp!=null && rp.isOk()) return; throw new RserveException(this,"removeFile failed",rp); } /** shutdown remote Rserve. Note that some Rserves cannot be shut down from the client side. */ public void shutdown() throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); RPacket rp=rt.request(RTalk.CMD_shutdown); if (rp!=null && rp.isOk()) return; throw new RserveException(this,"shutdown failed",rp); } /** Sets send buffer size of the Rserve (in bytes) for the current connection. All responses send by Rserve are stored in the send buffer before transmitting. This means that any objects you want to get from the Rserve need to fit into that buffer. By default the size of the send buffer is 2MB. If you need to receive larger objects from Rserve, you will need to use this function to enlarge the buffer. In order to save memory, you can also reduce the buffer size once it's not used anymore. Currently the buffer size is only limited by the memory available and/or 1GB (whichever is smaller). Current Rserve implementations won't go below buffer sizes of 32kb though. If the specified buffer size results in 'out of memory' on the server, the corresponding error is sent and the connection is terminated.
Note: This command may go away in future versions of Rserve which will use dynamic send buffer allocation. @param sbs send buffer size (in bytes) min=32k, max=1GB */ public void setSendBufferSize(long sbs) throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); RPacket rp=rt.request(RTalk.CMD_setBufferSize,(int)sbs); if (rp!=null && rp.isOk()) return; throw new RserveException(this,"setSendBufferSize failed",rp); } /** set string encoding for this session. It is strongly * recommended to make sure the encoding is always set to UTF-8 * because that is the only encoding supported by this Java * client. It can be done either by uisng the * encoding option in the server or by calling * setStringEncoding("utf8") at the beginning of a session (but * after login). @param enc name of the encoding as defined by Rserve - as of Rserve version 0.5-3 valid values are "utf8", "latin1" and "native" (case-sensitive) @since Rserve 0.5-3 */ public void setStringEncoding(String enc) throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); RPacket rp = rt.request(RTalk.CMD_setEncoding, enc); if (rp != null && rp.isOk()) return; throw new RserveException(this,"setStringEncoding failed", rp); } /** login using supplied user/pwd. Note that login must be the first command if used @param user username @param pwd password */ public void login(String user, String pwd) throws RserveException { login(user, pwd, false); } /** login using supplied user/pwd. Note that login must be the first command if used @param user username @param pwd password @param forcePlain if false (default) then crypt-based authentication is used if supported by the server, otherwise plain text password will be used. Note that crypt-based authentication cannot be used with passwords stored as hashes so in those cases true is needed here. */ public void login(String user, String pwd, boolean forcePlain) throws RserveException { if (!authReq) return; if (!connected || rt==null) throw new RserveException(this,"Not connected"); if (forcePlain) /* ignore forcePlain if not allowed */ forcePlain = authPlainAllowed; if (!forcePlain && authType == AT_crypt) { if (Key==null) Key="rs"; RPacket rp=rt.request(RTalk.CMD_login,user+"\n"+jcrypt.crypt(Key,pwd)); if (rp!=null && rp.isOk()) return; try { s.close(); } catch(Exception e) {}; is=null; os=null; s=null; connected=false; throw new RserveException(this, "crypt-based login failed", rp); } RPacket rp=rt.request(RTalk.CMD_login,user+"\n"+pwd); if (rp!=null && rp.isOk()) return; try {s.close();} catch (Exception e) {}; is=null; os=null; s=null; connected=false; throw new RserveException(this, "plain text login failed", rp); } /** detaches the session and closes the connection (requires Rserve 0.4+). The session can be only resumed by calling @link{RSession.attach} */ public RSession detach() throws RserveException { if (!connected || rt==null) throw new RserveException(this,"Not connected"); RPacket rp=rt.request(RTalk.CMD_detachSession); if (rp==null || !rp.isOk()) throw new RserveException(this,"Cannot detach",rp); RSession s = new RSession(this, rp); close(); return s; } /** check connection state. Note that currently this state is not checked on-the-spot, that is if connection went down by an outside event this is not reflected by the flag @return true if this connection is alive */ public boolean isConnected() { return connected; } /** check authentication requirement sent by server @return true is server requires authentication. In such case first command after connecting must be {@link #login}. */ public boolean needLogin() { return authReq; } /** get last error string @return last error string */ public String getLastError() { return lastError; } /** evaluates the given command in the master server process asynchronously (control command). Note that control commands are always asynchronous, i.e., the expression is enqueued for evaluation in the master process and the method returns before the expression is evaluated (in non-parallel builds the client has to close the connection before the expression can be evaluated). There is no way to check for errors and control commands should be sent with utmost care as they can abort the server process. The evaluation has no immediate effect on the client session. * @param cmd command/expression string * @since Rserve 0.6-0 */ public void serverEval(String cmd) throws RserveException { if (!connected || rt == null) throw new RserveException(this, "Not connected"); RPacket rp = rt.request(RTalk.CMD_ctrlEval, cmd+"\n"); if (rp != null && rp.isOk()) return; throw new RserveException(this,"serverEval failed",rp); } /** sources the given file (the path must be local to the server!) in the master server process asynchronously (control command). See {@link #serverEval()} for details on control commands. * @param serverFile path to a file on the server (it is recommended to always use full paths, because the server process has a different working directory than the client child process!). * @since Rserve 0.6-0 */ public void serverSource(String serverFile) throws RserveException { if (!connected || rt == null) throw new RserveException(this, "Not connected"); RPacket rp = rt.request(RTalk.CMD_ctrlSource, serverFile); if (rp != null && rp.isOk()) return; throw new RserveException(this,"serverSource failed",rp); } /** attempt to shut down the server process cleanly. Note that there is a fundamental difference between the {@link shutdown()} method and this method: serverShutdown() is a proper control command and thus fully authentication controllable, whereas {@link shutdown()} is a client-side command sent to the client child process and thus relying on the ability of the client to signal the server process which may be disabled. Therefore serverShutdown() is preferred and more reliable for Rserve 0.6-0 and higher. * @since Rserve 0.6-0 */ public void serverShutdown() throws RserveException { if (!connected || rt == null) throw new RserveException(this, "Not connected"); RPacket rp = rt.request(RTalk.CMD_ctrlShutdown); if (rp != null && rp.isOk()) return; throw new RserveException(this,"serverShutdown failed",rp); } //========= REngine interface API public REXP parse(String text, boolean resolve) throws REngineException { throw new REngineException(this, "Rserve doesn't support separate parsing step."); } public REXP eval(REXP what, REXP where, boolean resolve) throws REngineException { if (!connected || rt==null) throw new RserveException(this, "Not connected"); if (where != null) throw new REngineException(this, "Rserve doesn't support environments other than .GlobalEnv"); try { REXPFactory r = new REXPFactory(what); int rl = r.getBinaryLength(); byte[] rq = new byte[rl + ((rl > 0xfffff0) ? 8 : 4)]; RTalk.setHdr(RTalk.DT_SEXP, rl, rq, 0); r.getBinaryRepresentation(rq, ((rl > 0xfffff0) ? 8 : 4)); RPacket rp = rt.request(resolve ? RTalk.CMD_eval : RTalk.CMD_voidEval, rq); if (rp != null && rp.isOk()) return parseEvalResponse(rp); throw new RserveException(this,"eval failed", rp); } catch (REXPMismatchException me) { throw new RserveException(this, "Error creating binary representation: " + me.getMessage(), me); } } public REXP parseAndEval(String text, REXP where, boolean resolve) throws REngineException { if (where!=null) throw new REngineException(this, "Rserve doesn't support environments other than .GlobalEnv"); try { return eval(text); } catch (RserveException re) { throw new REngineException(this, re.getMessage(), re); } } /** assign into an environment @param symbol symbol name @param value value to assign @param env environment to assign to */ public void assign(String symbol, REXP value, REXP env) throws REngineException { if (env!=null) throw new REngineException(this, "Rserve doesn't support environments other than .GlobalEnv"); try { assign(symbol, value); } catch (RserveException re) { throw new REngineException(this, re.getMessage(), re); } } /** get a value from an environment @param symbol symbol name @param env environment @param resolve resolve the resulting REXP or just return a reference @return value */ public REXP get(String symbol, REXP env, boolean resolve) throws REngineException { if (!resolve) throw new REngineException(this, "Rserve doesn't support references"); try { return eval(new REXPSymbol(symbol), env, true); } catch (RserveException re) { throw new REngineException(this, re.getMessage()); } } /** fetch the contents of the given reference. The resulting REXP may never be REXPReference. @param ref reference to resolve @return resolved reference */ public REXP resolveReference(REXP ref) throws REngineException { throw new REngineException(this, "Rserve doesn't support references"); } public REXP createReference(REXP ref) throws REngineException { throw new REngineException(this, "Rserve doesn't support references"); } public void finalizeReference(REXP ref) throws REngineException { throw new REngineException(this, "Rserve doesn't support references"); } public REXP getParentEnvironment(REXP env, boolean resolve) throws REngineException { throw new REngineException(this, "Rserve doesn't support environments other than .GlobalEnv"); } public REXP newEnvironment(REXP parent, boolean resolve) throws REngineException { throw new REngineException(this, "Rserve doesn't support environments other than .GlobalEnv"); } } Rserve/src/client/java/REXPNull.java0000644000175100001440000000174014531234224017002 0ustar hornikuserspackage org.rosuda.REngine; /** represents a NULL object in R.

Note: there is a slight asymmetry - in R NULL is represented by a zero-length pairlist. For this reason REXPNull returns true for {@link #isList()} and {@link #asList()} will return an empty list. Nonetheless REXPList of the length 0 will NOT return true in {@link #isNull()} (currently), becasue it is considered a different object in Java. These nuances are still subject to change, because it's not clear how it should be treated. At any rate use REXPNull instead of empty REXPList if NULL is the intended value. */ public class REXPNull extends REXP { public REXPNull() { super(); } public REXPNull(REXPList attr) { super(attr); } public boolean isNull() { return true; } public boolean isList() { return true; } // NULL is a list public RList asList() { return new RList(); } public Object asNativeJavaObject() { return null; } } Rserve/src/client/java/REXPLanguage.java0000644000175100001440000000043614531234224017614 0ustar hornikuserspackage org.rosuda.REngine; /** represents a language object in R */ public class REXPLanguage extends REXPList { public REXPLanguage(RList list) { super(list); } public REXPLanguage(RList list, REXPList attr) { super(list, attr); } public boolean isLanguage() { return true; } } Rserve/src/client/java/REngineInputInterface.java0000644000175100001440000000157314531234224021565 0ustar hornikuserspackage org.rosuda.REngine; /** interface defining delegate methods used by {@link REngine} to forward input callbacks from R. */ public interface REngineInputInterface { /** called when R enters the read stage of the event loop. *

Important: implementations should never use a direct return! That will cause a tigh-spinning event loop. Implementation must wait for input asynchronously (e.g., declare synchonized RReadConsole and use wait()) and return only when a complete line is available for processing. * @param eng calling engine * @param prompt prompt to display in the console * @param addToHistory flag indicating whether the input is transient (false) or to be recorded in the command history (true). * @return string to be processed as console input */ public String RReadConsole(REngine eng, String prompt, int addToHistory); } Rserve/src/client/java/REXPRaw.java0000644000175100001440000000151414531234224016620 0ustar hornikuserspackage org.rosuda.REngine; /** REXPRaw represents a raw vector in R - essentially a sequence of bytes. */ public class REXPRaw extends REXPVector { private byte[] payload; /** create a new raw vector with the specified payload * @param load payload of the raw vector */ public REXPRaw(byte[] load) { super(); payload=(load==null)?new byte[0]:load; } /** create a new raw vector with the specified payload and attributes * @param load payload of the raw vector * @param attr attributes for the resulting R object */ public REXPRaw(byte[] load, REXPList attr) { super(attr); payload=(load==null)?new byte[0]:load; } public int length() { return payload.length; } public boolean isRaw() { return true; } public byte[] asBytes() { return payload; } public Object asNativeJavaObject() { return payload; } } Rserve/src/client/java/RFactor.java0000644000175100001440000001355114531234224016734 0ustar hornikuserspackage org.rosuda.REngine; // REngine // Copyright (C) 2007 Simon Urbanek // --- for licensing information see LICENSE file in the original distribution --- import java.util.*; /** representation of a factor variable. In R there is no actual object type called "factor", instead it is coded as an int vector with a list attribute. The parser code of REXP converts such constructs directly into the RFactor objects and defines an own XT_FACTOR type @version $Id$ */ public class RFactor { int ids[]; String levels[]; int index_base; /** create a new, empty factor var */ public RFactor() { ids=new int[0]; levels=new String[0]; } /** create a new factor variable, based on the supplied arrays. @param i array of IDs (inde_base..v.length+index_base-1) @param v values - cotegory names @param copy copy above vaules or just retain them @param index_base index of the first level element (1 for R factors, cannot be negtive) */ public RFactor(int[] i, String[] v, boolean copy, int index_base) { if (i==null) i = new int[0]; if (v==null) v = new String[0]; if (copy) { ids=new int[i.length]; System.arraycopy(i,0,ids,0,i.length); levels=new String[v.length]; System.arraycopy(v,0,levels,0,v.length); } else { ids=i; levels=v; } this.index_base = index_base; } /** create a new factor variable by factorizing a given string array. The levels will be created in the orer of appearance. @param c contents @param index_base base of the level index */ public RFactor(String c[], int index_base) { this.index_base = index_base; if (c == null) c = new String[0]; Vector lv = new Vector(); ids = new int[c.length]; int i = 0; while (i < c.length) { int ix = (c[i]==null)?-1:lv.indexOf(c[i]); if (ix<0 && c[i]!=null) { ix = lv.size(); lv.add(c[i]); } ids[i] = (ix<0)?REXPInteger.NA:(ix+index_base); i++; } levels = new String[lv.size()]; i = 0; while (i < levels.length) { levels[i] = (String) lv.elementAt(i); i++; } } /** same as RFactor(c, 1) */ public RFactor(String c[]) { this(c, 1); } /** same as RFactor(i,v, true, 1) */ public RFactor(int[] i, String[] v) { this(i, v, true, 1); } /** returns the level of a given case @param i case number @return name. may throw exception if out of range */ public String at(int i) { int li = ids[i] - index_base; return (li<0||li>levels.length)?null:levels[li]; } /** returns true if the data contain the given level index */ public boolean contains(int li) { int i = 0; while (i < ids.length) { if (ids[i] == li) return true; i++; } return false; } /** return true if the factor contains the given level (it is NOT the same as levelIndex==-1!) */ public boolean contains(String name) { int li = levelIndex(name); if (li<0) return false; int i = 0; while (i < ids.length) { if (ids[i] == li) return true; i++; } return false; } /** count the number of occurences of a given level index */ public int count(int levelIndex) { int i = 0; int ct = 0; while (i < ids.length) { if (ids[i] == levelIndex) ct++; i++; } return ct; } /** count the number of occurences of a given level name */ public int count(String name) { return count(levelIndex(name)); } /** return an array with level counts. */ public int[] counts() { int[] c = new int[levels.length]; int i = 0; while (i < ids.length) { final int li = ids[i] - index_base; if (li>=0 && lilevels.length)?null:levels[li]; } /** return the level index for a given case */ public int indexAt(int i) { return ids[i]; } /** return the factor as an array of strings */ public String[] asStrings() { String[] s = new String[ids.length]; int i = 0; while (i < ids.length) { s[i] = at(i); i++; } return s; } /** return the base of the levels index */ public int indexBase() { return index_base; } /** returns the number of cases */ public int size() { return ids.length; } public String toString() { return super.toString()+"["+ids.length+","+levels.length+",#"+index_base+"]"; } /** displayable representation of the factor variable public String toString() { //return "{"+((val==null)?";":("levels="+val.size()+";"))+((id==null)?"":("cases="+id.size()))+"}"; StringBuffer sb=new StringBuffer("{levels=("); if (val==null) sb.append("null"); else for (int i=0;i0)?",\"":"\""); sb.append((String)val.elementAt(i)); sb.append("\""); }; sb.append("),ids=("); if (id==null) sb.append("null"); else for (int i=0;i0) sb.append(","); sb.append((Integer)id.elementAt(i)); }; sb.append(")}"); return sb.toString(); } */ } Rserve/src/client/java/REXPUnknown.java0000644000175100001440000000175314531234224017533 0ustar hornikuserspackage org.rosuda.REngine; /** REXPUnknown is a stand-in for an object that cannot be represented in the REngine hierarchy. Usually this class can be encountered when new types are introduced in R or if a given engine doesn't support all data types. Usually REXPUnknown can only be retrieved from the engine but never assigned. */ public class REXPUnknown extends REXP { /** type of the unterlying obejct */ int type; /** creates a new unknown object of the given type * @param type internal R type code of this object */ public REXPUnknown(int type) { super(); this.type=type; } /** creates a new unknown object of the given type * @param type internal R type code of this object * @param attr attributes */ public REXPUnknown(int type, REXPList attr) { super(attr); this.type=type; } /** returns the internal R type of this unknown obejct * @return type code */ public int getType() { return type; } public String toString() { return super.toString()+"["+type+"]"; } } Rserve/src/client/java/REXPInteger.java0000644000175100001440000000415714531234224017472 0ustar hornikuserspackage org.rosuda.REngine; /** REXPDouble represents a vector of integer values. */ public class REXPInteger extends REXPVector { protected int[] payload; /** NA integer value as defined in R. Unlike its real equivalent this one can be used in comparisons, although {@link #isNA(int) } is provided for consistency. */ public static final int NA = -2147483648; public static boolean isNA(int value) { return (value == NA); } /** create integer vector of the length 1 with the given value as its first (and only) element */ public REXPInteger(int load) { super(); payload=new int[] { load }; } /** create integer vector with the payload specified by load */ public REXPInteger(int[] load) { super(); payload=(load==null)?new int[0]:load; } /** create integer vector with the payload specified by load and attributes attr */ public REXPInteger(int[] load, REXPList attr) { super(attr); payload=(load==null)?new int[0]:load; } public Object asNativeJavaObject() { return payload; } public int length() { return payload.length; } public boolean isInteger() { return true; } public boolean isNumeric() { return true; } public int[] asIntegers() { return payload; } /** returns the contents of this vector as doubles */ public double[] asDoubles() { double[] d = new double[payload.length]; int i = 0; while (i < payload.length) { d[i] = (double) payload[i]; i++; } return d; } /** returns the contents of this vector as strings */ public String[] asStrings() { String[] s = new String[payload.length]; int i = 0; while (i < payload.length) { s[i] = ""+payload[i]; i++; } return s; } public boolean[] isNA() { boolean a[] = new boolean[payload.length]; int i = 0; while (i < a.length) { a[i] = (payload[i]==NA); i++; } return a; } public String toDebugString() { StringBuffer sb = new StringBuffer(super.toDebugString()+"{"); int i = 0; while (i < payload.length && i < maxDebugItems) { if (i>0) sb.append(","); sb.append(payload[i]); i++; } if (i < payload.length) sb.append(",.."); return sb.toString()+"}"; } } Rserve/src/client/java/package-info.java0000644000175100001440000000011014531234224017703 0ustar hornikusers/** * High level java interface to R */ package org.rosuda.REngine ; Rserve/src/client/java/REXPExpressionVector.java0000644000175100001440000000137514531234224021416 0ustar hornikuserspackage org.rosuda.REngine; /** REXPExpressionVector represents a vector of expressions in R. It is essentially a special kind of generic vector - its elements are expected to be valid R expressions. */ public class REXPExpressionVector extends REXPGenericVector { /** create a new vector of expressions from a list of expressions. * @param list list of expressions to store in this vector */ public REXPExpressionVector(RList list) { super(list); } /** create a new vector of expressions from a list of expressions. * @param list list of expressions to store in this vector * @param attr attributes for the R object */ public REXPExpressionVector(RList list, REXPList attr) { super(list, attr); } public boolean isExpression() { return true; } } Rserve/src/client/php/0000755000175100001440000000000014531234224014372 5ustar hornikusersRserve/src/client/php/simple.php0000644000175100001440000002675414531234224016412 0ustar hornikusers>= 8; $r .= chr($i & 255); $i >>=8; $r .= chr($i & 255); $i >>=8; $r .= chr($i & 255); return $r; } function mkint24($i) { $r = chr($i & 255); $i >>= 8; $r .= chr($i & 255); $i >>=8; $r .= chr($i & 255); return $r; } function flt64($buf, $o=0) { $ss = substr($buf, $o, 8); if ($machine_is_bigendian) for ($k = 0; $k < 7; $k++) $ss[7 - $k] = $buf[$o + $k]; $r = unpack("d", substr($buf, $o, 8)); return $r[1]; } function mkp_str($cmd, $string) { $n = strlen($string) + 1; $string .= chr(0); while (($n & 3) != 0) { $string .= chr(1); $n++; } return mkint32($cmd) . mkint32($n + 4) . mkint32(0) . mkint32(0) . chr(4) . mkint24($n) . $string; } function get_rsp($socket) { $n = socket_recv($socket, $buf, 16, 0); if ($n != 16) return FALSE; $len = int32($buf, 4); $ltg = $len; while ($ltg > 0) { $n = socket_recv($socket, $b2, $ltg, 0); if ($n > 0) { $buf .= $b2; unset($b2); $ltg -= $n; } else break; } return $buf; } // parse SEXP results -- limited implementation for now (large packets and some data types are not supported) function parse_SEXP($buf, &$offset, &$attr = NULL) { $r = $buf; $i = $offset; // some simple parsing - just skip attributes and assume short responses $ra = int8($r, $i); $rl = int24($r, $i + 1); $i += 4; $offset = $eoa = $i + $rl; // echo "[data type ".($ra & 63).", length ".$rl." with payload from ".$i." to ".$eoa."]
\n"; if (($ra & 64) == 64) { echo "sorry, long packets are not supported (yet)."; return FALSE; } if ($ra > 127) { $ra &= 127; $al = int24($r, $i + 1); $attr = parse_SEXP($buf, $i); $i += $al + 4; } if ($ra == 0) return NULL; if ($ra == 16) { // generic vector $a = array(); while ($i < $eoa) $a[] = parse_SEXP($buf, /* & */ $i); // if the 'names' attribute is set, convert the plain array into a map if (isset($attr['names'])) { $names = $attr['names']; $na = array(); $n = count($a); for ($k = 0; $k < $n; $k++) $na[$names[$k]] = $a[$k]; return $na; } return $a; } if ($ra == 19) { // symbol $oi = $i; while ($i < $eoa && ord($r[$i]) != 0) $i++; return substr($buf, $oi, $i - $oi); } if ($ra == 20 || $ra == 22) { // pairlist w/o tags $a = array(); while ($i < $eoa) $a[] = parse_SEXP($buf, /* & */ $i); return $a; } if ($ra == 21 || $ra == 23) { // pairlist with tags $a = array(); while ($i < $eoa) { $val = parse_SEXP($buf, /* & */ $i); $tag = parse_SEXP($buf, /* & */ $i); $a[$tag] = $val; } return $a; } if ($ra == 32) { // integer array $a = array(); while ($i < $eoa) { $a[] = int32($r, $i); $i += 4; } if (count($a) == 1) return $a[0]; return $a; } if ($ra == 33) { // double array $a = array(); while ($i < $eoa) { $a[] = flt64($r, $i); $i += 8; } if (count($a) == 1) return $a[0]; return $a; } if ($ra == 34) { // string array $a = array(); $oi = $i; while ($i < $eoa) { if (ord($r[$i]) == 0) { $a[] = substr($r, $oi, $i - $oi); $oi = $i + 1; } $i++; } if (count($a) == 1) return $a[0]; return $a; } if ($ra == 36) { // boolean vector $n = int32($r, $i); $i += 4; $k = 0; $a = array(); while ($k < $n) { $v = int8($r, $i++); $a[$k++] = ($v == 1) ? TRUE : (($v == 0) ? FALSE : NULL); } if ($n == 1) return $a[0]; return $a; } if ($ra == 37) { // raw vector $len = int32($r, $i); $i += 4; return substr($r, $i, $len); } if ($ra == 48) { // unimplemented type in Rserve $uit = int32($r, $i); // echo "Note: result contains type #$uit unsupported by Rserve.
"; return NULL; } echo "Warning: type ".$ra." is currently not implemented in the PHP client."; return FALSE; } //------------ Rserve API functions // if port is 0 then host is interpreted as unix socket, otherwise host is the host to connect to (default is local) and port is the TCP port number (6311 is the default) function Rserve_connect($host="127.0.0.1", $port=6311) { if ($port == 0) $ok = (($socket = socket_create(AF_UNIX, SOCK_STREAM, 0)) and (socket_connect($socket, $host))); else $ok = (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) and (socket_connect($socket, $host, $port))); if ($ok) { $n = socket_recv($socket, $buf, 32, 0); if ($n < 32 || strncmp($buf, "Rsrv", 4) != 0) { echo "Invalid response from server."; return FALSE; } $rv = substr($buf, 4, 4); if (strcmp($rv, "0103") != 0) { echo "Unsupported protocol version."; return FALSE; } } else { echo "Unable to connect

".socket_strerror(socket_last_error())."
"; return FALSE; } return $socket; } function Rserve_eval($socket, $command, $attr = NULL) { $pkt = mkp_str(3, $command); socket_send($socket, $pkt, strlen($pkt), 0); $r = get_rsp($socket); $res = int32($r); $sc = ($res >> 24) & 127; $rr = $res & 255; if ($rr != 1) { echo "eval failed with error code " . $sc; return FALSE; } if (int8($r, 16) != 10) { echo "invalid response (expecting SEXP)"; return FALSE; } $i = 20; return parse_SEXP($r, $i, /* & */ $attr); } function Rserve_assign_raw($socket, $name, $what) { // CMD_setSEXP $bl = strlen($what); if ($bl > 16777088) trigger_error("Body in Rserve_assign_raw is too big ($bl bytes), only small QAP packets are currently supported."); $n = strlen($name) + 1; $name .= chr(0); while (($n & 3) != 0) { $name .= chr(1); $n++; } // [CMD_setSEXP][DT_STRING(name)][DT_SEXP([XT_RAW, (i32) len, what])] = payload + 4 + 4 + 8 $pkt = mkint32(0x20) /* CMD_setSXP */ . mkint32($n + $bl + 16) . mkint32(0) . mkint32(0) . chr(4) . mkint24($n) . $name . chr(10) /* SEXP */ . mkint24($bl + 8). chr(37) /* XT_RAW */ . mkint24($bl + 4) . mkint32($bl) . $what; socket_send($socket, $pkt, strlen($pkt), 0); $r = get_rsp($socket); $res = int32($r); $sc = ($res >> 24) & 127; $rr = $res & 255; if ($rr != 1) { echo "eval failed with error code " . $sc; return FALSE; } return TRUE; } function Rserve_close($socket) { return socket_close($socket); } //========== FastRWeb - compatible requests - sample use of the client to behave like Rcgi in FastRWeb $root = "/var/FastRWeb"; // set to the root of your FastRWeb installation - must be absolute function process_FastRWeb($host, $port) { global $root; // $req = array_merge($_GET, $_POST); $path = $_SERVER['PATH_INFO']; if (!isset($path)) { echo "No path specified."; return FALSE; } $path = str_replace("..", "_", $path); // sanitize paths // We cannot check for the presence of the script, because FastRWeb now // supports PATH_INFO *after* the script name. // If you don't care but want fast error, uncomment the followign two lines. // $script = "$root/web.R$path.R"; // if (!file_exists($script)) { echo "Script [$script] $path.R does not exist."; return FALSE; } $raddr = $_SERVER['REMOTE_ADDR']; $method = $_SERVER['REQUEST_METHOD']; $ct = $_SERVER['CONTENT_TYPE']; $cl = $_SERVER['CONTENT_LENGTH'] + 0; // escape as needed $uri = str_replace("\"", "\\\"", str_replace("\\", "\\\\", $_SERVER['REQUEST_URI'])); // NOTE: the C client URI-encodes control characters and quotes -- maybe a good idea? $cook = str_replace("\"", "\\\"", str_replace("\\", "\\\\", $_SERVER['HTTP_COOKIE'])); $qs = str_replace("\"", "\\\"", str_replace("\\", "\\\\", $_SERVER['QUERY_STRING'])); $path = str_replace("\"", "\\\"", str_replace("\\", "\\\\", $path)); $s = Rserve_connect($host, $port); $bodyval = "NULL"; if ($ct == "" && $cl == 0) $cl = -1; else { $body = file_get_contents("php://input"); Rserve_assign_raw($s, "body", $body); $bodyval = ".GlobalEnv\$body"; } $r = Rserve_eval($s, "{ library(FastRWeb); request<-list(uri=\"$uri\", method=\"$method\", c.type=\"$ct\", c.length=$cl, body=$bodyval, client.ip=\"$raddr\", query.string=\"$qs\", raw.cookies=\"$cook\"); FastRWeb:::.run(request,\"$root\",\"$path\") }"); Rserve_close($s); if (!is_array($r)) { // this ususally means that an erro rocurred since the returned value is jsut a string ob_end_flush(); echo $r; exit(0); } if (isset($r[2])) header("Content-type: $r[2]"); if (($r[0] == "file") or ($r[0] == "tmpfile")) { error_log("INFO: $r[0]: '$r[1]'"); $contents = file_get_contents($root."/tmp/".$r[1]); ob_end_clean(); echo $contents; if ($r[0] == "tmpfile") unlink($r[0]); exit(0); } if ($r[0] == "html") { ob_end_clean(); echo (is_array($r[1]) ? implode("\n", $r[1]) : $r[1]); exit(0); } print_r($r); ob_end_flush(); exit(0); } //--- the following lines serve as FastRWeb handler (see FastRWeb package and IASC paper) // NOTE: this implementation is for FastRWeb 1.1 and higher! // If you changed the socket setting or use remote server change the parameters (host, port) below process_FastRWeb("$root/socket", 0); // default FastRWeb setting ob_end_flush(); /*========== user code -- example and test -- comment out the above and uncomment this for testing $s = Rserve_connect(); if ($s == FALSE) { echo "Connect FAILED"; } else { print_r (Rserve_eval($s, "list(str=R.version.string,foo=1:10,bar=1:5/2,logic=c(TRUE,FALSE,NA))")); echo "

"; print_r (Rserve_eval($s, "{x=rnorm(10); y=x+rnorm(10)/2; lm(y~x)}")); Rserve_close($s); } ob_end_flush(); */ ?> Rserve/src/websockets.c0000644000175100001440000007005314531234224014647 0ustar hornikusers#include "Rsrv.h" #include "websockets.h" #include "md5.h" #include "sha1.h" #include "tls.h" #include "rsdebug.h" #include #include #include #include #include #include #include #ifdef WIN32 /* FIXME: this is a terribe, terrible hack around Win32 idiocy. we should use stdint type or some such ... */ static int getpid(void) { /* for compatibility */ return (int) GetProcessId(GetCurrentProcess()); } #endif struct args { server_t *srv; /* server that instantiated this connection */ SOCKET s; SOCKET ss; int msg_id; void *res1; /* used by TLS */ struct args *tls_arg; /* if set it is used to wire send/recv calls */ /* the following entries are not populated by Rserve but can be used by server implemetations */ char *buf, *sbuf; int ver, bp, bl, sp, sl, flags; size_t l1, l2; }; static ssize_t WS_recv_data(args_t *arg, void *buf, size_t read_len); static int WS_send_resp(args_t *arg, int rsp, size_t len, const void *buf); static ssize_t WS_send_data(args_t *arg, const void *buf, size_t len); /* those will eventually be in the API but for now ... */ ssize_t cio_send(int s, const void *buffer, size_t length, int flags); ssize_t cio_recv(int s, void *buffer, size_t length, int flags); static ssize_t WS_wire_send(args_t *arg, const void *buf, size_t len) { return (arg->tls_arg) ? arg->tls_arg->srv->send(arg->tls_arg, buf, len) : cio_send(arg->s, buf, len, 0); } static ssize_t WS_wire_recv(args_t *arg, void *buf, size_t len) { return (arg->tls_arg) ? arg->tls_arg->srv->recv(arg->tls_arg, buf, len) : cio_recv(arg->s, buf, len, 0); } static void WS_wire_close(args_t *arg) { if (arg->tls_arg) { close_tls(arg->tls_arg); closesocket(arg->tls_arg->s); if (arg->s != arg->tls_arg->s) closesocket(arg->s); arg->tls_arg->s = -1; /* the server is virtual and allocated only for this instance so it's ok to free it (all other server are re-used) */ free(arg->tls_arg->srv); free(arg->tls_arg); arg->tls_arg = 0; } else closesocket(arg->s); arg->s = -1; } static int do_mask(char *msg, size_t len, int koff, char *key) { size_t i = 0; while (i < len) { msg[i] ^= key[(i + koff) & 3]; i++; } return (i + koff) & 3; } /* due to very large cookies the lines may be very long, using 128kB for now */ #define LINE_BUF_SIZE (128*1024) struct header_info { int version; char *origin; char *host; char *key; char *key1; char *key2; char *path; char *query; char *protocol; }; static void free_header(struct header_info *h) { if (h->origin) free(h->origin); if (h->host) free(h->host); if (h->key) free(h->key); if (h->key1) free(h->key1); if (h->key2) free(h->key2); if (h->path) free(h->path); if (h->query) free(h->query); if (h->protocol) free(h->protocol); } static size_t count_spaces(const char *c) { size_t n = 0; while (*c) { if (*c == ' ') n++; c++; } return n; } static unsigned long count_digits(const char *c) { size_t n = 0; while (*c) { if (*c >= '0' && *c <= '9') n = n * 10L + (size_t)(*c - '0'); c++; } return n; } /* from base64.c */ void base64encode(const unsigned char *src, int len, char *dst); /* from Rserve.c */ void Rserve_QAP1_connected(args_t *arg); void Rserve_text_connected(args_t *arg); int check_tls_client(int verify, const char *cn); #define FRAME_BUFFER_SIZE 65536 static void WS_connected(void *parg) { args_t *arg = (args_t*) parg; int n, bp = 0, empty_lines = 0, request_line = 1; struct header_info h; char *buf; /* we have to perform a handshake before giving over to QAP but we have to fork() first as to not block the server on handshake */ if (Rserve_prepare_child(arg) != 0) { /* parent or error */ if (arg->s != -1) closesocket(arg->s); free(arg); return; } /* if TLS is requested then we need to synthesize arg and srv for the TLS leg. FIXME: check that disassociating arg->s and tls_arg->s has no bad side-effects. */ if (arg->srv->flags & WS_TLS) { char cn[256]; args_t *tls_arg = calloc(1, sizeof(args_t)); tls_arg->s = arg->s; tls_arg->srv = calloc(1, sizeof(server_t)); add_tls(tls_arg, shared_tls(0), 1); if (check_tls_client(verify_peer_tls(tls_arg, cn, 256), cn)) { close_tls(tls_arg); free(tls_arg->srv); free(tls_arg); if (arg->s != -1) closesocket(arg->s); free(arg); return; } arg->tls_arg = tls_arg; } else arg->tls_arg = 0; buf = (char*) malloc(LINE_BUF_SIZE); if (!buf) { char lbuf[64]; strcpy(lbuf, "HTTP/1.1 500 Out of memory\r\n\r\n"); WS_wire_send(arg, lbuf, strlen(lbuf)); WS_wire_close(arg); free(arg); return; } buf[LINE_BUF_SIZE - 1] = 0; memset(&h, 0, sizeof(h)); #ifdef RSERV_DEBUG printf("INFO:WS: connection accepted for WebSockets\n"); #endif while ((n = WS_wire_recv(arg, buf + bp, LINE_BUF_SIZE - bp - 1)) > 0) { char *c = buf, *nl = c; #ifdef RSERV_DEBUG buf[bp + n] = 0; printf("INFO:WS: recv(%d, %d) = %d\n%s\n---\n", bp, LINE_BUF_SIZE - bp - 1, n, buf); #endif bp += n; while (*c) { char *dc = 0, *kc; while (*c == ' ' || *c == '\t') c++; kc = c; while (*c && *c != '\n') { if (!dc) { if (*c >= 'A' && *c <= 'Z') *c |= 0x20; /* to lower */ if (*c == ':') { *c = 0; dc = c + 1; } } c++; } if (*c) { /* next full line */ nl = c + 1; if (c > buf && *(c - 1) == '\r') *(c - 1) = 0; *c = 0; c++; if (request_line) { char *r1 = kc; request_line = 0; while (*kc && *kc != ' ') kc++; if (*kc == ' ') { r1 = ++kc; while (*kc && *kc != ' ') kc++; if (*kc == ' ') { char *r2 = r1; *kc = 0; while (*r2 && *r2 != '?') r2++; if (*r2 == '?') { /* split off query part */ *(r2++) = 0; h.query = strdup(r2); } h.path = strdup(r1); #ifdef RSERV_DEBUG printf("INFO:WS: request for '%s' (query%c%s)\n", r1, h.query ? ':' : ' ', h.query ? h.query : "not specified"); #endif } } } else if (dc) { while (*dc == ' ' || *dc == '\t') dc++; #ifdef RSERV_DEBUG printf("INFO:WS: header '%s' = '%s'\n", kc, dc); #endif if (!strcmp(kc, "origin")) h.origin = strdup(dc); if (!strcmp(kc, "host")) h.host = strdup(dc); if (!strcmp(kc, "sec-websocket-version")) h.version = atoi(dc); if (!strcmp(kc, "sec-websocket-protocol")) h.protocol = strdup(dc); if (!strcmp(kc, "sec-websocket-key1")) h.key1 = strdup(dc); if (!strcmp(kc, "sec-websocket-key2")) h.key2 = strdup(dc); if (!strcmp(kc, "sec-websocket-key")) h.key = strdup(dc); } else if (!*kc && ++empty_lines) break; } } #ifdef RSERV_DEBUG printf("INFO: bp=%d, nl=buf+%d\n", bp, (int) (nl - buf)); #endif if (nl == buf) { if (bp >= LINE_BUF_SIZE - 1) { /* no line in the entire buffer */ strcpy(buf, "HTTP/1.1 400 Bad Request (line overflow)\r\n\r\n"); WS_wire_send(arg, buf, strlen(buf)); WS_wire_close(arg); arg->s = -1; free_header(&h); free(buf); free(arg); return; } /* otherwise it's fine, we will load more */ } else { if (nl >= buf + LINE_BUF_SIZE - 1 || (!empty_lines && !*nl)) /* everything was consumed */ bp = 0; else { bp -= nl - buf; memmove(buf, nl, bp); } } if (empty_lines > 0) break; } if (empty_lines < 1) { strcpy(buf, "HTTP/1.1 400 Bad Request (connection failed before EOH)\r\n\r\n"); WS_wire_send(arg, buf, strlen(buf)); WS_wire_close(arg); arg->s = -1; free(buf); free_header(&h); free(arg); return; } #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WebSockets version %d\n Origin: %s\n Host: %s\n Key: '%s'\n Key1: '%s'\n Key2: '%s'\n\n", h.version, h.origin ? h.origin : "", h.host ? h.host : "", h.key ? h.key : "", h.key1 ? h.key1 : "", h.key2 ? h.key2 : ""); #endif arg->ver = h.version; if (h.version < 4) { /* 00 .. 03 (in fact that was no version in the handshake before 04) */ unsigned int v[2]; unsigned char keyb[16]; unsigned char hash[16]; if (bp < 8) { n = WS_wire_recv(arg, buf + bp, 8 - bp); if (n < 8 - bp) { strcpy(buf, "HTTP/1.1 400 Bad Request (Key3 incomplete)\r\n\r\n"); WS_wire_send(arg, buf, strlen(buf)); WS_wire_close(arg); arg->s = -1; free(buf); free_header(&h); free(arg); return; } } if (!h.origin || !h.key1 || !h.key2 || !h.host) { strcpy(buf, "HTTP/1.1 400 Bad Request (at least one key header is missing)\r\n\r\n"); WS_wire_send(arg, buf, strlen(buf)); WS_wire_close(arg); arg->s = -1; free(buf); free_header(&h); free(arg); return; } v[0] = count_digits(h.key1) / count_spaces(h.key1); v[1] = count_digits(h.key2) / count_spaces(h.key2); keyb[3] = v[0] & 255; keyb[2] = (v[0] >> 8) & 255; keyb[1] = (v[0] >> 16) & 255; keyb[0] = (v[0] >> 24) & 255; keyb[7] = v[1] & 255; keyb[6] = (v[1] >> 8) & 255; keyb[5] = (v[1] >> 16) & 255; keyb[4] = (v[1] >> 24) & 255; memcpy(keyb + 8, buf, 8); md5hash(keyb, 16, hash); if (!h.path) h.path = strdup("/"); snprintf(buf, LINE_BUF_SIZE, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\nSec-WebSocket-Origin: %s\r\nSec-WebSocket-Location: ws://%s%s\r\n%s%s%s\r\n", h.origin, h.host, h.path, h.protocol ? "Sec-WebSocket-Protocol: " : "", h.protocol ? h.protocol : "", h.protocol ? "\r\n" : ""); bp = strlen(buf); memcpy(buf + bp, hash, 16); WS_wire_send(arg, buf, bp + 16); #ifdef RSERV_DEBUG printf("Responded with WebSockets.00 handshake\n"); #endif } else { unsigned char hash[21]; char b64[40]; strcpy(buf, h.key); strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); sha1hash(buf, strlen(buf), hash); hash[20] = 0; /* base64encode needs NUL sentinel */ base64encode(hash, sizeof(hash) - 1, b64); /* FIXME: if the client requests multiple protocols, we should be picking one but we don't */ snprintf(buf, LINE_BUF_SIZE, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n%s%s%s\r\n", b64, h.protocol ? "Sec-WebSocket-Protocol: " : "", h.protocol ? h.protocol : "", h.protocol ? "\r\n" : ""); WS_wire_send(arg, buf, strlen(buf)); #ifdef RSERV_DEBUG printf("Responded with WebSockets.04+ handshake (version = %02d)\n", h.version); #endif } free(buf); arg->bl = FRAME_BUFFER_SIZE; arg->bp = 0; arg->buf = (char*) malloc(FRAME_BUFFER_SIZE); arg->sl = FRAME_BUFFER_SIZE; arg->sbuf = (char*) malloc(FRAME_BUFFER_SIZE); /* textual protocol */ if (h.protocol && strstr(h.protocol, "text")) { free_header(&h); Rserve_text_connected(arg); return; } free_header(&h); /* switch to underlying QAP1 */ Rserve_QAP1_connected(arg); } static server_t *ws_upgrade_srv, *wss_upgrade_srv; /* virtual server that represents the WS layer in HTTP/WS stack */ /* upgrade HTTP connection to WS connection, only 13+ protocol is supported this way */ /* NOTE: not included: origin, host */ /* IMPORTANT: it mangles the arg structure, so the caller should make sure it releases any obejcts from the structure that may leak */ /* FIXME: it only works on connections that have a direct socket since we don't have a stack to do TLS <-> WS <-> QAP */ void WS13_upgrade(args_t *arg, const char *key, const char *protocol, const char *version) { char buf[512]; unsigned char hash[21]; char b64[44]; server_t *srv; srv = (arg->srv->flags & WS_TLS) ? wss_upgrade_srv : ws_upgrade_srv; if (!srv) { srv = (server_t*) calloc(1, sizeof(server_t)); if (!srv) { snprintf(buf, sizeof(buf), "HTTP/1.1 511 Allocation error\r\n\r\n"); arg->srv->send(arg, buf, strlen(buf)); return; } srv->parent = arg->srv; srv->connected = WS_connected; /* this is not actually called */ srv->send_resp = WS_send_resp; srv->recv = WS_recv_data; srv->send = WS_send_data; srv->fin = server_fin; srv->flags = arg->srv->flags & SRV_QAP_FLAGS; /* pass-through QAP flags */ if (arg->srv->flags & WS_TLS) wss_upgrade_srv = srv; else ws_upgrade_srv = srv; } /* FIXME: can we just use the parent server? */ if (arg->srv->flags & SRV_TLS) { /* if this server is connected through TLS we have to create wire TLS pass-through */ args_t *tls_arg = calloc(1, sizeof(args_t)); tls_arg->srv = calloc(1, sizeof(server_t)); copy_tls(arg, tls_arg); arg->tls_arg = tls_arg; } strncpy(buf, key, sizeof(buf) - 50); strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); sha1hash(buf, strlen(buf), hash); hash[20] = 0; /* base64encode needs NUL sentinel */ base64encode(hash, sizeof(hash) - 1, b64); /* FIXME: if the client requests multiple protocols, we should be picking one but we don't */ snprintf(buf, sizeof(buf), "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n%s%s%s\r\n", b64, protocol ? "Sec-WebSocket-Protocol: " : "", protocol ? protocol : "", protocol ? "\r\n" : ""); arg->srv->send(arg, buf, strlen(buf)); #ifdef RSERV_DEBUG printf("Responded with WebSockets.04+ handshake (version = %02d)\n", version ? atoi(version) : 0); #endif arg->bl = FRAME_BUFFER_SIZE; arg->bp = 0; arg->buf = (char*) malloc(FRAME_BUFFER_SIZE); arg->sl = FRAME_BUFFER_SIZE; arg->sbuf = (char*) malloc(FRAME_BUFFER_SIZE); arg->srv = srv; arg->ver = version ? atoi(version) : 13; /* let's assume 13 if not present */ /* textual protocol */ if (protocol && strstr(protocol, "text")) { Rserve_text_connected(arg); return; } /* switch to underlying QAP1 */ Rserve_QAP1_connected(arg); } static int WS_send_resp(args_t *arg, int rsp, size_t len, const void *buf) { unsigned char *sbuf = (unsigned char*) arg->sbuf; if (len > rlen_max - 128) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_send_resp: payload too big (would exceed rlen_max)\n"); #endif return -1; } if (arg->ver == 0) { /* FIXME: we can't really tunnel QAP1 without some encoding ... */ } else { struct phdr ph; size_t pl = 0; size_t flen = len + sizeof(ph); ph.cmd = itop(rsp | ((rsp & CMD_OOB) ? 0 : CMD_RESP)); ph.len = itop(len); #ifdef __LP64__ ph.res = itop(len >> 32); #else ph.res = 0; #endif ph.msg_id = arg->msg_id; #ifdef RSERV_DEBUG if (io_log) { struct timeval tv; snprintf(io_log_fn, sizeof(io_log_fn), "/tmp/Rserve-io-%d.log", getpid()); FILE *f = fopen(io_log_fn, "a"); if (f) { double ts = 0; if (!gettimeofday(&tv, 0)) ts = ((double) tv.tv_sec) + ((double) tv.tv_usec) / 1000000.0; if (first_ts < 1.0) first_ts = ts; fprintf(f, "%.3f [+%4.3f] SRV --> CLI [WS_send_resp] (%x, %ld bytes)\n HEAD ", ts, ts - first_ts, rsp, (long) len); fprintDump(f, &ph, sizeof(ph)); fprintf(f, " BODY "); if (len) fprintDump(f, buf, len); else fprintf(f, "\n"); fclose(f); } } #endif sbuf[pl++] = ((arg->flags & F_OUT_BIN) ? 1 : 0) + ((arg->ver < 4) ? 0x04 : 0x81); /* text/binary, 4+ has inverted FIN bit */ if (flen < 126) /* short length */ sbuf[pl++] = flen; else if (flen < 65536) { /* 16-bit */ sbuf[pl++] = 126; sbuf[pl++] = flen >> 8; sbuf[pl++] = flen & 255; } else { /* 64-bit (on 32-bit plarforms the high 4 will be 0) */ sbuf[pl++] = 127; { int i = 8; size_t l = flen; while (i--) { sbuf[pl + i] = l & 255; l >>= 8; } } pl += 8; } memcpy(sbuf + pl, &ph, sizeof(ph)); pl += sizeof(ph); while (len + pl) { ssize_t n; /* arg->sl is only 64k so there are no size issues */ size_t send_here = (len + pl > arg->sl) ? arg->sl : (len + pl); if (send_here > pl) memcpy(sbuf + pl, buf, send_here - pl); n = WS_wire_send(arg, sbuf, send_here); #ifdef RSERV_DEBUG if (pl) { fprintf(stderr, "WS_send_resp: sending 4+ frame (ver %02d), n = %ld / %ld (of total %ld)\n", arg->ver, (long) n, (unsigned long)send_here, (long) flen); #ifdef WS_DEBUG { int i, m = send_here; if (m > 100) m = 100; for (i = 0; i < m; i++) fprintf(stderr, " %02x", (int) sbuf[i]); fprintf(stderr,"\n"); } #endif } else fprintf(stderr, "WS_send_resp: continuation (%ld bytes)\n", (long) n); #endif if (n != send_here) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_send_resp: write failed (%ld expected, got %ld)\n", (long) send_here, (long) n); #endif return -1; } buf = ((char*)buf) + send_here - pl; len -= send_here - pl; pl = 0; } } return 0; } /* we use send_data only to send the ID string so we don't bother supporting frames bigger than the buffer */ /* FIXME: not true anymore - it is used for pass-through, so we did implement binary fragmentation */ static ssize_t WS_send_data(args_t *arg, const void *buf, size_t len) { unsigned char *sbuf = (unsigned char*) arg->sbuf; if (arg->ver == 0) { if (len < arg->sl - 2) { ssize_t n; sbuf[0] = 0; memcpy(sbuf + 1, buf, len); sbuf[len + 1] = 0xff; n = WS_wire_send(arg, sbuf, len + 2); #ifdef RSERV_DEBUG fprintf(stderr, "WS_send_data: sending 00 frame, n = %ld / %lu\n", (long) n, (unsigned long) len + 2); #endif if (n == len + 2) return len; if (n < len + 2 && n >= len) return len - 1; return n; } else { #ifdef RSERV_DEBUG fprintf(stderr, "ERROR in WS_send_data: data too large\n"); #endif return -1; } } else { size_t total = len, pl = 0; sbuf[pl++] = ((arg->flags & F_OUT_BIN) ? 1 : 0) + ((arg->ver < 4) ? 0x04 : 0x81); /* text, 4+ has inverted FIN bit */ if (len < 126) /* short length */ sbuf[pl++] = len; else if (len < 65536) { /* 16-bit */ sbuf[pl++] = 126; sbuf[pl++] = len >> 8; sbuf[pl++] = len & 255; } else { /* 64-bit */ sbuf[pl++] = 127; { int i = 8; size_t l = len; while (i--) { sbuf[pl + i] = l & 255; l >>= 8; } } pl += 8; } while (len + pl) { ssize_t n; size_t send_here = (len + pl > arg->sl) ? arg->sl : (len + pl); if (send_here > pl) memcpy(sbuf + pl, buf, send_here - pl); n = WS_wire_send(arg, sbuf, send_here); #ifdef RSERV_DEBUG if (pl) { fprintf(stderr, "WS_send_data: sending 4+ frame (ver %02d), n = %ld / %lu (of total %ld)\n", arg->ver, (long) n, (unsigned long) send_here, (long) len); #ifdef WS_DEBUG { int i, m = send_here; if (m > 100) m = 100; for (i = 0; i < m; i++) fprintf(stderr, " %02x", (int) sbuf[i]); fprintf(stderr,"\n"); } #endif } else fprintf(stderr, "WS_send_data: continuation (%ld bytes)\n", (long) n); #endif if (n != send_here) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_send_data: write failed (%ld expected, got %ld)\n", (long) send_here, (long) n); #endif return -1; } buf = ((char*)buf) + send_here - pl; len -= send_here - pl; pl = 0; } return total; } return 0; } static ssize_t WS_recv_data(args_t *arg, void *buf, size_t read_len) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data for %ld (bp = %d)\n", (long) read_len, arg->bp); #endif if (arg->ver == 0) { /* make sure we have at least one (in frame) or two (oof) bytes in the buffer */ int min_size = (arg->flags & F_INFRAME) ? 1 : 2; while (arg->bp < min_size) { ssize_t n = WS_wire_recv(arg, arg->buf + arg->bp, arg->bl - arg->bp); #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: needs ver 00 frame, reading %ld bytes in addition to %d\n", (long) n, arg->bp); #ifdef WS_DEBUG { ssize_t i; fprintf(stderr, "Buffer: "); for (i = 0; i < n; i++) fprintf(stderr, " %02x", (int) (unsigned char) arg->buf[i]); fprintf(stderr,"\n"); } #endif #endif if (n < 1) return n; arg->bp += n; } if (!(arg->flags & F_INFRAME)) { if (arg->buf[0] != 0x00) { #ifdef RSERV_DEBUG fprintf(stderr, "ERROR: WS_recv_data: ver0 yet not a text frame (0x%02x)\n", (int) (unsigned char) arg->buf[0]); #endif return -1; } /* now we're in-frame - this is silly but makes the processing easier */ arg->flags |= F_INFRAME; memmove(arg->buf, arg->buf + 1, arg->bp - 1); } /* first check if we can satify any need by using contents of the buffer */ /* NOTE: this is actually always true since we guarantee both F_INFRAME and bp > 0 above */ if ((arg->flags & F_INFRAME) && arg->bp > 0) { unsigned char *b = (unsigned char*) arg->buf; ssize_t i = 0; #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: have %d bytes of a frame, requested %d, returning what we have\n", arg->bp, (int) read_len); #endif while (i < arg->bp && i < read_len && b[i] != 0xff) i++; if (i >= arg->bp) { /* end of buffer, still in frame */ memcpy(buf, arg->buf, i); arg->bp = 0; return i; } if (b[i] == 0xff) { /* reached end of frame */ if (i) memcpy(buf, arg->buf, i); arg->bp -= i + 1; if (arg->bp > 0) memmove(arg->buf, arg->buf + i + 1, arg->bp); arg->flags ^= F_INFRAME; return i; } /* read_len was less than the buffer and did not even reach the end of frame */ memcpy(buf, arg->buf, i); arg->bp -= i; memmove(arg->buf, arg->buf + i, arg->bp); return i; } } /* ver 00 always returns before this */ if ((arg->flags & F_INFRAME) && arg->bp > 0) { /* do we have content of a frame what has not been picked up yet? */ #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: have %d bytes of a frame, requested %d, returning what we have\n", arg->bp, (int) read_len); #endif if (read_len > arg->bp) read_len = arg->bp; /* at most all buffer */ if (read_len > arg->l1) read_len = arg->l1; /* and not beyond the current frame */ memcpy(buf, arg->buf, read_len); if (arg->bp > read_len) memmove(arg->buf, arg->buf + read_len, arg->bp - read_len); arg->bp -= read_len; arg->l1 -= read_len; /* if the whole frame was consumed, flag out-of-frame for the next run */ if (arg->l1 == 0) arg->flags ^= F_INFRAME; return read_len; } /* make sure we have at least one byte in the buffer */ if (arg->bp == 0) { /* don't read past the current frame in case we're in a frame ... */ /* FIXME: it shouldn't matter but it appears that we don't handle that case correctly */ ssize_t n; size_t max_sz = ((arg->flags & F_INFRAME) && arg->l1) ? arg->l1 : arg->bl; if (max_sz > arg->bl) max_sz = arg->bl; n = WS_wire_recv(arg, arg->buf, max_sz); if (n < 1) return n; arg->bp = n; #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WS_recv_data: read %ld bytes:\n", (long) n); #ifdef WS_DEBUG { ssize_t i; for (i = 0; i < n; i++) fprintf(stderr, " %02x", (int) (unsigned char) arg->buf[i]); fprintf(stderr,"\n"); } #endif #endif } if (arg->flags & F_INFRAME) { /* in frame with new content */ if (read_len > arg->l1) /* we can do at most the end of the frame */ read_len = arg->l1; if (read_len > arg->bp) /* and at most what we got in the buffer */ read_len = arg->bp; memcpy(buf, arg->buf, read_len); if (arg->flags & F_MASK) SET_F_MASK(arg->flags, do_mask(buf, read_len, GET_MASK_ID(arg->flags), (char*)&arg->l2)); arg->bp -= read_len; arg->l1 -= read_len; if (arg->l1 == 0) /* was that the entire frame? */ arg->flags ^= F_INFRAME; return read_len; } else { /* not in frame - interpret a new frame */ unsigned char *fr = (unsigned char*) arg->buf; #ifdef RSERV_DEBUG /* FIXME: we don't use more -- why? */ size_t more = (arg->ver < 4) ? ((fr[0] & 0x80) == 0x80) : ((fr[0] & 0x80) == 0); #endif int mask = 0, ct = fr[0] & 127; size_t need = 0, at_least, payload; size_t len = 0; /* set the F_IN_BIN flag according to the frame type */ if ((arg->ver < 4 && ct == 5) || (arg->ver >= 4 && ct == 2)) arg->flags |= F_IN_BIN; else arg->flags &= ~ F_IN_BIN; SET_F_FT(arg->flags, ct); if (arg->bp == 1) { ssize_t n = WS_wire_recv(arg, arg->buf + 1, arg->bl - 1); if (n < 1) return n; arg->bp = n + 1; } if (arg->ver > 6 && fr[1] & 0x80) mask = 1; len = fr[1] & 127; need = 2 + (mask ? 4 : 0) + ((len < 126) ? 0 : ((len == 126) ? 2 : 8)); while (arg->bp < need) { ssize_t n = WS_wire_recv(arg, arg->buf + arg->bp, arg->bl - arg->bp); if (n < 1) return n; arg->bp += n; } if (len == 126) len = (fr[2] << 8) | fr[3]; else if (len == 127) { if (fr[2] || fr[3]) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: requested frame length is way too big - we support only up to 256TB\n"); #endif return -1; } #define SH(X,Y) (((uint64_t)X) << Y) uint64_t raw_len = SH(fr[4], 48) | SH(fr[5], 40) | SH(fr[5], 32) | SH(fr[6], 24) | SH(fr[7], 16) | SH(fr[8], 8) | (uint64_t)fr[9]; if (raw_len > rlen_max - 64L) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: requested frame length is larger than rlen_max for this platform\n"); #endif return -1; } len = (size_t) raw_len; } #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WS_recv_data frame type=%02x, len=%lu, more=%d, mask=%d (need=%d)\n", ct, (unsigned long) len, (int) more, (int) mask, (int) need); #endif at_least = need + len; if (at_least > arg->bl) at_least = arg->bl; /* this is always positive, because need is at most 14 and at_least is need + len only capped by the buffer size which is >14 */ payload = at_least - need; while (arg->bp < at_least) { ssize_t n = WS_wire_recv(arg, arg->buf + arg->bp, at_least - arg->bp); #ifdef RSERV_DEBUG fprintf(stderr, "INFO: read extra %ld bytes in addition to %d (need %ld)\n", (long) n, arg->bp, (long) need); #endif if (n < 1) return n; arg->bp += n; } /* FIXME: more recent protocols require MASK at all times */ if (mask) { #ifdef RSERV_DEBUG #ifdef WS_DEBUG { size_t i; for (i = 0; i < payload; i++) fprintf(stderr, " %02x", (int) (unsigned char) arg->buf[need + i]); fprintf(stderr,"\n"); } #endif #endif SET_F_MASK(arg->flags, do_mask(arg->buf + need, payload, 0, arg->buf + need - 4)); /* we (ab)use l2 for the key - its really just char[4] which long can always fit */ memcpy(&arg->l2, arg->buf + need - 4, 4); #ifdef RSERV_DEBUG #ifdef WS_DEBUG { size_t i; for (i = 0; i < payload; i++) fprintf(stderr, " %02x", (int) (unsigned char) arg->buf[need + i]); fprintf(stderr,"\n"); } #endif #endif } else arg->flags &= ~ F_MASK; /* if the frame fits in the buffer (payload == len) and the read will read it all, we can deliver the whole frame */ if (payload == len && read_len >= payload) { #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WS_recv_data frame has %d bytes, requested %d, returning entire frame\n", (int) len, (int) read_len); #endif memcpy(buf, arg->buf + need, len); if (arg->bp > at_least) { /* this is unlikely but possible if we got multiple frames in the first read */ memmove(arg->buf, arg->buf + at_least, arg->bp - at_least); arg->bp -= at_least; } else arg->bp = 0; return len; } /* left-over */ #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WS_recv_data frame has %lu bytes (of %lu frame), requested %d, returning partial frame\n", (unsigned long) payload, (unsigned long) len, (int) read_len); #endif /* we can only read all we got */ if (read_len > payload) read_len = payload; memcpy(buf, arg->buf + need, read_len); if (arg->bp > need + read_len) /* if there is any data beyond what we will deliver, we need to move it */ memmove(arg->buf, arg->buf + need + read_len, arg->bp - need - read_len); len -= read_len; /* left in the frame is total minus delivered - we only get here if the frame did not fit, so len > 0 */ arg->l1 = len; arg->flags |= F_INFRAME; arg->bp -= need + read_len; return read_len; } /* in frame */ } server_t *create_WS_server(int port, int flags) { server_t *srv = create_server(port, 0, 0, flags); if (srv) { srv->connected = WS_connected; srv->send_resp = WS_send_resp; srv->recv = WS_recv_data; srv->send = WS_send_data; srv->fin = server_fin; add_server(srv); return srv; } return 0; } void serverLoop(void); typedef void (*sig_fn_t)(int); #ifdef unix static void brkHandler_R(int i) { Rprintf("Caught break signal, shutting down WebSockets.\n"); stop_server_loop(); } #endif SEXP run_WSS(SEXP sPort) { server_t *srv = create_WS_server(asInteger(sPort), WS_PROT_ALL); if (srv) { sig_fn_t old; Rprintf("-- starting WebSockets server at port %d (pid=%d) --\n", asInteger(sPort), getpid()); #ifdef unix old = signal(SIGINT, brkHandler_R); #endif serverLoop(); #ifdef unix signal(SIGINT, old); #endif rm_server(srv); } return ScalarLogical(TRUE); } /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/proxy/0000755000175100001440000000000014531234224013506 5ustar hornikusersRserve/src/proxy/chandler.c0000644000175100001440000000164114531234224015434 0ustar hornikusers#include "chandler.h" struct content_handler { struct content_handler *next; content_handler_fn_t process_request; }; static content_handler_t *handlers; content_handler_t *add_content_handler(content_handler_fn_t fn) { content_handler_t *h = malloc(sizeof(content_handler_t)), *tail; if (!h) return 0; h->next = 0; h->process_request = fn; if (!handlers) return (handlers = h); tail = handlers; while (tail->next) tail = tail->next; return (tail->next = h); } content_handler_t *call_content_handlers(http_request_t *req, http_result_t *res, const char *path) { content_handler_t *h = handlers; while (h) { if (h->process_request(req, res, path)) return h; h = h->next; } return h; } void free_content_handlers(void) { while (handlers) { content_handler_t *n = handlers->next; free(handlers); handlers = n; } } Rserve/src/proxy/tls.h0000644000175100001440000000137114531234224014463 0ustar hornikusers#ifndef TLS_H__ #define TLS_H__ #include "server.h" typedef struct tls tls_t; /* for set_tls_verify() */ #define TLS_NONE 0 /* default */ #define TLS_REQUIRE 1 /* in case shared tls is not set, it will be set to new_tls (which can be NULL) */ tls_t *shared_tls(tls_t *new_tls); tls_t *new_tls(void); int set_tls_pk(tls_t *tls, const char *fn); int set_tls_cert(tls_t *tls, const char *fn); int set_tls_ca(tls_t *tls, const char *fn_ca, const char *path_ca); int set_tls_verify(tls_t *tls, int verify); void free_tls(tls_t *tls); int add_tls(args_t *c, tls_t *tls, int server); void copy_tls(args_t *src, args_t *dst); void close_tls(args_t *c); int verify_peer_tls(args_t *c, char *cn, int len); int perror_tls(const char *format, ...); #endif Rserve/src/proxy/forward.c0000644000175100001440000006360114531234224015324 0ustar hornikusers/* HTTP and WebSocket server serving static content and forwarding QAP1 protocol. Based on Rserve. (C)Copyright 2014 Simon Urbanek License: BSD */ #include "http.h" #include "http_tools.h" #include "websockets.h" #include "qap.h" #include "tls.h" #include "rserr.h" #include "ulog.h" #include "bsdcmpt.h" #include "chandler.h" #include #include #include #include #include #include #include /* needed for unix sockets */ #include #include #include #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif /* send OOB idle on WebSockets every 10 min (FIXME: make this configurable) */ #define HEARTBEAT_INTERVAL 600 #define MAX_READ_CHUNK (1024 * 1024) #define MAX_SEND_CHUNK (1024 * 1024) /* FIXME: only for little endian machines */ #define ptoi(X) (X) #define itop(X) (X) static char buf[1024]; static char *doc_root = "."; static int doc_root_len = 1; static char *sm_host = 0; static char *sm_port = 0; static char *default_sm_port = "40"; static const char *infer_content_type(const char *fn) { const char *ext = fn ? strrchr(fn, '.') : 0; if (!ext) return 0; ext++; if (!strcmp(ext, "svg")) return "image/svg+xml"; if (!strcmp(ext, "js")) return "application/javascript"; if (!strcmp(ext, "css")) return "text/css"; if (!strcmp(ext, "png")) return "image/png"; if (!strcmp(ext, "jpeg") || !strcmp(ext, "jpg")) return "image/jpeg"; return 0; } /* removes .. and . segments, control characters. non-ASCII characters are retained */ static void sanitize_path(char *path) { char *src = path, *dst = path; int pos = 0; if (*path == '/') *(dst++) = *(src++); while (*src) { if (!pos) { if (src[0] == '.') { /* .. */ if (src[1] == '.' && (!src[2] || src[2] == '/')) { src += 2; continue; } /* . (harmless, but we still remove it) */ if (!src[1] || src[1] == '/') { src++; continue; } } } if (*src == '/') { if (pos) { /* not a repeated / */ *(dst++) = *(src++); pos = 0; } else /* repeated, just ignore */ src++; continue; } pos++; if (*src >= 32) *(dst++) = *(src++); } *dst = 0; } static void http_request(http_request_t *req, http_result_t *res) { FILE *f; char *s; struct stat st; double ts; int not_modified = 0, add_slash = 0; const char *append_headers = 0, *c_type = 0; #ifdef RSERV_DEBUG fprintf(stderr, "----\nINFO: request for '%s', Date: %s, headers:\n%s\n", req->url, posix2http(req->date), req->headers ? req->headers : ""); #endif /* leave room for ".gz\0" plus leading slash */ if (req->url[0] != '/' && doc_root_len && doc_root[doc_root_len - 1] != '/') add_slash = 1; s = (char*) malloc(strlen(req->url) + doc_root_len + 8); /* FIXME: if (!s) */ strcpy(s + doc_root_len + add_slash, req->url); memcpy(s, doc_root, doc_root_len); if (add_slash) s[doc_root_len] = '/'; /* if any handler served the request, exit */ if (call_content_handlers(req, res, s)) { free(s); return; } /* FIXME: technically, the processing of regular, static files should also be jsut a handler -- move the code below into one. */ sanitize_path(s); if (stat(s, &st) || !(f = fopen(s, "rb"))) { free(s); res->err = strdup("Path not found"); res->code = 404; return; } c_type = infer_content_type(s); /* check for conditional GET */ if (req->headers) { const char *if_mod = get_header(req, "If-Modified-Since"); if (if_mod) { double since = http2posix(if_mod); if (since >= MTIME(st)) { not_modified = 1; res->code = 304; } } } /* worry about content only if the result is not 304 Not Modified */ if (!not_modified) { /* check whether the client is ok with gzip compressed version and use that if possible */ const char *accept = get_header(req, "Accept-Encoding"); if (accept) { const char *e = strchr(accept, '\n'); if (e && strnstr(accept, "gzip", e - accept)) { /* accepts gzip? */ struct stat gzst; FILE *gzf; strcat(s, ".gz"); /* .gz present and not older than the source = serve the compressed version */ if (!stat(s, &gzst) && MTIME(gzst) >= MTIME(st) && (gzf = fopen(s, "rb"))) { fclose(f); f = gzf; st = gzst; append_headers = "Content-Encoding: gzip\r\n"; } } } res->payload = (char*) malloc((st.st_size < 512) ? 512 : st.st_size); res->payload_len = st.st_size; if (fread(res->payload, 1, res->payload_len, f) != res->payload_len) { snprintf(res->payload, 512, "I/O error: %s", strerror(errno)); res->err = res->payload; res->payload = 0; res->payload_len = 0; res->code = 500; fclose(f); free(s); return; } } free(s); fclose(f); /* append Last-Modified: based on the served file and set no-cache */ ts = (double) time(0); snprintf(buf, sizeof(buf), "Last-Modified: %s\r\nCache-Control: no-cache\r\n%s", posix2http((MTIME(st) > ts) ? ts : MTIME(st)), append_headers ? append_headers : "" ); res->headers = strdup(buf); if (c_type) res->content_type = strdup(c_type); } struct args { server_t *srv; /* server that instantiated this connection */ }; typedef struct queue_fs { unsigned long len; unsigned long seq; struct queue_fs *next; char data[1]; } queue_ft; typedef struct { const char *qap_socket_path; args_t *ws; /* WebSocket args structure */ int qap; /* QAP socket */ pthread_mutex_t mux; pthread_cond_t queue_available; int queue_sleeping; /* if set the queue consumer is sleeping and wants to be signalled */ unsigned long queue_seq; int qap_stage, active, qap_alive, ws_alive; queue_ft *ws_to_qap; } proxy_t; /* FIXME: we have no good way to pass this to the http handler, so we use a global var for now */ proxy_t *proxy; static void *forward(void *ptr) { qap_hdr_t hdr; char idstr[34]; proxy_t *proxy = (proxy_t*) ptr; int s = proxy->qap; ssize_t n; queue_ft *qe; ulog("QAP->WS INFO: started forwarding thread"); while (proxy->active && proxy->qap_alive) { n = read(s, &hdr, sizeof(hdr)); ulog("QAP->WS INFO: read n = %d", n); if (n < 0) { /* error */ if (errno == EINTR) continue; /* don't worry about EINTR */ ulog("QAP->WS ERROR: read header: %s", strerror(errno)); break; } if (n != sizeof(hdr)) { /* not even complete header */ if (n == 0) ulog("QAP->WS NOTE: QAP socket closed"); else ulog("QAP->WS ERROR: read header: %d read, %d expected", n, (int) sizeof(hdr)); break; } /* there is one special case - if this is non-OCAP mode and qap_stage is zero then the first packet will be IDstring and not a QAP message */ if (proxy->qap_stage == 0) { /* the first 4 bytes from the server must be one of: Rsrv - Rserve ID string (32 bytes) RSpx - Rserve proxy RsOC - OCAP mode */ if (!memcmp((char*)&hdr, "Rsrv", 4) && !memcmp(((char*)&hdr) + 8, "QAP1", 4)) { /* QAP1 = ID string */ memcpy(idstr, &hdr, sizeof(hdr)); { idstr[12] = 0; /* it's RsrvQAP1 and stop at that for display purposes */ ulog("QAP->WS INFO: *** server protocol: %s", idstr); memcpy(idstr, &hdr, sizeof(hdr)); } n = read(s, idstr + sizeof(hdr), 32 - sizeof(hdr)); ulog("QAP->WS INFO: read[IDstring] n = %d", n); if (n < 32 - sizeof(hdr)) { ulog("QAP->WS ERROR: read QAP1 ID string: %d read, %d expected", n, 32 - sizeof(hdr)); break; } if (memcmp(idstr + 8, "QAP1", 4)) { ulog("QAP->WS ERROR: Rserve protocol used is not QAP1"); break; } pthread_mutex_lock(&proxy->mux); ulog("QAP->WS INFO: forwarding IDstring (%d bytes)", 32); n = proxy->ws_alive ? proxy->ws->srv->send(proxy->ws, idstr, 32) : -2; pthread_mutex_unlock(&proxy->mux); if (n < 32) { /* ID string forward failed */ ulog("QAP->WS ERROR: send QAP1 ID string failed: %d read, %d expected [%s]", n, 32, strerror(errno)); break; } /* done - back to normal mode */ proxy->qap_stage = 1; WS_set_binary(proxy->ws, 1); /* QAP is binary */ continue; } if (!memcmp((char*)&hdr, "RSpx", 4)) { /* RSpx = Rserve proxy */ ulog("QAP->WS ERROR: RSpx proxy protocol is currently unsupported"); /* currently unsupported */ break; } if (!memcmp((char*)&hdr, "RsOC", 4)) { /* RsOC = OCAP mode - strictly QAP from the start */ ulog("QAP->WS INFO: *** server protocol: Rserve OCAP QAP1"); proxy->qap_stage = 1; WS_set_binary(proxy->ws, 1); /* QAP is binary */ } else { /* everything else = bad packet */ ulog("QAP->WS ERROR: server doesn't use any of Rsrv/QAP1, RSpx, RsOC - aborting"); break; } } /* from here on it's guaranteed QAP */ { unsigned long tl, pos = 0; #if LONG_MAX > 2147483647 tl = ptoi(hdr.res); tl <<= 32; tl |= ptoi(hdr.len); #else tl = ptoi(hdr.len); #endif ulog("QAP->WS INFO: <<== message === (cmd=0x%x, msg_id=0x%x), size = %lu", hdr.cmd, hdr.msg_id, tl); /* FIXME: this is really an abuse of queue_ft for historical reasons -- we just use it as a buffer!! */ if (!(qe = malloc(tl + sizeof(hdr) + sizeof(queue_ft)))) { /* failed to allocate buffer for the message */ /* FIXME: we should flush the contents and respond with an error condition */ ulog("QAP->WS ERROR: unable to allocate memory for message of size %lu", tl); break; } qe->next = 0; qe->len = tl + sizeof(hdr); memcpy(qe->data, &hdr, sizeof(hdr)); while (pos < tl) { n = read(s, qe->data + sizeof(hdr) + pos, (tl - pos > MAX_READ_CHUNK) ? MAX_READ_CHUNK : (tl - pos)); ulog("QAP->WS INFO: read n=%d (%lu of %lu)", n, pos, tl); if (n < 1) break; pos += n; } if (pos < tl) { ulog("QAP->WS ERROR: could read only %lu bytes of %lu bytes message [%s]", pos, tl, strerror(errno)); break; /* bail out on read error/EOF */ } ulog("QAP->WS INFO: sending total of %lu bytes", qe->len); /* message complete - send */ pthread_mutex_lock(&proxy->mux); n = (proxy->ws_alive) ? proxy->ws->srv->send(proxy->ws, qe->data, qe->len) : -2; ulog("QAP->WS INFO: send returned %d", n); pthread_mutex_unlock(&proxy->mux); if (n < qe->len) { ulog("QAP->WS ERROR: was able to send only %ld bytes of %lu bytes message [%s]", (long) n, tl, strerror(errno)); free(qe); break; } free(qe); } } closesocket(s); proxy->qap_alive = 0; proxy->qap = -1; /* QAP socket is dead */ ulog("QAP->WS INFO: finished forwarding thread, QAP closed"); return 0; } /* WS->queue */ static void *enqueue(void *ptr) { proxy_t *proxy = (proxy_t*) ptr; qap_hdr_t hdr; ulog("WS ->Q INFO: started enqueuing thread"); while (proxy->active && proxy->ws_alive) { int n = proxy->ws->srv->recv(proxy->ws, &hdr, sizeof(hdr)); unsigned long tl, pos = 0; queue_ft *qe; ulog("WS ->Q INFO: WS recv = %d", n); if (n < sizeof(hdr)) { if (n == 0) ulog("WS ->Q INFO: WebSocket closed"); else ulog("WS ->Q ERROR: header read expected %d, got %d [%s]", sizeof(hdr), n, strerror(errno)); break; } #if LONG_MAX > 2147483647 tl = ptoi(hdr.res); tl <<= 32; tl |= ptoi(hdr.len); #else tl = ptoi(hdr.len); #endif ulog("WS ->Q INFO: === message ==>> (cmd=0x%x, msg_id=0x%x), size = %lu", hdr.cmd, hdr.msg_id, tl); if (!(qe = malloc(tl + sizeof(hdr) + sizeof(queue_ft)))) { /* failed to allocate buffer for the message */ /* FIXME: we should flush the contents and respond with an error condition */ ulog("WS ->Q ERROR: unable to allocate memory for message of size %lu", tl); break; } qe->next = 0; qe->len = tl + sizeof(hdr); memcpy(qe->data, &hdr, sizeof(hdr)); while (pos < tl) { ulog("WS ->Q INFO: requesting %lu (so far %lu of %lu)", tl - pos, pos, tl); n = proxy->ws->srv->recv(proxy->ws, qe->data + sizeof(hdr) + pos, tl - pos); if (n < 1) { ulog("WS ->Q ERROR: read %lu of %lu then got %d [%s]", pos, tl, n, strerror(errno)); break; } pos += n; } if (pos < tl) break; ulog("WS ->Q INFO: enqueuing message"); /* got the message - enqueue */ pthread_mutex_lock(&proxy->mux); qe->seq = ++proxy->queue_seq; /* currently not needed, but safer to increment when locked */ if (proxy->ws_to_qap) { queue_ft *q = proxy->ws_to_qap; /* find the end of the queue */ while (q->next) q = q->next; q->next = qe; /* append */ } else proxy->ws_to_qap = qe; if (proxy->queue_sleeping) pthread_cond_signal(&proxy->queue_available); pthread_mutex_unlock(&proxy->mux); ulog("WS ->Q INFO: done enqueuing"); } pthread_mutex_lock(&proxy->mux); proxy->ws_alive = 0; /* signal queue so the main thread can check our status and find out that we're done */ pthread_cond_signal(&proxy->queue_available); pthread_mutex_unlock(&proxy->mux); ulog("WS ->Q INFO: finished enqueuing thread"); /* WS will be closed by exitting from the main thread */ return 0; } static void *heartbeat(void *ptr) { proxy_t *proxy = (proxy_t*) ptr; struct { qap_hdr_t hdr; unsigned int sexp_hdr, list_hdr, str_hdr; char str[8]; } idle_msg; /* construct list("idle") OOB SEND packet by hand: QAP1(SEXP(list("idle"))) */ memset(&idle_msg, 0, sizeof(idle_msg)); idle_msg.hdr.cmd = itop(OOB_SEND); idle_msg.hdr.len = itop(20); /* 4 (SEXP) + 4 (VECTOR) + 4 (STR) + 8 ("idle\0\1\1\1") */ idle_msg.sexp_hdr = itop(SET_PAR(DT_SEXP, 16)); idle_msg.list_hdr = itop(SET_PAR(XT_VECTOR, 12)); idle_msg.str_hdr = itop(SET_PAR(XT_ARRAY_STR, 8)); memset(idle_msg.str, 1, 8); /* pad with 1 */ strcpy(idle_msg.str, "idle"); while (proxy->active && proxy->ws_alive) { sleep(HEARTBEAT_INTERVAL); pthread_mutex_lock(&proxy->mux); if (proxy->ws_alive) proxy->ws->srv->send(proxy->ws, &idle_msg, ptoi(idle_msg.hdr.len) + sizeof(qap_hdr_t)); pthread_mutex_unlock(&proxy->mux); } return 0; } static void ws_connected(args_t *arg, char *protocol) { int s; struct sockaddr_un sau; pthread_t forward_thread, enqueue_fthread, heartbeat_thread; pthread_attr_t thread_attr; fprintf(stderr, "INFO: web sockets connected (protocol %s)\n", protocol ? protocol : ""); proxy->ws = arg; if ((s = proxy->qap = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) { RSEprintf("unable to get local socket: %s\n", strerror(errno)); return; } memset(&sau, 0, sizeof(sau)); sau.sun_family = AF_LOCAL; if (strlen(proxy->qap_socket_path) + 1 > sizeof(sau.sun_path)) { RSEprintf("local socket path too long\n"); proxy->qap = -1; closesocket(s); return; } strcpy(sau.sun_path, proxy->qap_socket_path); if (connect(s, (struct sockaddr*)&sau, sizeof(sau))) { RSEprintf("unable to connect to local socket '%s': %s\n", sau.sun_path, strerror(errno)); /* FIXME: report this to the client? */ proxy->qap = -1; closesocket(s); return; } /* connected both ends */ pthread_mutex_init(&proxy->mux, 0); pthread_cond_init(&proxy->queue_available, 0); proxy->qap_stage = 0; proxy->ws_to_qap = 0; proxy->active = 1; proxy->ws_alive = 1; proxy->qap_alive = 1; /* create QAP -> WS forwarding thread */ pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); pthread_create(&forward_thread, &thread_attr, forward, proxy); /* create WS read enqueuing thread */ pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); pthread_create(&enqueue_fthread, &thread_attr, enqueue, proxy); /* create WS heartbeat thread */ pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); pthread_create(&heartbeat_thread, &thread_attr, heartbeat, proxy); /* Note about the mutex: the mutex is locked for a) all operations on the queue b) for all WS send operations so the one operation that doesn't lock is the blocking WS read. Hence no other thread than "enqueue" (WS->Q) is allowed to call WS read. */ /* what's left is queue -> QAP we use queue_available condition var to yield until equeue signals contents on the queue */ while (proxy->active) { queue_ft *q; pthread_mutex_lock(&proxy->mux); ulog("Q ->QAP INFO: waiting for message in the queue"); if (!proxy->ws_to_qap && proxy->qap_alive) { /* if there is nothing to process, wait until enqueue posts something */ proxy->queue_sleeping = 1; pthread_cond_wait(&proxy->queue_available, &proxy->mux); proxy->queue_sleeping = 0; } /* ok, we land here with the queue mutex still locked so we pull the message from the head of the queue and release the rest of the queue */ q = proxy->ws_to_qap; ulog("Q ->QAP INFO: queue signalled - %s", q ? "message present" : "queue empty"); if (q) proxy->ws_to_qap = q->next; pthread_mutex_unlock(&proxy->mux); /* mutex unlocked, we own the message */ if (q) { if (!proxy->qap_alive) { /* QAP is dead */ qap_hdr_t hdr = { 0, 0, 0, 0 }, *src = (qap_hdr_t*) q->data; if (!proxy->ws_alive) { /* WS is dead, too - get out */ proxy->active = 0; break; } hdr.cmd = itop(SET_STAT(RESP_ERR, ERR_conn_broken)); hdr.msg_id = src->msg_id; /* QAP is dead - signal an error */ pthread_mutex_lock(&proxy->mux); if (proxy->ws_alive) proxy->ws->srv->send(proxy->ws, &hdr, sizeof(hdr)); pthread_mutex_unlock(&proxy->mux); /* don't close WS - we'll still respond to all messages WS sends our way so it can unwind all callbacks */ } else { unsigned long tl = q->len, pos = 0; while (pos < tl && proxy->qap != -1) { int n = send(proxy->qap, q->data + pos, (tl - pos > MAX_SEND_CHUNK) ? MAX_SEND_CHUNK : (tl - pos), 0); ulog("Q ->QAP INFO: sent %d (at %lu of %lu)", n, pos, tl); if (n < 1) break; /* send failed or broken pipe */ pos += n; } if (pos < tl) { /* QAP broken */ ulog("Q ->QAP ERROR: send error, aborting QAP connection"); closesocket(proxy->qap); proxy->qap = -1; proxy->qap_alive = 0; free(q); break; } ulog("Q ->QAP INFO: message delivered"); } free(q); } else if (!proxy->ws_alive) { /* if the queue is empty and WS is dead, it's time to leave */ ulog("INFO: WS closed and queue empty, clean shutdown"); proxy->active = 0; } } if (proxy->qap_alive) { /* QAP is still alive ... inform the thread that we're done and signal so it breaks out of recv() */ proxy->qap_alive = 0; pthread_kill(forward_thread, SIGINT); } /* if WS is still alive, we inform it about our shutdown */ pthread_mutex_lock(&proxy->mux); if (proxy->ws_alive) { qap_hdr_t hdr = { 0, 0, 0, 0 }; hdr.cmd = itop(OOB_SEND); proxy->ws_alive = 0; proxy->ws->srv->send(proxy->ws, &hdr, sizeof(hdr)); } pthread_mutex_unlock(&proxy->mux); ulog("INFO: WebSockets forwarding process done."); } /* send a message to the server maranger if configured */ static void send_srvmgr(char *what) { struct addrinfo hints; struct addrinfo *result, *rp; int sfd, s; if (!sm_host || !sm_port) return; /* noop if no srvmgr is defined */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* IPv4/6 but TCP */ hints.ai_flags = 0; hints.ai_protocol = 0; if ((s = getaddrinfo(sm_host, sm_port, &hints, &result))) { ulog("ERROR: cannot resolve srvmgr host (%s): %s", sm_host, gai_strerror(s)); return; } for (rp = result; rp != NULL; rp = rp->ai_next) { struct timeval timeout; sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; /* reduce the timeout substantially to 200ms */ timeout.tv_sec = 0; timeout.tv_usec = 200000; setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) break; close(sfd); } if (!rp) { ulog("ERROR: cannot connect to srvmgr host (%s:%s): %s", sm_host, sm_port, strerror(errno)); return; } send(sfd, what, strlen(what), 0); ulog("INFO: send '%s' to srvmgr %s:%s", what, sm_host, sm_port); close(sfd); } /* queuing notes: so far we are using a simple FIFO, but we need something smarter due to OOB_MSG which have to deliver results back by "jumping" the queue. For that, we have to keep track of requests sent to the QAP side hold any further requests until the reqeust is done. In the meantime, we have to allow OOB MSG to pass. This meas that QAP->WS thread has to also signal the queue in case the queue is blocked due to a pending request result. To make things even more fun, we may need to support multiple QAP connections, thus running one QAP->WS thread for each. We may be ok with just one Q->QAP thread - it simplifies things and the only issue is that transmitting a message to one QAP process blocks transmission to another one. However, Q->QAP connection is a local socket, so it's really fast (a 20Mb packet took only 36ms to transmit in debugging mode). Finally, we may want some protocol for QAPs to exchange messages with each other. Thsi should be easy, though, since the QAP->WS thread can simply enqueue the message instead of sending it. */ /* from rscript.c */ int R_script_handler(http_request_t *req, http_result_t *res, const char *path); void R_script_socket(const char *s); static int die(const char *str) { fprintf(stderr,"\nERROR: %s\n\n", str); return 1; } #define TLS_INFO_KEY 1 #define TLS_INFO_CERT 2 #define TLS_INFO_CA 4 int main(int ac, char **av) { int http_port = 8088, ws_port = -1, i = 0, flags = 0, tls_info = 0; int active_servers = 0; const char *ulog_path = "ulog_socket"; const char *scr_path = "Rscript_socket"; ulog_set_app_name("forward"); proxy = (proxy_t*) malloc(sizeof(proxy_t)); memset(proxy, 0, sizeof(proxy_t)); proxy->qap_socket_path = "Rserve_socket"; while (++i < ac) if (av[i][0] == '-') switch (av[i][1]) { case 's': if (++i < ac) proxy->qap_socket_path = av[i]; else return die("missing path in -s "); break; case 'u': if (++i < ac) ulog_path = av[i]; else return die("missing path in -u "); break; case 'p': if (++i < ac) http_port = atoi(av[i]); else return die("missing HTTP port in -p "); break; case 'w': if (++i < ac) ws_port = atoi(av[i]); else return die("missing WebSockets port in -w "); break; case 'r': if (++i < ac) doc_root = av[i]; else return die("missing path in -r "); break; case 'R': if (++i < ac) scr_path = av[i]; else return die("missing path in -R "); break; case 'k': if (++i < ac) { tls_t *tls = shared_tls(0); if (!tls) tls = shared_tls(new_tls()); if (!tls) return die("unable to initialize SSL - you may be missing SSL support."); if (!set_tls_pk(tls, av[i])) return perror_tls("ERROR: Unable to load SSL key from '%s': ", av[i]); flags |= SRV_TLS; tls_info |= TLS_INFO_KEY; } else return die("missing key path in -k "); break; case 'C': if (++i < ac) { tls_t *tls = shared_tls(0); if (!tls) tls = shared_tls(new_tls()); if (!set_tls_ca(tls, av[i], 0)) return perror_tls("ERROR: Unable to load CA chain from '%s': ", av[i]); tls_info |= TLS_INFO_CA; } else return die("missing CA-path path in -C "); break; case 'S': if (++i < ac) { char *c = strchr(av[i], ':'); sm_port = c ? (c + 1) : default_sm_port; if (c) *c = 0; sm_host = av[i]; } else return die("missing host in -S [:]"); break; case 'c': if (++i < ac) { tls_t *tls = shared_tls(0); if (!tls) tls = shared_tls(new_tls()); if (!set_tls_cert(tls, av[i])) return perror_tls("ERROR: Unable to load SSL certificate from '%s': ", av[i]); tls_info |= TLS_INFO_CERT; } else return die("missing cert-path path in -C "); break; case 'h': printf("\n\ Usage: %s [-h] [-p ] [-w ] [-s ] [-R ] [-r ]\n\ [-k [-c ] [-C ]] [-u ] [-S [:]]]\n\n", av[0]); return 0; default: fprintf(stderr, "\nUnrecognized flag -%c\n", av[i][1]); return 1; } if (tls_info & TLS_INFO_KEY) { if ((tls_info & (TLS_INFO_KEY | TLS_INFO_CERT)) != (TLS_INFO_KEY | TLS_INFO_CERT)) return die("-k requires a corresponding certificate to be supplied with -c , but it is missing"); } else if (tls_info) fprintf(stderr, "WARNING: -c or -C are supplied without -k, they are ignored since SSL is only enabled if -k is present.\n"); doc_root_len = strlen(doc_root); ulog_set_path(ulog_path); ulog("----------------"); R_script_socket(scr_path); add_content_handler(R_script_handler); if (http_port > 0) { server_t *srv = create_HTTP_server(http_port, HTTP_WS_UPGRADE | flags, http_request, ws_connected); if (srv) { ulog("WS/QAP INFO: started HTTP server on port %d", http_port); active_servers++; } else ulog("WS/QAP ERROR: failed to start HTTP server on port %d", http_port); } if (ws_port > 0) { server_t *srv = create_WS_server(ws_port, WS_PROT_QAP | flags, ws_connected); if (srv) { ulog("WS/QAP INFO: started WebSocket server on port %d", ws_port); active_servers++; } else ulog("WS/QAP ERROR: failed to start WebSocket server on port %d", ws_port); } if (!active_servers) return die("there are no active servers, aborting."); ulog("WS/QAP INFO: starting server loop (http=%d, ws=%d, qap='%s', rscript='%s', doc_root='%s'", http_port, ws_port, proxy->qap_socket_path, scr_path, doc_root); send_srvmgr("ADD"); serverLoop(); send_srvmgr("DEL"); return 0; } Rserve/src/proxy/test.html0000644000175100001440000000146714531234224015363 0ustar hornikusers HTTP/WebSockets test

started
Rserve/src/proxy/websockets.h0000644000175100001440000000235014531234224016030 0ustar hornikusers#ifndef WEBSOCKETS_H__ #define WEBSOCKETS_H__ #include "server.h" #define WS_PROT_QAP 0x01 #define WS_PROT_TEXT 0x02 /* NOTE: this is not the same as SRV_TLS! It is annoying, but WS needs to chain TLS futher down, if SRC_TLS is set then QAP will be tunneled through TLS but we need to wrap WS around it first */ #define WS_TLS 0x08 /* WARNING: HTTP uses 0x10 and 0x20 */ #define WS_PROT_ALL (WS_PROT_QAP | WS_PROT_TEXT) typedef void (*ws_connected_fn_t)(args_t *arg, char *protocol); server_t *create_WS_server(int port, int protocols, ws_connected_fn_t connected); void WS_set_binary(args_t *arg, int flag); /* upgrade HTTP connection to WS - assumes that the HTTP server has parsed the request already only WS 13+ handshake is supported by this function */ void WS13_upgrade(args_t *arg, const char *key, const char *protocol, const char *version, ws_connected_fn_t connected); /* flags used in args_t.flags */ #define F_INFRAME 0x010 #define F_MASK 0x020 #define F_IN_BIN 0x040 #define F_OUT_BIN 0x080 #define SET_F_FT(X, FT) X = (((X) & 0xfff) | (((FT) & 15) << 12)) #define GET_F_FT(X) (((X) >> 12) & 15) #define GET_MASK_ID(X) ((X) & 3) #define SET_F_MASK(X, M) X = (((X) & 0xfffc) | F_MASK | ((M) & 3)) #endif Rserve/src/proxy/tls.c0000644000175100001440000000770014531234224014460 0ustar hornikusers#ifndef NO_CONFIG_H #include "config.h" #endif #include "tls.h" #ifdef HAVE_TLS #include #include #include #include struct tls { SSL_CTX *ctx; const SSL_METHOD *method; }; static int first_tls = 1; static tls_t *tls; tls_t *shared_tls(tls_t *new_tls) { if (!tls) tls = new_tls; return tls; } tls_t *new_tls(void) { tls_t *t = (tls_t*) calloc(1, sizeof(tls_t)); if (first_tls) { SSL_library_init(); #ifdef RSERV_DEBUG SSL_load_error_strings(); #endif first_tls = 0; tls = t; } t->method = SSLv23_server_method(); t->ctx = SSL_CTX_new(t->method); return t; } int set_tls_pk(tls_t *tls, const char *fn) { return SSL_CTX_use_PrivateKey_file(tls->ctx, fn, SSL_FILETYPE_PEM); } int set_tls_cert(tls_t *tls, const char *fn) { return SSL_CTX_use_certificate_file(tls->ctx, fn, SSL_FILETYPE_PEM); } int set_tls_ca(tls_t *tls, const char *fn_ca, const char *path_ca) { return SSL_CTX_load_verify_locations(tls->ctx, fn_ca, path_ca); } int set_tls_verify(tls_t *tls, int verify) { SSL_CTX_set_verify(tls->ctx, verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, 0); return 1; } struct args { server_t *srv; /* server that instantiated this connection */ int s; int ss; int msg_id; SSL *ssl; void *res2; }; static ssize_t tls_recv(args_t *c, void *buf, size_t len) { return SSL_read(c->ssl, buf, len); } static ssize_t tls_send(args_t *c, const void *buf, size_t len) { return SSL_write(c->ssl, buf, len); } int add_tls(args_t *c, tls_t *tls, int server) { c->ssl = SSL_new(tls->ctx); c->srv->send = tls_send; c->srv->recv = tls_recv; SSL_set_fd(c->ssl, c->s); if (server) return SSL_accept(c->ssl); else return SSL_connect(c->ssl); } void copy_tls(args_t *src, args_t *dst) { dst->ssl = src->ssl; dst->s = src->s; dst->srv->send = src->srv->send; dst->srv->recv = src->srv->recv; } void close_tls(args_t *c) { if (c->ssl) { SSL_shutdown(c->ssl); SSL_free(c->ssl); c->ssl = 0; } } void free_tls(tls_t *tls) { } /* if cn is present, len > 0 and there is a cert then the common name is copied to cn and terminated. It may be truncated if len is too short. Return values: 0 = present but verification failed 1 = present and verification successful -1 = absent */ int verify_peer_tls(args_t *c, char *cn, int len) { X509 *peer; if ((peer = SSL_get_peer_certificate(c->ssl))) { if (cn && len > 0) { X509_NAME *sn = X509_get_subject_name(peer); X509_NAME_get_text_by_NID(sn, NID_commonName, cn, len); fprintf(stderr, "INFO: peer cert common name: \"%s\"\n", cn); } X509_free(peer); if (SSL_get_verify_result(c->ssl) == X509_V_OK) { fprintf(stderr, "INFO: peer cert present and OK\n"); return 1; } else { fprintf(stderr, "INFO: peer cert present, but verification FAILED\n"); return 0; } } fprintf(stderr, "INFO: peer nas NO cert\n"); return -1; } int perror_tls(const char *format, ...) { va_list(ap); va_start(ap, format); vfprintf(stderr, format, ap); ERR_print_errors_fp(stderr); va_end(ap); return 1; } #else /* no SSL/TLS support, ignore everything, fail on everything */ #include tls_t *shared_tls(tls_t *new_tls) { return 0; } tls_t *new_tls(void) { return 0; } int set_tls_pk(tls_t *tls, const char *fn) { return -1; } int set_tls_cert(tls_t *tls, const char *fn) { return -1; } int set_tls_ca(tls_t *tls, const char *fn_ca, const char *path_ca) { return -1; } int set_tls_verify(tls_t *tls, int verify) { return -1; } void free_tls(tls_t *tls) { } int add_tls(args_t *c, tls_t *tls, int server) { return -1; } void copy_tls(args_t *src, args_t *dst) { } void close_tls(args_t *c) { } int verify_peer_tls(args_t *c, char *cn, int len) { return -1; } int perror_tls(const char *format, ...) { fprintf(stderr, "ERROR: this binary has been built without SSL/TLS support.\n"); return 1; } #endif Rserve/src/proxy/date.c0000644000175100001440000000753114531234224014575 0ustar hornikusers/* utilities to parse valid HTTP times and to generate RFC 822/1123 date (C)Copyright 2014,21 Simon Urbanek License: BSD */ /* -- interface -- */ char *posix2http(double ts); /* Note: returned buffer is static */ double http2posix(const char *c); /* -- implementation -- */ #include #include #include #include #include static const char *c_wkd[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char *c_mon[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char date_buf[64]; char *posix2http(double ts) { time_t t = (time_t) ts; struct tm *tm = gmtime(&t); if (!tm) return 0; snprintf(date_buf, sizeof(date_buf), "%s, %02d %s %d %02d:%02d:%02d GMT", c_wkd[tm->tm_wday], tm->tm_mday, c_mon[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); return date_buf; } static int lookup(const char *c, const char **where, int n) { int i; for (i = 0; i < n; i++) if (!memcmp(c, where[i], 3)) return i; return -1; } static double parse_hms(const char **c_ptr) { int h,m,s; const char *c = *c_ptr; while (*c == ' ') c++; h = atoi(c); while (*c >= '0' && *c <= '9') c++; if (*c != ':') return -1.0; c++; m = atoi(c); while (*c >= '0' && *c <= '9') c++; if (*c != ':') return -1.0; c++; s = atoi(c); while (*c >= '0' && *c <= '9') c++; *c_ptr = c; return (double) (s + (m * 60) + (h *3600)); } /* start of each month in seconds */ static const int cml[] = { 0, 0, 2678400, 5097600, 7776000, 10368000, 13046400, 15638400, 18316800, 20995200, 23587200, 26265600, 28857600, 31536000 }; typedef int64_t time_int_t; static double day2posix(int day, int month, int year) { double ts; /* check input ranges */ if (year < 1970 || year > 2199 || month < 1 || month > 12 || day < 1 || day > 31) return 0.0; year -= 1970; /* adjust for all leap years prior to the current one */ ts = ((time_int_t)((year + 1) / 4)) * (time_int_t) 86400; if (year > 130) /* 2100 is an exception - not a leap year */ ts -= 86400; ts += ((time_int_t) year) * ((time_int_t) 31536000); /* month */ ts += cml[month]; if (month > 2 && (year & 3) == 2 && year != 130 /* 2100 again */) ts += 86400; /* day */ ts += (day - 1) * 86400; return ts; } double http2posix(const char *c) { int mon, day, year; double hms; /* skip weekday */ while (*c && *c != ' ') c++; if (!*c) return 0.0; while (*c == ' ') c++; /* this is now one of "01-Jan 2000", "01-Jan-00" or "Jan 1" */ if (*c < '0' || *c > '9') { /* non-digit so it's either asctime() or invalid */ if ((mon = lookup(c, c_mon, 12)) < 0) return 0.0; mon++; while (*c && *c != ' ') c++; while (*c == ' ') c++; if (!*c) return 0.0; day = atoi(c); while (*c && *c != ' ') c++; if (!*c) return 0.0; if ((hms = parse_hms(&c)) < 0.0) return 0.0; while (*c == ' ') c++; if (!*c) return 0.0; year = atoi(c); } else { /* RFC 822/1123 or RFC 850/1036 - both can be parsed the same way if we ignore the the difference between ' ' and '-' and adjust year */ day = atoi(c); while (*c >= '0' && *c <= '9') c++; while (*c == '-' || *c ==' ') c++; if ((mon = lookup(c, c_mon, 12)) < 0) return 0.0; mon++; while (*c && (*c < '0' || *c > '9')) c++; if (!*c) return 0.0; year = atoi(c); /* RFC 850/1036 doesn't say how to interpret two-digit years, so we assume 70..99 are 1970..1999 and 00..69 are 2000..2069 */ if (year < 70) year += 2000; else if (year < 100) year += 1900; while (*c && *c != ' ') c++; if (!*c || (hms = parse_hms(&c)) < 0.0) return 0.0; } /* ok, we got hms and day/month/year - assemble it to POSIX */ return hms + day2posix(day, mon, year); } Rserve/src/proxy/server.c0000644000175100001440000003153614531234224015170 0ustar hornikusers#include "rserr.h" #include "server.h" #define SOCK_ERRORS #define LISTENQ 32 #ifndef WIN32 #include /* needed for unix sockets */ #endif #include #include #include /* AF_LOCAL is the POSIX version of AF_UNIX - we need this e.g. for AIX */ #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif /* keep track of all bound server sockets so they can be easily all closed after fork this is important for two reasons: so ports don't get stuck bound after the server has been shut down but children are still around, and so that a rogue child cannot impersonate the server after the server has been shut down (since the port may have been bound at higher privileges than the child may have at this point) */ #define MAX_SRVS 512 static int active_srv_sockets[MAX_SRVS]; static int active = 1; static void add_active_srv_socket(int s) { int i = 0; while (active_srv_sockets[i] && i < MAX_SRVS) { if (active_srv_sockets[i] == s) return; i++; } if (i < MAX_SRVS) active_srv_sockets[i] = s; } static void rm_active_srv_socket(int s) { int i = 0; while (i < MAX_SRVS) { if (active_srv_sockets[i] == s) { active_srv_sockets[i] = 0; break; } i++; } } /* this is typically used after fork in the child process */ void close_all_srv_sockets(void) { int i = 0; while (i < MAX_SRVS) { if (active_srv_sockets[i]) closesocket(active_srv_sockets[i]); i++; } } /* provides client socket from accept() to the server so that it can modify the socket as needed according to the server flags */ void accepted_server(server_t *srv, int cs) { #ifdef SO_KEEPALIVE /* if keep-alive is enabled and supported - try to set it */ if (srv->flags & SRV_KEEPALIVE) { int ka = 1; setsockopt(cs, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)); } #endif } server_t *create_server(int port, const char *localSocketName, int localSocketMode, int flags) { server_t *srv; SAIN ssa; int reuse, ss; #ifdef HAVE_IPV6 struct sockaddr_in6 ssa6; #endif #ifndef WIN32 struct sockaddr_un lusa; #endif #ifdef RSERV_DEBUG printf(" - create_server(port = %d, socket = %s, mode = %d, flags = 0x%x)\n", port, localSocketName ? localSocketName : "", localSocketMode, flags); #endif #ifdef WIN32 { WSADATA dt; /* initialize WinSock 1.1 */ WSAStartup(0x0101, &dt); } #endif if (localSocketName) { #ifdef WIN32 RSEprintf("ERROR: Local sockets are not supported on non-unix systems.\n"); return 0; #else if ((ss = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) { RSEprintf("ERROR: cannot create local socket: %s\n", strerror(errno)); return 0; } memset(&lusa, 0, sizeof(lusa)); lusa.sun_family = AF_LOCAL; if (strlen(localSocketName) > sizeof(lusa.sun_path) - 2) { RSEprintf("ERROR: Local socket name is too long for this system.\n"); return 0; } strcpy(lusa.sun_path, localSocketName); remove(localSocketName); /* remove existing if possible */ #endif } else #ifdef HAVE_IPV6 ss = socket((flags & SRV_IPV6) ? AF_INET6 : AF_INET, SOCK_STREAM, 0); #else ss = socket(AF_INET, SOCK_STREAM, 0); #endif if (ss == INVALID_SOCKET) { RSEprintf("ERROR: no available socket: %s\n", strerror(errno)); return 0; } srv = (server_t*) calloc(1, sizeof(server_t)); if (!srv) { RSEprintf("ERROR: cannot allocate memory for server structure\n"); return 0; } srv->ss = ss; srv->unix_socket = localSocketName ? 1 : 0; srv->flags = flags; srv->parent = 0; reuse = 1; /* enable socket address reusage */ setsockopt(ss, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)); #ifndef WIN32 if (localSocketName) { if (bind(ss, (SA*) &lusa, sizeof(lusa))) { RSEprintf("ERROR: unable to bind to %s: %s\n", lusa.sun_path, strerror(errno)); return 0; } if (localSocketMode) chmod(localSocketName, localSocketMode); } else { #endif #ifdef HAVE_IPV6 if (flags & SRV_IPV6) { memset(&ssa6, 0, sizeof(ssa6)); ssa6.sin6_family = AF_INET6; ssa6.sin6_port = htons(port); ssa6.sin6_addr = (flags & SRV_LOCAL) ? in6addr_loopback : in6addr_any; if (bind(ss, (struct sockaddr*) &ssa6, sizeof(ssa6))) { RSEprintf("ERROR: unable to bind to IPv6 port %d: %s\n", port, strerror(errno)); closesocket(ss); return 0; } } else { #endif memset(&ssa, 0, sizeof(ssa)); ssa.sin_family = AF_INET; ssa.sin_port = htons(port); ssa.sin_addr.s_addr = htonl((flags & SRV_LOCAL) ? INADDR_LOOPBACK : INADDR_ANY); if (bind(ss, (struct sockaddr*) &ssa, sizeof(ssa))) { RSEprintf("ERROR: unable to bind to IPv4 port %d: %s\n", port, strerror(errno)); closesocket(ss); return 0; } #ifdef HAVE_IPV6 } /* if (flags & SRV_IPV6) else */ #endif #ifndef WIN32 } /* if (localSocketName) else */ #endif if (listen(ss, LISTENQ)) { RSEprintf("ERROR: listen failed: %s\n", strerror(errno)); closesocket(ss); return 0; } add_active_srv_socket(ss); return srv; } void server_fin(void *x) { server_t *srv = (server_t*) x; if (srv) { closesocket(srv->ss); if (srv->ss != -1) rm_active_srv_socket(srv->ss); } } #define NSPS 16 struct server_stack { server_stack_t *prev, *next; int ns; server_t *srv[NSPS]; }; server_stack_t* create_server_stack(void) { server_stack_t *s = (server_stack_t*) malloc(sizeof(server_stack_t)); s->prev = s->next = 0; s->ns = 0; return s; } void push_server(server_stack_t *s, server_t *srv) { while (s->ns >= NSPS && s->next) s = s->next; if (s->ns >= NSPS) { server_stack_t *ns = create_server_stack(); ns->prev = s; s = s->next = ns; } s->srv[s->ns++] = srv; } void release_server_stack(server_stack_t *s) { while (s && s->next) s = s->next; while (s) { int i = s->ns; while (i-- > 0) { rm_server(s->srv[i]); free(s->srv[i]); } s->ns = 0; s = s->prev; } } int server_stack_size(server_stack_t *s) { int n = 0; while (s) { n += s->ns; s = s->next; } return n; } #define MAX_SERVERS 128 static int servers; static server_t *server[MAX_SERVERS]; int add_server(server_t *srv) { if (!srv) return 0; if (servers >= MAX_SERVERS) { RSEprintf("ERROR: too many servers\n"); return 0; } server[servers++] = srv; #ifdef RSERV_DEBUG printf("INFO: adding server %p (total %d servers)\n", (void*) srv, servers); #endif return 1; } int rm_server(server_t *srv) { int i = 0; if (!srv) return 0; while (i < servers) { if (server[i] == srv) { int j = i + 1; while (j < servers) { server[j - 1] = server[j]; j++; } servers--; } else i++; } if (srv->fin) srv->fin(srv); #ifdef RSERV_DEBUG printf("INFO: removing server %p (total %d servers left)\n", (void*) srv, servers); #endif return 1; } /* FIXME: those are copied from Rserve.c for now - clean it up ! */ static int UCIX = 1; static int use_ipv6 = 0; static int is_child = 0; static char **allowed_ips; struct args { server_t *srv; /* server that instantiated this connection */ SOCKET s; SOCKET ss; int msg_id; void *res1, *res2; /* the following entries are not populated by Rserve but can be used by server implemetations */ char *buf, *sbuf; int ver, bp, bl, sp, sl, flags; size_t l1, l2; /* The following fields are informational, populated by Rserve */ SAIN sa; int ucix; #ifndef WIN32 struct sockaddr_un su; #endif }; ssize_t server_recv(args_t *arg, void *buf, size_t len) { return recv(arg->s, buf, len, 0); } ssize_t server_send(args_t *arg, const void *buf, size_t len) { return send(arg->s, buf, len, 0); } typedef void (*sig_fn_t)(int); #ifndef WIN32 #include /* NULL ptr is used on some systems as SIG_DFL so we have to define our own value for "not set" */ static void sig_not_set(int x) {} #ifdef FORKED static void sigHandler(int i) { active = 0; } #endif sig_fn_t old_HUP = sig_not_set, old_TERM = sig_not_set, old_INT = sig_not_set; static void setup_signal_handlers(void) { #ifdef FORKED if (old_HUP == sig_not_set) old_HUP = signal(SIGHUP, sigHandler); if (old_TERM == sig_not_set) old_TERM = signal(SIGTERM, sigHandler); if (old_INT == sig_not_set) old_INT = signal(SIGINT, sigHandler); #endif } static void restore_signal_handlers(void) { if (old_HUP != sig_not_set) { signal(SIGHUP, old_HUP); old_HUP = sig_not_set; } if (old_TERM != sig_not_set) { signal(SIGTERM, old_TERM); old_TERM = sig_not_set; } if (old_INT != sig_not_set) { signal(SIGINT, old_INT); old_INT = sig_not_set; } } #else static void setup_signal_handlers(void) { } static void restore_signal_handlers(void) { } #endif static int RS_fork(args_t *arg) { #ifndef WIN32 return (arg->srv && arg->srv->fork) ? arg->srv->fork(arg) : fork(); #else return -1; #endif } void serverLoop(void) { struct timeval timv; int selRet = 0; fd_set readfds; setup_signal_handlers(); while(active && servers) { /* main serving loop */ int i; int maxfd = 0; #ifdef FORKED while (waitpid(-1, 0, WNOHANG) > 0); #endif /* 500ms (used to be 10ms) - it shouldn't really matter since it's ok for us to sleep -- the timeout will only influence how often we collect terminated children and (maybe) how quickly we react to shutdown */ timv.tv_sec = 0; timv.tv_usec = 500000; FD_ZERO(&readfds); for (i = 0; i < servers; i++) if (server[i]) { int ss = server[i]->ss; if (ss > maxfd) maxfd = ss; FD_SET(ss, &readfds); } selRet = select(maxfd + 1, &readfds, 0, 0, &timv); if (selRet > 0) { for (i = 0; i < servers; i++) { socklen_t al; struct args *sa; server_t *srv = server[i]; int ss = srv->ss; int succ = 0; if (server[i] && FD_ISSET(ss, &readfds)) { /* we may not know the size of args since servers may choose to add fileds, so allocate 1k which is safe */ sa = (struct args*)malloc(1024); memset(sa, 0, 1024); al = sizeof(sa->sa); #ifndef WIN32 if (server[i]->unix_socket) { al = sizeof(sa->su); sa->s = accept(ss, (SA*)&(sa->su), &al); } else #endif sa->s = accept(ss, (SA*)&(sa->sa), &al); if (sa->s == INVALID_SOCKET) { RSEprintf("accept failed: %s", strerror(errno)); continue; } accepted_server(srv, sa->s); sa->ucix = UCIX++; sa->ss = ss; sa->srv = srv; /* memset(sa->sk,0,16); sa->sfd=-1; #if defined SESSIONS && defined FORKED { int pd[2]; if (!pipe(&pd)) { } } #endif */ if (allowed_ips && !srv->unix_socket && !use_ipv6) { /* FIXME: IPv6 unsafe - filtering won't work on IPv6 addresses */ char **laddr = allowed_ips; int allowed = 0; while (*laddr) if (sa->sa.sin_addr.s_addr == inet_addr(*(laddr++))) { allowed=1; break; } if (allowed) { #ifdef RSERV_DEBUG printf("INFO: accepted connection for server %p, calling connected\n", (void*) srv); #endif srv->connected(sa); succ = 1; #ifdef FORKED /* when the child returns it means it's done (likely an error) but it is forked, so the only right thing to do is to exit */ if (is_child) exit(2); #endif } else { #ifdef RSERV_DEBUG printf("INFO: peer is not on allowed IP list, closing connection\n"); #endif closesocket(sa->s); } } else { /* ---> remote enabled */ #ifdef RSERV_DEBUG printf("INFO: accepted connection for server %p, calling connected\n", (void*) srv); #endif srv->connected(sa); succ = 1; if (is_child) /* same as above */ exit(2); } if (!succ) free(sa); } /* ready server */ } /* severs loop */ } /* select */ } /* end while(active) */ } #include static pid_t lastChild, parentPID; static args_t *self_args; int prepare_child(args_t *args) { #ifdef FORKED long rseed = random(); rseed ^= time(0); if (is_child) return 0; /* this is a no-op if we are already a child FIXME: thould this be an error ? */ if ((lastChild = RS_fork(args)) != 0) { /* parent/master part */ int forkErrno = errno; //grab errno close to source before it can be changed by other failures /* close the connection socket - the child has it already */ closesocket(args->s); if (lastChild == -1) RSEprintf("WARNING: fork() failed in prepare_child(): %s\n",strerror(forkErrno)); return lastChild; } /* child part */ restore_signal_handlers(); /* the handlers handle server shutdown so not needed in the child */ #if 0 if (main_argv && tag_argv && strlen(main_argv[0]) >= 8) strcpy(main_argv[0] + strlen(main_argv[0]) - 8, "/RsrvCHx"); #endif is_child = 1; srandom(rseed); parentPID = getppid(); close_all_srv_sockets(); /* close all server sockets - this includes arg->ss */ #ifdef CAN_TCP_NODELAY { int opt = 1; setsockopt(args->s, IPPROTO_TCP, TCP_NODELAY, (const char*) &opt, sizeof(opt)); } #endif #endif self_args = args; return 0; } /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/proxy/http_tools.h0000644000175100001440000000032714531234224016060 0ustar hornikusers#ifndef HTTP_TOOLS_H__ #define HTTP_TOOLS_H__ #include "http.h" /* from date.c */ char *posix2http(double); double http2posix(const char*); const char *get_header(http_request_t *req, const char *name); #endif Rserve/src/proxy/rscript.c0000644000175100001440000004635714531234224015357 0ustar hornikusers#include "chandler.h" #include "ulog.h" #include "qap.h" /* FIXME: add support for big-endian machines */ #define itop(X) (X) #include #include #include #include #include #include #include #include #include #include #include #include #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif static char *scr_socket = "Rscript_socket"; void R_script_socket(const char*s) { scr_socket = strdup(s); } static int recvn(int s, char *buf, int len) { int i = 0; while (len) { int n = recv(s, buf + i, len, 0); if (n == 0) return i; if (n < 0) return n; /* FIXME: handle EINTR ? */ i += n; len -= n; } return i; } static char *strapp(char *x, char *y) { if (y) { size_t l = strlen(y); memcpy(x, y, l); x += l; } return x; } typedef struct par_info { int type, attr_type; unsigned long len, attr_len; const char *attr, *payload, *next; } par_info_t; /* parse one parameter - check consistency of lengths involved, doesn't check alignment */ static int parse_par(par_info_t *pi, const char *buf, const char *eob) { const unsigned int *i = (const unsigned int*) buf; pi->type = 0; pi->len = 0; if (eob - buf < 4) return -1; /* incomplete (nothing is valid) */ pi->type = PAR_TYPE(itop(*i)); pi->len = PAR_LEN(itop(*(i++))); pi->attr_type = 0; pi->attr_len = 0; pi->attr = 0; if (pi->type & XT_LARGE) { if (eob - buf < 8) return -1; pi->len |= ((unsigned long) *(i++)) << 24; } pi->payload = (const char*) i; pi->next = pi->payload + pi->len; ulog("PAR [%d, %d bytes] %d left", pi->type, (int) pi->len, (int) (eob - pi->payload)); if ((eob - (const char*) i) < pi->len) return -2; /* truncated payload (type/len is valid) */ /* parse the attribute and check length consistencies */ if (pi->type & XT_HAS_ATTR) { if (pi->len < 4) return -3; /* inconsistent (attr doesn't fit) */ pi->attr_type = PAR_TYPE(*i); pi->attr_len = PAR_LEN(*(i++)); if (pi->attr_type & XT_HAS_ATTR) return -4; /* invalid recursive attribute */ if (pi->attr_type & XT_LARGE) { if (pi->attr_len < 8) return -3; pi->attr_len |= ((unsigned long) *(i++)) << 24; } if (pi->len < (pi->attr_len + ((pi->attr_type & XT_LARGE) ? 8 : 4))) return -3; pi->attr = (const char*) i; pi->payload = pi->attr + pi->attr_len; pi->attr_type &= 0x3F; /* strip LARGE/HAS_ATTR */ } pi->type &= 0x3F; /* strip LARGE/HAS_ATTR */ return 0; } /* >= 0 (string length) if the parameter has string, -1 otherwise */ static long string_par_len(par_info_t *pi) { char *c; if (pi->type != XT_ARRAY_STR && pi->len < 1) return -1; c = memchr(pi->payload, 0, pi->len); return (c) ? (c - pi->payload) : -1; } static char fs_buf[4096]; int R_script_handler(http_request_t *req, http_result_t *res, const char *path) { int l = strlen(path), s; const char *path_script = path, *path_info = 0; struct stat st; if (!req || !req->url) return 0; /* this should never happen, but to avoid crashes... */ /* /library/ and /doc/ are special since they refer to R documentation */ if (strncmp(req->url, "/library/", 9) && strncmp(req->url, "/doc/", 5)) { /* we only serve .R scripts */ if (l < 2 || (strcmp(path + l - 2, ".R") && !strstr(path, ".R/"))) return 0; size_t l = strlen(path); FILE *f; if (stat(path, &st)) { /* no match? try partial patch */ if (l < sizeof(fs_buf)) { /* also guard about too long strings */ char *d = fs_buf + l; strcpy(fs_buf, path); while (d > fs_buf) { while (d > fs_buf && *d != '/') d--; if (d == fs_buf) break; *d = 0; ulog("INFO: no match, try '%s'", fs_buf); if (!stat(fs_buf, &st)) { if (st.st_mode & S_IFREG) { path_script = fs_buf; path_info = d + 1; } break; } /* restore since it will be part of path.info */ *d = '/'; d--; } } } /* try once again - must be a regular file*/ if (stat(path_script, &st) || ((st.st_mode & S_IFREG) == 0)) { res->err = strdup("Path not found (R script)"); res->code = 404; return 1; } if (!(f = fopen(path_script, "rb"))) { res->err = strdup("Cannot open script file"); res->code = 403; return 1; } else fclose(f); } ulog("INFO: serving R script '%s' (pi='%s')", path_script, path_info ? path_info : ""); s = socket(AF_LOCAL, SOCK_STREAM, 0); { /* connect to script services QAP socket */ struct sockaddr_un sau; struct phdr hdr; char *oci; int n; memset(&sau, 0, sizeof(sau)); sau.sun_family = AF_LOCAL; strcpy(sau.sun_path, scr_socket); if (s == -1 || connect(s, (struct sockaddr*)&sau, sizeof(sau))) { ulog("ERROR: failed to connect to script socket '%s': %s", scr_socket, strerror(errno)); res->err = strdup("cannot connect to R services"); res->code = 500; return 1; } if ((n = recvn(s, (char*) &hdr, sizeof(hdr))) != sizeof(hdr)) { ulog("ERROR: cannot read ID string/header (n = %d, errno: %s)", n, strerror(errno)); res->err = strdup("cannot read ID string/header from R services"); res->code = 500; close(s); return 1; } hdr.cmd = itop(hdr.cmd); hdr.len = itop(hdr.len); if (hdr.cmd != CMD_OCinit) { ulog("ERROR: server did not respond with RsOC message - wrong protocol?"); res->err = strdup("R services are not running in OCAP mode"); res->code = 500; close(s); return 1; } if (hdr.res || hdr.len > 0x7fffff || hdr.len < 32) { ulog("ERROR: initial message doesn't have expected length (got %d bytes)", hdr.len); res->err = strdup("R services responded with invalid large message"); res->code = 500; close(s); return 1; } oci = (char*) malloc(hdr.len + 128); if (!oci) { ulog("ERROR: out of memory when allocating buffer for RsOC message"); res->err = strdup("out of memory"); res->code = 500; close(s); return 1; } if ((n = recvn(s, oci, hdr.len)) != hdr.len) { free(oci); ulog("ERROR: read error in RsOC payload (n = %d, errno: %s)", n, strerror(errno)); res->err = strdup("cannot read ID string/header from R services"); res->code = 500; close(s); return 1; } { char qq[4096], *q = qq; int i; for (i = 0; i < hdr.len; i++) q += snprintf(q, 8, " %02x", (int) ((unsigned char*)oci)[i]); ulog(qq); } /* parse RsOC */ { unsigned int *hp = (unsigned int*) oci; if (PAR_TYPE(itop(*hp)) == DT_SEXP) { hp++; if (PAR_TYPE(itop(*hp)) == (XT_ARRAY_STR | XT_HAS_ATTR)) { unsigned int ocl = PAR_LEN(itop(*hp)); /* check length sanity */ if (ocl <= hdr.len - 8) { /* simple packing: url, query, headers, body all but body may not contain \0 so they are separated by \0, body is the remainder */ unsigned long l = 0, tpl; char *outp, *oc; qap_hdr_t *oh; unsigned int *oi; int add_large = 0; if (req->url) l += strlen(req->url); if (req->query) l += strlen(req->query); if (req->headers) l += strlen(req->headers); if (req->body_len) l += req->body_len; l += 3; /* 3 separating \0s */ tpl = l + ocl + 36; /* DT_SEXP; XT_LANG_NOTAG; OCAP; XT_RAW; raw-len + 16-byte hdr */ if (l > 0xfff800) { add_large = XT_LARGE; tpl += 12; /* DT_SEXP | XT_LARGE + XT_LANG_NOTAG | XT_LARGE + XT_RAW | XT_LARGE */ } tpl = (tpl + 3) & (~3); /* align */ ulog("l = %lu, tpl = %lu", l, tpl); outp = (char*) malloc(tpl); if (!outp) { ulog("ERROR: out of memory when allocating output buffer (%lu bytes)", tpl); res->err = strdup("out of memory"); res->code = 500; close(s); return 1; } oh = (qap_hdr_t*) outp; oi = (unsigned int*) (outp + sizeof(qap_hdr_t)); oh->cmd = itop(CMD_OCcall); oh->len = itop((unsigned int) (tpl - sizeof(qap_hdr_t))); oh->res = 0; oh->msg_id = hdr.msg_id; tpl -= sizeof(qap_hdr_t) + 4; /* hdr - DT_SXP header */ *(oi++) = itop(SET_PAR(DT_SEXP | add_large, tpl)); tpl -= 4; if (add_large) { *(oi++) = itop(tpl >> 24); tpl -= 4; } *(oi++) = itop(SET_PAR(XT_LANG_NOTAG | add_large, tpl)); tpl -= 4; if (add_large) { *(oi++) = itop(tpl >> 24); tpl -= 4; } memcpy(oi, hp, ocl + 4); tpl -= ocl + 4; oi += (ocl + 4) / 4; /* Note: we don't check alignment */ *(oi++) = itop(SET_PAR(XT_RAW | add_large, (l + 7) & 0xfffffffc)); if (add_large) *(oi++) = itop((l + 7) >> 24); *(oi++) = itop(l); oc = (char*) oi; ulog("l will be stored at %ld", (long int) (oc - outp)); oc = strapp(oc, req->url); *(oc++) = 0; oc = strapp(oc, req->query); *(oc++) = 0; oc = strapp(oc, req->headers); *(oc++) = 0; if (req->body_len) memcpy(oc, req->body, req->body_len); ulog("INFO: sending %d bytes (n = %d)", itop(oh->len) + sizeof(qap_hdr_t), send(s, outp, itop(oh->len) + sizeof(qap_hdr_t), 0)); #if 0 { char qq[4096], *q = qq; int i; for (i = 0; i < ((tpl > 256) ? 256 : tpl); i++) q += snprintf(q, 8, " %02x", (int) ((unsigned char*)outp)[i]); ulog(qq); } #endif free(outp); /* ok, now we just wait for the response ... */ if ((n = recvn(s, (char*) &hdr, sizeof(hdr))) != sizeof(hdr)) { free(oci); ulog("ERROR: read error on OCcall response header (n = %d, errno: %s)", n, strerror(errno)); res->err = strdup("R aborted on the request"); res->code = 500; close(s); return 1; } hdr.cmd = itop(hdr.cmd); hdr.len = itop(hdr.len); ulog("INFO: OCcall response 0x%08x (%d bytes)", hdr.cmd, hdr.len); free(oci); oci = (char*) malloc(hdr.len + 128); if (!oci) { ulog("ERROR: out of memory when allocating buffer for OCcall response (%u bytes)", hdr.len + 128); res->err = strdup("out of memory"); res->code = 500; close(s); return 1; } if ((n = recvn(s, oci, hdr.len)) != hdr.len) { free(oci); ulog("ERROR: read error in OCCall response payload (n = %d, errno: %s)", n, strerror(errno)); res->err = strdup("incomplete response from R"); res->code = 500; close(s); return 1; } { char qq[4096], *q = qq; int i; for (i = 0; i < ((hdr.len > 256) ? 256 : hdr.len); i++) q += snprintf(q, 8, " %02x", (int) ((unsigned char*)oci)[i]); ulog(qq); } /* expect: DT_SEXP -> XT_VECTOR -> XT_ARRAY_STR ... */ { par_info_t pi; const char *eoci = oci + hdr.len, *cp = oci; int peo; if ((peo = parse_par(&pi, cp, eoci)) || pi.type != DT_SEXP || pi.len < 4) { free(oci); ulog("ERROR: invalid payload (at DT, parse error %d, type = %d, length = %d)", peo, pi.type, pi.len); res->err = strdup("invalid response payload from R"); res->code = 500; close(s); return 1; } cp = pi.payload; if ((peo = parse_par(&pi, cp, eoci))) { free(oci); ulog("ERROR: invalid payload (at SEXP, parse error %d)",peo); res->err = strdup("invalid response payload from R"); res->code = 500; close(s); return 1; } cp = pi.payload; eoci = cp + pi.len; res->payload = 0; if (pi.type == XT_VECTOR) { if (!(peo = parse_par(&pi, cp, eoci))) { if (pi.type == XT_RAW) { unsigned int *ptr = (unsigned int*) pi.payload, pl; pl = itop(*ptr); if (pl + 4 <= pi.len) { if ((res->payload = (char*) malloc(pl))) { res->payload_len = pl; memcpy(res->payload, (char*) (ptr + 1), pl); ulog("INFO: raw body (%u bytes)", pl); } } } else { long strl = string_par_len(&pi); /* FIXME: add support for named vectors that serve files */ if (strl >= 0) { res->payload = strdup(pi.payload); res->payload_len = strl; ulog("INFO: text body (%ld bytes)", strl); } } cp = pi.next; if (res->payload) { long strl; if (cp < eoci && !(peo = parse_par(&pi, cp, eoci)) && (strl = string_par_len(&pi)) >= 0) { res->content_type = strdup(pi.payload); ulog("INFO: content-type: '%s'", res->content_type); cp = pi.next; if (cp < eoci && !(peo = parse_par(&pi, cp, eoci)) && (strl = string_par_len(&pi)) >= 0) { res->headers = strdup(pi.payload); ulog("INFO: headers: '%s'", res->headers); cp = pi.next; if (cp < eoci && !(peo = parse_par(&pi, cp, eoci)) && pi.type == XT_ARRAY_INT && pi.len >= 4) ulog("INFO: HTTP code: %d", (res->code = *((const int*) pi.payload))); } /* headers */ } /* content-type */ free(oci); close(s); return 1; } /* body */ } free(oci); ulog("ERROR: invalid payload (missing body in the result list, parse error %d)", peo); res->err = strdup("missing body in response list from R"); res->code = 500; close(s); return 1; } else if (pi.type == XT_ARRAY_STR && string_par_len(&pi) >= 0) { res->err = strdup(pi.payload); free(oci); res->code = 500; close(s); return 1; } else { free(oci); ulog("ERROR: invalid payload (expected list[16]/string[34], got %d with %d bytes)", pi.type, pi.len); res->err = strdup("invalid response from R - neither a vector or character result"); res->code = 500; close(s); return 1; } } } close(s); } } } close(s); free(oci); } res->err = strdup("not implemented yet"); res->payload = 0; res->payload_len = 0; res->code = 500; return 1; } Rserve/src/proxy/bsdcmpt.h0000644000175100001440000000140314531234224015311 0ustar hornikusers#ifndef BSD_CMPT_H__ #define BSD_CMPT_H__ /* Implementation of BSD-specific pieces used in the proxy that are missing on other platforms. Curretnly we only used it on OS X but we should add a cfg check for other BSD variants. */ #include #ifdef __APPLE__ #define MTIME(X) (X).st_mtimespec.tv_sec #else #define MTIME(X) (X).st_mtime /* not part of Linux/POSIX so implement it ... */ static const char *strnstr(const char *haystack, const char *needle, size_t len) { const char *eohs = haystack + len; size_t nl = strlen(needle); while (eohs - haystack >= nl && (haystack = memchr(haystack, needle[0], eohs - haystack))) if (!memcmp(haystack, needle, nl)) return haystack; else haystack++; return 0; } #endif #endif Rserve/src/proxy/http.c0000644000175100001440000007044314531234224014641 0ustar hornikusers#include "tls.h" #include "http.h" #include "ulog.h" #include "websockets.h" /* for connection upgrade */ #include #include /* size of the line buffer for each worker (request and header only) * requests that have longer headers will be rejected with 413 * Note that cookies can be quite big and some browsers send them * in one line, so this should not be too small */ #define LINE_BUF_SIZE 32768 /* debug output - change the DBG(X) X to enable debugging output */ #ifdef RSERV_DEBUG #define DBG(X) X #else #define DBG(X) #endif #include "rserr.h" /* --- httpd --- */ #define PART_REQUEST 0 #define PART_HEADER 1 #define PART_BODY 2 #define METHOD_POST 1 #define METHOD_GET 2 #define METHOD_HEAD 3 #define METHOD_OTHER 8 /* for custom requests only */ /* attributes of a connection/worker */ #define CONNECTION_CLOSE 0x0001 /* Connection: close response behavior is requested */ #define HOST_HEADER 0x0002 /* headers contained Host: header (required for HTTP/1.1) */ #define HTTP_1_0 0x0004 /* the client requested HTTP/1.0 */ #define CONTENT_LENGTH 0x0008 /* Content-Length: was specified in the headers */ #define THREAD_OWNED 0x0010 /* the worker is owned by a thread and cannot removed */ #define THREAD_DISPOSE 0x0020 /* the thread should dispose of the worker */ #define CONTENT_TYPE 0x0040 /* message has a specific content type set */ #define CONTENT_FORM_UENC 0x0080 /* message content type is application/x-www-form-urlencoded */ #define WS_UPGRADE 0x0100 /* upgrade to WebSockets protocol */ struct buffer { struct buffer *next, *prev; size_t size, length; char data[1]; }; #ifndef WIN32 #include /* needed for unix sockets */ #endif #include struct aux_pass { http_handler_fn_t http_handler; #ifdef NO_WEBSOCKETS void *ws_connected; #else ws_connected_fn_t ws_connected; #endif }; struct args { server_t *srv; /* server that instantiated this connection */ SOCKET s; SOCKET ss; int msg_id; void *res1, *res2; /* the following entries are not populated by Rserve but can be used by server implemetations */ char *buf, *sbuf; int ver, bp, bl, sp, sl, flags; size_t l1, l2; /* The following fields are informational, populated by Rserve */ SAIN sa; int ucix; #ifdef unix struct sockaddr_un su; #endif char *line_buf; /* line buffer (used for request and headers) */ char *url, *body; /* URL and request body */ char *content_type; /* content type (if set) */ unsigned int line_pos, body_pos; /* positions in the buffers */ long content_length; /* desired content length */ char part, method; /* request part, method */ int attr; /* connection attributes */ double req_date; /* request date */ char *ws_protocol, *ws_version, *ws_key; struct buffer *headers; /* buffer holding header lines */ struct aux_pass *aux; }; #define IS_HTTP_1_1(C) (((C)->attr & HTTP_1_0) == 0) /* returns the HTTP/x.x string for a given connection - we support 1.0 and 1.1 only */ #define HTTP_SIG(C) (IS_HTTP_1_1(C) ? "HTTP/1.1" : "HTTP/1.0") /* free buffers starting from the tail(!!) */ static void free_buffer(struct buffer *buf) { if (!buf) return; if (buf->prev) free_buffer(buf->prev); free(buf); } /* allocate a new buffer */ static struct buffer *alloc_buffer(size_t size, struct buffer *parent) { struct buffer *buf = (struct buffer*) malloc(sizeof(struct buffer) + size); if (!buf) return buf; buf->next = 0; buf->prev = parent; if (parent) parent->next = buf; buf->size = size; buf->length = 0; return buf; } typedef struct { size_t size; char buf[1]; } buf_t; static buf_t *alloc_buf(size_t size) { buf_t *buf = (buf_t*) malloc(size + sizeof(buf_t)); buf->size = size; return buf; } /* convert doubly-linked buffers into one big raw vector */ static buf_t *collect_buffers(struct buffer *buf) { buf_t *res; char *dst; size_t len = 0; if (!buf) return alloc_buf(0); while (buf->prev) { /* count the total length and find the root */ len += buf->length; buf = buf->prev; } len += buf->length; res = alloc_buf(len + 1); dst = res->buf; while (buf) { memcpy(dst, buf->data, buf->length); dst += buf->length; buf = buf->next; } res->buf[len] = 0; /* guarantee a trailing NUL so it can be used as a string */ return res; } static void free_args(args_t *c) { DBG(printf("finalizing worker %p\n", (void*) c)); if (c->url) { free(c->url); c->url = NULL; } if (c->line_buf) { free(c->line_buf); c->line_buf = NULL; } if (c->body) { free(c->body); c->body = NULL; } if (c->content_type) { free(c->content_type); c->content_type = NULL; } if (c->headers) { free_buffer(c->headers); c->headers = NULL; } if (c->ws_key) { free(c->ws_key); c->ws_key = NULL; } if (c->ws_protocol) { free(c->ws_protocol); c->ws_protocol = NULL; } if (c->ws_version) { free(c->ws_version); c->ws_version = NULL; } if (c->s != INVALID_SOCKET) { closesocket(c->s); c->s = INVALID_SOCKET; } } static int send_response(args_t *c, const char *buf, size_t len) { server_t *srv = c->srv; unsigned int i = 0; /* we have to tell R to ignore SIGPIPE otherwise it can raise an error and get us into deep trouble */ while (i < len) { int n = srv->send(c, buf + i, len - i); if (n < 1) { return -1; } i += n; } return 0; } /* sends HTTP/x.x plus the text (which should be of the form " XXX ...") */ static int send_http_response(args_t *c, const char *text) { char buf[96]; server_t *srv = c->srv; const char *s = HTTP_SIG(c); int l = strlen(text), res; /* reduce the number of packets by sending the payload en-block from buf */ if (l < sizeof(buf) - 10) { strcpy(buf, s); strcpy(buf + 8, text); return send_response(c, buf, l + 8); } res = srv->send(c, s, 8); if (res < 8) return -1; return send_response(c, text, strlen(text)); } /* decode URI in place (decoding never expands) */ static void uri_decode(char *s) { char *t = s; while (*s) { if (*s == '+') { /* + -> SPC */ *(t++) = ' '; s++; } else if (*s == '%') { unsigned char ec = 0; s++; if (*s >= '0' && *s <= '9') ec |= ((unsigned char)(*s - '0')) << 4; else if (*s >= 'a' && *s <= 'f') ec |= ((unsigned char)(*s - 'a' + 10)) << 4; else if (*s >= 'A' && *s <= 'F') ec |= ((unsigned char)(*s - 'A' + 10)) << 4; if (*s) s++; if (*s >= '0' && *s <= '9') ec |= (unsigned char)(*s - '0'); else if (*s >= 'a' && *s <= 'f') ec |= (unsigned char)(*s - 'a' + 10); else if (*s >= 'A' && *s <= 'F') ec |= (unsigned char)(*s - 'A' + 10); if (*s) s++; *(t++) = (char) ec; } else *(t++) = *(s++); } *t = 0; } /* finalize a request - essentially for HTTP/1.0 it means that * we have to close the connection */ static void fin_request(args_t *c) { if (!IS_HTTP_1_1(c)) c->attr |= CONNECTION_CLOSE; } static void free_res(http_result_t* res) { if (res->err) free(res->err); if (res->payload) free(res->payload); if (res->content_type) free(res->content_type); if (res->headers) free(res->headers); } /* -- logging -- */ static char wlbuf[256]; static void web_log(http_request_t *req, http_result_t *res) { const char *c = req->headers ? strstr(req->headers, "X-Real-IP:") : ""; if (c) { const char *d; c += 10; while (*c == '\t' || *c == ' ') c++; d = c; while (*d && *d > ' ') d++; if (d - c > 64) d = c + 64; memcpy(wlbuf, c, d - c); wlbuf[d - c] = 0; } else /* FIXME: supply actual IP from the connection? */ *wlbuf = 0; ulog("HTTP %d\t%s\t%d\t%ld\t%s\t%s", res->code ? res->code : 200, wlbuf, res->payload_type, (long) res->payload_len, req->url, res->err ? res->err : ""); } /* -- from date.c -- */ char *posix2http(double ts); /* Note: returned buffer is static */ double http2posix(const char *c); /* process a request by calling the httpd() function in R */ static void process_request(args_t *c) { char *query = 0, *s; DBG(fprintf(stderr, "process request for %p\n", (void*) c)); if (!c || !c->url) return; /* if there is not enough to process, bail out */ #ifndef NO_WEBSOCKETS if ((c->attr & WS_UPGRADE) && (c->srv->flags & HTTP_WS_UPGRADE)) { WS13_upgrade(c, c->ws_key, c->ws_protocol, c->ws_version, c->aux->ws_connected); /* the WS swtich messes up args since it replaces it with its own version so we can't go back to serving - just bail out (NOTE: only works when forked!) */ exit(0); } #endif s = c->url; while (*s && *s != '?') s++; /* find the query part */ if (*s) { *(s++) = 0; query = s; } uri_decode(c->url); /* decode the path part */ { /* construct "try(httpd(url, query, body, headers), silent=TRUE)" */ http_request_t req; http_result_t res = { 0, 0, 0, 0, 0, 0 }; buf_t *headers = c->headers ? collect_buffers(c->headers) : 0; req.url = c->url; req.body = c->body; req.body_len = c->body_pos; req.query = query ? query : 0; req.headers = headers ? headers->buf : 0; req.date = c->req_date; c->aux->http_handler(&req, &res); web_log(&req, &res); if (headers) { free(headers); headers = 0; } /* the result is expected to have one of the following forms: a) character vector of length 1 => error (possibly from try), will create 500 response b) list(payload[, content-type[, headers[, status code]]]) payload: can be a character vector of length one or a raw vector. if the character vector is named "file" then the content of a file of that name is the payload content-type: must be a character vector of length one or NULL (if present, else default is "text/html") headers: must be a character vector - the elements will have CRLF appended and neither Content-Type nor Content-Length may be used status code: must be an integer if present (default is 200) */ if (res.err) { send_http_response(c, " 500 Evaluation error\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n"); DBG(fprintf(stderr, "respond with 500 and content: %s\n", s)); if (c->method != METHOD_HEAD) send_response(c, res.err, strlen(res.err)); c->attr |= CONNECTION_CLOSE; /* force close */ free_res(&res); return; } { int code = res.code ? res.code : 200; /* if no code is provided we assume 200 */ char buf[64]; const char *ct = res.content_type ? res.content_type : "text/html"; if (code == 200) { send_http_response(c, " 200 OK\r\nContent-Type: "); send_response(c, ct, strlen(ct)); } else if (code == 304) { /* not modified - don't need content type */ sprintf(buf, "%s 304 Not Modified", HTTP_SIG(c)); send_response(c, buf, strlen(buf)); } else { sprintf(buf, "%s %d Code %d\r\nContent-Type: ", HTTP_SIG(c), code, code); send_response(c, buf, strlen(buf)); send_response(c, ct, strlen(ct)); } /* the handler may explicitly avoid the generation of the Date: header by setting res.date to a negative value. Value of 0.0 (default) instructs the server to populate it with the current timestamp, other values are explicit dates */ if (res.date == 0.0) res.date = (double) time(0); if (res.date < 0.0) send_response(c, "\r\n", 2); else { sprintf(buf, "\r\nDate: %s\r\n", posix2http(res.date)); send_response(c, buf, strlen(buf)); } if (res.headers) { int hlen = strlen(res.headers); send_response(c, res.headers, hlen); /* the headers have to be terminated - do so if need be */ if (hlen && res.headers[hlen - 1] != '\n') send_response(c, "\r\n", 2); } if (res.payload_type == PAYLOAD_FILE || res.payload_type == PAYLOAD_TEMPFILE) { const char *fn = res.payload; if (fn) { char *fbuf; FILE *f = fopen(fn, "rb"); long fsz = 0; if (!f) { send_response(c, "Content-Length: 0\r\n\r\n", 23); fin_request(c); return; } fseek(f, 0, SEEK_END); fsz = ftell(f); fseek(f, 0, SEEK_SET); sprintf(buf, "Content-Length: %ld\r\n\r\n", fsz); send_response(c, buf, strlen(buf)); if (c->method != METHOD_HEAD) { fbuf = (char*) malloc(32768); if (fbuf) { while (fsz > 0 && !feof(f)) { int rd = (fsz > 32768) ? 32768 : fsz; if (fread(fbuf, 1, rd, f) != rd) { free(fbuf); free_res(&res); c->attr |= CONNECTION_CLOSE; fclose(f); if (res.payload_type == PAYLOAD_TEMPFILE) unlink(fn); return; } send_response(c, fbuf, rd); fsz -= rd; } free(fbuf); } else { /* allocation error - get out */ c->attr |= CONNECTION_CLOSE; free_res(&res); fclose(f); if (res.payload_type == PAYLOAD_TEMPFILE) unlink(fn); return; } } fclose(f); free_res(&res); if (res.payload_type == PAYLOAD_TEMPFILE) unlink(fn); fin_request(c); return; } sprintf(buf, "Content-Length: 0\r\n\r\n"); send_response(c, buf, strlen(buf)); free_res(&res); fin_request(c); return; } else { /* verbatim payload */ if (res.code == 304) /* 304 may NOT send any body and thus no content-length */ send_response(c, "\r\n", 2); else { sprintf(buf, "Content-Length: %lu\r\n\r\n", (unsigned long) res.payload_len); send_response(c, buf, strlen(buf)); if (c->method != METHOD_HEAD) send_response(c, res.payload, res.payload_len); } free_res(&res); fin_request(c); return; } } } send_http_response(c, " 500 Invalid response from handler.\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\nServer error: invalid response from handler.\r\n"); c->attr |= CONNECTION_CLOSE; /* force close */ } static void http_close(args_t *arg) { closesocket(arg->s); arg->s = -1; } /* this function is called to fetch new data from the client * connection socket and process it */ static void http_input_iteration(args_t *c) { int n; server_t *srv = c->srv; DBG(printf("worker_input_handler, data=%p\n", (void*) c)); if (!c) return; DBG(printf("input handler for worker %p (sock=%d, part=%d, method=%d, line_pos=%d)\n", (void*) c, (int)c->s, (int)c->part, (int)c->method, (int)c->line_pos)); /* FIXME: there is one edge case that is not caught on unix: if * recv reads two or more full requests into the line buffer then * this function exits after the first one, but input handlers may * not trigger, because there may be no further data. It is not * trivial to fix, because just checking for a full line at the * beginning and not calling recv won't trigger a new input * handler. However, under normal circumstance this should not * happen, because clients should wait for the response and even * if they don't it's unlikely that both requests get combined * into one packet. */ if (c->part < PART_BODY) { char *s = c->line_buf; n = srv->recv(c, c->line_buf + c->line_pos, LINE_BUF_SIZE - c->line_pos - 1); DBG(printf("[recv n=%d, line_pos=%d, part=%d]\n", n, c->line_pos, (int)c->part)); if (n < 0) { /* error, scrape this worker */ http_close(c); return; } if (n == 0) { /* connection closed -> try to process and then remove */ process_request(c); http_close(c); return; } c->line_pos += n; c->line_buf[c->line_pos] = 0; DBG(printf("in buffer: {%s}\n", c->line_buf)); while (*s) { /* ok, we have genuine data in the line buffer */ if (s[0] == '\n' || (s[0] == '\r' && s[1] == '\n')) { /* single, empty line - end of headers */ /* --- check request validity --- */ DBG(printf(" end of request, moving to body\n")); if (!(c->attr & HTTP_1_0) && !(c->attr & HOST_HEADER)) { /* HTTP/1.1 mandates Host: header */ send_http_response(c, " 400 Bad Request (Host: missing)\r\nConnection: close\r\n\r\n"); http_close(c); return; } if (c->attr & CONTENT_LENGTH && c->content_length) { if (c->content_length < 0 || /* we are parsing signed so negative numbers are bad */ c->content_length > 2147483640 || /* R will currently have issues with body around 2Gb or more, so better to not go there */ !(c->body = (char*) malloc(c->content_length + 1 /* allocate an extra termination byte */ ))) { send_http_response(c, " 413 Request Entity Too Large (request body too big)\r\nConnection: close\r\n\r\n"); http_close(c); return; } } c->body_pos = 0; c->part = PART_BODY; if (s[0] == '\r') s++; s++; /* move the body part to the beginning of the buffer */ c->line_pos -= s - c->line_buf; memmove(c->line_buf, s, c->line_pos); /* GET/HEAD or no content length mean no body */ if (c->method == METHOD_GET || c->method == METHOD_HEAD || !(c->attr & CONTENT_LENGTH) || c->content_length == 0) { if ((c->attr & CONTENT_LENGTH) && c->content_length > 0) { send_http_response(c, " 400 Bad Request (GET/HEAD with body)\r\n\r\n"); http_close(c); return; } process_request(c); if (c->attr & CONNECTION_CLOSE) { http_close(c); return; } /* keep-alive - reset the worker so it can process a new request */ if (c->url) { free(c->url); c->url = NULL; } if (c->body) { free(c->body); c->body = NULL; } if (c->content_type) { free(c->content_type); c->content_type = NULL; } if (c->headers) { free_buffer(c->headers); c->headers = NULL; } if (c->ws_key) { free(c->ws_key); c->ws_key = NULL; } if (c->ws_protocol) { free(c->ws_protocol); c->ws_protocol = NULL; } if (c->ws_version) { free(c->ws_version); c->ws_version = NULL; } c->body_pos = 0; c->method = 0; c->part = PART_REQUEST; c->attr = 0; c->content_length = 0; return; } /* copy body content (as far as available) */ c->body_pos = (c->content_length < c->line_pos) ? c->content_length : c->line_pos; if (c->body_pos) { memcpy(c->body, c->line_buf, c->body_pos); c->line_pos -= c->body_pos; /* NOTE: we are NOT moving the buffer since non-zero left-over causes connection close */ } /* POST will continue into the BODY part */ break; } { char *bol = s; while (*s && *s != '\r' && *s != '\n') s++; if (!*s) { /* incomplete line */ if (bol == c->line_buf) { if (c->line_pos < LINE_BUF_SIZE) /* one, incomplete line, but the buffer is not full yet, just return */ return; /* the buffer is full yet the line is incomplete - we're in trouble */ send_http_response(c, " 413 Request entity too large\r\nConnection: close\r\n\r\n"); http_close(c); return; } /* move the line to the begining of the buffer for later requests */ c->line_pos -= bol - c->line_buf; memmove(c->line_buf, bol, c->line_pos); return; } else { /* complete line, great! */ if (*s == '\r') *(s++) = 0; if (*s == '\n') *(s++) = 0; DBG(printf("complete line: {%s}\n", bol)); if (c->part == PART_REQUEST) { /* --- process request line --- */ unsigned int rll = strlen(bol); /* request line length */ char *url = strchr(bol, ' '); if (!url || rll < 14 || strncmp(bol + rll - 9, " HTTP/1.", 8)) { /* each request must have at least 14 characters [GET / HTTP/1.0] and have HTTP/1.x */ send_response(c, "HTTP/1.0 400 Bad Request\r\n\r\n", 28); http_close(c); return; } url++; if (!strncmp(bol + rll - 3, "1.0", 3)) c->attr |= HTTP_1_0; if (!strncmp(bol, "GET ", 4)) c->method = METHOD_GET; if (!strncmp(bol, "POST ", 5)) c->method = METHOD_POST; if (!strncmp(bol, "HEAD ", 5)) c->method = METHOD_HEAD; { char *mend = url - 1; /* we generate a header with the method so it can be passed to the handler */ if (!c->headers) c->headers = alloc_buffer(1024, NULL); /* make sure it fits */ if (c->headers->size - c->headers->length >= 18 + (mend - bol)) { if (!c->method) c->method = METHOD_OTHER; /* add "Request-Method: xxx" */ memcpy(c->headers->data + c->headers->length, "Request-Method: ", 16); c->headers->length += 16; memcpy(c->headers->data + c->headers->length, bol, mend - bol); c->headers->length += mend - bol; c->headers->data[c->headers->length++] = '\n'; } } if (!c->method) { send_http_response(c, " 501 Invalid or unimplemented method\r\n\r\n"); http_close(c); return; } bol[strlen(bol) - 9] = 0; c->url = strdup(url); c->part = PART_HEADER; DBG(printf("parsed request, method=%d, URL='%s'\n", (int)c->method, c->url)); } else if (c->part == PART_HEADER) { /* --- process headers --- */ char *k = bol; if (!c->headers) c->headers = alloc_buffer(1024, NULL); if (c->headers) { /* record the header line in the buffer */ int l = strlen(bol); if (l) { /* this should be really always true */ if (c->headers->length + l + 1 > c->headers->size) { /* not enough space? */ int fits = c->headers->size - c->headers->length; int needs = 2048; if (fits) { memcpy(c->headers->data + c->headers->length, bol, fits); c->headers->length += fits; } while (l + 1 - fits >= needs) needs <<= 1; if (alloc_buffer(needs, c->headers)) { c->headers = c->headers->next; memcpy(c->headers->data, bol + fits, l - fits); c->headers->length = l - fits; c->headers->data[c->headers->length++] = '\n'; } } else { memcpy(c->headers->data + c->headers->length, bol, l); c->headers->length += l; c->headers->data[c->headers->length++] = '\n'; } } } while (*k && *k != ':') { if (*k >= 'A' && *k <= 'Z') *k |= 0x20; k++; } if (*k == ':') { *(k++) = 0; while (*k == ' ' || *k == '\t') k++; DBG(printf("header '%s' => '%s'\n", bol, k)); if (!strcmp(bol, "upgrade") && !strcmp(k, "websocket")) c->attr |= WS_UPGRADE; if (!strcmp(bol, "content-length")) { c->attr |= CONTENT_LENGTH; c->content_length = atol(k); } if (!strcmp(bol, "content-type")) { char *l = k; while (*l) { if (*l >= 'A' && *l <= 'Z') *l |= 0x20; l++; } c->attr |= CONTENT_TYPE; if (c->content_type) free(c->content_type); c->content_type = strdup(k); if (!strncmp(k, "application/x-www-form-urlencoded", 33)) c->attr |= CONTENT_FORM_UENC; } if (!strcmp(bol, "host")) c->attr |= HOST_HEADER; if (!strcmp(bol, "date")) c->req_date = http2posix(k); if (!strcmp(bol, "connection")) { char *l = k; while (*l) { if (*l >= 'A' && *l <= 'Z') *l |= 0x20; l++; } if (!strncmp(k, "close", 5)) c->attr |= CONNECTION_CLOSE; } if (!strcmp(bol, "sec-websocket-key")) { if (c->ws_key) free(c->ws_key); c->ws_key = strdup(k); } if (!strcmp(bol, "sec-websocket-protocol")) { if (c->ws_protocol) free(c->ws_protocol); c->ws_protocol = strdup(k); } if (!strcmp(bol, "sec-websocket-version")) { if (c->ws_version) free(c->ws_version); c->ws_version = strdup(k); } DBG(fprintf(stderr, " [attr = %x]\n", c->attr)); } } } } } if (c->part < PART_BODY) { /* we end here if we processed a buffer of exactly one line */ c->line_pos = 0; return; } } if (c->part == PART_BODY && c->body) { /* BODY - this branch always returns */ if (c->body_pos < c->content_length) { /* need to receive more ? */ DBG(printf("BODY: body_pos=%d, content_length=%ld\n", c->body_pos, c->content_length)); n = srv->recv(c, c->body + c->body_pos, c->content_length - c->body_pos); DBG(printf(" [recv n=%d - had %u of %lu]\n", n, c->body_pos, c->content_length)); c->line_pos = 0; if (n < 0) { /* error, scrap this worker */ http_close(c); return; } if (n == 0) { /* connection closed -> try to process and then remove */ process_request(c); http_close(c); return; } c->body_pos += n; } if (c->body_pos == c->content_length) { /* yay! we got the whole body */ process_request(c); if (c->attr & CONNECTION_CLOSE || c->line_pos) { /* we have to close the connection if there was a double-hit */ http_close(c); return; } /* keep-alive - reset the worker so it can process a new request */ if (c->url) { free(c->url); c->url = NULL; } if (c->body) { free(c->body); c->body = NULL; } if (c->content_type) { free(c->content_type); c->content_type = NULL; } if (c->headers) { free_buffer(c->headers); c->headers = NULL; } if (c->ws_key) { free(c->ws_key); c->ws_key = NULL; } if (c->ws_protocol) { free(c->ws_protocol); c->ws_protocol = NULL; } if (c->ws_version) { free(c->ws_version); c->ws_version = NULL; } c->line_pos = 0; c->body_pos = 0; c->method = 0; c->part = PART_REQUEST; c->attr = 0; c->content_length = 0; return; } } /* we enter here only if recv was used to leave the headers with no body */ if (c->part == PART_BODY && !c->body) { char *s = c->line_buf; if (c->line_pos > 0) { if ((s[0] != '\r' || s[1] != '\n') && (s[0] != '\n')) { send_http_response(c, " 411 length is required for non-empty body\r\nConnection: close\r\n\r\n"); http_close(c); return; } /* empty body, good */ process_request(c); if (c->attr & CONNECTION_CLOSE) { http_close(c); return; } else { /* keep-alive */ int sh = 1; if (s[0] == '\r') sh++; if (c->line_pos <= sh) c->line_pos = 0; else { /* shift the remaining buffer */ memmove(c->line_buf, c->line_buf + sh, c->line_pos - sh); c->line_pos -= sh; } /* keep-alive - reset the worker so it can process a new request */ if (c->url) { free(c->url); c->url = NULL; } if (c->body) { free(c->body); c->body = NULL; } if (c->content_type) { free(c->content_type); c->content_type = NULL; } if (c->headers) { free_buffer(c->headers); c->headers = NULL; } if (c->ws_key) { free(c->ws_key); c->ws_key = NULL; } if (c->ws_protocol) { free(c->ws_protocol); c->ws_protocol = NULL; } if (c->ws_version) { free(c->ws_version); c->ws_version = NULL; } c->body_pos = 0; c->method = 0; c->part = PART_REQUEST; c->attr = 0; c->content_length = 0; return; } } n = srv->recv(c, c->line_buf + c->line_pos, LINE_BUF_SIZE - c->line_pos - 1); if (n < 0) { /* error, scrap this worker */ http_close(c); return; } if (n == 0) { /* connection closed -> try to process and then remove */ process_request(c); http_close(c); return; } if ((s[0] != '\r' || s[1] != '\n') && (s[0] != '\n')) { send_http_response(c, " 411 length is required for non-empty body\r\nConnection: close\r\n\r\n"); http_close(c); return; } } } static void HTTP_connected(void *parg) { args_t *arg = (args_t*) parg; if (prepare_child(arg) != 0) { /* parent or error */ free(arg); return; } if (!(arg->line_buf = (char*) malloc(LINE_BUF_SIZE))) { RSEprintf("ERROR: unable to allocate line buffer\n"); free(arg); return; } arg->aux = (struct aux_pass*) arg->srv->aux; if ((arg->srv->flags & SRV_TLS) && shared_tls(0)) add_tls(arg, shared_tls(0), 1); while (arg->s != -1) http_input_iteration(arg); free_args(arg); } #ifdef NO_WEBSOCKETS server_t *create_HTTP_server(int port, int flags, http_handler_fn_t handler, void *ws_connected) #else server_t *create_HTTP_server(int port, int flags, http_handler_fn_t handler, ws_connected_fn_t ws_connected) #endif { server_t *srv = create_server(port, 0, 0, flags); #ifdef RSERV_DEBUG fprintf(stderr, "create_HTTP_server(port = %d, flags=0x%x)\n", port, flags); #endif if (srv) { struct aux_pass *aux = (struct aux_pass*) malloc(sizeof(struct aux_pass)); if (!aux) return 0; /* FIXME: release srv? */ aux->http_handler = handler; aux->ws_connected = ws_connected; srv->connected = HTTP_connected; /* srv->send_resp = */ srv->recv = server_recv; srv->send = server_send; srv->fin = server_fin; srv->aux = aux; add_server(srv); return srv; } return 0; } /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/proxy/chandler.h0000644000175100001440000000154714531234224015446 0ustar hornikusers#include "http.h" /* handlers return 0 if they choose to not handle the request. If a handler doesn't choose to handle the request it is not allowed to modify req/res. If path is present it is the full path to the resource. */ typedef int (*content_handler_fn_t)(http_request_t *req, http_result_t *res, const char *path); typedef struct content_handler content_handler_t; /* add a new handler function (at the end) and return the corresponding handler. May return NULL if the handler cannot be allocated. */ content_handler_t *add_content_handler(content_handler_fn_t fn); /* call registered handlers sequentially. Returns the handler that took the request (if any) or NULL otherwise. */ content_handler_t *call_content_handlers(http_request_t *req, http_result_t *res, const char *path); /* release all handlers */ void free_content_handlers(void); Rserve/src/proxy/websockets.c0000644000175100001440000007135014531234224016031 0ustar hornikusers#include "websockets.h" #include "md5.h" #include "sha1.h" #include "tls.h" #include "qap.h" #include "ulog.h" #ifdef RSERV_DEBUG #include "rsdebug.h" #endif #include #include #include #include #include struct args { server_t *srv; /* server that instantiated this connection */ SOCKET s; SOCKET ss; int msg_id; void *res1; /* used by TLS */ struct args *tls_arg; /* if set it is used to wire send/recv calls */ /* the following entries are not populated by Rserve but can be used by server implemetations */ char *buf, *sbuf; int ver, bp, bl, sp, sl, flags; size_t l1, l2; }; static ssize_t WS_recv_data(args_t *arg, void *buf, size_t read_len); static int WS_send_resp(args_t *arg, int rsp, size_t len, const void *buf); static ssize_t WS_send_data(args_t *arg, const void *buf, size_t len); /* we don't actually use R here, so no point looking for large vectors, so let's use size_t width - no config, so let's hope for __SIZE_WIDTH__. Note that this only defines the max frame size so at the worst we limit to 2Gb frames - likley more than enough either way */ #if defined __SIZE_WIDTH__ && (__SIZE_WIDTH__ >= 64) #define rlen_max ((size_t) 0x7fffffffffffffff) #else #define rlen_max ((size_t) 0x7fffffff) #endif static ssize_t WS_wire_send(args_t *arg, const void *buf, size_t len) { return (arg->tls_arg) ? arg->tls_arg->srv->send(arg->tls_arg, buf, len) : send(arg->s, buf, len, 0); } static ssize_t WS_wire_recv(args_t *arg, void *buf, size_t len) { return (arg->tls_arg) ? arg->tls_arg->srv->recv(arg->tls_arg, buf, len) : recv(arg->s, buf, len, 0); } static void WS_wire_close(args_t *arg) { if (arg->tls_arg) { close_tls(arg->tls_arg); closesocket(arg->tls_arg->s); if (arg->s != arg->tls_arg->s) closesocket(arg->s); arg->tls_arg->s = -1; /* the server is virtual and allocated only for this instance so it's ok to free it (all other server are re-used) */ free(arg->tls_arg->srv); free(arg->tls_arg); arg->tls_arg = 0; } else closesocket(arg->s); arg->s = -1; } static int do_mask(char *msg, size_t len, int koff, char *key) { size_t i = 0; while (i < len) { msg[i] ^= key[(i + koff) & 3]; i++; } return (i + koff) & 3; } /* due to very large cookies the lines may be very long, using 128kB for now */ #define LINE_BUF_SIZE (128*1024) struct header_info { int version; char *origin; char *host; char *key; char *key1; char *key2; char *path; char *query; char *protocol; }; static void free_header(struct header_info *h) { if (h->origin) free(h->origin); if (h->host) free(h->host); if (h->key) free(h->key); if (h->key1) free(h->key1); if (h->key2) free(h->key2); if (h->path) free(h->path); if (h->query) free(h->query); if (h->protocol) free(h->protocol); } static size_t count_spaces(const char *c) { size_t n = 0; while (*c) { if (*c == ' ') n++; c++; } return n; } static unsigned long count_digits(const char *c) { size_t n = 0; while (*c) { if (*c >= '0' && *c <= '9') n = n * 10L + (size_t)(*c - '0'); c++; } return n; } /* from base64.c */ void base64encode(const unsigned char *src, int len, char *dst); #define FRAME_BUFFER_SIZE 65536 static void WS_connected(void *parg) { args_t *arg = (args_t*) parg; int n, bp = 0, empty_lines = 0, request_line = 1; struct header_info h; char *buf; /* we have to perform a handshake before giving over to QAP but we have to fork() first as to not block the server on handshake */ if (prepare_child(arg) != 0) { /* parent or error */ free(arg); return; } /* if TLS is requested then we need to synthesize arg and srv for the TLS leg. FIXME: check that disassociating arg->s and tls_arg->s has no bad side-effects. */ if (arg->srv->flags & WS_TLS) { args_t *tls_arg = calloc(1, sizeof(args_t)); tls_arg->s = arg->s; tls_arg->srv = calloc(1, sizeof(server_t)); add_tls(tls_arg, shared_tls(0), 1); arg->tls_arg = tls_arg; } else arg->tls_arg = 0; buf = (char*) malloc(LINE_BUF_SIZE); if (!buf) { char lbuf[64]; strcpy(lbuf, "HTTP/1.1 500 Out of memory\r\n\r\n"); WS_wire_send(arg, lbuf, strlen(lbuf)); WS_wire_close(arg); arg->s = -1; return; } buf[LINE_BUF_SIZE - 1] = 0; memset(&h, 0, sizeof(h)); #ifdef RSERV_DEBUG printf("INFO:WS: connection accepted for WebSockets\n"); #endif while ((n = WS_wire_recv(arg, buf + bp, LINE_BUF_SIZE - bp - 1)) > 0) { char *c = buf, *nl = c; #ifdef RSERV_DEBUG buf[bp + n] = 0; printf("INFO:WS: recv(%d, %d) = %d\n%s\n---\n", bp, LINE_BUF_SIZE - bp - 1, n, buf); #endif bp += n; while (*c) { char *dc = 0, *kc; while (*c == ' ' || *c == '\t') c++; kc = c; while (*c && *c != '\n') { if (!dc) { if (*c >= 'A' && *c <= 'Z') *c |= 0x20; /* to lower */ if (*c == ':') { *c = 0; dc = c + 1; } } c++; } if (*c) { /* next full line */ nl = c + 1; if (c > buf && *(c - 1) == '\r') *(c - 1) = 0; *c = 0; c++; if (request_line) { char *r1 = kc; request_line = 0; while (*kc && *kc != ' ') kc++; if (*kc == ' ') { r1 = ++kc; while (*kc && *kc != ' ') kc++; if (*kc == ' ') { char *r2 = r1; *kc = 0; while (*r2 && *r2 != '?') r2++; if (*r2 == '?') { /* split off query part */ *(r2++) = 0; h.query = strdup(r2); } h.path = strdup(r1); #ifdef RSERV_DEBUG printf("INFO:WS: request for '%s' (query%c%s)\n", r1, h.query ? ':' : ' ', h.query ? h.query : "not specified"); #endif } } } else if (dc) { while (*dc == ' ' || *dc == '\t') dc++; #ifdef RSERV_DEBUG printf("INFO:WS: header '%s' = '%s'\n", kc, dc); #endif if (!strcmp(kc, "origin")) h.origin = strdup(dc); if (!strcmp(kc, "host")) h.host = strdup(dc); if (!strcmp(kc, "sec-websocket-version")) h.version = atoi(dc); if (!strcmp(kc, "sec-websocket-protocol")) h.protocol = strdup(dc); if (!strcmp(kc, "sec-websocket-key1")) h.key1 = strdup(dc); if (!strcmp(kc, "sec-websocket-key2")) h.key2 = strdup(dc); if (!strcmp(kc, "sec-websocket-key")) h.key = strdup(dc); } else if (!*kc && ++empty_lines) break; } } #ifdef RSERV_DEBUG printf("INFO: bp=%d, nl=buf+%d\n", bp, (int) (nl - buf)); #endif if (nl == buf) { if (bp >= LINE_BUF_SIZE - 1) { /* no line in the entire buffer */ strcpy(buf, "HTTP/1.1 400 Bad Request (line overflow)\r\n\r\n"); WS_wire_send(arg, buf, strlen(buf)); WS_wire_close(arg); arg->s = -1; free_header(&h); free(buf); return; } /* otherwise it's fine, we will load more */ } else { if (nl >= buf + LINE_BUF_SIZE - 1 || (!empty_lines && !*nl)) /* everything was consumed */ bp = 0; else { bp -= nl - buf; memmove(buf, nl, bp); } } if (empty_lines > 0) break; } if (empty_lines < 1) { strcpy(buf, "HTTP/1.1 400 Bad Request (connection failed before EOH)\r\n\r\n"); WS_wire_send(arg, buf, strlen(buf)); WS_wire_close(arg); arg->s = -1; free(buf); free_header(&h); return; } #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WebSockets version %d\n Origin: %s\n Host: %s\n Key: '%s'\n Key1: '%s'\n Key2: '%s'\n\n", h.version, h.origin ? h.origin : "", h.host ? h.host : "", h.key ? h.key : "", h.key1 ? h.key1 : "", h.key2 ? h.key2 : ""); #endif arg->ver = h.version; if (h.version < 4) { /* 00 .. 03 (in fact that was no version in the handshake before 04) */ unsigned int v[2]; unsigned char keyb[16]; unsigned char hash[16]; if (bp < 8) { n = WS_wire_recv(arg, buf + bp, 8 - bp); if (n < 8 - bp) { strcpy(buf, "HTTP/1.1 400 Bad Request (Key3 incomplete)\r\n\r\n"); WS_wire_send(arg, buf, strlen(buf)); WS_wire_close(arg); arg->s = -1; free(buf); free_header(&h); return; } } if (!h.origin || !h.key1 || !h.key2 || !h.host) { strcpy(buf, "HTTP/1.1 400 Bad Request (at least one key header is missing)\r\n\r\n"); WS_wire_send(arg, buf, strlen(buf)); WS_wire_close(arg); arg->s = -1; free(buf); free_header(&h); return; } v[0] = count_digits(h.key1) / count_spaces(h.key1); v[1] = count_digits(h.key2) / count_spaces(h.key2); keyb[3] = v[0] & 255; keyb[2] = (v[0] >> 8) & 255; keyb[1] = (v[0] >> 16) & 255; keyb[0] = (v[0] >> 24) & 255; keyb[7] = v[1] & 255; keyb[6] = (v[1] >> 8) & 255; keyb[5] = (v[1] >> 16) & 255; keyb[4] = (v[1] >> 24) & 255; memcpy(keyb + 8, buf, 8); md5hash(keyb, 16, hash); if (!h.path) h.path = strdup("/"); snprintf(buf, LINE_BUF_SIZE, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\nSec-WebSocket-Origin: %s\r\nSec-WebSocket-Location: ws://%s%s\r\n%s%s%s\r\n", h.origin, h.host, h.path, h.protocol ? "Sec-WebSocket-Protocol: " : "", h.protocol ? h.protocol : "", h.protocol ? "\r\n" : ""); bp = strlen(buf); memcpy(buf + bp, hash, 16); WS_wire_send(arg, buf, bp + 16); #ifdef RSERV_DEBUG printf("Responded with WebSockets.00 handshake\n"); #endif } else { unsigned char hash[21]; char b64[40]; strcpy(buf, h.key); strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); sha1hash(buf, strlen(buf), hash); hash[20] = 0; /* base64encode needs NUL sentinel */ base64encode(hash, sizeof(hash) - 1, b64); /* FIXME: if the client requests multiple protocols, we should be picking one but we don't */ snprintf(buf, LINE_BUF_SIZE, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n%s%s%s\r\n", b64, h.protocol ? "Sec-WebSocket-Protocol: " : "", h.protocol ? h.protocol : "", h.protocol ? "\r\n" : ""); WS_wire_send(arg, buf, strlen(buf)); #ifdef RSERV_DEBUG printf("Responded with WebSockets.04+ handshake (version = %02d)\n", h.version); #endif } free(buf); arg->bl = FRAME_BUFFER_SIZE; arg->bp = 0; arg->buf = (char*) malloc(FRAME_BUFFER_SIZE); arg->sl = FRAME_BUFFER_SIZE; arg->sbuf = (char*) malloc(FRAME_BUFFER_SIZE); buf = h.protocol ? strdup(h.protocol) : 0; free_header(&h); { ws_connected_fn_t connected = (ws_connected_fn_t) arg->srv->aux; connected(arg, buf); } } static server_t *ws_upgrade_srv, *wss_upgrade_srv; /* virtual server that represents the WS layer in HTTP/WS stack */ /* upgrade HTTP connection to WS connection, only 13+ protocol is supported this way */ /* NOTE: not included: origin, host */ /* IMPORTANT: it mangles the arg structure, so the caller should make sure it releases any obejcts from the structure that may leak */ /* FIXME: it only works on connections that have a direct socket since we don't have a stack to do TLS <-> WS <-> QAP */ void WS13_upgrade(args_t *arg, const char *key, const char *protocol, const char *version, ws_connected_fn_t connected) { char buf[512]; unsigned char hash[21]; char b64[44]; server_t *srv; srv = (arg->srv->flags & WS_TLS) ? wss_upgrade_srv : ws_upgrade_srv; if (!srv) { srv = (server_t*) calloc(1, sizeof(server_t)); if (!srv) { snprintf(buf, sizeof(buf), "HTTP/1.1 511 Allocation error\r\n\r\n"); arg->srv->send(arg, buf, strlen(buf)); return; } srv->parent = arg->srv; srv->connected = WS_connected; /* this is not actually called */ srv->send_resp = WS_send_resp; srv->recv = WS_recv_data; srv->send = WS_send_data; srv->fin = server_fin; srv->flags = arg->srv->flags & SRV_QAP_FLAGS; /* pass-through QAP flags */ /* FIXME: this is really ugly - we have to pass ws_connected as aux, but since we are caching the server instance this means you cannot have different functions for different servers that are upgraded! */ srv->aux = (void*) connected; if (arg->srv->flags & WS_TLS) wss_upgrade_srv = srv; else ws_upgrade_srv = srv; } /* FIXME: can we just use the parent server? */ if (arg->srv->flags & SRV_TLS) { /* if this server is connected through TLS we have to create wire TLS pass-through */ args_t *tls_arg = calloc(1, sizeof(args_t)); tls_arg->srv = calloc(1, sizeof(server_t)); copy_tls(arg, tls_arg); arg->tls_arg = tls_arg; } strncpy(buf, key, sizeof(buf) - 50); strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); sha1hash(buf, strlen(buf), hash); hash[20] = 0; /* base64encode needs NUL sentinel */ base64encode(hash, sizeof(hash) - 1, b64); /* FIXME: if the client requests multiple protocols, we should be picking one but we don't */ snprintf(buf, sizeof(buf), "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n%s%s%s\r\n", b64, protocol ? "Sec-WebSocket-Protocol: " : "", protocol ? protocol : "", protocol ? "\r\n" : ""); arg->srv->send(arg, buf, strlen(buf)); #ifdef RSERV_DEBUG printf("Responded with WebSockets.04+ handshake (version = %02d)\n", version ? atoi(version) : 0); #endif arg->bl = FRAME_BUFFER_SIZE; arg->bp = 0; arg->buf = (char*) malloc(FRAME_BUFFER_SIZE); arg->sl = FRAME_BUFFER_SIZE; arg->sbuf = (char*) malloc(FRAME_BUFFER_SIZE); arg->srv = srv; arg->ver = version ? atoi(version) : 13; /* let's assume 13 if not present */ { ws_connected_fn_t connected = (ws_connected_fn_t) srv->aux; connected(arg, protocol ? strdup(protocol) : 0); } } /* FIXME: big endian machines? */ #define itop(X) (X) #define ptoi(X) (X) static int WS_send_resp(args_t *arg, int rsp, size_t len, const void *buf) { unsigned char *sbuf = (unsigned char*) arg->sbuf; if (len > rlen_max - 128) return -1; /* too big */ if (arg->ver == 0) { /* FIXME: we can't really tunnel QAP1 without some encoding ... */ } else { qap_hdr_t ph; size_t pl = 0; size_t flen = len + sizeof(ph); ph.cmd = itop(rsp | ((rsp & CMD_OOB) ? 0 : CMD_RESP)); ph.len = itop(len); #ifdef __LP64__ ph.res = itop(len >> 32); #else ph.res = 0; #endif ph.msg_id = arg->msg_id; #ifdef RSERV_DEBUG if (io_log) { struct timeval tv; snprintf(io_log_fn, sizeof(io_log_fn), "/tmp/Rserve-io-%d.log", getpid()); FILE *f = fopen(io_log_fn, "a"); if (f) { double ts = 0; if (!gettimeofday(&tv, 0)) ts = ((double) tv.tv_sec) + ((double) tv.tv_usec) / 1000000.0; if (first_ts < 1.0) first_ts = ts; fprintf(f, "%.3f [+%4.3f] SRV --> CLI [WS_send_resp] (%x, %ld bytes)\n HEAD ", ts, ts - first_ts, rsp, (long) len); fprintDump(f, &ph, sizeof(ph)); fprintf(f, " BODY "); if (len) fprintDump(f, buf, len); else fprintf(f, "\n"); fclose(f); } } #endif sbuf[pl++] = ((arg->flags & F_OUT_BIN) ? 1 : 0) + ((arg->ver < 4) ? 0x04 : 0x81); /* text/binary, 4+ has inverted FIN bit */ if (flen < 126) /* short length */ sbuf[pl++] = flen; else if (flen < 65536) { /* 16-bit */ sbuf[pl++] = 126; sbuf[pl++] = flen >> 8; sbuf[pl++] = flen & 255; } else { /* 64-bit (on 32-bit plarforms the high 4 will be 0) */ sbuf[pl++] = 127; { int i = 8; size_t l = flen; while (i--) { sbuf[pl + i] = l & 255; l >>= 8; } } pl += 8; } memcpy(sbuf + pl, &ph, sizeof(ph)); pl += sizeof(ph); while (len + pl) { ssize_t n; /* arg->sl is only 64k so there are no size issues */ size_t send_here = (len + pl > arg->sl) ? arg->sl : (len + pl); if (send_here > pl) memcpy(sbuf + pl, buf, send_here - pl); n = WS_wire_send(arg, sbuf, send_here); #ifdef RSERV_DEBUG if (pl) { fprintf(stderr, "WS_send_resp: sending 4+ frame (ver %02d), n = %ld / %ld (of total %ld)\n", arg->ver, (long) n, (unsigned long)send_here, flen); #ifdef WS_DEBUG { int i, m = send_here; if (m > 100) m = 100; for (i = 0; i < m; i++) fprintf(stderr, " %02x", (int) sbuf[i]); fprintf(stderr,"\n"); } #endif } else fprintf(stderr, "WS_send_resp: continuation (%ld bytes)\n", (long) n); #endif if (n != send_here) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_send_resp: write failed (%ld expected, got %ld)\n", (long) send_here, (long) n); #endif return -1; } buf = ((char*)buf) + send_here - pl; len -= send_here - pl; pl = 0; } } return 0; } void WS_set_binary(args_t *arg, int flag) { if (flag) arg->flags |= F_OUT_BIN; else arg->flags &= ~F_OUT_BIN; } static ssize_t WS_send_data_(args_t *arg, const void *buf, size_t len, int opcode); static ssize_t WS_send_data(args_t *arg, const void *buf, size_t len) { int opcode = ((arg->flags & F_OUT_BIN) ? 1 : 0) + ((arg->ver < 4) ? 4 : 1); /* 2/1 for ver4+, 5/4 for ver0 */ return WS_send_data_(arg, buf, len, opcode); } /* we use send_data only to send the ID string so we don't bother supporting frames bigger than the buffer */ static ssize_t WS_send_data_(args_t *arg, const void *buf, size_t len, int opcode) { unsigned char *sbuf = (unsigned char*) arg->sbuf; if (arg->ver == 0) { if (len < arg->sl - 2) { ssize_t n; sbuf[0] = 0; memcpy(sbuf + 1, buf, len); sbuf[len + 1] = 0xff; n = WS_wire_send(arg, sbuf, len + 2); #ifdef RSERV_DEBUG fprintf(stderr, "WS_send_data: sending 00 frame, n = %ld / %lu\n", (long) n, (unsigned long) len + 2); #endif if (n == len + 2) return len; if (n < len + 2 && n >= len) return len - 1; return n; } else { #ifdef RSERV_DEBUG fprintf(stderr, "ERROR in WS_send_data: data too large\n"); #endif return -1; } } else { size_t total = len, pl = 0; sbuf[pl++] = (opcode & 0x7f) | ((arg->ver < 4) ? 0 : 0x80); /* 4+ has inverted FIN bit */ if (len < 126) /* short length */ sbuf[pl++] = len; else if (len < 65536) { /* 16-bit */ sbuf[pl++] = 126; sbuf[pl++] = len >> 8; sbuf[pl++] = len & 255; } else { /* 64-bit */ sbuf[pl++] = 127; { int i = 8; size_t l = len; while (i--) { sbuf[pl + i] = l & 255; l >>= 8; } } pl += 8; } while (len + pl) { ssize_t n; size_t send_here = (len + pl > arg->sl) ? arg->sl : (len + pl); if (send_here > pl) memcpy(sbuf + pl, buf, send_here - pl); n = WS_wire_send(arg, sbuf, send_here); #ifdef RSERV_DEBUG if (pl) { fprintf(stderr, "WS_send_data: sending 4+ frame (ver %02d), n = %ld / %lu (of total %ld)\n", arg->ver, (long) n, (unsigned long) send_here, (long) len); #ifdef WS_DEBUG { int i, m = send_here; if (m > 100) m = 100; for (i = 0; i < m; i++) fprintf(stderr, " %02x", (int) sbuf[i]); fprintf(stderr,"\n"); } #endif } else fprintf(stderr, "WS_send_data: continuation (%ld bytes)\n", (long) n); #endif if (n != send_here) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_send_data: write failed (%ld expected, got %ld)\n", (long) send_here, (long) n); #endif return -1; } buf = ((char*)buf) + send_here - pl; len -= send_here - pl; pl = 0; } return total; } return 0; } #define FRT_CLOSE 8 #define FRT_PING 9 #define FRT_PONG 10 static ssize_t WS_recv_data_(args_t *arg, void *buf, size_t read_len); /* one extra indirection - we are handing WebSockets control frames internally so the application doesn't have to deal with them as they are WS-specific */ static ssize_t WS_recv_data(args_t *arg, void *buf, size_t read_len) { ssize_t n = 0; while (1) { n = WS_recv_data_(arg, buf, read_len); if (n < 1) break; /* catch control frames - those shouldn't go to the application */ if (GET_F_FT(arg->flags) > 7) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: control frame 0x%02x (%d bytes), catching\n", GET_F_FT(arg->flags), (int) n); #endif switch (GET_F_FT(arg->flags)) { case FRT_PING: if (WS_send_data_(arg, buf, n, FRT_PONG) < 0) return -1; break; case FRT_PONG: /* simply ignore PONGs */ break; case FRT_CLOSE: if (n > 1) ulog("INFO: WS CLOSE frame received, code = %u", (((unsigned int) ((unsigned char*)buf)[0]) << 8) | ((unsigned int) ((unsigned char*)buf)[1])); else ulog("INFO: WS CLOSE frame received"); /* respond with CLOSE */ WS_send_data_(arg, buf, 0, FRT_CLOSE); return 0; break; } } else break; } return n; } static ssize_t WS_recv_data_(args_t *arg, void *buf, size_t read_len) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data for %ld (bp = %d)\n", (long) read_len, arg->bp); #endif if (arg->ver == 0) { /* make sure we have at least one (in frame) or two (oof) bytes in the buffer */ int min_size = (arg->flags & F_INFRAME) ? 1 : 2; while (arg->bp < min_size) { ssize_t n = WS_wire_recv(arg, arg->buf + arg->bp, arg->bl - arg->bp); #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: needs ver 00 frame, reading %ld bytes in addition to %d\n", (long) n, arg->bp); #ifdef WS_DEBUG { size_t i; fprintf(stderr, "Buffer: "); for (i = 0; i < n; i++) fprintf(stderr, " %02x", (int) (unsigned char) arg->buf[i]); fprintf(stderr,"\n"); } #endif #endif if (n < 1) return n; arg->bp += n; } if (!(arg->flags & F_INFRAME)) { if (arg->buf[0] != 0x00) { #ifdef RSERV_DEBUG fprintf(stderr, "ERROR: WS_recv_data: ver0 yet not a text frame (0x%02x)\n", (int) (unsigned char) arg->buf[0]); #endif return -1; } /* now we're in-frame - this is silly but makes the processing easier */ arg->flags |= F_INFRAME; memmove(arg->buf, arg->buf + 1, arg->bp - 1); } /* first check if we can satify any need by using contents of the buffer */ /* NOTE: this is actually always true since we guarantee both F_INFRAME and bp > 0 above */ if ((arg->flags & F_INFRAME) && arg->bp > 0) { unsigned char *b = (unsigned char*) arg->buf; ssize_t i = 0; #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: have %d bytes of a frame, requested %d, returning what we have\n", arg->bp, (int) read_len); #endif while (i < arg->bp && i < read_len && b[i] != 0xff) i++; if (i >= arg->bp) { /* end of buffer, still in frame */ memcpy(buf, arg->buf, i); arg->bp = 0; return i; } if (b[i] == 0xff) { /* reached end of frame */ if (i) memcpy(buf, arg->buf, i); arg->bp -= i + 1; if (arg->bp > 0) memmove(arg->buf, arg->buf + i + 1, arg->bp); arg->flags ^= F_INFRAME; return i; } /* read_len was less than the buffer and did not even reach the end of frame */ memcpy(buf, arg->buf, i); arg->bp -= i; memmove(arg->buf, arg->buf + i, arg->bp); return i; } } /* ver 00 always returns before this */ if ((arg->flags & F_INFRAME) && arg->bp > 0) { /* do we have content of a frame what has not been picked up yet? */ #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: have %d bytes of a frame, requested %d, returning what we have\n", arg->bp, (int) read_len); #endif if (read_len > arg->bp) read_len = arg->bp; /* at most all buffer */ if (read_len > arg->l1) read_len = arg->l1; /* and not beyond the current frame */ memcpy(buf, arg->buf, read_len); if (arg->bp > read_len) memmove(arg->buf, arg->buf + read_len, arg->bp - read_len); arg->bp -= read_len; arg->l1 -= read_len; /* if the whole frame was consumed, flag out-of-frame for the next run */ if (arg->l1 == 0) arg->flags ^= F_INFRAME; return read_len; } /* make sure we have at least one byte in the buffer */ if (arg->bp == 0) { /* read as much as we can with one request */ ssize_t n = WS_wire_recv(arg, arg->buf, arg->bl); if (n < 1) return n; arg->bp = n; #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WS_recv_data: read %ld bytes:\n", (long) n); #ifdef WS_DEBUG { size_t i; for (i = 0; i < n; i++) fprintf(stderr, " %02x", (int) (unsigned char) arg->buf[i]); fprintf(stderr,"\n"); } #endif #endif } if (arg->flags & F_INFRAME) { /* in frame with new content */ if (read_len > arg->l1) /* we can do at most the end of the frame */ read_len = arg->l1; if (read_len > arg->bp) /* and at most what we got in the buffer */ read_len = arg->bp; memcpy(buf, arg->buf, read_len); if (arg->flags & F_MASK) SET_F_MASK(arg->flags, do_mask(buf, read_len, GET_MASK_ID(arg->flags), (char*)&arg->l2)); arg->bp -= read_len; arg->l1 -= read_len; if (arg->bp) /* if anything is left in the buffer, move it up */ memmove(arg->buf, arg->buf + read_len, arg->bp); if (arg->l1 == 0) /* was that the entire frame? */ arg->flags ^= F_INFRAME; return read_len; } else { /* not in frame - interpret a new frame */ unsigned char *fr = (unsigned char*) arg->buf; #ifdef RSERV_DEBUG /* FIXME: we don't use more -- why? */ size_t more = (arg->ver < 4) ? ((fr[0] & 0x80) == 0x80) : ((fr[0] & 0x80) == 0); #endif int mask = 0, ct = fr[0] & 127; size_t need = 0, at_least, payload; size_t len = 0; /* set the F_IN_BIN flag according to the frame type */ if ((arg->ver < 4 && ct == 5) || (arg->ver >= 4 && ct == 2)) arg->flags |= F_IN_BIN; else arg->flags &= ~ F_IN_BIN; SET_F_FT(arg->flags, ct); if (arg->bp == 1) { ssize_t n = WS_wire_recv(arg, arg->buf + 1, arg->bl - 1); if (n < 1) return n; arg->bp = n + 1; } if (arg->ver > 6 && fr[1] & 0x80) mask = 1; len = fr[1] & 127; need = 2 + (mask ? 4 : 0) + ((len < 126) ? 0 : ((len == 126) ? 2 : 8)); while (arg->bp < need) { ssize_t n = WS_wire_recv(arg, arg->buf + arg->bp, arg->bl - arg->bp); if (n < 1) return n; arg->bp += n; } if (len == 126) len = (fr[2] << 8) | fr[3]; else if (len == 127) { if (fr[2] || fr[3]) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: requested frame length is way too big - we support only up to 256TB\n"); #endif return -1; } #define SH(X,Y) (((uint64_t)X) << Y) uint64_t raw_len = SH(fr[4], 48) | SH(fr[5], 40) | SH(fr[5], 32) | SH(fr[6], 24) | SH(fr[7], 16) | SH(fr[8], 8) | (uint64_t)fr[9]; if (raw_len > rlen_max - 64L) { #ifdef RSERV_DEBUG fprintf(stderr, "WS_recv_data: requested frame length is larger than rlen_max for this platform\n"); #endif return -1; } len = (size_t) raw_len; } #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WS_recv_data frame type=%02x, len=%lu, more=%d, mask=%d (need=%d)\n", ct, (unsigned long) len, (int) more, (int) mask, (int) need); #endif at_least = need + len; if (at_least > arg->bl) at_least = arg->bl; /* this is always positive, because need is at most 14 and at_least is need + len only capped by the buffer size which is >14 */ payload = at_least - need; while (arg->bp < at_least) { ssize_t n = WS_wire_recv(arg, arg->buf + arg->bp, at_least - arg->bp); #ifdef RSERV_DEBUG fprintf(stderr, "INFO: read extra %ld bytes in addition to %d (need %ld)\n", (long) n, arg->bp, (long) need); #endif if (n < 1) return n; arg->bp += n; } /* FIXME: more recent protocols require MASK at all times */ if (mask) { #if defined RSERV_DEBUG && defined WS_DEBUG { int i; for (i = 0; i < payload; i++) fprintf(stderr, " %02x", (int) (unsigned char) arg->buf[need + i]); fprintf(stderr,"\n"); } #endif SET_F_MASK(arg->flags, do_mask(arg->buf + need, payload, 0, arg->buf + need - 4)); memcpy(&arg->l2, arg->buf + need - 4, 4); #if defined RSERV_DEBUG && defined WS_DEBUG { int i; for (i = 0; i < payload; i++) fprintf(stderr, " %02x", (int) (unsigned char) arg->buf[need + i]); fprintf(stderr,"\n"); } #endif } else arg->flags &= ~ F_MASK; /* if the frame fits in the buffer (payload == len since it has not been truncated) and read requested at least as much, we can deliver the whole frame */ if (payload == len && read_len >= payload) { #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WS_recv_data frame has %ld bytes, requested %ld, returning entire frame\n", (long) len, (long) read_len); #endif memcpy(buf, arg->buf + need, len); if (arg->bp > at_least) { /* this is unlikely but possible if we got multiple frames in the first read */ memmove(arg->buf, arg->buf + at_least, arg->bp - at_least); arg->bp -= at_least; } else arg->bp = 0; return len; } /* left-over - we will end up with an incompete frame - either we got an incomplete frame or less than the span of the frame was requested */ #ifdef RSERV_DEBUG fprintf(stderr, "INFO: WS_recv_data frame has %lu bytes (of %lu frame), requested %d, returning partial frame\n", (unsigned long) payload, (unsigned long) len, (int) read_len); #endif /* we can only return all we got */ if (read_len > payload) read_len = payload; memcpy(buf, arg->buf + need, read_len); if (arg->bp > need + read_len) /* if there is any data beyond what we will deliver, we need to move it */ memmove(arg->buf, arg->buf + need + read_len, arg->bp - need - read_len); len -= read_len; /* left in the frame is total minus delivered - we only get here if the frame did not fit, so len > 0 */ arg->l1 = len; arg->flags |= F_INFRAME; arg->bp -= need + read_len; return read_len; } /* in frame */ } server_t *create_WS_server(int port, int flags, ws_connected_fn_t connected) { server_t *srv = create_server(port, 0, 0, flags); if (srv) { srv->connected = WS_connected; srv->send_resp = WS_send_resp; srv->recv = WS_recv_data; srv->send = WS_send_data; srv->fin = server_fin; srv->aux = (void*) connected; add_server(srv); return srv; } return 0; } /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/proxy/http.h0000644000175100001440000000173314531234224014642 0ustar hornikusers#ifndef HTTP_H__ #define HTTP_H__ #ifdef NO_WEBSOCKETS #include "server.h" #else #include "websockets.h" #endif typedef struct { char *url; char *body; size_t body_len; char *query; char *headers; double date; } http_request_t; #define PAYLOAD_VERBATIM 0 #define PAYLOAD_FILE 1 #define PAYLOAD_TEMPFILE 2 typedef struct { char *err; char *payload; size_t payload_len; int payload_type; char *content_type; char *headers; double date; int code; } http_result_t; typedef void (*http_handler_fn_t)(http_request_t *req, http_result_t *res); #define HTTP_WS_UPGRADE 0x10 #define HTTP_RAW_BODY 0x20 /* if set, no attempts are made to decode the request body of known types */ #ifdef NO_WEBSOCKETS server_t *create_HTTP_server(int port, int flags, http_handler_fn_t handler, void *dummy); #else server_t *create_HTTP_server(int port, int flags, http_handler_fn_t handler, ws_connected_fn_t ws_connected); #endif #endif Rserve/src/proxy/Makefile0000644000175100001440000000156714531234227015162 0ustar hornikusers## very basic makefile for testing ## for example, on OS X you might use ## make clean && make CC=clang 'CFLAGS=-Wall -Wno-deprecated-declarations -g' 'CPPFLAGS=-DFORKED -DRSERV_DEBUG' -j8 all: forward forward: forward.o http.o http_tools.o server.o tls.o websockets.o md5.o sha1.o base64.o date.o ulog.o chandler.o rscript.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) forward.o: forward.c http.h websockets.h server.h http_tools.h qap.h rserr.h ulog.h bsdcmpt.h chandler.h websockets.o: websockets.c websockets.h server.h md5.h sha1.h tls.h qap.h base64.c md5.c: ../md5.c ln -sfn $^ $@ md5.h: ../md5.h ln -sfn $^ $@ ulog.c: ../ulog.c ln -sfn $^ $@ ulog.h: ../ulog.h ln -sfn $^ $@ sha1.c: ../sha1.c ln -sfn $^ $@ sha1.h: ../sha1.h ln -sfn $^ $@ base64.c: ../base64.c ln -sfn $^ $@ distclean: clean rm -f md5.[ch] ulog.[ch] sha1.[ch] base64.c *~ clean: rm -f *.o forward Rserve/src/proxy/rsdebug.h0000644000175100001440000000204114531234224015307 0ustar hornikusers/* debugging tools such as dump */ #ifndef RSDEBUG_H__ #define RSDEBUG_H__ #ifndef NO_CONFIG_H #include "config.h" #endif #ifdef unix #if HAVE_SYS_TIME_H # include #endif #include #else #define gettimeofday(X,Y) 1 #endif #include #if defined RSERV_DEBUG || defined RSERV_IOLOG static int io_log = 0; /* log all I/O operations */ static int dumpLimit = 128; static double first_ts = 0.0; static char io_log_fn[128]; static void fprintDump(FILE *f, const void *b, int len) { int i = 0; if (len < 1) { fprintf(f, "DUMP FAILED (len=%d)\n", len); }; fprintf(f, "DUMP [%d]:",len); while(i < len) { fprintf(f, " %02x",((const unsigned char*)b)[i++]); if (dumpLimit && i > dumpLimit) { fprintf(f, " ..."); break; }; } i = 0; fprintf(f, " |"); while (i < len) { unsigned char c = ((const unsigned char*)b)[i++]; if (c < 32 || c > 127) c = '.'; fputc(c, f); if (dumpLimit && i > dumpLimit) break; } fprintf(f, "\n"); } #define printDump(B,L) fprintDump(stdout, B, L) #endif #endif Rserve/src/proxy/http_tools.c0000644000175100001440000000127114531234224016052 0ustar hornikusers#include "http_tools.h" #include /* returns a pointer to the beginning of a value for a given header field or NULL if not present. */ const char *get_header(http_request_t *req, const char *name) { const char *c = req->headers, *e; int name_len = strlen(name); if (!c) return 0; while (*c && (e = strchr(c, '\n'))) { const char *v = strchr(c, ':'); if (v && (v < e) && (v - c == name_len)) { int i; for (i = 0; i < name_len; i++) if ((name[i] & 0xdf) != (c[i] & 0xdf)) break; if (i == name_len) { v++; while (*v == '\t' || *v == ' ') v++; return v; } } while (*e == '\n' || *e == '\t') e++; c = e; } return 0; } Rserve/src/proxy/qap.h0000644000175100001440000000467614531234224014455 0ustar hornikusers#ifndef QAP_H__ #define QAP_H__ typedef struct phdr { /* always 16 bytes */ int cmd; /* command */ int len; /* length of the packet minus header (ergo -16) */ int msg_id; /* message id (since 1.8) [WAS:data offset behind header (ergo usually 0)] */ int res; /* high 32-bit of the packet length (since 0103 and supported on 64-bit platforms only) aka "lenhi", but the name was not changed to maintain compatibility */ } qap_hdr_t; /* macros for handling the first int - split/combine (24-bit version only!) */ #define PAR_TYPE(X) ((X) & 255) #define PAR_LEN(X) (((unsigned int)(X)) >> 8) #define PAR_LENGTH PAR_LEN #define SET_PAR(TY,LEN) ((((unsigned int) (LEN) & 0xffffff) << 8) | ((TY) & 255)) #define CMD_STAT(X) (((X) >> 24)&127) /* returns the stat code of the response */ #define SET_STAT(X,s) ((X) | (((s) & 127) << 24)) /* sets the stat code */ #define CMD_RESP 0x10000 /* all responses have this flag set */ #define RESP_OK (CMD_RESP|0x0001) /* command succeeded; returned parameters depend on the command issued */ #define RESP_ERR (CMD_RESP|0x0002) /* command failed, check stats code attached string may describe the error */ #define CMD_OOB 0x20000 /* out-of-band data - i.e. unsolicited messages */ #define OOB_SEND (CMD_OOB | 0x1000) /* OOB send - unsolicited SEXP sent from the R instance to the client. 12 LSB are reserved for application-specific code */ #define OOB_MSG (CMD_OOB | 0x2000) /* OOB message - unsolicited message sent from the R instance to the client requiring a response. 12 LSB are reserved for application-specific code */ #define IS_OOB_SEND(X) (((X) & 0x0ffff000) == OOB_SEND) #define IS_OOB_MSG(X) (((X) & 0x0ffff000) == OOB_MSG) #define OOB_USR_CODE(X) ((X) & 0xfff) /* flag for create_server: Use QAP object-cap mode */ #define SRV_QAP_OC 0x40 /* mask of all flags that are relevant to QAP (so they can be passed through) */ #define SRV_QAP_FLAGS (SRV_QAP_OC) #define ERR_auth_failed 0x41 #define ERR_conn_broken 0x42 #define CMD_OCcall 0x00f #define CMD_OCinit 0x434f7352 #define DT_SEXP 10 #define DT_LARGE 64 #define XT_STR 3 #define XT_VECTOR 16 #define XT_LIST_TAG 21 #define XT_LANG_NOTAG 22 #define XT_LANG_TAG 23 #define XT_ARRAY_INT 32 #define XT_ARRAY_STR 34 #define XT_RAW 37 #define XT_LARGE 64 #define XT_HAS_ATTR 128 #endif Rserve/src/proxy/rserr.h0000644000175100001440000000050414531234224015013 0ustar hornikusers/* error I/O that uses either stderr or REprintf depending on the build */ #ifndef RSERR_H__ #define RSERR_H__ #include #include #include static void RSEprintf(const char *format, ...) { va_list(ap); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); } #endif Rserve/src/proxy/server.h0000644000175100001440000000667014531234224015176 0ustar hornikusers#ifndef RS_SERVER_H__ #define RS_SERVER_H__ /* this is a voluntary standart flag to request TLS support */ #define SRV_TLS 0x0800 /* these flags are global and respected by the default socket server */ #define SRV_IPV6 0x1000 /* use IPv6 */ #define SRV_LOCAL 0x4000 /* bind to local loopback interface only */ #define SRV_KEEPALIVE 0x8000 /* enable keep-alive - note that this is really a client option sice inheritance is not guaranteed */ #include #include #ifndef WIN32 #include #include #include #include #include #include #include #define sockerrno errno #define SOCKET int #define INVALID_SOCKET (-1) #define closesocket(A) close(A) #else #define windows #include #include #include #include #define inet_aton(A,B) (0, B.s_addr=inet_addr(A)) #define sockerrno WSAGetLastError() #endif #define SA struct sockaddr #define SAIN struct sockaddr_in typedef struct args args_t; typedef void (*work_fn_t)(void *par); typedef int (*send_fn_t)(args_t *arg, int rsp, size_t len, const void *buf); typedef ssize_t (*buf_fn_t) (args_t *arg, void *buf, size_t len); typedef ssize_t (*cbuf_fn_t)(args_t *arg, const void *buf, size_t len); typedef int (*fork_fn_t)(args_t *arg); /* definition of a server */ typedef struct server { int ss; /* server socket */ int unix_socket; /* 0 = TCP/IP, 1 = unix socket */ int flags; /* optional server-specific flags */ work_fn_t connected; /* function called for each new connection */ work_fn_t fin; /* optional finalization function */ send_fn_t send_resp; /* send response */ cbuf_fn_t send; /* direct send */ buf_fn_t recv; /* direct receive */ fork_fn_t fork; /* fork */ struct server *parent;/* parent server - used only by multi-layer servers */ void *aux; } server_t; /* this flag can be passed to create_server for an IP socket to modify the behavior */ #define LSM_IP_LOCAL 1 /* bind to loopback address only */ #define LSM_IPV6 2 /* use IPv6 (if available) */ server_t *create_server(int port, const char *localSocketName, int localSocketMode, int flags); void accepted_server(server_t *srv, int cs); /* performs additional tasks on client socket (eg SO_KEEPALIVE) */ int add_server(server_t *srv); int rm_server(server_t *srv); /* server stacks */ typedef struct server_stack server_stack_t; server_stack_t* create_server_stack(void); void push_server(server_stack_t *s, server_t *srv); int server_stack_size(server_stack_t *s); void release_server_stack(server_stack_t *s); /* some generic implementations */ void server_fin(void *x); ssize_t server_recv(args_t *arg, void *buf, size_t len); ssize_t server_send(args_t *arg, const void *buf, size_t len); void stop_server_loop(void); void serverLoop(void); /* helper function that prepares the process just like Rserve internal impleemntation - forking when desired, establishing pipes, setting see, uid/gid, cwd etc. returns 0 for the child */ int prepare_child(args_t *arg); /* this one is called by the former to close all server sockets in the child */ void close_all_srv_sockets(void); #endif /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/qap_encode.h0000644000175100001440000000041214531234224014571 0ustar hornikusers#ifndef QAP_ENCODE_H__ #define QAP_ENCODE_H__ #ifndef USE_RINTERNALS #define USE_RINTERNALS 1 #include #endif #include "Rsrv.h" rlen_t QAP_getStorageSize(SEXP x); unsigned int* QAP_storeSEXP(unsigned int* buf, SEXP x, rlen_t storage_size); #endif Rserve/src/session.c0000644000175100001440000000404614531234224014160 0ustar hornikusers/* * implements a vector of session scructures accessible by a session key. * * Author : Simon Urbanek * Created: 2005/08/30 * License: GPL2 * * $Id$ */ #include "config.h" #include "session.h" #ifdef HAVE_MEMORY_H #include #endif #include #include static struct sSession *session=0; static int sessions=0; static int sessions_allocated=0; /* find a session */ struct sSession *find_session(char key[16]) { int i=0; while (i128 && sessions < sessions_allocated/2) { sessions_allocated = sessions_allocated/2 + 64; session = (struct sSession*) realloc(session, sessions_allocated * sizeof(struct sSession)); } return; } i++; } } int total_sessions(void) { return sessions; } struct sSession *first_session(void) { return session; } struct sSession *next_session(struct sSession* current) { if (current=session+sessions-1) return 0; return current+1; } /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/ulog.h0000644000175100001440000000044214531234224013444 0ustar hornikusers#ifndef ULOG_H__ #define ULOG_H__ void ulog_set_path(const char *path); void ulog_set_app_name(const char *name); void ulog_begin(void); void ulog_add(const char *format, ...); void ulog_end(void); void ulog(const char *format, ...); int ulog_enabled(void); void ulog_reset(void); #endif Rserve/src/http.h0000644000175100001440000000037514531234224013462 0ustar hornikusers#ifndef HTTP_H__ #define HTTP_H__ #include "RSserver.h" #define HTTP_WS_UPGRADE 0x10 #define HTTP_RAW_BODY 0x20 /* if set, no attempts are made to decode the request body of known types */ server_t *create_HTTP_server(int port, int flags); #endif Rserve/src/oc.h0000644000175100001440000000024614531234224013101 0ustar hornikusers#ifndef OC_H__ #define OC_H__ #include SEXP oc_resolve(const char *ref); char *oc_register(SEXP what, char *dst, int len, const char *name); #endif Rserve/src/Makevars.win0000644000175100001440000000207014531234224014614 0ustar hornikusersPKG_CPPFLAGS=-DRSERVE_PKG -DWin32 -I. -Iinclude -Iinclude/Win32 PKG_LIBS=-lssl -lcrypto -lws2_32 -lcrypt32 -lz all: $(SHLIB) server # $(MAKE) client SERVER_SRC = standalone.c md5.c session.c qap_decode.c qap_encode.c sha1.c base64.c websockets.c RSserver.c tls.c http.c oc.c ulog.c ioc.c utils.c date.c SERVER_H = Rsrv.h qap_encode.h qap_decode.h RSserver.h http.h oc.h sha1.h md5.h ulog.h bsdcmpt.h server: $(SERVER_SRC) $(SERVER_H) $(CC) -DSTANDALONE_RSERVE -DDAEMON -I. -Iinclude $(ALL_CPPFLAGS) $(ALL_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(PKG_CPPFLAGS) $(PKG_CFLAGS) -o Rserve.exe $(SERVER_SRC) $(ALL_LIBS) $(PKG_LIBS) $(CC) -DSTANDALONE_RSERVE -DRSERV_DEBUG -DNODAEMON -I. -Iinclude $(ALL_CPPFLAGS) $(ALL_CFLAGS) $(PKG_CPPFLAGS) $(PKG_CFLAGS) -o Rserve_d.exe $(SERVER_SRC) $(ALL_LIBS) $(PKG_LIBS) client: config.h cp config.h client/cxx/ make -C client/cxx -@mkdir ../inst 2>/dev/null -rm -rf ../inst/client -cp -R client ../inst/ cp Rsrv.h config.h include/sisocks.h ../inst/client/cxx/ clean: rm -f *~ *.o *.lo *.so *.exe \#* $(XFILES) .PHONY: client clean server Rserve/src/session.h0000644000175100001440000000101414531234224014155 0ustar hornikusers#ifndef SESSION_H__ #define SESSION_H__ struct sSession { unsigned char key[16]; int s; }; struct sSession *new_session(char key[16]); struct sSession *find_session(char key[16]); void free_session(char key[16]); /* functions for walking thorugh sessions. warning: next_session becomes invalid if new_session or free_session is called between first_session and and any subsequent next_session */ struct sSession *first_session(void); struct sSession *next_session(struct sSession* current); #endif Rserve/src/standalone.c0000644000175100001440000002767014531234224014635 0ustar hornikusers#include #ifdef STANDALONE_RSERVE /* this is a bad hack for compatibility. Eventually we should have a defined layer */ #include "Rserv.c" extern int Rf_initEmbeddedR(int, char**); #include /* R API from oc.c */ SEXP Rserve_oc_register(SEXP what, SEXP sName); SEXP Rserve_oc_resolve(SEXP what); /* from utils.c */ SEXP Rserve_eval(SEXP what, SEXP rho, SEXP retLast, SEXP retExp, SEXP ctxObj, SEXP sHandler); SEXP Rserve_set_context(SEXP what); SEXP Rserve_set_last_condition(SEXP sCond); /* from http.c */ SEXP Rserve_set_http_request_fn(SEXP sFn); SEXP Rserve_http_add_static(SEXP sPrefix, SEXP sPath, SEXP sIndex, SEXP sFlags); static int ex(int res) { RSsrv_done(); return res; } /* main function - start Rserve */ int main(int argc, char **argv) { int stat, i, http_flags; char **top_argv; int top_argc; int rs_silent = 0; main_argv = argv; main_argc = argc; rserve_rev[0] = 0; { /* cut out the SVN revision from the Id string */ const char *c = strstr(rserve_ver_id, ".c "); if (c) { const char *d = c + 3; c = d; while (*c && *c != ' ') c++; strncpy(rserve_rev, d, c - d); } } #ifdef RSERV_DEBUG printf("Rserve %d.%d-%d (%s) (C)Copyright 2002-2013 Simon Urbanek\n%s\n\n",RSRV_VER>>16,(RSRV_VER>>8)&255,RSRV_VER&255, rserve_rev, rserve_ver_id); #endif if (!isByteSexOk()) { fprintf(stderr, "FATAL ERROR: This program was not correctly compiled - the endianess is wrong!\nUse -DSWAPEND when compiling on PPC or similar platforms.\n"); return -100; } ulog_set_app_name("Rserve"); loadConfig(CONFIG_FILE); /** copy argv while removing Rserve specific parameters */ top_argc = 1; top_argv = (char**) malloc(sizeof(char*) * (argc + 1)); top_argv[0] = argv[0]; i = 0; while (++i < argc) { int isRSP = 0; if (argv[i] && *argv[i] == '-' && argv[i][1] == '-') { if (!strcmp(argv[i] + 2, "RS-port")) { isRSP = 1; if (++i == argc) fprintf(stderr,"Missing port specification for --RS-port.\n"); else { port = satoi(argv[i]); if (port < 1) { fprintf(stderr,"Invalid port number in --RS-port, using default port.\n"); port = default_Rsrv_port; } } } if (!strcmp(argv[i] + 2, "RS-dumplimit")) { isRSP = 1; if (++i == argc) fprintf(stderr,"Missing limit specification for --RS-dumplimit.\n"); else { #ifdef RSERV_DEBUG dumpLimit = satoi(argv[i]); #endif } } if (!strcmp(argv[i] + 2, "RS-socket")) { isRSP = 1; if (++i == argc) fprintf(stderr,"Missing socket specification for --RS-socket.\n"); else localSocketName = argv[i]; } if (!strcmp(argv[i] + 2, "RS-encoding")) { isRSP = 1; if (++i == argc) fprintf(stderr,"Missing socket specification for --RS-encoding.\n"); else set_string_encoding(argv[i], 1); } if (!strcmp(argv[i] + 2, "RS-workdir")) { isRSP = 1; if (++i == argc) fprintf(stderr,"Missing directory specification for --RS-workdir.\n"); else workdir=argv[i]; } if (!strcmp(argv[i] + 2, "RS-conf")) { isRSP = 1; if (++i == argc) fprintf(stderr,"Missing config file specification for --RS-conf.\n"); else loadConfig(argv[i]); } if (!strcmp(argv[i] + 2, "RS-source")) { isRSP = 1; if (++i == argc) fprintf(stderr,"Missing R file specification for --RS-source.\n"); else setConfig("source", argv[i]); } if (!strcmp(argv[i] + 2, "RS-pidfile")) { isRSP = 1; if (++i == argc) fprintf(stderr,"Missing file specification for --RS-pidfile.\n"); else setConfig("pid.file", argv[i]); } if (!strcmp(argv[i] + 2, "RS-enable-control")) { isRSP = 1; setConfig("control", "enable"); } if (!strcmp(argv[i] + 2, "RS-enable-remote")) { isRSP = 1; setConfig("remote", "enable"); } if (!strcmp(argv[i] + 2, "RS-set")) { isRSP = 1; if (++i == argc) fprintf(stderr,"Missing argument for --RS-set.\n"); else { char *c = argv[i], *c2 = strchr(c, '='); if (!c2) c2 = ""; else { *c2 = 0; c2++; } if (!setConfig(c, c2)) fprintf(stderr, "WARNING: configuration directive '%s' is not supported (used in --RS-set)\n", c); } } if (!strcmp(argv[i] + 2, "RS-settings")) { printf("Rserve v%d.%d-%d\n\nconfig file: %s\nworking root: %s\nport: %d\nlocal socket: %s\nauthorization required: %s\nplain text password: %s\npasswords file: %s\nallow I/O: %s\nallow remote access: %s\ncontrol commands: %s\ninteractive: %s\nmax.input buffer size: %ld kB\n\n", RSRV_VER>>16, (RSRV_VER>>8)&255, RSRV_VER&255, CONFIG_FILE, workdir, port, localSocketName ? localSocketName : "[none, TCP/IP used]", authReq ? "yes" : "no", usePlain ? "allowed" : "not allowed", pwdfile ? pwdfile : "[none]", allowIO ? "yes" : "no", localonly ? "no" : "yes", "no", Rsrv_interactive ? "yes" : "no", (long) (maxInBuf / 1024L)); return 0; } if (!strcmp(argv[i] + 2, "version")) { printf("Rserve v%d.%d-%d (%s)\n",RSRV_VER>>16,(RSRV_VER>>8)&255,RSRV_VER&255,rserve_rev); } /* this is really an R option but we'll abuse it to stay really silent note that we don't use -q/--quiet so there is a way to pick and choose */ if (!strcmp(argv[i] + 2, "silent")) { rs_silent = 1; } if (!strcmp(argv[i] + 2, "help")) { printf("Usage: R CMD Rserve []\n\nOptions: --help this help screen\n --version prints Rserve version (also passed to R)\n --RS-port listen on the specified TCP port\n --RS-socket use specified local (unix) socket instead of TCP/IP.\n --RS-workdir use specified working directory root for connections.\n --RS-encoding set default server string encoding to .\n --RS-conf load additional config file.\n --RS-settings dumps current settings of the Rserve\n --RS-source source the specified file on startup.\n --RS-enable-control enable control commands\n --RS-enable-remote enable remote connections\n --RS-pidfile store the pid of the Rserve process in \n --RS-set = set configuration option as if it was\n read from a configuration file\n\nAll other options are passed to the R engine.\n\n"); #ifdef RSERV_DEBUG printf("debugging flag:\n --RS-dumplimit sets limit of items/bytes to dump in debugging output. set to 0 for unlimited\n\n"); #endif return 0; } } if (!isRSP) top_argv[top_argc++]=argv[i]; } performConfig(SU_NOW); stat = Rf_initEmbeddedR(top_argc,top_argv); if (stat < 0) { printf("Failed to initialize embedded R! (stat=%d)\n",stat); return 2; } #ifndef WIN32 /* windows uses this in init, unix doesn't so we set it here */ R_Interactive = Rsrv_interactive; /* we let R install sig handlers, but remove those that are bad */ signal(SIGSEGV, SIG_DFL); signal(SIGILL, SIG_DFL); #ifdef SIGBUS signal(SIGBUS, SIG_DFL); #endif /* FIXME: not sure about SIGPIPE - it's ok to use R's handling when caused by R code, but it's unclear if it can be caused by Rserve's internal code which would prefer death to surrender ... */ #endif /* registration must happen *before* source/eval */ { /* NOTE: R_registerRoutines *replaces* all existing registrations !! So we have to register everything for all. */ R_CallMethodDef mainCallMethods[] = { {"Rserve_ctrlEval", (DL_FUNC) &Rserve_ctrlEval, 1}, {"Rserve_ctrlSource", (DL_FUNC) &Rserve_ctrlSource, 1}, {"Rserve_oobSend", (DL_FUNC) &Rserve_oobSend, 2}, {"Rserve_oobMsg", (DL_FUNC) &Rserve_oobMsg, 2}, {"Rserve_oc_register", (DL_FUNC) &Rserve_oc_register, 2}, {"Rserve_oc_resolve", (DL_FUNC) &Rserve_oc_resolve, 1}, {"Rserve_ulog", (DL_FUNC) &Rserve_ulog, 1}, {"Rserve_fork_compute", (DL_FUNC) &Rserve_fork_compute, 1}, {"Rserve_kill_compute", (DL_FUNC) &Rserve_kill_compute, 1}, {"Rserve_forward_stdio", (DL_FUNC) &Rserve_forward_stdio, 0}, {"Rserve_eval", (DL_FUNC) &Rserve_eval, 5}, {"Rserve_get_context", (DL_FUNC) &Rserve_get_context, 0}, {"Rserve_set_context", (DL_FUNC) &Rserve_set_context, 1}, {"Rserve_set_http_request_fn", (DL_FUNC) &Rserve_set_http_request_fn, 1}, {"Rserve_http_add_static", (DL_FUNC) &Rserve_http_add_static, 4}, {"Rserve_set_last_condition", (DL_FUNC) &Rserve_set_last_condition, 1}, {NULL, NULL, 0} }; R_registerRoutines(R_getEmbeddingDllInfo(), 0, mainCallMethods, 0, 0); } if (src_list) { /* do any sourcing if necessary */ struct source_entry *se=src_list; #ifdef RSERV_DEBUG printf("Executing source/eval commands from the config file.\n"); #endif while (se) { #ifdef RSERV_DEBUG printf("voidEval(\"%s\")\n", se->line); #endif voidEval(se->line); se = se->next; } #ifdef RSERV_DEBUG printf("Done with initial commands.\n"); #endif } performConfig(SU_SERVER); #ifdef unix umask(umask_value); #endif if (enable_qap && !create_Rserve_QAP1(global_srv_flags | (qap_oc ? SRV_QAP_OC : 0))) { fprintf(stderr, "ERROR: unable to start Rserve server\n"); return ex(1); } if (tls_port > 0 && !create_Rserve_QAP1(global_srv_flags | SRV_TLS | (qap_oc ? SRV_QAP_OC : 0))) { fprintf(stderr, "ERROR: unable to start Rserve TLS server\n"); return ex(1); } http_flags = global_srv_flags; if (ws_upgrade) { http_flags = global_srv_flags | (enable_ws_qap ? WS_PROT_QAP : 0) | (enable_ws_text ? WS_PROT_TEXT : 0) | (ws_qap_oc ? SRV_QAP_OC : 0); if (http_flags & (WS_PROT_TEXT | WS_PROT_QAP)) http_flags |= HTTP_WS_UPGRADE; else fprintf(stderr, "WARNING: http.upgrade.websockets is enabled but no WS sub-protocol is enabled, ignoring\n"); } if (http_port > 0) { server_t *srv = create_HTTP_server(http_port, http_flags); if (!srv) { fprintf(stderr, "ERROR: unable to start Rserve HTTP server\n"); return ex(1); } srv->fork = fork_http; } if (https_port > 0) { server_t *srv = create_HTTP_server(https_port, http_flags | SRV_TLS); if (!srv) { fprintf(stderr, "ERROR: unable to start Rserve HTTPS server\n"); return ex(1); } srv->fork = fork_https; } if (enable_ws_text || enable_ws_qap) { if (ws_port < 1 && wss_port < 1) { if (!ws_upgrade) fprintf(stderr, "WARNING: Invalid or missing websockets port, WebSockets server will not start\n"); } else { if (ws_port > 0) { server_t *srv = create_WS_server(ws_port, global_srv_flags | (enable_ws_qap ? WS_PROT_QAP : 0) | (enable_ws_text ? WS_PROT_TEXT : 0) | (ws_qap_oc ? SRV_QAP_OC : 0)); if (srv) srv->fork = fork_ws; } if (wss_port > 0) { server_t *srv = create_WS_server(wss_port, global_srv_flags | (enable_ws_qap ? WS_PROT_QAP : 0) | (enable_ws_text ? WS_PROT_TEXT : 0) | (ws_qap_oc ? SRV_QAP_OC : 0) | WS_TLS); if (srv) srv->fork = fork_ws; } } } #if defined DAEMON && defined unix if (daemonize) { /* ok, we're in unix, so let's daemonize properly */ if (fork() != 0) { if (!rs_silent) puts("Rserv started in daemon mode."); exit(0); } setsid(); if (chdir("/")) {} /* start in root which is guaranteed to exist */ if (close_all_io) { int fd = open("/dev/null", O_RDWR); if (fd == -1 || dup2(fd, STDOUT_FILENO) == -1 || dup2(fd, STDERR_FILENO) == -1 || dup2(fd, STDIN_FILENO) == -1) ulog("WARNING: failed to redirect all I/O to /dev/null"); else { close(STDOUT_FILENO); close(STDERR_FILENO); close(STDIN_FILENO); } } } else if (!rs_silent) puts("Rserve started in non-daemon mode."); #endif #if defined RSERV_DEBUG || defined Win32 printf("Rserve: Ok, ready to answer queries.\n"); #endif RSsrv_init(); setup_signal_handlers(); serverLoop(); #ifdef unix if (localSocketName) remove(localSocketName); #endif #ifdef RSERV_DEBUG printf("\nServer terminated normally.\n"); #endif restore_signal_handlers(); return ex(0); } #endif /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/rsdebug.h0000644000175100001440000000213214531234224014127 0ustar hornikusers/* debugging tools such as dump */ #ifndef RSDEBUG_H__ #define RSDEBUG_H__ #ifndef NO_CONFIG_H #include "config.h" #endif #ifdef unix #if HAVE_SYS_TIME_H # include #endif #include #else #define gettimeofday(X,Y) 1 #endif #include #if defined RSERV_DEBUG || defined RSERV_IOLOG #ifdef MAIN int io_log = 0; /* log all I/O operations */ int dumpLimit = 128; double first_ts = 0.0; #else extern int io_log, dumpLimit; extern double first_ts; #endif static char io_log_fn[128]; static void fprintDump(FILE *f, const void *b, int len) { int i = 0; if (len < 1) { fprintf(f, "DUMP FAILED (len=%d)\n", len); }; fprintf(f, "DUMP [%d]:",len); while(i < len) { fprintf(f, " %02x",((const unsigned char*)b)[i++]); if (dumpLimit && i > dumpLimit) { fprintf(f, " ..."); break; }; } i = 0; fprintf(f, " |"); while (i < len) { unsigned char c = ((const unsigned char*)b)[i++]; if (c < 32 || c > 127) c = '.'; fputc(c, f); if (dumpLimit && i > dumpLimit) break; } fprintf(f, "\n"); } #define printDump(B,L) fprintDump(stdout, B, L) #endif #endif Rserve/src/md5.h0000644000175100001440000000101314531234224013156 0ustar hornikusers#ifndef MD5_H #define MD5_H typedef unsigned int uint32; struct MD5Context { uint32 buf[4]; uint32 bits[2]; unsigned char in[64]; }; void MD5Init(struct MD5Context *ctx); void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len); void MD5Final(unsigned char digest[16],struct MD5Context *ctx); void MD5Transform(uint32 buf[4], uint32 in[16]); typedef struct MD5Context MD5_CTX; unsigned char *md5hash(const void *buf, int len, unsigned char hash[16]); #endif /* !MD5_H */ Rserve/src/config.h.in0000644000175100001440000001156014531234224014353 0ustar hornikusers/* src/config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* Defined if the platform is big-endian */ #undef BS_BIG_ENDIAN /* Defined if the platform is little-endian */ #undef BS_LITTLE_ENDIAN /* If defined Rserve supports unix crypt password encryption. */ #undef HAS_CRYPT /* */ #undef HAVE_CONNECT /* Define to 1 if you have the header file. */ #undef HAVE_CRYPT_H /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* IPv6 support present and enabled */ #undef HAVE_IPV6 /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the `inet' library (-linet). */ #undef HAVE_LIBINET /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL /* Define to 1 if you have the `nsl_s' library (-lnsl_s). */ #undef HAVE_LIBNSL_S /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_TCP_H /* Have PTHREAD_PRIO_INHERIT. */ #undef HAVE_PTHREAD_PRIO_INHERIT /* Define to 1 if you have the `rmdir' function. */ #undef HAVE_RMDIR /* RSA crypto support */ #undef HAVE_RSA /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if you have the `srandomdev' function. */ #undef HAVE_SRANDOMDEV /* 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_SOCKET_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_TIME_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_SYS_UN_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* TLS/SSL support */ #undef HAVE_TLS /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* 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 /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #undef PTHREAD_CREATE_JOINABLE /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* The size of `size_t', as computed by sizeof. */ #undef SIZEOF_SIZE_T /* 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 /* set if threads can be used */ #undef WITH_THREADS /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to `int' if neither nor define. */ #undef socklen_t /* Define as `fork' if `vfork' does not work. */ #undef vfork Rserve/src/rserr.h0000644000175100001440000000107714531234224013640 0ustar hornikusers/* error I/O that uses either stderr or REprintf depending on the build */ #ifndef RSERR_H__ #define RSERR_H__ #ifndef NO_CONFIG_H #include "config.h" #endif #if defined STANDALONE_RSERVE && defined RSERVE_PKG #undef RSERVE_PKG #endif #include #include #ifndef STANDALONE_RSERVE #include /* for REvprintf */ #endif static void RSEprintf(const char *format, ...) { va_list(ap); va_start(ap, format); #ifdef STANDALONE_RSERVE vfprintf(stderr, format, ap); #else REvprintf(format, ap); #endif va_end(ap); } #endif Rserve/src/other/0000755000175100001440000000000014531234224013446 5ustar hornikusersRserve/src/other/RSpool.c0000644000175100001440000002534114531234224015035 0ustar hornikusers/* * RSpool : pool manager for synchronous Rserve workes instances * Part of the Rserve project. * Copyright (C) 2002-12 Simon Urbanek * * 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; version 2 of the License * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "Rsrv.h" #include "RSserver.h" #include #ifdef unix #include /* needed for unix sockets */ #endif #include #include #include #include #define default_max_pool 200 #define default_workers 20 static int active = 1, localonly = 1; typedef struct worker { #ifdef WIN32 SOCKET s; HANDLE w_in, w_out; /* worker pipe I/O handles */ #else int s; int w_in, w_out; /* worker pipe I/O handles, in = pool->worker, out = pool<-worker */ #endif long io_in_packet; long s_in_packet; } worker_t; static char **RSargv; static int RSargc; static char **allowed_ips = 0; /* spawns a new worker and returns worker structure to be used in the communication Returns only on the pool side, worker side. */ static worker_t* create_worker() { worker_t *w = (worker_t*) calloc(1, sizeof(worker_t)); if (!w) { fprintf(stderr, "ERROR: cannot allocate memory for a worker\n"); return w; } { #ifdef unix int pfd_in[2], pfd_out[2]; pid_t pid; if (pipe(pfd_in) != 0) { fprintf(stderr, "ERROR: cannot create I/O pipe 1\n"); free(w); return 0; } if (pipe(pfd_out) != 0) { fprintf(stderr, "ERROR: cannot create I/O pipe 2\n"); close(pfd_in[0]); close(pfd_in[1]); free(w); return 0; } w->w_in = pfd_in[1]; /* we write to w_in */ w->w_out = pfd_out[0];/* we read from w_out */ w->io_in_packet = -1; w->s_in_packet = -1; w->s = -1; /* all workers are unconnected first */ pid = fork(); if (pid == -1) { fprintf(stderr, "ERROR: cannot fork to exec\n"); close(pfd_in[0]); close(pfd_in[1]); close(pfd_out[0]); close(pfd_out[1]); free(w); return 0; } if (pid == 0) { /* child -> exec */ char buf[48]; /* close pool's side of the pipes */ close(pfd_in[1]); close(pfd_out[0]); /* add FD arguments for communication */ snprintf(buf, sizeof(buf), "--RS-pipe-io=%d,%d", pfd_in[0], pfd_out[1]); RSargv[RSargc++] = buf; RSargv[RSargc] = 0; /* exec */ execvp(RSargv[0], RSargv); /* should not return */ fprintf(stderr, "ERROR: cannot exec %s\n", RSargv[0]); perror("exec error"); exit(1); } /* successful fork */ #else #endif } return w; } static void remove_worker(worker_t *w) { close(w->w_out); close(w->w_in); free(w); } static int workers = default_workers, max_pool = default_max_pool; static worker_t **worker; static server_t *srv; static void connected(SOCKET s) { int i; worker_t *w = 0; for (i = 0; i < workers; i++) /* find any unconnected worker */ if (worker[i] && worker[i]->s == -1) { w = worker[i]; break; } if (!w) { /* no unconnected workers, need to spawn new one - find a slot for it*/ for (i = 0; i < max_pool; i++) if (!worker[i]) { w = worker[i] = create_worker(); if (i >= workers) workers = i + 1; break; } if (!w) { /* no slot */ fprintf(stderr, "ERROR: too many connections\n"); close(s); return; } } w->s = s; /* this should be unnecessary since the workes should be "fresh", but just in case ... */ w->s_in_packet = -1; w->io_in_packet = -1; } static char server_io_buffer[65536]; /* pool server loop - the server part is the same as Rserve, but it also has to include the workers part */ static void RSpool_serverLoop() { #ifdef unix struct timeval timv; int selRet = 0; fd_set readfds; #endif while(active) { /* main serving loop */ int i; #ifdef unix int maxfd = 0; while (waitpid(-1, 0, WNOHANG) > 0); /* 500ms (used to be 10ms) - it shouldn't really matter since it's ok for us to sleep -- the timeout will only influence how often we collect terminated children and (maybe) how quickly we react to shutdown */ timv.tv_sec = 0; timv.tv_usec = 500000; FD_ZERO(&readfds); if (srv) { int ss = srv->ss; if (ss > maxfd) maxfd = ss; FD_SET(ss, &readfds); } for (i = 0; i < workers; i++) if (worker[i]) { /* register output from workers as well as their sockets */ int fd = worker[i]->w_out; if (fd > maxfd) maxfd = fd; FD_SET(fd, &readfds); fd = worker[i]->s; if (fd > maxfd) maxfd = fd; if (fd != -1) FD_SET(fd, &readfds); } selRet = select(maxfd + 1, &readfds, 0, 0, &timv); if (selRet > 0) { /* for (i = 0; i < servers; i++) */ { socklen_t al; /* server_t *srv = server[i]; */ int ss = srv->ss; if (FD_ISSET(ss, &readfds)) { #endif SOCKET s; SAIN sa; #ifdef unix struct sockaddr_un su; if (srv->unix_socket) { al = sizeof(su); s = accept(ss, (SA*)&su, &al); } else #endif s = accept(ss, (SA*)&sa, &al); if (s != -1) { if (localonly && !srv->unix_socket) { char **laddr = allowed_ips; int allowed = 0; if (!laddr) { allowed_ips = (char**) malloc(sizeof(char*)*2); allowed_ips[0] = strdup("127.0.0.1"); allowed_ips[1] = 0; laddr = allowed_ips; } while (*laddr) if (sa.sin_addr.s_addr == inet_addr(*(laddr++))) { allowed = 1; break; }; if (allowed) { #ifdef RSERV_DEBUG printf("INFO: accepted connection for server %p, calling connected\n", (void*) srv); #endif connected(s); } else closesocket(s); } else { /* ---> remote enabled */ #ifdef RSERV_DEBUG printf("INFO: accepted connection for server %p, calling connected\n", (void*) srv); #endif connected(s); } } #ifdef unix } } /* end loop over servers */ for (i = 0; i < workers; i++) { worker_t *w = worker[i]; int remove = 0; /* socket read */ if (w && FD_ISSET(w->s, &readfds)) { remove = 1; if (w->s_in_packet <= 0) { /* new packet */ struct phdr hdr; int n = recv(w->s, &hdr, sizeof(hdr), 0); if (n == sizeof(hdr)) { n = write(w->w_in, &hdr, sizeof(hdr)); if (n == sizeof(hdr)) { long sz = hdr.len; if (hdr.res) sz |= ((long) hdr.res) << 32; remove = 0; w->s_in_packet = sz; } } } else { /* buffer IO */ int to_go = (int) (w->s_in_packet > sizeof(server_io_buffer)) ? sizeof(server_io_buffer) : w->s_in_packet; int n = recv(w->s, server_io_buffer, to_go, 0); if (n > 0 && write(w->w_in, server_io_buffer, n) == n) { remove = 0; w->s_in_packet -= to_go; } } } /* fd read */ if (w && FD_ISSET(w->w_out, &readfds)) { remove = 1; if (w->io_in_packet == -1) { /* first is the ID string */ char ids[32]; int n = read(w->w_out, ids, sizeof(ids)); if (n == sizeof(ids)) { n = send(w->s, ids, sizeof(ids), 0); if (n == sizeof(ids)) { w->io_in_packet = 0; /* done with ID, back to messages */ remove = 0; } } } else if (w->io_in_packet <= 0) { /* new packet */ struct phdr hdr; int n = read(w->w_out, &hdr, sizeof(hdr)); if (n == sizeof(hdr)) { n = send(w->s, &hdr, sizeof(hdr), 0); if (n == sizeof(hdr)) { long sz = hdr.len; if (hdr.res) sz |= ((long) hdr.res) << 32; remove = 0; w->io_in_packet = sz; } } } else { /* buffer IO */ int to_go = (int) (w->io_in_packet > sizeof(server_io_buffer)) ? sizeof(server_io_buffer) : w->io_in_packet; int n = read(w->w_out, server_io_buffer, to_go); if (n > 0 && send(w->s, server_io_buffer, n, 0) == n) { remove = 0; w->io_in_packet -= to_go; } } } if (remove) { remove_worker(w); /* FIXME: we should only create if it was not a surplus worker - but we have not recorded that number */ worker[i] = create_worker(); } } /* loop over workers */ } /* end if (selRet > 0) */ #endif } /* end while(active) */ } int main(int argc, char **argv) { int i = 0; int port = default_Rsrv_port; while (++i < argc) if (argv[i][0] == '-') switch (argv[i][1]) { case 'h': printf("\n Usage: %s [] \n\n Options: -w - specifies the number of workers (default %d)\n -p - port to listen on (default %d)\n -h - show this help\n\n Example: %s -w 30 R CMD Rserve --vanilla --no-save\n\n", argv[0], default_workers, default_Rsrv_port, argv[0]); return 0; case 'p': if (++i < argc) port = atoi(argv[i]); else { fprintf(stderr, "ERROR: missing port specification in -p \n"); return 1; }; break; case 'w': if (++i < argc) workers = atoi(argv[i]); else { fprintf(stderr, "ERROR: missing workers specification in -w \n"); return 1; }; break; default: fprintf(stderr, "ERROR: unknown option %s\n", argv[i]); return 1; } else break; if (i >= argc) { fprintf(stderr, "ERROR: missing Rserve startup command. See %s -h for usage.\n", argv[0]); return 0; } RSargv = (char**) calloc(argc - i + 3, sizeof(char*)); RSargc = argc - i; { /* Fill RSargv with startup + sentinel */ int j; for (j = 0; j < RSargc; j++) RSargv[j] = strdup(argv[i + j]); RSargv[j] = 0; } srv = create_server(port, 0, 0, 0); if (!srv) return 0; if (max_pool < workers) max_pool = workers; worker = (worker_t**) calloc(max_pool, sizeof(worker_t)); for (i = 0; i < workers; i++) worker[i] = create_worker(); RSpool_serverLoop(); return 0; } #ifdef RSERVE_PKG #include SEXP RSpool_run(SEXP args) { int argc, i, n; char **argv; if (TYPEOF(args) != STRSXP) Rf_error("Start arguments must be a character vector."); argc = LENGTH(args) + 1; argv = (char**) calloc(argc, sizeof(char*)); if (!argv) Rf_error("Cannot allocate memory for arguments"); for (i = 1; i < argc; i++) argv[i] = strdup(CHAR(STRING_ELT(args, i - 1))); argv[0] = "RSpool"; n = main(argc, argv); for (i = 1; i < argc; i++) free(argv[i]); free(argv); return ScalarLogical((n == 0) ? TRUE : FALSE); } #endif /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/src/qap_decode.h0000644000175100001440000000027714531234224014570 0ustar hornikusers#ifndef QAP_DECODE_H__ #define QAP_DECODE_H__ #ifndef USE_RINTERNALS #define USE_RINTERNALS 1 #include #endif #include "Rsrv.h" SEXP QAP_decode(unsigned int **buf); #endif Rserve/src/qap_encode.c0000644000175100001440000002255114531234224014574 0ustar hornikusers#include #include #include "qap_encode.h" #include /* compatibility re-mapping */ #define getStorageSize QAP_getStorageSize #define storeSEXP QAP_storeSEXP /* FIXME: we should move this to some common place ... */ /* string encoding handling */ #if (R_VERSION < R_Version(2,8,0)) || (defined DISABLE_ENCODING) #define mkRChar(X) mkChar(X) #define CHAR_FE(X) CHAR(X) #else #define USE_ENCODING 1 extern cetype_t string_encoding; #define mkRChar(X) mkCharCE((X), string_encoding) #define CHAR_FE(X) charsxp_to_current(X) static const char *charsxp_to_current(SEXP s) { if (Rf_getCharCE(s) == string_encoding) return CHAR(s); return Rf_reEnc(CHAR(s), getCharCE(s), string_encoding, 0); } #endif /* this is the representation of NAs in strings. We chose 0xff since that should never occur in UTF-8 strings. If 0xff occurs in the beginning of a string anyway, it will be doubled to avoid misrepresentation. */ static const unsigned char NaStringRepresentation[2] = { 255, 0 }; #define attrFixup if (hasAttr) buf = storeSEXP(buf, ATTRIB(x), 0); #define dist(A,B) (((rlen_t)(((char*)B)-((char*)A))) - 4L) #define align(A) (((A) + 3L) & (rlen_max ^ 3L)) rlen_t getStorageSize(SEXP x) { int t = TYPEOF(x); rlen_t len = 4; rlen_t tl = 0; #if defined RSERV_DEBUG && ! (defined DEBUG_NO_STORAGE) switch(tl) { /* only some types support XLENGTH calls now */ case CPLXSXP: case REALSXP: case INTSXP: case LGLSXP: case RAWSXP: case STRSXP: case EXPRSXP: case VECSXP: tl = XLENGTH(x); break; default: tl = (rlen_t) -1; } printf("getStorageSize(%p,type=%d,len=%ld) ", (void*)x, t, (long) tl); #endif if (t != CHARSXP && TYPEOF(ATTRIB(x)) == LISTSXP) { rlen_t alen = getStorageSize(ATTRIB(x)); len += alen; } switch (t) { case LISTSXP: case LANGSXP: { SEXP l = x; rlen_t tags = 0, n = 0; while (l != R_NilValue) { len += getStorageSize(CAR(l)); tags += getStorageSize(TAG(l)); n++; l = CDR(l); } if (tags > 4L * n) len += tags; /* use tagged list */ } break; case CLOSXP: len+=getStorageSize(FORMALS(x)); len+=getStorageSize(BODY(x)); break; case CPLXSXP: tl = XLENGTH(x); len += tl * 16L; break; case REALSXP: tl = XLENGTH(x); len += tl * 8L; break; case INTSXP: tl = XLENGTH(x); len += tl * 4L; break; case LGLSXP: case RAWSXP: tl = XLENGTH(x); if (tl > 1) len += 4L + align(tl); else len += 4L; break; case SYMSXP: case CHARSXP: { const char *ct = ((t==CHARSXP) ? CHAR_FE(x) : CHAR_FE(PRINTNAME(x))); if (!ct) len += 4L; else { rlen_t sl = strlen(ct) + 1L; len += align(sl); } } break; case STRSXP: { rlen_t i = 0; tl = XLENGTH(x); while (i < tl) { len += getStorageSize(STRING_ELT(x, i)); i++; } } break; case EXPRSXP: case VECSXP: { unsigned int i = 0; tl = XLENGTH(x); while(i < tl) { len += getStorageSize(VECTOR_ELT(x,i)); i++; } } break; case S4SXP: /* S4 really has the payload in attributes, so it doesn't occupy anything */ break; default: len += 4L; /* unknown types are simply stored as int */ } if (len > 0xfffff0) /* large types must be stored in the new format */ len += 4L; #if defined RSERV_DEBUG && ! (defined DEBUG_NO_STORAGE) printf("= %lu\n", (unsigned long) len); #endif return len; } /* if storage_size is > 0 then it it used instad of a call to getStorageSize() */ unsigned int* storeSEXP(unsigned int* buf, SEXP x, rlen_t storage_size) { int t = TYPEOF(x); int hasAttr = 0; int isLarge = 0; unsigned int *preBuf = buf; rlen_t txlen; if (!x) { /* null pointer will be treated as XT_NULL */ *buf = itop(XT_NULL); buf++; goto didit; } if (t != CHARSXP && TYPEOF(ATTRIB(x)) == LISTSXP) hasAttr = XT_HAS_ATTR; if (t == NILSXP) { *buf = itop(XT_NULL | hasAttr); buf++; attrFixup; goto didit; } /* check storage size */ if (!storage_size) storage_size = getStorageSize(x); txlen = storage_size; if (txlen > 0xfffff0) { /* if the entry is too big, use large format */ isLarge = 1; buf++; } if (t==LISTSXP || t==LANGSXP) { SEXP l = x; rlen_t tags = 0; while (l != R_NilValue) { if (TAG(l) != R_NilValue) tags++; l = CDR(l); } /* note that we are using the fact that XT_LANG_xx=XT_LIST_xx+2 */ *buf = itop((((t == LISTSXP) ? 0 : 2) + (tags ? XT_LIST_TAG : XT_LIST_NOTAG)) | hasAttr); buf++; attrFixup; l = x; while (l != R_NilValue) { buf = storeSEXP(buf, CAR(l), 0); if (tags) buf = storeSEXP(buf, TAG(l), 0); l = CDR(l); } goto didit; } if (t==CLOSXP) { /* closures (send FORMALS and BODY) */ *buf=itop(XT_CLOS|hasAttr); buf++; attrFixup; buf=storeSEXP(buf, FORMALS(x), 0); buf=storeSEXP(buf, BODY(x), 0); goto didit; } if (t==REALSXP) { *buf=itop(XT_ARRAY_DOUBLE|hasAttr); buf++; attrFixup; #ifdef NATIVE_COPY memcpy(buf, REAL(x), sizeof(double) * XLENGTH(x)); buf += XLENGTH(x) * sizeof(double) / sizeof(*buf); #else { rlen_t i = 0, n = XLENGTH(x); while(i < n) { fixdcpy(buf, REAL(x) + i); buf += 2; /* sizeof(double)=2*sizeof(int) */ i++; } } #endif goto didit; } if (t==CPLXSXP) { *buf = itop(XT_ARRAY_CPLX|hasAttr); buf++; attrFixup; #ifdef NATIVE_COPY memcpy(buf, COMPLEX(x), XLENGTH(x) * sizeof(*COMPLEX(x))); buf += XLENGTH(x) * sizeof(*COMPLEX(x)) / sizeof(*buf); #else { rlen_t i = 0, n = XLENGTH(x); while (i < n) { fixdcpy(buf, &(COMPLEX(x)[i].r)); buf += 2; /* sizeof(double)=2*sizeof(int) */ fixdcpy(buf, &(COMPLEX(x)[i].i)); buf += 2; /* sizeof(double)=2*sizeof(int) */ i++; } } #endif goto didit; } if (t==RAWSXP) { rlen_t ll = XLENGTH(x); *buf = itop(XT_RAW | hasAttr); buf++; attrFixup; *buf = itop(ll); buf++; if (ll) memcpy(buf, RAW(x), ll); ll += 3; ll /= 4; buf += ll; goto didit; } if (t==LGLSXP) { rlen_t ll = XLENGTH(x), i = 0; int *lgl = LOGICAL(x); *buf = itop(XT_ARRAY_BOOL | hasAttr); buf++; attrFixup; *buf = itop(ll); buf++; while(i < ll) { /* logical values are stored as bytes of values 0/1/2 */ int bv = lgl[i]; *((unsigned char*)buf) = (bv == 0) ? 0 : (bv==1) ? 1 : 2; buf = (unsigned int*)(((unsigned char*)buf) + 1); i++; } /* pad by 0xff to a multiple of 4 */ while (i & 3) { *((unsigned char*)buf) = 0xff; i++; buf=(unsigned int*)(((unsigned char*)buf) + 1); } goto didit; } if (t == STRSXP) { char *st; rlen_t nx = XLENGTH(x), i; *buf = itop(XT_ARRAY_STR|hasAttr); buf++; attrFixup; /* leading int n; is not needed due to the choice of padding */ st = (char *)buf; for (i = 0; i < nx; i++) { const char *cv = CHAR_FE(STRING_ELT(x, i)); rlen_t l = strlen(cv); if (STRING_ELT(x, i) == R_NaString) { cv = (const char*) NaStringRepresentation; l = 1; } else if ((unsigned char) cv[0] == NaStringRepresentation[0]) /* we will double the leading 0xff to avoid abiguity between NA and "\0xff" */ (st++)[0] = (char) NaStringRepresentation[0]; strcpy(st, cv); st += l + 1; } /* pad with '\01' to make sure we can determine the number of elements */ while ((st - (char*)buf) & 3) *(st++) = 1; buf = (unsigned int*)st; goto didit; } if (t==EXPRSXP || t==VECSXP) { rlen_t i = 0, n = XLENGTH(x); *buf = itop(((t == EXPRSXP) ? XT_VECTOR_EXP : XT_VECTOR) | hasAttr); buf++; attrFixup; while(i < n) { buf = storeSEXP(buf, VECTOR_ELT(x, i), 0); i++; } goto didit; } if (t==INTSXP) { rlen_t n = XLENGTH(x); int *iptr = INTEGER(x); *buf = itop(XT_ARRAY_INT | hasAttr); buf++; attrFixup; #ifdef NATIVE_COPY memcpy(buf, iptr, n * sizeof(int)); buf += n; #else { rlen_t i = 0; while(i < n) { *buf = itop(iptr[i]); buf++; i++; } } #endif goto didit; } if (t==S4SXP) { *buf=itop(XT_S4|hasAttr); buf++; attrFixup; goto didit; } if (t==CHARSXP||t==SYMSXP) { rlen_t sl; const char *val; if (t == CHARSXP) { *buf = itop(XT_STR | hasAttr); val = CHAR_FE(x); } else { *buf = itop(XT_SYMNAME | hasAttr); val = CHAR_FE(PRINTNAME(x)); } buf++; attrFixup; strcpy((char*)buf, val); sl = strlen((char*)buf); sl++; while (sl & 3) /* pad by 0 to a length divisible by 4 (since 0.1-10) */ ((char*)buf)[sl++] = 0; buf = (unsigned int*)(((char*)buf) + sl); goto didit; } *buf = itop(XT_UNKNOWN | hasAttr); buf++; attrFixup; *buf = itop(TYPEOF(x)); buf++; didit: if (isLarge) { txlen = dist(preBuf, buf) - 4L; preBuf[0] = itop(SET_PAR(PAR_TYPE(((unsigned char*) preBuf)[4] | XT_LARGE), txlen & 0xffffff)); preBuf[1] = itop(txlen >> 24); } else *preBuf = itop(SET_PAR(PAR_TYPE(ptoi(*preBuf)), dist(preBuf, buf))); #ifdef RSERV_DEBUG printf("stored %p at %p, %lu bytes\n", (void*)x, (void*)preBuf, (unsigned long) dist(preBuf, buf)); #endif if (dist(preBuf, buf) > storage_size) { #ifdef RSERVE_PKG REprintf("**ERROR: underestimated storage %ld / %ld SEXP type %d\n", (long) dist(preBuf, buf), (long) storage_size, TYPEOF(x)); #else fprintf(stderr, "**ERROR: underestimated storage %ld / %ld SEXP type %d\n", (long) dist(preBuf, buf), (long) storage_size, TYPEOF(x)); #endif /* R_inspect(x) // can't use this since it's hidden in R */ } return buf; } Rserve/src/Makevars.in0000644000175100001440000000305614531234224014432 0ustar hornikusersPKG_CPPFLAGS=-DRSERVE_PKG -I. -Iinclude @CPPFLAGS@ PKG_LIBS=@LIBS@ EMBED_CPPFLAGS=@RINC@ all: $(SHLIB) @WITH_SERVER_TRUE@ server @WITH_CLIENT_TRUE@ $(MAKE) client @WITH_PROXY_TRUE@ $(MAKE) -C proxy 'CC=$(CC)' 'CPPFLAGS=-I.. -DFORKED $(CPPFLAGS) $(PKG_CPPFLAGS)' CFLAGS='$(CFLAGS) $(PKG_CFLAGS) @PTHREAD_CFLAGS@' 'LDFLAGS=$(LDFLAGS)' 'LIBS=$(PKG_LIBS)' && cp -p proxy/forward . SERVER_SRC = standalone.c md5.c session.c qap_decode.c qap_encode.c sha1.c base64.c websockets.c RSserver.c tls.c http.c oc.c ulog.c ioc.c utils.c date.c SERVER_H = Rsrv.h qap_encode.h qap_decode.h RSserver.h http.h oc.h sha1.h md5.h ulog.h bsdcmpt.h server: $(SERVER_SRC) $(SERVER_H) $(CC) -DSTANDALONE_RSERVE -DDAEMON -I. -Iinclude $(ALL_CPPFLAGS) $(ALL_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(PKG_CPPFLAGS) $(EMBED_CPPFLAGS) $(PKG_CFLAGS) -o Rserve $(SERVER_SRC) $(LDFLAGS) $(ALL_LIBS) $(PKG_LIBS) $(CC) -DSTANDALONE_RSERVE -DRSERV_DEBUG -DNODAEMON -I. -Iinclude $(ALL_CPPFLAGS) $(ALL_CFLAGS) $(PKG_CPPFLAGS) $(EMBED_CPPFLAGS) $(PKG_CFLAGS) -o Rserve.dbg $(SERVER_SRC) $(LDFLAGS) $(ALL_LIBS) $(PKG_LIBS) # merging to bin/Rserve works only if installed from sources, won't work for binary -./mergefat Rserve "$(R_HOME)/bin/Rserve" -./mergefat Rserve.dbg "$(R_HOME)/bin/Rserve.dbg" client: config.h cp config.h client/cxx/ make -C client/cxx -@mkdir ../inst 2>/dev/null -rm -rf ../inst/client -cp -R client ../inst/ cp Rsrv.h config.h include/sisocks.h ../inst/client/cxx/ clean: rm -f *~ *.o *.lo *.so \#* $(XFILES) @WITH_PROXY_TRUE@ $(MAKE) -C proxy clean .PHONY: client clean server forward Rserve/src/mergefat0000755000175100001440000000160214531234224014044 0ustar hornikusers#!/bin/sh # Usage: mergefat # # Merges into possibly fat file and places the result in . # is assumed to be single-arch only. # Checks whether /usr/bin/lipo exists and uses cp if it doesn't. # # (C)2006,8 Simon Urbanek LIPO=/usr/bin/lipo if test -e "${LIPO}" -a -e "$2"; then myarch=`${LIPO} -detailed_info "$1"| sed -n -e 's|.\{0,\}architecture:\{0,1\} ||p'` binarch=`${LIPO} -detailed_info "$2"| sed -n -e 's|.\{0,\}architecture:\{0,1\} ||p'` if test "$myarch" = "$binarch"; then # the target is a single-arch of the same type as us - just replace cp "$1" "$2" else # try to remove our arch - if it fails (it is not fat or doesn't have our arch), # take the whole thing ${LIPO} "$2" -remove "$myarch" -o liposuction || cp "$2" liposuction ${LIPO} -create liposuction "$1" -o "$2" rm -f liposuction fi else cp "$1" "$2" fi Rserve/src/Rserv.c0000644000175100001440000044677614531234224013622 0ustar hornikusers/* * Rserv : R-server that allows to use embedded R via TCP/IP * Copyright (C) 2002-22 Simon Urbanek * * 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; version 2 of the License * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ */ /* external defines: COOPERATIVE - forces cooperative version of Rserv on unix platforms (default for non-unix platforms) FORKED - each connection is forked to a new process. This is the recommended way to use this server. The advantage is (beside the fact that this works ;)) that each client has a separate namespace since the processes are independent (default for unix platforms) SWAPEND - define if the platform has byte order inverse to Intel (like PPC) RSERV_DEBUG - if defined various verbose output is produced DAEMON - if defined the server daemonizes (unix only) CONFIG_FILE - location of the config file (default /etc/Rserv.conf) reported versions: -------------------- 0100 - Rserve 0.1-1 .. 0.1-9 CMD_eval sends SEXP directly without the data type header. This is in fact an inconsistency and was fixed in 0101. New clients should be aware of this and support this behavior or reject 0100 connections. 0101 - Rserve 0.1-10 .. 0.2-x 0102 - Rserve 0.3 added support for large parameters/expressions 0103 - Rserve 0.5 discard the notion of scalar types The current implementation uses DT_LARGE/XT_LARGE only for SEXPs larger than 0xfffff0. No commands except for CMD_set/assignREXP with DT_REXP accept large input, in particular all file operations. All objects smaller 8MB should be encoded without the use of DT_LARGE/XT_LARGE. */ /* config file entries: [default] ---------------------- workdir [depends on the CONFIG_FILE define] pwdfile [none=disabled] remote enable|disable [disable] auth required|disable [disable] plaintext enable|disable [disable] (strongly discouraged to enable) fileio enable|disable [enable] interactive yes|no [yes] (the default may change to "no" in the future!) socket [none] maxinbuf [262144 = 256MB] maxsendbuf [0 = no limit] cachepwd no|yes|indefinitely unix only (works only if Rserve was started by root): uid gid su now|server|client encoding native|latin1|utf8 [native] source eval control enable|disable [disable] r-control enable|disable [disable] A note about security: Anyone with access to R has access to the shell via "system" command, so you should consider following rules: - NEVER EVER run Rserv as root (unless uid/gid is used) - this compromises the box totally - use "remote disable" whenever you don't need remote access. - if you need remote access use "auth required" and "plaintext disable" consider also that anyone with the access can decipher other's passwords if he knows how to. the authentication prevents hackers from the net to break into Rserv, but it doesn't (and cannot) protect from inside attacks (since R has no security measures). You should also use a special, restricted user for running Rserv as a public server, so noone can try to hack the box it runs on. From 0.6-1 on you can set gid/uid and use "su client", "cachepwd yes" and only a root-readable password file such that clients cannot read it and also cannot affect the server process (this works on unix only). - don't enable plaintext unless you really have to. Passing passwords in plain text over the net is not wise and not necessary since both Rserv and JRclient provide encrypted passwords with server-side challenge (thus safe from sniffing). */ #ifndef NO_CONFIG_H #include "config.h" #endif #if defined STANDALONE_RSERVE || defined RSERVE_PKG #define USE_RINTERNALS 1 #define SOCK_ERRORS #ifndef LISTENQ #define LISTENQ 32 #endif #define MAIN /* some OSes don't like too large chunks to be sent/received, so we imit the socket I/O sizes by this constant. It should be a 31-bit value for compatibility. */ #ifdef WIN32 /* Windows is really bad (as usual) */ #define max_sio_chunk 1048576 #else #define max_sio_chunk 134217728 #endif #if defined NODAEMON && defined DAEMON #undef DAEMON #endif #if !defined WIN32 && !defined unix #define unix #endif /* FORKED is default for unix platforms */ #if defined unix && !defined COOPERATIVE && !defined FORKED #define FORKED #endif #ifndef CONFIG_FILE #ifdef unix #define CONFIG_FILE "/etc/Rserv.conf" #else #define CONFIG_FILE "Rserv.cfg" #endif #endif /* we have no configure for WIN32 so we have to take care of socklen_t */ #ifdef WIN32 typedef int socklen_t; #define random() rand() #define srandom() srand() #define CAN_TCP_NODELAY #include #include #include #include #include #include #endif #include #include #include #include #include #ifdef HAVE_LIMITS_H #include #endif #ifdef unix #if HAVE_SYS_TIME_H # include #endif #include #include #include #include #include #include /* needed for unix sockets */ #else #include #endif #include #ifdef FORKED #include #include #endif #ifdef ERROR #undef ERROR #endif #include #include #include #include #if (R_VERSION >= R_Version(2,3,0)) #ifdef WIN32 /* Windows doesn't have Rinterface */ extern __declspec(dllimport) int R_SignalHandlers; #else #define R_INTERFACE_PTRS #include #endif #endif #include #include "Rsrv.h" #include "qap_encode.h" #include "qap_decode.h" #include "ulog.h" #include "md5.h" /* we don't bother with sha1.h so this is the declaration */ void sha1hash(const char *buf, int len, unsigned char hash[20]); #ifdef HAVE_CRYPT_H #include #endif #if R_VERSION >= R_Version(2,9,0) #include #endif #if defined HAVE_NETINET_TCP_H && defined HAVE_NETINET_IN_H #define CAN_TCP_NODELAY #include #include #endif /* AF_LOCAL is the POSIX version of AF_UNIX - we need this e.g. for AIX */ #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX #endif /* send buffer size (default 2MB) Currently Rserve stores entire responses in memory before sending it. This is not really neccessary and may (hopefully will) change in the future. Send buffer specifies the maximal amount of data sent from Rserve to the client in one response. */ #ifndef sndBS /* configure may have defined one already */ #define sndBS (2048*1024) #endif /* the # of arguments to R_ParseVector changed since R 2.5.0 */ #if R_VERSION < R_Version(2,5,0) #define RS_ParseVector R_ParseVector #else #define RS_ParseVector(A,B,C) R_ParseVector(A,B,C,R_NilValue) #endif /* general RSMSG error commands */ #define RSMSG_ERR 0x800 /* is RSMSG error */ #define RSMSG_ERR_NOT_FOUND (RSMSG_ERR | 1) /* address not found */ #define RSMSG_ERR_NO_IO (RSMSG_ERR | 2) /* address exists but has no communication channel */ #define RSMSG_ERR_IO_FAILED (RSMSG_ERR | 3) /* error during an attempt to relay the message */ /* bits that govern presence of leading payload in RSMSG messages */ #define RSMSG_HAS_SRC 0x1000 /* has source address (mandatory if a reply is expected) */ #define RSMSG_HAS_DST 0x2000 /* has destination address (if not present, server is implied) */ typedef union { char c[16]; int i[4]; } rsmsg_addr_t; #define RSMSG_ADDR_LEN (sizeof(rsmsg_addr_t)) #define MAX_CTRL_DATA (1024*1024) /* max. length of data for control commands - larger data will be ignored */ #ifdef WIN32 #define pid_t int #endif #include "RSserver.h" #include "websockets.h" #include "http.h" #include "tls.h" #include "oc.h" struct args { server_t *srv; /* server that instantiated this connection */ SOCKET s; SOCKET ss; int msg_id; void *res1, *res2; /* the following entries are not populated by Rserve but can be used by server implemetations */ char *buf, *sbuf; int ver, bp, bl, sp, sl, flags; size_t l1, l2; /* The following fields are informational, populated by Rserve */ SAIN sa; int ucix; #ifdef unix struct sockaddr_un su; #endif char res[128]; /* reserved space for server-specific fields */ }; static int port = default_Rsrv_port; static int tls_port = -1; static int active = 1; /* 1 = server loop is active, 0 = shutdown */ static int UCIX = 1; /* unique connection index */ static char *localSocketName = 0; /* if set listen on this local (unix) socket instead of TCP/IP */ static int localSocketMode = 0; /* if set, chmod is used on the socket when created */ static int allowIO = 1; /* 1=allow I/O commands, 0=don't */ static char *workdir = "/tmp/Rserv"; static int wd_mode = 0755, wdt_mode = 0755; static char *pwdfile = 0; static int wipe_workdir = 0; /* if set acts as rm -rf otherwise just rmdir */ static SOCKET csock = -1; static pid_t parentPID = -1; int is_child = 0; /* 0 for parent (master), 1 for children */ static int tag_argv = 0;/* tag the ARGV with client/server IDs */ static char *pidfile = 0;/* if set by configuration generate pid file */ static int use_msg_id; /* enable/disable the use of msg-ids in message frames */ static int disable_shutdown; /* disable the shutdown command */ static int oob_console = 0; /* enable OOB commands for console callbacks */ static int read_console_enabled = 0; /* enable OOB MSG for read console as well */ static int idle_timeout = 0; /* interval to send idle OOBs, 0 = disabled */ static int forward_std = 0; /* flag whether to forward stdout/err as OOBs */ static int close_all_io = 0; /* if enabled all I/O is re-directed to /dev/null upon daemonization */ static int oob_allowed = 0; /* this flag is set once handshake is done such that OOB messages are permitted */ static int oob_context_prefix = 0; /* if set, context is prepended in OOB messages sent by Rserve itself */ /* configuration for TLS client checking */ static int tls_client_require = 0; static char *tls_client_match, *tls_client_prefix, *tls_client_suffix; #ifdef DAEMON int daemonize = 1; #endif char **main_argv; /* this is only set by standalone! */ int main_argc; size_t maxSendBufSize = 0; /* max. sendbuf for auto-resize. 0=no limit */ int Rsrv_interactive = 1; /* default for R_Interactive flag */ /* length of the authkey to send in CMD_keyReq authkey serves primarily as nonce so doesn't have to be too big, in fact versions <= 1.8-9 used 512 bytes which was too big since it guaranteed that the authentication information would be encrypted in the second block thus defeating the purpose. We use 4096-bit RSA keys which gives roughly 471 bytes of payload. */ #define SRV_KEY_LEN 256 static char authkey[SRV_KEY_LEN]; /* server-side authentication key */ static int authkey_req = 0; /* number of auth requests */ static char *auth_fn; /* authentication function */ #ifdef unix static int umask_value = 0; #endif int global_srv_flags = 0; static char *http_user, *https_user, *ws_user; static char **allowed_ips = 0; void stop_server_loop(void) { active = 0; } #include "rsdebug.h" #include "rserr.h" #ifdef unix #ifdef HAVE_SYS_TYPES_H #include #endif #include #include #include #endif static char tmpdir_buf[1024]; #include #ifdef unix char wdname[512]; #define mkdir_(A,B) mkdir(A,B) #else #define mkdir_(A,B) mkdir(A) /* no chmod on Windows */ #endif #if !defined(S_IFDIR) && defined(__S_IFDIR) # define S_IFDIR __S_IFDIR #endif /* modified version of what's used in R */ static int isDir(const char *path) { #ifdef Win32 struct _stati64 sb; #else struct stat sb; #endif int isdir = 0; if(!path) return 0; #ifdef Win32 if(_stati64(path, &sb) == 0) { #else if(stat(path, &sb) == 0) { #endif isdir = (sb.st_mode & S_IFDIR) > 0; /* is a directory */ } return isdir; } static void prepare_set_user(int uid, int gid) { const char *tmp = (const char*) R_TempDir; /* create a new tmpdir() and make it owned by uid:gid */ /* we use uid.gid in the name to minimize cleanup issues - we assume that it's ok to share tempdirs between sessions of the same user */ if (!tmp) { /* if there is no R_TempDir then it means that R has not been init'd yet so we have to take care of our own tempdir setting. This is replicating a subset of the logic used in R. */ const char *tm = getenv("TMPDIR"); char *tmpl; if (!isDir(tm)) { tm = getenv("TMP"); if (!isDir(tm)) { tm = getenv("TEMP"); if (!isDir(tm)) #ifdef Win32 tm = getenv("R_USER"); /* this one will succeed */ #else tm = "/tmp"; #endif } } /* Note: we'll be leaking this, but that's ok since it's tiny and only once per process */ tmpl = (char*) malloc(strlen(tm) + 10); if (tmpl) { strcpy(tmpl, tm); strcat(tmpl, "/Rstmp"); tmp = tmpl; } } snprintf(tmpdir_buf, sizeof(tmpdir_buf), "%s.%d.%d", tmp, uid, gid); if (mkdir_(tmpdir_buf, 0700)) {} /* it is ok to fail if it exists already */ /* gid can be 0 to denote no gid change -- but we will be using 0700 anyway so the actual gid is not really relevant */ #ifdef unix if (chown(tmpdir_buf, uid, gid)) {} if (workdir && /* FIXME: gid=0 will be bad here ! */ chown(wdname, uid, gid)) {} #endif R_TempDir = strdup(tmpdir_buf); } /* send/recv wrappers that are more robust */ ssize_t cio_send(int s, const void *buffer, size_t length, int flags) { ssize_t n; while ((n = send(s, buffer, length, flags)) == -1) { /* the only case we handle specially is EINTR to recover automatically */ if (errno != EINTR) break; } return n; } static int last_idle_time; /* FIXME: self.* commands can be loaded either from Rserve.so or from stand-alone binary. This will cause a mess since some things are private and some are not - we have to sort that out. In the meantime a quick hack is to make the relevant config (here enable_oob) global */ int enable_oob = 0; args_t *self_args; /* object to send with the idle call; it could be used for notification etc. */ SEXP idle_object; int compute_subprocess = 0; static int send_oob_sexp(int cmd, SEXP exp); /* stdout/err re-direction feeder FD (or 0 if not used) */ static int std_fw_fd; /* from ioc.c */ SEXP ioc_read(int *type); int ioc_setup(void); /* from utils.c */ SEXP Rserve_get_context(void); static void handle_std_fw(void) { int has_ctx = oob_context_prefix ? 1 : 0; SEXP q = PROTECT(allocVector(VECSXP, 2 + has_ctx)), r; int type = 0; /* ulog("handle_std_fw: reading I/O"); */ SET_VECTOR_ELT(q, 1 + has_ctx, r = ioc_read(&type)); /* ulog("handle_std_fw: read %d bytes", LENGTH(r)); */ SET_VECTOR_ELT(q, 0, mkString(type ? "stderr" : "stdout")); if (has_ctx) SET_VECTOR_ELT(q, 1, Rserve_get_context()); SET_VECTOR_ELT(q, 1 + has_ctx, ScalarString(mkCharLenCE((const char*) RAW(r), LENGTH(r), CE_UTF8))); if (oob_allowed) /* this should be really always true */ send_oob_sexp(OOB_SEND, q); UNPROTECT(1); } #ifdef unix #include static void std_fw_input_handler(void *dummy) { handle_std_fw(); } #endif /* */ ssize_t cio_recv(int s, void *buffer, size_t length, int flags) { ssize_t n; struct timeval timv; fd_set readfds; if (!last_idle_time) { last_idle_time = (int) time(NULL); if (!idle_object) idle_object = R_NilValue; } while (1) { int xfd = s; /* the timeout only determines granularity of idle calls */ timv.tv_sec = 1; timv.tv_usec = 0; FD_ZERO(&readfds); FD_SET(s, &readfds); if (oob_allowed && std_fw_fd && self_args && enable_oob) { if (std_fw_fd > xfd) xfd = std_fw_fd; FD_SET(std_fw_fd, &readfds); } n = select(xfd + 1, &readfds, 0, 0, &timv); if (n == -1) { if (errno == EINTR) continue; /* recover */ return -1; } if (n) { /* handle stdout/err forwarding first */ if (std_fw_fd && FD_ISSET(std_fw_fd, &readfds)) { handle_std_fw(); continue; } /* we only land here if FD_ISSET(s, ) is true so no need to check */ return recv(s, buffer, length, flags); } if (idle_timeout) { int delta = ((int) time(NULL)) - last_idle_time; if (delta > idle_timeout) { /* go only in oob mode */ if (self_args && enable_oob && oob_allowed) { SEXP q = PROTECT(allocVector(VECSXP, 2)); SET_VECTOR_ELT(q, 0, mkString("idle")); SET_VECTOR_ELT(q, 1, idle_object); send_oob_sexp(OOB_SEND, q); UNPROTECT(1); } last_idle_time = (int) time(NULL); } } } return -1; } /* this is only used on standalone mode */ #ifdef STANDALONE_RSERVE #ifdef unix static int set_user(const char *usr) { struct passwd *p = getpwnam(usr); if (!p) return 0; prepare_set_user(p->pw_uid, p->pw_gid); if (setgid(p->pw_gid)) return 0; initgroups(p->pw_name, p->pw_gid); if (setuid(p->pw_uid)) return 0; return 1; } static int fork_http(args_t *arg) { #ifdef unix int res = fork(); if (res == -1) RSEprintf("WARNING: fork() failed in fork_http(): %s\n",strerror(errno)); #else int res = -1; #endif if (res == 0 && http_user && !set_user(http_user)) { #ifdef STANDALONE_RSERVE fprintf(stderr, "ERROR: failed to set user '%s', aborting\n", http_user); #endif exit(1); } return res; } static int fork_https(args_t *arg) { #ifdef unix int res = fork(); if (res == -1) RSEprintf("WARNING: fork() failed in fork_https(): %s\n",strerror(errno)); #else int res = -1; #endif if (res == 0 && https_user && !set_user(https_user)) { #ifdef STANDALONE_RSERVE fprintf(stderr, "ERROR: failed to set user '%s', aborting\n", https_user); #endif exit(1); } return res; } static int fork_ws(args_t *arg) { #ifdef unix int res = fork(); if (res == -1) RSEprintf("WARNING: fork() failed in fork_ws(): %s\n",strerror(errno)); #else int res = -1; #endif if (res == 0 && ws_user && !set_user(ws_user)) { #ifdef STANDALONE_RSERVE fprintf(stderr, "ERROR: failed to set user '%s', aborting\n", ws_user); #endif exit(1); } return res; } #else static int fork_http(args_t *arg) { return -1; } static int fork_https(args_t *arg) { return -1; } static int fork_ws(args_t *arg) { return -1; } #endif #endif #ifdef STANDALONE_RSERVE static const char *rserve_ver_id = "$Id$"; static char rserve_rev[16]; /* this is generated from rserve_ver_id by main */ #endif #if 0 /* FIXME: not used yet, implements generate_addr() for random MSG IDs */ #ifdef HAVE_RSA #include static void generate_random_bytes(void *buf, int len) { #ifdef RAND_FALLBACK if (RAND_bytes(buf, len) != 1 && RAND_pseudo_bytes(buf, len) == -1) { int i; for (i = 0; i < len; i++) ((char*)buf)[i] = (char) random(); } #else #if OPENSSL_VERSION_NUMBER < 0x10100000L if (RAND_bytes(buf, len) != 1 && RAND_pseudo_bytes(buf, len) < 0) #else /* OpenSSL 1.1+ doesn't support pseudo random, so fail hard */ if (RAND_bytes(buf, len) != 1) #endif Rf_error("Cannot generate random bytes"); #endif } #else static void generate_random_bytes(void *buf, int len) { int i; for (i = 0; i < len; i++) ((char*)buf)[i] = (char) random(); } #endif static void generate_addr(rsmsg_addr_t *addr) { generate_random_bytes(addr, sizeof(*addr)); } #endif #define localUCIX UCIX /* string encoding handling */ #if (R_VERSION < R_Version(2,8,0)) || (defined DISABLE_ENCODING) #define mkRChar(X) mkChar(X) #else #define USE_ENCODING 1 cetype_t string_encoding = CE_NATIVE; /* default is native */ #define mkRChar(X) mkCharCE((X), string_encoding) #endif static SEXP Rserve_ctrlCMD(int command, SEXP what) { Rf_error("R control is not supported in this instance of Rserve"); return ScalarLogical(1); } SEXP Rserve_ctrlEval(SEXP what) { return Rserve_ctrlCMD(-1, what); } SEXP Rserve_ctrlSource(SEXP what) { return Rserve_ctrlCMD(-1, what); } static int set_string_encoding(const char *enc, int verbose) { #ifdef USE_ENCODING if (!strcmp(enc, "native")) string_encoding = CE_NATIVE; else if (!strcmp(enc, "latin1")) string_encoding = CE_LATIN1; else if (!strcmp(enc, "utf8")) string_encoding = CE_UTF8; else { if (verbose) RSEprintf("WARNING: invalid encoding value '%s' - muse be one of 'native', 'latin1' or 'utf8'.\n", enc); return 0; } return 1; #else if (verbose) RSEprintf("WARNING: 'encoding' defined but this Rserve has no encoding support.\n"); return 0; #endif } /* "smart" atoi - accepts 0x for hex and 0 for octal */ static int satoi(const char *str) { if (!str) return 0; if (str[0]=='0') { if (str[1]=='x') return strtol(str + 2, 0, 16); if (str[1]>='0' && str[1]<='9') return strtol(str + 1, 0, 8); } return atoi(str); } static char *getParseName(int n) { switch(n) { case PARSE_NULL: return "null"; case PARSE_OK: return "ok"; case PARSE_INCOMPLETE: return "incomplete"; case PARSE_ERROR: return "error"; case PARSE_EOF: return "EOF"; } return ""; } #ifdef RSERV_DEBUG static void printSEXP(SEXP e) /* merely for debugging purposes in fact Rserve binary transport supports more types than this function. */ { int t = TYPEOF(e); int i = 0; if (TYPEOF(ATTRIB(e)) == LISTSXP) printf("[*has attr*] "); if (t==NILSXP) { printf("NULL value\n"); return; } if (t==LANGSXP) { printf("language construct\n"); return; } if (t==LISTSXP) { SEXP l = e; printf("dotted-pair list:\n"); while (l != R_NilValue) { if (dumpLimit && i>dumpLimit) { printf("..."); break; }; if (TAG(l) != R_NilValue) { printf("(TAG:"); printSEXP(TAG(l)); printf(") "); } printSEXP(CAR(l)); l=CDR(l); } return; } if (t==REALSXP) { if (LENGTH(e)>1) { printf("Vector of real variables: "); while(idumpLimit) { printf("..."); break; } i++; } putchar('\n'); } else printf("Real variable %f\n",*REAL(e)); return; } if (t==CPLXSXP) { if (LENGTH(e)>1) { printf("Vector of complex variables: "); while(idumpLimit) { printf("..."); break; } i++; } putchar('\n'); } else printf("Complex variable %f+%fi\n",COMPLEX(e)[0].r,COMPLEX(e)[0].i); return; } if (t==RAWSXP) { printf("Raw vector: "); while(idumpLimit) { printf("..."); break; } i++; } putchar('\n'); return; } if (t==EXPRSXP) { printf("Vector of %d expressions:\n",LENGTH(e)); while(idumpLimit) { printf("..."); break; }; printSEXP(VECTOR_ELT(e,i)); i++; } return; } if (t==INTSXP) { printf("Vector of %d integers:\n",LENGTH(e)); while(idumpLimit) { printf("..."); break; } printf("%d",INTEGER(e)[i]); if (idumpLimit) { printf("..."); break; } printf("%d",INTEGER(e)[i]); if (idumpLimit) { printf("..."); break; }; printSEXP(VECTOR_ELT(e,i)); i++; } return; } if (t==STRSXP) { printf("String vector of length %d:\n",LENGTH(e)); while(idumpLimit) { printf("..."); break; }; printSEXP(STRING_ELT(e,i)); i++; } return; } if (t==CHARSXP) { printf("scalar string: \"%s\"\n", CHAR(e)); return; } if (t==SYMSXP) { printf("Symbol, name: "); printSEXP(PRINTNAME(e)); return; } if (t==S4SXP) { printf("S4 object\n"); return; } printf("Unknown type: %d\n",t); } #endif /* if set Rserve doesn't accept other than local connections. */ static int localonly = 1; #if defined (WIN32) && defined (RSERV_DEBUG) static int getpid(void) { return (int) GetCurrentProcessId(); } #endif /* send a response including the data part */ int Rserve_QAP1_send_resp(args_t *arg, int rsp, size_t len, const void *buf) { server_t *srv = arg->srv; struct phdr ph; size_t i = 0; /* do not tag OOB with CMD_RESP */ if (!(rsp & CMD_OOB)) rsp |= CMD_RESP; ph.cmd = itop(rsp); ph.len = itop(len); #ifdef __LP64__ ph.res = itop(len >> 32); #else ph.res = 0; #endif ph.msg_id = (int) arg->msg_id; ulog("QAP1: sending response 0x%08x, length %ld, msg.id 0x%x", ph.cmd, len, ph.msg_id); #ifdef RSERV_DEBUG printf("OUT.sendRespData\nHEAD "); printDump(&ph,sizeof(ph)); if (len == 0) printf("(no body)\n"); else { printf("BODY "); printDump(buf, len); } if (io_log) { struct timeval tv; snprintf(io_log_fn, sizeof(io_log_fn), "/tmp/Rserve-io-%d.log", getpid()); FILE *f = fopen(io_log_fn, "a"); if (f) { double ts = 0; if (!gettimeofday(&tv, 0)) ts = ((double) tv.tv_sec) + ((double) tv.tv_usec) / 1000000.0; if (first_ts < 1.0) first_ts = ts; fprintf(f, "%.3f [+%4.3f] SRV --> CLI [sendRespData] (%x, %ld bytes)\n HEAD ", ts, ts - first_ts, rsp, (long) len); fprintDump(f, &ph, sizeof(ph)); fprintf(f, " BODY "); if (len) fprintDump(f, buf, len); else fprintf(f, "\n"); fclose(f); } } #endif if (srv->send(arg, (char*)&ph, sizeof(ph)) < 0) return -1; while (i < len) { ssize_t rs = srv->send(arg, (char*)buf + i, (len - i > max_sio_chunk) ? max_sio_chunk : (len - i)); if (rs < 1) return -1; i += rs; } return 0; } /* initial ID string */ char *IDstring="Rsrv0103QAP1\r\n\r\n--------------\r\n"; /* require authentication flag (default: no) */ int authReq = 0; /* use plain password flag (default: no) */ int usePlain = 0; /* max. size of the input buffer (per connection) */ size_t maxInBuf = 256 * (1024 * 1024); /* default is 256MB */ /* if non-zero then the password file is loaded before client su so it can be unreadable by the clients */ int cache_pwd = 0; char *pwd_cache; /* if client_su is set then Rserve switches uid/gid */ #define SU_NOW 0 #define SU_SERVER 1 #define SU_CLIENT 2 static int su_time = SU_NOW; static void load_pwd_cache(void) { FILE *f = fopen(pwdfile, "r"); if (f) { int fs = 0; fseek(f, 0, SEEK_END); fs = ftell(f); fseek(f, 0, SEEK_SET); pwd_cache = (char*) malloc(fs + 1); if (pwd_cache) { if (fread(pwd_cache, 1, fs, f) != fs) { free(pwd_cache); pwd_cache = 0; } else pwd_cache[fs] = 0; } fclose(f); } } struct source_entry { struct source_entry* next; char line[8]; } *src_list=0, *src_tail=0; static int ws_port = -1, enable_qap = 1, enable_ws_qap = 0, enable_ws_text = 0, wss_port = 0; static int ws_qap_oc = 0, qap_oc = 0; static int http_port = -1; static int https_port = -1; static int switch_qap_tls = 0; static int ws_upgrade = 0; static int http_raw_body = 0; static int use_ipv6 = 0; static int requested_uid = 0, requested_gid = 0; static char *requested_chroot = 0; static int auto_uid = 0, auto_gid = 0; static int default_uid = 0, default_gid = 0; static int random_uid = 0, random_gid = 0; static int random_uid_low = 32768, random_uid_high = 65530; static int use_idle_callback = 0; #ifdef HAVE_RSA static int rsa_load_key(const char *buf); #endif /* FIXME: we are not preventing collisions - we have to keep track of the uid assignments to children and no reuse those alive */ static int get_random_uid(void) { int uid = random_uid_low + UCIX % (random_uid_high - random_uid_low + 1); return uid; } #ifdef unix static int chkres1(const char *cmd, int res) { if (res) { perror(cmd); RSEprintf("ERROR: %s failed\n", cmd); } return res; } #endif static int performConfig(int when) { int fail = 0; if (oob_console && !enable_oob) { RSEprintf("WARNING: oob.console is enabled, but oob is disabled, that won't work - disabling console\n"); oob_console = 0; } #ifdef unix if (when == SU_NOW) { if (requested_chroot && chroot(requested_chroot)) { perror("chroot"); RSEprintf("chroot(\"%s\"): failed.\n", requested_chroot); fail++; } } if (cache_pwd) load_pwd_cache();/* load pwd file into memory before su */ if (when == SU_CLIENT && random_uid) { /* FIXME: we */ int ruid = get_random_uid(); prepare_set_user(ruid, random_gid ? ruid : 0); if (chkres1("setgid", random_gid && setgid(ruid))) fail++; if (chkres1("setuid", setuid(ruid))) fail++; } else if (su_time == when) { if (requested_uid) prepare_set_user(requested_uid, requested_gid); if (chkres1("setuid", requested_gid && setgid(requested_gid))) fail++; if (chkres1("setuid", requested_uid && setuid(requested_uid))) fail++; } #endif return fail; } /* called once the server process is setup (e.g. after daemon fork for forked servers) */ static void RSsrv_init(void) { #ifdef unix if (pidfile) { FILE *f = fopen(pidfile, "w"); if (f) { fprintf(f, "%ld\n", (long) getpid()); fclose(f); } else RSEprintf("WARNING: cannot write into pid file '%s'\n", pidfile); } #endif } static void RSsrv_done(void) { if (pidfile) { unlink(pidfile); pidfile = 0; } } static char expand_buffer[1024]; static char expand_tmp[128]; static const char *expand_conf_string(const char *str) { char *dst = expand_buffer; const char *c = str, *x = str; if (!str || !*str) return ""; while ((x = strstr(c, "${"))) { char *tr = strchr(x + 2, '}'); if (tr && tr - x < 64) { char *repl; int rlen; if (x > c) { memcpy(dst, c, x - c); dst += x - c; } memcpy(expand_tmp, x + 2, tr - x - 2); expand_tmp[tr - x - 2] = 0; repl = getenv(expand_tmp); if (!repl) repl = ""; rlen = strlen(repl); if (rlen) { memcpy(dst, repl, rlen); dst += rlen; } c = tr + 1; } else { /* jsut ignore the ${ part */ memcpy(dst, x, 2); dst += 2; c = x + 2; } } if (dst == expand_buffer) return str; /* nothing got expanded */ strcpy(dst, c); /* copy the remaining content */ return expand_buffer; } static int conf_is_true(const char *str) { return (str && (*str == '1' || *str == 'y' || *str == 'e' || *str == 'T')) ? 1 : 0; } /* attempts to set a particular configuration setting returns: 1 = setting accepted, 0 = unknown setting, -1 = setting known but failed */ static int setConfig(const char *c, const char *p) { p = expand_conf_string(p); #ifdef RSERV_DEBUG if (p == expand_buffer) printf("conf> after expansion parameter=\"%s\"\n", p); #endif if (!strcmp(c, "log.io")) { #ifdef RSERV_DEBUG io_log = conf_is_true(p); #endif return 1; } if (!strcmp(c, "deamon") /* typo! but we keep it for compatibility */ || !strcmp(c, "daemon")) { #ifdef DAEMON daemonize = conf_is_true(p); #endif return 1; } if (!strcmp(c, "close.all.stdio")) { close_all_io = conf_is_true(p); return 1; } if (!strcmp(c, "msg.id")) { use_msg_id = conf_is_true(p); return 1; } if (!strcmp(c, "remote")) { localonly = !conf_is_true(p); return 1; } if (!strcmp(c, "tag.argv")) { tag_argv = conf_is_true(p); return 1; } if (!strcmp(c, "forward.stdio")) { forward_std = conf_is_true(p); return 1; } if (!strcmp(c, "io.use.context")) { oob_context_prefix = conf_is_true(p); return 1; } if (!strcmp(c, "ulog")) { ulog_set_path((*p) ? p : 0); return 1; } if (!strcmp(c, "keep.alive")) { if (conf_is_true(p)) global_srv_flags |= SRV_KEEPALIVE; else global_srv_flags &= ~ SRV_KEEPALIVE; return 1; } if (!strcmp(c, "switch.qap.tls")) { switch_qap_tls = conf_is_true(p); return 1; } if (!strcmp(c, "qap.oc") || !strcmp(c, "rserve.oc")) { qap_oc = conf_is_true(p); return 1; } if (!strcmp(c, "console.oob")) { oob_console = conf_is_true(p); return 1; } if (!strcmp(c, "console.input")) { read_console_enabled = conf_is_true(p); return 1; } if (!strcmp(c, "websockets.qap.oc")) { ws_qap_oc = conf_is_true(p); return 1; } if (!strcmp(c, "random.uid")) { random_uid = conf_is_true(p); return 1; } if (!strcmp(c, "random.gid")) { random_gid = conf_is_true(p); return 1; } if (!strcmp(c, "random.uid.range")) { const char *c = p; int lo = atoi(c); if (lo < 1) RSEprintf("ERROR: invalid random.uid.range start (%d)\n", lo); else { while (*c >= '0' && *c <= '9') c++; while (*c && (*c < '0' || *c > '9')) c++; if (*c) { int hi = atoi(c); if (hi <= lo) RSEprintf("ERROR: invalid random.uid.range (%d..%d)\n", lo, hi); else { random_uid_low = lo; random_uid_high = hi; } } } return 1; } if (!strcmp(c, "auto.uid")) { auto_uid = conf_is_true(p); return 1; } if (!strcmp(c, "auto.gid")) { auto_gid = conf_is_true(p); return 1; } if (!strcmp(c, "default.uid")) { default_uid = satoi(p); return 1; } if (!strcmp(c, "default.gid")) { default_gid = satoi(p); return 1; } if (!strcmp(c, "oob.idle.interval")) { idle_timeout = (*p) ? atoi(p) : 0; return 1; } if (!strcmp(c,"port") || !strcmp(c, "qap.port")) { if (*p) { int np = satoi(p); if (np > 0) port = np; } return 1; } if (!strcmp(c, "ipv6")) { use_ipv6 = conf_is_true(p); return 1; } if (!strcmp(c, "use.idle.callback")) { use_idle_callback = conf_is_true(p); return 1; } if (!strcmp(c, "http.upgrade.websockets")) { ws_upgrade = conf_is_true(p); return 1; } if (!strcmp(c, "http.raw.body")) { http_raw_body = conf_is_true(p); return 1; } if (!strcmp(c,"websockets.port")) { if (*p) { int np = satoi(p); if (np > 0) ws_port = np; } return 1; } if (!strcmp(c,"http.port")) { if (*p) { int np = satoi(p); if (np > 0) http_port = np; } return 1; } if (!strcmp(c, "tls.key")) { tls_t *tls = shared_tls(0); if (!tls) tls = shared_tls(new_tls()); if (set_tls_pk(tls, p) != 1) RSEprintf("WARNING: setting tls.key FAILED, TLS will NOT be used%s\n", tls ? " (check your key file)" : " (TLS support is not present, you may need to re-compile with OpenSSL)"); return 1; } if (!strcmp(c, "tls.ca")) { tls_t *tls = shared_tls(0); if (!tls) tls = shared_tls(new_tls()); if (set_tls_ca(tls, p, 0) != 1) RSEprintf("WARNING: setting tls.ca FAILED\n"); return 1; } if (!strcmp(c, "tls.cert")) { tls_t *tls = shared_tls(0); if (!tls) tls = shared_tls(new_tls()); if (set_tls_cert(tls, p) != 1) RSEprintf("WARNING: setting tls.cert FAILED%s\n", tls ? " (check your certificate)" : ""); return 1; } if (!strcmp(c, "tls.client")) { int tls_verify = 1, tls_require = 1; tls_t *tls; if (!strcmp(p, "require")) { /* ask: yes, verify: yes */ } else if (!strcmp(p, "none")) { /* ask: no, verify: no */ tls_verify = 0; tls_require = 0; } else if (!strcmp(p, "request")) { /* ask: yes, verify: no */ tls_require = 0; } else if (!strncmp(p, "match:", 6)) { /* all others imply require */ tls_client_match = strdup(p + 6); } else if (!strncmp(p, "prefix:", 7)) { tls_client_prefix = strdup(p + 7); } else if (!strncmp(p, "suffix:", 7)) { tls_client_suffix = strdup(p + 7); } else { RSEprintf("WARNING: invalid tls.client specification '%s', ignoring\n", p); return 1; } tls = shared_tls(0); if (!tls) tls = shared_tls(new_tls()); if (set_tls_verify(tls, tls_verify) != 1) RSEprintf("WARNING: setting tls.verify FAILED\n"); tls_client_require = tls_require; return 1; } if (!strcmp(c, "pid.file") && *p) { pidfile = strdup(p); return 1; } if (!strcmp(c, "rsa.key")) { #ifdef HAVE_RSA if (*p) { FILE *f = fopen(p, "r"); if (f) { char *buf = (char*) malloc(65536); if (buf) { int n = fread(buf, 1, 65535, f); buf[n] = 0; if (rsa_load_key(buf) == -1) RSEprintf("ERROR: not a valid RSA private key in '%s'\n", p); } else RSEprintf("ERROR: cannot allocate memory for the RSA key\n"); fclose(f); } else RSEprintf("ERROR: cannot open rsa.key file '%s'\n", p); } #else RSEprintf("WARNING: rsa.key specified but RSA is not supported in this build!\n"); #endif return 1; } if (!strcmp(c, "tls.port") || !strcmp(c, "qap.tls.port")) { if (*p) { int np = satoi(p); if (np > 0) tls_port = np; } return 1; } if (!strcmp(c,"https.port") || !strcmp(c, "http.tls.port")) { if (*p) { int np = satoi(p); if (np > 0) https_port = np; } return 1; } if (!strcmp(c, "websockets.tls.port")) { if (*p) { int np = satoi(p); if (np > 0) wss_port = np; } return 1; } if (!strcmp(c, "rserve") || !strcmp(c, "qap")) { enable_qap = conf_is_true(p); return 1; } if (!strcmp(c, "websockets.qap")) { enable_ws_qap = conf_is_true(p); return 1; } if (!strcmp(c, "websockets.text")) { enable_ws_text = conf_is_true(p); return 1; } if (!strcmp(c, "websockets") && conf_is_true(p)) { enable_ws_qap = 1; enable_ws_text = 1; return 1; } if (!strcmp(c,"maxinbuf")) { if (*p) { long ns = atol(p); if (ns > 32) { maxInBuf = ns; maxInBuf *= 1024; } } return 1; } if (!strcmp(c,"source") || !strcmp(c,"eval")) { #ifdef RSERV_DEBUG printf("Found source entry \"%s\"\n", p); #endif if (*p) { struct source_entry* se= (struct source_entry*) malloc(sizeof(struct source_entry)+strlen(p)+16); if (!strcmp(c,"source")) { strcpy(se->line, "try(source(\""); strcat(se->line, p); strcat(se->line, "\"))"); } else strcpy(se->line, p); se->next=0; if (!src_tail) src_tail=src_list=se; else { src_tail->next=se; src_tail=se; } } return 1; } if (!strcmp(c,"maxsendbuf")) { if (*p) { long ns = atol(p); if (ns > 32) { maxSendBufSize = ns; maxSendBufSize *= 1024; } } return 1; } #ifdef unix if (!strcmp(c, "su") && *p) { if (*p == 'n') su_time = SU_NOW; else if (*p == 's') su_time = SU_SERVER; else if (*p == 'c') su_time = SU_CLIENT; else { RSEprintf("su value invalid - must be 'now', 'server' or 'client'.\n"); return -1; } return 1; } if (!strcmp(c, "http.user") && *p) { http_user = strdup(p); return 1; } if (!strcmp(c, "https.user") && *p) { https_user = strdup(p); return 1; } if (!strcmp(c, "websockets.user") && *p) { ws_user = strdup(p); return 1; } if (!strcmp(c,"uid") && *p) { requested_uid = satoi(p); return 1; } if (!strcmp(c,"gid") && *p) { requested_gid = satoi(p); return 1; } if (!strcmp(c,"chroot") && *p) { requested_chroot = strdup(p); return 1; } if (!strcmp(c,"umask") && *p) { umask_value = satoi(p); return 1; } #endif if (!strcmp(c,"allow") && *p) { char **l; if (!allowed_ips) { allowed_ips = (char**) malloc(sizeof(char*)*128); *allowed_ips = 0; } l = allowed_ips; while (*l) l++; if (l - allowed_ips >= 127) { RSEprintf("WARNING: Maximum of allowed IPs (127) exceeded, ignoring 'allow %s'\n", p); return -1; } else { *l = strdup(p); l++; *l = 0; } return 1; } if (!strcmp(c, "control") && conf_is_true(p)) { RSEprintf("WARNING: control commands are NOT supported since Rserve 1.8"); return -1; } if (!strcmp(c, "shutdown")) { disable_shutdown = !conf_is_true(p); return 1; } if (!strcmp(c,"workdir")) { workdir = (*p) ? strdup(p) : 0; return 1; } if (!strcmp(c,"workdir.clean") && p) { wipe_workdir = conf_is_true(p); return 1; } if (!strcmp(c, "workdir.mode")) { int cm = satoi(p); if (!cm) RSEprintf("ERROR: invalid workdir.mode\n"); else { wd_mode = cm; if ((wd_mode & 0700) != 0700) RSEprintf("WARNING: workdir.mode does not contain 0700 - this may cause problems\n"); } return 1; } if (!strcmp(c, "workdir.parent.mode")) { int cm = satoi(p); if (!cm) RSEprintf("ERROR: invalid workdir.parent.mode\n"); else { wdt_mode = cm; if ((wdt_mode & 0700) != 0700) RSEprintf("WARNING: workdir.parent.mode does not contain 0700 - this may cause problems\n"); } return 1; } if (!strcmp(c,"encoding") && *p) { set_string_encoding(p, 1); return 1; } if (!strcmp(c,"socket")) { localSocketName = (*p) ? strdup(p) : 0; return 1; } if (!strcmp(c,"sockmod") && *p) { localSocketMode = satoi(p); return 1; } if (!strcmp(c,"pwdfile")) { pwdfile = (*p) ? strdup(p) : 0; return 1; } if (!strcmp(c,"auth.function")) { auth_fn = (*p) ? strdup(p) : 0; return 1; } if (!strcmp(c,"auth")) { authReq = (p && *p == 'r') || conf_is_true(p); return 1; } if (!strcmp(c,"interactive")) { Rsrv_interactive = conf_is_true(p); return 1; } if (!strcmp(c,"plaintext")) { usePlain = conf_is_true(p); return 1; } if (!strcmp(c,"oob")) { enable_oob = conf_is_true(p); return 1; } if (!strcmp(c,"fileio")) { allowIO = conf_is_true(p); return 1; } if (!strcmp(c, "r-control") || !strcmp(c, "r.control")) { RSEprintf("WARNING: control commands are NOT supported since Rserve 1.8"); return -1; } if (!strcmp(c, "cachepwd")) { cache_pwd = (*p == 'i') ? 2 : conf_is_true(p); return 1; } return 0; } /* load config file */ static int loadConfig(const char *fn) { FILE *f; char buf[512]; char *c,*p,*c1; #ifdef RSERV_DEBUG printf("Loading config file %s\n",fn); #endif f = fopen(fn,"r"); if (!f) { #ifdef RSERV_DEBUG printf("Failed to find config file %s\n",fn); #endif return -1; } buf[511] = 0; while(!feof(f)) if (fgets(buf,511,f)) { c = buf; while(*c == ' ' || *c == '\t') c++; if (!*c || *c == '\n' || *c == '#' || *c == ';') continue; /* skip comments and empty lines */ p = c; while(*p && *p != '\t' && *p != ' ' && *p != '=' && *p != ':') { if (*p >= 'A' && *p <= 'Z') *p |= 0x20; /* to lower case */ p++; } if (*p) { *p = 0; p++; while(*p && (*p == '\t' || *p == ' ')) p++; } c1 = p; /* find EOL */ while (*c1 && (*c1 != '\n' && *c1 != '\r')) c1++; /* trim trailing whitespace (PR#20) */ while (c1 > p && (c1[-1] == '\t' || c1[-1] == ' ')) c1--; *c1 = 0; #ifdef RSERV_DEBUG printf("conf> command=\"%s\", parameter=\"%s\"\n", c, p); #endif /* fork here is special - it only works in config files and the child stops reading after that */ if (!strcmp(c, "fork") && !strcmp(p, "here")) { #ifdef unix pid_t fres = fork(); if (fres < 0) RSEprintf("WARNING: fork here failed\n"); else if (fres == 0) { #ifdef RSERV_DEBUG printf(" -- forked child server with active config (%d)", getpid()); #endif break; /* get out - don't read the config file any further */ } #else RSEprintf("WARNING: fork here specified on system that doesn't support forking, ignoring.\n"); #endif } else setConfig(c, p); } fclose(f); #ifndef HAS_CRYPT if (!usePlain) { RSEprintf("WARNING: plain-text passwords are disabled, but this Rserve has no crypt support!\nSet 'plaintext enable' or compile with crypt support (if your system supports crypt).\nFalling back to plain text password.\n"); usePlain=1; } #endif #ifdef RSERV_DEBUG printf("Loaded config file %s\n",fn); #endif if (cache_pwd == 2) load_pwd_cache(); return 0; } /* size of the input buffer (default 512kB) was 2k before 1.23, but since 1.22 we support CMD_assign/set and hence the incoming packets can be substantially bigger. since 1.29 we support input buffer resizing, therefore we start with a small buffer and allocate more if necessary */ static size_t inBuf = 32768; /* 32kB should be ok unless CMD_assign sends large data */ /* static buffer size used for file transfer. The user is still free to allocate its own size */ #define sfbufSize 32768 /* static file buffer size */ /* pid of the last child (not really used ATM) */ static int lastChild; #ifdef FORKED static void sigHandler(int i) { if (i==SIGTERM || i==SIGHUP) active = 0; } static void brkHandler(int i) { #ifdef STANDALONE_RSERVE fprintf(stderr, "\nCaught break signal, shutting down Rserve.\n"); #else Rprintf("Caught break signal, shutting down Rserve.\n"); #endif active = 0; /* kill(getpid(), SIGUSR1); */ } #endif /* used for generating salt code (2x random from this array) */ const char *code64="./0123456789ABCDEFGHIJKLMNOPQRSTUVWYXZabcdefghijklmnopqrstuvwxyz"; /** parses a string, stores the number of expressions in parts and the resulting statis in status. the returned SEXP may contain multiple expressions */ SEXP parseString(const char *s, int *parts, ParseStatus *status) { int maxParts = 1; const char *c = s; SEXP cv, pr = R_NilValue; while (*c) { if (*c == '\n' || *c == ';') maxParts++; c++; } PROTECT(cv = allocVector(STRSXP, 1)); SET_STRING_ELT(cv, 0, mkRChar(s)); while (maxParts > 0) { pr = RS_ParseVector(cv, maxParts, status); if (*status != PARSE_INCOMPLETE && *status != PARSE_EOF) break; maxParts--; } UNPROTECT(1); *parts = maxParts; return pr; } /** parse a string containing the specified number of expressions */ SEXP parseExps(char *s, int exps, ParseStatus *status) { SEXP cv, pr; PROTECT(cv = allocVector(STRSXP, 1)); SET_STRING_ELT(cv, 0, mkRChar(s)); pr = RS_ParseVector(cv, 1, status); UNPROTECT(1); return pr; } void voidEval(const char *cmd) { ParseStatus stat; int Rerror; int j = 0; SEXP xp = parseString(cmd,&j,&stat); PROTECT(xp); #ifdef RSERV_DEBUG printf("voidEval: buffer parsed, stat=%d, parts=%d\n",stat,j); if (xp) printf("result type: %d, length: %d\n",TYPEOF(xp),LENGTH(xp)); else printf("result is \n"); #endif if (stat!=1) { UNPROTECT(1); return; } else { #ifdef RSERV_DEBUG printf("R_tryEval(xp,R_GlobalEnv,&Rerror);\n"); #endif if (TYPEOF(xp) == EXPRSXP && LENGTH(xp) > 0) { int bi = 0; while (bi < LENGTH(xp)) { SEXP pxp = VECTOR_ELT(xp, bi); Rerror = 0; #ifdef RSERV_DEBUG printf("Calling R_tryEval for expression %d [type=%d] ...\n", bi+1, TYPEOF(pxp)); #endif R_tryEval(pxp, R_GlobalEnv, &Rerror); bi++; #ifdef RSERV_DEBUG printf("Expression %d, error code: %d\n", bi, Rerror); if (Rerror) printf(">> early error, aborting further evaluations\n"); #endif if (Rerror) break; } } else { Rerror = 0; R_tryEval(xp, R_GlobalEnv, &Rerror); } UNPROTECT(1); } return; } #define sendRespData(A, C, L, D) srv->send_resp(A, C, L, D) #define sendResp(A,C) srv->send_resp(A, C, 0, 0) struct sockaddr_in session_peer_sa; SOCKET session_socket; unsigned char session_key[32]; /* detach session and setup everything such that in can be resumed at some point */ int detach_session(args_t *arg) { SAIN ssa; SOCKET s = arg->s; server_t *srv = arg->srv; int port = 32768; SOCKET ss = FCF("open socket",socket(AF_INET,SOCK_STREAM,0)); int reuse = 1; /* enable socket address reusage */ socklen_t sl = sizeof(session_peer_sa); struct dsresp { int pt1; int port; int pt2; unsigned char key[32]; } dsr; if (getpeername(s, (SA*) &session_peer_sa, &sl)) { sendResp(arg, SET_STAT(RESP_ERR,ERR_detach_failed)); return -1; } setsockopt(ss,SOL_SOCKET,SO_REUSEADDR,(const char*)&reuse,sizeof(reuse)); while ((port = (((int) random()) & 0x7fff)+32768)>65000) {}; while (bind(ss,build_sin(&ssa,0,port),sizeof(ssa))) { if (errno!=EADDRINUSE) { #ifdef RSERV_DEBUG printf("session: error in bind other than EADDRINUSE (0x%x)", errno); #endif closesocket(ss); sendResp(arg, SET_STAT(RESP_ERR,ERR_detach_failed)); return -1; } port++; if (port>65530) { #ifdef RSERV_DEBUG printf("session: can't find available prot to listed on.\n"); #endif closesocket(ss); sendResp(arg, SET_STAT(RESP_ERR,ERR_detach_failed)); return -1; } } if (listen(ss,LISTENQ)) { #ifdef RSERV_DEBUG printf("session: cannot listen.\n"); #endif closesocket(ss); sendResp(arg, SET_STAT(RESP_ERR,ERR_detach_failed)); return -1; } { int i=0; while (i<32) session_key[i++]=(unsigned char) rand(); } #ifdef RSERV_DEBUG printf("session: listening on port %d\n", port); #endif dsr.pt1 = itop(SET_PAR(DT_INT,sizeof(int))); dsr.port = itop(port); dsr.pt2 = itop(SET_PAR(DT_BYTESTREAM,32)); memcpy(dsr.key, session_key, 32); sendRespData(arg, RESP_OK, 3*sizeof(int)+32, &dsr); closesocket(s); #ifdef RSERV_DEBUG printf("session: detached, closing connection.\n"); #endif session_socket = ss; return 0; } /* static char *sres_id = "RsS1 \r\n\r\n"; */ /* resume detached session. return the new socket after resume is complete, but don't send the response message */ SOCKET resume_session(void) { SOCKET s=-1; SAIN lsa; socklen_t al=sizeof(lsa); char clk[32]; #ifdef RSERV_DEBUG printf("session: resuming session, waiting for connections.\n"); #endif while ((s=accept(session_socket, (SA*)&lsa,&al))>1) { if (lsa.sin_addr.s_addr != session_peer_sa.sin_addr.s_addr) { #ifdef RSERV_DEBUG printf("session: different IP, rejecting\n"); #endif closesocket(s); } else { int n=0; if ((n=recv(s, (char*)clk, 32, 0)) != 32) { #ifdef RSERV_DEBUG printf("session: expected 32, got %d = closing\n", n); #endif closesocket(s); } else if (memcmp(clk, session_key, 32)) { #ifdef RSERV_DEBUG printf("session: wrong key, closing\n"); #endif closesocket(s); } else { #ifdef RSERV_DEBUG printf("session: accepted\n"); #endif return s; } } } return -1; } #ifdef WIN32 # include #endif typedef struct child_process { pid_t pid; struct child_process *prev, *next; } child_process_t; child_process_t *children; /* handling of the password file - we emulate stdio API but allow both file and buffer back-ends transparently */ typedef struct pwdf { FILE *f; char *ptr; } pwdf_t; static pwdf_t *pwd_open(void) { pwdf_t *f = malloc(sizeof(pwdf_t)); if (!f) return 0; if (cache_pwd && pwd_cache) { f->ptr = pwd_cache; f->f = 0; return f; } f->f = fopen(pwdfile, "r"); if (!f->f) { free(f); return 0; } return f; } static char *pwd_gets(char *str, int n, pwdf_t *f) { char *c, *s = str; if (f->f) return fgets(str, n, f->f); c = f->ptr; while (*c == '\r' || *c == '\n') c++; /* skip empty lines */ while (*c && *c != '\r' && *c != '\n' && (--n > 0)) *(s++) = *(c++); if (*c == '\n' || *c == '\r') { *c = 0; c++; } f->ptr = c; *s = 0; return str; } static int pwd_eof(pwdf_t *f) { if (f->f) return feof(f->f); return (f->ptr[0]) ? 0 : 1; } static void pwd_close(pwdf_t *f) { if (f->f) fclose(f->f); free(f); } typedef struct qap_runtime qap_runtime_t; int OCAP_iteration(qap_runtime_t *rt, struct phdr *oob_hdr); static int new_msg_id(args_t *args) { return use_msg_id ? (int) random() : 0; } static char dump_buf[32768]; /* scratch buffer that is static so mem alloc doesn't fail */ static int send_oob_sexp(int cmd, SEXP exp) { int send_res = -1; if (!self_args) Rf_error("OOB commands can only be used from code evaluated inside an Rserve client instance"); if (!enable_oob) Rf_error("OOB command is disallowed by the current Rserve configuration - use 'oob enable' to allow its use"); PROTECT(exp); /* ulog("send_oob_sexp, cmd=0x%x, len=%d", cmd, LENGTH(exp)); */ { args_t *a = self_args; server_t *srv = a->srv; char *sendhead = 0, *sendbuf; rlen_t rs; if (!a || a->s == -1) /* if there is no connection, bail out right away */ return -1; /* check buffer size vs REXP size to avoid dangerous overflows todo: resize the buffer as necessary */ rs = QAP_getStorageSize(exp); if (rs < 0) Rf_error("Unable to encode R object"); /* FIXME: add a 4k security margin - it should no longer be needed, originally the space was grown proportionally to account for a bug, but that bug has been fixed. */ rs += 4096; #ifdef RSERV_DEBUG printf("result storage size = %ld bytes\n",(long)rs); #endif sendbuf = (char*) malloc(rs); if (!sendbuf) Rf_error("Unable to allocate large enough buffer to send the object"); else { /* first we have 4 bytes of a header saying this is an encoded SEXP, then comes the SEXP */ char *sxh = sendbuf + 8; char *tail = (char*)QAP_storeSEXP((unsigned int*)sxh, exp, rs); /* set type to DT_SEXP and correct length */ if ((tail - sxh) > 0xfffff0) { /* we must use the "long" format */ rlen_t ll = tail - sxh; ((unsigned int*)sendbuf)[0] = itop(SET_PAR(DT_SEXP | DT_LARGE, ll & 0xffffff)); ((unsigned int*)sendbuf)[1] = itop(ll >> 24); sendhead = sendbuf; } else { sendhead = sendbuf + 4; ((unsigned int*)sendbuf)[1] = itop(SET_PAR(DT_SEXP,tail - sxh)); } #ifdef RSERV_DEBUG printf("stored SEXP; length=%ld (incl. DT_SEXP header)\n",(long) (tail - sendhead)); #endif a->msg_id = new_msg_id(a); if (compute_subprocess) cmd |= (compute_subprocess << 8); send_res = sendRespData(a, cmd, tail - sendhead, sendhead); #ifdef OOB_ULOG ulog("OOB sent (cmd=0x%x, %d bytes, result=%d)", cmd, tail-sendhead, send_res); #endif free(sendbuf); } } UNPROTECT(1); return (send_res >= 0) ? 1 : send_res; } SEXP Rserve_ulog(SEXP sWhat) { if (TYPEOF(sWhat) == STRSXP && LENGTH(sWhat)) ulog(CHAR(STRING_ELT(sWhat, 0))); return sWhat; } SEXP Rserve_oobSend(SEXP exp, SEXP code) { int oob_code = asInteger(code); return ScalarLogical(send_oob_sexp(OOB_USR_CODE(oob_code) | OOB_SEND, exp) == 1 ? TRUE : FALSE); } /* internal version that can return NULL instead of throwing an error */ static SEXP Rserve_oobMsg_(SEXP exp, SEXP code, int throw_error) { struct phdr ph; int oob_code = asInteger(code), n; int res = send_oob_sexp(OOB_USR_CODE(oob_code) | OOB_MSG, exp); args_t *a = self_args; /* send_oob_sexp has checked this already so it's ok */ server_t *srv = a->srv; int msg_id = a->msg_id; /* remember the msg id since it may get clobered */ if (res != 1) { if (throw_error) Rf_error("Sending OOB_MSG failed"); else return 0; } /* FIXME: this is very similar (but not the same) as the read loop in Rserve itself - we should modularize this and re-use the parts */ #ifdef RSERV_DEBUG printf("OOB-msg (%x) - waiting for response packet\n", oob_code); #endif if (a->srv->flags & SRV_QAP_OC) { /* OCAP -- allow nested iteration */ while ((n = OCAP_iteration(0, &ph)) == 1) {} /* run OCAP until we get our response or an error */ n = (n == 2) ? sizeof(ph) : -1; } else n = srv->recv(a, (char*)&ph, sizeof(ph)); if (n == sizeof(ph)) { size_t plen = 0, i; #ifdef RSERV_DEBUG printf("\nOOB response header read result: %d\n", n); if (n > 0) printDump(&ph, n); #endif ph.len = ptoi(ph.len); ph.cmd = ptoi(ph.cmd); #ifdef __LP64__ ph.res = ptoi(ph.res); plen = (unsigned int) ph.len; plen |= (((size_t) (unsigned int) ph.res) << 32); #else plen = ph.len; #endif a->msg_id = ph.msg_id; #ifdef RSERV_DEBUG if (io_log) { struct timeval tv; snprintf(io_log_fn, sizeof(io_log_fn), "/tmp/Rserve-io-%d.log", getpid()); FILE *f = fopen(io_log_fn, "a"); if (f) { double ts = 0; if (!gettimeofday(&tv, 0)) ts = ((double) tv.tv_sec) + ((double) tv.tv_usec) / 1000000.0; if (first_ts < 1.0) first_ts = ts; fprintf(f, "%.3f [+%4.3f] SRV <-- CLI [OOB recv] (%x, %ld bytes)\n HEAD ", ts, ts - first_ts, ph.cmd, (long) plen); fprintDump(f, &ph, sizeof(ph)); fclose(f); } } #endif if (plen) { char *orb = (char*) malloc(plen + 8); if (!orb) { /* error, but we have to pull the while packet as to not kill the queue */ size_t chk = (sizeof(dump_buf) < max_sio_chunk) ? sizeof(dump_buf) : max_sio_chunk; i = plen; while((n = srv->recv(a, dump_buf, (i < chk) ? i : chk))) { if (n > 0) i -= n; if (i < 1 || n < 1) break; } if (i > 0) { /* something went wrong */ /* FIXME: is this ok? do we need a common close function to shutdown TLS etc.? */ closesocket(a->s); a->s = -1; if (!throw_error) return 0; Rf_error("cannot allocate buffer for OOB msg result + read error, aborting connection"); } /* packet discarded so connection is ok, but it is still a mem alloc error */ if (!throw_error) return 0; Rf_error("cannot allocate buffer for OOB msg result"); } /* ok, got the buffer, fill it */ i = 0; while ((n = srv->recv(a, orb + i, (plen - i > max_sio_chunk) ? max_sio_chunk : (plen - i)))) { if (n > 0) i += n; if (i >= plen || n < 1) break; } #ifdef RSERV_DEBUG if (io_log) { FILE *f = fopen(io_log_fn, "a"); if (f) { fprintf(f, " BODY "); if (i) fprintDump(f, orb, i); else fprintf(f, "\n"); fclose(f); } } #endif if (i < plen) { /* uh, oh, the stream is corrupted */ closesocket(a->s); a->s = -1; ulog("ERROR: read error while reading OOB msg respose, aborting connection"); free(orb); if (!throw_error) return 0; Rf_error("read error while reading OOB msg respose, aborting connection"); } a->msg_id = msg_id; /* restore msg_id */ ulog("OOBmsg response received"); /* parse the payload - we ony support SEXPs though (and DT_STRING) */ { unsigned int *hi = (unsigned int*) orb, pt = PAR_TYPE(ptoi(hi[0])); size_t psz = PAR_LEN(ptoi(hi[0])); SEXP res; if (pt & DT_LARGE) { psz |= hi[1] << 24; pt ^= DT_LARGE; hi++; } if (pt == DT_STRING) { const char *s = (const char *) ++hi, *se = s + psz; while (se-- > s) if (!*se) break; if (se == s && *s) { free(orb); if (!throw_error) return 0; Rf_error("unterminated string in OOB msg response"); } res = mkString(s); free(orb); return res; } if (pt != DT_SEXP) { free(orb); if (!throw_error) return 0; Rf_error("unsupported parameter type %d in OOB msg response", PAR_TYPE(ptoi(hi[0]))); } hi++; /* FIXME: we should use R allocation for orb since it will leak if there is an error in any allocation in decoding --- but we can't do the before reading since it would fail to read the stream in case of an error - so we're stuck a bit ... */ res = QAP_decode(&hi); free(orb); return res; } } a->msg_id = msg_id; /* restore msg_id */ } else { closesocket(a->s); a->s = -1; ulog("ERROR: read error in OOB msg header"); if (!throw_error) return 0; Rf_error("read error im OOB msg header"); } return R_NilValue; } /* visible API version */ SEXP Rserve_oobMsg(SEXP exp, SEXP code) { return Rserve_oobMsg_(exp, code, 1); } /* server forking For a regular forked server this is simply fork(), but for pre-forked servers ... ? */ int RS_fork(args_t *arg) { #ifdef unix return (arg->srv && arg->srv->fork) ? arg->srv->fork(arg) : fork(); #else return -1; #endif } static void restore_signal_handlers(void); /* forward decl */ /* return 0 if the child was prepared. Returns the result of fork() is forked and this is the parent */ int Rserve_prepare_child(args_t *args) { #ifdef FORKED long rseed = random(); rseed ^= time(0); if (is_child) return 0; /* this is a no-op if we are already a child FIXME: thould this be an error ? */ if ((lastChild = RS_fork(args)) != 0) { /* parent/master part */ int forkErrno = errno; //grab errno close to source before it can be changed by other failures /* close the connection socket - the child has it already */ closesocket(args->s); if (lastChild == -1) RSEprintf("WARNING: fork() failed in Rserve_prepare_child(): %s\n",strerror(forkErrno)); return lastChild; } /* child part */ restore_signal_handlers(); /* the handlers handle server shutdown so not needed in the child */ if (main_argv && tag_argv && strlen(main_argv[0]) >= 8) strcpy(main_argv[0] + strlen(main_argv[0]) - 8, "/RsrvCHx"); is_child = 1; srandom(rseed); parentPID = getppid(); close_all_srv_sockets(); /* close all server sockets - this includes arg->ss */ ulog("INFO: new child process %d (parent %d)", (int) getpid(), (int) parentPID); #ifdef CAN_TCP_NODELAY { int opt = 1; setsockopt(args->s, IPPROTO_TCP, TCP_NODELAY, (const char*) &opt, sizeof(opt)); } #endif performConfig(SU_CLIENT); #endif authkey_req = 0; /* reset auth count for non-forked servers */ self_args = args; return 0; } /* text protocol (exposed by WS) */ void Rserve_text_connected(void *thp) { args_t *arg = (args_t*) thp; server_t *srv = arg->srv; int bl = 1024*1024, bp = 0, n; ParseStatus stat; char *buf = (char*) malloc(bl--); if (!buf) { RSEprintf("ERROR: cannot allocate buffer\n"); if (arg->s != -1) closesocket(arg->s); free(arg); return; } self_args = arg; snprintf(buf, bl, "OK\n"); srv->send(arg, buf, strlen(buf)); while ((n = srv->recv(arg, buf + bp, bl - bp)) > 0) { bp += n; if (!(arg->flags & F_INFRAME)) { /* end of frame */ SEXP xp; int parts; buf[bp] = 0; xp = parseString(buf, &parts, &stat); if (stat != PARSE_OK) { snprintf(buf, bl, "ERROR: Parse error: %s\n", getParseName(stat)); srv->send(arg, buf, strlen(buf)); } else { SEXP exp = R_NilValue; int err = 0; PROTECT(xp); if (TYPEOF(xp) == EXPRSXP && LENGTH(xp) > 0) { int bi = 0; while (bi < LENGTH(xp)) { SEXP pxp = VECTOR_ELT(xp, bi); #ifdef RSERV_DEBUG printf("Calling R_tryEval for expression %d [type=%d] ...\n", bi + 1, TYPEOF(pxp)); #endif exp = R_tryEval(pxp, R_GlobalEnv, &err); bi++; #ifdef RSERV_DEBUG printf("Expression %d, error code: %d\n", bi, err); if (err) printf(">> early error, aborting further evaluations\n"); #endif if (err) break; } } else exp = R_tryEval(xp, R_GlobalEnv, &err); if (!err && TYPEOF(exp) != STRSXP) exp = R_tryEval(lang2(install("as.character"), exp), R_GlobalEnv, &err); if (!err && TYPEOF(exp) == STRSXP) { int i = 0, l = LENGTH(exp); size_t tl = 0; char *sb = buf; while (i < l) { tl += strlen(Rf_translateCharUTF8(STRING_ELT(exp, i))) + 1; i++; } if (tl > bl) { sb = (char*) malloc(tl); if (!sb) { RSEprintf("ERROR: cannot allocate buffer for the result string\n"); snprintf(buf, bl, "ERROR: cannot allocate buffer for the result string\n"); srv->send(arg, buf, strlen(buf)); } } if (sb) { tl = 0; for (i = 0; i < l; i++) { strcpy(sb + tl, Rf_translateCharUTF8(STRING_ELT(exp, i))); tl += strlen(sb + tl); if (i < l - 1) sb[tl++] = '\n'; } srv->send(arg, sb, tl); if (sb != buf) free(sb); } } else { if (err) snprintf(buf, bl, "ERROR: evaluation error %d\n", err); else snprintf(buf, bl, "ERROR: result cannot be coerced into character\n"); srv->send(arg, buf, strlen(buf)); } } bp = 0; } else { /* continuation of a frame */ if (bp >= bl) { RSEprintf("WARNING: frame exceeds max size, ignoring\n"); while ((arg->flags & F_INFRAME) && srv->recv(arg, buf, bl) > 0) ; bp = 0; } } } if (arg->s != -1) closesocket(arg->s); free(arg); } static char auth_buf[4096]; static const char *hexc = "0123456789abcdef"; static const char *sec_salt = "##secure"; /* special object to denote secure login */ static int auth_user(const char *usr, const char *pwd, const char *salt) { int authed = 0; unsigned char md5h[16]; unsigned char sh1h[20]; char md5_pwd[34]; /* MD5 hex representation of the password */ char sha1_pwd[42]; /* SHA1 hex representation of the password */ md5hash(pwd, strlen(pwd), md5h); sha1hash(pwd, strlen(pwd), sh1h); { /* create hex-encoded versions of the password hashes */ char *mp = md5_pwd; int k; for (k = 0; k < 16; k++) { *(mp++) = hexc[md5h[k] >> 4]; *(mp++) = hexc[md5h[k] & 15]; } *mp = 0; mp = sha1_pwd; for (k = 0; k < 20; k++) { *(mp++) = hexc[sh1h[k] >> 4]; *(mp++) = hexc[sh1h[k] & 15]; } *mp = 0; } authed = 1; #ifdef RSERV_DEBUG printf("Authentication attempt (login='%s', pwd='%s', pwdfile='%s')\n", usr, pwd, pwdfile); #endif if (auth_fn) { SEXP res, authv = PROTECT(allocVector(STRSXP, 2)); int eres = 0; SET_STRING_ELT(authv, 0, mkChar(usr)); SET_STRING_ELT(authv, 1, mkChar(pwd)); res = R_tryEval(lang2(install(auth_fn), authv), R_GlobalEnv, &eres); UNPROTECT(1); return (res && TYPEOF(res) == LGLSXP && LENGTH(res) == 1 && LOGICAL(res)[0] == TRUE); } if (pwdfile) { pwdf_t *pwf; int ctrl_flag = 0, u_uid = 0, u_gid = 0; authed = 0; /* if pwdfile exists, default is access denied */ /* we abuse variables of other commands since we are the first command ever used so we can trash them */ pwf = pwd_open(); if (pwf) { auth_buf[sizeof(auth_buf) - 1] = 0; while(!pwd_eof(pwf)) if (pwd_gets(auth_buf, sizeof(auth_buf) - 1, pwf)) { char *login = auth_buf, *c1 = auth_buf, *c2, *l_uid = 0, *l_gid = 0; /* and are valid separators */ while(*c1 && *c1 != ' ' && *c1 != '\t') { /* [@]username[/uid[,gid]] {$MD5/SHA1hash|password} */ if (*c1 == '/' && !l_uid) { *c1 = 0; l_uid = c1 + 1; } else if (*c1 == ',' && l_uid) { *c1 = 0; if (!l_gid) l_gid = c1 + 1; } c1++; } if (l_uid) u_uid = satoi(l_uid); if (l_gid) u_gid = satoi(l_gid); if (l_uid && !l_gid) u_gid = u_uid; if (*c1) { *c1 = 0; c1++; while(*c1 == ' ' || *c1 == '\t') c1++; /* skip leading blanks */ } c2 = c1; while(*c2) if (*c2 == '\r' || *c2=='\n') *c2 = 0; else c2++; ctrl_flag = 0; if (*login == '#') continue; /* skip comment lines */ if (*login == '@') { /* only users with @ prefix can use control commands */ login++; ctrl_flag = 1; } if (*login == '*') { /* general authentication - useful to set control access but leave client access open */ authed = 1; #ifdef RSERV_DEBUG printf("Public authentication enabled (found * entry), allowing login without checking.\n"); #endif break; } if (!strcmp(login, usr)) { /* login found */ #ifdef RSERV_DEBUG printf("Found login '%s', checking password.\n", usr); printf(" - stored pwd = '%s', md5='%s', sha1='%s'\n", c1, md5_pwd, sha1_pwd); #endif if ((usePlain || salt == sec_salt) && ((*c1 == '$' && strlen(c1) == 33 && !strcmp(c1 + 1, md5_pwd)) || (*c1 == '$' && strlen(c1) == 41 && !strcmp(c1 + 1, sha1_pwd)) || ((*c1 != '$' || (strlen(c1) != 33 && strlen(c1) !=41)) && !strcmp(c1, pwd)))) { authed = 1; #ifdef RSERV_DEBUG printf(" - %s password matches.\n", (*c1 == '$' && strlen(c1) == 33) ? "MD5" : ((*c1 == '$' && strlen(c1) == 41) ? "SHA1" : "plain")); #endif } else if (salt) { #ifdef HAS_CRYPT /* there is a bug in the Ubuntu 22.04+ libcrypt which incorrectly uses salt beyond the two bytes so to avoid it we use a copy and add NUL */ char salt3[3] = { salt[0], salt[1], 0 }; c2 = crypt(c1, salt3); #ifdef RSERV_DEBUG printf(" - checking crypted '%s' vs '%s'\n", c2, pwd); #endif if (!strcmp(c2, pwd)) authed = 1; #endif } } if (authed) break; } /* if fgets */ pwd_close(pwf); if (authed) { #ifdef unix if (auto_uid && !u_uid && !default_uid) { authed = 0; #ifdef DEBUG_RSERV printf(" - no uid in the user entry and no default.uid, refusing authentication\n"); #endif } else { if (auto_uid) prepare_set_user(u_uid ? u_uid : default_uid, auto_gid ? (u_gid ? u_gid : default_gid) : 0); chkres1("setgid", auto_gid && setgid(u_gid ? u_gid : default_gid)); chkres1("setuid", auto_uid && setuid(u_uid ? u_uid : default_uid)); } #endif } } /* if (pwf) */ } #ifdef DEBUG_RSERV printf(" - authentication %s\n", authed ? "succeeded" : "failed"); #endif return authed; } #ifdef HAVE_RSA #ifndef OPENSSL_SUPPRESS_DEPRECATED #define OPENSSL_SUPPRESS_DEPRECATED 1 #endif #include #include #include static RSA *rsa_srv_key; static char rsa_buf[32768]; /* from base64.c */ int base64decode(const char *src, void *dst, int max_len); static int rsa_load_key(const char *buf) { int n; const char *c = buf; const unsigned char *ptr; while (1) { while (*c == ' ' || *c == '\t') c++; if (*c == '-') { /* header line */ while (*c && *c != '\n' && *c != '\r') c++; while (*c == '\n' || *c == '\r') c++; continue; } if (*c == '\n' || *c == '\r') while (*c == '\n' || *c == '\r') c++; else break; } if (!*c) return -1; n = base64decode(c, rsa_buf, sizeof(rsa_buf)); if (n < 1) return -1; ptr = (const unsigned char*) rsa_buf; rsa_srv_key = d2i_RSAPrivateKey(NULL, &ptr, n); if (!rsa_srv_key) return -1; return 0; } /* OpenSSL 1.1 has deprecated RSA_generate_key() without providing an alternative, so we a have to re-implement it ourselves (for no good reason) ... */ static RSA *RSA_generate_key0(int bits, unsigned long expon) { #if OPENSSL_VERSION_NUMBER < 0x10100000L return RSA_generate_key(bits, expon, 0, 0); #else /* How to make simple things really complicated ... */ RSA *rsa = RSA_new(); if (!rsa) { Rf_warning("cannot allocate RSA key: %s", ERR_error_string(ERR_get_error(), NULL)); return 0; } { BIGNUM *e = BN_new(); if (!e) { RSA_free(rsa); Rf_warning("cannot allocate exponent: %s", ERR_error_string(ERR_get_error(), NULL)); return 0; } BN_set_word(e, expon); if (RSA_generate_key_ex(rsa, bits, e, NULL) <= 0) { BN_free(e); RSA_free(rsa); Rf_warning("cannot generate key: %s", ERR_error_string(ERR_get_error(), NULL)); return 0; } BN_free(e); } return rsa; #endif } static int rsa_gen_resp(char **dst) { unsigned char *kb; unsigned char *pt; int kl; if (!rsa_srv_key) { #ifdef RSERV_DEBUG printf("rsa_gen_resp: generating RSA key\n"); #endif rsa_srv_key = RSA_generate_key0(4096, 65537); #ifdef RSERV_DEBUG printf(" - done\n"); #endif } if (!rsa_srv_key || RAND_bytes((unsigned char*) authkey, sizeof(authkey)) != 1) return 0; kb = calloc(65536, 1); if (!kb) return 0; kb[0] = SRV_KEY_LEN & 0xff; kb[1] = (SRV_KEY_LEN >> 8) & 0xff; memcpy(kb + 4, authkey, SRV_KEY_LEN); pt = kb + SRV_KEY_LEN + 8; kl = i2d_RSAPublicKey(rsa_srv_key, &pt); kb[SRV_KEY_LEN + 4] = kl & 0xff; kb[SRV_KEY_LEN + 5] = (kl >> 8) & 0xff; *dst = (char*) kb; return SRV_KEY_LEN + kl + 8; } static int rsa_decode(char *dst, const char *src, int len) { int dec = 0, blk = RSA_size(rsa_srv_key); while (len > 0) { int db = (len > blk) ? blk : len; int n = RSA_private_decrypt(db, (unsigned char*)src, (unsigned char*) dst, rsa_srv_key, RSA_PKCS1_OAEP_PADDING); if (n <= 0) { #ifdef RSERV_DEBUG printf("rsa_decode (dec=%d, len=%d, db=%d) failed: %s\n", dec, len, db, ERR_error_string(ERR_get_error(), 0)); #endif return -1; } dst += n; dec += n; src += db; len -= db; } return dec; } /* the client encodes, so we don't use it for now static int rsa_encode(char *dst, char *src, int len) { return RSA_public_encrypt(len, (unsigned char*)src, (unsigned char*) dst, rsa_srv_key, RSA_PKCS1_OAEP_PADDING); } */ #endif #ifdef unix #include #include /* this should always be defined by POSIX but some broken system reportedly don't define it */ #ifndef PATH_MAX #define PATH_MAX 512 #endif static void rm_rf(const char *what) { struct stat st; if (!lstat(what, &st)) { chmod(what, st.st_mode | ((st.st_mode & S_IFDIR) ? S_IRWXU : S_IWUSR)); if (st.st_mode & S_IFDIR) { /* dirs need to be deleted recursively */ DIR *dir = opendir(what); char path[PATH_MAX]; if (dir) { struct dirent *d; while ((d = readdir(dir))) { if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; snprintf(path, sizeof(path), "%s/%s", what, d->d_name); rm_rf(path); } closedir(dir); } rmdir(what); } else unlink(what); } } #endif static char *child_workdir; char *get_workdir(void) { return child_workdir; } static void setup_workdir(void) { #ifdef unix if (workdir) { if (chdir(workdir) && mkdir(workdir, wdt_mode)) {} /* we override umask for the top-level since it is shared */ if (chmod(workdir, wdt_mode)) {} wdname[511]=0; snprintf(wdname, 511, "%s/conn%d", workdir, (int)getpid()); rm_rf(wdname); mkdir(wdname, wd_mode); /* we don't override umask for the individual ones -- should we? */ if (chdir(wdname)) {} child_workdir = strdup(wdname); } #endif } void Rserve_cleanup(void) { /* run .Rserve.done() if present */ SEXP fun, fsym = install(".Rserve.done"); fun = findVarInFrame(R_GlobalEnv, fsym); if (Rf_isFunction(fun)) { int Rerror = 0; #ifdef unix if (child_workdir && chdir(child_workdir)) {} /* guarantee that we are running in the workign directory */ #endif R_tryEval(lang1(fsym), R_GlobalEnv, &Rerror); } #ifdef unix if (child_workdir) { if (workdir && chdir(workdir)) {} /* change to the level up */ if (wipe_workdir) rm_rf(child_workdir); else rmdir(wdname); } #endif ulog("INFO: closing session"); } /*---- this is an attempt to factor out the OCAP mode into a minimal set of code that is not shared with other protocols to make it more safe and re-entrant. ----*/ struct qap_runtime { struct args *args; /* input args */ char *buf; /* send/recv buffer */ size_t buf_size; /* size of the buffer */ int level; /* re-entrance level */ }; static qap_runtime_t *current_runtime; qap_runtime_t *get_qap_runtime(void) { return current_runtime; } /* NOTE: the runtime becomes the owner of args! */ static qap_runtime_t *new_qap_runtime(struct args *args) { qap_runtime_t *n = (qap_runtime_t*) malloc(sizeof(qap_runtime_t)); if (!n) return n; n->args = args; n->level = 0; n->buf_size = 8*1024*1024; n->buf = (char*) malloc(n->buf_size); if (!n->buf) { free(n); return 0; } return n; } static void free_qap_runtime(qap_runtime_t *rt) { if (rt) { if (rt->buf) { free(rt->buf); rt->buf = 0; } if (rt->args) { free(rt->args); rt->args = 0; } if (rt == current_runtime) current_runtime = 0; free(rt); } } #ifdef R_INTERFACE_PTRS /* -- console buffering -- */ typedef struct { int pos; const char *oob; char buf[8192]; } con_buf_t; con_buf_t con_out = { 0, "console.out" }, con_err = { 0, "console.err" }; static void send_oob_str(const char *msg, const char *what, int len) { int has_ctx = oob_context_prefix ? 1 : 0; SEXP s = PROTECT(allocVector(VECSXP, 2 + has_ctx)); SET_VECTOR_ELT(s, 0, mkString(msg)); if (has_ctx) SET_VECTOR_ELT(s, 1, Rserve_get_context()); SET_VECTOR_ELT(s, 1 + has_ctx, ScalarString(Rf_mkCharLenCE(what, len, CE_UTF8))); UNPROTECT(1); send_oob_sexp(OOB_SEND, s); } static void con_flush_output(con_buf_t *cb) { if (cb->pos) send_oob_str(cb->oob, cb->buf, cb->pos); cb->pos = 0; } static void con_add_output(con_buf_t *cb, const char *what, int len) { if (len > sizeof(cb->buf)) { /* it's too big to fit anyway */ con_flush_output(cb); send_oob_str(cb->oob, what, len); return; } if (cb->pos + len > sizeof(cb->buf)) con_flush_output(cb); memcpy(cb->buf + cb->pos, what, len); cb->pos += len; /* is there any newline? if so, flush it */ if (memchr(what, '\n', len)) con_flush_output(cb); } /* --- actual callbacks --- */ static void RS_Busy(int which) { } static int eof_on_error; static int RS_ReadConsole(const char *prompt, unsigned char *buf, int len, int history) { SEXP args, res; const char *str; size_t slen; int has_ctx = oob_context_prefix ? 1 : 0; if (!read_console_enabled) Rf_error("direct console input is disabled"); con_flush_output(&con_out); con_flush_output(&con_err); args = PROTECT(allocVector(VECSXP, 2 + has_ctx)); SET_VECTOR_ELT(args, 0, mkString("console.in")); if (has_ctx) SET_VECTOR_ELT(args, 1, Rserve_get_context()); SET_VECTOR_ELT(args, 1 + has_ctx, mkString(prompt)); res = Rserve_oobMsg_(args, ScalarInteger(0), 0); UNPROTECT(1); /* args */ if (!res) { /* in order to try to break infinite loops we try both error and EOF since each of them causes a different infinite loop. EOF will cause an infinite loop for things like readLines() while error will cause an infinite loop in browser() */ eof_on_error = !eof_on_error; if (eof_on_error) return -1; Rf_error("console.in OOB message failed"); } if (TYPEOF(res) != STRSXP) Rf_error("invalid console input from the client - expecting a string"); if (LENGTH(res) < 1) return 0; str = CHAR(STRING_ELT(res, 0)); /* FIXME: should we buffer? */ if ((slen = strlen(str)) > len - 2) Rf_error("input from the client is too big (console can only read up to %d bytes)", len); if (!slen) return 0; memcpy(buf, str, slen + 1); /* R-exts suggests making sure that the string ends with "\n\0" */ if (slen && buf[slen - 1] != '\n') { buf[slen++] = '\n'; buf[slen] = 0; } return slen; } static void RS_ResetConsole(void) { SEXP s = PROTECT(allocVector(VECSXP, 2)); con_flush_output(&con_out); con_flush_output(&con_err); SET_VECTOR_ELT(s, 0, mkString("console.reset")); SET_VECTOR_ELT(s, 1, Rserve_get_context()); UNPROTECT(1); send_oob_sexp(OOB_SEND, s); } static void RS_FlushConsole(void) { con_flush_output(&con_out); con_flush_output(&con_err); } static void RS_ClearerrConsole(void) { con_flush_output(&con_out); con_flush_output(&con_err); } static void RS_WriteConsoleEx(const char *buf, int len, int oType) { con_flush_output(oType ? (&con_out) : (&con_err)); /* flush the other console type */ con_add_output(oType ? (&con_err) : (&con_out), buf, len); } static void RS_ShowMessage(const char *buf) { int has_ctx = oob_context_prefix ? 1 : 0; SEXP s = PROTECT(allocVector(VECSXP, 2 + has_ctx)); SET_VECTOR_ELT(s, 0, mkString("console.msg")); if (has_ctx) SET_VECTOR_ELT(s, 1, Rserve_get_context()); SET_VECTOR_ELT(s, 1 + has_ctx, ScalarString(Rf_mkCharCE(buf, CE_UTF8))); UNPROTECT(1); send_oob_sexp(OOB_SEND, s); } #endif SEXP Rserve_forward_stdio(void) { ulog("Rserve_forward_stdio: requested"); if (!enable_oob) Rf_error("I/O forwarding can only be used when OOB is enabled"); if (std_fw_fd) { ulog("Rserve_forward_stdio: already enabled"); return ScalarLogical(FALSE); } if (!(std_fw_fd = ioc_setup())) { ulog("WARNING: failed to setup stdio forwarding in Rserve_forward_stdio()"); Rf_error("failed to setup stdio forwarding"); } ulog("Rserve_forward_stdio: enabled, fd=%d", std_fw_fd); #ifdef unix /* also register an input handler, because calls like system/sleep will block the OCAP loop */ addInputHandler(R_InputHandlers, std_fw_fd, &std_fw_input_handler, 9); #endif return ScalarLogical(1); } /* return 0 to proceed or 1 to fail */ int check_tls_client(int verify, const char *cn) { int cnl = cn ? strlen(cn) : 0, failed = 0; /* if client cert is not required, always succeed */ if (!tls_client_require) return 0; /* if it is required, but is not valid, direct fail */ if (verify != 1) { ulog("WARNING: tls.client check enabled, but no valid certificate, rejecting"); return 1; } /* valid cert, let's see if we have specific match requirements */ if (tls_client_match) { if (cn) { const char *c = strstr(tls_client_match, cn); if (c && (c == tls_client_match || c[-1] == ',') && (c[cnl] == ',' || !c[cnl])) { ulog("INFO: TLS client '%s' matched, allowing", cn); return 0; } } ulog("INFO: TLS client '%s' fails match rule", cn ? cn : ""); failed++; } if (tls_client_prefix) { if (cn && !strncmp(cn, tls_client_prefix, strlen(tls_client_prefix))) { ulog("INFO: TLS client '%s' prefix match, allowing", cn); return 0; } ulog("INFO: TLS client '%s' fails prefix rule", cn ? cn : ""); failed++; } if (tls_client_suffix) { if (cn && cnl >= strlen(tls_client_suffix) && !strcmp(cn + cnl - strlen(tls_client_suffix), tls_client_suffix)) { ulog("INFO: TLS client '%s' suffix match, allowing", cn); return 0; } ulog("INFO: TLS client '%s' fails suffix rule", cn ? cn : ""); failed++; } if (!failed) ulog("INFO: TLS client '%s' has valid certificate, no rules to apply, allowing"); return failed ? 1 : 0; } void Rserve_OCAP_connected(void *thp) { struct args *args = (struct args*)thp; server_t *srv = args->srv; int fres = Rserve_prepare_child(args); qap_runtime_t *rt; int uses_tls = 0; if (fres != 0) { /* not a child (error or parent) */ if (args->s != -1) closesocket(args->s); free(args); return; } /* this should never happen, but just in case ... */ if (!(args->srv->flags & SRV_QAP_OC)) { RSEprintf("FATAL: OCAP is disabled yet we are in OCAPconnected"); if (args->s != -1) closesocket(args->s); free(args); return; } setup_workdir(); /* setup TLS if desired */ if ((args->srv->flags & SRV_TLS) && shared_tls(0)) { char cn[256]; add_tls(args, shared_tls(0), 1); if (check_tls_client(verify_peer_tls(args, cn, 256), cn)) { close_tls(args); if (args->s != -1) closesocket(args->s); free(args); return; } uses_tls = 1; } { /* OCinit */ SOCKET s = args->s; rlen_t rs; int Rerr = 0; SEXP oc; #ifdef RSERV_DEBUG printf("evaluating oc.init()\n"); #endif ulog("OCinit"); #ifdef R_INTERFACE_PTRS if (oob_console) { ptr_R_ShowMessage = RS_ShowMessage; ptr_R_ReadConsole = RS_ReadConsole; ptr_R_WriteConsole = NULL; ptr_R_WriteConsoleEx = RS_WriteConsoleEx; ptr_R_ResetConsole = RS_ResetConsole; ptr_R_FlushConsole = RS_FlushConsole; ptr_R_ClearerrConsole = RS_ClearerrConsole; ptr_R_Busy = RS_Busy; R_Outputfile = NULL; R_Consolefile = NULL; } #endif oob_allowed = 1; oc = R_tryEval(PROTECT(LCONS(install("oc.init"), R_NilValue)), R_GlobalEnv, &Rerr); UNPROTECT(1); ulog("OCinit-result: %s", Rerr ? "FAILED" : "OK"); if (Rerr) { /* cannot get any capabilities, bail out */ #ifdef RSERV_DEBUG printf("ERROR: failed to eval oc.init() - aborting!"); #endif if (uses_tls) close_tls(args); closesocket(s); free(args); return; } current_runtime = rt = new_qap_runtime(args); if (!rt) { ulog("OCAP-ERROR: cannot allocate QAP runtime"); if (uses_tls) close_tls(args); closesocket(s); free(args); return; } /* from now on the run-time takes ownership of args */ args->flags |= F_OUT_BIN; /* in OC everything is binary */ PROTECT(oc); /* enable I/O forwarding only *after* oc.init to make forking easier (no threads to deal with) */ if (forward_std && enable_oob) { if (!(std_fw_fd = ioc_setup())) ulog("WARNING: failed to setup stdio forwarding"); #ifdef unix /* also register an input handler, because calls like system/sleep will block the OCAP loop */ else addInputHandler(R_InputHandlers, std_fw_fd, &std_fw_input_handler, 9); #endif } rs = QAP_getStorageSize(oc); #ifdef RSERV_DEBUG printf("oc.init storage size = %ld bytes\n",(long)rs); #endif if (rs < 0 || rs > rt->buf_size - 64L) { /* cannot encode or is the send buffer too small ? */ unsigned int osz = (rs > 0xffffffff) ? 0xffffffff : rs; osz = itop(osz); #ifdef RSERV_DEBUG if (rs < 0) printf("ERROR: cannot QAP-encode R object\n"); else printf("ERROR: object too big (%ld available, %ld required)\n", (long) rt->buf_size, (long) rs); #endif sendRespData(args, SET_STAT(RESP_ERR, ERR_object_too_big), 4, &osz); if (uses_tls) close_tls(args); free_qap_runtime(rt); closesocket(s); UNPROTECT(1); return; } else { char *sxh = rt->buf + 8, *sendhead = 0; char *tail = (char*)QAP_storeSEXP((unsigned int*)sxh, oc, rs); UNPROTECT(1); /* set type to DT_SEXP and correct length */ if ((tail - sxh) > 0xfffff0) { /* we must use the "long" format */ rlen_t ll = tail - sxh; ((unsigned int*)rt->buf)[0] = itop(SET_PAR(DT_SEXP | DT_LARGE, ll & 0xffffff)); ((unsigned int*)rt->buf)[1] = itop(ll >> 24); sendhead = rt->buf; } else { sendhead = rt->buf + 4; ((unsigned int*)rt->buf)[1] = itop(SET_PAR(DT_SEXP,tail - sxh)); } #ifdef RSERV_DEBUG printf("stored SEXP; length=%ld (incl. DT_SEXP header)\n",(long) (tail - sendhead)); #endif sendRespData(args, CMD_OCinit, tail - sendhead, sendhead); } } /* everything is binary from now on */ args->flags |= F_OUT_BIN; while (OCAP_iteration(rt, 0)) {} /* FIXME: for compute_fd should we defer the cleanup to the compute process? */ Rserve_cleanup(); if (uses_tls) close_tls(args); free_qap_runtime(rt); } static int compute_fd = -1; static pid_t compute_pid = 0; static pid_t compute_ppid = 0; static char *compute_iobuf; static size_t compute_iobuf_len; typedef struct compq { struct compq *next; int len; char content[1]; } compq_t; static compq_t *compute_queue; static void compute_terminated(void) { SEXP q = PROTECT(allocVector(VECSXP, 1)); /* free the remaining queue */ while (compute_queue) { compq_t *nxt = compute_queue->next; free(compute_queue); compute_queue = nxt; } SET_VECTOR_ELT(q, 0, mkString("compute_terminated")); closesocket(compute_fd); compute_fd = -1; if (oob_allowed) /* this should be really always true */ send_oob_sexp(OOB_SEND, q); ulog("compute process connection lost"); UNPROTECT(1); } static int compute_send(void *p0, int p0_len, void *p1, int p1_len) { if (compute_fd == -1) return -1; /* FIXME: we should use the queue in blocking cases .. may need threads? */ if (send(compute_fd, p0, p0_len, 0) != p0_len) { ulog("ERROR: failed to send OCcall to compute process (header [%d bytes] send error)", p0_len); return -1; } if (p1_len && send(compute_fd, p1, p1_len, 0) != p1_len) { ulog("ERROR: failed to send OCcall to compute process (payload [%d bytes] send error)", p1_len); return -1; } return p0_len + p1_len; } /* fwd decl */ server_t *create_Rserve_QAP1(int flags); /* from oc.c */ extern char Rserve_oc_prefix; #define COMPUTE_OC_PREFIX '@' ssize_t server_recv(args_t *arg, void *buf, size_t len) { return recv(arg->s, buf, len, 0); } ssize_t server_send(args_t *arg, const void *buf, size_t len) { return send(arg->s, buf, len, 0); } SEXP Rserve_kill_compute(SEXP sSig) { #ifdef unix int sig = asInteger(sSig); if (!compute_pid) Rf_error("no compute process attached"); return ScalarLogical(kill(compute_pid, sig) == 0); #else Rf_error("Windows does not support separate compute process."); #endif } #ifdef unix SEXP Rserve_fork_compute(SEXP sExp) { int fd[2]; pid_t fpid; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) Rf_error("unable to create a socket for communication"); fpid = fork(); ulog_reset(); ulog("Rserve_fork_compute: fork() = %d", (int) fpid); if (fpid == -1) { close(fd[0]); close(fd[1]); Rf_error("unable to fork computing process"); } compute_pid = fpid; if (fpid == 0) { /* child = compute process */ closesocket(self_args->s); struct args *args = self_args = (struct args *) calloc(1, sizeof(struct args)); /* create a "fake" server entry for a virtual server that doesn't exist */ server_t *srv = (server_t*) calloc(1, sizeof(server_t)); srv->send_resp = Rserve_QAP1_send_resp; srv->fin = server_fin; srv->recv = server_recv; srv->send = server_send; srv->ss = -1; close(fd[0]); args->s = fd[1]; args->ucix = UCIX++; args->ss = -1; args->srv = srv; current_runtime = new_qap_runtime(args); if (!current_runtime) { ulog("OCAP-ERROR: cannot allocate QAP runtime in fork compute"); exit(1); } compute_ppid = getppid(); Rserve_oc_prefix = COMPUTE_OC_PREFIX; /* set a prefix for all child OCAPs */ compute_subprocess = 1; args->flags |= F_OUT_BIN; /* in OC everything is binary */ /* FIXME: we need something like on.exit(q("no")) to die on error */ if (sExp != R_NilValue) { SEXP res; ulog("OCAP-compute: evaluating fork expression in child process"); res = eval(sExp, R_GlobalEnv); PROTECT(res); ulog("OCAP-compute: sending fork command result to parent"); send_oob_sexp(OOB_SEND, res); UNPROTECT(1); } ulog("OCAP-compute: entering OCAP loop"); while (OCAP_iteration(current_runtime, 0) != 0) {} ulog("OCAP-compute: leaving OCAP loop, terminating"); /* FIXME: should we clean up something? */ exit(0); } /* parent - wait for the result */ compute_fd = fd[0]; close(fd[1]); compute_ppid = 0; { struct phdr ph; unsigned int len32, hi32; size_t plen; int rn, cmd; char *buf; if ((rn = recv(compute_fd, &ph, sizeof(ph), 0)) != sizeof(ph)) { ulog("ERROR: Read error when reading fork result header from OCAP-compute n = %d (expected %d)", rn, sizeof(ph)); closesocket(compute_fd); compute_fd = -1; Rf_error("error when reading result from compute process (n = %d)", rn); } #ifdef RSERV_DEBUG printf("\nOCAP fork result header read result: %d\n", rn); if (rn > 0) printDump(&ph, rn); #endif len32 = (unsigned int) ptoi(ph.len); cmd = ptoi(ph.cmd); plen = len32; #ifdef __LP64__ hi32 = (unsigned int) ptoi(ph.res); plen |= (((size_t) hi32) << 32); #endif ulog("INFO: OCAP compute fork result header, %ld bytes of payload to read", (long) plen); buf = (char*) malloc(plen + 1024); if (!buf) { closesocket(compute_fd); compute_fd = -1; Rf_error("out of memory: cannot allocate buffer for OCAP fork result"); } if ((rn = recv(compute_fd, buf, plen, 0)) != plen) { ulog("ERROR: Read error when reading fork result payload from OCAP-compute n = %d (expected %d)", rn, (int) plen); closesocket(compute_fd); compute_fd = -1; Rf_error("error when reading result from compute process (incomplete payload)"); } { unsigned int *ibuf = (unsigned int*) buf; /* FIXME: this is a bit hacky since we skipped parameter parsing */ int par_t = ibuf[0] & 0xff; if (par_t == DT_SEXP || par_t == (DT_SEXP | DT_LARGE)) { unsigned int *sptr; SEXP res; sptr = ibuf + ((par_t & DT_LARGE) ? 2 : 1); /* FIXME: we're not checking the size?!? */ res = QAP_decode(&sptr); ulog("INFO: OCAP compute fork result successfully decoded"); free(buf); return res; } } ulog("ERROR: Invalid response from forked compute process"); closesocket(compute_fd); compute_fd = -1; Rf_error("Invalid response from forked compute process"); } /* unreachable */ return R_NilValue; } #else SEXP Rserve_fork_compute(SEXP sExp) { Rf_error("Windows does not support separate compute process."); } #endif /* 1 = iteration successful - OCAP called 2 = iteration successful - OOB pending (only signalled if oob_hdr is non-null) 0 = iteration failed - assume conenction has been closed */ int OCAP_iteration(qap_runtime_t *rt, struct phdr *oob_hdr) { struct args *args; struct phdr ph; server_t *srv; SOCKET s; int msg_id; ssize_t rn; if (!rt) rt = current_runtime; if (!rt || !rt->args) return 0; args = rt->args; srv = args->srv; s = args->s; #ifdef RSERV_DEBUG ulog("OCAP: iteration start args=%p, s=%d", args, s); #endif while ((s = args->s) != -1) { /* we are now always using select() just to make sure we don't get stuck and can check things like the status of the processes we care about */ int which = 0; struct timeval timv; int max_fs = s; fd_set readfds; #ifdef FORKED /* for some unknown reason if the compute process dies the pipe doesn't signal EOF and thus it is never detected - hence we use waitpid() to check whether the compute process is still alive */ if (compute_fd != -1 && compute_pid > 0) { int stat = 0; if (waitpid(compute_pid, &stat, WNOHANG) == compute_pid && (WIFEXITED(stat) || WIFSIGNALED(stat))) { ulog("NOTE: compute process died, aborting compute connection"); compute_terminated(); continue; } } /* check the same in the compute process checking for control to make sure we don't have (idle) compute processes w/o control if our parent dies, the ppid will change (typically to 1=init) */ if (s != -1 && compute_ppid > 0 && getppid() != compute_ppid) { ulog("NOTE: control process died, abandoned compute"); close(s); args->s = -1; return 0; } #endif timv.tv_sec = 0; timv.tv_usec = 200000; FD_ZERO(&readfds); FD_SET(s, &readfds); if (compute_fd != -1) { FD_SET(compute_fd, &readfds); if (compute_fd > max_fs) max_fs = compute_fd; } if (std_fw_fd > 0) { FD_SET(std_fw_fd, &readfds); if (std_fw_fd > max_fs) max_fs = std_fw_fd; } rn = select(max_fs + 1, &readfds, 0, 0, &timv); if (rn == -1) { if (errno == EINTR) continue; /* INTR is ok, retry */ ulog("NOTE: OCAP iteration, select error %d, aborting", (int) errno); break; /* others are bad, get out */ } if (FD_ISSET(s, &readfds)) which = 1; else if (compute_fd != -1 && FD_ISSET(compute_fd, &readfds)) which = 2; else if (std_fw_fd > 0 && FD_ISSET(std_fw_fd, &readfds)) which = 3; if (use_idle_callback && which == 0) { SEXP var = findVarInFrame(R_GlobalEnv, install(".ocap.idle")); if (Rf_isFunction(var)) { /* idle callback */ SEXP l = PROTECT(lang1(var)); int errf = 0; R_tryEval(l, R_GlobalEnv, &errf); UNPROTECT(1); } } if (which == 3) /* std-forwarding */ handle_std_fw(); if (which == 2) { /* proxy pass-through */ size_t plen = 0, iob_pos; unsigned int len32, hi32; int cmd; rn = recv(compute_fd, (char*)&ph, sizeof(ph), 0); if (rn != sizeof(ph)) { ulog("read from compute incomplete - yields %d, closing", rn); compute_terminated(); continue; } #ifdef RSERV_DEBUG printf("\nOCAP pass-thru header read result: %ld\n", (long) rn); if (rn > 0) printDump(&ph, rn); #endif /* NOTE: do not touch ph since we may need to pass it unharmed to oob */ len32 = (unsigned int) ptoi(ph.len); cmd = ptoi(ph.cmd); plen = len32; #ifdef __LP64__ hi32 = (unsigned int) ptoi(ph.res); plen |= (((size_t) hi32) << 32); #endif if (!compute_iobuf) { if (!compute_iobuf_len) compute_iobuf_len = max_sio_chunk; compute_iobuf = (char*) malloc(compute_iobuf_len); if (!compute_iobuf) { #ifdef RSERV_DEBUG fprintf(stderr,"FATAL: out of memory while allocating pass-thru buffer\n"); #endif ulog("ERROR: out of memory while allocating pass-thru buffer of %lu\n", (unsigned long) compute_iobuf_len); closesocket(compute_fd); sendResp(args, SET_STAT(RESP_ERR,ERR_out_of_mem)); closesocket(s); args->s = -1; return 0; } } #ifdef RSERV_DEBUG printf("loading buffer (awaiting %ld bytes from subprocess)\n",(long) plen); #endif /* FIXME: this is not recorded in iolog ! */ /* avoid fragmentation, put the header in teh buffer */ memcpy(compute_iobuf, &ph, sizeof(ph)); iob_pos = sizeof(ph); /* FIXME: currently RserveJS cannot handle QAP messages that span multiple WS messages (=multiple sends). We have to either fix RserveJS or buffer everything Note: most recent Rserve-js supports fragmented messages thanks to Gordon */ while (iob_pos || plen) { if (plen) { rn = recv(compute_fd, compute_iobuf + iob_pos, (plen > compute_iobuf_len - iob_pos) ? (compute_iobuf_len - iob_pos) : plen, 0); #ifdef OOB_ULOG ulog("OCAP-pass-thru: read from compute yields %ld (expected %ld)", (long) rn, (long) (plen > compute_iobuf_len) ? compute_iobuf_len : plen); #endif if (rn > 0) { plen -= rn; if (iob_pos) rn += iob_pos; } } else rn = iob_pos; if (rn > 0 && srv->send(args, compute_iobuf, rn) != rn) { #ifdef RSERV_DEBUG fprintf(stderr,"ERROR: cannot send pass-thru OOB (payload send failed)\n"); #endif ulog("ERROR: cannot send pass-thru OOB (payload send failed; errno=%d)", (int) errno); closesocket(compute_fd); compute_fd = -1; closesocket(s); args->s = -1; return 0; } if (rn < 1) { compute_terminated(); break; /* break out of plen loop - still inside OCAP loop */ } iob_pos = 0; } if (compute_fd == -1) continue; if (plen) { ulog("ERROR: incomplete compute OCAP message - closing connection"); sendResp(args, SET_STAT(RESP_ERR, ERR_conn_broken)); closesocket(s); closesocket(compute_fd); compute_fd = -1; args->s = -1; return 0; } } /* end of pass-thru processing */ if (which == 1) { size_t plen = 0; unsigned int len32, hi32; int cmd, compute_pass_thru = 0; rn = srv->recv(args, (char*)&ph, sizeof(ph)); #ifdef RSERV_DEBUG printf("\nOCAP iter header read result: %ld\n", (long) rn); if (rn > 0) printDump(&ph, rn); #endif if (rn != sizeof(ph)) { ulog("NOTE: OCAP connection read yields %d (expected %d), aborting", rn, (int) sizeof(rn)); break; } /* NOTE: do not touch ph since we may need to pass it unharmed to oob */ len32 = (unsigned int) ptoi(ph.len); cmd = ptoi(ph.cmd); plen = len32; #ifdef __LP64__ hi32 = (unsigned int) ptoi(ph.res); plen |= (((size_t) hi32) << 32); #endif #ifdef RSERV_DEBUG if (io_log) { struct timeval tv; snprintf(io_log_fn, sizeof(io_log_fn), "/tmp/Rserve-io-%d.log", getpid()); FILE *f = fopen(io_log_fn, "a"); if (f) { double ts = 0; if (!gettimeofday(&tv, 0)) ts = ((double) tv.tv_sec) + ((double) tv.tv_usec) / 1000000.0; if (first_ts < 1.0) first_ts = ts; fprintf(f, "%.3f [+%4.3f] SRV <-- CLI [OCAP iter] (%x, %ld bytes)\n HEAD ", ts, ts - first_ts, cmd, (long) plen); fprintDump(f, &ph, sizeof(ph)); fclose(f); } } #endif if (oob_hdr && (cmd & CMD_OOB)) { /* we're nested in OOB and OOB has arrived - copy header and get out */ /* FIXME: we need a way to detect OOB MSG reposnses that need to be forwarded to compute_fd! */ memcpy(oob_hdr, &ph, sizeof(ph)); #ifdef OOB_ULOG ulog("OCiteration passing to OOB"); #endif return 2; } msg_id = args->msg_id = ph.msg_id; /* FIXME: we have to be quite permissive here since RserveJS can mix RESP_OK/ERR with MSG_OOB */ if (compute_pid && (cmd & CMD_OOB) && OOB_USR_CODE(cmd) > 0xff) { /* pass-thru OOB result */ #ifdef OOB_ULOG ulog("INFO: OOB response pass-through (cmd=0x%x, len=%ld)", cmd, (long)plen); #endif compute_pass_thru = 1; } /* in OC mode everything but OCcall is invalid */ if (!compute_pass_thru && cmd != CMD_OCcall) { ulog("VIOLATION: OCAP iteration - only OCcall is allowed but got 0x%x, aborting", cmd); sendResp(args, SET_STAT(RESP_ERR, ERR_disabled)); closesocket(s); args->s = -1; return 0; } { if (!maxInBuf || plen < maxInBuf) { size_t i; if (plen >= rt->buf_size) { #ifdef RSERV_DEBUG printf("resizing input buffer (was %ld, need %ld) to %ld\n", (long)rt->buf_size, (long) plen, (long)(((plen | 0x1fffL) + 1L))); #endif free(rt->buf); /* the buffer is just a scratchpad, so we don't need to use realloc */ rt->buf = (char*) malloc(rt->buf_size = ((plen | 0x1fffL) + 1L)); /* use 8kB granularity */ if (!rt->buf) { #ifdef RSERV_DEBUG fprintf(stderr,"FATAL: out of memory while resizing buffer to %ld,\n", (long)rt->buf_size); #endif ulog("ERROR: out of memory while resizing resizing buffer to %ld,\n", (long)rt->buf_size); sendResp(args, SET_STAT(RESP_ERR,ERR_out_of_mem)); closesocket(s); args->s = -1; return 0; } } #ifdef RSERV_DEBUG printf("loading buffer (awaiting %ld bytes)\n",(long) plen); #endif i = 0; while ((rn = srv->recv(args, ((char*)rt->buf) + i, (plen - i > max_sio_chunk) ? max_sio_chunk : (plen - i)))) { #ifdef RSERV_DEBUG printf(" rn = %ld (i = %ld)\n", (long) rn, (long) i); #endif if (rn > 0) i += rn; if (i >= plen || rn < 1) break; } #ifdef RSERV_DEBUG if (io_log) { FILE *f = fopen(io_log_fn, "a"); if (f) { fprintf(f, " BODY "); if (i) fprintDump(f, rt->buf, i); else fprintf(f, "\n"); fclose(f); } } #endif if (i < plen) { ulog("ERROR: incomplete OCAP message - closing connection"); sendResp(args, SET_STAT(RESP_ERR, ERR_conn_broken)); closesocket(s); args->s = -1; return 0; } memset(rt->buf + plen, 0, 8); } else { #ifdef RSERV_DEBUG fprintf(stderr,"ERROR: input is larger than input buffer limit\n"); #endif ulog("ERROR: input packet is larger than input buffer limit"); sendResp(args, SET_STAT(RESP_ERR, ERR_data_overflow)); closesocket(s); args->s = -1; return 0; } } if (compute_pass_thru) { /* pass-thru, normally only responses to OOB_MSG */ if (compute_send(&ph, sizeof(ph), rt->buf, plen) < 0) { ulog("ERROR: OOB msg pass-through to compute failed (errno=%d)", errno); sendResp(args, SET_STAT(RESP_ERR, ERR_ctrl_closed)); return 1; } #ifdef OOB_ULOG ulog("INFO: OOB msg passed to compute"); #endif continue; } { int valid = 0, Rerror = 0; SEXP val = R_NilValue, eval_result = 0, exp = R_NilValue; unsigned int *ibuf = (unsigned int*) rt->buf; /* FIXME: this is a bit hacky since we skipped parameter parsing */ int par_t = ibuf[0] & 0xff; const char *c_ocname = 0; #ifdef RSERV_DEBUG printf(" OCAP call\n"); #endif if (par_t == DT_SEXP || par_t == (DT_SEXP | DT_LARGE)) { unsigned int *sptr; #ifdef RSERV_DEBUG printf(" - OK, has DT_SEXP\n"); #endif sptr = ibuf + ((par_t & DT_LARGE) ? 2 : 1); /* FIXME: we're not checking the size?!? */ val = QAP_decode(&sptr); #ifdef RSERV_DEBUG printf(" - resulting type: %d\n", TYPEOF(val)); #endif if (val && TYPEOF(val) == LANGSXP) { SEXP ocref = CAR(val); #ifdef RSERV_DEBUG printf(" - good, is a call\n"); #endif if (TYPEOF(ocref) == STRSXP && LENGTH(ocref) == 1) { #ifdef RSERV_DEBUG printf(" - head is a ocref, trying to resolve %s\n", CHAR(STRING_ELT(ocref, 0))); #endif SEXP ocv = oc_resolve(CHAR(STRING_ELT(ocref, 0))); if (ocv && ocv != R_NilValue && CAR(ocv) != R_NilValue) { /* valid reference -- replace it in the call */ SEXP occall = CAR(ocv), ocname = TAG(ocv); SETCAR(val, occall); if (ocname != R_NilValue) c_ocname = CHAR(PRINTNAME(ocname)); ulog("OCcall '%s': ", (ocname == R_NilValue) ? "" : c_ocname); valid = 1; } else if (compute_pid && CHAR(STRING_ELT(ocref, 0))[0] == COMPUTE_OC_PREFIX) { /* it's a compute OCAP - need to pass-thru */ if (compute_send(&ph, sizeof(ph), rt->buf, plen) < 0) { sendResp(args, SET_STAT(RESP_ERR, ERR_ctrl_closed)); return 1; } /* we don't respond since subprocess is expected to */ /* FIXME: should we respond to acknowledge enqueuing? */ continue; } } } } /* invalid calls lead to immediate termination with no message */ if (!valid) { ulog("ERROR OCcall: invalid reference"); closesocket(s); args->s = -1; return 0; } PROTECT(val); #ifdef RSERV_DEBUG printf(" running eval on SEXP (after OC replacement): "); printSEXP(val); #endif eval_result = R_tryEval(val, R_GlobalEnv, &Rerror); args->msg_id = msg_id; /* restore msg_id - oob in eval would clober it */ UNPROTECT(1); ulog("OCresult '%s'", c_ocname ? c_ocname : ""); if (eval_result) exp = PROTECT(eval_result); #ifdef RSERV_DEBUG printf("expression(s) evaluated (Rerror=%d).\n",Rerror); if (!Rerror) printSEXP(exp); #endif if (Rerror) { sendResp(args, SET_STAT(RESP_ERR, (Rerror < 0) ? Rerror : -Rerror)); return 1; } else { char *sendhead = 0; size_t tempSB = 0; /* check buffer size vs REXP size to avoid dangerous overflows todo: resize the buffer as necessary */ rlen_t rs = QAP_getStorageSize(exp); if (rs < 0) { /* just in case there is encoding error */ sendResp(args, SET_STAT(RESP_ERR, ERR_inv_par)); return 1; } /* FIXME: add a 4k security margin - it should no longer be needed, originally the space was grown proportionally to account for a bug, but that bug has been fixed. */ rs += 4096; #ifdef RSERV_DEBUG printf("result storage size = %ld bytes (buffer %ld bytes)\n",(long)rs, (long)rt->buf_size); #endif if (rs > rt->buf_size - 64L) { /* is the send buffer too small ? */ if (maxSendBufSize && rs > maxSendBufSize - 4160L) { /* first check if we're allowed to resize */ unsigned int osz = (rs > 0xffffffff) ? 0xffffffff : rs; osz = itop(osz); #ifdef RSERV_DEBUG printf("ERROR: object too big (buffer=%ld)\n", (long int) rt->buf_size); #endif ulog("WARNING: object too big to send"); sendRespData(args, SET_STAT(RESP_ERR, ERR_object_too_big), 4, &osz); return 1; } else { /* try to allocate a large, temporary send buffer */ tempSB = rs + 64L; tempSB &= rlen_max ^ 0xfff; tempSB += 0x1000; #ifdef RSERV_DEBUG printf("Trying to allocate temporary send buffer of %ld bytes.\n", (long)tempSB); #endif free(rt->buf); rt->buf = (char*)malloc(tempSB); if (!rt->buf) { #ifdef RSERV_DEBUG printf("Failed to allocate temporary send buffer of %ld bytes. Restoring old send buffer of %ld bytes.\n", (long)tempSB, (long)rt->buf_size); #endif rt->buf = (char*)malloc(rt->buf_size); if (!rt->buf) { /* we couldn't re-allocate the buffer */ #ifdef RSERV_DEBUG fprintf(stderr,"FATAL: out of memory while re-allocating send buffer to %ld (fallback#1)\n", (long) rt->buf_size); #endif sendResp(args, SET_STAT(RESP_ERR, ERR_out_of_mem)); closesocket(s); args->s = -1; return 0; } else { unsigned int osz = (rs > 0xffffffff) ? 0xffffffff : rs; osz = itop(osz); #ifdef RSERV_DEBUG printf("ERROR: object too big (sendBuf=%ld) and couldn't allocate big enough send buffer\n", (long) rt->buf_size); #endif sendRespData(args, SET_STAT(RESP_ERR, ERR_object_too_big), 4, &osz); return 1; } } } } { /* first we have 4 bytes of a header saying this is an encoded SEXP, then comes the SEXP */ char *sxh = rt->buf + 8; char *tail = (char*)QAP_storeSEXP((unsigned int*)sxh, exp, rs); /* set type to DT_SEXP and correct length */ if ((tail - sxh) > 0xfffff0) { /* we must use the "long" format */ rlen_t ll = tail - sxh; ((unsigned int*)rt->buf)[0] = itop(SET_PAR(DT_SEXP | DT_LARGE, ll & 0xffffff)); ((unsigned int*)rt->buf)[1] = itop(ll >> 24); sendhead = rt->buf; } else { sendhead = rt->buf + 4; ((unsigned int*)rt->buf)[1] = itop(SET_PAR(DT_SEXP,tail - sxh)); } #ifdef RSERV_DEBUG printf("stored SEXP; length=%ld (incl. DT_SEXP header)\n",(long) (tail - sendhead)); #endif sendRespData(args, RESP_OK, tail - sendhead, sendhead); if (tempSB) { /* if this is just a temporary sendbuffer then shrink it back to normal */ #ifdef RSERV_DEBUG printf("Releasing temporary sendbuf and restoring old size of %ld bytes.\n", (long) rt->buf_size); #endif free(rt->buf); rt->buf = (char*)malloc(rt->buf_size); if (!rt->buf) { /* this should be really rare since tempSB was much larger */ #ifdef RSERV_DEBUG fprintf(stderr,"FATAL: out of memory while re-allocating send buffer to %ld (fallback#2),\n", (long) rt->buf_size); #endif sendResp(args, SET_STAT(RESP_ERR, ERR_out_of_mem)); ulog("ERROR: out of memory while shrinking send buffer"); closesocket(s); args->s = -1; return 0; } } } if (eval_result) UNPROTECT(1); /* exp / eval_result */ } #ifdef RSERV_DEBUG printf("reply sent.\n"); return 1; #endif } } } #ifdef RSERV_DEBUG ulog("OCAP: iteration fall-through args=%p, s=%d", args, s); #endif closesocket(s); args->s = -1; return 0; } /* working thread/function. the parameter is of the type struct args* */ /* This server function implements the Rserve QAP1 protocol */ void Rserve_QAP1_connected(void *thp) { SOCKET s; struct args *a = (struct args*)thp; struct phdr ph; server_t *srv = a->srv; char *buf, *c, *cc, *c1; int pars; int process; int rn; int uses_tls = 0; ParseStatus stat; char *sendbuf; size_t sendBufSize; char *tail; char *sfbuf; int Rerror; int authed=0; int unaligned=0; #ifdef HAS_CRYPT char salt[5]; #endif size_t tempSB=0; int parT[16]; size_t parL[16]; void *parP[16]; FILE *cf=0; int pc_res; /* OCAP has moved out to its own path for security reasons (this compatibility re-direct should go away after testing) */ if (a->srv->flags & SRV_QAP_OC) { Rserve_OCAP_connected(a); return; } pc_res = Rserve_prepare_child(a); if (pc_res != 0) { /* either failed or parent */ free(a); return; } /* FIXME: re-factor to use qap_runtime jsut like OCAP does */ buf = (char*) malloc(inBuf + 8); sfbuf = (char*) malloc(sfbufSize); if (!buf || !sfbuf) { RSEprintf("FATAL: cannot allocate initial buffers. closing client connection.\n"); s = a->s; free(a); closesocket(s); return; } memset(buf, 0, inBuf + 8); setup_workdir(); sendBufSize = sndBS; sendbuf = (char*) malloc(sendBufSize); #ifdef RSERV_DEBUG printf("connection accepted.\n"); #endif s = a->s; /* FIXME: we used to free a here, but now that we use it we have to defer that ... */ csock = s; if ((a->srv->flags & SRV_TLS) && shared_tls(0)) { char cn[256]; add_tls(a, shared_tls(0), 1); if (check_tls_client(verify_peer_tls(a, cn, 256), cn)) { s = a->s; close_tls(a); free(a); closesocket(s); return; } uses_tls = 1; } { strcpy(buf,IDstring); if (authReq) { #ifdef HAS_CRYPT /* advertize crypt */ memcpy(buf+16,"ARuc",4); salt[0]='K'; salt[1]=code64[rand()&63]; salt[2]=code64[rand()&63]; salt[3]=' '; salt[4]=0; memcpy(buf+20,salt,4); /* append plaintext if enabled */ if (usePlain) memcpy(buf + 24,"ARpt",4); #else /* if crypt is not an option, we may need to advertize plain text if enabled */ if (usePlain) memcpy(buf + 16, "ARpt", 4); #endif } #ifdef HAVE_TLS if (switch_qap_tls) { char *ep = buf + 16; while (*ep != '-') ep += 4; memcpy(ep, "TLS\n", 4); } #endif #ifdef RSERV_DEBUG printf("sending ID string.\n"); #endif srv->send(a, (char*)buf, 32); } /* everything is binary from now on */ a->flags |= F_OUT_BIN; while((rn = srv->recv(a, (char*)&ph, sizeof(ph))) == sizeof(ph)) { SEXP eval_result = 0; size_t plen = 0; SEXP pp = R_NilValue; /* packet payload (as a raw vector) for special commands */ int msg_id; Rerror = 0; #ifdef RSERV_DEBUG printf("\nheader read result: %d\n", rn); if (rn > 0) printDump(&ph, rn); #endif ph.len = ptoi(ph.len); ph.cmd = ptoi(ph.cmd); #ifdef __LP64__ ph.res = ptoi(ph.res); plen = (unsigned int) ph.len; plen |= (((size_t) (unsigned int) ph.res) << 32); #else plen = ph.len; #endif msg_id = a->msg_id = use_msg_id ? ph.msg_id : 0; process = 0; pars = 0; ulog("QAP1: CMD 0x%08x, length %ld, msg.id 0x%x", (int) ph.cmd, (long) plen, msg_id); #ifdef RSERV_DEBUG if (io_log) { struct timeval tv; snprintf(io_log_fn, sizeof(io_log_fn), "/tmp/Rserve-io-%d.log", getpid()); FILE *f = fopen(io_log_fn, "a"); if (f) { double ts = 0; if (!gettimeofday(&tv, 0)) ts = ((double) tv.tv_sec) + ((double) tv.tv_usec) / 1000000.0; if (first_ts < 1.0) first_ts = ts; fprintf(f, "%.3f [+%4.3f] SRV <-- CLI [QAP loop] (%x, %ld bytes)\n HEAD ", ts, ts - first_ts, ph.cmd, (long) plen); fprintDump(f, &ph, sizeof(ph)); fclose(f); } } #endif /* in OC mode everything but OCcall is invalid */ if ((a->srv->flags & SRV_QAP_OC) && ph.cmd != CMD_OCcall) { sendResp(a, SET_STAT(RESP_ERR, ERR_disabled)); free(sendbuf); free(sfbuf); if (uses_tls) close_tls(a); closesocket(s); free(a); return; } if ((ph.cmd & CMD_SPECIAL_MASK) == CMD_SPECIAL_MASK) { /* this is a very special case - we load the packet payload into a raw vector directly to prevent unnecessaru copying */ pp = allocVector(RAWSXP, plen); char *pbuf = (char*) RAW(pp); size_t i = 0; #ifdef RSERV_DEBUG printf("loading (raw) buffer (awaiting %d bytes)\n", (int)plen); #endif while((rn = srv->recv(a, pbuf + i, (plen - i > max_sio_chunk) ? max_sio_chunk : (plen - i)))) { if (rn > 0) i += rn; if (i >= plen || rn < 1) break; } } else if (plen > 0) { unsigned int phead; int parType = 0; size_t parLen = 0; if (!maxInBuf || plen < maxInBuf) { size_t i; if (plen >= inBuf) { #ifdef RSERV_DEBUG printf("resizing input buffer (was %ld, need %ld) to %ld\n", (long)inBuf, (long) plen, (long)(((plen | 0x1fffL) + 1L))); #endif free(buf); /* the buffer is just a scratchpad, so we don't need to use realloc */ buf = (char*) malloc(inBuf = ((plen | 0x1fffL) + 1L)); /* use 8kB granularity */ if (!buf) { #ifdef RSERV_DEBUG fprintf(stderr,"FATAL: out of memory while resizing buffer to %d,\n", (int)inBuf); #endif sendResp(a, SET_STAT(RESP_ERR,ERR_out_of_mem)); free(sendbuf); free(sfbuf); if (uses_tls) close_tls(a); closesocket(s); free(a); return; } } #ifdef RSERV_DEBUG printf("loading buffer (awaiting %ld bytes)\n",(long) plen); #endif i = 0; while ((rn = srv->recv(a, ((char*)buf) + i, (plen - i > max_sio_chunk) ? max_sio_chunk : (plen - i)))) { #ifdef RSERV_DEBUG printf(" [2] rn = %d (i = %ld)\n", rn, (long) i); #endif if (rn > 0) i += rn; if (i >= plen || rn < 1) break; } #ifdef RSERV_DEBUG if (io_log) { FILE *f = fopen(io_log_fn, "a"); if (f) { fprintf(f, " BODY "); if (i) fprintDump(f, buf, i); else fprintf(f, "\n"); fclose(f); } } #endif if (i < plen) break; memset(buf + plen, 0, 8); unaligned = 0; #ifdef RSERV_DEBUG printf("parsing parameters (buf=%p, len=%ld)\n", (void*) buf, (long) plen); if (plen > 0) printDump(buf,plen); #endif c = buf; while((c < buf + plen) && (phead = ptoi(*((unsigned int*)c)))) { size_t headSize = 4; parType = PAR_TYPE(phead); parLen = PAR_LEN(phead); if ((parType & DT_LARGE) > 0) { /* large parameter */ headSize += 4; parLen |= ((size_t)((unsigned int)ptoi(*(unsigned int*)(c + 4)))) << 24; parType ^= DT_LARGE; } #ifdef RSERV_DEBUG printf("PAR[%d]: %08lx (PAR_LEN=%ld, PAR_TYPE=%d, large=%s, c=%p, ptr=%p)\n", pars, (long unsigned) i, (long)parLen, parType, (headSize==8)?"yes":"no", (void*) c, (void*)(c + headSize)); #endif #ifdef ALIGN_DOUBLES if (unaligned) { /* on Sun machines it is deadly to process unaligned parameters, therefore we respond with ERR_inv_par */ #ifdef RSERV_DEBUG printf("Platform specific: last parameter resulted in unaligned stream for the current one, sending ERR_inv_par.\n"); #endif sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); process = 1; ph.cmd = 0; break; } #endif if (parLen & 3) unaligned=1; parT[pars] = parType; parL[pars] = parLen; parP[pars] = c + headSize; pars++; c += parLen + headSize; /* par length plus par head */ if (pars > 15) break; } /* we don't parse more than 16 parameters */ } else { RSEprintf("WARNING: discarding buffer because too big (awaiting %ld bytes)\n", (long)plen); size_t i = plen, chk = (inBuf < max_sio_chunk) ? inBuf : max_sio_chunk; while((rn = srv->recv(a, (char*)buf, (i < chk) ? i : chk))) { if (rn > 0) i -= rn; if (i < 1 || rn < 1) break; } if (i > 0) break; /* if the pars are bigger than my buffer, send data_overflow response (since 1.23/0.1-6; was inv_par before) */ sendResp(a, SET_STAT(RESP_ERR, ERR_data_overflow)); process = 1; ph.cmd = 0; } } /** IMPORTANT! The pointers in par[..] point to RAW data, i.e. you have to use ptoi(..) in order to get the real integer value. */ /** NOTE: Rserve doesn't check for alignment of parameters. This is ok for most platforms, but on Sun hardware this means that an user can send a package that will cause segfault in the client thread by sending unaligned parameters. This won't affect the server, only the connection child process dies. Since 0.1-10 we report ERR_inv_par on Sun for non-aligned parameters. */ #ifdef RSERV_DEBUG printf("CMD=%08x, pars=%d\n", ph.cmd, pars); #endif /* FIXME: now that OCAP has a separate server path, should we really support OCcall outside of OCAP mode? This piece is only run if OCAP mode is disabled */ if (ph.cmd == CMD_OCcall) { int valid = 0; SEXP val = R_NilValue; if (pars >= 1 && (parT[0] == DT_SEXP || parT[0] == (DT_SEXP | DT_LARGE))) { int boffs = 0; unsigned int *sptr; if (parT[0] & DT_LARGE) boffs++; sptr = ((unsigned int*)parP[0]) + boffs; val = QAP_decode(&sptr); if (val && TYPEOF(val) == LANGSXP) { SEXP ocref = CAR(val); if (TYPEOF(ocref) == STRSXP && LENGTH(ocref) == 1) { SEXP ocv = oc_resolve(CHAR(STRING_ELT(ocref, 0))); if (ocv && ocv != R_NilValue && CAR(ocv) != R_NilValue) { /* valid reference -- replace it in the call */ SEXP occall = CAR(ocv), ocname = TAG(ocv); SETCAR(val, occall); ulog("OCcall '%s': ", (ocname == R_NilValue) ? "" : CHAR(PRINTNAME(ocname))); valid = 1; } } } } /* invalid calls lead to immediate termination with no message */ if (!valid) { ulog("ERROR OCcall: invalid reference"); free(sendbuf); free(sfbuf); if (uses_tls) close_tls(a); closesocket(s); free(a); return; } PROTECT(val); #ifdef RSERV_DEBUG printf(" running eval on SEXP (after OC replacement): "); printSEXP(val); #endif eval_result = R_tryEval(val, R_GlobalEnv, &Rerror); UNPROTECT(1); ulog("OCresult"); process = 1; } if (ph.cmd == CMD_switch) { if (pars < 1 || parT[0] != DT_STRING) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { c = (char*) parP[0]; if (!strcmp(c, "TLS")) { if (switch_qap_tls && shared_tls(0)) { sendResp(a, RESP_OK); add_tls(a, shared_tls(0), 1); } else sendResp(a, SET_STAT(RESP_ERR, ERR_disabled)); } else sendResp(a, SET_STAT(RESP_ERR, ERR_unsupportedCmd)); } continue; } if (ph.cmd == CMD_keyReq) { if (pars < 1 || parT[0] != DT_STRING) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { c = (char*) parP[0]; #ifdef HAVE_RSA /* rsa-authkey - generates authkey and sends server's public RSA key */ if (strstr(c, "rsa-authkey")) { if (++authkey_req < 2) { char *pload = 0; int pl = rsa_gen_resp(&pload); if (pl < 1) sendResp(a, SET_STAT(RESP_ERR, ERR_cryptError)); else sendRespData(a, RESP_OK, pl, pload); if (pload) free(pload); } else { sendResp(a, SET_STAT(RESP_ERR, ERR_securityClose)); if (uses_tls) close_tls(a); closesocket(s); free(sendbuf); free(sfbuf); free(buf); free(a); return; } } else #endif sendResp(a, SET_STAT(RESP_ERR, ERR_unavailable)); } continue; } /* uint32_t len; byte[len] key; utin32_t len; char[len] auth (username\npwd\n) */ if (ph.cmd == CMD_secLogin) { #ifdef HAVE_RSA if (pars < 1 || parT[0] != DT_BYTESTREAM || parL[0] >= sizeof(rsa_buf)) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { int dl = 0; /* the authkey must have been requested */ if (!authkey_req || !rsa_srv_key || (dl = rsa_decode(rsa_buf, (char*) parP[0], parL[0])) < 1) { #ifdef RSERV_DEBUG printf("CMD_secLogin: decode failed - authkey_req=%d, rsa_srv_key=%p, dl = %d (payload %d)\n", authkey_req, (void*)rsa_srv_key, dl, (int) parL[0]); #endif sendResp(a, SET_STAT(RESP_ERR, ERR_auth_failed)); } else { unsigned char *rb = (unsigned char*) rsa_buf; if (rb[0] != (SRV_KEY_LEN & 0xff) || rb[1] != ((SRV_KEY_LEN >> 8) & 0xff) || rb[2] || rb[3] || memcmp(rb + 4, authkey, SRV_KEY_LEN)) { #ifdef RSERV_DEBUG printf("CMD_secLogin: authkey mismatch\n"); #endif sendResp(a, SET_STAT(RESP_ERR, ERR_auth_failed)); } else { unsigned int asl = rb[SRV_KEY_LEN + 5]; asl <<= 8; asl |= rb[SRV_KEY_LEN + 4]; #ifdef RSERV_DEBUG printf("CMD_secLogin: authkey matches, asl payload: %d\n", asl); #endif if (asl + SRV_KEY_LEN + 8 > dl) sendResp(a, SET_STAT(RESP_ERR, ERR_auth_failed)); else { char *ac, *au = 0, *ap = 0; int i; au = ac = ((char*) rb) + SRV_KEY_LEN + 8; for (i = 0; i < asl; i++) if (ac[i] == '\n') { ac[i] = 0; if (!ap) ap = ac + i + 1; } if (ac[asl - 1]) ac[asl] = 0; authed = auth_user(au, ap ? ap : "", sec_salt); a->msg_id = msg_id; /* just in case R-side auth used OOB (it shouldn't) */ if (authed) { process = 1; sendResp(a, RESP_OK); } } } } } #else sendResp(a, SET_STAT(RESP_ERR, ERR_unavailable)); continue; #endif } if (!authed && ph.cmd==CMD_login) { if (pars < 1 || parT[0] != DT_STRING) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { #ifdef HAS_CRYPT const char *my_salt = salt + 1; #else const char *my_salt = 0; #endif c = (char*)parP[0]; cc = c; while(*cc && *cc != '\n') cc++; if (*cc) { *cc = 0; cc++; }; c1 = cc; while(*c1) if(*c1 == '\n' || *c1 == '\r') *c1=0; else c1++; /* c=login, cc=pwd */ authed = auth_user(c, cc, my_salt); a->msg_id = msg_id; /* just in case R-side auth used OOB (it shouldn't) */ if (authed) { process = 1; sendResp(a, RESP_OK); } } } /* if not authed by now, close connection */ if (authReq && !authed) { sendResp(a, SET_STAT(RESP_ERR, ERR_auth_failed)); if (uses_tls) close_tls(a); closesocket(s); free(sendbuf); free(sfbuf); free(buf); free(a); return; } if (ph.cmd==CMD_shutdown) { /* FIXME: now that we have control commands we may rethink this ... */ if (disable_shutdown) { sendResp(a, SET_STAT(RESP_ERR, ERR_disabled)); continue; } sendResp(a, RESP_OK); #ifdef RSERV_DEBUG printf("initiating clean shutdown.\n"); #endif active = 0; if (uses_tls) close_tls(a); closesocket(s); free(sendbuf); free(sfbuf); free(buf); free(a); #ifdef FORKED if (parentPID > 0) kill(parentPID, SIGTERM); exit(0); #endif return; } if (ph.cmd == CMD_ctrlEval || ph.cmd == CMD_ctrlSource || ph.cmd == CMD_ctrlShutdown) { process = 1; sendResp(a, SET_STAT(RESP_ERR, ERR_unsupportedCmd)); } if (ph.cmd == CMD_setEncoding) { /* set string encoding */ process = 1; if (pars<1 || parT[0] != DT_STRING) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { char *c = (char*) parP[0]; #ifdef RSERV_DEBUG printf(">>CMD_setEncoding '%s'.\n", c ? c : ""); #endif #ifdef USE_ENCODING if (c && set_string_encoding(c, 0)) sendResp(a, RESP_OK); else sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); #else sendResp(a, SET_STAT(RESP_ERR, ERR_unsupportedCmd)); #endif } } if (ph.cmd == CMD_setBufferSize) { process = 1; /* FIXME: configuration allows 64-bit numbers but CMD_setBufferSize does not */ if (pars < 1 || parT[0] != DT_INT) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { int ns = ptoi(((unsigned int*)(parP[0]))[0]); #ifdef RSERV_DEBUG printf(">>CMD_setSendBuf to %d bytes.\n", ns); #endif if (ns > 0) { /* 0 means don't touch the buffer size */ if (ns < 32768) ns = 32768; /* we enforce a minimum of 32kB */ free(sendbuf); sendbuf = (char*)malloc(sendBufSize); if (!sendbuf) { #ifdef RSERV_DEBUG fprintf(stderr,"FATAL: out of memory while resizing send buffer to %ld,\n", (long) sendBufSize); #endif sendResp(a, SET_STAT(RESP_ERR, ERR_out_of_mem)); free(buf); free(sfbuf); if (uses_tls) close_tls(a); closesocket(s); free(a); return; } sendBufSize = ns; } sendResp(a, RESP_OK); } } if (ph.cmd==CMD_openFile||ph.cmd==CMD_createFile) { process=1; if (!allowIO) sendResp(a, SET_STAT(RESP_ERR,ERR_accessDenied)); else { if (pars<1 || parT[0]!=DT_STRING) sendResp(a, SET_STAT(RESP_ERR,ERR_inv_par)); else { c=(char*)(parP[0]); if (cf) fclose(cf); #ifdef RSERV_DEBUG printf(">>CMD_open/createFile(%s)\n",c); #endif cf=fopen(c,(ph.cmd==CMD_openFile)?"rb":"wb"); if (!cf) sendResp(a, SET_STAT(RESP_ERR, ERR_IOerror)); else sendResp(a, RESP_OK); } } } if (ph.cmd==CMD_removeFile) { process=1; if (!allowIO) sendResp(a, SET_STAT(RESP_ERR, ERR_accessDenied)); else { if (pars<1 || parT[0]!=DT_STRING) sendResp(a, SET_STAT(RESP_ERR,ERR_inv_par)); else { c=(char*)parP[0]; #ifdef RSERV_DEBUG printf(">>CMD_removeFile(%s)\n",c); #endif if (remove(c)) sendResp(a, SET_STAT(RESP_ERR, ERR_IOerror)); else sendResp(a, RESP_OK); } } } if (ph.cmd == CMD_closeFile) { process = 1; if (!allowIO) sendResp(a, SET_STAT(RESP_ERR, ERR_accessDenied)); else { if (cf) fclose(cf); #ifdef RSERV_DEBUG printf(">>CMD_closeFile\n"); #endif cf = 0; sendResp(a, RESP_OK); } } if (ph.cmd==CMD_readFile) { process = 1; if (!allowIO) sendResp(a, SET_STAT(RESP_ERR, ERR_accessDenied)); else { if (!cf) sendResp(a, SET_STAT(RESP_ERR, ERR_notOpen)); else { int fbufl = sfbufSize; char *fbuf = sfbuf; if (pars == 1 && parT[0] == DT_INT) fbufl = ptoi(((unsigned int*)(parP[0]))[0]); #ifdef RSERV_DEBUG printf(">>CMD_readFile(%d)\n", fbufl); #endif if (fbufl < 0) fbufl = sfbufSize; if (fbufl > sfbufSize) { #ifdef RSERV_DEBUG printf(" - requested size %ld is larger than default buffer %ld, allocating extra buffer\n", (long) fbufl, (long) sfbufSize); #endif fbuf = (char*)malloc(fbufl); } if (!fbuf) /* well, logically not clean (it's out of memory), but in practice likely true */ sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { size_t i = fread(fbuf, 1, fbufl, cf); if (i > 0) sendRespData(a, RESP_OK, i, fbuf); else sendResp(a, RESP_OK); if (fbuf != sfbuf) free(fbuf); } } } } if (ph.cmd==CMD_writeFile) { process=1; if (!allowIO) sendResp(a, SET_STAT(RESP_ERR, ERR_accessDenied)); else { if (!cf) sendResp(a, SET_STAT(RESP_ERR, ERR_notOpen)); else { if (pars < 1 || parT[0] != DT_BYTESTREAM) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { size_t i = 0; #ifdef RSERV_DEBUG printf(">>CMD_writeFile(%ld,...)\n", (long) parL[0]); #endif c = (char*)parP[0]; if (parL[0] > 0) i = fwrite(c, 1, parL[0], cf); if (i > 0 && i != parL[0]) sendResp(a, SET_STAT(RESP_ERR, ERR_IOerror)); else sendResp(a, RESP_OK); } } } } /*--- CMD_setSEXP / CMD_assignSEXP ---*/ if (ph.cmd==CMD_setSEXP || ph.cmd==CMD_assignSEXP) { process=1; if (pars < 2 || parT[0] != DT_STRING) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { SEXP val, sym=0; unsigned int *sptr; int parType = parT[1]; int boffs = 0; c=(char*)parP[0]; /* name of the symbol */ #ifdef RSERV_DEBUG printf(">>CMD_set/assignREXP (%s, REXP)\n",c); #endif if (ph.cmd==CMD_assignSEXP) { sym = parseExps(c, 1, &stat); if (stat != 1) { #ifdef RSERV_DEBUG printf(">>CMD_assignREXP-failed to parse \"%s\", stat=%d\n",c,stat); #endif sendResp(a, SET_STAT(RESP_ERR, stat)); goto respSt; } if (TYPEOF(sym)==EXPRSXP && LENGTH(sym)>0) { sym = VECTOR_ELT(sym,0); /* we should de-allocate the vector here .. if we can .. */ } } switch (parType) { case DT_STRING: #ifdef RSERV_DEBUG printf(" assigning string \"%s\"\n",((char*)(parP[1]))); #endif PROTECT(val = allocVector(STRSXP,1)); SET_STRING_ELT(val, 0, mkRChar((char*)(parP[1]))); defineVar(sym ? sym : install(c), val ,R_GlobalEnv); UNPROTECT(1); sendResp(a, RESP_OK); break; case DT_SEXP|DT_LARGE: boffs = 1; /* we're not using the size, so in fact we just advance the pointer and don't care about the length */ case DT_SEXP: sptr = ((unsigned int*)parP[1]) + boffs; val = QAP_decode(&sptr); if (val == 0) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else { PROTECT(val); #ifdef RSERV_DEBUG printf(" assigning SEXP: "); printSEXP(val); #endif defineVar(sym ? sym : install(c), val, R_GlobalEnv); UNPROTECT(1); sendResp(a, RESP_OK); } break; default: sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); } } } if (ph.cmd==CMD_detachSession) { process=1; if (!detach_session(a)) { s = resume_session(); sendResp(a, RESP_OK); } } if (ph.cmd==CMD_serEval || ph.cmd==CMD_serEEval || ph.cmd == CMD_serAssign) { SEXP us; int Rerr = 0; PROTECT(pp); us = R_tryEval(PROTECT(LCONS(install("unserialize"),PROTECT(CONS(pp,R_NilValue)))), R_GlobalEnv, &Rerr); UNPROTECT(3); PROTECT(us); a->msg_id = msg_id; /* just in case R-side used OOB */ process = 1; if (Rerr == 0) { if (ph.cmd == CMD_serAssign) { if (TYPEOF(us) != VECSXP || LENGTH(us) < 2) { sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); } else { R_tryEval(PROTECT(LCONS(install("<-"), PROTECT(CONS(VECTOR_ELT(us, 0), PROTECT(CONS(VECTOR_ELT(us, 1), R_NilValue)))))), R_GlobalEnv, &Rerr); UNPROTECT(3); a->msg_id = msg_id; /* just in case R-side used OOB (unlikely, but ...) */ if (Rerr == 0) sendResp(a, RESP_OK); else sendResp(a, SET_STAT(RESP_ERR, Rerr)); } } else { SEXP ev = R_tryEval(us, R_GlobalEnv, &Rerr); a->msg_id = msg_id; /* just in case R-side used OOB */ if (Rerr == 0 && ph.cmd == CMD_serEEval) /* one more round */ ev = R_tryEval(ev, R_GlobalEnv, &Rerr); PROTECT(ev); if (Rerr == 0) { SEXP sr = R_tryEval(PROTECT(LCONS(install("serialize"), PROTECT(CONS(ev, PROTECT(CONS(R_NilValue, R_NilValue)))))), R_GlobalEnv, &Rerr); UNPROTECT(3); a->msg_id = msg_id; /* just in case R-side used OOB */ if (Rerr == 0 && TYPEOF(sr) == RAWSXP) { sendRespData(a, RESP_OK, LENGTH(sr), RAW(sr)); } else if (Rerr == 0) Rerr = -2; } UNPROTECT(1); } UNPROTECT(1); if (Rerr) { sendResp(a, SET_STAT(RESP_ERR, Rerr)); } } } if (ph.cmd == CMD_voidEval || ph.cmd == CMD_eval || ph.cmd == CMD_detachedVoidEval) { int is_large = (parT[0] & DT_LARGE) ? 1 : 0; if (is_large) parT[0] ^= DT_LARGE; process = 1; if (pars < 1 || (parT[0] != DT_STRING && parT[0] != DT_SEXP)) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); else if (parT[0] == DT_SEXP) { unsigned int *sptr = ((unsigned int*)parP[0]) + is_large; SEXP val = QAP_decode(&sptr); if (!val) { #ifdef RSERV_DEBUG printf(" FAILED to decode SEXP parameter\n"); #endif sendResp(a, SET_STAT(RESP_ERR, ERR_inv_par)); } else { PROTECT(val); #ifdef RSERV_DEBUG printf(" running eval on SEXP: "); printSEXP(val); #endif eval_result = R_tryEval(val, R_GlobalEnv, &Rerror); a->msg_id = msg_id; /* just in case R-side used OOB */ UNPROTECT(1); } } else { int j = 0; c = (char*)parP[0]; if (is_large) c += 4; #ifdef RSERV_DEBUG printf("parseString(\"%s\")\n",c); #endif SEXP xp = parseString(c, &j, &stat); PROTECT(xp); #ifdef RSERV_DEBUG printf("buffer parsed, stat=%d, parts=%d\n", stat, j); if (xp) printf("result type: %d, length: %d\n",TYPEOF(xp),LENGTH(xp)); else printf("result is \n"); #endif if (stat == 1 && ph.cmd == CMD_detachedVoidEval && detach_session(a)) sendResp(a, SET_STAT(RESP_ERR, ERR_detach_failed)); else if (stat != 1) sendResp(a, SET_STAT(RESP_ERR, stat)); else { #ifdef RSERV_DEBUG printf("R_tryEval(xp,R_GlobalEnv,&Rerror);\n"); #endif if (ph.cmd==CMD_detachedVoidEval) s = -1; if (TYPEOF(xp) == EXPRSXP && LENGTH(xp) > 0) { int bi = 0; while (bi < LENGTH(xp)) { SEXP pxp = VECTOR_ELT(xp, bi); Rerror = 0; #ifdef RSERV_DEBUG printf("Calling R_tryEval for expression %d [type=%d] ...\n",bi+1,TYPEOF(pxp)); #endif eval_result = R_tryEval(pxp, R_GlobalEnv, &Rerror); bi++; #ifdef RSERV_DEBUG printf("Expression %d, error code: %d\n", bi, Rerror); if (Rerror) printf(">> early error, aborting further evaluations\n"); #endif if (Rerror) break; } } else { Rerror = 0; eval_result = R_tryEval(xp, R_GlobalEnv, &Rerror); } } UNPROTECT(1); /* xp */ a->msg_id = msg_id; /* just in case R-side used OOB */ } } /* any command above can set eval_result -- in that case we encode the result and send it as the reply */ if (eval_result || Rerror) { SEXP exp = eval_result ? PROTECT(eval_result) : R_NilValue; #ifdef RSERV_DEBUG printf("expression(s) evaluated (Rerror=%d).\n",Rerror); if (!Rerror) printSEXP(exp); #endif if (ph.cmd == CMD_detachedVoidEval && s == -1) s = resume_session(); if (Rerror) { sendResp(a, SET_STAT(RESP_ERR, (Rerror < 0) ? Rerror : -Rerror)); } else { if (ph.cmd == CMD_voidEval || ph.cmd == CMD_detachedVoidEval) sendResp(a, RESP_OK); else { char *sendhead = 0; int canProceed = 1; /* check buffer size vs REXP size to avoid dangerous overflows todo: resize the buffer as necessary */ rlen_t rs = QAP_getStorageSize(exp); /* FIXME: add a 4k security margin - it should no longer be needed, originally the space was grown proportionally to account for a bug, but that bug has been fixed. */ #ifdef RSERV_DEBUG printf("result storage size = %ld bytes\n",(long)rs); #endif if (rs >= 0) rs += 4096; if (rs < 0 || rs > sendBufSize - 64L) { /* encoding error or is the send buffer too small ? */ canProceed = 0; if ((rs < 0) || (maxSendBufSize && rs + 64L > maxSendBufSize)) { /* first check if we're allowed to resize */ unsigned int osz = (rs > 0xffffffff) ? 0xffffffff : rs; osz = itop(osz); #ifdef RSERV_DEBUG if (rs < 0) printf("ERROR: object encoding error\n"); else printf("ERROR: object too big (sendBuf=%ld)\n", (long) sendBufSize); #endif sendRespData(a, SET_STAT(RESP_ERR, ERR_object_too_big), 4, &osz); } else { /* try to allocate a large, temporary send buffer */ tempSB = rs + 64L; tempSB &= rlen_max ^ 0xfff; tempSB += 0x1000; #ifdef RSERV_DEBUG printf("Trying to allocate temporary send buffer of %ld bytes.\n", (long)tempSB); #endif free(sendbuf); sendbuf = (char*)malloc(tempSB); if (!sendbuf) { tempSB = 0; #ifdef RSERV_DEBUG printf("Failed to allocate temporary send buffer of %ld bytes. Restoring old send buffer of %ld bytes.\n", (long)tempSB, (long)sendBufSize); #endif sendbuf = (char*)malloc(sendBufSize); if (!sendbuf) { /* we couldn't re-allocate the buffer */ #ifdef RSERV_DEBUG fprintf(stderr,"FATAL: out of memory while re-allocating send buffer to %ld (fallback#1)\n", (long) sendBufSize); #endif sendResp(a, SET_STAT(RESP_ERR, ERR_out_of_mem)); free(buf); free(sfbuf); if (uses_tls) close_tls(a); closesocket(s); free(a); return; } else { unsigned int osz = (rs > 0xffffffff) ? 0xffffffff : rs; osz = itop(osz); #ifdef RSERV_DEBUG printf("ERROR: object too big (sendBuf=%ld) and couldn't allocate big enough send buffer\n", (long) sendBufSize); #endif sendRespData(a, SET_STAT(RESP_ERR, ERR_object_too_big), 4, &osz); } } else canProceed = 1; } } if (canProceed) { /* first we have 4 bytes of a header saying this is an encoded SEXP, then comes the SEXP */ char *sxh = sendbuf + 8; tail = (char*)QAP_storeSEXP((unsigned int*)sxh, exp, rs); /* set type to DT_SEXP and correct length */ if ((tail - sxh) > 0xfffff0) { /* we must use the "long" format */ rlen_t ll = tail - sxh; ((unsigned int*)sendbuf)[0] = itop(SET_PAR(DT_SEXP | DT_LARGE, ll & 0xffffff)); ((unsigned int*)sendbuf)[1] = itop(ll >> 24); sendhead = sendbuf; } else { sendhead = sendbuf + 4; ((unsigned int*)sendbuf)[1] = itop(SET_PAR(DT_SEXP,tail - sxh)); } #ifdef RSERV_DEBUG printf("stored SEXP; length=%ld (incl. DT_SEXP header)\n",(long) (tail - sendhead)); #endif sendRespData(a, RESP_OK, tail - sendhead, sendhead); if (tempSB) { /* if this is just a temporary sendbuffer then shrink it back to normal */ #ifdef RSERV_DEBUG printf("Releasing temporary sendbuf and restoring old size of %ld bytes.\n", (long) sendBufSize); #endif free(sendbuf); sendbuf = (char*)malloc(sendBufSize); if (!sendbuf) { /* this should be really rare since tempSB was much larger */ #ifdef RSERV_DEBUG fprintf(stderr,"FATAL: out of memory while re-allocating send buffer to %ld (fallback#2),\n", (long) sendBufSize); #endif sendResp(a, SET_STAT(RESP_ERR, ERR_out_of_mem)); free(buf); free(sfbuf); if (uses_tls) close_tls(a); closesocket(s); free(a); return; } } } } if (eval_result) UNPROTECT(1); /* exp / eval_result */ } #ifdef RSERV_DEBUG printf("reply sent.\n"); #endif } /* END if (eval_result) */ respSt: if (s == -1) { rn = 0; break; } if (!process) sendResp(a, SET_STAT(RESP_ERR, ERR_inv_cmd)); } #ifdef RSERV_DEBUG if (rn == 0) printf("Connection closed by peer.\n"); else { printf("malformed packet (n=%d). closing socket to prevent garbage.\n", rn); if (rn > 0) printDump(&ph, rn); } #endif if (rn > 0) sendResp(a, SET_STAT(RESP_ERR, ERR_conn_broken)); if (uses_tls) close_tls(a); closesocket(s); free(sendbuf); free(sfbuf); free(buf); free(a); ulog("INFO: closed connection"); #ifdef RSERV_DEBUG printf("done.\n"); #endif #ifdef FORKED /* we should not return to the main loop, but terminate instead */ exit(0); #endif } typedef void (*sig_fn_t)(int); #ifdef unix /* NULL ptr is used on some systems as SIG_DFL so we have to define our own value for "not set" */ static void sig_not_set(int x) {} sig_fn_t old_HUP = sig_not_set, old_TERM = sig_not_set, old_INT = sig_not_set; static void setup_signal_handlers(void) { #ifdef FORKED if (old_HUP == sig_not_set) old_HUP = signal(SIGHUP, sigHandler); if (old_TERM == sig_not_set) old_TERM = signal(SIGTERM, sigHandler); if (old_INT == sig_not_set) old_INT = signal(SIGINT, brkHandler); #endif } static void restore_signal_handlers(void) { if (old_HUP != sig_not_set) { signal(SIGHUP, old_HUP); old_HUP = sig_not_set; } if (old_TERM != sig_not_set) { signal(SIGTERM, old_TERM); old_TERM = sig_not_set; } if (old_INT != sig_not_set) { signal(SIGINT, old_INT); old_INT = sig_not_set; } } #else static void setup_signal_handlers(void) { } static void restore_signal_handlers(void) { } #endif #define MAX_SERVERS 128 static int servers; static server_t *server[MAX_SERVERS]; int add_server(server_t *srv) { if (!srv) return 0; if (servers >= MAX_SERVERS) { RSEprintf("ERROR: too many servers\n"); return 0; } server[servers++] = srv; #ifdef RSERV_DEBUG printf("INFO: adding server %p (total %d servers)\n", (void*) srv, servers); #endif return 1; } int rm_server(server_t *srv) { int i = 0; if (!srv) return 0; while (i < servers) { if (server[i] == srv) { int j = i + 1; while (j < servers) { server[j - 1] = server[j]; j++; } servers--; } else i++; } if (srv->fin) srv->fin(srv); #ifdef RSERV_DEBUG printf("INFO: removing server %p (total %d servers left)\n", (void*) srv, servers); #endif return 1; } server_t *create_Rserve_QAP1(int flags) { server_t *srv; if (use_ipv6) flags |= SRV_IPV6; if (localonly) flags |= SRV_LOCAL; srv = create_server((flags & SRV_TLS) ? tls_port : port, localSocketName, localSocketMode, flags); if (srv) { srv->connected = Rserve_QAP1_connected; srv->send_resp = Rserve_QAP1_send_resp; srv->fin = server_fin; srv->recv = server_recv; srv->send = server_send; add_server(srv); return srv; } return 0; } void serverLoop(void) { struct timeval timv; int selRet = 0; fd_set readfds; if (main_argv && tag_argv == 1 && strlen(main_argv[0]) >= 8) { strcpy(main_argv[0] + strlen(main_argv[0]) - 8, "/RsrvSRV"); tag_argv = 2; } ulog("INFO: Rserve server loop started"); while(active && (servers || children)) { /* main serving loop */ int i; int maxfd = 0; #ifdef FORKED while (waitpid(-1, 0, WNOHANG) > 0); #endif /* 500ms (used to be 10ms) - it shouldn't really matter since it's ok for us to sleep -- the timeout will only influence how often we collect terminated children and (maybe) how quickly we react to shutdown */ timv.tv_sec = 0; timv.tv_usec = 500000; FD_ZERO(&readfds); for (i = 0; i < servers; i++) if (server[i]) { int ss = server[i]->ss; if (ss > maxfd) maxfd = ss; FD_SET(ss, &readfds); } selRet = select(maxfd + 1, &readfds, 0, 0, &timv); if (selRet > 0) { for (i = 0; i < servers; i++) { socklen_t al; struct args *sa; server_t *srv = server[i]; int ss = srv->ss; int succ = 0; if (server[i] && FD_ISSET(ss, &readfds)) { /* sa is allocated here, and must be freed before the end of the iteration. The connected(sa) API function assumes ownership of sa so it MUST free the pointer even on error. Conversely, sa may NOT be used here once connected() was called. FIXME: we could change the semantics to not transfer ownership to avoid leaks in server implementations, but 1) it would require all implementations to change and 2) they may add nested structures to the payload which they control so those may still leak if we are responsible */ sa = (struct args*)malloc(sizeof(struct args)); memset(sa, 0, sizeof(struct args)); al = sizeof(sa->sa); #ifdef unix if (server[i]->unix_socket) { al = sizeof(sa->su); sa->s = CF("accept", accept(ss, (SA*)&(sa->su), &al)); } else #endif sa->s = CF("accept", accept(ss, (SA*)&(sa->sa), &al)); accepted_server(srv, sa->s); sa->ucix = UCIX++; sa->ss = ss; sa->srv = srv; /* memset(sa->sk,0,16); sa->sfd=-1; #if defined SESSIONS && defined FORKED { int pd[2]; if (!pipe(&pd)) { } } #endif */ if (allowed_ips && !srv->unix_socket && !use_ipv6) { /* FIXME: IPv6 unsafe - filtering won't work on IPv6 addresses */ char **laddr = allowed_ips; int allowed = 0; while (*laddr) if (sa->sa.sin_addr.s_addr == inet_addr(*(laddr++))) { allowed=1; break; } if (allowed) { #ifdef RSERV_DEBUG printf("INFO: accepted connection for server %p, calling connected\n", (void*) srv); #endif srv->connected(sa); succ = 1; #ifdef FORKED /* when the child returns it means it's done (likely an error) but it is forked, so the only right thing to do is to exit */ if (is_child) exit(2); #endif } else { #ifdef RSERV_DEBUG printf("INFO: peer is not on allowed IP list, closing connection\n"); #endif closesocket(sa->s); free(sa); } } else { /* ---> remote enabled */ #ifdef RSERV_DEBUG printf("INFO: accepted connection for server %p, calling connected\n", (void*) srv); #endif srv->connected(sa); succ = 1; if (is_child) /* same as above */ exit(2); } #ifdef Win32 } } } #else } if (succ) { /* if there was an actual connection, offer to run .Rserve.served */ SEXP fun, fsym = install(".Rserve.served"); int evalErr = 0; fun = findVarInFrame(R_GlobalEnv, fsym); if (Rf_isFunction(fun)) R_tryEval(lang1(fsym), R_GlobalEnv, &evalErr); } } /* end loop over servers */ } /* end if (selRet > 0) */ #endif } /* end while(active) */ ulog("INFO: Rserve server loop end"); } #ifndef STANDALONE_RSERVE /* run Rserve inside R */ SEXP run_Rserve(SEXP cfgFile, SEXP cfgPars) { server_stack_t *ss; if (TYPEOF(cfgFile) == STRSXP && LENGTH(cfgFile) > 0) { int i, n = LENGTH(cfgFile); for (i = 0; i < n; i++) loadConfig(CHAR(STRING_ELT(cfgFile, i))); } if (TYPEOF(cfgPars) == STRSXP && LENGTH(cfgPars) > 0) { int i, n = LENGTH(cfgPars); SEXP sNam = Rf_getAttrib(cfgPars, R_NamesSymbol); if (TYPEOF(sNam) != STRSXP || LENGTH(sNam) != n) Rf_error("invalid configuration parameters"); for (i = 0; i < n; i++) { const char *key = CHAR(STRING_ELT(sNam, i)); const char *value = CHAR(STRING_ELT(cfgPars, i)); int res = setConfig(key, value); if (res == 0) Rf_warning("Unknown configuration setting `%s`, ignored.", key); } } if (src_list) Rf_warning("server/eval configuration only applies to stand-alone Rserve and is ignored in run.Rserve()."); RSsrv_init(); /* FIXME: should we really do this ? setuid, chroot etc. are not meant to work inside R ... */ performConfig(SU_NOW); ss = create_server_stack(); if (enable_qap) { server_t *srv = create_Rserve_QAP1((qap_oc ? SRV_QAP_OC : 0) | global_srv_flags); if (!srv) { release_server_stack(ss); RSsrv_done(); Rf_error("Unable to start Rserve server"); } ulog("INFO: started QAP1 server (%s)", qap_oc ? "OCAP" : "eval"); push_server(ss, srv); } if (tls_port > 0) { server_t *srv = create_Rserve_QAP1(SRV_TLS | (qap_oc ? SRV_QAP_OC : 0) | global_srv_flags); if (!srv) { release_server_stack(ss); RSsrv_done(); Rf_error("Unable to start TLS/Rserve server"); } ulog("INFO: started TLS server (%s)", qap_oc ? "OCAP" : "eval"); push_server(ss, srv); } if (http_port > 0) { int flags = (enable_ws_qap ? WS_PROT_QAP : 0) | (enable_ws_text ? WS_PROT_TEXT : 0) | (ws_qap_oc ? SRV_QAP_OC : 0) | global_srv_flags; server_t *srv = create_HTTP_server(http_port, flags | (ws_upgrade ? HTTP_WS_UPGRADE : 0) | (http_raw_body ? HTTP_RAW_BODY : 0)); if (!srv) { release_server_stack(ss); RSsrv_done(); Rf_error("Unable to start HTTP server on port %d", http_port); } ulog("INFO: started HTTP server on port %d%s%s", http_port, enable_ws_qap ? " + WebSockets-QAP1" : "", ws_upgrade ? " + WebSocket Upgrade" : ""); push_server(ss, srv); } if (https_port > 0) { int flags = (enable_ws_qap ? WS_PROT_QAP : 0) | (enable_ws_text ? WS_PROT_TEXT : 0) | (ws_qap_oc ? SRV_QAP_OC : 0) | global_srv_flags; server_t *srv = create_HTTP_server(https_port, SRV_TLS | flags | (ws_upgrade ? HTTP_WS_UPGRADE : 0) | (http_raw_body ? HTTP_RAW_BODY : 0)); if (!srv) { release_server_stack(ss); RSsrv_done(); Rf_error("Unable to start HTTPS server on port %d", https_port); } ulog("INFO: started HTTPS server on port %d%s%s", https_port, enable_ws_qap ? " + WebSockets-QAP1" : "", ws_upgrade ? " + WebSocket Upgrade" : ""); push_server(ss, srv); } if (enable_ws_text || enable_ws_qap) { server_t *srv; if (ws_port < 1 && wss_port < 1 && !ws_upgrade) { release_server_stack(ss); RSsrv_done(); Rf_error("Invalid or missing websockets port"); } if (ws_port > 0) { srv = create_WS_server(ws_port, (enable_ws_qap ? WS_PROT_QAP : 0) | (enable_ws_text ? WS_PROT_TEXT : 0) | (ws_qap_oc ? SRV_QAP_OC : 0) | global_srv_flags); if (!srv) { release_server_stack(ss); RSsrv_done(); Rf_error("Unable to start WebSockets server on port %d", ws_port); } push_server(ss, srv); } if (wss_port > 0) { srv = create_WS_server(wss_port, (enable_ws_qap ? WS_PROT_QAP : 0) | (enable_ws_text ? WS_PROT_TEXT : 0) | (ws_qap_oc ? SRV_QAP_OC : 0) | WS_TLS | global_srv_flags); if (!srv) { release_server_stack(ss); RSsrv_done(); Rf_error("Unable to start TLS/WebSockets server on port %d", wss_port); } push_server(ss, srv); } } if (!server_stack_size(ss)) { Rf_warning("No server protocol is enabled, nothing to do"); release_server_stack(ss); RSsrv_done(); return ScalarLogical(FALSE); } setup_signal_handlers(); Rprintf("-- running Rserve in this R session (pid=%d), %d server(s) --\n(This session will block until Rserve is shut down)\n", getpid(), server_stack_size(ss)); ulog("INFO: Rserve in R session (pid=%d), %d server(s)\n", getpid(), server_stack_size(ss)); active = 1; serverLoop(); restore_signal_handlers(); release_server_stack(ss); RSsrv_done(); return ScalarLogical(TRUE); } #endif #endif /*--- The following makes the indenting behavior of emacs compatible with Xcode's 4/4 setting ---*/ /* Local Variables: */ /* indent-tabs-mode: t */ /* tab-width: 4 */ /* c-basic-offset: 4 */ /* End: */ Rserve/NEWS0000644000175100001440000014067114531234224012246 0ustar hornikusers NEWS/Changelog for Rserve --------------------------- NOTE: Rserve 1.8 series has many new features, but it has also removed support for control commands. If you absolutely need them, please use Rserve 1.7 series and notify me so I can assess whether they may be resurrected for the 1.9 series. If you don't know what it means, just ignore this note. 1.8-13 2023-11-28 o replace sprintf with snprintf even in safe cases to avoid compiler warnings. 1.8-12 2023-08-17 o added a work-around for buggy libcrypt (first seen in Ubuntu 22.04) which incorrectly uses salt leading to authentication error if crypt is used even with a correct password. (#192) o parsing of dates in conditional requests could be off, leading to fewer 304 Not Modified responses than expected (proxy). o added experimental built-in feature in Rserve's HTTP(s) server to serve static files directly (similar to the feature of the forward proxy). Multiple prefixes can be registered to serve static content from different paths using the Rserve:::Rserve.http.add.static() function. Static handlers are processed before R handers, but they can pass on requests if the file is not found. Conditional requests are supported. 1.8-11 2022-11-28 o fix possible buffer overflow attacks in WebSockets code (many thanks to Dane Henshall for performing a security audit!) o clean up code to avoid mixing 32-bit and 64-bit integers on 64-bit platforms o enhance `Rserve.eval()` to report the condition object for error conditions in the `condition` component of the `Rserve-eval-error` object (#154) and to support custom calling handlers. This is done by adding a new argument `handlers` to `Rserve.eval()` which allows registration of calling handlers for the duration of the evaluation. The default is to register an `error` handler which stores the condition (via `Rserve_set_last_condition`) so `Rserve.eval` can pick it up and return in the `condition` component. To revert to previous behavior, use `handers=NULL` which prevents the registration of handlers. o Issue a warning if eval/source configuration directive is used in `run.Rserve()` since they only affect stand-alone Rserve daemon startup and thus setting them in an R session is likely a mistake (as the user can run R code directly in the session prior to calling `run.Rserve()` instead). 1.8-10 2021-11-25 o reduce the size of the authkey (nonce) in CMD_reqKey to 256 bytes such that the payload of CMD_secLogin can fit into one encryption block (for 4096-bit RSA key). This improves the nonce entropy size from 50 bytes to 256. Note that effectively the maximum safe size of the authentication payload is 206 bytes. Larger sizes can be transmitted, but should be considered unsafe due to the second block not including any nonce. o Prevent replay attacks on non-forked servers using CMD_secLogin without CMD_keyReq. (Thanks to Dane Henshall for reporting!) Deployments relying on CMD_secLogin for authentication should upgrade to this version to avoid vulnerability. Note that clients do not have to be updated. o Respect CPPFLAGS and LDFLAGS from R CMD config 1.8-9 2021-11-05 o move m4 under tools according to R-exts 1.2 o several fixes to QAP encoding/decoding, use R_xlen_t type for indexing if available (previously Windows builds used 32-bit index due to long int size limits). o protection fixes for serialized commands o remove rsio entirely since it is not used 1.8-8 2021-10-31 o add basic ulog logging for QAP1 even outside of OCAP mode (#169) o TLS configuration options now check the success of the operation and will issue a warning if it failed. Most importantly `tls.key` must succeed in order for the server to support TLS. o New option `tls.client` governs the treatment of client certificates. There are following possible values: none - does not ask nor check the client certificate request - request certificate from the client, but do not check its validity require - require client certificate, if not present or not valid, reject the connection match:... - client's common name must match exactly one of the listed (comma-separated) names. No spaces are allowed around the commas. prefix:... - the client's common name must start with the specified prefix suffix:... - the client's common name must end with the specified suffix The options `match`, `prefix` and `suffix` imply `require`. Each of them can be specified only once. However, it is possible to use up to one each in which case the requirement is treated as logical "or", e.g., tls.client match:foo.bar tls.client suffix:me.com will allow both clients `foo.bar` and `foo.me.com`. NOTE: `none`/`request`/`require` are mutually exclusive. If more than one is specified, the behavior is undefined (currently the last one wins but that shold not be relied upon). All comparisons are case-senstitive (sorry, no regex support at this point, because we do not want to depend on PCRE just yet). If the `tls.client` option is not specified, then the default behavior is one of `none` or `request`. In that case no attempt is made to control the TLS behavior so it depends on the SSL library's default whether it asks for the client certificate or not, but in either case it is not checked. NOTE: probably the best way to use the new feature is to use certificates issued by your organization with `tls.client require` and `tls.ca` set to the organization's CA certificate which means you don't need to check client names and yet no unauthorized client can connect. o -DULOG_STDERR now correctly produces ulog output on stderr and ulog output is visible in the debug build o TLS shutdowns are performed explicitly and sockets closed (only affects non-forking servers) o several possible leaks of arguments under error conditions were fixed 1.8-7 2020-12-17 o proxy: fail with an error if no servers can bind (#152) o proxy: fail if SSL cannot be initialized o include err.h SSL header outside of debug mode 1.8-6 2020-06-11 o proxy: handle WebSockets control frames (PING/PONG/CLOSE) proper. o proxy: fail with an error if key/certificate cannot be loaded at start time. Both -k and -c are required to enable TLS/SSL. Also the proxy will issues an error if -k is used and SSL support has not been available at compile time. (#127) o proxy: linking no longer hard-codes `-lssl` (it effectively failed compilation when SSL was not available). o proxy: added -S [:] which allows automatic registration and de-registation with a server manager when the service is available (e.g., this can be used to keep the compute node list up-to-date automatically when load-balancing via the nginx reverse proxy). o support large vectors in QAP encoding/decoding o restore some Windows compatibility - at least to the point where it compiles. It is still strongly discouraged to use Windows given how limited the OS is and how it prevents any sensible use (Windows only supports single-client, single-thread, cooperative mode - so for toy uses only). o content-type header entry is lower-cased only up to a semicolon since trailing options may be case-sensitive. (#149) 1.8-5 2017-03-25 o add support for callback in OCAP idle mode. If the function .ocap.idle() exists in the global environment and the configuration option use.idle.callback yes is set then that function is called inside each OCAP iteration after a timeout of 200ms (i.e., if R is idle in the OCAP loop with no input from any side for at least 200ms). o control commands are now officially disabled since they never worked reliably in the 1.8 series after the the rsio re-write. 1.8-4 2015-12-23 o bugfix: when using compute separation on some Linux systems the death of the compute process may remain undetected. Rserve now actively detects if the compute process has terminated and will signal accordingly. The same goes of a compute process whose parent has died. o bugfix: make sure headers are correctly terminated when using forward proxy and R scripts. o bugfix: static files served by the proxy had duplicate (and possibly conflicting) content-type headers. 1.8-3 2015-07-20 o add support for the notion of a context object which can be retrieved/set using Rserve.context() function. If io.use.context yes configuration option is set then the context is passed as-is in OOB console callbacks as the first argument after the callback name. Rserve.eval() can also safely set a context object for the duration of the evaluation which guarantees that any previous context is restored upon exit - both on error or success. o added WebSockets/QAP proxy and HTTP server. It is a stand-alone program that can be used to separate the R process from the network to enhance security. typical setup is for the proxy to listen on an outside port and connect to Rserve on a local (unix) socket which is restricted to the user running the proxy. It is enabled by default and installed into the package's libs directory along with the Rserve binaries. It is, however, not installed into $R_HOME/bin. The building of the proxy can be disabled via --disable-proxy configure directive. 1.8-2 2015-05-20 o fix bug in the WebSockets protocol implementation where frames over 64kB from the client may be parsed incorrectly. 1.8-1 2015-04-08 o add ulog() R function to allow custom logging from R code o add "fork here" directive which allows to spawn multiple pre-forked instances of Rserve which all share the same memory. The rest of the configuration file is then ignored in the forked instance while the parent server instance continues to read on. This can be useful on machines with many cores and very short requests where the serial fork() time for each connection is in the order of the computing time. Note that by design this only works in configuration files and cannot be used on the command line. o daemonize only *after* all servers have been bound such the exit code can be used to detect if Rserve has actually started successfully o add Rserve.eval() function to perfrom REPL-like evaluation o add a new config option to close all stdio file descriptors (stdin, stdout, stderr) on daemonization: close.all.stdio enable For compatibiliy the default is false. o Rserve will honor --silent command line option (destined for R) to not print the "Rserve started .." line. o add support for console input OOB message, enabled via console.input enable When enabled R will request input to ReadConsole by sending a OOB message to the client, expecting back a string to be used as input to the console. It is only honored if console.oob is also enabled. 1.8-0 2014-09-03 o new logging mechanism has been added to Rserve. It can be enabled using the ulog directive and uses syslogd-compatible unix socket or UDP datagram transfer to log events. Currently, only OCAP events are logged. o OCAPs can now be tagged with a name o avoid duplicate symbols by not loading the Rserve dylib inside an embedded Rserve instance. This avoid issues of calling the wrong symbols, but it implies that run.Rserve() can no longer be used from within a child proces of an embedded Rserve instance (which you really don't want to do anyway). o symbols are now registered *before* processing source/eval directives from the configuration file o added new option to remove the working directory on session close recursively - activated by workdir.clean enable If not set, the default is to only remove it if it is empty (on the assumption there are files that will be served beyond the life of the session). o added workdir.parent.mode option which specifies the permissions on the parent directory of session working directories. The default is 0755. Unlike workdir.mode this one does not respect the umask (beause it may be shared and thus may need to include permissions that are otherwise not granted). o the data offset field in the QAP header is deprecated and can be used for message ID if enabled using msg.id enable In that mode all responses will copy the message ID from the request and new requests (such as OOB send/msg) will use randomly generated message IDs. This allows clients to more easily track responses for nested commands. Note that this is backwards-compatible if old clients use the convention of 0 data offset which was the norm (as long as OOB is not used). o nested evaluation is supported in OCAP mode. This means that OCcall followed by another OCcall can be processed before the first call terminates if the R side issues an OOB message in which case the second OCcall will be nested within the first call. o allow expansion of environment variables in the configuration file, i.e., ${VAR} will be replaced with the contents of the VAR environemnt variable. This only applies to the right-hand side of configuration directives. o added command line argument --RS-set which allows any configuration directive that is accepted in the configuration file to be specified on the command line as --RS-set directive=value o fix a typo in the "daemon" configuration option which was looking for "deamon" instead. o added support for console callbacks. They can be enabled using console.oob enable directive and they result in OOB messages being sent on console I/O operations. o add a configuration option "shutdown disable" that will disable the shutdown command. This makes is a bit harder for unprivileged users to shut down the Rserve instance. It does not disable the ctrlShutdown command, so users that have control command access can still issue a shutdown. Note that this option will eventually become the default so consider specifically using "shutdown enable" where CMD_shutdown is still needed. Note that the shutdown command is not functional in cases where user switching is performed anyway, so is it only used for backward compatibility. Only ctrlShutdown is guaranteed to work. o add a configuration option "oob.idle.interval" which will trigger automated OOB send of "idle" command after a specified interval. Currently it only works with WebSockets. o add a configuration option "forward.stdio enable" which will enable capturing of stdout/err and forward it to the peer via OOB send messages. Note that this requires thread support and uses additional file descriptors. It in currently only available in OCAP WebSockets. o bugfix: pairlists were incorrecty protected when parsing SEXPs (qap_decode) in messages from client to server (#16). 1.7-3 2013-08-21 o the handling of server configuration modes has been inconsistent for some combinations (mostly affected were combinations involving WebSockets upgrade and OC mode on HTTP/WS servers). Also the websockets.qap.oc configuration option has been misspelled. o HTTPS->WSS upgrade is now supported o mkdist -i installs the built package, use -c for check o Windows compatibility has been restored thanks to David Champagne from Revolution Analytics 1.7-2 2013-08-12 o when uid/gid is changed, create a new tempdir() and set its permissions as well as the wokring directory's owner to match. o bugfix: if the first command is not any of the eval family the Rserve may respond with an additional, spurious error response o deamonized server would record incorrect pid when pid.file is used (i#5). The pid is now removed on clean sutdown. o added support for keep.alive configuration option - it is global to all servers and if enabled the client sockets are instructed to keep the connection alive by periodic messages. 1.7-1 2013-07-02 o remove a spurious character that prevented compilation on Suns o add OPENSSL_INCLUDES precious variable that can be used to point to non-standard location of OpenSSL headers o check the usability of OpenSSL headers before enabling TLS support o added the choice of GPLv2 or GPLv2 with OpenSSL linking exception 1.7-0 *** ---- HEADLINE NEWS ---- *** new protocols: HTTP, HTTPS, WebSockets and TLS/QAP *** added protocol switching (from QAP to TLS/QAP) via CMD_switch *** The R client was moved to RSclient package *** New in-session server support with run.Rserve() *** Out-of-band messages via self.oobSend() *** user-based uid/gid switch, MD5/SHA1 stored passwords *** preliminary IPv6 support; RSA secure authentication *** .Rserve.done global env hook for optiopnal cleanup *** auth.function setting to allow custom authentication *** Object-capability mode for hardened, secure services *** ---- END - see below for details ---- o This is the first release in the new 1.x Rserve series. Many of the Rserve internals have been re-written or cleaned up. The original protocol remains the same (so all clients that worked with Rserve 0.6 will continue to work), but the suite of available protocols has been extended (see below). o added support for multiple protocols in Rserve: ** QAP ** this is the original Rserve protocol used in Rserve 0.x series. It works over TCP/IP and unix sockets. It is enabled by default and can be disabled using "qap disable" configuration directive. ** HTTP ** this is very similar to the built-in R http server except that on unix it forks on connection so it allows parallel separate, persistent connections. It requires a worker function .http.request to be defined in the session which will handle incoming requests. This allows the use of facilities like FastRWeb without an external webserver. This protocol is disabled by default and can be enabled by setting "http.port" configuration directive to the desired port to listen to. (Also see TLS support below for https server). The http.raw.body configuration option (default is false which results in the same behavior as Rhttpd) can be used to force passing body in raw form to the handler (useful for the FastRWeb handler which does its own parsing). ** WebSockets ** this protocol is used by HTML5 web browsers for direct access to R with a persistent connection. This allows implementation of websites that have a dedicated R session (and could be used as an R console). There are two subprotocols supported by Rserve: -- WebSocket(*, "QAP") -- this is a tunnel for the original QAP protocol through WebSockets. It requires a browser capable of binary WebSockets protocol (version 01 or higher). It allows very efficient data transfer, typically by loading ArrayBuffers directly into GPU or CPU. It is disabled by default and can be enabled using "websockets.qap enable" configuration directive. (If no subprotocol is specified, QAP is assumed) -- WebSocket(*, "text") -- this is a very simplistic protocol using plain text frames to send input to R and output from R directly as text. It acts essentially as an R console. This protocol works with any WebSockets implementation including version hybi-00 and hixie-75/76 It is disabled by default and can be enabled using "websockets.text enable" configuration directive. NOTE: The textual WebSockets protocol does NOT provide any authentication mechanism, so use with extreme care as you are essentially giving any user with a web browser access to R and thus to the shell. In addition to enabling each or both subprotocols, the port on which the WebSockets server should listen must be specified in the configuration using "websockets.port" directive, for example "websockets.port 8080". Alternatively, the HTTP server can be enabled to allow connection upgrade to WebSockets on the same port with "http.upgrade.websockets enable" NOTE: remember that the default in Rserve is to disallow remote connections, so you may need to use "remote enable" in order to use WebSockets or HTTP in practice, since the point is to serve remote machines. Typically, if both QAP and either HTTP or WebSockets are used, it is recommended to use QAP on a local unix socket for better access control. o Rserve now supports SSL/TLS connections on QAP, HTTP and WS protocols. The TLS key/CA entries are common for all protocols. The relevant new configuration directives are: tls.key tls.cert tls.ca SSL/TLS can be used in several ways: with separate port for TLS connections or by switching protocol form a regular QAP connection using CMD_switch with "TLS" as argument. The latter can be enabled using switch.qap.tls enable Enabled switching is advertized by Rserve with the presence of a "TLS" entry in the ID string. Keys and other TLS entries must be initialized in order for TLS to be enabled. Dedicated TLS servers can be enabled by specifying the port for the corresponding protocol: qap.tls.port - for Rserve/QAP http.tls.port - for HTTPS websockets.tls.port - for WebSockets (there are synonyms "https.port" for "http.tls.port" and "tls.port" for "qap.tls.port", however, the *.tls.port versions are preferred for clarity) The use of TLS protocols is encouraged where sensitive data is transmitted or when requiring secure authentication. For QAP protocol, using TCL/QAP with SHA1 passwords (also new, see below) is the currently recommended way where authorization is required. The only drawback is increased CPU utilization during transfers casued by the encryption and the fact that TLS-enabled clients must be used. See also RSA secure authentication (CMD_keyReq + CMD_secLogin) for a different method if only the authentication step is to be encrypted. When enabling TLS tls.key and tls.cert are mandatory, tls.ca is optional to establish CA chain of trust (whether this is needed depends on the client and the certificate). To generate a key and self-signed certificate, you can use something like openssl genrsa -out server.key 2048 openssl req -new -key server.key -out server.csr openssl x509 -req -days 365 -in server.csr \ -signkey server.key -out server.crt NOTE: TLS services are started **in addition** to any other servers, i.e., if you want to enable TLS/QAP only, you have to set tls.qap.port but also add "qap disable" to disable the plain Rserve access. o QAP servers (classic Rserve QAP, QAP/TLS and WebSocket/QAP) support object-capability (OC) mode in which all Rserve commands are disabled except for CMD_OCcall. All messages including the initial handshake are always QAP and the initial message defines capabilities (here opaque references to closures) that can be called. This mode can be enabled using qap.oc enable ## for Rserve QAP and QAP/TLS websockets.qap.oc enable ## for WebSockets/QAP In this mode the configuration *must* define a function oc.init (typically using eval or source configuration directives) which has to supply OC references that can be used in calls. If the evaluation of oc.init() fails, the connection is closed immediately. The use of invalid OC references or any other commands other than CMD_OCcall results in immediate connection termination. This allows creation of hardened, secure services that can disallow arbitrary code execution. NOTE: this mode is inherenty incompatible with all classic Rserve clients. The first four bytes of the initial packet are "RsOC" instead of "Rsrv" o Rserve can now be started from within an existing R session using run.Rserve() command. This allows the user to prepare a session "by hand", run Rserve from within that session and go back to the session (by shutting down the server or sending an interrupt). This allows the use of Rserve even without the presence of libR. o Rserve now supports out-of-band (OOB) messages. Those can be sent using the self.oobSend() [one-way] and self.oobMessage() [roundtrip] functions from within code that is evaluated in Rserve child instances. OOB messages are not used by Rserve itself but offer asynchronous notification to clients that support it (one typical use are WS-QAP1 tunnels to web browsers that allow status updates as R code is evaluated). o Rserve accepts additional command line arguments: --RS-source (same as "source " in cfg file) --RS-enable-remote (same as "remote enable" in cfg file) --RS-enable-control (same as "control enable" in cfg file) o The Rserve package no longer includes the R client. It has been moved to a separate package "RSclient" so that it can be used on machines separate from the server. o There was a bug in QAP storage estimation affecting pairlists, possibly resulting in buffer overflows. This should be fixed and an error message will be printed when such overflows are detected in the future (which hopefully won't happen). o Bugfix: command line parsing would skip over some arguments o Passwords file can contain MD5 or SHA1 hash of a password instead of the plaintext password for non-crypt authentication. In that case the hash must be lowercase hex representation with preceding $ sign, so for example user "foo" with password "bar" would have an entry foo $62cdb7020ff920e5aa642c3d4066950dd1f01f4d You can use echo -n 'password' | openssl sha1 to obtain the SHA1 hash of a password (openssl md5 for MD5 hash - MD5 is probably more common but less secure than SHA1). This feature makes sure that passwords are not stored in plain text and thus are safe from local attacks. o Rserve now has the ability to change uid/gid according to the user that has been authenticated. The following settings concern this feature (unix-only): auto.uid {enable|disable} [disable] auto.gid {enable}disable} [disable] default.uid [none] default.gid [none] The auto.uid/gid directives enable setuid/setgid based on user's uid/gid. In case no uid/gid is specified with the username, the default.uid/gid settings will be used. If there is no uid/gid in the username and no defaults are specified, the user's authentication will fail. User's uid/gid can be specified in the passwords file by appending /uid,gid to the username. If gid is not specified, uid will be used for both uid and gid. So for example user "foo" (from the above MD5 example) with uid=501 would have an entry on the passwords file: foo/501 $37b51d194a7513e45b56f6524f2d51f2 For this to work, Rserve must be started as root. However, with auto.uid enabled it is safe to do so since Rserve will prevent any R access until authenticated. You should, however, use a client capable of secure RSA authentication or use secure connection such as QAP/TLS as to not send password in cleartext over the wire. o Rserve can now be run in a mode where each connection has a different uid and/or gid such that separate client instances are isolated. This allows more restricted setup in cases where instances may not be trusted and need to be sandboxed. The following configuration directives are associated with this functionality: random.uid {enable|disable} [disable] random.gui {enable|disable} [disable] random.uid.range {..} [32768..65540] If random.uid is enabled and random.gid disable then only the uid of the process is changed. If both are enabled then the gid is set to match the value of the uid. random.gid cannot be enabled without random.uid. To support sandboxing, the permissions on the working directory can be specified using workdir.mode o If any kind of client-process uid switching is enabled in the configuration, the permissions on the working directory will match the uid of the process. Also the working directories are now named by the process ID to facilitate cleanup. o Rserve now supports secure authentication even outside of SSL/TLS. There are two new commands that can be used by the client: CMD_keyReq - requests an authentication key from the server that will be used to perform a secure login. The kind of the requested key is specified as a parameter. Currently, only "rsa-authkey" is supported which returns server authentication key (authkey) and a RSA public key which must be used to encode the authkey and the authentication information (see below). The RSA key can be compared on the client side to ensure the authenticity of the server. CMD_secLogin - secure login. It consists of an encrypted data stream that will authenticate the user. In the case of the "rsa-authkey" method, the stream consists of the authkey and the login + password, all of which must be encrypted using server's RSA key. The RSA key on the server (Rserve) side is specified using rsa.key configuration file directive. The file is expected to be in PEM format. You can generate such file, e.g., with: openssl genrsa -out server.key 4096 where 4096 is the key size in bits. A public key can be extracted from the private key using openssl rsa -pubout -in server.key -out server_pub.key The clients can pre-share the public key by other means to compare it to the key received from the server as to verify its authenticity. This will prevent them from sending the authentication information to rogue servers. NOTE: if the rsa.key directive is missing, Rserve will generate a key on the fly when asked for RSA authentication - although this allows encrypted transmission and thus is safe from sniffing, it is not safe from man-in-the-middle attacks where a rogue server intercepts the request and sends its own public key. Therefore the use of the rsa.key directive is highly recommended. The RSA authentication enables the client to a) check the authenticity of the server (by comparing the RSA public key) and b) send authentication information encrypted. This method is highly recommended in cases where a full TLS/SSL encryption of the entire connection would be too expensive (i.e. in cases where the data is large and the security of the transported data is not crucial). o Rserve has a preliminary IPv6 support. Rserve must be installed with --enable-ipv6 configure flag to enable it in the Rserve build. In order to start all servers on IPv6 add ipv6 enable to the configuration file. The option is global, i.e. once enabled it applies to all servers that support it. Note that not all features work with IPv6 yet - detaching sessions (they will use IPv4 for re-attach) and remote client filtering only work with IPv4 at this point. o Rserve now binds only to the loopback interface in "remote disable" mode. This is safer and prevents remote DoS attacks. Previously, Rserve would bind on all interfaces and check the peer IP address. If desired, you can replicate the old behavior by adding remote enable allow 127.0.0.1 to the configuration (if you don't know the difference then you don't need this -- if you actually need this, then you probably want to add more "allow" entries for the machine's other interfaces as well). o If a function .Rserve.done() is defined in the global environment, it will be run after a clean connection shutdown. This allows custom code to be run when a client connection is closed. o If a function .Rserve.served() is defined in the global environment of the server, it will be run after a client connection has been served. For forked servers this is just after the fork(), for co-operative servers this is after the client conenction has been closed. It is guaranteed that no other client is served before the call so it can be used to manage resources that are unsafe to share with forked processes (e.g. sockets etc.). o The server and client process can be tagged with extra information in argv[0] so it is possible to distinguish the server and children. This behavior can be enabled using tag.argv enable Note, however, that this not always possible and it will have impact on programs that use argv[0] such as killall. o Added configuration option pid.file and command-line option --RS-pidfile which instructs Rserve to write its process id (pid) into that file at startup. o Added configuration directives http.user, https.user and websockets.user which take a username and perform setuid/setgid/initgroups immediately after forking. This minimizes the amount of code that is run with elevated privileges in cases where user switching is desired. o Added configuration directive daemon disable which can be used to prevent Rserve from daemonizing. It has effect only in builds of Rserve that support daemonization. Note that -DNODAEMON build flag disables daemonization entirely and can be used in any Rserve version. o All commands based on eval now also accept DT_SEXP in addition to DT_STRING. In such case the parse step is skipped and the expression is evaluated directly. The intended use of this functionality is to evaluate language constructs and thus allow calls with both reference and inlined arguments. o QAP decoding is slightly more efficient and avoids protection cascades. QAP_decode() has now only one argument and it is guaranteed to not increase the protection stack when returning (which implies that it is the responsibility of the caller to protect the result if needed). o Both QAP encoding and decoding now use native copy operations on little-endian machines which can increase the speed considerably when the compiler cannot do this optimization on its own (most commoly used compilers don't). o Assigning logical NAs now uses the proper NA_LOGICAL value that is also recognized by R. (PR#276) o Forked child processes will now close all server sockets so that any server can be restarted without closing existing children. o Signal handling has been streamlined: the server process captures HUP, TERM and INT which will lead to clean shutdown. Child processes restore signal handlers back to R so that regular R signal handling rules apply. Note that interrupt during eval will result in RESP_ERR with code 127 even if try() is used. --- In order to support new ideas a major re-organization of Rserve --- --- has been started - almost 10 years after the first release. --- --- It is time to look ahead again with a new major version. The --- --- protocol will remain compatible so 1.x series can be used to --- --- replace the previous 0.x series --- 0.6-8 2012-02-20 o added RSserverEval() and RSserverSource() control commands in the R client as well as ctrl parameter to RSshutdown(). o added new facility that allows R scripts running in Rserve to issue control commands if allowed. This feature must be enabled in the Rserve configuration file using r-control enable This will make self.ctrlEval() and self.ctrlSource() functions available to code that is running within the Rserve instance. It is also possible to use this feature without explicitly loading the Rserve package via .Call("Rserve_ctrlEval", paste(text, collapse='\n')) .Call("Rserve_ctrlSource", as.character(file)) although this may change in the future. 0.6-7 2012-01-17 o fix processing of login information **IMPORTANT**: this fixes a serious security hole in the remote login mechanism! If you rely on authentication, please make sure you update your Rserve immediately! (Thanks to Daniel Faber for reporting) o add a namespace to make R 2.14+ happy o work around broken readBin() in R 2.14.0 that errors on unsigned integers (affects R client only) 0.6-6 2011-12-10 o fix a bug that can cause heap corruption due to incorrect addressing in padding of symbols. Unless extremely long symbol names are used it is unlikely to have a real effect in practice, but in theory it could be used to zero targetted parts of the heap. Thanks to Ralph Heinkel for reporting. o fix Rserve() call on Windows with quote=FALSE and more than one argument. o clarify that sisocks.h is under LGPL 2.1 as well as the other headers used by clients. o add support for plain S4 objects (S4SEXP) in assignments (Note: derived S4 objects - those using other native SEXP type as a base - cannot be supported properly, becasue there is no way to distinguish them from S3 objects!) o Unsupported types in CMD_assign will no longer crash R. The resulting object is always NULL and an error is printed on the R side. 0.6-5 2011-06-21 o use new install.libs.R custom installation script in R 2.13.1 to install binaries o install clients by default on Windows as well o multi-arch binaries are no longer installed with the arch suffix in the package root. The canonical place is libs$(R_ARCH) instead. For now Rserve.exe/Rserve_d.exe are still installed in the root but they will be also removed in the future as they are not multi-arch safe. 0.6-4 2011-05-19 o make all buffers capable of using 64-bit sizes. This means that clients can use more that 4Gb of data on 64-bit platforms when communicating with Rserve, provided the buffer limits are either disabled or configured to be high enough. Note that this does not change the limitations in R with respect to vector lengths so you still can only use up to 2^31-1 elements. o bug fix: contrary to the documentation scalar logicals were sent in the old XT_BOOL format instead of XT_ARRAY_BOOL o work around several issues introduced in R 2.13.0 for Windows Rserve() now also allows arguments to be passed to system() for more fine-grained control of the environment, mostly to work around bugs and incompatible changes to system() on Windows in R 2.13.0 (commonly used options are invisible=FALSE to get back to a more reasonable pre-2.13.0 behavior and wait=TRUE if using R 2.13.0 that has broken wait=FALSE support). o In Rserve() startup wrapper, args are now quoted automatically if quote=TRUE is set. For backward compatilility args are not quoted by default if they consist of just one string. 0.6-3 2011-01-17 o bug fix: the child process could get stuck in the server loop after some abnormal return from the child connection code Thanks to David Richardson for reporting. o set R_ARCH automatically on Windows if a multi-arch R is detected (such as CRAN binaries since R 2.12.0) o add R_ARCH support in Rserve() on Windows to locate the proper binary o bug fix: C++ client did not handle new-style lists (introduced in Rserve 0.5) properly. Thanks to Carl Martin Grewe for reporting. 0.6-2 2010-09-02 o add support for NAs in character vectors by using a special "\xff" string. Any string beginning with '\xff' is prepended by additional '\xff' to remove ambiuguity and clients should remove leading '\xff' accordingly. (Note that UTF-8 encoded strings never contain '\xff' so in most uses it never occurs). The Java client has been updated accordingly and represents NA strings with null. o add a new config file option "interactive" that allows to run Rserve in interactive or non-interactive mode across platforms. Previously Windows ran in non-interactive mode and unix in interactive mode. Non-interactive mode is useful if you want to prevent R from soliciting user input, but it requires error option to be set if you don't want to quit R on all errors (i.e., something like options(error=function() NULL) will do) Note: on unix the interactivity flag can only be set *after* R initialization (due to limitation in R) so you still may have to pass flags like --no-save in order to appease R. o more Windows fixes - Rserve uses R's own initialization in recent R versions. This also fixes issues with Win64 and more recent toolchains. Note that both Widnows and unix now behave consistently with respect to interactive mode - the default is now interactive for both platforms but can be changed in the config file. 0.6-1 2010-05-24 o add a safety margin to the send buffer to avoid crashes when size estimates are off (e.g., due to re-coding) o added a very primitive PHP client o Win64 fixes by Brian Ripley o added new configuration options: su {now|server|client} - switches user either immediately as the config file is loaded ("now", default and always the behavior of Rserve before 0.6-1), when the server is ready ("server") or when a client is spawned ("client"). The latter is useful to restrict clients from sending signals to the server process. uid, gid config options are interpreted accordingly to the su value. cachepwd - {no|yes|indefinitely} - allows Rserve to cache the password file. "no" = read it at each authorization (default and behavior before 0.6-1), "yes" = read it when a client is spawned before su, "indefinitely" = read it just after the config file (most efficient but changes are only active after re-start). "yes" has only effect in unix and can be used to restrict permissions on the password file such that client code has no access to it (do does "indefinitely" but can be used anywhere). 0.6-0 2009-10-27 o added support for control commands CMD_ctrlEval, CMD_ctrlSource and CMD_ctrlShutdown. Those commands provide control over the server process. The side-efect of eval and source are then available to all future connections. Control commands are only available if they are enabled, e.g., with the config file entry "control enable". In addition if authorization is required or the passwords file is set only designated users will have control access (see next point). Note that enabling control commands will make Rserve use at least one file descriptor per active child process, so you may want to adjust the maximum number of file descriptor in your system if you expect hundreds of concurrent clients. o The passwords file format has been enhanced to give finer-granularity control over the user authorization. Only users with "@" prefix can issue control commands. The prefix is not part of the user name for authentication purposes. In addition, if the password file contains an entry starting with "*" it will be interpreted as blank authorization, i.e. any username/pwd will authenticate. This may be useful in conjunction with control prefix, e.g., the following file would give blank authorization to all users but only the user "joe" will be able to use control commands: @joe foobar * o Windows build cleanup (thanks to Brian Ripley) o fixed decoding of XT_RAW (it advanced too far), this affected the use of XT_RAW as non-last element only (thanks to Saptarshi Guha for reporting) o don't advertize ARuc if not supported (this bug only affected systems without crypt support with plaintext enabled and required authorization) o add assign support for logical vectors 0.5-3 2009-01-25 o fix SET_VECTOR_ELT/SET_STRING_ELT mismatches o set object flag when decoding objects that have a "class" attribute (fixes issues with S3 objects that were passed from the client to the server). o set S4 bit for pure S4 objects (S4SEXP). No other S4 objects are supported because there is no way to tell that an assembled object is really an S4 object o added string encoding support (where R supports it) The string encoding can be set in the configuration file (directive "encoding"), on the command line with --RS-encoding or within a session by the client command CMD_setEncoding. This means that strings are converted to the given encoding before being sent to the client and also all strings from the client are assumed to come from the given encoding. (Previously the strings were always passed as-is with no conversion). The currently supported encodings are "native" (same as the server session locale), "utf8" and "latin1". The server default is currently "native" for compatibility with previous versions (but may change to "utf8" in the future, so explicit use of encoding in the config file is advised). If a server is used mainly by Java clients, it is advisable to set the server encoding to "utf8" since that it the only encoding supported by Java clients. For efficieny it is still advisable to run Rserve in the same locale as the majority of clients to minimize the necessary conversions. With diverse clients UTF-8 is the most versatile encoding for the server to run in while it can still serve latin1 clients as well. 0.5-2 2008-10-17 o fix a bug in CMD_readFile and CMD_setBufferSize that resulted in invalid buffer sizes (one of the ways to trigger the bug was to attempt to read a small number of bytes with readFile). Thanks to H. Rehauer for reporting. o ignore attributes if they are not in a LISTSXP - there seem to be other uses of the ATTRIB entry in conjunction with character hashes in recent R versions. (BR #76) o adapt C++ client to changes in 0.5 (at least to the point where the demo1 code works) o add support for XT_VECTOR_EXP in assignments o improve protection for vectors o report "remote" setting in --RS-settings o updates in the REngine Java client, added documentation 0.5-1 2008-07-22 o fix build issue with R 2.7.x on Windows o mergefat now works properly and uses cp if there is no lipo (this fixes multi-arch issues on Mac OS X and makes sure that Rserve/Rserve.dbg are installed even on non-Mac systems) 0.5-0 2008-07-21 o added CMD_serEval and CMD_serAssign which are highly efficient when talking to R clients as they don't need any intermediate buffer. The corresponding R client functions RSeval and RSassign have been re-written to use this new API. o deprecate scalar types in the protocol o add more efficient storage for dotted-pair lists and symbol names o add support for complex numbers o new Java client: REngine it is more flexible than JRclient and it can be used with other Java/R engines such as JRI. Also it has a much more clean API and better exeption handling. - allow NaNs to be passed in raw form to R, i.e. double NAs can be created using Double.longBitsToDouble(0x7ff00000000007a2L) (nice methods for this should follow) o C++ client was moved to src/client/cxx JRclient: o change the representation of lists to generic named vectors (class RList) o change the ways attributes are accessed 0.4-7 2007-01-14 o relax DLL versions checking on Windows o added more sophisticated implementation of RSassign in R client to support larger data. Nevertheless, due to limitations in R, objects must be serializable to less than 8MB to be assignable via RSassign. o added more robust error handling in the R client o fixed compilation on systems with custom include dir (such as Debian) o JRclient is now part of the Rserve package. See clients.txt for details. It is not compiled by default (but installed when --with-client is specified), because we cannot assume the existence of a Java compiler. 0.4-6 2006-11-30 o fixed bug in RSeval when handling large objects o minor fix in RSassign o add an endianness hack for Windows in case config.h is not included properly 0.4-5 2006-11-29 o added --with-server option (by default enabled). When disabled, the server itself is not built. When enabled, R must provide R shared library, i.e. it must have been compiled with --enable-R-shlib. o added --with-client option (by default disabled). When enabled, the C/C++ client is built and installed in the package. It will be copied in the "client" directory of the package and contains all files necessary for building a client application. This option has no effect on the R client which is always built and installed. o Windows version of Rserve now builds and installs both debug (Rserve_d.exe) and regular (Rserve.exe) version of Rserve. In addition, the Rserve function can now be used to launch Rserve even on Windows. o endianness detection now prefers information from the compiler macros thus allowing cross-compilation. Use -D_BIG_ENDIAN_ or -D_LITTLE_ENDIAN_ to override it if necessary. o allows universal build on Mac OS X o adapt to R_ParseVector interface change in R-devel 0.4-4 2006-11-15 o first release on CRAN o added support for RAW type (both in and out) o added rudimentary client support (thanks to David Reiss for his contributions) and documentation Previous major releases: 0.4 2005-08-31 * added support for sessions 0.3 2003-10-07 * new format for boolean arrays last version: 0.3-18 (2005-08-28) 0.2 2003-08-21 * support for large objects 0.1 2002-07-06 * first release Rserve/configure.win0000755000175100001440000000063014531234224014240 0ustar hornikusers#!/bin/sh echo '--- Rserve for Windows ---' echo '' echo '** MAKE SURE YOU READ THE RSERVE RELEASE NOTES FOR WINDOWS !! **' echo '** Rserve for Windows is different in several aspects **' echo '** from the unix version, see **' echo '** http://rforge.net/Rserve/rserve-win.html **' echo '' mkdir inst 2>/dev/null cp -R src/client inst/ 2>/dev/null Rserve/R/0000755000175100001440000000000014531234224011737 5ustar hornikusersRserve/R/zzz.R0000644000175100001440000000231714531234224012722 0ustar hornikusers## we have to load the dylib/so/DLL by hand ## because it is optional in case we're loaded ## into an embedded Rserve instance .register <- c("Rserve_ctrlEval", "Rserve_ctrlSource", "Rserve_fork_compute", "Rserve_kill_compute", "Rserve_oobSend", "Rserve_oobMsg", "Rserve_ulog", "Rserve_forward_stdio", "Rserve_eval", "Rserve_oc_register", "Rserve_oc_resolve", "run_Rserve", "Rserve_get_context", "Rserve_set_context", "Rserve_set_last_condition", "Rserve_set_http_request_fn", "Rserve_http_add_static") .onLoad <- function(libname, pkgname) { env <- environment(.onLoad) ## unless we are runnning in an embedded Rserve (which provides ## registration in the "(embedding)" domain) ## we have to load the package dylib ## R 3.6.0 broke NativeSymbolInfo by renaming the `package` to `dll` so we now have to check both pkg <- function(o) if (is.null(o$package)) o$dll else o$package if (!isTRUE(tryCatch(pkg(getNativeSymbolInfo(.register[1L]))[["name"]] == "(embedding)", error=function(...) FALSE))) library.dynam(pkgname, pkgname, libname) for (i in .register) env[[i]] <- tryCatch(getNativeSymbolInfo(i), error=function(...) NULL) } Rserve/R/conn.R0000644000175100001440000001047714531234224013030 0ustar hornikusersRserve <- function(debug=FALSE, port, args=NULL, quote=(length(args) > 1), wait, ...) { args <- as.character(args) if (!isTRUE(quote) && length(args) > 1) args <- paste(args, collapse=' ') if (.Platform$OS.type == "windows") { arch <- .Platform$r_arch if (is.null(arch) || !nzchar(arch)) arch <- "" ffn <- if (debug) "Rserve_d.exe" else "Rserve.exe" fn <- shortPathName(if (nzchar(arch)) system.file("libs", arch, ffn, package="Rserve") else system.file(package="Rserve", ffn)) if (!nchar(fn) || !file.exists(fn)) stop("Cannot find ", ffn) else { if (!missing(port)) args <- c( args, "--RS-port", as.integer(port) ) if (nzchar(arch)) arch <- paste("\\", arch, sep='') pad <- gsub("/", "\\", shortPathName(paste(R.home(),"\\bin",arch,";",sep='')), fixed=TRUE) if (charmatch(pad, Sys.getenv("PATH"), nomatch=0) == 0) Sys.setenv(PATH=paste(pad, Sys.getenv("PATH"), sep='')) fn <- if (isTRUE(quote)) paste(shQuote(c(fn, args), "cmd"), collapse=' ') else paste(shQuote(fn, "cmd"), paste(args, collapse=' ')) cat("Starting Rserve...\n", fn, "\n") if (missing(wait)) wait <- FALSE return(invisible(system(fn, wait=wait, ...))) } } name <- if (!debug) "Rserve" else "Rserve.dbg" fn <- system.file(package="Rserve", "libs", .Platform$r_arch, name) if (!nchar(fn)) fn <- name if (!missing(port)) args <- c( args, "--RS-port", as.integer(port) ) if (length(args)) fn <- paste(fn, paste(if (isTRUE(quote)) shQuote(args, "sh") else args, collapse=' ')) cmd <- paste(file.path(R.home(),"bin","R"), "CMD", fn) if (!missing(port)) cat("Starting Rserve on port", port, ":\n",cmd,"\n\n") else cat("Starting Rserve:\n",cmd,"\n\n") if (debug) cat("Note: debug version of Rserve doesn't daemonize so your R session will be blocked until you shut down Rserve.\n") if (missing(wait)) wait <- TRUE invisible(system(cmd, wait=wait, ...)) } run.Rserve <- function(..., config.file="/etc/Rserve.conf") { if (is.null(run_Rserve)) stop("Runnig inside an embedded Rserve instance - starting Rserve recursively is not supported") .Call(run_Rserve, as.character(config.file), sapply(list(...), as.character)) } self.ctrlEval <- function(expr) { if (!is.loaded("Rserve_ctrlEval")) stop("This command can only be run inside Rserve with r-control enabled") if (is.language(expr)) expr <- deparse(expr) if (!is.character(expr)) stop("expr must me a character vector, name, call or an expression") call <- getNativeSymbolInfo("Rserve_ctrlEval") invisible(.Call(call, paste(expr, collapse='\n'))) } self.ctrlSource <- function(file) { if (!is.loaded("Rserve_ctrlSource")) stop("This command can only be run inside Rserve with r-control enabled") if (!is.character(file) || length(file) != 1) stop("`file' must be a string") call <- getNativeSymbolInfo("Rserve_ctrlSource") invisible(.Call(call, file)) } self.oobSend <- function(what, code = 0L) { if (!is.loaded("Rserve_oobSend")) stop("This command can only be run inside Rserve with oob enabled") call <- getNativeSymbolInfo("Rserve_oobSend") invisible(.Call(call, what, code)) } self.oobMessage <- function(what, code = 0L) { if (!is.loaded("Rserve_oobMsg")) stop("This command can only be run inside Rserve with oob enabled") call <- getNativeSymbolInfo("Rserve_oobMsg") invisible(.Call(call, what, code)) } ulog <- function(...) invisible(.Call(Rserve_ulog, paste(..., collapse="\n", sep=""))) ocap <- function(fun, name=deparse(substitute(fun))) .Call(Rserve_oc_register, fun, name) .save.condition <- function(cond) .Call(Rserve_set_last_condition, cond) Rserve.eval <- function(what, where=.GlobalEnv, last.value=FALSE, exp.value=FALSE, context=NULL, handlers=list(error=.save.condition)) .Call(Rserve_eval, what, where, last.value, exp.value, context, handlers) Rserve.context <- function(what) if (missing(what)) .Call(Rserve_get_context) else .Call(Rserve_set_context, what) .persistence <- new.env() Rserve.set.http.request <- function(what) { if (!is.null(what) && !is.symbol(what)) .persistence$http.request <- what invisible(.Call(Rserve_set_http_request_fn, what)) } Rserve.http.add.static <- function(prefix, path, index=NULL, last=FALSE) .Call(Rserve_http_add_static, prefix, path, index, isTRUE(last)) resolve.ocap <- function(ocap) .Call(Rserve_oc_resolve, ocap) Rserve/MD50000644000175100001440000002330014531324156012050 0ustar hornikusersb951d7c8013dd9f05420589b93be838a *DESCRIPTION 51ab443d0a22e0e9e4f693c12f07f8e9 *LICENSE 7b0712906331719be38febaa574b9187 *NAMESPACE bae541212aff9a63fd4b75d170ac0df7 *NEWS 871824a53f662f6e6835fa8e93de6bf5 *R/conn.R 2e2966d22b6d4d5aa7bab15c65af81f2 *R/zzz.R 1285c2452b360dcb43dae2fae24c1dc8 *cleanup e94a3fd662424dc6bc0ae0df512ebb54 *configure cc2d614047cd2c4da770d56491f444ac *configure.ac 243e9a3eede74518a6bc030bfec66beb *configure.win c76ba78209dd2da31620a4147f20327d *inst/java/REngine.jar 359d76d5367bb908fea5927f6e07f4a9 *inst/java/Rserve.jar b2c9af5ad6e9685f0e2bf4a495e18e12 *man/Rserv.Rd 49247478b4dcf4e41faae9969849a7c9 *man/Rserve.eval.Rd 065d1f5c67cf5fe53d0455bdfe887581 *man/ocap.Rd ffcadeb5fc4e139fa5da05eac3c3d905 *man/run.Rserve.Rd e76ccbbe06bdf6737fe05d45c953dc53 *man/self.Rd 03a6e8d26d6f23c29847320067e84988 *man/ulog.Rd 6d41a78fddda7a041b072d3d78af8b25 *src/Makevars.in f1c348c8317bfc75ca7c135f5ec1e327 *src/Makevars.win 4f0bced26106dc9ff7c4f40c0abc8f09 *src/RSserver.c a4fd65791a1703b79b120776cfe0e271 *src/RSserver.h d8c74b056729d70ccd755ac56cc59a1f *src/Rserv.c 09b7c9fb31d29de4cfdaa16858ee6776 *src/Rsrv.h b4bafa877c47764dad4c9e3777904f9d *src/base64.c 26e15425aa9d684c218be9bdb33460b1 *src/bsdcmpt.h 2d6d65e154495e0623b04894c4d956a8 *src/client/README.txt fbc093901857fcd118f065f900982c24 *src/client/cxx/COPYING e0d11aa8d62727526e8d3037a456aded *src/client/cxx/Makefile.in 4b639fc216ef057350a5a03939b76753 *src/client/cxx/Makefile.win f853d9c2cc1bcc9eebf54c7d65873b7c *src/client/cxx/Rconnection.cc 7d1e4cf642eae209a4ef8e568121feff *src/client/cxx/Rconnection.h edff7c7d2bee83e149e109900d099d84 *src/client/cxx/ReadMe.txt 09b7c9fb31d29de4cfdaa16858ee6776 *src/client/cxx/Rsrv.h 58e2981c4468f0c827e446860b3d16a0 *src/client/cxx/config.h.in df0a4ab460d481b4ff95186aa98b51b5 *src/client/cxx/configure 7ebb2c9fe05c0636af32b2ff92e33d4b *src/client/cxx/configure.ac 993a295d84a30c1d73f70e3f62130c0f *src/client/cxx/demo1.cc 8b96ec5504b8e8e1da6721b46a4a32d2 *src/client/cxx/rcmd.cc a0b407b59f56cd555ceb51ca2015ea87 *src/client/cxx/rcons.cc 8baea46b2f4700829a587bde50c84526 *src/client/cxx/rsdown.cc 55e4bb5689944c1cf98cff11d2d31a66 *src/client/cxx/sisocks.h cd72d9d129d543222b6fead0b44a7852 *src/client/java/JRI/JRIEngine.java 8cd227aa278a590acb08ea8e2eaf8478 *src/client/java/JRI/Makefile 9714690518f4d6dbfe3f89fefb0e8a91 *src/client/java/JRI/package-info.java a24881fced120a304d50299e2bca6233 *src/client/java/JRI/test/Makefile cf61905afba88cc39be79c5dabcf4d07 *src/client/java/JRI/test/RTest.java 067d3e0bb9ba9932948fecad436036e6 *src/client/java/LICENSE be6b96b4349a35452a7b2cab4efbe224 *src/client/java/Makefile 3927ba79c7a801f36075f1b809d06196 *src/client/java/MutableREXP.java 865520643c7aa95ed069a4b2a0173fc8 *src/client/java/REXP.java a8de3e1fab786f0d9762b5b2b0f63bed *src/client/java/REXPDouble.java 3683350b5fe442d759a1176a96ea7790 *src/client/java/REXPEnvironment.java 024e5f5858a25b9c88e437bde83b0a08 *src/client/java/REXPExpressionVector.java 754b193f82b377f2e20437a8deaeb60a *src/client/java/REXPFactor.java ab79865ed622de5287ea8429514c5984 *src/client/java/REXPGenericVector.java 8def14772888086b046354a84b5ef042 *src/client/java/REXPInteger.java edee0fd33051c198b82956231f0f5a68 *src/client/java/REXPJavaReference.java 42f721124ae0cd5ef5edfb115a412cb6 *src/client/java/REXPLanguage.java c6c00f3859d2ef66e7b16bd784beebc1 *src/client/java/REXPList.java e9d0ea19f11eaac2e15980e9b7cf6e9a *src/client/java/REXPLogical.java c951b85ed10dd9f326d595af605c2aef *src/client/java/REXPMismatchException.java 28d4839ce78289590aae84bc6d141339 *src/client/java/REXPNull.java beab9bdcfe5d6a09e8bb0258d086a684 *src/client/java/REXPRaw.java 0caa0ae63edbeb0ebd28c2371b8d520f *src/client/java/REXPReference.java e03aebe85120fe43490135da423dcd24 *src/client/java/REXPS4.java 12f0c290a307d36c419d85cb5e9f8a32 *src/client/java/REXPString.java 16494ce82d7ac67394151cad5cee3844 *src/client/java/REXPSymbol.java f28e65acd497901e47295b156775a469 *src/client/java/REXPUnknown.java 2ad6c462e1fa0498d7ed43d89ba9ca4d *src/client/java/REXPVector.java 4a2893e415791cf97e161e94f9a626d1 *src/client/java/REXPWrapper.java 0f4e28d5a7719a3348a7321cd530c74a *src/client/java/REngine.java ba7130aa5f03935284e484d82f05b2f2 *src/client/java/REngineCallbacks.java 80f05407ddfa287167fcf5ef9cd84390 *src/client/java/REngineConsoleHistoryInterface.java c71f9739a92170a9cc623291d1fcd524 *src/client/java/REngineEvalException.java 7afd3d765c1f3c8aaeb4e595f9bbe72c *src/client/java/REngineException.java fe69b8b51e8c7ae6a9cdfc5c80f5a2f0 *src/client/java/REngineInputInterface.java 22b51c4f124c06d1f6d6c9431e6b86ea *src/client/java/REngineOutputInterface.java baaafc80d15203c724de9f9e439fb157 *src/client/java/REngineStdOutput.java 78312e95629e7556d324acfd11ddd547 *src/client/java/REngineUIInterface.java b05e012fb558a1f17213e7f4912c4027 *src/client/java/RFactor.java 9e0e7022027bd5efb0a5556340364e36 *src/client/java/RList.java bdbc8db40934207c428bb1f5fb5d1ba2 *src/client/java/Rserve/Makefile 0a8f260223d6c05eb2fb443b7a107647 *src/client/java/Rserve/OOBInterface.java 1ae9376220fbbed4cd4209c2c91fa4f9 *src/client/java/Rserve/RConnection.java 1d3f3cac377aaa8428cc6f03782dfd9d *src/client/java/Rserve/RFileInputStream.java d48ea3cff02124d49b40cdacc461307f *src/client/java/Rserve/RFileOutputStream.java 8217731c41f582992313a4946401074f *src/client/java/Rserve/RSession.java b1d5fc3ceec94f421ee7f4591fa19d53 *src/client/java/Rserve/Rserve.jar 54b81e86a57e56b1637f856be4a86a2d *src/client/java/Rserve/RserveException.java 7de85b2e0124e7e357ba5ee9f8588930 *src/client/java/Rserve/StartRserve.java d6244d39698b355ff09cb2c8835b1851 *src/client/java/Rserve/mkmvn.sh 78bf28c04d3b9de9ef4ef95a0c7918c1 *src/client/java/Rserve/package-info.java 4fe685ee89c76adc3ba30e4865ee590c *src/client/java/Rserve/pom.xml 68e1a1474896cc52b31f07652ca74225 *src/client/java/Rserve/protocol/REXPFactory.java c47aa8abcc0595f96a188c26033ed563 *src/client/java/Rserve/protocol/RPacket.java a18a52eefeb061ebaaafa23dabaf35a3 *src/client/java/Rserve/protocol/RTalk.java ed28b70af013379d2a96d0d7dca1a7d6 *src/client/java/Rserve/protocol/jcrypt.java c3bb8e0b0b40c50d479a3e2b98d20763 *src/client/java/Rserve/src/test/java/org/rosuda/rserve/RserveTest.java 6c18ff19b49eaf54fb6dd44072f8c727 *src/client/java/Rserve/test/Makefile 2592ee47962bec10a6c90519c67dd4aa *src/client/java/Rserve/test/PlotDemo.java a593b733b11ca43a7955c59ebb589e37 *src/client/java/Rserve/test/StartRserve.java d4ff8f3834f9ca9b742f05c4936a3baa *src/client/java/Rserve/test/jt.java 3ce7ff2c4dfade193e791813c94d196e *src/client/java/Rserve/test/test.java e36ef3f74c06d457ba9b5b4a717cd63c *src/client/java/mkmvn.sh fd1948ffcc8aa12424c33d08869eeb72 *src/client/java/package-info.java c17346150974cac840361a335e5dca7c *src/client/java/pom.xml 8533aa43245961e8d15d0602432d20f6 *src/client/php/simple.php 45eda837c3d8cf88f83d3049d3074ad7 *src/config.h.in bdbace1ae4608d2cc6224079350d8179 *src/date.c 58eb30085a074e34824c33fd60e89300 *src/http.c eea5617dbcc9fb006cec57cbaaf75451 *src/http.h 07f4e02182a19800f5f9a6c0b2140c7e *src/include/Parse.h 90f990b9a30211202d6ed2095ffbe4e2 *src/include/Win32/Startup.h 14a6b118ede02bb4ff538dc59393c50c *src/include/Win32/config.h 06b89bc548e3388a756a1b9bbdaf3683 *src/include/Win32/psignal.h a1f31afcfe229fffeda88e3104734009 *src/include/sbthread.h 55e4bb5689944c1cf98cff11d2d31a66 *src/include/sisocks.h 00991e6d09a28848410b306e4c3b8d7e *src/install.libs.R 10fb69baf2ef70119dbf5203870254a1 *src/ioc.c 320c0eec10d6f19990d0574705dd4565 *src/md5.c e0b51dbcf1ca861f67b34097658e3713 *src/md5.h 252501b1958da38383088bc595e2f0ee *src/mergefat 5bc469a3b9199e78033ccbd4aa23bda9 *src/oc.c 70b89d86328e9353c17943fd68487d38 *src/oc.h 776937666580d8effe519b1d61ea902e *src/other/RSpool.c c05975ccd0e8803613b4d8430cfaade4 *src/proxy/Makefile 26e15425aa9d684c218be9bdb33460b1 *src/proxy/bsdcmpt.h 9133c369d6a1d64bbbe1d5123e1b149c *src/proxy/chandler.c 2fc3431d07c7d947efdfbda7f7ed237d *src/proxy/chandler.h bdbace1ae4608d2cc6224079350d8179 *src/proxy/date.c 106277c9f34756df1d30be0520a0360d *src/proxy/forward.c 8d20291f43ffa6d22f07b8446a5afa78 *src/proxy/http.c c9c0c8b915e1970adfb31cbb0bfd3e50 *src/proxy/http.h c93c2a6d36dd5b11889a5a9244ad6331 *src/proxy/http_tools.c ab137ef9b6d2a4dc18bfa4053ed4ada1 *src/proxy/http_tools.h 2c1fc347151049ab192a38a7e93c086c *src/proxy/qap.h 894f144bd601a4f8a55c7786ef923a57 *src/proxy/rscript.c 30fcc57c02796102d3f863cd77ca829c *src/proxy/rsdebug.h 62d3c8067e3e7c2b327a19aafda1fe73 *src/proxy/rserr.h 8f1b39f6f79911f28741ffae9408431f *src/proxy/server.c c638533eefbf2b7faf7600efb8581a66 *src/proxy/server.h b8e6014bdecc2026690629485d615131 *src/proxy/test.html 5a86b3d71f0c13e5249893cbae9777ec *src/proxy/tls.c f00819a3f1b22c615c6de514aabcbb41 *src/proxy/tls.h 71f1e77f73c9eb4f548ee6ed83786f5b *src/proxy/websockets.c 85f40d4638d5b75c5859a23d2b313bf7 *src/proxy/websockets.h 1344dc39577de5d0de651393e5d95ed1 *src/qap_decode.c ee2f74fbf8cd5b0a0bbededbe780ade4 *src/qap_decode.h 73c79a0bccf7f92048d7f1dbc1825573 *src/qap_encode.c 01782f7ec33b0bb4e14d1da0b8b1595f *src/qap_encode.h 5ed458fd8fe7f8143ab3aad83236e075 *src/rsdebug.h e21336c443664f6c40fa3a04ed4a6e92 *src/rserr.h 2d5383f74bcbaacaa0da6c83dfe6fb45 *src/session.c 8117eaf31656e5e568923ead13c2d952 *src/session.h af56434a66f449b3acaa179ce6d52d37 *src/sha1.c 6be2d1704b37fb778ca61bca437bb6af *src/sha1.h e12bc660911e28e8803eb07ffa5e69a5 *src/standalone.c c2db10fbacd90efa190872ab667b2e5f *src/tls.c 6fb90865afe5687d10632bad9c3f6531 *src/tls.h 06e48cadef8541725394939a814738f9 *src/ulog.c 55290cb4776181177f16e0217abbc4b1 *src/ulog.h a916238e6222796eda8097716233cd56 *src/utils.c 504e13d79eba7b719a9599dca4f60f53 *src/websockets.c 68c0813df8afaf04ef638b87c076572b *src/websockets.h 9107ede92807ab7cd9653344a91d9064 *src/winembed.c 9828f446225b05e296dc404578a4f092 *tools/config.guess 7efa0e8e26af69d26cb455993dc6587a *tools/config.sub 621dede3c31e72a0f406b431a0758409 *tools/m4/ax_pthread.m4 Rserve/inst/0000755000175100001440000000000014531234227012516 5ustar hornikusersRserve/inst/java/0000755000175100001440000000000014531234227013437 5ustar hornikusersRserve/inst/java/REngine.jar0000644000175100001440000010316314531234225015466 0ustar hornikusersPKè|W META-INF/þÊPKPKè|WMETA-INF/MANIFEST.MFóMÌËLK-.Ñ K-*ÎÌϳR0Ô3àår.JM,IMÑuª Eô M4\R“2ó4y¹x¹PK¸o67PK è|Worg/PK è|W org/rosuda/PK è|Worg/rosuda/REngine/PKè|W org/rosuda/REngine/RFactor.classuVkoe~Æ3öØÓ mÓ8%‰”ÞHp) ± â *…"B­ .×!Ò~^iÀ®´ûaÁªÝîsÞ™8Á5­t潜ësžó:ýß·Ëv¡la Ž¡˜–ƒ•Õ£&³`âac"ÆE;_öfôRÉ=;Uœ;«!µ¶÷¾Ížl#EY¿o£§j(èHÇt7—û[ò.æÍx³^¡Ê¿àÀ-òÝq£‚[~„>®´ÿ± Äš(»™}!É w wŠ]„á.p7pFЋqNäqìæ€Ý2öàYŽé9ôáUôã-<€÷±c¿m Ö :Óh=ì:M˜ÚÆÚ5$´XHp'ÇVbËc½æX—cí¿ˆ4t(¼ïˆ²š!~Í”c\ÅúUVYêxˆÍ8  î vWÂßXÊI4ÙPkò¢æ ßšÀä1ž‹ÉvÁ½­‡2’ëK\€Pè~ÄéëÄ®KUD}ocd̸BbôkhÑôA“Î4ÂyOàþPà¾Cï‡!¶+.ßDOÛE„¥ó!¶êßúRÕs³#Ü¥×c$æ’8¡¢D%JHk «½AˆYêü:)§‚}‰÷Ö—ôþäÚpÉž„N¯ ×ο7€I"9Åbr¸Cž"ôÓtžWam×`³¥ššOvúDz«Þ§÷¯Ô×\­/ÂpªÀ%W#¶ª*pW¤íHµV”8Ÿe-ý: M‹û¡v¡¶\°RªÌ —j™³”÷“±¾þët.©íQmä³Ú€.?AÕêþälJƒd9Éã=§Mrþ›³Únÿ%y x‘­ ›ð2ß”sÌ÷é<[ñ*}Må¿Aò·„Ñ×ÐIRK{«eœ øÐË—#Zò“’Ø;}Šý‚Íþ‚Enz–\GNú4ù{¨Å7(ÿĬþŒx“Ãýiñv€¢‘†íðÛ8¿~ø$¿‚UX‚\ªðÊþ*€kUCµª”êUúXß×&Ù^DT™(´¿·FV©Ø’NúdTзh¡ã?Ó«@7*?IŠø\H`ÿ²2_ ×TÛt_u|³4Zt¨Ð¹½mœÜ¶ÚÉm»ir?%í?[™©¦•±¨»#pkú¯B-Õ¾ Ü_õ$“®>!ò#µ†kD*QAÓ¸êàÖpÊïà—ìÔW,ï Ÿè ¸J¢£c¢×±NIùõ|ÕéK¤6±eÊÁªj{ QÉÔêþD9¤Е‡JNû¾Cœ¿dÍü‰Û\Á­-ʼ‚ÖÆ6c¨MÂßDd亂öZšüLùUqöÿPKÙÆéÍå PKè|W#org/rosuda/REngine/REXPDouble.classVÏWWþ^˜0 ù!*AQ‚ ¶ÖVЪDZ0¢UA[;À£!C“‰mOO›®»rÕElܸ°Ú‚­ÔmÏé?ÐÓ¡Ýtו¥ßy ‚¿XÜwß}÷Þï~÷Ý7á÷ÿ~yàn™øC+ÿ®øUhۉ6œ-#ÚY#Ι¨Â™(ÎËzAĨˆ1“nã>Ï‹Q\2Ãe‰ˆbR6WD\âcYÇ¢ø¤âö?D†± È×ÄõS¶)cÞþ2ïÚ3 ¡+iŠ‘“ ŠŠ1ròÚTÎ+q7¬É•ä ’H''¹ ¸3ŽBm&WpFÊsSNqÜžÊÓR3æÙÓ7ÏÚóz_ÙŸ+ä¼ãAàE…ŠÄ®ÚÚ©fÜb¶·è–Ê3vïèéB–é¸^>ŸÉ•¼>ñ›fмSÈz׉äB]±½Ü-gؾeŸ›ºáL{ ‰dæ÷½y»í ¬} U,º<çsÓ~4 ¯²Ki·ÌÒJRRR›vi¨à9Y§¨mCf|Ï1¯˜+dim¤u]þÀÞgÀ & Ì’ºç¦©r68ÝX“ŽQˆöOçuOX[b޹åâ´3˜“~Õ û Â 6µp9 {±ÏB7N[ØvÑn(Ä6æWhÚh:UÎågœ¢,ÜD^Äœ…,t"¡°msÀì¬S´p ¼ú¯ʵ0ϸë–ð¢v%ÜÝÓCÛ×<”-ìA‡BËK.4 ôòó‹¼0—E6¿b d@9õ/¸ 9š|®«€õ3¾2îŽÚŸg\²ó'Z¦‘CÝ–xÍrúìùy§ÀyØŸØ »ù‚u·YPœ¯8Žzîê•5¾(3¡kæì/ü‰òœ9y†$ßý†UÈ¥ùÅEèÓX^7dÜ]mW$1œLsÂZùeÂÉ´QÛ!×Ëu»Ì!×~†8>PHr×JzÒkß#¨„n?@D–;ßÁˆÜE$|‡!tQV2ØŠeBM'È‹¶_g:@‡0×X×*º"ËÆD¸sô'Tþ@›òlñÏ·!‚&Ô²‰îÑÑ×"u4øÑ©ßP^6ˆŸÒBë243CõhñKÙ‹Ð Ó… ´è…âº"z¿f'Ø 6Ët’¨±«{ ÆkÐÚHv7ØKAK Z á «ƒk€ëLÏ0á-¹ Êï_eר|ro­)AW;(߯aíÛ¢}+Ä÷þ×NÊwpD»îÔ®¡ÈÆ”)ÊwñÞ›¤”K8Š>í:Áö ñ½~¥Ëf&|,î« ¨OùZüà·ç¾ ©»+¥î¯u«Žaò %e“döŽtÌDè)LýJnüŽk˜›ì«ÀñsÿŠè:œŽTü1ª&–`ÖU/ 0Q³ˆ-c>🛀r¬ûPÍ>L5àjï«$!;qB_Öü:~ÁM´q•Ü#ÔŽû(oB9EzÌœæ8œ~ŽÞIÕÄüüòj”Ÿ5Jé1bš g{+éÔÕQÊê×qÞ€†´Æ¿‡™ªk\ĶK©UâM—üzþXõ¥ÃvqÐyS‹Ø!ywyŸÝÎr!ß°üÂa“Îb#ÔÎã*.ø$,Dž¢Í@LíŒÕ2&MrCþ«ä«m@ó#´<Ä®@á×â!"ÏÞ¶éûEy Õ´ ú|ð?PKjG…}È6 PKè|W)org/rosuda/REngine/REngineStdOutput.class•S]OA=Ó¯i×-…ª ?Ú ¬ àC4’0]£ñqÚŽeqÙmvg5þÿ€ÏòPMüþ(âm…h ‰ÙäÞÙ;çœ{æë×Ù÷Ÿ6ðÌ€‰Rw° Ã¢ëXâ¸k RË:ßÓᾞyÀñ£ÌQá¨2dž;ž£^0$Ë•7 ©ºß‘ “ Ç“ûÑqK¯EË¥J¾ù6p”¬û^èëÿrúVà‡QGXÍ—^—r­q$> Ë^ײUàxÝÚ®VÏÛJ´?ì‰^,ÊñˆÁlÚ‡þ§=†¢K²ëÿ)«6wÜ(<<·¶p¥†f¶m¹ãhxq8c«ÎA¤z‘ZÓ]LLbŠcÅÄ*ÖLX:<Æ:Ã=lGŽÛ‘í]µZ]4é@ž˜xŠM[¿|¹—óŽ Sª­#ÙVWëÂu[´“!CårÔ@{×S2x/Ú´Ò™¸‰ã[¯È·"÷RÿÕÚþ*I¥¤¯=cð5š•­6ÝÓEB•ÇŸJFôzÒë0¬ŽŒ”†»HòYåJ ³åQ !xÜÚõ°„ktõÈc‚^B LÅiú+Qf”ÓÕS°o4`(PÌÄÅQg0;„ÖH"E¹Pú‚Ü _‘9Ar¥”æ%bžAY³§ÁQ¤GÂØæôžèFàæPh Iú€y¢ÿ@úÝ)2ÞG–¤²}äú0.Œ  ÌÑÅù¡Æ\Ü£ž'(ÞŠ'oÿPK%:¡ÿûPKè|W.org/rosuda/REngine/REngineInputInterface.class;õo×>#NvvvFž  ÔÄçü¼âüœTFg Ÿü¢tý¢üâÒ”Dý ×¼ô̼Tmí“•X–¨Ÿ“˜—®\R”™—ní©‰)ÆÈÀœ_Z”œê– 2R ªÛ3¯ ´Ä3¯$µ(-19U¤‘A·m¨êù'e¥&—°120201€# #3 ˆÅÀ $™ØPKrv­–œëPKè|W$org/rosuda/REngine/REXPLogical.classW[SGþfga–u¹¸*,ˆ$F–AðBTÄ  èŠx’àú »¸»˜˜T*Vb’Jªüñ!Iù‹I+ÁªxyLª|Kò˜×T^óžŠ!_÷4»Ã. é™þúœ>ßùÎé|þïÏìÅMC~„0\ çÅÛõ[\,Â%Œõ¡Þ‡>ìðÓdL oxÓÀ[~”bX¸Œ‹·Ë>Xâ9áG &ÅvS>Øb2íCT<'|¸b ¦Á˜³nÎ$¬) ž±. ú;Çcñ´Œ[3´> ÅÇñTÚŠ§/X3ó6Íú;¹Ð¥/--ÝÒà<ߣ“¡¦¡ ·32$' 襄¡·¡+<ÊÇñÄ}K#±¸Ý??;a'‡­‰"ÅCikòÚkNÍ Çâ±ôQá8fúµÎ¸{ÃØòS®\ÕPO(’HF[’‰Ôü”Õ2Ø2Ÿ—"±Tº]Ø]“v£ëØ1òŒ¦¯hÐÂL»(–Š$¢±I!æ´RýV:vÃ>eݰÎN\µ'ÓÊ‘«œ·ÌXñh‹ƒ¶kð[©>ªµ“)‘@x¬Ï72¬T×Í´­0Ê]d¥ºóÌ\AÝf%:”NÆâQ¢D]¼Ý@Üq ¯ÂXJ»ÇR²”ÅòwÛsI{ÒJÛSκ5“ª§ÝöÄ|ÔÙ-7 ƒÞC‰ùä¤Ý•)“j9’4 c µkiêXÐŒD5¨oskÛ+© \ IÆÊ%À)ôp¬Leîb×üô´M¯Íù ±™);ÀY 륽À¼˜5ãFo£ŽP“X{‡enjnæô} 5k½Àê&’â¨P÷êÿé(aÒ'†n ›V©Ÿì)6]]ú}¹§oÈ—! ­¹9;ÎïjÈ•_Z¥ YøÒ‰å¨XÍ•ñ‹g­wd³ô¥íY6dÓK†5iÇv^!^ðŠFàÛlCÑí|÷ [YòW2óW9ßáš¿ÆùN×¼å¼ Ãh$bi!¦ñ¨*»õ5 ï¼ú}iÙıP®•a—dàñwP.V¾E9_  ÔøžFï߈^ý…Údøèße6*¸Ö*˜D%6óGl¸ ž%á1ÄÝçåh`7ÿiKÂK‚YÐ ¼GÞ­—¹/Ô\«0Ä{¼FzïUÞãôÞåÒÛüEú9›«PÞÎ걉 Ê;åRÉŽ¤Äa+æœÁö©`O¹Øèàr0C_@ùì‰ÑÌŸP¯ ™Ïñ{è!3´/#àm¶°ôg–P- Ž;¹Ÿ(b˜ÐÈF0)J#ÐB<‹Â%+"­Š –™KYÿŸ`9t”«ŽêD—’ÿ-ëߌ×U*Ó$"ËØØôÞu„%ÚÃ({%/SW¦° û3Ú¹ ·|TÌçL×Ëg[&fž~Gk2úÕ˜5.ýôÕôÛO^؉y0ÚXÞCdØÆY»ä9&ô+Y"ËSsC+Tôfp—nЭåA†ròª…&ÏV¡ ýì~¦ow„ã!Rrl«”­Ç›kwŒãai-ìj”]ØóAŽiÇ£ÒA˜~£ºò° ÿÄaÊ×{h4å[hŸ¸|ÁÂltæw¥ô^ïYÙ˜¿™2ÊVRS >œàQ9ÉF;Aú}RÑã(x¿ S¥TìR $‡ ‹èbTÊuÊÖÍ2Âñ8º•é·*Ë#N–†+KÓeÑCî4K˜fé Ló×¼4˜æ9¦9ÈsqŽ5Z‘fS¨V)ôȤz\ifd]Œº“f/•s¸?TÜIÂOás‘oZY¢¢lZæî úy<‚†$û_òØ_âí?¶å!açŒIö=‚ý']E:)¹ ¤8Ѳˆ.F>‡˜UwøßVüMG{oDÝs!7w÷M÷‡‹kPžùq*}~XÜvBòlWªÜJ•+.°Ö¼ ¬UÓ£SFw£ÖF;²Œ¾âE¾®¼„Ï£v…Ôb¤v•·Çµòñ䜱ErÏØ»8çÿ(ý«:ç:|qàß‘*ã¿TÆw£dä1JGÉùÆEƒ›8,¢ü*\=ßzˆÊ{h } ¿ܼˆ-Íõ0’‚=]Þ…®[ª"š‹¨«ˆYUë©§(K->â7ö6?Jó¨Âvü”ŸÁÏpŸK•`¼@­j€ãþfOG‰”»„‡£¨”à9¹ûàPKF:bœ¯PKè|Worg/rosuda/REngine/REXP.class­W{|SõÿÞÜ$÷&MjHÓP¤N(ˆ¥ Å¶(U4t»M/i°Mj’òP6ëtîí{ Î­SÙƒ)NmÕ*ŠÜt¾_›{ºÍ׺×?2ûþî½iILjÖääÞßï|¿çwÎïüÎùÝ'ÿ{ÿuø·͸ɅJ|[ÁÍ*¾ã†ŒïªTñ=·¨¸UÅm*öªø¾›J?â‡BüHˆ}n,À…¸ÝîPq©Þ¯âNñÿ7ªq—‚»Ý(ÁMÂÒ=âiHŰŠ{Åã=*îðûUŒ¨x@Ń (xHÁà *xDÁ£nñ˜‚Ç……CBù 7æã§âõg*žÿO)ø¹Š§<£àYϹQçÅÄ âéEùúêÆ¼¤âe¯¸±¯Šé›„ø…‚_ºÑˆ'¼æF“VâWbæ×".¿Qð[ v-•JH(o‰'" ñd—¶pÚX$ÓùÞ™-Ñdj¹„â^mG“ÞÙiNé½I R³gC4M­” *7’iu¼K—0¹…жþÞN=q¶ÖÙÃ`\rU£ÉöT"‹d›$¸¢Irè‰hØxnŽ¥ôˆÎu:ÅxOX«…SqsLIpG“gjÑ„ùBTK< kT.Ž&×ĶEñX¯3[´X¤_‹pyNîèKèÉd43—²³·3nÚØ¨›6Ñäm»Áº:ÞÛ×£ïPÄ1=ÜŸHF·éÖÛ=¡ÇÂ|si–CŒ•/PÙѲUÛ¦-ì¡Ñ…æ8cê^³#¬÷¥h•Jn-í$_ìD4$Mñ~ÆÐj’ hÉÆ©ô@#×,çË•9Ãlm ªÆ«"¦9O]¯–lÓRôj½¾s+c aQcN˜£Ôuöè±HªÛØ7.ÙÎý9Õ\Ü&ÃÑSÓΪMÆ@zÏ3¹Gä‰è©S™žÑÎþa5+åö„©%r¶=¥…ÏoÕú¬<ôtkÉcè|¹è¸h¹+Ú«àwbûcÝÌÀTRÁ͓2+OôÆÎŠšŠ§+NÅS“~Ÿ”B«ÆæƒêhRð:£NèZJÏœ¯pz<''[(-¥­Mh½ôkiîãfžµq˜˜I«5q´Úòž×åygÆc>-G¤'Æ´6Ó„ˆ6ÿ?D²°ãc±0!Ó­ù7pB|[&À7!Cœ†&´µ!Ücu5w{¼?Ö×FEíp‰ùZ±¡´a½ëp†„@¢Öh²WK…»G ÜÇy§´iâ´èôk=ɬnoÝ^D·wj}}z¬+ßí"ÏIY.:wG³0³(¿•åðF@ÊÇëМŸèhúÈ+³=½P×¾æñêYÎKŽ@Ÿ¯ïdT¦ò,qÙ8KüÈ¥ÉZW—ðrœ¿³ù ÒÌÏ좘òÉ%rÃøx“D¥<“oå¢ ñ߆t'DQ:‹Òi ª,Õ9$³‰/"¡¬º¶lý)”í8ÛÒ?Þ¢¶Éû²ô|”ç 7“rcz¥”ç WAy^z³)Cè@¹©½”è)?Y€^ å§ Ð[Dùéô–Pn.@¯žò3èL© ×@ÙY€Þ)”áô)» Ð[CÉ®ÎlzsyDÄhÑäPÐk†ã¡,@3"”BMæWƒÜPgèP^(rC•ÐÖ hzsCÕÐõP^YrC]9 ge@ûpAn¨;´=š@27´(ôœ (›fn¨'tSt¶ÝœÝ1ju¶Uê\Á!·TɵÙÔ•܉ s'¸øŽ,`$xvåN&°npk·M+Ë×&ó¿”À)­Õ‡à®Âq{àöóÁ[5„©‚ÊfPM2Tppk¼ŒòÅÂ"lG0EÁqZx¥µx[-ÞÙiÞÁ»Þ4ë!(ö½°‡Ëdw\Dö]³[0Ï"ó*A})OI²|õ½Ó†àÛ Ÿ°AZñ:•'­´¿EÚo8^Æ%g¬ÿ2Ž\Îb~…a¥ré*_àODf`Ôƒ[ŒæÇêôN§†DÞg<Î`ˆ…Gså•åÕQZ]^w“)é×ÌÝpØ÷ ÈÒÞ£op­ôÏFu,V2 åÉÆ¿¹š =¾ÉÙ«ØÒ®F ®a+º–{y5¯§î ÔÞƒ¸ÑXéT8‹>Àd_”f¼G£X0×ÊO d7ã»aËN€AJ~@Xªçr btîJBÃ8ž=¹texª·|/Þ  aÖØö›D{ÅL‡m“‚’£Â¤ÂË‚/ ªùzŨ‘eäD“¶Ê²åõ[–†0›OÞ9âÕ´Os{¡ˆ—l«·VØ®6Í|_1s_â}Éˆä…Æ¡1’bFkõ˜dܹâà2ëŠÛj8nNž FkäÚz{½¶Þá³ûcžm™S®WäzÕ§úƒÈõ.ŸËgÄ̧ÏUçS«|Ê€"-Þ0àâ¿5 R¾Zâ[ì2æ0Ć÷r?ïƒ÷c1F°²u<ŒÓq—¢Gتe9„ò ‹Îc†ƒKáü¥ ¾Ê˜yy”yáâ›9ƉñžG§q.é0JÓØØÙvákøºÉÁ•™+åyEðÖìÆº \Ç¿ÕÁ âiEiY÷J›\o—GÙ æËõNŸ³t3j|ö»ô9ë|ºì¤³ï 8(_ã&ÉD`~¨f B#„ì¢2$ r<àÉ¥ëCö²õèjçDuHöNkFÍ0j‡±p,^õ¼$OqñOcžÁ <Ëû/‹Ïc^@-^ÄIx‰q{‘­ðb^æì#Vóá<ŠœF83&*cRÂãqXT™Ã É7xÊÌ:ù:C"jÇm Góe÷Ö'2BxÁ¼«õ.‰”‡PwKödMž8:ù0–´Œ`i(˜vßi¹_òž4ŒO´‡ìâ™&NƲöc40ÞåŒ +ECʈŽÓŒÎt¼+¨ç]9§SÆâTaläü“yôšð6ïï²à¾‡[ù,âá€ì9®,#øagÅ0ßE5«kƪÖj.íÔsYªXÂŽ«®*¯ïFázo¡êa¬³ï5ÀïCÅaføxu=bØôÀö¨þF}ªaðjËà<£Îñ#`M"xkªîÅÚì¢tÔ€\cA–Y-`ް/Öé°bj0BUŒÍiÖÂŽá‘L_¯µxVÂmúùiç‡yBŽê<\ƒë:‹«‘\Âõ`šKÉÍrÖäáS ¾ë-¾% ¡ð±4ÓÇà8ι ‚oY'‘@87+Ó¹àGxUdì¶H–“Än–ÿc½ àN1¡{F¿ÿ*ŒmäÜÿ]8=ëƒNt79tãÿPK óx; ûPKè|W+org/rosuda/REngine/REngineUIInterface.class;õo×>#nvNv.F® §ÒâÊà’Ä’TF Ÿü¢tý¢üâÒ”Dý ×¼ô̼Tmí©ÆÈÀ䜑Ÿ_œê–™Ô`ˆWC”¦OVbY¢~Nb^º~pIQf^º5ÐÆàüÒ¢d¨âPµ¡žžy%©Ei‰É©z =Œ ª¸ FRÌÈ €°Â?)+5¹„‘‘‰˜X˜X€4+P„‘$ÎÀPKw½ Ý® PKè|W$org/rosuda/REngine/REXPInteger.classUßSWþîfa“% ?…€ˆb‰µUJù¥@0‚ míKº&Ù8ít:Ógú_t:¾øâƒvZ˜VêkgútúÞ§þ-=çî2€Ê˹÷~÷Üóó³Éÿýú À؆ßÒÖD†C¸Î»n1a`8ˆ¯£lÆØŒ¸ÅNALšˆà6?Kq‡Sl¦ƒ¸Ëëx˜06í¯²y{M@[ž 3uC@Ð&2’Ï=;çÍÛÙ’# »E¾Òã‰%ZFòkV§Ýœ3UÚXq söJ–Ȭg¯>¼coªs倛s½!ÿá¼@E|™VÍ´Mç ™d!_,­ÙÉ™Ñ\†ÂÑzïnÚ-zýì7+µ‹S¶ç>r&íGöôÊgÕ¨‹'ÒèœÌÚ¹LÒGû‰.ëä2Þx‚йʼnœçdœ‚D–$Bù:wUÀ´÷n‹œ_‚ëÙÅT¾D©+(e`N¢³^ÁÍe­'´ŒÚÇû |ì?X2@eF¼|ÊY)eüÛÃéª7”Ál¾TXuÆ\–ª† W õ°³@ÛkäQ^aœÇBgÐÌ»{â0‡@ãaèfÉÍ®± cKl–Ãø”NÃQßõu¦ùoÅ×ÌòiŸ!F§n~yŸÍç$nwOaß´¾&åyjPžX[ÞÐqžÁ”@í1úòÕ’l"©ÛËÜÐ Ø››NަúRüh°£½P¢MŒæô ×A/¿§lýq‘¹÷ö—²ùž³AÓ} Xjbh9>y‹sô=7Ño‚ÛN»3hAŒÐV‰jôi‡Ð†³„´’$„:psTû†þzà™ôNdï(²u Ç껺·Qñ¶ÕÕŠ:’‰Ù,f«AÀj ¾OXp&Ð¥8[!¤~]?A¾¯‰/*7ÊB·rmS®•ìúêÙ!_Öûz”o³òÕôÃ~LŸ<‹rïž$ÍÙ+xO¹.RX N™æŽ‘ Æäö j-¹‹õ|7óXOwÿ±žï«¥g  ‚”›Iž'öùÇ¥ý ÓÀû¢‰®âš¢yHú3M¯Œý*Ëx.X±—0·Œ†¶`úœ[¨ÚBxVÿu„ø*Mü5šâ^Ú}p@\e Wp}m„úÄU}–_ŸÎ¼‘ÆöŠ;øHæ$ÙßGȨÊA""é†%Yº¬²f¦AÍLŸà‰é+›"BlëN?§*£_TFÅ—ˆ,ªÂé{9E¥G«ÉPÙÛ¨)ÓçbìGœ~‚³±ïaZÑèj¬=‘êdÒîù’C=;¨¸Ö8n£÷ ²ª !¡R”Ô(uoŒ'{ iLÒÃmYi˜+m7Í5ÕTÀ€Œ0ø?PKKç}X²PKè|W org/rosuda/REngine/REXPRaw.classQ[KA=³»É俥1ZUAØMÄ@_->¤´PImÑJ}(“dׯ]ÙÝ(þ¢¾ô¡…AН…þ¨Ú3›íÁZ¾Ûœ9çû¾ùþãâÀ¬A5 ‹:º'Q“XÇêl¨¾€±ßÈ>ô|/ÞÈØû-§#`= ú®ÀTÛóÝÑQ× _ªî•‰½XõÞ=SÇI.!Vù¦„ƒfD£¾jî>ö|FÿêEÛ‹âM§#qŸ"C×Ħí<¥”íªÓ${͆TÔ:‹ÝˆÒ¶£[*«hGÅÞ‰»­NÔóî¡Û‹*¶Ó>dÞ*ÐW7 {Á(ì¹O<ÝaIë’yCKÈa¹„,¤ŽVª74š´R»á²C™ XüÇ”É Üܲ}Ë.°ÂßÈðw¸{Ý£,ãò´foX7è+õsˆzãòæ×Ü{X/0>±n H; “¶@®"fPâÖ`\a †„%1A¥¤ùï:Å&S±·¤ÓD³õõs˜·¨•Ù÷ *#.ÁËÎÀÇÎÀÏÈÀf“™—YbÇÈÀ¬¡ÆÈÀ✟’ÊÈÀï“™—êWš›”Z’˜”QÐðÉ/J×/Ê/.MIÔrÍKªÒ>™Å%Ö ½\Áù¥EÉ©n™ õÜ ©`½¬Ä²DV6ÁÉÈ ‰Ã”`Fqr Š Ì@7ƒ#È0 ÉäÉiF ͪµq#ÁÈÀ$Ù ‚`¥œP¥r@­L 9-íí LèjA$ØxnPKM!N<È-PKè|W.org/rosuda/REngine/REXPMismatchException.class}RïoÒP=o0ZºNf™n€ÓÎ)+…ÑÍŸ4&ºÌO8è2?>ÊK×ZÒ>Œ–&Ž%šøøGïcÄ)0›¼sÛ{ïyïÜÓ÷ó×·ె[6tÜVñŽ›îbKÇ=•¹o`ÕQ·Jsôíx˜øâe¨v.+Þ«0íséŸ|òÅ@†qÔT4†µiö‹aØ#&,Ôiz.¥è¤-cûÂÛD;š&<ìjØ3ég”h0›«ÚC”õ‘‰k(˜XÁuçŠYf41/åü•Í8ʺ È †gŽ·3©É äÆÊeéuçTø’A'÷{\YXüÇÂq’8…©ƒF”CÞ'Cu_Ápcž”#lÒ}[¦kº@‹|€zÈ Â ]L EÂUúzOߊ{îw°çX°2#dë#,Ž£7K#hÐA?GÞ­ŸÁpgXúB$:ÐB–pU”PG»¨På&Ö&GlPdݯ0>ÿ¡åÆI›pˆ³­KÓ­UÂòx¤ÊoPKë“=ê„PKè|W(org/rosuda/REngine/REXPEnvironment.class•TkSÓ@=Û–¤ ¤P(òRHÓByú € ÷ˆÃßB›)AH;mÊø£ü€3RfdFýìr¼R„ØÔ¡™ÞÍîž{î¹÷îæ×ïoßL`[B;FCˆ É͘„qLˆ˜1%bZ‚ˆÑ žññ97/‚xÉÇ RyÌr9næƒxÅW^‹x#bÁ¯›9†èF¾˜Kó¥rVK¾K›9ÃÔ«cŠA8ÒÌì‰ÎÞ8Öδä‰fæ’Û‡ÇzÆâ»³†iXó ãJ=š]c{ Å|–ˆ[6²U>=Ô‹ïµCªÉ(¥Í3£˜7OuÓ"¡Jì€!”Ó­UGLD‰Õ’ã'èrko×*f.u«­ïù5íZZæã¦VpâKéO½`y³Ä0Rƒ­™ •JFά-ÃÓ×C(hE;ߨRWîâ¹{«l”vóåbF_6ì’¹öG¹8]X”ÑNñHÄ’Œ¤›FéT³2G7bônü-T§» eã$«:jòÎÈXÆ 7«Ôú>Ãì£Þ*1o±ÆU¯s¡ƒ2†±!c[ 2]—ãbPþ_'’æ²õ¥Ë;A†•ût¹n[­PÐͬ׉ó¨_Ê…¯Þ¯:ø •¿^rß#'Ö=nsUÝÞ= Q÷D¨Ó;vï´iÚCTýº¢Ÿ>yíô-õÑŸÎ9øŽ:Ù ¨·è&¥Ù$!ü4¶¨—`jü>5qÿZbè!F€l+Ù0BhC33Ÿ_AÜ¿D0ª@© 1,ÓKM—hþasIh$ŸÍÞlç6@+ƒñ„;âºHˆ§ô ÁŽ=äÄî%^3Q*hq MÜq†â¸ ÓÕhKN¨<ø[BÉfœ¤qÊvh.Æo«C¡9'Hrµ»‚ÖóÍZ)'xÊaWÊ!¢¾›rŠVf)í¹jÊkî”cˆ;¡ûi´YTʸí'"î8&ìS5òPKpð_a¬PKè|W-org/rosuda/REngine/REXPExpressionVector.class}ÏJÃ@Æ¿MbbclÕ›‚Š Ø?bÀ£Š‰^‚H•"ÞÒt)+º[6‰øP^<<ø>”8ƒE!Xwá›o~3ûñùöàk!<4YZV¬ ø'J«òT`³;Ž­)ªQ÷=VZÆýTåqg à™‘h¥d_VCio²á9Gÿ4þYIn¯~¦FªHž'V…2ZÀmwîÂkSÙ\ž+¿Îü/3yiìÁ}ö”EX€ÏÒØ›³¨Þ(°;‡¼ZZ•cØK¿ÄÇ…à=¤e[pè~·7…x¥—À"çA³»M½.»ÝÞþNŽHC,Íà Šì:ÞKk’F\ÁòPK=}ÏÉPKè|Worg/rosuda/REngine/RList.classµWit”Õ~î,ù²LV²O&¬B˜™Id)J„$B*8$cšYjE¥Z·¢¶.€¢ÒÖØšj°:QŠÔ­V{ú£¶=íéžSë9þ±?´`ú¼÷ûf’|™áø£=9¹ß]Þû¾Ï»ßy÷ëWN¨ÅÇ™pãî ”â™Ý+Ã}~(ßC™Ü¾_fÈL‡²°Vfn<(Ëø±,2ð°|‘áQ99,³#2•á17pLΞœ2ÓLž”åSÂøx¶ã'2üT~&OËì!9í—Ùã2‘á>9Õ{zxÆÀÏ30Q•á2<›…È­Âü~){ÏÉÍç <Ÿ‰:ÜŽAùžÍÒñ+¡x1/¥#&û'Óñ²|_00¤àކv†{ VoíÕôõF:k6„Ûz»º/SH[‰FzœU37(¸–wµ‡rWG¢áæ¾ÛÂÝׄ¶urÇWµyuWwGMwWO_{¨fÝŠhIø½víer1»¥7Ô¶£)´KÓx…r«7ÉQYÕ(ÁË»:;);ÒÕ×f_„ífóZg(ÚQÓÒÛ‰vðŠS ÁSÜxU¡&ÅÔÈŒHO3íÖ®-³IÁêU¨®J"!¥ U;vïï]J¶EB6ޱBzO¸w•IR\Õ˜L9zŒͧœœ€2ŽåH‡9¨àŸè*ÑÈ“|8†yà4Pjà*Êœ E®²D¶À¥Ezý^JÔ¼+#× î²3FV‰AÎnj–‰©”8MËÈæBd(¥5d°x×Áo–?pi6#ähÙ3ÉÐy‘ÉÅ&ëâc&âÖÈE#x+ƒ§a¹F~†»íŒóÞ%ÜÕeàJ7úÑI” ÚZä³ù„³®l²ršô«ò&ÓM¥V •·Ši0èø {žé²\¿Àö¢•]Ôhеœx8¬·äLò³®xu]qH]©#Ãe·ÜË”1ÄÔy…arŠ5ðÕxi8Ï8–¼‰$Â#JsLeH”øœõ!T*4Wa¢¢Ë'Tø9¤ÃäõýÃŸŽ 3]ÏP§×"oÛ˜È÷v ÞŽ{,ûÒ™@ÛK)uGBö_yQà^7Jö˜¯ºšœ N‰ÉÛK|Á"WÀ_äŠaê¦9~f±Þ|͆ƒ.æò'E®c(aL‘pîáá/4mCùÓQQ5‹H€wˆó]†ñ{Äù>;˜ė÷b¾‚—á#Ò}Œ«ð{–?hì‹‘–ý5² t*%Íï&\éä;,ýaô¶Ko« Qvg"<}V·qS¿Kì/°?rŒ¢Ë"hÃ_A¿O·Âq¾“ 6K†!12£ÕNü'Žü™0ŽØ+ö±ÿ™co"ú*-â4áVÈ‚A³ãEÿßÛÒD}®ëÍ—[ŠBm±rµŽz ,bµ¾¤ø¯ˆó?,øúšïñaI`ÌP•µÊ……Ê+U¶0d;TºÖ%.Oùy¦½Ôôï±)jTJžß&x¥‡±ž6-m2gŠ–Õ­'‚¢‰N]‚”Dœ°È]æ•ôj–£yþ2w|]Óª³øÃ~ÌcÝ™­ÐÄF1gTùñ™Åg‘Ë_æ ”¹†Pë€\ëþÛH—ݾ å¡ÓrXær‘¯òøS Ÿu¬€\ 1MQùbT«Ô©R,ReX©¼üÁ]k•›U% 1a5‰ù;}j nVSq¯š†Cjº6N 2ÜçQÆt¿ÀÄš=‰/"ϰD³.æ² ÜÊj÷%Ë»˜ð6+(ÎX&\gšðh¸#4°CñÇŒò`€¯Ê U5ŠT ÊÕløÔLUµ¨¹4ô<4¨ùX¥.åK}®V µ’¥H£’¹6%¿Ò¿3oOdÖöÄÃâbàfçÊ ¿óªGÂTÿœP‹‘¡êQ è©Ëé©%·”à–ÙÆñ}{æÛSY]ÁñÜiÑí´Þ O¡Ž¯Ñù—ư€oƒ…ü,’y —FzÁâ~¸ êÍ >M .ç<†%¶w°Z¥1ÃÑn nXPÐBâ÷:óUüM×PKC~T ¬PKè|W!org/rosuda/REngine/REXPNull.classËJÃP†ÿÓKbkÚjmm­Ú]ZÁ€[ÅèBJQw§m(§ÄréS¹ÐUAÁð¡Ä™4«`À˜Ë™oþ™“ïŸ/Ç蔡¡Éf[G«Œ<š:Ú:v´SåªðL oö çÞÔ¨ •k¢—±íß˱C7]sèù3Ë÷‚h*­Û wFùÇ›¡ ÂîÕT0Š'–zŽS.Q “`Ïìÿ)+Ôe0’¡ZØWr!¯Çs{B= ê™Sn9ÒY«[bËw^äOìKÅ»Ux }ĤklÖÚYãv3ž³zB+£ŠŠôùÓ xÙeûäùâ` ñNí˜@ˆ!Ú'A£CµÁá¹4["k ’°D6WxMq¬Výg­a#áº49Þèù§% o)šõ6QO«Š4W%»Å4~PKKõ=Z>fPKè|W7org/rosuda/REngine/REngineConsoleHistoryInterface.classuޱ Â0Eojmµ8ø.ºtí(ŠBAhÁ=¶1¤”Ò´à¯9ø~”Ø€Õ©o¹ð÷œ÷z?ž¶ˆBLBL fiÆZ~”µÕæN°Y&ÚjtÝŒ¦{%¤â}ÆIÉZF+¦ͬ‘JÄ«‹C$š?D”éÆäü +N°øVwZÕºê='e¹¹±œ¯°³;Šóÿ/çkÉsxpãù#ø@—c—Ý%p{„PK©º%©PKè|W#org/rosuda/REngine/REXPString.classUKOa=_gè à P^ZŠ>h;¥å¡(***XЈQÁ˜8ÀXGKKÚ©Ñ7Æ•?Â6.Ð($>ˆ;Wþ ÿ…â½Ó¡ àcó=î½çÜ{Ï/óõç‡UÝÓPN]å¨C7_zUpLƒ|ïåÓq'xïÓP†“Û¯b€/ƒ*N©8ÍÇ>g )8+ Ì›OÒYsV övòùÈL¤ÍL*1áäìLª_À?`glç”@}x§;rC@>—µª’vÆ/ÌM[¹ëætš, á]Q9á˜3ÇÌy7PA£@Ïn±Él.•Èeó…Y3qm8“¢´ßºš´ó)8G奭Lʹ/ …##ª/‚]Ô@ÀÌ›ŽýÈ%ö+Ó¬G .Ù’­h¥VËMœçn#»Ê!Ûùñ!ÚÈ=¥à<5ãdÏ[Ó…ÔFÚß¹K8m"[ÈÍXlV¦Š»(ºâ«c/†ª·ãt4 ‘HÍíγ…{÷¬œ@ãN‡žµr:bèÐq—ÄS#|Û‹}:Fq™L1ö%éÐFZÅâq:=hþƒæíýɃ$ÌR5M™™€ïö”;úZÂÿ/ÍÖœŸ·2ôevìöéí0y}“ت“ݨ·rÎ|ìÎgıæh®‚>’ØÒ±¾ýh¥7TOOªçqЩœÎ$$­AºuуòÑ^]ˆÊŸá›”Œ‰÷Þ¸ &Z÷@¢µ2tT£Ò…‡<ø]3¼Þ…kÐ$¢X„lx¾-¢¨¥zêÐL·Ãð­ŸOA‚ý´¯3À»—ì”퀗-EtLÔ­@þWº µÖD͇Üt§«T¤UÐRʸŴ™´m^R¾ ÚýÑwV_—dñ»VöÄ!/6èÅúäíq”Ž:>âÅ5{qe̹´-ô ­íÿOh;­D½Ðç¤/7q+ý$'¥Á±º€ bK¨{ ŠLbI×_øÄâúwc©¤†5RéÙiè ⸫Zòh ±Nc+*eÖ‰-Ø´H¼ ®ŠÞ­WÏ7¯ž—Q6ùþÉ(ô¨Ë(h´,£b:Wé¼€ÁÐ[T. 7ô šسŒª›†‡ T Øë‹pŽp{ù²AA¸¶z0cޝ-Æo6ÜF­òi?zh6GщcèG/îà8fЇ#NvvvFžâÔÇ’’¢Ì¤Ò’TF= Ÿ¬Ä²DýœÄ¼tý` p^ºµO~Qº~Q~qiJ¢~k^zf^*Ž°Ö cdà Î/-JNuËÌêð--ILÊIÉêÌadâIPÂ>ÿ¤¬Ôä6FF&`dad`f`±X$PKc”ÂPKè|W*org/rosuda/REngine/REXPJavaReference.classRÛNÂ@=ËZ‹(ÞQ¼”z!ñãƒF Q£ÆhŒÖ¦[RŠß¥‰B¢‰àGg¡–¹s©—kÙ (ÙŽQpìF³ªÎ-ƒ4d¯ÏJf£[-np÷ÔëgBÍêHÑ'ºk>ñcÊõ¸1×¾pÓ2ü²n”dÒ…Ýt*üȽMŠM…þœßs‡[¾-$2’X—1†„ðT†)¡ý¦Y«rGFÓ2òÐØ­p6ȹcXrÀ_{QÝ!4† *ÆUÿœTD¯×¹UeØRûÛ?¯ñ¢ß»È¡|,Ñ“¥'Æè§Á†ÉObœP¡Õ2ô’ÖÓ6Þxé°S„‘ŽJêð'<~ŽØA²#ÚfÁ‚a“ž`ž¬ˆ†µWž}ÔáÔÿ¨iBº5Z¤6D4÷ÐM›mDZˆ*1¡n!®Hä·0â/”!œ!ÀìPK·\VΰPKè|W#org/rosuda/REngine/REXPFactor.class¥U[oWþŽ×ñY/ ¹â„@B| ¦¡@۸ܓbjÄb\ÚnìÅlpíÈ»‰Ô‡>÷§ô¥­ÔØ<ô¥? :³^œÔx Š2眙of¿ùÎů߼x`U §ðµÄå0fpEâ*×4qg7$nJ,K¬H|£án©˜ã1«â´ŠÛÂøVƒŠ£ïp±UN¾Ëæ›ûîK¬i8Ž<Öyö@ÅC¿SñˆÇu‰‚ÄcPÕÜ1«¶ÀÑbnÓØ1ÒU£VIç†U«,Qø©Qrê É\½QI7êövÙH¯-×*VÍL¯­¸QÆe¬šå\³=*Å oÔ˦ÀPŽRW·Þ0ëÆF•<ƒyÇ(=¿cl¹k‰¢Ä¬À…Þ•zòX~t/gÙŽû™éX?ªŒÈôE|ðªe¯xª(±8i¨ÇT,Þ_¨°a·!ÉGbñž¢G {Õp¬ó6Åînlš%GàUÞǶ½„Uz;¯Ñ©¦åëÛ’¹b±ÔCÜI›ÌYÆê˜Ç÷ÃÝy:NóLø÷¢ã ŠœþƒŽ9œ8ÑG7:½¢íИO¢@Ô'òŽã<~dó“À@©jØ6/Ü–6t”P晩ã)Üv.글‹ô¹î^¯o[Õ²Ù`ô3_â+6D‘'ÏiòÄŸJgã}âÙšcVLŠY¢IgšÜ2~©Ö2)Üû”?va£1Ÿ«4ëí?G >D–|JE{_†ÎiŽCô£}¯…À)êãƒ7G3lO›µÈÆYºC [[fYèÕÚ{.oÏèÓTÆ7Loá =@€þèD»3:­4†!hÃcdã´ú‡ÞX…F+‘lA$RÿBS^"ð;‚©](‰= ‰¿1@ÿŠl!´ INµ°‡paà%´‚²‡C QZÐó… ¯"ƒ-ÎS4PP"CäŒ ç[8ÒBdGÿr©$ÈŽb€ì ÙÃÁù†ñŒfIò&x‹#P$f$R 4}K‘®€;]pû9ëõó$ý©Dr¡…cÕÐ>¥ˆ›;‰¢DoŠhL»t>c:ì|[ÒOÑ;Fÿ÷$•öHýJ"h|H›a¡“,d²‰Ñ6©OTt–vxŽ$=Cëy¬#åR9çQÉÐnó~·©¤X£ƒ\ö«µµX„†ó´9ŸcŒ^AJ,z•&h¬\ðNNÈõ\"{ž2Ú¸¨‡cÉåŸ]Ð Yzœ<èIª2´‰±nôU²—ðÅ{…›ï†Þ$K/Z§ë€ëÝÃñB ‰N41‰’a©_51™¦E'»+Ý"»äžÌPKÿݳïÑÎPKè|W#org/rosuda/REngine/REXPVector.classQmkÓ`=·‹M³U»ÎêÖê¶:M[·‚_+‚¯0CÜêðCº>ÄGºd¤É~•æ—6ñø£Ä{Ó ¡£b÷Üœ{ï¹Ïyòë÷ÅOO±cc $¬ÛXƉMÆ”iJöЖà# ›RqM´L´ Åg:ÔÉs‚Û:$¯¢"”=ª½ô¤¯â¿?dfÝõ¢8èÆÑ(øÝ÷o€;?¼óô(éÉlq¨Â ù’Ií,=:TÇIgÄ'ÖÖ£½ n눿¬$ÚOb„ªÛò¾úg~wè‡AwÊö‹IôZõÓàªÍÞÒøX½Õrž²¬žêïȬƒ2nIXvPÅ ¡6«ø2ÕʬbÍAOt$É6'ŸÔ±FhÌ1yå¤6§ÎîýÓSÛîu3×ýå§a›uww~ÙØàºyLxäx›¿ŒÄx£=}ç„PáXœ’YërÞº‰¿\kw&(üíµ3Öâî’AriYåjùÜj¾¢`|›Ñ/s¼‹{yߣ(•Úc,ü0¼ÎùÌŠ*Ÿ}…¾ø|¤Ç¼5/a|œd&Šc˜‹ƒ¨ŒQªØœqó|f·l­ÿKÈùO!¹Á†ØÃý?PK‰ÁþƒÃMPKè|W!org/rosuda/REngine/REXPList.classUËRG=­3 #Ûˆ§A`ÙGHB"Äqó~€#G`‚lA^#1ˆ½J¹pRÙe•?È&Uö†E² ©Dª •,“ª|R^äÞÑX¦d‰b¡žéÛçžÓ}îíÑŸÿýò€iŒcAÂ-,tb ·9rGÂ] ‹\’pOA'Þã!Æ‘ûÞWàÁ#ãü¶¬Pâ ¯=±*ãÆ%¬1"!ã¡‚~|Èìë2ñä1ƒ“26ø¹© ƒañJ\ÆÇ>‘ð©€TÔžf Ú–ÀP¼PÊDK…reK‹®-æ3F^®Å²9#Ð1kä s^`$Ð6±.àºSØÒÎÇ)¼RÉ¥ôÒC-•¥ˆ'ajé½e­hÏožBÔreññjC%Ò:™ 3ñ]í‰ÍjùL4a–Œ|ÆJðjåÍ4žè÷iõAjWO›½‰èz”Ϊ,î§õ¢iòe ŸÑÙ³z>cî81šeÞ‡5Ý ´Q^ÕŒR=Ôe”×ôt¥T&%Bj6ÒGB§˜+›…úV›·d€Ì3 wõT%ó¦$ •RZ_2,g_XáLhƒíôT\Ãk J ´1QàBó&8#-0Ö&ãžž×KFz,”;¡"Š)[¸N:Íl·+FvK'à fUèØVñnªÈà†€;¯åtjHô¿š¸½Íys˜_°ÒŽ »ްÂT{*²ÈÑ✊< T¦p$BÓ/†Oi+êì6«õ3 Ú¬/åœf¦w]cuõœ¿m“6úx*°Ù¶‘7[w²«l|nõV±¨çÉ¥É@ Ü+!Ûpj%É ›`ùÛ×*“<9mß궘©çÊd5}øŒ*\qïéOo™,kÙÏͺ±ÖׂOËô)7ƒ;–Þºè‹Æ ÍÒpÒ 0¬ACÀsG²ç\¡ŸáúÖÑxŽœí‚Šúj†i6Ç1zà0&LÐó˜ìy#N‚“¶à.Ñ0ÑÅ`¸÷{àF/Ñg)†X±Î:3 Ñ¡“º[w²Eç·Ê’®_Ñ‘t†ô”’Îp¢Ù–'ä}tà\Â(Eé*+³MÚ¶u¡3ü ®”x¨Š®ÃFºb®[Wñ:½¹(>M¿7pÝÞ’Ÿžt?!3Aê÷Ü+~Æ7qÃFÙh‡« ñ­3à¸æoŸ¢‘¾#6nÄÆ¹y—‡MP®*}|lè†å9müªè9²ú|‚UtWáý²·çno/Ūè;lºÎ5e¸úWõ³ª]K‰¦s ¿ÉL=Ÿ¡?ùRk€x½ƒuò.Æs>ÛÙçXõýˆ¡çˆù¾…òWá{Äk¾*FV&ÇpȦ™dŽÑ:ƒB6êR~žåÇß½ä%²Ë·Ó©®0ÃÕæ#Fèæ€*?JõS ¦©bsT%r:E^—ÈÆ pŸ¢_cÞ²¢îá—Ð/|ÿpCK¡¯›,˜·XßýPKËñ ^ PKè|W$org/rosuda/REngine/REXPWrapper.class}WktTÕþÎǹ¹¹IÈ%“ð(‘IȃDo*!ÐBÀ$UB˜ C˜ÌÄÉDHÅg± ‚-V(Úh ¡NPh@­¶"ÖŠ¯²º–mi»ªR[×rµ«Ò}ν™Éäa~ä»gïýí½ÏcïsæüWÏw(Á% µhæ¸M`˜£EƒŽV NÜα‘c“m’ð]Ž;4èhãØ¬!Uàwi‚»5¤ãŽ{5dànŽû8¾§![4dá~ŽïslÕ0Û’Pƒ8ƒ‡Ä`;Çsü@à9vŠ`ˆÁ8¸‹c·ÀÇ8öÜ˱Oà9ö |œã ‘ÁOÄà§ä8$ðIާ¶s郟qü\Å <­b§ŠÝ*žPqHÅaGUSñŒŠã*:TœPÑ©â$Ç/4TáÙ$Dѥ┆çð<ÇiŽ3 ZC[Ä·jnuõÜ:†ôÊõžÛ=EO°±h^ÀÓÒ2“!¹e](é±HòcßZ lì$¯ „<1•¾&ÔÚˆùMi…>O0¦®‰„ýq®VÖ+‡äšÞñR*‚_£/3­ìsABÌòĘe‰1³üAdƒÍ{3ƒ}^h!­ÒôUµ65øÂµb“bcØÓÌPàîµKÖû¼‘™¹•¡pcQ8ÔÒºÆST=?ØH\ÂeKi™Rj"ï†Åžfé†ã— ê,oÀЩՄZÃ^ß¿ˆ0DPn¡(;p¡¢Ã‡µ Yƒx×ѳ ©ñ|Äzé8‡F Bªöln_¤)ÆyriF±ÖZÇKø• ¿L'"N¶´ ‰ˆÝHˆ w„aÔ Ì-Òñ ~-ü†#Î5• 1­=<åÊP£ßë èxç…Ç×<šÇlðtL½à]Ðq+èX ­¯ìKŸ)ô¯ëøŽÐ+õe:VНôÞ–bCÈîÓ¤F0~«c• Åá2Ó°BÇjñ•ÑÛÆZg²ª3­êðô‹(VžL–›& DÄ7t4ô‹(7„ ëMÃrÞ~ó4žŒV˜FË…·ßéXÓ/7k?ÈôM\Œy)ºBkµbyšR¹2±œ,K¹ 1צ°gÚ}ørž}øæœú„·&ÑÇkOÂdŸÅüM^_sÄ êx k9ÞÖñÞeß‘¦ìë¨P³Eíú=šTvd/Û+¢¯…ã=¿Ç…ÁϤUÚ 'Ñì ¥",u‰F_ÄúêΠ'‰}³'Ðꓽ«ŒÁá®/=L¥fWTPïrWy²Ù}ãªr¡**ÝêÄqÝr¡[.t.wÿ³/ä™îŠB(( Ë-”ŽøÚP¸ÊÓDþsr9ÀÓšI‘-´6ìñú«¸­%âk¢d}aZT—I÷‡Š–šœ°ÏÓÛßD1¥"‚Cwg-=Ò ‰J¦/M”«ÄeÖY¸ÜÂz WXx«…+-\eáj =6XèµpD˜èóô¿‘F£¡#¯ ì}0¬£ÿN)L¦w„ëMSg==m8ñWæ½e/Ô¼sP:ò¢°UN4ìía?£.η‘Ô…£ö4œuù]à µÆi$Õ‘JBëB2 õ¸P"Ŧƅ©Q¤™Â!R˜.„C¢0º0”„qaF.S˜)…YB˜Ű. 'áˆv¤ÆH!Ñ…otLìĨ¸ht®¢l)r Ñ™u'ƶ£”†ãçwÏÉï>£Î°ÛJ.Ǩƒp ·»ù.G‰˜è;|íŠà·[Ìñí(!f1ÏhUÝ¥&Óe?ˆôÉœ²DÒþ)&[Ð…ëk‚ÏmÅÓŒ§-鉗$ãIf®L^.[ž%šh:ËÿZg)9+hÇdbögµ˜EÛLÞÇ ¼"3⤯˜6PÄb3b‰Åäý#NÚQÝ1]òn¼ÉfÄ)ýy½"Õ={1Kå‚ÉÓ3ÕMkÇtN'g[Jo[©ÓåÜš»g?ùs¸œù.'ùsUoq’¿¥?‡Ež!ýɃ7³ ³„h¶™Ü+9û€É ‹ž,™Ü¬ÖAu§ˆd/¢™¾WRÍ­‚¸RÓ©h³¨G’6‡ê²ÞÞ“Ñ„ydWÛ¨}DȺ•$›Ð‚6Ü‡ÍØ†;ñîÁã¸G±$éÆCxÛéêÜIÈ#ø+vá vã²ü{p{™‚},•0ûÙh`98ÈòpˆáIvžb³ÑÎæ.ÂV‹§Y=޲Õ8Ƽx†ùqœ…ÑÁî"Ü‚Nö0N±]xŽ wþzC7Íò,‹â;KoÇ×ßÄKìô»ŒWÙßqž}D/¨Oèr»Š×.(IxCŠ‹Ê¼¥\‡·•±xGqã]¥ï)³ çá’²ï+µø£R‡?)+ðg¥—• ø‹ÒJxþ¦Ü”íøPÙ‰”GqEÙ‡(‡ð±rœðYüK9‹+¯à?ÊE\U.áså}üO¹Œ/”ð¥ò)¾R®áK›ƒÚsÚ2·eš-—%Û ™n+f)¶©,Õv#K³UV³tÛ –‰ ´ã¯1 ù—n×h#µ$ãÇ8ÆP»ýYŸ!)A•ÑǤ*ã3¨ *7ºV¢Çü]‚ª0¦rõUMœUBª©³¦ÄTVÃâºé¶Ýð~9Î!ÞÌ~"7õÜIÌA ®ŸožÂ'‘mÌ•8Þ(“˜k?“L×ÎIó¤ Ø(—XjÌ—8ÃX q”ñ-‰coKœ`THœh,”Xd,’8Ù¨”8ÍX,qöa YD7Û’N,5nŠ¢ú„̧ ªÊ,NTÓït`,å=Ž~¾§YçÐÝ~=r1Åpc:ò0ùT˜¸‰JµEt/O¢²-¦R-!_ÓÉÛ*Ï©TšÓðfˆÃB+¡ü›9ªt ”½ ôPK«Ÿ®žznPKè|W&org/rosuda/REngine/REXPReference.class}UYWGþzèalqAeqÉ0 D1‰QÃ&à°nIL3Ó ­C7™éÁ-fß;ïÉ›/yÐs"æ$ç$oyÈÊÉw{šÚiú«ª[ßwëö­[Uÿþ÷Ç_ã—(Ú1[‰6¤æ¢0q9ÊÞf¢˜‡¥ÂV± Ý£È"'ÓŽèò‹W® \¸!pSà%[/ ¼"ðªÀk¯ ¼!ð¦À[o ¼#ð®À{*Þ¢³2¸-½"øPÚ"ø8‚O¤{[ŧ*>SPfXi ;›îÈÚ¹|Jï˜è·Ò¦e,·] *æt+•1Ô&.ë‹zGF·Òc3—¤ÃÙª¬‘³3‹FjZÏäIÚQÚÙ¹qñtÜ´Lç„‚C±õ–|x™Öiá^;EÿÕ RFóó3FvJŸ‘°šÖu6,ZÕ RÁÎXë:VM:zòʈ¾à¹ŽšÖ¢ž1SºÃAYL\EfM‹¦†ŠÏIè¿–4Ó¶rœ2s“NÖ””’{AA¥™c¤FÖLºý!Ë1ÒF–y{&ã*ô¤cl 3ç¸Ä„6“:ç«Ì\¿µhfmkÞ°‰'—`ZòzÚ(,w}~Æ.ø™6 ~ÊÍÜ„~ÕuÓkÏ/dŒk 6Ðf$óÙœ))pG³FÖ°’Uê^Ðü­±Ö‹«’_°3-Q}9v’Â$ ¹º>;Ï,y¦>þ‚îýBC@’e–î"zñ¯w0 óR2–¨3çf”«–_Ò‡ºÆàmô©LΠW¸[È.QºB)ƒ)ž‚ˆc/oîZw+Yš´óÙ¤1`ºgEB)¦ù Ð5t⸆8¨¡ªøB×øJÌG4Âa_køß*ˆüÛˆ™›×ä\±êì ŽºÈÒð¾Wñƒ†n‰à(žÔp Oièèèè8-0(0$0,pF !0"0*0ާ5L`RÞÑ0³Îἆ ¸¨áY<§ ÎŸªž¼™IY 3Hjø?q[or—»eð3wº}®[r‹'; «Ê·.€¢`óʺSsYûjáDo\±&lÙLuQî­±Y bë÷U¦¹«õÁùUPãÝ+«:pñ~YïæÙ´|­¬rÕ°Ž+ÞD5þ’–¸°`X)bWèÃEëíD—¿|éòÑÌ'­bÂRÏì…¥¤Ý–…Ìv7©kâcu"D.P%Þv¡xû}”Ý£IÁãÄZ â&Tr´›]ÙžƒýœF4ÞÖô;ÂP¾¢Ò9PGÝvZXÜžæ—”™½ñßPñ"ÒÜCñ%¨÷QáwN(wÉÔЀ]ˆ¸m3½…\ï-´€•s¹F{ÍüÁ}Ä=œßcdhkã*"½*¥Œ  ǽ8ZèIa[W¸¨?î6”3•a9™ ÿ[÷¼P£LÚ†;ˆ&¤mûûžë,‚jb!ÄzTÑÖÉ0Žp¦[Øn£; MEhLʼn œt7HÁ ~<ÿ^|Ml]—\K[BÕ¯Å+\»ìAO{£Ÿ}”ØÄ®ö³e¯ú‚Ø5~ö1b{“ŸÝEb×úÙ²[§ƒØ›ýìnâ`{‹Ÿ-ù boõ³O‡ƒØÛüìSÄ3Aì:?[x‰ öv?»‡8ÄÞág÷GƒØõ~vq¬È®÷Ø¡°Ÿ×Oä+ã Ÿ×w}ìÁbGøña*­kðë†Öèø–•Öíòë†×èøü•ÖíöëάÑñÅ,­kôëkt|dKëšüY]£ã»\z—šýëŸÇ%½Ëc—óf*óS'ˆ/@/A ù©SD>þõ´w?vü‰–ó°‡×ÜÞ%ì«ÝOõ©úeÒoe q¿Ó³Ä””ŒÿPKÿgög¯ PKè|W org/rosuda/REngine/REngine.class¥WùwUþ^3ɤãXh€J±-A¶4i)îÒ¢BKÁj[*E Ôi:m‡NgâdR@Ü÷}ßÜeóŽ…ß<ǿɣÞ73¥!™Iã±çô½™ûîû¾ûî»ËäÏ¿ýÀMøEÂLI¨‡.bZ„!AÀT&Ÿ³|xDBV96×Ë‹˜‘p‡D®Å<*∈ÇD<^‹'𤈧$šŸ–hé><ˇçDýw.!rÊÄ«hâBKÍ™úŒºCW-ÕÈûn vC%¤KUìb úqÍPtíÑbYSp:Þb:ÞBºtë3šeÓôÈpk𮊧«3ÔƒWÉNˆl6Æzo¯>O¼pF7y„Q>Ž0ÄrùlÖ´ìÜ•óQê-žñ’X¾¢Û;ÔOΚ}í73SÄÊp_fmá>ñ]éã+‰ê²1¤›¯¬õ‹%_ ¿¼ªx›¢mætÖGy¦;/‘¼á> çQÛtÑÈ{”ãe">'݃–’-¹±í£ÔŒ]ñÆ¢3ºWD¥a3oeÔ­/o²§·Ž£ÉÔWn–q_0Äçàb:hÚ[Í<Ìl9$_–ZØ×ô1ÕbXšQŒµvœâ~,îÖäx†ƒÄe|‰¯dd0ƹ¾&~7[fk[¬øÚÞ.ßà[†E{Ë,â;ßãòà‚(c=n¤H+Á-Aô\̰²Š’-⸌ð#•R›dœÀI›°YF7zd aCsÀÅl1óÔd¸+~’±½ÊšZnZ±3“Eî¯`i‘V›ïî¸fÄÝ¢œhsŒØ»¿µÓ¹žŸ¹9§¨ÍXÒgØê„jq­Ó ­óÂk†í`{Áõ=wǃæp>39 Ú“fq"åJŸ®«о9CE0W¤’šS±Ôq"¥£Ï˜13 _Þ©XTï‹´–&ÕqÓT¦)GVûëÒ´á]7›U± ê¼´q‰Ÿ>Õ§Z2Ò=;æyJ®kD1Ëì±]¢Y´F¦kä›):ëŸ2çSZËEÔvçdݦ©« 9VØ™¢,«÷q—H0¯nghHŒz›yÛK¸È¿ø;ôÆ€¶í~°ù;›¸œ¦Ðèd¤àô­ <Ýmñû·„ôᾄ~2P­å•žâôL…žÆ[è­™fŠw„“çÁÎ8Š·Òq„QÔâ6ÜŽGõ}õ 4w'/ ¦?õZ."”¾!}áX¤1IÿDÏ£öR*&±Ë¸¦y ÑÓµÔ ¶_Æ‚ô9,‹ÅÃdhg¸1ÌhmI:”¢¥6Zi¾€ZªëŒ4Flo!þåXCníÁ ¹ éˆËÄ \¿ˆËxqáâW?ûB5‹¸ä….¹%hB?Ú Š„š?#E˜™ˆoÐL‚]ùðÞ‘âÒòQM! â>C0€ê×Z \œhU<­ÜXkˆØ…ÄŒ—qå,g ³î¿¸úPKŠaCcPKè|W/org/rosuda/REngine/REngineOutputInterface.class•ŽÍjÂ@…ÏUkjjÀ}nëÆ`¶.KAÐõ4' a¦Ì}·.|ª˜m¡ à]ܳ8÷|÷~¾÷Džô QºÑ¥å¯JUsBò²PZÄZ÷ÁâôMŠRò‹NÛ±¸fRęեÓùhMè§Y¡¾–Ü&ÆäN†GDé¬v¦øí1¼Éð‰0SNç|Vúóç³³röÓÙ¹´\oYÎÇþatõ/@üÕ[½W<·]¡?í¡Ðèº' ðØ8„^³[PKã uGËbPKè|W*org/rosuda/REngine/REXPGenericVector.classVëSWÿÝd“ Ë¢ Õ@¡ØR ¨ø@E*(ÖÚ%,°’4Ù¨ø¨}Pûní‡~ðKÛq¦ÃL3¶SÃL™:m?´3ýÔ¯ýOÚ-=g³€ ã0s³çõ;çþî9÷òÇ¿?ÞЂO4£GF¯zJAõË8.ㄌ“, (ð`PÆ)N³<¤Àav>Ãá#¬•qV=¼¼Èšs d¼Äây/+¨b[4c jXhF”¿ÆBÒ=˜ð`’娌)6L+؆ œ)æÁ q†N04™“¬‰zðŠŒ”Œ´€œÔfc m\ º7‘šŒ¤é̸èŠOq=2Ðk¤Ívw‡7̽µÁânõCÒÁĸ.°¾—Ôý™™1=uJ‹‘¦lÐÔ¢ú´¤-·­TÐÒuæÄJ¯–î×Lã¢~L»¨›Ö£¦ÀÆ`}ï4É‘˜ŸŒä´í2L¥ërTOšF"ž–q‘6Óã“æ”€3XßM¢‘fpK(5Òz4“JS 2j¶1@Ö Éc&Í”ŸÌ¯%§%23qHËL.»)ƒ‰L*ª6˜‘JÞâ=®§ŒèÕžH51„Š]¸$PU,±ŠgТâ2Ô¬AœÀ¦"V:Õ"–\*fq…˸*Pž¿+W\›ÑÓl¿ÆË³*®ãUþº¡â5t TX1ÓˆEŽjé)ê¯ã obNÅ hSñn.c[~¹ý«xïPÝù9dŒØ¸NæÃ8¢â]¼§âºìJ¨•Ad>31Á!GqD@\åúÞWñ>p„FùHÅǸE-nj"—ëÛ‹Ðò¿C*ÎÞ²}ÃÙB½Pžß«Á"@}FzF3£S+=lõ)ÍlÐX[–.è³4ξ`}Ád•ÁjFh&C‘¬íEB$Í4y×kN©@]átŒ¥´q…¿4šˆ›šO÷è³¼…ǧ˜g²Dé3zÜÜo²OwY'V’²î.€P³€¢wåò©dˆïƒdRéÁ =¦²»µ=ðFËf´ËÖ½Ðmê3tŠ‚n¤ðbsW´C³î§îŸ&¶Ð£Ð _ôUBß4°´>GÒW(% 0аÑúe‹pŒ,À9)tRòpÝÆ®†E¸GØ(ýyĹÏHÎX²@W)KGœ^upe Xwë¿#TZi­¦w(ƒ„uØ„rª©»éÁ;‰xž,;à\Â8dDd ô»ÄÁ¶lÿvXuï¶ëž†“þCxå _M¿Îr¬†‹Í*¬”!8–(»3-SËYQ­Ä×ýR^qŽÀdrû6·÷ŠŽ‚¦l6úÂ÷k¾Àè"¼T͆~©Ur¶º|®š;Ø×ö¹Z²Øx%ÎViMâseáksûÝ¿¡Ìïþr•mnËÕïÎbÓðœKÌ/ýâ“nÃÕxwUëïsî­%Ä Ôr¼ä—8^²ã¥°Ÿj©žsRè_á»+\LÀOëúGeÀNb%ˆ:ÔÓÚ@œ„¨-ÂØ‡F@º¨qNPÓœ¦¶9OÔO“=I$déÚq¸‰=¸…½ø”¢>G'¾$Ý×8hqÜÏÁ¸‰E"—e¯ [ºòü2:þAùßp?D‰Œ*ñµ–ª”Ð@m"Qb§}ØuôK¡ðؤc54ïÇméÓºŸjÎyWÛÞ)ßï(­ŸÀï­ô¶Ø~µ¶Ÿ‹³ßÍsí¥•$ÛuÔêêèEÔÐ1h¨èt67dñ”Õ#oÝ<\Þ-¤Ëbëê±ä°Ž[´UÂqNFÍg%ê¸ kd¢Fð+fçù•H⦾¶ˆm#«¹¶®÷éøvô:÷lÆî ø;ï`{à3(!o0‹úáYPy!–çÔ-®†_˜õvòiäMùÕo¥v±§è¨¸]†è ‡Ñ‡3¤…޳ÖÎTHQ'c›ø*h'ݱÿPK½Éf PKè|W)org/rosuda/REngine/REngineCallbacks.class;õo×>#vvVv6F®àüÒ¢äT·ÌœTFÑ ×¼ô̼TçÄœœ¤Ääìb½¬Ä²DFåü¢tý¢üâÒ”D}¨}t¥Œ  Åú9‰yéúþIY©É%@㘠€‘H21°PK*‚hsk„PKè|W-org/rosuda/REngine/REngineEvalException.class•Q]KÂ`=¯n.×LíÛ‹ˆò#ièU`a Ãbš·1uŒÅÚdN©ÿÔMP]ôúQÖ³¡}\´‹çpž÷œó<ï»·éË+€¶EðXO"Ž ›"aNÀCJmvN5õìZm^^µ˜J½†çà :†32ãïô1ðŠ®_è!™2pÁýÀdHÛ®œ0ÔŠšç[²ï G}CÖײ]sŽuíÆ²c¸–Ü |Ûµêj©C! ¯O!i4ÍÑm×ôÛFסNõŸia˜`™A;Z*^,ÑÄ–7ò{æ¹æf^el8Ê]϶ç†9RÈJ 0~úÃz–vÿϥء‡æéÐs# ÄbH¿ñEpá‘’…ùTÓÄ*Ä9B©|P™€•óψ=gÈP]¢S`Ÿ’ ”PŒœÙ™s|ái’œ™éÜ—M¤@•Fר³Œ•™%OÈùòbŸòDÔ<¢ºíºöPKcqË=iUPKè|W$org/rosuda/REngine/REXPUnknown.class…QÛJãP]§­MÑvªã­Þjç’ÆKÁ׊ŠB¡ˆxC‘yˆÓ2Ó9)1Uü'FÐü?J\'æ©Z$d¯}öY{í³Îy~yx°†%Ã( ÂÀŒÊf5ÌéH¡ ó*[È ¨p1ƒ’Ây ß4|H…×-G@ÔÒëžô ÖÌZù˜°å7¸•­{ÒÙmÿ;w‚Cû¼ÉJѬÕýÀ­þE»aWö·¥K ñd¯î]„UÕ¬¹NxI'Í2Å3¡žtÆÌrý}iWš¶t+oÕª€~à·ƒßÎŽ§F䔨‘ü+ý+¹ªÈrøa`Y•ý˜è•Øl{͆˜À¤eº:S‰Åä—À\Ÿ#ÇS¨Ø‡Y ¥óS×i»ÕrdC`Å|oñ½ëøÈ4?Ã+ï»"v˜-øóSÌsøÂ˜çj ~€nu!¬Â=·{”1ué,æ—ÈN‡¬å.’6d¿b#!.>ÁÏÎ ÀÎ ÈÈÀf“™—YbÇÈ «á“_”®_”_\š’¨äš—ž™—ªä“Y\b­ÆÈÀ✟’ÊÈÀïö+ÍMJ- ILÊŠXáшUÆ5"n*Wf±Ob^zib:Ð$f Í( Pp~iQrª[&ÈpA°j¨ ½¬Ä²DV6ÁÉÈ Ëx¸‘ÒxÀ ÈÀ `f` $Ù<9& d``ÓÒÞÎÀ¸Èbdàñ4PH-'T­

ghVç [7îƒë ÝÀsÚqäÞ4Ó¹ŽÂG·7äu³Ë _„Ú[l‘ïrtÛãQGôNÜ †iéMöªæü»äÛá(êó¦/¶)ßxêó»Øƒc±@G:¨"Ûd¨ü?qâd(ýnеª <‹1Clv±O?—¥Ÿ¤w§¢,CyÅ„PKè|W META-INF/þÊPKè|W¸o67=META-INF/MANIFEST.MFPK è|Wµorg/PK è|W ×org/rosuda/PK è|Worg/rosuda/REngine/PKè|WÙÆéÍå 1org/rosuda/REngine/RFactor.classPKè|WjG…}È6 #dorg/rosuda/REngine/REXPDouble.classPKè|W%:¡ÿû)} org/rosuda/REngine/REngineStdOutput.classPKè|Wrv­–œë.ïorg/rosuda/REngine/REngineInputInterface.classPKè|WF:bœ¯$çorg/rosuda/REngine/REXPLogical.classPKè|W óx; ûÕorg/rosuda/REngine/REXP.classPKè|Ww½ Ý® +[#org/rosuda/REngine/REngineUIInterface.classPKè|WKç}X²$b$org/rosuda/REngine/REXPInteger.classPKè|W×÷‡ÞÎE )org/rosuda/REngine/REXPRaw.classPKè|WM!N<È-(+org/rosuda/REngine/REXPS4.classPKè|Wë“=ê„.=,org/rosuda/REngine/REXPMismatchException.classPKè|Wpð_a¬(ƒ.org/rosuda/REngine/REXPEnvironment.classPKè|W=}ÏÉ-é1org/rosuda/REngine/REXPExpressionVector.classPKè|WC~T ¬I3org/rosuda/REngine/RList.classPKè|WKõ=Z>f!2?org/rosuda/REngine/REXPNull.classPKè|W©º%©7¿@org/rosuda/REngine/REngineConsoleHistoryInterface.classPKè|WgK}Ù#ÍAorg/rosuda/REngine/REXPString.classPKè|Wc”Â$›Eorg/rosuda/REngine/MutableREXP.classPKè|W·\Vΰ*Forg/rosuda/REngine/REXPJavaReference.classPKè|WÿݳïÑÎ#‰Horg/rosuda/REngine/REXPFactor.classPKè|W‰ÁþƒÃM#«Lorg/rosuda/REngine/REXPVector.classPKè|WËñ ^ !¿Norg/rosuda/REngine/REXPList.classPKè|W«Ÿ®žzn$lSorg/rosuda/REngine/REXPWrapper.classPKè|Wÿgög¯ &8\org/rosuda/REngine/REXPReference.classPKè|WW^Dñ¡ óaorg/rosuda/REngine/REngine.classPKè|WŠaCc#2iorg/rosuda/REngine/REXPSymbol.classPKè|Wã uGËb/Ækorg/rosuda/REngine/REngineOutputInterface.classPKè|W½Éf *îlorg/rosuda/REngine/REXPGenericVector.classPKè|W*‚hsk„)sorg/rosuda/REngine/REngineCallbacks.classPKè|WcqË=iU-Ñsorg/rosuda/REngine/REngineEvalException.classPKè|W½ÈÆšÚ$•uorg/rosuda/REngine/REXPUnknown.classPKè|Wäõõ®%worg/rosuda/REngine/REXPLanguage.classPKè|W³Ø*u>„)Éxorg/rosuda/REngine/REngineException.classPK&&ÿ ^zRserve/inst/java/Rserve.jar0000644000175100001440000011011314531234226015377 0ustar hornikusersPKé|W META-INF/þÊPKPKé|WMETA-INF/MANIFEST.MFóMÌËLK-.Ñ K-*ÎÌϳR0Ô3àår.JM,IMÑuª Eô M4\R“2ó4y¹x¹PK¸o67PK é|Worg/PK é|W org/rosuda/PK é|Worg/rosuda/REngine/PK é|Worg/rosuda/REngine/Rserve/PKé|W,org/rosuda/REngine/Rserve/OOBInterface.class}½ Â@„g£&þ4ú¶¢W‰… P"Äö’¬!!ÜÁæá,|J¼tê4³ß ìóuXb  O´NbVa< wÚäÂh{ˤ8nT^(v~>¬f'Bß‘{¶VæLXüƒ^ÜH¬o&åmQ¹‘Q­Cues‘)ÏKYKÂä[ײ©Y|Ò„aËJª\DIÉéÕ'<4òÚ„Ú€ó|—¸G›Ý7PKiÒ€©PKé|W+org/rosuda/REngine/Rserve/StartRserve.classWYtÕþÆ’5‚@oYjûŽLg_—3è®Ù—Mæ1Åp [cx]„ö†íM¹ölvWVdÌvüÀBÑðóÂ\¶Mï4†MÝ+Ñ ÐM“ŒÇ*|ë9³ú˜±Ð1‹’'<öLß'¼6 ǯP dY‹2)–“ PœJe¬~×pÇSÛ\bsÌq‡½T¶mpn‘Êšž½'q”'?ÃODæV¤Jž›*ˆÊJ¬þT6`! ƒ $É[&Õ¤¼±¹çSävÎqì9Z4åý`¡á§1tŠãý™HÜ[1ü\”ÚcÁ¡.*‹]ýûœ'±ü}k„lË*”ý"ÎÝ®ÃDx‹ëlÜóÍK†LŸûEÓõÇœ]©ÅUÒ^]0í!?/{Rsâ•ú½rå®HttT–1÷—Œ‚wR# "“4J_NDµ<±PI™¼9Š_à— ’k”5zÒÔ×$‚”5oæ„Òj¸CÞ–&¥©y®(X9BH²ær†¿‡hãÁgûô¥ïÿlÞ2Oaó€™SÐô?òZ>! $Í\ÞÑ›>8.FßÜt£""KTlúU‡œ´<3WI»Éë ’»ëõ“1ÃU¨:®ÐDm{‚E´ =¡4ŸÕœŠiXVÁ&{|Q¬ öû¼Zùæª%"Ú]×qçDVΡ‚º:ìbiÞÿ†DÅÞ95 ˆ´,âÛæ¸æ:é·1DÌš¨èý†E©d/c×:‘ŽrzŠAüA7ãÁDrÇ£Î3 w³Ã•Æ´à\P•Ýyú7@a¯`šEÂ'q¥¼¡ìsÄ >C¶Í݆(¾óËm¸dËæJ—Ü’­gÛ¯8Ñ÷ý¼©‹î%^º3¨g¥Åæ…é>ñb©|tK”>ö²¾l‘,jøÛ4ë&¹8'–ëù'^~… 5×ôJ‹"»·¢%ÍË—|¾Ål¿íò· ÖγYö¨3l–¹ƒRÞfä|ÇåÍò:–qœáSë îÖ‚áy&ý|ha¨eÁEd;ßEÓ[~p‰/ì/šØ÷VhjïU±•‡×eùæf¿ç›àCù¶èJP‰gò¢{™¼MWóšÎûÇqÕÈYái9åyqÙF{™ d«ï×2ë^É5Ú¯ŠW…¦:|‡äßðWൺ† 5¡‘xx‘tuCõ1\ÜP=…êzõÎk¨Õ«SPãÚj&°6¼12MõÐâK&‰ÇZ×Í`)0…Útx)îV¿„ºžP¼¾«'?¥«'²¹…Üü0éšÂ²tøœÚžÁr!½â(Vö4„§ð‘Ð4¤Õ¹å*¹Ô–G¢F¬OÛC©øé˜ÄʲŠ)¬žÁRKè°¶1¼<ü6…Þsg¦# ‘)¬Ù>œŽæˆd>K2ŸŠµÓ8›Ž¥#w„g'g3]!&éE^Iñ6þŒ¿pþ'ÞÅ,šø­$ÒxVsì!_/¢Ø‹fô¡×ò›êz\ƒ~ìç< ·c÷"C°x¯ÞÇR(Po‘šGx‹µñ&Þdöã-x´TÂ)õ'ŒÑâü ã´zíÞBË7³ÜnUTÜÆÃ^Cí,.„ª¢.øQ¥âJγ<Ù÷ì…‚=þ({Ú{÷ÃrJEùÈü¾4±t!‹ŠŒd¿q¾Š•üÍ21áÅ:—½‹*å*>ôªhR"D¯T •¿µaÎçL#1Hø°„⎖cðZÊ8Üײ†{šy‚J†x‹“«¶S¦•x /;[P’SXÇÿÖÌ$â”hA² ’u¯c©ÐѬf¦±þpœ>¬?ˆ§bCOüÜ#8o çO`Iü\I¾S’7Γ7Jò¨$oš'o’äë$ù‚yò’¼]’/œ'_(ÉçHrzžœ–äU’¼yŽ\ßLòT–Z˜hUp?ä÷¥:]œÎñNû],í»Q‹{ÐBnÀ}ä¼[ð‘ú ¿>B&(û(¥Ã«§›‹O‡OsOSòø_PK~³7s¢ PK é|W#org/rosuda/REngine/Rserve/protocol/PKé|W.org/rosuda/REngine/Rserve/protocol/RTalk.class•˜y|TÕÇÏÍ,o2È#d€ÉDp˜L‹T²Y`Q\šLfÉ@2/μ D-‚ÕÖÚŪÝk¡Rl¬K …¦Õ¶ÚÚÖ®nu·nUÛÿº`ú;wÞLž1~>ðGÞÜï¹÷ž{–{Ï}/O|òð­ ÷Üt:=XH.:ÄÃ6¢q²áløãÖøû ºÑw„GB8>Îô?æÇ1~wÓ/iÌM¿¢_së…uS)ýF¡ßºiýÎMÑãüø=þC!=AtÓ½ô'^æc…þì¦ z’áÇ_ú› gcGg¸µC šÖ 'ÓF4il‰öe4KB‚ ëë"Œ‚ mÖ77±À–´wD­ëX`‡ê·v4AØT×ÂBGVK{Óś݂\ÀºH¤n+sQ–›ë"ë¤Ò5PÚÐÒØÙ§÷$’‚<ÜÔñ¦Áh†2j²){Ò½#®ïÄ@7c[C,Ú×ÇjŠó’D2aØÚÒsŠ> %×&ú¤‡ª é,‹¥´¨¡å¤38,íÓÓya‰9#ã9ÙLsàÎTbbv©©3¥õëƒy©WP‘4X3r‘¨4FÓéDO2''h†9°>³m›–jO\)5ìTlv4%cz<‘ìañµæø¸fDc½í”éIîX"¨t¢C‹o1ƒÈ}KÍIQcÒ¤e¦—1#Õ—\Ÿ díz&“æ4 RóR3 ,o„™M‘Hg4côvn‹Âý8‹ëLqLO&;»Sú 9+bI"9Øë—ƒ,¢h )dŠh©”ž2»Âm’xôZØÊ¢¤nȤ²l“«Çbp ¾'Ùõ× šÉ™d:30 § -ž[5lš–IîH‰œxƒ©*5¢Èdj[Ÿ¾“;6 *á½{»3: ]ïìNÈ\4#R²'‹¶uöký,mɹŽHe÷”Ôߊ²8~gw&=ÄòM¹ueÞ,!ÜlúO¤£Ý¦,š·=:ˆ,gq·iH,54`4å35§µX;v¨mᎸy°"MíØƒ'Ÿnw¶mdDpIÄdfEž­¶zðhš8á­`•g3·´£(Tò„DZ·y;l¬Iè5áä@Æh7p’úW¡SGç¬|g[ưö:Wóù=_ÐâÀ”ó§ž·h‹ {ƒ×žæDRkÍôwk©Tâ…“¬ „/­óX­c¹a)ãzØŽøïh‰Èi ýÃ’ÚN9̉a‹.ÅÁpö˜ºœsKšys+ÜГ=¹>ì'%) æÒJJ»"£¥¡¢&^Ô¬§zjRz:ÖDš’(ZM$­¥µš”nè1½¯&² vi‚³”8Å9®”–@¥×8¤§8wIà”—;›M„«§êZ] œMm_4ÙSƒ´¢Ü­:% ýCÐz¨™jŠí©jû'ûÊ~¸³“¯@¤#Ú·c1ûå¡[è)}“nòзèfA“QËÓ=ô}ú‡öÑ~}—¾ç¡;h˜w{èNºK¡§=ô =«Ðsú=Ïð‚ àÉÍ–½ˆj9ý¦]1mÀ@òÐKô”B/{èz•¯ñš?WèßzÞðЛô¶Õɬ…¬Æ =5Äë½í¡ÿÐ;z—ö£*N¬Ü&K,jŸ5uò~4ûsr+ÈàÃ5sŠ’ÊÀw¸ ïæð§õ¥ # £©Tt(¦ !tæÉ­ O!Êžæ€ÜëaY" ¢âØjÈbÒ‘ŠÆ° J§ªY°G¾F˜vMèBkÁçG4‚·¶$ÖGv°”‘Š&Óxghè¦PkpQ}ö¡ 2Õ×ÝÀ§Œƒ=7ðùç†b‰d45„Z×côÊ€ÃëÙyyD@¥Ñ’F”m£yx+=WÍJòÑ|:—Â~¥¤…à3-/²p\eá¸Ú‹Á5^^jáeàå> |ö¤õk'­¿bÒúçLZÿ\ ³?«,¼|ž…Ï_`á5à: ׃,Ün²ðZð: ¯‡-¼¼ÑÂÍà ·‚Û,¼ ¼ÙÂp»…;ÀZx ø" _ ÞjáKÀ—Zø2ðåþ¸sÒü. GÁÝ“æÇ&é[Xo³p¸× ðv ï÷Y¸œ´°°ðà”…Ó`ÃÂð …w‚wYx|¥…¯_má/‚w[øð ï_ká/¯³ðõà/[ø+à,üUðþøëþž¸tøK“ïþBß-t+žßÕ`Œü~ !¬:LÁÐa²ÝÏŸƒô<§ËîídGh§#´…| ™“/ƒ”{Ϫš[6ƒÆwßÜq]@»Ä¾[u]™'ÇnU çnuhb…YÄÂiò ðex_Ž@òÅg®ô,ÆØñÛ*—+ùK”ƒäR× “ݶªm"Tî7Mí¼ YÊ™`ræB–™†È¶Ïþ”ß#ÈÉÍd2U ¢åHQR³©¹)¹ )‰!ÛþÊñøâ/Áç±PèG(•üãòƒ9+±K‰øÇ­n£›^6šñô™î¹àžrÜÕRæÙŽRáE¡‘¼IÙ´ÜBÅÈälLæeTPÄŸÓü®`j\œæ 9‡'è·wɆêÚµ'èw˜ 28M˜³kÏ=ùä8ùóÒOòJo2•vA©ºf÷>ªÍ«P鲪”ú• ýôð$¦L$ D&V܉Š{*ÌÏr¯îfo§¦q-êÄÿ(¹¯/¥¢kêxí¬°Ï²«•CüS¹—Ÿ÷æ}Í®òуHõ!܇¡ú§tÐT}úyÄœ VtC¨ü(M«P+¯B‹õO›|h‚¦‡‘cÞ‹³ZÎDŸüGˆ ™ úC£4}$?Ñ-û–yTN6'uÃ'ùˆ _„l¡ÇI± “#46JÅ{"›«'dd–RÁ8Mã­çâ-Gn8xÛ“˜;ób|öñ»¹^T²2gPŒ’:2i;<)ÇÞ•+V# ¤7T=N>U=îj¢‚ªQšqÞ\UÝO1R…íë>¯JÁóüò}´©ü¸k¥ÝVë¨SÕƒäåŸ8HU}v›×q”J¼ŽòTÁz|v´½Žø(ͬuz^gW­cxüµcTºu®Ï~„¼#²)¸Õ‚`Î#Ù3„ó: õdPþîDÑåßl .A‹è)Dùi$ø$þYšCÏaôóTI/ ñ/â ¿„âø2^(^Á À«¸È_ÃÅû:.Ó77qñ¼…jø64¿Íï¢2¼‡jð_óü;ÊÆñjÂÑ•±•‡ž*? ÷8,ÈŠ âY2Ëw›‘Ü ‹ 1¬ú1šïµWÝNE¢q¦R¯£zÌk$·ü­uxí·‘ÓV‹ðÈ_Gµ¹)¼ŽZgè1*í#·×ëªurVV*~Ÿ‚ÅëBÑs‰áñ÷ýûi"oó)£4šTÖTÄ„wL+­† ˜Õ^,?J¾à(•¬tù\Ùø \‡pxrñÞB^Ö­Õ¹x^\zóñX‰A¢ GÏOÓÅ\ªå´PœFKD%­Âo˜GëÅéˆÉÔ%P¯XH q&õ‹EÒçùä8Aìè róÏìÒqš‘;Õ÷Nl¬_˜ËeÅÍǨbkèÆ–U²«ðz⪑n«î¼ÕpÐÚ?Jó¦ô-Œ×Òœo y‹eT(–S±8‹æ‹³i±¨¥z±‚6ˆsh£8—ÚÄ*éÇäGY»ïSÊ^”Ÿ°¬"[«L#ŽŸÜeËvaZQ.*÷MDeÄÜ—›õ¼\uwµÎ­æCaWªÍVK/M}¨ 9Ë8”¢u­ Çs-Íë¨L¬'¿Ø ½B¼$»Ôý²4?ðPK†y´/ "PKé|W/org/rosuda/REngine/Rserve/protocol/jcrypt.classZ |TÅÕŸ™½»{w³IæÞËB6Ù 7!À&@²$°@^ƒTDÅá!˜Ð$XИFJíû¡mmíó+}`[û[µmk[k[[û°­Ú÷ÓGŸ¶_û©íg¾ó?gyhù¾ß—ùgæÌ™sÎÿœ™¹sùÆ ÷ܧ”Zdv'MÊ,Lªˆ)ÆÍ"ü]©¤”–DzH)”Ú#é'¢&ÕdD¢¤"! ‘ÊÉÉÉ©t:Ñ:™¤VT»Ð·;ÒF?I3ß,õ•2+âæ,׬Lª*³ ³Q:Ú«¡}.à<ÀÈÖ¢õü¸ñ#!œ؈ÒT"°‘¥KÊE«‹V­.Z!ã’R! €n! €n! €nhuÑê¢ÕE+d(‘a +(…(ÑÃ)ÉP QR.üºð†Rˆ’J@–€ ¥%2 0 0 0౸ˆ¥%2=ÈP Q2£Br¢Paˆ@)­Z´¢¢PTÐ%€ P(* è€ZQ"°ðë,œû ç>À¹°ˆÀX„á,Âðaø‹X|€E@>À" `°ˆÊX„æ,Bó¡ù²¤:¢$• ÓQƒDÐ`4@„ úô5è‹d2j@_ƒ¾}Q‚LCæÂ› o.¼¹ð–€,Y²d.übFAÅ"P1€T ö ìØC $ K@–€,™‹X\Äâ"±$ K@–€,™²«ÊE `QõUÏ8ˆÙ2E‹@QÝH†€ÌP  <”Ê¢ ` ö(d2ï œûƒ|€A>À `0ˆÊ˜òaöØs`Ï=öØs`Ï=öØs`Ï=öØs`Ï=[ZU”œH_вæpÕÁjá@F*<ˆ&ºÇÃ)222R†JB¥¡R„P)°2ÆOiË ¬ƒ* ÑZ„h-B¨!T ¬Ì z0à1—"C@(B¨!T €*@•ÀÉ.rƒ€Jg—‰2¨„-ôÐÃüs TCY£”@ 2´¨AR-2šàuÈá’1p™øM ü&~“ƒŒJ ÂH bIŒbG%%%†(W#ÙHL*É,–JXþ5d*DkìçÑ«ž†LC¦!£%‘õ,ô0™†LC¦!S.–à:‘y¬4¨RZ#pn(A¦!S!º…ÐË£”G_È4d2 éA=ò(åa2 ™†LCæ8œì´\8X}ÞS‡Ì ŠV¶T¢-„rˆj=ªõ¨ÖC­!Z*DkˆV6k"–ô˜¨Â2€‹ªy´(hTÑ ÀfMʰ P.,»° Py´æÑ Py´æÑŠÒ!’‰ zÊ ”— d¼6BU± ST¡¤X­ÖÁFåpIñƒª “YÆûŒV=(õDzJ J¦OT¤*Ë ëlËP¥lƳ9X@¥d°ªTyF•“dæ}@£ÚШ.#o=j@©Öc¯G‰e(aQè±hµ”!Qæ†$STR7xÖ5CC{öïÓ*µzpp`xÅÞþ‘LówžgɆ°uNÿàö½# Òñ SïëØwpßÀÔ7¯y)3/¹’‰ý{÷nØ=:@IÄÌüŦUíÿ­§êhLÑšSÕ¦ÜT(m*©fè`XéDåjLcþK3™ÿN+ý­âö2êCÙBXCµœÂ!A©hÓ]JßNm²lÂu¢œ*©¶Ó~‚74[ÝYón¯9ªÜO«+nãÐ+‰v½¦Þ°™Nu:ÂÿK%õY”¹Hµ’~ èï’¦šÃZ·Ý­LWödѺ&N¯ÚW«P½íd˜SU”ŠÉÇ5*£¯¥SɘZ¤Ç)lÊ¥’»­Ø‰þœìa£«=59~cŸ”­;ö¢ª}qµªT½ý%þ^©Rú°ªÑ¯RMúµD¿šüÑ"Rò·†¼ÅèoX«9”/F«ÓÑìC5éè¡ÎŒ©îÍ8NMï)«ÕÐ×oT ý&ÚkÞ¬ÒúFU­oRÓõ[É2­L%Ë‹±IÓß*Š´fûêCÙñîêÜ¡jc‡:ªOKžXߢÊô»ÔTý~ZeÄŠ9@Ï€÷·{mx<¹¦)r·rºšâ„ÝÑãÉv'—ûÑŒs·ŠQ¨ÍÝjsWÖ¾à“†Û•+ºsYÇO¼T+g]?yRØásVb6ç—Oäü•Ç&²~ùx|l¢;ëWŒwEŠñHÑM»ÖÑS©Ê´Ûv‹ªÊFDz¶šf@.:–C¡û¨JgÖ@è b!GÐ}ŒN¥­Y»t¼™J•bc±ñ¬ÙÎñ‰æ FIX>f+IZ1f %iŒ¤SƦÇll|"k§ŽÙÅh,F©9Þš+Ùt©'›ôä§lR÷œ­ƒ W¡ž†̰blN:~8®Ó1†tÔ÷Æ'Ìxo:J‘Žùþ8ùIGãÔb³cT.)GIç°«¾ðÔœOŸÌ¹hIPú*ª?HtHyú#Dù­tTÿ(MÏ«6}›êÔŸT«ô§Ô:ÊðÍú˜ПQCú³ê ¾Kݬ?§Þ­«÷éûÔ­ú‹êv}¿ºGY= ¿¦ÖªGõ7ÕOõCêWúÛº¨Ñ×éÇôúqý>ýý1ýSýY}Ÿþ¼þ9ç{N9“ê*7Mq5CkŠV’ïyõ+šË´£–æò32 Õ½55ôЇ@6¥J<í¦qªÄÓq™C5‡2Ñló!–»'Î$Š¥cq,›=@£Y}LN+Õ˜– †¢{‚ÀEÕž¬!T¯:Y´’³R9Šò©žqTOëC½ÔóE W«5ý½a=­*ôï)…ÿ fé?Òâð'µRÿE}^?GO»¼<¾þ¥<¢ri'¯É6Ý­¦t§\:½BjEçpÜ9:ùãM§;¥zLüRÚ)F9 ¦Ó 8é¨3F3ˆÊÝ93NÌxÑAŽÇȲ2†¬ŒEš‹N&†TM;œÀ'ÄÝ’'õÓgR¶¾we,/Q†Óx&Éõfâ¤BxjþŽ+š9úÚ3&U¯Ñô†âÓ»qÖÄèm)®Q¹Ë$TIª¦LMíki㻀¶¼ÍÆS;L ®¤ omrûM½ådÔëiŒßAÖÐÞõ š™wÓÞóS¯6 êqZ¨KKêÓ´ þ&$æmó¶LÅyÒâG©Ñjü¼šý¼ªTÓb ¥Å³QáŽH鯦;ÕÔèUÞtš¦ÔyG'Ÿù¼ªÚägîRÕk›"wªšî&‡°èÌäîTÙ¹ôØôç˜Êåš±†Ðð5Çi–wÛe­ËÄï;¢*34Õ#}ÈòÉ?Ÿ7¤Ý9äðˆª™“va6½tÂ9p£è>ž¡e¹¶Ý͸éhšFz{Â&Èt2“ˆ4g’´È‡™„C¥8JIK>¢Å²H1婉byºÌ–Q"ÅŠH±2]acGTOºÒ9P¬Ì$Ó©¶tùø-*A‚ j-wƨCù»TÙá”æÞsÓeÇT]º²ù&zÂÃÍ—Þ6÷NUŠè›T Dð|"¸^¨êMQ5šÅªÅ,QEÓADwÁÝDpºØ,S—Óßíf…:`V±g«×Qù-æ\"÷<"w­ºÕôªcf:n.P÷› ê³QýÒ\¤ž0›Ô_Í%êYs©zÎÒ:ÇL¿.3Ût•Ù¨kéPß`v0ùÒ1Ç›T]X¶æãŸªÂ 5Œ¦Áó*øMÍçU~RuªŠ—jЄÁ?RÅœùo:èœÿœòŸ¥ÕÍ5­'NYµ“*NžTíhÀŽ'7E"½›úÒoŒ~ãôëÒ¯EÅ¢f¹š$e€ P¨X€ð` ˜ ˜¨dÕ€@Ô¦B@ 0И ˜˜ ÈM€9€¹€y€f@‹CPˆÌ´Æ Ú\‚õ…‚¢…d‘M.¶IÂ%¶Œ°âVìdÅ.VìfÅ¥¬ØÃŠËlŠp¹-'\a+ϲ•„+­%\e=³­OxŽ WÛ)„çÚ4áyv*á;p­­"<ßf{m5á:[CxÍ®·9 ¶–°ÏN'ÜhC máE¶žðb;ƒ†‹ð;“p3ë\Ê:—±Î嬳…u®`~;‹p«M¸Íæ ·ÛFÂÛD¸ÃÎ!Üiçî²ówÛfÂ+m á[ Ükç^e[ má]@¸Ï.$|™-ÛE„#v1á¨]B¸ß¶^m;_n; Ø.ƒ¶›ð»”ðZÐ8¸0xE¤÷EGÎãMã>šÆ}›¢NߦýÆé×¥_‹ŠE ë Mc”’€2@ P¨TFúîP•Ö½WÍØ±='ÒôE}§˜OÃ÷i”\ƒó1Hqƒäz®Bžx.ÈNú²2C–ò1då>†¬ÂÇUú2Ë”xÁ|’ øði&àv&àpð&à³LÀLÀ]LÀÝLÀ瘀{˜€Ï3Ç™€{™€û˜€/0_d¾ÄÜÏ|™ ø ðU&à&àkLÀƒLÀ×™€o0ß$b§eÁCÈÍYð-¢‘ëxÚežåµÈÿ'‚§˜‡ï‚÷®rÿ{ Âó\fâû`„3áÌÙ‡1213?þO8~Ê,üŒYø9³ð fá—̯˜…_3 ¿a~Ë,üŽYx‚Yx’YxŠYxšYø=³ðfáÌŸ˜…?3 ažaþÊ,üYøOfáïÌÂ?˜…ÿbžežcžgþÉ,ü‹Yøofáfa,^ÛhÌÈî@c¶- t„˜ˆŸÆÄ(rv‚X )-âqÄ¥:2 h䀋mÃ&ç„ÀvQ0S©@ãüPh *De SÌÅCà"Ð8IøÆQ"4ÎSý%hœ&¦ljiÆy¢*Ð8PdEu q¤¨ 4ÎÙ@ãP‘ 4NµÆ±bz q®eºÔç‹ú@ã€1#Ð8a4xKÜÌ@ã¤1+ÐØ‚fçˆ| qh 4NMƳΠ4ÎsÃļ@c£l4½%ÐLæåü@cl 46ɶ@c—\hl“ }²hl”‹oq ±=. 4öÇö@cƒìôam¡°VÖ k‹‰5÷4Öh%ˆ"ˆ%Ú,ã¼ü»nç r\!®ƒ‰û×ÉÄ=)Äu qÝBÜR!®GˆÃfÊcåñJãóñXÃö:Ås´°†mvªç$„µ³„µ•ÂÚ*aílaíamµ°v®°vž°¶†êR!m­v¾ÖË9µK8['œ] œ­Î6g}ÂÙFáìBáì"áìbál“p† ¹èÍBÚ¥BÚeBÚåBÚ!í !­_HÛ*¤mÒ¶ iBÚ!m§¶KHÛ-¤]I¤ÙÓV=^ð¢8Ëm{Nì<Þ+év•°† Ùå“vÂÓrëÖ†„µ}ÂÚË„µaam„ÓírI·QI·ýBÜÕ’n/âHºâ®â®âÆ„¸ë„¸q!îBÜ„w½wˆÓ÷¼:/¢„¹W s‡™¹#ÂÜ«„¹„9ìçyÏ੽ˆæ^#̽V˜{0÷zaî ÂÜ…¹7 soæÞ"ÌÝ(ÌÝ$̽U˜{›0÷vaîfaîÂÜ;…¹[„¹w sïæÞ#̽̾J>râÄhÚôãQæ ŒDv|—vÈ6ìüÉ@â°÷§¼Ðqâ>,Äaß/ }Tˆ»UˆÃ` ¿ãoÞ>.¼á$På…¡ðö áí“ÂÎY/¬Þ>-¼Ý.¼cÞÜÒ2y‡ðöá ç„Ï5BÜBÜ]BÜÝL\^IÊ}Nˆ»GˆÃÙa®—7BÜq!î^!§ˆ‚œ÷‰¸/q_âpžXà¹õBÜýBÜ—…8œ,{ùPˆûª÷€Çg /_/Ä=(Ä}]ˆûFï†;ðŸ”N{ó ô7Á -ƒÑ@?ÄâÈèo3‰Kò}GXÄ~U&¸#Xü®°ø=I¿ï ‹8¬Èt¶¼Ð‡‡?(É÷-!ñ»Bâ÷„ÄHò¡CFr©Z:‰?bY˜Ÿµ"<íJAÌÖ‹¡FƒD=“£™%®f‹F^ 4ŠÕ&q5Gžy®<ó<‰¦Y„-pAüÌ—­"l“ È@,GE‰a¢[Ì,‘övÑîà:ÅK—ÄÓ-ñ,E'_•ýhé>‡“ˆz ë%-P®¼Åø $.)v*ïp®KâŒRÆíD×…®ŸHÒáôWgº°Dxü^âK¿@¬[8 ¦ùuGn{ÄJ+g¤¹ZLÖðY)˺96Y+ñMç'°¡t­íÒk“Xh™¢1‹ É=[k;MltŽD8W"œÇ Íb¦…£*ˆƒù¢Ð 3mlqA\èyTè9"é…aX,6—°ƒvñÖÁv²É®¸dÖcBΑS¯P¦c²èŸãÒÃìü‚3ê—8<Þ, õ ¡çW’P89'pÌD>ýFòé·BÐï„ '„ ßJFáœ"÷pláPÀzBò }§²ÙiÒéI!é×BÒS’Np™•hävŽÃœ.í¡¯cãõà ¶Ú žfJ³ÄÎly8¹®“®MbzŽxŸ+êóØG³DÙ"f âq¾DÛÊm¢±€=.”È‹âc‘Ø],Â%I¥'%•žTú™¤Ìvó,E˜'_·ý4“Eï"Ñ(sõ‡Òí(¿"QýÂÔŸ„©?K"aoKò«T™çaêýÂÞm*ød_É 6Цð.ãËUD¢ž¢þÈDÁá4i¯«r}*ÎkÄy–cŪ«µ/½{=$DAV'}ëY6CâjW3¥ó,xŸí—V=8—{Uñ=GüÉݪ˜lß-¢Pàçš/®[å‰ÛØÛ‘-Œ G¿ŽžŽ`t‰ÄÑξ;Äw§ÄÛÅV»%Þ¥pxòM G`ÇëQ'ߊýWΨ¿ñ…7˜·¬t¬Ç›¡ËÊ6ÁoÁI94—yË”õ!êo’Rx{”‹mQðøÀí{=èÈûöq’''V=X­b1ZÍqÙ雕Xr2-|liº8 åOô«—3¤Cƒ?“-Ï7³%€<ÇÖ(6‰7¹—Èæq{³xl«ñ1_„²öIÏ2 %–¢¸H¼/KD¥]ÜwˆJ'GÖ%.»%襈óäK.PœËù{®㨕.Oc|_ç[KW.R|™ä‹É2~™NñÕj9,Q:us:áÊr7Mø|Í)_ Ätšß ¦ò¥æ4n­b˶PÍ–kÄe–Usì²–MOg—¡4×±n=‹fps[ɯòY‚ó¬Ø(þ›ØçŽq.kÎcÿÍ즅]X2Ÿ%­¬ÙÆO³€Ÿu!GZdrRËK¸µ5;8’NÖì’p»ÙôRrꥊß÷OMð9áYΛç8ožVsÞX¼ºÈ @ãÊ„–7Ü™$=…·Ú‰pw’r$i^¤¨R¬¨{r»à‹Ù€}”¾ ±oìp93MÒN„k˜Œg¯—Äá8ÉŠ(' µ>ÒæŸÌ ·ÕIõ¢2CâhfJ‡YÒa¶¨ä%ÆFéÞ$!”‡ÕçIpÍ Eâ- y¾tlQ›t\ ŠÃ¢<ê"q¸Xžd µËXtˆB§¸è…ny„¥P9õ2à¬ç¸%¸åouî@ÝÀðÁ.0rïdøÞ‰ßŒ|ó™ Ÿì¸-s†o“`Æ ®Ÿ*¥³ n¡Dv&wËÇÞÆ4qBOâ¦HSÝŸlŠe};òPK`‚3Çï·PKé|W4org/rosuda/REngine/Rserve/protocol/REXPFactory.class; xUÕÑ3çÞwï}K’—„¼,,@Ø|h€@A!¡IX"y$Ï ïż6E¢¦.­·ªÁ ©K£ˆ·€‚¨­÷ÝVE[íFkµÕÚEÈ?sî}É &øÿ¾Ü{gÎÌ™33çœ93'ðâ©'Àt|Çü…_Õáüþ¦Ã§°Áß°>Óáï"þƒ9>ç–/àƒêð¥ÿÒáß:üG‡ÿêð•_ëp\‡oìpN& :P â@m,‚ä¨ñK'ñh0Áî &§.$bœñð`‚nœÀDæHr€“ b Ç |aàPÒ‡8œÔA¯)(ÅTÓOwÀd¡ãH Á3X]63ù5ŠûŽæ×Äa‰Ä,Ç’y8Ž›³ù•£c®й_1æ8ÞÀ Ü{"óuœ¤ãd§è8Õe,&ž_>œfdzÐÇ M×ñlÏq@°˜l~Íp@2Î4p»¡PÇÙ8ç8 $rX17Ï呿±ˆ†æóë\–}¿J™°@žžÏÙ= ¹G³,b´œ¡ vêbF¿ÇÔJ« ¬6p‰K \fàrk <ßÀ^`àJW¸ÚÀZý®1°ÎÀz^h`ƒk l4ð"ר”‹u "èË«W—/)+CÀR„¸¹¡`8âF–ú›Z -.@Ј¥´¼š1D°6¯bIqY 7“\U]ɘbÊ++*?—QÕ"Ö,bÌf‹+*ÊÕlLœÆˆnÊ]Z2·ºBJr[’J«ä¸‰&:·¬¢ŠÑ$‡)¸¼h‘Ô#™t·øW—WTÉñ‡ 8£V“Çâ# ûø†Z|Üh5 3ùL…V—,_Ì)ý-›S\ÔXTYYTuSBBo[Ÿ³2cY­î£ܽmì›ÕKЏ}´9V_;7Ž1ZY´Œ±¬X–¹‹Ë–sãXÓ5KÊ–W,+ç–I¦oçE}»Í4÷¼¢ªÕEÕ¦mjdss€>þH¤aRY¨¥!¿%n­÷çW–ƒüÊp eC ¿¹% Õ…š¨}ùâùþºH¨eó êY F¼ö$Nb1ZB¡HYc˜ØRdcñé wAHÍÎ9ƒK‚ë‚¡AóˆÒ&?¹àwìÓÇðqv3´÷»ð |’—Ë$| ¹ði|ÆÓÅg™ïøK>‡¿ráa<âÂç‘Béïátr™9—B ­/ÊJËÏ¥ÖÊ’"jUù¼§sé,3©Ù˜Ì_¦Óט[±hqYÉò\Q³¨˜;éVRDÝ9Ÿá¥?ÄÀŸ¼(/¢çEnQ9¿"¥(¿@53ס¡L%V¬¤6@0S ÓÊ6 |±ßú¨XsM,Bö ®^d­³˜‰+æñ«˜_tx%¯èÄê×jB­¶Õfê¢ùÃfŠ‘6ÈÑM2Ã|0ÖËÓ÷üþ {s8XO„@ ô”EábR€Ïá€ý ¾„/ÓÎÌÍÍ͈9®2úÖñZh‰G2(m¶Þ¿.@Ùu?²¬1²6šg‡&œ!ÁÐú´!kšk ò9?@"°tY8ýÜ­ö7­#RºA© ØAu“Nd±œj•…8 ˜é΂~žŒž„î¦ç.‘pu(Ú¤f/ȡɕ½bÞwBLÅßÉd—ѽ.ÔLùAnö·—HéM¥Ü‘Í-åÜ•†)ýÎa„?"'íÛN>SæëG£åì§U \Üêo Ÿ6–ž¼>íQ’'gÀq0á;m2ÃÑœƒAKSÅ_Ï»£¹• >{­Ðs Y0ð"’ƒ§f*ŸH¤U8YØ\Dš Í(ÓåTœÔ-i ¬ðTèEÓÒhê§GBE¼b¾åÎ^ÍÇ[Bä :7ÔÔDͦf àb–í„iYƒï¾J A“•jÊÓ‚á -s×r!A–$ 4Ñ^Þkƒøajöÿg ( È·Š„^Odf÷ÆHl ®õë›õ\KpØÓýáâÍ‘@˜·{‡uʬ̒Çá[y´E,•KÜŒVÓ<â¥gÚW¶uæ¢0¸t2:ÐÖ”C“;Ï«§‰7²KKee&GìÍæ™.Àž-ÉK嶆+:$Hd3™­Q ^f…4ÖuÇ== …zöK‚sf«™PdðUÑ+œs¿Mk¤†Á ¡uKQó€°ŽßâÃ9Z×ÚŒà*¥EÒ2—“T¶òöX+-fzžœƒð³ãŒ– «iÒ``gä|[Ä\SSUc$0CG*³þWºQvf>È~À*à…Âu€ð#¾t‚ë ߃ß@ø1øM„߃ßBøcð[ ¿-¿ðŽ|áwÄà?!üÎ|'á»bðNƒßEøÝ1ø=„߃ÿŒð®ü>ÂïÁwþ@ ¾‡ðcðŸþP ¾—ð‡cðG4ŒðÇcðnÂ÷Åàû "’ð1øAŸŠÁþt þ áÏÆà¿€øe þ½©‚çûD¾Jßçáù¥š…Þv⥼œÞ¯–N_ä;ÃÜÇ÷Ê[È×øÎP6ÖЛêS‹u†Å:”XÅб ⤎π²Wß×÷|x“¯A8KuP¨é-xÛ”Ù;æ>PîÓAý.VJöw'vì¡•¾‚ÙóŽ€óØjöÑ~Íë}QnÞã€ãCBî0jÆïûã òž[8s•ÇÁÑ/ªtÀÙÄï,ÏÐ ®0Üž.°¹‡Qã:`X.Ùâp{:‰4ŒICeßíDïW®Û-ñm„'H\—xˆp·Ä3$¾šðD‰gJ¼‚ð$‰’øl“%ž,ñ|‡H¬§¤m¢íÖLÛåbZö-´lôü"´|Zil ÿo„`ü 6ç4â¿a+3Ûä¼®ƒ¤Xè`è°àxi–ã{`8¨f¡:ø ë¡éìßÊýpùà¤ã D‚õã„_ó 71þ†žwá=sYÄWR)`ܘ—F›ª0/mj"´]ÖºÚªâS©Á=§·1>û2Ÿæ¡•¡µ •~ÓÒk}z®G#OËÕ³Rhñä"­(Úa®î¼´nHåÑvÀ\^x¹Ý¶Ò‰%mG³uB!?bº¡Ôk”¡Æ~YYàhFšGßñ4}I4u}uO¬ñ:L™–wf',ñèiõn£Ég(>»Ç8¨8¨3E6¯Ãc—ÒY(‰l·cWϱ>Á£Î$Xë„Jõ Q£áÕ†×P¦v@"Ô]`§¯»­šzzj¼†Ùs4õl(Å%•´Ú]àäaƘÃH©£;a%«ÕÕ(pä¥y ·í‡,bS|NÓë8td’þN4Y~iT4l»“ìøÐÜÑ7¸`L'\À6õ4Crò×®xȵYŠÏáqxíR¸ÝãÂù+…ÀÂ,Üt É·÷—¯vÂtõ ƒ½BcTÄåîuÁ8éµÏÃÙ1¦gtB7›©÷N”Ú¨¡Ñ‰[Á ‹gé“>9Ö,ñ²âaÃbþtCnE¤ñÎ(61—×yò½®ÃëuvÃĤün˜Ôé¤çdò–×Õ SLe§’<÷6ŸFÁŠdP>"—¨»×§ã¢>Íê„©ƒûÔtÕ^Wí6d)®¹=» ‘>CÉÅôÖ /Z{¥Àˆöà#`ºå,pzèÎaVÏ<¯ÝlõÚIßn8{Ä[à9´ß,p"õv¡µêð²¡`Y¸ sZøŒe]=¹ýtJ>q½†Ï$ö ôâ³Ø¢Þù(Œ™ÓDÚ Mï„#ŠÏ Φas-c‡Ùª/ÖDpDm`ön˜ãcß϶T/X–k¥ ¼Ë\QyF¦­l¶ žÝA“Fýy˘ÆwC‘Çè€il_b'xØæ°Lé‚$6µ¯e&/+Z[³¥AnÓ#)˜sŠIṆÔ%³×Þ90,¥çuõü®Ï=%Ör•+uOtmΧµyîŒE ìÈΈN­Ë:°Š:·ƒl§¯“g²ΣUí:ô”8_œ'Ž3º䉛ò , »«Úãhßü‰Oš9öÁBZÕҞܲ¯Ó´w‘œÜø^¼œìï‚s,Öf5e샊ÞøÇiÍåÑu>ªöÓô§Ñž¶³«’óõRw±.5¥K›)²î€zâž*:a }ÕZjp‘aVuPZ#)i{½Zÿ,Þß#¢7†È¤^‚‹|F¤¤ª*‰]0‚“kNgÙË$5©ÀΪ/'ÕÍ“ÚÜÊ Ð—¢ÁG bëjÈxS@tç'Q¢…'uB±ž_#ƒ¤©ÊŠ^ŠÈž`þDIÑñIö$¥­œ¤¥íEìQ@Q`šÖ¦½¢½•úÝúgúç0ÍÌÞ”Ýð ¥4WQ¦|5ev×À8¸ò©ìšNyY%ò³©äZB¥V=•ZTbm¢k åkmTN]MåÔ-TFÝFeÔT>ÝKåÓ}=A¥Ò*~AåÑ«T½MeÑûT#ŽO¨ úœ¸þC¥Ï)ØMYÜL‚q<„©°ÇÂÃ8Á2x+à1\ãJèÆìõð^ðb8ˆ[à)lƒCx<ÛáÜÏâ ð | žÃ7áWøÆàþžÇOááÅpxIäÀË"^“á5Q¯‹ xCT›b9¼%jámQ¿xW4Á{b#¼/¶ÂQq%| ~Šà·âVøHü>÷ÀïEüQìcâQø‹xþ*^ƒOÄŸáSq>S¾ ¯®ØàŸJ:|©Œ„+cá?Êø¯2 ¾R|ðµ2Ž+sá¥N(Ká”Ò‚ \‚¨´£P~„Šr3ªÊ­hSv¢¦ìA]y åmt(ÇЩü ]Ê1NÕ0^Š êXt«ã1Q†Iêt¢žƒCÕù8L-Åáêbôª+0E]E{¸ÓÕf¡n‘ê嘡^£Ôãhõ£ÞcÕgqœú&樿Á\õw˜§~ãm N°8ÉæÀ)¶á8Õ–‰Ólãð,Û$ôÙÎÆé¶b<ÛV‚çØb­ gØ–b¡­ gÛ¶àÛV,²mÇbÛm8×¶çÙîÅÛƒ8ßö*žg;Š¥¶?àÛ—¸PS°LÓp‘åZVh3q±Vˆ•Z Vi q‰¶—j¸L âr-‚5Ú<_kà ´kp¥v#®Òv`­¶×h¯`@{ë´7±^{/Ô>ÀíclÔŽa“ö®×ŽcHGlÖx±îÆÝ‹a=#úDlÕ'ã}:nÔgã&½·èex‰Þ„—ê[q«¾ ·é×a›¾/×ïÆ+õû±]¯Ò?ÃèŸãÕú?ñý8^«÷à ×*^o8p»‘Œ7©x£1o2&ãÍÆT¼Õ(À»ŒYx·1fÌÇ.ã|¼ÏX‰÷«qq!>h´âÏMø±1¶á£Æø˜±ö7U;x êOÀœƒ' žÞ'! ž“0ª—÷¿†¤S0©Öy?Õý$€±:Íǹx.YàEë‡A€‘ÇÁö÷-ý<'`ºP¿S0Œ9?îþ–ë0 ‡}èK=)RýúNÀJÓíIÇÁ%Ê©­BVT.pÆØË­Ö’IëÉ?kL"ºWÉžñ§©jQ£u®ÖŒX€¸ŒvŸ„³e÷á)È Átø-~é=0¦¿Lâ5ÙúŠC×8¬‘¿›©a2ØOã²°³O‚ qè H¤ÞYi’Siè69! Ä:–”¤¡>Ä4j"Lž˜Â¾?êDçÈ”~•æïà#³ÒTP›“*ïW”™|G0K^Pæè1o vQµÎÀN•+ÏYÊà=Ôï²ÁìIG6å³”B>M TÚ¿^õ0•/*%VÛS6e£Är'ØÔÂtÊ­R¹í†Uµ3Óvó @!˜?céá†éy”žß˜´èôX| +ÍGòÿ¦m?cAÿëÅ_[ø4’ó}Gwá-í¨váõíhtá5©ºéÕ‡jkg¦j—íÄÖTúÔëµ3»ð¢T³|áR=!7šªÔªQÖ}¬³SMºÿ¾–ñ| _sÈmȆ§7Ä¥FGÖ-yp¼WüÚ§MñéÝ«‘ãï‚Z¯æÑ»¡®ÀHõ¤—NzqrÁ٣ݜ ¾)ššê³›œõTò£šêu˜FP¡£?8£ãµë” ýD¶mèÓa©Ã”^(ýšÏr§†)òKP78¯9´†p O §ÖŽHꪉF™@/nã_g¿'¾o%5éÂ{˜EMÕk÷ÐÜEÄb'TZwJ¿¥üð m‹§@ÇC0 Ÿ†"|áóPAçü|–ÓY_/C_ø*\ޝáx|óñ-< ߯øÖà»Æ÷H£x ~€÷â‡Ø¿%êŸ :†á_ðü+~‰Ÿ'þM$â§b~&Òñï"ÿ!¦â碿óð_â\ü·XŽÇ…¿õxB4áIÁq¹qµ@q“âv¡’ºØ)l¢“¾w CüLØÅýÂ!.ñŒp‹D’¼·ú²N’a˜Z„à<CѼuŠûv ›-}!l'hõ£7RˆI nwúIŽ«>bH“A¨—ù eßI‚i2.ŸN£§TvÕ'S÷¯!Ažn©Å‡tüL (h뛣ûº}ˆW+Ua·Ñ/¤}½<Ó–Ñpñ”‰þ˜bЪÂt^Ñ{3Åg“IÃZŠ˜4LºW?LU«.“¦úøÂØ!k¡hPÓÝ£d =Hl}æØè3¨b°u€=ÚX‘¶t¾‚3Ü´¨U½žó†ei1Mµ³˜»÷Šní,±[FEñœ³è¹žèy’Ú÷™´èôX|Àg–õæÊó8™äT Þ‰(ÔÙ%¯ãÆçɾ$Â5ÕÝFóe“·*„í]!Ÿª7V·»(p¼éqj—uàF“_«îêùŠ©§©³ÄRg2+έow]=ìÕˆÕaÛi£ðEá¡ýÕ…iш×OÔ±< z%òk½8o½qÞ8ôœ4))ª 'h|ƒÅßZŸ âÈ$~õ²™_żr¼ÃãJ«çëI2n7IªIú{šÏ= œ|·ÙtœSžxŸ¤ÌpY€(ˆ“gB y\'¯¥âÙ0o» ¾“Ê`²¬@eïz*@cX¥«;Iß<Ë÷Cp™Çž.Có­âuñV44SVJ (l" ’D:xÄH#a„È€\‘ bÌ£a±ëDüPŒƒE6 ÒëE‘‹17Љx•ÈÇÛÅü)Ù.1 gá/Å |YÌÄ×Ä,|WâQ1?s((‰1GxD±'ΓD©ð‰¢P,KÄ÷Ä*Q)E"Õb£X.ÚD¸Jœ/®+Hû•†WQ^-µâ á¿kÄ+¢žìjo‰€x‡¾ï’„ÄEâ/bø»X/þ%‚Š]lV\b‹â—()âR%]lUƉ˔Ib›R(Ú” q¹²R\¡lW*[E»Ò&¾¯\)®SnÛe²~)äSºGizxc³U+šCÂIð ¦Ð €eÄà8‡òZaóAI÷RùÞ™dR2¿ˆO<ñ”Ú#%È©2[>Ê"S!îÛ$Ê)îQ©ÏwqÀàŠüýk0ÇŸÇ‘)Ṟ™BÉ|  (ƒXÌsE£ŒzÈ)HF¦œ`ýŒHûš'áŠ9nìüï﬿øí&©6ú䤪E©…ã­Ý­zU%7Ý«ò6æOm!¨|£­æ¦·+´qÓy¯ÆYHWÏ—é´;HöXÈéM\&ÊìüfÐÅ-`·Ò¹ÒEŒ;`¬¸rÄG‰Î± Š)†p"0lTÎdòŸŽòk‡ZÉþ#üÉÔ¯£ø/•Ÿ¤ì ½C{STJ»’š÷¦hü½xoŠ¿-{Sܲ!L@F1ÐJ@&ÃÀFÆ2°ioŠÁßÍÔÌÀ–½):/¡†D.%ÀÃÀV†0pÃØFÀPÚHbàr²¸‚)çJÜ ´ÀEGÒ÷ Haà*¶1p5“¸foÊ“p-@ߟqƒ´"At‘Wïƒq? »a¤x²Å˜,¤˜ósŠ9A™Ø KÄðR<ŠG!(ƒâqh£’åZ:4oûáñÜ#ž¤˜tºÅAxZ<Ï‹Cð†xÞÏÀijrVÒ¨º¥Cþè†X? ÀŸ¥vÇðuùçbÄW)õ|¶ù)þ?(Dïáÿ7#ßEò½þPK !šEi¹5PKé|W1org/rosuda/REngine/Rserve/RFileOutputStream.class•TmSU~nv“ a)$Pjl´B 4}±/¼m"HlB0`+\’[Ø&ìÆÝ µÿÄ:~t¦Ÿ±Ô©Ní§:ãoñƒ?Ài<÷&H!Ô¡™Ü—sî½gŸsžçÞ?_?à:J! Ñ…~$5L„ `2„\Р⢘^ŠÐÆ«!pMl»¢îFS šÍ¿ÅiÑÍh˜ãÇæ4Ì3ø!‘³Í”c»Š‘*.X›¦ÅSE—;;@-Š÷iå4Í^ÒS©Ò8Ÿx–H>…/ñ3|}á‰]¨Ë“¯šÜ…ÿ{ ýŠÀúäF´'ÐÉ|Ž.àB¿'”§èþI~ê õÃШOPÐ$í˜ “âÇR˜ÃE Ñêm¨Mrªú5(†5²Ð„~Èå b„þM-(­²Ä(  â›ÚYœkç5A>…F]ý-˜OL(ê.t’I'äÚ4í™A7fÅø cŒ|¢~]‰¤’|q @H.¤ XæÐáÑöá¿È•àTÏîÇèŒôˆ‚ ý¿279ñ#4õ Tåšú½Ó~Yú¨?yfh}ÓhຣÉÀˆ ´)èÞ}öËŽ ‰‡‘#¾óg™ˆ(Pž+X¢·¢‚¢¤ `Øßu“½ÆÓÖD•{ É*‡kûô /5éCkJk­ƒ„1œo×à1•YÔiJ&a/ÞE$—$Y%÷e•Ü“Uò€¬Ô²„Ÿú/‰¹uRï=\A 7ð•Ìå2Ô•)èðI˜y”þB;{.¥åêü!fpTLmŸé€t|M™Ä%˜qÜ‘ü3¬œ/èÈe²ƒd_¡öÑ¿PKù·ÎwÐPKé|W0org/rosuda/REngine/Rserve/RFileInputStream.class•T]SW~Nv“ Ë"Hl>Ähñ °"‰ Ñ6¡ZÍKrÄ•°›în˜zÓ‹NDé¥7ÞpÓÅÛ±½©Îô§ô70Mß³‹ÌlΞóî9ïyžç}Îùç¿W¯\Ä}½H¶¡)iN©ˆcTÁé02¢{&BÏ©ἘvA4Uj.…1.LˆY“ .‹Á× ®(˜bØ.Cª`ÙËÛrU=Sœ1— “gŠ·×x¦n[®U±j™â¢^[™dUj–ë ì>ƒÄ­‡ºl˜†{…a*qðL…Çúšž©éær¦äÚ†¹<™¼Ã ç¬*gè,ÐÂùÆê·õ¥E:J®^Y™ÓëÞXÁUÓ êÌ^w Ëth­ÍuÂ%%’y%QÎæó¢ô{qÚ@-Y »Âg ‘4Zï¼Yo¸„ë«§( GpRC} ‰ƒòÑENÃ5Ì0ôxÔ +“_xáhÎ2M^ƒ¸kÅý,ñ‡:!¨j˜Å †®¬e¹Žkëõ9î>²ªNg×ø¡!›Ö- ‡Ñ¯!&šã¦%‚AÜpâ¦åÆ­:7‚†9ÌSuËY1\ œÇ^ vâßíÚ[°Ofm©s›êÆÉeŠÍ¿op‡zÓ‰ü>Õ?uüddCÙpV¼¢’ •eN0uWÅm|ÃÐWôwŠÛÜmØf¼Bžšˆ3†Ã«ú §2Tt÷®á>¢žãê¦KÞ‰&òÉ1‰øþ>=“ s}b’v$þr"YÎ2œMäËÙÏJ¢ (¬@û·P暵·ÁùäfõŠkÙO|G‡³`Y+:ƒ–'ûÙ¹šî8œÿ²“Ùvßu7t³Zãΰ¿pŸƒú±…‹Oê|Ÿéå¡…¥Çt&“¦ÈéµZÉp9‘¼Ç0r l ƒŸž‡/è쥛Q¢?hˆ ïóÞ2ýà(8F½¿i¦ˆ\K½K¥_ zŽ@WשMÈó£o Žn"ø+~GèÞè[„#Ê3h ¿BðêŸ)éÚE£ýFy v µÃ”y„¦$D_b Œ#‰Rô¸¹IAYAIÁB÷5šÐö„a ÑÓDxÏÉÿ@#‰h bT|úljmr9Š„òáB*-É›èŸ"ØHKcïÑòÔ£ÉçÐóº0غïN=ì§fQŠ Ž?‘\íëèúDyz<‡¶.öð„ìØDç„“ß =&{Z‰¹1y[Ìm©)F]ÁXð-Ô”L¢6¤ ¡h(|ý½écÑЃX0[ü9Äž5ÿ¥p‹ÇW¤0E˜¯R…§I÷,±Êané;˜A™.ݸŽ%:R7ñ#Õ@pÍ£­;¼…~µ‰=•»ÛVŒž&áÛ—ü¸  o!Àúw‰5Bü:¬“À¢ãž$öº7)¤É^é–½Òïì•Þe/¡½å¬>©-RÍJäçEâ÷-.»A¿¼…˜ÇBCÀCëˆÑ#ìó.$ù¡=Ƒȣb—eTŠ•p—vˆá¬ïÊÏ0ö?PKÉuõ”‚£PKé|W/org/rosuda/REngine/Rserve/RserveException.class¥VùsEþz²“°˜ÂÍ sÁ ( 4 „Ž$‚×d·“ Ù^æàúK¬Ò’ÒÒµ†H™ò*-ñ,-ýÍ¿Å*ã׳›d#ní×ÓÓóÞû^¿£g~ükú »q­ÑYÇaŸýxÞÀ º tè1pÐÀ!½è3Ðoàˆ£ 8fÒÌPžÄ°62bBà´3&xQ¯œÓÏÎëÙp-và%}ûrvá•$^Mâ5*éyæÀû’ÎÙîxz8ðw¼S`‰'/É ôÜ••¢_`õ¸ †äÅPúÁ!ÏSÞAég<§8Êhli­d§º¨^?à¸òX˜•Þˆ=šãÊò–þŠ K†;39hJru$”¾oË$lš}Žëöµ (o<í)?ÌÚé¡Cî8)ÒC¾ô.ñÒ£\Wf´k³´ž8ùøêe+#žº¬¥Í$F“Èì|ËýÚ³‰ÿáÙ?+<¨ŒÊ¥‡N0¾2ˆÎ2oóI-ÏwUK+3^7¬B/#{‰Æ¢¥CW22Îù6MŸÂflIá)´ ®²¤. –ÊU°=Êïµ·3*_ÈÉ€†VÌ?ô¯º}eV«Ñƒ å9×lmß³ÉK—eæölzjR²Üê÷’s²ÍæmWKͮж' 6õ§[Ô &¤oOV”Ùt|ËU¥ Úð&;“a¹YYé:2kµäTÆÎY*Ónh]?,”È2êCwÒU—Ýù•æ¬Ø–¢ÒXN]î(†™²âõ@)kÔè–t=,îÚcÆÂ\‡5ÊÈyqVH£F/ÐaímI/öʳ]_û!°³·k¤k`¯UL“Å–¢¾³ò2¯¼«V&§|M>¿wú쓬…ÑпÊΜ]ÉJ¶âÄ\ÒT <•³ NAjî¼í3Ê++Ž h™MÏ&ii·RO ƒ’‰Íúõ5ÆRG{ [Ñ¢+§ÅÀ„^q`à‚žN¦Æ3zÈ¥G³ž¹)(ìh}DsÜ_ Lf%ÙâµLjéƒ}$°yAÈ:¨p´-¼ ëPÀEžzÅ"Ͱ÷öZ‚…›·'%‰2vpÆ &8óÛ |2v°"âvµ¸„~,¿¥¥Â)WéxMJï© ½@ýÞʇSñºð³R 6g—^#Ûÿ£Q­Ÿä¹ÅWE„§+æ{m^ŽG+°$^ c¯ ØI\á;d@©É° êg*½ºÂšx½<.%ÅÊíc7ç¤ß\T|ô>ïS¹Z¨´ƒóeKÇã¾¾/Ü%=v.7ì²3 öåæù&°þÑrüØÈ/ð3¡›ÐÌYµ>Ä¡»Oè~äØÊ»”`K¢¶­í6Ä]$"Þ°¸9ÖÄšbñö¢¸8Çk‚«¬¹ ýû0Qü½ÓoUÄÛDñ.ÑMÜ zˆˆƒÄGD/¡Ÿ}Ä]¢Ÿø”8B|F%¾$ˆ¯‰Aâ[âñ q‚øž8IüdVEfud.ŠÌšÈLF¦™µ‘Y™‹#3™K"ó‰È¬Ì¥‘¹,2ÍÈlˆÌÆhÍ4–IÄÛB#Ç5xkqëðÖã=lÀû°p“qû˜ñ½ÅØÞft§ÛiF÷s†ê+Æöë­üÀÀýŒüÊcðwoq@þÄ›‰‡~ŒìÖ¹´Œ0‚:úVÛVèÌ$®£¾í.š¦±RGr‘¹j«ËÝ-fkgL±‰³Il›á’Hêó†Þ¦ñt‰¡™¡³d´µw$¦°æÖ\Þëâ,îF{bí%³Ô¨æu5¶Nam[âDû=,n§cëî`ý­9gÌX°“&ö!…ýôù@ìØrˆÞTÓ©$vÄ^íŒyù"(±œ¢WZy%Y¦°¡mÝ¿tqçÝXÌÊjbUi’MÒTF"JÏ–(&JiÐùÉÄ $·Þ…UŠB¢, ‡ÉÒ[Ý‰Ä iªkfß…ªÒ|F»\¶>;gôÆ=%Öu:¼.Òéüð.;JÏÅÜ{Æì>.#À*ç}#ŸŸàÚÉx<gÿPKafˆf PKé|W(org/rosuda/REngine/Rserve/RSession.class•TÝrÓF=ë8‘­È‰I(?ý .e;¢%4m~šPQÀ™a¸Rœ£ÄH®$gH¯ú}†öZf00…;.x¥Î@ÏÊ ãq=ãÝo÷Ûï;笎ôêõßÏ,à–Žƒø*‹i|Å$Ϊ謊æU4¯ÃÂ9 ßd° #ƒou|‡ïUfQ K:Îゆ‹: .©ªÔe +.kXÈG2ôÜÖ¦ #/ðo9—ÄUÜJàG±ëÇ›n«#G?3óÛ?k;eôÝ Š¦ª;îžk·\¿i×ãÐó›‹Ìµƒ9áŒìÊ}ÔeÃc·q÷†Û̖ؕ«AØ´Ã êl»vmÕoz¾´kd±'ívÄA#hÙµÞiö£p¯ÏN`lÉó½øû›ÅM®ÛR`²Êë{[2Üp·ZÜÙ4 Ô¨Í—˜ÿ…˜«SËî5·iXÓPÐWï7d[5ŒÈ±§W h‡dÁõ 6äš§Øçju)Ásê’ œÄ¬/qÜÀgøÜÀ ̸‚‰0 }2½å%Prü=·åmBµITâ õp ÛRQfê玌â9éh¸jà'T |¡¡ ášu\˜J—jsÃÀMÔ Ô±!p|@Y_2ùÎY×·vØIà`²åv=1«÷Kï)[Ã?<­)cRc”6‹Ê—KC{ä#«+'˜Ã€o¸­]:‚ÐŽB3ï,;Eç=õý(–÷²nºû Í÷Æ2«^¢ó[Ž"rz Žþµ&”Sêí´†²¼"N[j}Gئ3Èͽ,ôë4¿\Ÿ` Ÿâ3>ÂOZ G9ÒÈP?Z+™é.Ž¿*—'ëÉþÒÊü¬<Å•ÅZÁY·CX¢‹Ô®x'xDL#,1Á:“çUÝŸå>P[g•b¤‹´šG»+?‚¶^y ½ò<_þO‘¹]šÊ>†þªhO0Þ…aå Ï2]ä*yÃzˆÜH¾ðAŠÀÆ9î8‚”y”Âg(µH±ó”zž«UJ­Ql‘§!õ†AZô†I –†å¡Ì\šÂ2üWع'cS ã)&oSJ¾ªèH=Â%•þúà.N’Æ,oâÔ{íì„ð™PKªJc³O_PKé|W)org/rosuda/REngine/Rserve/StreamHog.classUßSZGþ‹×5 šhIÔ‘JšŸ­F“J4’‚Z I5m“ ¬x#ÞËÜ»8ñ©3íCû'4“? }l:gÌLóп¨}hÚ³\¢8!2ÃÙÝsö|û»÷7¯\džŠ!Ä»1ˆI)*‰älJARÁE >VáÇ%).pEÅ\•âš×ø¤Ÿb:Hps*nâV s æU ¥à¶‚á0„3õ=iXÉ´Y«‹¼°¹¾=à”ôš¨Ûœ­3ô¦#ôjuU› A×§ª›•$9f…ü7 Ós ‘XGÈõ‰{ Þ”U&ȾŒaòåúv‘Û½X%Mo…‹tû±‰N§tÙu“dL‚È ½´•ÕkM ‹ jÞªÛ%¾hHÌ~²Û"çp{‡OI, #×p  à´†;ryà ƒo)Ï×76¸ÍË9®—¹MÑtˆÅµI´%)Òîb”’Ô€†Ï‘ÑŲ†iôçî<̯+XÕðrÄnÞ²„#l½–åbÓ*;}~ä(hø÷Ü×ðÖ ä‡)¬,<)ñš0,SÃŒ3ŒZv%i[N½¬'s f…ÒštNºT—¬ u”ÈÂ&iËÇTnn|ŽLéÎõ“™Ü4µ )+J]c˜eþdeƒú*önù&Ò ÝN½è´N ÇÒ‹ì¥ÉöqŽ»Žà¤ê²ê¢½gWÉã-A_㆑¶ªOGsѶ¢Dg£Œah[ßâ)Ë,éâ¾!6iFLAwá|'Ά:œOÁ×äªj¾'xÊTø8·æ8G”új.µsÁÖKÔËßÊ6(2Œá掵Å[p.ÿE½$,{WUÔŸ±¬­zAK›&·SUÝq8õs;—†ÛqKºY®rgÌuœy—òû »5Þaûƒ6ÕJñ1/‰cÙkA¤¨yCðÔ0ãÿ‹Uõ¿÷!JÏã=w]ô§û ù£+Þé‚·,#øÂ(ÍfàijBñ}°øä<ñ3{èŠ7à}Aj†³$á#9/Âïo/$x†sm ÓÈhôŇï×CWSyšäÆÝ­ì$ÁùIûÓKø×^BY#Ï>ûèΰìdêZö5ʤízŠåD°§mnøn%†û{5p¢ÞioÄì#Ã5_Ø÷ Áˆ7ìë÷ãï|¿¡?â=ÀI àó~¡uâ¡Öòés2tZøE“ãwøžBô4Yß…üdDiëY ùåk”Ø!Aò"Îc–¾.‹ˆÑÛ6uLâY¶1…’„s….á\ƸJ»AÙVþFX_Á…7¸Íh`"èù ½ó ¼T‚móœN£J„¢D°*(ßÜ ÝlS~ö/PKc¡½!PKé|W+org/rosuda/REngine/Rserve/RConnection.class¥Z |TÕÕ?çÍò^†!™ 08JÈÂ"ŠÔÊ*Á ‰ à’IòHF&3q–`jÕÚÚZµu×\ ”–jm+‚‚Jµ­Ö®ÚÚÚ½µ­Z­Ý>­ÅæûŸûÞLf&“4i‘ûÞ»÷œsÏ=û¹ãsÿ>ôÆÿ0˜?ið§t¾ÉC·ðÍò}‹Á·ê|SI4œL-O$â &ý¥ážðÜh8Ö1·)•ˆÄ:1q’©ÜZˆ™©¹Mñ¶­f ó%mñXÌlK™í€ÙĤE°#ñ¹u±ît DÌp€µ8'dפS¹«z8êl4/c2ä­¹·ÛÍ:&Ÿ|®†#±ÅÑh|›lå8Ïì½DŠ©²>žè˜›ˆ'Óíá¹Ëc‘˜9·1i&z̹݉x*ÞÎmlG·bo[¸;܉FR¼‹â.¿`-@ñx+SÅ0Ô׬YRK™‰-á6îHrÍÒÅk™œñ$svÇ…¿²T"Kn1K;ɤ‰cqó%Ýr¦±Kã±d*K­GÓ¦¬õ¶DowJ¾™iL"™èYo&’‘8PÜgFb‘ÔÙ`°bözì²4Þ9•Õƒ±†tW«™h·F1ãY~y›ÙŽh¤b°R{B‘ù:Y˜5ÜÁ›Ì¤0£HÔ#1Rä±M©pÛÖÕán›éñƒlLÀܤÍT5b}š!’²t2a0áÍK¦T`6DRÖ,Óéƒ!GvoÇ–["±p4òAœÅ×a¦š(‘ÕT{vµEãIS}ÁcŽ«˜=Œ=ñHûòžpTç;Àlæk™ ¹u0›§×‘° oîsbf²VŽÎN¼δ6lif¾&3ÕŒ˜? Í{1eƒ‹›°ÑŽF-%ŸRœ}!=ô¦:ßÉ4§ØvCÒ’]ãÝflEDlöœÑê@Ðr£ÎwÁ]Ûðž2-’‹ÿ’áÔ“0»â=6A#Ù™NµÇ·A²åI1ËXû’ô¥&eªÎŠUr(µ¤v[k‹·ã cÆ;$RUŒH!›”·¶ÛÖyÒ¦=ÈÇD’KòHIÌ4Ûë­m½p¢úÜ4‹d'¢˜X®lÎk}4ÅÓ‰6œ­ÔþÌ À¥ ¿¸Î7 gœ C›× Ãô*NÇÚ-ÆÏKxT”†µsG‡ÄD_ÂLÆ£=f£ “1c"Ö2Ë^sfÊ3¡/gnÊ0 êãA}m°©å±žH"ëÂ+Ó©Cc {ìÒ˜¹-qf[ÔΖË,wð5Úæó›#’‚ÑÍ?ù´9óð7ßKûé ÉpÀKwÒ]^ÚN;¼´“v08ŒIõÒ.ú¬—v Úç„Àú¼—¾@{½ôEºßKȧé3^ú`7 ¯lÞfš=ÌVê‘…õò§é lI<žJ¢âè^m¦:ãíÉ27Æàí^ÞÁwã8|—¾$ܲV1iPñ‘•ÂïèUiö’:¿êåßó þ£˜ú€¤ú¤šÖpQ•J–ÞDÕb…Ræå©‚•±Kñ<5S¦”TY˜q¹EDv6_KdçguõÌ5hKŽ¡ö¸™ŒÍJ…lU"B¡@. I9 ç†auÏ}¼ÆtÆHæ@žƒµ§:a“*Í97o G‘½ôú¡PyÝK/ÒO˜N‚T"“¯Ñ(N"4õvµÆ£b Ý¿ Œ:¿yEÍéL“‡>;”¶yɰFXØS@mC0I‘r©°&G¨”« æ‡ßà?A¶zU—…0oöDâéd&.©6„¦zbÒu[Xu™><)Uk±â»HÕ¹nØy (R'çÌ4w&âÛ$HY 1¼ ¹­»!¾ÌŒ†{¥2W%uyæLQu#‘íÛæU ™Më†Z rËñ~$SZº¶)h¾ÛOÊ-h;&Úœ'‰Ã”e^ñ›©· è'$‡WÁ.ç’#£™žª:ƒÐ¶N AV(j§Âj×ÜJ¢Ž %áD"ÜÛï†|+s•½¦õRwQ]‘)u)2p…a^Þ­’}hÁÉ¡ÖÞjŒN°g&ªCËÍK]Qã9ó¿7aEÏ’dº5©¦åŽ£®ø^%H5ˆ-fs|ˆ› ÈqÙà³I™’¼F"3³Gµb&k…¦ótd H6ÜŽÊ©|€¸ÜÅt˜hÚ ÕæÔIA¾|ð.éX6£enÊj³ ž]ª ¥P>Z)] 3lãnë 'Kañ.E›²UîÇ3%Èj["’‚—虥Èé¹F“D>RQת¨B ¥,GcpæeiS®óWÔ®)/âtÎHrÍV¦Îÿ!pŒæ~']?â­FIX‡ƒ]©`¶Dùæ\™¥MÄ ±ªò0®RjB$U¤z»ÍÐüy³¼G,jK<­ª¡d:š )ž#öº¤¸M+£²2ƒ[+F,LYSeÝ€K©ÛÅæDXZÑiþÌX6Ñf"¨O¼D\¸øµ¨:¤\D®l›†¯Ù›Î¯¨uô]YQüŠt諪!I¹`Sr5ê…t!2ž4²RH+o•b At8vÖKè%S¶³²´ó£=¬ÕÎKÞY‰…½õf¬#…Jmbv¦ÑDb‡ç¦ÂV0ËÒ®º”Ͷ*((8L©ù#»ãT?½s%¤JóTdÊ0­úRUýÊ…²õ,v<ÂZÆ`'¦\\ê9„4VŒgˆÒGç7¥¦ÿK¦=T‘XO|«icZŚݴêü7˜|}<¾5ÝÍä­CK,¢ ÷ýL®lÖ}ˆ¤Ÿ¨™œi!Ï]¢üU|óàRaö`KÑÖ5!-ÒùïL'Žˆ7¬ááè2è"‡wÒ]òÛ‘\(©çvÚ¡žwÓ=êy/ݧž;íù]ôYõÜmÎÆßCŸWÏ/Ð^õü"ݯžØp_²áTø%Òî㤯à›é«x×è!|ïËùþ9å* ïs1·Ÿ`®_'‘ßDžJ?—OÚ{´}ê篃2¢“±ÃzoNÌSØÚØ'ʯÂCeUqä3 žÚäC6òLÌÉkFeÕ>HŽBÜ%¤ÓÒ\îá\Má²£ªîJàÖà>fárœ\ø#z¸ò 9+ù¹*È-ƒ.C‰ Y#ƒW†±2”ÊBYå~roÇú~òõQ¹ÌûöÒäZça·±2èì£ñ‡(u8Ò„#5GilÍ~šXaÒYÖ>U(X9åM>LÇm¬šr¦Ô:ƒN NzMMDîø ¹}8ÂB¬žüôaXÙÝxjêØ=4c=Žë‡¾ÆS)Mı'á/ˆ•É4Ž£Yx«¦i4ŸB Ò@Ëh h5k-¾ÖQ5Q5S”ΧËhh^@WÐFì´™n¤‹èVº{†±ë%°åØT+=Ž]§‘»Äœ::ÍcV«“ÂØˆŒêÂVA ¢þžÿR ,bÄÛä…("–V&®VR¬Îè¤ZdXYÅñ>0pη9+Áõ³\‚]´ˆb Ò é]Ù%@/ ŠIºR‡üÒ´MIh<9ú¤) =A.ãòär„¾ŽQL{:øV†RZh؂ԮÄÛ“ô”í k E'ž3*}(Téá8EûÉ‹£ŸÐPY «šé ›LnŒ×bü¡“®Ã1?ͯÏaK“[hkÇ!Àˆ$ã…-_¥%íh¦ýzâ: oP¯QŸET£$~˜*6j&þtfC™ÕÏð¾ÐcFƒ¶Ð)+@¨\èÃwY†ïRª`ø.!pú|Ÿ¥e5޾Æ]tfs/¹‹N©q-ð­ÙEÕ5î¾¥»h&ÀB»iBÀù˜Qëªq]Ž€óªº*«°EÍ>ØIãÔç!šCÇÜ#‡iÞF°:¿Ö½Nö/è£S¶Û€A×!:ÕÄ»î3ð-„°÷’«Väòuì¡Rì?Mà‚.Ÿáó ¡Ó¡É6!{ö£¢çó.tÜÂtKÐÀ«Þ‚åZ=¨ûk¸&¾Ÿô0|gÖ-ðæÁú"µn/`( êŽ>:ÓwÞ.xHPwºA¾s­Û¹·ç^šQë²=ÄbšEuNR¾tÙKóD?Õûé,‡/ÔGghómâÛÐÜ•þÅpÜ}ˆ¶.Øõ4¸Î:8ÀÅx¾Ï^.Ã3Mñ#°¥Çù€<ù?ÉO“Ÿ_á×øOYç{Y‚è“ rlñfк ÔnAä» èvZŽ$[‡Û€T·Ah3‚ÐÅH°-H‰i¤Õ{4?‡´y?’æÃH›}H–!Q>ޤø4Rà‹H†¿ÀÊ›@ïS{é —Ó£<™ñ‰t˜‚ËÕàñz‚M:‚ñuî¡'ù zŠ?LOóÇè(ßLÏðô,o§çx=Ï_•3Ñ÷qªïð!ú.¿Dßã—éü ½È¯Ñqº—øMú¼öeÍ ŸjcémýL„(M¾Xb@?LÜeE„M¾ÉÄ3ÿEç¸'£ ÄÓuºü?d³Ž¡:k³ &~,-£Möé– ÀO!§’ÎÓÈÇÇÃ[N é<ð ZÄ3élžEËx6­æJ:Ÿ«h3WÓE\C­<‡¶ñ|uú2r¾øœçBËÓ×臶®±ígù°úrç©ËgÙO‰T.Ó²@×ç‘Jà|:tttT #ZfΤ3ø¬\C:¾Ð^¤—ìúë-0æÁsòŒU}6ôÑ ÕÖ³ÖYó„³e¡+蔇;àr_uy.ÿÆ«tLÜÖ·ÛúƺÞp·è-Èźc¡0jžØMãƒzÀÐ[jÆ‚æk ÞÛÿFÀ¸vS¹5ï°&ßRðØh7e!àjñ-AgëU̹wS``ÑÆ|]¸¡Mô€ËàB>”S„‚Èí›kK‚%GÉ,ÉsÒ ƒ%"`+ãù/V©’ R?…î‰ÇÊÓ–þ¥?ñrH¤¿’Nà:ªäU(~Ï£Ó¸žÎE2ÙÀ ÔÎk)Æë¨Ï«¹‘>ÎMt7ÓN>Ÿ¾Šç^ij äz™7Ò«¼‰þÊ›±Û…Øï".å‹•6—·ÔÓO5¤[5¶úï›î°ÊÞ§2y8^›:é\‹^è'/9² ’.ʳ‚Ñm+¸ÃvÐw‡3ϲ™™K²¦ þÜ"ƺFÞN÷*cmÀÐêo»Êß¾‹f®ô(ä!ÓåeýWÕßB§ó­´’o£¸Ã•|'ÝÆwÑ=üi¨ô3¨ÿ¶£¶ÛA?ç»éu¾‡Þà{é¾ÞåJŸuö£‘ȺæË:5°*åh-÷CƒEV4æ÷eþ›ßOT2DÁ‡äE¨ â´AØ öyžÿ²ò|4›yõSz%{c]£Œ=LIéмU)UP:ñÞ,òÏðï稣!§3È=…È_ÉCþe¶¬JÙiñÌá˘@Uñ’j[±’ ±B.ÐÞÏ䃈Åäf …™ðWÙ;°°å µÃò[½¼¾ œTåqÒ[U„“ÇÁÉàäë0³'i?•ËÉøBN~²Úâ¤Ç.îΖ“rºæøOôÑjÀMM7WÔáæ9pó<¸yNâïÐÉüÝ\n&róÛ¬ŽÒ¶ŽÎúÜ|d%}¨˜’~ f~f~M'òoà}¿Íefb!3¿Ë”+¹·…Õès¯,¸á7PÌý©÷U;Éucg¹ïøÕL;÷ y ©Û±Á~òœ=umÅK‰sµá9æTcþ«ä. 8Î*™ª~„®>DVU›d% bN[9­¶« ÕV-µå5R¤ZùËYUý¿ÑúˆE 'ŽP7%Ñ@|$ÛN­ rHâdðÿÑ~%Ë»ÐÀ?Q¶¼‡÷/ZвA)Âÿ¦4Îõê]šF{5Мô¤æ¢—4·ÒVˆ¼ÆXbãD(¬NºÍ÷(tŒ¦e¾òôð{´‚–o± ê¼á~žíižªÜ¤ýѪlׂ·óV«®¥º kѼTŠF;¨•Ò ­Œæh>ªÕÊi™æ§:4ß9]Ëø‚®…éEÛCwA{¨MÆøZQP½ôxŒ¯ÓE@]qR›ñOYÏëµµxxA-®ë¼¶ˆ÷i³!žJˆ§ŠfkÕtªV“ë}Çzß›£ סˆ+ÆË)àåTð²fj§Ñ<íôaÃõ[Ùp´Ãõ¢áyYV<^¼H¼ÖÎ++çÀjÓ\mI.+BVþLo̰۬ƒÒ˜Ãthâ ]¤@±+³¨×©¾ð/vLzÃ`éÑ!O1–ZtoºRÛ÷.«Ý¡áŸUX{QHåæFõå ºU!tÝy™º 1Nwc€R~éAý(ù¥[!lÈK¶ç ê"¬œ#¬ÊËê­q ºƒv£º¸ãîl©u6zcÒê!ÓÕiMÕÖP…¶ŽNÖé ­‰VkÍtv>uiëémݤ]@wji·¶‰öh›•ìï§1¥žÒ~ùmAU3(z^f)|ˆœhЬ&ÓÇÛ¥Vv…‘\ºK$HEV3Ö*†ÑäŠÆºæêÊ9!åUcž~ÿJ³M£Ån¬f¨±æxãC"Òë,‘~R¤ù©#@.S÷_ãl)ªË7­…Ê´V hm4QkÏÜ}•-—[¾Ü}_¤¿ÛûvÙûVÕî —¼i/o½Oí@ÿ“Ù[Ý.h]Ø;޽4Ië¦ÉÚeT©%9ÊV‚‡ò<&þ‘=|愉9Swd˜¸Y1q˜n#¾µ»ß–'å:ÂÇTè<_W€+išv…´«³2h(”ÁÿešZå–Ú€[Þ\Ä-¯ËC}g4¨7桾Kÿ9êMy¨ïÑ¿ŠÇ‘Š Þ–‡zl4¨wå ô~öxšJG€òßþ0mØ—¥~þ·Š“ýü¶Š†Ìoñ_ùÏ(ÞÐJÑZËÌMPã45ž¤Æ*5ÎUãij. # # # 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" 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 and $0: Simon.Urbanek@r-project.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'" 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='Rserve' PACKAGE_TARNAME='rserve' PACKAGE_VERSION='1.8' PACKAGE_STRING='Rserve 1.8' PACKAGE_BUGREPORT='Simon.Urbanek@r-project.org' PACKAGE_URL='' ac_unique_file="src/Rserv.c" # 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_func_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC ax_pthread_config host_os host_vendor host_cpu host build_os build_vendor build_cpu build OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC PKG_LIBS PKG_CPPFLAGS OPENSSL_INCLUDES RLD RINC R_HOME WITH_PROXY_FALSE WITH_PROXY_TRUE WITH_CLIENT_FALSE WITH_CLIENT_TRUE WITH_SERVER_FALSE WITH_SERVER_TRUE 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' ac_subst_files='' ac_user_opts=' enable_option_checking with_server with_client with_proxy enable_ipv6 enable_threads ' ac_precious_vars='build_alias host_alias target_alias OPENSSL_INCLUDES PKG_CPPFLAGS PKG_LIBS CC CFLAGS LDFLAGS LIBS CPPFLAGS' # 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 Rserve 1.8 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/rserve] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Rserve 1.8:";; 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-ipv6 enable the use of IPv6 protocol. [no] --enable-threads enable the use of threads in code than may benefit from it. Currently, it is only used in stdout/err forwarding, it does not enable the threaded server. [auto] Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-server compile Rserve server (default is [yes]). Given that this is the main functionality of Rserve, the only reason to disable the server is to configure R or C++ client separately. --with-client compile additional C/C++ Rserve client (default is [no]). The client can be always compiled manually regardless of this setting. --with-proxy compile WebSockets/QAP proxy (default is [yes]). Some influential environment variables: OPENSSL_INCLUDES optional path to the include directory for OpenSSL headers PKG_CPPFLAGS additional pre-processor flags PKG_LIBS additional linker library flags 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 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 . _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 Rserve configure 1.8 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_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_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 &5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop eval "$3=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 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_type # 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_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_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Rserve $as_me 1.8, 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" as_fn_append ac_header_c_list " vfork.h vfork_h HAVE_VFORK_H" as_fn_append ac_func_c_list " fork HAVE_FORK" as_fn_append ac_func_c_list " vfork HAVE_VFORK" # Auxiliary files required by this configure script. ac_aux_files="config.guess config.sub" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}/tools" # 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 src/config.h" # find R home and set CC/CFLAGS : ${R_HOME=`R RHOME`} if test -z "${R_HOME}"; then echo "could not determine R_HOME" exit 1 fi # Check whether --with-server was given. if test ${with_server+y} then : withval=$with_server; with_server=$withval else $as_nop with_server=yes fi # Check whether --with-client was given. if test ${with_client+y} then : withval=$with_client; with_client=$withval else $as_nop with_client=no fi # Check whether --with-proxy was given. if test ${with_proxy+y} then : withval=$with_proxy; with_proxy=$withval else $as_nop with_proxy=yes fi # Check whether --enable-ipv6 was given. if test ${enable_ipv6+y} then : enableval=$enable_ipv6; want_ipv6="${enableval}" else $as_nop want_ipv6=no fi RLD=`${R_HOME}/bin/R CMD config --ldflags 2>/dev/null` has_R_shlib=no if test -n "$RLD"; then has_R_shlib=yes fi # Check whether --enable-threads was given. if test ${enable_threads+y} then : enableval=$enable_threads; want_threads="${enableval}" else $as_nop want_threads=auto fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to compile the server" >&5 printf %s "checking whether to compile the server... " >&6; } if test "${with_server}" = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } if test "${has_R_shlib}" = no; then as_fn_error $? "R was configured without --enable-R-shlib or --enable-R-static-lib *** Rserve requires R (shared or static) library. *** *** Please install R library or compile R with either --enable-R-shlib *** *** or --enable-R-static-lib support *** Alternatively use --without-server if you wish to build only Rserve client. " "$LINENO" 5 fi 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}: checking whether to compile the client" >&5 printf %s "checking whether to compile the client... " >&6; } if test "${with_client}" = yes; 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" >&5 printf "%s\n" "no" >&6; } fi if test "x${with_server}" = xyes; then WITH_SERVER_TRUE= WITH_SERVER_FALSE='#' else WITH_SERVER_TRUE='#' WITH_SERVER_FALSE= fi if test "x${with_client}" = xyes; then WITH_CLIENT_TRUE= WITH_CLIENT_FALSE='#' else WITH_CLIENT_TRUE='#' WITH_CLIENT_FALSE= fi if test "x${with_proxy}" = xyes; then WITH_PROXY_TRUE= WITH_PROXY_FALSE='#' else WITH_PROXY_TRUE='#' WITH_PROXY_FALSE= fi CC=`${R_HOME}/bin/R CMD config CC`; CXX=`${R_HOME}/bin/R CMD config CXX`; R_CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS`; LDFLAGS=`${R_HOME}/bin/R CMD config LDFLAGS`; CPPFLAGS="${CPPFLAGS} ${PKG_CPPFLAGS} ${R_CPPFLAGS}" CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS` CXXFLAGS=`${R_HOME}/bin/R CMD config CXXFLAGS` RINC=`${R_HOME}/bin/R CMD config --cppflags` LIBS="${LIBS} ${PKG_LIBS}" if test "x${OPENSSL_INCLUDES}" != x; then CPPFLAGS="${CPPFLAGS} -I${OPENSSL_INCLUDES}" fi # Checks for programs. 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 # Checks for libraries. # Checks for header files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 printf %s "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if test ${ac_cv_header_sys_wait_h+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main (void) { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_header_sys_wait_h=yes else $as_nop ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 printf "%s\n" "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi 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" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = xyes then : printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = xyes then : printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "memory.h" "ac_cv_header_memory_h" "$ac_includes_default" if test "x$ac_cv_header_memory_h" = xyes then : printf "%s\n" "#define HAVE_MEMORY_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" if test "x$ac_cv_header_sys_time_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TIME_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes then : printf "%s\n" "#define HAVE_UNISTD_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/stat.h" "ac_cv_header_sys_stat_h" "$ac_includes_default" if test "x$ac_cv_header_sys_stat_h" = xyes then : printf "%s\n" "#define HAVE_SYS_STAT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" if test "x$ac_cv_header_sys_types_h" = xyes then : printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" if test "x$ac_cv_header_sys_socket_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "$ac_includes_default" if test "x$ac_cv_header_sys_un_h" = xyes then : printf "%s\n" "#define HAVE_SYS_UN_H 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" "netinet/tcp.h" "ac_cv_header_netinet_tcp_h" "$ac_includes_default" if test "x$ac_cv_header_netinet_tcp_h" = xyes then : printf "%s\n" "#define HAVE_NETINET_TCP_H 1" >>confdefs.h fi # Checks for typedefs, structures, and compiler characteristics. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 printf %s "checking for an ANSI C-conforming const... " >&6; } if test ${ac_cv_c_const+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* IBM XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* IBM XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_const=yes else $as_nop ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 printf "%s\n" "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then printf "%s\n" "#define const /**/" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 printf %s "checking whether byte ordering is bigendian... " >&6; } if test ${ac_cv_c_bigendian+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO" then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no 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 if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no 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 if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ unsigned short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; unsigned short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } unsigned short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; unsigned short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main (void) { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_c_bigendian=no else $as_nop ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 printf "%s\n" "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) printf "%s\n" "#define BS_BIG_ENDIAN 1" >>confdefs.h ;; #( no) printf "%s\n" "#define BS_LITTLE_ENDIAN 1" >>confdefs.h ;; #( universal) printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: endianness unknown - will rely solely on compiler macros" >&5 printf "%s\n" "endianness unknown - will rely solely on compiler macros" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether compiler sets endianness macros" >&5 printf %s "checking whether compiler sets endianness macros... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined __LITTLE_ENDIAN__ || defined _LITTLE_ENDIAN_ || defined __BIG_ENDIAN__ || defined _BIG_ENDIAN_ #define BS_OK 1 #else cannot determine compiler's endianness #endif _ACEOF if ac_fn_c_try_compile "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } as_fn_error $? "Cannot determine endianness neither from the compiler nor using a test. Try adding -D_BIG_ENDIAN_ or -D_LITTLE_ENDIAN_ to PKG_CPPFLAGS. " "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac # 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 size_t" >&5 printf %s "checking size of size_t... " >&6; } if test ${ac_cv_sizeof_size_t+y} then : printf %s "(cached) " >&6 else $as_nop if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default" then : else $as_nop if test "$ac_cv_type_size_t" = 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 (size_t) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_size_t=0 fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5 printf "%s\n" "$ac_cv_sizeof_size_t" >&6; } printf "%s\n" "#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t" >>confdefs.h # Checks for library functions. ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default " if test "x$ac_cv_type_pid_t" = xyes then : else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined _WIN64 && !defined __CYGWIN__ LLP64 #endif int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_pid_type='int' else $as_nop ac_pid_type='__int64' fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h fi ac_func= for ac_item in $ac_func_c_list do if test $ac_func; then ac_fn_c_check_func "$LINENO" $ac_func ac_cv_func_$ac_func if eval test \"x\$ac_cv_func_$ac_func\" = xyes; then echo "#define $ac_item 1" >> confdefs.h fi ac_func= else ac_func=$ac_item fi done if test "x$ac_cv_func_fork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 printf %s "checking for working fork... " >&6; } if test ${ac_cv_func_fork_works+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_func_fork_works=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_fork_works=yes else $as_nop ac_cv_func_fork_works=no 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_func_fork_works" >&5 printf "%s\n" "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 printf %s "checking for working vfork... " >&6; } if test ${ac_cv_func_vfork_works+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ac_cv_func_vfork_works=cross else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #include #ifdef HAVE_VFORK_H # include #endif static void do_nothing (int sig) { (void) sig; } /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void sparc_address_test (int arg) { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main (void) { pid_t parent = getpid (); pid_t child; sparc_address_test (0); /* On Solaris 2.4, changes by the child to the signal handler also munge signal handlers in the parent. To detect this, start by putting the parent's handler in a known state. */ signal (SIGTERM, SIG_DFL); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* Alter the child's signal handler. */ if (signal (SIGTERM, do_nothing) != SIG_DFL) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child munge the parent's signal handler? */ || signal (SIGTERM, SIG_DFL) != SIG_DFL /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_vfork_works=yes else $as_nop ac_cv_func_vfork_works=no 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_func_vfork_works" >&5 printf "%s\n" "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 printf "%s\n" "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_VFORK 1" >>confdefs.h else printf "%s\n" "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then printf "%s\n" "#define HAVE_WORKING_FORK 1" >>confdefs.h fi # NOTE: autoconf claims this must be void and thus is not needed { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 printf %s "checking return type of signal handlers... " >&6; } if test ${ac_cv_type_signal+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_type_signal=int else $as_nop ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 printf "%s\n" "$ac_cv_type_signal" >&6; } printf "%s\n" "#define RETSIGTYPE $ac_cv_type_signal" >>confdefs.h ac_fn_c_check_func "$LINENO" "memset" "ac_cv_func_memset" if test "x$ac_cv_func_memset" = xyes then : printf "%s\n" "#define HAVE_MEMSET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mkdir" "ac_cv_func_mkdir" if test "x$ac_cv_func_mkdir" = xyes then : printf "%s\n" "#define HAVE_MKDIR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "rmdir" "ac_cv_func_rmdir" if test "x$ac_cv_func_rmdir" = xyes then : printf "%s\n" "#define HAVE_RMDIR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "select" "ac_cv_func_select" if test "x$ac_cv_func_select" = xyes then : printf "%s\n" "#define HAVE_SELECT 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" if test "x$ac_cv_func_socket" = xyes then : printf "%s\n" "#define HAVE_SOCKET 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "srandomdev" "ac_cv_func_srandomdev" if test "x$ac_cv_func_srandomdev" = xyes then : printf "%s\n" "#define HAVE_SRANDOMDEV 1" >>confdefs.h fi # Check whether we can use crypt (and if we do if it's in the crypt library) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing crypt" >&5 printf %s "checking for library containing crypt... " >&6; } if test ${ac_cv_search_crypt+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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 crypt (); int main (void) { return crypt (); ; return 0; } _ACEOF for ac_lib in '' crypt do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_crypt=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_crypt+y} then : break fi done if test ${ac_cv_search_crypt+y} then : else $as_nop ac_cv_search_crypt=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_crypt" >&5 printf "%s\n" "$ac_cv_search_crypt" >&6; } ac_res=$ac_cv_search_crypt if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" printf "%s\n" "#define HAS_CRYPT 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "crypt.h" "ac_cv_header_crypt_h" "$ac_includes_default" if test "x$ac_cv_header_crypt_h" = xyes then : printf "%s\n" "#define HAVE_CRYPT_H 1" >>confdefs.h fi # socket related stuff - indroduced first due to Solaris # socklen_t - note that we don't try to find an equivalent! # we'll use BSD-style int in case this one isn't defined. # that should be fine for all major platforms. ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" " #include #include " if test "x$ac_cv_type_socklen_t" = xyes then : else $as_nop printf "%s\n" "#define socklen_t int" >>confdefs.h fi # connect may need -lsocket and/or -lnsl (e.g. on Solaris) ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes then : printf "%s\n" "#define HAVE_CONNECT 1" >>confdefs.h fi if test x"$ac_cv_func_connect" = x"no"; then case "$LIBS" in *-lnsl*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for printf in -lnsl_s" >&5 printf %s "checking for printf in -lnsl_s... " >&6; } if test ${ac_cv_lib_nsl_s_printf+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl_s $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 printf (); int main (void) { return printf (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_nsl_s_printf=yes else $as_nop ac_cv_lib_nsl_s_printf=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_nsl_s_printf" >&5 printf "%s\n" "$ac_cv_lib_nsl_s_printf" >&6; } if test "x$ac_cv_lib_nsl_s_printf" = xyes then : printf "%s\n" "#define HAVE_LIBNSL_S 1" >>confdefs.h LIBS="-lnsl_s $LIBS" fi ;; esac case "$LIBS" in *-lnsl*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for printf in -lnsl" >&5 printf %s "checking for printf in -lnsl... " >&6; } if test ${ac_cv_lib_nsl_printf+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $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 printf (); int main (void) { return printf (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_nsl_printf=yes else $as_nop ac_cv_lib_nsl_printf=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_nsl_printf" >&5 printf "%s\n" "$ac_cv_lib_nsl_printf" >&6; } if test "x$ac_cv_lib_nsl_printf" = xyes then : printf "%s\n" "#define HAVE_LIBNSL 1" >>confdefs.h LIBS="-lnsl $LIBS" fi ;; esac case "$LIBS" in *-lsocket*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 printf %s "checking for connect in -lsocket... " >&6; } if test ${ac_cv_lib_socket_connect+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 connect (); int main (void) { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_socket_connect=yes else $as_nop ac_cv_lib_socket_connect=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_connect" >&5 printf "%s\n" "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = xyes then : printf "%s\n" "#define HAVE_LIBSOCKET 1" >>confdefs.h LIBS="-lsocket $LIBS" fi ;; esac case "$LIBS" in *-linet*) ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for connect in -linet" >&5 printf %s "checking for connect in -linet... " >&6; } if test ${ac_cv_lib_inet_connect+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-linet $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 connect (); int main (void) { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_inet_connect=yes else $as_nop ac_cv_lib_inet_connect=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_inet_connect" >&5 printf "%s\n" "$ac_cv_lib_inet_connect" >&6; } if test "x$ac_cv_lib_inet_connect" = xyes then : printf "%s\n" "#define HAVE_LIBINET 1" >>confdefs.h LIBS="-linet $LIBS" fi ;; esac if test x"$ac_cv_lib_socket_connect" = x"yes" || test x"$ac_cv_lib_inet_connect" = x"yes"; then # ac_cv_func_connect=yes # don't! it would cause AC_CHECK_FUNC to succeed next time configure is run printf "%s\n" "#define HAVE_CONNECT 1" >>confdefs.h fi fi # IPv6 have_ipv6=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable IPv6" >&5 printf %s "checking whether to enable IPv6... " >&6; } if test "$want_ipv6" = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working IPv6 sockets" >&5 printf %s "checking for working IPv6 sockets... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main(void) { struct sockaddr_in6 sin; int i = socket(PF_INET6, SOCK_STREAM, 0); sin.sin6_family = AF_INET6; sin.sin6_addr = in6addr_any; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } have_ipv6=yes else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "$have_ipv6" = yes; then printf "%s\n" "#define HAVE_IPV6 1" >>confdefs.h fi # on some platforms libR expects dl code in the binary { 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 : printf "%s\n" "#define HAVE_LIBDL 1" >>confdefs.h LIBS="-ldl $LIBS" fi # check RSA/crypto ac_fn_c_check_header_compile "$LINENO" "openssl/rsa.h" "ac_cv_header_openssl_rsa_h" "$ac_includes_default" if test "x$ac_cv_header_openssl_rsa_h" = xyes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing RSA_generate_key" >&5 printf %s "checking for library containing RSA_generate_key... " >&6; } if test ${ac_cv_search_RSA_generate_key+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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 RSA_generate_key (); int main (void) { return RSA_generate_key (); ; return 0; } _ACEOF for ac_lib in '' crypto ssl openssl do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_RSA_generate_key=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_RSA_generate_key+y} then : break fi done if test ${ac_cv_search_RSA_generate_key+y} then : else $as_nop ac_cv_search_RSA_generate_key=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_RSA_generate_key" >&5 printf "%s\n" "$ac_cv_search_RSA_generate_key" >&6; } ac_res=$ac_cv_search_RSA_generate_key if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" printf "%s\n" "#define HAVE_RSA 1" >>confdefs.h fi fi # check SSL support ac_fn_c_check_header_compile "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default" if test "x$ac_cv_header_openssl_ssl_h" = xyes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing SSL_CTX_load_verify_locations" >&5 printf %s "checking for library containing SSL_CTX_load_verify_locations... " >&6; } if test ${ac_cv_search_SSL_CTX_load_verify_locations+y} then : printf %s "(cached) " >&6 else $as_nop ac_func_search_save_LIBS=$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 SSL_CTX_load_verify_locations (); int main (void) { return SSL_CTX_load_verify_locations (); ; return 0; } _ACEOF for ac_lib in '' ssl openssl do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO" then : ac_cv_search_SSL_CTX_load_verify_locations=$ac_res fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext if test ${ac_cv_search_SSL_CTX_load_verify_locations+y} then : break fi done if test ${ac_cv_search_SSL_CTX_load_verify_locations+y} then : else $as_nop ac_cv_search_SSL_CTX_load_verify_locations=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_SSL_CTX_load_verify_locations" >&5 printf "%s\n" "$ac_cv_search_SSL_CTX_load_verify_locations" >&6; } ac_res=$ac_cv_search_SSL_CTX_load_verify_locations if test "$ac_res" != no then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" printf "%s\n" "#define HAVE_TLS 1" >>confdefs.h fi fi # check threads { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether threads are desired" >&5 printf %s "checking whether threads are desired... " >&6; } if test "$want_threads" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } # 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 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 ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 printf %s "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } 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 pthread_join (); int main (void) { return pthread_join (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ax_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 printf "%s\n" "$ax_pthread_ok" >&6; } if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac # Clang doesn't consider unrecognized options an error unless we specify # -Werror. We throw in some extra Clang-specific options to ensure that # this doesn't happen for GCC, which also accepts -Werror. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler needs -Werror to reject unknown flags" >&5 printf %s "checking if compiler needs -Werror to reject unknown flags... " >&6; } save_CFLAGS="$CFLAGS" ax_pthread_extra_flags="-Werror" CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo(void); int main (void) { foo() ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else $as_nop ax_pthread_extra_flags= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$save_CFLAGS" if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 printf %s "checking whether pthreads work without any flags... " >&6; } ;; -*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 printf %s "checking whether pthreads work with $flag... " >&6; } PTHREAD_CFLAGS="$flag" ;; pthread-config) # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; 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_ax_pthread_config+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ax_pthread_config"; then ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS 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_ax_pthread_config="yes" 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_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no" fi fi ax_pthread_config=$ac_cv_prog_ax_pthread_config if test -n "$ax_pthread_config"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 printf "%s\n" "$ax_pthread_config" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 printf %s "checking for the pthreads library -l$flag... " >&6; } PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. # NOTE: RedHat is broken and requires an explicit # inclusion of pthread_atfork in the test otherwise it # will appear to work without -pthread even though it doesn't. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include static void routine(void *a) { a = 0; } static void atfork_null() { } static void *start_routine(void *a) { return a; } int main (void) { pthread_t th; pthread_attr_t attr; pthread_atfork(atfork_null, atfork_null, atfork_null); pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */ ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ax_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 printf "%s\n" "$ax_pthread_ok" >&6; } if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 printf %s "checking for joinable pthread attribute... " >&6; } attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int attr = $attr; return attr /* ; */ ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : attr_name=$attr; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 printf "%s\n" "$attr_name" >&6; } if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then printf "%s\n" "#define PTHREAD_CREATE_JOINABLE $attr_name" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 printf %s "checking if more special flags are required for pthreads... " >&6; } flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else # TODO: What about Clang on Solaris? flag="-mt -D_REENTRANT" fi ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $flag" >&5 printf "%s\n" "$flag" >&6; } if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5 printf %s "checking for PTHREAD_PRIO_INHERIT... " >&6; } if test ${ax_cv_PTHREAD_PRIO_INHERIT+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int i = PTHREAD_PRIO_INHERIT; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ax_cv_PTHREAD_PRIO_INHERIT=yes else $as_nop ax_cv_PTHREAD_PRIO_INHERIT=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 printf "%s\n" "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" then : printf "%s\n" "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: compile with *_r variant if test "x$GCC" != xyes; then case $host_os in aix*) case "x/$CC" in #( x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) : #handle absolute path differently from PATH based program lookup case "x$CC" in #( x/*) : if as_fn_executable_p ${CC}_r then : PTHREAD_CC="${CC}_r" fi ;; #( *) : for ac_prog in ${CC}_r 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_PTHREAD_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$PTHREAD_CC"; then ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS 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_PTHREAD_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 PTHREAD_CC=$ac_cv_prog_PTHREAD_CC if test -n "$PTHREAD_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5 printf "%s\n" "$PTHREAD_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$PTHREAD_CC" && break done test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" ;; esac ;; #( *) : ;; esac ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then LIBS="$PTHREAD_LIBS $LIBS" ## we don't want to mess with CFLAGS so we (ab)use CPPFLAGS CPPFLAGS="$CPPFLAGS $PTHREAD_CFLAGS" ## and we ignore PTHREAD_CC since we have to use R's settings with_threads=yes { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working threads support" >&5 printf %s "checking for working threads support... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } : else ax_pthread_ok=no { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working threads support" >&5 printf %s "checking for working threads support... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } if test "$want_threads" = yes; then as_fn_error $? "Threads were requested, but no working threads support was found" "$LINENO" 5 fi with_threads=no 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 else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } with_threads=no fi if test x"$with_threads" = xyes; then printf "%s\n" "#define WITH_THREADS 1" >>confdefs.h fi ac_config_files="$ac_config_files src/Makevars" ac_config_files="$ac_config_files src/client/cxx/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { 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 if test -z "${WITH_SERVER_TRUE}" && test -z "${WITH_SERVER_FALSE}"; then as_fn_error $? "conditional \"WITH_SERVER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_CLIENT_TRUE}" && test -z "${WITH_CLIENT_FALSE}"; then as_fn_error $? "conditional \"WITH_CLIENT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WITH_PROXY_TRUE}" && test -z "${WITH_PROXY_FALSE}"; then as_fn_error $? "conditional \"WITH_PROXY\" 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 Rserve $as_me 1.8, 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" _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 Report bugs to ." _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="\\ Rserve config.status 1.8 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' 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 _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 "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; "src/Makevars") CONFIG_FILES="$CONFIG_FILES src/Makevars" ;; "src/client/cxx/Makefile") CONFIG_FILES="$CONFIG_FILES src/client/cxx/Makefile" ;; *) 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 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 " 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 # _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 $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 ;; 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