summaryrefslogtreecommitdiff
path: root/trunk/missing
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/missing')
-rw-r--r--trunk/missing/acosh.c93
-rw-r--r--trunk/missing/alloca.c194
-rw-r--r--trunk/missing/cbrt.c10
-rw-r--r--trunk/missing/crypt.c992
-rw-r--r--trunk/missing/dup2.c60
-rw-r--r--trunk/missing/erf.c88
-rw-r--r--trunk/missing/file.h22
-rw-r--r--trunk/missing/fileblocks.c1
-rw-r--r--trunk/missing/finite.c7
-rw-r--r--trunk/missing/flock.c129
-rw-r--r--trunk/missing/hypot.c16
-rw-r--r--trunk/missing/isinf.c69
-rw-r--r--trunk/missing/isnan.c15
-rw-r--r--trunk/missing/lgamma_r.c68
-rw-r--r--trunk/missing/memcmp.c17
-rw-r--r--trunk/missing/memmove.c21
-rw-r--r--trunk/missing/os2.c138
-rw-r--r--trunk/missing/strchr.c28
-rw-r--r--trunk/missing/strerror.c16
-rw-r--r--trunk/missing/strlcat.c73
-rw-r--r--trunk/missing/strlcpy.c69
-rw-r--r--trunk/missing/strstr.c25
-rw-r--r--trunk/missing/strtol.c26
-rw-r--r--trunk/missing/tgamma.c92
-rw-r--r--trunk/missing/vsnprintf.c1201
-rw-r--r--trunk/missing/x68.c40
26 files changed, 3510 insertions, 0 deletions
diff --git a/trunk/missing/acosh.c b/trunk/missing/acosh.c
new file mode 100644
index 0000000000..c6695b599e
--- /dev/null
+++ b/trunk/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/trunk/missing/alloca.c b/trunk/missing/alloca.c
new file mode 100644
index 0000000000..067f76b183
--- /dev/null
+++ b/trunk/missing/alloca.c
@@ -0,0 +1,194 @@
+/* alloca -- (mostly) portable public-domain implementation -- D A Gwyn
+
+ last edit: 86/05/30 rms
+ include config.h, since on VMS it renames some symbols.
+ Use xmalloc instead of malloc.
+
+ This implementation of the PWB library alloca() function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+
+ It should work under any C implementation that uses an
+ actual procedure stack (as opposed to a linked list of
+ frames). There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca()-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection.
+*/
+#ifndef lint
+static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
+#endif
+
+#include "ruby/config.h"
+#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 */
+
+#define NULL 0 /* null pointer constant */
+
+#ifdef RUBY_LIB
+#define xmalloc ruby_xmalloc
+#define xfree ruby_xfree
+#endif
+
+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));
+ }
+}
+
diff --git a/trunk/missing/cbrt.c b/trunk/missing/cbrt.c
new file mode 100644
index 0000000000..54db2703a0
--- /dev/null
+++ b/trunk/missing/cbrt.c
@@ -0,0 +1,10 @@
+#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/trunk/missing/crypt.c b/trunk/missing/crypt.c
new file mode 100644
index 0000000000..32736bccfb
--- /dev/null
+++ b/trunk/missing/crypt.c
@@ -0,0 +1,992 @@
+/*
+ * 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 */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <limits.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <stdio.h>
+#ifndef _PASSWORD_EFMT1
+#define _PASSWORD_EFMT1 '_'
+#endif
+
+/*
+ * UNIX password, and DES, encryption.
+ * By Tom Truscott, trt@rti.rti.org,
+ * from algorithms by Robert W. Baldwin and James Gillogly.
+ *
+ * References:
+ * "Mathematical Cryptology for Computer Scientists and Mathematicians,"
+ * by Wayne Patterson, 1987, ISBN 0-8476-7438-X.
+ *
+ * "Password Security: A Case History," R. Morris and Ken Thompson,
+ * Communications of the ACM, vol. 22, pp. 594-597, Nov. 1979.
+ *
+ * "DES will be Totally Insecure within Ten Years," M.E. Hellman,
+ * IEEE Spectrum, vol. 16, pp. 32-39, July 1979.
+ */
+
+/* ===== Configuration ==================== */
+
+/*
+ * define "MUST_ALIGN" if your compiler cannot load/store
+ * long integers at arbitrary (e.g. odd) memory locations.
+ * (Either that or never pass unaligned addresses to des_cipher!)
+ */
+#if !defined(vax)
+#define MUST_ALIGN
+#endif
+
+#ifdef CHAR_BITS
+#if CHAR_BITS != 8
+ #error C_block structure assumes 8 bit characters
+#endif
+#endif
+
+/*
+ * define "LONG_IS_32_BITS" only if sizeof(long)==4.
+ * This avoids use of bit fields (your compiler may be sloppy with them).
+ */
+#if !defined(cray)
+#define LONG_IS_32_BITS
+#endif
+
+/*
+ * define "B64" to be the declaration for a 64 bit integer.
+ * XXX this feature is currently unused, see "endian" comment below.
+ */
+#if defined(cray)
+#define B64 long
+#endif
+#if defined(convex)
+#define B64 long long
+#endif
+
+/*
+ * define "LARGEDATA" to get faster permutations, by using about 72 kilobytes
+ * of lookup tables. This speeds up des_setkey() and des_cipher(), but has
+ * little effect on crypt().
+ */
+#if defined(notdef)
+#define LARGEDATA
+#endif
+
+int des_setkey(), des_cipher();
+
+/* compile with "-DSTATIC=int" when profiling */
+#ifndef STATIC
+#define STATIC static
+#endif
+STATIC void init_des(), init_perm(), permute();
+#ifdef DEBUG
+STATIC void prtab();
+#endif
+
+/* ==================================== */
+
+/*
+ * Cipher-block representation (Bob Baldwin):
+ *
+ * DES operates on groups of 64 bits, numbered 1..64 (sigh). One
+ * representation is to store one bit per byte in an array of bytes. Bit N of
+ * the NBS spec is stored as the LSB of the Nth byte (index N-1) in the array.
+ * Another representation stores the 64 bits in 8 bytes, with bits 1..8 in the
+ * first byte, 9..16 in the second, and so on. The DES spec apparently has
+ * bit 1 in the MSB of the first byte, but that is particularly noxious so we
+ * bit-reverse each byte so that bit 1 is the LSB of the first byte, bit 8 is
+ * the MSB of the first byte. Specifically, the 64-bit input data and key are
+ * converted to LSB format, and the output 64-bit block is converted back into
+ * MSB format.
+ *
+ * DES operates internally on groups of 32 bits which are expanded to 48 bits
+ * by permutation E and shrunk back to 32 bits by the S boxes. To speed up
+ * the computation, the expansion is applied only once, the expanded
+ * representation is maintained during the encryption, and a compression
+ * permutation is applied only at the end. To speed up the S-box lookups,
+ * the 48 bits are maintained as eight 6 bit groups, one per byte, which
+ * directly feed the eight S-boxes. Within each byte, the 6 bits are the
+ * most significant ones. The low two bits of each byte are zero. (Thus,
+ * bit 1 of the 48 bit E expansion is stored as the "4"-valued bit of the
+ * first byte in the eight byte representation, bit 2 of the 48 bit value is
+ * the "8"-valued bit, and so on.) In fact, a combined "SPE"-box lookup is
+ * used, in which the output is the 64 bit result of an S-box lookup which
+ * has been permuted by P and expanded by E, and is ready for use in the next
+ * iteration. Two 32-bit wide tables, SPE[0] and SPE[1], are used for this
+ * lookup. Since each byte in the 48 bit path is a multiple of four, indexed
+ * lookup of SPE[0] and SPE[1] is simple and fast. The key schedule and
+ * "salt" are also converted to this 8*(6+2) format. The SPE table size is
+ * 8*64*8 = 4K bytes.
+ *
+ * To speed up bit-parallel operations (such as XOR), the 8 byte
+ * representation is "union"ed with 32 bit values "i0" and "i1", and, on
+ * machines which support it, a 64 bit value "b64". This data structure,
+ * "C_block", has two problems. First, alignment restrictions must be
+ * honored. Second, the byte-order (e.g. little-endian or big-endian) of
+ * the architecture becomes visible.
+ *
+ * The byte-order problem is unfortunate, since on the one hand it is good
+ * to have a machine-independent C_block representation (bits 1..8 in the
+ * first byte, etc.), and on the other hand it is good for the LSB of the
+ * first byte to be the LSB of i0. We cannot have both these things, so we
+ * currently use the "little-endian" representation and avoid any multi-byte
+ * operations that depend on byte order. This largely precludes use of the
+ * 64-bit datatype since the relative order of i0 and i1 are unknown. It
+ * also inhibits grouping the SPE table to look up 12 bits at a time. (The
+ * 12 bits can be stored in a 16-bit field with 3 low-order zeroes and 1
+ * high-order zero, providing fast indexing into a 64-bit wide SPE.) On the
+ * other hand, 64-bit datatypes are currently rare, and a 12-bit SPE lookup
+ * requires a 128 kilobyte table, so perhaps this is not a big loss.
+ *
+ * Permutation representation (Jim Gillogly):
+ *
+ * A transformation is defined by its effect on each of the 8 bytes of the
+ * 64-bit input. For each byte we give a 64-bit output that has the bits in
+ * the input distributed appropriately. The transformation is then the OR
+ * of the 8 sets of 64-bits. This uses 8*256*8 = 16K bytes of storage for
+ * each transformation. Unless LARGEDATA is defined, however, a more compact
+ * table is used which looks up 16 4-bit "chunks" rather than 8 8-bit chunks.
+ * The smaller table uses 16*16*8 = 2K bytes for each transformation. This
+ * is slower but tolerable, particularly for password encryption in which
+ * the SPE transformation is iterated many times. The small tables total 9K
+ * bytes, the large tables total 72K bytes.
+ *
+ * The transformations used are:
+ * IE3264: MSB->LSB conversion, initial permutation, and expansion.
+ * This is done by collecting the 32 even-numbered bits and applying
+ * a 32->64 bit transformation, and then collecting the 32 odd-numbered
+ * bits and applying the same transformation. Since there are only
+ * 32 input bits, the IE3264 transformation table is half the size of
+ * the usual table.
+ * CF6464: Compression, final permutation, and LSB->MSB conversion.
+ * This is done by two trivial 48->32 bit compressions to obtain
+ * a 64-bit block (the bit numbering is given in the "CIFP" table)
+ * followed by a 64->64 bit "cleanup" transformation. (It would
+ * be possible to group the bits in the 64-bit block so that 2
+ * identical 32->32 bit transformations could be used instead,
+ * saving a factor of 4 in space and possibly 2 in time, but
+ * byte-ordering and other complications rear their ugly head.
+ * Similar opportunities/problems arise in the key schedule
+ * transforms.)
+ * PC1ROT: MSB->LSB, PC1 permutation, rotate, and PC2 permutation.
+ * This admittedly baroque 64->64 bit transformation is used to
+ * produce the first code (in 8*(6+2) format) of the key schedule.
+ * PC2ROT[0]: Inverse PC2 permutation, rotate, and PC2 permutation.
+ * It would be possible to define 15 more transformations, each
+ * with a different rotation, to generate the entire key schedule.
+ * To save space, however, we instead permute each code into the
+ * next by using a transformation that "undoes" the PC2 permutation,
+ * rotates the code, and then applies PC2. Unfortunately, PC2
+ * transforms 56 bits into 48 bits, dropping 8 bits, so PC2 is not
+ * invertible. We get around that problem by using a modified PC2
+ * which retains the 8 otherwise-lost bits in the unused low-order
+ * bits of each byte. The low-order bits are cleared when the
+ * codes are stored into the key schedule.
+ * PC2ROT[1]: Same as PC2ROT[0], but with two rotations.
+ * This is faster than applying PC2ROT[0] twice,
+ *
+ * The Bell Labs "salt" (Bob Baldwin):
+ *
+ * The salting is a simple permutation applied to the 48-bit result of E.
+ * Specifically, if bit i (1 <= i <= 24) of the salt is set then bits i and
+ * i+24 of the result are swapped. The salt is thus a 24 bit number, with
+ * 16777216 possible values. (The original salt was 12 bits and could not
+ * swap bits 13..24 with 36..48.)
+ *
+ * It is possible, but ugly, to warp the SPE table to account for the salt
+ * permutation. Fortunately, the conditional bit swapping requires only
+ * about four machine instructions and can be done on-the-fly with about an
+ * 8% performance penalty.
+ */
+
+typedef union {
+ unsigned char b[8];
+ struct {
+#if defined(LONG_IS_32_BITS)
+ /* long is often faster than a 32-bit bit field */
+ long i0;
+ long i1;
+#else
+ long i0: 32;
+ long i1: 32;
+#endif
+ } b32;
+#if defined(B64)
+ B64 b64;
+#endif
+} C_block;
+
+/*
+ * Convert twenty-four-bit long in host-order
+ * to six bits (and 2 low-order zeroes) per char little-endian format.
+ */
+#define TO_SIX_BIT(rslt, src) { \
+ C_block cvt; \
+ cvt.b[0] = src; src >>= 6; \
+ cvt.b[1] = src; src >>= 6; \
+ cvt.b[2] = src; src >>= 6; \
+ cvt.b[3] = src; \
+ rslt = (cvt.b32.i0 & 0x3f3f3f3fL) << 2; \
+ }
+
+/*
+ * These macros may someday permit efficient use of 64-bit integers.
+ */
+#define ZERO(d,d0,d1) d0 = 0, d1 = 0
+#define LOAD(d,d0,d1,bl) d0 = (bl).b32.i0, d1 = (bl).b32.i1
+#define LOADREG(d,d0,d1,s,s0,s1) d0 = s0, d1 = s1
+#define OR(d,d0,d1,bl) d0 |= (bl).b32.i0, d1 |= (bl).b32.i1
+#define STORE(s,s0,s1,bl) (bl).b32.i0 = s0, (bl).b32.i1 = s1
+#define DCL_BLOCK(d,d0,d1) long d0, d1
+
+#if defined(LARGEDATA)
+ /* Waste memory like crazy. Also, do permutations in line */
+#define LGCHUNKBITS 3
+#define CHUNKBITS (1<<LGCHUNKBITS)
+#define PERM6464(d,d0,d1,cpp,p) \
+ LOAD(d,d0,d1,(p)[(0<<CHUNKBITS)+(cpp)[0]]); \
+ OR (d,d0,d1,(p)[(1<<CHUNKBITS)+(cpp)[1]]); \
+ OR (d,d0,d1,(p)[(2<<CHUNKBITS)+(cpp)[2]]); \
+ OR (d,d0,d1,(p)[(3<<CHUNKBITS)+(cpp)[3]]); \
+ OR (d,d0,d1,(p)[(4<<CHUNKBITS)+(cpp)[4]]); \
+ OR (d,d0,d1,(p)[(5<<CHUNKBITS)+(cpp)[5]]); \
+ OR (d,d0,d1,(p)[(6<<CHUNKBITS)+(cpp)[6]]); \
+ OR (d,d0,d1,(p)[(7<<CHUNKBITS)+(cpp)[7]]);
+#define PERM3264(d,d0,d1,cpp,p) \
+ LOAD(d,d0,d1,(p)[(0<<CHUNKBITS)+(cpp)[0]]); \
+ OR (d,d0,d1,(p)[(1<<CHUNKBITS)+(cpp)[1]]); \
+ OR (d,d0,d1,(p)[(2<<CHUNKBITS)+(cpp)[2]]); \
+ OR (d,d0,d1,(p)[(3<<CHUNKBITS)+(cpp)[3]]);
+#else
+ /* "small data" */
+#define LGCHUNKBITS 2
+#define CHUNKBITS (1<<LGCHUNKBITS)
+#define PERM6464(d,d0,d1,cpp,p) \
+ { C_block tblk; permute(cpp,&tblk,p,8); LOAD (d,d0,d1,tblk); }
+#define PERM3264(d,d0,d1,cpp,p) \
+ { C_block tblk; permute(cpp,&tblk,p,4); LOAD (d,d0,d1,tblk); }
+
+STATIC void
+permute(cp, out, p, chars_in)
+ unsigned char *cp;
+ C_block *out;
+ register C_block *p;
+ int chars_in;
+{
+ register DCL_BLOCK(D,D0,D1);
+ register C_block *tp;
+ register int t;
+
+ ZERO(D,D0,D1);
+ do {
+ t = *cp++;
+ tp = &p[t&0xf]; OR(D,D0,D1,*tp); p += (1<<CHUNKBITS);
+ tp = &p[t>>4]; OR(D,D0,D1,*tp); p += (1<<CHUNKBITS);
+ } while (--chars_in > 0);
+ STORE(D,D0,D1,*out);
+}
+#endif /* LARGEDATA */
+
+
+/* ===== (mostly) Standard DES Tables ==================== */
+
+static unsigned char IP[] = { /* initial permutation */
+ 58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7,
+};
+
+/* The final permutation is the inverse of IP - no table is necessary */
+
+static unsigned char ExpandTr[] = { /* expansion operation */
+ 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1,
+};
+
+static unsigned char PC1[] = { /* permuted choice table 1 */
+ 57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4,
+};
+
+static unsigned char Rotates[] = { /* PC1 rotation schedule */
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
+};
+
+/* note: each "row" of PC2 is left-padded with bits that make it invertible */
+static unsigned char PC2[] = { /* permuted choice table 2 */
+ 9, 18, 14, 17, 11, 24, 1, 5,
+ 22, 25, 3, 28, 15, 6, 21, 10,
+ 35, 38, 23, 19, 12, 4, 26, 8,
+ 43, 54, 16, 7, 27, 20, 13, 2,
+
+ 0, 0, 41, 52, 31, 37, 47, 55,
+ 0, 0, 30, 40, 51, 45, 33, 48,
+ 0, 0, 44, 49, 39, 56, 34, 53,
+ 0, 0, 46, 42, 50, 36, 29, 32,
+};
+
+static unsigned char S[8][64] = { /* 48->32 bit substitution tables */
+ {
+ /* S[1] */
+ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
+ },
+ {
+ /* S[2] */
+ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
+ },
+ {
+ /* S[3] */
+ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
+ },
+ {
+ /* S[4] */
+ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
+ },
+ {
+ /* S[5] */
+ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
+ },
+ {
+ /* S[6] */
+ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
+ },
+ {
+ /* S[7] */
+ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
+ },
+ {
+ /* S[8] */
+ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11,
+ },
+};
+
+static unsigned char P32Tr[] = { /* 32-bit permutation function */
+ 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25,
+};
+
+static unsigned char CIFP[] = { /* compressed/interleaved permutation */
+ 1, 2, 3, 4, 17, 18, 19, 20,
+ 5, 6, 7, 8, 21, 22, 23, 24,
+ 9, 10, 11, 12, 25, 26, 27, 28,
+ 13, 14, 15, 16, 29, 30, 31, 32,
+
+ 33, 34, 35, 36, 49, 50, 51, 52,
+ 37, 38, 39, 40, 53, 54, 55, 56,
+ 41, 42, 43, 44, 57, 58, 59, 60,
+ 45, 46, 47, 48, 61, 62, 63, 64,
+};
+
+static unsigned char itoa64[] = /* 0..63 => ascii-64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+
+/* ===== Tables that are initialized at run time ==================== */
+
+
+static unsigned char a64toi[128]; /* ascii-64 => 0..63 */
+
+/* Initial key schedule permutation */
+static C_block PC1ROT[64/CHUNKBITS][1<<CHUNKBITS];
+
+/* Subsequent key schedule rotation permutations */
+static C_block PC2ROT[2][64/CHUNKBITS][1<<CHUNKBITS];
+
+/* Initial permutation/expansion table */
+static C_block IE3264[32/CHUNKBITS][1<<CHUNKBITS];
+
+/* Table that combines the S, P, and E operations. */
+static long SPE[2][8][64];
+
+/* compressed/interleaved => final permutation table */
+static C_block CF6464[64/CHUNKBITS][1<<CHUNKBITS];
+
+
+/* ==================================== */
+
+
+static C_block constdatablock; /* encryption constant */
+static char cryptresult[1+4+4+11+1]; /* encrypted result */
+
+/*
+ * Return a pointer to static data consisting of the "setting"
+ * followed by an encryption produced by the "key" and "setting".
+ */
+char *
+crypt(key, setting)
+ register const char *key;
+ register const char *setting;
+{
+ register char *encp;
+ register long i;
+ register int t;
+ long salt;
+ int num_iter, salt_size;
+ C_block keyblock, rsltblock;
+
+ for (i = 0; i < 8; i++) {
+ if ((t = 2*(unsigned char)(*key)) != 0)
+ key++;
+ keyblock.b[i] = t;
+ }
+ if (des_setkey((char *)keyblock.b)) /* also initializes "a64toi" */
+ return (NULL);
+
+ encp = &cryptresult[0];
+ switch (*setting) {
+ case _PASSWORD_EFMT1:
+ /*
+ * Involve the rest of the password 8 characters at a time.
+ */
+ while (*key) {
+ if (des_cipher((char *)&keyblock,
+ (char *)&keyblock, 0L, 1))
+ return (NULL);
+ for (i = 0; i < 8; i++) {
+ if ((t = 2*(unsigned char)(*key)) != 0)
+ key++;
+ keyblock.b[i] ^= t;
+ }
+ if (des_setkey((char *)keyblock.b))
+ return (NULL);
+ }
+
+ *encp++ = *setting++;
+
+ /* get iteration count */
+ num_iter = 0;
+ for (i = 4; --i >= 0; ) {
+ if ((t = (unsigned char)setting[i]) == '\0')
+ t = '.';
+ encp[i] = t;
+ num_iter = (num_iter<<6) | a64toi[t];
+ }
+ setting += 4;
+ encp += 4;
+ salt_size = 4;
+ break;
+ default:
+ num_iter = 25;
+ salt_size = 2;
+ }
+
+ salt = 0;
+ for (i = salt_size; --i >= 0; ) {
+ if ((t = (unsigned char)setting[i]) == '\0')
+ t = '.';
+ encp[i] = t;
+ salt = (salt<<6) | a64toi[t];
+ }
+ encp += salt_size;
+ if (des_cipher((char *)&constdatablock, (char *)&rsltblock,
+ salt, num_iter))
+ return (NULL);
+
+ /*
+ * Encode the 64 cipher bits as 11 ascii characters.
+ */
+ i = ((long)((rsltblock.b[0]<<8) | rsltblock.b[1])<<8) | rsltblock.b[2];
+ encp[3] = itoa64[i&0x3f]; i >>= 6;
+ encp[2] = itoa64[i&0x3f]; i >>= 6;
+ encp[1] = itoa64[i&0x3f]; i >>= 6;
+ encp[0] = itoa64[i]; encp += 4;
+ i = ((long)((rsltblock.b[3]<<8) | rsltblock.b[4])<<8) | rsltblock.b[5];
+ encp[3] = itoa64[i&0x3f]; i >>= 6;
+ encp[2] = itoa64[i&0x3f]; i >>= 6;
+ encp[1] = itoa64[i&0x3f]; i >>= 6;
+ encp[0] = itoa64[i]; encp += 4;
+ i = ((long)((rsltblock.b[6])<<8) | rsltblock.b[7])<<2;
+ encp[2] = itoa64[i&0x3f]; i >>= 6;
+ encp[1] = itoa64[i&0x3f]; i >>= 6;
+ encp[0] = itoa64[i];
+
+ encp[3] = 0;
+
+ return (cryptresult);
+}
+
+
+/*
+ * The Key Schedule, filled in by des_setkey() or setkey().
+ */
+#define KS_SIZE 16
+static C_block KS[KS_SIZE];
+
+/*
+ * Set up the key schedule from the key.
+ */
+int
+des_setkey(key)
+ register const char *key;
+{
+ register DCL_BLOCK(K, K0, K1);
+ register C_block *ptabp;
+ register int i;
+ static int des_ready = 0;
+
+ if (!des_ready) {
+ init_des();
+ des_ready = 1;
+ }
+
+ PERM6464(K,K0,K1,(unsigned char *)key,(C_block *)PC1ROT);
+ key = (char *)&KS[0];
+ STORE(K&~0x03030303L, K0&~0x03030303L, K1, *(C_block *)key);
+ for (i = 1; i < 16; i++) {
+ key += sizeof(C_block);
+ STORE(K,K0,K1,*(C_block *)key);
+ ptabp = (C_block *)PC2ROT[Rotates[i]-1];
+ PERM6464(K,K0,K1,(unsigned char *)key,ptabp);
+ STORE(K&~0x03030303L, K0&~0x03030303L, K1, *(C_block *)key);
+ }
+ return (0);
+}
+
+/*
+ * Encrypt (or decrypt if num_iter < 0) the 8 chars at "in" with abs(num_iter)
+ * iterations of DES, using the the given 24-bit salt and the pre-computed key
+ * schedule, and store the resulting 8 chars at "out" (in == out is permitted).
+ *
+ * NOTE: the performance of this routine is critically dependent on your
+ * compiler and machine architecture.
+ */
+int
+des_cipher(in, out, salt, num_iter)
+ const char *in;
+ char *out;
+ long salt;
+ int num_iter;
+{
+ /* variables that we want in registers, most important first */
+#if defined(pdp11)
+ register int j;
+#endif
+ register long L0, L1, R0, R1, k;
+ register C_block *kp;
+ register int ks_inc, loop_count;
+ C_block B;
+
+ L0 = salt;
+ TO_SIX_BIT(salt, L0); /* convert to 4*(6+2) format */
+
+#if defined(vax) || defined(pdp11)
+ salt = ~salt; /* "x &~ y" is faster than "x & y". */
+#define SALT (~salt)
+#else
+#define SALT salt
+#endif
+
+#if defined(MUST_ALIGN)
+ B.b[0] = in[0]; B.b[1] = in[1]; B.b[2] = in[2]; B.b[3] = in[3];
+ B.b[4] = in[4]; B.b[5] = in[5]; B.b[6] = in[6]; B.b[7] = in[7];
+ LOAD(L,L0,L1,B);
+#else
+ LOAD(L,L0,L1,*(C_block *)in);
+#endif
+ LOADREG(R,R0,R1,L,L0,L1);
+ L0 &= 0x55555555L;
+ L1 &= 0x55555555L;
+ L0 = (L0 << 1) | L1; /* L0 is the even-numbered input bits */
+ R0 &= 0xaaaaaaaaL;
+ R1 = (R1 >> 1) & 0x55555555L;
+ L1 = R0 | R1; /* L1 is the odd-numbered input bits */
+ STORE(L,L0,L1,B);
+ PERM3264(L,L0,L1,B.b, (C_block *)IE3264); /* even bits */
+ PERM3264(R,R0,R1,B.b+4,(C_block *)IE3264); /* odd bits */
+
+ if (num_iter >= 0)
+ { /* encryption */
+ kp = &KS[0];
+ ks_inc = sizeof(*kp);
+ }
+ else
+ { /* decryption */
+ num_iter = -num_iter;
+ kp = &KS[KS_SIZE-1];
+ ks_inc = -sizeof(*kp);
+ }
+
+ while (--num_iter >= 0) {
+ loop_count = 8;
+ do {
+
+#define SPTAB(t, i) (*(long *)((unsigned char *)t + i*(sizeof(long)/4)))
+#if defined(gould)
+ /* use this if B.b[i] is evaluated just once ... */
+#define DOXOR(x,y,i) x^=SPTAB(SPE[0][i],B.b[i]); y^=SPTAB(SPE[1][i],B.b[i]);
+#else
+#if defined(pdp11)
+ /* use this if your "long" int indexing is slow */
+#define DOXOR(x,y,i) j=B.b[i]; x^=SPTAB(SPE[0][i],j); y^=SPTAB(SPE[1][i],j);
+#else
+ /* use this if "k" is allocated to a register ... */
+#define DOXOR(x,y,i) k=B.b[i]; x^=SPTAB(SPE[0][i],k); y^=SPTAB(SPE[1][i],k);
+#endif
+#endif
+
+#define CRUNCH(p0, p1, q0, q1) \
+ k = (q0 ^ q1) & SALT; \
+ B.b32.i0 = k ^ q0 ^ kp->b32.i0; \
+ B.b32.i1 = k ^ q1 ^ kp->b32.i1; \
+ kp = (C_block *)((char *)kp+ks_inc); \
+ \
+ DOXOR(p0, p1, 0); \
+ DOXOR(p0, p1, 1); \
+ DOXOR(p0, p1, 2); \
+ DOXOR(p0, p1, 3); \
+ DOXOR(p0, p1, 4); \
+ DOXOR(p0, p1, 5); \
+ DOXOR(p0, p1, 6); \
+ DOXOR(p0, p1, 7);
+
+ CRUNCH(L0, L1, R0, R1);
+ CRUNCH(R0, R1, L0, L1);
+ } while (--loop_count != 0);
+ kp = (C_block *)((char *)kp-(ks_inc*KS_SIZE));
+
+
+ /* swap L and R */
+ L0 ^= R0; L1 ^= R1;
+ R0 ^= L0; R1 ^= L1;
+ L0 ^= R0; L1 ^= R1;
+ }
+
+ /* store the encrypted (or decrypted) result */
+ L0 = ((L0 >> 3) & 0x0f0f0f0fL) | ((L1 << 1) & 0xf0f0f0f0L);
+ L1 = ((R0 >> 3) & 0x0f0f0f0fL) | ((R1 << 1) & 0xf0f0f0f0L);
+ STORE(L,L0,L1,B);
+ PERM6464(L,L0,L1,B.b, (C_block *)CF6464);
+#if defined(MUST_ALIGN)
+ STORE(L,L0,L1,B);
+ out[0] = B.b[0]; out[1] = B.b[1]; out[2] = B.b[2]; out[3] = B.b[3];
+ out[4] = B.b[4]; out[5] = B.b[5]; out[6] = B.b[6]; out[7] = B.b[7];
+#else
+ STORE(L,L0,L1,*(C_block *)out);
+#endif
+ return (0);
+}
+
+
+/*
+ * Initialize various tables. This need only be done once. It could even be
+ * done at compile time, if the compiler were capable of that sort of thing.
+ */
+STATIC void
+init_des()
+{
+ register int i, j;
+ register long k;
+ register int tableno;
+ static unsigned char perm[64], tmp32[32]; /* "static" for speed */
+
+ /*
+ * table that converts chars "./0-9A-Za-z"to integers 0-63.
+ */
+ for (i = 0; i < 64; i++)
+ a64toi[itoa64[i]] = i;
+
+ /*
+ * PC1ROT - bit reverse, then PC1, then Rotate, then PC2.
+ */
+ for (i = 0; i < 64; i++)
+ perm[i] = 0;
+ for (i = 0; i < 64; i++) {
+ if ((k = PC2[i]) == 0)
+ continue;
+ k += Rotates[0]-1;
+ if ((k%28) < Rotates[0]) k -= 28;
+ k = PC1[k];
+ if (k > 0) {
+ k--;
+ k = (k|07) - (k&07);
+ k++;
+ }
+ perm[i] = 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] = 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] = (k >> i) & 01;
+ k = 0;
+ for (i = 24; --i >= 0; )
+ k = (k<<1) | tmp32[perm[i]-1];
+ TO_SIX_BIT(SPE[0][tableno][j], k);
+ k = 0;
+ for (i = 24; --i >= 0; )
+ k = (k<<1) | tmp32[perm[i+24]-1];
+ TO_SIX_BIT(SPE[1][tableno][j], k);
+ }
+ }
+}
+
+/*
+ * Initialize "perm" to represent transformation "p", which rearranges
+ * (perhaps with expansion and/or contraction) one packed array of bits
+ * (of size "chars_in" characters) into another array (of size "chars_out"
+ * characters).
+ *
+ * "perm" must be all-zeroes on entry to this routine.
+ */
+STATIC void
+init_perm(perm, p, chars_in, chars_out)
+ C_block perm[64/CHUNKBITS][1<<CHUNKBITS];
+ unsigned char p[64];
+ int chars_in, chars_out;
+{
+ register int i, j, k, l;
+
+ for (k = 0; k < chars_out*8; k++) { /* each output bit position */
+ l = p[k] - 1; /* where this bit comes from */
+ if (l < 0)
+ continue; /* output bit is always 0 */
+ i = l>>LGCHUNKBITS; /* which chunk this bit comes from */
+ l = 1<<(l&(CHUNKBITS-1)); /* mask for this bit */
+ for (j = 0; j < (1<<CHUNKBITS); j++) { /* each chunk value */
+ if ((j & l) != 0)
+ perm[i][j].b[k>>3] |= 1<<(k&07);
+ }
+ }
+}
+
+/*
+ * "setkey" routine (for backwards compatibility)
+ */
+int
+setkey(key)
+ register const char *key;
+{
+ register int i, j, k;
+ C_block keyblock;
+
+ for (i = 0; i < 8; i++) {
+ k = 0;
+ for (j = 0; j < 8; j++) {
+ k <<= 1;
+ k |= (unsigned char)*key++;
+ }
+ keyblock.b[i] = k;
+ }
+ return (des_setkey((char *)keyblock.b));
+}
+
+/*
+ * "encrypt" routine (for backwards compatibility)
+ */
+int
+encrypt(block, flag)
+ register char *block;
+ int flag;
+{
+ register int i, j, k;
+ C_block cblock;
+
+ for (i = 0; i < 8; i++) {
+ k = 0;
+ for (j = 0; j < 8; j++) {
+ k <<= 1;
+ k |= (unsigned char)*block++;
+ }
+ cblock.b[i] = k;
+ }
+ if (des_cipher((char *)&cblock, (char *)&cblock, 0L, (flag ? -1: 1)))
+ return (1);
+ for (i = 7; i >= 0; i--) {
+ k = cblock.b[i];
+ for (j = 7; j >= 0; j--) {
+ *--block = k&01;
+ k >>= 1;
+ }
+ }
+ return (0);
+}
+
+#ifdef DEBUG
+STATIC void
+prtab(s, t, num_rows)
+ char *s;
+ unsigned char *t;
+ int num_rows;
+{
+ register int i, j;
+
+ (void)printf("%s:\n", s);
+ for (i = 0; i < num_rows; i++) {
+ for (j = 0; j < 8; j++) {
+ (void)printf("%3d", t[i*8+j]);
+ }
+ (void)printf("\n");
+ }
+ (void)printf("\n");
+}
+#endif
diff --git a/trunk/missing/dup2.c b/trunk/missing/dup2.c
new file mode 100644
index 0000000000..7554084c5d
--- /dev/null
+++ b/trunk/missing/dup2.c
@@ -0,0 +1,60 @@
+/*
+ * Public domain dup2() lookalike
+ * by Curtis Jackson @ AT&T Technologies, Burlington, NC
+ * electronic address: burl!rcj
+ *
+ * dup2 performs the following functions:
+ *
+ * Check to make sure that fd1 is a valid open file descriptor.
+ * Check to see if fd2 is already open; if so, close it.
+ * Duplicate fd1 onto fd2; checking to make sure fd2 is a valid fd.
+ * Return fd2 if all went well; return BADEXIT otherwise.
+ */
+
+#include "ruby/config.h"
+
+#if defined(HAVE_FCNTL)
+# include <fcntl.h>
+#endif
+
+#if !defined(HAVE_FCNTL) || !defined(F_DUPFD)
+# include <errno.h>
+#endif
+
+#define BADEXIT -1
+
+int
+dup2(int fd1, int fd2)
+{
+#if defined(HAVE_FCNTL) && defined(F_DUPFD)
+ if (fd1 != fd2) {
+#ifdef F_GETFL
+ if (fcntl(fd1, F_GETFL) < 0)
+ return BADEXIT;
+ if (fcntl(fd2, F_GETFL) >= 0)
+ close(fd2);
+#else
+ close(fd2);
+#endif
+ if (fcntl(fd1, F_DUPFD, fd2) < 0)
+ return BADEXIT;
+ }
+ return fd2;
+#else
+ extern int errno;
+ int i, fd, fds[256];
+
+ if (fd1 == fd2) return 0;
+ close(fd2);
+ for (i=0; i<256; i++) {
+ fd = fds[i] = dup(fd1);
+ if (fd == fd2) break;
+ }
+ while (i) {
+ close(fds[i--]);
+ }
+ if (fd == fd2) return 0;
+ errno = EMFILE;
+ return BADEXIT;
+#endif
+}
diff --git a/trunk/missing/erf.c b/trunk/missing/erf.c
new file mode 100644
index 0000000000..fe65b9a479
--- /dev/null
+++ b/trunk/missing/erf.c
@@ -0,0 +1,88 @@
+/* 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 <stdio.h>
+#include <math.h>
+
+#ifdef _WIN32
+# include <float.h>
+# if !defined __MINGW32__ || defined __NO_ISOCEXT
+# ifndef isnan
+# define isnan(x) _isnan(x)
+# endif
+# ifndef isinf
+# define isinf(x) (!_finite(x) && !_isnan(x))
+# endif
+# ifndef finite
+# define finite(x) _finite(x)
+# endif
+# endif
+#endif
+
+static double q_gamma(double, double, double);
+
+/* Incomplete gamma function
+ 1 / Gamma(a) * Int_0^x exp(-t) t^(a-1) dt */
+static double p_gamma(double a, double x, double loggamma_a)
+{
+ int k;
+ double result, term, previous;
+
+ if (x >= 1 + a) return 1 - q_gamma(a, x, loggamma_a);
+ if (x == 0) return 0;
+ result = term = exp(a * log(x) - x - loggamma_a) / a;
+ for (k = 1; k < 1000; k++) {
+ term *= x / (a + k);
+ previous = result; result += term;
+ if (result == previous) return result;
+ }
+ fprintf(stderr, "erf.c:%d:p_gamma() could not converge.", __LINE__);
+ return result;
+}
+
+/* Incomplete gamma function
+ 1 / Gamma(a) * Int_x^inf exp(-t) t^(a-1) dt */
+static double q_gamma(double a, double x, double loggamma_a)
+{
+ int k;
+ double result, w, temp, previous;
+ double la = 1, lb = 1 + x - a; /* Laguerre polynomial */
+
+ if (x < 1 + a) return 1 - p_gamma(a, x, loggamma_a);
+ w = exp(a * log(x) - x - loggamma_a);
+ result = w / lb;
+ for (k = 2; k < 1000; k++) {
+ temp = ((k - 1 - a) * (lb - la) + (k + x) * lb) / k;
+ la = lb; lb = temp;
+ w *= (k - 1 - a) / k;
+ temp = w / (la * lb);
+ previous = result; result += temp;
+ if (result == previous) return result;
+ }
+ fprintf(stderr, "erf.c:%d:q_gamma() could not converge.", __LINE__);
+ return result;
+}
+
+#define LOG_PI_OVER_2 0.572364942924700087071713675675 /* log_e(PI)/2 */
+
+double erf(double x)
+{
+ if (!finite(x)) {
+ if (isnan(x)) return x; /* erf(NaN) = NaN */
+ return (x>0 ? 1.0 : -1.0); /* erf(+-inf) = +-1.0 */
+ }
+ if (x >= 0) return p_gamma(0.5, x * x, LOG_PI_OVER_2);
+ else return - p_gamma(0.5, x * x, LOG_PI_OVER_2);
+}
+
+double erfc(double x)
+{
+ if (!finite(x)) {
+ if (isnan(x)) return x; /* erfc(NaN) = NaN */
+ return (x>0 ? 0.0 : 2.0); /* erfc(+-inf) = 0.0, 2.0 */
+ }
+ if (x >= 0) return q_gamma(0.5, x * x, LOG_PI_OVER_2);
+ else return 1 + p_gamma(0.5, x * x, LOG_PI_OVER_2);
+}
diff --git a/trunk/missing/file.h b/trunk/missing/file.h
new file mode 100644
index 0000000000..2d491d0fc1
--- /dev/null
+++ b/trunk/missing/file.h
@@ -0,0 +1,22 @@
+/* This is file FILE.H */
+
+#ifndef _FILE_H_
+#define _FILE_H_
+
+#include <fcntl.h>
+
+#ifndef L_SET
+# define L_SET 0 /* seek from beginning. */
+# define L_CURR 1 /* seek from current position. */
+# define L_INCR 1 /* ditto. */
+# define L_XTND 2 /* seek from end. */
+#endif
+
+#ifndef R_OK
+# define R_OK 4 /* test whether readable. */
+# define W_OK 2 /* test whether writable. */
+# define X_OK 1 /* test whether execubale. */
+# define F_OK 0 /* test whether exist. */
+#endif
+
+#endif
diff --git a/trunk/missing/fileblocks.c b/trunk/missing/fileblocks.c
new file mode 100644
index 0000000000..ccb8d667b4
--- /dev/null
+++ b/trunk/missing/fileblocks.c
@@ -0,0 +1 @@
+/* dummy for autoconf */
diff --git a/trunk/missing/finite.c b/trunk/missing/finite.c
new file mode 100644
index 0000000000..8d0b7af262
--- /dev/null
+++ b/trunk/missing/finite.c
@@ -0,0 +1,7 @@
+/* public domain rewrite of finite(3) */
+
+int
+finite(double n)
+{
+ return !isnan(n) && !isinf(n);
+}
diff --git a/trunk/missing/flock.c b/trunk/missing/flock.c
new file mode 100644
index 0000000000..b02f8bf832
--- /dev/null
+++ b/trunk/missing/flock.c
@@ -0,0 +1,129 @@
+#include "ruby/config.h"
+
+#if defined _WIN32
+#elif defined HAVE_FCNTL && defined HAVE_FCNTL_H
+
+/* These are the flock() constants. Since this sytems 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 sytems 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/trunk/missing/hypot.c b/trunk/missing/hypot.c
new file mode 100644
index 0000000000..5a663553cf
--- /dev/null
+++ b/trunk/missing/hypot.c
@@ -0,0 +1,16 @@
+/* public domain rewrite of hypot */
+
+#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/trunk/missing/isinf.c b/trunk/missing/isinf.c
new file mode 100644
index 0000000000..4aef51b213
--- /dev/null
+++ b/trunk/missing/isinf.c
@@ -0,0 +1,69 @@
+/* public domain rewrite of isinf(3) */
+
+#ifdef __osf__
+
+#define _IEEE 1
+#include <nan.h>
+
+int
+isinf(double n)
+{
+ if (IsNANorINF(n) && IsINF(n)) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+#else
+
+#include "ruby/config.h"
+
+#if defined(HAVE_FINITE) && defined(HAVE_ISNAN)
+
+#include <math.h>
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+
+/*
+ * isinf may be provided only as a macro.
+ * ex. HP-UX, Solaris 10
+ * http://www.gnu.org/software/automake/manual/autoconf/Function-Portability.html
+ */
+#ifndef isinf
+int
+isinf(double n)
+{
+ return (!finite(n) && !isnan(n));
+}
+#endif
+
+#else
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+static double zero(void) { return 0.0; }
+static double one (void) { return 1.0; }
+static double inf (void) { return one() / zero(); }
+
+int
+isinf(double n)
+{
+ static double pinf = 0.0;
+ static double ninf = 0.0;
+
+ if (pinf == 0.0) {
+ pinf = inf();
+ ninf = -pinf;
+ }
+ return memcmp(&n, &pinf, sizeof n) == 0
+ || memcmp(&n, &ninf, sizeof n) == 0;
+}
+#endif
+#endif
diff --git a/trunk/missing/isnan.c b/trunk/missing/isnan.c
new file mode 100644
index 0000000000..a8733978ad
--- /dev/null
+++ b/trunk/missing/isnan.c
@@ -0,0 +1,15 @@
+/* public domain rewrite of isnan(3) */
+
+static int double_ne(double n1, double n2);
+
+int
+isnan(double n)
+{
+ return double_ne(n, n);
+}
+
+static int
+double_ne(double n1, double n2)
+{
+ return n1 != n2;
+}
diff --git a/trunk/missing/lgamma_r.c b/trunk/missing/lgamma_r.c
new file mode 100644
index 0000000000..ba8535b18a
--- /dev/null
+++ b/trunk/missing/lgamma_r.c
@@ -0,0 +1,68 @@
+/* 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/
+*/
+
+/***********************************************************
+ 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);
+}
+
+/* the natural logarithm of the absolute value of the Gamma function */
+double
+lgamma_r(double x, int *signp)
+{
+ if (x <= 0) {
+ double i, f, s;
+ f = modf(-x, &i);
+ if (f == 0.0) { /* pole error */
+ *signp = 1;
+ errno = ERANGE;
+ return HUGE_VAL;
+ }
+ *signp = (fmod(i, 2.0) != 0.0) ? 1 : -1;
+ s = sin(PI * f);
+ if (s < 0) s = -s;
+ return LOG_PI - log(s) - loggamma(1 - x);
+ }
+ *signp = 1;
+ return loggamma(x);
+}
diff --git a/trunk/missing/memcmp.c b/trunk/missing/memcmp.c
new file mode 100644
index 0000000000..5b3ad3817a
--- /dev/null
+++ b/trunk/missing/memcmp.c
@@ -0,0 +1,17 @@
+/* public domain rewrite of memcmp(3) */
+
+#include <stddef.h>
+
+int
+memcmp(const void *s1, const void *s2, size_t len)
+{
+ register unsigned char *a = (unsigned char*)s1;
+ register unsigned char *b = (unsigned char*)s2;
+ register int tmp;
+
+ for (; len; --len) {
+ if (tmp = *a++ - *b++)
+ return tmp;
+ }
+ return 0;
+}
diff --git a/trunk/missing/memmove.c b/trunk/missing/memmove.c
new file mode 100644
index 0000000000..19c5f18847
--- /dev/null
+++ b/trunk/missing/memmove.c
@@ -0,0 +1,21 @@
+/* public domain rewrite of memcmp(3) */
+
+#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/trunk/missing/os2.c b/trunk/missing/os2.c
new file mode 100644
index 0000000000..3448cdc281
--- /dev/null
+++ b/trunk/missing/os2.c
@@ -0,0 +1,138 @@
+/* os/2 compatibility functions -- follows Ruby's license */
+
+#include "ruby.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <process.h>
+#include <limits.h>
+#include <errno.h>
+
+#define INCL_DOS
+#include <os2.h>
+
+int
+chown(char *path, int owner, int group)
+{
+ return 0;
+}
+
+#if 0
+int
+link(char *from, char *to)
+{
+ return -1;
+}
+#endif
+
+#if defined(EMX_REPLACE_GETCWD) && (EMX_REPLACE_GETCWD) \
+ || defined(EMX_REPLACE_CHDIR) && (EMX_REPLACE_CHDIR)
+#include <unistd.h>
+
+#if defined(EMX_REPLACE_GETCWD) && (EMX_REPLACE_GETCWD)
+/* to handle the drive letter and DBCS characters within a given path */
+char *
+getcwd(char *path, size_t len)
+{
+ return _getcwd2(path, (int)len);
+}
+#endif
+
+#if defined(EMX_REPLACE_CHDIR) && (EMX_REPLACE_CHDIR)
+/* to handle the drive letter and DBCS characters within a given path */
+int
+chdir(__const__ char *path)
+{
+ return _chdir2(path);
+}
+#endif
+#endif
+
+typedef char* CHARP;
+
+int
+do_spawn(cmd)
+char *cmd;
+{
+ register char **a;
+ register char *s;
+ char **argv;
+ char *shell, *sw, *cmd2;
+ int status;
+
+ if ((shell = getenv("RUBYSHELL")) != NULL && *shell != '\0') {
+ s = shell;
+ do
+ *s = isupper(*s) ? tolower(*s) : *s;
+ while (*++s);
+ if (strstr(shell, "cmd") || strstr(shell, "4os2"))
+ sw = "/c";
+ else
+ sw = "-c";
+ } else if ((shell = getenv("SHELL")) != NULL && *shell != '\0') {
+ s = shell;
+ do
+ *s = isupper(*s) ? tolower(*s) : *s;
+ while (*++s);
+ if (strstr(shell, "cmd") || strstr(shell, "4os2"))
+ sw = "/c";
+ else
+ sw = "-c";
+ } else if ((shell = getenv("COMSPEC")) != NULL && *shell != '\0') {
+ s = shell;
+ do
+ *s = isupper(*s) ? tolower(*s) : *s;
+ while (*++s);
+ if (strstr(shell, "cmd") || strstr(shell, "4os2"))
+ sw = "/c";
+ else
+ sw = "-c";
+ }
+ /* see if there are shell metacharacters in it */
+ /*SUPPRESS 530*/
+ /* for (s = cmd; *s && isalpha(*s); s++) ;
+ if (*s == '=')
+ goto doshell; */
+ for (s = cmd; *s; s++) {
+ if (*sw == '-' && *s != ' ' &&
+ !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
+ if (*s == '\n' && !s[1]) {
+ *s = '\0';
+ break;
+ }
+ goto doshell;
+ } else if (*sw == '/' && *s != ' ' &&
+ !isalpha(*s) && index("^()<>|&\n",*s)) {
+ if (*s == '\n' && !s[1]) {
+ *s = '\0';
+ break;
+ }
+ doshell:
+ status = spawnlp(P_WAIT,shell,shell,sw,cmd,(char*)NULL);
+ return status;
+ }
+ }
+ argv = ALLOC_N(CHARP,(strlen(cmd) / 2 + 2));
+ cmd2 = ALLOC_N(char, (strlen(cmd) + 1));
+ strcpy(cmd2, cmd);
+ a = argv;
+ for (s = cmd2; *s;) {
+ while (*s && isspace(*s)) s++;
+ if (*s)
+ *(a++) = s;
+ while (*s && !isspace(*s)) s++;
+ if (*s)
+ *s++ = '\0';
+ }
+ *a = NULL;
+ if (argv[0]) {
+ if ((status = spawnvp(P_WAIT, argv[0], argv)) == -1) {
+ free(argv);
+ free(cmd2);
+ return -1;
+ }
+ }
+ free(cmd2);
+ free(argv);
+ return status;
+}
diff --git a/trunk/missing/strchr.c b/trunk/missing/strchr.c
new file mode 100644
index 0000000000..bebd7ba578
--- /dev/null
+++ b/trunk/missing/strchr.c
@@ -0,0 +1,28 @@
+/* public domain rewrite of strchr(3) and strrchr(3) */
+
+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/trunk/missing/strerror.c b/trunk/missing/strerror.c
new file mode 100644
index 0000000000..023935a1ff
--- /dev/null
+++ b/trunk/missing/strerror.c
@@ -0,0 +1,16 @@
+/* public domain rewrite of strerror(3) */
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+static char msg[50];
+
+char *
+strerror(int error)
+{
+ if (error <= sys_nerr && error > 0) {
+ return sys_errlist[error];
+ }
+ sprintf(msg, "Unknown error (%d)", error);
+ return msg;
+}
diff --git a/trunk/missing/strlcat.c b/trunk/missing/strlcat.c
new file mode 100644
index 0000000000..b309648155
--- /dev/null
+++ b/trunk/missing/strlcat.c
@@ -0,0 +1,73 @@
+/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
diff --git a/trunk/missing/strlcpy.c b/trunk/missing/strlcpy.c
new file mode 100644
index 0000000000..5f586964b7
--- /dev/null
+++ b/trunk/missing/strlcpy.c
@@ -0,0 +1,69 @@
+/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/trunk/missing/strstr.c b/trunk/missing/strstr.c
new file mode 100644
index 0000000000..2e9c282fb1
--- /dev/null
+++ b/trunk/missing/strstr.c
@@ -0,0 +1,25 @@
+/* public domain rewrite of strstr(3) */
+
+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/trunk/missing/strtol.c b/trunk/missing/strtol.c
new file mode 100644
index 0000000000..da6636f316
--- /dev/null
+++ b/trunk/missing/strtol.c
@@ -0,0 +1,26 @@
+/* public domain rewrite of strtol(3) */
+
+#include <ctype.h>
+
+long
+strtol(const char *nptr, char **endptr, int base)
+{
+ long result;
+ const char *p = nptr;
+
+ while (isspace(*p)) {
+ p++;
+ }
+ if (*p == '-') {
+ p++;
+ result = -strtoul(p, endptr, base);
+ }
+ else {
+ if (*p == '+') p++;
+ result = strtoul(p, endptr, base);
+ }
+ if (endptr != 0 && *endptr == p) {
+ *endptr = (char *)nptr;
+ }
+ return result;
+}
diff --git a/trunk/missing/tgamma.c b/trunk/missing/tgamma.c
new file mode 100644
index 0000000000..5e306fbb43
--- /dev/null
+++ b/trunk/missing/tgamma.c
@@ -0,0 +1,92 @@
+/* tgamma.c - public domain implementation of function tgamma(3m)
+
+reference - Haruhiko Okumura: C-gengo niyoru saishin algorithm jiten
+ (New Algorithm handbook in C language) (Gijyutsu hyouron
+ sha, Tokyo, 1991) [in Japanese]
+ http://oku.edu.mie-u.ac.jp/~okumura/algo/
+*/
+
+/***********************************************************
+ gamma.c -- Gamma function
+***********************************************************/
+#include "ruby/config.h"
+#include <math.h>
+#include <errno.h>
+
+#ifdef HAVE_LGAMMA_R
+
+double tgamma(double x)
+{
+ int sign;
+ double d;
+ if (x == 0.0) { /* Pole Error */
+ errno = ERANGE;
+ return 1/x < 0 ? -HUGE_VAL : HUGE_VAL;
+ }
+ if (x < 0) {
+ static double zero = 0.0;
+ double i, f;
+ f = modf(-x, &i);
+ if (f == 0.0) { /* Domain Error */
+ errno = EDOM;
+ return zero/zero;
+ }
+ }
+ d = lgamma_r(x, &sign);
+ return sign * exp(d);
+}
+
+#else
+
+#include <errno.h>
+#define PI 3.14159265358979324 /* $\pi$ */
+#define LOG_2PI 1.83787706640934548 /* $\log 2\pi$ */
+#define N 8
+
+#define B0 1 /* Bernoulli numbers */
+#define B1 (-1.0 / 2.0)
+#define B2 ( 1.0 / 6.0)
+#define B4 (-1.0 / 30.0)
+#define B6 ( 1.0 / 42.0)
+#define B8 (-1.0 / 30.0)
+#define B10 ( 5.0 / 66.0)
+#define B12 (-691.0 / 2730.0)
+#define B14 ( 7.0 / 6.0)
+#define B16 (-3617.0 / 510.0)
+
+static double
+loggamma(double x) /* the natural logarithm of the Gamma function. */
+{
+ double v, w;
+
+ v = 1;
+ while (x < N) { v *= x; x++; }
+ w = 1 / (x * x);
+ return ((((((((B16 / (16 * 15)) * w + (B14 / (14 * 13))) * w
+ + (B12 / (12 * 11))) * w + (B10 / (10 * 9))) * w
+ + (B8 / ( 8 * 7))) * w + (B6 / ( 6 * 5))) * w
+ + (B4 / ( 4 * 3))) * w + (B2 / ( 2 * 1))) / x
+ + 0.5 * LOG_2PI - log(v) - x + (x - 0.5) * log(x);
+}
+
+double tgamma(double x) /* Gamma function */
+{
+ if (x == 0.0) { /* Pole Error */
+ errno = ERANGE;
+ return 1/x < 0 ? -HUGE_VAL : HUGE_VAL;
+ }
+ if (x < 0) {
+ int sign;
+ static double zero = 0.0;
+ double i, f;
+ f = modf(-x, &i);
+ if (f == 0.0) { /* Domain Error */
+ errno = EDOM;
+ return zero/zero;
+ }
+ sign = (fmod(i, 2.0) != 0.0) ? 1 : -1;
+ return sign * PI / (sin(PI * f) * exp(loggamma(1 - x)));
+ }
+ return exp(loggamma(x));
+}
+#endif
diff --git a/trunk/missing/vsnprintf.c b/trunk/missing/vsnprintf.c
new file mode 100644
index 0000000000..17990a57fc
--- /dev/null
+++ b/trunk/missing/vsnprintf.c
@@ -0,0 +1,1201 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * IMPORTANT NOTE:
+ * --------------
+ * From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
+ * paragraph 3 above is now null and void.
+ */
+
+/* SNPRINTF.C
+ * fjc 7-31-97 Modified by Mib Software to be a standalone snprintf.c module.
+ * http://www.mibsoftware.com
+ * Mib Software does not warrant this software any differently than the
+ * University of California, Berkeley as described above. All warranties
+ * are disclaimed. Use this software at your own risk.
+ *
+ * All code referencing FILE * functions was eliminated, since it could
+ * never be called. All header files and necessary files are collapsed
+ * into one file, internal functions are declared static. This should
+ * allow inclusion into libraries with less chance of namespace collisions.
+ *
+ * snprintf should be the only externally visible item.
+ *
+ * As of 7-31-97 FLOATING_POINT is NOT provided. The code is somewhat
+ * non-portable, so it is disabled.
+ */
+
+/* Define FLOATING_POINT to get floating point. */
+/*
+#define FLOATING_POINT
+*/
+
+#include <sys/types.h>
+#define u_long unsigned long
+#define u_short unsigned short
+#define u_int unsigned int
+
+#if !defined(HAVE_STDARG_PROTOTYPES)
+#if defined(__STDC__)
+#define HAVE_STDARG_PROTOTYPES 1
+#endif
+#endif
+
+#undef __P
+#if defined(HAVE_STDARG_PROTOTYPES)
+# include <stdarg.h>
+# if !defined(__P)
+# define __P(x) x
+# endif
+#else
+# define __P(x) ()
+# if !defined(const)
+# define const
+# endif
+# include <varargs.h>
+#endif
+#ifndef _BSD_VA_LIST_
+#define _BSD_VA_LIST_ va_list
+#endif
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# ifndef LONG_MAX
+# ifdef HAVE_LIMITS_H
+# include <limits.h>
+# else
+ /* assuming 32bit(2's compliment) long */
+# define LONG_MAX 2147483647
+# endif
+# endif
+#endif
+
+#if defined(__hpux) && !defined(__GNUC__) && !defined(__STDC__)
+#define const
+#endif
+
+#if defined(sgi)
+#undef __const
+#define __const
+#endif /* People who don't like const sys_error */
+
+#include <stddef.h>
+#if defined(__hpux) && !defined(__GNUC__) || defined(__DECC)
+#include <string.h>
+#endif
+
+#if !defined(__CYGWIN32__) && defined(__hpux) && !defined(__GNUC__)
+#include <stdlib.h>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * NB: to fit things in six character monocase externals, the stdio
+ * code uses the prefix `__s' for stdio objects, typically followed
+ * by a three-character attempt at a mnemonic.
+ */
+
+/* stdio buffers */
+struct __sbuf {
+ unsigned char *_base;
+ size_t _size;
+};
+
+
+/*
+ * stdio state variables.
+ *
+ * The following always hold:
+ *
+ * if (_flags&(__SLBF|__SWR)) == (__SLBF|__SWR),
+ * _lbfsize is -_bf._size, else _lbfsize is 0
+ * if _flags&__SRD, _w is 0
+ * if _flags&__SWR, _r is 0
+ *
+ * This ensures that the getc and putc macros (or inline functions) never
+ * try to write or read from a file that is in `read' or `write' mode.
+ * (Moreover, they can, and do, automatically switch from read mode to
+ * write mode, and back, on "r+" and "w+" files.)
+ *
+ * _lbfsize is used only to make the inline line-buffered output stream
+ * code as compact as possible.
+ *
+ * _ub, _up, and _ur are used when ungetc() pushes back more characters
+ * than fit in the current _bf, or when ungetc() pushes back a character
+ * that does not match the previous one in _bf. When this happens,
+ * _ub._base becomes non-nil (i.e., a stream has ungetc() data iff
+ * _ub._base!=NULL) and _up and _ur save the current values of _p and _r.
+ *
+ * NB: see WARNING above before changing the layout of this structure!
+ */
+typedef struct __sFILE {
+ unsigned char *_p; /* current position in (some) buffer */
+#if 0
+ size_t _r; /* read space left for getc() */
+#endif
+ size_t _w; /* write space left for putc() */
+ short _flags; /* flags, below; this FILE is free if 0 */
+ short _file; /* fileno, if Unix descriptor, else -1 */
+ struct __sbuf _bf; /* the buffer (at least 1 byte, if !NULL) */
+ size_t _lbfsize; /* 0 or -_bf._size, for inline putc */
+ int (*vwrite)(/* struct __sFILE*, struct __suio * */);
+} FILE;
+
+
+#define __SLBF 0x0001 /* line buffered */
+#define __SNBF 0x0002 /* unbuffered */
+#define __SRD 0x0004 /* OK to read */
+#define __SWR 0x0008 /* OK to write */
+ /* RD and WR are never simultaneously asserted */
+#define __SRW 0x0010 /* open for reading & writing */
+#define __SEOF 0x0020 /* found EOF */
+#define __SERR 0x0040 /* found error */
+#define __SMBF 0x0080 /* _buf is from malloc */
+#define __SAPP 0x0100 /* fdopen()ed in append mode */
+#define __SSTR 0x0200 /* this is an sprintf/snprintf string */
+#define __SOPT 0x0400 /* do fseek() optimisation */
+#define __SNPT 0x0800 /* do not do fseek() optimisation */
+#define __SOFF 0x1000 /* set iff _offset is in fact correct */
+#define __SMOD 0x2000 /* true => fgetln modified _p text */
+
+
+#define EOF (-1)
+
+
+#define __sfeof(p) (((p)->_flags & __SEOF) != 0)
+#define __sferror(p) (((p)->_flags & __SERR) != 0)
+#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
+#define __sfileno(p) ((p)->_file)
+
+#undef feof
+#undef ferror
+#undef clearerr
+#define feof(p) __sfeof(p)
+#define ferror(p) __sferror(p)
+#define clearerr(p) __sclearerr(p)
+
+#ifndef _ANSI_SOURCE
+#define fileno(p) __sfileno(p)
+#endif
+
+
+/*
+ * I/O descriptors for __sfvwrite().
+ */
+struct __siov {
+ const void *iov_base;
+ size_t iov_len;
+};
+struct __suio {
+ struct __siov *uio_iov;
+ int uio_iovcnt;
+ int uio_resid;
+};
+
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_SNPRINTF)
+/*
+ * Write some memory regions. Return zero on success, EOF on error.
+ *
+ * This routine is large and unsightly, but most of the ugliness due
+ * to the three different kinds of output buffering is handled here.
+ */
+static int BSD__sfvwrite(fp, uio)
+ register FILE *fp;
+ register struct __suio *uio;
+{
+ register size_t len;
+ register char *p;
+ register struct __siov *iov;
+ register int w;
+
+ if ((len = uio->uio_resid) == 0)
+ return (0);
+#ifndef __hpux
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
+
+ iov = uio->uio_iov;
+ p = iov->iov_base;
+ len = iov->iov_len;
+ iov++;
+#define GETIOV(extra_work) \
+ while (len == 0) { \
+ extra_work; \
+ p = iov->iov_base; \
+ len = iov->iov_len; \
+ iov++; \
+ }
+ if (fp->_flags & __SNBF) {
+ /* fjc 7-31-97 Will never happen. We are working with
+ strings only
+ */
+ } else if ((fp->_flags & __SLBF) == 0) {
+ /*
+ * Fully buffered: fill partially full buffer, if any,
+ * and then flush. If there is no partial buffer, write
+ * one _bf._size byte chunk directly (without copying).
+ *
+ * String output is a special case: write as many bytes
+ * as fit, but pretend we wrote everything. This makes
+ * snprintf() return the number of bytes needed, rather
+ * than the number used, and avoids its write function
+ * (so that the write function can be invalid).
+ */
+ do {
+ GETIOV(;);
+ w = fp->_w;
+ if (fp->_flags & __SSTR) {
+ if (len < w)
+ w = len;
+ COPY(w); /* copy MIN(fp->_w,len), */
+ fp->_w -= w;
+ fp->_p += w;
+ w = len; /* but pretend copied all */
+ } else {
+ /* fjc 7-31-97 Will never happen. We are working with
+ strings only
+ */
+ }
+ p += w;
+ len -= w;
+ } while ((uio->uio_resid -= w) != 0);
+ } else {
+ /* fjc 7-31-97 Will never happen. We are working with
+ strings only
+ */
+ }
+ return (0);
+}
+#endif
+
+/*
+ * Actual printf innards.
+ *
+ * This code is large and complicated...
+ */
+
+/*
+ * Flush out all the vectors defined by the given uio,
+ * then reset it so that it can be reused.
+ */
+static int
+BSD__sprint(FILE *fp, register struct __suio *uio)
+{
+ register int err;
+
+ if (uio->uio_resid == 0) {
+ uio->uio_iovcnt = 0;
+ return (0);
+ }
+ err = (*fp->vwrite)(fp, uio);
+ uio->uio_resid = 0;
+ uio->uio_iovcnt = 0;
+ return (err);
+}
+
+
+/*
+ * Helper function for `fprintf to unbuffered unix file': creates a
+ * temporary buffer. We only work on write-only files; this avoids
+ * worries about ungetc buffers and so forth.
+ */
+static int
+BSD__sbprintf(register FILE *fp, const char *fmt, va_list ap)
+{
+/* We don't support files. */
+ return 0;
+}
+
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define to_digit(c) ((c) - '0')
+#define is_digit(c) ((unsigned)to_digit(c) <= 9)
+#define to_char(n) ((n) + '0')
+
+#ifdef _HAVE_SANE_QUAD_
+/*
+ * Convert an unsigned long long to ASCII for printf purposes, returning
+ * a pointer to the first character of the string representation.
+ * Octal numbers can be forced to have a leading zero; hex numbers
+ * use the given digits.
+ */
+static char *
+BSD__uqtoa(register u_quad_t val, char *endp, int base, int octzero, const char *xdigs)
+{
+ register char *cp = endp;
+ register long sval;
+
+ /*
+ * Handle the three cases separately, in the hope of getting
+ * better/faster code.
+ */
+ switch (base) {
+ case 10:
+ if (val < 10) { /* many numbers are 1 digit */
+ *--cp = to_char(val);
+ return (cp);
+ }
+ /*
+ * On many machines, unsigned arithmetic is harder than
+ * signed arithmetic, so we do at most one unsigned mod and
+ * divide; this is sufficient to reduce the range of
+ * the incoming value to where signed arithmetic works.
+ */
+ if (val > LLONG_MAX) {
+ *--cp = to_char(val % 10);
+ sval = val / 10;
+ } else
+ sval = val;
+ do {
+ *--cp = to_char(sval % 10);
+ sval /= 10;
+ } while (sval != 0);
+ break;
+
+ case 8:
+ do {
+ *--cp = to_char(val & 7);
+ val >>= 3;
+ } while (val);
+ if (octzero && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default: /* oops */
+ /*
+ abort();
+ */
+ break; /* fjc 7-31-97. Don't reference abort() here */
+ }
+ return (cp);
+}
+#endif /* _HAVE_SANE_QUAD_ */
+
+/*
+ * Convert an unsigned long to ASCII for printf purposes, returning
+ * a pointer to the first character of the string representation.
+ * Octal numbers can be forced to have a leading zero; hex numbers
+ * use the given digits.
+ */
+static char *
+BSD__ultoa(register u_long val, char *endp, int base, int octzero, const char *xdigs)
+{
+ register char *cp = endp;
+ register long sval;
+
+ /*
+ * Handle the three cases separately, in the hope of getting
+ * better/faster code.
+ */
+ switch (base) {
+ case 10:
+ if (val < 10) { /* many numbers are 1 digit */
+ *--cp = to_char(val);
+ return (cp);
+ }
+ /*
+ * On many machines, unsigned arithmetic is harder than
+ * signed arithmetic, so we do at most one unsigned mod and
+ * divide; this is sufficient to reduce the range of
+ * the incoming value to where signed arithmetic works.
+ */
+ if (val > LONG_MAX) {
+ *--cp = to_char(val % 10);
+ sval = val / 10;
+ } else
+ sval = val;
+ do {
+ *--cp = to_char(sval % 10);
+ sval /= 10;
+ } while (sval != 0);
+ break;
+
+ case 8:
+ do {
+ *--cp = to_char(val & 7);
+ val >>= 3;
+ } while (val);
+ if (octzero && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default: /* oops */
+ /*
+ abort();
+ */
+ break; /* fjc 7-31-97. Don't reference abort() here */
+ }
+ return (cp);
+}
+
+#ifdef FLOATING_POINT
+#include <math.h>
+/* #include "floatio.h" */
+
+#ifndef MAXEXP
+# define MAXEXP 1024
+#endif
+
+#ifndef MAXFRACT
+# define MAXFRACT 64
+#endif
+
+#define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
+#define DEFPREC 6
+
+static char *cvt __P((double, int, int, char *, int *, int, int *));
+static int exponent __P((char *, int, int));
+
+#else /* no FLOATING_POINT */
+
+#define BUF 68
+
+#endif /* FLOATING_POINT */
+
+
+/*
+ * Flags used during conversion.
+ */
+#define ALT 0x001 /* alternate form */
+#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
+#define LADJUST 0x004 /* left adjustment */
+#define LONGDBL 0x008 /* long double; unimplemented */
+#define LONGINT 0x010 /* long integer */
+
+#ifdef _HAVE_SANE_QUAD_
+#define QUADINT 0x020 /* quad integer */
+#endif /* _HAVE_SANE_QUAD_ */
+
+#define SHORTINT 0x040 /* short integer */
+#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
+#define FPT 0x100 /* Floating point number */
+static int
+BSD_vfprintf(FILE *fp, const char *fmt0, va_list ap)
+{
+ register const char *fmt; /* format string */
+ register int ch; /* character from fmt */
+ register int n; /* handy integer (short term usage) */
+ register const char *cp;/* handy char pointer (short term usage) */
+ register struct __siov *iovp;/* for PRINT macro */
+ register int flags; /* flags as above */
+ int ret; /* return value accumulator */
+ int width; /* width from format (%8d), or 0 */
+ int prec; /* precision from format (%.3d), or -1 */
+ char sign; /* sign prefix (' ', '+', '-', or \0) */
+#ifdef FLOATING_POINT
+ char softsign; /* temporary negative sign for floats */
+ double _double = 0; /* double precision arguments %[eEfgG] */
+ int expt; /* integer value of exponent */
+ int expsize = 0; /* character count for expstr */
+ int ndig = 0; /* actual number of digits returned by cvt */
+ char expstr[7]; /* buffer for exponent string */
+#endif
+ u_long ulval; /* integer arguments %[diouxX] */
+#ifdef _HAVE_SANE_QUAD_
+ u_quad_t uqval; /* %q integers */
+#endif /* _HAVE_SANE_QUAD_ */
+ int base; /* base for [diouxX] conversion */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ int fieldsz; /* field size expanded by sign, etc */
+ int realsz; /* field size expanded by dprec */
+ int size; /* size of converted field or string */
+ const char *xdigs = 0; /* digits for [xX] conversion */
+#define NIOV 8
+ struct __suio uio; /* output information: summary */
+ struct __siov iov[NIOV];/* ... and individual io vectors */
+ char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
+ char ox[2]; /* space for 0x hex-prefix */
+ char *const ebuf = buf + sizeof(buf);
+
+ /*
+ * Choose PADSIZE to trade efficiency vs. size. If larger printf
+ * fields occur frequently, increase PADSIZE and make the initializers
+ * below longer.
+ */
+#define PADSIZE 16 /* pad chunk size */
+ static const char blanks[PADSIZE] =
+ {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+ static const char zeroes[PADSIZE] =
+ {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+ /*
+ * BEWARE, these `goto error' on error, and PAD uses `n'.
+ */
+#define PRINT(ptr, len) { \
+ iovp->iov_base = (ptr); \
+ iovp->iov_len = (len); \
+ uio.uio_resid += (len); \
+ iovp++; \
+ if (++uio.uio_iovcnt >= NIOV) { \
+ if (BSD__sprint(fp, &uio)) \
+ goto error; \
+ iovp = iov; \
+ } \
+}
+#define PAD(howmany, with) { \
+ if ((n = (howmany)) > 0) { \
+ while (n > PADSIZE) { \
+ PRINT(with, PADSIZE); \
+ n -= PADSIZE; \
+ } \
+ PRINT(with, n); \
+ } \
+}
+#define FLUSH() { \
+ if (uio.uio_resid && BSD__sprint(fp, &uio)) \
+ goto error; \
+ uio.uio_iovcnt = 0; \
+ iovp = iov; \
+}
+
+ /*
+ * To extend shorts properly, we need both signed and unsigned
+ * argument extraction methods.
+ */
+#define SARG() \
+ (flags&LONGINT ? va_arg(ap, long) : \
+ flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
+ (long)va_arg(ap, int))
+#define UARG() \
+ (flags&LONGINT ? va_arg(ap, u_long) : \
+ flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
+ (u_long)va_arg(ap, u_int))
+
+ /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+ fp->_file >= 0)
+ return (BSD__sbprintf(fp, fmt0, ap));
+
+ fmt = fmt0;
+ uio.uio_iov = iovp = iov;
+ uio.uio_resid = 0;
+ uio.uio_iovcnt = 0;
+ ret = 0;
+ xdigs = 0;
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+ /* void */;
+ if ((n = fmt - cp) != 0) {
+ PRINT(cp, n);
+ ret += n;
+ }
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ sign = '\0';
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ /*
+ * ``If the space and + flags both appear, the space
+ * flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (!sign)
+ sign = ' ';
+ goto rflag;
+ case '#':
+ flags |= ALT;
+ goto rflag;
+ case '*':
+ /*
+ * ``A negative field width argument is taken as a
+ * - flag followed by a positive field width.''
+ * -- ANSI X3J11
+ * They don't exclude field widths read from args.
+ */
+ if ((width = va_arg(ap, int)) >= 0)
+ goto rflag;
+ width = -width;
+ /* FALLTHROUGH */
+ case '-':
+ flags |= LADJUST;
+ goto rflag;
+ case '+':
+ sign = '+';
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ n = va_arg(ap, int);
+ prec = n < 0 ? -1 : n;
+ goto rflag;
+ }
+ n = 0;
+ while (is_digit(ch)) {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ }
+ prec = n < 0 ? -1 : n;
+ goto reswitch;
+ case '0':
+ /*
+ * ``Note that 0 is taken as a flag, not as the
+ * beginning of a field width.''
+ * -- ANSI X3J11
+ */
+ flags |= ZEROPAD;
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ width = n;
+ goto reswitch;
+#ifdef FLOATING_POINT
+ case 'L':
+ flags |= LONGDBL;
+ goto rflag;
+#endif
+ case 'h':
+ flags |= SHORTINT;
+ goto rflag;
+ case 'l':
+ flags |= LONGINT;
+ goto rflag;
+#ifdef _HAVE_SANE_QUAD_
+ case 'q':
+ flags |= QUADINT;
+ goto rflag;
+#endif /* _HAVE_SANE_QUAD_ */
+ case 'c':
+ cp = buf;
+ *buf = (char)va_arg(ap, int);
+ size = 1;
+ sign = '\0';
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+#ifdef _HAVE_SANE_QUAD_
+ if (flags & QUADINT) {
+ uqval = va_arg(ap, quad_t);
+ if ((quad_t)uqval < 0) {
+ uqval = -uqval;
+ sign = '-';
+ }
+ } else
+#endif /* _HAVE_SANE_QUAD_ */
+ {
+ ulval = SARG();
+ if ((long)ulval < 0) {
+ ulval = -ulval;
+ sign = '-';
+ }
+ }
+ base = 10;
+ goto number;
+#ifdef FLOATING_POINT
+ case 'e': /* anomalous precision */
+ case 'E':
+ prec = (prec == -1) ?
+ DEFPREC + 1 : prec + 1;
+ /* FALLTHROUGH */
+ goto fp_begin;
+ case 'f': /* always print trailing zeroes */
+ if (prec != 0)
+ flags |= ALT;
+ case 'g':
+ case 'G':
+ if (prec == -1)
+ prec = DEFPREC;
+fp_begin: _double = va_arg(ap, double);
+ /* do this before tricky precision changes */
+ if (isinf(_double)) {
+ if (_double < 0)
+ sign = '-';
+ cp = "Inf";
+ size = 3;
+ break;
+ }
+ if (isnan(_double)) {
+ cp = "NaN";
+ size = 3;
+ break;
+ }
+ flags |= FPT;
+ cp = cvt(_double, prec, flags, &softsign,
+ &expt, ch, &ndig);
+ if (ch == 'g' || ch == 'G') {
+ if (expt <= -4 || expt > prec)
+ ch = (ch == 'g') ? 'e' : 'E';
+ else
+ ch = 'g';
+ }
+ if (ch <= 'e') { /* 'e' or 'E' fmt */
+ --expt;
+ expsize = exponent(expstr, expt, ch);
+ size = expsize + ndig;
+ if (ndig > 1 || flags & ALT)
+ ++size;
+ } else if (ch == 'f') { /* f fmt */
+ if (expt > 0) {
+ size = expt;
+ if (prec || flags & ALT)
+ size += prec + 1;
+ } else /* "0.X" */
+ size = prec + 2;
+ } else if (expt >= ndig) { /* fixed g fmt */
+ size = expt;
+ if (flags & ALT)
+ ++size;
+ } else
+ size = ndig + (expt > 0 ?
+ 1 : 2 - expt);
+
+ if (softsign)
+ sign = '-';
+ break;
+#endif /* FLOATING_POINT */
+ case 'n':
+#ifdef _HAVE_SANE_QUAD_
+ if (flags & QUADINT)
+ *va_arg(ap, quad_t *) = ret;
+ else if (flags & LONGINT)
+#else /* _HAVE_SANE_QUAD_ */
+ if (flags & LONGINT)
+#endif /* _HAVE_SANE_QUAD_ */
+ *va_arg(ap, long *) = ret;
+ else if (flags & SHORTINT)
+ *va_arg(ap, short *) = ret;
+ else
+ *va_arg(ap, int *) = ret;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+#ifdef _HAVE_SANE_QUAD_
+ if (flags & QUADINT)
+ uqval = va_arg(ap, u_quad_t);
+ else
+#endif /* _HAVE_SANE_QUAD_ */
+ ulval = UARG();
+ base = 8;
+ goto nosign;
+ case 'p':
+ /*
+ * ``The argument shall be a pointer to void. The
+ * value of the pointer is converted to a sequence
+ * of printable characters, in an implementation-
+ * defined manner.''
+ * -- ANSI X3J11
+ */
+ prec = sizeof(void*)*CHAR_BIT/4;
+#ifdef _HAVE_LLP64_
+ uqval = (u_long)va_arg(ap, void *);
+ flags = (flags) | QUADINT | HEXPREFIX;
+#else
+ ulval = (u_long)va_arg(ap, void *);
+#ifdef _HAVE_SANE_QUAD_
+ flags = (flags & ~QUADINT) | HEXPREFIX;
+#else /* _HAVE_SANE_QUAD_ */
+ flags = (flags) | HEXPREFIX;
+#endif /* _HAVE_SANE_QUAD_ */
+#endif
+ base = 16;
+ xdigs = "0123456789abcdef";
+ ch = 'x';
+ goto nosign;
+ case 's':
+ if ((cp = va_arg(ap, char *)) == NULL)
+ cp = "(null)";
+ if (prec >= 0) {
+ /*
+ * can't use strlen; can only look for the
+ * NUL in the first `prec' characters, and
+ * strlen() will go further.
+ */
+ const char *p = (char *)memchr(cp, 0, prec);
+
+ if (p != NULL) {
+ size = p - cp;
+ if (size > prec)
+ size = prec;
+ } else
+ size = prec;
+ } else
+ size = strlen(cp);
+ sign = '\0';
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+#ifdef _HAVE_SANE_QUAD_
+ if (flags & QUADINT)
+ uqval = va_arg(ap, u_quad_t);
+ else
+#endif /* _HAVE_SANE_QUAD_ */
+ ulval = UARG();
+ base = 10;
+ goto nosign;
+ case 'X':
+ xdigs = "0123456789ABCDEF";
+ goto hex;
+ case 'x':
+ xdigs = "0123456789abcdef";
+hex:
+#ifdef _HAVE_SANE_QUAD_
+ if (flags & QUADINT)
+ uqval = va_arg(ap, u_quad_t);
+ else
+#endif /* _HAVE_SANE_QUAD_ */
+ ulval = UARG();
+ base = 16;
+ /* leading 0x/X only if non-zero */
+ if (flags & ALT &&
+#ifdef _HAVE_SANE_QUAD_
+ (flags & QUADINT ? uqval != 0 : ulval != 0)
+#else /* _HAVE_SANE_QUAD_ */
+ ulval != 0
+#endif /* _HAVE_SANE_QUAD_ */
+ )
+ flags |= HEXPREFIX;
+
+ /* unsigned conversions */
+nosign: sign = '\0';
+ /*
+ * ``... diouXx conversions ... if a precision is
+ * specified, the 0 flag will be ignored.''
+ * -- ANSI X3J11
+ */
+number: if ((dprec = prec) >= 0)
+ flags &= ~ZEROPAD;
+
+ /*
+ * ``The result of converting a zero value with an
+ * explicit precision of zero is no characters.''
+ * -- ANSI X3J11
+ */
+#ifdef _HAVE_SANE_QUAD_
+ if (flags & QUADINT) {
+ if (uqval != 0 || prec != 0)
+ cp = BSD__uqtoa(uqval, ebuf, base,
+ flags & ALT, xdigs);
+ } else
+#else /* _HAVE_SANE_QUAD_ */
+#endif /* _HAVE_SANE_QUAD_ */
+ {
+ if (ulval != 0 || prec != 0)
+ cp = BSD__ultoa(ulval, ebuf, base,
+ flags & ALT, xdigs);
+ }
+ size = ebuf - cp;
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ /* pretend it was %c with argument ch */
+ cp = buf;
+ *buf = ch;
+ size = 1;
+ sign = '\0';
+ break;
+ }
+
+ /*
+ * All reasonable formats wind up here. At this point, `cp'
+ * points to a string which (if not flags&LADJUST) should be
+ * padded out to `width' places. If flags&ZEROPAD, it should
+ * first be prefixed by any sign or other prefix; otherwise,
+ * it should be blank padded before the prefix is emitted.
+ * After any left-hand padding and prefixing, emit zeroes
+ * required by a decimal [diouxX] precision, then print the
+ * string proper, then emit zeroes required by any leftover
+ * floating precision; finally, if LADJUST, pad with blanks.
+ *
+ * Compute actual size, so we know how much to pad.
+ * fieldsz excludes decimal prec; realsz includes it.
+ */
+ fieldsz = size;
+ if (sign)
+ fieldsz++;
+ else if (flags & HEXPREFIX)
+ fieldsz += 2;
+ realsz = dprec > fieldsz ? dprec : fieldsz;
+
+ /* right-adjusting blank padding */
+ if ((flags & (LADJUST|ZEROPAD)) == 0)
+ PAD(width - realsz, blanks);
+
+ /* prefix */
+ if (sign) {
+ PRINT(&sign, 1);
+ } else if (flags & HEXPREFIX) {
+ ox[0] = '0';
+ ox[1] = ch;
+ PRINT(ox, 2);
+ }
+
+ /* right-adjusting zero padding */
+ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+ PAD(width - realsz, zeroes);
+
+ /* leading zeroes from decimal precision */
+ PAD(dprec - fieldsz, zeroes);
+
+ /* the string or number proper */
+#ifdef FLOATING_POINT
+ if ((flags & FPT) == 0) {
+ PRINT(cp, size);
+ } else { /* glue together f_p fragments */
+ if (ch >= 'f') { /* 'f' or 'g' */
+ if (_double == 0) {
+ /* kludge for __dtoa irregularity */
+ if (prec == 0 ||
+ (flags & ALT) == 0) {
+ PRINT("0", 1);
+ } else {
+ PRINT("0.", 2);
+ PAD(ndig - 1, zeroes);
+ }
+ } else if (expt <= 0) {
+ PRINT("0.", 2);
+ PAD(-expt, zeroes);
+ PRINT(cp, ndig);
+ } else if (expt >= ndig) {
+ PRINT(cp, ndig);
+ PAD(expt - ndig, zeroes);
+ if (flags & ALT)
+ PRINT(".", 1);
+ } else {
+ PRINT(cp, expt);
+ cp += expt;
+ PRINT(".", 1);
+ PRINT(cp, ndig-expt);
+ }
+ } else { /* 'e' or 'E' */
+ if (ndig > 1 || flags & ALT) {
+ ox[0] = *cp++;
+ ox[1] = '.';
+ PRINT(ox, 2);
+ if (_double || flags & ALT == 0) {
+ PRINT(cp, ndig-1);
+ } else /* 0.[0..] */
+ /* __dtoa irregularity */
+ PAD(ndig - 1, zeroes);
+ } else /* XeYYY */
+ PRINT(cp, 1);
+ PRINT(expstr, expsize);
+ }
+ }
+#else
+ PRINT(cp, size);
+#endif
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD(width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += width > realsz ? width : realsz;
+
+ FLUSH(); /* copy out the I/O vectors */
+ }
+done:
+ FLUSH();
+error:
+ return (__sferror(fp) ? EOF : ret);
+ /* NOTREACHED */
+}
+
+#ifdef FLOATING_POINT
+
+extern char *BSD__dtoa __P((double, int, int, int *, int *, char **));
+
+static char *
+cvt(value, ndigits, flags, sign, decpt, ch, length)
+ double value;
+ int ndigits, flags, *decpt, ch, *length;
+ char *sign;
+{
+ int mode, dsgn;
+ char *digits, *bp, *rve;
+
+ if (ch == 'f')
+ mode = 3;
+ else {
+ mode = 2;
+ }
+ if (value < 0) {
+ value = -value;
+ *sign = '-';
+ } else if (value == 0.0 && 1.0/value < 0) {
+ *sign = '-';
+ } else {
+ *sign = '\000';
+ }
+ digits = BSD__dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
+ if (flags & ALT) { /* Print trailing zeros */
+ bp = digits + ndigits;
+ if (ch == 'f') {
+ if (*digits == '0' && value)
+ *decpt = -ndigits + 1;
+ bp += *decpt;
+ }
+ if (value == 0) /* kludge for __dtoa irregularity */
+ rve = bp;
+ while (rve < bp)
+ *rve++ = '0';
+ }
+ *length = rve - digits;
+ return (digits);
+}
+
+static int
+exponent(p0, exp, fmtch)
+ char *p0;
+ int exp, fmtch;
+{
+ register char *p, *t;
+ char expbuf[MAXEXP];
+
+ p = p0;
+ *p++ = fmtch;
+ if (exp < 0) {
+ exp = -exp;
+ *p++ = '-';
+ }
+ else
+ *p++ = '+';
+ t = expbuf + MAXEXP;
+ if (exp > 9) {
+ do {
+ *--t = to_char(exp % 10);
+ } while ((exp /= 10) > 9);
+ *--t = to_char(exp);
+ for (; t < expbuf + MAXEXP; *p++ = *t++);
+ }
+ else {
+ *p++ = '0';
+ *p++ = to_char(exp);
+ }
+ return (p - p0);
+}
+#endif /* FLOATING_POINT */
+
+#ifndef HAVE_VSNPRINTF
+int
+vsnprintf(str, n, fmt, ap)
+ char *str;
+ size_t n;
+ const char *fmt;
+ _BSD_VA_LIST_ ap;
+{
+ int ret;
+ FILE f;
+
+ if ((int)n < 1)
+ return (EOF);
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n - 1;
+ f.vwrite = BSD__sfvwrite;
+ ret = BSD_vfprintf(&f, fmt, ap);
+ *f._p = 0;
+ return (ret);
+}
+#endif
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)snprintf.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#ifndef HAVE_SNPRINTF
+int
+#if defined(HAVE_STDARG_PROTOTYPES)
+snprintf(char *str, size_t n, char const *fmt, ...)
+#else
+snprintf(str, n, fmt, va_alist)
+char *str, *fmt;
+size_t n;
+va_dcl
+#endif
+{
+ int ret;
+ va_list ap;
+ FILE f;
+
+ if ((int)n < 1)
+ return (EOF);
+
+#if defined(HAVE_STDARG_PROTOTYPES)
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ f._flags = __SWR | __SSTR;
+ f._bf._base = f._p = (unsigned char *)str;
+ f._bf._size = f._w = n - 1;
+ f.vwrite = BSD__sfvwrite;
+ ret = BSD_vfprintf(&f, fmt, ap);
+ *f._p = 0;
+ va_end(ap);
+ return (ret);
+}
+#endif
diff --git a/trunk/missing/x68.c b/trunk/missing/x68.c
new file mode 100644
index 0000000000..ece840d9ce
--- /dev/null
+++ b/trunk/missing/x68.c
@@ -0,0 +1,40 @@
+/* x68 compatibility functions -- follows Ruby's license */
+
+#include "ruby/config.h"
+
+#if !HAVE_SELECT
+#include "x68/select.c"
+#endif
+#if MISSING__DTOS18
+#include "x68/_dtos18.c"
+#endif
+#if MISSING_FCONVERT
+#include "x68/_round.c"
+#include "x68/fconvert.c"
+#endif
+
+/* missing some basic syscalls */
+int
+link(const char *src, const char *dst)
+{
+ return symlink(src, dst);
+}
+
+#ifndef HAVE_GETTIMEOFDAY
+#include <time.h>
+#include <sys/time.h>
+
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+
+int
+gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ tv->tv_sec = (long)time((time_t*)0);
+ tv->tv_usec = 0;
+
+ return 0;
+}
+#endif