diff options
Diffstat (limited to 'util.c')
| -rw-r--r-- | util.c | 1014 |
1 files changed, 505 insertions, 509 deletions
@@ -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" |
