diff options
Diffstat (limited to 'util.c')
| -rw-r--r-- | util.c | 1096 |
1 files changed, 609 insertions, 487 deletions
@@ -2,15 +2,18 @@ util.c - - $Author: nobu $ - $Date: 2006/07/18 01:55:15 $ + $Author$ created at: Fri Mar 10 17:22:34 JST 1995 - Copyright (C) 1993-2003 Yukihiro Matsumoto + Copyright (C) 1993-2008 Yukihiro Matsumoto **********************************************************************/ -#include "ruby.h" +#if defined __MINGW32__ || defined __MINGW64__ +#define MINGW_HAS_SECURE_API 1 +#endif + +#include "internal.h" #include <ctype.h> #include <stdio.h> @@ -22,16 +25,13 @@ #include "missing/file.h" #endif -#include "util.h" -#ifndef HAVE_STRING_H -char *strchr _((char*,char)); -#endif +#include "ruby/util.h" + +const char ruby_hexdigits[] = "0123456789abcdef0123456789ABCDEF"; +#define hexdigit ruby_hexdigits unsigned long -scan_oct(start, len, retlen) - const char *start; - int len; - int *retlen; +ruby_scan_oct(const char *start, size_t len, size_t *retlen) { register const char *s = start; register unsigned long retval = 0; @@ -40,416 +40,283 @@ scan_oct(start, len, retlen) retval <<= 3; retval |= *s++ - '0'; } - *retlen = s - start; + *retlen = (int)(s - start); /* less than len */ return retval; } unsigned long -scan_hex(start, len, retlen) - const char *start; - int len; - int *retlen; +ruby_scan_hex(const char *start, size_t len, size_t *retlen) { - static char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; register const char *s = start; register unsigned long retval = 0; - char *tmp; + const char *tmp; while (len-- && *s && (tmp = strchr(hexdigit, *s))) { retval <<= 4; retval |= (tmp - hexdigit) & 15; s++; } - *retlen = s - start; + *retlen = (int)(s - start); /* less than len */ return retval; } -#include <sys/types.h> -#include <sys/stat.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#if defined(HAVE_FCNTL_H) -#include <fcntl.h> -#endif - -#ifndef S_ISDIR -# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) -#endif - -#if defined(MSDOS) || defined(__CYGWIN32__) || defined(_WIN32) -/* - * Copyright (c) 1993, Intergraph Corporation - * - * You may distribute under the terms of either the GNU General Public - * License or the Artistic License, as specified in the perl README file. - * - * Various Unix compatibility functions and NT specific functions. - * - * Some of this code was derived from the MSDOS port(s) and the OS/2 port. - * - */ - - -/* - * Suffix appending for in-place editing under MS-DOS and OS/2 (and now NT!). - * - * Here are the rules: - * - * Style 0: Append the suffix exactly as standard perl would do it. - * If the filesystem groks it, use it. (HPFS will always - * grok it. So will NTFS. FAT will rarely accept it.) - * - * Style 1: The suffix begins with a '.'. The extension is replaced. - * If the name matches the original name, use the fallback method. - * - * Style 2: The suffix is a single character, not a '.'. Try to add the - * suffix to the following places, using the first one that works. - * [1] Append to extension. - * [2] Append to filename, - * [3] Replace end of extension, - * [4] Replace end of filename. - * If the name matches the original name, use the fallback method. - * - * Style 3: Any other case: Ignore the suffix completely and use the - * fallback method. - * - * Fallback method: Change the extension to ".$$$". If that matches the - * original name, then change the extension to ".~~~". - * - * If filename is more than 1000 characters long, we die a horrible - * death. Sorry. - * - * The filename restriction is a cheat so that we can use buf[] to store - * assorted temporary goo. - * - * Examples, assuming style 0 failed. - * - * suffix = ".bak" (style 1) - * foo.bar => foo.bak - * foo.bak => foo.$$$ (fallback) - * foo.$$$ => foo.~~~ (fallback) - * makefile => makefile.bak - * - * suffix = "~" (style 2) - * foo.c => foo.c~ - * foo.c~ => foo.c~~ - * foo.c~~ => foo~.c~~ - * foo~.c~~ => foo~~.c~~ - * foo~~~~~.c~~ => foo~~~~~.$$$ (fallback) - * - * foo.pas => foo~.pas - * makefile => makefile.~ - * longname.fil => longname.fi~ - * longname.fi~ => longnam~.fi~ - * longnam~.fi~ => longnam~.$$$ - * - */ - - -static int valid_filename(char *s); - -static char suffix1[] = ".$$$"; -static char suffix2[] = ".~~~"; - -#define ext (&buf[1000]) - -#define strEQ(s1,s2) (strcmp(s1,s2) == 0) +const signed char ruby_digit36_to_number_table[] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /*0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*1*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*2*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*3*/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + /*4*/ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + /*5*/ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + /*6*/ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + /*7*/ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + /*8*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*9*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*a*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*b*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*c*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*d*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*e*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + /*f*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +}; -void -ruby_add_suffix(str, suffix) - VALUE str; - char *suffix; +unsigned long +ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow) { - int baselen; - int extlen = strlen(suffix); - char *s, *t, *p; - long slen; - char buf[1024]; - - if (RSTRING(str)->len > 1000) - rb_fatal("Cannot do inplace edit on long filename (%ld characters)", - RSTRING(str)->len); -#if defined(DJGPP) || defined(__CYGWIN32__) || defined(_WIN32) - /* Style 0 */ - slen = RSTRING(str)->len; - rb_str_cat(str, suffix, extlen); -#if defined(DJGPP) - if (_USE_LFN) return; -#else - if (valid_filename(RSTRING(str)->ptr)) return; -#endif + const char *start = str; + unsigned long ret = 0, x; + unsigned long mul_overflow = (~(unsigned long)0) / base; - /* Fooey, style 0 failed. Fix str before continuing. */ - RSTRING(str)->ptr[RSTRING(str)->len = slen] = '\0'; -#endif + *overflow = 0; - slen = extlen; - t = buf; baselen = 0; s = RSTRING(str)->ptr; - while ((*t = *s) && *s != '.') { - baselen++; - if (*s == '\\' || *s == '/') baselen = 0; - s++; t++; + if (!len) { + *retlen = 0; + return 0; } - p = t; - t = ext; extlen = 0; - while (*t++ = *s++) extlen++; - if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; } - - if (*suffix == '.') { /* Style 1 */ - if (strEQ(ext, suffix)) goto fallback; - strcpy(p, suffix); - } - else if (suffix[1] == '\0') { /* Style 2 */ - if (extlen < 4) { - ext[extlen] = *suffix; - ext[++extlen] = '\0'; + do { + int d = ruby_digit36_to_number_table[(unsigned char)*str++]; + if (d == -1 || base <= d) { + --str; + break; } - else if (baselen < 8) { - *p++ = *suffix; - } - else if (ext[3] != *suffix) { - ext[3] = *suffix; - } - else if (buf[7] != *suffix) { - buf[7] = *suffix; - } - else goto fallback; - strcpy(p, ext); - } - else { /* Style 3: Panic */ -fallback: - (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5); - } - rb_str_resize(str, strlen(buf)); - memcpy(RSTRING(str)->ptr, buf, RSTRING(str)->len); + if (mul_overflow < ret) + *overflow = 1; + ret *= base; + x = ret; + ret += d; + if (ret < x) + *overflow = 1; + } while (len < 0 || --len); + *retlen = str - start; + return ret; } -#if defined(__CYGWIN32__) || defined(_WIN32) -static int -valid_filename(char *s) +unsigned long +ruby_strtoul(const char *str, char **endptr, int base) { - int fd; - - /* - // if the file exists, then it's a valid filename! - */ - - if (_access(s, 0) == 0) { - return 1; + int c, b, overflow; + int sign = 0; + size_t len; + unsigned long ret; + const char *subject_found = str; + + if (base == 1 || 36 < base) { + errno = EINVAL; + return 0; } - /* - // It doesn't exist, so see if we can open it. - */ + while ((c = *str) && ISSPACE(c)) + str++; - if ((fd = _open(s, O_CREAT, 0666)) >= 0) { - _close(fd); - _unlink(s); /* don't leave it laying around */ - return 1; + if (c == '+') { + sign = 1; + str++; + } + else if (c == '-') { + sign = -1; + str++; } - return 0; -} -#endif -#endif -#if defined __DJGPP__ + if (str[0] == '0') { + subject_found = str+1; + if (base == 0 || base == 16) { + if (str[1] == 'x' || str[1] == 'X') { + b = 16; + str += 2; + } + else { + b = base == 0 ? 8 : 16; + str++; + } + } + else { + b = base; + str++; + } + } + else { + b = base == 0 ? 10 : base; + } -#include <dpmi.h> + ret = ruby_scan_digits(str, -1, b, &len, &overflow); -static char dbcs_table[256]; + if (0 < len) + subject_found = str+len; -int -make_dbcs_table() -{ - __dpmi_regs r; - struct { - unsigned char start; - unsigned char end; - } vec; - int offset; - - memset(&r, 0, sizeof(r)); - r.x.ax = 0x6300; - __dpmi_int(0x21, &r); - offset = r.x.ds * 16 + r.x.si; + if (endptr) + *endptr = (char*)subject_found; - for (;;) { - int i; - dosmemget(offset, sizeof vec, &vec); - if (!vec.start && !vec.end) - break; - for (i = vec.start; i <= vec.end; i++) - dbcs_table[i] = 1; - offset += 2; + if (overflow) { + errno = ERANGE; + return ULONG_MAX; } -} -int -mblen(const char *s, size_t n) -{ - static int need_init = 1; - if (need_init) { - make_dbcs_table(); - need_init = 0; - } - if (s) { - if (n == 0 || *s == 0) - return 0; - else if (!s[1]) - return 1; - return dbcs_table[(unsigned char)*s] + 1; + if (sign < 0) { + ret = (unsigned long)(-(long)ret); + return ret; + } + else { + return ret; } - else - return 1; } -struct PathList { - struct PathList *next; - char *path; -}; +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#if defined(HAVE_FCNTL_H) +#include <fcntl.h> +#endif -struct PathInfo { - struct PathList *head; - int count; +#ifndef S_ISDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +#if !defined HAVE_BSD_QSORT_R && defined HAVE_QSORT_S +# define qsort_r(base, nel, size, arg, cmp) qsort_s(base, nel, size, cmp, arg) +# define cmp_bsd_qsort cmp_ms_qsort +# define HAVE_BSD_QSORT_R 1 +#endif +#if defined HAVE_BSD_QSORT_R +typedef int (cmpfunc_t)(const void*, const void*, void*); + +struct bsd_qsort_r_args { + cmpfunc_t *cmp; + void *arg; }; -static void -push_element(const char *path, VALUE vinfo) +static int +cmp_bsd_qsort(void *d, const void *a, const void *b) { - struct PathList *p; - struct PathInfo *info = (struct PathInfo *)vinfo; - - p = ALLOC(struct PathList); - MEMZERO(p, struct PathList, 1); - p->path = ruby_strdup(path); - p->next = info->head; - info->head = p; - info->count++; + const struct bsd_qsort_r_args *args = d; + return (*args->cmp)(a, b, args->arg); } -#include <dirent.h> -int __opendir_flags = __OPENDIR_PRESERVE_CASE; - -char ** -__crt0_glob_function(char *path) +void +ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void *d) { - int len = strlen(path); - int i; - char **rv; - char path_buffer[PATH_MAX]; - char *buf = path_buffer; - char *p; - struct PathInfo info; - struct PathList *plist; - - if (PATH_MAX <= len) - buf = ruby_xmalloc(len + 1); - - strncpy(buf, path, len); - buf[len] = '\0'; - - for (p = buf; *p; p += mblen(p, MB_CUR_MAX)) - if (*p == '\\') - *p = '/'; - - info.count = 0; - info.head = 0; - - rb_globi(buf, push_element, (VALUE)&info); - - if (buf != path_buffer) - ruby_xfree(buf); - - if (info.count == 0) - return 0; - - rv = ruby_xmalloc((info.count + 1) * sizeof (char *)); - - plist = info.head; - i = 0; - while (plist) { - struct PathList *cur; - rv[i] = plist->path; - cur = plist; - plist = plist->next; - ruby_xfree(cur); - i++; - } - rv[i] = 0; - return rv; + struct bsd_qsort_r_args args; + args.cmp = cmp; + args.arg = d; + qsort_r(base, nel, size, &args, cmp_bsd_qsort); } - -#endif - +#elif !defined HAVE_GNU_QSORT_R /* mm.c */ -#define A ((int*)a) -#define B ((int*)b) -#define C ((int*)c) -#define D ((int*)d) +#define mmtype long +#define mmcount (16 / SIZEOF_LONG) +#define A ((mmtype*)a) +#define B ((mmtype*)b) +#define C ((mmtype*)c) +#define D ((mmtype*)d) +#define mmstep (sizeof(mmtype) * mmcount) #define mmprepare(base, size) do {\ - if (((long)base & (0x3)) == 0)\ - if (size >= 16) mmkind = 1;\ - else mmkind = 0;\ - else mmkind = -1;\ - high = (size & (~0xf));\ - low = (size & 0x0c);\ + if (((VALUE)(base) % sizeof(mmtype)) == 0 && ((size) % sizeof(mmtype)) == 0) \ + if ((size) >= mmstep) mmkind = 1;\ + else mmkind = 0;\ + else mmkind = -1;\ + high = ((size) / mmstep) * mmstep;\ + low = ((size) % mmstep);\ } while (0)\ #define mmarg mmkind, size, high, low +#define mmargdecl int mmkind, size_t size, size_t high, size_t low -static void mmswap_(a, b, mmarg) - register char *a, *b; - int mmarg; +static void mmswap_(register char *a, register char *b, mmargdecl) { - register int s; if (a == b) return; if (mmkind >= 0) { + register mmtype s; +#if mmcount > 1 if (mmkind > 0) { register char *t = a + high; do { s = A[0]; A[0] = B[0]; B[0] = s; s = A[1]; A[1] = B[1]; B[1] = s; +#if mmcount > 2 s = A[2]; A[2] = B[2]; B[2] = s; - s = A[3]; A[3] = B[3]; B[3] = s; a += 16; b += 16; +#if mmcount > 3 + s = A[3]; A[3] = B[3]; B[3] = s; +#endif +#endif + a += mmstep; b += mmstep; } while (a < t); } +#endif if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = s; - if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = s; - if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}} +#if mmcount > 2 + if (low >= 2 * sizeof(mmtype)) { s = A[1]; A[1] = B[1]; B[1] = s; +#if mmcount > 3 + if (low >= 3 * sizeof(mmtype)) {s = A[2]; A[2] = B[2]; B[2] = s;} +#endif + } +#endif + } } else { - register char *t = a + size; + register char *t = a + size, s; do {s = *a; *a++ = *b; *b++ = s;} while (a < t); } } #define mmswap(a,b) mmswap_((a),(b),mmarg) -static void mmrot3_(a, b, c, mmarg) - register char *a, *b, *c; - int mmarg; +/* a, b, c = b, c, a */ +static void mmrot3_(register char *a, register char *b, register char *c, mmargdecl) { - register int s; if (mmkind >= 0) { + register mmtype s; +#if mmcount > 1 if (mmkind > 0) { register char *t = a + high; do { s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s; s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s; +#if mmcount > 2 s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s; - s = A[3]; A[3] = B[3]; B[3] = C[3]; C[3] = s; a += 16; b += 16; c += 16; +#if mmcount > 3 + s = A[3]; A[3] = B[3]; B[3] = C[3]; C[3] = s; +#endif +#endif + a += mmstep; b += mmstep; c += mmstep; } while (a < t); } +#endif if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s; - if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s; - if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;}}} +#if mmcount > 2 + if (low >= 2 * sizeof(mmtype)) { s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s; +#if mmcount > 3 + if (low == 3 * sizeof(mmtype)) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;} +#endif + } +#endif + } } else { - register char *t = a + size; + register char *t = a + size, s; do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t); } } @@ -466,26 +333,26 @@ static void mmrot3_(a, b, c, mmarg) typedef struct { char *LL, *RR; } stack_node; /* Stack structure for L,l,R,r */ #define PUSH(ll,rr) do { top->LL = (ll); top->RR = (rr); ++top; } while (0) /* Push L,l,R,r */ -#define POP(ll,rr) do { --top; ll = top->LL; rr = top->RR; } while (0) /* Pop L,l,R,r */ - -#define med3(a,b,c) ((*cmp)(a,b,d)<0 ? \ - ((*cmp)(b,c,d)<0 ? b : ((*cmp)(a,c,d)<0 ? c : a)) : \ - ((*cmp)(b,c,d)>0 ? b : ((*cmp)(a,c,d)<0 ? a : c))) - -void ruby_qsort (base, nel, size, cmp, d) - void* base; - const int nel; - const int size; - int (*cmp)(); - void *d; +#define POP(ll,rr) do { --top; (ll) = top->LL; (rr) = top->RR; } while (0) /* Pop L,l,R,r */ + +#define med3(a,b,c) ((*cmp)((a),(b),d)<0 ? \ + ((*cmp)((b),(c),d)<0 ? (b) : ((*cmp)((a),(c),d)<0 ? (c) : (a))) : \ + ((*cmp)((b),(c),d)>0 ? (b) : ((*cmp)((a),(c),d)<0 ? (a) : (c)))) + +typedef int (cmpfunc_t)(const void*, const void*, void*); +void +ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void *d) { register char *l, *r, *m; /* l,r:left,right group m:median point */ - register int t, eq_l, eq_r; /* eq_l: all items in left group are equal to S */ - char *L = base; /* left end of curren region */ + register int t, eq_l, eq_r; /* eq_l: all items in left group are equal to S */ + char *L = base; /* left end of current region */ char *R = (char*)base + size*(nel-1); /* right end of current region */ - int chklim = 63; /* threshold of ordering element check */ - stack_node stack[32], *top = stack; /* 32 is enough for 32bit CPU */ - int mmkind, high, low; + size_t chklim = 63; /* threshold of ordering element check */ + enum {size_bits = sizeof(size) * CHAR_BIT}; + stack_node stack[size_bits]; /* enough for size_t size */ + stack_node *top = stack; + int mmkind; + size_t high, low, n; if (nel <= 1) return; /* need not to sort */ mmprepare(base, size); @@ -502,29 +369,29 @@ void ruby_qsort (base, nel, size, cmp, d) } l = L; r = R; - t = (r - l + size) / size; /* number of elements */ - m = l + size * (t >> 1); /* calculate median value */ + n = (r - l + size) / size; /* number of elements */ + m = l + size * (n >> 1); /* calculate median value */ - if (t >= 60) { + if (n >= 60) { register char *m1; register char *m3; - if (t >= 200) { - t = size*(t>>3); /* number of bytes in splitting 8 */ + if (n >= 200) { + n = size*(n>>3); /* number of bytes in splitting 8 */ { - register char *p1 = l + t; - register char *p2 = p1 + t; - register char *p3 = p2 + t; + register char *p1 = l + n; + register char *p2 = p1 + n; + register char *p3 = p2 + n; m1 = med3(p1, p2, p3); - p1 = m + t; - p2 = p1 + t; - p3 = p2 + t; + p1 = m + n; + p2 = p1 + n; + p3 = p2 + n; m3 = med3(p1, p2, p3); } } else { - t = size*(t>>2); /* number of bytes in splitting 4 */ - m1 = l + t; - m3 = m + t; + n = size*(n>>2); /* number of bytes in splitting 4 */ + m1 = l + n; + m3 = m + n; } m = med3(m1, m, m3); } @@ -623,13 +490,13 @@ void ruby_qsort (base, nel, size, cmp, d) else goto nxt; /* need not to sort both sides */ } } +#endif /* HAVE_GNU_QSORT_R */ char * -ruby_strdup(str) - const char *str; +ruby_strdup(const char *str) { char *tmp; - int len = strlen(str) + 1; + size_t len = strlen(str) + 1; tmp = xmalloc(len); memcpy(tmp, str, len); @@ -638,20 +505,36 @@ ruby_strdup(str) } char * -ruby_getcwd() +ruby_getcwd(void) { -#ifdef HAVE_GETCWD +#if defined HAVE_GETCWD +# undef RUBY_UNTYPED_DATA_WARNING +# define RUBY_UNTYPED_DATA_WARNING 0 +# if defined NO_GETCWD_MALLOC + VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, RUBY_DEFAULT_FREE, NULL); int size = 200; char *buf = xmalloc(size); while (!getcwd(buf, size)) { - if (errno != ERANGE) { - free(buf); - rb_sys_fail("getcwd"); + int e = errno; + if (e != ERANGE) { + xfree(buf); + DATA_PTR(guard) = NULL; + rb_syserr_fail(e, "getcwd"); } size *= 2; + DATA_PTR(guard) = buf; buf = xrealloc(buf, size); } +# else + VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, free, NULL); + char *buf, *cwd = getcwd(NULL, 0); + DATA_PTR(guard) = cwd; + if (!cwd) rb_sys_fail("getcwd"); + buf = ruby_strdup(cwd); /* allocate by xmalloc */ + free(cwd); +# endif + DATA_PTR(RB_GC_GUARD(guard)) = NULL; #else # ifndef PATH_MAX # define PATH_MAX 8192 @@ -659,14 +542,14 @@ ruby_getcwd() char *buf = xmalloc(PATH_MAX+1); if (!getwd(buf)) { - free(buf); - rb_sys_fail("getwd"); + int e = errno; + xfree(buf); + rb_syserr_fail(e, "getwd"); } #endif return buf; } - /**************************************************************** * * The author of this software is David M. Gay. @@ -866,7 +749,7 @@ ruby_getcwd() #ifdef DEBUG #include "stdio.h" -#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} +#define Bug(x) {fprintf(stderr, "%s\n", (x)); exit(EXIT_FAILURE);} #endif #include "stdlib.h" @@ -879,7 +762,12 @@ ruby_getcwd() #ifdef MALLOC extern void *MALLOC(size_t); #else -#define MALLOC malloc +#define MALLOC xmalloc +#endif +#ifdef FREE +extern void FREE(void*); +#else +#define FREE xfree #endif #ifndef Omit_Private_Memory @@ -899,8 +787,6 @@ static double private_mem[PRIVATE_mem], *pmem_next = private_mem; #define IEEE_Arith #endif -#include "errno.h" - #ifdef Bad_float_h #ifdef IEEE_Arith @@ -940,6 +826,9 @@ static double private_mem[PRIVATE_mem], *pmem_next = private_mem; #ifdef __cplusplus extern "C" { +#if 0 +} /* satisfy cc-mode */ +#endif #endif #if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + defined(IBM) != 1 @@ -949,23 +838,25 @@ Exactly one of IEEE_LITTLE_ENDIAN, IEEE_BIG_ENDIAN, VAX, or IBM should be define typedef union { double d; ULong L[2]; } U; #ifdef YES_ALIAS -#define dval(x) x -#ifdef IEEE_LITTLE_ENDIAN -#define word0(x) ((ULong *)&x)[1] -#define word1(x) ((ULong *)&x)[0] -#else -#define word0(x) ((ULong *)&x)[0] -#define word1(x) ((ULong *)&x)[1] -#endif -#else -#ifdef IEEE_LITTLE_ENDIAN -#define word0(x) ((U*)&x)->L[1] -#define word1(x) ((U*)&x)->L[0] -#else -#define word0(x) ((U*)&x)->L[0] -#define word1(x) ((U*)&x)->L[1] -#endif -#define dval(x) ((U*)&x)->d +typedef double double_u; +# define dval(x) (x) +# ifdef IEEE_LITTLE_ENDIAN +# define word0(x) (((ULong *)&(x))[1]) +# define word1(x) (((ULong *)&(x))[0]) +# else +# define word0(x) (((ULong *)&(x))[0]) +# define word1(x) (((ULong *)&(x))[1]) +# endif +#else +typedef U double_u; +# ifdef IEEE_LITTLE_ENDIAN +# define word0(x) ((x).L[1]) +# define word1(x) ((x).L[0]) +# else +# define word0(x) ((x).L[0]) +# define word1(x) ((x).L[1]) +# endif +# define dval(x) ((x).d) #endif /* The following definition of Storeinc is appropriate for MIPS processors. @@ -973,11 +864,11 @@ typedef union { double d; ULong L[2]; } U; * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) */ #if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(__arm__) -#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ -((unsigned short *)a)[0] = (unsigned short)c, a++) +#define Storeinc(a,b,c) (((unsigned short *)(a))[1] = (unsigned short)(b), \ +((unsigned short *)(a))[0] = (unsigned short)(c), (a)++) #else -#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ -((unsigned short *)a)[1] = (unsigned short)c, a++) +#define Storeinc(a,b,c) (((unsigned short *)(a))[0] = (unsigned short)(b), \ +((unsigned short *)(a))[1] = (unsigned short)(c), (a)++) #endif /* #define P DBL_MANT_DIG */ @@ -1100,12 +991,12 @@ typedef union { double d; ULong L[2]; } U; #endif #ifdef RND_PRODQUOT -#define rounded_product(a,b) a = rnd_prod(a, b) -#define rounded_quotient(a,b) a = rnd_quot(a, b) +#define rounded_product(a,b) ((a) = rnd_prod((a), (b))) +#define rounded_quotient(a,b) ((a) = rnd_quot((a), (b))) extern double rnd_prod(double, double), rnd_quot(double, double); #else -#define rounded_product(a,b) a *= b -#define rounded_quotient(a,b) a /= b +#define rounded_product(a,b) ((a) *= (b)) +#define rounded_quotient(a,b) ((a) /= (b)) #endif #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) @@ -1136,9 +1027,14 @@ extern double rnd_prod(double, double), rnd_quot(double, double); #endif #endif /* NO_LONG_LONG */ +#define MULTIPLE_THREADS 1 + #ifndef MULTIPLE_THREADS #define ACQUIRE_DTOA_LOCK(n) /*nothing*/ #define FREE_DTOA_LOCK(n) /*nothing*/ +#else +#define ACQUIRE_DTOA_LOCK(n) /*unused right now*/ +#define FREE_DTOA_LOCK(n) /*unused right now*/ #endif #define Kmax 15 @@ -1159,11 +1055,11 @@ Balloc(int k) int x; Bigint *rv; #ifndef Omit_Private_Memory - unsigned int len; + size_t len; #endif ACQUIRE_DTOA_LOCK(0); - if ((rv = freelist[k]) != 0) { + if (k <= Kmax && (rv = freelist[k]) != 0) { freelist[k] = rv->next; } else { @@ -1173,7 +1069,7 @@ Balloc(int k) #else len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) /sizeof(double); - if (pmem_next - private_mem + len <= PRIVATE_mem) { + if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { rv = (Bigint*)pmem_next; pmem_next += len; } @@ -1192,6 +1088,10 @@ static void Bfree(Bigint *v) { if (v) { + if (v->k > Kmax) { + FREE(v); + return; + } ACQUIRE_DTOA_LOCK(0); v->next = freelist[v->k]; freelist[v->k] = v; @@ -1199,18 +1099,18 @@ Bfree(Bigint *v) } } -#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ -y->wds*sizeof(Long) + 2*sizeof(int)) +#define Bcopy(x,y) memcpy((char *)&(x)->sign, (char *)&(y)->sign, \ +(y)->wds*sizeof(Long) + 2*sizeof(int)) static Bigint * multadd(Bigint *b, int m, int a) /* multiply by m and add a */ { int i, wds; -#ifdef ULLong ULong *x; +#ifdef ULLong ULLong carry, y; #else - ULong carry, *x, y; + ULong carry, y; #ifdef Pack_32 ULong xi, z; #endif @@ -1225,7 +1125,7 @@ multadd(Bigint *b, int m, int a) /* multiply by m and add a */ #ifdef ULLong y = *x * (ULLong)m + carry; carry = y >> 32; - *x++ = y & FFFFFFFF; + *x++ = (ULong)(y & FFFFFFFF); #else #ifdef Pack_32 xi = *x; @@ -1247,7 +1147,7 @@ multadd(Bigint *b, int m, int a) /* multiply by m and add a */ Bfree(b); b = b1; } - b->x[wds++] = carry; + b->x[wds++] = (ULong)carry; b->wds = wds; } return b; @@ -1414,9 +1314,9 @@ mult(Bigint *a, Bigint *b) do { z = *x++ * (ULLong)y + *xc + carry; carry = z >> 32; - *xc++ = z & FFFFFFFF; + *xc++ = (ULong)(z & FFFFFFFF); } while (x < xae); - *xc = carry; + *xc = (ULong)carry; } } #else @@ -1433,7 +1333,7 @@ mult(Bigint *a, Bigint *b) carry = z2 >> 16; Storeinc(xc, z2, z); } while (x < xae); - *xc = carry; + *xc = (ULong)carry; } if (y = *xb >> 16) { x = xa; @@ -1461,7 +1361,7 @@ mult(Bigint *a, Bigint *b) carry = z >> 16; *xc++ = z & 0xffff; } while (x < xae); - *xc = carry; + *xc = (ULong)carry; } } #endif @@ -1652,12 +1552,12 @@ diff(Bigint *a, Bigint *b) do { y = (ULLong)*xa++ - *xb++ - borrow; borrow = y >> 32 & (ULong)1; - *xc++ = y & FFFFFFFF; + *xc++ = (ULong)(y & FFFFFFFF); } while (xb < xbe); while (xa < xae) { y = *xa++ - borrow; borrow = y >> 32 & (ULong)1; - *xc++ = y & FFFFFFFF; + *xc++ = (ULong)(y & FFFFFFFF); } #else #ifdef Pack_32 @@ -1695,10 +1595,11 @@ diff(Bigint *a, Bigint *b) } static double -ulp(double x) +ulp(double x_) { register Long L; - double a; + double_u x, a; + dval(x) = x_; L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; #ifndef Avoid_Underflow @@ -1736,7 +1637,7 @@ b2d(Bigint *a, int *e) { ULong *xa, *xa0, w, y, z; int k; - double d; + double_u d; #ifdef VAX ULong d0, d1; #else @@ -1797,8 +1698,9 @@ ret_d: } static Bigint * -d2b(double d, int *e, int *bits) +d2b(double d_, int *e, int *bits) { + double_u d; Bigint *b; int de, k; ULong *x, y, z; @@ -1807,6 +1709,9 @@ d2b(double d, int *e, int *bits) #endif #ifdef VAX ULong d0, d1; +#endif + dval(d) = d_; +#ifdef VAX d0 = word0(d) >> 16 | word0(d) << 16; d1 = word1(d) >> 16 | word1(d) << 16; #else @@ -1932,7 +1837,7 @@ d2b(double d, int *e, int *bits) static double ratio(Bigint *a, Bigint *b) { - double da, db; + double_u da, db; int k, ka, kb; dval(da) = b2d(a, &ka); @@ -2091,7 +1996,8 @@ ruby_strtod(const char *s00, char **se) int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; const char *s, *s0, *s1; - double aadj, aadj1, adj, rv, rv0; + double aadj, adj; + double_u aadj1, rv, rv0; Long L; ULong y, z; Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; @@ -2105,6 +2011,7 @@ ruby_strtod(const char *s00, char **se) const char *s2; #endif + errno = 0; sign = nz0 = nz = 0; dval(rv) = 0.; for (s = s00;;s++) @@ -2130,6 +2037,73 @@ ruby_strtod(const char *s00, char **se) } break2: if (*s == '0') { + if (s[1] == 'x' || s[1] == 'X') { + s0 = ++s; + adj = 0; + aadj = 1.0; + nd0 = -4; + + if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; + if (*s == '0') { + while (*++s == '0'); + s1 = strchr(hexdigit, *s); + } + if (s1 != NULL) { + do { + adj += aadj * ((s1 - hexdigit) & 15); + nd0 += 4; + aadj /= 16; + } while (*++s && (s1 = strchr(hexdigit, *s))); + } + + if (*s == '.') { + dsign = 1; + if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0; + if (nd0 < 0) { + while (*s == '0') { + s++; + nd0 -= 4; + } + } + for (; *s && (s1 = strchr(hexdigit, *s)); ++s) { + adj += aadj * ((s1 - hexdigit) & 15); + if ((aadj /= 16) == 0.0) { + while (strchr(hexdigit, *++s)); + break; + } + } + } + else { + dsign = 0; + } + + if (*s == 'P' || *s == 'p') { + dsign = 0x2C - *++s; /* +: 2B, -: 2D */ + if (abs(dsign) == 1) s++; + else dsign = 1; + + nd = 0; + c = *s; + if (c < '0' || '9' < c) goto ret0; + do { + nd *= 10; + nd += c; + nd -= '0'; + c = *++s; + /* Float("0x0."+("0"*267)+"1fp2095") */ + if (nd + dsign * nd0 > 2095) { + while ('0' <= c && c <= '9') c = *++s; + break; + } + } while ('0' <= c && c <= '9'); + nd0 += nd * dsign; + } + else { + if (dsign) goto ret0; + } + dval(rv) = ldexp(adj, nd0); + goto ret; + } nz0 = 1; while (*++s == '0') ; if (!*s) @@ -2140,7 +2114,7 @@ break2: for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) if (nd < 9) y = 10*y + c - '0'; - else if (nd < 16) + else if (nd < DBL_DIG + 2) z = 10*z + c - '0'; nd0 = nd; #ifdef USE_LOCALE @@ -2163,6 +2137,8 @@ break2: } #endif if (c == '.') { + if (!ISDIGIT(s[1])) + goto dig_done; c = *++s; if (!nd) { for (; c == '0'; c = *++s) @@ -2178,16 +2154,19 @@ break2: for (; c >= '0' && c <= '9'; c = *++s) { have_dig: nz++; + if (nd > DBL_DIG * 4) { + continue; + } if (c -= '0') { nf += nz; for (i = 1; i < nz; i++) if (nd++ < 9) y *= 10; - else if (nd <= DBL_DIG + 1) + else if (nd <= DBL_DIG + 2) z *= 10; if (nd++ < 9) y = 10*y + c; - else if (nd <= DBL_DIG + 1) + else if (nd <= DBL_DIG + 2) z = 10*z + c; nz = 0; } @@ -2275,7 +2254,7 @@ ret0: if (!nd0) nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; + k = nd < DBL_DIG + 2 ? nd : DBL_DIG + 2; dval(rv) = y; if (k > 9) { #ifdef SET_INEXACT @@ -2284,7 +2263,7 @@ ret0: #endif dval(rv) = tens[k - 9] * dval(rv) + z; } - bd0 = 0; + bd0 = bb = bd = bs = delta = 0; if (nd <= DBL_DIG #ifndef RND_PRODQUOT #ifndef Honor_FLT_ROUNDS @@ -2302,7 +2281,7 @@ ret0: #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { - rv = -rv; + dval(rv) = -dval(rv); sign = 0; } #endif @@ -2318,7 +2297,7 @@ ret0: #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { - rv = -rv; + dval(rv) = -dval(rv); sign = 0; } #endif @@ -2346,7 +2325,7 @@ vax_ovfl_check: #ifdef Honor_FLT_ROUNDS /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { - rv = -rv; + dval(rv) = -dval(rv); sign = 0; } #endif @@ -2787,14 +2766,14 @@ drop_down: } if ((aadj = ratio(delta, bs)) <= 2.) { if (dsign) - aadj = aadj1 = 1.; + aadj = dval(aadj1) = 1.; else if (word1(rv) || word0(rv) & Bndry_mask) { #ifndef Sudden_Underflow if (word1(rv) == Tiny1 && !word0(rv)) goto undfl; #endif aadj = 1.; - aadj1 = -1.; + dval(aadj1) = -1.; } else { /* special case -- power of FLT_RADIX to be */ @@ -2804,24 +2783,24 @@ drop_down: aadj = 1./FLT_RADIX; else aadj *= 0.5; - aadj1 = -aadj; + dval(aadj1) = -aadj; } } else { aadj *= 0.5; - aadj1 = dsign ? aadj : -aadj; + dval(aadj1) = dsign ? aadj : -aadj; #ifdef Check_FLT_ROUNDS switch (Rounding) { case 2: /* towards +infinity */ - aadj1 -= 0.5; + dval(aadj1) -= 0.5; break; case 0: /* towards 0 */ case 3: /* towards -infinity */ - aadj1 += 0.5; + dval(aadj1) += 0.5; } #else if (Flt_Rounds == 0) - aadj1 += 0.5; + dval(aadj1) += 0.5; #endif /*Check_FLT_ROUNDS*/ } y = word0(rv) & Exp_mask; @@ -2831,7 +2810,7 @@ drop_down: if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { dval(rv0) = dval(rv); word0(rv) -= P*Exp_msk1; - adj = aadj1 * ulp(dval(rv)); + adj = dval(aadj1) * ulp(dval(rv)); dval(rv) += adj; if ((word0(rv) & Exp_mask) >= Exp_msk1*(DBL_MAX_EXP+Bias-P)) { @@ -2848,21 +2827,21 @@ drop_down: #ifdef Avoid_Underflow if (scale && y <= 2*P*Exp_msk1) { if (aadj <= 0x7fffffff) { - if ((z = aadj) <= 0) + if ((z = (int)aadj) <= 0) z = 1; aadj = z; - aadj1 = dsign ? aadj : -aadj; + dval(aadj1) = dsign ? aadj : -aadj; } word0(aadj1) += (2*P+1)*Exp_msk1 - y; } - adj = aadj1 * ulp(dval(rv)); + adj = dval(aadj1) * ulp(dval(rv)); dval(rv) += adj; #else #ifdef Sudden_Underflow if ((word0(rv) & Exp_mask) <= P*Exp_msk1) { dval(rv0) = dval(rv); word0(rv) += P*Exp_msk1; - adj = aadj1 * ulp(dval(rv)); + adj = dval(aadj1) * ulp(dval(rv)); dval(rv) += adj; #ifdef IBM if ((word0(rv) & Exp_mask) < P*Exp_msk1) @@ -2880,7 +2859,7 @@ drop_down: word0(rv) -= P*Exp_msk1; } else { - adj = aadj1 * ulp(dval(rv)); + adj = dval(aadj1) * ulp(dval(rv)); dval(rv) += adj; } #else /*Sudden_Underflow*/ @@ -2892,11 +2871,11 @@ drop_down: * example: 1.2e-307 . */ if (y <= (P-1)*Exp_msk1 && aadj > 1.) { - aadj1 = (double)(int)(aadj + 0.5); + dval(aadj1) = (double)(int)(aadj + 0.5); if (!dsign) - aadj1 = -aadj1; + dval(aadj1) = -dval(aadj1); } - adj = aadj1 * ulp(dval(rv)); + adj = dval(aadj1) * ulp(dval(rv)); dval(rv) += adj; #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ @@ -3006,7 +2985,7 @@ quorem(Bigint *b, Bigint *S) carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; - *bx++ = y & FFFFFFFF; + *bx++ = (ULong)(y & FFFFFFFF); #else #ifdef Pack_32 si = *sx++; @@ -3046,7 +3025,7 @@ quorem(Bigint *b, Bigint *S) carry = ys >> 32; y = *bx - (ys & FFFFFFFF) - borrow; borrow = y >> 32 & (ULong)1; - *bx++ = y & FFFFFFFF; + *bx++ = (ULong)(y & FFFFFFFF); #else #ifdef Pack_32 si = *sx++; @@ -3082,27 +3061,18 @@ quorem(Bigint *b, Bigint *S) static char *dtoa_result; #endif +#ifndef MULTIPLE_THREADS static char * rv_alloc(int i) { - int j, k, *r; - - j = sizeof(ULong); - for (k = 0; - sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i; - j <<= 1) - k++; - r = (int*)Balloc(k); - *r = k; - return -#ifndef MULTIPLE_THREADS - dtoa_result = -#endif - (char *)(r+1); + return dtoa_result = xmalloc(i); } +#else +#define rv_alloc(i) xmalloc(i) +#endif static char * -nrv_alloc(char *s, char **rve, int n) +nrv_alloc(const char *s, char **rve, size_t n) { char *rv, *t; @@ -3113,23 +3083,25 @@ nrv_alloc(char *s, char **rve, int n) return rv; } +#define rv_strdup(s, rve) nrv_alloc((s), (rve), strlen(s)+1) + +#ifndef MULTIPLE_THREADS /* freedtoa(s) must be used to free values s returned by dtoa * when MULTIPLE_THREADS is #defined. It should be used in all cases, * but for consistency with earlier versions of dtoa, it is optional * when MULTIPLE_THREADS is not defined. */ -void +static void freedtoa(char *s) { - Bigint *b = (Bigint *)((int *)s - 1); - b->maxwds = 1 << (b->k = *(int*)b); - Bfree(b); -#ifndef MULTIPLE_THREADS - if (s == dtoa_result) - dtoa_result = 0; -#endif + xfree(s); } +#endif + +static const char INFSTR[] = "Infinity"; +static const char NANSTR[] = "NaN"; +static const char ZEROSTR[] = "0"; /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * @@ -3166,7 +3138,7 @@ freedtoa(char *s) */ char * -dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) +ruby_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve) { /* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt; trailing zeros are suppressed from @@ -3204,14 +3176,15 @@ dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - spec_case, try_quick; + spec_case, try_quick, half = 0; Long L; #ifndef Sudden_Underflow int denorm; ULong x; #endif - Bigint *b, *b1, *delta, *mlo, *mhi, *S; - double d2, ds, eps; + Bigint *b, *b1, *delta, *mlo = 0, *mhi = 0, *S; + double ds; + double_u d, d2, eps; char *s, *s0; #ifdef Honor_FLT_ROUNDS int rounding; @@ -3220,6 +3193,8 @@ dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) int inexact, oldinexact; #endif + dval(d) = d_; + #ifndef MULTIPLE_THREADS if (dtoa_result) { freedtoa(dtoa_result); @@ -3246,9 +3221,9 @@ dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) *decpt = 9999; #ifdef IEEE_Arith if (!word1(d) && !(word0(d) & 0xfffff)) - return nrv_alloc("Infinity", rve, 8); + return rv_strdup(INFSTR, rve); #endif - return nrv_alloc("NaN", rve, 3); + return rv_strdup(NANSTR, rve); } #endif #ifdef IBM @@ -3256,7 +3231,7 @@ dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) #endif if (!dval(d)) { *decpt = 1; - return nrv_alloc("0", rve, 1); + return rv_strdup(ZEROSTR, rve); } #ifdef SET_INEXACT @@ -3399,7 +3374,7 @@ dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) if (i <= 0) i = 1; } - s = s0 = rv_alloc(i); + s = s0 = rv_alloc(i+1); #ifdef Honor_FLT_ROUNDS if (mode > 1 && rounding != 1) @@ -3465,7 +3440,7 @@ dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) */ dval(eps) = 0.5/tens[ilim-1] - dval(eps); for (i = 0;;) { - L = dval(d); + L = (int)dval(d); dval(d) -= L; *s++ = '0' + (int)L; if (dval(d) < dval(eps)) @@ -3495,6 +3470,10 @@ dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve) s++; goto ret1; } + half = 1; + if ((*(s-1) - '0') & 1) { + goto bump_up; + } break; } } @@ -3563,7 +3542,6 @@ bump_up: m2 = b2; m5 = b5; - mhi = mlo = 0; if (leftright) { i = #ifndef Sudden_Underflow @@ -3803,12 +3781,13 @@ keep_dig: *s++ = '1'; goto ret; } - ++*s++; + if (!half || (*s - '0') & 1) + ++*s; } else { while (*--s == '0') ; - s++; } + s++; ret: Bfree(S); if (mhi) { @@ -3848,11 +3827,154 @@ ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *ar if (!*str) break; end = str; while (*end && !ISSPACE(*end) && *end != ',') end++; - len = end - str; + len = (int)(end - str); /* assume no string exceeds INT_MAX */ (*func)(str, len, arg); } } +/*- + * Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define DBL_MANH_SIZE 20 +#define DBL_MANL_SIZE 32 +#define DBL_ADJ (DBL_MAX_EXP - 2) +#define SIGFIGS ((DBL_MANT_DIG + 3) / 4 + 1) +#define dexp_get(u) ((int)(word0(u) >> Exp_shift) & ~Exp_msk1) +#define dexp_set(u,v) (word0(u) = (((int)(word0(u)) & ~Exp_mask) | ((v) << Exp_shift))) +#define dmanh_get(u) ((uint32_t)(word0(u) & Frac_mask)) +#define dmanl_get(u) ((uint32_t)word1(u)) + + +/* + * This procedure converts a double-precision number in IEEE format + * into a string of hexadecimal digits and an exponent of 2. Its + * behavior is bug-for-bug compatible with dtoa() in mode 2, with the + * following exceptions: + * + * - An ndigits < 0 causes it to use as many digits as necessary to + * represent the number exactly. + * - The additional xdigs argument should point to either the string + * "0123456789ABCDEF" or the string "0123456789abcdef", depending on + * which case is desired. + * - This routine does not repeat dtoa's mistake of setting decpt + * to 9999 in the case of an infinity or NaN. INT_MAX is used + * for this purpose instead. + * + * Note that the C99 standard does not specify what the leading digit + * should be for non-zero numbers. For instance, 0x1.3p3 is the same + * as 0x2.6p2 is the same as 0x4.cp3. This implementation always makes + * the leading digit a 1. This ensures that the exponent printed is the + * actual base-2 exponent, i.e., ilogb(d). + * + * Inputs: d, xdigs, ndigits + * Outputs: decpt, sign, rve + */ +char * +ruby_hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, + char **rve) +{ + U u; + char *s, *s0; + int bufsize; + uint32_t manh, manl; + + u.d = d; + if (word0(u) & Sign_bit) { + /* set sign for everything, including 0's and NaNs */ + *sign = 1; + word0(u) &= ~Sign_bit; /* clear sign bit */ + } + else + *sign = 0; + + if (isinf(d)) { /* FP_INFINITE */ + *decpt = INT_MAX; + return rv_strdup(INFSTR, rve); + } + else if (isnan(d)) { /* FP_NAN */ + *decpt = INT_MAX; + return rv_strdup(NANSTR, rve); + } + else if (d == 0.0) { /* FP_ZERO */ + *decpt = 1; + return rv_strdup(ZEROSTR, rve); + } + else if (dexp_get(u)) { /* FP_NORMAL */ + *decpt = dexp_get(u) - DBL_ADJ; + } + else { /* FP_SUBNORMAL */ + u.d *= 5.363123171977039e+154 /* 0x1p514 */; + *decpt = dexp_get(u) - (514 + DBL_ADJ); + } + + if (ndigits == 0) /* dtoa() compatibility */ + ndigits = 1; + + /* + * If ndigits < 0, we are expected to auto-size, so we allocate + * enough space for all the digits. + */ + bufsize = (ndigits > 0) ? ndigits : SIGFIGS; + s0 = rv_alloc(bufsize+1); + + /* Round to the desired number of digits. */ + if (SIGFIGS > ndigits && ndigits > 0) { + float redux = 1.0f; + int offset = 4 * ndigits + DBL_MAX_EXP - 4 - DBL_MANT_DIG; + dexp_set(u, offset); + u.d += redux; + u.d -= redux; + *decpt += dexp_get(u) - offset; + } + + manh = dmanh_get(u); + manl = dmanl_get(u); + *s0 = '1'; + for (s = s0 + 1; s < s0 + bufsize; s++) { + *s = xdigs[(manh >> (DBL_MANH_SIZE - 4)) & 0xf]; + manh = (manh << 4) | (manl >> (DBL_MANL_SIZE - 4)); + manl <<= 4; + } + + /* If ndigits < 0, we are expected to auto-size the precision. */ + if (ndigits < 0) { + for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--) + ; + } + + s = s0 + ndigits; + *s = '\0'; + if (rve != NULL) + *rve = s; + return (s0); +} + #ifdef __cplusplus +#if 0 +{ /* satisfy cc-mode */ +#endif } #endif |
