diff options
Diffstat (limited to 'jni/ruby/missing')
32 files changed, 2883 insertions, 0 deletions
diff --git a/jni/ruby/missing/acosh.c b/jni/ruby/missing/acosh.c new file mode 100644 index 0000000..004bfb1 --- /dev/null +++ b/jni/ruby/missing/acosh.c @@ -0,0 +1,93 @@ +/********************************************************************** + + acosh.c - + + $Author: akr $ + created at: Fri Apr 12 00:34:17 JST 2002 + + public domain rewrite of acosh(3), asinh(3) and atanh(3) + +**********************************************************************/ + +#include <errno.h> +#include <float.h> +#include <math.h> +#include "ruby.h" + +/* DBL_MANT_DIG must be less than 4 times of bits of int */ +#ifndef DBL_MANT_DIG +#define DBL_MANT_DIG 53 /* in this case, at least 12 digit precision */ +#endif +#define BIG_CRITERIA_BIT (1<<DBL_MANT_DIG/2) +#if BIG_CRITERIA_BIT > 0 +#define BIG_CRITERIA (1.0*BIG_CRITERIA_BIT) +#else +#define BIG_CRITERIA (1.0*(1<<DBL_MANT_DIG/4)*(1<<(DBL_MANT_DIG/2+1-DBL_MANT_DIG/4))) +#endif +#define SMALL_CRITERIA_BIT (1<<(DBL_MANT_DIG/3)) +#if SMALL_CRITERIA_BIT > 0 +#define SMALL_CRITERIA (1.0/SMALL_CRITERIA_BIT) +#else +#define SMALL_CRITERIA (1.0*(1<<DBL_MANT_DIG/4)*(1<<(DBL_MANT_DIG/3+1-DBL_MANT_DIG/4))) +#endif + +#ifndef HAVE_ACOSH +double +acosh(double x) +{ + if (x < 1) + x = -1; /* NaN */ + else if (x == 1) + return 0; + else if (x > BIG_CRITERIA) + x += x; + else + x += sqrt((x + 1) * (x - 1)); + return log(x); +} +#endif + +#ifndef HAVE_ASINH +double +asinh(double x) +{ + int neg = x < 0; + double z = fabs(x); + + if (z < SMALL_CRITERIA) return x; + if (z < (1.0/(1<<DBL_MANT_DIG/5))) { + double x2 = z * z; + z *= 1 + x2 * (-1.0/6.0 + x2 * 3.0/40.0); + } + else if (z > BIG_CRITERIA) { + z = log(z + z); + } + else { + z = log(z + sqrt(z * z + 1)); + } + if (neg) z = -z; + return z; +} +#endif + +#ifndef HAVE_ATANH +double +atanh(double x) +{ + int neg = x < 0; + double z = fabs(x); + + if (z < SMALL_CRITERIA) return x; + z = log(z > 1 ? -1 : (1 + z) / (1 - z)) / 2; + if (neg) z = -z; + if (isinf(z)) +#if defined(ERANGE) + errno = ERANGE; +#elif defined(EDOM) + errno = EDOM; +#else + ; +#endif + return z; +} +#endif diff --git a/jni/ruby/missing/alloca.c b/jni/ruby/missing/alloca.c new file mode 100644 index 0000000..96121f7 --- /dev/null +++ b/jni/ruby/missing/alloca.c @@ -0,0 +1,199 @@ +/* alloca -- (mostly) portable public-domain implementation -- D A Gwyn + + last edit: 86/05/30 rms + include config.h, since on VMS it renames some symbols. + Use xmalloc instead of malloc. + + This implementation of the PWB library alloca() function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + + It should work under any C implementation that uses an + actual procedure stack (as opposed to a linked list of + frames). There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca()-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. +*/ +#ifndef lint +static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ +#endif + +#include "ruby/config.h" +#define X3J11 1 /* config.h should contain void if needed */ + +#ifdef C_ALLOCA + +#ifdef emacs +#ifdef static +/* actually, only want this if static is defined as "" + -- this is for usg, in which emacs must undefine static + in order to make unexec workable + */ +#ifndef STACK_DIRECTION +you +lose +-- must know STACK_DIRECTION at compile-time +#endif /* STACK_DIRECTION undefined */ +#endif /* static */ +#endif /* emacs */ + +#ifdef X3J11 +typedef void *pointer; /* generic pointer type */ +#else +typedef char *pointer; /* generic pointer type */ +#endif /* X3J11 */ + +#ifndef NULL +#define NULL 0 /* null pointer constant */ +#endif + +#define xmalloc ruby_xmalloc +#define xfree ruby_xfree + +extern void xfree(); +extern pointer xmalloc(); + +/* + Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown +*/ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* direction unknown */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* known at compile-time */ + +#else /* STACK_DIRECTION == 0; need run-time code */ + +static int stack_dir; /* 1 or -1 once known */ +#define STACK_DIR stack_dir + +static void +find_stack_direction (/* void */) +{ + static char *addr = NULL; /* address of first + `dummy', once known */ + auto char dummy; /* to get stack address */ + + if (addr == NULL) + { /* initial entry */ + addr = &dummy; + + find_stack_direction (); /* recurse once */ + } + else /* second entry */ + if (&dummy > addr) + stack_dir = 1; /* stack grew upward */ + else + stack_dir = -1; /* stack grew downward */ +} + +#endif /* STACK_DIRECTION == 0 */ + +/* + An "alloca header" is used to: + (a) chain together all alloca()ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc() + alignment chunk size. The following default should work okay. +*/ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* to force sizeof(header) */ + struct + { + union hdr *next; /* for chaining headers */ + char *deep; /* for stack depth measure */ + } h; +} header; + +/* + alloca( size ) returns a pointer to at least `size' bytes of + storage which will be automatically reclaimed upon exit from + the procedure that called alloca(). Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. +*/ + +static header *last_alloca_header = NULL; /* -> last alloca header */ + +pointer +alloca (size) /* returns pointer to storage */ + unsigned size; /* # bytes to allocate */ +{ + auto char probe; /* probes stack depth: */ + register char *depth = &probe; + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* unknown growth direction */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca()ed storage that + was allocated from deeper in the stack than currently. */ + { + register header *hp; /* traverses linked list */ + + for (hp = last_alloca_header; hp != NULL;) + if (STACK_DIR > 0 && hp->h.deep > depth + || STACK_DIR < 0 && hp->h.deep < depth) + { + register header *np = hp->h.next; + + xfree ((pointer) hp); /* collect garbage */ + + hp = np; /* -> next header */ + } + else + break; /* rest are not deeper */ + + last_alloca_header = hp; /* -> last valid storage */ + } + + if (size == 0) + return NULL; /* no allocation required */ + + /* Allocate combined header + user data storage. */ + + { + register pointer new = xmalloc (sizeof (header) + size); + /* address of header */ + + ((header *)new)->h.next = last_alloca_header; + ((header *)new)->h.deep = depth; + + last_alloca_header = (header *)new; + + /* User storage begins just after header. */ + + return (pointer)((char *)new + sizeof(header)); + } +} + +#endif diff --git a/jni/ruby/missing/cbrt.c b/jni/ruby/missing/cbrt.c new file mode 100644 index 0000000..1bcbc63 --- /dev/null +++ b/jni/ruby/missing/cbrt.c @@ -0,0 +1,11 @@ +#include "ruby/missing.h" +#include <math.h> + +double cbrt(double x) +{ + if (x < 0) + return -pow(-x, 1/3.0); + else + return pow(x, 1/3.0); +} + diff --git a/jni/ruby/missing/close.c b/jni/ruby/missing/close.c new file mode 100644 index 0000000..831e75e --- /dev/null +++ b/jni/ruby/missing/close.c @@ -0,0 +1,72 @@ +/* Ignore ECONNRESET of FreeBSD */ +#include "ruby/missing.h" +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> + +#undef getpeername +int +ruby_getpeername(int s, struct sockaddr * name, + socklen_t * namelen) +{ + int err = errno; + errno = 0; + s = getpeername(s, name, namelen); + if (errno == ECONNRESET) { + errno = 0; + s = 0; + } + else if (errno == 0) + errno = err; + return s; +} + +#undef getsockname +int +ruby_getsockname(int s, struct sockaddr * name, + socklen_t * namelen) +{ + int err = errno; + errno = 0; + s = getsockname(s, name, namelen); + if (errno == ECONNRESET) { + errno = 0; + s = 0; + } + else if (errno == 0) + errno = err; + return s; +} + +#undef shutdown +int +ruby_shutdown(int s, int how) +{ + int err = errno; + errno = 0; + s = shutdown(s, how); + if (errno == ECONNRESET) { + errno = 0; + s = 0; + } + else if (errno == 0) + errno = err; + return s; +} + +#undef close +int +ruby_close(int s) +{ + int err = errno; + errno = 0; + s = close(s); + if (errno == ECONNRESET) { + errno = 0; + s = 0; + } + else if (errno == 0) + errno = err; + return s; +} diff --git a/jni/ruby/missing/crt_externs.h b/jni/ruby/missing/crt_externs.h new file mode 100644 index 0000000..cc96d46 --- /dev/null +++ b/jni/ruby/missing/crt_externs.h @@ -0,0 +1,8 @@ +#ifndef MISSING_CRT_EXTERNS_H +#define MISSING_CRT_EXTERNS_H + +char ***_NSGetEnviron(); +#undef environ +#define environ (*_NSGetEnviron()) + +#endif diff --git a/jni/ruby/missing/crypt.c b/jni/ruby/missing/crypt.c new file mode 100644 index 0000000..366fba0 --- /dev/null +++ b/jni/ruby/missing/crypt.c @@ -0,0 +1,993 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tom Truscott. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)crypt.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include "ruby/missing.h" +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <limits.h> +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#include <stdio.h> +#ifndef _PASSWORD_EFMT1 +#define _PASSWORD_EFMT1 '_' +#endif + +/* + * UNIX password, and DES, encryption. + * By Tom Truscott, trt@rti.rti.org, + * from algorithms by Robert W. Baldwin and James Gillogly. + * + * References: + * "Mathematical Cryptology for Computer Scientists and Mathematicians," + * by Wayne Patterson, 1987, ISBN 0-8476-7438-X. + * + * "Password Security: A Case History," R. Morris and Ken Thompson, + * Communications of the ACM, vol. 22, pp. 594-597, Nov. 1979. + * + * "DES will be Totally Insecure within Ten Years," M.E. Hellman, + * IEEE Spectrum, vol. 16, pp. 32-39, July 1979. + */ + +/* ===== Configuration ==================== */ + +/* + * define "MUST_ALIGN" if your compiler cannot load/store + * long integers at arbitrary (e.g. odd) memory locations. + * (Either that or never pass unaligned addresses to des_cipher!) + */ +#if !defined(vax) +#define MUST_ALIGN +#endif + +#ifdef CHAR_BITS +#if CHAR_BITS != 8 + #error C_block structure assumes 8 bit characters +#endif +#endif + +/* + * define "LONG_IS_32_BITS" only if sizeof(long)==4. + * This avoids use of bit fields (your compiler may be sloppy with them). + */ +#if !defined(cray) +#define LONG_IS_32_BITS +#endif + +/* + * define "B64" to be the declaration for a 64 bit integer. + * XXX this feature is currently unused, see "endian" comment below. + */ +#if defined(cray) +#define B64 long +#endif +#if defined(convex) +#define B64 long long +#endif + +/* + * define "LARGEDATA" to get faster permutations, by using about 72 kilobytes + * of lookup tables. This speeds up des_setkey() and des_cipher(), but has + * little effect on crypt(). + */ +#if defined(notdef) +#define LARGEDATA +#endif + +int des_setkey(), des_cipher(); + +/* compile with "-DSTATIC=int" when profiling */ +#ifndef STATIC +#define STATIC static +#endif +STATIC void init_des(), init_perm(), permute(); +#ifdef DEBUG +STATIC void prtab(); +#endif + +/* ==================================== */ + +/* + * Cipher-block representation (Bob Baldwin): + * + * DES operates on groups of 64 bits, numbered 1..64 (sigh). One + * representation is to store one bit per byte in an array of bytes. Bit N of + * the NBS spec is stored as the LSB of the Nth byte (index N-1) in the array. + * Another representation stores the 64 bits in 8 bytes, with bits 1..8 in the + * first byte, 9..16 in the second, and so on. The DES spec apparently has + * bit 1 in the MSB of the first byte, but that is particularly noxious so we + * bit-reverse each byte so that bit 1 is the LSB of the first byte, bit 8 is + * the MSB of the first byte. Specifically, the 64-bit input data and key are + * converted to LSB format, and the output 64-bit block is converted back into + * MSB format. + * + * DES operates internally on groups of 32 bits which are expanded to 48 bits + * by permutation E and shrunk back to 32 bits by the S boxes. To speed up + * the computation, the expansion is applied only once, the expanded + * representation is maintained during the encryption, and a compression + * permutation is applied only at the end. To speed up the S-box lookups, + * the 48 bits are maintained as eight 6 bit groups, one per byte, which + * directly feed the eight S-boxes. Within each byte, the 6 bits are the + * most significant ones. The low two bits of each byte are zero. (Thus, + * bit 1 of the 48 bit E expansion is stored as the "4"-valued bit of the + * first byte in the eight byte representation, bit 2 of the 48 bit value is + * the "8"-valued bit, and so on.) In fact, a combined "SPE"-box lookup is + * used, in which the output is the 64 bit result of an S-box lookup which + * has been permuted by P and expanded by E, and is ready for use in the next + * iteration. Two 32-bit wide tables, SPE[0] and SPE[1], are used for this + * lookup. Since each byte in the 48 bit path is a multiple of four, indexed + * lookup of SPE[0] and SPE[1] is simple and fast. The key schedule and + * "salt" are also converted to this 8*(6+2) format. The SPE table size is + * 8*64*8 = 4K bytes. + * + * To speed up bit-parallel operations (such as XOR), the 8 byte + * representation is "union"ed with 32 bit values "i0" and "i1", and, on + * machines which support it, a 64 bit value "b64". This data structure, + * "C_block", has two problems. First, alignment restrictions must be + * honored. Second, the byte-order (e.g. little-endian or big-endian) of + * the architecture becomes visible. + * + * The byte-order problem is unfortunate, since on the one hand it is good + * to have a machine-independent C_block representation (bits 1..8 in the + * first byte, etc.), and on the other hand it is good for the LSB of the + * first byte to be the LSB of i0. We cannot have both these things, so we + * currently use the "little-endian" representation and avoid any multi-byte + * operations that depend on byte order. This largely precludes use of the + * 64-bit datatype since the relative order of i0 and i1 are unknown. It + * also inhibits grouping the SPE table to look up 12 bits at a time. (The + * 12 bits can be stored in a 16-bit field with 3 low-order zeroes and 1 + * high-order zero, providing fast indexing into a 64-bit wide SPE.) On the + * other hand, 64-bit datatypes are currently rare, and a 12-bit SPE lookup + * requires a 128 kilobyte table, so perhaps this is not a big loss. + * + * Permutation representation (Jim Gillogly): + * + * A transformation is defined by its effect on each of the 8 bytes of the + * 64-bit input. For each byte we give a 64-bit output that has the bits in + * the input distributed appropriately. The transformation is then the OR + * of the 8 sets of 64-bits. This uses 8*256*8 = 16K bytes of storage for + * each transformation. Unless LARGEDATA is defined, however, a more compact + * table is used which looks up 16 4-bit "chunks" rather than 8 8-bit chunks. + * The smaller table uses 16*16*8 = 2K bytes for each transformation. This + * is slower but tolerable, particularly for password encryption in which + * the SPE transformation is iterated many times. The small tables total 9K + * bytes, the large tables total 72K bytes. + * + * The transformations used are: + * IE3264: MSB->LSB conversion, initial permutation, and expansion. + * This is done by collecting the 32 even-numbered bits and applying + * a 32->64 bit transformation, and then collecting the 32 odd-numbered + * bits and applying the same transformation. Since there are only + * 32 input bits, the IE3264 transformation table is half the size of + * the usual table. + * CF6464: Compression, final permutation, and LSB->MSB conversion. + * This is done by two trivial 48->32 bit compressions to obtain + * a 64-bit block (the bit numbering is given in the "CIFP" table) + * followed by a 64->64 bit "cleanup" transformation. (It would + * be possible to group the bits in the 64-bit block so that 2 + * identical 32->32 bit transformations could be used instead, + * saving a factor of 4 in space and possibly 2 in time, but + * byte-ordering and other complications rear their ugly head. + * Similar opportunities/problems arise in the key schedule + * transforms.) + * PC1ROT: MSB->LSB, PC1 permutation, rotate, and PC2 permutation. + * This admittedly baroque 64->64 bit transformation is used to + * produce the first code (in 8*(6+2) format) of the key schedule. + * PC2ROT[0]: Inverse PC2 permutation, rotate, and PC2 permutation. + * It would be possible to define 15 more transformations, each + * with a different rotation, to generate the entire key schedule. + * To save space, however, we instead permute each code into the + * next by using a transformation that "undoes" the PC2 permutation, + * rotates the code, and then applies PC2. Unfortunately, PC2 + * transforms 56 bits into 48 bits, dropping 8 bits, so PC2 is not + * invertible. We get around that problem by using a modified PC2 + * which retains the 8 otherwise-lost bits in the unused low-order + * bits of each byte. The low-order bits are cleared when the + * codes are stored into the key schedule. + * PC2ROT[1]: Same as PC2ROT[0], but with two rotations. + * This is faster than applying PC2ROT[0] twice, + * + * The Bell Labs "salt" (Bob Baldwin): + * + * The salting is a simple permutation applied to the 48-bit result of E. + * Specifically, if bit i (1 <= i <= 24) of the salt is set then bits i and + * i+24 of the result are swapped. The salt is thus a 24 bit number, with + * 16777216 possible values. (The original salt was 12 bits and could not + * swap bits 13..24 with 36..48.) + * + * It is possible, but ugly, to warp the SPE table to account for the salt + * permutation. Fortunately, the conditional bit swapping requires only + * about four machine instructions and can be done on-the-fly with about an + * 8% performance penalty. + */ + +typedef union { + unsigned char b[8]; + struct { +#if defined(LONG_IS_32_BITS) + /* long is often faster than a 32-bit bit field */ + long i0; + long i1; +#else + long i0: 32; + long i1: 32; +#endif + } b32; +#if defined(B64) + B64 b64; +#endif +} C_block; + +/* + * Convert twenty-four-bit long in host-order + * to six bits (and 2 low-order zeroes) per char little-endian format. + */ +#define TO_SIX_BIT(rslt, src) { \ + C_block cvt; \ + cvt.b[0] = (unsigned char)(src); (src) >>= 6; \ + cvt.b[1] = (unsigned char)(src); (src) >>= 6; \ + cvt.b[2] = (unsigned char)(src); (src) >>= 6; \ + cvt.b[3] = (unsigned char)(src); \ + (rslt) = (cvt.b32.i0 & 0x3f3f3f3fL) << 2; \ + } + +/* + * These macros may someday permit efficient use of 64-bit integers. + */ +#define ZERO(d,d0,d1) ((d0) = 0, (d1) = 0) +#define LOAD(d,d0,d1,bl) ((d0) = (bl).b32.i0, (d1) = (bl).b32.i1) +#define LOADREG(d,d0,d1,s,s0,s1) ((d0) = (s0), (d1) = (s1)) +#define OR(d,d0,d1,bl) ((d0) |= (bl).b32.i0, (d1) |= (bl).b32.i1) +#define STORE(s,s0,s1,bl) ((bl).b32.i0 = (s0), (bl).b32.i1 = (s1)) +#define DCL_BLOCK(d,d0,d1) long d0, d1 + +#if defined(LARGEDATA) + /* Waste memory like crazy. Also, do permutations in line */ +#define LGCHUNKBITS 3 +#define CHUNKBITS (1<<LGCHUNKBITS) +#define PERM6464(d,d0,d1,cpp,p) \ + LOAD((d),(d0),(d1),(p)[(0<<CHUNKBITS)+(cpp)[0]]); \ + OR ((d),(d0),(d1),(p)[(1<<CHUNKBITS)+(cpp)[1]]); \ + OR ((d),(d0),(d1),(p)[(2<<CHUNKBITS)+(cpp)[2]]); \ + OR ((d),(d0),(d1),(p)[(3<<CHUNKBITS)+(cpp)[3]]); \ + OR (d),(d0),(d1),(p)[(4<<CHUNKBITS)+(cpp)[4]]); \ + OR (d),(d0),(d1),(p)[(5<<CHUNKBITS)+(cpp)[5]]); \ + OR (d),(d0),(d1),(p)[(6<<CHUNKBITS)+(cpp)[6]]); \ + OR (d),(d0),(d1),(p)[(7<<CHUNKBITS)+(cpp)[7]]); +#define PERM3264(d,d0,d1,cpp,p) \ + LOAD((d),(d0),(d1),(p)[(0<<CHUNKBITS)+(cpp)[0]]); \ + OR ((d),(d0),(d1),(p)[(1<<CHUNKBITS)+(cpp)[1]]); \ + OR ((d),(d0),(d1),(p)[(2<<CHUNKBITS)+(cpp)[2]]); \ + OR ((d),(d0),(d1),(p)[(3<<CHUNKBITS)+(cpp)[3]]); +#else + /* "small data" */ +#define LGCHUNKBITS 2 +#define CHUNKBITS (1<<LGCHUNKBITS) +#define PERM6464(d,d0,d1,cpp,p) \ + { C_block tblk; permute((cpp),&tblk,(p),8); LOAD ((d),(d0),(d1),tblk); } +#define PERM3264(d,d0,d1,cpp,p) \ + { C_block tblk; permute((cpp),&tblk,(p),4); LOAD ((d),(d0),(d1),tblk); } + +STATIC void +permute(cp, out, p, chars_in) + unsigned char *cp; + C_block *out; + register C_block *p; + int chars_in; +{ + register DCL_BLOCK(D,D0,D1); + register C_block *tp; + register int t; + + ZERO(D,D0,D1); + do { + t = *cp++; + tp = &p[t&0xf]; OR(D,D0,D1,*tp); p += (1<<CHUNKBITS); + tp = &p[t>>4]; OR(D,D0,D1,*tp); p += (1<<CHUNKBITS); + } while (--chars_in > 0); + STORE(D,D0,D1,*out); +} +#endif /* LARGEDATA */ + + +/* ===== (mostly) Standard DES Tables ==================== */ + +static unsigned char IP[] = { /* initial permutation */ + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, +}; + +/* The final permutation is the inverse of IP - no table is necessary */ + +static unsigned char ExpandTr[] = { /* expansion operation */ + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1, +}; + +static unsigned char PC1[] = { /* permuted choice table 1 */ + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4, +}; + +static unsigned char Rotates[] = { /* PC1 rotation schedule */ + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, +}; + +/* note: each "row" of PC2 is left-padded with bits that make it invertible */ +static unsigned char PC2[] = { /* permuted choice table 2 */ + 9, 18, 14, 17, 11, 24, 1, 5, + 22, 25, 3, 28, 15, 6, 21, 10, + 35, 38, 23, 19, 12, 4, 26, 8, + 43, 54, 16, 7, 27, 20, 13, 2, + + 0, 0, 41, 52, 31, 37, 47, 55, + 0, 0, 30, 40, 51, 45, 33, 48, + 0, 0, 44, 49, 39, 56, 34, 53, + 0, 0, 46, 42, 50, 36, 29, 32, +}; + +static unsigned char S[8][64] = { /* 48->32 bit substitution tables */ + { + /* S[1] */ + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, + }, + { + /* S[2] */ + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, + }, + { + /* S[3] */ + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, + }, + { + /* S[4] */ + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, + }, + { + /* S[5] */ + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, + }, + { + /* S[6] */ + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, + }, + { + /* S[7] */ + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, + }, + { + /* S[8] */ + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11, + }, +}; + +static unsigned char P32Tr[] = { /* 32-bit permutation function */ + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25, +}; + +static unsigned char CIFP[] = { /* compressed/interleaved permutation */ + 1, 2, 3, 4, 17, 18, 19, 20, + 5, 6, 7, 8, 21, 22, 23, 24, + 9, 10, 11, 12, 25, 26, 27, 28, + 13, 14, 15, 16, 29, 30, 31, 32, + + 33, 34, 35, 36, 49, 50, 51, 52, + 37, 38, 39, 40, 53, 54, 55, 56, + 41, 42, 43, 44, 57, 58, 59, 60, + 45, 46, 47, 48, 61, 62, 63, 64, +}; + +static unsigned char itoa64[] = /* 0..63 => ascii-64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + +/* ===== Tables that are initialized at run time ==================== */ + + +static unsigned char a64toi[128]; /* ascii-64 => 0..63 */ + +/* Initial key schedule permutation */ +static C_block PC1ROT[64/CHUNKBITS][1<<CHUNKBITS]; + +/* Subsequent key schedule rotation permutations */ +static C_block PC2ROT[2][64/CHUNKBITS][1<<CHUNKBITS]; + +/* Initial permutation/expansion table */ +static C_block IE3264[32/CHUNKBITS][1<<CHUNKBITS]; + +/* Table that combines the S, P, and E operations. */ +static long SPE[2][8][64]; + +/* compressed/interleaved => final permutation table */ +static C_block CF6464[64/CHUNKBITS][1<<CHUNKBITS]; + + +/* ==================================== */ + + +static C_block constdatablock; /* encryption constant */ +static char cryptresult[1+4+4+11+1]; /* encrypted result */ + +/* + * Return a pointer to static data consisting of the "setting" + * followed by an encryption produced by the "key" and "setting". + */ +char * +crypt(key, setting) + register const char *key; + register const char *setting; +{ + register char *encp; + register long i; + register int t; + long salt; + int num_iter, salt_size; + C_block keyblock, rsltblock; + + for (i = 0; i < 8; i++) { + if ((t = 2*(unsigned char)(*key)) != 0) + key++; + keyblock.b[i] = t; + } + if (des_setkey((char *)keyblock.b)) /* also initializes "a64toi" */ + return (NULL); + + encp = &cryptresult[0]; + switch (*setting) { + case _PASSWORD_EFMT1: + /* + * Involve the rest of the password 8 characters at a time. + */ + while (*key) { + if (des_cipher((char *)&keyblock, + (char *)&keyblock, 0L, 1)) + return (NULL); + for (i = 0; i < 8; i++) { + if ((t = 2*(unsigned char)(*key)) != 0) + key++; + keyblock.b[i] ^= t; + } + if (des_setkey((char *)keyblock.b)) + return (NULL); + } + + *encp++ = *setting++; + + /* get iteration count */ + num_iter = 0; + for (i = 4; --i >= 0; ) { + if ((t = (unsigned char)setting[i]) == '\0') + t = '.'; + encp[i] = t; + num_iter = (num_iter<<6) | a64toi[t]; + } + setting += 4; + encp += 4; + salt_size = 4; + break; + default: + num_iter = 25; + salt_size = 2; + } + + salt = 0; + for (i = salt_size; --i >= 0; ) { + if ((t = (unsigned char)setting[i]) == '\0') + t = '.'; + encp[i] = t; + salt = (salt<<6) | a64toi[t]; + } + encp += salt_size; + if (des_cipher((char *)&constdatablock, (char *)&rsltblock, + salt, num_iter)) + return (NULL); + + /* + * Encode the 64 cipher bits as 11 ascii characters. + */ + i = ((long)((rsltblock.b[0]<<8) | rsltblock.b[1])<<8) | rsltblock.b[2]; + encp[3] = itoa64[i&0x3f]; i >>= 6; + encp[2] = itoa64[i&0x3f]; i >>= 6; + encp[1] = itoa64[i&0x3f]; i >>= 6; + encp[0] = itoa64[i]; encp += 4; + i = ((long)((rsltblock.b[3]<<8) | rsltblock.b[4])<<8) | rsltblock.b[5]; + encp[3] = itoa64[i&0x3f]; i >>= 6; + encp[2] = itoa64[i&0x3f]; i >>= 6; + encp[1] = itoa64[i&0x3f]; i >>= 6; + encp[0] = itoa64[i]; encp += 4; + i = ((long)((rsltblock.b[6])<<8) | rsltblock.b[7])<<2; + encp[2] = itoa64[i&0x3f]; i >>= 6; + encp[1] = itoa64[i&0x3f]; i >>= 6; + encp[0] = itoa64[i]; + + encp[3] = 0; + + return (cryptresult); +} + + +/* + * The Key Schedule, filled in by des_setkey() or setkey(). + */ +#define KS_SIZE 16 +static C_block KS[KS_SIZE]; + +/* + * Set up the key schedule from the key. + */ +int +des_setkey(key) + register const char *key; +{ + register DCL_BLOCK(K, K0, K1); + register C_block *ptabp; + register int i; + static int des_ready = 0; + + if (!des_ready) { + init_des(); + des_ready = 1; + } + + PERM6464(K,K0,K1,(unsigned char *)key,(C_block *)PC1ROT); + key = (char *)&KS[0]; + STORE(K&~0x03030303L, K0&~0x03030303L, K1, *(C_block *)key); + for (i = 1; i < 16; i++) { + key += sizeof(C_block); + STORE(K,K0,K1,*(C_block *)key); + ptabp = (C_block *)PC2ROT[Rotates[i]-1]; + PERM6464(K,K0,K1,(unsigned char *)key,ptabp); + STORE(K&~0x03030303L, K0&~0x03030303L, K1, *(C_block *)key); + } + return (0); +} + +/* + * Encrypt (or decrypt if num_iter < 0) the 8 chars at "in" with abs(num_iter) + * iterations of DES, using the given 24-bit salt and the pre-computed key + * schedule, and store the resulting 8 chars at "out" (in == out is permitted). + * + * NOTE: the performance of this routine is critically dependent on your + * compiler and machine architecture. + */ +int +des_cipher(in, out, salt, num_iter) + const char *in; + char *out; + long salt; + int num_iter; +{ + /* variables that we want in registers, most important first */ +#if defined(pdp11) + register int j; +#endif + register long L0, L1, R0, R1, k; + register C_block *kp; + register int ks_inc, loop_count; + C_block B; + + L0 = salt; + TO_SIX_BIT(salt, L0); /* convert to 4*(6+2) format */ + +#if defined(vax) || defined(pdp11) + salt = ~salt; /* "x &~ y" is faster than "x & y". */ +#define SALT (~salt) +#else +#define SALT salt +#endif + +#if defined(MUST_ALIGN) + B.b[0] = in[0]; B.b[1] = in[1]; B.b[2] = in[2]; B.b[3] = in[3]; + B.b[4] = in[4]; B.b[5] = in[5]; B.b[6] = in[6]; B.b[7] = in[7]; + LOAD(L,L0,L1,B); +#else + LOAD(L,L0,L1,*(C_block *)in); +#endif + LOADREG(R,R0,R1,L,L0,L1); + L0 &= 0x55555555L; + L1 &= 0x55555555L; + L0 = (L0 << 1) | L1; /* L0 is the even-numbered input bits */ + R0 &= 0xaaaaaaaaL; + R1 = (R1 >> 1) & 0x55555555L; + L1 = R0 | R1; /* L1 is the odd-numbered input bits */ + STORE(L,L0,L1,B); + PERM3264(L,L0,L1,B.b, (C_block *)IE3264); /* even bits */ + PERM3264(R,R0,R1,B.b+4,(C_block *)IE3264); /* odd bits */ + + if (num_iter >= 0) + { /* encryption */ + kp = &KS[0]; + ks_inc = (int)sizeof(*kp); + } + else + { /* decryption */ + num_iter = -num_iter; + kp = &KS[KS_SIZE-1]; + ks_inc = -(int)sizeof(*kp); + } + + while (--num_iter >= 0) { + loop_count = 8; + do { + +#define SPTAB(t, i) (*(long *)((unsigned char *)(t) + (i)*(sizeof(long)/4))) +#if defined(gould) + /* use this if B.b[i] is evaluated just once ... */ +#define DOXOR(x,y,i) (x)^=SPTAB(SPE[0][(i)],B.b[(i)]); (y)^=SPTAB(SPE[1][(i)],B.b[(i)]); +#else +#if defined(pdp11) + /* use this if your "long" int indexing is slow */ +#define DOXOR(x,y,i) j=B.b[(i)]; (x)^=SPTAB(SPE[0][(i)],j); (y)^=SPTAB(SPE[1][(i)],j); +#else + /* use this if "k" is allocated to a register ... */ +#define DOXOR(x,y,i) k=B.b[(i)]; (x)^=SPTAB(SPE[0][(i)],k); (y)^=SPTAB(SPE[1][(i)],k); +#endif +#endif + +#define CRUNCH(p0, p1, q0, q1) \ + k = ((q0) ^ (q1)) & SALT; \ + B.b32.i0 = k ^ (q0) ^ kp->b32.i0; \ + B.b32.i1 = k ^ (q1) ^ kp->b32.i1; \ + kp = (C_block *)((char *)kp+ks_inc); \ + \ + DOXOR((p0), (p1), 0); \ + DOXOR((p0), (p1), 1); \ + DOXOR((p0), (p1), 2); \ + DOXOR((p0), (p1), 3); \ + DOXOR((p0), (p1), 4); \ + DOXOR((p0), (p1), 5); \ + DOXOR((p0), (p1), 6); \ + DOXOR((p0), (p1), 7); + + CRUNCH(L0, L1, R0, R1); + CRUNCH(R0, R1, L0, L1); + } while (--loop_count != 0); + kp = (C_block *)((char *)kp-(ks_inc*KS_SIZE)); + + + /* swap L and R */ + L0 ^= R0; L1 ^= R1; + R0 ^= L0; R1 ^= L1; + L0 ^= R0; L1 ^= R1; + } + + /* store the encrypted (or decrypted) result */ + L0 = ((L0 >> 3) & 0x0f0f0f0fL) | ((L1 << 1) & 0xf0f0f0f0L); + L1 = ((R0 >> 3) & 0x0f0f0f0fL) | ((R1 << 1) & 0xf0f0f0f0L); + STORE(L,L0,L1,B); + PERM6464(L,L0,L1,B.b, (C_block *)CF6464); +#if defined(MUST_ALIGN) + STORE(L,L0,L1,B); + out[0] = B.b[0]; out[1] = B.b[1]; out[2] = B.b[2]; out[3] = B.b[3]; + out[4] = B.b[4]; out[5] = B.b[5]; out[6] = B.b[6]; out[7] = B.b[7]; +#else + STORE(L,L0,L1,*(C_block *)out); +#endif + return (0); +} + + +/* + * Initialize various tables. This need only be done once. It could even be + * done at compile time, if the compiler were capable of that sort of thing. + */ +STATIC void +init_des() +{ + register int i, j; + register long k; + register int tableno; + static unsigned char perm[64], tmp32[32]; /* "static" for speed */ + + /* + * table that converts chars "./0-9A-Za-z"to integers 0-63. + */ + for (i = 0; i < 64; i++) + a64toi[itoa64[i]] = i; + + /* + * PC1ROT - bit reverse, then PC1, then Rotate, then PC2. + */ + for (i = 0; i < 64; i++) + perm[i] = 0; + for (i = 0; i < 64; i++) { + if ((k = PC2[i]) == 0) + continue; + k += Rotates[0]-1; + if ((k%28) < Rotates[0]) k -= 28; + k = PC1[k]; + if (k > 0) { + k--; + k = (k|07) - (k&07); + k++; + } + perm[i] = (unsigned char)k; + } +#ifdef DEBUG + prtab("pc1tab", perm, 8); +#endif + init_perm(PC1ROT, perm, 8, 8); + + /* + * PC2ROT - PC2 inverse, then Rotate (once or twice), then PC2. + */ + for (j = 0; j < 2; j++) { + unsigned char pc2inv[64]; + for (i = 0; i < 64; i++) + perm[i] = pc2inv[i] = 0; + for (i = 0; i < 64; i++) { + if ((k = PC2[i]) == 0) + continue; + pc2inv[k-1] = i+1; + } + for (i = 0; i < 64; i++) { + if ((k = PC2[i]) == 0) + continue; + k += j; + if ((k%28) <= j) k -= 28; + perm[i] = pc2inv[k]; + } +#ifdef DEBUG + prtab("pc2tab", perm, 8); +#endif + init_perm(PC2ROT[j], perm, 8, 8); + } + + /* + * Bit reverse, then initial permutation, then expansion. + */ + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + k = (j < 2)? 0: IP[ExpandTr[i*6+j-2]-1]; + if (k > 32) + k -= 32; + else if (k > 0) + k--; + if (k > 0) { + k--; + k = (k|07) - (k&07); + k++; + } + perm[i*8+j] = (unsigned char)k; + } + } +#ifdef DEBUG + prtab("ietab", perm, 8); +#endif + init_perm(IE3264, perm, 4, 8); + + /* + * Compression, then final permutation, then bit reverse. + */ + for (i = 0; i < 64; i++) { + k = IP[CIFP[i]-1]; + if (k > 0) { + k--; + k = (k|07) - (k&07); + k++; + } + perm[k-1] = i+1; + } +#ifdef DEBUG + prtab("cftab", perm, 8); +#endif + init_perm(CF6464, perm, 8, 8); + + /* + * SPE table + */ + for (i = 0; i < 48; i++) + perm[i] = P32Tr[ExpandTr[i]-1]; + for (tableno = 0; tableno < 8; tableno++) { + for (j = 0; j < 64; j++) { + k = (((j >> 0) &01) << 5)| + (((j >> 1) &01) << 3)| + (((j >> 2) &01) << 2)| + (((j >> 3) &01) << 1)| + (((j >> 4) &01) << 0)| + (((j >> 5) &01) << 4); + k = S[tableno][k]; + k = (((k >> 3)&01) << 0)| + (((k >> 2)&01) << 1)| + (((k >> 1)&01) << 2)| + (((k >> 0)&01) << 3); + for (i = 0; i < 32; i++) + tmp32[i] = 0; + for (i = 0; i < 4; i++) + tmp32[4 * tableno + i] = (unsigned char)(k >> i) & 01; + k = 0; + for (i = 24; --i >= 0; ) + k = (k<<1) | tmp32[perm[i]-1]; + TO_SIX_BIT(SPE[0][tableno][j], k); + k = 0; + for (i = 24; --i >= 0; ) + k = (k<<1) | tmp32[perm[i+24]-1]; + TO_SIX_BIT(SPE[1][tableno][j], k); + } + } +} + +/* + * Initialize "perm" to represent transformation "p", which rearranges + * (perhaps with expansion and/or contraction) one packed array of bits + * (of size "chars_in" characters) into another array (of size "chars_out" + * characters). + * + * "perm" must be all-zeroes on entry to this routine. + */ +STATIC void +init_perm(perm, p, chars_in, chars_out) + C_block perm[64/CHUNKBITS][1<<CHUNKBITS]; + unsigned char p[64]; + int chars_in, chars_out; +{ + register int i, j, k, l; + + for (k = 0; k < chars_out*8; k++) { /* each output bit position */ + l = p[k] - 1; /* where this bit comes from */ + if (l < 0) + continue; /* output bit is always 0 */ + i = l>>LGCHUNKBITS; /* which chunk this bit comes from */ + l = 1<<(l&(CHUNKBITS-1)); /* mask for this bit */ + for (j = 0; j < (1<<CHUNKBITS); j++) { /* each chunk value */ + if ((j & l) != 0) + perm[i][j].b[k>>3] |= 1<<(k&07); + } + } +} + +/* + * "setkey" routine (for backwards compatibility) + */ +int +setkey(key) + register const char *key; +{ + register int i, j, k; + C_block keyblock; + + for (i = 0; i < 8; i++) { + k = 0; + for (j = 0; j < 8; j++) { + k <<= 1; + k |= (unsigned char)*key++; + } + keyblock.b[i] = k; + } + return (des_setkey((char *)keyblock.b)); +} + +/* + * "encrypt" routine (for backwards compatibility) + */ +int +encrypt(block, flag) + register char *block; + int flag; +{ + register int i, j, k; + C_block cblock; + + for (i = 0; i < 8; i++) { + k = 0; + for (j = 0; j < 8; j++) { + k <<= 1; + k |= (unsigned char)*block++; + } + cblock.b[i] = k; + } + if (des_cipher((char *)&cblock, (char *)&cblock, 0L, (flag ? -1: 1))) + return (1); + for (i = 7; i >= 0; i--) { + k = cblock.b[i]; + for (j = 7; j >= 0; j--) { + *--block = k&01; + k >>= 1; + } + } + return (0); +} + +#ifdef DEBUG +STATIC void +prtab(s, t, num_rows) + char *s; + unsigned char *t; + int num_rows; +{ + register int i, j; + + (void)printf("%s:\n", s); + for (i = 0; i < num_rows; i++) { + for (j = 0; j < 8; j++) { + (void)printf("%3d", t[i*8+j]); + } + (void)printf("\n"); + } + (void)printf("\n"); +} +#endif diff --git a/jni/ruby/missing/dup2.c b/jni/ruby/missing/dup2.c new file mode 100644 index 0000000..7554084 --- /dev/null +++ b/jni/ruby/missing/dup2.c @@ -0,0 +1,60 @@ +/* + * Public domain dup2() lookalike + * by Curtis Jackson @ AT&T Technologies, Burlington, NC + * electronic address: burl!rcj + * + * dup2 performs the following functions: + * + * Check to make sure that fd1 is a valid open file descriptor. + * Check to see if fd2 is already open; if so, close it. + * Duplicate fd1 onto fd2; checking to make sure fd2 is a valid fd. + * Return fd2 if all went well; return BADEXIT otherwise. + */ + +#include "ruby/config.h" + +#if defined(HAVE_FCNTL) +# include <fcntl.h> +#endif + +#if !defined(HAVE_FCNTL) || !defined(F_DUPFD) +# include <errno.h> +#endif + +#define BADEXIT -1 + +int +dup2(int fd1, int fd2) +{ +#if defined(HAVE_FCNTL) && defined(F_DUPFD) + if (fd1 != fd2) { +#ifdef F_GETFL + if (fcntl(fd1, F_GETFL) < 0) + return BADEXIT; + if (fcntl(fd2, F_GETFL) >= 0) + close(fd2); +#else + close(fd2); +#endif + if (fcntl(fd1, F_DUPFD, fd2) < 0) + return BADEXIT; + } + return fd2; +#else + extern int errno; + int i, fd, fds[256]; + + if (fd1 == fd2) return 0; + close(fd2); + for (i=0; i<256; i++) { + fd = fds[i] = dup(fd1); + if (fd == fd2) break; + } + while (i) { + close(fds[i--]); + } + if (fd == fd2) return 0; + errno = EMFILE; + return BADEXIT; +#endif +} diff --git a/jni/ruby/missing/erf.c b/jni/ruby/missing/erf.c new file mode 100644 index 0000000..d72c4ea --- /dev/null +++ b/jni/ruby/missing/erf.c @@ -0,0 +1,89 @@ +/* erf.c - public domain implementation of error function erf(3m) + +reference - Haruhiko Okumura: C-gengo niyoru saishin algorithm jiten + (New Algorithm handbook in C language) (Gijyutsu hyouron + sha, Tokyo, 1991) p.227 [in Japanese] */ +#include "ruby/missing.h" +#include <stdio.h> +#include <math.h> + +#ifdef _WIN32 +# include <float.h> +# if !defined __MINGW32__ || defined __NO_ISOCEXT +# ifndef isnan +# define isnan(x) _isnan(x) +# endif +# ifndef isinf +# define isinf(x) (!_finite(x) && !_isnan(x)) +# endif +# ifndef finite +# define finite(x) _finite(x) +# endif +# endif +#endif + +static double q_gamma(double, double, double); + +/* Incomplete gamma function + 1 / Gamma(a) * Int_0^x exp(-t) t^(a-1) dt */ +static double p_gamma(double a, double x, double loggamma_a) +{ + int k; + double result, term, previous; + + if (x >= 1 + a) return 1 - q_gamma(a, x, loggamma_a); + if (x == 0) return 0; + result = term = exp(a * log(x) - x - loggamma_a) / a; + for (k = 1; k < 1000; k++) { + term *= x / (a + k); + previous = result; result += term; + if (result == previous) return result; + } + fprintf(stderr, "erf.c:%d:p_gamma() could not converge.", __LINE__); + return result; +} + +/* Incomplete gamma function + 1 / Gamma(a) * Int_x^inf exp(-t) t^(a-1) dt */ +static double q_gamma(double a, double x, double loggamma_a) +{ + int k; + double result, w, temp, previous; + double la = 1, lb = 1 + x - a; /* Laguerre polynomial */ + + if (x < 1 + a) return 1 - p_gamma(a, x, loggamma_a); + w = exp(a * log(x) - x - loggamma_a); + result = w / lb; + for (k = 2; k < 1000; k++) { + temp = ((k - 1 - a) * (lb - la) + (k + x) * lb) / k; + la = lb; lb = temp; + w *= (k - 1 - a) / k; + temp = w / (la * lb); + previous = result; result += temp; + if (result == previous) return result; + } + fprintf(stderr, "erf.c:%d:q_gamma() could not converge.", __LINE__); + return result; +} + +#define LOG_PI_OVER_2 0.572364942924700087071713675675 /* log_e(PI)/2 */ + +double erf(double x) +{ + if (!finite(x)) { + if (isnan(x)) return x; /* erf(NaN) = NaN */ + return (x>0 ? 1.0 : -1.0); /* erf(+-inf) = +-1.0 */ + } + if (x >= 0) return p_gamma(0.5, x * x, LOG_PI_OVER_2); + else return - p_gamma(0.5, x * x, LOG_PI_OVER_2); +} + +double erfc(double x) +{ + if (!finite(x)) { + if (isnan(x)) return x; /* erfc(NaN) = NaN */ + return (x>0 ? 0.0 : 2.0); /* erfc(+-inf) = 0.0, 2.0 */ + } + if (x >= 0) return q_gamma(0.5, x * x, LOG_PI_OVER_2); + else return 1 + p_gamma(0.5, x * x, LOG_PI_OVER_2); +} diff --git a/jni/ruby/missing/ffs.c b/jni/ruby/missing/ffs.c new file mode 100644 index 0000000..bad99cf --- /dev/null +++ b/jni/ruby/missing/ffs.c @@ -0,0 +1,49 @@ +/* ffs.c - find first set bit */ +/* ffs() is defined by Single Unix Specification. */ + +#include "ruby.h" + +int ffs(int arg) +{ + unsigned int x = (unsigned int)arg; + int r; + + if (x == 0) + return 0; + + r = 1; + +#if 32 < SIZEOF_INT * CHAR_BIT + if ((x & 0xffffffff) == 0) { + x >>= 32; + r += 32; + } +#endif + + if ((x & 0xffff) == 0) { + x >>= 16; + r += 16; + } + + if ((x & 0xff) == 0) { + x >>= 8; + r += 8; + } + + if ((x & 0xf) == 0) { + x >>= 4; + r += 4; + } + + if ((x & 0x3) == 0) { + x >>= 2; + r += 2; + } + + if ((x & 0x1) == 0) { + x >>= 1; + r += 1; + } + + return r; +} diff --git a/jni/ruby/missing/file.h b/jni/ruby/missing/file.h new file mode 100644 index 0000000..241d716 --- /dev/null +++ b/jni/ruby/missing/file.h @@ -0,0 +1,22 @@ +/* This is file FILE.H */ + +#ifndef _FILE_H_ +#define _FILE_H_ + +#include <fcntl.h> + +#ifndef L_SET +# define L_SET 0 /* seek from beginning. */ +# define L_CURR 1 /* seek from current position. */ +# define L_INCR 1 /* ditto. */ +# define L_XTND 2 /* seek from end. */ +#endif + +#ifndef R_OK +# define R_OK 4 /* test whether readable. */ +# define W_OK 2 /* test whether writable. */ +# define X_OK 1 /* test whether executable. */ +# define F_OK 0 /* test whether exist. */ +#endif + +#endif diff --git a/jni/ruby/missing/fileblocks.c b/jni/ruby/missing/fileblocks.c new file mode 100644 index 0000000..ccb8d66 --- /dev/null +++ b/jni/ruby/missing/fileblocks.c @@ -0,0 +1 @@ +/* dummy for autoconf */ diff --git a/jni/ruby/missing/finite.c b/jni/ruby/missing/finite.c new file mode 100644 index 0000000..ab76863 --- /dev/null +++ b/jni/ruby/missing/finite.c @@ -0,0 +1,9 @@ +/* public domain rewrite of finite(3) */ + +#include "ruby/missing.h" + +int +finite(double n) +{ + return !isnan(n) && !isinf(n); +} diff --git a/jni/ruby/missing/flock.c b/jni/ruby/missing/flock.c new file mode 100644 index 0000000..829f431 --- /dev/null +++ b/jni/ruby/missing/flock.c @@ -0,0 +1,130 @@ +#include "ruby/config.h" +#include "ruby/ruby.h" + +#if defined _WIN32 +#elif defined HAVE_FCNTL && defined HAVE_FCNTL_H && !defined(__native_client__) + +/* These are the flock() constants. Since this systems doesn't have + flock(), the values of the constants are probably not available. +*/ +# ifndef LOCK_SH +# define LOCK_SH 1 +# endif +# ifndef LOCK_EX +# define LOCK_EX 2 +# endif +# ifndef LOCK_NB +# define LOCK_NB 4 +# endif +# ifndef LOCK_UN +# define LOCK_UN 8 +# endif + +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +int +flock(int fd, int operation) +{ + struct flock lock; + + switch (operation & ~LOCK_NB) { + case LOCK_SH: + lock.l_type = F_RDLCK; + break; + case LOCK_EX: + lock.l_type = F_WRLCK; + break; + case LOCK_UN: + lock.l_type = F_UNLCK; + break; + default: + errno = EINVAL; + return -1; + } + lock.l_whence = SEEK_SET; + lock.l_start = lock.l_len = 0L; + + return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lock); +} + +#elif defined(HAVE_LOCKF) + +#include <unistd.h> +#include <errno.h> + +/* Emulate flock() with lockf() or fcntl(). This is just to increase + portability of scripts. The calls might not be completely + interchangeable. What's really needed is a good file + locking module. +*/ + +# ifndef F_ULOCK +# define F_ULOCK 0 /* Unlock a previously locked region */ +# endif +# ifndef F_LOCK +# define F_LOCK 1 /* Lock a region for exclusive use */ +# endif +# ifndef F_TLOCK +# define F_TLOCK 2 /* Test and lock a region for exclusive use */ +# endif +# ifndef F_TEST +# define F_TEST 3 /* Test a region for other processes locks */ +# endif + +/* These are the flock() constants. Since this systems doesn't have + flock(), the values of the constants are probably not available. +*/ +# ifndef LOCK_SH +# define LOCK_SH 1 +# endif +# ifndef LOCK_EX +# define LOCK_EX 2 +# endif +# ifndef LOCK_NB +# define LOCK_NB 4 +# endif +# ifndef LOCK_UN +# define LOCK_UN 8 +# endif + +int +flock(int fd, int operation) +{ + switch (operation) { + + /* LOCK_SH - get a shared lock */ + case LOCK_SH: + rb_notimplement(); + return -1; + /* LOCK_EX - get an exclusive lock */ + case LOCK_EX: + return lockf (fd, F_LOCK, 0); + + /* LOCK_SH|LOCK_NB - get a non-blocking shared lock */ + case LOCK_SH|LOCK_NB: + rb_notimplement(); + return -1; + /* LOCK_EX|LOCK_NB - get a non-blocking exclusive lock */ + case LOCK_EX|LOCK_NB: + return lockf (fd, F_TLOCK, 0); + + /* LOCK_UN - unlock */ + case LOCK_UN: + return lockf (fd, F_ULOCK, 0); + + /* Default - can't decipher operation */ + default: + errno = EINVAL; + return -1; + } +} +#else +int +flock(int fd, int operation) +{ + rb_notimplement(); + return -1; +} +#endif diff --git a/jni/ruby/missing/hypot.c b/jni/ruby/missing/hypot.c new file mode 100644 index 0000000..765581b --- /dev/null +++ b/jni/ruby/missing/hypot.c @@ -0,0 +1,17 @@ +/* public domain rewrite of hypot */ + +#include "ruby/missing.h" +#include <math.h> + +double hypot(double x, double y) +{ + if (x < 0) x = -x; + if (y < 0) y = -y; + if (x < y) { + double tmp = x; + x = y; y = tmp; + } + if (y == 0.0) return x; + y /= x; + return x * sqrt(1.0+y*y); +} diff --git a/jni/ruby/missing/isinf.c b/jni/ruby/missing/isinf.c new file mode 100644 index 0000000..55187ad --- /dev/null +++ b/jni/ruby/missing/isinf.c @@ -0,0 +1,69 @@ +/* public domain rewrite of isinf(3) */ + +#ifdef __osf__ + +#define _IEEE 1 +#include <nan.h> + +int +isinf(double n) +{ + if (IsNANorINF(n) && IsINF(n)) { + return 1; + } + else { + return 0; + } +} + +#else + +#include "ruby/config.h" + +#if defined(HAVE_FINITE) && defined(HAVE_ISNAN) + +#include <math.h> +#ifdef HAVE_IEEEFP_H +#include <ieeefp.h> +#endif + +/* + * isinf may be provided only as a macro. + * ex. HP-UX, Solaris 10 + * http://www.gnu.org/software/automake/manual/autoconf/Function-Portability.html + */ +#ifndef isinf +int +isinf(double n) +{ + return (!finite(n) && !isnan(n)); +} +#endif + +#else + +#ifdef HAVE_STRING_H +# include <string.h> +#else +# include <strings.h> +#endif + +static double zero(void) { return 0.0; } +static double one (void) { return 1.0; } +static double inf (void) { return one() / zero(); } + +int +isinf(double n) +{ + static double pinf = 0.0; + static double ninf = 0.0; + + if (pinf == 0.0) { + pinf = inf(); + ninf = -pinf; + } + return memcmp(&n, &pinf, sizeof n) == 0 + || memcmp(&n, &ninf, sizeof n) == 0; +} +#endif +#endif diff --git a/jni/ruby/missing/isnan.c b/jni/ruby/missing/isnan.c new file mode 100644 index 0000000..ed10bf5 --- /dev/null +++ b/jni/ruby/missing/isnan.c @@ -0,0 +1,32 @@ +/* public domain rewrite of isnan(3) */ + +#include "ruby/missing.h" + +/* + * isnan() may be a macro, a function or both. + * (The C99 standard defines that isnan() is a macro, though.) + * http://www.gnu.org/software/automake/manual/autoconf/Function-Portability.html + * + * macro only: uClibc + * both: GNU libc + * + * This file is compile if no isnan() function is available. + * (autoconf AC_REPLACE_FUNCS detects only the function.) + * The macro is detected by following #ifndef. + */ + +#ifndef isnan +static int double_ne(double n1, double n2); + +int +isnan(double n) +{ + return double_ne(n, n); +} + +static int +double_ne(double n1, double n2) +{ + return n1 != n2; +} +#endif diff --git a/jni/ruby/missing/langinfo.c b/jni/ruby/missing/langinfo.c new file mode 100644 index 0000000..9ba06b1 --- /dev/null +++ b/jni/ruby/missing/langinfo.c @@ -0,0 +1,148 @@ +/* -*- c-file-style: "gnu" -*- */ +/* + * This is a quick-and-dirty emulator of the nl_langinfo(CODESET) + * function defined in the Single Unix Specification for those systems + * (FreeBSD, etc.) that don't have one yet. It behaves as if it had + * been called after setlocale(LC_CTYPE, ""), that is it looks at + * the locale environment variables. + * + * http://www.opengroup.org/onlinepubs/7908799/xsh/langinfo.h.html + * + * Please extend it as needed and suggest improvements to the author. + * This emulator will hopefully become redundant soon as + * nl_langinfo(CODESET) becomes more widely implemented. + * + * Since the proposed Li18nux encoding name registry is still not mature, + * the output follows the MIME registry where possible: + * + * http://www.iana.org/assignments/character-sets + * + * A possible autoconf test for the availability of nl_langinfo(CODESET) + * can be found in + * + * http://www.cl.cam.ac.uk/~mgk25/unicode.html#activate + * + * Markus.Kuhn@cl.cam.ac.uk -- 2002-03-11 + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted. The author + * disclaims all warranties with regard to this software. + * + * Latest version: + * + * http://www.cl.cam.ac.uk/~mgk25/ucs/langinfo.c + */ + +#include "ruby/missing.h" +#include <stdlib.h> +#include <string.h> +#if defined _WIN32 || defined __CYGWIN__ +#include <windows.h> +#if defined _WIN32 && !defined strncasecmp +#define strncasecmp strnicmp +#endif +#endif +#ifdef HAVE_LANGINFO_H +#include "langinfo.h" +#endif + +#define C_CODESET "US-ASCII" /* Return this as the encoding of the + * C/POSIX locale. Could as well one day + * become "UTF-8". */ + +#if defined _WIN32 || defined __CYGWIN__ +#define JA_CODESET "Windows-31J" +#else +#define JA_CODESET "EUC-JP" +#endif + +#define digit(x) ((x) >= '0' && (x) <= '9') +#define strstart(s, n) (strncasecmp((s), (n), strlen(n)) == 0) + +static char buf[16]; + +const char * +nl_langinfo_codeset(void) +{ + const char *l, *p; + int n; + + if (((l = getenv("LC_ALL")) && *l) || + ((l = getenv("LC_CTYPE")) && *l) || + ((l = getenv("LANG")) && *l)) { + /* check standardized locales */ + if (!strcmp(l, "C") || !strcmp(l, "POSIX")) + return C_CODESET; + /* check for encoding name fragment */ + p = strchr(l, '.'); + if (!p++) p = l; + if (strstart(p, "UTF")) + return "UTF-8"; + if ((n = 5, strstart(p, "8859-")) || (n = 9, strstart(p, "ISO-8859-"))) { + if (digit(p[n])) { + p += n; + memcpy(buf, "ISO-8859-\0\0", 12); + buf[9] = *p++; + if (digit(*p)) buf[10] = *p++; + return buf; + } + } + if (strstart(p, "KOI8-R")) return "KOI8-R"; + if (strstart(p, "KOI8-U")) return "KOI8-U"; + if (strstart(p, "620")) return "TIS-620"; + if (strstart(p, "2312")) return "GB2312"; + if (strstart(p, "HKSCS")) return "Big5HKSCS"; /* no MIME charset */ + if (strstart(p, "BIG5")) return "Big5"; + if (strstart(p, "GBK")) return "GBK"; /* no MIME charset */ + if (strstart(p, "18030")) return "GB18030"; /* no MIME charset */ + if (strstart(p, "Shift_JIS") || strstart(p, "SJIS")) return "Windows-31J"; + /* check for conclusive modifier */ + if (strstart(p, "euro")) return "ISO-8859-15"; + /* check for language (and perhaps country) codes */ + if (strstart(l, "zh_TW")) return "Big5"; + if (strstart(l, "zh_HK")) return "Big5HKSCS"; /* no MIME charset */ + if (strstart(l, "zh")) return "GB2312"; + if (strstart(l, "ja")) return JA_CODESET; + if (strstart(l, "ko")) return "EUC-KR"; + if (strstart(l, "ru")) return "KOI8-R"; + if (strstart(l, "uk")) return "KOI8-U"; + if (strstart(l, "pl") || strstart(l, "hr") || + strstart(l, "hu") || strstart(l, "cs") || + strstart(l, "sk") || strstart(l, "sl")) return "ISO-8859-2"; + if (strstart(l, "eo") || strstart(l, "mt")) return "ISO-8859-3"; + if (strstart(l, "el")) return "ISO-8859-7"; + if (strstart(l, "he")) return "ISO-8859-8"; + if (strstart(l, "tr")) return "ISO-8859-9"; + if (strstart(l, "th")) return "TIS-620"; /* or ISO-8859-11 */ + if (strstart(l, "lt")) return "ISO-8859-13"; + if (strstart(l, "cy")) return "ISO-8859-14"; + if (strstart(l, "ro")) return "ISO-8859-2"; /* or ISO-8859-16 */ + if (strstart(l, "am") || strstart(l, "vi")) return "UTF-8"; + /* Send me further rules if you like, but don't forget that we are + * *only* interested in locale naming conventions on platforms + * that do not already provide an nl_langinfo(CODESET) implementation. */ + } + return NULL; +} + +#ifdef HAVE_LANGINFO_H +char *nl_langinfo(nl_item item) +{ + const char *codeset; + if (item != CODESET) + return NULL; + codeset = nl_langinfo_codeset(); + if (!codeset) codeset = C_CODESET; + return (char *)codeset; +} +#endif + +/* For a demo, compile with "gcc -W -Wall -o langinfo -D TEST langinfo.c" */ + +#ifdef TEST +#include <stdio.h> +int main() +{ + printf("%s\n", nl_langinfo(CODESET)); + return 0; +} +#endif diff --git a/jni/ruby/missing/lgamma_r.c b/jni/ruby/missing/lgamma_r.c new file mode 100644 index 0000000..6d2f38f --- /dev/null +++ b/jni/ruby/missing/lgamma_r.c @@ -0,0 +1,80 @@ +/* lgamma_r.c - public domain implementation of function lgamma_r(3m) + +lgamma_r() is based on gamma(). modified by Tanaka Akira. + +reference - Haruhiko Okumura: C-gengo niyoru saishin algorithm jiten + (New Algorithm handbook in C language) (Gijyutsu hyouron + sha, Tokyo, 1991) [in Japanese] + http://oku.edu.mie-u.ac.jp/~okumura/algo/ +*/ + +#include "ruby/missing.h" +/*********************************************************** + gamma.c -- Gamma function +***********************************************************/ +#include <math.h> +#include <errno.h> +#define PI 3.14159265358979324 /* $\pi$ */ +#define LOG_2PI 1.83787706640934548 /* $\log 2\pi$ */ +#define LOG_PI 1.14472988584940017 /* $\log_e \pi$ */ +#define N 8 + +#define B0 1 /* Bernoulli numbers */ +#define B1 (-1.0 / 2.0) +#define B2 ( 1.0 / 6.0) +#define B4 (-1.0 / 30.0) +#define B6 ( 1.0 / 42.0) +#define B8 (-1.0 / 30.0) +#define B10 ( 5.0 / 66.0) +#define B12 (-691.0 / 2730.0) +#define B14 ( 7.0 / 6.0) +#define B16 (-3617.0 / 510.0) + +static double +loggamma(double x) /* the natural logarithm of the Gamma function. */ +{ + double v, w; + + if (x == 1.0 || x == 2.0) return 0.0; + + v = 1; + while (x < N) { v *= x; x++; } + w = 1 / (x * x); + return ((((((((B16 / (16 * 15)) * w + (B14 / (14 * 13))) * w + + (B12 / (12 * 11))) * w + (B10 / (10 * 9))) * w + + (B8 / ( 8 * 7))) * w + (B6 / ( 6 * 5))) * w + + (B4 / ( 4 * 3))) * w + (B2 / ( 2 * 1))) / x + + 0.5 * LOG_2PI - log(v) - x + (x - 0.5) * log(x); +} + + +#ifdef __MINGW_ATTRIB_PURE +/* get rid of bugs in math.h of mingw */ +#define modf(_X, _Y) __extension__ ({\ + double intpart_modf_bug = intpart_modf_bug;\ + double result_modf_bug = modf((_X), &intpart_modf_bug);\ + *(_Y) = intpart_modf_bug;\ + result_modf_bug;\ +}) +#endif + +/* the natural logarithm of the absolute value of the Gamma function */ +double +lgamma_r(double x, int *signp) +{ + if (x <= 0) { + double i, f, s; + f = modf(-x, &i); + if (f == 0.0) { /* pole error */ + *signp = 1; + errno = ERANGE; + return HUGE_VAL; + } + *signp = (fmod(i, 2.0) != 0.0) ? 1 : -1; + s = sin(PI * f); + if (s < 0) s = -s; + return LOG_PI - log(s) - loggamma(1 - x); + } + *signp = 1; + return loggamma(x); +} diff --git a/jni/ruby/missing/memcmp.c b/jni/ruby/missing/memcmp.c new file mode 100644 index 0000000..a81eec4 --- /dev/null +++ b/jni/ruby/missing/memcmp.c @@ -0,0 +1,18 @@ +/* public domain rewrite of memcmp(3) */ + +#include "ruby/missing.h" +#include <stddef.h> + +int +memcmp(const void *s1, const void *s2, size_t len) +{ + register unsigned char *a = (unsigned char*)s1; + register unsigned char *b = (unsigned char*)s2; + register int tmp; + + for (; len; --len) { + if (tmp = *a++ - *b++) + return tmp; + } + return 0; +} diff --git a/jni/ruby/missing/memmove.c b/jni/ruby/missing/memmove.c new file mode 100644 index 0000000..e8e17e8 --- /dev/null +++ b/jni/ruby/missing/memmove.c @@ -0,0 +1,22 @@ +/* public domain rewrite of memcmp(3) */ + +#include "ruby/missing.h" +#include <stddef.h> + +void * +memmove(void *d, const void *s, size_t n) +{ + char *dst = (char *)d; + const char *src = (const char *)s; + + if (src < dst) { + src += n; + dst += n; + for (; n; --n) + *--dst = *--src; + } + else if (dst < src) + for (; n; --n) + *dst++ = *src++; + return d; +} diff --git a/jni/ruby/missing/nextafter.c b/jni/ruby/missing/nextafter.c new file mode 100644 index 0000000..dd1f1f2 --- /dev/null +++ b/jni/ruby/missing/nextafter.c @@ -0,0 +1,77 @@ +#include "ruby/missing.h" + +#include <math.h> +#include <float.h> + +/* This function doesn't set errno. It should on POSIX, though. */ + +double +nextafter(double x, double y) +{ + double x1, x2, d; + int e; + + if (isnan(x)) + return x; + if (isnan(y)) + return y; + + if (x == y) + return y; + + if (x == 0) { + /* the minimum "subnormal" float */ + x1 = ldexp(0.5, DBL_MIN_EXP - DBL_MANT_DIG + 1); + if (x1 == 0) + x1 = DBL_MIN; /* the minimum "normal" float */ + if (0 < y) + return x1; + else + return -x1; + } + + if (x < 0) { + if (isinf(x)) + return -DBL_MAX; + if (x == -DBL_MAX && y < 0 && isinf(y)) + return y; + } + else { + if (isinf(x)) + return DBL_MAX; + if (x == DBL_MAX && 0 < y && isinf(y)) + return y; + } + + x1 = frexp(x, &e); + + if (x < y) { + d = DBL_EPSILON/2; + if (x1 == -0.5) { + x1 *= 2; + e--; + } + } + else { + d = -DBL_EPSILON/2; + if (x1 == 0.5) { + x1 *= 2; + e--; + } + } + + if (e < DBL_MIN_EXP) { + d = ldexp(d, DBL_MIN_EXP-e); + } + + x2 = x1 + d; + + if (x2 == 0.0) { + if (x1 < 0) + return -0.0; + else + return +0.0; + } + + return ldexp(x2, e); +} diff --git a/jni/ruby/missing/os2.c b/jni/ruby/missing/os2.c new file mode 100644 index 0000000..27dc2f1 --- /dev/null +++ b/jni/ruby/missing/os2.c @@ -0,0 +1,138 @@ +/* os/2 compatibility functions -- follows Ruby's license */ + +#include "ruby.h" +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <process.h> +#include <limits.h> +#include <errno.h> + +#define INCL_DOS +#include <os2.h> + +int +chown(char *path, int owner, int group) +{ + return 0; +} + +#if 0 +int +link(char *from, char *to) +{ + return -1; +} +#endif + +#if defined(EMX_REPLACE_GETCWD) && (EMX_REPLACE_GETCWD) \ + || defined(EMX_REPLACE_CHDIR) && (EMX_REPLACE_CHDIR) +#include <unistd.h> + +#if defined(EMX_REPLACE_GETCWD) && (EMX_REPLACE_GETCWD) +/* to handle the drive letter and DBCS characters within a given path */ +char * +getcwd(char *path, size_t len) +{ + return _getcwd2(path, (int)len); +} +#endif + +#if defined(EMX_REPLACE_CHDIR) && (EMX_REPLACE_CHDIR) +/* to handle the drive letter and DBCS characters within a given path */ +int +chdir(__const__ char *path) +{ + return _chdir2(path); +} +#endif +#endif + +typedef char* CHARP; + +int +do_spawn(cmd) +char *cmd; +{ + register char **a; + register char *s; + char **argv; + char *shell, *sw, *cmd2; + int status; + + if ((shell = getenv("RUBYSHELL")) != NULL && *shell != '\0') { + s = shell; + do + *s = isupper(*s) ? tolower(*s) : *s; + while (*++s); + if (strstr(shell, "cmd") || strstr(shell, "4os2")) + sw = "/c"; + else + sw = "-c"; + } else if ((shell = getenv("SHELL")) != NULL && *shell != '\0') { + s = shell; + do + *s = isupper(*s) ? tolower(*s) : *s; + while (*++s); + if (strstr(shell, "cmd") || strstr(shell, "4os2")) + sw = "/c"; + else + sw = "-c"; + } else if ((shell = getenv("COMSPEC")) != NULL && *shell != '\0') { + s = shell; + do + *s = isupper(*s) ? tolower(*s) : *s; + while (*++s); + if (strstr(shell, "cmd") || strstr(shell, "4os2")) + sw = "/c"; + else + sw = "-c"; + } + /* see if there are shell metacharacters in it */ + /*SUPPRESS 530*/ + /* for (s = cmd; *s && isalpha(*s); s++) ; + if (*s == '=') + goto doshell; */ + for (s = cmd; *s; s++) { + if (*sw == '-' && *s != ' ' && + !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) { + if (*s == '\n' && !s[1]) { + *s = '\0'; + break; + } + goto doshell; + } else if (*sw == '/' && *s != ' ' && + !isalpha(*s) && index("^()<>|&\n",*s)) { + if (*s == '\n' && !s[1]) { + *s = '\0'; + break; + } + doshell: + status = spawnlp(P_WAIT,shell,shell,sw,cmd,(char*)NULL); + return status; + } + } + argv = ALLOC_N(CHARP,(strlen(cmd) / 2 + 2)); + cmd2 = ALLOC_N(char, (strlen(cmd) + 1)); + strcpy(cmd2, cmd); + a = argv; + for (s = cmd2; *s;) { + while (*s && isspace(*s)) s++; + if (*s) + *(a++) = s; + while (*s && !isspace(*s)) s++; + if (*s) + *s++ = '\0'; + } + *a = NULL; + if (argv[0]) { + if ((status = spawnvp(P_WAIT, argv[0], argv)) == -1) { + free(argv); + free(cmd2); + return -1; + } + } + free(cmd2); + free(argv); + return status; +} diff --git a/jni/ruby/missing/setproctitle.c b/jni/ruby/missing/setproctitle.c new file mode 100644 index 0000000..602ddf1 --- /dev/null +++ b/jni/ruby/missing/setproctitle.c @@ -0,0 +1,175 @@ +/* Based on setproctitle.c from openssh-5.6p1 */ +/* Based on conf.c from UCB sendmail 8.8.8 */ + +/* + * Copyright 2003 Damien Miller + * Copyright (c) 1983, 1995-1997 Eric P. Allman + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ruby.h" +#include "ruby/util.h" +#define compat_init_setproctitle ruby_init_setproctitle + +#ifndef HAVE_SETPROCTITLE + +#include <stdarg.h> +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_PSTAT_H +#include <sys/pstat.h> +#endif +#include <string.h> + +#if defined(__APPLE__) +# ifdef HAVE_CRT_EXTERNS_H +# include <crt_externs.h> +# undef environ +# define environ (*_NSGetEnviron()) +# else +# include "crt_externs.h" +# endif +#endif + +#define SPT_NONE 0 /* don't use it at all */ +#define SPT_PSTAT 1 /* use pstat(PSTAT_SETCMD, ...) */ +#define SPT_REUSEARGV 2 /* cover argv with title information */ + +#ifndef SPT_TYPE +# define SPT_TYPE SPT_NONE +#endif + +#ifndef SPT_PADCHAR +# define SPT_PADCHAR '\0' +#endif + +#if SPT_TYPE == SPT_REUSEARGV +static char *argv_start = NULL; +static size_t argv_env_len = 0; +static size_t argv_len = 0; +static char **argv1_addr = NULL; +#endif + +#endif /* HAVE_SETPROCTITLE */ + +void +compat_init_setproctitle(int argc, char *argv[]) +{ +#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV + extern char **environ; + char *lastargv = NULL; + char *lastenvp = NULL; + char **envp = environ; + int i; + + /* + * NB: This assumes that argv has already been copied out of the + * way. This is true for sshd, but may not be true for other + * programs. Beware. + */ + + if (argc == 0 || argv[0] == NULL) + return; + + /* Fail if we can't allocate room for the new environment */ + for (i = 0; envp[i] != NULL; i++) + ; + if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) { + environ = envp; /* put it back */ + return; + } + + /* + * Find the last argv string or environment variable within + * our process memory area. + */ + for (i = 0; i < argc; i++) { + if (lastargv == NULL || lastargv + 1 == argv[i]) + lastargv = argv[i] + strlen(argv[i]); + } + lastenvp = lastargv; + for (i = 0; envp[i] != NULL; i++) { + if (lastenvp + 1 == envp[i]) + lastenvp = envp[i] + strlen(envp[i]); + } + + /* We keep argv[1], argv[2], etc. at this moment, + because the ps command of AIX refers to them. */ + argv1_addr = &argv[1]; + argv_start = argv[0]; + argv_len = lastargv - argv[0]; + argv_env_len = lastenvp - argv[0]; + + for (i = 0; envp[i] != NULL; i++) + environ[i] = ruby_strdup(envp[i]); + environ[i] = NULL; +#endif /* SPT_REUSEARGV */ +} + +#ifndef HAVE_SETPROCTITLE +void +setproctitle(const char *fmt, ...) +{ +#if SPT_TYPE != SPT_NONE + va_list ap; + char ptitle[1024]; + size_t len; + size_t argvlen; +#if SPT_TYPE == SPT_PSTAT + union pstun pst; +#endif + +#if SPT_TYPE == SPT_REUSEARGV + if (argv_env_len <= 0) + return; +#endif + + va_start(ap, fmt); + if (fmt != NULL) { + vsnprintf(ptitle, sizeof(ptitle) , fmt, ap); + } + va_end(ap); + +#if SPT_TYPE == SPT_PSTAT + pst.pst_command = ptitle; + pstat(PSTAT_SETCMD, pst, strlen(ptitle), 0, 0); +#elif SPT_TYPE == SPT_REUSEARGV + len = strlcpy(argv_start, ptitle, argv_env_len); + argvlen = len > argv_len ? argv_env_len : argv_len; + for(; len < argvlen; len++) + argv_start[len] = SPT_PADCHAR; + /* argv[1], argv[2], etc. are no longer valid. */ + *argv1_addr = NULL; +#endif + +#endif /* SPT_NONE */ +} + +#endif /* HAVE_SETPROCTITLE */ diff --git a/jni/ruby/missing/signbit.c b/jni/ruby/missing/signbit.c new file mode 100644 index 0000000..2f7ce8c --- /dev/null +++ b/jni/ruby/missing/signbit.c @@ -0,0 +1,19 @@ +#include <limits.h> +#include "ruby.h" + +int +signbit(double x) +{ + enum {double_per_long = sizeof(double) / sizeof(long)}; + enum {long_msb = sizeof(long) * CHAR_BIT - 1}; + union {double d; unsigned long i[double_per_long];} u; + unsigned long l; + + u.d = x; +#ifdef WORDS_BIGENDIAN + l = u.i[0]; +#else + l = u.i[double_per_long - 1]; +#endif + return (int)(l >> long_msb); +} diff --git a/jni/ruby/missing/strchr.c b/jni/ruby/missing/strchr.c new file mode 100644 index 0000000..465f07b --- /dev/null +++ b/jni/ruby/missing/strchr.c @@ -0,0 +1,32 @@ +/* public domain rewrite of strchr(3) and strrchr(3) */ + +#include "ruby/missing.h" + +size_t strlen(const char*); + +char * +strchr(const char *s, int c) +{ + if (c == 0) return (char *)s + strlen(s); + while (*s) { + if (*s == c) + return (char *)s; + s++; + } + return 0; +} + +char * +strrchr(const char *s, int c) +{ + const char *save; + + if (c == 0) return (char *)s + strlen(s); + save = 0; + while (*s) { + if (*s == c) + save = s; + s++; + } + return (char *)save; +} diff --git a/jni/ruby/missing/strerror.c b/jni/ruby/missing/strerror.c new file mode 100644 index 0000000..907b5ae --- /dev/null +++ b/jni/ruby/missing/strerror.c @@ -0,0 +1,18 @@ +/* public domain rewrite of strerror(3) */ + +#include "ruby/missing.h" + +extern int sys_nerr; +extern char *sys_errlist[]; + +static char msg[50]; + +char * +strerror(int error) +{ + if (error <= sys_nerr && error > 0) { + return sys_errlist[error]; + } + sprintf(msg, "Unknown error (%d)", error); + return msg; +} diff --git a/jni/ruby/missing/strlcat.c b/jni/ruby/missing/strlcat.c new file mode 100644 index 0000000..4e2d7cc --- /dev/null +++ b/jni/ruby/missing/strlcat.c @@ -0,0 +1,74 @@ +/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "ruby/missing.h" +#include <sys/types.h> +#include <string.h> + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/jni/ruby/missing/strlcpy.c b/jni/ruby/missing/strlcpy.c new file mode 100644 index 0000000..2ebc38f --- /dev/null +++ b/jni/ruby/missing/strlcpy.c @@ -0,0 +1,70 @@ +/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "ruby/missing.h" +#include <sys/types.h> +#include <string.h> + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} diff --git a/jni/ruby/missing/strstr.c b/jni/ruby/missing/strstr.c new file mode 100644 index 0000000..e6613c5 --- /dev/null +++ b/jni/ruby/missing/strstr.c @@ -0,0 +1,29 @@ +/* public domain rewrite of strstr(3) */ + +#include "ruby/missing.h" + +size_t strlen(const char*); + +char * +strstr(const char *haystack, const char *needle) +{ + const char *hend; + const char *a, *b; + + if (*needle == 0) return (char *)haystack; + hend = haystack + strlen(haystack) - strlen(needle) + 1; + while (haystack < hend) { + if (*haystack == *needle) { + a = haystack; + b = needle; + for (;;) { + if (*b == 0) return (char *)haystack; + if (*a++ != *b++) { + break; + } + } + } + haystack++; + } + return 0; +} diff --git a/jni/ruby/missing/strtol.c b/jni/ruby/missing/strtol.c new file mode 100644 index 0000000..87bd731 --- /dev/null +++ b/jni/ruby/missing/strtol.c @@ -0,0 +1,27 @@ +/* public domain rewrite of strtol(3) */ + +#include "ruby/missing.h" +#include <ctype.h> + +long +strtol(const char *nptr, char **endptr, int base) +{ + long result; + const char *p = nptr; + + while (isspace(*p)) { + p++; + } + if (*p == '-') { + p++; + result = -strtoul(p, endptr, base); + } + else { + if (*p == '+') p++; + result = strtoul(p, endptr, base); + } + if (endptr != 0 && *endptr == p) { + *endptr = (char *)nptr; + } + return result; +} diff --git a/jni/ruby/missing/tgamma.c b/jni/ruby/missing/tgamma.c new file mode 100644 index 0000000..5e306fb --- /dev/null +++ b/jni/ruby/missing/tgamma.c @@ -0,0 +1,92 @@ +/* tgamma.c - public domain implementation of function tgamma(3m) + +reference - Haruhiko Okumura: C-gengo niyoru saishin algorithm jiten + (New Algorithm handbook in C language) (Gijyutsu hyouron + sha, Tokyo, 1991) [in Japanese] + http://oku.edu.mie-u.ac.jp/~okumura/algo/ +*/ + +/*********************************************************** + gamma.c -- Gamma function +***********************************************************/ +#include "ruby/config.h" +#include <math.h> +#include <errno.h> + +#ifdef HAVE_LGAMMA_R + +double tgamma(double x) +{ + int sign; + double d; + if (x == 0.0) { /* Pole Error */ + errno = ERANGE; + return 1/x < 0 ? -HUGE_VAL : HUGE_VAL; + } + if (x < 0) { + static double zero = 0.0; + double i, f; + f = modf(-x, &i); + if (f == 0.0) { /* Domain Error */ + errno = EDOM; + return zero/zero; + } + } + d = lgamma_r(x, &sign); + return sign * exp(d); +} + +#else + +#include <errno.h> +#define PI 3.14159265358979324 /* $\pi$ */ +#define LOG_2PI 1.83787706640934548 /* $\log 2\pi$ */ +#define N 8 + +#define B0 1 /* Bernoulli numbers */ +#define B1 (-1.0 / 2.0) +#define B2 ( 1.0 / 6.0) +#define B4 (-1.0 / 30.0) +#define B6 ( 1.0 / 42.0) +#define B8 (-1.0 / 30.0) +#define B10 ( 5.0 / 66.0) +#define B12 (-691.0 / 2730.0) +#define B14 ( 7.0 / 6.0) +#define B16 (-3617.0 / 510.0) + +static double +loggamma(double x) /* the natural logarithm of the Gamma function. */ +{ + double v, w; + + v = 1; + while (x < N) { v *= x; x++; } + w = 1 / (x * x); + return ((((((((B16 / (16 * 15)) * w + (B14 / (14 * 13))) * w + + (B12 / (12 * 11))) * w + (B10 / (10 * 9))) * w + + (B8 / ( 8 * 7))) * w + (B6 / ( 6 * 5))) * w + + (B4 / ( 4 * 3))) * w + (B2 / ( 2 * 1))) / x + + 0.5 * LOG_2PI - log(v) - x + (x - 0.5) * log(x); +} + +double tgamma(double x) /* Gamma function */ +{ + if (x == 0.0) { /* Pole Error */ + errno = ERANGE; + return 1/x < 0 ? -HUGE_VAL : HUGE_VAL; + } + if (x < 0) { + int sign; + static double zero = 0.0; + double i, f; + f = modf(-x, &i); + if (f == 0.0) { /* Domain Error */ + errno = EDOM; + return zero/zero; + } + sign = (fmod(i, 2.0) != 0.0) ? 1 : -1; + return sign * PI / (sin(PI * f) * exp(loggamma(1 - x))); + } + return exp(loggamma(x)); +} +#endif diff --git a/jni/ruby/missing/x86_64-chkstk.s b/jni/ruby/missing/x86_64-chkstk.s new file mode 100644 index 0000000..6d1227b --- /dev/null +++ b/jni/ruby/missing/x86_64-chkstk.s @@ -0,0 +1,10 @@ + .text +.globl ___chkstk +___chkstk: + pushq %rax + movq %rax, %rcx + movq %rsp, %rdx + call _ruby_alloca_chkstk + popq %rax + subq %rax, %rsp + ret |