diff options
Diffstat (limited to 'tests/examplefiles/example.c')
-rw-r--r-- | tests/examplefiles/example.c | 5334 |
1 files changed, 0 insertions, 5334 deletions
diff --git a/tests/examplefiles/example.c b/tests/examplefiles/example.c index 9f9c477d..67b8d17d 100644 --- a/tests/examplefiles/example.c +++ b/tests/examplefiles/example.c @@ -4507,5337 +4507,3 @@ bigsub(x, y) return z; } -static VALUE -bigadd(x, y, sign) - VALUE x, y; - char sign; -{ - VALUE z; - BDIGIT_DBL num; - long i, len; - - sign = (sign == RBIGNUM(y)->sign); - if (RBIGNUM(x)->sign != sign) { - if (sign) return bigsub(y, x); - return bigsub(x, y); - } - - if (RBIGNUM(x)->len > RBIGNUM(y)->len) { - len = RBIGNUM(x)->len + 1; - z = x; x = y; y = z; - } - else { - len = RBIGNUM(y)->len + 1; - } - z = bignew(len, sign); - - len = RBIGNUM(x)->len; - for (i = 0, num = 0; i < len; i++) { - num += (BDIGIT_DBL)BDIGITS(x)[i] + BDIGITS(y)[i]; - BDIGITS(z)[i] = BIGLO(num); - num = BIGDN(num); - } - len = RBIGNUM(y)->len; - while (num && i < len) { - num += BDIGITS(y)[i]; - BDIGITS(z)[i++] = BIGLO(num); - num = BIGDN(num); - } - while (i < len) { - BDIGITS(z)[i] = BDIGITS(y)[i]; - i++; - } - BDIGITS(z)[i] = (BDIGIT)num; - - return z; -} - -/* - * call-seq: - * big + other => Numeric - * - * Adds big and other, returning the result. - */ - -VALUE -rb_big_plus(x, y) - VALUE x, y; -{ - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - /* fall through */ - case T_BIGNUM: - return bignorm(bigadd(x, y, 1)); - - case T_FLOAT: - return rb_float_new(rb_big2dbl(x) + RFLOAT(y)->value); - - default: - return rb_num_coerce_bin(x, y); - } -} - -/* - * call-seq: - * big - other => Numeric - * - * Subtracts other from big, returning the result. - */ - -VALUE -rb_big_minus(x, y) - VALUE x, y; -{ - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - /* fall through */ - case T_BIGNUM: - return bignorm(bigadd(x, y, 0)); - - case T_FLOAT: - return rb_float_new(rb_big2dbl(x) - RFLOAT(y)->value); - - default: - return rb_num_coerce_bin(x, y); - } -} - -/* - * call-seq: - * big * other => Numeric - * - * Multiplies big and other, returning the result. - */ - -VALUE -rb_big_mul(x, y) - VALUE x, y; -{ - long i, j; - BDIGIT_DBL n = 0; - VALUE z; - BDIGIT *zds; - - if (FIXNUM_P(x)) x = rb_int2big(FIX2LONG(x)); - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - case T_FLOAT: - return rb_float_new(rb_big2dbl(x) * RFLOAT(y)->value); - - default: - return rb_num_coerce_bin(x, y); - } - - j = RBIGNUM(x)->len + RBIGNUM(y)->len + 1; - z = bignew(j, RBIGNUM(x)->sign==RBIGNUM(y)->sign); - zds = BDIGITS(z); - while (j--) zds[j] = 0; - for (i = 0; i < RBIGNUM(x)->len; i++) { - BDIGIT_DBL dd = BDIGITS(x)[i]; - if (dd == 0) continue; - n = 0; - for (j = 0; j < RBIGNUM(y)->len; j++) { - BDIGIT_DBL ee = n + (BDIGIT_DBL)dd * BDIGITS(y)[j]; - n = zds[i + j] + ee; - if (ee) zds[i + j] = BIGLO(n); - n = BIGDN(n); - } - if (n) { - zds[i + j] = n; - } - } - - return bignorm(z); -} - -static void -bigdivrem(x, y, divp, modp) - VALUE x, y; - VALUE *divp, *modp; -{ - long nx = RBIGNUM(x)->len, ny = RBIGNUM(y)->len; - long i, j; - VALUE yy, z; - BDIGIT *xds, *yds, *zds, *tds; - BDIGIT_DBL t2; - BDIGIT_DBL_SIGNED num; - BDIGIT dd, q; - - if (BIGZEROP(y)) rb_num_zerodiv(); - yds = BDIGITS(y); - if (nx < ny || (nx == ny && BDIGITS(x)[nx - 1] < BDIGITS(y)[ny - 1])) { - if (divp) *divp = rb_int2big(0); - if (modp) *modp = x; - return; - } - xds = BDIGITS(x); - if (ny == 1) { - dd = yds[0]; - z = rb_big_clone(x); - zds = BDIGITS(z); - t2 = 0; i = nx; - while (i--) { - t2 = BIGUP(t2) + zds[i]; - zds[i] = (BDIGIT)(t2 / dd); - t2 %= dd; - } - RBIGNUM(z)->sign = RBIGNUM(x)->sign==RBIGNUM(y)->sign; - if (modp) { - *modp = rb_uint2big((unsigned long)t2); - RBIGNUM(*modp)->sign = RBIGNUM(x)->sign; - } - if (divp) *divp = z; - return; - } - z = bignew(nx==ny?nx+2:nx+1, RBIGNUM(x)->sign==RBIGNUM(y)->sign); - zds = BDIGITS(z); - if (nx==ny) zds[nx+1] = 0; - while (!yds[ny-1]) ny--; - - dd = 0; - q = yds[ny-1]; - while ((q & (1<<(BITSPERDIG-1))) == 0) { - q <<= 1; - dd++; - } - if (dd) { - yy = rb_big_clone(y); - tds = BDIGITS(yy); - j = 0; - t2 = 0; - while (j<ny) { - t2 += (BDIGIT_DBL)yds[j]<<dd; - tds[j++] = BIGLO(t2); - t2 = BIGDN(t2); - } - yds = tds; - j = 0; - t2 = 0; - while (j<nx) { - t2 += (BDIGIT_DBL)xds[j]<<dd; - zds[j++] = BIGLO(t2); - t2 = BIGDN(t2); - } - zds[j] = (BDIGIT)t2; - } - else { - zds[nx] = 0; - j = nx; - while (j--) zds[j] = xds[j]; - } - - j = nx==ny?nx+1:nx; - do { - if (zds[j] == yds[ny-1]) q = BIGRAD-1; - else q = (BDIGIT)((BIGUP(zds[j]) + zds[j-1])/yds[ny-1]); - if (q) { - i = 0; num = 0; t2 = 0; - do { /* multiply and subtract */ - BDIGIT_DBL ee; - t2 += (BDIGIT_DBL)yds[i] * q; - ee = num - BIGLO(t2); - num = (BDIGIT_DBL)zds[j - ny + i] + ee; - if (ee) zds[j - ny + i] = BIGLO(num); - num = BIGDN(num); - t2 = BIGDN(t2); - } while (++i < ny); - num += zds[j - ny + i] - t2;/* borrow from high digit; don't update */ - while (num) { /* "add back" required */ - i = 0; num = 0; q--; - do { - BDIGIT_DBL ee = num + yds[i]; - num = (BDIGIT_DBL)zds[j - ny + i] + ee; - if (ee) zds[j - ny + i] = BIGLO(num); - num = BIGDN(num); - } while (++i < ny); - num--; - } - } - zds[j] = q; - } while (--j >= ny); - if (divp) { /* move quotient down in z */ - *divp = rb_big_clone(z); - zds = BDIGITS(*divp); - j = (nx==ny ? nx+2 : nx+1) - ny; - for (i = 0;i < j;i++) zds[i] = zds[i+ny]; - RBIGNUM(*divp)->len = i; - } - if (modp) { /* normalize remainder */ - *modp = rb_big_clone(z); - zds = BDIGITS(*modp); - while (--ny && !zds[ny]); ++ny; - if (dd) { - t2 = 0; i = ny; - while(i--) { - t2 = (t2 | zds[i]) >> dd; - q = zds[i]; - zds[i] = BIGLO(t2); - t2 = BIGUP(q); - } - } - RBIGNUM(*modp)->len = ny; - RBIGNUM(*modp)->sign = RBIGNUM(x)->sign; - } -} - -static void -bigdivmod(x, y, divp, modp) - VALUE x, y; - VALUE *divp, *modp; -{ - VALUE mod; - - bigdivrem(x, y, divp, &mod); - if (RBIGNUM(x)->sign != RBIGNUM(y)->sign && !BIGZEROP(mod)) { - if (divp) *divp = bigadd(*divp, rb_int2big(1), 0); - if (modp) *modp = bigadd(mod, y, 1); - } - else { - if (divp) *divp = *divp; - if (modp) *modp = mod; - } -} - -/* - * call-seq: - * big / other => Numeric - * big.div(other) => Numeric - * - * Divides big by other, returning the result. - */ - -static VALUE -rb_big_div(x, y) - VALUE x, y; -{ - VALUE z; - - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - case T_FLOAT: - return rb_float_new(rb_big2dbl(x) / RFLOAT(y)->value); - - default: - return rb_num_coerce_bin(x, y); - } - bigdivmod(x, y, &z, 0); - - return bignorm(z); -} - -/* - * call-seq: - * big % other => Numeric - * big.modulo(other) => Numeric - * - * Returns big modulo other. See Numeric.divmod for more - * information. - */ - -static VALUE -rb_big_modulo(x, y) - VALUE x, y; -{ - VALUE z; - - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - default: - return rb_num_coerce_bin(x, y); - } - bigdivmod(x, y, 0, &z); - - return bignorm(z); -} - -/* - * call-seq: - * big.remainder(numeric) => number - * - * Returns the remainder after dividing <i>big</i> by <i>numeric</i>. - * - * -1234567890987654321.remainder(13731) #=> -6966 - * -1234567890987654321.remainder(13731.24) #=> -9906.22531493148 - */ -static VALUE -rb_big_remainder(x, y) - VALUE x, y; -{ - VALUE z; - - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - default: - return rb_num_coerce_bin(x, y); - } - bigdivrem(x, y, 0, &z); - - return bignorm(z); -} - -/* - * call-seq: - * big.divmod(numeric) => array - * - * See <code>Numeric#divmod</code>. - * - */ -VALUE -rb_big_divmod(x, y) - VALUE x, y; -{ - VALUE div, mod; - - switch (TYPE(y)) { - case T_FIXNUM: - y = rb_int2big(FIX2LONG(y)); - break; - - case T_BIGNUM: - break; - - default: - return rb_num_coerce_bin(x, y); - } - bigdivmod(x, y, &div, &mod); - - return rb_assoc_new(bignorm(div), bignorm(mod)); -} - -/* - * call-seq: - * big.quo(numeric) -> float - * - * Returns the floating point result of dividing <i>big</i> by - * <i>numeric</i>. - * - * -1234567890987654321.quo(13731) #=> -89910996357705.5 - * -1234567890987654321.quo(13731.24) #=> -89909424858035.7 - * - */ - -static VALUE -rb_big_quo(x, y) - VALUE x, y; -{ - double dx = rb_big2dbl(x); - double dy; - - switch (TYPE(y)) { - case T_FIXNUM: - dy = (double)FIX2LONG(y); - break; - - case T_BIGNUM: - dy = rb_big2dbl(y); - break; - - case T_FLOAT: - dy = RFLOAT(y)->value; - break; - - default: - return rb_num_coerce_bin(x, y); - } - return rb_float_new(dx / dy); -} - -/* - * call-seq: - * big ** exponent #=> numeric - * - * Raises _big_ to the _exponent_ power (which may be an integer, float, - * or anything that will coerce to a number). The result may be - * a Fixnum, Bignum, or Float - * - * 123456789 ** 2 #=> 15241578750190521 - * 123456789 ** 1.2 #=> 5126464716.09932 - * 123456789 ** -2 #=> 6.5610001194102e-17 - */ - -VALUE -rb_big_pow(x, y) - VALUE x, y; -{ - double d; - long yy; - - if (y == INT2FIX(0)) return INT2FIX(1); - switch (TYPE(y)) { - case T_FLOAT: - d = RFLOAT(y)->value; - break; - - case T_BIGNUM: - rb_warn("in a**b, b may be too big"); - d = rb_big2dbl(y); - break; - - case T_FIXNUM: - yy = FIX2LONG(y); - if (yy > 0) { - VALUE z = x; - - for (;;) { - yy -= 1; - if (yy == 0) break; - while (yy % 2 == 0) { - yy /= 2; - x = rb_big_mul(x, x); - } - z = rb_big_mul(z, x); - } - return bignorm(z); - } - d = (double)yy; - break; - - default: - return rb_num_coerce_bin(x, y); - } - return rb_float_new(pow(rb_big2dbl(x), d)); -} - -/* - * call-seq: - * big & numeric => integer - * - * Performs bitwise +and+ between _big_ and _numeric_. - */ - -VALUE -rb_big_and(xx, yy) - VALUE xx, yy; -{ - volatile VALUE x, y, z; - BDIGIT *ds1, *ds2, *zds; - long i, l1, l2; - char sign; - - x = xx; - y = rb_to_int(yy); - if (FIXNUM_P(y)) { - y = rb_int2big(FIX2LONG(y)); - } - if (!RBIGNUM(y)->sign) { - y = rb_big_clone(y); - get2comp(y, Qtrue); - } - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - if (RBIGNUM(x)->len > RBIGNUM(y)->len) { - l1 = RBIGNUM(y)->len; - l2 = RBIGNUM(x)->len; - ds1 = BDIGITS(y); - ds2 = BDIGITS(x); - sign = RBIGNUM(y)->sign; - } - else { - l1 = RBIGNUM(x)->len; - l2 = RBIGNUM(y)->len; - ds1 = BDIGITS(x); - ds2 = BDIGITS(y); - sign = RBIGNUM(x)->sign; - } - z = bignew(l2, RBIGNUM(x)->sign || RBIGNUM(y)->sign); - zds = BDIGITS(z); - - for (i=0; i<l1; i++) { - zds[i] = ds1[i] & ds2[i]; - } - for (; i<l2; i++) { - zds[i] = sign?0:ds2[i]; - } - if (!RBIGNUM(z)->sign) get2comp(z, Qfalse); - return bignorm(z); -} - -/* - * call-seq: - * big | numeric => integer - * - * Performs bitwise +or+ between _big_ and _numeric_. - */ - -VALUE -rb_big_or(xx, yy) - VALUE xx, yy; -{ - volatile VALUE x, y, z; - BDIGIT *ds1, *ds2, *zds; - long i, l1, l2; - char sign; - - x = xx; - y = rb_to_int(yy); - if (FIXNUM_P(y)) { - y = rb_int2big(FIX2LONG(y)); - } - - if (!RBIGNUM(y)->sign) { - y = rb_big_clone(y); - get2comp(y, Qtrue); - } - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - if (RBIGNUM(x)->len > RBIGNUM(y)->len) { - l1 = RBIGNUM(y)->len; - l2 = RBIGNUM(x)->len; - ds1 = BDIGITS(y); - ds2 = BDIGITS(x); - sign = RBIGNUM(y)->sign; - } - else { - l1 = RBIGNUM(x)->len; - l2 = RBIGNUM(y)->len; - ds1 = BDIGITS(x); - ds2 = BDIGITS(y); - sign = RBIGNUM(x)->sign; - } - z = bignew(l2, RBIGNUM(x)->sign && RBIGNUM(y)->sign); - zds = BDIGITS(z); - - for (i=0; i<l1; i++) { - zds[i] = ds1[i] | ds2[i]; - } - for (; i<l2; i++) { - zds[i] = sign?ds2[i]:(BIGRAD-1); - } - if (!RBIGNUM(z)->sign) get2comp(z, Qfalse); - - return bignorm(z); -} - -/* - * call-seq: - * big ^ numeric => integer - * - * Performs bitwise +exclusive or+ between _big_ and _numeric_. - */ - -VALUE -rb_big_xor(xx, yy) - VALUE xx, yy; -{ - volatile VALUE x, y; - VALUE z; - BDIGIT *ds1, *ds2, *zds; - long i, l1, l2; - char sign; - - x = xx; - y = rb_to_int(yy); - if (FIXNUM_P(y)) { - y = rb_int2big(FIX2LONG(y)); - } - - if (!RBIGNUM(y)->sign) { - y = rb_big_clone(y); - get2comp(y, Qtrue); - } - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - if (RBIGNUM(x)->len > RBIGNUM(y)->len) { - l1 = RBIGNUM(y)->len; - l2 = RBIGNUM(x)->len; - ds1 = BDIGITS(y); - ds2 = BDIGITS(x); - sign = RBIGNUM(y)->sign; - } - else { - l1 = RBIGNUM(x)->len; - l2 = RBIGNUM(y)->len; - ds1 = BDIGITS(x); - ds2 = BDIGITS(y); - sign = RBIGNUM(x)->sign; - } - RBIGNUM(x)->sign = RBIGNUM(x)->sign?1:0; - RBIGNUM(y)->sign = RBIGNUM(y)->sign?1:0; - z = bignew(l2, !(RBIGNUM(x)->sign ^ RBIGNUM(y)->sign)); - zds = BDIGITS(z); - - for (i=0; i<l1; i++) { - zds[i] = ds1[i] ^ ds2[i]; - } - for (; i<l2; i++) { - zds[i] = sign?ds2[i]:~ds2[i]; - } - if (!RBIGNUM(z)->sign) get2comp(z, Qfalse); - - return bignorm(z); -} - -static VALUE rb_big_rshift _((VALUE,VALUE)); - -/* - * call-seq: - * big << numeric => integer - * - * Shifts big left _numeric_ positions (right if _numeric_ is negative). - */ - -VALUE -rb_big_lshift(x, y) - VALUE x, y; -{ - BDIGIT *xds, *zds; - int shift = NUM2INT(y); - int s1 = shift/BITSPERDIG; - int s2 = shift%BITSPERDIG; - VALUE z; - BDIGIT_DBL num = 0; - long len, i; - - if (shift < 0) return rb_big_rshift(x, INT2FIX(-shift)); - len = RBIGNUM(x)->len; - z = bignew(len+s1+1, RBIGNUM(x)->sign); - zds = BDIGITS(z); - for (i=0; i<s1; i++) { - *zds++ = 0; - } - xds = BDIGITS(x); - for (i=0; i<len; i++) { - num = num | (BDIGIT_DBL)*xds++<<s2; - *zds++ = BIGLO(num); - num = BIGDN(num); - } - *zds = BIGLO(num); - return bignorm(z); -} - -/* - * call-seq: - * big >> numeric => integer - * - * Shifts big right _numeric_ positions (left if _numeric_ is negative). - */ - -static VALUE -rb_big_rshift(x, y) - VALUE x, y; -{ - BDIGIT *xds, *zds; - int shift = NUM2INT(y); - long s1 = shift/BITSPERDIG; - long s2 = shift%BITSPERDIG; - VALUE z; - BDIGIT_DBL num = 0; - long i, j; - - if (shift < 0) return rb_big_lshift(x, INT2FIX(-shift)); - - if (s1 > RBIGNUM(x)->len) { - if (RBIGNUM(x)->sign) - return INT2FIX(0); - else - return INT2FIX(-1); - } - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - xds = BDIGITS(x); - i = RBIGNUM(x)->len; j = i - s1; - z = bignew(j, RBIGNUM(x)->sign); - if (!RBIGNUM(x)->sign) { - num = ((BDIGIT_DBL)~0) << BITSPERDIG; - } - zds = BDIGITS(z); - while (i--, j--) { - num = (num | xds[i]) >> s2; - zds[j] = BIGLO(num); - num = BIGUP(xds[i]); - } - if (!RBIGNUM(x)->sign) { - get2comp(z, Qfalse); - } - return bignorm(z); -} - -/* - * call-seq: - * big[n] -> 0, 1 - * - * Bit Reference---Returns the <em>n</em>th bit in the (assumed) binary - * representation of <i>big</i>, where <i>big</i>[0] is the least - * significant bit. - * - * a = 9**15 - * 50.downto(0) do |n| - * print a[n] - * end - * - * <em>produces:</em> - * - * 000101110110100000111000011110010100111100010111001 - * - */ - -static VALUE -rb_big_aref(x, y) - VALUE x, y; -{ - BDIGIT *xds; - int shift; - long s1, s2; - - if (TYPE(y) == T_BIGNUM) { - if (!RBIGNUM(y)->sign || RBIGNUM(x)->sign) - return INT2FIX(0); - return INT2FIX(1); - } - shift = NUM2INT(y); - if (shift < 0) return INT2FIX(0); - s1 = shift/BITSPERDIG; - s2 = shift%BITSPERDIG; - - if (!RBIGNUM(x)->sign) { - if (s1 >= RBIGNUM(x)->len) return INT2FIX(1); - x = rb_big_clone(x); - get2comp(x, Qtrue); - } - else { - if (s1 >= RBIGNUM(x)->len) return INT2FIX(0); - } - xds = BDIGITS(x); - if (xds[s1] & (1<<s2)) - return INT2FIX(1); - return INT2FIX(0); -} - -/* - * call-seq: - * big.hash => fixnum - * - * Compute a hash based on the value of _big_. - */ - -static VALUE -rb_big_hash(x) - VALUE x; -{ - long i, len, key; - BDIGIT *digits; - - key = 0; digits = BDIGITS(x); len = RBIGNUM(x)->len; - for (i=0; i<len; i++) { - key ^= *digits++; - } - return LONG2FIX(key); -} - -/* - * MISSING: documentation - */ - -static VALUE -rb_big_coerce(x, y) - VALUE x, y; -{ - if (FIXNUM_P(y)) { - return rb_assoc_new(rb_int2big(FIX2LONG(y)), x); - } - else { - rb_raise(rb_eTypeError, "can't coerce %s to Bignum", - rb_obj_classname(y)); - } - /* not reached */ - return Qnil; -} - -/* - * call-seq: - * big.abs -> aBignum - * - * Returns the absolute value of <i>big</i>. - * - * -1234567890987654321.abs #=> 1234567890987654321 - */ - -static VALUE -rb_big_abs(x) - VALUE x; -{ - if (!RBIGNUM(x)->sign) { - x = rb_big_clone(x); - RBIGNUM(x)->sign = 1; - } - return x; -} - -VALUE -rb_big_rand(max, rand_buf) - VALUE max; - double *rand_buf; -{ - VALUE v; - long len = RBIGNUM(max)->len; - - if (BIGZEROP(max)) { - return rb_float_new(rand_buf[0]); - } - v = bignew(len,1); - len--; - BDIGITS(v)[len] = BDIGITS(max)[len] * rand_buf[len]; - while (len--) { - BDIGITS(v)[len] = ((BDIGIT)~0) * rand_buf[len]; - } - - return v; -} - -/* - * call-seq: - * big.size -> integer - * - * Returns the number of bytes in the machine representation of - * <i>big</i>. - * - * (256**10 - 1).size #=> 12 - * (256**20 - 1).size #=> 20 - * (256**40 - 1).size #=> 40 - */ - -static VALUE -rb_big_size(big) - VALUE big; -{ - return LONG2FIX(RBIGNUM(big)->len*SIZEOF_BDIGITS); -} - -/* - * Bignum objects hold integers outside the range of - * Fixnum. Bignum objects are created - * automatically when integer calculations would otherwise overflow a - * Fixnum. When a calculation involving - * Bignum objects returns a result that will fit in a - * Fixnum, the result is automatically converted. - * - * For the purposes of the bitwise operations and <code>[]</code>, a - * Bignum is treated as if it were an infinite-length - * bitstring with 2's complement representation. - * - * While Fixnum values are immediate, Bignum - * objects are not---assignment and parameter passing work with - * references to objects, not the objects themselves. - * - */ - -void -Init_Bignum() -{ - rb_cBignum = rb_define_class("Bignum", rb_cInteger); - - rb_define_method(rb_cBignum, "to_s", rb_big_to_s, -1); - rb_define_method(rb_cBignum, "coerce", rb_big_coerce, 1); - rb_define_method(rb_cBignum, "-@", rb_big_uminus, 0); - rb_define_method(rb_cBignum, "+", rb_big_plus, 1); - rb_define_method(rb_cBignum, "-", rb_big_minus, 1); - rb_define_method(rb_cBignum, "*", rb_big_mul, 1); - rb_define_method(rb_cBignum, "/", rb_big_div, 1); - rb_define_method(rb_cBignum, "%", rb_big_modulo, 1); - rb_define_method(rb_cBignum, "div", rb_big_div, 1); - rb_define_method(rb_cBignum, "divmod", rb_big_divmod, 1); - rb_define_method(rb_cBignum, "modulo", rb_big_modulo, 1); - rb_define_method(rb_cBignum, "remainder", rb_big_remainder, 1); - rb_define_method(rb_cBignum, "quo", rb_big_quo, 1); - rb_define_method(rb_cBignum, "**", rb_big_pow, 1); - rb_define_method(rb_cBignum, "&", rb_big_and, 1); - rb_define_method(rb_cBignum, "|", rb_big_or, 1); - rb_define_method(rb_cBignum, "^", rb_big_xor, 1); - rb_define_method(rb_cBignum, "~", rb_big_neg, 0); - rb_define_method(rb_cBignum, "<<", rb_big_lshift, 1); - rb_define_method(rb_cBignum, ">>", rb_big_rshift, 1); - rb_define_method(rb_cBignum, "[]", rb_big_aref, 1); - - rb_define_method(rb_cBignum, "<=>", rb_big_cmp, 1); - rb_define_method(rb_cBignum, "==", rb_big_eq, 1); - rb_define_method(rb_cBignum, "eql?", rb_big_eql, 1); - rb_define_method(rb_cBignum, "hash", rb_big_hash, 0); - rb_define_method(rb_cBignum, "to_f", rb_big_to_f, 0); - rb_define_method(rb_cBignum, "abs", rb_big_abs, 0); - rb_define_method(rb_cBignum, "size", rb_big_size, 0); -} -/********************************************************************** - - class.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Tue Aug 10 15:05:44 JST 1993 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - -**********************************************************************/ - -#include "ruby.h" -#include "rubysig.h" -#include "node.h" -#include "st.h" -#include <ctype.h> - -extern st_table *rb_class_tbl; - -VALUE -rb_class_boot(super) - VALUE super; -{ - NEWOBJ(klass, struct RClass); - OBJSETUP(klass, rb_cClass, T_CLASS); - - klass->super = super; - klass->iv_tbl = 0; - klass->m_tbl = 0; /* safe GC */ - klass->m_tbl = st_init_numtable(); - - OBJ_INFECT(klass, super); - return (VALUE)klass; -} - -void -rb_check_inheritable(super) - VALUE super; -{ - if (TYPE(super) != T_CLASS) { - rb_raise(rb_eTypeError, "superclass must be a Class (%s given)", - rb_obj_classname(super)); - } - if (RBASIC(super)->flags & FL_SINGLETON) { - rb_raise(rb_eTypeError, "can't make subclass of singleton class"); - } -} - -VALUE -rb_class_new(super) - VALUE super; -{ - Check_Type(super, T_CLASS); - rb_check_inheritable(super); - if (super == rb_cClass) { - rb_raise(rb_eTypeError, "can't make subclass of Class"); - } - return rb_class_boot(super); -} - -static int -clone_method(mid, body, tbl) - ID mid; - NODE *body; - st_table *tbl; -{ - st_insert(tbl, mid, (st_data_t)NEW_METHOD(body->nd_body, body->nd_noex)); - return ST_CONTINUE; -} - -/* :nodoc: */ -VALUE -rb_mod_init_copy(clone, orig) - VALUE clone, orig; -{ - rb_obj_init_copy(clone, orig); - if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { - RBASIC(clone)->klass = rb_singleton_class_clone(orig); - } - RCLASS(clone)->super = RCLASS(orig)->super; - if (RCLASS(orig)->iv_tbl) { - ID id; - - RCLASS(clone)->iv_tbl = st_copy(RCLASS(orig)->iv_tbl); - id = rb_intern("__classpath__"); - st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0); - id = rb_intern("__classid__"); - st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0); - } - if (RCLASS(orig)->m_tbl) { - RCLASS(clone)->m_tbl = st_init_numtable(); - st_foreach(RCLASS(orig)->m_tbl, clone_method, - (st_data_t)RCLASS(clone)->m_tbl); - } - - return clone; -} - -/* :nodoc: */ -VALUE -rb_class_init_copy(clone, orig) - VALUE clone, orig; -{ - if (RCLASS(clone)->super != 0) { - rb_raise(rb_eTypeError, "already initialized class"); - } - return rb_mod_init_copy(clone, orig); -} - -VALUE -rb_singleton_class_clone(obj) - VALUE obj; -{ - VALUE klass = RBASIC(obj)->klass; - - if (!FL_TEST(klass, FL_SINGLETON)) - return klass; - else { - /* copy singleton(unnamed) class */ - NEWOBJ(clone, struct RClass); - OBJSETUP(clone, 0, RBASIC(klass)->flags); - - if (BUILTIN_TYPE(obj) == T_CLASS) { - RBASIC(clone)->klass = (VALUE)clone; - } - else { - RBASIC(clone)->klass = rb_singleton_class_clone(klass); - } - - clone->super = RCLASS(klass)->super; - clone->iv_tbl = 0; - clone->m_tbl = 0; - if (RCLASS(klass)->iv_tbl) { - clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl); - } - clone->m_tbl = st_init_numtable(); - st_foreach(RCLASS(klass)->m_tbl, clone_method, - (st_data_t)clone->m_tbl); - rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); - FL_SET(clone, FL_SINGLETON); - return (VALUE)clone; - } -} - -void -rb_singleton_class_attached(klass, obj) - VALUE klass, obj; -{ - if (FL_TEST(klass, FL_SINGLETON)) { - if (!RCLASS(klass)->iv_tbl) { - RCLASS(klass)->iv_tbl = st_init_numtable(); - } - st_insert(RCLASS(klass)->iv_tbl, rb_intern("__attached__"), obj); - } -} - -VALUE -rb_make_metaclass(obj, super) - VALUE obj, super; -{ - if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) { - return RBASIC(obj)->klass = rb_cClass; - } - else { - VALUE metasuper; - VALUE klass = rb_class_boot(super); - - FL_SET(klass, FL_SINGLETON); - RBASIC(obj)->klass = klass; - rb_singleton_class_attached(klass, obj); - - metasuper = RBASIC(rb_class_real(super))->klass; - /* metaclass of a superclass may be NULL at boot time */ - if (metasuper) { - RBASIC(klass)->klass = metasuper; - } - return klass; - } -} - -VALUE -rb_define_class_id(id, super) - ID id; - VALUE super; -{ - VALUE klass; - - if (!super) super = rb_cObject; - klass = rb_class_new(super); - rb_make_metaclass(klass, RBASIC(super)->klass); - - return klass; -} - -VALUE -rb_class_inherited(super, klass) - VALUE super, klass; -{ - if (!super) super = rb_cObject; - return rb_funcall(super, rb_intern("inherited"), 1, klass); -} - -VALUE -rb_define_class(name, super) - const char *name; - VALUE super; -{ - VALUE klass; - ID id; - - id = rb_intern(name); - if (rb_const_defined(rb_cObject, id)) { - klass = rb_const_get(rb_cObject, id); - if (TYPE(klass) != T_CLASS) { - rb_raise(rb_eTypeError, "%s is not a class", name); - } - if (rb_class_real(RCLASS(klass)->super) != super) { - rb_name_error(id, "%s is already defined", name); - } - return klass; - } - if (!super) { - rb_warn("no super class for `%s', Object assumed", name); - } - klass = rb_define_class_id(id, super); - st_add_direct(rb_class_tbl, id, klass); - rb_name_class(klass, id); - rb_const_set(rb_cObject, id, klass); - rb_class_inherited(super, klass); - - return klass; -} - -VALUE -rb_define_class_under(outer, name, super) - VALUE outer; - const char *name; - VALUE super; -{ - VALUE klass; - ID id; - - id = rb_intern(name); - if (rb_const_defined_at(outer, id)) { - klass = rb_const_get_at(outer, id); - if (TYPE(klass) != T_CLASS) { - rb_raise(rb_eTypeError, "%s is not a class", name); - } - if (rb_class_real(RCLASS(klass)->super) != super) { - rb_name_error(id, "%s is already defined", name); - } - return klass; - } - if (!super) { - rb_warn("no super class for `%s::%s', Object assumed", - rb_class2name(outer), name); - } - klass = rb_define_class_id(id, super); - rb_set_class_path(klass, outer, name); - rb_const_set(outer, id, klass); - rb_class_inherited(super, klass); - - return klass; -} - -VALUE -rb_module_new() -{ - NEWOBJ(mdl, struct RClass); - OBJSETUP(mdl, rb_cModule, T_MODULE); - - mdl->super = 0; - mdl->iv_tbl = 0; - mdl->m_tbl = 0; - mdl->m_tbl = st_init_numtable(); - - return (VALUE)mdl; -} - -VALUE -rb_define_module_id(id) - ID id; -{ - VALUE mdl; - - mdl = rb_module_new(); - rb_name_class(mdl, id); - - return mdl; -} - -VALUE -rb_define_module(name) - const char *name; -{ - VALUE module; - ID id; - - id = rb_intern(name); - if (rb_const_defined(rb_cObject, id)) { - module = rb_const_get(rb_cObject, id); - if (TYPE(module) == T_MODULE) - return module; - rb_raise(rb_eTypeError, "%s is not a module", rb_obj_classname(module)); - } - module = rb_define_module_id(id); - st_add_direct(rb_class_tbl, id, module); - rb_const_set(rb_cObject, id, module); - - return module; -} - -VALUE -rb_define_module_under(outer, name) - VALUE outer; - const char *name; -{ - VALUE module; - ID id; - - id = rb_intern(name); - if (rb_const_defined_at(outer, id)) { - module = rb_const_get_at(outer, id); - if (TYPE(module) == T_MODULE) - return module; - rb_raise(rb_eTypeError, "%s::%s is not a module", - rb_class2name(outer), rb_obj_classname(module)); - } - module = rb_define_module_id(id); - rb_const_set(outer, id, module); - rb_set_class_path(module, outer, name); - - return module; -} - -static VALUE -include_class_new(module, super) - VALUE module, super; -{ - NEWOBJ(klass, struct RClass); - OBJSETUP(klass, rb_cClass, T_ICLASS); - - if (BUILTIN_TYPE(module) == T_ICLASS) { - module = RBASIC(module)->klass; - } - if (!RCLASS(module)->iv_tbl) { - RCLASS(module)->iv_tbl = st_init_numtable(); - } - klass->iv_tbl = RCLASS(module)->iv_tbl; - klass->m_tbl = RCLASS(module)->m_tbl; - klass->super = super; - if (TYPE(module) == T_ICLASS) { - RBASIC(klass)->klass = RBASIC(module)->klass; - } - else { - RBASIC(klass)->klass = module; - } - OBJ_INFECT(klass, module); - OBJ_INFECT(klass, super); - - return (VALUE)klass; -} - -void -rb_include_module(klass, module) - VALUE klass, module; -{ - VALUE p, c; - int changed = 0; - - rb_frozen_class_p(klass); - if (!OBJ_TAINTED(klass)) { - rb_secure(4); - } - - if (NIL_P(module)) return; - if (klass == module) return; - - if (TYPE(module) != T_MODULE) { - Check_Type(module, T_MODULE); - } - - OBJ_INFECT(klass, module); - c = klass; - while (module) { - int superclass_seen = Qfalse; - - if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl) - rb_raise(rb_eArgError, "cyclic include detected"); - /* ignore if the module included already in superclasses */ - for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) { - switch (BUILTIN_TYPE(p)) { - case T_ICLASS: - if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) { - if (!superclass_seen) { - c = p; /* move insertion point */ - } - goto skip; - } - break; - case T_CLASS: - superclass_seen = Qtrue; - break; - } - } - c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super); - changed = 1; - skip: - module = RCLASS(module)->super; - } - if (changed) rb_clear_cache(); -} - -/* - * call-seq: - * mod.included_modules -> array - * - * Returns the list of modules included in <i>mod</i>. - * - * module Mixin - * end - * - * module Outer - * include Mixin - * end - * - * Mixin.included_modules #=> [] - * Outer.included_modules #=> [Mixin] - */ - -VALUE -rb_mod_included_modules(mod) - VALUE mod; -{ - VALUE ary = rb_ary_new(); - VALUE p; - - for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) { - if (BUILTIN_TYPE(p) == T_ICLASS) { - rb_ary_push(ary, RBASIC(p)->klass); - } - } - return ary; -} - -/* - * call-seq: - * mod.include?(module) => true or false - * - * Returns <code>true</code> if <i>module</i> is included in - * <i>mod</i> or one of <i>mod</i>'s ancestors. - * - * module A - * end - * class B - * include A - * end - * class C < B - * end - * B.include?(A) #=> true - * C.include?(A) #=> true - * A.include?(A) #=> false - */ - -VALUE -rb_mod_include_p(mod, mod2) - VALUE mod; - VALUE mod2; -{ - VALUE p; - - Check_Type(mod2, T_MODULE); - for (p = RCLASS(mod)->super; p; p = RCLASS(p)->super) { - if (BUILTIN_TYPE(p) == T_ICLASS) { - if (RBASIC(p)->klass == mod2) return Qtrue; - } - } - return Qfalse; -} - -/* - * call-seq: - * mod.ancestors -> array - * - * Returns a list of modules included in <i>mod</i> (including - * <i>mod</i> itself). - * - * module Mod - * include Math - * include Comparable - * end - * - * Mod.ancestors #=> [Mod, Comparable, Math] - * Math.ancestors #=> [Math] - */ - -VALUE -rb_mod_ancestors(mod) - VALUE mod; -{ - VALUE p, ary = rb_ary_new(); - - for (p = mod; p; p = RCLASS(p)->super) { - if (FL_TEST(p, FL_SINGLETON)) - continue; - if (BUILTIN_TYPE(p) == T_ICLASS) { - rb_ary_push(ary, RBASIC(p)->klass); - } - else { - rb_ary_push(ary, p); - } - } - return ary; -} - -#define VISI(x) ((x)&NOEX_MASK) -#define VISI_CHECK(x,f) (VISI(x) == (f)) - -static int -ins_methods_push(name, type, ary, visi) - ID name; - long type; - VALUE ary; - long visi; -{ - if (type == -1) return ST_CONTINUE; - switch (visi) { - case NOEX_PRIVATE: - case NOEX_PROTECTED: - case NOEX_PUBLIC: - visi = (type == visi); - break; - default: - visi = (type != NOEX_PRIVATE); - break; - } - if (visi) { - rb_ary_push(ary, rb_str_new2(rb_id2name(name))); - } - return ST_CONTINUE; -} - -static int -ins_methods_i(name, type, ary) - ID name; - long type; - VALUE ary; -{ - return ins_methods_push(name, type, ary, -1); /* everything but private */ -} - -static int -ins_methods_prot_i(name, type, ary) - ID name; - long type; - VALUE ary; -{ - return ins_methods_push(name, type, ary, NOEX_PROTECTED); -} - -static int -ins_methods_priv_i(name, type, ary) - ID name; - long type; - VALUE ary; -{ - return ins_methods_push(name, type, ary, NOEX_PRIVATE); -} - -static int -ins_methods_pub_i(name, type, ary) - ID name; - long type; - VALUE ary; -{ - return ins_methods_push(name, type, ary, NOEX_PUBLIC); -} - -static int -method_entry(key, body, list) - ID key; - NODE *body; - st_table *list; -{ - long type; - - if (key == ID_ALLOCATOR) return ST_CONTINUE; - if (!st_lookup(list, key, 0)) { - if (!body->nd_body) type = -1; /* none */ - else type = VISI(body->nd_noex); - st_add_direct(list, key, type); - } - return ST_CONTINUE; -} - -static VALUE -class_instance_method_list(argc, argv, mod, func) - int argc; - VALUE *argv; - VALUE mod; - int (*func) _((ID, long, VALUE)); -{ - VALUE ary; - int recur; - st_table *list; - - if (argc == 0) { - recur = Qtrue; - } - else { - VALUE r; - rb_scan_args(argc, argv, "01", &r); - recur = RTEST(r); - } - - list = st_init_numtable(); - for (; mod; mod = RCLASS(mod)->super) { - st_foreach(RCLASS(mod)->m_tbl, method_entry, (st_data_t)list); - if (BUILTIN_TYPE(mod) == T_ICLASS) continue; - if (FL_TEST(mod, FL_SINGLETON)) continue; - if (!recur) break; - } - ary = rb_ary_new(); - st_foreach(list, func, ary); - st_free_table(list); - - return ary; -} - -/* - * call-seq: - * mod.instance_methods(include_super=true) => array - * - * Returns an array containing the names of public instance methods in - * the receiver. For a module, these are the public methods; for a - * class, they are the instance (not singleton) methods. With no - * argument, or with an argument that is <code>false</code>, the - * instance methods in <i>mod</i> are returned, otherwise the methods - * in <i>mod</i> and <i>mod</i>'s superclasses are returned. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * def method3() end - * end - * - * A.instance_methods #=> ["method1"] - * B.instance_methods(false) #=> ["method2"] - * C.instance_methods(false) #=> ["method3"] - * C.instance_methods(true).length #=> 43 - */ - -VALUE -rb_class_instance_methods(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - return class_instance_method_list(argc, argv, mod, ins_methods_i); -} - -/* - * call-seq: - * mod.protected_instance_methods(include_super=true) => array - * - * Returns a list of the protected instance methods defined in - * <i>mod</i>. If the optional parameter is not <code>false</code>, the - * methods of any ancestors are included. - */ - -VALUE -rb_class_protected_instance_methods(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - return class_instance_method_list(argc, argv, mod, ins_methods_prot_i); -} - -/* - * call-seq: - * mod.private_instance_methods(include_super=true) => array - * - * Returns a list of the private instance methods defined in - * <i>mod</i>. If the optional parameter is not <code>false</code>, the - * methods of any ancestors are included. - * - * module Mod - * def method1() end - * private :method1 - * def method2() end - * end - * Mod.instance_methods #=> ["method2"] - * Mod.private_instance_methods #=> ["method1"] - */ - -VALUE -rb_class_private_instance_methods(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - return class_instance_method_list(argc, argv, mod, ins_methods_priv_i); -} - -/* - * call-seq: - * mod.public_instance_methods(include_super=true) => array - * - * Returns a list of the public instance methods defined in <i>mod</i>. - * If the optional parameter is not <code>false</code>, the methods of - * any ancestors are included. - */ - -VALUE -rb_class_public_instance_methods(argc, argv, mod) - int argc; - VALUE *argv; - VALUE mod; -{ - return class_instance_method_list(argc, argv, mod, ins_methods_pub_i); -} - -/* - * call-seq: - * obj.singleton_methods(all=true) => array - * - * Returns an array of the names of singleton methods for <i>obj</i>. - * If the optional <i>all</i> parameter is true, the list will include - * methods in modules included in <i>obj</i>. - * - * module Other - * def three() end - * end - * - * class Single - * def Single.four() end - * end - * - * a = Single.new - * - * def a.one() - * end - * - * class << a - * include Other - * def two() - * end - * end - * - * Single.singleton_methods #=> ["four"] - * a.singleton_methods(false) #=> ["two", "one"] - * a.singleton_methods #=> ["two", "one", "three"] - */ - -VALUE -rb_obj_singleton_methods(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE recur, ary, klass; - st_table *list; - - rb_scan_args(argc, argv, "01", &recur); - if (argc == 0) { - recur = Qtrue; - } - klass = CLASS_OF(obj); - list = st_init_numtable(); - if (klass && FL_TEST(klass, FL_SINGLETON)) { - st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list); - klass = RCLASS(klass)->super; - } - if (RTEST(recur)) { - while (klass && (FL_TEST(klass, FL_SINGLETON) || TYPE(klass) == T_ICLASS)) { - st_foreach(RCLASS(klass)->m_tbl, method_entry, (st_data_t)list); - klass = RCLASS(klass)->super; - } - } - ary = rb_ary_new(); - st_foreach(list, ins_methods_i, ary); - st_free_table(list); - - return ary; -} - -void -rb_define_method_id(klass, name, func, argc) - VALUE klass; - ID name; - VALUE (*func)(); - int argc; -{ - rb_add_method(klass, name, NEW_CFUNC(func,argc), NOEX_PUBLIC); -} - -void -rb_define_method(klass, name, func, argc) - VALUE klass; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PUBLIC); -} - -void -rb_define_protected_method(klass, name, func, argc) - VALUE klass; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PROTECTED); -} - -void -rb_define_private_method(klass, name, func, argc) - VALUE klass; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_add_method(klass, rb_intern(name), NEW_CFUNC(func, argc), NOEX_PRIVATE); -} - -void -rb_undef_method(klass, name) - VALUE klass; - const char *name; -{ - rb_add_method(klass, rb_intern(name), 0, NOEX_UNDEF); -} - -#define SPECIAL_SINGLETON(x,c) do {\ - if (obj == (x)) {\ - return c;\ - }\ -} while (0) - -VALUE -rb_singleton_class(obj) - VALUE obj; -{ - VALUE klass; - - if (FIXNUM_P(obj) || SYMBOL_P(obj)) { - rb_raise(rb_eTypeError, "can't define singleton"); - } - if (rb_special_const_p(obj)) { - SPECIAL_SINGLETON(Qnil, rb_cNilClass); - SPECIAL_SINGLETON(Qfalse, rb_cFalseClass); - SPECIAL_SINGLETON(Qtrue, rb_cTrueClass); - rb_bug("unknown immediate %ld", obj); - } - - DEFER_INTS; - if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) && - rb_iv_get(RBASIC(obj)->klass, "__attached__") == obj) { - klass = RBASIC(obj)->klass; - } - else { - klass = rb_make_metaclass(obj, RBASIC(obj)->klass); - } - if (OBJ_TAINTED(obj)) { - OBJ_TAINT(klass); - } - else { - FL_UNSET(klass, FL_TAINT); - } - if (OBJ_FROZEN(obj)) OBJ_FREEZE(klass); - ALLOW_INTS; - - return klass; -} - -void -rb_define_singleton_method(obj, name, func, argc) - VALUE obj; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_define_method(rb_singleton_class(obj), name, func, argc); -} - -void -rb_define_module_function(module, name, func, argc) - VALUE module; - const char *name; - VALUE (*func)(); - int argc; -{ - rb_define_private_method(module, name, func, argc); - rb_define_singleton_method(module, name, func, argc); -} - -void -rb_define_global_function(name, func, argc) - const char *name; - VALUE (*func)(); - int argc; -{ - rb_define_module_function(rb_mKernel, name, func, argc); -} - -void -rb_define_alias(klass, name1, name2) - VALUE klass; - const char *name1, *name2; -{ - rb_alias(klass, rb_intern(name1), rb_intern(name2)); -} - -void -rb_define_attr(klass, name, read, write) - VALUE klass; - const char *name; - int read, write; -{ - rb_attr(klass, rb_intern(name), read, write, Qfalse); -} - -#ifdef HAVE_STDARG_PROTOTYPES -#include <stdarg.h> -#define va_init_list(a,b) va_start(a,b) -#else -#include <varargs.h> -#define va_init_list(a,b) va_start(a) -#endif - -int -#ifdef HAVE_STDARG_PROTOTYPES -rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...) -#else -rb_scan_args(argc, argv, fmt, va_alist) - int argc; - const VALUE *argv; - const char *fmt; - va_dcl -#endif -{ - int n, i = 0; - const char *p = fmt; - VALUE *var; - va_list vargs; - - va_init_list(vargs, fmt); - - if (*p == '*') goto rest_arg; - - if (ISDIGIT(*p)) { - n = *p - '0'; - if (n > argc) - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, n); - for (i=0; i<n; i++) { - var = va_arg(vargs, VALUE*); - if (var) *var = argv[i]; - } - p++; - } - else { - goto error; - } - - if (ISDIGIT(*p)) { - n = i + *p - '0'; - for (; i<n; i++) { - var = va_arg(vargs, VALUE*); - if (argc > i) { - if (var) *var = argv[i]; - } - else { - if (var) *var = Qnil; - } - } - p++; - } - - if(*p == '*') { - rest_arg: - var = va_arg(vargs, VALUE*); - if (argc > i) { - if (var) *var = rb_ary_new4(argc-i, argv+i); - i = argc; - } - else { - if (var) *var = rb_ary_new(); - } - p++; - } - - if (*p == '&') { - var = va_arg(vargs, VALUE*); - if (rb_block_given_p()) { - *var = rb_block_proc(); - } - else { - *var = Qnil; - } - p++; - } - va_end(vargs); - - if (*p != '\0') { - goto error; - } - - if (argc > i) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, i); - } - - return argc; - - error: - rb_fatal("bad scan arg format: %s", fmt); - return 0; -} -/********************************************************************** - - compar.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Thu Aug 26 14:39:48 JST 1993 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - -**********************************************************************/ - -#include "ruby.h" - -VALUE rb_mComparable; - -static ID cmp; - -int -rb_cmpint(val, a, b) - VALUE val, a, b; -{ - if (NIL_P(val)) { - rb_cmperr(a, b); - } - if (FIXNUM_P(val)) return FIX2INT(val); - if (TYPE(val) == T_BIGNUM) { - if (RBIGNUM(val)->sign) return 1; - return -1; - } - if (RTEST(rb_funcall(val, '>', 1, INT2FIX(0)))) return 1; - if (RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))) return -1; - return 0; -} - -void -rb_cmperr(x, y) - VALUE x, y; -{ - const char *classname; - - if (SPECIAL_CONST_P(y)) { - y = rb_inspect(y); - classname = StringValuePtr(y); - } - else { - classname = rb_obj_classname(y); - } - rb_raise(rb_eArgError, "comparison of %s with %s failed", - rb_obj_classname(x), classname); -} - -static VALUE -cmp_eq(a) - VALUE *a; -{ - VALUE c = rb_funcall(a[0], cmp, 1, a[1]); - - if (NIL_P(c)) return Qnil; - if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue; - return Qfalse; -} - -static VALUE -cmp_failed() -{ - return Qnil; -} - -/* - * call-seq: - * obj == other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns 0. Also returns true if - * _obj_ and _other_ are the same object. - */ - -static VALUE -cmp_equal(x, y) - VALUE x, y; -{ - VALUE a[2]; - - if (x == y) return Qtrue; - - a[0] = x; a[1] = y; - return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0); -} - -/* - * call-seq: - * obj > other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns 1. - */ - -static VALUE -cmp_gt(x, y) - VALUE x, y; -{ - VALUE c = rb_funcall(x, cmp, 1, y); - - if (rb_cmpint(c, x, y) > 0) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * obj >= other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns 0 or 1. - */ - -static VALUE -cmp_ge(x, y) - VALUE x, y; -{ - VALUE c = rb_funcall(x, cmp, 1, y); - - if (rb_cmpint(c, x, y) >= 0) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * obj < other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns -1. - */ - -static VALUE -cmp_lt(x, y) - VALUE x, y; -{ - VALUE c = rb_funcall(x, cmp, 1, y); - - if (rb_cmpint(c, x, y) < 0) return Qtrue; - return Qfalse; -} - - -/* - * call-seq: - * obj <= other => true or false - * - * Compares two objects based on the receiver's <code><=></code> - * method, returning true if it returns -1 or 0. - */ - -static VALUE -cmp_le(x, y) - VALUE x, y; -{ - VALUE c = rb_funcall(x, cmp, 1, y); - - if (rb_cmpint(c, x, y) <= 0) return Qtrue; - return Qfalse; -} - -/* - * call-seq: - * obj.between?(min, max) => true or false - * - * Returns <code>false</code> if <i>obj</i> <code><=></code> - * <i>min</i> is less than zero or if <i>anObject</i> <code><=></code> - * <i>max</i> is greater than zero, <code>true</code> otherwise. - * - * 3.between?(1, 5) #=> true - * 6.between?(1, 5) #=> false - * 'cat'.between?('ant', 'dog') #=> true - * 'gnu'.between?('ant', 'dog') #=> false - * - */ - -static VALUE -cmp_between(x, min, max) - VALUE x, min, max; -{ - if (RTEST(cmp_lt(x, min))) return Qfalse; - if (RTEST(cmp_gt(x, max))) return Qfalse; - return Qtrue; -} - -/* - * The <code>Comparable</code> mixin is used by classes whose objects - * may be ordered. The class must define the <code><=></code> operator, - * which compares the receiver against another object, returning -1, 0, - * or +1 depending on whether the receiver is less than, equal to, or - * greater than the other object. <code>Comparable</code> uses - * <code><=></code> to implement the conventional comparison operators - * (<code><</code>, <code><=</code>, <code>==</code>, <code>>=</code>, - * and <code>></code>) and the method <code>between?</code>. - * - * class SizeMatters - * include Comparable - * attr :str - * def <=>(anOther) - * str.size <=> anOther.str.size - * end - * def initialize(str) - * @str = str - * end - * def inspect - * @str - * end - * end - * - * s1 = SizeMatters.new("Z") - * s2 = SizeMatters.new("YY") - * s3 = SizeMatters.new("XXX") - * s4 = SizeMatters.new("WWWW") - * s5 = SizeMatters.new("VVVVV") - * - * s1 < s2 #=> true - * s4.between?(s1, s3) #=> false - * s4.between?(s3, s5) #=> true - * [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV] - * - */ - -void -Init_Comparable() -{ - rb_mComparable = rb_define_module("Comparable"); - rb_define_method(rb_mComparable, "==", cmp_equal, 1); - rb_define_method(rb_mComparable, ">", cmp_gt, 1); - rb_define_method(rb_mComparable, ">=", cmp_ge, 1); - rb_define_method(rb_mComparable, "<", cmp_lt, 1); - rb_define_method(rb_mComparable, "<=", cmp_le, 1); - rb_define_method(rb_mComparable, "between?", cmp_between, 2); - - cmp = rb_intern("<=>"); -} -/********************************************************************** - - dir.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Wed Jan 5 09:51:01 JST 1994 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - Copyright (C) 2000 Network Applied Communication Laboratory, Inc. - Copyright (C) 2000 Information-technology Promotion Agency, Japan - -**********************************************************************/ - -#include "ruby.h" - -#include <sys/types.h> -#include <sys/stat.h> - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#if defined HAVE_DIRENT_H && !defined _WIN32 -# include <dirent.h> -# define NAMLEN(dirent) strlen((dirent)->d_name) -#elif defined HAVE_DIRECT_H && !defined _WIN32 -# include <direct.h> -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# if !defined __NeXT__ -# define NAMLEN(dirent) (dirent)->d_namlen -# else -# /* On some versions of NextStep, d_namlen is always zero, so avoid it. */ -# define NAMLEN(dirent) strlen((dirent)->d_name) -# endif -# if HAVE_SYS_NDIR_H -# include <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -# include <sys/dir.h> -# endif -# if HAVE_NDIR_H -# include <ndir.h> -# endif -# ifdef _WIN32 -# include "win32/dir.h" -# endif -#endif - -#include <errno.h> - -#ifndef HAVE_STDLIB_H -char *getenv(); -#endif - -#ifndef HAVE_STRING_H -char *strchr _((char*,char)); -#endif - -#include <ctype.h> - -#include "util.h" - -#if !defined HAVE_LSTAT && !defined lstat -#define lstat stat -#endif - -#define FNM_NOESCAPE 0x01 -#define FNM_PATHNAME 0x02 -#define FNM_DOTMATCH 0x04 -#define FNM_CASEFOLD 0x08 - -#define FNM_NOMATCH 1 -#define FNM_ERROR 2 - -#define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c)) -#define compare(c1, c2) (((unsigned char)(c1)) - ((unsigned char)(c2))) - -/* caution: in case *p == '\0' - Next(p) == p + 1 in single byte environment - Next(p) == p in multi byte environment -*/ -#if defined(CharNext) -# define Next(p) CharNext(p) -#elif defined(DJGPP) -# define Next(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE)) -#elif defined(__EMX__) -# define Next(p) ((p) + emx_mblen(p)) -static inline int -emx_mblen(p) - const char *p; -{ - int n = mblen(p, RUBY_MBCHAR_MAXSIZE); - return (n < 0) ? 1 : n; -} -#endif - -#ifndef Next /* single byte environment */ -# define Next(p) ((p) + 1) -# define Inc(p) (++(p)) -# define Compare(p1, p2) (compare(downcase(*(p1)), downcase(*(p2)))) -#else /* multi byte environment */ -# define Inc(p) ((p) = Next(p)) -# define Compare(p1, p2) (CompareImpl(p1, p2, nocase)) -static int -CompareImpl(p1, p2, nocase) - const char *p1; - const char *p2; - int nocase; -{ - const int len1 = Next(p1) - p1; - const int len2 = Next(p2) - p2; -#ifdef _WIN32 - char buf1[10], buf2[10]; /* large enough? */ -#endif - - if (len1 < 0 || len2 < 0) { - rb_fatal("CompareImpl: negative len"); - } - - if (len1 == 0) return len2; - if (len2 == 0) return -len1; - -#ifdef _WIN32 - if (nocase) { - if (len1 > 1) { - if (len1 >= sizeof(buf1)) { - rb_fatal("CompareImpl: too large len"); - } - memcpy(buf1, p1, len1); - buf1[len1] = '\0'; - CharLower(buf1); - p1 = buf1; /* trick */ - } - if (len2 > 1) { - if (len2 >= sizeof(buf2)) { - rb_fatal("CompareImpl: too large len"); - } - memcpy(buf2, p2, len2); - buf2[len2] = '\0'; - CharLower(buf2); - p2 = buf2; /* trick */ - } - } -#endif - if (len1 == 1) - if (len2 == 1) - return compare(downcase(*p1), downcase(*p2)); - else { - const int ret = compare(downcase(*p1), *p2); - return ret ? ret : -1; - } - else - if (len2 == 1) { - const int ret = compare(*p1, downcase(*p2)); - return ret ? ret : 1; - } - else { - const int ret = memcmp(p1, p2, len1 < len2 ? len1 : len2); - return ret ? ret : len1 - len2; - } -} -#endif /* environment */ - -static char * -bracket(p, s, flags) - const char *p; /* pattern (next to '[') */ - const char *s; /* string */ - int flags; -{ - const int nocase = flags & FNM_CASEFOLD; - const int escape = !(flags & FNM_NOESCAPE); - - int ok = 0, not = 0; - - if (*p == '!' || *p == '^') { - not = 1; - p++; - } - - while (*p != ']') { - const char *t1 = p; - if (escape && *t1 == '\\') - t1++; - if (!*t1) - return NULL; - p = Next(t1); - if (p[0] == '-' && p[1] != ']') { - const char *t2 = p + 1; - if (escape && *t2 == '\\') - t2++; - if (!*t2) - return NULL; - p = Next(t2); - if (!ok && Compare(t1, s) <= 0 && Compare(s, t2) <= 0) - ok = 1; - } - else - if (!ok && Compare(t1, s) == 0) - ok = 1; - } - - return ok == not ? NULL : (char *)p + 1; -} - -/* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0') - Otherwise, entire string will be matched. - End marker itself won't be compared. - And if function succeeds, *pcur reaches end marker. -*/ -#define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p)) -#define ISEND(p) (!*(p) || (pathname && *(p) == '/')) -#define RETURN(val) return *pcur = p, *scur = s, (val); - -static int -fnmatch_helper(pcur, scur, flags) - const char **pcur; /* pattern */ - const char **scur; /* string */ - int flags; -{ - const int period = !(flags & FNM_DOTMATCH); - const int pathname = flags & FNM_PATHNAME; - const int escape = !(flags & FNM_NOESCAPE); - const int nocase = flags & FNM_CASEFOLD; - - const char *ptmp = 0; - const char *stmp = 0; - - const char *p = *pcur; - const char *s = *scur; - - if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */ - RETURN(FNM_NOMATCH); - - while (1) { - switch (*p) { - case '*': - do { p++; } while (*p == '*'); - if (ISEND(UNESCAPE(p))) { - p = UNESCAPE(p); - RETURN(0); - } - if (ISEND(s)) - RETURN(FNM_NOMATCH); - ptmp = p; - stmp = s; - continue; - - case '?': - if (ISEND(s)) - RETURN(FNM_NOMATCH); - p++; - Inc(s); - continue; - - case '[': { - const char *t; - if (ISEND(s)) - RETURN(FNM_NOMATCH); - if (t = bracket(p + 1, s, flags)) { - p = t; - Inc(s); - continue; - } - goto failed; - } - } - - /* ordinary */ - p = UNESCAPE(p); - if (ISEND(s)) - RETURN(ISEND(p) ? 0 : FNM_NOMATCH); - if (ISEND(p)) - goto failed; - if (Compare(p, s) != 0) - goto failed; - Inc(p); - Inc(s); - continue; - - failed: /* try next '*' position */ - if (ptmp && stmp) { - p = ptmp; - Inc(stmp); /* !ISEND(*stmp) */ - s = stmp; - continue; - } - RETURN(FNM_NOMATCH); - } -} - -static int -fnmatch(p, s, flags) - const char *p; /* pattern */ - const char *s; /* string */ - int flags; -{ - const int period = !(flags & FNM_DOTMATCH); - const int pathname = flags & FNM_PATHNAME; - - const char *ptmp = 0; - const char *stmp = 0; - - if (pathname) { - while (1) { - if (p[0] == '*' && p[1] == '*' && p[2] == '/') { - do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); - ptmp = p; - stmp = s; - } - if (fnmatch_helper(&p, &s, flags) == 0) { - while (*s && *s != '/') Inc(s); - if (*p && *s) { - p++; - s++; - continue; - } - if (!*p && !*s) - return 0; - } - /* failed : try next recursion */ - if (ptmp && stmp && !(period && *stmp == '.')) { - while (*stmp && *stmp != '/') Inc(stmp); - if (*stmp) { - p = ptmp; - stmp++; - s = stmp; - continue; - } - } - return FNM_NOMATCH; - } - } - else - return fnmatch_helper(&p, &s, flags); -} - -VALUE rb_cDir; - -struct dir_data { - DIR *dir; - char *path; -}; - -static void -free_dir(dir) - struct dir_data *dir; -{ - if (dir) { - if (dir->dir) closedir(dir->dir); - if (dir->path) free(dir->path); - } - free(dir); -} - -static VALUE dir_close _((VALUE)); - -static VALUE dir_s_alloc _((VALUE)); -static VALUE -dir_s_alloc(klass) - VALUE klass; -{ - struct dir_data *dirp; - VALUE obj = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dirp); - - dirp->dir = NULL; - dirp->path = NULL; - - return obj; -} - -/* - * call-seq: - * Dir.new( string ) -> aDir - * - * Returns a new directory object for the named directory. - */ -static VALUE -dir_initialize(dir, dirname) - VALUE dir, dirname; -{ - struct dir_data *dp; - - FilePathValue(dirname); - Data_Get_Struct(dir, struct dir_data, dp); - if (dp->dir) closedir(dp->dir); - if (dp->path) free(dp->path); - dp->dir = NULL; - dp->path = NULL; - dp->dir = opendir(RSTRING(dirname)->ptr); - if (dp->dir == NULL) { - if (errno == EMFILE || errno == ENFILE) { - rb_gc(); - dp->dir = opendir(RSTRING(dirname)->ptr); - } - if (dp->dir == NULL) { - rb_sys_fail(RSTRING(dirname)->ptr); - } - } - dp->path = strdup(RSTRING(dirname)->ptr); - - return dir; -} - -/* - * call-seq: - * Dir.open( string ) => aDir - * Dir.open( string ) {| aDir | block } => anObject - * - * With no block, <code>open</code> is a synonym for - * <code>Dir::new</code>. If a block is present, it is passed - * <i>aDir</i> as a parameter. The directory is closed at the end of - * the block, and <code>Dir::open</code> returns the value of the - * block. - */ -static VALUE -dir_s_open(klass, dirname) - VALUE klass, dirname; -{ - struct dir_data *dp; - VALUE dir = Data_Make_Struct(klass, struct dir_data, 0, free_dir, dp); - - dir_initialize(dir, dirname); - if (rb_block_given_p()) { - return rb_ensure(rb_yield, dir, dir_close, dir); - } - - return dir; -} - -static void -dir_closed() -{ - rb_raise(rb_eIOError, "closed directory"); -} - -#define GetDIR(obj, dirp) do {\ - Data_Get_Struct(obj, struct dir_data, dirp);\ - if (dirp->dir == NULL) dir_closed();\ -} while (0) - -/* - * call-seq: - * dir.inspect => string - * - * Return a string describing this Dir object. - */ -static VALUE -dir_inspect(dir) - VALUE dir; -{ - struct dir_data *dirp; - - GetDIR(dir, dirp); - if (dirp->path) { - char *c = rb_obj_classname(dir); - int len = strlen(c) + strlen(dirp->path) + 4; - VALUE s = rb_str_new(0, len); - snprintf(RSTRING(s)->ptr, len+1, "#<%s:%s>", c, dirp->path); - return s; - } - return rb_funcall(dir, rb_intern("to_s"), 0, 0); -} - -/* - * call-seq: - * dir.path => string or nil - * - * Returns the path parameter passed to <em>dir</em>'s constructor. - * - * d = Dir.new("..") - * d.path #=> ".." - */ -static VALUE -dir_path(dir) - VALUE dir; -{ - struct dir_data *dirp; - - GetDIR(dir, dirp); - if (!dirp->path) return Qnil; - return rb_str_new2(dirp->path); -} - -/* - * call-seq: - * dir.read => string or nil - * - * Reads the next entry from <em>dir</em> and returns it as a string. - * Returns <code>nil</code> at the end of the stream. - * - * d = Dir.new("testdir") - * d.read #=> "." - * d.read #=> ".." - * d.read #=> "config.h" - */ -static VALUE -dir_read(dir) - VALUE dir; -{ - struct dir_data *dirp; - struct dirent *dp; - - GetDIR(dir, dirp); - errno = 0; - dp = readdir(dirp->dir); - if (dp) { - return rb_tainted_str_new(dp->d_name, NAMLEN(dp)); - } - else if (errno == 0) { /* end of stream */ - return Qnil; - } - else { - rb_sys_fail(0); - } - return Qnil; /* not reached */ -} - -/* - * call-seq: - * dir.each { |filename| block } => dir - * - * Calls the block once for each entry in this directory, passing the - * filename of each entry as a parameter to the block. - * - * d = Dir.new("testdir") - * d.each {|x| puts "Got #{x}" } - * - * <em>produces:</em> - * - * Got . - * Got .. - * Got config.h - * Got main.rb - */ -static VALUE -dir_each(dir) - VALUE dir; -{ - struct dir_data *dirp; - struct dirent *dp; - - GetDIR(dir, dirp); - for (dp = readdir(dirp->dir); dp != NULL; dp = readdir(dirp->dir)) { - rb_yield(rb_tainted_str_new(dp->d_name, NAMLEN(dp))); - if (dirp->dir == NULL) dir_closed(); - } - return dir; -} - -/* - * call-seq: - * dir.pos => integer - * dir.tell => integer - * - * Returns the current position in <em>dir</em>. See also - * <code>Dir#seek</code>. - * - * d = Dir.new("testdir") - * d.tell #=> 0 - * d.read #=> "." - * d.tell #=> 12 - */ -static VALUE -dir_tell(dir) - VALUE dir; -{ -#ifdef HAVE_TELLDIR - struct dir_data *dirp; - long pos; - - GetDIR(dir, dirp); - pos = telldir(dirp->dir); - return rb_int2inum(pos); -#else - rb_notimplement(); -#endif -} - -/* - * call-seq: - * dir.seek( integer ) => dir - * - * Seeks to a particular location in <em>dir</em>. <i>integer</i> - * must be a value returned by <code>Dir#tell</code>. - * - * d = Dir.new("testdir") #=> #<Dir:0x401b3c40> - * d.read #=> "." - * i = d.tell #=> 12 - * d.read #=> ".." - * d.seek(i) #=> #<Dir:0x401b3c40> - * d.read #=> ".." - */ -static VALUE -dir_seek(dir, pos) - VALUE dir, pos; -{ - struct dir_data *dirp; - off_t p = NUM2OFFT(pos); - - GetDIR(dir, dirp); -#ifdef HAVE_SEEKDIR - seekdir(dirp->dir, p); - return dir; -#else - rb_notimplement(); -#endif -} - -/* - * call-seq: - * dir.pos( integer ) => integer - * - * Synonym for <code>Dir#seek</code>, but returns the position - * parameter. - * - * d = Dir.new("testdir") #=> #<Dir:0x401b3c40> - * d.read #=> "." - * i = d.pos #=> 12 - * d.read #=> ".." - * d.pos = i #=> 12 - * d.read #=> ".." - */ -static VALUE -dir_set_pos(dir, pos) - VALUE dir, pos; -{ - dir_seek(dir, pos); - return pos; -} - -/* - * call-seq: - * dir.rewind => dir - * - * Repositions <em>dir</em> to the first entry. - * - * d = Dir.new("testdir") - * d.read #=> "." - * d.rewind #=> #<Dir:0x401b3fb0> - * d.read #=> "." - */ -static VALUE -dir_rewind(dir) - VALUE dir; -{ - struct dir_data *dirp; - - GetDIR(dir, dirp); - rewinddir(dirp->dir); - return dir; -} - -/* - * call-seq: - * dir.close => nil - * - * Closes the directory stream. Any further attempts to access - * <em>dir</em> will raise an <code>IOError</code>. - * - * d = Dir.new("testdir") - * d.close #=> nil - */ -static VALUE -dir_close(dir) - VALUE dir; -{ - struct dir_data *dirp; - - GetDIR(dir, dirp); - closedir(dirp->dir); - dirp->dir = NULL; - - return Qnil; -} - -static void -dir_chdir(path) - VALUE path; -{ - if (chdir(RSTRING(path)->ptr) < 0) - rb_sys_fail(RSTRING(path)->ptr); -} - -static int chdir_blocking = 0; -static VALUE chdir_thread = Qnil; - -struct chdir_data { - VALUE old_path, new_path; - int done; -}; - -static VALUE -chdir_yield(args) - struct chdir_data *args; -{ - dir_chdir(args->new_path); - args->done = Qtrue; - chdir_blocking++; - if (chdir_thread == Qnil) - chdir_thread = rb_thread_current(); - return rb_yield(args->new_path); -} - -static VALUE -chdir_restore(args) - struct chdir_data *args; -{ - if (args->done) { - chdir_blocking--; - if (chdir_blocking == 0) - chdir_thread = Qnil; - dir_chdir(args->old_path); - } - return Qnil; -} - -/* - * call-seq: - * Dir.chdir( [ string] ) => 0 - * Dir.chdir( [ string] ) {| path | block } => anObject - * - * Changes the current working directory of the process to the given - * string. When called without an argument, changes the directory to - * the value of the environment variable <code>HOME</code>, or - * <code>LOGDIR</code>. <code>SystemCallError</code> (probably - * <code>Errno::ENOENT</code>) if the target directory does not exist. - * - * If a block is given, it is passed the name of the new current - * directory, and the block is executed with that as the current - * directory. The original working directory is restored when the block - * exits. The return value of <code>chdir</code> is the value of the - * block. <code>chdir</code> blocks can be nested, but in a - * multi-threaded program an error will be raised if a thread attempts - * to open a <code>chdir</code> block while another thread has one - * open. - * - * Dir.chdir("/var/spool/mail") - * puts Dir.pwd - * Dir.chdir("/tmp") do - * puts Dir.pwd - * Dir.chdir("/usr") do - * puts Dir.pwd - * end - * puts Dir.pwd - * end - * puts Dir.pwd - * - * <em>produces:</em> - * - * /var/spool/mail - * /tmp - * /usr - * /tmp - * /var/spool/mail - */ -static VALUE -dir_s_chdir(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE path = Qnil; - - rb_secure(2); - if (rb_scan_args(argc, argv, "01", &path) == 1) { - FilePathValue(path); - } - else { - const char *dist = getenv("HOME"); - if (!dist) { - dist = getenv("LOGDIR"); - if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set"); - } - path = rb_str_new2(dist); - } - - if (chdir_blocking > 0) { - if (!rb_block_given_p() || rb_thread_current() != chdir_thread) - rb_warn("conflicting chdir during another chdir block"); - } - - if (rb_block_given_p()) { - struct chdir_data args; - char *cwd = my_getcwd(); - - args.old_path = rb_tainted_str_new2(cwd); free(cwd); - args.new_path = path; - args.done = Qfalse; - return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args); - } - dir_chdir(path); - - return INT2FIX(0); -} - -/* - * call-seq: - * Dir.getwd => string - * Dir.pwd => string - * - * Returns the path to the current working directory of this process as - * a string. - * - * Dir.chdir("/tmp") #=> 0 - * Dir.getwd #=> "/tmp" - */ -static VALUE -dir_s_getwd(dir) - VALUE dir; -{ - char *path; - VALUE cwd; - - rb_secure(4); - path = my_getcwd(); - cwd = rb_tainted_str_new2(path); - - free(path); - return cwd; -} - -static void check_dirname _((volatile VALUE *)); -static void -check_dirname(dir) - volatile VALUE *dir; -{ - char *path, *pend; - - rb_secure(2); - FilePathValue(*dir); - path = RSTRING(*dir)->ptr; - if (path && *(pend = rb_path_end(rb_path_skip_prefix(path)))) { - *dir = rb_str_new(path, pend - path); - } -} - -/* - * call-seq: - * Dir.chroot( string ) => 0 - * - * Changes this process's idea of the file system root. Only a - * privileged process may make this call. Not available on all - * platforms. On Unix systems, see <code>chroot(2)</code> for more - * information. - */ -static VALUE -dir_s_chroot(dir, path) - VALUE dir, path; -{ -#if defined(HAVE_CHROOT) && !defined(__CHECKER__) - check_dirname(&path); - - if (chroot(RSTRING(path)->ptr) == -1) - rb_sys_fail(RSTRING(path)->ptr); - - return INT2FIX(0); -#else - rb_notimplement(); - return Qnil; /* not reached */ -#endif -} - -/* - * call-seq: - * Dir.mkdir( string [, integer] ) => 0 - * - * Makes a new directory named by <i>string</i>, with permissions - * specified by the optional parameter <i>anInteger</i>. The - * permissions may be modified by the value of - * <code>File::umask</code>, and are ignored on NT. Raises a - * <code>SystemCallError</code> if the directory cannot be created. See - * also the discussion of permissions in the class documentation for - * <code>File</code>. - * - */ -static VALUE -dir_s_mkdir(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE path, vmode; - int mode; - - if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) { - mode = NUM2INT(vmode); - } - else { - mode = 0777; - } - - check_dirname(&path); - if (mkdir(RSTRING(path)->ptr, mode) == -1) - rb_sys_fail(RSTRING(path)->ptr); - - return INT2FIX(0); -} - -/* - * call-seq: - * Dir.delete( string ) => 0 - * Dir.rmdir( string ) => 0 - * Dir.unlink( string ) => 0 - * - * Deletes the named directory. Raises a subclass of - * <code>SystemCallError</code> if the directory isn't empty. - */ -static VALUE -dir_s_rmdir(obj, dir) - VALUE obj, dir; -{ - check_dirname(&dir); - if (rmdir(RSTRING(dir)->ptr) < 0) - rb_sys_fail(RSTRING(dir)->ptr); - - return INT2FIX(0); -} - -/* System call with warning */ -static int -do_stat(path, pst) - const char *path; - struct stat *pst; -{ - int ret = stat(path, pst); - if (ret < 0 && errno != ENOENT) - rb_sys_warning(path); - - return ret; -} - -static int -do_lstat(path, pst) - const char *path; - struct stat *pst; -{ - int ret = lstat(path, pst); - if (ret < 0 && errno != ENOENT) - rb_sys_warning(path); - - return ret; -} - -static DIR * -do_opendir(path) - const char *path; -{ - DIR *dirp = opendir(path); - if (dirp == NULL && errno != ENOENT && errno != ENOTDIR) - rb_sys_warning(path); - - return dirp; -} - -/* Return nonzero if S has any special globbing chars in it. */ -static int -has_magic(s, flags) - const char *s; - int flags; -{ - const int escape = !(flags & FNM_NOESCAPE); - - register const char *p = s; - register char c; - - while (c = *p++) { - switch (c) { - case '*': - case '?': - case '[': - return 1; - - case '\\': - if (escape && !(c = *p++)) - return 0; - continue; - } - - p = Next(p-1); - } - - return 0; -} - -/* Find separator in globbing pattern. */ -static char * -find_dirsep(s, flags) - const char *s; - int flags; -{ - const int escape = !(flags & FNM_NOESCAPE); - - register const char *p = s; - register char c; - int open = 0; - - while (c = *p++) { - switch (c) { - case '[': - open = 1; - continue; - case ']': - open = 0; - continue; - - case '/': - if (!open) - return (char *)p-1; - continue; - - case '\\': - if (escape && !(c = *p++)) - return (char *)p-1; - continue; - } - - p = Next(p-1); - } - - return (char *)p-1; -} - -/* Remove escaping baskclashes */ -static void -remove_backslashes(p) - char *p; -{ - char *t = p; - char *s = p; - - while (*p) { - if (*p == '\\') { - if (t != s) - memmove(t, s, p - s); - t += p - s; - s = ++p; - if (!*p) break; - } - Inc(p); - } - - while (*p++); - - if (t != s) - memmove(t, s, p - s); /* move '\0' too */ -} - -/* Globing pattern */ -enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR }; - -struct glob_pattern { - char *str; - enum glob_pattern_type type; - struct glob_pattern *next; -}; - -static struct glob_pattern * -glob_make_pattern(p, flags) - const char *p; - int flags; -{ - struct glob_pattern *list, *tmp, **tail = &list; - int dirsep = 0; /* pattern is terminated with '/' */ - - while (*p) { - tmp = ALLOC(struct glob_pattern); - if (p[0] == '*' && p[1] == '*' && p[2] == '/') { - /* fold continuous RECURSIVEs (needed in glob_helper) */ - do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); - tmp->type = RECURSIVE; - tmp->str = 0; - dirsep = 1; - } - else { - const char *m = find_dirsep(p, flags); - char *buf = ALLOC_N(char, m-p+1); - memcpy(buf, p, m-p); - buf[m-p] = '\0'; - tmp->type = has_magic(buf, flags) ? MAGICAL : PLAIN; - tmp->str = buf; - if (*m) { - dirsep = 1; - p = m + 1; - } - else { - dirsep = 0; - p = m; - } - } - *tail = tmp; - tail = &tmp->next; - } - - tmp = ALLOC(struct glob_pattern); - tmp->type = dirsep ? MATCH_DIR : MATCH_ALL; - tmp->str = 0; - *tail = tmp; - tmp->next = 0; - - return list; -} - -static void -glob_free_pattern(list) - struct glob_pattern *list; -{ - while (list) { - struct glob_pattern *tmp = list; - list = list->next; - if (tmp->str) - free(tmp->str); - free(tmp); - } -} - -static VALUE -join_path(path, dirsep, name) - VALUE path; - int dirsep; - const char *name; -{ - long len = RSTRING(path)->len; - VALUE buf = rb_str_new(0, RSTRING(path)->len+strlen(name)+(dirsep?1:0)); - - memcpy(RSTRING(buf)->ptr, RSTRING(path)->ptr, len); - if (dirsep) { - strcpy(RSTRING(buf)->ptr+len, "/"); - len++; - } - strcpy(RSTRING(buf)->ptr+len, name); - return buf; -} - -enum answer { YES, NO, UNKNOWN }; - -#ifndef S_ISDIR -# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) -#endif - -#ifndef S_ISLNK -# ifndef S_IFLNK -# define S_ISLNK(m) (0) -# else -# define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK) -# endif -#endif - -struct glob_args { - void (*func) _((VALUE, VALUE)); - VALUE c; - VALUE v; -}; - -static VALUE glob_func_caller _((VALUE)); - -static VALUE -glob_func_caller(val) - VALUE val; -{ - struct glob_args *args = (struct glob_args *)val; - VALUE path = args->c; - - OBJ_TAINT(path); - (*args->func)(path, args->v); - return Qnil; -} - -static int -glob_call_func(func, path, arg) - void (*func) _((VALUE, VALUE)); - VALUE path; - VALUE arg; -{ - int status; - struct glob_args args; - - args.func = func; - args.c = path; - args.v = arg; - - rb_protect(glob_func_caller, (VALUE)&args, &status); - return status; -} - -static int -glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) - VALUE path; - int dirsep; /* '/' should be placed before appending child entry's name to 'path'. */ - enum answer exist; /* Does 'path' indicate an existing entry? */ - enum answer isdir; /* Does 'path' indicate a directory or a symlink to a directory? */ - struct glob_pattern **beg; - struct glob_pattern **end; - int flags; - void (*func) _((VALUE, VALUE)); - VALUE arg; -{ - struct stat st; - int status = 0; - struct glob_pattern **cur, **new_beg, **new_end; - int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0; - int escape = !(flags & FNM_NOESCAPE); - - for (cur = beg; cur < end; ++cur) { - struct glob_pattern *p = *cur; - if (p->type == RECURSIVE) { - recursive = 1; - p = p->next; - } - switch (p->type) { - case PLAIN: - plain = 1; - break; - case MAGICAL: - magical = 1; - break; - case MATCH_ALL: - match_all = 1; - break; - case MATCH_DIR: - match_dir = 1; - break; - } - } - - if (RSTRING(path)->len > 0) { - if (match_all && exist == UNKNOWN) { - if (do_lstat(RSTRING(path)->ptr, &st) == 0) { - exist = YES; - isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; - } - else { - exist = NO; - isdir = NO; - } - } - - if (match_dir && isdir == UNKNOWN) { - if (do_stat(RSTRING(path)->ptr, &st) == 0) { - exist = YES; - isdir = S_ISDIR(st.st_mode) ? YES : NO; - } - else { - exist = NO; - isdir = NO; - } - } - - if (match_all && exist == YES) { - status = glob_call_func(func, path, arg); - if (status) return status; - } - - if (match_dir && isdir == YES) { - status = glob_call_func(func, join_path(path, dirsep, ""), arg); - if (status) return status; - } - } - - if (exist == NO || isdir == NO) return 0; - - if (magical || recursive) { - struct dirent *dp; - DIR *dirp = do_opendir(RSTRING(path)->len > 0 ? RSTRING(path)->ptr : "."); - if (dirp == NULL) return 0; - - for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { - VALUE buf = join_path(path, dirsep, dp->d_name); - - enum answer new_isdir = UNKNOWN; - if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 - && fnmatch("*", dp->d_name, flags) == 0) { -#ifndef _WIN32 - if (do_lstat(RSTRING(buf)->ptr, &st) == 0) - new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; - else - new_isdir = NO; -#else - new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO; -#endif - } - - new_beg = new_end = ALLOC_N(struct glob_pattern *, (end - beg) * 2); - - for (cur = beg; cur < end; ++cur) { - struct glob_pattern *p = *cur; - if (p->type == RECURSIVE) { - if (new_isdir == YES) /* not symlink but real directory */ - *new_end++ = p; /* append recursive pattern */ - p = p->next; /* 0 times recursion */ - } - if (p->type == PLAIN || p->type == MAGICAL) { - if (fnmatch(p->str, dp->d_name, flags) == 0) - *new_end++ = p->next; - } - } - - status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end, flags, func, arg); - free(new_beg); - if (status) break; - } - - closedir(dirp); - } - else if (plain) { - struct glob_pattern **copy_beg, **copy_end, **cur2; - - copy_beg = copy_end = ALLOC_N(struct glob_pattern *, end - beg); - for (cur = beg; cur < end; ++cur) - *copy_end++ = (*cur)->type == PLAIN ? *cur : 0; - - for (cur = copy_beg; cur < copy_end; ++cur) { - if (*cur) { - VALUE buf; - char *name; - name = ALLOC_N(char, strlen((*cur)->str) + 1); - strcpy(name, (*cur)->str); - if (escape) remove_backslashes(name); - - new_beg = new_end = ALLOC_N(struct glob_pattern *, end - beg); - *new_end++ = (*cur)->next; - for (cur2 = cur + 1; cur2 < copy_end; ++cur2) { - if (*cur2 && fnmatch((*cur2)->str, name, flags) == 0) { - *new_end++ = (*cur2)->next; - *cur2 = 0; - } - } - - buf = join_path(path, dirsep, name); - free(name); - status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg, new_end, flags, func, arg); - free(new_beg); - if (status) break; - } - } - - free(copy_beg); - } - - return status; -} - -static int -rb_glob2(path, offset, flags, func, arg) - VALUE path; - long offset; - int flags; - void (*func) _((VALUE, VALUE)); - VALUE arg; -{ - struct glob_pattern *list; - const char *root, *start; - VALUE buf; - int n; - int status; - - if (flags & FNM_CASEFOLD) { - rb_warn("Dir.glob() ignores File::FNM_CASEFOLD"); - } - - start = root = StringValuePtr(path) + offset; -#if defined DOSISH - flags |= FNM_CASEFOLD; - root = rb_path_skip_prefix(root); -#else - flags &= ~FNM_CASEFOLD; -#endif - - if (root && *root == '/') root++; - - n = root - start; - buf = rb_str_new(start, n); - - list = glob_make_pattern(root, flags); - status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg); - glob_free_pattern(list); - - return status; -} - -struct rb_glob_args { - void (*func) _((const char*, VALUE)); - VALUE arg; -}; - -static VALUE -rb_glob_caller(path, a) - VALUE path, a; -{ - struct rb_glob_args *args = (struct rb_glob_args *)a; - (*args->func)(RSTRING(path)->ptr, args->arg); - return Qnil; -} - -void -rb_glob(path, func, arg) - const char *path; - void (*func) _((const char*, VALUE)); - VALUE arg; -{ - struct rb_glob_args args; - int status; - - args.func = func; - args.arg = arg; - status = rb_glob2(rb_str_new2(path), 0, 0, rb_glob_caller, &args); - - if (status) rb_jump_tag(status); -} - -static void -push_pattern(path, ary) - VALUE path, ary; -{ - rb_ary_push(ary, path); -} - -static int -push_glob(VALUE ary, VALUE s, long offset, int flags); - -static int -push_glob(ary, str, offset, flags) - VALUE ary; - VALUE str; - long offset; - int flags; -{ - const int escape = !(flags & FNM_NOESCAPE); - - const char *p = RSTRING(str)->ptr + offset; - const char *s = p; - const char *lbrace = 0, *rbrace = 0; - int nest = 0, status = 0; - - while (*p) { - if (*p == '{' && nest++ == 0) { - lbrace = p; - } - if (*p == '}' && --nest <= 0) { - rbrace = p; - break; - } - if (*p == '\\' && escape) { - if (!*++p) break; - } - Inc(p); - } - - if (lbrace && rbrace) { - VALUE buffer = rb_str_new(0, strlen(s)); - char *buf; - long shift; - - buf = RSTRING(buffer)->ptr; - memcpy(buf, s, lbrace-s); - shift = (lbrace-s); - p = lbrace; - while (p < rbrace) { - const char *t = ++p; - nest = 0; - while (p < rbrace && !(*p == ',' && nest == 0)) { - if (*p == '{') nest++; - if (*p == '}') nest--; - if (*p == '\\' && escape) { - if (++p == rbrace) break; - } - Inc(p); - } - memcpy(buf+shift, t, p-t); - strcpy(buf+shift+(p-t), rbrace+1); - status = push_glob(ary, buffer, offset, flags); - if (status) break; - } - } - else if (!lbrace && !rbrace) { - status = rb_glob2(str, offset, flags, push_pattern, ary); - } - - return status; -} - -static VALUE -rb_push_glob(str, flags) /* '\0' is delimiter */ - VALUE str; - int flags; -{ - long offset = 0; - VALUE ary; - - FilePathValue(str); - - ary = rb_ary_new(); - - while (offset < RSTRING(str)->len) { - int status = push_glob(ary, str, offset, flags); - char *p, *pend; - if (status) rb_jump_tag(status); - p = RSTRING(str)->ptr + offset; - p += strlen(p) + 1; - pend = RSTRING(str)->ptr + RSTRING(str)->len; - while (p < pend && !*p) - p++; - offset = p - RSTRING(str)->ptr; - } - - if (rb_block_given_p()) { - rb_ary_each(ary); - return Qnil; - } - return ary; -} - -/* - * call-seq: - * Dir[ string ] => array - * - * Equivalent to calling - * <em>dir</em>.<code>glob(</code><i>string,</i><code>0)</code>. - * - */ -static VALUE -dir_s_aref(obj, str) - VALUE obj, str; -{ - return rb_push_glob(str, 0); -} - -/* - * call-seq: - * Dir.glob( string, [flags] ) => array - * Dir.glob( string, [flags] ) {| filename | block } => nil - * - * Returns the filenames found by expanding the pattern given in - * <i>string</i>, either as an <i>array</i> or as parameters to the - * block. Note that this pattern is not a regexp (it's closer to a - * shell glob). See <code>File::fnmatch</code> for the meaning of - * the <i>flags</i> parameter. Note that case sensitivity - * depends on your system (so <code>File::FNM_CASEFOLD</code> is ignored) - * - * <code>*</code>:: Matches any file. Can be restricted by - * other values in the glob. <code>*</code> - * will match all files; <code>c*</code> will - * match all files beginning with - * <code>c</code>; <code>*c</code> will match - * all files ending with <code>c</code>; and - * <code>*c*</code> will match all files that - * have <code>c</code> in them (including at - * the beginning or end). Equivalent to - * <code>/ .* /x</code> in regexp. - * <code>**</code>:: Matches directories recursively. - * <code>?</code>:: Matches any one character. Equivalent to - * <code>/.{1}/</code> in regexp. - * <code>[set]</code>:: Matches any one character in +set+. - * Behaves exactly like character sets in - * Regexp, including set negation - * (<code>[^a-z]</code>). - * <code>{p,q}</code>:: Matches either literal <code>p</code> or - * literal <code>q</code>. Matching literals - * may be more than one character in length. - * More than two literals may be specified. - * Equivalent to pattern alternation in - * regexp. - * <code>\</code>:: Escapes the next metacharacter. - * - * Dir["config.?"] #=> ["config.h"] - * Dir.glob("config.?") #=> ["config.h"] - * Dir.glob("*.[a-z][a-z]") #=> ["main.rb"] - * Dir.glob("*.[^r]*") #=> ["config.h"] - * Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"] - * Dir.glob("*") #=> ["config.h", "main.rb"] - * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"] - * - * rbfiles = File.join("**", "*.rb") - * Dir.glob(rbfiles) #=> ["main.rb", - * "lib/song.rb", - * "lib/song/karaoke.rb"] - * libdirs = File.join("**", "lib") - * Dir.glob(libdirs) #=> ["lib"] - * - * librbfiles = File.join("**", "lib", "**", "*.rb") - * Dir.glob(librbfiles) #=> ["lib/song.rb", - * "lib/song/karaoke.rb"] - * - * librbfiles = File.join("**", "lib", "*.rb") - * Dir.glob(librbfiles) #=> ["lib/song.rb"] - */ -static VALUE -dir_s_glob(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE str, rflags; - int flags; - - if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2) - flags = NUM2INT(rflags); - else - flags = 0; - - return rb_push_glob(str, flags); -} - -static VALUE -dir_open_dir(path) - VALUE path; -{ - struct dir_data *dp; - VALUE dir = rb_funcall(rb_cDir, rb_intern("open"), 1, path); - - if (TYPE(dir) != T_DATA || - RDATA(dir)->dfree != (RUBY_DATA_FUNC)free_dir) { - rb_raise(rb_eTypeError, "wrong argument type %s (expected Dir)", - rb_obj_classname(dir)); - } - return dir; -} - - -/* - * call-seq: - * Dir.foreach( dirname ) {| filename | block } => nil - * - * Calls the block once for each entry in the named directory, passing - * the filename of each entry as a parameter to the block. - * - * Dir.foreach("testdir") {|x| puts "Got #{x}" } - * - * <em>produces:</em> - * - * Got . - * Got .. - * Got config.h - * Got main.rb - * - */ -static VALUE -dir_foreach(io, dirname) - VALUE io, dirname; -{ - VALUE dir; - - dir = dir_open_dir(dirname); - rb_ensure(dir_each, dir, dir_close, dir); - return Qnil; -} - -/* - * call-seq: - * Dir.entries( dirname ) => array - * - * Returns an array containing all of the filenames in the given - * directory. Will raise a <code>SystemCallError</code> if the named - * directory doesn't exist. - * - * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"] - * - */ -static VALUE -dir_entries(io, dirname) - VALUE io, dirname; -{ - VALUE dir; - - dir = dir_open_dir(dirname); - return rb_ensure(rb_Array, dir, dir_close, dir); -} - -/* - * call-seq: - * File.fnmatch( pattern, path, [flags] ) => (true or false) - * File.fnmatch?( pattern, path, [flags] ) => (true or false) - * - * Returns true if <i>path</i> matches against <i>pattern</i> The - * pattern is not a regular expression; instead it follows rules - * similar to shell filename globbing. It may contain the following - * metacharacters: - * - * <code>*</code>:: Matches any file. Can be restricted by - * other values in the glob. <code>*</code> - * will match all files; <code>c*</code> will - * match all files beginning with - * <code>c</code>; <code>*c</code> will match - * all files ending with <code>c</code>; and - * <code>*c*</code> will match all files that - * have <code>c</code> in them (including at - * the beginning or end). Equivalent to - * <code>/ .* /x</code> in regexp. - * <code>**</code>:: Matches directories recursively or files - * expansively. - * <code>?</code>:: Matches any one character. Equivalent to - * <code>/.{1}/</code> in regexp. - * <code>[set]</code>:: Matches any one character in +set+. - * Behaves exactly like character sets in - * Regexp, including set negation - * (<code>[^a-z]</code>). - * <code>\</code>:: Escapes the next metacharacter. - * - * <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code> - * parameters. The same glob pattern and flags are used by - * <code>Dir::glob</code>. - * - * File.fnmatch('cat', 'cat') #=> true : match entire string - * File.fnmatch('cat', 'category') #=> false : only match partial string - * File.fnmatch('c{at,ub}s', 'cats') #=> false : { } isn't supported - * - * File.fnmatch('c?t', 'cat') #=> true : '?' match only 1 character - * File.fnmatch('c??t', 'cat') #=> false : ditto - * File.fnmatch('c*', 'cats') #=> true : '*' match 0 or more characters - * File.fnmatch('c*t', 'c/a/b/t') #=> true : ditto - * File.fnmatch('ca[a-z]', 'cat') #=> true : inclusive bracket expression - * File.fnmatch('ca[^t]', 'cat') #=> false : exclusive bracket expression ('^' or '!') - * - * File.fnmatch('cat', 'CAT') #=> false : case sensitive - * File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true : case insensitive - * - * File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false : wildcard doesn't match '/' on FNM_PATHNAME - * File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false : ditto - * File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false : ditto - * - * File.fnmatch('\?', '?') #=> true : escaped wildcard becomes ordinary - * File.fnmatch('\a', 'a') #=> true : escaped ordinary remains ordinary - * File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true : FNM_NOESACPE makes '\' ordinary - * File.fnmatch('[\?]', '?') #=> true : can escape inside bracket expression - * - * File.fnmatch('*', '.profile') #=> false : wildcard doesn't match leading - * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true period by default. - * File.fnmatch('.*', '.profile') #=> true - * - * rbfiles = File.join("**", "*.rb") - * File.fnmatch(rbfiles, 'main.rb') #=> false - * File.fnmatch(rbfiles, './main.rb') #=> false - * File.fnmatch(rbfiles, 'lib/song.rb') #=> true - * File.fnmatch('**.rb', 'main.rb') #=> true - * File.fnmatch('**.rb', './main.rb') #=> false - * File.fnmatch('**.rb', 'lib/song.rb') #=> true - * File.fnmatch('*', 'dave/.profile') #=> true - * - * File.fnmatch('* IGNORE /*', 'dave/.profile', File::FNM_PATHNAME) #=> false - * File.fnmatch('* IGNORE /*', 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true - * - * File.fnmatch('** IGNORE /foo', 'a/b/c/foo', File::FNM_PATHNAME) #=> true - * File.fnmatch('** IGNORE /foo', '/a/b/c/foo', File::FNM_PATHNAME) #=> true - * File.fnmatch('** IGNORE /foo', 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true - * File.fnmatch('** IGNORE /foo', 'a/.b/c/foo', File::FNM_PATHNAME) #=> false - * File.fnmatch('** IGNORE /foo', 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true - */ -static VALUE -file_s_fnmatch(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - VALUE pattern, path; - VALUE rflags; - int flags; - - if (rb_scan_args(argc, argv, "21", &pattern, &path, &rflags) == 3) - flags = NUM2INT(rflags); - else - flags = 0; - - StringValue(pattern); - StringValue(path); - - if (fnmatch(RSTRING(pattern)->ptr, RSTRING(path)->ptr, flags) == 0) - return Qtrue; - - return Qfalse; -} - -/* - * Objects of class <code>Dir</code> are directory streams representing - * directories in the underlying file system. They provide a variety of - * ways to list directories and their contents. See also - * <code>File</code>. - * - * The directory used in these examples contains the two regular files - * (<code>config.h</code> and <code>main.rb</code>), the parent - * directory (<code>..</code>), and the directory itself - * (<code>.</code>). - */ -void -Init_Dir() -{ - rb_cDir = rb_define_class("Dir", rb_cObject); - - rb_include_module(rb_cDir, rb_mEnumerable); - - rb_define_alloc_func(rb_cDir, dir_s_alloc); - rb_define_singleton_method(rb_cDir, "open", dir_s_open, 1); - rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, 1); - rb_define_singleton_method(rb_cDir, "entries", dir_entries, 1); - - rb_define_method(rb_cDir,"initialize", dir_initialize, 1); - rb_define_method(rb_cDir,"path", dir_path, 0); - rb_define_method(rb_cDir,"inspect", dir_inspect, 0); - rb_define_method(rb_cDir,"read", dir_read, 0); - rb_define_method(rb_cDir,"each", dir_each, 0); - rb_define_method(rb_cDir,"rewind", dir_rewind, 0); - rb_define_method(rb_cDir,"tell", dir_tell, 0); - rb_define_method(rb_cDir,"seek", dir_seek, 1); - rb_define_method(rb_cDir,"pos", dir_tell, 0); - rb_define_method(rb_cDir,"pos=", dir_set_pos, 1); - rb_define_method(rb_cDir,"close", dir_close, 0); - - rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1); - rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0); - rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0); - rb_define_singleton_method(rb_cDir,"chroot", dir_s_chroot, 1); - rb_define_singleton_method(rb_cDir,"mkdir", dir_s_mkdir, -1); - rb_define_singleton_method(rb_cDir,"rmdir", dir_s_rmdir, 1); - rb_define_singleton_method(rb_cDir,"delete", dir_s_rmdir, 1); - rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1); - - rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1); - rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, 1); - - rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1); - rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1); - - rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE)); - rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME)); - rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH)); - rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD)); -} -/********************************************************************** - - dln.c - - - $Author: murphy $ - $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $ - created at: Tue Jan 18 17:05:06 JST 1994 - - Copyright (C) 1993-2003 Yukihiro Matsumoto - -**********************************************************************/ - -#include "ruby.h" -#include "dln.h" - -#ifdef HAVE_STDLIB_H -# include <stdlib.h> -#endif - -#ifdef __CHECKER__ -#undef HAVE_DLOPEN -#undef USE_DLN_A_OUT -#undef USE_DLN_DLOPEN -#endif - -#ifdef USE_DLN_A_OUT -char *dln_argv0; -#endif - -#ifdef _AIX -#pragma alloca -#endif - -#if defined(HAVE_ALLOCA_H) -#include <alloca.h> -#endif - -#ifdef HAVE_STRING_H -# include <string.h> -#else -# include <strings.h> -#endif - -#ifndef xmalloc -void *xmalloc(); -void *xcalloc(); -void *xrealloc(); -#endif - -#include <stdio.h> -#if defined(_WIN32) || defined(__VMS) -#include "missing/file.h" -#endif -#include <sys/types.h> -#include <sys/stat.h> - -#ifndef S_ISDIR -# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) -#endif - -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> -#endif -#ifndef MAXPATHLEN -# define MAXPATHLEN 1024 -#endif - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#ifndef _WIN32 -char *getenv(); -#endif - -#if defined(__VMS) -#pragma builtins -#include <dlfcn.h> -#endif - -#ifdef __MACOS__ -# include <TextUtils.h> -# include <CodeFragments.h> -# include <Aliases.h> -# include "macruby_private.h" -#endif - -#ifdef __BEOS__ -# include <image.h> -#endif - -int eaccess(); - -#ifndef NO_DLN_LOAD - -#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(__APPLE__) && !defined(_UNICOSMP) -/* dynamic load with dlopen() */ -# define USE_DLN_DLOPEN -#endif - -#ifndef FUNCNAME_PATTERN -# if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(__APPLE__) -# define FUNCNAME_PATTERN "_Init_%s" -# else -# define FUNCNAME_PATTERN "Init_%s" -# endif -#endif - -static int -init_funcname_len(buf, file) - char **buf; - const char *file; -{ - char *p; - const char *slash; - int len; - - /* Load the file as an object one */ - for (slash = file-1; *file; file++) /* Find position of last '/' */ -#ifdef __MACOS__ - if (*file == ':') slash = file; -#else - if (*file == '/') slash = file; -#endif - - len = strlen(FUNCNAME_PATTERN) + strlen(slash + 1); - *buf = xmalloc(len); - snprintf(*buf, len, FUNCNAME_PATTERN, slash + 1); - for (p = *buf; *p; p++) { /* Delete suffix if it exists */ - if (*p == '.') { - *p = '\0'; break; - } - } - return p - *buf; -} - -#define init_funcname(buf, file) do {\ - int len = init_funcname_len(buf, file);\ - char *tmp = ALLOCA_N(char, len+1);\ - if (!tmp) {\ - free(*buf);\ - rb_memerror();\ - }\ - strcpy(tmp, *buf);\ - free(*buf);\ - *buf = tmp;\ -} while (0) - -#ifdef USE_DLN_A_OUT - -#ifndef LIBC_NAME -# define LIBC_NAME "libc.a" -#endif - -#ifndef DLN_DEFAULT_LIB_PATH -# define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:." -#endif - -#include <errno.h> - -static int dln_errno; - -#define DLN_ENOEXEC ENOEXEC /* Exec format error */ -#define DLN_ECONFL 1201 /* Symbol name conflict */ -#define DLN_ENOINIT 1202 /* No initializer given */ -#define DLN_EUNDEF 1203 /* Undefine symbol remains */ -#define DLN_ENOTLIB 1204 /* Not a library file */ -#define DLN_EBADLIB 1205 /* Malformed library file */ -#define DLN_EINIT 1206 /* Not initialized */ - -static int dln_init_p = 0; - -#include <ar.h> -#include <a.out.h> -#ifndef N_COMM -# define N_COMM 0x12 -#endif -#ifndef N_MAGIC -# define N_MAGIC(x) (x).a_magic -#endif - -#define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC) - -#include "util.h" -#include "st.h" - -static st_table *sym_tbl; -static st_table *undef_tbl; - -static int load_lib(); - -static int -load_header(fd, hdrp, disp) - int fd; - struct exec *hdrp; - long disp; -{ - int size; - - lseek(fd, disp, 0); - size = read(fd, hdrp, sizeof(struct exec)); - if (size == -1) { - dln_errno = errno; - return -1; - } - if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) { - dln_errno = DLN_ENOEXEC; - return -1; - } - return 0; -} - -#if defined(sequent) -#define RELOC_SYMBOL(r) ((r)->r_symbolnum) -#define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr) -#define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr) -#define RELOC_TARGET_SIZE(r) ((r)->r_length) -#endif - -/* Default macros */ -#ifndef RELOC_ADDRESS -#define RELOC_ADDRESS(r) ((r)->r_address) -#define RELOC_EXTERN_P(r) ((r)->r_extern) -#define RELOC_SYMBOL(r) ((r)->r_symbolnum) -#define RELOC_MEMORY_SUB_P(r) 0 -#define RELOC_PCREL_P(r) ((r)->r_pcrel) -#define RELOC_TARGET_SIZE(r) ((r)->r_length) -#endif - -#if defined(sun) && defined(sparc) -/* Sparc (Sun 4) macros */ -# undef relocation_info -# define relocation_info reloc_info_sparc -# define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type]) -# define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type]) -# define R_LENGTH(r) (reloc_r_length[(r)->r_type]) -static int reloc_r_rightshift[] = { - 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0, -}; -static int reloc_r_bitsize[] = { - 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16, -}; -static int reloc_r_length[] = { - 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -}; -# define R_PCREL(r) \ - ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) -# define R_SYMBOL(r) ((r)->r_index) -#endif - -#if defined(sequent) -#define R_SYMBOL(r) ((r)->r_symbolnum) -#define R_MEMORY_SUB(r) ((r)->r_bsr) -#define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr) -#define R_LENGTH(r) ((r)->r_length) -#endif - -#ifndef R_SYMBOL -# define R_SYMBOL(r) ((r)->r_symbolnum) -# define R_MEMORY_SUB(r) 0 -# define R_PCREL(r) ((r)->r_pcrel) -# define R_LENGTH(r) ((r)->r_length) -#endif - -static struct relocation_info * -load_reloc(fd, hdrp, disp) - int fd; - struct exec *hdrp; - long disp; -{ - struct relocation_info *reloc; - int size; - - lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0); - size = hdrp->a_trsize + hdrp->a_drsize; - reloc = (struct relocation_info*)xmalloc(size); - if (reloc == NULL) { - dln_errno = errno; - return NULL; - } - - if (read(fd, reloc, size) != size) { - dln_errno = errno; - free(reloc); - return NULL; - } - - return reloc; -} - -static struct nlist * -load_sym(fd, hdrp, disp) - int fd; - struct exec *hdrp; - long disp; -{ - struct nlist * buffer; - struct nlist * sym; - struct nlist * end; - long displ; - int size; - - lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0); - if (read(fd, &size, sizeof(int)) != sizeof(int)) { - goto err_noexec; - } - - buffer = (struct nlist*)xmalloc(hdrp->a_syms + size); - if (buffer == NULL) { - dln_errno = errno; - return NULL; - } - - lseek(fd, disp + N_SYMOFF(*hdrp), 0); - if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) { - free(buffer); - goto err_noexec; - } - - sym = buffer; - end = sym + hdrp->a_syms / sizeof(struct nlist); - displ = (long)buffer + (long)(hdrp->a_syms); - - while (sym < end) { - sym->n_un.n_name = (char*)sym->n_un.n_strx + displ; - sym++; - } - return buffer; - - err_noexec: - dln_errno = DLN_ENOEXEC; - return NULL; -} - -static st_table * -sym_hash(hdrp, syms) - struct exec *hdrp; - struct nlist *syms; -{ - st_table *tbl; - struct nlist *sym = syms; - struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist)); - - tbl = st_init_strtable(); - if (tbl == NULL) { - dln_errno = errno; - return NULL; - } - - while (sym < end) { - st_insert(tbl, sym->n_un.n_name, sym); - sym++; - } - return tbl; -} - -static int -dln_init(prog) - const char *prog; -{ - char *file; - int fd; - struct exec hdr; - struct nlist *syms; - - if (dln_init_p == 1) return 0; - - file = dln_find_exe(prog, NULL); - if (file == NULL || (fd = open(file, O_RDONLY)) < 0) { - dln_errno = errno; - return -1; - } - - if (load_header(fd, &hdr, 0) == -1) return -1; - syms = load_sym(fd, &hdr, 0); - if (syms == NULL) { - close(fd); - return -1; - } - sym_tbl = sym_hash(&hdr, syms); - if (sym_tbl == NULL) { /* file may be start with #! */ - char c = '\0'; - char buf[MAXPATHLEN]; - char *p; - - free(syms); - lseek(fd, 0L, 0); - if (read(fd, &c, 1) == -1) { - dln_errno = errno; - return -1; - } - if (c != '#') goto err_noexec; - if (read(fd, &c, 1) == -1) { - dln_errno = errno; - return -1; - } - if (c != '!') goto err_noexec; - - p = buf; - /* skip forwarding spaces */ - while (read(fd, &c, 1) == 1) { - if (c == '\n') goto err_noexec; - if (c != '\t' && c != ' ') { - *p++ = c; - break; - } - } - /* read in command name */ - while (read(fd, p, 1) == 1) { - if (*p == '\n' || *p == '\t' || *p == ' ') break; - p++; - if (p-buf >= MAXPATHLEN) { - dln_errno = ENAMETOOLONG; - return -1; - } - } - *p = '\0'; - - return dln_init(buf); - } - dln_init_p = 1; - undef_tbl = st_init_strtable(); - close(fd); - return 0; - - err_noexec: - close(fd); - dln_errno = DLN_ENOEXEC; - return -1; -} - -static long -load_text_data(fd, hdrp, bss, disp) - int fd; - struct exec *hdrp; - int bss; - long disp; -{ - int size; - unsigned char* addr; - - lseek(fd, disp + N_TXTOFF(*hdrp), 0); - size = hdrp->a_text + hdrp->a_data; - - if (bss == -1) size += hdrp->a_bss; - else if (bss > 1) size += bss; - - addr = (unsigned char*)xmalloc(size); - if (addr == NULL) { - dln_errno = errno; - return 0; - } - - if (read(fd, addr, size) != size) { - dln_errno = errno; - free(addr); - return 0; - } - - if (bss == -1) { - memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss); - } - else if (bss > 0) { - memset(addr + hdrp->a_text + hdrp->a_data, 0, bss); - } - - return (long)addr; -} - -static int -undef_print(key, value) - char *key, *value; -{ - fprintf(stderr, " %s\n", key); - return ST_CONTINUE; -} - -static void -dln_print_undef() -{ - fprintf(stderr, " Undefined symbols:\n"); - st_foreach(undef_tbl, undef_print, NULL); -} - -static void -dln_undefined() -{ - if (undef_tbl->num_entries > 0) { - fprintf(stderr, "dln: Calling undefined function\n"); - dln_print_undef(); - rb_exit(1); - } -} - -struct undef { - char *name; - struct relocation_info reloc; - long base; - char *addr; - union { - char c; - short s; - long l; - } u; -}; - -static st_table *reloc_tbl = NULL; -static void -link_undef(name, base, reloc) - const char *name; - long base; - struct relocation_info *reloc; -{ - static int u_no = 0; - struct undef *obj; - char *addr = (char*)(reloc->r_address + base); - - obj = (struct undef*)xmalloc(sizeof(struct undef)); - obj->name = strdup(name); - obj->reloc = *reloc; - obj->base = base; - switch (R_LENGTH(reloc)) { - case 0: /* byte */ - obj->u.c = *addr; - break; - case 1: /* word */ - obj->u.s = *(short*)addr; - break; - case 2: /* long */ - obj->u.l = *(long*)addr; - break; - } - if (reloc_tbl == NULL) { - reloc_tbl = st_init_numtable(); - } - st_insert(reloc_tbl, u_no++, obj); -} - -struct reloc_arg { - const char *name; - long value; -}; - -static int -reloc_undef(no, undef, arg) - int no; - struct undef *undef; - struct reloc_arg *arg; -{ - int datum; - char *address; -#if defined(sun) && defined(sparc) - unsigned int mask = 0; -#endif - - if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE; - address = (char*)(undef->base + undef->reloc.r_address); - datum = arg->value; - - if (R_PCREL(&(undef->reloc))) datum -= undef->base; -#if defined(sun) && defined(sparc) - datum += undef->reloc.r_addend; - datum >>= R_RIGHTSHIFT(&(undef->reloc)); - mask = (1 << R_BITSIZE(&(undef->reloc))) - 1; - mask |= mask -1; - datum &= mask; - switch (R_LENGTH(&(undef->reloc))) { - case 0: - *address = undef->u.c; - *address &= ~mask; - *address |= datum; - break; - case 1: - *(short *)address = undef->u.s; - *(short *)address &= ~mask; - *(short *)address |= datum; - break; - case 2: - *(long *)address = undef->u.l; - *(long *)address &= ~mask; - *(long *)address |= datum; - break; - } -#else - switch (R_LENGTH(&(undef->reloc))) { - case 0: /* byte */ - if (R_MEMORY_SUB(&(undef->reloc))) - *address = datum - *address; - else *address = undef->u.c + datum; - break; - case 1: /* word */ - if (R_MEMORY_SUB(&(undef->reloc))) - *(short*)address = datum - *(short*)address; - else *(short*)address = undef->u.s + datum; - break; - case 2: /* long */ - if (R_MEMORY_SUB(&(undef->reloc))) - *(long*)address = datum - *(long*)address; - else *(long*)address = undef->u.l + datum; - break; - } -#endif - free(undef->name); - free(undef); - return ST_DELETE; -} - -static void -unlink_undef(name, value) - const char *name; - long value; -{ - struct reloc_arg arg; - - arg.name = name; - arg.value = value; - st_foreach(reloc_tbl, reloc_undef, &arg); -} - -#ifdef N_INDR -struct indr_data { - char *name0, *name1; -}; - -static int -reloc_repl(no, undef, data) - int no; - struct undef *undef; - struct indr_data *data; -{ - if (strcmp(data->name0, undef->name) == 0) { - free(undef->name); - undef->name = strdup(data->name1); - } - return ST_CONTINUE; -} -#endif - -static int -load_1(fd, disp, need_init) - int fd; - long disp; - const char *need_init; -{ - static char *libc = LIBC_NAME; - struct exec hdr; - struct relocation_info *reloc = NULL; - long block = 0; - long new_common = 0; /* Length of new common */ - struct nlist *syms = NULL; - struct nlist *sym; - struct nlist *end; - int init_p = 0; - - if (load_header(fd, &hdr, disp) == -1) return -1; - if (INVALID_OBJECT(hdr)) { - dln_errno = DLN_ENOEXEC; - return -1; - } - reloc = load_reloc(fd, &hdr, disp); - if (reloc == NULL) return -1; - - syms = load_sym(fd, &hdr, disp); - if (syms == NULL) { - free(reloc); - return -1; - } - - sym = syms; - end = syms + (hdr.a_syms / sizeof(struct nlist)); - while (sym < end) { - struct nlist *old_sym; - int value = sym->n_value; - -#ifdef N_INDR - if (sym->n_type == (N_INDR | N_EXT)) { - char *key = sym->n_un.n_name; - - if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) { - if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { - unlink_undef(key, old_sym->n_value); - free(key); - } - } - else { - struct indr_data data; - - data.name0 = sym->n_un.n_name; - data.name1 = sym[1].n_un.n_name; - st_foreach(reloc_tbl, reloc_repl, &data); - - st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL); - if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) { - free(key); - } - } - sym += 2; - continue; - } -#endif - if (sym->n_type == (N_UNDF | N_EXT)) { - if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) { - old_sym = NULL; - } - - if (value) { - if (old_sym) { - sym->n_type = N_EXT | N_COMM; - sym->n_value = old_sym->n_value; - } - else { - int rnd = - value >= sizeof(double) ? sizeof(double) - 1 - : value >= sizeof(long) ? sizeof(long) - 1 - : sizeof(short) - 1; - - sym->n_type = N_COMM; - new_common += rnd; - new_common &= ~(long)rnd; - sym->n_value = new_common; - new_common += value; - } - } - else { - if (old_sym) { - sym->n_type = N_EXT | N_COMM; - sym->n_value = old_sym->n_value; - } - else { - sym->n_value = (long)dln_undefined; - st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL); - } - } - } - sym++; - } - - block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp); - if (block == 0) goto err_exit; - - sym = syms; - while (sym < end) { - struct nlist *new_sym; - char *key; - - switch (sym->n_type) { - case N_COMM: - sym->n_value += hdr.a_text + hdr.a_data; - case N_TEXT|N_EXT: - case N_DATA|N_EXT: - - sym->n_value += block; - - if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0 - && new_sym->n_value != (long)dln_undefined) { - dln_errno = DLN_ECONFL; - goto err_exit; - } - - key = sym->n_un.n_name; - if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) { - unlink_undef(key, sym->n_value); - free(key); - } - - new_sym = (struct nlist*)xmalloc(sizeof(struct nlist)); - *new_sym = *sym; - new_sym->n_un.n_name = strdup(sym->n_un.n_name); - st_insert(sym_tbl, new_sym->n_un.n_name, new_sym); - break; - - case N_TEXT: - case N_DATA: - sym->n_value += block; - break; - } - sym++; - } - - /* - * First comes the text-relocation - */ - { - struct relocation_info * rel = reloc; - struct relocation_info * rel_beg = reloc + - (hdr.a_trsize/sizeof(struct relocation_info)); - struct relocation_info * rel_end = reloc + - (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info); - - while (rel < rel_end) { - char *address = (char*)(rel->r_address + block); - long datum = 0; -#if defined(sun) && defined(sparc) - unsigned int mask = 0; -#endif - - if(rel >= rel_beg) - address += hdr.a_text; - - if (rel->r_extern) { /* Look it up in symbol-table */ - sym = &(syms[R_SYMBOL(rel)]); - switch (sym->n_type) { - case N_EXT|N_UNDF: - link_undef(sym->n_un.n_name, block, rel); - case N_EXT|N_COMM: - case N_COMM: - datum = sym->n_value; - break; - default: - goto err_exit; - } - } /* end.. look it up */ - else { /* is static */ - switch (R_SYMBOL(rel)) { - case N_TEXT: - case N_DATA: - datum = block; - break; - case N_BSS: - datum = block + new_common; - break; - case N_ABS: - break; - } - } /* end .. is static */ - if (R_PCREL(rel)) datum -= block; - -#if defined(sun) && defined(sparc) - datum += rel->r_addend; - datum >>= R_RIGHTSHIFT(rel); - mask = (1 << R_BITSIZE(rel)) - 1; - mask |= mask -1; - datum &= mask; - - switch (R_LENGTH(rel)) { - case 0: - *address &= ~mask; - *address |= datum; - break; - case 1: - *(short *)address &= ~mask; - *(short *)address |= datum; - break; - case 2: - *(long *)address &= ~mask; - *(long *)address |= datum; - break; - } -#else - switch (R_LENGTH(rel)) { - case 0: /* byte */ - if (datum < -128 || datum > 127) goto err_exit; - *address += datum; - break; - case 1: /* word */ - *(short *)address += datum; - break; - case 2: /* long */ - *(long *)address += datum; - break; - } -#endif - rel++; - } - } - - if (need_init) { - int len; - char **libs_to_be_linked = 0; - char *buf; - - if (undef_tbl->num_entries > 0) { - if (load_lib(libc) == -1) goto err_exit; - } - - init_funcname(&buf, need_init); - len = strlen(buf); - - for (sym = syms; sym<end; sym++) { - char *name = sym->n_un.n_name; - if (name[0] == '_' && sym->n_value >= block) { - if (strcmp(name+1, "dln_libs_to_be_linked") == 0) { - libs_to_be_linked = (char**)sym->n_value; - } - else if (strcmp(name+1, buf) == 0) { - init_p = 1; - ((int (*)())sym->n_value)(); - } - } - } - if (libs_to_be_linked && undef_tbl->num_entries > 0) { - while (*libs_to_be_linked) { - load_lib(*libs_to_be_linked); - libs_to_be_linked++; - } - } - } - free(reloc); - free(syms); - if (need_init) { - if (init_p == 0) { - dln_errno = DLN_ENOINIT; - return -1; - } - if (undef_tbl->num_entries > 0) { - if (load_lib(libc) == -1) goto err_exit; - if (undef_tbl->num_entries > 0) { - dln_errno = DLN_EUNDEF; - return -1; - } - } - } - return 0; - - err_exit: - if (syms) free(syms); - if (reloc) free(reloc); - if (block) free((char*)block); - return -1; -} - -static int target_offset; -static int -search_undef(key, value, lib_tbl) - const char *key; - int value; - st_table *lib_tbl; -{ - long offset; - - if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE; - target_offset = offset; - return ST_STOP; -} - -struct symdef { - int rb_str_index; - int lib_offset; -}; - -char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH; - -static int -load_lib(lib) - const char *lib; -{ - char *path, *file; - char armagic[SARMAG]; - int fd, size; - struct ar_hdr ahdr; - st_table *lib_tbl = NULL; - int *data, nsym; - struct symdef *base; - char *name_base; - - if (dln_init_p == 0) { - dln_errno = DLN_ENOINIT; - return -1; - } - - if (undef_tbl->num_entries == 0) return 0; - dln_errno = DLN_EBADLIB; - - if (lib[0] == '-' && lib[1] == 'l') { - char *p = alloca(strlen(lib) + 4); - sprintf(p, "lib%s.a", lib+2); - lib = p; - } - - /* library search path: */ - /* look for environment variable DLN_LIBRARY_PATH first. */ - /* then variable dln_librrb_ary_path. */ - /* if path is still NULL, use "." for path. */ - path = getenv("DLN_LIBRARY_PATH"); - if (path == NULL) path = dln_librrb_ary_path; - - file = dln_find_file(lib, path); - fd = open(file, O_RDONLY); - if (fd == -1) goto syserr; - size = read(fd, armagic, SARMAG); - if (size == -1) goto syserr; - - if (size != SARMAG) { - dln_errno = DLN_ENOTLIB; - goto badlib; - } - size = read(fd, &ahdr, sizeof(ahdr)); - if (size == -1) goto syserr; - if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) { - goto badlib; - } - - if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) { - /* make hash table from __.SYMDEF */ - - lib_tbl = st_init_strtable(); - data = (int*)xmalloc(size); - if (data == NULL) goto syserr; - size = read(fd, data, size); - nsym = *data / sizeof(struct symdef); - base = (struct symdef*)(data + 1); - name_base = (char*)(base + nsym) + sizeof(int); - while (nsym > 0) { - char *name = name_base + base->rb_str_index; - - st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr)); - nsym--; - base++; - } - for (;;) { - target_offset = -1; - st_foreach(undef_tbl, search_undef, lib_tbl); - if (target_offset == -1) break; - if (load_1(fd, target_offset, 0) == -1) { - st_free_table(lib_tbl); - free(data); - goto badlib; - } - if (undef_tbl->num_entries == 0) break; - } - free(data); - st_free_table(lib_tbl); - } - else { - /* linear library, need to scan (FUTURE) */ - - for (;;) { - int offset = SARMAG; - int found = 0; - struct exec hdr; - struct nlist *syms, *sym, *end; - - while (undef_tbl->num_entries > 0) { - found = 0; - lseek(fd, offset, 0); - size = read(fd, &ahdr, sizeof(ahdr)); - if (size == -1) goto syserr; - if (size == 0) break; - if (size != sizeof(ahdr) - || sscanf(ahdr.ar_size, "%d", &size) != 1) { - goto badlib; - } - offset += sizeof(ahdr); - if (load_header(fd, &hdr, offset) == -1) - goto badlib; - syms = load_sym(fd, &hdr, offset); - if (syms == NULL) goto badlib; - sym = syms; - end = syms + (hdr.a_syms / sizeof(struct nlist)); - while (sym < end) { - if (sym->n_type == N_EXT|N_TEXT - && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) { - break; - } - sym++; - } - if (sym < end) { - found++; - free(syms); - if (load_1(fd, offset, 0) == -1) { - goto badlib; - } - } - offset += size; - if (offset & 1) offset++; - } - if (found) break; - } - } - close(fd); - return 0; - - syserr: - dln_errno = errno; - badlib: - if (fd >= 0) close(fd); - return -1; -} - -static int -load(file) - const char *file; -{ - int fd; - int result; - - if (dln_init_p == 0) { - if (dln_init(dln_argv0) == -1) return -1; - } - result = strlen(file); - if (file[result-1] == 'a') { - return load_lib(file); - } - - fd = open(file, O_RDONLY); - if (fd == -1) { - dln_errno = errno; - return -1; - } - result = load_1(fd, 0, file); - close(fd); - - return result; -} - -void* -dln_sym(name) - const char *name; -{ - struct nlist *sym; - - if (st_lookup(sym_tbl, name, &sym)) - return (void*)sym->n_value; - return NULL; -} - -#endif /* USE_DLN_A_OUT */ - -#ifdef USE_DLN_DLOPEN -# include <dlfcn.h> -#endif - -#ifdef __hpux -#include <errno.h> -#include "dl.h" -#endif - -#if defined(_AIX) -#include <ctype.h> /* for isdigit() */ -#include <errno.h> /* for global errno */ -#include <sys/ldr.h> -#endif - -#ifdef NeXT -#if NS_TARGET_MAJOR < 4 -#include <mach-o/rld.h> -#else -#include <mach-o/dyld.h> -#ifndef NSLINKMODULE_OPTION_BINDNOW -#define NSLINKMODULE_OPTION_BINDNOW 1 -#endif -#endif -#else -#ifdef __APPLE__ -#include <mach-o/dyld.h> -#endif -#endif - -#if defined _WIN32 && !defined __CYGWIN__ -#include <windows.h> -#endif - -#ifdef _WIN32_WCE -#undef FormatMessage -#define FormatMessage FormatMessageA -#undef LoadLibrary -#define LoadLibrary LoadLibraryA -#undef GetProcAddress -#define GetProcAddress GetProcAddressA -#endif - -static const char * -dln_strerror() -{ -#ifdef USE_DLN_A_OUT - char *strerror(); - - switch (dln_errno) { - case DLN_ECONFL: - return "Symbol name conflict"; - case DLN_ENOINIT: - return "No initializer given"; - case DLN_EUNDEF: - return "Unresolved symbols"; - case DLN_ENOTLIB: - return "Not a library file"; - case DLN_EBADLIB: - return "Malformed library file"; - case DLN_EINIT: - return "Not initialized"; - default: - return strerror(dln_errno); - } -#endif - -#ifdef USE_DLN_DLOPEN - return (char*)dlerror(); -#endif - -#if defined _WIN32 && !defined __CYGWIN__ - static char message[1024]; - int error = GetLastError(); - char *p = message; - p += sprintf(message, "%d: ", error); - FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - p, - sizeof message - strlen(message), - NULL); - - for (p = message; *p; p++) { - if (*p == '\n' || *p == '\r') - *p = ' '; - } - return message; -#endif -} - - -#if defined(_AIX) && ! defined(_IA64) -static void -aix_loaderror(const char *pathname) -{ - char *message[8], errbuf[1024]; - int i,j; - - struct errtab { - int errnum; - char *errstr; - } load_errtab[] = { - {L_ERROR_TOOMANY, "too many errors, rest skipped."}, - {L_ERROR_NOLIB, "can't load library:"}, - {L_ERROR_UNDEF, "can't find symbol in library:"}, - {L_ERROR_RLDBAD, - "RLD index out of range or bad relocation type:"}, - {L_ERROR_FORMAT, "not a valid, executable xcoff file:"}, - {L_ERROR_MEMBER, - "file not an archive or does not contain requested member:"}, - {L_ERROR_TYPE, "symbol table mismatch:"}, - {L_ERROR_ALIGN, "text alignment in file is wrong."}, - {L_ERROR_SYSTEM, "System error:"}, - {L_ERROR_ERRNO, NULL} - }; - -#define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0])) -#define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1) - - snprintf(errbuf, 1024, "load failed - %s ", pathname); - - if (!loadquery(1, &message[0], sizeof(message))) - ERRBUF_APPEND(strerror(errno)); - for(i = 0; message[i] && *message[i]; i++) { - int nerr = atoi(message[i]); - for (j=0; j<LOAD_ERRTAB_LEN; j++) { - if (nerr == load_errtab[i].errnum && load_errtab[i].errstr) - ERRBUF_APPEND(load_errtab[i].errstr); - } - while (isdigit(*message[i])) message[i]++; - ERRBUF_APPEND(message[i]); - ERRBUF_APPEND("\n"); - } - errbuf[strlen(errbuf)-1] = '\0'; /* trim off last newline */ - rb_loaderror(errbuf); - return; -} -#endif - -#endif /* NO_DLN_LOAD */ - |