X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Ftv%2Fstrcalc.c;h=ec802385e157d479d2b707e8277f3b73a9cb3fdc;hb=0d405c994b4dea9ecb15f2b866dba45bea4ffb81;hp=c9d1b8aae0fb5c11a582ffd63d35490e3159efdd;hpb=003979e6f8a15a2e380407134af0092268ce2bbc;p=libfirm diff --git a/ir/tv/strcalc.c b/ir/tv/strcalc.c index c9d1b8aae..ec802385e 100644 --- a/ir/tv/strcalc.c +++ b/ir/tv/strcalc.c @@ -1,30 +1,56 @@ -/****i* strcalc/implementation - * - * AUTHORS - * Matthias Heil - * - * NOTES - ******/ +/* + * Project: libFIRM + * File name: ir/tv/strcalc.c + * Purpose: + * Author: Mathias Heil + * Modified by: + * Created: + * CVS-ID: $Id$ + * Copyright: (c) 2003 Universität Karlsruhe + * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. + */ -#include "strcalc.h" -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +# include +#endif +#ifdef HAVE_ALLOCA_H +# include +#endif +#ifdef HAVE_MALLOC_H +# include +#endif +#ifdef HAVE_STRING_H +# include /* memset/memcmp */ +#endif #include /* assertions */ -#include /* memset/memcmp */ #include /* output for error messages */ #include /* definition of LONG_MIN, used in sc_get_val_from_long */ +#include "strcalc.h" +#include "xmalloc.h" + /* * local definitions and macros */ -#define CLEAR_CALC_BUFFER() assert(calc_buffer); memset(calc_buffer, SC_0, CALC_BUFFER_SIZE) +#define CLEAR_BUFFER(b) assert(b); memset(b, SC_0, calc_buffer_size) #define _val(a) ((a)-SC_0) #define _digit(a) ((a)+SC_0) #define _bitisset(digit, pos) (and_table[_val(digit)][_val(shift_table[pos])] != SC_0) #define fail_char(a, b, c, d) _fail_char((a), (b), (c), (d), __FILE__, __LINE__) -#ifdef STRCALC_DEBUG_COMPUTATION +/* shortcut output for debugging */ +# define sc_print_hex(a) sc_print((a), 0, SC_HEX, 0) +# define sc_print_dec(a) sc_print((a), 0, SC_DEC, 1) +# define sc_print_oct(a) sc_print((a), 0, SC_OCT, 0) +# define sc_print_bin(a) sc_print((a), 0, SC_BIN, 0) + +#ifdef STRCALC_DEBUG_PRINTCOMP # define DEBUGPRINTF_COMPUTATION(x) printf x #else # define DEBUGPRINTF_COMPUTATION(x) ((void)0) @@ -39,17 +65,19 @@ /* * private variables */ - static char *calc_buffer = NULL; /* buffer holding all results */ static char *output_buffer = NULL; /* buffer for output */ -static int BIT_PATTERN_SIZE; /* maximum number of bits */ -static int CALC_BUFFER_SIZE; /* size of internally stored values */ -static int MAX_VALUE_SIZE; /* maximum size of values */ +static int bit_pattern_size; /* maximum number of bits */ +static int calc_buffer_size; /* size of internally stored values */ +static int max_value_size; /* maximum size of values */ -static int carry_flag; /* some computation set carry_flag: */ - /* rightshift if bits were lost due to shifting */ - /* division if there was a remainder */ +static int carry_flag; /**< some computation set the carry_flag: + - right shift if bits were lost due to shifting + - division if there was a remainder + However, the meaning of carry is machine dependent + and often defined in other ways! */ +static const char sex_digit[4] = { SC_E, SC_C, SC_8, SC_0 }; static const char max_digit[4] = { SC_0, SC_1, SC_3, SC_7 }; static const char min_digit[4] = { SC_F, SC_E, SC_C, SC_8 }; @@ -389,7 +417,7 @@ static char const shrs_table[16][4][2] = { { {SC_F, SC_0}, {SC_7, SC_8}, {SC_3, SC_C}, {SC_1, SC_E} } }; -/* for converting to binary string */ +/** converting a digit to a binary string */ static const char *binary_table[16] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" @@ -408,44 +436,62 @@ static void _fail_char(const char *str, size_t len, const char fchar, int pos, exit(-1); } +/** + * implements the bitwise NOT operation + */ static void _bitnot(const char *val, char *buffer) { int counter; - for (counter = 0; counter= 0; counter--) + for (counter = calc_buffer_size - 2; counter >= 0; counter--) { buffer[counter+1] = buffer[counter]; } buffer[0] = digit; } -/* XXX: This is MOST slow */ -static void _divmod(const char *dividend, const char *divisor, char *quot, char *rem) +/** + * Implements truncating integer division and remainder. + * + * Note: This is MOST slow + */ +static void _divmod(const char *rDividend, const char *divisor, char *quot, char *rem) { + const char *dividend = rDividend; const char *minus_divisor; - char neg_val1[CALC_BUFFER_SIZE]; - char neg_val2[CALC_BUFFER_SIZE]; + char *neg_val1; + char *neg_val2; - char sign = 0; /* remember result sign */ + char div_sign = 0; /* remember division result sign */ + char rem_sign = 0; /* remember remainder esult sign */ int c_dividend; /* loop counters */ + neg_val1 = alloca(calc_buffer_size); + neg_val2 = alloca(calc_buffer_size); + /* clear result buffer */ - memset(quot, SC_0, CALC_BUFFER_SIZE); - memset(rem, SC_0, CALC_BUFFER_SIZE); + memset(quot, SC_0, calc_buffer_size); + memset(rem, SC_0, calc_buffer_size); /* if the divisor is zero this won't work (quot is zero) */ if (sc_comp(divisor, quot) == 0) assert(0 && "division by zero!"); @@ -614,24 +695,21 @@ static void _divmod(const char *dividend, const char *divisor, char *quot, char if (sc_comp(dividend, quot) == 0) return; - if (_sign(dividend) == -1) - { + if (_sign(dividend) == -1) { _negate(dividend, neg_val1); - sign ^= 1; + div_sign ^= 1; + rem_sign ^= 1; dividend = neg_val1; } _negate(divisor, neg_val2); - if (_sign(divisor) == -1) - { - sign ^= 1; + if (_sign(divisor) == -1) { + div_sign ^= 1; minus_divisor = divisor; divisor = neg_val2; } else - { minus_divisor = neg_val2; - } /* if divisor >= dividend division is easy * (remember these are absolute values) */ @@ -642,14 +720,14 @@ static void _divmod(const char *dividend, const char *divisor, char *quot, char return; case -1: /* dividend < divisor */ - memcpy(rem, dividend, CALC_BUFFER_SIZE); + memcpy(rem, rDividend, calc_buffer_size); return; default: /* unluckily division is necessary :( */ break; } - for (c_dividend = CALC_BUFFER_SIZE - 1; c_dividend >= 0; c_dividend--) + for (c_dividend = calc_buffer_size - 1; c_dividend >= 0; c_dividend--) { _push(dividend[c_dividend], rem); _push(SC_0, quot); @@ -671,15 +749,22 @@ static void _divmod(const char *dividend, const char *divisor, char *quot, char } } + /* sets carry if remainder is non-zero ??? */ carry_flag = !sc_is_zero(rem); - if (sign) - { + if (div_sign) _negate(quot, quot); + + if (rem_sign) _negate(rem, rem); - } } +/** + * Implements a Shift Left, which can either preserve the sign bit + * or not. + * + * @todo Assertions seems to be wrong + */ static void _shl(const char *val1, char *buffer, long offset, int radius, unsigned is_signed) { const char *shl; @@ -697,7 +782,7 @@ static void _shl(const char *val1, char *buffer, long offset, int radius, unsign /* if shifting far enough the result is zero */ if (offset >= radius) { - memset(buffer, SC_0, CALC_BUFFER_SIZE); + memset(buffer, SC_0, calc_buffer_size); return; } @@ -731,22 +816,28 @@ static void _shl(const char *val1, char *buffer, long offset, int radius, unsign { /* this sets the upper bits of the leftmost digit */ buffer[offset] = or_table[_val(buffer[offset])][_val(min_digit[bitoffset])]; - for (counter = offset+1; counter < CALC_BUFFER_SIZE; counter++) + for (counter = offset+1; counter < calc_buffer_size; counter++) { buffer[counter] = SC_F; } } else if (is_signed && !_bitisset(buffer[offset], bitoffset)) { - /* this unsets the upper bits of the leftmost digit */ + /* this clears the upper bits of the leftmost digit */ buffer[offset] = and_table[_val(buffer[offset])][_val(max_digit[bitoffset])]; - for (counter = offset+1; counter < CALC_BUFFER_SIZE; counter++) + for (counter = offset+1; counter < calc_buffer_size; counter++) { buffer[counter] = SC_0; } } } +/** + * Implements a Shift Right, which can either preserve the sign bit + * or not. + * + * @todo Assertions seems to be wrong + */ static void _shr(const char *val1, char *buffer, long offset, int radius, unsigned is_signed, int signed_shift) { const char *shrs; @@ -759,7 +850,6 @@ static void _shr(const char *val1, char *buffer, long offset, int radius, unsign int bitoffset = 0; assert((offset >= 0) || (0 && "negative rightshift")); - assert(((_sign(val1) != -1) || is_signed) || (0 && "unsigned mode and negative value")); assert(((!_bitisset(val1[(radius-1)/4], (radius-1)%4)) || !is_signed || (_sign(val1) == -1)) || (0 && "value is positive, should be negative")); assert(((_bitisset(val1[(radius-1)/4], (radius-1)%4)) || !is_signed || (_sign(val1) == 1)) || (0 && "value is negative, should be positive")); @@ -768,25 +858,29 @@ static void _shr(const char *val1, char *buffer, long offset, int radius, unsign /* if shifting far enough the result is either 0 or -1 */ if (offset >= radius) { - memset(buffer, sign, CALC_BUFFER_SIZE); + if (!sc_is_zero(val1)) { + carry_flag = 1; + } + memset(buffer, sign, calc_buffer_size); return; } shift = offset % 4; offset = offset / 4; - /* check if any bits are lost, and set carry_flag is so */ + /* check if any bits are lost, and set carry_flag if so */ for (counter = 0; counter < offset; counter++) { - if (val1[counter] != carry_flag) + if (val1[counter] != 0) { carry_flag = 1; break; } } - if ((carry_flag == 0) && (_val(val1[counter]) & shift != 0)) + if ((_val(val1[counter]) & ((1< 0) { @@ -802,7 +896,7 @@ static void _shr(const char *val1, char *buffer, long offset, int radius, unsign /* the last digit is special in regard of signed/unsigned shift */ bitoffset = radius%4; - msd = (radius/4 0) buffer[counter - 1] = or_table[_val(buffer[counter-1])][_val(shrs[1])]; /* fill with SC_F or SC_0 depending on sign */ - for (counter++; counter < CALC_BUFFER_SIZE; counter++) + for (counter++; counter < calc_buffer_size; counter++) { buffer[counter] = sign; } } -/* positive: low-order -> high order, negative other direction */ +/** + * Implements a Rotate Right. + * positive: low-order -> high order, negative other direction + */ static void _rot(const char *val1, char *buffer, long offset, int radius, unsigned is_signed) { - char temp1[CALC_BUFFER_SIZE]; - char temp2[CALC_BUFFER_SIZE]; - - const char *shl; - char carry = SC_0; - - int counter, old_counter; - int shift; - int bitoffset; + char *temp1, *temp2; + temp1 = alloca(calc_buffer_size); + temp2 = alloca(calc_buffer_size); offset = offset % radius; - /* rotation by multiples of the typelength is identity */ + /* rotation by multiples of the type length is identity */ if (offset == 0) { - memmove(buffer, val1, CALC_BUFFER_SIZE); + memmove(buffer, val1, calc_buffer_size); return; } @@ -862,29 +953,54 @@ const void *sc_get_buffer(void) return (void*)calc_buffer; } -const int sc_get_buffer_length(void) +int sc_get_buffer_length(void) { - return CALC_BUFFER_SIZE; + return calc_buffer_size; } -/* XXX doesn't check for overflows */ -void sc_val_from_str(const char *str, unsigned int len) +/** + * Do sign extension if the mode is signed, expects all upper bits + * cleared. + */ +void sign_extend(char *calc_buffer, ir_mode *mode) { + if (mode_is_signed(mode)) { + int bits = get_mode_size_bits(mode) - 1; + int ofs = bits >> 2; + int max = max_digit[bits & 3]; + int i; + + if (calc_buffer[ofs] > max) { + /* sign bit is set, we need sign expansion */ + + for (i = ofs + 1; i < calc_buffer_size; ++i) + calc_buffer[i] = SC_F; + calc_buffer[ofs] = or_table[(int) calc_buffer[ofs]][(int) sex_digit[bits & 3]]; + } + } +} + +/* FIXME doesn't check for overflows */ +void sc_val_from_str(const char *str, unsigned int len, void *buffer, ir_mode *mode) { const char *orig_str = str; unsigned int orig_len = len; char sign = 0; - char base[CALC_BUFFER_SIZE]; - char val[CALC_BUFFER_SIZE]; + char *base, *val; + + base = alloca(calc_buffer_size); + val = alloca(calc_buffer_size); /* verify valid pointers (not null) */ assert(str); /* a string no characters long is an error */ assert(len); - CLEAR_CALC_BUFFER(); - memset(base, SC_0, CALC_BUFFER_SIZE); - memset(val, SC_0, CALC_BUFFER_SIZE); + if (buffer == NULL) buffer = calc_buffer; + + CLEAR_BUFFER(buffer); + CLEAR_BUFFER(base); + CLEAR_BUFFER(val); /* strip leading spaces */ while ((len > 0) && (*str == ' ')) { len--; str++; } @@ -1007,21 +1123,24 @@ void sc_val_from_str(const char *str, unsigned int len) } /* while (len > 0 ) */ if (sign) - { _negate(calc_buffer, calc_buffer); - } + + /* beware: even if hex numbers have no sign, we need sign extension here */ + sign_extend(calc_buffer, mode); } -void sc_val_from_long(long value) +void sc_val_from_long(long value, void *buffer) { char *pos; char sign, is_minlong; - pos = calc_buffer; + if (buffer == NULL) buffer = calc_buffer; + pos = buffer; + sign = (value < 0); is_minlong = value == LONG_MIN; - /* use absolute value, special treatment of MIN_LONG */ + /* use absolute value, special treatment of MIN_LONG to avoid overflow */ if (sign) { if (is_minlong) value = -(value+1); @@ -1029,18 +1148,33 @@ void sc_val_from_long(long value) value = -value; } - CLEAR_CALC_BUFFER(); + CLEAR_BUFFER(buffer); - while ((value != 0) && (pos < calc_buffer + CALC_BUFFER_SIZE)) + while ((value != 0) && (pos < (char*)buffer + calc_buffer_size)) { - *pos++ = _digit(value % 16); - value /= 16; + *pos++ = _digit(value & 0xf); + value >>= 4; } - if (sign) { - if (is_minlong) _inc(calc_buffer, calc_buffer); - _negate(calc_buffer, calc_buffer); + if (is_minlong) + _inc(buffer, buffer); + + _negate(buffer, buffer); + } +} + +void sc_val_from_ulong(unsigned long value, void *buffer) +{ + unsigned char *pos; + + if (buffer == NULL) buffer = calc_buffer; + pos = buffer; + + while (pos < (unsigned char *)buffer + calc_buffer_size) + { + *pos++ = (unsigned char)_digit(value & 0xf); + value >>= 4; } } @@ -1049,22 +1183,24 @@ long sc_val_to_long(const void *val) int i; long l = 0; - for (i = CALC_BUFFER_SIZE - 1; i >= 0; i--) + for (i = calc_buffer_size - 1; i >= 0; i--) { l = (l << 4) + _val(((char *)val)[i]); } return l; } -void sc_min_from_bits(unsigned int num_bits, unsigned int sign) +void sc_min_from_bits(unsigned int num_bits, unsigned int sign, void *buffer) { char* pos; int i, bits; - CLEAR_CALC_BUFFER(); + if (buffer == NULL) buffer = calc_buffer; + CLEAR_BUFFER(buffer); + if (!sign) return; /* unsigned means minimum is 0(zero) */ - pos = calc_buffer; + pos = buffer; bits = num_bits - 1; for (i = 0; i < bits/4; i++) @@ -1072,17 +1208,18 @@ void sc_min_from_bits(unsigned int num_bits, unsigned int sign) *pos++ = min_digit[bits%4]; - for (i++; i <= CALC_BUFFER_SIZE - 1; i++) + for (i++; i <= calc_buffer_size - 1; i++) *pos++ = SC_F; } -void sc_max_from_bits(unsigned int num_bits, unsigned int sign) +void sc_max_from_bits(unsigned int num_bits, unsigned int sign, void *buffer) { char* pos; int i, bits; - CLEAR_CALC_BUFFER(); - pos = calc_buffer; + if (buffer == NULL) buffer = calc_buffer; + CLEAR_BUFFER(buffer); + pos = buffer; bits = num_bits - sign; for (i = 0; i < bits/4; i++) @@ -1090,17 +1227,20 @@ void sc_max_from_bits(unsigned int num_bits, unsigned int sign) *pos++ = max_digit[bits%4]; - for (i++; i <= CALC_BUFFER_SIZE - 1; i++) + for (i++; i <= calc_buffer_size - 1; i++) *pos++ = SC_0; } -void sc_calc(const void* value1, const void* value2, unsigned op) +void sc_calc(const void* value1, const void* value2, unsigned op, void *buffer) { - char unused_res[CALC_BUFFER_SIZE]; /* temp buffer holding unused result of divmod */ + char *unused_res; /* temp buffer holding unused result of divmod */ const char *val1 = (const char *)value1; const char *val2 = (const char *)value2; - CLEAR_CALC_BUFFER(); + + unused_res = alloca(calc_buffer_size); + + CLEAR_BUFFER(calc_buffer); carry_flag = 0; DEBUGPRINTF_COMPUTATION(("%s ", sc_print_hex(value1))); @@ -1110,7 +1250,7 @@ void sc_calc(const void* value1, const void* value2, unsigned op) case SC_NEG: _negate(val1, calc_buffer); DEBUGPRINTF_COMPUTATION(("negated: %s\n", sc_print_hex(calc_buffer))); - return; + break; case SC_OR: DEBUGPRINTF_COMPUTATION(("| ")); _bitor(val1, val2, calc_buffer); @@ -1126,7 +1266,7 @@ void sc_calc(const void* value1, const void* value2, unsigned op) case SC_NOT: _bitnot(val1, calc_buffer); DEBUGPRINTF_COMPUTATION(("bit-negated: %s\n", sc_print_hex(calc_buffer))); - return; + break; case SC_ADD: DEBUGPRINTF_COMPUTATION(("+ ")); _add(val1, val2, calc_buffer); @@ -1152,9 +1292,14 @@ void sc_calc(const void* value1, const void* value2, unsigned op) } DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2))); DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer))); + + if ((buffer != NULL) && (buffer != calc_buffer)) + { + memcpy(buffer, calc_buffer, calc_buffer_size); + } } -void sc_bitcalc(const void* value1, const void* value2, int radius, int sign, unsigned op) +void sc_bitcalc(const void* value1, const void* value2, int radius, int sign, unsigned op, void* buffer) { const char *val1 = (const char *)value1; const char *val2 = (const char *)value2; @@ -1167,30 +1312,35 @@ void sc_bitcalc(const void* value1, const void* value2, int radius, int sign, un switch (op) { case SC_SHL: - DEBUGPRINTF_COMPUTATION(("<< %d ", offset)); + DEBUGPRINTF_COMPUTATION(("<< %ld ", offset)); _shl(val1, calc_buffer, offset, radius, sign); break; case SC_SHR: - DEBUGPRINTF_COMPUTATION((">> %d ", offset)); + DEBUGPRINTF_COMPUTATION((">> %ld ", offset)); _shr(val1, calc_buffer, offset, radius, sign, 0); break; case SC_SHRS: - DEBUGPRINTF_COMPUTATION((">>> %d ", offset)); + DEBUGPRINTF_COMPUTATION((">>> %ld ", offset)); _shr(val1, calc_buffer, offset, radius, sign, 1); break; case SC_ROT: - DEBUGPRINTF_COMPUTATION(("<<>> %d ", offset)); + DEBUGPRINTF_COMPUTATION(("<<>> %ld ", offset)); _rot(val1, calc_buffer, offset, radius, sign); break; default: assert(0); } DEBUGPRINTF_COMPUTATION(("-> %s\n", sc_print_hex(calc_buffer))); + + if ((buffer != NULL) && (buffer != calc_buffer)) + { + memmove(buffer, calc_buffer, calc_buffer_size); + } } int sc_comp(const void* value1, const void* value2) { - int counter = CALC_BUFFER_SIZE - 1; + int counter = calc_buffer_size - 1; const char *val1 = (const char *)value1; const char *val2 = (const char *)value2; @@ -1216,11 +1366,10 @@ int sc_get_highest_set_bit(const void *value) { const char *val = (const char*)value; int high, counter; - char sign; - high = CALC_BUFFER_SIZE * 4; + high = calc_buffer_size * 4 - 1; - for (counter = CALC_BUFFER_SIZE-1; counter >= 0; counter--) { + for (counter = calc_buffer_size-1; counter >= 0; counter--) { if (val[counter] == SC_0) high -= 4; else { if (val[counter] > SC_7) return high; @@ -1241,7 +1390,7 @@ int sc_get_lowest_set_bit(const void *value) sign = (_sign(val)==1)?(SC_0):(SC_F); low = 0; - for (counter = 0; counter < CALC_BUFFER_SIZE; counter++) { + for (counter = 0; counter < calc_buffer_size; counter++) { if (val[counter] == SC_0) low += 4; else { if (val[counter] < SC_2) return low; @@ -1250,7 +1399,7 @@ int sc_get_lowest_set_bit(const void *value) else return low + 3; } } - return low; + return -1; } int sc_is_zero(const void *value) @@ -1258,7 +1407,7 @@ int sc_is_zero(const void *value) const char* val = (const char *)value; int counter; - for (counter = 0; counter < CALC_BUFFER_SIZE; counter++) { + for (counter = 0; counter < calc_buffer_size; counter++) { if (val[counter] != SC_0) return 0; } return 1; @@ -1276,8 +1425,8 @@ int sc_had_carry(void) unsigned char sc_sub_bits(const void *value, int len, unsigned byte_ofs) { - const char *val = (const char *)value; - unsigned nibble_ofs = 2 * byte_ofs; + const char *val = (const char *)value; + int nibble_ofs = 2 * byte_ofs; unsigned char res; /* the current scheme uses one byte to store a nibble */ @@ -1293,16 +1442,14 @@ unsigned char sc_sub_bits(const void *value, int len, unsigned byte_ofs) /* * convert to a string + * FIXME: Doesn't check buffer bounds */ -const char *sc_print(const void *value, unsigned bits, enum base_t base) +const char *sc_print(const void *value, unsigned bits, enum base_t base, int signed_mode) { static const char big_digits[] = "0123456789ABCDEF"; static const char small_digits[] = "0123456789abcdef"; - char base_val[CALC_BUFFER_SIZE]; - char div1_res[CALC_BUFFER_SIZE]; - char div2_res[CALC_BUFFER_SIZE]; - char rem_res[CALC_BUFFER_SIZE]; + char *base_val, *div1_res, *div2_res, *rem_res; int counter, nibbles, i, sign; char x; @@ -1312,12 +1459,17 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base) char *pos; const char *digits = small_digits; - pos = output_buffer + BIT_PATTERN_SIZE; - *pos = '\0'; + base_val = alloca(calc_buffer_size); + div1_res = alloca(calc_buffer_size); + div2_res = alloca(calc_buffer_size); + rem_res = alloca(calc_buffer_size); + + pos = output_buffer + bit_pattern_size; + *(--pos) = '\0'; /* special case */ if (bits == 0) { - bits = BIT_PATTERN_SIZE; + bits = bit_pattern_size; #ifdef STRCALC_DEBUG_FULLPRINT bits <<= 1; #endif @@ -1382,22 +1534,22 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base) case SC_DEC: case SC_OCT: - memset(base_val, SC_0, CALC_BUFFER_SIZE); + memset(base_val, SC_0, calc_buffer_size); base_val[0] = base == SC_DEC ? SC_A : SC_8; p = val; sign = 0; - if (base == SC_DEC) { + if (signed_mode && base == SC_DEC) { /* check for negative values */ if (_bit(val, bits - 1)) { - _negate(val, div2_res); - sign = 1; - p = div2_res; + _negate(val, div2_res); + sign = 1; + p = div2_res; } } - /* transfer data into oscilating buffers */ - memset(div1_res, SC_0, CALC_BUFFER_SIZE); + /* transfer data into oscillating buffers */ + memset(div1_res, SC_0, calc_buffer_size); for (counter = 0; counter < nibbles; ++counter) div1_res[counter] = p[counter]; @@ -1418,7 +1570,7 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base) *(--pos) = digits[_val(rem_res[0])]; x = 0; - for (i = 0; i < sizeof(div1_res); ++i) + for (i = 0; i < calc_buffer_size; ++i) x |= _val(m[i]); if (x == 0) @@ -1429,34 +1581,39 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base) break; default: + printf("%i\n", base); assert(0); return NULL; } return pos; } -void init_strcalc(int precision_in_bytes) +void init_strcalc(int precision) { if (calc_buffer == NULL) { - if (precision_in_bytes <= 0) precision_in_bytes = DEFAULT_PRECISION_IN_BYTES; + if (precision <= 0) precision = SC_DEFAULT_PRECISION; - BIT_PATTERN_SIZE = (8 * precision_in_bytes); - CALC_BUFFER_SIZE = (4 * precision_in_bytes); - MAX_VALUE_SIZE = (2 * precision_in_bytes); + /* round up to multiple of 4 */ + precision = (precision + 3) & ~3; - calc_buffer = malloc(CALC_BUFFER_SIZE * sizeof(char)); - output_buffer = malloc(BIT_PATTERN_SIZE * sizeof(char)); + bit_pattern_size = (precision); + calc_buffer_size = (precision / 2); + max_value_size = (precision / 4); - if (calc_buffer == NULL || output_buffer == NULL) - { - assert(0 && "malloc failed"); - exit(-1); - } + calc_buffer = xmalloc(calc_buffer_size+1 * sizeof(char)); + output_buffer = xmalloc(bit_pattern_size+1 * sizeof(char)); - DEBUGPRINTF(("init strcalc: \n\tPRECISION: %d\n\tCALC_BUFFER_SIZE = %d\n\tMAX_VALUE_SIZE = %d\n\tbuffer pointer: %p\n", precision_in_bytes, CALC_BUFFER_SIZE, MAX_VALUE_SIZE, calc_buffer)); + DEBUGPRINTF(("init strcalc: \n\tPRECISION: %d\n\tCALC_BUFFER_SIZE = %d\n\tMAX_VALUE_SIZE = %d\n\tbuffer pointer: %p\n", precision, calc_buffer_size, max_value_size, calc_buffer)); } } -int get_precision() + + +void finish_strcalc() { + free(calc_buffer); calc_buffer = NULL; + free(output_buffer); output_buffer = NULL; +} + +int sc_get_precision(void) { - return CALC_BUFFER_SIZE/4; + return bit_pattern_size; }