summaryrefslogtreecommitdiff
path: root/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'util.c')
-rw-r--r--util.c1077
1 files changed, 380 insertions, 697 deletions
diff --git a/util.c b/util.c
index e9e53ed4b3..4caa324849 100644
--- a/util.c
+++ b/util.c
@@ -3,440 +3,338 @@
util.c -
$Author$
- $Date$
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
+
+#ifndef __STDC_WANT_LIB_EXT1__
+#define __STDC_WANT_LIB_EXT1__ 1 /* for qsort_s() */
+#endif
+
+#include "ruby/internal/config.h"
#include <ctype.h>
-#include <stdio.h>
#include <errno.h>
-#include <math.h>
#include <float.h>
+#include <math.h>
+#include <stdio.h>
#ifdef _WIN32
-#include "missing/file.h"
+# include "missing/file.h"
#endif
-#include "util.h"
+#include "internal.h"
+#include "internal/sanitizers.h"
+#include "internal/imemo.h"
+#include "internal/util.h"
+#include "ruby/util.h"
+#include "ruby_atomic.h"
+
+const char ruby_hexdigits[] = "0123456789abcdef0123456789ABCDEF";
+#define hexdigit ruby_hexdigits
unsigned long
-ruby_scan_oct(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;
-
- while (len-- && *s >= '0' && *s <= '7') {
- retval <<= 3;
- retval |= *s++ - '0';
- }
- *retlen = s - start;
- return retval;
+ int overflow;
+ unsigned long val = ruby_scan_digits(start, (ssize_t)len, 8, retlen, &overflow);
+ (void)overflow;
+ return val;
}
unsigned long
-ruby_scan_hex(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;
-
- while (len-- && *s && (tmp = strchr(hexdigit, *s))) {
- retval <<= 4;
- retval |= (tmp - hexdigit) & 15;
- s++;
- }
- *retlen = s - start;
- return retval;
+ int overflow;
+ unsigned long val = ruby_scan_digits(start, (ssize_t)len, 16, retlen, &overflow);
+ (void)overflow;
+ return val;
}
-#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(const char *s);
-
-static const char suffix1[] = ".$$$";
-static const 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(VALUE str, const char *suffix)
+NO_SANITIZE("unsigned-integer-overflow", extern unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow));
+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_LEN(str) > 1000)
- rb_fatal("Cannot do inplace edit on long filename (%ld characters)",
- RSTRING_LEN(str));
-
-#if defined(DJGPP) || defined(__CYGWIN32__) || defined(_WIN32)
- /* Style 0 */
- slen = RSTRING_LEN(str);
- rb_str_cat(str, suffix, extlen);
-#if defined(DJGPP)
- if (_USE_LFN) return;
-#else
- if (valid_filename(RSTRING_PTR(str))) return;
-#endif
+ RBIMPL_ASSERT_OR_ASSUME(base >= 2);
+ RBIMPL_ASSERT_OR_ASSUME(base <= 36);
- /* Fooey, style 0 failed. Fix str before continuing. */
- rb_str_resize(str, slen);
-#endif
+ const char *start = str;
+ unsigned long ret = 0, x;
+ unsigned long mul_overflow = (~(unsigned long)0) / base;
- slen = extlen;
- t = buf; baselen = 0; s = RSTRING_PTR(str);
- while ((*t = *s) && *s != '.') {
- baselen++;
- if (*s == '\\' || *s == '/') baselen = 0;
- s++; t++;
- }
- p = t;
-
- t = ext; extlen = 0;
- while (*t++ = *s++) extlen++;
- if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; }
+ *overflow = 0;
- if (*suffix == '.') { /* Style 1 */
- if (strEQ(ext, suffix)) goto fallback;
- strcpy(p, suffix);
+ if (!len) {
+ *retlen = 0;
+ return 0;
}
- 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_PTR(str), buf, RSTRING_LEN(str));
+ 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(const 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!
- */
+ int c, b, overflow;
+ int sign = 0;
+ size_t len;
+ unsigned long ret;
+ const char *subject_found = str;
+
+ if (base < 0) {
+ errno = EINVAL;
+ return 0;
+ }
- if (_access(s, 0) == 0) {
- return 1;
+ 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 (sign < 0) {
+ ret = (unsigned long)(-(long)ret);
+ return ret;
}
- if (s) {
- if (n == 0 || *s == 0)
- return 0;
- else if (!s[1])
- return 1;
- return dbcs_table[(unsigned char)*s] + 1;
+ else {
+ return ret;
}
- else
- return 1;
}
-struct PathList {
- struct PathList *next;
- char *path;
-};
+#if !defined HAVE_GNU_QSORT_R
+#include <sys/types.h>
+#include <stdint.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+typedef int (cmpfunc_t)(const void*, const void*, void*);
+
+#if defined HAVE_QSORT_S && defined RUBY_MSVCRT_VERSION
+/* In contrast to its name, Visual Studio qsort_s is incompatible with
+ * C11 in the order of the comparison function's arguments, and same
+ * as BSD qsort_r rather. */
+# 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
-struct PathInfo {
- struct PathList *head;
- int count;
+#if defined HAVE_BSD_QSORT_R
+struct bsd_qsort_r_args {
+ cmpfunc_t *cmp;
+ void *arg;
};
static int
-push_element(const char *path, VALUE vinfo)
+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++;
-
- return 0;
+ 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, RUBY_MBCHAR_MAXSIZE))
- if (*p == '\\')
- *p = '/';
-
- info.count = 0;
- info.head = 0;
-
- ruby_glob(buf, 0, 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);
}
+#elif defined HAVE_QSORT_S
+/* C11 qsort_s has the same arguments as GNU's, but uses
+ * runtime-constraints handler. */
+void
+ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void *d)
+{
+ if (!nel || !size) return; /* nothing to sort */
-#endif
+ /* get rid of runtime-constraints handler for MT-safeness */
+ if (!base || !cmp) return;
+ if (nel > RSIZE_MAX || size > RSIZE_MAX) return;
+ qsort_s(base, nel, size, cmp, d);
+}
+# define HAVE_GNU_QSORT_R 1
+#else
/* 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_(register char *a, register char *b, int mmkind, int size, int high, int low)
+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_(register char *a, register char *b, register char *c, int mmkind, int size, int high, int low)
+/* 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);
}
}
@@ -453,23 +351,25 @@ static void mmrot3_(register char *a, register char *b, register char *c, int mm
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 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)))
+#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(void* base, const int nel, const int size,
- int (*cmp)(const void*, const void*, void*), void *d)
+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);
@@ -482,68 +382,69 @@ ruby_qsort(void* base, const int nel, const int size,
for (;;) {
start:
if (L + size == R) { /* 2 elements */
- if ((*cmp)(L,R,d) > 0) mmswap(L,R); goto nxt;
+ if ((*cmp)(L,R,d) > 0) mmswap(L,R);
+ goto nxt;
}
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 */
- {
- register char *p1 = l + t;
- register char *p2 = p1 + t;
- register char *p3 = p2 + t;
- m1 = med3(p1, p2, p3);
- p1 = m + t;
- p2 = p1 + t;
- p3 = p2 + t;
- m3 = med3(p1, p2, p3);
- }
+ if (n >= 200) {
+ n = size*(n>>3); /* number of bytes in splitting 8 */
+ {
+ register char *p1 = l + n;
+ register char *p2 = p1 + n;
+ register char *p3 = p2 + n;
+ m1 = med3(p1, p2, p3);
+ 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);
}
if ((t = (*cmp)(l,m,d)) < 0) { /*3-5-?*/
if ((t = (*cmp)(m,r,d)) < 0) { /*3-5-7*/
- if (chklim && nel >= chklim) { /* check if already ascending order */
- char *p;
- chklim = 0;
- for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) > 0) goto fail;
- goto nxt;
- }
- fail: goto loopA; /*3-5-7*/
+ if (chklim && nel >= chklim) { /* check if already ascending order */
+ char *p;
+ chklim = 0;
+ for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) > 0) goto fail;
+ goto nxt;
+ }
+ fail: goto loopA; /*3-5-7*/
}
if (t > 0) {
- if ((*cmp)(l,r,d) <= 0) {mmswap(m,r); goto loopA;} /*3-5-4*/
- mmrot3(r,m,l); goto loopA; /*3-5-2*/
+ if ((*cmp)(l,r,d) <= 0) {mmswap(m,r); goto loopA;} /*3-5-4*/
+ mmrot3(r,m,l); goto loopA; /*3-5-2*/
}
goto loopB; /*3-5-5*/
}
if (t > 0) { /*7-5-?*/
if ((t = (*cmp)(m,r,d)) > 0) { /*7-5-3*/
- if (chklim && nel >= chklim) { /* check if already ascending order */
- char *p;
- chklim = 0;
- for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) < 0) goto fail2;
- while (l<r) {mmswap(l,r); l+=size; r-=size;} /* reverse region */
- goto nxt;
- }
- fail2: mmswap(l,r); goto loopA; /*7-5-3*/
+ if (chklim && nel >= chklim) { /* check if already ascending order */
+ char *p;
+ chklim = 0;
+ for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) < 0) goto fail2;
+ while (l<r) {mmswap(l,r); l+=size; r-=size;} /* reverse region */
+ goto nxt;
+ }
+ fail2: mmswap(l,r); goto loopA; /*7-5-3*/
}
if (t < 0) {
- if ((*cmp)(l,r,d) <= 0) {mmswap(l,m); goto loopB;} /*7-5-8*/
- mmrot3(l,m,r); goto loopA; /*7-5-6*/
+ if ((*cmp)(l,r,d) <= 0) {mmswap(l,m); goto loopB;} /*7-5-8*/
+ mmrot3(l,m,r); goto loopA; /*7-5-6*/
}
mmswap(l,r); goto loopA; /*7-5-5*/
}
@@ -562,18 +463,18 @@ ruby_qsort(void* base, const int nel, const int size,
loopA: eq_l = 1; eq_r = 1; /* splitting type A */ /* left <= median < right */
for (;;) {
for (;;) {
- if ((l += size) == r)
- {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
- if (l == m) continue;
- if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;}
- if (t < 0) eq_l = 0;
+ if ((l += size) == r)
+ {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
+ if (l == m) continue;
+ if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;}
+ if (t < 0) eq_l = 0;
}
for (;;) {
- if (l == (r -= size))
- {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
- if (r == m) {m = l; break;}
- if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;}
- if (t == 0) break;
+ if (l == (r -= size))
+ {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
+ if (r == m) {m = l; break;}
+ if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;}
+ if (t == 0) break;
}
mmswap(l,r); /* swap left and right */
}
@@ -581,18 +482,18 @@ ruby_qsort(void* base, const int nel, const int size,
loopB: eq_l = 1; eq_r = 1; /* splitting type B */ /* left < median <= right */
for (;;) {
for (;;) {
- if (l == (r -= size))
- {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
- if (r == m) continue;
- if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;}
- if (t > 0) eq_r = 0;
+ if (l == (r -= size))
+ {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
+ if (r == m) continue;
+ if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;}
+ if (t > 0) eq_r = 0;
}
for (;;) {
- if ((l += size) == r)
- {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
- if (l == m) {m = r; break;}
- if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;}
- if (t == 0) break;
+ if ((l += size) == r)
+ {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
+ if (l == m) {m = r; break;}
+ if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;}
+ if (t == 0) break;
}
mmswap(l,r); /* swap left and right */
}
@@ -600,19 +501,21 @@ ruby_qsort(void* base, const int nel, const int size,
fin:
if (eq_l == 0) /* need to sort left side */
if (eq_r == 0) /* need to sort right side */
- if (l-L < R-r) {PUSH(r,R); R = l;} /* sort left side first */
- else {PUSH(L,l); L = r;} /* sort right side first */
+ if (l-L < R-r) {PUSH(r,R); R = l;} /* sort left side first */
+ else {PUSH(L,l); L = r;} /* sort right side first */
else R = l; /* need to sort left side only */
else if (eq_r == 0) L = r; /* need to sort right side only */
else goto nxt; /* need not to sort both sides */
}
}
+#endif
+#endif /* !HAVE_GNU_QSORT_R */
char *
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);
@@ -620,316 +523,96 @@ ruby_strdup(const char *str)
return tmp;
}
+#if defined HAVE_GETCWD
+# if defined NO_GETCWD_MALLOC
+
char *
ruby_getcwd(void)
{
-#ifdef HAVE_GETCWD
+ VALUE guard = rb_imemo_tmpbuf_new();
int size = 200;
char *buf = xmalloc(size);
while (!getcwd(buf, size)) {
- if (errno != ERANGE) {
- free(buf);
- rb_sys_fail("getcwd");
- }
- size *= 2;
- buf = xrealloc(buf, size);
+ int e = errno;
+ if (e != ERANGE) {
+ rb_free_tmp_buffer(&guard);
+ rb_syserr_fail(e, "getcwd");
+ }
+ size *= 2;
+ rb_imemo_tmpbuf_set_ptr(guard, buf);
+ buf = xrealloc(buf, size);
}
+ rb_imemo_tmpbuf_set_ptr(guard, NULL);
+ return buf;
+}
+
+# else
+
+static const rb_data_type_t getcwd_buffer_guard_type = {
+ .wrap_struct_name = "ruby_getcwd_guard",
+ .function = {
+ .dfree = free // not xfree.
+ },
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+};
+
+char *
+ruby_getcwd(void)
+{
+ VALUE guard = TypedData_Wrap_Struct((VALUE)0, &getcwd_buffer_guard_type, NULL);
+ char *buf, *cwd = getcwd(NULL, 0);
+ RTYPEDDATA_DATA(guard) = cwd;
+ if (!cwd) rb_sys_fail("getcwd");
+ buf = ruby_strdup(cwd); /* allocate by xmalloc */
+ free(cwd);
+ RTYPEDDATA_DATA(RB_GC_GUARD(guard)) = NULL;
+ return buf;
+}
+
+# endif
#else
+
# ifndef PATH_MAX
# define PATH_MAX 8192
# endif
+
+char *
+ruby_getcwd(void)
+{
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;
}
-/* copyright notice for strtod implementation --
- *
- * Copyright (c) 1988-1993 The Regents of the University of California.
- * Copyright (c) 1994 Sun Microsystems, Inc.
- *
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- *
- */
-
-#define MDMINEXPT DBL_MIN_10_EXP
-#define MDMAXEXPT DBL_MAX_10_EXP
-
-static const double powersOf10[] = { /* Table giving binary powers of 10. Entry */
- 10.0, /* is 10^2^i. Used to convert decimal */
- 100.0, /* exponents into floating-point numbers. */
- 1.0e4,
- 1.0e8,
- 1.0e16,
- 1.0e32,
- 1.0e64,
- 1.0e128,
- 1.0e256
-};
+#endif
-/*
- *----------------------------------------------------------------------
- *
- * strtod --
- *
- * This procedure converts a floating-point number from an ASCII
- * decimal representation to internal double-precision format.
- *
- * Results:
- * The return value is the double-precision floating-point
- * representation of the characters in string. If endPtr isn't
- * NULL, then *endPtr is filled in with the address of the
- * next character after the last one that was part of the
- * floating-point number.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-double
-ruby_strtod(
- const char *string, /* A decimal ASCII floating-point number,
- * optionally preceded by white space.
- * Must have form "-I.FE-X", where I is the
- * integer part of the mantissa, F is the
- * fractional part of the mantissa, and X
- * is the exponent. Either of the signs
- * may be "+", "-", or omitted. Either I
- * or F may be omitted, but both cannot be
- * ommitted at once. The decimal
- * point isn't necessary unless F is present.
- * The "E" may actually be an "e". E and X
- * may both be omitted (but not just one).
- */
- char **endPtr) /* If non-NULL, store terminating character's
- * address here. */
+void
+ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *arg)
{
- int sign, expSign = Qfalse;
- double fraction = 0.0, dblExp;
- const double *d;
- register const char *p;
- register int c;
- int exp = 0; /* Exponent read from "EX" field. */
- int fracExp = 0; /* Exponent that derives from the fractional
- * part. Under normal circumstatnces, it is
- * the negative of the number of digits in F.
- * However, if I is very long, the last digits
- * of I get dropped (otherwise a long I with a
- * large negative exponent could cause an
- * unnecessary overflow on I alone). In this
- * case, fracExp is incremented one for each
- * dropped digit. */
- int mantSize = 0; /* Number of digits in mantissa. */
- int hasPoint = Qfalse; /* Decimal point exists. */
- int hasDigit = Qfalse; /* I or F exists. */
- const char *pMant; /* Temporarily holds location of mantissa
- * in string. */
- const char *pExp; /* Temporarily holds location of exponent
- * in string. */
-
- /*
- * Strip off leading blanks and check for a sign.
- */
-
- errno = 0;
- p = string;
- while (ISSPACE(*p)) p++;
- if (*p == '-') {
- sign = Qtrue;
- p++;
- }
- else {
- if (*p == '+') p++;
- sign = Qfalse;
- }
-
- fraction = 0.;
- exp = 0;
-
- /*
- * Count the number of digits in the mantissa
- * and also locate the decimal point.
- */
-
- for ( ; (c = *p) != '\0'; p++) {
- if (!ISDIGIT(c)) {
- if (c != '.' || hasPoint || !ISDIGIT(p[1])) {
- break;
- }
- hasPoint = Qtrue;
- }
- else {
- if (hasPoint) { /* already in fractional part */
- fracExp--;
- }
- if (mantSize) { /* already in mantissa */
- mantSize++;
- }
- else if (c != '0') { /* have entered mantissa */
- mantSize++;
- pMant = p;
- }
- hasDigit = Qtrue;
- }
- }
-
- /*
- * Now suck up the digits in the mantissa. Use two integers to
- * collect 9 digits each (this is faster than using floating-point).
- * If the mantissa has more than 18 digits, ignore the extras, since
- * they can't affect the value anyway.
- */
-
- pExp = p;
- if (mantSize) {
- p = pMant;
- }
- if (mantSize > 18) {
- fracExp += (mantSize - 18);
- mantSize = 18;
+ const char *end;
+ int len;
+
+ if (!str) return;
+ for (; *str; str = end) {
+ while (ISSPACE(*str) || *str == ',') str++;
+ if (!*str) break;
+ end = str;
+ while (*end && !ISSPACE(*end) && *end != ',') end++;
+ len = (int)(end - str); /* assume no string exceeds INT_MAX */
+ (*func)(str, len, arg);
}
- if (!hasDigit) {
- fraction = 0.0;
- p = string;
- }
- else {
- double frac1, frac2;
- frac1 = 0;
- for ( ; mantSize > 9; mantSize -= 1) {
- c = *p;
- p += 1;
- if (c == '.') {
- c = *p;
- p += 1;
- }
- frac1 = 10*frac1 + (c - '0');
- }
- frac2 = 0;
- for (; mantSize > 0; mantSize -= 1) {
- c = *p;
- p += 1;
- if (c == '.') {
- c = *p;
- p += 1;
- }
- frac2 = 10*frac2 + (c - '0');
- }
-
- /*
- * Skim off the exponent.
- */
-
- p = pExp;
- if ((*p == 'E') || (*p == 'e')) {
- p++;
- if (*p == '-') {
- expSign = Qtrue;
- p++;
- }
- else {
- if (*p == '+') {
- p++;
- }
- expSign = Qfalse;
- }
- if (ISDIGIT(*p)) {
- do {
- exp = exp * 10 + (*p++ - '0');
- }
- while (ISDIGIT(*p));
- }
- else {
- p = pExp;
- }
- }
- if (expSign) {
- exp = fracExp - exp;
- }
- else {
- exp = fracExp + exp;
- }
-
- /*
- * Generate a floating-point number that represents the exponent.
- * Do this by processing the exponent one bit at a time to combine
- * many powers of 2 of 10. Then combine the exponent with the
- * fraction.
- */
-
- if (exp >= MDMAXEXPT) {
- errno = ERANGE;
- fraction = HUGE_VAL;
- goto ret;
- }
- else if (exp < MDMINEXPT) {
- errno = ERANGE;
- fraction = 0.0;
- goto ret;
- }
- fracExp = exp;
- exp += 9;
- if (exp < 0) {
- expSign = Qtrue;
- exp = -exp;
- }
- else {
- expSign = Qfalse;
- }
- dblExp = 1.0;
- for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
- if (exp & 01) {
- dblExp *= *d;
- }
- }
- if (expSign) {
- frac1 /= dblExp;
- }
- else {
- frac1 *= dblExp;
- }
- exp = fracExp;
- if (exp < 0) {
- expSign = Qtrue;
- exp = -exp;
- }
- else {
- expSign = Qfalse;
- }
- dblExp = 1.0;
- for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
- if (exp & 01) {
- dblExp *= *d;
- }
- }
- if (expSign) {
- frac2 /= dblExp;
- }
- else {
- frac2 *= dblExp;
- }
- fraction = frac1 + frac2;
- }
-
- ret:
- if (endPtr != NULL) {
- *endPtr = (char *)p;
- }
- if (sign) {
- return -fraction;
- }
- return fraction;
}
+
+#undef strtod
+#define strtod ruby_strtod
+#undef dtoa
+#define dtoa ruby_dtoa
+#undef hdtoa
+#define hdtoa ruby_hdtoa
+#include "missing/dtoa.c"