diff options
Diffstat (limited to 'missing')
45 files changed, 7021 insertions, 3286 deletions
diff --git a/missing/acosh.c b/missing/acosh.c index a4443e191f..c6695b599e 100644 --- a/missing/acosh.c +++ b/missing/acosh.c @@ -3,7 +3,6 @@ acosh.c - $Author$ - $Date$ created at: Fri Apr 12 00:34:17 JST 2002 public domain rewrite of acosh(3), asinh(3) and atanh(3) @@ -13,6 +12,7 @@ #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 @@ -33,8 +33,7 @@ #ifndef HAVE_ACOSH double -acosh(x) - double x; +acosh(double x) { if (x < 1) x = -1; /* NaN */ @@ -50,8 +49,7 @@ acosh(x) #ifndef HAVE_ASINH double -asinh(x) - double x; +asinh(double x) { int neg = x < 0; double z = fabs(x); @@ -74,8 +72,7 @@ asinh(x) #ifndef HAVE_ATANH double -atanh(x) - double x; +atanh(double x) { int neg = x < 0; double z = fabs(x); @@ -83,6 +80,14 @@ atanh(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/missing/alloca.c b/missing/alloca.c index 39697f114a..d039dfc2cc 100644 --- a/missing/alloca.c +++ b/missing/alloca.c @@ -6,7 +6,7 @@ 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, + 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 @@ -29,7 +29,11 @@ static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ #endif -#include "config.h" +#include "ruby/internal/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 "" @@ -50,12 +54,12 @@ typedef void *pointer; /* generic pointer type */ typedef char *pointer; /* generic pointer type */ #endif /* X3J11 */ +#ifndef NULL #define NULL 0 /* null pointer constant */ +#endif -#ifdef RUBY_LIB #define xmalloc ruby_xmalloc #define xfree ruby_xfree -#endif extern void xfree(); extern pointer xmalloc(); @@ -192,3 +196,4 @@ alloca (size) /* returns pointer to storage */ } } +#endif diff --git a/missing/cbrt.c b/missing/cbrt.c new file mode 100644 index 0000000000..1bcbc63392 --- /dev/null +++ b/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/missing/close.c b/missing/close.c new file mode 100644 index 0000000000..831e75efe1 --- /dev/null +++ b/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/missing/crt_externs.h b/missing/crt_externs.h new file mode 100644 index 0000000000..cc96d46738 --- /dev/null +++ b/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/missing/crypt.c b/missing/crypt.c index 486df5050b..f523aa51e6 100644 --- a/missing/crypt.c +++ b/missing/crypt.c @@ -34,6 +34,8 @@ static char sccsid[] = "@(#)crypt.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ +#include "ruby/missing.h" +#include "crypt.h" #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -42,10 +44,15 @@ static char sccsid[] = "@(#)crypt.c 8.1 (Berkeley) 6/4/93"; #include <pwd.h> #endif #include <stdio.h> +#include <string.h> #ifndef _PASSWORD_EFMT1 #define _PASSWORD_EFMT1 '_' #endif +#ifndef numberof +#define numberof(array) (int)(sizeof(array) / sizeof((array)[0])) +#endif + /* * UNIX password, and DES, encryption. * By Tom Truscott, trt@rti.rti.org, @@ -79,175 +86,22 @@ static char sccsid[] = "@(#)crypt.c 8.1 (Berkeley) 6/4/93"; #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 - -/* compile with "-DSTATIC=int" when profiling */ -#ifndef STATIC -#define STATIC static -#endif -STATIC init_des(), init_perm(), permute(); -#ifdef DEBUG -STATIC 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; +#ifndef INIT_DES +# if defined DUMP || defined NO_DES_TABLES +# define INIT_DES 1 +# else +# define INIT_DES 0 +# endif #endif - } b32; -#if defined(B64) - B64 b64; +#if !INIT_DES +# include "des_tables.c" +# ifdef HAVE_DES_TABLES +# define init_des() ((void)0) +# else +# undef INIT_DES +# define INIT_DES 1 +# endif #endif -} C_block; /* * Convert twenty-four-bit long in host-order @@ -255,59 +109,51 @@ typedef union { */ #define TO_SIX_BIT(rslt, src) { \ C_block cvt; \ - cvt.b[0] = src; src >>= 6; \ - cvt.b[1] = src; src >>= 6; \ - cvt.b[2] = src; src >>= 6; \ - cvt.b[3] = src; \ - rslt = (cvt.b32.i0 & 0x3f3f3f3fL) << 2; \ + 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 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]]); + 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]]); + 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); } + { 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 -permute(cp, out, p, chars_in) - unsigned char *cp; - C_block *out; - register C_block *p; - int chars_in; + { C_block tblk; permute((cpp),&tblk,(p),4); LOAD ((d),(d0),(d1),tblk); } + +STATIC void +permute(const unsigned char *cp, C_block *out, register const C_block *p, int chars_in) { register DCL_BLOCK(D,D0,D1); - register C_block *tp; + register const C_block *tp; register int t; ZERO(D,D0,D1); @@ -320,10 +166,14 @@ permute(cp, out, p, chars_in) } #endif /* LARGEDATA */ +#ifdef DEBUG +STATIC void prtab(const char *s, const unsigned char *t, int num_rows); +#endif +#if INIT_DES /* ===== (mostly) Standard DES Tables ==================== */ -static unsigned char IP[] = { /* initial permutation */ +static const 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, @@ -336,7 +186,7 @@ static unsigned char IP[] = { /* initial permutation */ /* The final permutation is the inverse of IP - no table is necessary */ -static unsigned char ExpandTr[] = { /* expansion operation */ +static const unsigned char ExpandTr[] = { /* expansion operation */ 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, @@ -347,7 +197,7 @@ static unsigned char ExpandTr[] = { /* expansion operation */ 28, 29, 30, 31, 32, 1, }; -static unsigned char PC1[] = { /* permuted choice table 1 */ +static const 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, @@ -358,13 +208,15 @@ static unsigned char PC1[] = { /* permuted choice table 1 */ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4, }; +#endif -static unsigned char Rotates[] = { /* PC1 rotation schedule */ +static const unsigned char Rotates[] = { /* PC1 rotation schedule */ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, }; +#if INIT_DES /* note: each "row" of PC2 is left-padded with bits that make it invertible */ -static unsigned char PC2[] = { /* permuted choice table 2 */ +static const 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, @@ -376,50 +228,66 @@ static unsigned char PC2[] = { /* permuted choice table 2 */ 0, 0, 46, 42, 50, 36, 29, 32, }; -static unsigned char S[8][64] = { /* 48->32 bit substitution tables */ +static const 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 */ +static const unsigned char P32Tr[] = { /* 32-bit permutation function */ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, @@ -430,7 +298,7 @@ static unsigned char P32Tr[] = { /* 32-bit permutation function */ 22, 11, 4, 25, }; -static unsigned char CIFP[] = { /* compressed/interleaved permutation */ +static const 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, @@ -441,46 +309,91 @@ static unsigned char CIFP[] = { /* compressed/interleaved permutation */ 41, 42, 43, 44, 57, 58, 59, 60, 45, 46, 47, 48, 61, 62, 63, 64, }; +#endif -static unsigned char itoa64[] = /* 0..63 => ascii-64 */ +static const unsigned char itoa64[] = /* 0..63 => ascii-64 */ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +/* table that converts chars "./0-9A-Za-z"to integers 0-63. */ +static const unsigned char a64toi[256] = { +#define A64TOI1(c) \ + ((c) == '.' ? 0 : \ + (c) == '/' ? 1 : \ + ('0' <= (c) && (c) <= '9') ? (c) - '0' + 2 : \ + ('A' <= (c) && (c) <= 'Z') ? (c) - 'A' + 12 : \ + ('a' <= (c) && (c) <= 'z') ? (c) - 'a' + 38 : \ + 0) +#define A64TOI4(base) A64TOI1(base+0), A64TOI1(base+1), A64TOI1(base+2), A64TOI1(base+3) +#define A64TOI16(base) A64TOI4(base+0), A64TOI4(base+4), A64TOI4(base+8), A64TOI4(base+12) +#define A64TOI64(base) A64TOI16(base+0x00), A64TOI16(base+0x10), A64TOI16(base+0x20), A64TOI16(base+0x30) + A64TOI64(0x00), A64TOI64(0x40), + A64TOI64(0x00), A64TOI64(0x40), +}; +#if INIT_DES /* ===== Tables that are initialized at run time ==================== */ +typedef struct { + /* Initial key schedule permutation */ + C_block PC1ROT[64/CHUNKBITS][1<<CHUNKBITS]; -static unsigned char a64toi[128]; /* ascii-64 => 0..63 */ + /* Subsequent key schedule rotation permutations */ + C_block PC2ROT[2][64/CHUNKBITS][1<<CHUNKBITS]; -/* Initial key schedule permutation */ -static C_block PC1ROT[64/CHUNKBITS][1<<CHUNKBITS]; + /* Initial permutation/expansion table */ + C_block IE3264[32/CHUNKBITS][1<<CHUNKBITS]; -/* Subsequent key schedule rotation permutations */ -static C_block PC2ROT[2][64/CHUNKBITS][1<<CHUNKBITS]; + /* Table that combines the S, P, and E operations. */ + unsigned long SPE[2][8][64]; -/* Initial permutation/expansion table */ -static C_block IE3264[32/CHUNKBITS][1<<CHUNKBITS]; + /* compressed/interleaved => final permutation table */ + C_block CF6464[64/CHUNKBITS][1<<CHUNKBITS]; -/* Table that combines the S, P, and E operations. */ -static long SPE[2][8][64]; + int ready; +} des_tables_t; +static des_tables_t des_tables[1]; -/* compressed/interleaved => final permutation table */ -static C_block CF6464[64/CHUNKBITS][1<<CHUNKBITS]; +#define des_tables ((const des_tables_t *)des_tables) +#define PC1ROT (des_tables->PC1ROT) +#define PC2ROT (des_tables->PC2ROT) +#define IE3264 (des_tables->IE3264) +#define SPE (des_tables->SPE) +#define CF6464 (des_tables->CF6464) +STATIC void init_des(void); +STATIC void init_perm(C_block perm[64/CHUNKBITS][1<<CHUNKBITS], unsigned char p[64], int chars_in, int chars_out); +#endif -/* ==================================== */ +static const C_block constdatablock = {{0}}; /* encryption constant */ +#define KS (data->KS) +#define cryptresult (data->cryptresult) -static C_block constdatablock; /* encryption constant */ -static char cryptresult[1+4+4+11+1]; /* encrypted result */ +static void des_setkey_r(const unsigned char *key, struct crypt_data *data); +static void des_cipher_r(const unsigned char *in, unsigned char *out, long salt, int num_iter, struct crypt_data *data); +#ifdef USE_NONREENTRANT_CRYPT +static struct crypt_data default_crypt_data; +#endif + +#ifdef USE_NONREENTRANT_CRYPT /* * 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; +crypt(const char *key, const char *setting) +{ + return crypt_r(key, setting, &default_crypt_data); +} +#endif + +/* + * Return a pointer to data consisting of the "setting" followed by an + * encryption produced by the "key" and "setting". + */ +char * +crypt_r(const char *key, const char *setting, struct crypt_data *data) { register char *encp; register long i; @@ -494,8 +407,7 @@ crypt(key, setting) key++; keyblock.b[i] = t; } - if (des_setkey((char *)keyblock.b)) /* also initializes "a64toi" */ - return (NULL); + des_setkey_r(keyblock.b, data); /* also initializes "a64toi" */ encp = &cryptresult[0]; switch (*setting) { @@ -504,16 +416,13 @@ crypt(key, setting) * Involve the rest of the password 8 characters at a time. */ while (*key) { - if (des_cipher((char *)&keyblock, - (char *)&keyblock, 0L, 1)) - return (NULL); + des_cipher_r(keyblock.b, keyblock.b, 0L, 1, data); 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); + des_setkey_r(keyblock.b, data); } *encp++ = *setting++; @@ -543,9 +452,7 @@ crypt(key, setting) salt = (salt<<6) | a64toi[t]; } encp += salt_size; - if (des_cipher((char *)&constdatablock, (char *)&rsltblock, - salt, num_iter)) - return (NULL); + des_cipher_r(constdatablock.b, rsltblock.b, salt, num_iter, data); /* * Encode the 64 cipher bits as 11 ascii characters. @@ -570,62 +477,48 @@ crypt(key, setting) 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. */ -des_setkey(key) - register const char *key; +static void +des_setkey_r(const unsigned char *key, struct crypt_data *data) { register DCL_BLOCK(K, K0, K1); - register C_block *ptabp; + register const C_block *ptabp; register int i; - static int des_ready = 0; - - if (!des_ready) { - init_des(); - des_ready = 1; + C_block *ksp; + + init_des(); + + PERM6464(K,K0,K1,key,PC1ROT[0]); + ksp = &KS[0]; + STORE(K&~0x03030303L, K0&~0x03030303L, K1, *ksp); + for (i = 1; i < numberof(KS); i++) { + ksp++; + STORE(K,K0,K1,*ksp); + ptabp = PC2ROT[Rotates[i]-1][0]; + PERM6464(K,K0,K1,ksp->b,ptabp); + STORE(K&~0x03030303L, K0&~0x03030303L, K1, *ksp); } - - 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 the given 24-bit salt and the pre-computed key + * 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. */ -des_cipher(in, out, salt, num_iter) - const char *in; - char *out; - long salt; - int num_iter; +void +des_cipher_r(const unsigned char *in, unsigned char *out, long salt, int num_iter, struct crypt_data *data) { /* 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 unsigned long L0, L1, R0, R1, k; + register const C_block *kp; register int ks_inc, loop_count; C_block B; @@ -654,58 +547,58 @@ des_cipher(in, out, salt, num_iter) 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 */ + PERM3264(L,L0,L1,B.b, IE3264[0]); /* even bits */ + PERM3264(R,R0,R1,B.b+4,IE3264[0]); /* odd bits */ if (num_iter >= 0) { /* encryption */ kp = &KS[0]; - ks_inc = sizeof(*kp); + ks_inc = +1; } else { /* decryption */ num_iter = -num_iter; kp = &KS[KS_SIZE-1]; - ks_inc = -sizeof(*kp); + ks_inc = -1; } while (--num_iter >= 0) { loop_count = 8; do { -#define SPTAB(t, i) (*(long *)((unsigned char *)t + i*(sizeof(long)/4))) +#define SPTAB(t, i) (*(const unsigned long *)((const 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]); +#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); +#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); +#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); \ + k = ((q0) ^ (q1)) & SALT; \ + B.b32.i0 = k ^ (q0) ^ kp->b32.i0; \ + B.b32.i1 = k ^ (q1) ^ kp->b32.i1; \ + 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); + 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)); + kp -= (ks_inc*KS_SIZE); /* swap L and R */ @@ -718,7 +611,7 @@ des_cipher(in, out, salt, num_iter) 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); + PERM6464(L,L0,L1,B.b, CF6464[0]); #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]; @@ -726,27 +619,26 @@ des_cipher(in, out, salt, num_iter) #else STORE(L,L0,L1,*(C_block *)out); #endif - return (0); } +#undef des_tables +#undef KS +#undef cryptresult +#if INIT_DES /* * 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 -init_des() +STATIC void +init_des(void) { register int i, j; register long k; register int tableno; - static unsigned char perm[64], tmp32[32]; /* "static" for speed */ + unsigned char perm[64], tmp32[32]; - /* - * table that converts chars "./0-9A-Za-z"to integers 0-63. - */ - for (i = 0; i < 64; i++) - a64toi[itoa64[i]] = i; + if (des_tables->ready) return; /* * PC1ROT - bit reverse, then PC1, then Rotate, then PC2. @@ -764,7 +656,7 @@ init_des() k = (k|07) - (k&07); k++; } - perm[i] = k; + perm[i] = (unsigned char)k; } #ifdef DEBUG prtab("pc1tab", perm, 8); @@ -811,7 +703,7 @@ init_des() k = (k|07) - (k&07); k++; } - perm[i*8+j] = k; + perm[i*8+j] = (unsigned char)k; } } #ifdef DEBUG @@ -857,7 +749,7 @@ init_des() for (i = 0; i < 32; i++) tmp32[i] = 0; for (i = 0; i < 4; i++) - tmp32[4 * tableno + i] = (k >> i) & 01; + tmp32[4 * tableno + i] = (unsigned char)(k >> i) & 01; k = 0; for (i = 24; --i >= 0; ) k = (k<<1) | tmp32[perm[i]-1]; @@ -868,6 +760,8 @@ init_des() TO_SIX_BIT(SPE[1][tableno][j], k); } } + + des_tables->ready = 1; } /* @@ -878,11 +772,9 @@ init_des() * * "perm" must be all-zeroes on entry to this routine. */ -STATIC -init_perm(perm, p, chars_in, chars_out) - C_block perm[64/CHUNKBITS][1<<CHUNKBITS]; - unsigned char p[64]; - int chars_in, chars_out; +STATIC void +init_perm(C_block perm[64/CHUNKBITS][1<<CHUNKBITS], + unsigned char p[64], int chars_in, int chars_out) { register int i, j, k, l; @@ -898,12 +790,21 @@ init_perm(perm, p, chars_in, chars_out) } } } +#endif /* * "setkey" routine (for backwards compatibility) */ -setkey(key) - register const char *key; +#ifdef USE_NONREENTRANT_CRYPT +void +setkey(const char *key) +{ + setkey_r(key, &default_crypt_data); +} +#endif + +void +setkey_r(const char *key, struct crypt_data *data) { register int i, j, k; C_block keyblock; @@ -916,15 +817,22 @@ setkey(key) } keyblock.b[i] = k; } - return (des_setkey((char *)keyblock.b)); + des_setkey_r(keyblock.b, data); } /* * "encrypt" routine (for backwards compatibility) */ -encrypt(block, flag) - register char *block; - int flag; +#ifdef USE_NONREENTRANT_CRYPT +void +encrypt(char *block, int flag) +{ + encrypt_r(block, flag, &default_crypt_data); +} +#endif + +void +encrypt_r(char *block, int flag, struct crypt_data *data) { register int i, j, k; C_block cblock; @@ -937,8 +845,7 @@ encrypt(block, flag) } cblock.b[i] = k; } - if (des_cipher((char *)&cblock, (char *)&cblock, 0L, (flag ? -1: 1))) - return (1); + des_cipher_r(cblock.b, cblock.b, 0L, (flag ? -1: 1), data); for (i = 7; i >= 0; i--) { k = cblock.b[i]; for (j = 7; j >= 0; j--) { @@ -946,15 +853,11 @@ encrypt(block, flag) k >>= 1; } } - return (0); } #ifdef DEBUG -STATIC -prtab(s, t, num_rows) - char *s; - unsigned char *t; - int num_rows; +STATIC void +prtab(const char *s, const unsigned char *t, int num_rows) { register int i, j; @@ -968,3 +871,97 @@ prtab(s, t, num_rows) (void)printf("\n"); } #endif + +#ifdef DUMP +void +dump_block(const C_block *block) +{ + int i; + printf("{{"); + for (i = 0; i < numberof(block->b); ++i) { + printf("%3d,", block->b[i]); + } + printf("}},\n"); +} + +int +main(void) +{ + int i, j, k; + init_des(); + + printf("#ifndef HAVE_DES_TABLES\n\n"); + printf("/* Initial key schedule permutation */\n"); + printf("static const C_block PC1ROT[64/CHUNKBITS][1<<CHUNKBITS] = {\n"); + for (i = 0; i < numberof(PC1ROT); ++i) { + printf("\t{\n"); + for (j = 0; j < numberof(PC1ROT[0]); ++j) { + printf("\t\t"); + dump_block(&PC1ROT[i][j]); + } + printf("\t},\n"); + } + printf("};\n\n"); + + printf("/* Subsequent key schedule rotation permutations */\n"); + printf("static const C_block PC2ROT[2][64/CHUNKBITS][1<<CHUNKBITS] = {\n"); + for (i = 0; i < numberof(PC2ROT); ++i) { + printf("\t{\n"); + for (j = 0; j < numberof(PC2ROT[0]); ++j) { + printf("\t\t{\n"); + for (k = 0; k < numberof(PC2ROT[0][0]); ++k) { + printf("\t\t\t"); + dump_block(&PC2ROT[i][j][k]); + } + printf("\t\t},\n"); + } + printf("\t},\n"); + } + printf("};\n\n"); + + printf("/* Initial permutation/expansion table */\n"); + printf("static const C_block IE3264[32/CHUNKBITS][1<<CHUNKBITS] = {\n"); + for (i = 0; i < numberof(IE3264); ++i) { + printf("\t{\n"); + for (j = 0; j < numberof(IE3264[0]); ++j) { + printf("\t\t"); + dump_block(&IE3264[i][j]); + } + printf("\t},\n"); + } + printf("};\n\n"); + + printf("/* Table that combines the S, P, and E operations. */\n"); + printf("static const unsigned long SPE[2][8][64] = {\n"); + for (i = 0; i < numberof(SPE); ++i) { + printf("\t{\n"); + for (j = 0; j < numberof(SPE[0]); ++j) { + int r = 0; + printf("\t\t{"); + for (k = 0; k < numberof(SPE[0][0]); ++k) { + if (r == 0) printf("\n\t\t\t"); + printf("%#10lx,", SPE[i][j][k]); + if (++r == 4) r = 0; + } + printf("\n\t\t},\n"); + } + printf("\t},\n"); + } + printf("};\n\n"); + + printf("/* compressed/interleaved => final permutation table */\n"); + printf("static const C_block CF6464[64/CHUNKBITS][1<<CHUNKBITS] = {\n"); + for (i = 0; i < numberof(CF6464); ++i) { + printf("\t{\n"); + for (j = 0; j < numberof(CF6464[0]); ++j) { + printf("\t\t"); + dump_block(&CF6464[i][j]); + } + printf("\t},\n"); + } + printf("};\n\n"); + printf("#define HAVE_DES_TABLES 1\n""#endif\n"); + + return 0; +} +#endif diff --git a/missing/crypt.h b/missing/crypt.h new file mode 100644 index 0000000000..ff135eee93 --- /dev/null +++ b/missing/crypt.h @@ -0,0 +1,247 @@ +#ifndef CRYPT_H +#define CRYPT_H 1 +/* + * 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. + */ + +/* ===== Configuration ==================== */ + +#ifdef CHAR_BITS +#if CHAR_BITS != 8 + #error C_block structure assumes 8 bit characters +#endif +#endif + +#ifndef LONG_LONG +# if SIZEOF_LONG_LONG > 0 +# define LONG_LONG long long +# elif SIZEOF___INT64 > 0 +# define HAVE_LONG_LONG 1 +# define LONG_LONG __int64 +# undef SIZEOF_LONG_LONG +# define SIZEOF_LONG_LONG SIZEOF___INT64 +# 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 SIZEOF_LONG == 4 +#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 SIZEOF_LONG == 8 +#define B64 long +#elif SIZEOF_LONG_LONG == 8 +#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 + +/* compile with "-DSTATIC=int" when profiling */ +#ifndef STATIC +#define STATIC static +#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; + +#if defined(LARGEDATA) + /* Waste memory like crazy. Also, do permutations in line */ +#define LGCHUNKBITS 3 +#define CHUNKBITS (1<<LGCHUNKBITS) +#else + /* "small data" */ +#define LGCHUNKBITS 2 +#define CHUNKBITS (1<<LGCHUNKBITS) +#endif + +struct crypt_data { + /* The Key Schedule, filled in by des_setkey() or setkey(). */ +#define KS_SIZE 16 + C_block KS[KS_SIZE]; + + /* ==================================== */ + + char cryptresult[1+4+4+11+1]; /* encrypted result */ +}; + +char *crypt(const char *key, const char *setting); +void setkey(const char *key); +void encrypt(char *block, int flag); + +char *crypt_r(const char *key, const char *setting, struct crypt_data *data); +void setkey_r(const char *key, struct crypt_data *data); +void encrypt_r(char *block, int flag, struct crypt_data *data); + +#endif /* CRYPT_H */ diff --git a/missing/des_tables.c b/missing/des_tables.c new file mode 100644 index 0000000000..ab6b1d1883 --- /dev/null +++ b/missing/des_tables.c @@ -0,0 +1,1616 @@ +#ifndef HAVE_DES_TABLES + +/* Initial key schedule permutation */ +static const C_block PC1ROT[64/CHUNKBITS][1<<CHUNKBITS] = { + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 1, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 1, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 1, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 1, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 1, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 1, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 16, 0, 0,}}, + {{ 0, 0, 1, 1, 0, 16, 0, 0,}}, + {{ 0, 0, 1, 1, 0, 16, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0,128, 0, 0, 0,}}, + {{ 0, 0, 4, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 4, 0,128, 0, 0, 0,}}, + {{ 0, 16, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 0,128, 0, 0, 0,}}, + {{ 0, 16, 4, 0, 0, 0, 0, 0,}}, + {{ 0, 16, 4, 0,128, 0, 0, 0,}}, + {{ 0, 0, 0, 8, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 8,128, 0, 0, 0,}}, + {{ 0, 0, 4, 8, 0, 0, 0, 0,}}, + {{ 0, 0, 4, 8,128, 0, 0, 0,}}, + {{ 0, 16, 0, 8, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 8,128, 0, 0, 0,}}, + {{ 0, 16, 4, 8, 0, 0, 0, 0,}}, + {{ 0, 16, 4, 8,128, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 8,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 8,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 24,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 24,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 24,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 24,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 2, 0, 0, 0, 0,}}, + {{ 0, 1, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 1, 0, 2, 0, 0, 0, 0,}}, + {{ 4, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 4, 0, 0, 2, 0, 0, 0, 0,}}, + {{ 4, 1, 0, 0, 0, 0, 0, 0,}}, + {{ 4, 1, 0, 2, 0, 0, 0, 0,}}, + {{ 0, 32, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 32, 0, 2, 0, 0, 0, 0,}}, + {{ 0, 33, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 33, 0, 2, 0, 0, 0, 0,}}, + {{ 4, 32, 0, 0, 0, 0, 0, 0,}}, + {{ 4, 32, 0, 2, 0, 0, 0, 0,}}, + {{ 4, 33, 0, 0, 0, 0, 0, 0,}}, + {{ 4, 33, 0, 2, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 64, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 64, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 64, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 64, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 0, 64, 8, 0,}}, + {{ 0, 0, 0, 0, 0, 64, 8, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 4, 64, 8, 0,}}, + {{ 0, 0, 0, 0, 4, 64, 8, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0,128, 0,}}, + {{ 0, 64, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 64, 0, 0, 0, 0,128, 0,}}, + {{ 0, 0, 0, 64, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 64, 0, 0,128, 0,}}, + {{ 0, 64, 0, 64, 0, 0, 0, 0,}}, + {{ 0, 64, 0, 64, 0, 0,128, 0,}}, + {{128, 0, 0, 0, 0, 0, 0, 0,}}, + {{128, 0, 0, 0, 0, 0,128, 0,}}, + {{128, 64, 0, 0, 0, 0, 0, 0,}}, + {{128, 64, 0, 0, 0, 0,128, 0,}}, + {{128, 0, 0, 64, 0, 0, 0, 0,}}, + {{128, 0, 0, 64, 0, 0,128, 0,}}, + {{128, 64, 0, 64, 0, 0, 0, 0,}}, + {{128, 64, 0, 64, 0, 0,128, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0,128,}}, + {{ 0, 0, 0, 0, 0, 0, 0,128,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0,128,}}, + {{ 0, 0, 0, 0, 0, 8, 0,128,}}, + {{ 0, 0, 0, 0, 0,128, 0, 0,}}, + {{ 0, 0, 0, 0, 0,128, 0, 0,}}, + {{ 0, 0, 0, 0, 0,128, 0,128,}}, + {{ 0, 0, 0, 0, 0,128, 0,128,}}, + {{ 0, 0, 0, 0, 0,136, 0, 0,}}, + {{ 0, 0, 0, 0, 0,136, 0, 0,}}, + {{ 0, 0, 0, 0, 0,136, 0,128,}}, + {{ 0, 0, 0, 0, 0,136, 0,128,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 8, 0, 0, 0,}}, + {{ 0, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 32, 8, 0, 0, 0,}}, + {{ 0, 0, 16, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 0, 8, 0, 0, 0,}}, + {{ 0, 0, 16, 32, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 32, 8, 0, 0, 0,}}, + {{ 0, 0, 32, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 32, 0, 8, 0, 0, 0,}}, + {{ 0, 0, 32, 32, 0, 0, 0, 0,}}, + {{ 0, 0, 32, 32, 8, 0, 0, 0,}}, + {{ 0, 0, 48, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 48, 0, 8, 0, 0, 0,}}, + {{ 0, 0, 48, 32, 0, 0, 0, 0,}}, + {{ 0, 0, 48, 32, 8, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 80, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 80, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 80, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 80, 0, 16, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 0, 8, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 8, 16, 0, 0, 0, 0,}}, + {{ 16, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 16, 0, 8, 0, 0, 0, 0, 0,}}, + {{ 16, 0, 8, 16, 0, 0, 0, 0,}}, + {{ 0, 4, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 4, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 4, 8, 0, 0, 0, 0, 0,}}, + {{ 0, 4, 8, 16, 0, 0, 0, 0,}}, + {{ 16, 4, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 4, 0, 16, 0, 0, 0, 0,}}, + {{ 16, 4, 8, 0, 0, 0, 0, 0,}}, + {{ 16, 4, 8, 16, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 4, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 4, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 4,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 4,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 4,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 4,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 4,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 4,}}, + {{ 0, 0, 2, 0, 0, 4, 0, 4,}}, + {{ 0, 0, 2, 0, 0, 4, 0, 4,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 64, 0, 0, 0, 0, 0,}}, + {{ 2, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 2, 0, 64, 0, 0, 0, 0, 0,}}, + {{ 0,128, 0, 0, 0, 0, 0, 0,}}, + {{ 0,128, 64, 0, 0, 0, 0, 0,}}, + {{ 2,128, 0, 0, 0, 0, 0, 0,}}, + {{ 2,128, 64, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0,128, 0, 0, 0, 0,}}, + {{ 0, 0, 64,128, 0, 0, 0, 0,}}, + {{ 2, 0, 0,128, 0, 0, 0, 0,}}, + {{ 2, 0, 64,128, 0, 0, 0, 0,}}, + {{ 0,128, 0,128, 0, 0, 0, 0,}}, + {{ 0,128, 64,128, 0, 0, 0, 0,}}, + {{ 2,128, 0,128, 0, 0, 0, 0,}}, + {{ 2,128, 64,128, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 64,}}, + {{ 0, 0, 0, 0, 32, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 32, 0, 64,}}, + {{ 0, 0, 0, 0, 32, 32, 0, 64,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 8, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 8, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 1, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 1, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 9, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 9, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 64, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 72, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 72, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 65, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 65, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 73, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 73, 2, 0, 0, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 36, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 36, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 36, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 36, 32,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 4, 0, 0, 0, 0,}}, + {{ 32, 0, 0, 4, 0, 0, 0, 0,}}, + {{ 0, 0,128, 0, 0, 0, 0, 0,}}, + {{ 32, 0,128, 0, 0, 0, 0, 0,}}, + {{ 0, 0,128, 4, 0, 0, 0, 0,}}, + {{ 32, 0,128, 4, 0, 0, 0, 0,}}, + {{ 0, 8, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 8, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 8, 0, 4, 0, 0, 0, 0,}}, + {{ 32, 8, 0, 4, 0, 0, 0, 0,}}, + {{ 0, 8,128, 0, 0, 0, 0, 0,}}, + {{ 32, 8,128, 0, 0, 0, 0, 0,}}, + {{ 0, 8,128, 4, 0, 0, 0, 0,}}, + {{ 32, 8,128, 4, 0, 0, 0, 0,}}, + }, +}; + +/* Subsequent key schedule rotation permutations */ +static const C_block PC2ROT[2][64/CHUNKBITS][1<<CHUNKBITS] = { + { + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0,128, 0, 0, 0, 0, 0,}}, + {{ 8, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 8, 0,128, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 64, 0, 0, 0, 0,}}, + {{ 0, 0,128, 64, 0, 0, 0, 0,}}, + {{ 8, 0, 0, 64, 0, 0, 0, 0,}}, + {{ 8, 0,128, 64, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 4, 0, 0, 0, 0,}}, + {{ 0, 0,128, 4, 0, 0, 0, 0,}}, + {{ 8, 0, 0, 4, 0, 0, 0, 0,}}, + {{ 8, 0,128, 4, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 68, 0, 0, 0, 0,}}, + {{ 0, 0,128, 68, 0, 0, 0, 0,}}, + {{ 8, 0, 0, 68, 0, 0, 0, 0,}}, + {{ 8, 0,128, 68, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0,128, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 4, 0, 0, 0, 0, 0,}}, + {{ 0,128, 4, 0, 0, 0, 0, 0,}}, + {{ 0, 8, 0, 0, 0, 0, 0, 0,}}, + {{ 0,136, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 8, 4, 0, 0, 0, 0, 0,}}, + {{ 0,136, 4, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 32, 0, 0, 0, 0, 0,}}, + {{ 0,128, 32, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 36, 0, 0, 0, 0, 0,}}, + {{ 0,128, 36, 0, 0, 0, 0, 0,}}, + {{ 0, 8, 32, 0, 0, 0, 0, 0,}}, + {{ 0,136, 32, 0, 0, 0, 0, 0,}}, + {{ 0, 8, 36, 0, 0, 0, 0, 0,}}, + {{ 0,136, 36, 0, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 64, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 64, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0,128, 0, 0, 0, 0,}}, + {{ 0, 64, 0,128, 0, 0, 0, 0,}}, + {{ 32, 0, 0,128, 0, 0, 0, 0,}}, + {{ 32, 64, 0,128, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 64, 0, 16, 0, 0, 0, 0,}}, + {{ 32, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 32, 64, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 0, 0,144, 0, 0, 0, 0,}}, + {{ 0, 64, 0,144, 0, 0, 0, 0,}}, + {{ 32, 0, 0,144, 0, 0, 0, 0,}}, + {{ 32, 64, 0,144, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 4, 0, 0, 0, 0, 0, 0, 0,}}, + {{128, 0, 0, 0, 0, 0, 0, 0,}}, + {{132, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 4, 0, 0, 32, 0, 0, 0, 0,}}, + {{128, 0, 0, 32, 0, 0, 0, 0,}}, + {{132, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 1, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 5, 0, 0, 0, 0, 0, 0, 0,}}, + {{129, 0, 0, 0, 0, 0, 0, 0,}}, + {{133, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 1, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 5, 0, 0, 32, 0, 0, 0, 0,}}, + {{129, 0, 0, 32, 0, 0, 0, 0,}}, + {{133, 0, 0, 32, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 0,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 0, 64, 0,}}, + {{ 0, 1, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 1, 0, 0, 0, 0, 64, 0,}}, + {{ 0, 1, 0, 0, 32, 0, 0, 0,}}, + {{ 0, 1, 0, 0, 32, 0, 64, 0,}}, + {{ 2, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 2, 0, 0, 0, 0, 0, 64, 0,}}, + {{ 2, 0, 0, 0, 32, 0, 0, 0,}}, + {{ 2, 0, 0, 0, 32, 0, 64, 0,}}, + {{ 2, 1, 0, 0, 0, 0, 0, 0,}}, + {{ 2, 1, 0, 0, 0, 0, 64, 0,}}, + {{ 2, 1, 0, 0, 32, 0, 0, 0,}}, + {{ 2, 1, 0, 0, 32, 0, 64, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 4, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 4, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 6, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 6, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 8, 0, 0, 0, 0,}}, + {{ 16, 0, 0, 8, 0, 0, 0, 0,}}, + {{ 0, 4, 0, 8, 0, 0, 0, 0,}}, + {{ 16, 4, 0, 8, 0, 0, 0, 0,}}, + {{ 0, 2, 0, 8, 0, 0, 0, 0,}}, + {{ 16, 2, 0, 8, 0, 0, 0, 0,}}, + {{ 0, 6, 0, 8, 0, 0, 0, 0,}}, + {{ 16, 6, 0, 8, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 0, 0,128, 0,}}, + {{ 0, 0, 0, 0, 0, 0,128, 8,}}, + {{ 0, 16, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 16, 0, 0, 0, 0,128, 0,}}, + {{ 0, 16, 0, 0, 0, 0,128, 8,}}, + {{ 0, 32, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 32, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 32, 0, 0, 0, 0,128, 0,}}, + {{ 0, 32, 0, 0, 0, 0,128, 8,}}, + {{ 0, 48, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 48, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 48, 0, 0, 0, 0,128, 0,}}, + {{ 0, 48, 0, 0, 0, 0,128, 8,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 64, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 8, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 72, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 80, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 24, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 88, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 64, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 8, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 72, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 16, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 80, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 24, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 88, 0, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 24, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 24, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 24, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 24, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 32,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 4,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 4,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 36,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 36,}}, + {{ 0, 0, 0, 2, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 2, 0, 4, 0, 0,}}, + {{ 0, 0, 0, 2, 0, 0, 0, 32,}}, + {{ 0, 0, 0, 2, 0, 4, 0, 32,}}, + {{ 0, 0, 0, 2, 0, 0, 0, 4,}}, + {{ 0, 0, 0, 2, 0, 4, 0, 4,}}, + {{ 0, 0, 0, 2, 0, 0, 0, 36,}}, + {{ 0, 0, 0, 2, 0, 4, 0, 36,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 64,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 64,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 64,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 64,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 0,128,}}, + {{ 0, 0, 0, 0, 0, 0, 0,144,}}, + {{ 0, 0, 0, 0, 0, 0, 4,128,}}, + {{ 0, 0, 0, 0, 0, 0, 4,144,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 64, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 4, 16,}}, + {{ 0, 0, 0, 0, 64, 0, 0,128,}}, + {{ 0, 0, 0, 0, 64, 0, 0,144,}}, + {{ 0, 0, 0, 0, 64, 0, 4,128,}}, + {{ 0, 0, 0, 0, 64, 0, 4,144,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0,128, 0, 0,}}, + {{ 0, 0, 0, 0, 0,128, 0, 0,}}, + {{ 0, 0, 0, 0, 0,128, 0, 0,}}, + {{ 0, 0, 0, 0, 0,128, 0, 0,}}, + {{ 0, 0, 0, 1, 0,128, 0, 0,}}, + {{ 0, 0, 0, 1, 0,128, 0, 0,}}, + {{ 0, 0, 0, 1, 0,128, 0, 0,}}, + {{ 0, 0, 0, 1, 0,128, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0,128, 0, 0, 0,}}, + {{ 0, 0, 2, 0,128, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 64, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 64, 0, 0,}}, + {{ 0, 0, 0, 0,128, 64, 0, 0,}}, + {{ 0, 0, 2, 0,128, 64, 0, 0,}}, + {{ 0, 0, 0, 0, 8, 0, 0, 0,}}, + {{ 0, 0, 2, 0, 8, 0, 0, 0,}}, + {{ 0, 0, 0, 0,136, 0, 0, 0,}}, + {{ 0, 0, 2, 0,136, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 8, 64, 0, 0,}}, + {{ 0, 0, 2, 0, 8, 64, 0, 0,}}, + {{ 0, 0, 0, 0,136, 64, 0, 0,}}, + {{ 0, 0, 2, 0,136, 64, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 32, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 8, 0,}}, + {{ 0, 0, 1, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 1, 0, 0, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 40, 0,}}, + {{ 0, 0, 1, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 1, 0, 0, 0, 40, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 8, 0,}}, + {{ 0, 0, 1, 0, 16, 0, 0, 0,}}, + {{ 0, 0, 1, 0, 16, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 40, 0,}}, + {{ 0, 0, 1, 0, 16, 0, 32, 0,}}, + {{ 0, 0, 1, 0, 16, 0, 40, 0,}}, + }, + }, + { + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 8, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 4, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 12, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 8, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 4, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 12, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 8, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 4, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 12, 0, 0, 0, 0,}}, + {{ 0, 16, 16, 0, 0, 0, 0, 0,}}, + {{ 0, 16, 16, 8, 0, 0, 0, 0,}}, + {{ 0, 16, 16, 4, 0, 0, 0, 0,}}, + {{ 0, 16, 16, 12, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 1, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 1, 0, 0, 0, 0, 0, 0,}}, + {{ 1, 1, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 1, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 1, 0, 16, 0, 0, 0, 0,}}, + {{ 1, 1, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 4, 0, 0, 0, 0, 0, 0,}}, + {{ 1, 4, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 5, 0, 0, 0, 0, 0, 0,}}, + {{ 1, 5, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 4, 0, 16, 0, 0, 0, 0,}}, + {{ 1, 4, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 5, 0, 16, 0, 0, 0, 0,}}, + {{ 1, 5, 0, 16, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 0, 0, 4, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 4, 32, 0, 0, 0, 0,}}, + {{ 64, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 64, 0, 4, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 4, 32, 0, 0, 0, 0,}}, + {{ 0, 0, 64, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 64, 32, 0, 0, 0, 0,}}, + {{ 0, 0, 68, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 68, 32, 0, 0, 0, 0,}}, + {{ 64, 0, 64, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 64, 32, 0, 0, 0, 0,}}, + {{ 64, 0, 68, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 68, 32, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 64, 0, 0, 0, 0,}}, + {{ 0, 0, 32, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 32, 64, 0, 0, 0, 0,}}, + {{ 0, 0, 8, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 8, 64, 0, 0, 0, 0,}}, + {{ 0, 0, 40, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 40, 64, 0, 0, 0, 0,}}, + {{ 0, 0,128, 0, 0, 0, 0, 0,}}, + {{ 0, 0,128, 64, 0, 0, 0, 0,}}, + {{ 0, 0,160, 0, 0, 0, 0, 0,}}, + {{ 0, 0,160, 64, 0, 0, 0, 0,}}, + {{ 0, 0,136, 0, 0, 0, 0, 0,}}, + {{ 0, 0,136, 64, 0, 0, 0, 0,}}, + {{ 0, 0,168, 0, 0, 0, 0, 0,}}, + {{ 0, 0,168, 64, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 64, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 32,}}, + {{ 0, 0, 0, 0, 0, 64, 0, 32,}}, + {{ 0, 64, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 64, 0, 0, 0, 64, 0, 0,}}, + {{ 0, 64, 0, 0, 0, 0, 0, 32,}}, + {{ 0, 64, 0, 0, 0, 64, 0, 32,}}, + {{ 8, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 8, 0, 0, 0, 0, 64, 0, 0,}}, + {{ 8, 0, 0, 0, 0, 0, 0, 32,}}, + {{ 8, 0, 0, 0, 0, 64, 0, 32,}}, + {{ 8, 64, 0, 0, 0, 0, 0, 0,}}, + {{ 8, 64, 0, 0, 0, 64, 0, 0,}}, + {{ 8, 64, 0, 0, 0, 0, 0, 32,}}, + {{ 8, 64, 0, 0, 0, 64, 0, 32,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0,128, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0,128, 0, 0, 0, 0,}}, + {{ 0,128, 0,128, 0, 0, 0, 0,}}, + {{ 32, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 32,128, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 0, 0,128, 0, 0, 0, 0,}}, + {{ 32,128, 0,128, 0, 0, 0, 0,}}, + {{ 0, 32, 0, 0, 0, 0, 0, 0,}}, + {{ 0,160, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 32, 0,128, 0, 0, 0, 0,}}, + {{ 0,160, 0,128, 0, 0, 0, 0,}}, + {{ 32, 32, 0, 0, 0, 0, 0, 0,}}, + {{ 32,160, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 32, 0,128, 0, 0, 0, 0,}}, + {{ 32,160, 0,128, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 8, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 12, 0, 0, 0,}}, + {{ 4, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 4, 0, 0, 0, 4, 0, 0, 0,}}, + {{ 4, 0, 0, 0, 8, 0, 0, 0,}}, + {{ 4, 0, 0, 0, 12, 0, 0, 0,}}, + {{128, 0, 0, 0, 0, 0, 0, 0,}}, + {{128, 0, 0, 0, 4, 0, 0, 0,}}, + {{128, 0, 0, 0, 8, 0, 0, 0,}}, + {{128, 0, 0, 0, 12, 0, 0, 0,}}, + {{132, 0, 0, 0, 0, 0, 0, 0,}}, + {{132, 0, 0, 0, 4, 0, 0, 0,}}, + {{132, 0, 0, 0, 8, 0, 0, 0,}}, + {{132, 0, 0, 0, 12, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 2, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 2, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 18, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 18, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 8, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 10, 0, 0, 0, 0, 0, 0,}}, + {{ 2, 8, 0, 0, 0, 0, 0, 0,}}, + {{ 2, 10, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 8, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 10, 0, 0, 0, 0, 0, 0,}}, + {{ 18, 8, 0, 0, 0, 0, 0, 0,}}, + {{ 18, 10, 0, 0, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 16,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 64,}}, + {{ 0, 0, 1, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 1, 0, 0, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 64,}}, + {{ 0, 0, 1, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 1, 0, 0, 32, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 0,128, 0,}}, + {{ 0, 0, 0, 0, 0, 0,128, 64,}}, + {{ 0, 0, 1, 0, 0, 0,128, 0,}}, + {{ 0, 0, 1, 0, 0, 0,128, 64,}}, + {{ 0, 0, 0, 0, 0, 32,128, 0,}}, + {{ 0, 0, 0, 0, 0, 32,128, 64,}}, + {{ 0, 0, 1, 0, 0, 32,128, 0,}}, + {{ 0, 0, 1, 0, 0, 32,128, 64,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 32, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 8, 0,}}, + {{ 0, 0, 0, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 8, 0,}}, + {{ 0, 0, 0, 1, 16, 0, 0, 0,}}, + {{ 0, 0, 0, 1, 16, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 4,}}, + {{ 0, 0, 0, 0, 0, 0, 8, 4,}}, + {{ 0, 0, 0, 1, 0, 0, 0, 4,}}, + {{ 0, 0, 0, 1, 0, 0, 8, 4,}}, + {{ 0, 0, 0, 0, 16, 0, 0, 4,}}, + {{ 0, 0, 0, 0, 16, 0, 8, 4,}}, + {{ 0, 0, 0, 1, 16, 0, 0, 4,}}, + {{ 0, 0, 0, 1, 16, 0, 8, 4,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 8,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 0,}}, + {{ 0, 0, 0, 2, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 2, 32, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0,128,}}, + {{ 0, 0, 0, 0, 32, 0, 0,128,}}, + {{ 0, 0, 0, 2, 0, 0, 0,128,}}, + {{ 0, 0, 0, 2, 32, 0, 0,128,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 16, 0, 0,}}, + {{ 0, 0, 0, 2, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 2, 32, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 0,128,}}, + {{ 0, 0, 0, 0, 32, 16, 0,128,}}, + {{ 0, 0, 0, 2, 0, 16, 0,128,}}, + {{ 0, 0, 0, 2, 32, 16, 0,128,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 4, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0,128, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 0,}}, + {{ 0, 0, 0, 0, 0,128, 64, 0,}}, + {{ 0, 0, 0, 0,128, 0, 0, 0,}}, + {{ 0, 0, 0, 0,128,128, 0, 0,}}, + {{ 0, 0, 0, 0,128, 0, 64, 0,}}, + {{ 0, 0, 0, 0,128,128, 64, 0,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 0,}}, + {{ 0, 0, 0, 0, 0,132, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 4, 64, 0,}}, + {{ 0, 0, 0, 0, 0,132, 64, 0,}}, + {{ 0, 0, 0, 0,128, 4, 0, 0,}}, + {{ 0, 0, 0, 0,128,132, 0, 0,}}, + {{ 0, 0, 0, 0,128, 4, 64, 0,}}, + {{ 0, 0, 0, 0,128,132, 64, 0,}}, + }, + }, +}; + +/* Initial permutation/expansion table */ +static const C_block IE3264[32/CHUNKBITS][1<<CHUNKBITS] = { + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 4,}}, + {{ 4, 0, 0, 0, 0, 0, 0, 64,}}, + {{ 4, 0, 0, 0, 0, 0, 64, 68,}}, + {{ 0, 0, 0, 0, 64, 4, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 4, 64, 4,}}, + {{ 4, 0, 0, 0, 64, 4, 0, 64,}}, + {{ 4, 0, 0, 0, 64, 4, 64, 68,}}, + {{ 0, 0, 0, 0, 0, 64, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 64, 68, 4,}}, + {{ 4, 0, 0, 0, 0, 64, 4, 64,}}, + {{ 4, 0, 0, 0, 0, 64, 68, 68,}}, + {{ 0, 0, 0, 0, 64, 68, 4, 0,}}, + {{ 0, 0, 0, 0, 64, 68, 68, 4,}}, + {{ 4, 0, 0, 0, 64, 68, 4, 64,}}, + {{ 4, 0, 0, 0, 64, 68, 68, 68,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 64, 4, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 64, 4, 0, 0, 0,}}, + {{ 0, 0, 64, 68, 4, 0, 0, 0,}}, + {{ 64, 4, 0, 0, 0, 0, 0, 0,}}, + {{ 64, 4, 64, 4, 0, 0, 0, 0,}}, + {{ 64, 4, 0, 64, 4, 0, 0, 0,}}, + {{ 64, 4, 64, 68, 4, 0, 0, 0,}}, + {{ 0, 64, 4, 0, 0, 0, 0, 0,}}, + {{ 0, 64, 68, 4, 0, 0, 0, 0,}}, + {{ 0, 64, 4, 64, 4, 0, 0, 0,}}, + {{ 0, 64, 68, 68, 4, 0, 0, 0,}}, + {{ 64, 68, 4, 0, 0, 0, 0, 0,}}, + {{ 64, 68, 68, 4, 0, 0, 0, 0,}}, + {{ 64, 68, 4, 64, 4, 0, 0, 0,}}, + {{ 64, 68, 68, 68, 4, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 32,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 32,}}, + {{ 0, 0, 0, 0, 32, 0, 32, 32,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 32,}}, + {{ 0, 0, 0, 0, 0, 32, 32, 32,}}, + {{ 0, 0, 0, 0, 32, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 32, 32, 0,}}, + {{ 0, 0, 0, 0, 32, 32, 0, 32,}}, + {{ 0, 0, 0, 0, 32, 32, 32, 32,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 32, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 0, 0, 32, 32, 0, 0, 0, 0,}}, + {{ 32, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 0, 32, 0, 0, 0, 0, 0,}}, + {{ 32, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 32, 0, 32, 32, 0, 0, 0, 0,}}, + {{ 0, 32, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 32, 32, 0, 0, 0, 0, 0,}}, + {{ 0, 32, 0, 32, 0, 0, 0, 0,}}, + {{ 0, 32, 32, 32, 0, 0, 0, 0,}}, + {{ 32, 32, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 32, 32, 0, 0, 0, 0, 0,}}, + {{ 32, 32, 0, 32, 0, 0, 0, 0,}}, + {{ 32, 32, 32, 32, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 16,}}, + {{ 0, 0, 0, 0, 16, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 16, 0, 16, 16,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 16, 16, 16,}}, + {{ 0, 0, 0, 0, 16, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 16, 16, 16, 0,}}, + {{ 0, 0, 0, 0, 16, 16, 0, 16,}}, + {{ 0, 0, 0, 0, 16, 16, 16, 16,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 16, 0, 0, 0, 0,}}, + {{ 16, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 0, 16, 0, 0, 0, 0, 0,}}, + {{ 16, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 16, 0, 16, 16, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 16, 16, 0, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 16, 16, 16, 0, 0, 0, 0,}}, + {{ 16, 16, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 16, 16, 0, 0, 0, 0, 0,}}, + {{ 16, 16, 0, 16, 0, 0, 0, 0,}}, + {{ 16, 16, 16, 16, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0,128, 8, 0,}}, + {{ 0, 0, 0, 0, 0, 0,128, 8,}}, + {{ 0, 0, 0, 0, 0,128,136, 8,}}, + {{ 0, 0, 0,128, 8, 0, 0, 0,}}, + {{ 0, 0, 0,128, 8,128, 8, 0,}}, + {{ 0, 0, 0,128, 8, 0,128, 8,}}, + {{ 0, 0, 0,128, 8,128,136, 8,}}, + {{ 0, 0, 0, 0,128, 8, 0, 0,}}, + {{ 0, 0, 0, 0,128,136, 8, 0,}}, + {{ 0, 0, 0, 0,128, 8,128, 8,}}, + {{ 0, 0, 0, 0,128,136,136, 8,}}, + {{ 0, 0, 0,128,136, 8, 0, 0,}}, + {{ 0, 0, 0,128,136,136, 8, 0,}}, + {{ 0, 0, 0,128,136, 8,128, 8,}}, + {{ 0, 0, 0,128,136,136,136, 8,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0,128, 8, 0, 0, 0, 0, 0,}}, + {{ 0, 0,128, 8, 0, 0, 0, 0,}}, + {{ 0,128,136, 8, 0, 0, 0, 0,}}, + {{ 8, 0, 0, 0, 0, 0, 0,128,}}, + {{ 8,128, 8, 0, 0, 0, 0,128,}}, + {{ 8, 0,128, 8, 0, 0, 0,128,}}, + {{ 8,128,136, 8, 0, 0, 0,128,}}, + {{128, 8, 0, 0, 0, 0, 0, 0,}}, + {{128,136, 8, 0, 0, 0, 0, 0,}}, + {{128, 8,128, 8, 0, 0, 0, 0,}}, + {{128,136,136, 8, 0, 0, 0, 0,}}, + {{136, 8, 0, 0, 0, 0, 0,128,}}, + {{136,136, 8, 0, 0, 0, 0,128,}}, + {{136, 8,128, 8, 0, 0, 0,128,}}, + {{136,136,136, 8, 0, 0, 0,128,}}, + }, +}; + +/* Table that combines the S, P, and E operations. */ +static const unsigned long SPE[2][8][64] = { + { + { + 0x80088000,0x80000000, 0,0x80088000, + 0,0x80088000,0x80000000, 0, + 0x80088000,0x80088000,0x80000000, 0x88000, + 0x88000, 0, 0,0x80000000, + 0x80000000, 0, 0x88000,0x80088000, + 0x80088000,0x80000000, 0x88000, 0x88000, + 0, 0x88000,0x80088000,0x80000000, + 0x88000, 0x88000,0x80000000, 0, + 0,0x80088000, 0x88000,0x80000000, + 0x80088000,0x80000000, 0x88000, 0x88000, + 0x80000000, 0x88000,0x80088000, 0, + 0x80088000, 0, 0,0x80000000, + 0x80088000,0x80088000,0x80000000, 0x88000, + 0, 0x88000,0x80000000, 0, + 0x80000000, 0, 0x88000,0x80088000, + 0,0x80000000, 0x88000,0x80088000, + }, + { + 0x8800010, 0, 0x8800000, 0, + 0x10, 0x8800010, 0x8800000, 0x8800000, + 0x8800000, 0x10, 0x10, 0x8800000, + 0x10, 0x8800000, 0, 0x10, + 0, 0x8800010, 0x10, 0x8800000, + 0x8800010, 0, 0, 0x10, + 0x8800010, 0x8800010, 0x8800000, 0x10, + 0, 0, 0x8800010, 0x8800010, + 0x10, 0x8800000, 0x8800000, 0x8800010, + 0x8800010, 0x10, 0x10, 0, + 0, 0x8800010, 0, 0x10, + 0x8800000, 0, 0x8800010, 0x8800010, + 0x8800000, 0x8800000, 0, 0x10, + 0x10, 0x8800010, 0x8800000, 0, + 0x10, 0, 0x8800010, 0x8800000, + 0x8800010, 0x10, 0, 0x8800000, + }, + { + 0,0x40001000, 0x1000, 0x1000, + 0x40000000, 0, 0x1000,0x40001000, + 0x1000,0x40000000,0x40000000, 0, + 0x40001000, 0x1000, 0,0x40000000, + 0,0x40000000,0x40001000, 0x1000, + 0x1000,0x40001000,0x40000000, 0, + 0x40000000, 0x1000,0x40001000,0x40000000, + 0x40001000, 0, 0,0x40001000, + 0x40001000, 0x1000, 0,0x40000000, + 0x1000,0x40000000,0x40000000, 0x1000, + 0,0x40001000,0x40001000,0x40000000, + 0x40000000, 0,0x40001000, 0, + 0x40001000, 0, 0,0x40001000, + 0x40000000, 0x1000, 0x1000,0x40001000, + 0x1000, 0,0x40000000, 0x1000, + 0,0x40001000, 0x1000,0x40000000, + }, + { + 0x100008, 0x100000, 0x8, 0x100008, + 0, 0, 0x100008, 0x8, + 0x100000, 0x8, 0, 0x100008, + 0x8, 0x100008, 0, 0, + 0x8, 0x100000, 0x100000, 0x8, + 0x100000, 0x100008, 0, 0x100000, + 0x100008, 0, 0x8, 0x100000, + 0x100000, 0x8, 0x100008, 0, + 0x8, 0x100008, 0, 0x8, + 0x100000, 0x100000, 0x8, 0, + 0x100008, 0, 0x100000, 0x8, + 0, 0x8, 0x100000, 0x100000, + 0, 0x100008, 0x100008, 0, + 0x100008, 0x8, 0x100000, 0x100008, + 0x8, 0x100000, 0, 0x100008, + 0x100008, 0, 0x8, 0x100000, + }, + { + 0,0x10000000, 0x44000,0x10044020, + 0x10000020, 0x44000,0x10044020,0x10000000, + 0x10000000, 0x20, 0x20,0x10044000, + 0x44020,0x10000020,0x10044000, 0, + 0x10044000, 0,0x10000020, 0x44020, + 0x44000,0x10044020, 0, 0x20, + 0x20, 0x44020,0x10044020,0x10000020, + 0x10000000, 0x44000, 0x44020,0x10044000, + 0x10044000, 0x44020,0x10000020,0x10000000, + 0x10000000, 0x20, 0x20, 0x44000, + 0,0x10044000,0x10044020, 0, + 0x10044020, 0, 0x44000,0x10000020, + 0x44020, 0x44000, 0,0x10044020, + 0x10000020,0x10044000, 0x44020,0x10000000, + 0x10044000,0x10000020, 0x44000, 0x44020, + 0x20,0x10044020,0x10000000, 0x20, + }, + { + 0x440, 0x440, 0, 0x200000, + 0x440, 0x200000, 0x200440, 0, + 0x200440, 0x200440, 0x200000, 0, + 0x200000, 0x440, 0, 0x200440, + 0, 0x200440, 0x440, 0, + 0x200000, 0x440, 0x200000, 0x440, + 0x200440, 0, 0, 0x200440, + 0x440, 0x200000, 0x200440, 0x200000, + 0x200440, 0, 0x200000, 0x200440, + 0x200000, 0x440, 0, 0x200000, + 0, 0x200000, 0x440, 0, + 0x440, 0x200440, 0x200000, 0x440, + 0x200440, 0x200000, 0, 0x200440, + 0x440, 0, 0x200440, 0, + 0x200000, 0x440, 0x200440, 0x200000, + 0, 0x200440, 0x440, 0x440, + }, + { + 0x4400000, 0x2000, 0x2000, 0x4, + 0x4402004, 0x4400004, 0x4402000, 0, + 0, 0x2004, 0x2004, 0x4400000, + 0x4, 0x4402000, 0x4400000, 0x2004, + 0x2004, 0x4400000, 0x4400004, 0x4402004, + 0, 0x2000, 0x4, 0x4402000, + 0x4400004, 0x4402004, 0x4402000, 0x4, + 0x4402004, 0x4400004, 0x2000, 0, + 0x4402004, 0x4400000, 0x4400004, 0x2004, + 0x4400000, 0x2000, 0, 0x4400004, + 0x2004, 0x4402004, 0x4402000, 0, + 0x2000, 0x4, 0x4, 0x2000, + 0, 0x2004, 0x2000, 0x4402000, + 0x2004, 0x4400000, 0x4402004, 0, + 0x4402000, 0x4, 0x4400004, 0x4402004, + 0x4, 0x4402000, 0x4400000, 0x4400004, + }, + { + 0x880,0x20000000,0x20000880, 0, + 0x20000000, 0x880, 0,0x20000880, + 0x880, 0,0x20000000,0x20000880, + 0x20000880,0x20000880, 0x880, 0, + 0x20000000,0x20000880, 0x880,0x20000000, + 0x20000880, 0x880, 0,0x20000000, + 0, 0,0x20000880, 0x880, + 0,0x20000000,0x20000000, 0x880, + 0,0x20000000, 0x880,0x20000880, + 0x20000880, 0, 0,0x20000000, + 0x880,0x20000880,0x20000000, 0x880, + 0x20000000, 0x880, 0x880,0x20000000, + 0x20000880, 0, 0, 0x880, + 0x20000000,0x20000880,0x20000880, 0, + 0x880,0x20000000,0x20000880, 0, + 0, 0x880,0x20000000,0x20000880, + }, + }, + { + { + 0x2008, 0x8,0x20002000,0x20002008, + 0x2000,0x20000008,0x20000008,0x20002000, + 0x20000008, 0x2008, 0x2008,0x20000000, + 0x20002000, 0x2000, 0,0x20000008, + 0x8,0x20000000, 0x2000, 0x8, + 0x20002008, 0x2008,0x20000000, 0x2000, + 0x20000000, 0, 0x8,0x20002008, + 0,0x20002000,0x20002008, 0, + 0,0x20002008, 0x2000,0x20000008, + 0x2008, 0x8,0x20000000, 0x2000, + 0x20002008, 0, 0x8,0x20002000, + 0x20000008,0x20000000,0x20002000, 0x2008, + 0x20002008, 0x8, 0x2008,0x20002000, + 0x2000,0x20000000,0x20000008, 0, + 0x8, 0x2000,0x20002000, 0x2008, + 0x20000000,0x20002008, 0,0x20000008, + }, + { + 0x4400010, 0, 0x10, 0x4400010, + 0x4400000, 0, 0x4400000, 0x10, + 0, 0x4400010, 0, 0x4400000, + 0x10, 0x4400010, 0x4400010, 0, + 0x10, 0x4400000, 0x4400010, 0, + 0x10, 0x4400000, 0, 0x10, + 0x4400000, 0x10, 0x4400010, 0x4400000, + 0x4400000, 0x10, 0, 0x4400010, + 0x10, 0x4400010, 0x4400000, 0x10, + 0x4400010, 0x10, 0x4400000, 0, + 0x4400000, 0, 0x10, 0x4400010, + 0, 0x4400000, 0x10, 0x4400000, + 0x4400010, 0, 0, 0x4400000, + 0, 0x4400010, 0x10, 0x4400010, + 0x4400010, 0x10, 0, 0x4400000, + 0x4400000, 0, 0x4400010, 0x10, + }, + { + 0x10044000, 0x44004, 0,0x10044000, + 0x10000004, 0x44000,0x10044000, 0x4, + 0x44000, 0x4, 0x44004,0x10000000, + 0x10044004,0x10000000,0x10000000,0x10044004, + 0,0x10000004, 0x44004, 0, + 0x10000000,0x10044004, 0x4,0x10044000, + 0x10044004, 0x44000,0x10000004, 0x44004, + 0x4, 0, 0x44000,0x10000004, + 0x44004, 0,0x10000000, 0x4, + 0x10000000,0x10000004, 0x44004,0x10044000, + 0, 0x44004, 0x4,0x10044004, + 0x10000004, 0x44000,0x10044004,0x10000000, + 0x10000004,0x10044000, 0x44000,0x10044004, + 0x4, 0x44000,0x10044000, 0x4, + 0x44000, 0,0x10044004,0x10000000, + 0x10044000,0x10000004, 0, 0x44004, + }, + { + 0x80000440, 0x100000,0x80000000,0x80100440, + 0, 0x100440,0x80100000,0x80000440, + 0x100440,0x80100000, 0x100000,0x80000000, + 0x80100000,0x80000440, 0x440, 0x100000, + 0x80100440, 0x440, 0,0x80000000, + 0x440,0x80100000, 0x100440, 0, + 0x80000000, 0,0x80000440, 0x100440, + 0x100000,0x80100440,0x80100440, 0x440, + 0x80100440,0x80000000, 0x440,0x80100000, + 0x440, 0x100000,0x80000000, 0x100440, + 0x80100000, 0, 0,0x80000440, + 0,0x80100440, 0x100440, 0, + 0x100000,0x80100440,0x80000440, 0x440, + 0x80100440,0x80000000, 0x100000,0x80000440, + 0x80000440, 0x440, 0x100440,0x80100000, + 0x80000000, 0x100000,0x80100000, 0x100440, + }, + { + 0x88000, 0, 0, 0x88000, + 0x88000, 0x88000, 0, 0x88000, + 0, 0, 0x88000, 0, + 0x88000, 0x88000, 0x88000, 0, + 0, 0x88000, 0, 0, + 0x88000, 0, 0, 0x88000, + 0, 0x88000, 0x88000, 0, + 0x88000, 0, 0, 0x88000, + 0x88000, 0x88000, 0, 0x88000, + 0, 0, 0x88000, 0x88000, + 0x88000, 0, 0x88000, 0, + 0, 0x88000, 0, 0, + 0x88000, 0, 0, 0x88000, + 0x88000, 0x88000, 0, 0, + 0, 0x88000, 0x88000, 0, + 0, 0, 0x88000, 0x88000, + }, + { + 0x8800000, 0x20, 0, 0x8800020, + 0x20, 0, 0x8800000, 0x20, + 0, 0x8800020, 0x20, 0x8800000, + 0x8800000, 0x8800000, 0x8800020, 0x20, + 0x20, 0x8800000, 0x8800020, 0, + 0, 0, 0x8800020, 0x8800020, + 0x8800020, 0x8800020, 0x8800000, 0, + 0, 0x20, 0x20, 0x8800000, + 0, 0x8800000, 0x8800000, 0x20, + 0x8800020, 0x20, 0, 0x8800000, + 0x8800000, 0, 0x8800020, 0x20, + 0x20, 0x8800020, 0x20, 0, + 0x8800020, 0x20, 0x20, 0x8800000, + 0x8800000, 0x8800020, 0x20, 0, + 0, 0x8800000, 0x8800000, 0x8800020, + 0x8800020, 0, 0, 0x8800020, + }, + { + 0, 0, 0x1000,0x40001000, + 0x40001000,0x40000000, 0, 0, + 0x1000,0x40001000,0x40000000, 0x1000, + 0x40000000, 0x1000, 0x1000,0x40000000, + 0x40001000, 0,0x40000000,0x40001000, + 0, 0x1000,0x40001000, 0, + 0x40001000,0x40000000, 0x1000,0x40000000, + 0x40000000,0x40001000, 0, 0x1000, + 0x40000000, 0x1000,0x40001000,0x40000000, + 0, 0, 0x1000,0x40001000, + 0x40001000,0x40000000, 0, 0, + 0,0x40001000,0x40000000, 0x1000, + 0,0x40001000, 0x1000, 0, + 0x40000000, 0,0x40001000, 0x1000, + 0x1000,0x40000000,0x40000000,0x40001000, + 0x40001000, 0x1000, 0x1000,0x40000000, + }, + { + 0x200880, 0x200880, 0, 0, + 0x200000, 0x880, 0x200880, 0x200880, + 0, 0x200000, 0x880, 0, + 0x880, 0x200000, 0x200000, 0x200880, + 0, 0x880, 0x880, 0x200000, + 0x200880, 0x200000, 0, 0x880, + 0x200000, 0x880, 0x200000, 0x200880, + 0x880, 0, 0x200880, 0, + 0x880, 0, 0x200000, 0x200880, + 0, 0x200000, 0, 0x880, + 0x200880, 0x200000, 0x200000, 0x880, + 0x200880, 0, 0x880, 0x200000, + 0x200880, 0x880, 0x200880, 0x200000, + 0x880, 0, 0x200000, 0x200880, + 0, 0x200880, 0x880, 0, + 0x200000, 0x200880, 0, 0x880, + }, + }, +}; + +/* compressed/interleaved => final permutation table */ +static const C_block CF6464[64/CHUNKBITS][1<<CHUNKBITS] = { + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 64, 64,}}, + {{ 0, 0, 0, 0, 0, 64, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 64, 0, 64,}}, + {{ 0, 0, 0, 0, 0, 64, 64, 0,}}, + {{ 0, 0, 0, 0, 0, 64, 64, 64,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 0, 64,}}, + {{ 0, 0, 0, 0, 64, 0, 64, 0,}}, + {{ 0, 0, 0, 0, 64, 0, 64, 64,}}, + {{ 0, 0, 0, 0, 64, 64, 0, 0,}}, + {{ 0, 0, 0, 0, 64, 64, 0, 64,}}, + {{ 0, 0, 0, 0, 64, 64, 64, 0,}}, + {{ 0, 0, 0, 0, 64, 64, 64, 64,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 4,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 4, 4,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 4, 0, 4,}}, + {{ 0, 0, 0, 0, 0, 4, 4, 0,}}, + {{ 0, 0, 0, 0, 0, 4, 4, 4,}}, + {{ 0, 0, 0, 0, 4, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 0, 4,}}, + {{ 0, 0, 0, 0, 4, 0, 4, 0,}}, + {{ 0, 0, 0, 0, 4, 0, 4, 4,}}, + {{ 0, 0, 0, 0, 4, 4, 0, 0,}}, + {{ 0, 0, 0, 0, 4, 4, 0, 4,}}, + {{ 0, 0, 0, 0, 4, 4, 4, 0,}}, + {{ 0, 0, 0, 0, 4, 4, 4, 4,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 64, 0, 0, 0, 0,}}, + {{ 0, 0, 64, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 64, 64, 0, 0, 0, 0,}}, + {{ 0, 64, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 64, 0, 64, 0, 0, 0, 0,}}, + {{ 0, 64, 64, 0, 0, 0, 0, 0,}}, + {{ 0, 64, 64, 64, 0, 0, 0, 0,}}, + {{ 64, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 0, 64, 0, 0, 0, 0,}}, + {{ 64, 0, 64, 0, 0, 0, 0, 0,}}, + {{ 64, 0, 64, 64, 0, 0, 0, 0,}}, + {{ 64, 64, 0, 0, 0, 0, 0, 0,}}, + {{ 64, 64, 0, 64, 0, 0, 0, 0,}}, + {{ 64, 64, 64, 0, 0, 0, 0, 0,}}, + {{ 64, 64, 64, 64, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 4, 0, 0, 0, 0,}}, + {{ 0, 0, 4, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 4, 4, 0, 0, 0, 0,}}, + {{ 0, 4, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 4, 0, 4, 0, 0, 0, 0,}}, + {{ 0, 4, 4, 0, 0, 0, 0, 0,}}, + {{ 0, 4, 4, 4, 0, 0, 0, 0,}}, + {{ 4, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 4, 0, 0, 4, 0, 0, 0, 0,}}, + {{ 4, 0, 4, 0, 0, 0, 0, 0,}}, + {{ 4, 0, 4, 4, 0, 0, 0, 0,}}, + {{ 4, 4, 0, 0, 0, 0, 0, 0,}}, + {{ 4, 4, 0, 4, 0, 0, 0, 0,}}, + {{ 4, 4, 4, 0, 0, 0, 0, 0,}}, + {{ 4, 4, 4, 4, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 16, 16,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 0, 16,}}, + {{ 0, 0, 0, 0, 0, 16, 16, 0,}}, + {{ 0, 0, 0, 0, 0, 16, 16, 16,}}, + {{ 0, 0, 0, 0, 16, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 0, 16,}}, + {{ 0, 0, 0, 0, 16, 0, 16, 0,}}, + {{ 0, 0, 0, 0, 16, 0, 16, 16,}}, + {{ 0, 0, 0, 0, 16, 16, 0, 0,}}, + {{ 0, 0, 0, 0, 16, 16, 0, 16,}}, + {{ 0, 0, 0, 0, 16, 16, 16, 0,}}, + {{ 0, 0, 0, 0, 16, 16, 16, 16,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 1,}}, + {{ 0, 0, 0, 0, 0, 0, 1, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 1, 1,}}, + {{ 0, 0, 0, 0, 0, 1, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 1, 0, 1,}}, + {{ 0, 0, 0, 0, 0, 1, 1, 0,}}, + {{ 0, 0, 0, 0, 0, 1, 1, 1,}}, + {{ 0, 0, 0, 0, 1, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 1, 0, 0, 1,}}, + {{ 0, 0, 0, 0, 1, 0, 1, 0,}}, + {{ 0, 0, 0, 0, 1, 0, 1, 1,}}, + {{ 0, 0, 0, 0, 1, 1, 0, 0,}}, + {{ 0, 0, 0, 0, 1, 1, 0, 1,}}, + {{ 0, 0, 0, 0, 1, 1, 1, 0,}}, + {{ 0, 0, 0, 0, 1, 1, 1, 1,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 16, 16, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 16, 0, 16, 0, 0, 0, 0,}}, + {{ 0, 16, 16, 0, 0, 0, 0, 0,}}, + {{ 0, 16, 16, 16, 0, 0, 0, 0,}}, + {{ 16, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 0, 0, 16, 0, 0, 0, 0,}}, + {{ 16, 0, 16, 0, 0, 0, 0, 0,}}, + {{ 16, 0, 16, 16, 0, 0, 0, 0,}}, + {{ 16, 16, 0, 0, 0, 0, 0, 0,}}, + {{ 16, 16, 0, 16, 0, 0, 0, 0,}}, + {{ 16, 16, 16, 0, 0, 0, 0, 0,}}, + {{ 16, 16, 16, 16, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 1, 0, 0, 0, 0,}}, + {{ 0, 0, 1, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 1, 1, 0, 0, 0, 0,}}, + {{ 0, 1, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 1, 0, 1, 0, 0, 0, 0,}}, + {{ 0, 1, 1, 0, 0, 0, 0, 0,}}, + {{ 0, 1, 1, 1, 0, 0, 0, 0,}}, + {{ 1, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 1, 0, 0, 1, 0, 0, 0, 0,}}, + {{ 1, 0, 1, 0, 0, 0, 0, 0,}}, + {{ 1, 0, 1, 1, 0, 0, 0, 0,}}, + {{ 1, 1, 0, 0, 0, 0, 0, 0,}}, + {{ 1, 1, 0, 1, 0, 0, 0, 0,}}, + {{ 1, 1, 1, 0, 0, 0, 0, 0,}}, + {{ 1, 1, 1, 1, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0,128,}}, + {{ 0, 0, 0, 0, 0, 0,128, 0,}}, + {{ 0, 0, 0, 0, 0, 0,128,128,}}, + {{ 0, 0, 0, 0, 0,128, 0, 0,}}, + {{ 0, 0, 0, 0, 0,128, 0,128,}}, + {{ 0, 0, 0, 0, 0,128,128, 0,}}, + {{ 0, 0, 0, 0, 0,128,128,128,}}, + {{ 0, 0, 0, 0,128, 0, 0, 0,}}, + {{ 0, 0, 0, 0,128, 0, 0,128,}}, + {{ 0, 0, 0, 0,128, 0,128, 0,}}, + {{ 0, 0, 0, 0,128, 0,128,128,}}, + {{ 0, 0, 0, 0,128,128, 0, 0,}}, + {{ 0, 0, 0, 0,128,128, 0,128,}}, + {{ 0, 0, 0, 0,128,128,128, 0,}}, + {{ 0, 0, 0, 0,128,128,128,128,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 0, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 8, 8,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 0, 8,}}, + {{ 0, 0, 0, 0, 0, 8, 8, 0,}}, + {{ 0, 0, 0, 0, 0, 8, 8, 8,}}, + {{ 0, 0, 0, 0, 8, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 8, 0, 0, 8,}}, + {{ 0, 0, 0, 0, 8, 0, 8, 0,}}, + {{ 0, 0, 0, 0, 8, 0, 8, 8,}}, + {{ 0, 0, 0, 0, 8, 8, 0, 0,}}, + {{ 0, 0, 0, 0, 8, 8, 0, 8,}}, + {{ 0, 0, 0, 0, 8, 8, 8, 0,}}, + {{ 0, 0, 0, 0, 8, 8, 8, 8,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0,128, 0, 0, 0, 0,}}, + {{ 0, 0,128, 0, 0, 0, 0, 0,}}, + {{ 0, 0,128,128, 0, 0, 0, 0,}}, + {{ 0,128, 0, 0, 0, 0, 0, 0,}}, + {{ 0,128, 0,128, 0, 0, 0, 0,}}, + {{ 0,128,128, 0, 0, 0, 0, 0,}}, + {{ 0,128,128,128, 0, 0, 0, 0,}}, + {{128, 0, 0, 0, 0, 0, 0, 0,}}, + {{128, 0, 0,128, 0, 0, 0, 0,}}, + {{128, 0,128, 0, 0, 0, 0, 0,}}, + {{128, 0,128,128, 0, 0, 0, 0,}}, + {{128,128, 0, 0, 0, 0, 0, 0,}}, + {{128,128, 0,128, 0, 0, 0, 0,}}, + {{128,128,128, 0, 0, 0, 0, 0,}}, + {{128,128,128,128, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 8, 0, 0, 0, 0,}}, + {{ 0, 0, 8, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 8, 8, 0, 0, 0, 0,}}, + {{ 0, 8, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 8, 0, 8, 0, 0, 0, 0,}}, + {{ 0, 8, 8, 0, 0, 0, 0, 0,}}, + {{ 0, 8, 8, 8, 0, 0, 0, 0,}}, + {{ 8, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 8, 0, 0, 8, 0, 0, 0, 0,}}, + {{ 8, 0, 8, 0, 0, 0, 0, 0,}}, + {{ 8, 0, 8, 8, 0, 0, 0, 0,}}, + {{ 8, 8, 0, 0, 0, 0, 0, 0,}}, + {{ 8, 8, 0, 8, 0, 0, 0, 0,}}, + {{ 8, 8, 8, 0, 0, 0, 0, 0,}}, + {{ 8, 8, 8, 8, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 32,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 32, 32,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 0, 32,}}, + {{ 0, 0, 0, 0, 0, 32, 32, 0,}}, + {{ 0, 0, 0, 0, 0, 32, 32, 32,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 0, 0, 32,}}, + {{ 0, 0, 0, 0, 32, 0, 32, 0,}}, + {{ 0, 0, 0, 0, 32, 0, 32, 32,}}, + {{ 0, 0, 0, 0, 32, 32, 0, 0,}}, + {{ 0, 0, 0, 0, 32, 32, 0, 32,}}, + {{ 0, 0, 0, 0, 32, 32, 32, 0,}}, + {{ 0, 0, 0, 0, 32, 32, 32, 32,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 0, 2,}}, + {{ 0, 0, 0, 0, 0, 0, 2, 0,}}, + {{ 0, 0, 0, 0, 0, 0, 2, 2,}}, + {{ 0, 0, 0, 0, 0, 2, 0, 0,}}, + {{ 0, 0, 0, 0, 0, 2, 0, 2,}}, + {{ 0, 0, 0, 0, 0, 2, 2, 0,}}, + {{ 0, 0, 0, 0, 0, 2, 2, 2,}}, + {{ 0, 0, 0, 0, 2, 0, 0, 0,}}, + {{ 0, 0, 0, 0, 2, 0, 0, 2,}}, + {{ 0, 0, 0, 0, 2, 0, 2, 0,}}, + {{ 0, 0, 0, 0, 2, 0, 2, 2,}}, + {{ 0, 0, 0, 0, 2, 2, 0, 0,}}, + {{ 0, 0, 0, 0, 2, 2, 0, 2,}}, + {{ 0, 0, 0, 0, 2, 2, 2, 0,}}, + {{ 0, 0, 0, 0, 2, 2, 2, 2,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 0, 0, 32, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 32, 32, 0, 0, 0, 0,}}, + {{ 0, 32, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 32, 0, 32, 0, 0, 0, 0,}}, + {{ 0, 32, 32, 0, 0, 0, 0, 0,}}, + {{ 0, 32, 32, 32, 0, 0, 0, 0,}}, + {{ 32, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 0, 0, 32, 0, 0, 0, 0,}}, + {{ 32, 0, 32, 0, 0, 0, 0, 0,}}, + {{ 32, 0, 32, 32, 0, 0, 0, 0,}}, + {{ 32, 32, 0, 0, 0, 0, 0, 0,}}, + {{ 32, 32, 0, 32, 0, 0, 0, 0,}}, + {{ 32, 32, 32, 0, 0, 0, 0, 0,}}, + {{ 32, 32, 32, 32, 0, 0, 0, 0,}}, + }, + { + {{ 0, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 0, 2, 0, 0, 0, 0,}}, + {{ 0, 0, 2, 0, 0, 0, 0, 0,}}, + {{ 0, 0, 2, 2, 0, 0, 0, 0,}}, + {{ 0, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 0, 2, 0, 2, 0, 0, 0, 0,}}, + {{ 0, 2, 2, 0, 0, 0, 0, 0,}}, + {{ 0, 2, 2, 2, 0, 0, 0, 0,}}, + {{ 2, 0, 0, 0, 0, 0, 0, 0,}}, + {{ 2, 0, 0, 2, 0, 0, 0, 0,}}, + {{ 2, 0, 2, 0, 0, 0, 0, 0,}}, + {{ 2, 0, 2, 2, 0, 0, 0, 0,}}, + {{ 2, 2, 0, 0, 0, 0, 0, 0,}}, + {{ 2, 2, 0, 2, 0, 0, 0, 0,}}, + {{ 2, 2, 2, 0, 0, 0, 0, 0,}}, + {{ 2, 2, 2, 2, 0, 0, 0, 0,}}, + }, +}; + +#define HAVE_DES_TABLES 1 +#endif diff --git a/missing/dtoa.c b/missing/dtoa.c new file mode 100644 index 0000000000..ba8cd46ebd --- /dev/null +++ b/missing/dtoa.c @@ -0,0 +1,3509 @@ +/**************************************************************** + * + * The author of this software is David M. Gay. + * + * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + * + ***************************************************************/ + +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ + +/* On a machine with IEEE extended-precision registers, it is + * necessary to specify double-precision (53-bit) rounding precision + * before invoking strtod or dtoa. If the machine uses (the equivalent + * of) Intel 80x87 arithmetic, the call + * _control87(PC_53, MCW_PC); + * does this with many compilers. Whether this or another call is + * appropriate depends on the compiler; for this to work, it may be + * necessary to #include "float.h" or another system-dependent header + * file. + */ + +/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. + * + * This strtod returns a nearest machine number to the input decimal + * string (or sets errno to ERANGE). With IEEE arithmetic, ties are + * broken by the IEEE round-even rule. Otherwise ties are broken by + * biased rounding (add half and chop). + * + * Inspired loosely by William D. Clinger's paper "How to Read Floating + * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. + * + * Modifications: + * + * 1. We only require IEEE, IBM, or VAX double-precision + * arithmetic (not IEEE double-extended). + * 2. We get by with floating-point arithmetic in a case that + * Clinger missed -- when we're computing d * 10^n + * for a small integer d and the integer n is not too + * much larger than 22 (the maximum integer k for which + * we can represent 10^k exactly), we may be able to + * compute (d*10^k) * 10^(e-k) with just one roundoff. + * 3. Rather than a bit-at-a-time adjustment of the binary + * result in the hard case, we use floating-point + * arithmetic to determine the adjustment to within + * one bit; only in really hard cases do we need to + * compute a second residual. + * 4. Because of 3., we don't need a large table of powers of 10 + * for ten-to-e (just some small tables, e.g. of 10^k + * for 0 <= k <= 22). + */ + +/* + * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least + * significant byte has the lowest address. + * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most + * significant byte has the lowest address. + * #define Long int on machines with 32-bit ints and 64-bit longs. + * #define IBM for IBM mainframe-style floating-point arithmetic. + * #define VAX for VAX-style floating-point arithmetic (D_floating). + * #define No_leftright to omit left-right logic in fast floating-point + * computation of dtoa. + * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and strtod and dtoa should round accordingly. + * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 + * and Honor_FLT_ROUNDS is not #defined. + * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines + * that use extended-precision instructions to compute rounded + * products and quotients) with IBM. + * #define ROUND_BIASED for IEEE-format with biased rounding. + * #define Inaccurate_Divide for IEEE-format with correctly rounded + * products but inaccurate quotients, e.g., for Intel i860. + * #define NO_LONG_LONG on machines that do not have a "long long" + * integer type (of >= 64 bits). On such machines, you can + * #define Just_16 to store 16 bits per 32-bit Long when doing + * high-precision integer arithmetic. Whether this speeds things + * up or slows things down depends on the machine and the number + * being converted. If long long is available and the name is + * something other than "long long", #define Llong to be the name, + * and if "unsigned Llong" does not work as an unsigned version of + * Llong, #define #ULLong to be the corresponding unsigned type. + * #define KR_headers for old-style C function headers. + * #define Bad_float_h if your system lacks a float.h or if it does not + * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, + * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. + * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) + * if memory is available and otherwise does something you deem + * appropriate. If MALLOC is undefined, malloc will be invoked + * directly -- and assumed always to succeed. + * #define INFNAN_CHECK on IEEE systems to cause strtod to check for + * Infinity and NaN (case insensitively). On some systems (e.g., + * some HP systems), it may be necessary to #define NAN_WORD0 + * appropriately -- to the most significant word of a quiet NaN. + * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) + * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, + * strtod also accepts (case insensitively) strings of the form + * NaN(x), where x is a string of hexadecimal digits and spaces; + * if there is only one string of hexadecimal digits, it is taken + * for the 52 fraction bits of the resulting NaN; if there are two + * or more strings of hex digits, the first is for the high 20 bits, + * the second and subsequent for the low 32 bits, with intervening + * white space ignored; but if this results in none of the 52 + * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 + * and NAN_WORD1 are used instead. + * #define MULTIPLE_THREADS if the system offers preemptively scheduled + * multiple threads. In this case, you must provide (or suitably + * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed + * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed + * in pow5mult, ensures lazy evaluation of only one copy of high + * powers of 5; omitting this lock would introduce a small + * probability of wasting memory, but would otherwise be harmless.) + * You must also invoke freedtoa(s) to free the value s returned by + * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. + * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that + * avoids underflows on inputs whose result does not underflow. + * If you #define NO_IEEE_Scale on a machine that uses IEEE-format + * floating-point numbers and flushes underflows to zero rather + * than implementing gradual underflow, then you must also #define + * Sudden_Underflow. + * #define YES_ALIAS to permit aliasing certain double values with + * arrays of ULongs. This leads to slightly better code with + * some compilers and was always used prior to 19990916, but it + * is not strictly legal and can cause trouble with aggressively + * optimizing compilers (e.g., gcc 2.95.1 under -O2). + * #define USE_LOCALE to use the current locale's decimal_point value. + * #define SET_INEXACT if IEEE arithmetic is being used and extra + * computation should be done to set the inexact flag when the + * result is inexact and avoid setting inexact when the result + * is exact. In this case, dtoa.c must be compiled in + * an environment, perhaps provided by #include "dtoa.c" in a + * suitable wrapper, that defines two functions, + * int get_inexact(void); + * void clear_inexact(void); + * such that get_inexact() returns a nonzero value if the + * inexact bit is already set, and clear_inexact() sets the + * inexact bit to 0. When SET_INEXACT is #defined, strtod + * also does extra computations to set the underflow and overflow + * flags when appropriate (i.e., when the result is tiny and + * inexact or when it is a numeric value rounded to +-infinity). + * #define NO_ERRNO if strtod should not assign errno = ERANGE when + * the result overflows to +-Infinity or underflows to 0. + */ + +#ifdef WORDS_BIGENDIAN +#define IEEE_BIG_ENDIAN +#else +#define IEEE_LITTLE_ENDIAN +#endif + +#ifdef __vax__ +#define VAX +#undef IEEE_BIG_ENDIAN +#undef IEEE_LITTLE_ENDIAN +#endif + +#if defined(__arm__) && !defined(__VFP_FP__) +#define IEEE_BIG_ENDIAN +#undef IEEE_LITTLE_ENDIAN +#endif + +#undef Long +#undef ULong + +#include <assert.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h> + +#if (INT_MAX >> 30) && !(INT_MAX >> 31) +#define Long int +#define ULong unsigned int +#elif (LONG_MAX >> 30) && !(LONG_MAX >> 31) +#define Long long int +#define ULong unsigned long int +#else +#error No 32bit integer +#endif + +#if defined(HAVE_LONG_LONG) && (HAVE_LONG_LONG) +#define Llong LONG_LONG +#else +#define NO_LONG_LONG +#endif + +#ifdef DEBUG +#include <stdio.h> +#define Bug(x) {fprintf(stderr, "%s\n", (x)); exit(EXIT_FAILURE);} +#endif + +#ifndef ISDIGIT +#include <ctype.h> +#define ISDIGIT(c) isdigit(c) +#endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#ifdef USE_LOCALE +#include <locale.h> +#endif + +#if defined(HAVE_STDCKDINT_H) || !defined(__has_include) +#elif __has_include(<stdckdint.h>) +# define HAVE_STDCKDINT_H 1 +#endif +#ifdef HAVE_STDCKDINT_H +# include <stdckdint.h> +#endif + +#if !defined(ckd_add) +static inline int /* bool */ +ckd_add(int *result, int x, int y) +{ + if (x < 0) { + if (y < INT_MIN - x) return 1; + } + else if (x > 0) { + if (y > INT_MAX - x) return 1; + } + *result = x + y; + return 0; +} +#endif + +#ifdef MALLOC +extern void *MALLOC(size_t); +#else +#define MALLOC malloc +#endif +#ifdef FREE +extern void FREE(void*); +#else +#define FREE free +#endif +#ifndef NO_SANITIZE +#define NO_SANITIZE(x, y) y +#endif + +#undef IEEE_Arith +#undef Avoid_Underflow +#ifdef IEEE_BIG_ENDIAN +#define IEEE_Arith +#endif +#ifdef IEEE_LITTLE_ENDIAN +#define IEEE_Arith +#endif + +#ifdef Bad_float_h + +#ifdef IEEE_Arith +#define DBL_DIG 15 +#define DBL_MAX_10_EXP 308 +#define DBL_MAX_EXP 1024 +#define FLT_RADIX 2 +#endif /*IEEE_Arith*/ + +#ifdef IBM +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 75 +#define DBL_MAX_EXP 63 +#define FLT_RADIX 16 +#define DBL_MAX 7.2370055773322621e+75 +#endif + +#ifdef VAX +#define DBL_DIG 16 +#define DBL_MAX_10_EXP 38 +#define DBL_MAX_EXP 127 +#define FLT_RADIX 2 +#define DBL_MAX 1.7014118346046923e+38 +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#else /* ifndef Bad_float_h */ +#include <float.h> +#endif /* Bad_float_h */ + +#include <math.h> + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* satisfy cc-mode */ +#endif +#endif + +#ifndef hexdigit +static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; +#endif + +#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + defined(IBM) != 1 +Exactly one of IEEE_LITTLE_ENDIAN, IEEE_BIG_ENDIAN, VAX, or IBM should be defined. +#endif + +typedef union { double d; ULong L[2]; } U; + +#ifdef YES_ALIAS +typedef double double_u; +# define dval(x) (x) +# ifdef IEEE_LITTLE_ENDIAN +# define word0(x) (((ULong *)&(x))[1]) +# define word1(x) (((ULong *)&(x))[0]) +# else +# define word0(x) (((ULong *)&(x))[0]) +# define word1(x) (((ULong *)&(x))[1]) +# endif +#else +typedef U double_u; +# ifdef IEEE_LITTLE_ENDIAN +# define word0(x) ((x).L[1]) +# define word1(x) ((x).L[0]) +# else +# define word0(x) ((x).L[0]) +# define word1(x) ((x).L[1]) +# endif +# define dval(x) ((x).d) +#endif + +/* The following definition of Storeinc is appropriate for MIPS processors. + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +#if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(__arm__) +#define Storeinc(a,b,c) (((unsigned short *)(a))[1] = (unsigned short)(b), \ +((unsigned short *)(a))[0] = (unsigned short)(c), (a)++) +#else +#define Storeinc(a,b,c) (((unsigned short *)(a))[0] = (unsigned short)(b), \ +((unsigned short *)(a))[1] = (unsigned short)(c), (a)++) +#endif + +/* #define P DBL_MANT_DIG */ +/* Ten_pmax = floor(P*log(2)/log(5)) */ +/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ +/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ +/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ + +#ifdef IEEE_Arith +#define Exp_shift 20 +#define Exp_shift1 20 +#define Exp_msk1 0x100000 +#define Exp_msk11 0x100000 +#define Exp_mask 0x7ff00000 +#define P 53 +#define Bias 1023 +#define Emin (-1022) +#define Exp_1 0x3ff00000 +#define Exp_11 0x3ff00000 +#define Ebits 11 +#define Frac_mask 0xfffff +#define Frac_mask1 0xfffff +#define Ten_pmax 22 +#define Bletch 0x10 +#define Bndry_mask 0xfffff +#define Bndry_mask1 0xfffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 1 +#define Tiny0 0 +#define Tiny1 1 +#define Quick_max 14 +#define Int_max 14 +#ifndef NO_IEEE_Scale +#define Avoid_Underflow +#ifdef Flush_Denorm /* debugging option */ +#undef Sudden_Underflow +#endif +#endif + +#ifndef Flt_Rounds +#ifdef FLT_ROUNDS +#define Flt_Rounds FLT_ROUNDS +#else +#define Flt_Rounds 1 +#endif +#endif /*Flt_Rounds*/ + +#ifdef Honor_FLT_ROUNDS +#define Rounding rounding +#undef Check_FLT_ROUNDS +#define Check_FLT_ROUNDS +#else +#define Rounding Flt_Rounds +#endif + +#else /* ifndef IEEE_Arith */ +#undef Check_FLT_ROUNDS +#undef Honor_FLT_ROUNDS +#undef SET_INEXACT +#undef Sudden_Underflow +#define Sudden_Underflow +#ifdef IBM +#undef Flt_Rounds +#define Flt_Rounds 0 +#define Exp_shift 24 +#define Exp_shift1 24 +#define Exp_msk1 0x1000000 +#define Exp_msk11 0x1000000 +#define Exp_mask 0x7f000000 +#define P 14 +#define Bias 65 +#define Exp_1 0x41000000 +#define Exp_11 0x41000000 +#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ +#define Frac_mask 0xffffff +#define Frac_mask1 0xffffff +#define Bletch 4 +#define Ten_pmax 22 +#define Bndry_mask 0xefffff +#define Bndry_mask1 0xffffff +#define LSB 1 +#define Sign_bit 0x80000000 +#define Log2P 4 +#define Tiny0 0x100000 +#define Tiny1 0 +#define Quick_max 14 +#define Int_max 15 +#else /* VAX */ +#undef Flt_Rounds +#define Flt_Rounds 1 +#define Exp_shift 23 +#define Exp_shift1 7 +#define Exp_msk1 0x80 +#define Exp_msk11 0x800000 +#define Exp_mask 0x7f80 +#define P 56 +#define Bias 129 +#define Exp_1 0x40800000 +#define Exp_11 0x4080 +#define Ebits 8 +#define Frac_mask 0x7fffff +#define Frac_mask1 0xffff007f +#define Ten_pmax 24 +#define Bletch 2 +#define Bndry_mask 0xffff007f +#define Bndry_mask1 0xffff007f +#define LSB 0x10000 +#define Sign_bit 0x8000 +#define Log2P 1 +#define Tiny0 0x80 +#define Tiny1 0 +#define Quick_max 15 +#define Int_max 15 +#endif /* IBM, VAX */ +#endif /* IEEE_Arith */ + +#ifndef IEEE_Arith +#define ROUND_BIASED +#endif + +#ifdef RND_PRODQUOT +#define rounded_product(a,b) ((a) = rnd_prod((a), (b))) +#define rounded_quotient(a,b) ((a) = rnd_quot((a), (b))) +extern double rnd_prod(double, double), rnd_quot(double, double); +#else +#define rounded_product(a,b) ((a) *= (b)) +#define rounded_quotient(a,b) ((a) /= (b)) +#endif + +#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) +#define Big1 0xffffffff + +#ifndef Pack_32 +#define Pack_32 +#endif + +#define FFFFFFFF 0xffffffffUL + +#ifdef NO_LONG_LONG +#undef ULLong +#ifdef Just_16 +#undef Pack_32 +/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. + * This makes some inner loops simpler and sometimes saves work + * during multiplications, but it often seems to make things slightly + * slower. Hence the default is now to store 32 bits per Long. + */ +#endif +#else /* long long available */ +#ifndef Llong +#define Llong long long +#endif +#ifndef ULLong +#define ULLong unsigned Llong +#endif +#endif /* NO_LONG_LONG */ + +#define MULTIPLE_THREADS 1 + +#ifndef MULTIPLE_THREADS +#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ +#define FREE_DTOA_LOCK(n) /*nothing*/ +#else +#define ACQUIRE_DTOA_LOCK(n) /*unused right now*/ +#define FREE_DTOA_LOCK(n) /*unused right now*/ +#endif + +#ifndef ATOMIC_PTR_CAS +#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (void *)(old)) +#endif +#ifndef LIKELY +#define LIKELY(x) (x) +#endif +#ifndef UNLIKELY +#define UNLIKELY(x) (x) +#endif +#ifndef ASSUME +#define ASSUME(x) (void)(x) +#endif + +#define Kmax 15 + +struct Bigint { + struct Bigint *next; + int k, maxwds, sign, wds; + ULong x[1]; +}; + +typedef struct Bigint Bigint; + +static Bigint * +Balloc(int k) +{ + int x; + Bigint *rv; + + x = 1 << k; + rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); + if (!rv) return NULL; + rv->k = k; + rv->maxwds = x; + rv->sign = rv->wds = 0; + return rv; +} + +static void +Bclear(Bigint **vp) +{ + Bigint *v = *vp; + *vp = NULL; + if (v) FREE(v); +} +#define Bfree(v) Bclear(&(v)) + +#define Bcopy(x,y) memcpy((char *)&(x)->sign, (char *)&(y)->sign, \ +(y)->wds*sizeof(Long) + 2*sizeof(int)) + +static Bigint * +multadd(Bigint *b, int m, int a) /* multiply by m and add a */ +{ + int i, wds; + ULong *x; +#ifdef ULLong + ULLong carry, y; +#else + ULong carry, y; +#ifdef Pack_32 + ULong xi, z; +#endif +#endif + Bigint *b1; + + wds = b->wds; + x = b->x; + i = 0; + carry = a; + do { +#ifdef ULLong + y = *x * (ULLong)m + carry; + carry = y >> 32; + *x++ = (ULong)(y & FFFFFFFF); +#else +#ifdef Pack_32 + xi = *x; + y = (xi & 0xffff) * m + carry; + z = (xi >> 16) * m + (y >> 16); + carry = z >> 16; + *x++ = (z << 16) + (y & 0xffff); +#else + y = *x * m + carry; + carry = y >> 16; + *x++ = y & 0xffff; +#endif +#endif + } while (++i < wds); + if (carry) { + if (wds >= b->maxwds) { + b1 = Balloc(b->k+1); + if (!b1) { + Bfree(b); + return NULL; + } + Bcopy(b1, b); + Bfree(b); + b = b1; + } + b->x[wds++] = (ULong)carry; + b->wds = wds; + } + return b; +} + +static Bigint * +s2b(const char *s, int nd0, int nd, ULong y9) +{ + Bigint *b; + int i, k; + Long x, y; + + x = (nd + 8) / 9; + for (k = 0, y = 1; x > y; y <<= 1, k++) ; +#ifdef Pack_32 + b = Balloc(k); + if (!b) return NULL; + b->x[0] = y9; + b->wds = 1; +#else + b = Balloc(k+1); + if (!b) return NULL; + b->x[0] = y9 & 0xffff; + b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; +#endif + + i = 9; + if (9 < nd0) { + s += 9; + do { + b = multadd(b, 10, *s++ - '0'); + if (!b) return NULL; + } while (++i < nd0); + s++; + } + else + s += 10; + for (; i < nd; i++) { + b = multadd(b, 10, *s++ - '0'); + if (!b) return NULL; + } + return b; +} + +static int +hi0bits(register ULong x) +{ + register int k = 0; + + if (!(x & 0xffff0000)) { + k = 16; + x <<= 16; + } + if (!(x & 0xff000000)) { + k += 8; + x <<= 8; + } + if (!(x & 0xf0000000)) { + k += 4; + x <<= 4; + } + if (!(x & 0xc0000000)) { + k += 2; + x <<= 2; + } + if (!(x & 0x80000000)) { + k++; + if (!(x & 0x40000000)) + return 32; + } + return k; +} + +static int +lo0bits(ULong *y) +{ + register int k; + register ULong x = *y; + + if (x & 7) { + if (x & 1) + return 0; + if (x & 2) { + *y = x >> 1; + return 1; + } + *y = x >> 2; + return 2; + } + k = 0; + if (!(x & 0xffff)) { + k = 16; + x >>= 16; + } + if (!(x & 0xff)) { + k += 8; + x >>= 8; + } + if (!(x & 0xf)) { + k += 4; + x >>= 4; + } + if (!(x & 0x3)) { + k += 2; + x >>= 2; + } + if (!(x & 1)) { + k++; + x >>= 1; + if (!x) + return 32; + } + *y = x; + return k; +} + +static Bigint * +i2b(int i) +{ + Bigint *b; + + b = Balloc(1); + if (!b) return NULL; + b->x[0] = i; + b->wds = 1; + return b; +} + +#define Bzero_p(b) (!(b)->x[0] && (b)->wds <= 1) + +static Bigint * +mult(Bigint *a, Bigint *b) +{ + Bigint *c; + int k, wa, wb, wc; + ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; + ULong y; +#ifdef ULLong + ULLong carry, z; +#else + ULong carry, z; +#ifdef Pack_32 + ULong z2; +#endif +#endif + + if (Bzero_p(a) || Bzero_p(b)) { + c = Balloc(0); + if (!c) return NULL; + c->wds = 1; + c->x[0] = 0; + return c; + } + + if (a->wds < b->wds) { + c = a; + a = b; + b = c; + } + k = a->k; + wa = a->wds; + wb = b->wds; + wc = wa + wb; + if (wc > a->maxwds) + k++; + c = Balloc(k); + if (!c) return NULL; + for (x = c->x, xa = x + wc; x < xa; x++) + *x = 0; + xa = a->x; + xae = xa + wa; + xb = b->x; + xbe = xb + wb; + xc0 = c->x; +#ifdef ULLong + for (; xb < xbe; xc0++) { + if ((y = *xb++) != 0) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * (ULLong)y + *xc + carry; + carry = z >> 32; + *xc++ = (ULong)(z & FFFFFFFF); + } while (x < xae); + *xc = (ULong)carry; + } + } +#else +#ifdef Pack_32 + for (; xb < xbe; xb++, xc0++) { + if ((y = *xb & 0xffff) != 0) { + x = xa; + xc = xc0; + carry = 0; + do { + z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; + carry = z >> 16; + z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; + carry = z2 >> 16; + Storeinc(xc, z2, z); + } while (x < xae); + *xc = (ULong)carry; + } + if ((y = *xb >> 16) != 0) { + x = xa; + xc = xc0; + carry = 0; + z2 = *xc; + do { + z = (*x & 0xffff) * y + (*xc >> 16) + carry; + carry = z >> 16; + Storeinc(xc, z, z2); + z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; + carry = z2 >> 16; + } while (x < xae); + *xc = z2; + } + } +#else + for (; xb < xbe; xc0++) { + if (y = *xb++) { + x = xa; + xc = xc0; + carry = 0; + do { + z = *x++ * y + *xc + carry; + carry = z >> 16; + *xc++ = z & 0xffff; + } while (x < xae); + *xc = (ULong)carry; + } + } +#endif +#endif + for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; + c->wds = wc; + return c; +} + +static Bigint *p5s; + +static Bigint * +pow5mult(Bigint *b, int k) +{ + Bigint *b1, *p5, *p51; + int i; + static const int p05[3] = { 5, 25, 125 }; + + if ((i = k & 3) != 0) { + b = multadd(b, p05[i-1], 0); + if (!b) return NULL; + } + +#define b_cache(var, addr, new_expr) \ + if ((var = addr) != 0) {} else { \ + Bigint *tmp = 0; \ + ACQUIRE_DTOA_LOCK(1); \ + if (!(var = addr) && (var = (new_expr)) != 0) { \ + var->next = 0; \ + tmp = ATOMIC_PTR_CAS(addr, NULL, var); \ + } \ + FREE_DTOA_LOCK(1); \ + if (UNLIKELY(tmp)) { \ + Bfree(var); \ + var = tmp; \ + } \ + else if (!var) { \ + Bfree(b); \ + return NULL; \ + } \ + } + + if (!(k >>= 2)) + return b; + /* first time */ + b_cache(p5, p5s, i2b(625)); + for (;;) { + if (k & 1) { + b1 = mult(b, p5); + Bfree(b); + b = b1; + if (!b) return NULL; + } + if (!(k >>= 1)) + break; + b_cache(p51, p5->next, mult(p5, p5)); + p5 = p51; + } + return b; +} + +static Bigint * +lshift(Bigint *b, int k) +{ + int i, k1, n, n1; + Bigint *b1; + ULong *x, *x1, *xe, z; + + if (!k || Bzero_p(b)) return b; + +#ifdef Pack_32 + n = k >> 5; +#else + n = k >> 4; +#endif + k1 = b->k; + n1 = n + b->wds + 1; + for (i = b->maxwds; n1 > i; i <<= 1) + k1++; + b1 = Balloc(k1); + if (!b1) { + Bfree(b); + return NULL; + } + x1 = b1->x; + for (i = 0; i < n; i++) + *x1++ = 0; + x = b->x; + xe = x + b->wds; +#ifdef Pack_32 + if (k &= 0x1f) { + k1 = 32 - k; + z = 0; + do { + *x1++ = *x << k | z; + z = *x++ >> k1; + } while (x < xe); + if ((*x1 = z) != 0) + ++n1; + } +#else + if (k &= 0xf) { + k1 = 16 - k; + z = 0; + do { + *x1++ = *x << k & 0xffff | z; + z = *x++ >> k1; + } while (x < xe); + if (*x1 = z) + ++n1; + } +#endif + else + do { + *x1++ = *x++; + } while (x < xe); + b1->wds = n1 - 1; + Bfree(b); + return b1; +} + +static int +cmp(Bigint *a, Bigint *b) +{ + ULong *xa, *xa0, *xb, *xb0; + int i, j; + + i = a->wds; + j = b->wds; +#ifdef DEBUG + if (i > 1 && !a->x[i-1]) + Bug("cmp called with a->x[a->wds-1] == 0"); + if (j > 1 && !b->x[j-1]) + Bug("cmp called with b->x[b->wds-1] == 0"); +#endif + if (i -= j) + return i; + xa0 = a->x; + xa = xa0 + j; + xb0 = b->x; + xb = xb0 + j; + for (;;) { + if (*--xa != *--xb) + return *xa < *xb ? -1 : 1; + if (xa <= xa0) + break; + } + return 0; +} + +NO_SANITIZE("unsigned-integer-overflow", static Bigint * diff(Bigint *a, Bigint *b)); +static Bigint * +diff(Bigint *a, Bigint *b) +{ + Bigint *c; + int i, wa, wb; + ULong *xa, *xae, *xb, *xbe, *xc; +#ifdef ULLong + ULLong borrow, y; +#else + ULong borrow, y; +#ifdef Pack_32 + ULong z; +#endif +#endif + + i = cmp(a,b); + if (!i) { + c = Balloc(0); + if (!c) return NULL; + c->wds = 1; + c->x[0] = 0; + return c; + } + if (i < 0) { + c = a; + a = b; + b = c; + i = 1; + } + else + i = 0; + c = Balloc(a->k); + if (!c) return NULL; + c->sign = i; + wa = a->wds; + xa = a->x; + xae = xa + wa; + wb = b->wds; + xb = b->x; + xbe = xb + wb; + xc = c->x; + borrow = 0; +#ifdef ULLong + do { + y = (ULLong)*xa++ - *xb++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong)(y & FFFFFFFF); + } while (xb < xbe); + while (xa < xae) { + y = *xa++ - borrow; + borrow = y >> 32 & (ULong)1; + *xc++ = (ULong)(y & FFFFFFFF); + } +#else +#ifdef Pack_32 + do { + y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } while (xb < xbe); + while (xa < xae) { + y = (*xa & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*xa++ >> 16) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(xc, z, y); + } +#else + do { + y = *xa++ - *xb++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } while (xb < xbe); + while (xa < xae) { + y = *xa++ - borrow; + borrow = (y & 0x10000) >> 16; + *xc++ = y & 0xffff; + } +#endif +#endif + while (!*--xc) + wa--; + c->wds = wa; + return c; +} + +static double +ulp(double x_) +{ + register Long L; + double_u x, a; + dval(x) = x_; + + L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + if (L > 0) { +#endif +#endif +#ifdef IBM + L |= Exp_msk1 >> 4; +#endif + word0(a) = L; + word1(a) = 0; +#ifndef Avoid_Underflow +#ifndef Sudden_Underflow + } + else { + L = -L >> Exp_shift; + if (L < Exp_shift) { + word0(a) = 0x80000 >> L; + word1(a) = 0; + } + else { + word0(a) = 0; + L -= Exp_shift; + word1(a) = L >= 31 ? 1 : 1 << 31 - L; + } + } +#endif +#endif + return dval(a); +} + +static double +b2d(Bigint *a, int *e) +{ + ULong *xa, *xa0, w, y, z; + int k; + double_u d; +#ifdef VAX + ULong d0, d1; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + + xa0 = a->x; + xa = xa0 + a->wds; + y = *--xa; +#ifdef DEBUG + if (!y) Bug("zero y in b2d"); +#endif + k = hi0bits(y); + *e = 32 - k; +#ifdef Pack_32 + if (k < Ebits) { + d0 = Exp_1 | y >> (Ebits - k); + w = xa > xa0 ? *--xa : 0; + d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + if (k -= Ebits) { + d0 = Exp_1 | y << k | z >> (32 - k); + y = xa > xa0 ? *--xa : 0; + d1 = z << k | y >> (32 - k); + } + else { + d0 = Exp_1 | y; + d1 = z; + } +#else + if (k < Ebits + 16) { + z = xa > xa0 ? *--xa : 0; + d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; + w = xa > xa0 ? *--xa : 0; + y = xa > xa0 ? *--xa : 0; + d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; + goto ret_d; + } + z = xa > xa0 ? *--xa : 0; + w = xa > xa0 ? *--xa : 0; + k -= Ebits + 16; + d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; + y = xa > xa0 ? *--xa : 0; + d1 = w << k + 16 | y << k; +#endif +ret_d: +#ifdef VAX + word0(d) = d0 >> 16 | d0 << 16; + word1(d) = d1 >> 16 | d1 << 16; +#else +#undef d0 +#undef d1 +#endif + return dval(d); +} + +static Bigint * +d2b(double d_, int *e, int *bits) +{ + double_u d; + Bigint *b; + int de, k; + ULong *x, y, z; +#ifndef Sudden_Underflow + int i; +#endif +#ifdef VAX + ULong d0, d1; +#endif + dval(d) = d_; +#ifdef VAX + d0 = word0(d) >> 16 | word0(d) << 16; + d1 = word1(d) >> 16 | word1(d) << 16; +#else +#define d0 word0(d) +#define d1 word1(d) +#endif + +#ifdef Pack_32 + b = Balloc(1); +#else + b = Balloc(2); +#endif + if (!b) return NULL; + x = b->x; + + z = d0 & Frac_mask; + d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ +#ifdef Sudden_Underflow + de = (int)(d0 >> Exp_shift); +#ifndef IBM + z |= Exp_msk11; +#endif +#else + if ((de = (int)(d0 >> Exp_shift)) != 0) + z |= Exp_msk1; +#endif +#ifdef Pack_32 + if ((y = d1) != 0) { + if ((k = lo0bits(&y)) != 0) { + x[0] = y | z << (32 - k); + z >>= k; + } + else + x[0] = y; +#ifndef Sudden_Underflow + i = +#endif + b->wds = (x[1] = z) ? 2 : 1; + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + x[0] = z; +#ifndef Sudden_Underflow + i = +#endif + b->wds = 1; + k += 32; + } +#else + if (y = d1) { + if (k = lo0bits(&y)) + if (k >= 16) { + x[0] = y | z << 32 - k & 0xffff; + x[1] = z >> k - 16 & 0xffff; + x[2] = z >> k; + i = 2; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16 | z << 16 - k & 0xffff; + x[2] = z >> k & 0xffff; + x[3] = z >> k+16; + i = 3; + } + else { + x[0] = y & 0xffff; + x[1] = y >> 16; + x[2] = z & 0xffff; + x[3] = z >> 16; + i = 3; + } + } + else { +#ifdef DEBUG + if (!z) + Bug("Zero passed to d2b"); +#endif + k = lo0bits(&z); + if (k >= 16) { + x[0] = z; + i = 0; + } + else { + x[0] = z & 0xffff; + x[1] = z >> 16; + i = 1; + } + k += 32; + } + while (!x[i]) + --i; + b->wds = i + 1; +#endif +#ifndef Sudden_Underflow + if (de) { +#endif +#ifdef IBM + *e = (de - Bias - (P-1) << 2) + k; + *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask); +#else + *e = de - Bias - (P-1) + k; + *bits = P - k; +#endif +#ifndef Sudden_Underflow + } + else { + *e = de - Bias - (P-1) + 1 + k; +#ifdef Pack_32 + *bits = 32*i - hi0bits(x[i-1]); +#else + *bits = (i+2)*16 - hi0bits(x[i]); +#endif + } +#endif + return b; +} +#undef d0 +#undef d1 + +static double +ratio(Bigint *a, Bigint *b) +{ + double_u da, db; + int k, ka, kb; + + dval(da) = b2d(a, &ka); + dval(db) = b2d(b, &kb); +#ifdef Pack_32 + k = ka - kb + 32*(a->wds - b->wds); +#else + k = ka - kb + 16*(a->wds - b->wds); +#endif +#ifdef IBM + if (k > 0) { + word0(da) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(da) *= 1 << k; + } + else { + k = -k; + word0(db) += (k >> 2)*Exp_msk1; + if (k &= 3) + dval(db) *= 1 << k; + } +#else + if (k > 0) + word0(da) += k*Exp_msk1; + else { + k = -k; + word0(db) += k*Exp_msk1; + } +#endif + return dval(da) / dval(db); +} + +static const double +tens[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 +#ifdef VAX + , 1e23, 1e24 +#endif +}; + +static const double +#ifdef IEEE_Arith +bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; +static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, +#ifdef Avoid_Underflow + 9007199254740992.*9007199254740992.e-256 + /* = 2^106 * 1e-53 */ +#else + 1e-256 +#endif +}; +/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ +#define Scale_Bit 0x10 +#define n_bigtens 5 +#else +#ifdef IBM +bigtens[] = { 1e16, 1e32, 1e64 }; +static const double tinytens[] = { 1e-16, 1e-32, 1e-64 }; +#define n_bigtens 3 +#else +bigtens[] = { 1e16, 1e32 }; +static const double tinytens[] = { 1e-16, 1e-32 }; +#define n_bigtens 2 +#endif +#endif + +#ifndef IEEE_Arith +#undef INFNAN_CHECK +#endif + +#ifdef INFNAN_CHECK + +#ifndef NAN_WORD0 +#define NAN_WORD0 0x7ff80000 +#endif + +#ifndef NAN_WORD1 +#define NAN_WORD1 0 +#endif + +static int +match(const char **sp, char *t) +{ + int c, d; + const char *s = *sp; + + while (d = *t++) { + if ((c = *++s) >= 'A' && c <= 'Z') + c += 'a' - 'A'; + if (c != d) + return 0; + } + *sp = s + 1; + return 1; +} + +#ifndef No_Hex_NaN +static void +hexnan(double *rvp, const char **sp) +{ + ULong c, x[2]; + const char *s; + int havedig, udx0, xshift; + + x[0] = x[1] = 0; + havedig = xshift = 0; + udx0 = 1; + s = *sp; + while (c = *(const unsigned char*)++s) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c += 10 - 'a'; + else if (c >= 'A' && c <= 'F') + c += 10 - 'A'; + else if (c <= ' ') { + if (udx0 && havedig) { + udx0 = 0; + xshift = 1; + } + continue; + } + else if (/*(*/ c == ')' && havedig) { + *sp = s + 1; + break; + } + else + return; /* invalid form: don't change *sp */ + havedig = 1; + if (xshift) { + xshift = 0; + x[0] = x[1]; + x[1] = 0; + } + if (udx0) + x[0] = (x[0] << 4) | (x[1] >> 28); + x[1] = (x[1] << 4) | c; + } + if ((x[0] &= 0xfffff) || x[1]) { + word0(*rvp) = Exp_mask | x[0]; + word1(*rvp) = x[1]; + } +} +#endif /*No_Hex_NaN*/ +#endif /* INFNAN_CHECK */ + +NO_SANITIZE("unsigned-integer-overflow", double strtod(const char *s00, char **se)); +double +strtod(const char *s00, char **se) +{ +#ifdef Avoid_Underflow + int scale; +#endif + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + const char *s, *s0, *s1; + double aadj, adj; + double_u aadj1, rv, rv0; + Long L; + ULong y, z; + Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef USE_LOCALE + const char *s2; +#endif + + errno = 0; + sign = nz0 = nz = 0; + dval(rv) = 0.; + for (s = s00;;s++) + switch (*s) { + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) + goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; + } +break2: + if (*s == '0') { + if (s[1] == 'x' || s[1] == 'X') { + s0 = ++s; + adj = 0; + aadj = 1.0; + nd0 = -4; + + if (!*++s || (!(s1 = strchr(hexdigit, *s)) && *s != '.')) goto ret0; + if (*s == '0') { + while (*++s == '0'); + if (!*s) goto ret; + s1 = strchr(hexdigit, *s); + } + if (s1 != NULL) { + do { + adj += aadj * ((s1 - hexdigit) & 15); + nd0 += 4; + aadj /= 16; + } while (*++s && (s1 = strchr(hexdigit, *s))); + } + + if ((*s == '.') && *++s && (s1 = strchr(hexdigit, *s))) { + if (nd0 < 0) { + while (*s == '0') { + s++; + nd0 -= 4; + } + } + for (; *s && (s1 = strchr(hexdigit, *s)); ++s) { + adj += aadj * ((s1 - hexdigit) & 15); + if ((aadj /= 16) == 0.0) { + while (*++s && strchr(hexdigit, *s)); + break; + } + } + } + + if (*s == 'P' || *s == 'p') { + dsign = 0x2C - *++s; /* +: 2B, -: 2D */ + if (abs(dsign) == 1) s++; + else dsign = 1; + + nd = 0; + c = *s; + if (c < '0' || '9' < c) goto ret0; + do { + nd *= 10; + nd += c; + nd -= '0'; + c = *++s; + /* Float("0x0."+("0"*267)+"1fp2095") */ + if (nd + dsign * nd0 > 2095) { + while ('0' <= c && c <= '9') c = *++s; + break; + } + } while ('0' <= c && c <= '9'); + nd0 += nd * dsign; + } + dval(rv) = ldexp(adj, nd0); + goto ret; + } + nz0 = 1; + while (*++s == '0') ; + if (!*s) + goto ret; + } + s0 = s; + y = z = 0; + for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) + if (nd < 9) + y = 10*y + c - '0'; + else if (nd < DBL_DIG + 2) + z = 10*z + c - '0'; + nd0 = nd; +#ifdef USE_LOCALE + s1 = localeconv()->decimal_point; + if (c == *s1) { + c = '.'; + if (*++s1) { + s2 = s; + for (;;) { + if (*++s2 != *s1) { + c = 0; + break; + } + if (!*++s1) { + s = s2; + break; + } + } + } + } +#endif + if (c == '.') { + c = *++s; + if (!ISDIGIT(c)) + goto dig_done; + if (!nd) { + for (; c == '0'; c = *++s) + nz++; + if (c > '0' && c <= '9') { + s0 = s; + nf += nz; + nz = 0; + goto have_dig; + } + goto dig_done; + } + for (; c >= '0' && c <= '9'; c = *++s) { +have_dig: + nz++; + if (nd > DBL_DIG * 4) { + continue; + } + if (c -= '0') { + nf += nz; + for (i = 1; i < nz; i++) + if (nd++ < 9) + y *= 10; + else if (nd <= DBL_DIG + 2) + z *= 10; + if (nd++ < 9) + y = 10*y + c; + else if (nd <= DBL_DIG + 2) + z = 10*z + c; + nz = 0; + } + } + } +dig_done: + e = 0; + if (c == 'e' || c == 'E') { + if (!nd && !nz && !nz0) { + goto ret0; + } + s00 = s; + esign = 0; + switch (c = *++s) { + case '-': + esign = 1; + case '+': + c = *++s; + } + if (c >= '0' && c <= '9') { + while (c == '0') + c = *++s; + if (c > '0' && c <= '9') { + L = c - '0'; + s1 = s; + while ((c = *++s) >= '0' && c <= '9') + L = 10*L + c - '0'; + if (s - s1 > 8 || L > 19999) + /* Avoid confusion from exponents + * so large that e might overflow. + */ + e = 19999; /* safe for 16 bit ints */ + else + e = (int)L; + if (esign) + e = -e; + } + else + e = 0; + } + else + s = s00; + } + if (!nd) { + if (!nz && !nz0) { +#ifdef INFNAN_CHECK + /* Check for Nan and Infinity */ + switch (c) { + case 'i': + case 'I': + if (match(&s,"nf")) { + --s; + if (!match(&s,"inity")) + ++s; + word0(rv) = 0x7ff00000; + word1(rv) = 0; + goto ret; + } + break; + case 'n': + case 'N': + if (match(&s, "an")) { + word0(rv) = NAN_WORD0; + word1(rv) = NAN_WORD1; +#ifndef No_Hex_NaN + if (*s == '(') /*)*/ + hexnan(&rv, &s); +#endif + goto ret; + } + } +#endif /* INFNAN_CHECK */ +ret0: + s = s00; + sign = 0; + } + goto ret; + } + e1 = e -= nf; + + /* Now we have nd0 digits, starting at s0, followed by a + * decimal point, followed by nd-nd0 digits. The number we're + * after is the integer represented by those digits times + * 10**e */ + + if (!nd0) + nd0 = nd; + k = nd < DBL_DIG + 2 ? nd : DBL_DIG + 2; + dval(rv) = y; + if (k > 9) { +#ifdef SET_INEXACT + if (k > DBL_DIG) + oldinexact = get_inexact(); +#endif + dval(rv) = tens[k - 9] * dval(rv) + z; + } + bd0 = bb = bd = bs = delta = 0; + if (nd <= DBL_DIG +#ifndef RND_PRODQUOT +#ifndef Honor_FLT_ROUNDS + && Flt_Rounds == 1 +#endif +#endif + ) { + if (!e) + goto ret; + if (e > 0) { + if (e <= Ten_pmax) { +#ifdef VAX + goto vax_ovfl_check; +#else +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + dval(rv) = -dval(rv); + sign = 0; + } +#endif + /* rv = */ rounded_product(dval(rv), tens[e]); + goto ret; +#endif + } + i = DBL_DIG - nd; + if (e <= Ten_pmax + i) { + /* A fancier test would sometimes let us do + * this for larger i values. + */ +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + dval(rv) = -dval(rv); + sign = 0; + } +#endif + e -= i; + dval(rv) *= tens[i]; +#ifdef VAX + /* VAX exponent range is so narrow we must + * worry about overflow here... + */ +vax_ovfl_check: + word0(rv) -= P*Exp_msk1; + /* rv = */ rounded_product(dval(rv), tens[e]); + if ((word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) + goto ovfl; + word0(rv) += P*Exp_msk1; +#else + /* rv = */ rounded_product(dval(rv), tens[e]); +#endif + goto ret; + } + } +#ifndef Inaccurate_Divide + else if (e >= -Ten_pmax) { +#ifdef Honor_FLT_ROUNDS + /* round correctly FLT_ROUNDS = 2 or 3 */ + if (sign) { + dval(rv) = -dval(rv); + sign = 0; + } +#endif + /* rv = */ rounded_quotient(dval(rv), tens[-e]); + goto ret; + } +#endif + } + e1 += nd - k; + +#ifdef IEEE_Arith +#ifdef SET_INEXACT + inexact = 1; + if (k <= DBL_DIG) + oldinexact = get_inexact(); +#endif +#ifdef Avoid_Underflow + scale = 0; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif +#endif /*IEEE_Arith*/ + + /* Get starting approximation = rv * 10**e1 */ + + if (e1 > 0) { + if ((i = e1 & 15) != 0) + dval(rv) *= tens[i]; + if (e1 &= ~15) { + if (e1 > DBL_MAX_10_EXP) { +ovfl: +#ifndef NO_ERRNO + errno = ERANGE; +#endif + /* Can't trust HUGE_VAL */ +#ifdef IEEE_Arith +#ifdef Honor_FLT_ROUNDS + switch (rounding) { + case 0: /* toward 0 */ + case 3: /* toward -infinity */ + word0(rv) = Big0; + word1(rv) = Big1; + break; + default: + word0(rv) = Exp_mask; + word1(rv) = 0; + } +#else /*Honor_FLT_ROUNDS*/ + word0(rv) = Exp_mask; + word1(rv) = 0; +#endif /*Honor_FLT_ROUNDS*/ +#ifdef SET_INEXACT + /* set overflow bit */ + dval(rv0) = 1e300; + dval(rv0) *= dval(rv0); +#endif +#else /*IEEE_Arith*/ + word0(rv) = Big0; + word1(rv) = Big1; +#endif /*IEEE_Arith*/ + if (bd0) + goto retfree; + goto ret; + } + e1 >>= 4; + for (j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= bigtens[j]; + /* The last multiplication could overflow. */ + word0(rv) -= P*Exp_msk1; + dval(rv) *= bigtens[j]; + if ((z = word0(rv) & Exp_mask) + > Exp_msk1*(DBL_MAX_EXP+Bias-P)) + goto ovfl; + if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { + /* set to largest number */ + /* (Can't trust DBL_MAX) */ + word0(rv) = Big0; + word1(rv) = Big1; + } + else + word0(rv) += P*Exp_msk1; + } + } + else if (e1 < 0) { + e1 = -e1; + if ((i = e1 & 15) != 0) + dval(rv) /= tens[i]; + if (e1 >>= 4) { + if (e1 >= 1 << n_bigtens) + goto undfl; +#ifdef Avoid_Underflow + if (e1 & Scale_Bit) + scale = 2*P; + for (j = 0; e1 > 0; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask) + >> Exp_shift)) > 0) { + /* scaled rv is denormal; zap j low bits */ + if (j >= 32) { + word1(rv) = 0; + if (j >= 53) + word0(rv) = (P+2)*Exp_msk1; + else + word0(rv) &= 0xffffffff << (j-32); + } + else + word1(rv) &= 0xffffffff << j; + } +#else + for (j = 0; e1 > 1; j++, e1 >>= 1) + if (e1 & 1) + dval(rv) *= tinytens[j]; + /* The last multiplication could underflow. */ + dval(rv0) = dval(rv); + dval(rv) *= tinytens[j]; + if (!dval(rv)) { + dval(rv) = 2.*dval(rv0); + dval(rv) *= tinytens[j]; +#endif + if (!dval(rv)) { +undfl: + dval(rv) = 0.; +#ifndef NO_ERRNO + errno = ERANGE; +#endif + if (bd0) + goto retfree; + goto ret; + } +#ifndef Avoid_Underflow + word0(rv) = Tiny0; + word1(rv) = Tiny1; + /* The refinement below will clean + * this approximation up. + */ + } +#endif + } + } + + /* Now the hard part -- adjusting rv to the correct value.*/ + + /* Put digits into bd: true value = bd * 10^e */ + + bd0 = s2b(s0, nd0, nd, y); + if (!bd0) goto ret; + + for (;;) { + bd = Balloc(bd0->k); + if (!bd) goto retfree; + Bcopy(bd, bd0); + bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ + if (!bb) goto retfree; + bs = i2b(1); + if (!bs) goto retfree; + + if (e >= 0) { + bb2 = bb5 = 0; + bd2 = bd5 = e; + } + else { + bb2 = bb5 = -e; + bd2 = bd5 = 0; + } + if (bbe >= 0) + bb2 += bbe; + else + bd2 -= bbe; + bs2 = bb2; +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) + bs2++; +#endif +#ifdef Avoid_Underflow + j = bbe - scale; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#else /*Avoid_Underflow*/ +#ifdef Sudden_Underflow +#ifdef IBM + j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); +#else + j = P + 1 - bbbits; +#endif +#else /*Sudden_Underflow*/ + j = bbe; + i = j + bbbits - 1; /* logb(rv) */ + if (i < Emin) /* denormal */ + j += P - Emin; + else + j = P + 1 - bbbits; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + bb2 += j; + bd2 += j; +#ifdef Avoid_Underflow + bd2 += scale; +#endif + i = bb2 < bd2 ? bb2 : bd2; + if (i > bs2) + i = bs2; + if (i > 0) { + bb2 -= i; + bd2 -= i; + bs2 -= i; + } + if (bb5 > 0) { + bs = pow5mult(bs, bb5); + if (!bs) goto retfree; + bb1 = mult(bs, bb); + Bfree(bb); + bb = bb1; + if (!bb) goto retfree; + } + if (bb2 > 0) { + bb = lshift(bb, bb2); + if (!bb) goto retfree; + } + if (bd5 > 0) { + bd = pow5mult(bd, bd5); + if (!bd) goto retfree; + } + if (bd2 > 0) { + bd = lshift(bd, bd2); + if (!bd) goto retfree; + } + if (bs2 > 0) { + bs = lshift(bs, bs2); + if (!bs) goto retfree; + } + delta = diff(bb, bd); + if (!delta) goto retfree; + dsign = delta->sign; + delta->sign = 0; + i = cmp(delta, bs); +#ifdef Honor_FLT_ROUNDS + if (rounding != 1) { + if (i < 0) { + /* Error is less than an ulp */ + if (!delta->x[0] && delta->wds <= 1) { + /* exact */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (rounding) { + if (dsign) { + adj = 1.; + goto apply_adj; + } + } + else if (!dsign) { + adj = -1.; + if (!word1(rv) + && !(word0(rv) & Frac_mask)) { + y = word0(rv) & Exp_mask; +#ifdef Avoid_Underflow + if (!scale || y > 2*P*Exp_msk1) +#else + if (y) +#endif + { + delta = lshift(delta,Log2P); + if (!delta) goto nomem; + if (cmp(delta, bs) <= 0) + adj = -0.5; + } + } +apply_adj: +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) + <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= + P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + dval(rv) += adj*ulp(dval(rv)); + word0(rv) -= P*Exp_msk1; + } + else +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + dval(rv) += adj*ulp(dval(rv)); + } + break; + } + adj = ratio(delta, bs); + if (adj < 1.) + adj = 1.; + if (adj <= 0x7ffffffe) { + /* adj = rounding ? ceil(adj) : floor(adj); */ + y = adj; + if (y != adj) { + if (!((rounding>>1) ^ dsign)) + y++; + adj = y; + } + } +#ifdef Avoid_Underflow + if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + word0(adj) += (2*P+1)*Exp_msk1 - y; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + word0(rv) += P*Exp_msk1; + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + word0(rv) -= P*Exp_msk1; + goto cont; + } +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + adj *= ulp(dval(rv)); + if (dsign) + dval(rv) += adj; + else + dval(rv) -= adj; + goto cont; + } +#endif /*Honor_FLT_ROUNDS*/ + + if (i < 0) { + /* Error is less than half an ulp -- check for + * special case of mantissa a power of two. + */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask +#ifdef IEEE_Arith +#ifdef Avoid_Underflow + || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1 +#else + || (word0(rv) & Exp_mask) <= Exp_msk1 +#endif +#endif + ) { +#ifdef SET_INEXACT + if (!delta->x[0] && delta->wds <= 1) + inexact = 0; +#endif + break; + } + if (!delta->x[0] && delta->wds <= 1) { + /* exact result */ +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + delta = lshift(delta,Log2P); + if (!delta) goto retfree; + if (cmp(delta, bs) > 0) + goto drop_down; + break; + } + if (i == 0) { + /* exactly half-way between */ + if (dsign) { + if ((word0(rv) & Bndry_mask1) == Bndry_mask1 + && word1(rv) == ( +#ifdef Avoid_Underflow + (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1) + ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : +#endif + 0xffffffff)) { + /*boundary case -- increment exponent*/ + word0(rv) = (word0(rv) & Exp_mask) + + Exp_msk1 +#ifdef IBM + | Exp_msk1 >> 4 +#endif + ; + word1(rv) = 0; +#ifdef Avoid_Underflow + dsign = 0; +#endif + break; + } + } + else if (!(word0(rv) & Bndry_mask) && !word1(rv)) { +drop_down: + /* boundary case -- decrement exponent */ +#ifdef Sudden_Underflow /*{{*/ + L = word0(rv) & Exp_mask; +#ifdef IBM + if (L < Exp_msk1) +#else +#ifdef Avoid_Underflow + if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) +#else + if (L <= Exp_msk1) +#endif /*Avoid_Underflow*/ +#endif /*IBM*/ + goto undfl; + L -= Exp_msk1; +#else /*Sudden_Underflow}{*/ +#ifdef Avoid_Underflow + if (scale) { + L = word0(rv) & Exp_mask; + if (L <= (2*P+1)*Exp_msk1) { + if (L > (P+2)*Exp_msk1) + /* round even ==> */ + /* accept rv */ + break; + /* rv = smallest denormal */ + goto undfl; + } + } +#endif /*Avoid_Underflow*/ + L = (word0(rv) & Exp_mask) - Exp_msk1; +#endif /*Sudden_Underflow}}*/ + word0(rv) = L | Bndry_mask1; + word1(rv) = 0xffffffff; +#ifdef IBM + goto cont; +#else + break; +#endif + } +#ifndef ROUND_BIASED + if (!(word1(rv) & LSB)) + break; +#endif + if (dsign) + dval(rv) += ulp(dval(rv)); +#ifndef ROUND_BIASED + else { + dval(rv) -= ulp(dval(rv)); +#ifndef Sudden_Underflow + if (!dval(rv)) + goto undfl; +#endif + } +#ifdef Avoid_Underflow + dsign = 1 - dsign; +#endif +#endif + break; + } + if ((aadj = ratio(delta, bs)) <= 2.) { + if (dsign) + aadj = dval(aadj1) = 1.; + else if (word1(rv) || word0(rv) & Bndry_mask) { +#ifndef Sudden_Underflow + if (word1(rv) == Tiny1 && !word0(rv)) + goto undfl; +#endif + aadj = 1.; + dval(aadj1) = -1.; + } + else { + /* special case -- power of FLT_RADIX to be */ + /* rounded down... */ + + if (aadj < 2./FLT_RADIX) + aadj = 1./FLT_RADIX; + else + aadj *= 0.5; + dval(aadj1) = -aadj; + } + } + else { + aadj *= 0.5; + dval(aadj1) = dsign ? aadj : -aadj; +#ifdef Check_FLT_ROUNDS + switch (Rounding) { + case 2: /* towards +infinity */ + dval(aadj1) -= 0.5; + break; + case 0: /* towards 0 */ + case 3: /* towards -infinity */ + dval(aadj1) += 0.5; + } +#else + if (Flt_Rounds == 0) + dval(aadj1) += 0.5; +#endif /*Check_FLT_ROUNDS*/ + } + y = word0(rv) & Exp_mask; + + /* Check for overflow */ + + if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { + dval(rv0) = dval(rv); + word0(rv) -= P*Exp_msk1; + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; + if ((word0(rv) & Exp_mask) >= + Exp_msk1*(DBL_MAX_EXP+Bias-P)) { + if (word0(rv0) == Big0 && word1(rv0) == Big1) + goto ovfl; + word0(rv) = Big0; + word1(rv) = Big1; + goto cont; + } + else + word0(rv) += P*Exp_msk1; + } + else { +#ifdef Avoid_Underflow + if (scale && y <= 2*P*Exp_msk1) { + if (aadj <= 0x7fffffff) { + if ((z = (int)aadj) <= 0) + z = 1; + aadj = z; + dval(aadj1) = dsign ? aadj : -aadj; + } + word0(aadj1) += (2*P+1)*Exp_msk1 - y; + } + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; +#else +#ifdef Sudden_Underflow + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { + dval(rv0) = dval(rv); + word0(rv) += P*Exp_msk1; + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; +#ifdef IBM + if ((word0(rv) & Exp_mask) < P*Exp_msk1) +#else + if ((word0(rv) & Exp_mask) <= P*Exp_msk1) +#endif + { + if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1) + goto undfl; + word0(rv) = Tiny0; + word1(rv) = Tiny1; + goto cont; + } + else + word0(rv) -= P*Exp_msk1; + } + else { + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; + } +#else /*Sudden_Underflow*/ + /* Compute adj so that the IEEE rounding rules will + * correctly round rv + adj in some half-way cases. + * If rv * ulp(rv) is denormalized (i.e., + * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid + * trouble from bits lost to denormalization; + * example: 1.2e-307 . + */ + if (y <= (P-1)*Exp_msk1 && aadj > 1.) { + dval(aadj1) = (double)(int)(aadj + 0.5); + if (!dsign) + dval(aadj1) = -dval(aadj1); + } + adj = dval(aadj1) * ulp(dval(rv)); + dval(rv) += adj; +#endif /*Sudden_Underflow*/ +#endif /*Avoid_Underflow*/ + } + z = word0(rv) & Exp_mask; +#ifndef SET_INEXACT +#ifdef Avoid_Underflow + if (!scale) +#endif + if (y == z) { + /* Can we stop now? */ + L = (Long)aadj; + aadj -= L; + /* The tolerances below are conservative. */ + if (dsign || word1(rv) || word0(rv) & Bndry_mask) { + if (aadj < .4999999 || aadj > .5000001) + break; + } + else if (aadj < .4999999/FLT_RADIX) + break; + } +#endif +cont: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(delta); + } +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(rv0) = Exp_1 + (70 << Exp_shift); + word1(rv0) = 0; + dval(rv0) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif +#ifdef Avoid_Underflow + if (scale) { + word0(rv0) = Exp_1 - 2*P*Exp_msk1; + word1(rv0) = 0; + dval(rv) *= dval(rv0); +#ifndef NO_ERRNO + /* try to avoid the bug of testing an 8087 register value */ + if (word0(rv) == 0 && word1(rv) == 0) + errno = ERANGE; +#endif + } +#endif /* Avoid_Underflow */ +#ifdef SET_INEXACT + if (inexact && !(word0(rv) & Exp_mask)) { + /* set underflow bit */ + dval(rv0) = 1e-300; + dval(rv0) *= dval(rv0); + } +#endif +retfree: + Bfree(bb); + Bfree(bd); + Bfree(bs); + Bfree(bd0); + Bfree(delta); +ret: + if (se) + *se = (char *)s; + return sign ? -dval(rv) : dval(rv); +} + +NO_SANITIZE("unsigned-integer-overflow", static int quorem(Bigint *b, Bigint *S)); +static int +quorem(Bigint *b, Bigint *S) +{ + int n; + ULong *bx, *bxe, q, *sx, *sxe; +#ifdef ULLong + ULLong borrow, carry, y, ys; +#else + ULong borrow, carry, y, ys; +#ifdef Pack_32 + ULong si, z, zs; +#endif +#endif + + n = S->wds; +#ifdef DEBUG + /*debug*/ if (b->wds > n) + /*debug*/ Bug("oversize b in quorem"); +#endif + if (b->wds < n) + return 0; + sx = S->x; + sxe = sx + --n; + bx = b->x; + bxe = bx + n; + q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ +#ifdef DEBUG + /*debug*/ if (q > 9) + /*debug*/ Bug("oversized quotient in quorem"); +#endif + if (q) { + borrow = 0; + carry = 0; + do { +#ifdef ULLong + ys = *sx++ * (ULLong)q + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong)(y & FFFFFFFF); +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) * q + carry; + zs = (si >> 16) * q + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ * q + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } while (sx <= sxe); + if (!*bxe) { + bx = b->x; + while (--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + if (cmp(b, S) >= 0) { + q++; + borrow = 0; + carry = 0; + bx = b->x; + sx = S->x; + do { +#ifdef ULLong + ys = *sx++ + carry; + carry = ys >> 32; + y = *bx - (ys & FFFFFFFF) - borrow; + borrow = y >> 32 & (ULong)1; + *bx++ = (ULong)(y & FFFFFFFF); +#else +#ifdef Pack_32 + si = *sx++; + ys = (si & 0xffff) + carry; + zs = (si >> 16) + (ys >> 16); + carry = zs >> 16; + y = (*bx & 0xffff) - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + z = (*bx >> 16) - (zs & 0xffff) - borrow; + borrow = (z & 0x10000) >> 16; + Storeinc(bx, z, y); +#else + ys = *sx++ + carry; + carry = ys >> 16; + y = *bx - (ys & 0xffff) - borrow; + borrow = (y & 0x10000) >> 16; + *bx++ = y & 0xffff; +#endif +#endif + } while (sx <= sxe); + bx = b->x; + bxe = bx + n; + if (!*bxe) { + while (--bxe > bx && !*bxe) + --n; + b->wds = n; + } + } + return q; +} + +#ifndef MULTIPLE_THREADS +static char *dtoa_result; +#endif + +#ifndef MULTIPLE_THREADS +static char * +rv_alloc(int i) +{ + return dtoa_result = MALLOC(i); +} +#else +#define rv_alloc(i) MALLOC(i) +#endif + +static char * +nrv_alloc(const char *s, char **rve, size_t n) +{ + char *rv, *t; + + t = rv = rv_alloc(n); + if (!rv) return NULL; + while ((*t = *s++) != 0) t++; + if (rve) + *rve = t; + return rv; +} + +#define rv_strdup(s, rve) nrv_alloc((s), (rve), strlen(s)+1) + +#ifndef MULTIPLE_THREADS +/* freedtoa(s) must be used to free values s returned by dtoa + * when MULTIPLE_THREADS is #defined. It should be used in all cases, + * but for consistency with earlier versions of dtoa, it is optional + * when MULTIPLE_THREADS is not defined. + */ + +static void +freedtoa(char *s) +{ + FREE(s); +} +#endif + +static const char INFSTR[] = "Infinity"; +static const char NANSTR[] = "NaN"; +static const char ZEROSTR[] = "0"; + +/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. + * + * Inspired by "How to Print Floating-Point Numbers Accurately" by + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. + * + * Modifications: + * 1. Rather than iterating, we use a simple numeric overestimate + * to determine k = floor(log10(d)). We scale relevant + * quantities using O(log2(k)) rather than O(k) multiplications. + * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't + * try to generate digits strictly left to right. Instead, we + * compute with fewer bits and propagate the carry if necessary + * when rounding the final digit up. This is often faster. + * 3. Under the assumption that input will be rounded nearest, + * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. + * That is, we allow equality in stopping tests when the + * round-nearest rule will give the same floating-point value + * as would satisfaction of the stopping test with strict + * inequality. + * 4. We remove common factors of powers of 2 from relevant + * quantities. + * 5. When converting floating-point integers less than 1e16, + * we use floating-point arithmetic rather than resorting + * to multiple-precision integers. + * 6. When asked to produce fewer than 15 digits, we first try + * to get by with floating-point arithmetic; we resort to + * multiple-precision integer arithmetic only if we cannot + * guarantee that the floating-point calculation has given + * the correctly rounded result. For k requested digits and + * "uniformly" distributed input, the probability is + * something like 10^(k-15) that we must resort to the Long + * calculation. + */ + +char * +dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve) +{ + /* Arguments ndigits, decpt, sign are similar to those + of ecvt and fcvt; trailing zeros are suppressed from + the returned string. If not null, *rve is set to point + to the end of the return value. If d is +-Infinity or NaN, + then *decpt is set to 9999. + + mode: + 0 ==> shortest string that yields d when read in + and rounded to nearest. + 1 ==> like 0, but with Steele & White stopping rule; + e.g. with IEEE P754 arithmetic , mode 0 gives + 1e23 whereas mode 1 gives 9.999999999999999e22. + 2 ==> max(1,ndigits) significant digits. This gives a + return value similar to that of ecvt, except + that trailing zeros are suppressed. + 3 ==> through ndigits past the decimal point. This + gives a return value similar to that from fcvt, + except that trailing zeros are suppressed, and + ndigits can be negative. + 4,5 ==> similar to 2 and 3, respectively, but (in + round-nearest mode) with the tests of mode 0 to + possibly return a shorter string that rounds to d. + With IEEE arithmetic and compilation with + -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same + as modes 2 and 3 when FLT_ROUNDS != 1. + 6-9 ==> Debugging modes similar to mode - 4: don't try + fast floating-point estimate (if applicable). + + Values of mode other than 0-9 are treated as mode 0. + + Sufficient space is allocated to the return value + to hold the suppressed trailing zeros. + */ + + int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, + j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, + spec_case, try_quick, half = 0; + Long L; +#ifndef Sudden_Underflow + int denorm; + ULong x; +#endif + Bigint *b, *b1, *delta, *mlo = 0, *mhi = 0, *S; + double ds; + double_u d, d2, eps; + char *s, *s0; +#ifdef Honor_FLT_ROUNDS + int rounding; +#endif +#ifdef SET_INEXACT + int inexact, oldinexact; +#endif + + dval(d) = d_; + +#ifndef MULTIPLE_THREADS + if (dtoa_result) { + freedtoa(dtoa_result); + dtoa_result = 0; + } +#endif + + if (word0(d) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(d) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + +#if defined(IEEE_Arith) + defined(VAX) +#ifdef IEEE_Arith + if ((word0(d) & Exp_mask) == Exp_mask) +#else + if (word0(d) == 0x8000) +#endif + { + /* Infinity or NaN */ + *decpt = 9999; +#ifdef IEEE_Arith + if (!word1(d) && !(word0(d) & 0xfffff)) + return rv_strdup(INFSTR, rve); +#endif + return rv_strdup(NANSTR, rve); + } +#endif +#ifdef IBM + dval(d) += 0; /* normalize */ +#endif + if (!dval(d)) { + *decpt = 1; + return rv_strdup(ZEROSTR, rve); + } + +#ifdef SET_INEXACT + try_quick = oldinexact = get_inexact(); + inexact = 1; +#endif +#ifdef Honor_FLT_ROUNDS + if ((rounding = Flt_Rounds) >= 2) { + if (*sign) + rounding = rounding == 2 ? 0 : 2; + else + if (rounding != 2) + rounding = 0; + } +#endif + + b = d2b(dval(d), &be, &bbits); + if (!b) return NULL; +#ifdef Sudden_Underflow + i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); +#else + if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) { +#endif + dval(d2) = dval(d); + word0(d2) &= Frac_mask1; + word0(d2) |= Exp_11; +#ifdef IBM + if (j = 11 - hi0bits(word0(d2) & Frac_mask)) + dval(d2) /= 1 << j; +#endif + + /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 + * log10(x) = log(x) / log(10) + * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) + * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) + * + * This suggests computing an approximation k to log10(d) by + * + * k = (i - Bias)*0.301029995663981 + * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); + * + * We want k to be too large rather than too small. + * The error in the first-order Taylor series approximation + * is in our favor, so we just round up the constant enough + * to compensate for any error in the multiplication of + * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, + * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, + * adding 1e-13 to the constant term more than suffices. + * Hence we adjust the constant term to 0.1760912590558. + * (We could get a more accurate k by invoking log10, + * but this is probably not worthwhile.) + */ + + i -= Bias; +#ifdef IBM + i <<= 2; + i += j; +#endif +#ifndef Sudden_Underflow + denorm = 0; + } + else { + /* d is denormalized */ + + i = bbits + be + (Bias + (P-1) - 1); + x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) + : word1(d) << (32 - i); + dval(d2) = x; + word0(d2) -= 31*Exp_msk1; /* adjust exponent */ + i -= (Bias + (P-1) - 1) + 1; + denorm = 1; + } +#endif + ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + k = (int)ds; + if (ds < 0. && ds != k) + k--; /* want k = floor(ds) */ + k_check = 1; + if (k >= 0 && k <= Ten_pmax) { + if (dval(d) < tens[k]) + k--; + k_check = 0; + } + j = bbits - i - 1; + if (j >= 0) { + b2 = 0; + s2 = j; + } + else { + b2 = -j; + s2 = 0; + } + if (k >= 0) { + b5 = 0; + s5 = k; + s2 += k; + } + else { + b2 -= k; + b5 = -k; + s5 = 0; + } + if (mode < 0 || mode > 9) + mode = 0; + +#ifndef SET_INEXACT +#ifdef Check_FLT_ROUNDS + try_quick = Rounding == 1; +#else + try_quick = 1; +#endif +#endif /*SET_INEXACT*/ + + if (mode > 5) { + mode -= 4; + try_quick = 0; + } + leftright = 1; + ilim = ilim1 = -1; + switch (mode) { + case 0: + case 1: + i = 18; + ndigits = 0; + break; + case 2: + leftright = 0; + /* no break */ + case 4: + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + break; + case 3: + leftright = 0; + /* no break */ + case 5: + if (ckd_add(&i, ndigits, k + 1)) { /* k + 1 should be safe */ + Bfree(b); + return NULL; + } + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } + s = s0 = rv_alloc(i+1); + if (!s) { + Bfree(b); + return NULL; + } + +#ifdef Honor_FLT_ROUNDS + if (mode > 1 && rounding != 1) + leftright = 0; +#endif + + if (ilim >= 0 && ilim <= Quick_max && try_quick) { + + /* Try to get by with floating-point arithmetic. */ + + i = 0; + dval(d2) = dval(d); + k0 = k; + ilim0 = ilim; + ieps = 2; /* conservative */ + if (k > 0) { + ds = tens[k&0xf]; + j = k >> 4; + if (j & Bletch) { + /* prevent overflows */ + j &= Bletch - 1; + dval(d) /= bigtens[n_bigtens-1]; + ieps++; + } + for (; j; j >>= 1, i++) + if (j & 1) { + ieps++; + ds *= bigtens[i]; + } + dval(d) /= ds; + } + else if ((j1 = -k) != 0) { + dval(d) *= tens[j1 & 0xf]; + for (j = j1 >> 4; j; j >>= 1, i++) + if (j & 1) { + ieps++; + dval(d) *= bigtens[i]; + } + } + if (k_check && dval(d) < 1. && ilim > 0) { + if (ilim1 <= 0) + goto fast_failed; + ilim = ilim1; + k--; + dval(d) *= 10.; + ieps++; + } + dval(eps) = ieps*dval(d) + 7.; + word0(eps) -= (P-1)*Exp_msk1; + if (ilim == 0) { + S = mhi = 0; + dval(d) -= 5.; + if (dval(d) > dval(eps)) + goto one_digit; + if (dval(d) < -dval(eps)) + goto no_digits; + goto fast_failed; + } +#ifndef No_leftright + if (leftright) { + /* Use Steele & White method of only + * generating digits needed. + */ + dval(eps) = 0.5/tens[ilim-1] - dval(eps); + for (i = 0;;) { + L = (int)dval(d); + dval(d) -= L; + *s++ = '0' + (int)L; + if (dval(d) < dval(eps)) + goto ret1; + if (1. - dval(d) < dval(eps)) + goto bump_up; + if (++i >= ilim) + break; + dval(eps) *= 10.; + dval(d) *= 10.; + } + } + else { +#endif + /* Generate ilim digits, then fix them up. */ + dval(eps) *= tens[ilim-1]; + for (i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d)); + if (!(dval(d) -= L)) + ilim = i; + *s++ = '0' + (int)L; + if (i == ilim) { + if (dval(d) > 0.5 + dval(eps)) + goto bump_up; + else if (dval(d) < 0.5 - dval(eps)) { + while (*--s == '0') ; + s++; + goto ret1; + } + half = 1; + if ((*(s-1) - '0') & 1) { + goto bump_up; + } + break; + } + } +#ifndef No_leftright + } +#endif +fast_failed: + s = s0; + dval(d) = dval(d2); + k = k0; + ilim = ilim0; + } + + /* Do we have a "small" integer? */ + + if (be >= 0 && k <= Int_max) { + /* Yes. */ + ds = tens[k]; + if (ndigits < 0 && ilim <= 0) { + S = mhi = 0; + if (ilim < 0 || dval(d) <= 5*ds) + goto no_digits; + goto one_digit; + } + for (i = 1;; i++, dval(d) *= 10.) { + L = (Long)(dval(d) / ds); + dval(d) -= L*ds; +#ifdef Check_FLT_ROUNDS + /* If FLT_ROUNDS == 2, L will usually be high by 1 */ + if (dval(d) < 0) { + L--; + dval(d) += ds; + } +#endif + *s++ = '0' + (int)L; + if (!dval(d)) { +#ifdef SET_INEXACT + inexact = 0; +#endif + break; + } + if (i == ilim) { +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch (rounding) { + case 0: goto ret1; + case 2: goto bump_up; + } +#endif + dval(d) += dval(d); + if (dval(d) > ds || (dval(d) == ds && (L & 1))) { +bump_up: + while (*--s == '9') + if (s == s0) { + k++; + *s = '0'; + break; + } + ++*s++; + } + break; + } + } + goto ret1; + } + + m2 = b2; + m5 = b5; + if (leftright) { + i = +#ifndef Sudden_Underflow + denorm ? be + (Bias + (P-1) - 1 + 1) : +#endif +#ifdef IBM + 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); +#else + 1 + P - bbits; +#endif + b2 += i; + s2 += i; + mhi = i2b(1); + if (!mhi) goto nomem; + } + if (m2 > 0 && s2 > 0) { + i = m2 < s2 ? m2 : s2; + b2 -= i; + m2 -= i; + s2 -= i; + } + if (b5 > 0) { + if (leftright) { + if (m5 > 0) { + mhi = pow5mult(mhi, m5); + if (!mhi) goto nomem; + b1 = mult(mhi, b); + Bfree(b); + b = b1; + if (!b) goto nomem; + } + if ((j = b5 - m5) != 0) { + b = pow5mult(b, j); + if (!b) goto nomem; + } + } + else { + b = pow5mult(b, b5); + if (!b) goto nomem; + } + } + S = i2b(1); + if (!S) goto nomem; + if (s5 > 0) { + S = pow5mult(S, s5); + if (!S) goto nomem; + } + + /* Check for special case that d is a normalized power of 2. */ + + spec_case = 0; + if ((mode < 2 || leftright) +#ifdef Honor_FLT_ROUNDS + && rounding == 1 +#endif + ) { + if (!word1(d) && !(word0(d) & Bndry_mask) +#ifndef Sudden_Underflow + && word0(d) & (Exp_mask & ~Exp_msk1) +#endif + ) { + /* The special case */ + b2 += Log2P; + s2 += Log2P; + spec_case = 1; + } + } + + /* Arrange for convenient computation of quotients: + * shift left if necessary so divisor has 4 leading 0 bits. + * + * Perhaps we should just compute leading 28 bits of S once + * and for all and pass them and a shift to quorem, so it + * can do shifts and ors to compute the numerator for q. + */ +#ifdef Pack_32 + if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0) + i = 32 - i; +#else + if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) != 0) + i = 16 - i; +#endif + if (i > 4) { + i -= 4; + b2 += i; + m2 += i; + s2 += i; + } + else if (i < 4) { + i += 28; + b2 += i; + m2 += i; + s2 += i; + } + if (b2 > 0) { + b = lshift(b, b2); + if (!b) goto nomem; + } + if (s2 > 0) { + S = lshift(S, s2); + if (!S) goto nomem; + } + if (k_check) { + if (cmp(b,S) < 0) { + k--; + b = multadd(b, 10, 0); /* we botched the k estimate */ + if (!b) goto nomem; + if (leftright) { + mhi = multadd(mhi, 10, 0); + if (!mhi) goto nomem; + } + ilim = ilim1; + } + } + if (ilim <= 0 && (mode == 3 || mode == 5)) { + if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { + /* no digits, fcvt style */ +no_digits: + k = -1 - ndigits; + goto ret; + } +one_digit: + *s++ = '1'; + k++; + goto ret; + } + if (leftright) { + if (m2 > 0) { + mhi = lshift(mhi, m2); + if (!mhi) goto nomem; + } + + /* Compute mlo -- check for special case + * that d is a normalized power of 2. + */ + + mlo = mhi; + if (spec_case) { + mhi = Balloc(mhi->k); + if (!mhi) goto nomem; + Bcopy(mhi, mlo); + mhi = lshift(mhi, Log2P); + if (!mhi) goto nomem; + } + + for (i = 1;;i++) { + dig = quorem(b,S) + '0'; + /* Do we yet have the shortest decimal string + * that will round to d? + */ + j = cmp(b, mlo); + delta = diff(S, mhi); + if (!delta) goto nomem; + j1 = delta->sign ? 1 : cmp(b, delta); + Bfree(delta); +#ifndef ROUND_BIASED + if (j1 == 0 && mode != 1 && !(word1(d) & 1) +#ifdef Honor_FLT_ROUNDS + && rounding >= 1 +#endif + ) { + if (dig == '9') + goto round_9_up; + if (j > 0) + dig++; +#ifdef SET_INEXACT + else if (!b->x[0] && b->wds <= 1) + inexact = 0; +#endif + *s++ = dig; + goto ret; + } +#endif + if (j < 0 || (j == 0 && mode != 1 +#ifndef ROUND_BIASED + && !(word1(d) & 1) +#endif + )) { + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto accept_dig; + } +#ifdef Honor_FLT_ROUNDS + if (mode > 1) + switch (rounding) { + case 0: goto accept_dig; + case 2: goto keep_dig; + } +#endif /*Honor_FLT_ROUNDS*/ + if (j1 > 0) { + b = lshift(b, 1); + if (!b) goto nomem; + j1 = cmp(b, S); + if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9') + goto round_9_up; + } +accept_dig: + *s++ = dig; + goto ret; + } + if (j1 > 0) { +#ifdef Honor_FLT_ROUNDS + if (!rounding) + goto accept_dig; +#endif + if (dig == '9') { /* possible if i == 1 */ +round_9_up: + *s++ = '9'; + goto roundoff; + } + *s++ = dig + 1; + goto ret; + } +#ifdef Honor_FLT_ROUNDS +keep_dig: +#endif + *s++ = dig; + if (i == ilim) + break; + b = multadd(b, 10, 0); + if (!b) goto nomem; + if (mlo == mhi) { + mlo = mhi = multadd(mhi, 10, 0); + if (!mlo) goto nomem; + } + else { + mlo = multadd(mlo, 10, 0); + if (!mlo) goto nomem; + mhi = multadd(mhi, 10, 0); + if (!mhi) goto nomem; + } + } + } + else + for (i = 1;; i++) { + *s++ = dig = quorem(b,S) + '0'; + if (!b->x[0] && b->wds <= 1) { +#ifdef SET_INEXACT + inexact = 0; +#endif + goto ret; + } + if (i >= ilim) + break; + b = multadd(b, 10, 0); + if (!b) goto nomem; + } + + /* Round off last digit */ + +#ifdef Honor_FLT_ROUNDS + switch (rounding) { + case 0: goto trimzeros; + case 2: goto roundoff; + } +#endif + b = lshift(b, 1); + if (!b) goto nomem; + j = cmp(b, S); + if (j > 0 || (j == 0 && (dig & 1))) { + roundoff: + while (*--s == '9') + if (s == s0) { + k++; + *s++ = '1'; + goto ret; + } + if (!half || (*s - '0') & 1) + ++*s; + } + else { + while (*--s == '0') ; + } + s++; +ret: + Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } +ret1: +#ifdef SET_INEXACT + if (inexact) { + if (!oldinexact) { + word0(d) = Exp_1 + (70 << Exp_shift); + word1(d) = 0; + dval(d) += 1.; + } + } + else if (!oldinexact) + clear_inexact(); +#endif + Bfree(b); + *s = 0; + *decpt = k + 1; + if (rve) + *rve = s; + return s0; + nomem: + if (S) Bfree(S); + if (mhi) { + if (mlo && mlo != mhi) + Bfree(mlo); + Bfree(mhi); + } + if (b) Bfree(b); + FREE(s0); + return NULL; +} + +/*- + * Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG> + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define DBL_MANH_SIZE 20 +#define DBL_MANL_SIZE 32 +#define DBL_ADJ (DBL_MAX_EXP - 2) +#define SIGFIGS ((DBL_MANT_DIG + 3) / 4 + 1) +#define dexp_get(u) ((int)(word0(u) >> Exp_shift) & ~Exp_msk1) +#define dexp_set(u,v) (word0(u) = (((int)(word0(u)) & ~Exp_mask) | ((v) << Exp_shift))) +#define dmanh_get(u) ((uint32_t)(word0(u) & Frac_mask)) +#define dmanl_get(u) ((uint32_t)word1(u)) + + +/* + * This procedure converts a double-precision number in IEEE format + * into a string of hexadecimal digits and an exponent of 2. Its + * behavior is bug-for-bug compatible with dtoa() in mode 2, with the + * following exceptions: + * + * - An ndigits < 0 causes it to use as many digits as necessary to + * represent the number exactly. + * - The additional xdigs argument should point to either the string + * "0123456789ABCDEF" or the string "0123456789abcdef", depending on + * which case is desired. + * - This routine does not repeat dtoa's mistake of setting decpt + * to 9999 in the case of an infinity or NaN. INT_MAX is used + * for this purpose instead. + * + * Note that the C99 standard does not specify what the leading digit + * should be for non-zero numbers. For instance, 0x1.3p3 is the same + * as 0x2.6p2 is the same as 0x4.cp3. This implementation always makes + * the leading digit a 1. This ensures that the exponent printed is the + * actual base-2 exponent, i.e., ilogb(d). + * + * Inputs: d, xdigs, ndigits + * Outputs: decpt, sign, rve + */ +char * +hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve) +{ + U u; + char *s, *s0; + int bufsize; + uint32_t manh, manl; + + u.d = d; + if (word0(u) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(u) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + + if (isinf(d)) { /* FP_INFINITE */ + *decpt = INT_MAX; + return rv_strdup(INFSTR, rve); + } + else if (isnan(d)) { /* FP_NAN */ + *decpt = INT_MAX; + return rv_strdup(NANSTR, rve); + } + else if (d == 0.0) { /* FP_ZERO */ + *decpt = 1; + return rv_strdup(ZEROSTR, rve); + } + else if (dexp_get(u)) { /* FP_NORMAL */ + *decpt = dexp_get(u) - DBL_ADJ; + } + else { /* FP_SUBNORMAL */ + u.d *= 5.363123171977039e+154 /* 0x1p514 */; + *decpt = dexp_get(u) - (514 + DBL_ADJ); + } + + if (ndigits == 0) /* dtoa() compatibility */ + ndigits = 1; + + /* + * If ndigits < 0, we are expected to auto-size, so we allocate + * enough space for all the digits. + */ + bufsize = (ndigits > 0) ? ndigits : SIGFIGS; + s0 = rv_alloc(bufsize+1); + if (!s0) return NULL; + + /* Round to the desired number of digits. */ + if (SIGFIGS > ndigits && ndigits > 0) { + float redux = 1.0f; + int offset = 4 * ndigits + DBL_MAX_EXP - 4 - DBL_MANT_DIG; + dexp_set(u, offset); + u.d += redux; + u.d -= redux; + *decpt += dexp_get(u) - offset; + } + + manh = dmanh_get(u); + manl = dmanl_get(u); + *s0 = '1'; + for (s = s0 + 1; s < s0 + bufsize; s++) { + *s = xdigs[(manh >> (DBL_MANH_SIZE - 4)) & 0xf]; + manh = (manh << 4) | (manl >> (DBL_MANL_SIZE - 4)); + manl <<= 4; + } + + /* If ndigits < 0, we are expected to auto-size the precision. */ + if (ndigits < 0) { + for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--) + ; + } + + s = s0 + ndigits; + *s = '\0'; + if (rve != NULL) + *rve = s; + return (s0); +} + +#ifdef __cplusplus +#if 0 +{ /* satisfy cc-mode */ +#endif +} +#endif diff --git a/missing/dup2.c b/missing/dup2.c deleted file mode 100644 index e7cc46f4c1..0000000000 --- a/missing/dup2.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 "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(fd1, fd2) -int fd1, 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/missing/erf.c b/missing/erf.c index d9e7469024..c2c9d5f7e9 100644 --- a/missing/erf.c +++ b/missing/erf.c @@ -3,30 +3,15 @@ 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(a, x, loggamma_a) - double a, x, loggamma_a; +static double p_gamma(double a, double x, double loggamma_a) { int k; double result, term, previous; @@ -45,8 +30,7 @@ static double p_gamma(a, x, loggamma_a) /* Incomplete gamma function 1 / Gamma(a) * Int_x^inf exp(-t) t^(a-1) dt */ -static double q_gamma(a, x, loggamma_a) - double a, x, loggamma_a; +static double q_gamma(double a, double x, double loggamma_a) { int k; double result, w, temp, previous; @@ -69,8 +53,7 @@ static double q_gamma(a, x, loggamma_a) #define LOG_PI_OVER_2 0.572364942924700087071713675675 /* log_e(PI)/2 */ -double erf(x) - double x; +double erf(double x) { if (!finite(x)) { if (isnan(x)) return x; /* erf(NaN) = NaN */ @@ -80,8 +63,7 @@ double erf(x) else return - p_gamma(0.5, x * x, LOG_PI_OVER_2); } -double erfc(x) - double x; +double erfc(double x) { if (!finite(x)) { if (isnan(x)) return x; /* erfc(NaN) = NaN */ diff --git a/missing/explicit_bzero.c b/missing/explicit_bzero.c new file mode 100644 index 0000000000..59417e158e --- /dev/null +++ b/missing/explicit_bzero.c @@ -0,0 +1,91 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s() */ +#endif + +#include "ruby/missing.h" +#include <string.h> + +#ifdef _WIN32 +#include <windows.h> +#endif + +/* Similar to bzero(), but has a guarantee not to be eliminated from compiler + optimization. */ + +/* OS support note: + * BSDs have explicit_bzero(). + * macOS has memset_s(). + * Windows has SecureZeroMemory() since XP. + * Linux has explicit_bzero() since glibc 2.25, musl libc 1.1.20. + */ + +/* + * Following URL explains why memset_s is added to the standard. + * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1381.pdf + */ + +#ifndef FUNC_UNOPTIMIZED +# define FUNC_UNOPTIMIZED(x) x +#endif + +#undef explicit_bzero +#ifndef HAVE_EXPLICIT_BZERO + #ifdef HAVE_EXPLICIT_MEMSET +void +explicit_bzero(void *b, size_t len) +{ + (void)explicit_memset(b, 0, len); +} + #elif defined HAVE_MEMSET_S +void +explicit_bzero(void *b, size_t len) +{ + memset_s(b, len, 0, len); +} + #elif defined SecureZeroMemory +void +explicit_bzero(void *b, size_t len) +{ + SecureZeroMemory(b, len); +} + + #elif defined HAVE_FUNC_WEAK + +/* A weak function never be optimized away. Even if nobody uses it. */ +WEAK(void ruby_explicit_bzero_hook_unused(void *buf, size_t len)); +void +ruby_explicit_bzero_hook_unused(void *buf, size_t len) +{ +} + +void +explicit_bzero(void *b, size_t len) +{ + memset(b, 0, len); + ruby_explicit_bzero_hook_unused(b, len); +} + + #else /* Your OS have no capability. Sigh. */ + +FUNC_UNOPTIMIZED(void explicit_bzero(void *b, size_t len)); +#undef explicit_bzero + +void +explicit_bzero(void *b, size_t len) +{ + /* + * volatile is not enough if the compiler has an LTO (link time + * optimization). At least, the standard provides no guarantee. + * However, gcc and major other compilers never optimize a volatile + * variable away. So, using volatile is practically ok. + */ + volatile char* p = (volatile char*)b; + + while(len) { + *p = 0; + p++; + len--; + } +} + #endif +#endif /* HAVE_EXPLICIT_BZERO */ diff --git a/missing/ffs.c b/missing/ffs.c new file mode 100644 index 0000000000..bad99cf116 --- /dev/null +++ b/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/missing/file.h b/missing/file.h index 2d491d0fc1..5e25c4761c 100644 --- a/missing/file.h +++ b/missing/file.h @@ -1,7 +1,6 @@ -/* This is file FILE.H */ - #ifndef _FILE_H_ #define _FILE_H_ +/* This is file FILE.H */ #include <fcntl.h> @@ -15,7 +14,7 @@ #ifndef R_OK # define R_OK 4 /* test whether readable. */ # define W_OK 2 /* test whether writable. */ -# define X_OK 1 /* test whether execubale. */ +# define X_OK 1 /* test whether executable. */ # define F_OK 0 /* test whether exist. */ #endif diff --git a/missing/fileblocks.c b/missing/fileblocks.c deleted file mode 100644 index ccb8d667b4..0000000000 --- a/missing/fileblocks.c +++ /dev/null @@ -1 +0,0 @@ -/* dummy for autoconf */ diff --git a/missing/finite.c b/missing/finite.c deleted file mode 100644 index f91035a8cd..0000000000 --- a/missing/finite.c +++ /dev/null @@ -1,8 +0,0 @@ -/* public domain rewrite of finite(3) */ - -int -finite(n) - double n; -{ - return !isnan(n) && !isinf(n); -} diff --git a/missing/flock.c b/missing/flock.c index 5f6b41c357..0b76961762 100644 --- a/missing/flock.c +++ b/missing/flock.c @@ -1,9 +1,19 @@ -#include "config.h" +#include "ruby/internal/config.h" +#include "ruby/ruby.h" #if defined _WIN32 +#elif defined __wasi__ +#include <errno.h> + +int +flock(int fd, int operation) +{ + errno = EINVAL; + return -1; +} #elif defined HAVE_FCNTL && defined HAVE_FCNTL_H -/* These are the flock() constants. Since this sytems doesn't have +/* These are the flock() constants. Since this systems doesn't have flock(), the values of the constants are probably not available. */ # ifndef LOCK_SH @@ -24,12 +34,10 @@ #include <errno.h> int -flock(fd, operation) - int fd; - int operation; +flock(int fd, int operation) { struct flock lock; - + switch (operation & ~LOCK_NB) { case LOCK_SH: lock.l_type = F_RDLCK; @@ -46,7 +54,7 @@ flock(fd, operation) } lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; - + return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lock); } @@ -74,7 +82,7 @@ flock(fd, operation) # define F_TEST 3 /* Test a region for other processes locks */ # endif -/* These are the flock() constants. Since this sytems doesn't have +/* These are the flock() constants. Since this systems doesn't have flock(), the values of the constants are probably not available. */ # ifndef LOCK_SH @@ -91,9 +99,7 @@ flock(fd, operation) # endif int -flock(fd, operation) - int fd; - int operation; +flock(int fd, int operation) { switch (operation) { @@ -125,9 +131,7 @@ flock(fd, operation) } #else int -flock(fd, operation) - int fd; - int operation; +flock(int fd, int operation) { rb_notimplement(); return -1; diff --git a/missing/hypot.c b/missing/hypot.c index aad5259e92..765581bacb 100644 --- a/missing/hypot.c +++ b/missing/hypot.c @@ -1,9 +1,9 @@ /* public domain rewrite of hypot */ +#include "ruby/missing.h" #include <math.h> -double hypot(x,y) - double x, y; +double hypot(double x, double y) { if (x < 0) x = -x; if (y < 0) y = -y; diff --git a/missing/isinf.c b/missing/isinf.c deleted file mode 100644 index c9e49c6795..0000000000 --- a/missing/isinf.c +++ /dev/null @@ -1,72 +0,0 @@ -/* public domain rewrite of isinf(3) */ - -#ifdef __osf__ - -#define _IEEE 1 -#include <nan.h> - -int -isinf(n) - double n; -{ - if (IsNANorINF(n) && IsINF(n)) { - return 1; - } - else { - return 0; - } -} - -#else - -#include "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(n) - double n; -{ - return (!finite(n) && !isnan(n)); -} -#endif - -#else - -#ifdef HAVE_STRING_H -# include <string.h> -#else -# include <strings.h> -#endif - -static double zero() { return 0.0; } -static double one() { return 1.0; } -static double inf() { return one() / zero(); } - -int -isinf(n) - 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/missing/isnan.c b/missing/isnan.c deleted file mode 100644 index 459048e936..0000000000 --- a/missing/isnan.c +++ /dev/null @@ -1,17 +0,0 @@ -/* public domain rewrite of isnan(3) */ - -static int double_ne(); - -int -isnan(n) - double n; -{ - return double_ne(n, n); -} - -static int -double_ne(n1, n2) - double n1, n2; -{ - return n1 != n2; -} diff --git a/missing/langinfo.c b/missing/langinfo.c new file mode 100644 index 0000000000..0274a378f5 --- /dev/null +++ b/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(void) +{ + printf("%s\n", nl_langinfo(CODESET)); + return 0; +} +#endif diff --git a/missing/lgamma_r.c b/missing/lgamma_r.c new file mode 100644 index 0000000000..01066d2930 --- /dev/null +++ b/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 = signbit(x) ? -1 : 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/missing/memcmp.c b/missing/memcmp.c index 9edc9c13b9..9657e6c372 100644 --- a/missing/memcmp.c +++ b/missing/memcmp.c @@ -1,17 +1,18 @@ /* public domain rewrite of memcmp(3) */ +#include "ruby/missing.h" +#include <stddef.h> + int -memcmp(s1,s2,len) - char *s1; - char *s2; - register int len; +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; - while (len--) { - if (tmp = *a++ - *b++) + for (; len; --len) { + tmp = *a++ - *b++; + if (tmp) return tmp; } return 0; diff --git a/missing/memmove.c b/missing/memmove.c index c9d67d8b45..e8e17e87e7 100644 --- a/missing/memmove.c +++ b/missing/memmove.c @@ -1,22 +1,22 @@ /* public domain rewrite of memcmp(3) */ +#include "ruby/missing.h" +#include <stddef.h> + void * -memmove (d, s, n) - void *d, *s; - int n; +memmove(void *d, const void *s, size_t n) { - char *dst = d; - char *src = s; - void *ret = dst; + char *dst = (char *)d; + const char *src = (const char *)s; if (src < dst) { src += n; dst += n; - while (n--) + for (; n; --n) *--dst = *--src; } else if (dst < src) - while (n--) + for (; n; --n) *dst++ = *src++; - return ret; + return d; } diff --git a/missing/mt19937.c b/missing/mt19937.c new file mode 100644 index 0000000000..cf1da349fb --- /dev/null +++ b/missing/mt19937.c @@ -0,0 +1,158 @@ +/* +This is based on trimmed version of MT19937. To get the original version, +contact <http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html>. + +The original copyright notice follows. + + A C-program for MT19937, with initialization improved 2002/2/10. + Coded by Takuji Nishimura and Makoto Matsumoto. + This is a faster version by taking Shawn Cokus's optimization, + Matthe Bellew's simplification, Isaku Wada's real version. + + Before using, initialize the state by using init_genrand(mt, seed) + or init_by_array(mt, init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + 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 names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Any feedback is very welcome. + http://www.math.keio.ac.jp/matumoto/emt.html + email: matumoto@math.keio.ac.jp +*/ + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfU /* constant vector a */ +#define UMASK 0x80000000U /* most significant w-r bits */ +#define LMASK 0x7fffffffU /* least significant r bits */ +#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) ) +#define TWIST(u,v) ((MIXBITS((u),(v)) >> 1) ^ ((v)&1U ? MATRIX_A : 0U)) + +enum {MT_MAX_STATE = N}; + +struct MT { + /* assume int is enough to store 32bits */ + uint32_t state[N]; /* the array for the state vector */ + uint32_t *next; + int left; +}; + +#define genrand_initialized(mt) ((mt)->next != 0) +#define uninit_genrand(mt) ((mt)->next = 0) + +NO_SANITIZE("unsigned-integer-overflow", static void init_genrand(struct MT *mt, unsigned int s)); +NO_SANITIZE("unsigned-integer-overflow", static void init_by_array(struct MT *mt, const uint32_t init_key[], int key_length)); + +/* initializes state[N] with a seed */ +static void +init_genrand(struct MT *mt, unsigned int s) +{ + int j; + mt->state[0] = s & 0xffffffffU; + for (j=1; j<N; j++) { + mt->state[j] = (1812433253U * (mt->state[j-1] ^ (mt->state[j-1] >> 30)) + j); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array state[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt->state[j] &= 0xffffffff; /* for >32 bit machines */ + } + mt->left = 1; + mt->next = mt->state + N; +} + +/* initialize by an array with array-length */ +/* init_key is the array for initializing keys */ +/* key_length is its length */ +/* slight change for C++, 2004/2/26 */ +static void +init_by_array(struct MT *mt, const uint32_t init_key[], int key_length) +{ + int i, j, k; + init_genrand(mt, 19650218U); + i=1; j=0; + k = (N>key_length ? N : key_length); + for (; k; k--) { + mt->state[i] = (mt->state[i] ^ ((mt->state[i-1] ^ (mt->state[i-1] >> 30)) * 1664525U)) + + init_key[j] + j; /* non linear */ + mt->state[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */ + i++; j++; + if (i>=N) { mt->state[0] = mt->state[N-1]; i=1; } + if (j>=key_length) j=0; + } + for (k=N-1; k; k--) { + mt->state[i] = (mt->state[i] ^ ((mt->state[i-1] ^ (mt->state[i-1] >> 30)) * 1566083941U)) + - i; /* non linear */ + mt->state[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */ + i++; + if (i>=N) { mt->state[0] = mt->state[N-1]; i=1; } + } + + mt->state[0] = 0x80000000U; /* MSB is 1; assuring non-zero initial array */ +} + +static void +next_state(struct MT *mt) +{ + uint32_t *p = mt->state; + int j; + + mt->left = N; + mt->next = mt->state; + + for (j=N-M+1; --j; p++) + *p = p[M] ^ TWIST(p[0], p[1]); + + for (j=M; --j; p++) + *p = p[M-N] ^ TWIST(p[0], p[1]); + + *p = p[M-N] ^ TWIST(p[0], mt->state[0]); +} + +/* generates a random number on [0,0xffffffff]-interval */ +static unsigned int +genrand_int32(struct MT *mt) +{ + /* mt must be initialized */ + unsigned int y; + + if (--mt->left <= 0) next_state(mt); + y = *mt->next++; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680; + y ^= (y << 15) & 0xefc60000; + y ^= (y >> 18); + + return y; +} diff --git a/missing/nan.c b/missing/nan.c new file mode 100644 index 0000000000..686c48a336 --- /dev/null +++ b/missing/nan.c @@ -0,0 +1,28 @@ +#include "ruby/missing.h" +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +double +nan(const char *spec) +{ +#if 0 + /* FIXME: we have not yet seen any situation this is + * necessary. Please write a proper implementation that + * covers this branch. */ + if (spec && spec[0]) { + double generated_nan; + int len = snprintf(NULL, 0, "NAN(%s)", spec); + char *buf = malloc(len + 1); /* +1 for NUL */ + sprintf(buf, "NAN(%s)", spec); + generated_nan = strtod(buf, NULL); + free(buf); + return generated_nan; + } + else +#endif + { + assert(!spec || !spec[0]); + return (double)NAN; + } +} diff --git a/missing/nextafter.c b/missing/nextafter.c new file mode 100644 index 0000000000..dd1f1f2319 --- /dev/null +++ b/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/missing/os2.c b/missing/os2.c deleted file mode 100644 index fe7238aad1..0000000000 --- a/missing/os2.c +++ /dev/null @@ -1,113 +0,0 @@ -/* 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; -} - -int -link(char *from, char *to) -{ - return -1; -} - -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/missing/procstat_vm.c b/missing/procstat_vm.c new file mode 100644 index 0000000000..155ee355d1 --- /dev/null +++ b/missing/procstat_vm.c @@ -0,0 +1,85 @@ +#include <sys/user.h> +#include <sys/sysctl.h> +#include <sys/param.h> +#include <libprocstat.h> +# ifndef KVME_TYPE_MGTDEVICE +# define KVME_TYPE_MGTDEVICE 8 +# endif +void +procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp, FILE *errout) +{ + struct kinfo_vmentry *freep, *kve; + int ptrwidth; + unsigned int i, cnt; + const char *str; +#ifdef __x86_64__ + ptrwidth = 14; +#else + ptrwidth = 2*sizeof(void *) + 2; +#endif + fprintf(errout, "%*s %*s %3s %4s %4s %3s %3s %4s %-2s %-s\n", + ptrwidth, "START", ptrwidth, "END", "PRT", "RES", + "P""RES", "REF", "SHD", "FL", "TP", "PATH"); + +#ifdef HAVE_PROCSTAT_GETVMMAP + freep = procstat_getvmmap(procstat, kipp, &cnt); +#else + freep = kinfo_getvmmap(kipp->ki_pid, &cnt); +#endif + if (freep == NULL) + return; + for (i = 0; i < cnt; i++) { + kve = &freep[i]; + fprintf(errout, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_start); + fprintf(errout, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_end); + fprintf(errout, "%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-"); + fprintf(errout, "%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-"); + fprintf(errout, "%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-"); + fprintf(errout, "%4d ", kve->kve_resident); + fprintf(errout, "%4d ", kve->kve_private_resident); + fprintf(errout, "%3d ", kve->kve_ref_count); + fprintf(errout, "%3d ", kve->kve_shadow_count); + fprintf(errout, "%-1s", kve->kve_flags & KVME_FLAG_COW ? "C" : "-"); + fprintf(errout, "%-1s", kve->kve_flags & KVME_FLAG_NEEDS_COPY ? "N" : + "-"); + fprintf(errout, "%-1s", kve->kve_flags & KVME_FLAG_SUPER ? "S" : "-"); + fprintf(errout, "%-1s ", kve->kve_flags & KVME_FLAG_GROWS_UP ? "U" : + kve->kve_flags & KVME_FLAG_GROWS_DOWN ? "D" : "-"); + switch (kve->kve_type) { + case KVME_TYPE_NONE: + str = "--"; + break; + case KVME_TYPE_DEFAULT: + str = "df"; + break; + case KVME_TYPE_VNODE: + str = "vn"; + break; + case KVME_TYPE_SWAP: + str = "sw"; + break; + case KVME_TYPE_DEVICE: + str = "dv"; + break; + case KVME_TYPE_PHYS: + str = "ph"; + break; + case KVME_TYPE_DEAD: + str = "dd"; + break; + case KVME_TYPE_SG: + str = "sg"; + break; + case KVME_TYPE_MGTDEVICE: + str = "md"; + break; + case KVME_TYPE_UNKNOWN: + default: + str = "??"; + break; + } + fprintf(errout, "%-2s ", str); + fprintf(errout, "%-s\n", kve->kve_path); + } + free(freep); +} diff --git a/missing/setproctitle.c b/missing/setproctitle.c new file mode 100644 index 0000000000..5b2dfa65ce --- /dev/null +++ b/missing/setproctitle.c @@ -0,0 +1,231 @@ +/* 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 +RUBY_FUNC_EXPORTED void ruby_init_setproctitle(int argc, char *argv[]); + +#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 */ + +#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV +# define ALLOCATE_ENVIRON 1 +#else +# define ALLOCATE_ENVIRON 0 +#endif + +#if ALLOCATE_ENVIRON +/* system_environ is the value of environ before we allocate a custom buffer. + * + * We use this to restore environ in ruby_free_proctitle. + */ +static char **system_environ = NULL; +/* orig_environ is the buffer we allocate for environ. + * + * We use this to free this buffer in ruby_free_proctitle. When we add new + * environment variables using setenv, the system may change environ to a + * different buffer and will not free the original buffer, so we need to hold + * onto this so we can free it in ruby_free_proctitle. + * + * We must not free any of the contents because it may change if the system + * updates existing environment variables. + */ +static char **orig_environ = NULL; +/* alloc_environ is a copy of orig_environ. + * + * We use this to free all the original string copies that were in orig_environ. + * Since environ could be changed to point to strings allocated by the system + * if environment variables are updated, so we need this to point to the + * original strings. + */ +static char **alloc_environ = NULL; +#endif + +void +compat_init_setproctitle(int argc, char *argv[]) +{ +#if ALLOCATE_ENVIRON + 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++); + + system_environ = environ; + + alloc_environ = xcalloc(i + 1, sizeof(*environ)); + orig_environ = environ = xcalloc(i + 1, sizeof(*environ)); + if (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++) + alloc_environ[i] = environ[i] = ruby_strdup(envp[i]); + alloc_environ[i] = environ[i] = NULL; +#endif /* SPT_REUSEARGV */ +} + +void +ruby_free_proctitle(void) +{ +#if ALLOCATE_ENVIRON + extern char **environ; + + if (!orig_environ) return; /* environ is allocated by OS */ + + for (int i = 0; alloc_environ[i] != NULL; i++) { + xfree(alloc_environ[i]); + } + xfree(alloc_environ); + xfree(orig_environ); + + environ = system_environ; +#endif +} + +#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 + + /* fmt must be non-NULL */ + va_start(ap, fmt); + 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/missing/strcasecmp.c b/missing/strcasecmp.c deleted file mode 100644 index fddb8385be..0000000000 --- a/missing/strcasecmp.c +++ /dev/null @@ -1,16 +0,0 @@ -/* public domain rewrite of strcasecmp(3) */ - -#include <ctype.h> - -int -strcasecmp(p1, p2) - char *p1, *p2; -{ - while (*p1 && *p2) { - if (toupper(*p1) != toupper(*p2)) - return toupper(*p1) - toupper(*p2); - p1++; - p2++; - } - return strlen(p1) - strlen(p2); -} diff --git a/missing/strchr.c b/missing/strchr.c index 886d70ede6..465f07b61e 100644 --- a/missing/strchr.c +++ b/missing/strchr.c @@ -1,32 +1,32 @@ /* public domain rewrite of strchr(3) and strrchr(3) */ +#include "ruby/missing.h" + +size_t strlen(const char*); + char * -strchr(s, c) - char *s; - int c; +strchr(const char *s, int c) { - if (c == 0) return s + strlen(s); + if (c == 0) return (char *)s + strlen(s); while (*s) { if (*s == c) - return s; + return (char *)s; s++; } return 0; } char * -strrchr(s, c) - char *s; - int c; +strrchr(const char *s, int c) { - char *save; + const char *save; - if (c == 0) return s + strlen(s); + if (c == 0) return (char *)s + strlen(s); save = 0; while (*s) { if (*s == c) save = s; s++; } - return save; + return (char *)save; } diff --git a/missing/strerror.c b/missing/strerror.c index c1bf6feff8..d3b61c3f12 100644 --- a/missing/strerror.c +++ b/missing/strerror.c @@ -1,17 +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(error) - int error; +strerror(int error) { if (error <= sys_nerr && error > 0) { return sys_errlist[error]; } - sprintf(msg, "Unknown error (%d)", error); + snprintf(msg, sizeof(msg), "Unknown error (%d)", error); return msg; } diff --git a/missing/strftime.c b/missing/strftime.c deleted file mode 100644 index caa5eb8719..0000000000 --- a/missing/strftime.c +++ /dev/null @@ -1,903 +0,0 @@ -/* - * strftime.c - * - * Public-domain implementation of ANSI C library routine. - * - * It's written in old-style C for maximal portability. - * However, since I'm used to prototypes, I've included them too. - * - * If you want stuff in the System V ascftime routine, add the SYSV_EXT define. - * For extensions from SunOS, add SUNOS_EXT. - * For stuff needed to implement the P1003.2 date command, add POSIX2_DATE. - * For VMS dates, add VMS_EXT. - * For a an RFC822 time format, add MAILHEADER_EXT. - * For ISO week years, add ISO_DATE_EXT. - * For complete POSIX semantics, add POSIX_SEMANTICS. - * - * The code for %c, %x, and %X now follows the 1003.2 specification for - * the POSIX locale. - * This version ignores LOCALE information. - * It also doesn't worry about multi-byte characters. - * So there. - * - * This file is also shipped with GAWK (GNU Awk), gawk specific bits of - * code are included if GAWK is defined. - * - * Arnold Robbins - * January, February, March, 1991 - * Updated March, April 1992 - * Updated April, 1993 - * Updated February, 1994 - * Updated May, 1994 - * Updated January, 1995 - * Updated September, 1995 - * Updated January, 1996 - * - * Fixes from ado@elsie.nci.nih.gov - * February 1991, May 1992 - * Fixes from Tor Lillqvist tml@tik.vtt.fi - * May, 1993 - * Further fixes from ado@elsie.nci.nih.gov - * February 1994 - * %z code from chip@chinacat.unicom.com - * Applied September 1995 - * %V code fixed (again) and %G, %g added, - * January 1996 - */ - -#include "config.h" - -#ifndef GAWK -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#include <time.h> -#endif -#if defined(TM_IN_SYS_TIME) || !defined(GAWK) && !defined(_WIN32_WCE) -#include <sys/types.h> -#include <sys/time.h> -#endif - -/* defaults: season to taste */ -#define SYSV_EXT 1 /* stuff in System V ascftime routine */ -#define SUNOS_EXT 1 /* stuff in SunOS strftime routine */ -#define POSIX2_DATE 1 /* stuff in Posix 1003.2 date command */ -#define VMS_EXT 1 /* include %v for VMS date format */ -#define MAILHEADER_EXT 1 /* add %z for HHMM format */ -#define ISO_DATE_EXT 1 /* %G and %g for year of ISO week */ -#ifndef GAWK -#define POSIX_SEMANTICS 1 /* call tzset() if TZ changes */ -#endif - -#if defined(ISO_DATE_EXT) -#if ! defined(POSIX2_DATE) -#define POSIX2_DATE 1 -#endif -#endif - -#if defined(POSIX2_DATE) -#if ! defined(SYSV_EXT) -#define SYSV_EXT 1 -#endif -#if ! defined(SUNOS_EXT) -#define SUNOS_EXT 1 -#endif -#endif - -#if defined(POSIX2_DATE) -#define adddecl(stuff) stuff -#else -#define adddecl(stuff) -#endif - -#undef strchr /* avoid AIX weirdness */ - -#ifndef __STDC__ -#define const /**/ -extern void tzset(); -static int weeknumber(); -adddecl(static int iso8601wknum();) -#else -extern void tzset(void); -static int weeknumber(const struct tm *timeptr, int firstweekday); -adddecl(static int iso8601wknum(const struct tm *timeptr);) -#endif - -#ifdef STDC_HEADERS -#include <stdlib.h> -#include <string.h> -#else -extern void *malloc(); -extern void *realloc(); -extern char *getenv(); -extern char *strchr(); -#endif - -#define range(low, item, hi) max(low, min(item, hi)) - -#ifdef __CYGWIN__ -#define DLL_IMPORT __declspec(dllimport) -#endif -#ifdef __WIN32__ -#define DLL_IMPORT __declspec(dllimport) -#endif -#if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME) -extern DLL_IMPORT char *tzname[2]; -#ifdef HAVE_DAYLIGHT -extern DLL_IMPORT int daylight; -#endif -#ifdef HAVE_VAR_TIMEZONE -extern DLL_IMPORT TYPEOF_VAR_TIMEZONE timezone; -#endif -#ifdef HAVE_VAR_ALTZONE -extern DLL_IMPORT TYPEOF_VAR_ALTZONE altzone; -#endif -#endif - -#undef min /* just in case */ - -/* min --- return minimum of two numbers */ - -#ifndef __STDC__ -static inline int -min(a, b) -int a, b; -#else -static inline int -min(int a, int b) -#endif -{ - return (a < b ? a : b); -} - -#undef max /* also, just in case */ - -/* max --- return maximum of two numbers */ - -#ifndef __STDC__ -static inline int -max(a, b) -int a, b; -#else -static inline int -max(int a, int b) -#endif -{ - return (a > b ? a : b); -} - -/* strftime --- produce formatted time */ - -#ifndef __STDC__ -size_t -strftime(s, maxsize, format, timeptr) -char *s; -size_t maxsize; -const char *format; -const struct tm *timeptr; -#else -size_t -strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr) -#endif -{ - char *endp = s + maxsize; - char *start = s; - auto char tbuf[100]; - long off; - int i, w; - long y; - static short first = 1; -#ifdef POSIX_SEMANTICS - static char *savetz = NULL; - static int savetzlen = 0; - char *tz; -#endif /* POSIX_SEMANTICS */ -#ifndef HAVE_TM_ZONE -#ifndef HAVE_TM_NAME - struct timeval tv; - struct timezone zone; -#endif /* HAVE_TM_NAME */ -#endif /* HAVE_TM_ZONE */ - - /* various tables, useful in North America */ - static const char *days_a[] = { - "Sun", "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat", - }; - static const char *days_l[] = { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday", - }; - static const char *months_a[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - }; - static const char *months_l[] = { - "January", "February", "March", "April", - "May", "June", "July", "August", "September", - "October", "November", "December", - }; - static const char *ampm[] = { "AM", "PM", }; - - if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0) - return 0; - - /* quick check if we even need to bother */ - if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) - return 0; - -#ifndef POSIX_SEMANTICS - if (first) { - tzset(); - first = 0; - } -#else /* POSIX_SEMANTICS */ - tz = getenv("TZ"); - if (first) { - if (tz != NULL) { - int tzlen = strlen(tz); - - savetz = (char *) malloc(tzlen + 1); - if (savetz != NULL) { - savetzlen = tzlen + 1; - strcpy(savetz, tz); - } - } - tzset(); - first = 0; - } - /* if we have a saved TZ, and it is different, recapture and reset */ - if (tz && savetz && (tz[0] != savetz[0] || strcmp(tz, savetz) != 0)) { - i = strlen(tz) + 1; - if (i > savetzlen) { - savetz = (char *) realloc(savetz, i); - if (savetz) { - savetzlen = i; - strcpy(savetz, tz); - } - } else - strcpy(savetz, tz); - tzset(); - } -#endif /* POSIX_SEMANTICS */ - - for (; *format && s < endp - 1; format++) { - tbuf[0] = '\0'; - if (*format != '%') { - *s++ = *format; - continue; - } - again: - switch (*++format) { - case '\0': - *s++ = '%'; - goto out; - - case '%': - *s++ = '%'; - continue; - - case 'a': /* abbreviated weekday name */ - if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6) - strcpy(tbuf, "?"); - else - strcpy(tbuf, days_a[timeptr->tm_wday]); - break; - - case 'A': /* full weekday name */ - if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6) - strcpy(tbuf, "?"); - else - strcpy(tbuf, days_l[timeptr->tm_wday]); - break; - -#ifdef SYSV_EXT - case 'h': /* abbreviated month name */ -#endif - case 'b': /* abbreviated month name */ - if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11) - strcpy(tbuf, "?"); - else - strcpy(tbuf, months_a[timeptr->tm_mon]); - break; - - case 'B': /* full month name */ - if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11) - strcpy(tbuf, "?"); - else - strcpy(tbuf, months_l[timeptr->tm_mon]); - break; - - case 'c': /* appropriate date and time representation */ - strftime(tbuf, sizeof tbuf, "%a %b %e %H:%M:%S %Y", timeptr); - break; - - case 'd': /* day of the month, 01 - 31 */ - i = range(1, timeptr->tm_mday, 31); - sprintf(tbuf, "%02d", i); - break; - - case 'H': /* hour, 24-hour clock, 00 - 23 */ - i = range(0, timeptr->tm_hour, 23); - sprintf(tbuf, "%02d", i); - break; - - case 'I': /* hour, 12-hour clock, 01 - 12 */ - i = range(0, timeptr->tm_hour, 23); - if (i == 0) - i = 12; - else if (i > 12) - i -= 12; - sprintf(tbuf, "%02d", i); - break; - - case 'j': /* day of the year, 001 - 366 */ - sprintf(tbuf, "%03d", timeptr->tm_yday + 1); - break; - - case 'm': /* month, 01 - 12 */ - i = range(0, timeptr->tm_mon, 11); - sprintf(tbuf, "%02d", i + 1); - break; - - case 'M': /* minute, 00 - 59 */ - i = range(0, timeptr->tm_min, 59); - sprintf(tbuf, "%02d", i); - break; - - case 'p': /* am or pm based on 12-hour clock */ - i = range(0, timeptr->tm_hour, 23); - if (i < 12) - strcpy(tbuf, ampm[0]); - else - strcpy(tbuf, ampm[1]); - break; - - case 'S': /* second, 00 - 60 */ - i = range(0, timeptr->tm_sec, 60); - sprintf(tbuf, "%02d", i); - break; - - case 'U': /* week of year, Sunday is first day of week */ - sprintf(tbuf, "%02d", weeknumber(timeptr, 0)); - break; - - case 'w': /* weekday, Sunday == 0, 0 - 6 */ - i = range(0, timeptr->tm_wday, 6); - sprintf(tbuf, "%d", i); - break; - - case 'W': /* week of year, Monday is first day of week */ - sprintf(tbuf, "%02d", weeknumber(timeptr, 1)); - break; - - case 'x': /* appropriate date representation */ - strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr); - break; - - case 'X': /* appropriate time representation */ - strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr); - break; - - case 'y': /* year without a century, 00 - 99 */ - i = timeptr->tm_year % 100; - sprintf(tbuf, "%02d", i); - break; - - case 'Y': /* year with century */ - sprintf(tbuf, "%ld", 1900L + timeptr->tm_year); - break; - -#ifdef MAILHEADER_EXT - /* - * From: Chip Rosenthal <chip@chinacat.unicom.com> - * Date: Sun, 19 Mar 1995 00:33:29 -0600 (CST) - * - * Warning: the %z [code] is implemented by inspecting the - * timezone name conditional compile settings, and - * inferring a method to get timezone offsets. I've tried - * this code on a couple of machines, but I don't doubt - * there is some system out there that won't like it. - * Maybe the easiest thing to do would be to bracket this - * with an #ifdef that can turn it off. The %z feature - * would be an admittedly obscure one that most folks can - * live without, but it would be a great help to those of - * us that muck around with various message processors. - */ - case 'z': /* time zone offset east of GMT e.g. -0600 */ -#ifdef HAVE_TM_NAME - /* - * Systems with tm_name probably have tm_tzadj as - * secs west of GMT. Convert to mins east of GMT. - */ - off = -timeptr->tm_tzadj / 60; -#else /* !HAVE_TM_NAME */ -#ifdef HAVE_TM_ZONE - /* - * Systems with tm_zone probably have tm_gmtoff as - * secs east of GMT. Convert to mins east of GMT. - */ - off = timeptr->tm_gmtoff / 60; -#else /* !HAVE_TM_ZONE */ -#ifdef HAVE_GETTIMEOFDAY - gettimeofday(&tv, &zone); - off = -zone.tz_minuteswest; -#else -#if HAVE_VAR_TIMEZONE -#if HAVE_VAR_ALTZONE - off = -(daylight ? timezone : altzone) / 60; -#else - off = -timezone / 60; -#endif -#endif -#endif -#endif /* !HAVE_TM_ZONE */ -#endif /* !HAVE_TM_NAME */ - if (off < 0) { - tbuf[0] = '-'; - off = -off; - } else { - tbuf[0] = '+'; - } - sprintf(tbuf+1, "%02u%02u", (unsigned)off/60, (unsigned)off%60); - break; -#endif /* MAILHEADER_EXT */ - - case 'Z': /* time zone name or abbrevation */ -#ifdef HAVE_TZNAME - i = (daylight && timeptr->tm_isdst > 0); /* 0 or 1 */ - strcpy(tbuf, tzname[i]); -#else -#ifdef HAVE_TM_ZONE - strcpy(tbuf, timeptr->tm_zone); -#else -#ifdef HAVE_TM_NAME - strcpy(tbuf, timeptr->tm_name); -#else -#ifdef HAVE_TIMEZONE - gettimeofday(& tv, & zone); -#ifdef TIMEZONE_VOID - strcpy(tbuf, timezone()); -#else - strcpy(tbuf, timezone(zone.tz_minuteswest, - timeptr->tm_isdst > 0)); -#endif /* TIMEZONE_VOID */ -#endif /* HAVE_TIMEZONE */ -#endif /* HAVE_TM_NAME */ -#endif /* HAVE_TM_ZONE */ -#endif /* HAVE_TZNAME */ - break; - -#ifdef SYSV_EXT - case 'n': /* same as \n */ - tbuf[0] = '\n'; - tbuf[1] = '\0'; - break; - - case 't': /* same as \t */ - tbuf[0] = '\t'; - tbuf[1] = '\0'; - break; - - case 'D': /* date as %m/%d/%y */ - strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr); - break; - - case 'e': /* day of month, blank padded */ - sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31)); - break; - - case 'r': /* time as %I:%M:%S %p */ - strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr); - break; - - case 'R': /* time as %H:%M */ - strftime(tbuf, sizeof tbuf, "%H:%M", timeptr); - break; - - case 'T': /* time as %H:%M:%S */ - strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr); - break; -#endif - -#ifdef SUNOS_EXT - case 'k': /* hour, 24-hour clock, blank pad */ - sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23)); - break; - - case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */ - i = range(0, timeptr->tm_hour, 23); - if (i == 0) - i = 12; - else if (i > 12) - i -= 12; - sprintf(tbuf, "%2d", i); - break; -#endif - - -#ifdef VMS_EXT - case 'v': /* date as dd-bbb-YYYY */ - sprintf(tbuf, "%2d-%3.3s-%4ld", - range(1, timeptr->tm_mday, 31), - months_a[range(0, timeptr->tm_mon, 11)], - timeptr->tm_year + 1900L); - for (i = 3; i < 6; i++) - if (islower(tbuf[i])) - tbuf[i] = toupper(tbuf[i]); - break; -#endif - - -#ifdef POSIX2_DATE - case 'C': - sprintf(tbuf, "%02ld", (timeptr->tm_year + 1900L) / 100); - break; - - - case 'E': - case 'O': - /* POSIX locale extensions, ignored for now */ - goto again; - - case 'V': /* week of year according ISO 8601 */ - sprintf(tbuf, "%02d", iso8601wknum(timeptr)); - break; - - case 'u': - /* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */ - sprintf(tbuf, "%d", timeptr->tm_wday == 0 ? 7 : - timeptr->tm_wday); - break; -#endif /* POSIX2_DATE */ - -#ifdef ISO_DATE_EXT - case 'G': - case 'g': - /* - * Year of ISO week. - * - * If it's December but the ISO week number is one, - * that week is in next year. - * If it's January but the ISO week number is 52 or - * 53, that week is in last year. - * Otherwise, it's this year. - */ - w = iso8601wknum(timeptr); - if (timeptr->tm_mon == 11 && w == 1) - y = 1900L + timeptr->tm_year + 1; - else if (timeptr->tm_mon == 0 && w >= 52) - y = 1900L + timeptr->tm_year - 1; - else - y = 1900L + timeptr->tm_year; - - if (*format == 'G') - sprintf(tbuf, "%ld", y); - else - sprintf(tbuf, "%02ld", y % 100); - break; -#endif /* ISO_DATE_EXT */ - default: - tbuf[0] = '%'; - tbuf[1] = *format; - tbuf[2] = '\0'; - break; - } - i = strlen(tbuf); - if (i) { - if (s + i < endp - 1) { - strcpy(s, tbuf); - s += i; - } else - return 0; - } - } -out: - if (s < endp && *format == '\0') { - *s = '\0'; - return (s - start); - } else - return 0; -} - -/* isleap --- is a year a leap year? */ - -#ifndef __STDC__ -static int -isleap(year) -long year; -#else -static int -isleap(long year) -#endif -{ - return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); -} - - -#ifdef POSIX2_DATE -/* iso8601wknum --- compute week number according to ISO 8601 */ - -#ifndef __STDC__ -static int -iso8601wknum(timeptr) -const struct tm *timeptr; -#else -static int -iso8601wknum(const struct tm *timeptr) -#endif -{ - /* - * From 1003.2: - * If the week (Monday to Sunday) containing January 1 - * has four or more days in the new year, then it is week 1; - * otherwise it is the highest numbered week of the previous - * year (52 or 53), and the next week is week 1. - * - * ADR: This means if Jan 1 was Monday through Thursday, - * it was week 1, otherwise week 52 or 53. - * - * XPG4 erroneously included POSIX.2 rationale text in the - * main body of the standard. Thus it requires week 53. - */ - - int weeknum, jan1day; - - /* get week number, Monday as first day of the week */ - weeknum = weeknumber(timeptr, 1); - - /* - * With thanks and tip of the hatlo to tml@tik.vtt.fi - * - * What day of the week does January 1 fall on? - * We know that - * (timeptr->tm_yday - jan1.tm_yday) MOD 7 == - * (timeptr->tm_wday - jan1.tm_wday) MOD 7 - * and that - * jan1.tm_yday == 0 - * and that - * timeptr->tm_wday MOD 7 == timeptr->tm_wday - * from which it follows that. . . - */ - jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7); - if (jan1day < 0) - jan1day += 7; - - /* - * If Jan 1 was a Monday through Thursday, it was in - * week 1. Otherwise it was last year's highest week, which is - * this year's week 0. - * - * What does that mean? - * If Jan 1 was Monday, the week number is exactly right, it can - * never be 0. - * If it was Tuesday through Thursday, the weeknumber is one - * less than it should be, so we add one. - * Otherwise, Friday, Saturday or Sunday, the week number is - * OK, but if it is 0, it needs to be 52 or 53. - */ - switch (jan1day) { - case 1: /* Monday */ - break; - case 2: /* Tuesday */ - case 3: /* Wednesday */ - case 4: /* Thursday */ - weeknum++; - break; - case 5: /* Friday */ - case 6: /* Saturday */ - case 0: /* Sunday */ - if (weeknum == 0) { -#ifdef USE_BROKEN_XPG4 - /* XPG4 (as of March 1994) says 53 unconditionally */ - weeknum = 53; -#else - /* get week number of last week of last year */ - struct tm dec31ly; /* 12/31 last year */ - dec31ly = *timeptr; - dec31ly.tm_year--; - dec31ly.tm_mon = 11; - dec31ly.tm_mday = 31; - dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1; - dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900L); - weeknum = iso8601wknum(& dec31ly); -#endif - } - break; - } - - if (timeptr->tm_mon == 11) { - /* - * The last week of the year - * can be in week 1 of next year. - * Sigh. - * - * This can only happen if - * M T W - * 29 30 31 - * 30 31 - * 31 - */ - int wday, mday; - - wday = timeptr->tm_wday; - mday = timeptr->tm_mday; - if ( (wday == 1 && (mday >= 29 && mday <= 31)) - || (wday == 2 && (mday == 30 || mday == 31)) - || (wday == 3 && mday == 31)) - weeknum = 1; - } - - return weeknum; -} -#endif - -/* weeknumber --- figure how many weeks into the year */ - -/* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */ - -#ifndef __STDC__ -static int -weeknumber(timeptr, firstweekday) -const struct tm *timeptr; -int firstweekday; -#else -static int -weeknumber(const struct tm *timeptr, int firstweekday) -#endif -{ - int wday = timeptr->tm_wday; - int ret; - - if (firstweekday == 1) { - if (wday == 0) /* sunday */ - wday = 6; - else - wday--; - } - ret = ((timeptr->tm_yday + 7 - wday) / 7); - if (ret < 0) - ret = 0; - return ret; -} - -#if 0 -/* ADR --- I'm loathe to mess with ado's code ... */ - -Date: Wed, 24 Apr 91 20:54:08 MDT -From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK> -To: arnold@audiofax.com - -Hi Arnold, -in a process of fixing of strftime() in libraries on Atari ST I grabbed -some pieces of code from your own strftime. When doing that it came -to mind that your weeknumber() function compiles a little bit nicer -in the following form: -/* - * firstweekday is 0 if starting in Sunday, non-zero if in Monday - */ -{ - return (timeptr->tm_yday - timeptr->tm_wday + - (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7; -} -How nicer it depends on a compiler, of course, but always a tiny bit. - - Cheers, - Michal - ntomczak@vm.ucs.ualberta.ca -#endif - -#ifdef TEST_STRFTIME - -/* - * NAME: - * tst - * - * SYNOPSIS: - * tst - * - * DESCRIPTION: - * "tst" is a test driver for the function "strftime". - * - * OPTIONS: - * None. - * - * AUTHOR: - * Karl Vogel - * Control Data Systems, Inc. - * vogelke@c-17igp.wpafb.af.mil - * - * BUGS: - * None noticed yet. - * - * COMPILE: - * cc -o tst -DTEST_STRFTIME strftime.c - */ - -/* ADR: I reformatted this to my liking, and deleted some unneeded code. */ - -#ifndef NULL -#include <stdio.h> -#endif -#include <sys/time.h> -#include <string.h> - -#define MAXTIME 132 - -/* - * Array of time formats. - */ - -static char *array[] = -{ - "(%%A) full weekday name, var length (Sunday..Saturday) %A", - "(%%B) full month name, var length (January..December) %B", - "(%%C) Century %C", - "(%%D) date (%%m/%%d/%%y) %D", - "(%%E) Locale extensions (ignored) %E", - "(%%H) hour (24-hour clock, 00..23) %H", - "(%%I) hour (12-hour clock, 01..12) %I", - "(%%M) minute (00..59) %M", - "(%%O) Locale extensions (ignored) %O", - "(%%R) time, 24-hour (%%H:%%M) %R", - "(%%S) second (00..60) %S", - "(%%T) time, 24-hour (%%H:%%M:%%S) %T", - "(%%U) week of year, Sunday as first day of week (00..53) %U", - "(%%V) week of year according to ISO 8601 %V", - "(%%W) week of year, Monday as first day of week (00..53) %W", - "(%%X) appropriate locale time representation (%H:%M:%S) %X", - "(%%Y) year with century (1970...) %Y", - "(%%Z) timezone (EDT), or blank if timezone not determinable %Z", - "(%%a) locale's abbreviated weekday name (Sun..Sat) %a", - "(%%b) locale's abbreviated month name (Jan..Dec) %b", - "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c", - "(%%d) day of the month (01..31) %d", - "(%%e) day of the month, blank-padded ( 1..31) %e", - "(%%h) should be same as (%%b) %h", - "(%%j) day of the year (001..366) %j", - "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k", - "(%%l) hour, 12-hour clock, blank pad ( 0..12) %l", - "(%%m) month (01..12) %m", - "(%%p) locale's AM or PM based on 12-hour clock %p", - "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r", - "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u", - "(%%v) VMS date (dd-bbb-YYYY) %v", - "(%%w) day of week (0..6, Sunday == 0) %w", - "(%%x) appropriate locale date representation %x", - "(%%y) last two digits of year (00..99) %y", - "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z", - (char *) NULL -}; - -/* main routine. */ - -int -main(argc, argv) -int argc; -char **argv; -{ - long time(); - - char *next; - char string[MAXTIME]; - - int k; - int length; - - struct tm *tm; - - long clock; - - /* Call the function. */ - - clock = time((long *) 0); - tm = localtime(&clock); - - for (k = 0; next = array[k]; k++) { - length = strftime(string, MAXTIME, next, tm); - printf("%s\n", string); - } - - exit(0); -} -#endif /* TEST_STRFTIME */ diff --git a/missing/strlcat.c b/missing/strlcat.c new file mode 100644 index 0000000000..7749afa4fd --- /dev/null +++ b/missing/strlcat.c @@ -0,0 +1,56 @@ +/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ruby/missing.h" +#include <sys/types.h> +#include <string.h> + +/* + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t dsize) +{ + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return(dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return(dlen + (src - osrc)); /* count does not include NUL */ +} diff --git a/missing/strlcpy.c b/missing/strlcpy.c new file mode 100644 index 0000000000..6607574f80 --- /dev/null +++ b/missing/strlcpy.c @@ -0,0 +1,51 @@ +/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ruby/missing.h" +#include <sys/types.h> +#include <string.h> + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} diff --git a/missing/strncasecmp.c b/missing/strncasecmp.c deleted file mode 100644 index a4cc5828b8..0000000000 --- a/missing/strncasecmp.c +++ /dev/null @@ -1,21 +0,0 @@ -/* public domain rewrite of strncasecmp(3) */ - -#include <ctype.h> - -int -strncasecmp(p1, p2, len) - char *p1; - char *p2; - int len; -{ - while (len != 0) { - if (toupper(*p1) != toupper(*p2)) { - return toupper(*p1) - toupper(*p2); - } - if (*p1 == '\0') { - return 0; - } - len--; p1++; p2++; - } - return 0; -} diff --git a/missing/strstr.c b/missing/strstr.c index 1673518f06..e6613c5d2f 100644 --- a/missing/strstr.c +++ b/missing/strstr.c @@ -1,20 +1,23 @@ /* public domain rewrite of strstr(3) */ +#include "ruby/missing.h" + +size_t strlen(const char*); + char * -strstr(haystack, needle) - char *haystack, *needle; +strstr(const char *haystack, const char *needle) { - char *hend; - char *a, *b; + const char *hend; + const char *a, *b; - if (*needle == 0) return haystack; + 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 haystack; + if (*b == 0) return (char *)haystack; if (*a++ != *b++) { break; } diff --git a/missing/strtod.c b/missing/strtod.c deleted file mode 100644 index fdccd48081..0000000000 --- a/missing/strtod.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * strtod.c -- - * - * Source code for the "strtod" library procedure. - * - * Copyright (c) 1988-1993 The Regents of the University of California. - * Copyright (c) 1994 Sun Microsystems, Inc. - * - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - * - * RCS: @(#) $Id$ - */ - -#include "config.h" -#ifdef HAVE_STDLIB_H -# include <stdlib.h> -#endif -#include <ctype.h> -#include <errno.h> -extern int errno; - -#ifndef __STDC__ -# ifdef __GNUC__ -# define const __const__ -# else -# define const -# endif -#endif - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif -#ifndef NULL -#define NULL 0 -#endif - -static int maxExponent = 511; /* Largest possible base 10 exponent. Any - * exponent larger than this will already - * produce underflow or overflow, so there's - * no need to worry about additional digits. - */ -static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ - 10., /* is 10^2^i. Used to convert decimal */ - 100., /* exponents into floating-point numbers. */ - 1.0e4, - 1.0e8, - 1.0e16, - 1.0e32, - 1.0e64, - 1.0e128, - 1.0e256 -}; - -/* - *---------------------------------------------------------------------- - * - * strtod -- - * - * This procedure converts a floating-point number from an ASCII - * decimal representation to internal double-precision format. - * - * Results: - * The return value is the double-precision floating-point - * representation of the characters in string. If endPtr isn't - * NULL, then *endPtr is filled in with the address of the - * next character after the last one that was part of the - * floating-point number. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -double -strtod(string, endPtr) - const char *string; /* A decimal ASCII floating-point number, - * optionally preceded by white space. - * Must have form "-I.FE-X", where I is the - * integer part of the mantissa, F is the - * fractional part of the mantissa, and X - * is the exponent. Either of the signs - * may be "+", "-", or omitted. Either I - * or F may be omitted, or both. The decimal - * point isn't necessary unless F is present. - * The "E" may actually be an "e". E and X - * may both be omitted (but not just one). - */ - char **endPtr; /* If non-NULL, store terminating character's - * address here. */ -{ - int sign, expSign = FALSE; - double fraction, dblExp, *d; - register const char *p; - register int c; - int exp = 0; /* Exponent read from "EX" field. */ - int fracExp = 0; /* Exponent that derives from the fractional - * part. Under normal circumstatnces, it is - * the negative of the number of digits in F. - * However, if I is very long, the last digits - * of I get dropped (otherwise a long I with a - * large negative exponent could cause an - * unnecessary overflow on I alone). In this - * case, fracExp is incremented one for each - * dropped digit. */ - int mantSize; /* Number of digits in mantissa. */ - int decPt; /* Number of mantissa digits BEFORE decimal - * point. */ - const char *pExp; /* Temporarily holds location of exponent - * in string. */ - - /* - * Strip off leading blanks and check for a sign. - */ - - p = string; - while (isspace(*p)) { - p += 1; - } - if (*p == '-') { - sign = TRUE; - p += 1; - } else { - if (*p == '+') { - p += 1; - } - sign = FALSE; - } - - /* - * Count the number of digits in the mantissa (including the decimal - * point), and also locate the decimal point. - */ - - decPt = -1; - for (mantSize = 0; ; mantSize += 1) - { - c = *p; - if (!isdigit(c)) { - if ((c != '.') || (decPt >= 0)) { - break; - } - decPt = mantSize; - } - p += 1; - } - - /* - * Now suck up the digits in the mantissa. Use two integers to - * collect 9 digits each (this is faster than using floating-point). - * If the mantissa has more than 18 digits, ignore the extras, since - * they can't affect the value anyway. - */ - - pExp = p; - p -= mantSize; - if (decPt < 0) { - decPt = mantSize; - } else { - mantSize -= 1; /* One of the digits was the point. */ - } - if (mantSize > 18) { - fracExp = decPt - 18; - mantSize = 18; - } else { - fracExp = decPt - mantSize; - } - if (mantSize == 0) { - fraction = 0.0; - p = string; - goto done; - } else { - int frac1, frac2; - frac1 = 0; - for ( ; mantSize > 9; mantSize -= 1) - { - c = *p; - p += 1; - if (c == '.') { - c = *p; - p += 1; - } - frac1 = 10*frac1 + (c - '0'); - } - frac2 = 0; - for (; mantSize > 0; mantSize -= 1) - { - c = *p; - p += 1; - if (c == '.') { - c = *p; - p += 1; - } - frac2 = 10*frac2 + (c - '0'); - } - fraction = (1.0e9 * frac1) + frac2; - } - - /* - * Skim off the exponent. - */ - - p = pExp; - if ((*p == 'E') || (*p == 'e')) { - p += 1; - if (*p == '-') { - expSign = TRUE; - p += 1; - } else { - if (*p == '+') { - p += 1; - } - expSign = FALSE; - } - while (isdigit(*p)) { - exp = exp * 10 + (*p - '0'); - p += 1; - } - } - if (expSign) { - exp = fracExp - exp; - } else { - exp = fracExp + exp; - } - - /* - * Generate a floating-point number that represents the exponent. - * Do this by processing the exponent one bit at a time to combine - * many powers of 2 of 10. Then combine the exponent with the - * fraction. - */ - - if (exp < 0) { - expSign = TRUE; - exp = -exp; - } else { - expSign = FALSE; - } - if (exp > maxExponent) { - exp = maxExponent; - errno = ERANGE; - } - dblExp = 1.0; - for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { - if (exp & 01) { - dblExp *= *d; - } - } - if (expSign) { - fraction /= dblExp; - } else { - fraction *= dblExp; - } - -done: - if (endPtr != NULL) { - *endPtr = (char *) p; - } - - if (sign) { - return -fraction; - } - return fraction; -} diff --git a/missing/strtol.c b/missing/strtol.c deleted file mode 100644 index e94aa54ca0..0000000000 --- a/missing/strtol.c +++ /dev/null @@ -1,29 +0,0 @@ -/* public domain rewrite of strtol(3) */ - -#include <ctype.h> - -long -strtol(nptr, endptr, base) - char *nptr; - char **endptr; - int base; -{ - long result; - 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 = nptr; - } - return result; -} diff --git a/missing/strtoul.c b/missing/strtoul.c deleted file mode 100644 index f16f2ad9cf..0000000000 --- a/missing/strtoul.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * strtoul.c -- - * - * Source code for the "strtoul" library procedure. - * - * Copyright 1988 Regents of the University of California - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - */ - -#include <ctype.h> - -/* - * The table below is used to convert from ASCII digits to a - * numerical equivalent. It maps from '0' through 'z' to integers - * (100 for non-digit characters). - */ - -static char cvtIn[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ - 100, 100, 100, 100, 100, 100, 100, /* punctuation */ - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */ - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, - 100, 100, 100, 100, 100, 100, /* punctuation */ - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */ - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35}; - -/* - *---------------------------------------------------------------------- - * - * strtoul -- - * - * Convert an ASCII string into an integer. - * - * Results: - * The return value is the integer equivalent of string. If endPtr - * is non-NULL, then *endPtr is filled in with the character - * after the last one that was part of the integer. If string - * doesn't contain a valid integer value, then zero is returned - * and *endPtr is set to string. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -unsigned long int -strtoul(string, endPtr, base) - char *string; /* String of ASCII digits, possibly - * preceded by white space. For bases - * greater than 10, either lower- or - * upper-case digits may be used. - */ - char **endPtr; /* Where to store address of terminating - * character, or NULL. */ - int base; /* Base for conversion. Must be less - * than 37. If 0, then the base is chosen - * from the leading characters of string: - * "0x" means hex, "0" means octal, anything - * else means decimal. - */ -{ - register char *p; - register unsigned long int result = 0; - register unsigned digit; - int anyDigits = 0; - - /* - * Skip any leading blanks. - */ - - p = string; - while (isspace(*p)) { - p += 1; - } - - /* - * If no base was provided, pick one from the leading characters - * of the string. - */ - - if (base == 0) - { - if (*p == '0') { - p += 1; - if (*p == 'x') { - p += 1; - base = 16; - } else { - - /* - * Must set anyDigits here, otherwise "0" produces a - * "no digits" error. - */ - - anyDigits = 1; - base = 8; - } - } - else base = 10; - } else if (base == 16) { - - /* - * Skip a leading "0x" from hex numbers. - */ - - if ((p[0] == '0') && (p[1] == 'x')) { - p += 2; - } - } - - /* - * Sorry this code is so messy, but speed seems important. Do - * different things for base 8, 10, 16, and other. - */ - - if (base == 8) { - for ( ; ; p += 1) { - digit = *p - '0'; - if (digit > 7) { - break; - } - result = (result << 3) + digit; - anyDigits = 1; - } - } else if (base == 10) { - for ( ; ; p += 1) { - digit = *p - '0'; - if (digit > 9) { - break; - } - result = (10*result) + digit; - anyDigits = 1; - } - } else if (base == 16) { - for ( ; ; p += 1) { - digit = *p - '0'; - if (digit > ('z' - '0')) { - break; - } - digit = cvtIn[digit]; - if (digit > 15) { - break; - } - result = (result << 4) + digit; - anyDigits = 1; - } - } else { - for ( ; ; p += 1) { - digit = *p - '0'; - if (digit > ('z' - '0')) { - break; - } - digit = cvtIn[digit]; - if (digit >= base) { - break; - } - result = result*base + digit; - anyDigits = 1; - } - } - - /* - * See if there were any digits at all. - */ - - if (!anyDigits) { - p = string; - } - - if (endPtr != 0) { - *endPtr = p; - } - - return result; -} diff --git a/missing/tgamma.c b/missing/tgamma.c new file mode 100644 index 0000000000..82d614d755 --- /dev/null +++ b/missing/tgamma.c @@ -0,0 +1,82 @@ +/* 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/internal/config.h" +#include "ruby/missing.h" +#include <math.h> +#include <errno.h> + +#ifndef HAVE_LGAMMA_R + +#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); +} +#endif + +double tgamma(double x) /* Gamma function */ +{ + int sign; + if (x == 0.0) { /* Pole Error */ + errno = ERANGE; + return 1/x < 0 ? -HUGE_VAL : HUGE_VAL; + } + if (isinf(x)) { + if (x < 0) goto domain_error; + return x; + } + if (x < 0) { + static double zero = 0.0; + double i, f; + f = modf(-x, &i); + if (f == 0.0) { /* Domain Error */ + domain_error: + errno = EDOM; + return zero/zero; + } +#ifndef HAVE_LGAMMA_R + sign = (fmod(i, 2.0) != 0.0) ? 1 : -1; + return sign * PI / (sin(PI * f) * exp(loggamma(1 - x))); +#endif + } +#ifndef HAVE_LGAMMA_R + return exp(loggamma(x)); +#else + x = lgamma_r(x, &sign); + return sign * exp(x); +#endif +} diff --git a/missing/vsnprintf.c b/missing/vsnprintf.c deleted file mode 100644 index 6afdfa189f..0000000000 --- a/missing/vsnprintf.c +++ /dev/null @@ -1,1135 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * 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. - */ - -/* - * IMPORTANT NOTE: - * -------------- - * From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change - * paragraph 3 above is now null and void. - */ - -/* SNPRINTF.C - * fjc 7-31-97 Modified by Mib Software to be a standalone snprintf.c module. - * http://www.mibsoftware.com - * Mib Software does not warrant this software any differently than the - * University of California, Berkeley as described above. All warranties - * are disclaimed. Use this software at your own risk. - * - * All code referencing FILE * functions was eliminated, since it could - * never be called. All header files and necessary files are collapsed - * into one file, internal functions are declared static. This should - * allow inclusion into libraries with less chance of namespace collisions. - * - * snprintf should be the only externally visible item. - * - * As of 7-31-97 FLOATING_POINT is NOT provided. The code is somewhat - * non-portable, so it is disabled. - */ - -/* Define FLOATING_POINT to get floating point. */ -/* -#define FLOATING_POINT -*/ - -#include <sys/types.h> -#define u_long unsigned long -#define u_short unsigned short -#define u_int unsigned int - -#undef __P -#if defined(__STDC__) -# include <stdarg.h> -# if !defined(__P) -# define __P(x) x -# endif -#else -# define __P(x) () -# if !defined(const) -# define const -# endif -# include <varargs.h> -#endif -#ifndef _BSD_VA_LIST_ -#define _BSD_VA_LIST_ va_list -#endif - -#ifdef __STDC__ -# include <limits.h> -#else -# ifndef LONG_MAX -# ifdef HAVE_LIMITS_H -# include <limits.h> -# else - /* assuming 32bit(2's compliment) long */ -# define LONG_MAX 2147483647 -# endif -# endif -#endif - -#if defined(__hpux) && !defined(__GNUC__) && !defined(__STDC__) -#define const -#endif - -#if defined(sgi) -#undef __const -#define __const -#endif /* People who don't like const sys_error */ - -#include <stddef.h> - -#ifndef NULL -#define NULL 0 -#endif - -/* - * NB: to fit things in six character monocase externals, the stdio - * code uses the prefix `__s' for stdio objects, typically followed - * by a three-character attempt at a mnemonic. - */ - -/* stdio buffers */ -struct __sbuf { - unsigned char *_base; - int _size; -}; - - -/* - * stdio state variables. - * - * The following always hold: - * - * if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR), - * _lbfsize is -_bf._size, else _lbfsize is 0 - * if _flags&__SRD, _w is 0 - * if _flags&__SWR, _r is 0 - * - * This ensures that the getc and putc macros (or inline functions) never - * try to write or read from a file that is in `read' or `write' mode. - * (Moreover, they can, and do, automatically switch from read mode to - * write mode, and back, on "r+" and "w+" files.) - * - * _lbfsize is used only to make the inline line-buffered output stream - * code as compact as possible. - * - * _ub, _up, and _ur are used when ungetc() pushes back more characters - * than fit in the current _bf, or when ungetc() pushes back a character - * that does not match the previous one in _bf. When this happens, - * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff - * _ub._base!=NULL) and _up and _ur save the current values of _p and _r. - * - * NB: see WARNING above before changing the layout of this structure! - */ -typedef struct __sFILE { - unsigned char *_p; /* current position in (some) buffer */ - int _r; /* read space left for getc() */ - int _w; /* write space left for putc() */ - short _flags; /* flags, below; this FILE is free if 0 */ - short _file; /* fileno, if Unix descriptor, else -1 */ - struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */ - int _lbfsize; /* 0 or -_bf._size, for inline putc */ -} FILE; - - -#define __SLBF 0x0001 /* line buffered */ -#define __SNBF 0x0002 /* unbuffered */ -#define __SRD 0x0004 /* OK to read */ -#define __SWR 0x0008 /* OK to write */ - /* RD and WR are never simultaneously asserted */ -#define __SRW 0x0010 /* open for reading & writing */ -#define __SEOF 0x0020 /* found EOF */ -#define __SERR 0x0040 /* found error */ -#define __SMBF 0x0080 /* _buf is from malloc */ -#define __SAPP 0x0100 /* fdopen()ed in append mode */ -#define __SSTR 0x0200 /* this is an sprintf/snprintf string */ -#define __SOPT 0x0400 /* do fseek() optimisation */ -#define __SNPT 0x0800 /* do not do fseek() optimisation */ -#define __SOFF 0x1000 /* set iff _offset is in fact correct */ -#define __SMOD 0x2000 /* true => fgetln modified _p text */ - - -#define EOF (-1) - - -#define __sfeof(p) (((p)->_flags & __SEOF) != 0) -#define __sferror(p) (((p)->_flags & __SERR) != 0) -#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF))) -#define __sfileno(p) ((p)->_file) - -#define feof(p) __sfeof(p) -#define ferror(p) __sferror(p) -#define clearerr(p) __sclearerr(p) - -#ifndef _ANSI_SOURCE -#define fileno(p) __sfileno(p) -#endif - - -#if defined(__hpux) && !defined(__GNUC__) || defined(__DECC) -#include <string.h> -#endif - -/* - * I/O descriptors for __sfvwrite(). - */ -struct __siov { - void *iov_base; - size_t iov_len; -}; -struct __suio { - struct __siov *uio_iov; - int uio_iovcnt; - int uio_resid; -}; - -/* - * Write some memory regions. Return zero on success, EOF on error. - * - * This routine is large and unsightly, but most of the ugliness due - * to the three different kinds of output buffering is handled here. - */ -static BSD__sfvwrite(fp, uio) - register FILE *fp; - register struct __suio *uio; -{ - register size_t len; - register char *p; - register struct __siov *iov; - register int w; - - if ((len = uio->uio_resid) == 0) - return (0); -#ifndef __hpux -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif -#define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n)) - - iov = uio->uio_iov; - p = iov->iov_base; - len = iov->iov_len; - iov++; -#define GETIOV(extra_work) \ - while (len == 0) { \ - extra_work; \ - p = iov->iov_base; \ - len = iov->iov_len; \ - iov++; \ - } - if (fp->_flags & __SNBF) { - /* fjc 7-31-97 Will never happen. We are working with - strings only - */ - } else if ((fp->_flags & __SLBF) == 0) { - /* - * Fully buffered: fill partially full buffer, if any, - * and then flush. If there is no partial buffer, write - * one _bf._size byte chunk directly (without copying). - * - * String output is a special case: write as many bytes - * as fit, but pretend we wrote everything. This makes - * snprintf() return the number of bytes needed, rather - * than the number used, and avoids its write function - * (so that the write function can be invalid). - */ - do { - GETIOV(;); - w = fp->_w; - if (fp->_flags & __SSTR) { - if (len < w) - w = len; - COPY(w); /* copy MIN(fp->_w,len), */ - fp->_w -= w; - fp->_p += w; - w = len; /* but pretend copied all */ - } else { - /* fjc 7-31-97 Will never happen. We are working with - strings only - */ - } - p += w; - len -= w; - } while ((uio->uio_resid -= w) != 0); - } else { - /* fjc 7-31-97 Will never happen. We are working with - strings only - */ - } - return (0); - -err: - fp->_flags |= __SERR; - return (EOF); -} - -/* - * Actual printf innards. - * - * This code is large and complicated... - */ - -#if !defined(__CYGWIN32__) && defined(__hpux) && !defined(__GNUC__) -#include <stdlib.h> -#endif - -/* - * Flush out all the vectors defined by the given uio, - * then reset it so that it can be reused. - */ -static int -BSD__sprint(fp, uio) - FILE *fp; - register struct __suio *uio; -{ - register int err; - - if (uio->uio_resid == 0) { - uio->uio_iovcnt = 0; - return (0); - } - err = BSD__sfvwrite(fp, uio); - uio->uio_resid = 0; - uio->uio_iovcnt = 0; - return (err); -} - - -/* - * Helper function for `fprintf to unbuffered unix file': creates a - * temporary buffer. We only work on write-only files; this avoids - * worries about ungetc buffers and so forth. - */ -static int -BSD__sbprintf(fp, fmt, ap) - register FILE *fp; - const char *fmt; - va_list ap; -{ -/* We don't support files. */ - return 0; -} - - -/* - * Macros for converting digits to letters and vice versa - */ -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -/* - * Convert an unsigned long to ASCII for printf purposes, returning - * a pointer to the first character of the string representation. - * Octal numbers can be forced to have a leading zero; hex numbers - * use the given digits. - */ -static char * -BSD__ultoa(val, endp, base, octzero, xdigs) - register u_long val; - char *endp; - int base, octzero; - char *xdigs; -{ - register char *cp = endp; - register long sval; - - /* - * Handle the three cases separately, in the hope of getting - * better/faster code. - */ - switch (base) { - case 10: - if (val < 10) { /* many numbers are 1 digit */ - *--cp = to_char(val); - return (cp); - } - /* - * On many machines, unsigned arithmetic is harder than - * signed arithmetic, so we do at most one unsigned mod and - * divide; this is sufficient to reduce the range of - * the incoming value to where signed arithmetic works. - */ - if (val > LONG_MAX) { - *--cp = to_char(val % 10); - sval = val / 10; - } else - sval = val; - do { - *--cp = to_char(sval % 10); - sval /= 10; - } while (sval != 0); - break; - - case 8: - do { - *--cp = to_char(val & 7); - val >>= 3; - } while (val); - if (octzero && *cp != '0') - *--cp = '0'; - break; - - case 16: - do { - *--cp = xdigs[val & 15]; - val >>= 4; - } while (val); - break; - - default: /* oops */ - /* - abort(); - */ - break; /* fjc 7-31-97. Don't reference abort() here */ - } - return (cp); -} - -#ifdef FLOATING_POINT -#include <math.h> -/* #include "floatio.h" */ - -#ifndef MAXEXP -# define MAXEXP 1024 -#endif - -#ifndef MAXFRACT -# define MAXFRACT 64 -#endif - -#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ -#define DEFPREC 6 - -static char *cvt __P((double, int, int, char *, int *, int, int *)); -static int exponent __P((char *, int, int)); - -#else /* no FLOATING_POINT */ - -#define BUF 68 - -#endif /* FLOATING_POINT */ - - -/* - * Flags used during conversion. - */ -#define ALT 0x001 /* alternate form */ -#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ -#define LADJUST 0x004 /* left adjustment */ -#define LONGDBL 0x008 /* long double; unimplemented */ -#define LONGINT 0x010 /* long integer */ - -#ifdef _HAVE_SANE_QUAD_ -#define QUADINT 0x020 /* quad integer */ -#endif /* _HAVE_SANE_QUAD_ */ - -#define SHORTINT 0x040 /* short integer */ -#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ -#define FPT 0x100 /* Floating point number */ -static int -BSD_vfprintf(fp, fmt0, ap) - FILE *fp; - const char *fmt0; - va_list ap; -{ - register char *fmt; /* format string */ - register int ch; /* character from fmt */ - register int n; /* handy integer (short term usage) */ - register char *cp; /* handy char pointer (short term usage) */ - register struct __siov *iovp;/* for PRINT macro */ - register int flags; /* flags as above */ - int ret; /* return value accumulator */ - int width; /* width from format (%8d), or 0 */ - int prec; /* precision from format (%.3d), or -1 */ - char sign; /* sign prefix (' ', '+', '-', or \0) */ -#ifdef FLOATING_POINT - char softsign; /* temporary negative sign for floats */ - double _double; /* double precision arguments %[eEfgG] */ - int expt; /* integer value of exponent */ - int expsize; /* character count for expstr */ - int ndig; /* actual number of digits returned by cvt */ - char expstr[7]; /* buffer for exponent string */ -#endif - u_long ulval; /* integer arguments %[diouxX] */ -#ifdef _HAVE_SANE_QUAD_ - u_quad_t uqval; /* %q integers */ -#endif /* _HAVE_SANE_QUAD_ */ - int base; /* base for [diouxX] conversion */ - int dprec; /* a copy of prec if [diouxX], 0 otherwise */ - int fieldsz; /* field size expanded by sign, etc */ - int realsz; /* field size expanded by dprec */ - int size; /* size of converted field or string */ - char *xdigs; /* digits for [xX] conversion */ -#define NIOV 8 - struct __suio uio; /* output information: summary */ - struct __siov iov[NIOV];/* ... and individual io vectors */ - char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ - char ox[2]; /* space for 0x hex-prefix */ - - /* - * Choose PADSIZE to trade efficiency vs. size. If larger printf - * fields occur frequently, increase PADSIZE and make the initialisers - * below longer. - */ -#define PADSIZE 16 /* pad chunk size */ - static char blanks[PADSIZE] = - {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; - static char zeroes[PADSIZE] = - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; - - /* - * BEWARE, these `goto error' on error, and PAD uses `n'. - */ -#define PRINT(ptr, len) { \ - iovp->iov_base = (ptr); \ - iovp->iov_len = (len); \ - uio.uio_resid += (len); \ - iovp++; \ - if (++uio.uio_iovcnt >= NIOV) { \ - if (BSD__sprint(fp, &uio)) \ - goto error; \ - iovp = iov; \ - } \ -} -#define PAD(howmany, with) { \ - if ((n = (howmany)) > 0) { \ - while (n > PADSIZE) { \ - PRINT(with, PADSIZE); \ - n -= PADSIZE; \ - } \ - PRINT(with, n); \ - } \ -} -#define FLUSH() { \ - if (uio.uio_resid && BSD__sprint(fp, &uio)) \ - goto error; \ - uio.uio_iovcnt = 0; \ - iovp = iov; \ -} - - /* - * To extend shorts properly, we need both signed and unsigned - * argument extraction methods. - */ -#define SARG() \ - (flags&LONGINT ? va_arg(ap, long) : \ - flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ - (long)va_arg(ap, int)) -#define UARG() \ - (flags&LONGINT ? va_arg(ap, u_long) : \ - flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \ - (u_long)va_arg(ap, u_int)) - - /* optimise fprintf(stderr) (and other unbuffered Unix files) */ - if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && - fp->_file >= 0) - return (BSD__sbprintf(fp, fmt0, ap)); - - fmt = (char *)fmt0; - uio.uio_iov = iovp = iov; - uio.uio_resid = 0; - uio.uio_iovcnt = 0; - ret = 0; - - /* - * Scan the format for conversions (`%' character). - */ - for (;;) { - for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) - /* void */; - if ((n = fmt - cp) != 0) { - PRINT(cp, n); - ret += n; - } - if (ch == '\0') - goto done; - fmt++; /* skip over '%' */ - - flags = 0; - dprec = 0; - width = 0; - prec = -1; - sign = '\0'; - -rflag: ch = *fmt++; -reswitch: switch (ch) { - case ' ': - /* - * ``If the space and + flags both appear, the space - * flag will be ignored.'' - * -- ANSI X3J11 - */ - if (!sign) - sign = ' '; - goto rflag; - case '#': - flags |= ALT; - goto rflag; - case '*': - /* - * ``A negative field width argument is taken as a - * - flag followed by a positive field width.'' - * -- ANSI X3J11 - * They don't exclude field widths read from args. - */ - if ((width = va_arg(ap, int)) >= 0) - goto rflag; - width = -width; - /* FALLTHROUGH */ - case '-': - flags |= LADJUST; - goto rflag; - case '+': - sign = '+'; - goto rflag; - case '.': - if ((ch = *fmt++) == '*') { - n = va_arg(ap, int); - prec = n < 0 ? -1 : n; - goto rflag; - } - n = 0; - while (is_digit(ch)) { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } - prec = n < 0 ? -1 : n; - goto reswitch; - case '0': - /* - * ``Note that 0 is taken as a flag, not as the - * beginning of a field width.'' - * -- ANSI X3J11 - */ - flags |= ZEROPAD; - goto rflag; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = 0; - do { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } while (is_digit(ch)); - width = n; - goto reswitch; -#ifdef FLOATING_POINT - case 'L': - flags |= LONGDBL; - goto rflag; -#endif - case 'h': - flags |= SHORTINT; - goto rflag; - case 'l': - flags |= LONGINT; - goto rflag; -#ifdef _HAVE_SANE_QUAD_ - case 'q': - flags |= QUADINT; - goto rflag; -#endif /* _HAVE_SANE_QUAD_ */ - case 'c': - *(cp = buf) = va_arg(ap, int); - size = 1; - sign = '\0'; - break; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': -#ifdef _HAVE_SANE_QUAD_ - if (flags & QUADINT) { - uqval = va_arg(ap, quad_t); - if ((quad_t)uqval < 0) { - uqval = -uqval; - sign = '-'; - } - } else { -#else /* _HAVE_SANE_QUAD_ */ - { -#endif /* _HAVE_SANE_QUAD_ */ - ulval = SARG(); - if ((long)ulval < 0) { - ulval = -ulval; - sign = '-'; - } - } - base = 10; - goto number; -#ifdef FLOATING_POINT - case 'e': /* anomalous precision */ - case 'E': - prec = (prec == -1) ? - DEFPREC + 1 : prec + 1; - /* FALLTHROUGH */ - goto fp_begin; - case 'f': /* always print trailing zeroes */ - if (prec != 0) - flags |= ALT; - case 'g': - case 'G': - if (prec == -1) - prec = DEFPREC; -fp_begin: _double = va_arg(ap, double); - /* do this before tricky precision changes */ - if (isinf(_double)) { - if (_double < 0) - sign = '-'; - cp = "Inf"; - size = 3; - break; - } - if (isnan(_double)) { - cp = "NaN"; - size = 3; - break; - } - flags |= FPT; - cp = cvt(_double, prec, flags, &softsign, - &expt, ch, &ndig); - if (ch == 'g' || ch == 'G') { - if (expt <= -4 || expt > prec) - ch = (ch == 'g') ? 'e' : 'E'; - else - ch = 'g'; - } - if (ch <= 'e') { /* 'e' or 'E' fmt */ - --expt; - expsize = exponent(expstr, expt, ch); - size = expsize + ndig; - if (ndig > 1 || flags & ALT) - ++size; - } else if (ch == 'f') { /* f fmt */ - if (expt > 0) { - size = expt; - if (prec || flags & ALT) - size += prec + 1; - } else /* "0.X" */ - size = prec + 2; - } else if (expt >= ndig) { /* fixed g fmt */ - size = expt; - if (flags & ALT) - ++size; - } else - size = ndig + (expt > 0 ? - 1 : 2 - expt); - - if (softsign) - sign = '-'; - break; -#endif /* FLOATING_POINT */ - case 'n': -#ifdef _HAVE_SANE_QUAD_ - if (flags & QUADINT) - *va_arg(ap, quad_t *) = ret; - else if (flags & LONGINT) -#else /* _HAVE_SANE_QUAD_ */ - if (flags & LONGINT) -#endif /* _HAVE_SANE_QUAD_ */ - *va_arg(ap, long *) = ret; - else if (flags & SHORTINT) - *va_arg(ap, short *) = ret; - else - *va_arg(ap, int *) = ret; - continue; /* no output */ - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': -#ifdef _HAVE_SANE_QUAD_ - if (flags & QUADINT) - uqval = va_arg(ap, u_quad_t); - else -#endif /* _HAVE_SANE_QUAD_ */ - ulval = UARG(); - base = 8; - goto nosign; - case 'p': - /* - * ``The argument shall be a pointer to void. The - * value of the pointer is converted to a sequence - * of printable characters, in an implementation- - * defined manner.'' - * -- ANSI X3J11 - */ -#ifdef _HAVE_LLP64_ - uqval = (u_long)va_arg(ap, void *); - flags = (flags) | QUADINT | HEXPREFIX; -#else - ulval = (u_long)va_arg(ap, void *); -#ifdef _HAVE_SANE_QUAD_ - flags = (flags & ~QUADINT) | HEXPREFIX; -#else /* _HAVE_SANE_QUAD_ */ - flags = (flags) | HEXPREFIX; -#endif /* _HAVE_SANE_QUAD_ */ -#endif - base = 16; - xdigs = "0123456789abcdef"; - ch = 'x'; - goto nosign; - case 's': - if ((cp = va_arg(ap, char *)) == NULL) - cp = "(null)"; - if (prec >= 0) { - /* - * can't use strlen; can only look for the - * NUL in the first `prec' characters, and - * strlen() will go further. - */ - char *p = (char *)memchr(cp, 0, prec); - - if (p != NULL) { - size = p - cp; - if (size > prec) - size = prec; - } else - size = prec; - } else - size = strlen(cp); - sign = '\0'; - break; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': -#ifdef _HAVE_SANE_QUAD_ - if (flags & QUADINT) - uqval = va_arg(ap, u_quad_t); - else -#endif /* _HAVE_SANE_QUAD_ */ - ulval = UARG(); - base = 10; - goto nosign; - case 'X': - xdigs = "0123456789ABCDEF"; - goto hex; - case 'x': - xdigs = "0123456789abcdef"; -hex: -#ifdef _HAVE_SANE_QUAD_ - if (flags & QUADINT) - uqval = va_arg(ap, u_quad_t); - else -#endif /* _HAVE_SANE_QUAD_ */ - ulval = UARG(); - base = 16; - /* leading 0x/X only if non-zero */ - if (flags & ALT && -#ifdef _HAVE_SANE_QUAD_ - (flags & QUADINT ? uqval != 0 : ulval != 0)) -#else /* _HAVE_SANE_QUAD_ */ - ulval != 0) -#endif /* _HAVE_SANE_QUAD_ */ - flags |= HEXPREFIX; - - /* unsigned conversions */ -nosign: sign = '\0'; - /* - * ``... diouXx conversions ... if a precision is - * specified, the 0 flag will be ignored.'' - * -- ANSI X3J11 - */ -number: if ((dprec = prec) >= 0) - flags &= ~ZEROPAD; - - /* - * ``The result of converting a zero value with an - * explicit precision of zero is no characters.'' - * -- ANSI X3J11 - */ - cp = buf + BUF; -#ifdef _HAVE_SANE_QUAD_ - if (flags & QUADINT) { - if (uqval != 0 || prec != 0) - cp = __uqtoa(uqval, cp, base, - flags & ALT, xdigs); - } else { -#else /* _HAVE_SANE_QUAD_ */ - { -#endif /* _HAVE_SANE_QUAD_ */ - if (ulval != 0 || prec != 0) - cp = BSD__ultoa(ulval, cp, base, - flags & ALT, xdigs); - } - size = buf + BUF - cp; - break; - default: /* "%?" prints ?, unless ? is NUL */ - if (ch == '\0') - goto done; - /* pretend it was %c with argument ch */ - cp = buf; - *cp = ch; - size = 1; - sign = '\0'; - break; - } - - /* - * All reasonable formats wind up here. At this point, `cp' - * points to a string which (if not flags&LADJUST) should be - * padded out to `width' places. If flags&ZEROPAD, it should - * first be prefixed by any sign or other prefix; otherwise, - * it should be blank padded before the prefix is emitted. - * After any left-hand padding and prefixing, emit zeroes - * required by a decimal [diouxX] precision, then print the - * string proper, then emit zeroes required by any leftover - * floating precision; finally, if LADJUST, pad with blanks. - * - * Compute actual size, so we know how much to pad. - * fieldsz excludes decimal prec; realsz includes it. - */ - fieldsz = size; - if (sign) - fieldsz++; - else if (flags & HEXPREFIX) - fieldsz += 2; - realsz = dprec > fieldsz ? dprec : fieldsz; - - /* right-adjusting blank padding */ - if ((flags & (LADJUST|ZEROPAD)) == 0) - PAD(width - realsz, blanks); - - /* prefix */ - if (sign) { - PRINT(&sign, 1); - } else if (flags & HEXPREFIX) { - ox[0] = '0'; - ox[1] = ch; - PRINT(ox, 2); - } - - /* right-adjusting zero padding */ - if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) - PAD(width - realsz, zeroes); - - /* leading zeroes from decimal precision */ - PAD(dprec - fieldsz, zeroes); - - /* the string or number proper */ -#ifdef FLOATING_POINT - if ((flags & FPT) == 0) { - PRINT(cp, size); - } else { /* glue together f_p fragments */ - if (ch >= 'f') { /* 'f' or 'g' */ - if (_double == 0) { - /* kludge for __dtoa irregularity */ - if (prec == 0 || - (flags & ALT) == 0) { - PRINT("0", 1); - } else { - PRINT("0.", 2); - PAD(ndig - 1, zeroes); - } - } else if (expt <= 0) { - PRINT("0.", 2); - PAD(-expt, zeroes); - PRINT(cp, ndig); - } else if (expt >= ndig) { - PRINT(cp, ndig); - PAD(expt - ndig, zeroes); - if (flags & ALT) - PRINT(".", 1); - } else { - PRINT(cp, expt); - cp += expt; - PRINT(".", 1); - PRINT(cp, ndig-expt); - } - } else { /* 'e' or 'E' */ - if (ndig > 1 || flags & ALT) { - ox[0] = *cp++; - ox[1] = '.'; - PRINT(ox, 2); - if (_double || flags & ALT == 0) { - PRINT(cp, ndig-1); - } else /* 0.[0..] */ - /* __dtoa irregularity */ - PAD(ndig - 1, zeroes); - } else /* XeYYY */ - PRINT(cp, 1); - PRINT(expstr, expsize); - } - } -#else - PRINT(cp, size); -#endif - /* left-adjusting padding (always blank) */ - if (flags & LADJUST) - PAD(width - realsz, blanks); - - /* finally, adjust ret */ - ret += width > realsz ? width : realsz; - - FLUSH(); /* copy out the I/O vectors */ - } -done: - FLUSH(); -error: - return (__sferror(fp) ? EOF : ret); - /* NOTREACHED */ -} - -#ifdef FLOATING_POINT - -extern char *BSD__dtoa __P((double, int, int, int *, int *, char **)); - -static char * -cvt(value, ndigits, flags, sign, decpt, ch, length) - double value; - int ndigits, flags, *decpt, ch, *length; - char *sign; -{ - int mode, dsgn; - char *digits, *bp, *rve; - - if (ch == 'f') - mode = 3; - else { - mode = 2; - } - if (value < 0) { - value = -value; - *sign = '-'; - } else if (value == 0.0 && 1.0/value < 0) { - *sign = '-'; - } else { - *sign = '\000'; - } - digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve); - if (flags & ALT) { /* Print trailing zeros */ - bp = digits + ndigits; - if (ch == 'f') { - if (*digits == '0' && value) - *decpt = -ndigits + 1; - bp += *decpt; - } - if (value == 0) /* kludge for __dtoa irregularity */ - rve = bp; - while (rve < bp) - *rve++ = '0'; - } - *length = rve - digits; - return (digits); -} - -static int -exponent(p0, exp, fmtch) - char *p0; - int exp, fmtch; -{ - register char *p, *t; - char expbuf[MAXEXP]; - - p = p0; - *p++ = fmtch; - if (exp < 0) { - exp = -exp; - *p++ = '-'; - } - else - *p++ = '+'; - t = expbuf + MAXEXP; - if (exp > 9) { - do { - *--t = to_char(exp % 10); - } while ((exp /= 10) > 9); - *--t = to_char(exp); - for (; t < expbuf + MAXEXP; *p++ = *t++); - } - else { - *p++ = '0'; - *p++ = to_char(exp); - } - return (p - p0); -} -#endif /* FLOATING_POINT */ - -int -vsnprintf(str, n, fmt, ap) - char *str; - size_t n; - const char *fmt; - _BSD_VA_LIST_ ap; -{ - int ret; - FILE f; - - if ((int)n < 1) - return (EOF); - f._flags = __SWR | __SSTR; - f._bf._base = f._p = (unsigned char *)str; - f._bf._size = f._w = n - 1; - ret = BSD_vfprintf(&f, fmt, ap); - *f._p = 0; - return (ret); -} - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)snprintf.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ - -#if defined(__STDC__) -# include <stdarg.h> -#else -# include <varargs.h> -#endif - -int -#if defined(__STDC__) -snprintf(char *str, size_t n, char const *fmt, ...) -#else -snprintf(str, n, fmt, va_alist) -char *str, *fmt; -size_t n; -va_dcl -#endif -{ - int ret; - va_list ap; - FILE f; - - if ((int)n < 1) - return (EOF); - -#if defined(__STDC__) - va_start(ap, fmt); -#else - va_start(ap); -#endif - f._flags = __SWR | __SSTR; - f._bf._base = f._p = (unsigned char *)str; - f._bf._size = f._w = n - 1; - ret = BSD_vfprintf(&f, fmt, ap); - *f._p = 0; - va_end(ap); - return (ret); -} diff --git a/missing/x68.c b/missing/x68.c deleted file mode 100644 index 8d00d50041..0000000000 --- a/missing/x68.c +++ /dev/null @@ -1,40 +0,0 @@ -/* x68 compatibility functions -- follows Ruby's license */ - -#include "config.h" - -#if !HAVE_SELECT -#include "x68/select.c" -#endif -#if MISSING__DTOS18 -#include "x68/_dtos18.c" -#endif -#if MISSING_FCONVERT -#include "x68/_round.c" -#include "x68/fconvert.c" -#endif - -/* missing some basic syscalls */ -int -link(const char *src, const char *dst) -{ - return symlink(src, dst); -} - -#ifndef HAVE_GETTIMEOFDAY -#include <time.h> -#include <sys/time.h> - -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; - -int -gettimeofday(struct timeval *tv, struct timezone *tz) -{ - tv->tv_sec = (long)time((time_t*)0); - tv->tv_usec = 0; - - return 0; -} -#endif diff --git a/missing/x86_64-chkstk.S b/missing/x86_64-chkstk.S new file mode 100644 index 0000000000..6d1227b6d2 --- /dev/null +++ b/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 |
