/*
 * call-seq:
 *     big ^ numeric   =>  integer
 *
 * Performs bitwise +exclusive or+ between _big_ and _numeric_.
 */

VALUE
rb_big_xor(VALUE xx, VALUE yy)
{
    volatile VALUE x, y;
    VALUE z;
    BDIGIT *ds1, *ds2, *zds;
    long i, l1, l2;
    char sign;

    x = xx;
    y = bit_coerce(yy);
    if (FIXNUM_P(y)) {
        y = rb_int2big(FIX2LONG(y));
    }

    if (!RBIGNUM_SIGN(y)) {
        y = rb_big_clone(y);
        get2comp(y);
    }
    if (!RBIGNUM_SIGN(x)) {
        x = rb_big_clone(x);
        get2comp(x);
    }
    if (RBIGNUM_LEN(x) > RBIGNUM_LEN(y)) {
        l1 = RBIGNUM_LEN(y);
        l2 = RBIGNUM_LEN(x);
        ds1 = BDIGITS(y);
        ds2 = BDIGITS(x);
        sign = RBIGNUM_SIGN(y);
    }
    else {
        l1 = RBIGNUM_LEN(x);
        l2 = RBIGNUM_LEN(y);
        ds1 = BDIGITS(x);
        ds2 = BDIGITS(y);
        sign = RBIGNUM_SIGN(x);
    }
    RBIGNUM_SET_SIGN(x, RBIGNUM_SIGN(x)?1:0);
    RBIGNUM_SET_SIGN(y, RBIGNUM_SIGN(y)?1:0);
    z = bignew(l2, !(RBIGNUM_SIGN(x) ^ RBIGNUM_SIGN(y)));
    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_SIGN(z)) get2comp(z);

    return bignorm(z);
}