summaryrefslogtreecommitdiff
path: root/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'util.c')
-rw-r--r--util.c1014
1 files changed, 505 insertions, 509 deletions
diff --git a/util.c b/util.c
index 46fcf0ba79..4caa324849 100644
--- a/util.c
+++ b/util.c
@@ -3,449 +3,342 @@
util.c -
$Author$
- $Date$
created at: Fri Mar 10 17:22:34 JST 1995
- Copyright (C) 1993-2000 Yukihiro Matsumoto
+ Copyright (C) 1993-2008 Yukihiro Matsumoto
**********************************************************************/
-#include <stdio.h>
+#if defined __MINGW32__ || defined __MINGW64__
+# define MINGW_HAS_SECURE_API 1
+#endif
-#ifdef NT
-#include "missing/file.h"
+#ifndef __STDC_WANT_LIB_EXT1__
+#define __STDC_WANT_LIB_EXT1__ 1 /* for qsort_s() */
#endif
-#define RUBY_NO_INLINE
-#include "ruby.h"
+#include "ruby/internal/config.h"
-#include "util.h"
-#ifndef HAVE_STRING_H
-char *strchr _((char*,char));
+#include <ctype.h>
+#include <errno.h>
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+# include "missing/file.h"
#endif
+#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
-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;
-
- 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
-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[] = "0123456789abcdef0123456789ABCDEFx";
- 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
-
-#ifdef NT
-#include "missing/file.h"
-#endif
-
-#if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT)
-/*
- * 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;
+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;
- int slen;
- char buf[1024];
-
- if (RSTRING(str)->len > 1000)
- rb_fatal("Cannot do inplace edit on long filename (%d characters)",
- RSTRING(str)->len);
-
-#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
- /* 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
+ RBIMPL_ASSERT_OR_ASSUME(base >= 2);
+ RBIMPL_ASSERT_OR_ASSUME(base <= 36);
- /* Fooey, style 0 failed. Fix str before continuing. */
- RSTRING(str)->ptr[RSTRING(str)->len = slen] = '\0';
-#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(str)->ptr;
- 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++; }
-
- 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';
- } 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);
+ *overflow = 0;
+
+ if (!len) {
+ *retlen = 0;
+ return 0;
}
- rb_str_resize(str, strlen(buf));
- memcpy(RSTRING(str)->ptr, buf, RSTRING(str)->len);
+
+ do {
+ int d = ruby_digit36_to_number_table[(unsigned char)*str++];
+ if (d == -1 || base <= d) {
+ --str;
+ break;
+ }
+ 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(NT)
-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!
- */
+ 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.
- */
-
- if ((fd = _open(s, O_CREAT, 0666)) >= 0) {
- _close(fd);
- _unlink (s); /* don't leave it laying around */
- return 1;
+ while ((c = *str) && ISSPACE(c))
+ str++;
+
+ 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;
- 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*);
-struct PathInfo {
- struct PathList *head;
- int count;
+#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
+
+#if defined HAVE_BSD_QSORT_R
+struct bsd_qsort_r_args {
+ cmpfunc_t *cmp;
+ void *arg;
};
-static void
-push_element(char *path, struct PathInfo *info)
+static int
+cmp_bsd_qsort(void *d, const void *a, const void *b)
{
- struct PathList *p;
-
- 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_iglob(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
-
-/* mm.c */
-
-static int mmkind, mmsize, high, low;
-
-#define A ((int*)a)
-#define B ((int*)b)
-#define C ((int*)c)
-#define D ((int*)d)
-
-static void mmprepare(base, size) void *base; int size;
+#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)
{
-#ifdef DEBUG
- if (sizeof(int) != 4) die("sizeof(int) != 4");
- if (size <= 0) die("mmsize <= 0");
-#endif
+ if (!nel || !size) return; /* nothing to sort */
- if (((long)base & (4-1)) == 0 && ((long)base & (4-1)) == 0)
- if (size >= 16) mmkind = 1;
- else mmkind = 0;
- else mmkind = -1;
-
- mmsize = size;
- high = (size & (-16));
- low = (size & 0x0c);
+ /* 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 */
-static void mmswap(a, b) register char *a, *b;
+#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 (((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, 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;}}}
- }else{
- register char *t = a + mmsize;
+#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, 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) register char *a, *b, *c;
+/* 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;
- }while (a < t);
+#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;}}}
- }else{
- register char *t = a + mmsize;
+#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, s;
do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t);
}
}
+#define mmrot3(a,b,c) mmrot3_((a),(b),(c),mmarg)
/* qs6.c */
/*****************************************************/
@@ -457,166 +350,269 @@ static void mmrot3(a, b, c) register char *a, *b, *c;
/*****************************************************/
typedef struct { char *LL, *RR; } stack_node; /* Stack structure for L,l,R,r */
-#define PUSH(ll,rr) {top->LL = (ll); top->RR = (rr); ++top;} /* Push L,l,R,r */
-#define POP(ll,rr) {--top; ll = top->LL; rr = top->RR;} /* Pop 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)<0 ? \
- ((*cmp)(b,c)<0 ? b : ((*cmp)(a,c)<0 ? c : a)) : \
- ((*cmp)(b,c)>0 ? b : ((*cmp)(a,c)<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 (base, nel, size, cmp) void* base; int nel; int size; int (*cmp)();
+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 */
- 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 */
-
- if (nel <= 1) return; /* need not to sort */
- mmprepare(base, size);
- goto start;
-
- nxt:
- if (stack == top) return; /* return if stack is empty */
- POP(L,R);
-
- for (;;) {
- start:
- if (L + size == R) {if ((*cmp)(L,R) > 0) mmswap(L,R); goto nxt;}/* 2 elements */
-
- l = L; r = R;
- t = (r - l + size) / size; /* number of elements */
- m = l + size * (t >> 1); /* calculate median value */
-
- if (t >= 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);
- }
- }else{
- t = size*(t>>2); /* number of bytes in splitting 4 */
- m1 = l + t;
- m3 = m + t;
- }
- m = med3(m1, m, m3);
- }
-
- if ((t = (*cmp)(l,m)) < 0) { /*3-5-?*/
- if ((t = (*cmp)(m,r)) < 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) > 0) goto fail;
- goto nxt;
- }
- fail: goto loopA; /*3-5-7*/
- }
- if (t > 0) {
- if ((*cmp)(l,r) <= 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)) > 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) < 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) <= 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*/
- }
-
- if ((t = (*cmp)(m,r)) < 0) {goto loopA;} /*5-5-7*/
- if (t > 0) {mmswap(l,r); goto loopB;} /*5-5-3*/
-
- /* deteming splitting type in case 5-5-5 */ /*5-5-5*/
- for (;;) {
- if ((l += size) == r) goto nxt; /*5-5-5*/
- if (l == m) continue;
- if ((t = (*cmp)(l,m)) > 0) {mmswap(l,r); l = L; goto loopA;} /*575-5*/
- if (t < 0) {mmswap(L,l); l = L; goto loopB;} /*535-5*/
- }
-
- 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)) > 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)) < 0) {eq_l = 0; break;}
- if (t == 0) break;
- }
- mmswap(l,r); /* swap left and right */
- }
-
- 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)) < 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)) > 0) {eq_r = 0; break;}
- if (t == 0) break;
- }
- mmswap(l,r); /* swap left and right */
- }
-
- 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 */
- 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 */
- }
+ 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 current region */
+ char *R = (char*)base + size*(nel-1); /* right end of current region */
+ 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);
+ goto start;
+
+ nxt:
+ if (stack == top) return; /* return if stack is empty */
+ POP(L,R);
+
+ for (;;) {
+ start:
+ if (L + size == R) { /* 2 elements */
+ if ((*cmp)(L,R,d) > 0) mmswap(L,R);
+ goto nxt;
+ }
+
+ l = L; r = R;
+ n = (r - l + size) / size; /* number of elements */
+ m = l + size * (n >> 1); /* calculate median value */
+
+ if (n >= 60) {
+ register char *m1;
+ register char *m3;
+ 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 {
+ 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 (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*/
+ }
+ 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 (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*/
+ }
+ mmswap(l,r); goto loopA; /*7-5-5*/
+ }
+
+ if ((t = (*cmp)(m,r,d)) < 0) {goto loopA;} /*5-5-7*/
+ if (t > 0) {mmswap(l,r); goto loopB;} /*5-5-3*/
+
+ /* determining splitting type in case 5-5-5 */ /*5-5-5*/
+ for (;;) {
+ if ((l += size) == r) goto nxt; /*5-5-5*/
+ if (l == m) continue;
+ if ((t = (*cmp)(l,m,d)) > 0) {mmswap(l,r); l = L; goto loopA;}/*575-5*/
+ if (t < 0) {mmswap(L,l); l = L; goto loopB;} /*535-5*/
+ }
+
+ 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;
+ }
+ 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;
+ }
+ mmswap(l,r); /* swap left and right */
+ }
+
+ 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;
+ }
+ 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;
+ }
+ mmswap(l,r); /* swap left and right */
+ }
+
+ 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 */
+ 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(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);
- if (tmp == NULL) return NULL;
memcpy(tmp, str, len);
return tmp;
}
+
+#if defined HAVE_GETCWD
+# if defined NO_GETCWD_MALLOC
+
+char *
+ruby_getcwd(void)
+{
+ VALUE guard = rb_imemo_tmpbuf_new();
+ int size = 200;
+ char *buf = xmalloc(size);
+
+ while (!getcwd(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)) {
+ int e = errno;
+ xfree(buf);
+ rb_syserr_fail(e, "getwd");
+ }
+ return buf;
+}
+
+#endif
+
+void
+ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *arg)
+{
+ 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);
+ }
+}
+
+#undef strtod
+#define strtod ruby_strtod
+#undef dtoa
+#define dtoa ruby_dtoa
+#undef hdtoa
+#define hdtoa ruby_hdtoa
+#include "missing/dtoa.c"