#include #include #include typedef struct { unsigned char * bytes; unsigned length; } longNumber; void convert(const char *, unsigned char, unsigned char); void convertBases(const char *, const char *, const char *); char * convertedNumber(const char *, const char *, const char *); char * baseString(unsigned char); char * toUppercase(const char *); unsigned char valueOf(char, const char *); unsigned char checkBase(const char *); longNumber convertFrom(const char *, const char *, unsigned char); char * convertTo(longNumber, const char *, unsigned char); void destroyNumber(longNumber); longNumber createNumber(unsigned long long); longNumber copyNumber(longNumber); unsigned char isZero(longNumber); longNumber add(longNumber, longNumber); longNumber addMultiple(longNumber *, unsigned); longNumber multiplyDigit(longNumber, unsigned char); longNumber divideDigit(longNumber, unsigned char, unsigned char *); void convert (const char * number, unsigned char baseFrom, unsigned char baseTo) { if (!number) return; if ((baseFrom < 2) || (baseFrom > 36) || (baseTo < 2) || (baseTo > 36)) return; if (baseFrom == baseTo) { printf("%s\n", number); return; } unsigned char negative = 0; for (; !isalnum(*number); number ++) switch (*number) { case '-': negative = !negative; break; case '+': case ' ': break; default: return; // error character } if (!(*number)) return; char * from = baseString(baseFrom); char * to = baseString(baseTo); char * uppercaseNumber = toUppercase(number); char * conversionResult = convertedNumber(uppercaseNumber, from, to); if (conversionResult) { if (negative) putchar('-'); printf("%s\n", conversionResult); free(conversionResult); } free(uppercaseNumber); free(from); free(to); } void convertBases (const char * number, const char * baseFrom, const char * baseTo) { if (!number) return; char * conversionResult = convertedNumber(number, baseFrom, baseTo); if (conversionResult) { printf("%s\n", conversionResult); free(conversionResult); } } char * convertedNumber (const char * number, const char * baseFrom, const char * baseTo) { unsigned char from, to; from = checkBase(baseFrom); if (!from) return NULL; to = checkBase(baseTo); if (!to) return NULL; longNumber converted = convertFrom(number, baseFrom, from); if (!converted.length) return NULL; char * result = convertTo(converted, baseTo, to); destroyNumber(converted); return result; } char * baseString (unsigned char base) { if (base < 2) return NULL; if (base > 36) return NULL; char * result = malloc(base + 1); result[base] = 0; unsigned char pos; for (pos = 0; (pos < base) && (pos < 10); pos ++) result[pos] = 48 + pos; // ASCII for the digit if (base <= 10) return result; for (; pos < base; pos ++) result[pos] = 55 + pos; // ASCII for the letter return result; } char * toUppercase (const char * string) { // I think there's a strtoupper() somewhere, but that's for pussies char * result = malloc(strlen(string) + 1); unsigned pos; for (pos = 0; string[pos]; pos ++) if ((string[pos] >= 97) && (string[pos] <= 122)) result[pos] = string[pos] - 32; else result[pos] = string[pos]; result[pos] = 0; return result; } unsigned char valueOf (char digit, const char * base) { unsigned char pos; for (pos = 0; base[pos]; pos ++) if (digit == base[pos]) return pos; return (unsigned char) -1; } unsigned char checkBase (const char * base) { char checked[256]; // yeah, I'm assuming chars are really 8 bits, kill me unsigned pos; for (pos = 0; pos < 256; pos ++) checked[pos] = 0; for (pos = 0; base[pos]; pos ++) if (checked[base[pos]]) return 0; else checked[base[pos]] = 1; if (pos == 1) return 0; // base 1 is not valid! return pos; // return the actual size of the base, because why not } longNumber convertFrom (const char * number, const char * base, unsigned char baseSize) { if (!number) return (longNumber) {NULL, 0}; if (!(*number)) return (longNumber) {NULL, 0}; longNumber total = createNumber(0); longNumber positionValue = createNumber(1); longNumber temp, temp2; const char * current = number + (strlen(number) - 1); unsigned char digitValue; for (; current >= number; current --) { digitValue = valueOf(*current, base); if (digitValue == (unsigned char) -1) { destroyNumber(total); destroyNumber(positionValue); return (longNumber) {NULL, 0}; } temp = multiplyDigit(positionValue, digitValue); temp2 = add(total, temp); destroyNumber(total); destroyNumber(temp); total = temp2; temp = multiplyDigit(positionValue, baseSize); destroyNumber(positionValue); positionValue = temp; } destroyNumber(positionValue); return total; } char * convertTo (longNumber number, const char * base, unsigned char baseSize) { if (isZero(number)) { char * result = malloc(2); *result = *base; result[1] = 0; return result; } unsigned char nextDigit; char * result = NULL; unsigned resultLength = 0; longNumber temp; number = copyNumber(number); while (!isZero(number)) { temp = divideDigit(number, baseSize, &nextDigit); destroyNumber(number); number = temp; result = realloc(result, resultLength + 1); result[resultLength ++] = base[nextDigit]; } destroyNumber(number); char * reversed = result; result = malloc(resultLength + 1); unsigned pos; for (pos = 0; pos < resultLength; pos ++) result[pos] = reversed[resultLength - pos - 1]; free(reversed); result[resultLength] = 0; return result; } // this reminds me of a class definition, but oh well void destroyNumber (longNumber number) { if (number.length) free(number.bytes); } longNumber createNumber (unsigned long long number) { if (!number) { longNumber result; result.length = 1; result.bytes = malloc(1); *(result.bytes) = 0; return result; } unsigned char * newNumber = malloc(sizeof(unsigned long long)); unsigned char length; for (length = 0; number; length ++, number >>= 8) newNumber[length] = number & 255; newNumber = realloc(newNumber, length); return (longNumber) {newNumber, length}; } longNumber copyNumber (longNumber number) { unsigned char * newNumber = malloc(number.length); memcpy(newNumber, number.bytes, number.length); return (longNumber) {newNumber, number.length}; } unsigned char isZero (longNumber number) { unsigned pos; for (pos = number.length - 1; pos < number.length; pos --) if (number.bytes[pos]) return 0; return 1; } longNumber add (longNumber number1, longNumber number2) { longNumber numbers[2] = {number1, number2}; return addMultiple(numbers, 2); } longNumber addMultiple (longNumber * numbers, unsigned amount) { unsigned long long total; unsigned pos; unsigned current; unsigned resultLength; unsigned char * result; if (!amount) return createNumber(0); if (amount == 1) return copyNumber(*numbers); resultLength = (*numbers).length; for (current = 1; current < amount; current ++) if ((numbers[current]).length > resultLength) resultLength = (numbers[current]).length; resultLength += sizeof(unsigned); total = 0; result = malloc(resultLength); for (pos = 0; pos < resultLength; pos ++) { for (current = 0; current < amount; current ++) total += (pos < (numbers[current]).length) ? ((numbers[current]).bytes[pos]) : 0; result[pos] = total & 255; total >>= 8; // keeps the carry } for (; (resultLength > 1) && (!(result[resultLength - 1])); resultLength --); result = realloc(result, resultLength); return (longNumber) {result, resultLength}; } longNumber multiplyDigit (longNumber number, unsigned char digit) { if (!digit) return createNumber(0); if (digit == 1) return copyNumber(number); unsigned resultLength = number.length + 1; unsigned char * result = malloc(resultLength); unsigned short total = 0; unsigned pos; for (pos = 0; pos < number.length; pos ++) { total += number.bytes[pos] * digit; result[pos] = total & 255; total >>= 8; } result[number.length] = total; for (; (resultLength > 1) && (!(result[resultLength - 1])); resultLength --); result = realloc(result, resultLength); return (longNumber) {result, resultLength}; } longNumber divideDigit (longNumber number, unsigned char divisor, unsigned char * remainder) { if (!divisor) return (longNumber) {NULL, 0}; // BLACKHOLE!!! if (divisor == 1) { if (remainder) *remainder = 0; return copyNumber(number); } unsigned resultLength = number.length; unsigned char * result = malloc(resultLength); unsigned pos; unsigned short total = 0; for (pos = resultLength - 1; pos < resultLength /* -1 = 4294967295 or so */; pos --) { total <<= 8; total += number.bytes[pos]; result[pos] = total / divisor; total %= divisor; } if (remainder) *remainder = total; for (; (resultLength > 1) && (!(result[resultLength - 1])); resultLength --); result = realloc(result, resultLength); return (longNumber) {result, resultLength}; }