diff options
Diffstat (limited to '')
-rw-r--r-- | CInt64.c | 893 |
1 files changed, 893 insertions, 0 deletions
diff --git a/CInt64.c b/CInt64.c new file mode 100644 index 0000000..9b793bd --- /dev/null +++ b/CInt64.c @@ -0,0 +1,893 @@ +#include <MacHeadersMach-O> +#include "CInt64.h" + +const CInt64 cint64_negone = {0xFFFFFFFF, 0xFFFFFFFF}; +const CInt64 cint64_zero = {0, 0}; +const CInt64 cint64_one = {0, 1}; +const CInt64 cint64_max = {0x7FFFFFFF, 0xFFFFFFFF}; +const CInt64 cint64_min = {0x80000000, 0}; + +#define SHIFT_LEFT_ONE(a, b) do { a <<= 1; if (b & 0x80000000) { a |= 1; } b <<= 1; } while(0) + +void CInt64_Init() { +} + +CInt64 CInt64_Not(CInt64 input) { + CInt64 output; + unsigned char c; + + c = (input.a == 0 && input.b == 0); + CInt64_SetLong(&output, c); + + return output; +} + +CInt64 CInt64_Inv(CInt64 input) { + CInt64 output; + output.a = ~input.a; + output.b = ~input.b; + return output; +} + +CInt64 CInt64_Add(CInt64 lhs, CInt64 rhs) { + if (lhs.b & 0x80000000) { + if (rhs.b & 0x80000000) { + lhs.b += rhs.b; + lhs.a += 1; + } else { + lhs.b += rhs.b; + if (!(lhs.b & 0x80000000)) + lhs.a += 1; + } + } else { + if (rhs.b & 0x80000000) { + lhs.b += rhs.b; + if (!(lhs.b & 0x80000000)) + lhs.a += 1; + } else { + lhs.b += rhs.b; + } + } + lhs.a += rhs.a; + return lhs; +} + +CInt64 CInt64_Neg(CInt64 input) { + CInt64 result; + result = CInt64_Add(CInt64_Inv(input), cint64_one); + return result; +} + +CInt64 CInt64_Sub(CInt64 lhs, CInt64 rhs) { + lhs = CInt64_Add(lhs, CInt64_Neg(rhs)); + return lhs; +} + +CInt64 CInt64_MulU(CInt64 lhs, CInt64 rhs) { + CInt64 result; + CInt64 work1; + unsigned long aaaa; + unsigned long bbbb; + unsigned long cccc; + unsigned long dddd; + unsigned long eeee; + + aaaa = rhs.b; + result.a = result.b = 0; + bbbb = lhs.b; + cccc = rhs.a; + dddd = rhs.b; + + while (bbbb != 0) { + if (bbbb & 1) { + work1.a = cccc; + work1.b = dddd; + result = CInt64_Add(result, work1); + } + cccc <<= 1; + if (dddd & 0x80000000) + cccc |= 1; + dddd <<= 1; + bbbb >>= 1; + } + + eeee = lhs.a; + while (eeee != 0 && aaaa != 0) { + if (eeee & 1) + result.a += aaaa; + aaaa <<= 1; + eeee >>= 1; + } + + return result; +} + +CInt64 CInt64_Mul(CInt64 lhs, CInt64 rhs) { + if (CInt64_IsNegative(&rhs)) { + if (CInt64_IsNegative(&lhs)) { + return CInt64_MulU(CInt64_Neg(lhs), CInt64_Neg(rhs)); + } + return CInt64_Neg(CInt64_MulU(lhs, CInt64_Neg(rhs))); + } + if (CInt64_IsNegative(&lhs)) { + return CInt64_Neg(CInt64_MulU(CInt64_Neg(lhs), rhs)); + } + return CInt64_MulU(lhs, rhs); +} + +void CInt64_DivMod(const CInt64 *lhs, const CInt64 *rhs, CInt64 *pDiv, CInt64 *pMod) { + unsigned char bad; + unsigned long workA; + unsigned long workB; + unsigned long leftA; + unsigned long leftB; + unsigned long rightA; + unsigned long rightB; + unsigned long outA; + unsigned long outB; + CInt64 work; + int counter; + + bad = (rhs->a == 0) && (rhs->b == 0); + if (!bad) { + workA = 0; + workB = 0; + leftA = lhs->a; + leftB = lhs->b; + rightA = rhs->a; + rightB = rhs->b; + outA = 0; + outB = 0; + counter = 0; + + do { + workA <<= 1; + if (workB & 0x80000000) + workA |= 1; + workB <<= 1; + if (leftA & 0x80000000) + workB |= 1; + leftA <<= 1; + if (leftB & 0x80000000) + leftA |= 1; + leftB <<= 1; + + outA <<= 1; + if (outB & 0x80000000) + outA |= 1; + outB <<= 1; + + if (workA <= rightA) { + if (workA != rightA) + continue; + if (workB < rightB) + continue; + } + + outB |= 1; + + work.a = workA; + work.b = workB; + work = CInt64_Sub(work, *rhs); + workA = work.a; + workB = work.b; + } while (++counter < 64); + + if (pDiv) { + pDiv->a = outA; + pDiv->b = outB; + } + if (pMod) { + pMod->a = workA; + pMod->b = workB; + } + } +} + +CInt64 CInt64_Div(CInt64 lhs, CInt64 rhs) { + CInt64 result; + if (CInt64_IsNegative(&rhs)) { + rhs = CInt64_Neg(rhs); + if (CInt64_IsNegative(&lhs)) { + lhs = CInt64_Neg(lhs); + CInt64_DivMod(&lhs, &rhs, &result, 0); + return result; + } else { + CInt64_DivMod(&lhs, &rhs, &result, 0); + return CInt64_Neg(result); + } + } else { + if (CInt64_IsNegative(&lhs)) { + lhs = CInt64_Neg(lhs); + CInt64_DivMod(&lhs, &rhs, &result, 0); + return CInt64_Neg(result); + } else { + CInt64_DivMod(&lhs, &rhs, &result, 0); + return result; + } + } +} + +CInt64 CInt64_DivU(CInt64 lhs, CInt64 rhs) { + CInt64 result; + CInt64_DivMod(&lhs, &rhs, &result, 0); + return result; +} + +CInt64 CInt64_Mod(CInt64 lhs, CInt64 rhs) { + CInt64 result; + if (CInt64_IsNegative(&lhs)) { + lhs = CInt64_Neg(lhs); + if (CInt64_IsNegative(&rhs)) + rhs = CInt64_Neg(rhs); + CInt64_DivMod(&lhs, &rhs, 0, &result); + return CInt64_Neg(result); + } else { + if (CInt64_IsNegative(&rhs)) + rhs = CInt64_Neg(rhs); + CInt64_DivMod(&lhs, &rhs, 0, &result); + return result; + } +} + +CInt64 CInt64_ModU(CInt64 lhs, CInt64 rhs) { + CInt64 result; + CInt64_DivMod(&lhs, &rhs, 0, &result); + return result; +} + +CInt64 CInt64_Shl(CInt64 lhs, CInt64 rhs) { + int counter; + unsigned long a; + unsigned long b; + + if (rhs.a == 0 && rhs.b < 64) { + a = lhs.a; + b = lhs.b; + for (counter = rhs.b; counter != 0; --counter) { + a <<= 1; + if (b & 0x80000000) + a |= 1; + b <<= 1; + } + lhs.a = a; + lhs.b = b; + } else { + lhs.a = 0; + lhs.b = 0; + } + return lhs; +} + +CInt64 CInt64_Shr(CInt64 lhs, CInt64 rhs) { + int counter; + long a; + unsigned long b; + + if (rhs.a == 0 && rhs.b < 64) { + a = lhs.a; + b = lhs.b; + for (counter = rhs.b; counter != 0; --counter) { + b >>= 1; + if (a & 1) + b |= 0x80000000; + a >>= 1; + } + lhs.a = a; + lhs.b = b; + } else { + if (lhs.a & 0x80000000) { + lhs.a = 0xFFFFFFFF; + lhs.b = 0xFFFFFFFF; + } else { + lhs.a = 0; + lhs.b = 0; + } + } + return lhs; +} + +CInt64 CInt64_ShrU(CInt64 lhs, CInt64 rhs) { + int counter; + unsigned long a; + unsigned long b; + + if (rhs.a == 0 && rhs.b < 64) { + a = lhs.a; + b = lhs.b; + for (counter = rhs.b; counter != 0; --counter) { + b >>= 1; + if (a & 1) + b |= 0x80000000; + a >>= 1; + } + lhs.a = a; + lhs.b = b; + } else { + lhs.a = 0; + lhs.b = 0; + } + return lhs; +} + +int CInt64_UnsignedCompare(const CInt64 *lhs, const CInt64 *rhs) { + if (lhs->a == rhs->a) { + if (lhs->b < rhs->b) + return -1; + else + return lhs->b > rhs->b; + } else { + return ((unsigned long) lhs->a < rhs->a) ? -1 : 1; + } +} + +int CInt64_SignedCompare(const CInt64 *lhs, const CInt64 *rhs) { + CInt64 lhs_; + CInt64 rhs_; + + lhs_ = CInt64_Xor(*lhs, cint64_min); + rhs_ = CInt64_Xor(*rhs, cint64_min); + return CInt64_UnsignedCompare(&lhs_, &rhs_); +} + +unsigned char CInt64_Less(CInt64 lhs, CInt64 rhs) { + return CInt64_SignedCompare(&lhs, &rhs) < 0; +} + +unsigned char CInt64_LessU(CInt64 lhs, CInt64 rhs) { + return CInt64_UnsignedCompare(&lhs, &rhs) < 0; +} + +unsigned char CInt64_Greater(CInt64 lhs, CInt64 rhs) { + return CInt64_SignedCompare(&lhs, &rhs) > 0; +} + +unsigned char CInt64_GreaterU(CInt64 lhs, CInt64 rhs) { + return CInt64_UnsignedCompare(&lhs, &rhs) > 0; +} + +unsigned char CInt64_LessEqual(CInt64 lhs, CInt64 rhs) { + return CInt64_SignedCompare(&lhs, &rhs) <= 0; +} + +unsigned char CInt64_LessEqualU(CInt64 lhs, CInt64 rhs) { + return CInt64_UnsignedCompare(&lhs, &rhs) <= 0; +} + +unsigned char CInt64_GreaterEqual(CInt64 lhs, CInt64 rhs) { + return CInt64_SignedCompare(&lhs, &rhs) >= 0; +} + +unsigned char CInt64_GreaterEqualU(CInt64 lhs, CInt64 rhs) { + return CInt64_UnsignedCompare(&lhs, &rhs) >= 0; +} + +unsigned char CInt64_Equal(CInt64 lhs, CInt64 rhs) { + return lhs.a == rhs.a && lhs.b == rhs.b; +} + +unsigned char CInt64_NotEqual(CInt64 lhs, CInt64 rhs) { + return lhs.a != rhs.a || lhs.b != rhs.b; +} + +unsigned char CInt64_IsInRange(CInt64 value, short len) { + CInt64 bound; + + if (value.a & 0x80000000) { + switch (len) { + case 1: + bound.b = 0xFFFFFF80; + bound.a = 0xFFFFFFFF; + break; + case 2: + bound.b = 0xFFFF8000; + bound.a = 0xFFFFFFFF; + break; + case 4: + bound.b = 0x80000000; + bound.a = 0xFFFFFFFF; + break; + case 8: + return 1; + default: + return 0; + } + return CInt64_GreaterEqual(value, bound); + } else { + switch (len) { + case 1: + bound.b = 0x7F; + bound.a = 0; + break; + case 2: + bound.b = 0x7FFF; + bound.a = 0; + break; + case 4: + bound.b = 0x7FFFFFFF; + bound.a = 0; + break; + case 8: + return 1; + default: + return 0; + } + return CInt64_LessEqual(value, bound); + } +} + +unsigned char CInt64_IsInURange(CInt64 value, short len) { + switch (len) { + case 1: + return value.a == 0 && (value.b & 0xFFFFFF00) == 0; + case 2: + return value.a == 0 && (value.b & 0xFFFF0000) == 0; + case 4: + return value.a == 0; + case 8: + return 1; + default: + return 0; + } +} + +CInt64 CInt64_And(CInt64 lhs, CInt64 rhs) { + lhs.a &= rhs.a; + lhs.b &= rhs.b; + return lhs; +} + +CInt64 CInt64_Xor(CInt64 lhs, CInt64 rhs) { + lhs.a ^= rhs.a; + lhs.b ^= rhs.b; + return lhs; +} + +CInt64 CInt64_Or(CInt64 lhs, CInt64 rhs) { + lhs.a |= rhs.a; + lhs.b |= rhs.b; + return lhs; +} + +void CInt64_ConvertInt32(CInt64 *i) { + CInt64_Extend32(i); +} + +void CInt64_ConvertUInt32(CInt64 *i) { + CInt64_SetULong(i, (unsigned long) i->b); +} + +void CInt64_ConvertInt16(CInt64 *i) { + i->b = (short) i->b; + CInt64_Extend32(i); +} + +void CInt64_ConvertUInt16(CInt64 *i) { + CInt64_SetULong(i, (unsigned short) i->b); +} + +void CInt64_ConvertInt8(CInt64 *i) { + i->b = (char) i->b; + CInt64_Extend32(i); +} + +void CInt64_ConvertUInt8(CInt64 *i) { + CInt64_SetULong(i, (unsigned char) i->b); +} + +void CInt64_ConvertUFromLongDouble(CInt64 *pResult, double value) { + union { float f; unsigned long l; } cvt; + unsigned long a, b; + float threshold; + int bits; + + if (value <= 0.0) { + pResult->a = 0; + pResult->b = 0; + return; + } + + cvt.l = 0x5F800000; + if (value >= cvt.f) { + pResult->a = 0xFFFFFFFF; + pResult->b = 0xFFFFFFFF; + return; + } + + a = b = 0; + for (bits = 63; bits >= 0; bits--) { + a <<= 1; + if (b & 0x80000000) + a |= 1; + b <<= 1; + + if ((short) bits == 0) { + threshold = 1.0f; + } else { + cvt.l = (((short) bits + 127) & 255) << 23; + threshold = cvt.f; + } + + if (threshold <= value) { + b |= 1; + value -= threshold; + } + } + + pResult->a = a; + pResult->b = b; +} + +void CInt64_ConvertFromLongDouble(CInt64 *pResult, double value) { + if (value < 0.0) { + CInt64_ConvertUFromLongDouble(pResult, -value); + *pResult = CInt64_Neg(*pResult); + } else { + CInt64_ConvertUFromLongDouble(pResult, value); + } +} + +double CInt64_ConvertUToLongDouble(const CInt64 *value) { + unsigned char bad; + unsigned long work; + int counter; + double result; + + bad = (value->a == 0) && (value->b == 0); + if (bad) { + return 0.0; + } else { + result = 0.0; + + work = value->a; + if (work != 0) { + for (counter = 0; counter < 32; counter++) { + result += result; + if (work & 0x80000000) + result += 1.0; + work <<= 1; + } + } + + counter = 0; + work = value->b; + for (; counter < 32; counter++) { + result += result; + if (work & 0x80000000) + result += 1.0; + work <<= 1; + } + + return result; + } +} + +double CInt64_ConvertToLongDouble(const CInt64 *value) { + CInt64 tmp; + if (value->a & 0x80000000) { + tmp = CInt64_Neg(*value); + return -CInt64_ConvertUToLongDouble(&tmp); + } else { + return CInt64_ConvertUToLongDouble(value); + } +} + +char *CInt64_ScanOctString(CInt64 *pResult, char *str, unsigned char *pFail) { + int ch; + CInt64 tmp; + unsigned long a; + unsigned long b; + + *pFail = 0; + pResult->a = pResult->b = 0; + + while ((ch = *str) >= '0' && *str <= '7') { + a = pResult->a; + b = pResult->b; + if (a & 0xE0000000) + *pFail = 1; + + SHIFT_LEFT_ONE(a, b); + SHIFT_LEFT_ONE(a, b); + SHIFT_LEFT_ONE(a, b); + + pResult->a = a; + pResult->b = b; + + CInt64_SetLong(&tmp, ch - '0'); + *pResult = CInt64_Add(*pResult, tmp); + ++str; + } + + return str; +} + +char *CInt64_ScanDecString(CInt64 *pResult, char *str, unsigned char *pFail) { + int ch; + CInt64 tmp; + unsigned long a; + unsigned long b; + + *pFail = 0; + pResult->a = pResult->b = 0; + + while ((ch = *str) >= '0' && *str <= '9') { + a = pResult->a; + b = pResult->b; + if (a & 0xE0000000) + *pFail = 1; + + SHIFT_LEFT_ONE(a, b); + tmp.a = a; + tmp.b = b; + SHIFT_LEFT_ONE(a, b); + SHIFT_LEFT_ONE(a, b); + pResult->a = a; + pResult->b = b; + + if (CInt64_IsNegative(pResult)) { + *pResult = CInt64_Add(*pResult, tmp); + if (!CInt64_IsNegative(pResult)) + *pFail = 1; + } else { + *pResult = CInt64_Add(*pResult, tmp); + } + + CInt64_SetLong(&tmp, ch - '0'); + if (CInt64_IsNegative(pResult)) { + *pResult = CInt64_Add(*pResult, tmp); + if (!CInt64_IsNegative(pResult)) + *pFail = 1; + } else { + *pResult = CInt64_Add(*pResult, tmp); + } + + ++str; + } + + return str; +} + +char *CInt64_ScanHexString(CInt64 *pResult, char *str, unsigned char *pFail) { + /* NOT MATCHING */ + int digit; + CInt64 tmp; + unsigned long a; + unsigned long b; + + *pFail = 0; + pResult->a = pResult->b = 0; + + for (;;) { + if ((digit = str[0]) >= '0' && digit <= '9') + digit = digit - '0'; + else if (digit >= 'A' && digit <= 'F') + digit = digit - 'A' + 10; + else if (digit >= 'a' && digit <= 'f') + digit = digit - 'a' + 10; + else + break; + + a = pResult->a; + b = pResult->b; + ++str; + + if (a & 0xF0000000) + *pFail = 1; + + SHIFT_LEFT_ONE(a, b); + SHIFT_LEFT_ONE(a, b); + SHIFT_LEFT_ONE(a, b); + SHIFT_LEFT_ONE(a, b); + + pResult->a = a; + pResult->b = b; + + CInt64_SetLong(&tmp, (char) digit); + *pResult = CInt64_Add(*pResult, tmp); + } + + return str; +} + +char *CInt64_ScanBinString(CInt64 *pResult, char *str, unsigned char *pFail) { + char digit; + unsigned long a; + unsigned long b; + + *pFail = 0; + pResult->a = pResult->b = 0; + + for (;;) { + if (*str == '0') + digit = 0; + else if (*str == '1') + digit = 1; + else + break; + + a = pResult->a; + b = pResult->b; + ++str; + + if (a & 0x80000000) + *pFail = 1; + + SHIFT_LEFT_ONE(a, b); + + pResult->a = a; + pResult->b = b; + + if (digit == 1) + *pResult = CInt64_Add(*pResult, cint64_one); + } + + return str; +} + +char *CInt64_ScanAsmNumber(CInt64 *pResult, char *str, unsigned char *pFail) { + unsigned char isMaybeBin; + unsigned char isOct; + unsigned char isMaybeDec; + unsigned char isBin; + char *p; + + isMaybeBin = 1; + isOct = *str == '0'; + isMaybeDec = 1; + isBin = 0; + p = str; + + for (;;) { + if (*p == 0) + break; + + if (strchr("01", p[0])) { + if (isBin) + isMaybeBin = 0; + } else if (strchr("bB", p[0])) { + isBin = 1; + isMaybeDec = 0; + isOct = 0; + } else if (strchr("234567", p[0])) { + isMaybeBin = 0; + } else if (strchr("89", p[0])) { + isOct = 0; + isMaybeBin = 0; + } else if (strchr("acdefACEDF", p[0])) { + isMaybeDec = 0; + isMaybeBin = 0; + } else { + break; + } + + ++p; + } + + if (isMaybeBin && isBin) { + return CInt64_ScanBinString(pResult, str, pFail) + 1; + } else if (p[0] == 'h' || p[0] == 'H') { + return CInt64_ScanHexString(pResult, str, pFail) + 1; + } else if (isOct) { + return CInt64_ScanOctString(pResult, str, pFail); + } else if (isMaybeDec) { + return CInt64_ScanDecString(pResult, str, pFail); + } else { + *pFail = 1; + return p; + } +} + +int CInt64_PrintDec(char *output, CInt64 value) { + int length; + CInt64 rem; + CInt64 divisor; + char buf[40]; + char *bufp; + + length = 0; + if (CInt64_IsNegative(&value)) { + value = CInt64_Neg(value); + *output = '-'; + length++; + output++; + } + + if (!CInt64_IsZero(&value)) { + divisor.b = 10; + divisor.a = 0; + + bufp = buf; + for (;;) { + rem = CInt64_ModU(value, divisor); + *(bufp++) = rem.b + '0'; + value = CInt64_DivU(value, divisor); + if (CInt64_IsZero(&value) != 0) + break; + } + + while (--bufp >= buf) { + *(output++) = *bufp; + length++; + } + } else { + *(output++) = '0'; + length++; + } + + *output = 0; + return length; +} + +int CInt64_PrintHex(char *output, CInt64 value) { + int length; + CInt64 rem; + CInt64 shift; + CInt64 mask; + char buf[32]; + char *bufp; + + length = 0; + if (!CInt64_IsZero(&value)) { + shift.b = 4; + shift.a = 0; + mask.b = 0xF; + mask.a = 0; + + bufp = buf; + for (;;) { + rem = CInt64_And(value, mask); + if ((long) rem.b >= 10) + *(bufp++) = rem.b + 'A'; + else + *(bufp++) = rem.b + '0'; + value = CInt64_ShrU(value, shift); + if (CInt64_IsZero(&value) != 0) + break; + } + + while (--bufp >= buf) { + *(output++) = *bufp; + length++; + } + } else { + *(output++) = '0'; + length++; + } + + *output = 0; + return length; +} + +int CInt64_PrintBin(char *output, CInt64 value) { + int length; + CInt64 rem; + char buf[64]; + char *bufp; + + length = 0; + if (!CInt64_IsZero(&value)) { + bufp = buf; + for (;;) { + rem = CInt64_And(value, cint64_one); + if (CInt64_Equal(rem, cint64_one)) + *(bufp++) = '1'; + else + *(bufp++) = '0'; + value = CInt64_ShrU(value, cint64_one); + if (CInt64_IsZero(&value) != 0) + break; + } + + while (--bufp >= buf) { + *(output++) = *bufp; + length++; + } + } else { + *(output++) = '0'; + length++; + } + + *output = 0; + return length; +} |