some fixes for xml dumper / still buggy.
[libfirm] / ir / tv / strcalc.c
index 4dd5d63..8a2d9ed 100644 (file)
@@ -6,21 +6,17 @@
  * NOTES
  ******/
 
-#include <assert.h>   /* assertions */
-#include <string.h>   /* memset/memcmp */
-
 #include "strcalc.h"
 
-#include <stdio.h>    /* output for error messages */
 #include <stdlib.h>
+#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 */
 
-/*****************************************************************************
+/*
  * local definitions and macros
- *****************************************************************************/
-#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 _val(a) ((a)-SC_0)
 #define _digit(a) ((a)+SC_0)
 
 #define fail_char(a, b, c, d) _fail_char((a), (b), (c), (d), __FILE__,  __LINE__)
 
-#if 0
-#  define DEBUGPRINTF(...) printf(__VA_ARGS__)
+#ifdef STRCALC_DEBUG_COMPUTATION
+#  define DEBUGPRINTF_COMPUTATION(x) printf x
 #else
-#  define DEBUGPRINTF(...) ((void)0)
+#  define DEBUGPRINTF_COMPUTATION(x) ((void)0)
+#endif
+#ifdef STRCALC_DEBUG
+#  define DEBUGPRINTF(x) printf x
+#else
+#  define DEBUGPRINTF(x) ((void)0)
 #endif
 
-/*****************************************************************************
+
+/*
  * private variables
- *****************************************************************************/
+ */
 
-static char calc_buffer[CALC_BUFFER_SIZE];    /* buffer holding all results */
+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 char quot[CALC_BUFFER_SIZE]; /* temp buffer holding result of divmod */
-static char rem[CALC_BUFFER_SIZE]; /* temp buffer holding remainder of divmod */
+static int carry_flag;              /* some computation set carry_flag: */
+                                    /* rightshift if bits were lost due to shifting */
+                                    /* division if there was a remainder */
 
-static char max_digit[4] = { SC_0, SC_1, SC_3, SC_7 };
-static 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 };
 
