+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#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 */
-#define BIT_PATTERN_SIZE (8 * BIGGEST_INTEGER_SIZE_IN_BYTES)
-#define CALC_BUFFER_SIZE (4 * BIGGEST_INTEGER_SIZE_IN_BYTES)
-#define MAX_VALUE_SIZE (2 * BIGGEST_INTEGER_SIZE_IN_BYTES)
-
-#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__)
#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__)
# 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)
# 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)
/*
* private variables
*/
static char *calc_buffer = NULL; /* buffer holding all results */
static char *output_buffer = NULL; /* buffer for output */
/*
* private variables
*/
static char *calc_buffer = NULL; /* buffer holding all results */
static char *output_buffer = NULL; /* buffer for output */
-static int BIT_PATTERN_SIZE;
-static int CALC_BUFFER_SIZE;
-static int MAX_VALUE_SIZE;
+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 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 };
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_8, SC_8, SC_8, SC_8, SC_C, SC_C, SC_C, SC_C },
{ SC_0, SC_1, SC_0, SC_1, SC_4, SC_5, SC_4, SC_5,
SC_8, SC_8, SC_8, SC_8, SC_C, SC_C, SC_C, SC_C },
{ SC_0, SC_1, SC_0, SC_1, SC_4, SC_5, SC_4, SC_5,
- SC_8, SC_9, SC_8, SC_9, SC_D, SC_E, SC_D, SC_E },
+ SC_8, SC_9, SC_8, SC_9, SC_C, SC_D, SC_C, SC_D },
{ SC_0, SC_0, SC_2, SC_2, SC_4, SC_4, SC_6, SC_6,
SC_8, SC_8, SC_A, SC_A, SC_C, SC_C, SC_E, SC_E },
{ SC_0, SC_0, SC_2, SC_2, SC_4, SC_4, SC_6, SC_6,
SC_8, SC_8, SC_A, SC_A, SC_C, SC_C, SC_E, SC_E },
- 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)
+{
+ int bit = pos & 3;
+ int nibble = pos >> 2;
+
+ return _bitisset(val[nibble], bit);
- /* here a carry could be lost, this is intended because this will only
- * happen when a value changes sign. */
+ /* here a carry could be lost, this is intended because this should
+ * happen only when a value changes sign. */
- 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 */
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 */
/* init result buffer to zeroes */
memset(temp_buffer, SC_0, CALC_BUFFER_SIZE);
/* init result buffer to zeroes */
memset(temp_buffer, SC_0, CALC_BUFFER_SIZE);
/* A carry may hang over */
/* c_outer is always smaller than MAX_VALUE_SIZE! */
temp_buffer[MAX_VALUE_SIZE + c_outer] = carry;
/* A carry may hang over */
/* c_outer is always smaller than MAX_VALUE_SIZE! */
temp_buffer[MAX_VALUE_SIZE + c_outer] = carry;
_negate(val2, temp_buffer);
_add(val1, temp_buffer, buffer);
_negate(val2, temp_buffer);
_add(val1, temp_buffer, buffer);
static void _divmod(const char *dividend, const char *divisor, char *quot, char *rem)
{
const char *minus_divisor;
static void _divmod(const char *dividend, const char *divisor, char *quot, char *rem)
{
const char *minus_divisor;
/* clear result buffer */
memset(quot, SC_0, CALC_BUFFER_SIZE);
memset(rem, SC_0, CALC_BUFFER_SIZE);
/* clear result buffer */
memset(quot, SC_0, CALC_BUFFER_SIZE);
memset(rem, SC_0, CALC_BUFFER_SIZE);
/* if the dividend is zero result is zero (quot is zero)*/
if (sc_comp(dividend, quot) == 0)
return;
/* if the dividend is zero result is zero (quot is zero)*/
if (sc_comp(dividend, quot) == 0)
return;
* (remember these are absolute values) */
switch (sc_comp(dividend, divisor))
{
* (remember these are absolute values) */
switch (sc_comp(dividend, divisor))
{
+ /* check if any bits are lost, and set carry_flag if so */
+ for (counter = 0; counter < offset; counter++)
+ {
+ if (val1[counter] != 0)
+ {
+ carry_flag = 1;
+ break;
+ }
+ }
+ if ((_val(val1[counter]) & ((1<<shift)-1)) != 0)
+ {
+ carry_flag = 1;
+ }
+ /* shift digits to the right with offset, carry and all */
shrs = shrs_table[_val(val1[counter + offset])][shift];
buffer[counter] = shrs[0];
buffer[counter-1] = or_table[_val(buffer[counter-1])][_val(shrs[1])];
shrs = shrs_table[_val(val1[counter + offset])][shift];
buffer[counter] = shrs[0];
buffer[counter-1] = or_table[_val(buffer[counter-1])][_val(shrs[1])];
/* remove sign bits if mode was signed and this is an unsigned shift */
if (!signed_shift && is_signed) {
/* 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 */
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 */
/* positive: low-order -> high order, negative other direction */
static void _rot(const char *val1, char *buffer, long offset, int radius, unsigned is_signed)
{
/* 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);
_shl(val1, temp1, offset, radius, is_signed);
_shr(val1, temp2, radius - offset, radius, is_signed, 0);
_bitor(temp1, temp2, buffer);
_shl(val1, temp1, offset, radius, is_signed);
_shr(val1, temp2, radius - offset, radius, is_signed, 0);
_bitor(temp1, temp2, buffer);
memset(base, SC_0, CALC_BUFFER_SIZE);
memset(val, SC_0, CALC_BUFFER_SIZE);
memset(base, SC_0, CALC_BUFFER_SIZE);
memset(val, SC_0, CALC_BUFFER_SIZE);
- if (sign) _negate(calc_buffer, calc_buffer);
+
+ if (sign) {
+ if (is_minlong)
+ _inc(buffer, buffer);
+
+ _negate(buffer, buffer);
+ }
+}
+
+void sc_val_from_ulong(unsigned long value, void *buffer)
+{
+ char *pos;
+
+ if (buffer == NULL) buffer = calc_buffer;
+ pos = buffer;
+
+ while (pos < (char*)buffer + CALC_BUFFER_SIZE)
+ {
+ *pos++ = _digit(value & 0xf);
+ value >>= 4;
+ }
-void sc_calc(const void* value1, const void* value2, unsigned op)
+void sc_calc(const void* value1, const void* value2, unsigned op, void *buffer)
- DEBUGPRINTF(("%s ", sc_print(value1, SC_HEX)));
+ unused_res = alloca(CALC_BUFFER_SIZE);
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s ", sc_print_hex(value1)));
_bitxor(val1, val2, calc_buffer);
break;
case SC_NOT:
_bitnot(val1, calc_buffer);
_bitxor(val1, val2, calc_buffer);
break;
case SC_NOT:
_bitnot(val1, calc_buffer);
_divmod(val1, val2, calc_buffer, unused_res);
break;
case SC_MOD:
_divmod(val1, val2, calc_buffer, unused_res);
break;
case SC_MOD:
_divmod(val1, val2, unused_res, calc_buffer);
break;
default:
assert(0);
}
_divmod(val1, val2, unused_res, calc_buffer);
break;
default:
assert(0);
}
- DEBUGPRINTF(("%s -> ", sc_print_hex(value2)));
- DEBUGPRINTF(("%s\n", sc_print_hex(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)
_shl(val1, calc_buffer, offset, radius, sign);
break;
case SC_SHR:
_shl(val1, calc_buffer, offset, radius, sign);
break;
case SC_SHR:
_shr(val1, calc_buffer, offset, radius, sign, 0);
break;
case SC_SHRS:
_shr(val1, calc_buffer, offset, radius, sign, 0);
break;
case SC_SHRS:
_shr(val1, calc_buffer, offset, radius, sign, 1);
break;
case SC_ROT:
_shr(val1, calc_buffer, offset, radius, sign, 1);
break;
case SC_ROT:
_rot(val1, calc_buffer, offset, radius, sign);
break;
default:
assert(0);
}
_rot(val1, calc_buffer, offset, radius, sign);
break;
default:
assert(0);
}
- DEBUGPRINTF(("-> %s\n", sc_print_hex(calc_buffer)));
+ DEBUGPRINTF_COMPUTATION(("-> %s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer))
+ {
+ memmove(buffer, calc_buffer, CALC_BUFFER_SIZE);
+ }
+ 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++) {
+ if (val[counter] != SC_0) return 0;
+ }
+ return 1;
+}
+
+int sc_is_negative(const void *value)
+{
+ return _sign(value) == -1;
+}
+
+int sc_had_carry(void)
+{
+ return carry_flag;
- char base_val[CALC_BUFFER_SIZE];
- char div1_res[CALC_BUFFER_SIZE];
- char div2_res[CALC_BUFFER_SIZE];
- char rem_res[CALC_BUFFER_SIZE];
- int counter, nibbles, i;
+ static const char big_digits[] = "0123456789ABCDEF";
+ static const char small_digits[] = "0123456789abcdef";
+
+ char *base_val, *div1_res, *div2_res, *rem_res;
+ int counter, nibbles, i, sign;
+ const char *digits = small_digits;
+
+ base_val = alloca(CALC_BUFFER_SIZE);
+ div1_res = alloca(CALC_BUFFER_SIZE);
+ div2_res = alloca(CALC_BUFFER_SIZE);
+ rem_res = alloca(CALC_BUFFER_SIZE);
- for (counter = 0; counter < nibbles; ++counter)
- *(--pos) = "0123456789abcdef"[_val(val[counter])];
+ digits = big_digits;
+ case SC_hex:
+ for (counter = 0; counter < nibbles; ++counter) {
+ *(--pos) = digits[_val(val[counter])];
+#ifdef STRCALC_DEBUG_GROUPPRINT
+ if ((counter+1)%8 == 0)
+ *(--pos) = ' ';
+#endif
+ }
- for (; counter > 1; --counter, ++pos)
+ for (; counter > 1; --counter, ++pos) {
+#ifdef STRCALC_DEBUG_GROUPPRINT
+ if (pos[0] == ' ') ++pos;
+#endif
memset(base_val, SC_0, CALC_BUFFER_SIZE);
base_val[0] = base == SC_DEC ? SC_A : SC_8;
memset(base_val, SC_0, CALC_BUFFER_SIZE);
base_val[0] = base == SC_DEC ? SC_A : SC_8;
/* transfer data into oscilating buffers */
memset(div1_res, SC_0, CALC_BUFFER_SIZE);
for (counter = 0; counter < nibbles; ++counter)
/* transfer data into oscilating buffers */
memset(div1_res, SC_0, CALC_BUFFER_SIZE);
for (counter = 0; counter < nibbles; ++counter)
- 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 = malloc(CALC_BUFFER_SIZE+1 * sizeof(char));
+ output_buffer = malloc(BIT_PATTERN_SIZE+1 * sizeof(char));
+
+ if (calc_buffer == NULL || output_buffer == NULL) {
- 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));