abCalc/abCalc/expr/abCExprInt.c

273 lines
6.3 KiB
C

/*
abCExprInt.c
By: Jeremy Rand
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "abCMode.h"
#include "expr/abCExpr.h"
static abCalcExpr *abCalcExprIntParse(abCalcExpr *expr, char *buffer);
static char *abCalcExprIntFormat(abCalcExpr *expr, char *buffer);
static abCalcExprCallbacks gIntCallbacks = {
abCalcExprIntParse,
abCalcExprIntFormat
};
void abCalcExprIntInit(void)
{
abCalcRegisterExprType(abCalcExprTypeInt, &gIntCallbacks);
}
abCalcExpr *abCalcExprIntParse(abCalcExpr *expr, char *buffer)
{
abCalcModeIntBase base = abCalcModeGetBase();
abCalcIntType value = 0;
int len;
int offset = 1;
if (buffer == NULL)
return NULL;
if (expr == NULL)
return NULL;
len = strlen(buffer);
if (len < 2)
return NULL;
if (buffer[0] == '$') {
base = abCalcModeHexBase;
} else if ((buffer[0] == '0') &&
(buffer[1] == 'x')) {
base = abCalcModeHexBase;
offset = 2;
} else if (buffer[0] != '#')
return NULL;
switch (base) {
case abCalcModeBinBase:
for ( ; offset < len; offset++) {
value <<= 1;
switch (buffer[offset]) {
case '1':
value++;
break;
case '0':
break;
default:
return NULL;
}
}
break;
case abCalcModeOctBase:
for ( ; offset < len; offset++) {
value <<= 3;
switch (buffer[offset]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
value += (buffer[offset] - '0');;
break;
default:
return NULL;
}
}
break;
case abCalcModeDecBase:
for ( ; offset < len; offset++) {
value *= 10;
switch (buffer[offset]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
value += (buffer[offset] - '0');;
break;
default:
return NULL;
}
}
break;
case abCalcModeHexBase:
for ( ; offset < len; offset++) {
value <<= 4;
switch (buffer[offset]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
value += (buffer[offset] - '0');;
break;
case 'a':
case 'A':
value += 10;
break;
case 'b':
case 'B':
value += 11;
break;
case 'c':
case 'C':
value += 12;
break;
case 'd':
case 'D':
value += 13;
break;
case 'e':
case 'E':
value += 14;
break;
case 'f':
case 'F':
value += 15;
break;
default:
return NULL;
}
}
break;
default:
return NULL;
}
expr->type = abCalcExprTypeInt;
expr->u.integer = value;
return expr;
}
char *abCalcExprIntFormat(abCalcExpr *expr, char *buffer)
{
abCalcModeIntBase base = abCalcModeGetBase();
int width = abCalcModeGetIntWidth();
abCalcIntType value;
char *ptr;
int gotFirstOne;
int i;
if (expr == NULL)
return NULL;
if (buffer == NULL)
return NULL;
if (expr->type != abCalcExprTypeInt)
return NULL;
value = expr->u.integer;
if (width < AB_CALC_EXPR_MAX_INT_WIDTH) {
value &= ((1l << width) - 1);
}
switch (base) {
case abCalcModeBinBase:
gotFirstOne = 0;
ptr = buffer;
*ptr = '#';
ptr++;
for (i = width - 1; i >= 0; i--) {
if ((value >> i) & 1) {
*ptr = '1';
ptr++;
gotFirstOne = 1;
} else {
if (gotFirstOne) {
*ptr = '0';
ptr++;
}
}
}
if (!gotFirstOne) {
*ptr = '0';
ptr++;
}
*ptr = ' ';
ptr++;
*ptr = 'b';
ptr++;
*ptr = '\0';
break;
case abCalcModeOctBase:
sprintf(buffer, "#%lo o", value);
break;
case abCalcModeDecBase:
sprintf(buffer, "#%lu d", value);
break;
case abCalcModeHexBase:
sprintf(buffer, "#%lX h", value);
break;
default:
return NULL;
}
return buffer;
}
void abCalcExprIntSet(abCalcExpr *expr, abCalcIntType value)
{
int width;
if (expr == NULL)
return;
width = abCalcModeGetIntWidth();
expr->type = abCalcExprTypeInt;
expr->u.integer = value;
if (width < AB_CALC_EXPR_MAX_INT_WIDTH) {
expr->u.integer &= ((1l << width) - 1);
}
}