* 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"
+
/*
* local definitions and macros
*/
/*
* 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 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:
+ - rightshift if bits were lost due to shifting
+ - division if there was a remainder
+ However, the meaning of carry is machine dependant
+ and often devined in other ways! */
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 };
exit(-1);
}
+/**
+ * implements the bitwise NOT operation
+ */
static void _bitnot(const char *val, char *buffer)
{
int 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;
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;
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;
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);
}
-/*
+/**
* 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;
* 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;
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[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);
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);
-}
-
+/**
+ * Shift the buffer to left and add a 4 bit digit
+ */
static void _push(const char digit, char *buffer)
{
int 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);
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 :( */
}
}
+ /* 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;
}
}
+/**
+ * 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;
}
}
-/* 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;
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);
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);
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;
+ 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';
if (precision <= 0) precision = SC_DEFAULT_PRECISION;
/* round up to multiple of 4 */
- if (precision & 0x3) precision += 4 - (precision&0x3);
+ precision = (precision + 3) & ~3;
BIT_PATTERN_SIZE = (precision);
CALC_BUFFER_SIZE = (precision / 2);
MAX_VALUE_SIZE = (precision / 4);
- calc_buffer = malloc(CALC_BUFFER_SIZE+1 * sizeof(char));
+ 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)
- {
+ 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, CALC_BUFFER_SIZE, MAX_VALUE_SIZE, calc_buffer));
}
}
+
+
+void finish_strcalc() {
+ free(calc_buffer); calc_buffer = NULL;
+ free(output_buffer); output_buffer = NULL;
+}
+
int sc_get_precision(void)
{
return BIT_PATTERN_SIZE;