diff options
Diffstat (limited to 'missing')
| -rw-r--r-- | missing/acosh.c | 93 | ||||
| -rw-r--r-- | missing/alloca.c | 199 | ||||
| -rw-r--r-- | missing/cbrt.c | 11 | ||||
| -rw-r--r-- | missing/close.c | 72 | ||||
| -rw-r--r-- | missing/crt_externs.h | 8 | ||||
| -rw-r--r-- | missing/crypt.c | 967 | ||||
| -rw-r--r-- | missing/crypt.h | 247 | ||||
| -rw-r--r-- | missing/des_tables.c | 1616 | ||||
| -rw-r--r-- | missing/dtoa.c | 3509 | ||||
| -rw-r--r-- | missing/erf.c | 74 | ||||
| -rw-r--r-- | missing/explicit_bzero.c | 91 | ||||
| -rw-r--r-- | missing/ffs.c | 49 | ||||
| -rw-r--r-- | missing/file.h | 21 | ||||
| -rw-r--r-- | missing/flock.c | 139 | ||||
| -rw-r--r-- | missing/hypot.c | 17 | ||||
| -rw-r--r-- | missing/langinfo.c | 148 | ||||
| -rw-r--r-- | missing/lgamma_r.c | 80 | ||||
| -rw-r--r-- | missing/memcmp.c | 19 | ||||
| -rw-r--r-- | missing/memmove.c | 22 | ||||
| -rw-r--r-- | missing/mt19937.c | 158 | ||||
| -rw-r--r-- | missing/nan.c | 28 | ||||
| -rw-r--r-- | missing/nextafter.c | 77 | ||||
| -rw-r--r-- | missing/procstat_vm.c | 85 | ||||
| -rw-r--r-- | missing/setproctitle.c | 231 | ||||
| -rw-r--r-- | missing/strchr.c | 32 | ||||
| -rw-r--r-- | missing/strerror.c | 18 | ||||
| -rw-r--r-- | missing/strlcat.c | 56 | ||||
| -rw-r--r-- | missing/strlcpy.c | 51 | ||||
| -rw-r--r-- | missing/strstr.c | 29 | ||||
| -rw-r--r-- | missing/tgamma.c | 82 | ||||
| -rw-r--r-- | missing/x86_64-chkstk.S | 10 |
31 files changed, 8239 insertions, 0 deletions
diff --git a/missing/acosh.c b/missing/acosh.c new file mode 100644 index 0000000000..c6695b599e --- /dev/null +++ b/missing/acosh.c @@ -0,0 +1,93 @@ +/********************************************************************** + + acosh.c - + + $Author$ + created at: Fri Apr 12 00:34:17 JST 2002 + + public domain rewrite of acosh(3), asinh(3) and atanh(3) + +**********************************************************************/ + +#include <errno.h> +#include <float.h> +#include <math.h> +#include "ruby.h" + +/* DBL_MANT_DIG must be less than 4 times of bits of int */ +#ifndef DBL_MANT_DIG +#define DBL_MANT_DIG 53 /* in this case, at least 12 digit precision */ +#endif +#define BIG_CRITERIA_BIT (1<<DBL_MANT_DIG/2) +#if BIG_CRITERIA_BIT > 0 +#define BIG_CRITERIA (1.0*BIG_CRITERIA_BIT) +#else +#define BIG_CRITERIA (1.0*(1<<DBL_MANT_DIG/4)*(1<<(DBL_MANT_DIG/2+1-DBL_MANT_DIG/4))) +#endif +#define SMALL_CRITERIA_BIT (1<<(DBL_MANT_DIG/3)) +#if SMALL_CRITERIA_BIT > 0 +#define SMALL_CRITERIA (1.0/SMALL_CRITERIA_BIT) +#else +#define SMALL_CRITERIA (1.0*(1<<DBL_MANT_DIG/4)*(1<<(DBL_MANT_DIG/3+1-DBL_MANT_DIG/4))) +#endif + +#ifndef HAVE_ACOSH +double +acosh(double x) +{ + if (x < 1) + x = -1; /* NaN */ + else if (x == 1) + return 0; + else if (x > BIG_CRITERIA) + x += x; + else + x += sqrt((x + 1) * (x - 1)); + return log(x); +} +#endif + +#ifndef HAVE_ASINH +double +asinh(double x) +{ + int neg = x < 0; + double z = fabs(x); + + if (z < SMALL_CRITERIA) return x; + if (z < (1.0/(1<<DBL_MANT_DIG/5))) { + double x2 = z * z; + z *= 1 + x2 * (-1.0/6.0 + x2 * 3.0/40.0); + } + else if (z > BIG_CRITERIA) { + z = log(z + z); + } + else { + z = log(z + sqrt(z * z + 1)); + } + if (neg) z = -z; + return z; +} +#endif + +#ifndef HAVE_ATANH +double +atanh(double x) +{ + int neg = x < 0; + double z = fabs(x); + + if (z < SMALL_CRITERIA) return x; + z = log(z > 1 ? -1 : (1 + z) / (1 - z)) / 2; + if (neg) z = -z; + if (isinf(z)) +#if defined(ERANGE) + errno = ERANGE; +#elif defined(EDOM) + errno = EDOM; +#else + ; +#endif + return z; +} +#endif diff --git a/missing/alloca.c b/missing/alloca.c new file mode 100644 index 0000000000..d039dfc2cc --- /dev/null +++ b/missing/alloca.c @@ -0,0 +1,199 @@ +/* alloca -- (mostly) portable public-domain implementation -- D A Gwyn + + last edit: 86/05/30 rms + include config.h, since on VMS it renames some symbols. + Use xmalloc instead of malloc. + + This implementation of the PWB library alloca() function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + + It should work under any C implementation that uses an + actual procedure stack (as opposed to a linked list of + frames). There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca()-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. +*/ +#ifndef lint +static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ +#endif + +#include "ruby/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 "" + -- this is for usg, in which emacs must undefine static + in order to make unexec workable + */ +#ifndef STACK_DIRECTION +you +lose +-- must know STACK_DIRECTION at compile-time +#endif /* STACK_DIRECTION undefined */ +#endif /* static */ +#endif /* emacs */ + +#ifdef X3J11 +typedef void *pointer; /* generic pointer type */ +#else +typedef char *pointer; /* generic pointer type */ +#endif /* X3J11 */ + +#ifndef NULL +#define NULL 0 /* null pointer constant */ +#endif + +#define xmalloc ruby_xmalloc +#define xfree ruby_xfree + +extern void xfree(); +extern pointer xmalloc(); + +/* + Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown +*/ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* direction unknown */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* known at compile-time */ + +#else /* STACK_DIRECTION == 0; need run-time code */ + +static int stack_dir; /* 1 or -1 once known */ +#define STACK_DIR stack_dir + +static void +find_stack_direction (/* void */) +{ + static char *addr = NULL; /* address of first + `dummy', once known */ + auto char dummy; /* to get stack address */ + + if (addr == NULL) + { /* initial entry */ + addr = &dummy; + + find_stack_direction (); /* recurse once */ + } + else /* second entry */ + if (&dummy > addr) + stack_dir = 1; /* stack grew upward */ + else + stack_dir = -1; /* stack grew downward */ +} + +#endif /* STACK_DIRECTION == 0 */ + +/* + An "alloca header" is used to: + (a) chain together all alloca()ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc() + alignment chunk size. The following default should work okay. +*/ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* to force sizeof(header) */ + struct + { + union hdr *next; /* for chaining headers */ + char *deep; /* for stack depth measure */ + } h; +} header; + +/* + alloca( size ) returns a pointer to at least `size' bytes of + storage which will be automatically reclaimed upon exit from + the procedure that called alloca(). Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. +*/ + +static header *last_alloca_header = NULL; /* -> last alloca header */ + +pointer +alloca (size) /* returns pointer to storage */ + unsigned size; /* # bytes to allocate */ +{ + auto char probe; /* probes stack depth: */ + register char *depth = &probe; + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* unknown growth direction */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca()ed storage that + was allocated from deeper in the stack than currently. */ + { + register header *hp; /* traverses linked list */ + + for (hp = last_alloca_header; hp != NULL;) + if (STACK_DIR > 0 && hp->h.deep > depth + || STACK_DIR < 0 && hp->h.deep < depth) + { + register header *np = hp->h.next; + + xfree ((pointer) hp); /* collect garbage */ + + hp = np; /* -> next header */ + } + else + break; /* rest are not deeper */ + + last_alloca_header = hp; /* -> last valid storage */ + } + + if (size == 0) + return NULL; /* no allocation required */ + + /* Allocate combined header + user data storage. */ + + { + register pointer new = xmalloc (sizeof (header) + size); + /* address of header */ + + ((header *)new)->h.next = last_alloca_header; + ((header *)new)->h.deep = depth; + + last_alloca_header = (header *)new; + + /* User storage begins just after header. */ + + return (pointer)((char *)new + sizeof(header)); + } +} + +#endif diff --git a/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 new file mode 100644 index 0000000000..f523aa51e6 --- /dev/null +++ b/missing/crypt.c @@ -0,0 +1,967 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tom Truscott. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)crypt.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +#include "ruby/missing.h" +#include "crypt.h" +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <limits.h> +#ifdef HAVE_PWD_H +#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, + * from algorithms by Robert W. Baldwin and James Gillogly. + * + * References: + * "Mathematical Cryptology for Computer Scientists and Mathematicians," + * by Wayne Patterson, 1987, ISBN 0-8476-7438-X. + * + * "Password Security: A Case History," R. Morris and Ken Thompson, + * Communications of the ACM, vol. 22, pp. 594-597, Nov. 1979. + * + * "DES will be Totally Insecure within Ten Years," M.E. Hellman, + * IEEE Spectrum, vol. 16, pp. 32-39, July 1979. + */ + +/* ===== Configuration ==================== */ + +/* + * define "MUST_ALIGN" if your compiler cannot load/store + * long integers at arbitrary (e.g. odd) memory locations. + * (Either that or never pass unaligned addresses to des_cipher!) + */ +#if !defined(vax) +#define MUST_ALIGN +#endif + +#ifdef CHAR_BITS +#if CHAR_BITS != 8 + #error C_block structure assumes 8 bit characters +#endif +#endif + +#ifndef INIT_DES +# if defined DUMP || defined NO_DES_TABLES +# define INIT_DES 1 +# else +# define INIT_DES 0 +# endif +#endif +#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 + +/* + * Convert twenty-four-bit long in host-order + * to six bits (and 2 low-order zeroes) per char little-endian format. + */ +#define TO_SIX_BIT(rslt, src) { \ + C_block cvt; \ + cvt.b[0] = (unsigned char)(src); (src) >>= 6; \ + cvt.b[1] = (unsigned char)(src); (src) >>= 6; \ + cvt.b[2] = (unsigned char)(src); (src) >>= 6; \ + cvt.b[3] = (unsigned char)(src); \ + (rslt) = (cvt.b32.i0 & 0x3f3f3f3fL) << 2; \ + } + +/* + * These macros may someday permit efficient use of 64-bit integers. + */ +#define ZERO(d,d0,d1) ((d0) = 0, (d1) = 0) +#define LOAD(d,d0,d1,bl) ((d0) = (bl).b32.i0, (d1) = (bl).b32.i1) +#define LOADREG(d,d0,d1,s,s0,s1) ((d0) = (s0), (d1) = (s1)) +#define OR(d,d0,d1,bl) ((d0) |= (bl).b32.i0, (d1) |= (bl).b32.i1) +#define STORE(s,s0,s1,bl) ((bl).b32.i0 = (s0), (bl).b32.i1 = (s1)) +#define DCL_BLOCK(d,d0,d1) long d0, d1 + +#if defined(LARGEDATA) + /* Waste memory like crazy. Also, do permutations in line */ +#define PERM6464(d,d0,d1,cpp,p) \ + LOAD((d),(d0),(d1),(p)[(0<<CHUNKBITS)+(cpp)[0]]); \ + OR ((d),(d0),(d1),(p)[(1<<CHUNKBITS)+(cpp)[1]]); \ + OR ((d),(d0),(d1),(p)[(2<<CHUNKBITS)+(cpp)[2]]); \ + OR ((d),(d0),(d1),(p)[(3<<CHUNKBITS)+(cpp)[3]]); \ + OR (d),(d0),(d1),(p)[(4<<CHUNKBITS)+(cpp)[4]]); \ + OR (d),(d0),(d1),(p)[(5<<CHUNKBITS)+(cpp)[5]]); \ + OR (d),(d0),(d1),(p)[(6<<CHUNKBITS)+(cpp)[6]]); \ + OR (d),(d0),(d1),(p)[(7<<CHUNKBITS)+(cpp)[7]]); +#define PERM3264(d,d0,d1,cpp,p) \ + LOAD((d),(d0),(d1),(p)[(0<<CHUNKBITS)+(cpp)[0]]); \ + OR ((d),(d0),(d1),(p)[(1<<CHUNKBITS)+(cpp)[1]]); \ + OR ((d),(d0),(d1),(p)[(2<<CHUNKBITS)+(cpp)[2]]); \ + OR ((d),(d0),(d1),(p)[(3<<CHUNKBITS)+(cpp)[3]]); +#else + /* "small data" */ +#define PERM6464(d,d0,d1,cpp,p) \ + { C_block tblk; permute((cpp),&tblk,(p),8); LOAD ((d),(d0),(d1),tblk); } +#define PERM3264(d,d0,d1,cpp,p) \ + { C_block tblk; permute((cpp),&tblk,(p),4); LOAD ((d),(d0),(d1),tblk); } + +STATIC void +permute(const unsigned char *cp, C_block *out, register const C_block *p, int chars_in) +{ + register DCL_BLOCK(D,D0,D1); + register const C_block *tp; + register int t; + + ZERO(D,D0,D1); + do { + t = *cp++; + tp = &p[t&0xf]; OR(D,D0,D1,*tp); p += (1<<CHUNKBITS); + tp = &p[t>>4]; OR(D,D0,D1,*tp); p += (1<<CHUNKBITS); + } while (--chars_in > 0); + STORE(D,D0,D1,*out); +} +#endif /* LARGEDATA */ + +#ifdef DEBUG +STATIC void prtab(const char *s, const unsigned char *t, int num_rows); +#endif + +#if INIT_DES +/* ===== (mostly) Standard DES Tables ==================== */ + +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, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, +}; + +/* The final permutation is the inverse of IP - no table is necessary */ + +static const unsigned char ExpandTr[] = { /* expansion operation */ + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1, +}; + +static 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, + 19, 11, 3, 60, 52, 44, 36, + + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4, +}; +#endif + +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 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, + 43, 54, 16, 7, 27, 20, 13, 2, + + 0, 0, 41, 52, 31, 37, 47, 55, + 0, 0, 30, 40, 51, 45, 33, 48, + 0, 0, 44, 49, 39, 56, 34, 53, + 0, 0, 46, 42, 50, 36, 29, 32, +}; + +static 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 const unsigned char P32Tr[] = { /* 32-bit permutation function */ + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25, +}; + +static 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, + 13, 14, 15, 16, 29, 30, 31, 32, + + 33, 34, 35, 36, 49, 50, 51, 52, + 37, 38, 39, 40, 53, 54, 55, 56, + 41, 42, 43, 44, 57, 58, 59, 60, + 45, 46, 47, 48, 61, 62, 63, 64, +}; +#endif + +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]; + + /* Subsequent key schedule rotation permutations */ + C_block PC2ROT[2][64/CHUNKBITS][1<<CHUNKBITS]; + + /* Initial permutation/expansion table */ + C_block IE3264[32/CHUNKBITS][1<<CHUNKBITS]; + + /* Table that combines the S, P, and E operations. */ + unsigned long SPE[2][8][64]; + + /* compressed/interleaved => final permutation table */ + C_block CF6464[64/CHUNKBITS][1<<CHUNKBITS]; + + int ready; +} des_tables_t; +static des_tables_t des_tables[1]; + +#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 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(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; + register int t; + long salt; + int num_iter, salt_size; + C_block keyblock, rsltblock; + + for (i = 0; i < 8; i++) { + if ((t = 2*(unsigned char)(*key)) != 0) + key++; + keyblock.b[i] = t; + } + des_setkey_r(keyblock.b, data); /* also initializes "a64toi" */ + + encp = &cryptresult[0]; + switch (*setting) { + case _PASSWORD_EFMT1: + /* + * Involve the rest of the password 8 characters at a time. + */ + while (*key) { + 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; + } + des_setkey_r(keyblock.b, data); + } + + *encp++ = *setting++; + + /* get iteration count */ + num_iter = 0; + for (i = 4; --i >= 0; ) { + if ((t = (unsigned char)setting[i]) == '\0') + t = '.'; + encp[i] = t; + num_iter = (num_iter<<6) | a64toi[t]; + } + setting += 4; + encp += 4; + salt_size = 4; + break; + default: + num_iter = 25; + salt_size = 2; + } + + salt = 0; + for (i = salt_size; --i >= 0; ) { + if ((t = (unsigned char)setting[i]) == '\0') + t = '.'; + encp[i] = t; + salt = (salt<<6) | a64toi[t]; + } + encp += salt_size; + des_cipher_r(constdatablock.b, rsltblock.b, salt, num_iter, data); + + /* + * Encode the 64 cipher bits as 11 ascii characters. + */ + i = ((long)((rsltblock.b[0]<<8) | rsltblock.b[1])<<8) | rsltblock.b[2]; + encp[3] = itoa64[i&0x3f]; i >>= 6; + encp[2] = itoa64[i&0x3f]; i >>= 6; + encp[1] = itoa64[i&0x3f]; i >>= 6; + encp[0] = itoa64[i]; encp += 4; + i = ((long)((rsltblock.b[3]<<8) | rsltblock.b[4])<<8) | rsltblock.b[5]; + encp[3] = itoa64[i&0x3f]; i >>= 6; + encp[2] = itoa64[i&0x3f]; i >>= 6; + encp[1] = itoa64[i&0x3f]; i >>= 6; + encp[0] = itoa64[i]; encp += 4; + i = ((long)((rsltblock.b[6])<<8) | rsltblock.b[7])<<2; + encp[2] = itoa64[i&0x3f]; i >>= 6; + encp[1] = itoa64[i&0x3f]; i >>= 6; + encp[0] = itoa64[i]; + + encp[3] = 0; + + return (cryptresult); +} + +/* + * Set up the key schedule from the key. + */ +static void +des_setkey_r(const unsigned char *key, struct crypt_data *data) +{ + register DCL_BLOCK(K, K0, K1); + register const C_block *ptabp; + register int i; + 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); + } +} + +/* + * Encrypt (or decrypt if num_iter < 0) the 8 chars at "in" with abs(num_iter) + * iterations of DES, using the given 24-bit salt and the pre-computed key + * schedule, and store the resulting 8 chars at "out" (in == out is permitted). + * + * NOTE: the performance of this routine is critically dependent on your + * compiler and machine architecture. + */ +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 unsigned long L0, L1, R0, R1, k; + register const C_block *kp; + register int ks_inc, loop_count; + C_block B; + + L0 = salt; + TO_SIX_BIT(salt, L0); /* convert to 4*(6+2) format */ + +#if defined(vax) || defined(pdp11) + salt = ~salt; /* "x &~ y" is faster than "x & y". */ +#define SALT (~salt) +#else +#define SALT salt +#endif + +#if defined(MUST_ALIGN) + B.b[0] = in[0]; B.b[1] = in[1]; B.b[2] = in[2]; B.b[3] = in[3]; + B.b[4] = in[4]; B.b[5] = in[5]; B.b[6] = in[6]; B.b[7] = in[7]; + LOAD(L,L0,L1,B); +#else + LOAD(L,L0,L1,*(C_block *)in); +#endif + LOADREG(R,R0,R1,L,L0,L1); + L0 &= 0x55555555L; + L1 &= 0x55555555L; + L0 = (L0 << 1) | L1; /* L0 is the even-numbered input bits */ + R0 &= 0xaaaaaaaaL; + R1 = (R1 >> 1) & 0x55555555L; + L1 = R0 | R1; /* L1 is the odd-numbered input bits */ + STORE(L,L0,L1,B); + PERM3264(L,L0,L1,B.b, 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 = +1; + } + else + { /* decryption */ + num_iter = -num_iter; + kp = &KS[KS_SIZE-1]; + ks_inc = -1; + } + + while (--num_iter >= 0) { + loop_count = 8; + do { + +#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)]); +#else +#if defined(pdp11) + /* use this if your "long" int indexing is slow */ +#define DOXOR(x,y,i) j=B.b[(i)]; (x)^=SPTAB(SPE[0][(i)],j); (y)^=SPTAB(SPE[1][(i)],j); +#else + /* use this if "k" is allocated to a register ... */ +#define DOXOR(x,y,i) k=B.b[(i)]; (x)^=SPTAB(SPE[0][(i)],k); (y)^=SPTAB(SPE[1][(i)],k); +#endif +#endif + +#define CRUNCH(p0, p1, q0, q1) \ + k = ((q0) ^ (q1)) & SALT; \ + B.b32.i0 = k ^ (q0) ^ kp->b32.i0; \ + B.b32.i1 = k ^ (q1) ^ kp->b32.i1; \ + kp += ks_inc; \ + \ + DOXOR((p0), (p1), 0); \ + DOXOR((p0), (p1), 1); \ + DOXOR((p0), (p1), 2); \ + DOXOR((p0), (p1), 3); \ + DOXOR((p0), (p1), 4); \ + DOXOR((p0), (p1), 5); \ + DOXOR((p0), (p1), 6); \ + DOXOR((p0), (p1), 7); + + CRUNCH(L0, L1, R0, R1); + CRUNCH(R0, R1, L0, L1); + } while (--loop_count != 0); + kp -= (ks_inc*KS_SIZE); + + + /* swap L and R */ + L0 ^= R0; L1 ^= R1; + R0 ^= L0; R1 ^= L1; + L0 ^= R0; L1 ^= R1; + } + + /* store the encrypted (or decrypted) result */ + L0 = ((L0 >> 3) & 0x0f0f0f0fL) | ((L1 << 1) & 0xf0f0f0f0L); + L1 = ((R0 >> 3) & 0x0f0f0f0fL) | ((R1 << 1) & 0xf0f0f0f0L); + STORE(L,L0,L1,B); + PERM6464(L,L0,L1,B.b, 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]; + out[4] = B.b[4]; out[5] = B.b[5]; out[6] = B.b[6]; out[7] = B.b[7]; +#else + STORE(L,L0,L1,*(C_block *)out); +#endif +} + +#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 void +init_des(void) +{ + register int i, j; + register long k; + register int tableno; + unsigned char perm[64], tmp32[32]; + + if (des_tables->ready) return; + + /* + * PC1ROT - bit reverse, then PC1, then Rotate, then PC2. + */ + for (i = 0; i < 64; i++) + perm[i] = 0; + for (i = 0; i < 64; i++) { + if ((k = PC2[i]) == 0) + continue; + k += Rotates[0]-1; + if ((k%28) < Rotates[0]) k -= 28; + k = PC1[k]; + if (k > 0) { + k--; + k = (k|07) - (k&07); + k++; + } + perm[i] = (unsigned char)k; + } +#ifdef DEBUG + prtab("pc1tab", perm, 8); +#endif + init_perm(PC1ROT, perm, 8, 8); + + /* + * PC2ROT - PC2 inverse, then Rotate (once or twice), then PC2. + */ + for (j = 0; j < 2; j++) { + unsigned char pc2inv[64]; + for (i = 0; i < 64; i++) + perm[i] = pc2inv[i] = 0; + for (i = 0; i < 64; i++) { + if ((k = PC2[i]) == 0) + continue; + pc2inv[k-1] = i+1; + } + for (i = 0; i < 64; i++) { + if ((k = PC2[i]) == 0) + continue; + k += j; + if ((k%28) <= j) k -= 28; + perm[i] = pc2inv[k]; + } +#ifdef DEBUG + prtab("pc2tab", perm, 8); +#endif + init_perm(PC2ROT[j], perm, 8, 8); + } + + /* + * Bit reverse, then initial permutation, then expansion. + */ + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++) { + k = (j < 2)? 0: IP[ExpandTr[i*6+j-2]-1]; + if (k > 32) + k -= 32; + else if (k > 0) + k--; + if (k > 0) { + k--; + k = (k|07) - (k&07); + k++; + } + perm[i*8+j] = (unsigned char)k; + } + } +#ifdef DEBUG + prtab("ietab", perm, 8); +#endif + init_perm(IE3264, perm, 4, 8); + + /* + * Compression, then final permutation, then bit reverse. + */ + for (i = 0; i < 64; i++) { + k = IP[CIFP[i]-1]; + if (k > 0) { + k--; + k = (k|07) - (k&07); + k++; + } + perm[k-1] = i+1; + } +#ifdef DEBUG + prtab("cftab", perm, 8); +#endif + init_perm(CF6464, perm, 8, 8); + + /* + * SPE table + */ + for (i = 0; i < 48; i++) + perm[i] = P32Tr[ExpandTr[i]-1]; + for (tableno = 0; tableno < 8; tableno++) { + for (j = 0; j < 64; j++) { + k = (((j >> 0) &01) << 5)| + (((j >> 1) &01) << 3)| + (((j >> 2) &01) << 2)| + (((j >> 3) &01) << 1)| + (((j >> 4) &01) << 0)| + (((j >> 5) &01) << 4); + k = S[tableno][k]; + k = (((k >> 3)&01) << 0)| + (((k >> 2)&01) << 1)| + (((k >> 1)&01) << 2)| + (((k >> 0)&01) << 3); + for (i = 0; i < 32; i++) + tmp32[i] = 0; + for (i = 0; i < 4; i++) + tmp32[4 * tableno + i] = (unsigned char)(k >> i) & 01; + k = 0; + for (i = 24; --i >= 0; ) + k = (k<<1) | tmp32[perm[i]-1]; + TO_SIX_BIT(SPE[0][tableno][j], k); + k = 0; + for (i = 24; --i >= 0; ) + k = (k<<1) | tmp32[perm[i+24]-1]; + TO_SIX_BIT(SPE[1][tableno][j], k); + } + } + + des_tables->ready = 1; +} + +/* + * Initialize "perm" to represent transformation "p", which rearranges + * (perhaps with expansion and/or contraction) one packed array of bits + * (of size "chars_in" characters) into another array (of size "chars_out" + * characters). + * + * "perm" must be all-zeroes on entry to this routine. + */ +STATIC void +init_perm(C_block perm[64/CHUNKBITS][1<<CHUNKBITS], + unsigned char p[64], int chars_in, int chars_out) +{ + register int i, j, k, l; + + for (k = 0; k < chars_out*8; k++) { /* each output bit position */ + l = p[k] - 1; /* where this bit comes from */ + if (l < 0) + continue; /* output bit is always 0 */ + i = l>>LGCHUNKBITS; /* which chunk this bit comes from */ + l = 1<<(l&(CHUNKBITS-1)); /* mask for this bit */ + for (j = 0; j < (1<<CHUNKBITS); j++) { /* each chunk value */ + if ((j & l) != 0) + perm[i][j].b[k>>3] |= 1<<(k&07); + } + } +} +#endif + +/* + * "setkey" routine (for backwards compatibility) + */ +#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; + + for (i = 0; i < 8; i++) { + k = 0; + for (j = 0; j < 8; j++) { + k <<= 1; + k |= (unsigned char)*key++; + } + keyblock.b[i] = k; + } + des_setkey_r(keyblock.b, data); +} + +/* + * "encrypt" routine (for backwards compatibility) + */ +#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; + + for (i = 0; i < 8; i++) { + k = 0; + for (j = 0; j < 8; j++) { + k <<= 1; + k |= (unsigned char)*block++; + } + cblock.b[i] = k; + } + 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--) { + *--block = k&01; + k >>= 1; + } + } +} + +#ifdef DEBUG +STATIC void +prtab(const char *s, const unsigned char *t, int num_rows) +{ + register int i, j; + + (void)printf("%s:\n", s); + for (i = 0; i < num_rows; i++) { + for (j = 0; j < 8; j++) { + (void)printf("%3d", t[i*8+j]); + } + (void)printf("\n"); + } + (void)printf("\n"); +} +#endif + +#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/erf.c b/missing/erf.c new file mode 100644 index 0000000000..c2c9d5f7e9 --- /dev/null +++ b/missing/erf.c @@ -0,0 +1,74 @@ +/* erf.c - public domain implementation of error function erf(3m) + +reference - Haruhiko Okumura: C-gengo niyoru saishin algorithm jiten + (New Algorithm handbook in C language) (Gijyutsu hyouron + sha, Tokyo, 1991) p.227 [in Japanese] */ +#include "ruby/missing.h" +#include <stdio.h> +#include <math.h> + +static double q_gamma(double, double, double); + +/* Incomplete gamma function + 1 / Gamma(a) * Int_0^x exp(-t) t^(a-1) dt */ +static double p_gamma(double a, double x, double loggamma_a) +{ + int k; + double result, term, previous; + + if (x >= 1 + a) return 1 - q_gamma(a, x, loggamma_a); + if (x == 0) return 0; + result = term = exp(a * log(x) - x - loggamma_a) / a; + for (k = 1; k < 1000; k++) { + term *= x / (a + k); + previous = result; result += term; + if (result == previous) return result; + } + fprintf(stderr, "erf.c:%d:p_gamma() could not converge.", __LINE__); + return result; +} + +/* Incomplete gamma function + 1 / Gamma(a) * Int_x^inf exp(-t) t^(a-1) dt */ +static double q_gamma(double a, double x, double loggamma_a) +{ + int k; + double result, w, temp, previous; + double la = 1, lb = 1 + x - a; /* Laguerre polynomial */ + + if (x < 1 + a) return 1 - p_gamma(a, x, loggamma_a); + w = exp(a * log(x) - x - loggamma_a); + result = w / lb; + for (k = 2; k < 1000; k++) { + temp = ((k - 1 - a) * (lb - la) + (k + x) * lb) / k; + la = lb; lb = temp; + w *= (k - 1 - a) / k; + temp = w / (la * lb); + previous = result; result += temp; + if (result == previous) return result; + } + fprintf(stderr, "erf.c:%d:q_gamma() could not converge.", __LINE__); + return result; +} + +#define LOG_PI_OVER_2 0.572364942924700087071713675675 /* log_e(PI)/2 */ + +double erf(double x) +{ + if (!finite(x)) { + if (isnan(x)) return x; /* erf(NaN) = NaN */ + return (x>0 ? 1.0 : -1.0); /* erf(+-inf) = +-1.0 */ + } + if (x >= 0) return p_gamma(0.5, x * x, LOG_PI_OVER_2); + else return - p_gamma(0.5, x * x, LOG_PI_OVER_2); +} + +double erfc(double x) +{ + if (!finite(x)) { + if (isnan(x)) return x; /* erfc(NaN) = NaN */ + return (x>0 ? 0.0 : 2.0); /* erfc(+-inf) = 0.0, 2.0 */ + } + if (x >= 0) return q_gamma(0.5, x * x, LOG_PI_OVER_2); + else return 1 + p_gamma(0.5, x * x, LOG_PI_OVER_2); +} diff --git a/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 new file mode 100644 index 0000000000..5e25c4761c --- /dev/null +++ b/missing/file.h @@ -0,0 +1,21 @@ +#ifndef _FILE_H_ +#define _FILE_H_ +/* This is file FILE.H */ + +#include <fcntl.h> + +#ifndef L_SET +# define L_SET 0 /* seek from beginning. */ +# define L_CURR 1 /* seek from current position. */ +# define L_INCR 1 /* ditto. */ +# define L_XTND 2 /* seek from end. */ +#endif + +#ifndef R_OK +# define R_OK 4 /* test whether readable. */ +# define W_OK 2 /* test whether writable. */ +# define X_OK 1 /* test whether executable. */ +# define F_OK 0 /* test whether exist. */ +#endif + +#endif diff --git a/missing/flock.c b/missing/flock.c new file mode 100644 index 0000000000..0b76961762 --- /dev/null +++ b/missing/flock.c @@ -0,0 +1,139 @@ +#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 systems doesn't have + flock(), the values of the constants are probably not available. +*/ +# ifndef LOCK_SH +# define LOCK_SH 1 +# endif +# ifndef LOCK_EX +# define LOCK_EX 2 +# endif +# ifndef LOCK_NB +# define LOCK_NB 4 +# endif +# ifndef LOCK_UN +# define LOCK_UN 8 +# endif + +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +int +flock(int fd, int operation) +{ + struct flock lock; + + switch (operation & ~LOCK_NB) { + case LOCK_SH: + lock.l_type = F_RDLCK; + break; + case LOCK_EX: + lock.l_type = F_WRLCK; + break; + case LOCK_UN: + lock.l_type = F_UNLCK; + break; + default: + errno = EINVAL; + return -1; + } + lock.l_whence = SEEK_SET; + lock.l_start = lock.l_len = 0L; + + return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lock); +} + +#elif defined(HAVE_LOCKF) + +#include <unistd.h> +#include <errno.h> + +/* Emulate flock() with lockf() or fcntl(). This is just to increase + portability of scripts. The calls might not be completely + interchangeable. What's really needed is a good file + locking module. +*/ + +# ifndef F_ULOCK +# define F_ULOCK 0 /* Unlock a previously locked region */ +# endif +# ifndef F_LOCK +# define F_LOCK 1 /* Lock a region for exclusive use */ +# endif +# ifndef F_TLOCK +# define F_TLOCK 2 /* Test and lock a region for exclusive use */ +# endif +# ifndef F_TEST +# define F_TEST 3 /* Test a region for other processes locks */ +# endif + +/* These are the flock() constants. Since this systems doesn't have + flock(), the values of the constants are probably not available. +*/ +# ifndef LOCK_SH +# define LOCK_SH 1 +# endif +# ifndef LOCK_EX +# define LOCK_EX 2 +# endif +# ifndef LOCK_NB +# define LOCK_NB 4 +# endif +# ifndef LOCK_UN +# define LOCK_UN 8 +# endif + +int +flock(int fd, int operation) +{ + switch (operation) { + + /* LOCK_SH - get a shared lock */ + case LOCK_SH: + rb_notimplement(); + return -1; + /* LOCK_EX - get an exclusive lock */ + case LOCK_EX: + return lockf (fd, F_LOCK, 0); + + /* LOCK_SH|LOCK_NB - get a non-blocking shared lock */ + case LOCK_SH|LOCK_NB: + rb_notimplement(); + return -1; + /* LOCK_EX|LOCK_NB - get a non-blocking exclusive lock */ + case LOCK_EX|LOCK_NB: + return lockf (fd, F_TLOCK, 0); + + /* LOCK_UN - unlock */ + case LOCK_UN: + return lockf (fd, F_ULOCK, 0); + + /* Default - can't decipher operation */ + default: + errno = EINVAL; + return -1; + } +} +#else +int +flock(int fd, int operation) +{ + rb_notimplement(); + return -1; +} +#endif diff --git a/missing/hypot.c b/missing/hypot.c new file mode 100644 index 0000000000..765581bacb --- /dev/null +++ b/missing/hypot.c @@ -0,0 +1,17 @@ +/* public domain rewrite of hypot */ + +#include "ruby/missing.h" +#include <math.h> + +double hypot(double x, double y) +{ + if (x < 0) x = -x; + if (y < 0) y = -y; + if (x < y) { + double tmp = x; + x = y; y = tmp; + } + if (y == 0.0) return x; + y /= x; + return x * sqrt(1.0+y*y); +} diff --git a/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 new file mode 100644 index 0000000000..9657e6c372 --- /dev/null +++ b/missing/memcmp.c @@ -0,0 +1,19 @@ +/* public domain rewrite of memcmp(3) */ + +#include "ruby/missing.h" +#include <stddef.h> + +int +memcmp(const void *s1, const void *s2, size_t len) +{ + register unsigned char *a = (unsigned char*)s1; + register unsigned char *b = (unsigned char*)s2; + register int tmp; + + for (; len; --len) { + tmp = *a++ - *b++; + if (tmp) + return tmp; + } + return 0; +} diff --git a/missing/memmove.c b/missing/memmove.c new file mode 100644 index 0000000000..e8e17e87e7 --- /dev/null +++ b/missing/memmove.c @@ -0,0 +1,22 @@ +/* public domain rewrite of memcmp(3) */ + +#include "ruby/missing.h" +#include <stddef.h> + +void * +memmove(void *d, const void *s, size_t n) +{ + char *dst = (char *)d; + const char *src = (const char *)s; + + if (src < dst) { + src += n; + dst += n; + for (; n; --n) + *--dst = *--src; + } + else if (dst < src) + for (; n; --n) + *dst++ = *src++; + return d; +} diff --git a/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/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/strchr.c b/missing/strchr.c new file mode 100644 index 0000000000..465f07b61e --- /dev/null +++ b/missing/strchr.c @@ -0,0 +1,32 @@ +/* public domain rewrite of strchr(3) and strrchr(3) */ + +#include "ruby/missing.h" + +size_t strlen(const char*); + +char * +strchr(const char *s, int c) +{ + if (c == 0) return (char *)s + strlen(s); + while (*s) { + if (*s == c) + return (char *)s; + s++; + } + return 0; +} + +char * +strrchr(const char *s, int c) +{ + const char *save; + + if (c == 0) return (char *)s + strlen(s); + save = 0; + while (*s) { + if (*s == c) + save = s; + s++; + } + return (char *)save; +} diff --git a/missing/strerror.c b/missing/strerror.c new file mode 100644 index 0000000000..d3b61c3f12 --- /dev/null +++ b/missing/strerror.c @@ -0,0 +1,18 @@ +/* public domain rewrite of strerror(3) */ + +#include "ruby/missing.h" + +extern int sys_nerr; +extern char *sys_errlist[]; + +static char msg[50]; + +char * +strerror(int error) +{ + if (error <= sys_nerr && error > 0) { + return sys_errlist[error]; + } + snprintf(msg, sizeof(msg), "Unknown error (%d)", error); + return msg; +} 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/strstr.c b/missing/strstr.c new file mode 100644 index 0000000000..e6613c5d2f --- /dev/null +++ b/missing/strstr.c @@ -0,0 +1,29 @@ +/* public domain rewrite of strstr(3) */ + +#include "ruby/missing.h" + +size_t strlen(const char*); + +char * +strstr(const char *haystack, const char *needle) +{ + const char *hend; + const char *a, *b; + + if (*needle == 0) return (char *)haystack; + hend = haystack + strlen(haystack) - strlen(needle) + 1; + while (haystack < hend) { + if (*haystack == *needle) { + a = haystack; + b = needle; + for (;;) { + if (*b == 0) return (char *)haystack; + if (*a++ != *b++) { + break; + } + } + } + haystack++; + } + return 0; +} diff --git a/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/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 |
