-/****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 <stdlib.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+#ifdef HAVE_STRING_H
+# include <string.h> /* memset/memcmp */
+#endif
#include <assert.h> /* assertions */
-#include <string.h> /* memset/memcmp */
#include <stdio.h> /* output for error messages */
#include <limits.h> /* 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)
+# define sc_print_dec(a) sc_print((a), 0, SC_DEC)
+# define sc_print_oct(a) sc_print((a), 0, SC_OCT)
+# define sc_print_bin(a) sc_print((a), 0, SC_BIN)
+
+#ifdef STRCALC_DEBUG_PRINTCOMP
# define DEBUGPRINTF_COMPUTATION(x) printf x
#else
# define DEBUGPRINTF_COMPUTATION(x) ((void)0)
/*
* 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 };
{ {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"
exit(-1);
}
+/**
+ * implements the bitwise NOT operation
+ */
static void _bitnot(const char *val, char *buffer)
{
int counter;
- for (counter = 0; counter<CALC_BUFFER_SIZE; counter++)
+ for (counter = 0; counter<calc_buffer_size; counter++)
buffer[counter] = not_table[_val(val[counter])];
}
+/**
+ * implements the bitwise OR operation
+ */
static void _bitor(const char *val1, const char *val2, char *buffer)
{
int counter;
- for (counter = 0; counter<CALC_BUFFER_SIZE; counter++)
+ for (counter = 0; counter<calc_buffer_size; counter++)
buffer[counter] = or_table[_val(val1[counter])][_val(val2[counter])];
}
+/**
+ * implements the bitwise eXclusive OR operation
+ */
static void _bitxor(const char *val1, const char *val2, char *buffer)
{
int counter;
- for (counter = 0; counter<CALC_BUFFER_SIZE; counter++)
+ for (counter = 0; counter<calc_buffer_size; counter++)
buffer[counter] = xor_table[_val(val1[counter])][_val(val2[counter])];
}
+/**
+ * implements the bitwise AND operation
+ */
static void _bitand(const char *val1, const char *val2, char *buffer)
{
int counter;
- for (counter = 0; counter<CALC_BUFFER_SIZE; counter++)
+ for (counter = 0; counter<calc_buffer_size; counter++)
buffer[counter] = and_table[_val(val1[counter])][_val(val2[counter])];
}
+/**
+ * returns the sign bit.
+ *
+ * @todo This implementation is wrong, as it returns the highest bit of the buffer
+ * NOT the highest bit depending on the real mode
+ */
static int _sign(const char *val)
{
- return (val[CALC_BUFFER_SIZE-1] <= SC_7) ? (1) : (-1);
+ return (val[calc_buffer_size-1] <= SC_7) ? (1) : (-1);
}
-/*
+/**
* returns non-zero if bit at position pos is set
*/
static int _bit(const char *val, int pos)
return _bitisset(val[nibble], bit);
}
-static void _inc(char *val, char *buffer)
+/**
+ * Implements a fast ADD + 1
+ */
+static void _inc(const char *val, char *buffer)
{
int counter = 0;
- while (counter++ < CALC_BUFFER_SIZE)
+ while (counter++ < calc_buffer_size)
{
if (*val == SC_F)
{
* happen only when a value changes sign. */
}
+/**
+ * Implements a unary MINUS
+ */
static void _negate(const char *val, char *buffer)
{
_bitnot(val, buffer);
_inc(buffer, buffer);
}
+/**
+ * Implements a binary ADD
+ *
+ * @todo The implementation of carry is wrong, as it is the
+ * calc_buffer_size carry, not the mode depending
+ */
static void _add(const char *val1, const char *val2, char *buffer)
{
int counter;
const char *add1, *add2;
char carry = SC_0;
- for (counter = 0; counter < CALC_BUFFER_SIZE; counter++)
+ for (counter = 0; counter < calc_buffer_size; counter++)
{
add1 = add_table[_val(val1[counter])][_val(val2[counter])];
add2 = add_table[_val(add1[0])][_val(carry)];
buffer[counter] = add2[0];
carry = add_table[_val(add1[1])][_val(add2[1])][0];
}
+ carry_flag = carry != SC_0;
}
+/**
+ * Implements a binary SUB
+ */
+static void _sub(const char *val1, const char *val2, char *buffer)
+{
+ char *temp_buffer = alloca(calc_buffer_size); /* intermediate buffer to hold -val2 */
+
+ _negate(val2, temp_buffer);
+ _add(val1, temp_buffer, buffer);
+}
+
+/**
+ * Implements a binary MUL
+ */
static void _mul(const char *val1, const char *val2, char *buffer)
{
- char temp_buffer[CALC_BUFFER_SIZE]; /* result buffer */
- char neg_val1[CALC_BUFFER_SIZE]; /* abs of val1 */
- char neg_val2[CALC_BUFFER_SIZE]; /* abs of val2 */
+ char *temp_buffer; /* result buffer */
+ char *neg_val1; /* abs of val1 */
+ char *neg_val2; /* abs of val2 */
const char *mul, *add1, *add2; /* intermediate result containers */
char carry = SC_0; /* container for carries */
char sign = 0; /* marks result sign */
int c_inner, c_outer; /* loop counters */
+ temp_buffer = alloca(calc_buffer_size);
+ neg_val1 = alloca(calc_buffer_size);
+ neg_val2 = alloca(calc_buffer_size);
+
/* init result buffer to zeroes */
- memset(temp_buffer, SC_0, CALC_BUFFER_SIZE);
+ memset(temp_buffer, SC_0, calc_buffer_size);
/* the multiplication works only for positive values, for negative values *
* it is necessary to negate them and adjust the result accordingly */
sign ^= 1;
}
- for (c_outer = 0; c_outer < MAX_VALUE_SIZE; c_outer++)
+ for (c_outer = 0; c_outer < max_value_size; c_outer++)
{
if (val2[c_outer] != SC_0)
{
- for (c_inner = 0; c_inner < MAX_VALUE_SIZE; c_inner++)
+ for (c_inner = 0; c_inner < max_value_size; c_inner++)
{
/* do the following calculation: *
* Add the current carry, the value at position c_outer+c_inner *
}
/* A carry may hang over */
- /* c_outer is always smaller than MAX_VALUE_SIZE! */
- temp_buffer[MAX_VALUE_SIZE + c_outer] = carry;
+ /* c_outer is always smaller than max_value_size! */
+ temp_buffer[max_value_size + c_outer] = carry;
carry = SC_0;
}
}
if (sign)
_negate(temp_buffer, buffer);
else
- memcpy(buffer, temp_buffer, CALC_BUFFER_SIZE);
-}
-
-static void _sub(const char *val1, const char *val2, char *buffer)
-{
- char temp_buffer[CALC_BUFFER_SIZE]; /* intermediate buffer to hold -val2 */
-
- _negate(val2, temp_buffer);
- _add(val1, temp_buffer, buffer);
+ memcpy(buffer, temp_buffer, calc_buffer_size);
}
+/**
+ * Shift the buffer to left and add a 4 bit digit
+ */
static void _push(const char digit, char *buffer)
{
int counter;
- for (counter = CALC_BUFFER_SIZE - 2; 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!");
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) */
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);
}
}
+ /* 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;
/* 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;
}
{
/* 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;
/* 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<<shift)-1)) != 0)
+ {
carry_flag = 1;
-
+ }
/* shift digits to the right with offset, carry and all */
counter = 0;
if (radius/4 - offset > 0) {
/* the last digit is special in regard of signed/unsigned shift */
bitoffset = radius%4;
- msd = (radius/4<CALC_BUFFER_SIZE)?(val1[radius/4]):(sign); /* most significant digit */
+ msd = (radius/4<calc_buffer_size)?(val1[radius/4]):(sign); /* most significant digit */
/* remove sign bits if mode was signed and this is an unsigned shift */
if (!signed_shift && is_signed) {
if (counter > 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];
+ 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;
}
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;
+}
+
+/**
+ * Do sign extension if the mode is signed, expects all upper bits
+ * cleared.
+ */
+static 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[calc_buffer[ofs]][sex_digit[bits & 3]];
+ }
+ }
}
-/* XXX doesn't check for overflows */
-void sc_val_from_str(const char *str, unsigned int len)
+/* 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++; }
} /* 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);
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;
}
}
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++)
*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++)
*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)));
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);
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);
}
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;
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;
const char *val = (const char*)value;
int high, counter;
- 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;
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;
else return low + 3;
}
}
- return low;
+ return -1;
}
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;
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 */
/*
* convert to a string
+ * FIXME: Doesn't check buffer bounds
*/
const char *sc_print(const void *value, unsigned bits, enum base_t base)
{
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;
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
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;
if (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];
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)
- {
+ calc_buffer = xmalloc(calc_buffer_size+1 * sizeof(char));
+ output_buffer = xmalloc(bit_pattern_size+1 * sizeof(char));
+
+ if (calc_buffer == NULL || output_buffer == NULL) {
assert(0 && "malloc failed");
exit(-1);
}
- 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;
}