-static char not_table[16] = { SC_F, SC_E, SC_D, SC_C, SC_B, SC_A, SC_9, SC_8,
+static const char not_table[16] = { SC_F, SC_E, SC_D, SC_C, SC_B, SC_A, SC_9, SC_8,
                               SC_7, SC_6, SC_5, SC_4, SC_3, SC_2, SC_1, SC_0 };
 
-static char shift_table[4] = { SC_1, SC_2, SC_4, SC_8 };
+static const char shift_table[4] = { SC_1, SC_2, SC_4, SC_8 };
 
-static char and_table[16][16] = {
+static const char and_table[16][16] = {
                             { SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0,
                               SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0 },
 
@@ -92,7 +99,7 @@ static char and_table[16][16] = {
                               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 },
@@ -100,7 +107,7 @@ static char and_table[16][16] = {
                             { SC_0, SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7,
                               SC_8, SC_9, SC_A, SC_B, SC_C, SC_D, SC_E, SC_F } };
 
-static char or_table[16][16] = {
+static const char or_table[16][16] = {
                             { SC_0, SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7,
                               SC_8, SC_9, SC_A, SC_B, SC_C, SC_D, SC_E, SC_F },
 
@@ -149,7 +156,7 @@ static char or_table[16][16] = {
                             { SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F,
                               SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F } };
 
-static char xor_table[16][16] = {
+static char const xor_table[16][16] = {
                              { SC_0, SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7,
                                SC_8, SC_9, SC_A, SC_B, SC_C, SC_D, SC_E, SC_F },
 
@@ -199,7 +206,7 @@ static char xor_table[16][16] = {
                                SC_7, SC_6, SC_5, SC_4, SC_3, SC_2, SC_1, SC_0 }
                                 };
 
-static char add_table[16][16][2] = {
+static char const add_table[16][16][2] = {
                        { {SC_0, SC_0}, {SC_1, SC_0}, {SC_2, SC_0}, {SC_3, SC_0},
                          {SC_4, SC_0}, {SC_5, SC_0}, {SC_6, SC_0}, {SC_7, SC_0},
                          {SC_8, SC_0}, {SC_9, SC_0}, {SC_A, SC_0}, {SC_B, SC_0},
@@ -281,7 +288,7 @@ static char add_table[16][16][2] = {
                          {SC_B, SC_1}, {SC_C, SC_1}, {SC_D, SC_1}, {SC_E, SC_1} }
                              };
 
-static char mul_table[16][16][2] = {
+static char const mul_table[16][16][2] = {
                        { {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0},
                          {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0},
                          {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0},
@@ -363,7 +370,7 @@ static char mul_table[16][16][2] = {
                          {SC_4, SC_B}, {SC_3, SC_C}, {SC_2, SC_D}, {SC_1, SC_E} }
                              };
 
-static char shrs_table[16][4][2] = {
+static char const shrs_table[16][4][2] = {
                        { {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0} },
                        { {SC_1, SC_0}, {SC_0, SC_8}, {SC_0, SC_4}, {SC_0, SC_2} },
                        { {SC_2, SC_0}, {SC_1, SC_0}, {SC_0, SC_8}, {SC_0, SC_4} },
@@ -381,6 +388,13 @@ static char shrs_table[16][4][2] = {
                        { {SC_E, SC_0}, {SC_7, SC_0}, {SC_3, SC_8}, {SC_1, SC_C} },
                        { {SC_F, SC_0}, {SC_7, SC_8}, {SC_3, SC_C}, {SC_1, SC_E} }
                                    };
+
+/* for converting to binary string */
+static const char *binary_table[16] = {
+  "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
+  "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
+};
+
 /*****************************************************************************
  * private functions
  *****************************************************************************/
@@ -428,7 +442,18 @@ static void _bitand(const char *val1, const char *val2, char *buffer)
 
 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)
+{
+  int bit    = pos & 3;
+  int nibble = pos >> 2;
+
+  return _bitisset(val[nibble], bit);
 }
 
 static void _inc(char *val, char *buffer)
@@ -449,8 +474,8 @@ static void _inc(char *val, char *buffer)
       return;
     }
   }
-  /* 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. */
 }
 
 static void _negate(const char *val, char *buffer)
@@ -462,7 +487,7 @@ static void _negate(const char *val, char *buffer)
 static void _add(const char *val1, const char *val2, char *buffer)
 {
   int counter;
-  char *add1, *add2;
+  const char *add1, *add2;
   char carry = SC_0;
 
   for (counter = 0; counter < CALC_BUFFER_SIZE; counter++)
@@ -473,16 +498,15 @@ static void _add(const char *val1, const char *val2, char *buffer)
     buffer[counter] = add2[0];
     carry = add_table[_val(add1[1])][_val(add2[1])][0];
   }
-  /* loose last carry, which will occur only when changing sign */
 }
 
 static void _mul(const char *val1, const char *val2, char *buffer)
 {
-  static char temp_buffer[CALC_BUFFER_SIZE]; /* result buffer */
-  static char neg_val1[CALC_BUFFER_SIZE];    /* abs of val1 */
-  static char neg_val2[CALC_BUFFER_SIZE];    /* abs of val2 */
+  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 *mul, *add1, *add2;            /* intermediate result containers */
+  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 */
@@ -539,12 +563,14 @@ static void _mul(const char *val1, const char *val2, char *buffer)
       /* A carry may hang over */
       /* 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, temp_buffer);
-
-  memcpy(buffer, temp_buffer, CALC_BUFFER_SIZE);
+  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)
@@ -567,11 +593,11 @@ static void _push(const char digit, char *buffer)
 }
 
 /* XXX: This is MOST slow */
-static void _divmod(const char *dividend, const char *divisor)
+static void _divmod(const char *dividend, const char *divisor, char *quot, char *rem)
 {
   const char *minus_divisor;
-  static char neg_val1[CALC_BUFFER_SIZE];
-  static char neg_val2[CALC_BUFFER_SIZE];
+  char neg_val1[CALC_BUFFER_SIZE];
+  char neg_val2[CALC_BUFFER_SIZE];
 
   char sign = 0;     /* remember result sign */
 
@@ -580,10 +606,13 @@ static void _divmod(const char *dividend, const char *divisor)
   /* 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 divisor is zero this won't work (quot is zero) */
-  if (sc_comp(divisor, quot) == 0) assert(0 && "quotision by zero!");
+  if (sc_comp(divisor, quot) == 0) assert(0 && "division by zero!");
+
+  /* if the dividend is zero result is zero (quot is zero)*/
+  if (sc_comp(dividend, quot) == 0)
+    return;
 
   if (_sign(dividend) == -1)
   {
@@ -604,7 +633,7 @@ static void _divmod(const char *dividend, const char *divisor)
     minus_divisor = neg_val2;
   }
 
-  /* if divisor >= dividend quotision is easy
+  /* if divisor >= dividend division is easy
    * (remember these are absolute values) */
   switch (sc_comp(dividend, divisor))
   {
@@ -616,11 +645,11 @@ static void _divmod(const char *dividend, const char *divisor)
       memcpy(rem, dividend, CALC_BUFFER_SIZE);
       return;
 
-    default: /* unluckily quotision is necessary :( */
+    default: /* unluckily division is necessary :( */
       break;
   }
 
-  for (c_dividend = MAX_VALUE_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);
@@ -642,6 +671,8 @@ static void _divmod(const char *dividend, const char *divisor)
     }
   }
 
+  carry_flag = !sc_is_zero(rem);
+
   if (sign)
   {
     _negate(quot, quot);
@@ -649,54 +680,54 @@ static void _divmod(const char *dividend, const char *divisor)
   }
 }
 
-static void _shl(const char *val1, const char *val2, char *buffer, unsigned radius, unsigned is_signed)
+static void _shl(const char *val1, char *buffer, long offset, int radius, unsigned is_signed)
 {
-  char *shl;
+  const char *shl;
   char shift;
   char carry = SC_0;
 
   int counter;
-  int offset = 0;
   int bitoffset = 0;
 
-  assert((_sign(val2) != -1) || (0 && "negative leftshift"));
+  assert((offset >= 0) || (0 && "negative leftshift"));
   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"));
 
-  /* the whole value must be moved left the number of bytes represented
-   * by the value in quot, with bytes to the right set to zero */
-  /*XXX This might result in trouble */
-  for (counter = MAX_VALUE_SIZE - 1; counter >= 0; counter--)
-  {
-    offset = (offset << 4) | (_val(val2[counter]));
-  }
-
-  shift = shift_table[_val(offset%4)];      /* this is 2 ** (val2 % 4) */
-
   /* if shifting far enough the result is zero */
   if (offset >= radius)
   {
     memset(buffer, SC_0, CALC_BUFFER_SIZE);
     return;
   }
+
+  shift = shift_table[_val(offset%4)];      /* this is 2 ** (offset % 4) */
   offset = offset / 4;
 
   /* shift the single digits some bytes (offset) and some bits (table)
    * to the left */
-  for (counter = 0; counter < CALC_BUFFER_SIZE - offset; counter++)
+  for (counter = 0; counter < radius/4 - offset; counter++)
   {
     shl = mul_table[_val(val1[counter])][_val(shift)];
     buffer[counter + offset] = or_table[_val(shl[0])][_val(carry)];
     carry = shl[1];
   }
+  if (radius%4 > 0)
+  {
+    shl = mul_table[_val(val1[counter])][_val(shift)];
+    buffer[counter + offset] = or_table[_val(shl[0])][_val(carry)];
+    bitoffset = counter;
+  } else {
+    bitoffset = counter - 1;
+  }
 
   /* fill with zeroes */
-  for (counter = 0; counter < offset; counter++) buffer[counter] = 0;
+  for (counter = 0; counter < offset; counter++) buffer[counter] = SC_0;
+
   /* if the mode was signed, change sign when the mode's msb is now 1 */
-  offset = (radius - 1) / 4;
-  bitoffset = (radius - 1) % 4;
-  if (is_signed && _bitisset(buffer[offset], bitoffset) && (_sign(buffer) == 1))
+  offset = bitoffset + offset;
+  bitoffset = (radius-1) % 4;
+  if (is_signed && _bitisset(buffer[offset], bitoffset))
   {
     /* this sets the upper bits of the leftmost digit */
     buffer[offset] = or_table[_val(buffer[offset])][_val(min_digit[bitoffset])];
@@ -705,11 +736,10 @@ static void _shl(const char *val1, const char *val2, char *buffer, unsigned radi
       buffer[counter] = SC_F;
     }
   }
-  else if (is_signed && !_bitisset(buffer[offset], bitoffset) && (_sign(buffer) == -1))
+  else if (is_signed && !_bitisset(buffer[offset], bitoffset))
   {
     /* this unsets the upper bits of the leftmost digit */
     buffer[offset] = and_table[_val(buffer[offset])][_val(max_digit[bitoffset])];
-    /* zero the upper part of the value */
     for (counter = offset+1; counter < CALC_BUFFER_SIZE; counter++)
     {
       buffer[counter] = SC_0;
@@ -717,44 +747,53 @@ static void _shl(const char *val1, const char *val2, char *buffer, unsigned radi
   }
 }
 
-static void _shr(const char *val1, const char *val2, char *buffer, unsigned radius, unsigned is_signed, int signed_shift)
+static void _shr(const char *val1, char *buffer, long offset, int radius, unsigned is_signed, int signed_shift)
 {
-  char *shrs;
+  const char *shrs;
   char sign;
   char msd;
 
   int shift;
 
   int counter;
-  int offset = 0;
   int bitoffset = 0;
 
-  assert((_sign(val2) != -1) || (0 && "negative rightshift"));
+  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"));
 
-  /*XXX get the value of val2, this might result in trouble *
-   * (but who wants shifts THAT far anyway)                 */
-  for (counter = MAX_VALUE_SIZE - 1; counter >= 0; counter--)
-  {
-    offset = (offset << 4) | (_val(val2[counter]));
-  }
-
-  shift = offset % 4;     /* this is val2 % 4 */
-
   sign = ((signed_shift) && (_sign(val1) == -1))?(SC_F):(SC_0);
+
   /* if shifting far enough the result is either 0 or -1 */
   if (offset >= radius)
   {
     memset(buffer, sign, CALC_BUFFER_SIZE);
     return;
   }
+
+  shift = offset % 4;
   offset = offset / 4;
 
-  buffer[0] = shrs_table[_val(val1[offset])][shift][0];
+  /* check if any bits are lost, and set carry_flag is so */
+  for (counter = 0; counter < offset; counter++)
+  {
+    if (val1[counter] != carry_flag)
+    {
+      carry_flag = 1;
+      break;
+    }
+  }
+  if ((carry_flag == 0) && (_val(val1[counter]) & shift) != 0)
+    carry_flag = 1;
+
   /* shift digits to the right with offset, carry and all */
-  for (counter = 1; counter < radius/4; counter++)
+  counter = 0;
+  if (radius/4 - offset > 0) {
+    buffer[counter] = shrs_table[_val(val1[offset])][shift][0];
+    counter = 1;
+  }
+  for (; counter < radius/4 - offset; counter++)
   {
     shrs = shrs_table[_val(val1[counter + offset])][shift];
     buffer[counter] = shrs[0];
@@ -762,9 +801,8 @@ static void _shr(const char *val1, const char *val2, char *buffer, unsigned radi
   }
 
   /* the last digit is special in regard of signed/unsigned shift */
-  /* counter = radius/4 (after for loop) */
   bitoffset = radius%4;
-  msd = val1[counter];  /* 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) {
@@ -779,7 +817,8 @@ static void _shr(const char *val1, const char *val2, char *buffer, unsigned radi
   } else {
     buffer[counter] = shrs[0];
   }
-  buffer[counter - 1] = or_table[_val(buffer[counter-1])][_val(shrs[1])];
+
+  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++)
@@ -789,68 +828,23 @@ static void _shr(const char *val1, const char *val2, char *buffer, unsigned radi
 }
 
 /* positive: low-order -> high order, negative other direction */
-static void _rot(const char *val1, const char *val2, char *buffer, unsigned radius, unsigned is_signed)
+static void _rot(const char *val1, char *buffer, long offset, int radius, unsigned is_signed)
 {
-  static char temp_buffer[CALC_BUFFER_SIZE];
-
-  char *shl;
-  char carry = SC_0;
+  char temp1[CALC_BUFFER_SIZE];
+  char temp2[CALC_BUFFER_SIZE];
 
-  int counter, old_counter;
-  int shift;
-  int offset = 0;
-  int bitoffset;
+  offset = offset % radius;
 
-  /*XXX get the value of val2, this might result in trouble *
-   * (but who wants shifts THAT far anyway)                 */
-  for (counter = MAX_VALUE_SIZE - 1; counter >= 0; counter--)
-  {
-    offset = (offset << 4) | (_val(val2[counter]));
-  }
   /* rotation by multiples of the typelength is identity */
-  offset = offset % radius;
   if (offset == 0) {
     memmove(buffer, val1, CALC_BUFFER_SIZE);
     return;
   }
-  /* rotation to the right is the same as rotation to the left
-   * when done by the right amount */
-  if (offset < 0) offset = radius + offset;
-
-  shift = _val(shift_table[offset % 4]);
-  offset = offset / 4;
-
-  DEBUGPRINTF("offset: %d, shift: %d\n", offset, shift);
-  for (counter = 0; counter < radius/4 - offset; counter++)
-  {
-    shl = mul_table[_val(val1[counter])][_val(shift)];
-    temp_buffer[counter + offset] = or_table[_val(shl[0])][_val(carry)];
-    carry = shl[1];
-    DEBUGPRINTF("%d(%x): %s\n", counter, shl[0], sc_print_hex(temp_buffer));
-  }
-  old_counter = counter;
-  for (; counter < radius/4; counter++)
-  {
-    shl = mul_table[_val(val1[counter])][_val(shift)];
-    temp_buffer[counter - old_counter] = or_table[_val(shl[0])][_val(carry)];
-    carry = shl[1];
-    DEBUGPRINTF("%d(%x)> %s\n", counter, shl[0], sc_print_hex(temp_buffer));
-  }
-  temp_buffer[counter - old_counter] = or_table[_val(temp_buffer[counter-old_counter])][_val(carry)];
-
-  offset = (radius-1)/4;
-  bitoffset - (radius-1)%4;
-  /* fill the rest of the buffer depending on msb and mode signedness*/
-  if (is_signed && _bitisset(temp_buffer[offset], bitoffset))
-  {
-
-  }
-  else
-  {
-
-  }
 
-  memcpy(buffer, temp_buffer, CALC_BUFFER_SIZE);
+  _shl(val1, temp1, offset, radius, is_signed);
+  _shr(val1, temp2, radius - offset, radius, is_signed, 0);
+  _bitor(temp1, temp2, buffer);
+  carry_flag = 0; /* set by shr, but due to rot this is false */
 }
 
 /*****************************************************************************
@@ -866,14 +860,15 @@ const int sc_get_buffer_length(void)
   return CALC_BUFFER_SIZE;
 }
 
+/* XXX doesn't check for overflows */
 void sc_val_from_str(const char *str, unsigned int len)
 {
   const char *orig_str = str;
   unsigned int orig_len = len;
 
   char sign = 0;
-  static char base[CALC_BUFFER_SIZE];
-  static char val[CALC_BUFFER_SIZE];
+  char base[CALC_BUFFER_SIZE];
+  char val[CALC_BUFFER_SIZE];
 
   /* verify valid pointers (not null) */
   assert(str);
@@ -936,7 +931,7 @@ void sc_val_from_str(const char *str, unsigned int len)
     base[1] = SC_0; base[0] = SC_A;
   }
 
-  /* begin string evaluation, from left to right */
+  /* BEGIN string evaluation, from left to right */
   while (len > 0)
   {
     switch (*str)
@@ -1013,13 +1008,19 @@ void sc_val_from_str(const char *str, unsigned int len)
 void sc_val_from_long(long value)
 {
   char *pos;
-  int sign;
+  char sign, is_minlong;
 
   pos = calc_buffer;
   sign = (value < 0);
+  is_minlong = value == LONG_MIN;
 
-  /* FIXME MININT won't work */
-  if (sign) value = -value;
+  /* use absolute value, special treatment of MIN_LONG */
+  if (sign) {
+    if (is_minlong)
+      value = -(value+1);
+    else
+      value = -value;
+  }
 
   CLEAR_CALC_BUFFER();
 
@@ -1029,7 +1030,11 @@ void sc_val_from_long(long value)
     value /= 16;
   }
 
-  if (sign) _negate(calc_buffer, calc_buffer);
+
+  if (sign) {
+    if (is_minlong) _inc(calc_buffer, calc_buffer);
+    _negate(calc_buffer, calc_buffer);
+  }
 }
 
 long sc_val_to_long(const void *val)
@@ -1084,99 +1089,103 @@ void sc_max_from_bits(unsigned int num_bits, unsigned int sign)
 
 void sc_calc(const void* value1, const void* value2, unsigned op)
 {
-  const char *val1 = (char *)value1;
-  const char *val2 = (char *)value2;
+  char unused_res[CALC_BUFFER_SIZE]; /* temp buffer holding unused result of divmod */
+
+  const char *val1 = (const char *)value1;
+  const char *val2 = (const char *)value2;
   CLEAR_CALC_BUFFER();
+  carry_flag = 0;
 
-  DEBUGPRINTF("%s ", sc_print(value1, SC_HEX));
+  DEBUGPRINTF_COMPUTATION(("%s ", sc_print_hex(value1)));
 
   switch (op)
   {
     case SC_NEG:
       _negate(val1, calc_buffer);
-      DEBUGPRINTF("negated: %s\n", sc_print(calc_buffer, SC_HEX));
+      DEBUGPRINTF_COMPUTATION(("negated: %s\n", sc_print_hex(calc_buffer)));
       return;
     case SC_OR:
-      DEBUGPRINTF("| ");
+      DEBUGPRINTF_COMPUTATION(("| "));
       _bitor(val1, val2, calc_buffer);
       break;
     case SC_AND:
-      DEBUGPRINTF("& ");
+      DEBUGPRINTF_COMPUTATION(("& "));
       _bitand(val1, val2, calc_buffer);
       break;
     case SC_XOR:
-      DEBUGPRINTF("^ ");
+      DEBUGPRINTF_COMPUTATION(("^ "));
       _bitxor(val1, val2, calc_buffer);
       break;
     case SC_NOT:
       _bitnot(val1, calc_buffer);
-      DEBUGPRINTF("bit-negated: %s\n", sc_print(calc_buffer, SC_HEX));
+      DEBUGPRINTF_COMPUTATION(("bit-negated: %s\n", sc_print_hex(calc_buffer)));
       return;
     case SC_ADD:
-      DEBUGPRINTF("+ ");
+      DEBUGPRINTF_COMPUTATION(("+ "));
       _add(val1, val2, calc_buffer);
       break;
     case SC_SUB:
-      DEBUGPRINTF("- ");
+      DEBUGPRINTF_COMPUTATION(("- "));
       _sub(val1, val2, calc_buffer);
       break;
     case SC_MUL:
-      DEBUGPRINTF("* ");
+      DEBUGPRINTF_COMPUTATION(("* "));
       _mul(val1, val2, calc_buffer);
       break;
     case SC_DIV:
-      DEBUGPRINTF("/ ");
-      _divmod(val1, val2);
-      memcpy(calc_buffer, quot, CALC_BUFFER_SIZE);
+      DEBUGPRINTF_COMPUTATION(("/ "));
+      _divmod(val1, val2, calc_buffer, unused_res);
       break;
     case SC_MOD:
-      DEBUGPRINTF("%% ");
-      _divmod(val1, val2);
-      memcpy(calc_buffer, rem, CALC_BUFFER_SIZE);
+      DEBUGPRINTF_COMPUTATION(("%% "));
+      _divmod(val1, val2, unused_res, calc_buffer);
       break;
     default:
       assert(0);
   }
-  DEBUGPRINTF("%s -> ", sc_print(value2, SC_HEX));
-  DEBUGPRINTF("%s\n", sc_print(calc_buffer, SC_HEX));
+  DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+  DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
 }
-void sc_bitcalc(const void* value1, const void* value2, unsigned radius, unsigned sign, unsigned op)
+
+void sc_bitcalc(const void* value1, const void* value2, int radius, int sign, unsigned op)
 {
-  const char *val1 = (char *)value1;
-  const char *val2 = (char *)value2;
-  CLEAR_CALC_BUFFER();
+  const char *val1 = (const char *)value1;
+  const char *val2 = (const char *)value2;
+  long offset;
+
+  carry_flag = 0;
+  offset = sc_val_to_long(val2);
 
-  DEBUGPRINTF("%s ", sc_print(value1, SC_HEX));
+  DEBUGPRINTF_COMPUTATION(("%s ", sc_print_hex(value1)));
   switch (op)
   {
     case SC_SHL:
-      DEBUGPRINTF("<< ");
-      _shl(val1, val2, calc_buffer, radius, sign);
+      DEBUGPRINTF_COMPUTATION(("<< %d ", offset));
+      _shl(val1, calc_buffer, offset, radius, sign);
       break;
     case SC_SHR:
-      DEBUGPRINTF(">> ");
-      _shr(val1, val2, calc_buffer, radius, sign, 0);
+      DEBUGPRINTF_COMPUTATION((">> %d ", offset));
+      _shr(val1, calc_buffer, offset, radius, sign, 0);
       break;
     case SC_SHRS:
-      DEBUGPRINTF(">>> ");
-      _shr(val1, val2, calc_buffer, radius, sign, 1);
+      DEBUGPRINTF_COMPUTATION((">>> %d ", offset));
+      _shr(val1, calc_buffer, offset, radius, sign, 1);
       break;
     case SC_ROT:
-      DEBUGPRINTF("<<>> ");
-      _rot(val1, val2, calc_buffer, radius, sign);
+      DEBUGPRINTF_COMPUTATION(("<<>> %d ", offset));
+      _rot(val1, calc_buffer, offset, radius, sign);
       break;
     default:
       assert(0);
   }
-  DEBUGPRINTF("%s -> ", sc_print(value2, SC_HEX));
-  DEBUGPRINTF("%s\n", sc_print(calc_buffer, SC_HEX));
+  DEBUGPRINTF_COMPUTATION(("-> %s\n", sc_print_hex(calc_buffer)));
 }
 
 int sc_comp(const void* value1, const void* value2)
 {
   int counter = CALC_BUFFER_SIZE - 1;
-  const char *val1 = (char *)value1;
-  const char *val2 = (char *)value2;
+  const char *val1 = (const char *)value1;
+  const char *val2 = (const char *)value2;
 
   /* compare signs first:
    * the loop below can only compare values of the same sign! */
@@ -1196,34 +1205,251 @@ int sc_comp(const void* value1, const void* value2)
   return (val1[counter] > val2[counter]) ? (1) : (-1);
 }
 
-char *sc_print(const void *value, unsigned base)
+int sc_get_highest_set_bit(const void *value)
+{
+  const char *val = (const char*)value;
+  int high, counter;
+
+  high = CALC_BUFFER_SIZE * 4;
+
+  for (counter = CALC_BUFFER_SIZE-1; counter >= 0; counter--) {
+    if (val[counter] == SC_0) high -= 4;
+    else {
+      if (val[counter] > SC_7) return high;
+      else if (val[counter] > SC_3) return high - 1;
+      else if (val[counter] > SC_1) return high - 2;
+      else return high - 3;
+    }
+  }
+  return high;
+}
+
+int sc_get_lowest_set_bit(const void *value)
+{
+  const char *val = (const char*)value;
+  int low, counter;
+  char sign;
+
+  sign = (_sign(val)==1)?(SC_0):(SC_F);
+  low = 0;
+
+  for (counter = 0; counter < CALC_BUFFER_SIZE; counter++) {
+    if (val[counter] == SC_0) low += 4;
+    else {
+      if (val[counter] < SC_2) return low;
+      else if (val[counter] < SC_4) return low + 1;
+      else if (val[counter] < SC_8) return low + 2;
+      else return low + 3;
+    }
+  }
+  return low;
+}
+
+int sc_is_zero(const void *value)
 {
+  const char* val = (const char *)value;
   int counter;
 
-  const char *val = (char*)value;
+  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;
+}
+
+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;
+  unsigned char res;
+
+  /* the current scheme uses one byte to store a nibble */
+  if (nibble_ofs >= len)
+    return 0;
+
+  res = _val(val[nibble_ofs]);
+  if (len > nibble_ofs + 1)
+    res |= _val(val[nibble_ofs + 1]) << 4;
+
+  return res;
+}
+
+/*
+ * convert to a string
+ * XXX 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];
+  int counter, nibbles, i, sign;
+  char x;
+
+  const char *val = (const char *)value;
+  const char *p;
+  char *m, *n, *t;
   char *pos;
-  static char *buf = NULL;
+  const char *digits = small_digits;
+
+  pos = output_buffer + BIT_PATTERN_SIZE ;
+  *(--pos) = '\0';
 
-  if (buf != NULL) free(buf);
-  buf = malloc(BIT_PATTERN_SIZE);
+  /* special case */
+  if (bits == 0) {
+    bits = BIT_PATTERN_SIZE;
+#ifdef STRCALC_DEBUG_FULLPRINT
+    bits <<= 1;
+#endif
+  }
+  nibbles = bits >> 2;
+  switch (base) {
+
+  case SC_HEX:
+    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
+    }
 
-  pos = buf + BIT_PATTERN_SIZE - 1;
-  *pos = '\0';
+    /* last nibble must be masked */
+    if (bits & 3) {
+      x = and_table[_val(val[++counter])][bits & 3];
+      *(--pos) = digits[_val(x)];
+    }
 
-  switch (base)
-  {
-    case SC_HEX:
-      for (counter = 0; counter < MAX_VALUE_SIZE; counter++)
-      {
-        if (val[counter] < SC_A)
-          *(--pos) = val[counter] + '0';
-        else
-          *(--pos) = val[counter] + 'a' - 10;
+    /* now kill zeros */
+    for (; counter > 1; --counter, ++pos) {
+#ifdef STRCALC_DEBUG_GROUPPRINT
+      if (pos[0] == ' ') ++pos;
+#endif
+      if (pos[0] != '0')
+       break;
+    }
+    break;
+
+  case SC_BIN:
+    for (counter = 0; counter < nibbles; ++counter) {
+      pos -= 4;
+      p = binary_table[_val(val[counter])];
+      pos[0] = p[0];
+      pos[1] = p[1];
+      pos[2] = p[2];
+      pos[3] = p[3];
+    }
+
+    /* last nibble must be masked */
+    if (bits & 3) {
+      x = and_table[_val(val[++counter])][bits & 3];
+
+      pos -= 4;
+      p = binary_table[_val(x)];
+      pos[0] = p[0];
+      pos[1] = p[1];
+      pos[2] = p[2];
+      pos[3] = p[3];
+    }
+
+    /* now kill zeros */
+    for (counter <<= 2; counter > 1; --counter, ++pos)
+      if (pos[0] != '0')
+       break;
+    break;
+
+  case SC_DEC:
+  case SC_OCT:
+    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) {
+      /* check for negative values */
+      if (_bit(val, bits - 1)) {
+       _negate(val, div2_res);
+       sign = 1;
+       p = div2_res;
       }
-      break;
+    }
 
-    default:
-      assert(0);
-  }
+    /* transfer data into oscilating buffers */
+    memset(div1_res, SC_0, CALC_BUFFER_SIZE);
+    for (counter = 0; counter < nibbles; ++counter)
+      div1_res[counter] = p[counter];
+
+     /* last nibble must be masked */
+    if (bits & 3) {
+      ++counter;
+
+      div1_res[counter] = and_table[_val(p[counter])][bits & 3];
+    }
+
+    m = div1_res;
+    n = div2_res;
+    for (;;) {
+      _divmod(m, base_val, n, rem_res);
+      t = m;
+      m = n;
+      n = t;
+      *(--pos) = digits[_val(rem_res[0])];
+
+      x = 0;
+      for (i = 0; i < sizeof(div1_res); ++i)
+       x |= _val(m[i]);
+
+      if (x == 0)
+       break;
+    }
+    if (sign)
+       *(--pos) = '-';
+    break;
+
+  default:
+    assert(0);
+    return NULL;
+}
   return pos;
 }
+
+void init_strcalc(int precision_in_bytes)
+{
+  if (calc_buffer == NULL) {
+    if (precision_in_bytes <= 0) precision_in_bytes = DEFAULT_PRECISION_IN_BYTES;
+
+    BIT_PATTERN_SIZE = (8 * precision_in_bytes);
+    CALC_BUFFER_SIZE = (4 * precision_in_bytes);
+    MAX_VALUE_SIZE   = (2 * precision_in_bytes);
+
+    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)
+    {
+      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));
+  }
+}
+int get_precision()
+{
+  return CALC_BUFFER_SIZE/4;
+}