Fixes for not, add startswith and endswith operators

This commit is contained in:
Ron Pedde 2005-12-13 20:42:03 +00:00
parent a8e9e7bfd6
commit 24f40d7956

View File

@ -132,7 +132,9 @@ typedef struct tag_sp_node {
#define T_YEAR 0x0019 #define T_YEAR 0x0019
#define T_DATE 0x001a #define T_DATE 0x001a
#define T_NOT 0x001b #define T_NOT 0x001b
#define T_LAST 0x001c #define T_STARTSWITH 0x001c
#define T_ENDSWITH 0x001d
#define T_LAST 0x001e
#define T_EOF 0x00fd #define T_EOF 0x00fd
#define T_BOF 0x00fe #define T_BOF 0x00fe
@ -166,7 +168,9 @@ char *sp_token_descr[] = {
"month(s)", "month(s)",
"year(s)", "year(s)",
"date", "date",
"not" "not",
"like",
"like"
}; };
typedef struct tag_fieldlookup { typedef struct tag_fieldlookup {
@ -212,7 +216,7 @@ FIELDLOOKUP sp_fields[] = {
{ T_INT_FIELD, "force_update" }, { T_INT_FIELD, "force_update" },
{ T_STRING_FIELD, "codectype" }, { T_STRING_FIELD, "codectype" },
{ T_INT_FIELD, "idx" }, { T_INT_FIELD, "idx" },
/* end of db fields */ /* end of db fields */
{ T_OR, "or" }, { T_OR, "or" },
{ T_AND, "and" }, { T_AND, "and" },
@ -231,7 +235,9 @@ FIELDLOOKUP sp_fields[] = {
{ T_YEAR, "years" }, { T_YEAR, "years" },
{ T_YEAR, "year" }, { T_YEAR, "year" },
{ T_NOT, "not" }, { T_NOT, "not" },
{ T_STARTSWITH, "startswith" },
{ T_ENDSWITH, "endswith" },
/* end */ /* end */
{ 0, NULL }, { 0, NULL },
}; };
@ -269,7 +275,7 @@ char *sp_errorstrings[] = {
"Expecting '\"' (closing quote)", "Expecting '\"' (closing quote)",
"Expecting literal string", "Expecting literal string",
"Expecting '\"' (opening quote)", "Expecting '\"' (opening quote)",
"Expecting integer comparison operator (=,<,>, etc)", "Expecting integer comparison operator (=,<,>, etc)",
"Expecting integer", "Expecting integer",
"Expecting date comparison operator (<,<=,>,>=)", "Expecting date comparison operator (<,<=,>,>=)",
"Expecting interval comparison (before, after)", "Expecting interval comparison (before, after)",
@ -312,8 +318,8 @@ void sp_enter_exit(PARSETREE tree, char *function, int enter, void *result) {
tree->level--; tree->level--;
} }
} }
/** /**
* see if a string is actually a number * see if a string is actually a number
* *
@ -322,11 +328,11 @@ void sp_enter_exit(PARSETREE tree, char *function, int enter, void *result) {
*/ */
int sp_isnumber(char *string) { int sp_isnumber(char *string) {
char *current=string; char *current=string;
while(*current && (*current >= '0') && (*current <= '9')) { while(*current && (*current >= '0') && (*current <= '9')) {
current++; current++;
} }
return *current ? 0 : 1; return *current ? 0 : 1;
} }
@ -340,12 +346,12 @@ int sp_isnumber(char *string) {
time_t sp_isdate(char *string) { time_t sp_isdate(char *string) {
struct tm date_time; struct tm date_time;
time_t seconds=0; time_t seconds=0;
memset((void*)&date_time,0,sizeof(date_time)); memset((void*)&date_time,0,sizeof(date_time));
if(strptime(string,"%Y-%m-%d",&date_time)) { if(strptime(string,"%Y-%m-%d",&date_time)) {
seconds=timegm(&date_time); seconds=timegm(&date_time);
} }
return seconds; return seconds;
} }
@ -448,8 +454,8 @@ int sp_scan(PARSETREE tree) {
tree->token.token_id = T_NOT; tree->token.token_id = T_NOT;
break; break;
} }
} }
if(*tree->current == '"') { if(*tree->current == '"') {
advance = 1; advance = 1;
@ -509,7 +515,8 @@ int sp_scan(PARSETREE tree) {
} }
/* check for numberic? */ /* check for numberic? */
if(tree->token.token_id == T_STRING && if(tree->token.token_id == T_STRING &&
(!tree->in_string) &&
sp_isnumber(tree->token.data.cvalue)) { sp_isnumber(tree->token.data.cvalue)) {
/* woops! */ /* woops! */
numval = atoi(tree->token.data.cvalue); numval = atoi(tree->token.data.cvalue);
@ -517,15 +524,16 @@ int sp_scan(PARSETREE tree) {
tree->token.data.ivalue = numval; tree->token.data.ivalue = numval;
tree->token.token_id = T_NUMBER; tree->token.token_id = T_NUMBER;
} }
if(tree->token.token_id == T_STRING && if(tree->token.token_id == T_STRING &&
(!tree->in_string) &&
(tval=sp_isdate(tree->token.data.cvalue))) { (tval=sp_isdate(tree->token.data.cvalue))) {
free(tree->token.data.cvalue); free(tree->token.data.cvalue);
tree->token.data.tvalue = tval; tree->token.data.tvalue = tval;
tree->token.token_id = T_DATE; tree->token.token_id = T_DATE;
} }
tree->current=tail; tree->current=tail;
} }
@ -581,9 +589,9 @@ int sp_parse(PARSETREE tree, char *term) {
tree->current=tree->term; tree->current=tree->term;
tree->token.token_id=T_BOF; tree->token.token_id=T_BOF;
if(tree->tree) if(tree->tree)
sp_free_node(tree->tree); sp_free_node(tree->tree);
sp_scan(tree); sp_scan(tree);
tree->tree = sp_parse_phrase(tree); tree->tree = sp_parse_phrase(tree);
@ -610,10 +618,10 @@ SP_NODE *sp_parse_phrase(PARSETREE tree) {
SP_NODE *expr; SP_NODE *expr;
sp_enter_exit(tree,"sp_parse_phrase",1,NULL); sp_enter_exit(tree,"sp_parse_phrase",1,NULL);
DPRINTF(E_SPAM,L_PARSE,"%*s Entering sp_parse_phrase\n",tree->level," "); DPRINTF(E_SPAM,L_PARSE,"%*s Entering sp_parse_phrase\n",tree->level," ");
tree->level++; tree->level++;
expr = sp_parse_oexpr(tree); expr = sp_parse_oexpr(tree);
if((!expr) || (tree->token.token_id != T_EOF)) { if((!expr) || (tree->token.token_id != T_EOF)) {
sp_free_node(expr); sp_free_node(expr);
@ -635,30 +643,30 @@ SP_NODE *sp_parse_phrase(PARSETREE tree) {
SP_NODE *sp_parse_aexpr(PARSETREE tree) { SP_NODE *sp_parse_aexpr(PARSETREE tree) {
SP_NODE *expr; SP_NODE *expr;
SP_NODE *pnew; SP_NODE *pnew;
sp_enter_exit(tree,"sp_parse_aexpr",1,NULL); sp_enter_exit(tree,"sp_parse_aexpr",1,NULL);
expr = sp_parse_expr(tree); expr = sp_parse_expr(tree);
while(expr && (tree->token.token_id == T_AND)) { while(expr && (tree->token.token_id == T_AND)) {
pnew = (SP_NODE*)malloc(sizeof(SP_NODE)); pnew = (SP_NODE*)malloc(sizeof(SP_NODE));
if(!pnew) { if(!pnew) {
DPRINTF(E_FATAL,L_PARSE,"Malloc error\n"); DPRINTF(E_FATAL,L_PARSE,"Malloc error\n");
} }
memset(pnew,0x00,sizeof(SP_NODE)); memset(pnew,0x00,sizeof(SP_NODE));
pnew->op=T_AND; pnew->op=T_AND;
pnew->op_type = SP_OPTYPE_ANDOR; pnew->op_type = SP_OPTYPE_ANDOR;
pnew->left.node = expr; pnew->left.node = expr;
sp_scan(tree); sp_scan(tree);
pnew->right.node = sp_parse_expr(tree); pnew->right.node = sp_parse_expr(tree);
if(!pnew->right.node) { if(!pnew->right.node) {
sp_free_node(pnew); sp_free_node(pnew);
pnew=NULL; pnew=NULL;
} }
expr=pnew; expr=pnew;
} }
@ -677,30 +685,30 @@ SP_NODE *sp_parse_aexpr(PARSETREE tree) {
SP_NODE *sp_parse_oexpr(PARSETREE tree) { SP_NODE *sp_parse_oexpr(PARSETREE tree) {
SP_NODE *expr; SP_NODE *expr;
SP_NODE *pnew; SP_NODE *pnew;
sp_enter_exit(tree,"sp_parse_oexpr",1,NULL); sp_enter_exit(tree,"sp_parse_oexpr",1,NULL);
expr = sp_parse_aexpr(tree); expr = sp_parse_aexpr(tree);
while(expr && (tree->token.token_id == T_OR)) { while(expr && (tree->token.token_id == T_OR)) {
pnew = (SP_NODE*)malloc(sizeof(SP_NODE)); pnew = (SP_NODE*)malloc(sizeof(SP_NODE));
if(!pnew) { if(!pnew) {
DPRINTF(E_FATAL,L_PARSE,"Malloc error\n"); DPRINTF(E_FATAL,L_PARSE,"Malloc error\n");
} }
memset(pnew,0x00,sizeof(SP_NODE)); memset(pnew,0x00,sizeof(SP_NODE));
pnew->op=T_OR; pnew->op=T_OR;
pnew->op_type = SP_OPTYPE_ANDOR; pnew->op_type = SP_OPTYPE_ANDOR;
pnew->left.node = expr; pnew->left.node = expr;
sp_scan(tree); sp_scan(tree);
pnew->right.node = sp_parse_aexpr(tree); pnew->right.node = sp_parse_aexpr(tree);
if(!pnew->right.node) { if(!pnew->right.node) {
sp_free_node(pnew); sp_free_node(pnew);
pnew=NULL; pnew=NULL;
} }
expr=pnew; expr=pnew;
} }
@ -720,7 +728,7 @@ SP_NODE *sp_parse_expr(PARSETREE tree) {
SP_NODE *expr; SP_NODE *expr;
sp_enter_exit(tree,"sp_parse_expr",1,NULL); sp_enter_exit(tree,"sp_parse_expr",1,NULL);
if(tree->token.token_id == T_OPENPAREN) { if(tree->token.token_id == T_OPENPAREN) {
sp_scan(tree); sp_scan(tree);
expr = sp_parse_oexpr(tree); expr = sp_parse_oexpr(tree);
@ -750,9 +758,9 @@ SP_NODE *sp_parse_expr(PARSETREE tree) {
*/ */
SP_NODE *sp_parse_criterion(PARSETREE tree) { SP_NODE *sp_parse_criterion(PARSETREE tree) {
SP_NODE *expr=NULL; SP_NODE *expr=NULL;
sp_enter_exit(tree,"sp_parse_criterion",1,expr); sp_enter_exit(tree,"sp_parse_criterion",1,expr);
switch(tree->token.token_id) { switch(tree->token.token_id) {
case T_STRING_FIELD: case T_STRING_FIELD:
expr = sp_parse_string_criterion(tree); expr = sp_parse_string_criterion(tree);
@ -788,7 +796,7 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
SP_NODE *pnew = NULL; SP_NODE *pnew = NULL;
sp_enter_exit(tree,"sp_parse_string_criterion",1,NULL); sp_enter_exit(tree,"sp_parse_string_criterion",1,NULL);
pnew = malloc(sizeof(SP_NODE)); pnew = malloc(sizeof(SP_NODE));
if(!pnew) { if(!pnew) {
DPRINTF(E_FATAL,L_PARSE,"Malloc Error\n"); DPRINTF(E_FATAL,L_PARSE,"Malloc Error\n");
@ -802,10 +810,12 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
pnew->not_flag=1; pnew->not_flag=1;
sp_scan(tree); sp_scan(tree);
} }
switch(tree->token.token_id) { switch(tree->token.token_id) {
case T_EQUAL: case T_EQUAL:
case T_INCLUDES: case T_INCLUDES:
case T_STARTSWITH:
case T_ENDSWITH:
pnew->op=tree->token.token_id; pnew->op=tree->token.token_id;
pnew->op_type = SP_OPTYPE_STRING; pnew->op_type = SP_OPTYPE_STRING;
result = 1; result = 1;
@ -845,7 +855,7 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
if(!result) { if(!result) {
sp_free_node(pnew); sp_free_node(pnew);
pnew=NULL; pnew=NULL;
} }
sp_enter_exit(tree,"sp_parse_string_criterion",0,pnew); sp_enter_exit(tree,"sp_parse_string_criterion",0,pnew);
@ -861,7 +871,7 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
SP_NODE *sp_parse_int_criterion(PARSETREE tree) { SP_NODE *sp_parse_int_criterion(PARSETREE tree) {
int result=0; int result=0;
SP_NODE *pnew = NULL; SP_NODE *pnew = NULL;
sp_enter_exit(tree,"sp_parse_int_criterion",1,pnew); sp_enter_exit(tree,"sp_parse_int_criterion",1,pnew);
pnew = malloc(sizeof(SP_NODE)); pnew = malloc(sizeof(SP_NODE));
if(!pnew) { if(!pnew) {
@ -915,7 +925,7 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
sp_free_node(pnew); sp_free_node(pnew);
pnew=NULL; pnew=NULL;
} }
sp_enter_exit(tree,"sp_parse_int_criterion",0,pnew); sp_enter_exit(tree,"sp_parse_int_criterion",0,pnew);
return pnew; return pnew;
@ -931,7 +941,7 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
SP_NODE *sp_parse_date_criterion(PARSETREE tree) { SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
SP_NODE *pnew=NULL; SP_NODE *pnew=NULL;
int result=0; int result=0;
sp_enter_exit(tree,"sp_parse_date_criterion",1,pnew); sp_enter_exit(tree,"sp_parse_date_criterion",1,pnew);
pnew = malloc(sizeof(SP_NODE)); pnew = malloc(sizeof(SP_NODE));
if(!pnew) { if(!pnew) {
@ -989,7 +999,7 @@ SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
sp_free_node(pnew); sp_free_node(pnew);
pnew=NULL; pnew=NULL;
} }
sp_enter_exit(tree,"sp_parse_date_criterion",0,pnew); sp_enter_exit(tree,"sp_parse_date_criterion",0,pnew);
@ -999,7 +1009,7 @@ SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
/** /**
* parse a date value for a date field comparison * parse a date value for a date field comparison
* *
* date -> T_TODAY | T_DATE | * date -> T_TODAY | T_DATE |
* date_interval T_BEFORE date | date_interval T_AFTER date * date_interval T_BEFORE date | date_interval T_AFTER date
* date_interval -> T_NUMBER ( T_DAY | T_WEEK | T_MONTH | T_YEAR) * date_interval -> T_NUMBER ( T_DAY | T_WEEK | T_MONTH | T_YEAR)
* (T_BEFORE | T_AFTER) date * (T_BEFORE | T_AFTER) date
@ -1011,7 +1021,7 @@ time_t sp_parse_date(PARSETREE tree) {
time_t result=0; time_t result=0;
time_t interval; time_t interval;
int before; int before;
sp_enter_exit(tree,"sp_parse_date",1,(void*)result); sp_enter_exit(tree,"sp_parse_date",1,(void*)result);
switch(tree->token.token_id) { switch(tree->token.token_id) {
@ -1024,7 +1034,7 @@ time_t sp_parse_date(PARSETREE tree) {
sp_scan(tree); sp_scan(tree);
break; break;
} }
if(!result) { if(!result) {
/* must be an interval */ /* must be an interval */
interval = sp_parse_date_interval(tree); interval = sp_parse_date_interval(tree);
@ -1038,7 +1048,7 @@ time_t sp_parse_date(PARSETREE tree) {
before = 1; before = 1;
if(tree->token.token_id == T_AFTER) if(tree->token.token_id == T_AFTER)
before = 0; before = 0;
sp_scan(tree); sp_scan(tree);
result = sp_parse_date(tree); result = sp_parse_date(tree);
if(result) { if(result) {
@ -1050,7 +1060,7 @@ time_t sp_parse_date(PARSETREE tree) {
} }
} }
} }
sp_enter_exit(tree,"sp_parse_date_criterion",0,(void*)result); sp_enter_exit(tree,"sp_parse_date_criterion",0,(void*)result);
return result; return result;
@ -1066,12 +1076,12 @@ time_t sp_parse_date(PARSETREE tree) {
time_t sp_parse_date_interval(PARSETREE tree) { time_t sp_parse_date_interval(PARSETREE tree) {
time_t result=0; time_t result=0;
int count; int count;
sp_enter_exit(tree,"sp_parse_date_interval",1,(void*)result); sp_enter_exit(tree,"sp_parse_date_interval",1,(void*)result);
if(tree->token.token_id != T_NUMBER) { if(tree->token.token_id != T_NUMBER) {
result=0; result=0;
sp_set_error(tree,SP_E_NUMBER); sp_set_error(tree,SP_E_NUMBER);
} else { } else {
count = tree->token.data.ivalue; count = tree->token.data.ivalue;
sp_scan(tree); sp_scan(tree);
@ -1098,12 +1108,12 @@ time_t sp_parse_date_interval(PARSETREE tree) {
break; break;
} }
} }
sp_enter_exit(tree,"sp_parse_date_interval",0,(void*)result); sp_enter_exit(tree,"sp_parse_date_interval",0,(void*)result);
return result; return result;
} }
/** /**
* free a node, and all left/right subnodes * free a node, and all left/right subnodes
@ -1118,8 +1128,8 @@ void sp_free_node(SP_NODE *node) {
if(node->left.node) { if(node->left.node) {
sp_free_node(node->left.node); sp_free_node(node->left.node);
node->left.node = NULL; node->left.node = NULL;
} }
if(node->right.node) { if(node->right.node) {
sp_free_node(node->right.node); sp_free_node(node->right.node);
node->right.node = NULL; node->right.node = NULL;
@ -1129,7 +1139,7 @@ void sp_free_node(SP_NODE *node) {
free(node->left.field); free(node->left.field);
node->left.field = NULL; node->left.field = NULL;
} }
if(node->op_type == SP_OPTYPE_STRING) { if(node->op_type == SP_OPTYPE_STRING) {
if(node->right.cvalue) { if(node->right.cvalue) {
free(node->right.cvalue); free(node->right.cvalue);
@ -1152,19 +1162,19 @@ void sp_free_node(SP_NODE *node) {
int sp_dispose(PARSETREE tree) { int sp_dispose(PARSETREE tree) {
if(tree->term) if(tree->term)
free(tree->term); free(tree->term);
if(tree->token.token_id & 0x2000) if(tree->token.token_id & 0x2000)
free(tree->token.data.cvalue); free(tree->token.data.cvalue);
if(tree->error) if(tree->error)
free(tree->error); free(tree->error);
free(tree); free(tree);
return 1; return 1;
} }
/** /**
* calculate the size required to render the tree as a * calculate the size required to render the tree as a
* sql query. * sql query.
* *
* @parameter node node/tree to calculate * @parameter node node/tree to calculate
@ -1172,7 +1182,7 @@ int sp_dispose(PARSETREE tree) {
*/ */
int sp_node_size(SP_NODE *node) { int sp_node_size(SP_NODE *node) {
int size; int size;
if(node->op_type == SP_OPTYPE_ANDOR) { if(node->op_type == SP_OPTYPE_ANDOR) {
size = sp_node_size(node->left.node); size = sp_node_size(node->left.node);
size += sp_node_size(node->right.node); size += sp_node_size(node->right.node);
@ -1186,23 +1196,26 @@ int sp_node_size(SP_NODE *node) {
} else { } else {
size += strlen(sp_token_descr[node->op & 0x0FFF]); size += strlen(sp_token_descr[node->op & 0x0FFF]);
} }
if(node->op_type == SP_OPTYPE_STRING) { if(node->op_type == SP_OPTYPE_STRING) {
size += (2 + strlen(node->right.cvalue)); size += (2 + strlen(node->right.cvalue));
if(node->op == T_INCLUDES) { if(node->op == T_INCLUDES) {
size += 2; /* extra %'s */ size += 2; /* extra %'s */
} }
if((node->op == T_STARTSWITH)||(node->op == T_ENDSWITH)) {
size += 1;
}
} }
if((node->op_type == SP_OPTYPE_INT) || (node->op_type == SP_OPTYPE_DATE)) { if((node->op_type == SP_OPTYPE_INT) || (node->op_type == SP_OPTYPE_DATE)) {
size += 40; /* what *is* the max size of int64? */ size += 40; /* what *is* the max size of int64? */
} }
if(node->not_flag) { if(node->not_flag) {
size += 5; /* " not " */ size += 5; /* " not " */
} }
} }
return size; return size;
} }
@ -1214,7 +1227,7 @@ int sp_node_size(SP_NODE *node) {
*/ */
void sp_serialize_sql(SP_NODE *node, char *string) { void sp_serialize_sql(SP_NODE *node, char *string) {
char buffer[40]; char buffer[40];
if(node->op_type == SP_OPTYPE_ANDOR) { if(node->op_type == SP_OPTYPE_ANDOR) {
strcat(string,"("); strcat(string,"(");
sp_serialize_sql(node->left.node,string); sp_serialize_sql(node->left.node,string);
@ -1224,34 +1237,34 @@ void sp_serialize_sql(SP_NODE *node, char *string) {
strcat(string,")"); strcat(string,")");
} else { } else {
strcat(string,"("); strcat(string,"(");
strcat(string,node->left.field);
strcat(string," ");
if(node->not_flag) { if(node->not_flag) {
strcat(string,"not "); strcat(string,"not ");
} }
strcat(string,node->left.field);
strcat(string," ");
strcat(string,sp_token_descr[node->op & 0x0FFF]); strcat(string,sp_token_descr[node->op & 0x0FFF]);
strcat(string," "); strcat(string," ");
if(node->op_type == SP_OPTYPE_STRING) { if(node->op_type == SP_OPTYPE_STRING) {
strcat(string,"'"); strcat(string,"'");
if(node->op == T_INCLUDES) if((node->op == T_INCLUDES) || (node->op == T_ENDSWITH))
strcat(string,"%"); strcat(string,"%");
strcat(string,node->right.cvalue); strcat(string,node->right.cvalue);
if(node->op == T_INCLUDES) if((node->op == T_INCLUDES) || (node->op == T_STARTSWITH))
strcat(string,"%"); strcat(string,"%");
strcat(string,"'"); strcat(string,"'");
} }
if(node->op_type == SP_OPTYPE_INT) { if(node->op_type == SP_OPTYPE_INT) {
sprintf(buffer,"%d",node->right.ivalue); sprintf(buffer,"%d",node->right.ivalue);
strcat(string,buffer); strcat(string,buffer);
} }
if(node->op_type == SP_OPTYPE_DATE) { if(node->op_type == SP_OPTYPE_DATE) {
sprintf(buffer,"%d",(int)node->right.tvalue); sprintf(buffer,"%d",(int)node->right.tvalue);
strcat(string,buffer); strcat(string,buffer);
} }
strcat(string,")"); strcat(string,")");
} }
} }
@ -1269,10 +1282,10 @@ char *sp_sql_clause(PARSETREE tree) {
size = sp_node_size(tree->tree); size = sp_node_size(tree->tree);
sql = (char*)malloc(size+1); sql = (char*)malloc(size+1);
memset(sql,0x00,size+1); memset(sql,0x00,size+1);
sp_serialize_sql(tree->tree,sql); sp_serialize_sql(tree->tree,sql);
return sql; return sql;
} }
@ -1302,17 +1315,17 @@ char *sp_get_error(PARSETREE tree) {
*/ */
void sp_set_error(PARSETREE tree, int error) { void sp_set_error(PARSETREE tree, int error) {
int len; int len;
if(tree->error) if(tree->error)
free(tree->error); free(tree->error);
len = 10 + (tree->token_pos / 10) + 1 + strlen(sp_errorstrings[error]) + 1; len = 10 + (tree->token_pos / 10) + 1 + strlen(sp_errorstrings[error]) + 1;
tree->error = (char*)malloc(len); tree->error = (char*)malloc(len);
if(!tree->error) { if(!tree->error) {
DPRINTF(E_FATAL,L_PARSE,"Malloc error"); DPRINTF(E_FATAL,L_PARSE,"Malloc error");
return; return;
} }
sprintf(tree->error,"Offset %d: %s",tree->token_pos + 1,sp_errorstrings[error]); sprintf(tree->error,"Offset %d: %s",tree->token_pos + 1,sp_errorstrings[error]);
return; return;
} }