mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-26 07:05:57 -05:00
parser still not quite working on both queries and smart playlists
This commit is contained in:
parent
43afe26932
commit
2b6b8cd208
@ -4,7 +4,12 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define os_opensyslog()
|
||||
#define os_syslog(a,b)
|
||||
#define os_closesyslog()
|
||||
|
||||
#include "conf.h"
|
||||
#include "err.h"
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
# $Id$
|
||||
CC=gcc
|
||||
CFLAGS := $(CFLAGS) -g -DHAVE_CONFIG_H -I. -I..
|
||||
CFLAGS := $(CFLAGS) -g -DHAVE_CONFIG_H -I. -I.. -DERR_LEAN
|
||||
LDFLAGS := $(LDFLAGS)
|
||||
TARGET = conf
|
||||
OBJECTS=config-driver.o conf.o ll.o err.o
|
||||
|
16
src/err.c
16
src/err.c
@ -41,7 +41,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "err.h"
|
||||
#include "os.h"
|
||||
#ifndef ERR_LEAN
|
||||
# include "os.h"
|
||||
#endif
|
||||
|
||||
static int err_debuglevel=0; /**< current debuglevel, set from command line with -d */
|
||||
static int err_logdestination=LOGDEST_STDERR; /**< current log destination */
|
||||
@ -64,13 +66,13 @@ static int _err_unlock(void);
|
||||
|
||||
/**
|
||||
* Write a printf-style formatted message to the log destination.
|
||||
* This can be stderr, syslog/eventviewer, or a logfile, as determined by
|
||||
* This can be stderr, syslog/eventviewer, or a logfile, as determined by
|
||||
* err_setdest(). Note that this function should not be directly
|
||||
* used, rather it should be used via the #DPRINTF macro.
|
||||
*
|
||||
* \param level Level at which to log \ref log_levels
|
||||
* \param cat the category to log \ref log_categories
|
||||
* \param fmt printf-style
|
||||
* \param fmt printf-style
|
||||
*/
|
||||
void err_log(int level, unsigned int cat, char *fmt, ...)
|
||||
{
|
||||
@ -91,7 +93,7 @@ void err_log(int level, unsigned int cat, char *fmt, ...)
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
|
||||
_err_lock(); /* atomic file writes */
|
||||
|
||||
if((!level) && (err_logdestination != LOGDEST_STDERR)) {
|
||||
@ -127,7 +129,7 @@ void err_log(int level, unsigned int cat, char *fmt, ...)
|
||||
}
|
||||
|
||||
/*
|
||||
* simple get/set interface to debuglevel to avoid global
|
||||
* simple get/set interface to debuglevel to avoid global
|
||||
*/
|
||||
void err_setlevel(int level) {
|
||||
err_debuglevel = level;
|
||||
@ -176,7 +178,7 @@ void err_setdest(char *cvalue, int destination) {
|
||||
* through the err_categorylist and sets the bitfields for the
|
||||
* requested log modules.
|
||||
*
|
||||
* \param list comma separated list of modules to debug.
|
||||
* \param list comma separated list of modules to debug.
|
||||
*/
|
||||
extern int err_setdebugmask(char *list) {
|
||||
unsigned int rack;
|
||||
@ -193,7 +195,7 @@ extern int err_setdebugmask(char *list) {
|
||||
if(token) {
|
||||
rack=1;
|
||||
index=0;
|
||||
while((err_categorylist[index]) &&
|
||||
while((err_categorylist[index]) &&
|
||||
(strcasecmp(err_categorylist[index],token))) {
|
||||
rack <<= 1;
|
||||
index++;
|
||||
|
@ -74,4 +74,10 @@ extern int err_setdebugmask(char *list);
|
||||
|
||||
#define DPRINTF err_log
|
||||
|
||||
#ifdef ERR_LEAN
|
||||
# define os_syslog(a,b)
|
||||
# define os_opensyslog(a)
|
||||
# define os_closesyslog(a)
|
||||
#endif
|
||||
|
||||
#endif /* __ERR_H__ */
|
||||
|
@ -22,7 +22,7 @@ int main(int argc, char *argv[]) {
|
||||
while((option = getopt(argc, argv, "d:")) != -1) {
|
||||
switch(option) {
|
||||
case 'd':
|
||||
err_debuglevel = atoi(optarg);
|
||||
err_setlevel(atoi(optarg));
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Error: unknown option (%c)\n\n",option);
|
||||
|
@ -1,5 +1,5 @@
|
||||
CC=gcc
|
||||
CFLAGS := $(CFLAGS) -g -I/sw/include -DHAVE_CONFIG_H -I. -I.. -Wall
|
||||
CFLAGS := $(CFLAGS) -g -I/sw/include -DHAVE_CONFIG_H -I. -I.. -Wall -DERR_LEAN
|
||||
TARGET=parser
|
||||
OBJECTS=parser-driver.o smart-parser.o err.o
|
||||
|
||||
|
@ -56,6 +56,11 @@ typedef struct tag_sp_node {
|
||||
#define SP_OPTYPE_INT 2
|
||||
#define SP_OPTYPE_DATE 3
|
||||
|
||||
#define SP_HINT_NONE 0
|
||||
#define SP_HINT_STRING 1
|
||||
#define SP_HINT_INT 2
|
||||
#define SP_HINT_DATE 3
|
||||
|
||||
/*
|
||||
#define T_ID 0x00
|
||||
#define T_PATH 0x01
|
||||
@ -184,10 +189,10 @@ typedef struct tag_fieldlookup {
|
||||
char *name;
|
||||
} FIELDLOOKUP;
|
||||
|
||||
/* normal terminators, in-string terminators, escapes */
|
||||
char *sp_terminators[2][3] = {
|
||||
{ " \t\n\r\"<>=()|&!", "\"","\"" },
|
||||
{ "()'+: -,", "')", "\\*'" }
|
||||
/* normal terminators, in-string terminators, escapes, quotes */
|
||||
char *sp_terminators[2][4] = {
|
||||
{ " \t\n\r\"<>=()|&!", "\"","\"","\"" },
|
||||
{ "()'+: -,", "')", "\\*'","" }
|
||||
};
|
||||
|
||||
FIELDLOOKUP sp_symbols_0[] = {
|
||||
@ -404,16 +409,16 @@ time_t sp_isdate(char *string) {
|
||||
* @param tree current working parse tree.
|
||||
* @returns next token (token, not the value)
|
||||
*/
|
||||
int sp_scan(PARSETREE tree) {
|
||||
int sp_scan(PARSETREE tree, int hint) {
|
||||
char *terminator=NULL;
|
||||
char *tail;
|
||||
int advance=0;
|
||||
FIELDLOOKUP *pfield=sp_fields[tree->token_list];
|
||||
int len;
|
||||
int found;
|
||||
int numval;
|
||||
int is_qstr;
|
||||
time_t tval;
|
||||
int found_symbol;
|
||||
char *qstr;
|
||||
|
||||
if(tree->token.token_id & 0x2000) {
|
||||
if(tree->token.data.cvalue)
|
||||
@ -441,100 +446,122 @@ int sp_scan(PARSETREE tree) {
|
||||
DPRINTF(E_SPAM,L_PARSE,"Current offset: %d, char: %c\n",
|
||||
tree->token_pos, *(tree->current));
|
||||
|
||||
/* check singletons */
|
||||
found_symbol=0;
|
||||
if(hint == SP_HINT_STRING) {
|
||||
terminator=sp_terminators[tree->token_list][1];
|
||||
tree->in_string = 1;
|
||||
} else {
|
||||
terminator = sp_terminators[tree->token_list][0];
|
||||
tree->in_string = 0;
|
||||
}
|
||||
|
||||
/* check symbols */
|
||||
if(!tree->in_string) {
|
||||
pfield=sp_symbols[tree->token_list];
|
||||
while((pfield->name) && (!found_symbol)) {
|
||||
while(pfield->name) {
|
||||
if(!strncmp(pfield->name,tree->current,strlen(pfield->name))) {
|
||||
/* that's a match */
|
||||
tree->current += strlen(pfield->name);
|
||||
tree->token.token_id = pfield->type;
|
||||
found_symbol = 1;
|
||||
return pfield->type;
|
||||
}
|
||||
pfield++;
|
||||
}
|
||||
}
|
||||
|
||||
if((!found_symbol) && (*tree->current == '"')) {
|
||||
tree->current++;
|
||||
tree->in_string = !tree->in_string;
|
||||
tree->token.token_id = T_QUOTE;
|
||||
qstr = sp_terminators[tree->token_list][3];
|
||||
is_qstr = (strstr(qstr,tree->current) != NULL);
|
||||
if(strlen(qstr)) { /* strings ARE quoted */
|
||||
if(hint == SP_HINT_STRING) { /* MUST be a quote */
|
||||
if(!is_qstr)
|
||||
return T_ERROR;
|
||||
} else {
|
||||
tree->in_string = 1; /* guess we're in a string */
|
||||
tree->current++;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found_symbol) { /* either a keyword token or a quoted string */
|
||||
DPRINTF(E_SPAM,L_PARSE,"keyword or string!\n");
|
||||
DPRINTF(E_SPAM,L_PARSE,"keyword or string!\n");
|
||||
|
||||
/* walk to a terminator */
|
||||
tail = tree->current;
|
||||
/* walk to a terminator */
|
||||
tail = tree->current;
|
||||
|
||||
/* out-of-string terminator */
|
||||
terminator = sp_terminators[tree->token_list][0];
|
||||
if(tree->in_string) { /* in-string terminator */
|
||||
terminator=sp_terminators[tree->token_list][1];
|
||||
}
|
||||
/* FIXME: escaped characters */
|
||||
while((*tail) && (!strchr(terminator,*tail))) {
|
||||
tail++;
|
||||
}
|
||||
|
||||
/* FIXME: escaped characters */
|
||||
while((*tail) && (!strchr(terminator,*tail))) {
|
||||
tail++;
|
||||
}
|
||||
found=0;
|
||||
len = (int) (tail - tree->current);
|
||||
|
||||
found=0;
|
||||
len = (int) (tail - tree->current);
|
||||
|
||||
if(!tree->in_string) {
|
||||
/* find it in the token list */
|
||||
pfield=sp_fields[tree->token_list];
|
||||
DPRINTF(E_SPAM,L_PARSE,"Len is %d\n",len);
|
||||
while(pfield->name) {
|
||||
if(strlen(pfield->name) == len) {
|
||||
if(strncasecmp(pfield->name,tree->current,len) == 0) {
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
if(!tree->in_string) {
|
||||
/* find it in the token list */
|
||||
pfield=sp_fields[tree->token_list];
|
||||
DPRINTF(E_SPAM,L_PARSE,"Len is %d\n",len);
|
||||
while(pfield->name) {
|
||||
if(strlen(pfield->name) == len) {
|
||||
if(strncasecmp(pfield->name,tree->current,len) == 0) {
|
||||
DPRINTF(E_DBG,L_PARSE,"%*s Returning token %04x (%s)\n",
|
||||
tree->level," ", tree->token.token_id,
|
||||
pfield->name);
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
pfield++;
|
||||
}
|
||||
pfield++;
|
||||
}
|
||||
}
|
||||
|
||||
if(found) {
|
||||
tree->token.token_id = pfield->type;
|
||||
} else {
|
||||
tree->token.token_id = T_STRING;
|
||||
if(found) {
|
||||
tree->token.token_id = pfield->type;
|
||||
} else {
|
||||
tree->token.token_id = T_STRING;
|
||||
}
|
||||
|
||||
if(tree->token.token_id & 0x2000) {
|
||||
tree->token.data.cvalue = malloc(len + 1);
|
||||
if(!tree->token.data.cvalue) {
|
||||
/* fail on malloc error */
|
||||
DPRINTF(E_FATAL,L_PARSE,"Malloc error.\n");
|
||||
}
|
||||
strncpy(tree->token.data.cvalue,tree->current,len);
|
||||
tree->token.data.cvalue[len] = '\x0';
|
||||
}
|
||||
|
||||
if(tree->token.token_id & 0x2000) {
|
||||
tree->token.data.cvalue = malloc(len + 1);
|
||||
if(!tree->token.data.cvalue) {
|
||||
/* fail on malloc error */
|
||||
DPRINTF(E_FATAL,L_PARSE,"Malloc error.\n");
|
||||
}
|
||||
strncpy(tree->token.data.cvalue,tree->current,len);
|
||||
tree->token.data.cvalue[len] = '\x0';
|
||||
}
|
||||
|
||||
/* check for numberic? */
|
||||
if((hint == SP_HINT_NONE) || (hint == SP_HINT_INT)) {
|
||||
/* check for numeric? */
|
||||
if(tree->token.token_id == T_STRING &&
|
||||
(!tree->in_string) &&
|
||||
sp_isnumber(tree->token.data.cvalue)) {
|
||||
sp_isnumber(tree->token.data.cvalue)) {
|
||||
/* woops! */
|
||||
numval = atoi(tree->token.data.cvalue);
|
||||
free(tree->token.data.cvalue);
|
||||
tree->token.data.ivalue = numval;
|
||||
tree->token.token_id = T_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
if((hint == SP_HINT_NONE) || (hint == SP_HINT_DATE)) {
|
||||
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);
|
||||
tree->token.data.tvalue = tval;
|
||||
tree->token.token_id = T_DATE;
|
||||
}
|
||||
}
|
||||
|
||||
tree->current=tail;
|
||||
|
||||
tree->current=tail;
|
||||
/* if we are in_string, and we have quoted strings, ensure we
|
||||
* have a quote */
|
||||
|
||||
is_qstr = (strstr(qstr,tree->current) != NULL);
|
||||
if((!found) && strlen(qstr) && (!is_qstr) && (tree->in_string)) {
|
||||
DPRINTF(E_INF,L_PARSE,"Missing closing quotes\n");
|
||||
if(tree->token.token_id & 0x2000) {
|
||||
free(tree->token.data.cvalue);
|
||||
}
|
||||
tree->token.token_id = T_ERROR;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_PARSE,"%*s Returning token %04x\n",tree->level," ",
|
||||
@ -595,7 +622,7 @@ int sp_parse(PARSETREE tree, char *term) {
|
||||
if(tree->tree)
|
||||
sp_free_node(tree->tree);
|
||||
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
tree->tree = sp_parse_phrase(tree);
|
||||
|
||||
if(tree->tree) {
|
||||
@ -662,7 +689,7 @@ SP_NODE *sp_parse_aexpr(PARSETREE tree) {
|
||||
pnew->op_type = SP_OPTYPE_ANDOR;
|
||||
|
||||
pnew->left.node = expr;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
pnew->right.node = sp_parse_expr(tree);
|
||||
|
||||
if(!pnew->right.node) {
|
||||
@ -704,7 +731,7 @@ SP_NODE *sp_parse_oexpr(PARSETREE tree) {
|
||||
pnew->op_type = SP_OPTYPE_ANDOR;
|
||||
|
||||
pnew->left.node = expr;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
pnew->right.node = sp_parse_aexpr(tree);
|
||||
|
||||
if(!pnew->right.node) {
|
||||
@ -733,10 +760,10 @@ SP_NODE *sp_parse_expr(PARSETREE tree) {
|
||||
sp_enter_exit(tree,"sp_parse_expr",1,NULL);
|
||||
|
||||
if(tree->token.token_id == T_OPENPAREN) {
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
expr = sp_parse_oexpr(tree);
|
||||
if((expr) && (tree->token.token_id == T_CLOSEPAREN)) {
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
} else {
|
||||
/* Error: expecting close paren */
|
||||
sp_set_error(tree,SP_E_CLOSE);
|
||||
@ -807,11 +834,11 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||
memset(pnew,0x00,sizeof(SP_NODE));
|
||||
pnew->left.field = strdup(tree->token.data.cvalue);
|
||||
|
||||
sp_scan(tree); /* scan past the string field we know is there */
|
||||
sp_scan(tree,SP_HINT_NONE);/* scan past the string field we know is there */
|
||||
|
||||
if(tree->token.token_id == T_NOT) {
|
||||
pnew->not_flag=1;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
}
|
||||
|
||||
switch(tree->token.token_id) {
|
||||
@ -830,28 +857,17 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||
}
|
||||
|
||||
if(result) {
|
||||
sp_scan(tree);
|
||||
/* should be sitting on quote literal string quote */
|
||||
|
||||
if(tree->token.token_id == T_QUOTE) {
|
||||
sp_scan(tree);
|
||||
if(tree->token.token_id == T_STRING) {
|
||||
pnew->right.cvalue=strdup(tree->token.data.cvalue);
|
||||
sp_scan(tree);
|
||||
if(tree->token.token_id == T_QUOTE) {
|
||||
result=1;
|
||||
sp_scan(tree);
|
||||
} else {
|
||||
sp_set_error(tree,SP_E_CLOSEQUOTE);
|
||||
DPRINTF(E_SPAM,L_PARSE,"Expecting closign quote\n");
|
||||
}
|
||||
} else {
|
||||
sp_set_error(tree,SP_E_STRING);
|
||||
DPRINTF(E_SPAM,L_PARSE,"Expecting literal string\n");
|
||||
}
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
/* should be sitting on string literal */
|
||||
if(tree->token.token_id == T_STRING) {
|
||||
result = 1;
|
||||
pnew->right.cvalue=strdup(tree->token.data.cvalue);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
} else {
|
||||
sp_set_error(tree,SP_E_OPENQUOTE);
|
||||
DPRINTF(E_SPAM,L_PARSE,"Expecting opening quote\n");
|
||||
DPRINTF(E_SPAM,L_PARSE,"Expecting string, got %04X\n",
|
||||
tree->token.token_id);
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -883,11 +899,11 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||
memset(pnew,0x00,sizeof(SP_NODE));
|
||||
pnew->left.field = strdup(tree->token.data.cvalue);
|
||||
|
||||
sp_scan(tree); /* scan past the int field we know is there */
|
||||
sp_scan(tree,SP_HINT_NONE); /* scan past the int field we know is there */
|
||||
|
||||
if(tree->token.token_id == T_NOT) {
|
||||
pnew->not_flag=1;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
}
|
||||
|
||||
switch(tree->token.token_id) {
|
||||
@ -909,12 +925,12 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||
}
|
||||
|
||||
if(result) {
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
/* should be sitting on a literal string */
|
||||
if(tree->token.token_id == T_NUMBER) {
|
||||
result = 1;
|
||||
pnew->right.ivalue=tree->token.data.ivalue;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
} else {
|
||||
/* Error: Expecting number */
|
||||
sp_set_error(tree,SP_E_NUMBER);
|
||||
@ -953,11 +969,11 @@ SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
|
||||
memset(pnew,0x00,sizeof(SP_NODE));
|
||||
pnew->left.field = strdup(tree->token.data.cvalue);
|
||||
|
||||
sp_scan(tree); /* scan past the date field we know is there */
|
||||
sp_scan(tree,SP_HINT_NONE); /* scan past the date field we know is there */
|
||||
|
||||
if(tree->token.token_id == T_NOT) {
|
||||
pnew->not_flag=1;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
}
|
||||
|
||||
switch(tree->token.token_id) {
|
||||
@ -988,7 +1004,7 @@ SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
|
||||
}
|
||||
|
||||
if(result) {
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
/* should be sitting on a date */
|
||||
if((pnew->right.tvalue = sp_parse_date(tree))) {
|
||||
result=1;
|
||||
@ -1030,11 +1046,11 @@ time_t sp_parse_date(PARSETREE tree) {
|
||||
switch(tree->token.token_id) {
|
||||
case T_TODAY:
|
||||
result = time(NULL);
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
break;
|
||||
case T_DATE:
|
||||
result = tree->token.data.tvalue;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1052,7 +1068,7 @@ time_t sp_parse_date(PARSETREE tree) {
|
||||
if(tree->token.token_id == T_AFTER)
|
||||
before = 0;
|
||||
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
result = sp_parse_date(tree);
|
||||
if(result) {
|
||||
if(before) {
|
||||
@ -1087,23 +1103,23 @@ time_t sp_parse_date_interval(PARSETREE tree) {
|
||||
sp_set_error(tree,SP_E_NUMBER);
|
||||
} else {
|
||||
count = tree->token.data.ivalue;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
switch(tree->token.token_id) {
|
||||
case T_DAY:
|
||||
result = count * 3600 * 24;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
break;
|
||||
case T_WEEK:
|
||||
result = count * 3600 * 24 * 7;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
break;
|
||||
case T_MONTH:
|
||||
result = count * 3600 * 24 * 30;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
break;
|
||||
case T_YEAR:
|
||||
result = count * 3600 * 24 * 365;
|
||||
sp_scan(tree);
|
||||
sp_scan(tree,SP_HINT_NONE);
|
||||
break;
|
||||
default:
|
||||
result=0;
|
||||
|
Loading…
Reference in New Issue
Block a user