almost have both query types working
This commit is contained in:
parent
e1c98c5fda
commit
4964fb1374
|
@ -23,6 +23,7 @@
|
||||||
#define _DB_GENERIC_H_
|
#define _DB_GENERIC_H_
|
||||||
|
|
||||||
#include "mp3-scanner.h" /** for MP3FILE */
|
#include "mp3-scanner.h" /** for MP3FILE */
|
||||||
|
#include "smart-parser.h" /** for PARSETREE */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// generic meta data
|
// generic meta data
|
||||||
|
@ -77,11 +78,11 @@ typedef enum {
|
||||||
metaItmsGenreId,
|
metaItmsGenreId,
|
||||||
metaItmsStorefrontId,
|
metaItmsStorefrontId,
|
||||||
metaItunesSmartPlaylist,
|
metaItunesSmartPlaylist,
|
||||||
|
|
||||||
/* iTunes 5.0 + */
|
/* iTunes 5.0 + */
|
||||||
metaSongContentRating,
|
metaSongContentRating,
|
||||||
metaHasChildContainers,
|
metaHasChildContainers,
|
||||||
|
|
||||||
/* iTunes 6.0.2+ */
|
/* iTunes 6.0.2+ */
|
||||||
metaItunesHasVideo,
|
metaItunesHasVideo,
|
||||||
|
|
||||||
|
@ -125,7 +126,7 @@ typedef struct tag_dbqueryinfo {
|
||||||
int session_id;
|
int session_id;
|
||||||
int uri_count;
|
int uri_count;
|
||||||
char *uri_sections[10];
|
char *uri_sections[10];
|
||||||
char *whereclause;
|
PARSETREE pt;
|
||||||
void *output_info;
|
void *output_info;
|
||||||
} DBQUERYINFO;
|
} DBQUERYINFO;
|
||||||
|
|
||||||
|
|
60
src/db-sql.c
60
src/db-sql.c
|
@ -233,28 +233,28 @@ int db_sql_parse_smart(char **pe, char **clause, char *phrase) {
|
||||||
*clause = strdup("1");
|
*clause = strdup("1");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pt=sp_init();
|
pt=sp_init();
|
||||||
if(!pt) {
|
if(!pt) {
|
||||||
if(pe) *pe = strdup("Could not initialize parse tree");
|
if(pe) *pe = strdup("Could not initialize parse tree");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!sp_parse(pt,phrase)) {
|
if(!sp_parse(pt,phrase,SP_TYPE_PLAYLIST)) {
|
||||||
if(pe) *pe = strdup(sp_get_error(pt));
|
if(pe) *pe = strdup(sp_get_error(pt));
|
||||||
|
|
||||||
DPRINTF(E_LOG,L_DB,"Error parsing playlist: %s\n",sp_get_error(pt));
|
DPRINTF(E_LOG,L_DB,"Error parsing playlist: %s\n",sp_get_error(pt));
|
||||||
|
|
||||||
sp_dispose(pt);
|
sp_dispose(pt);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
} else {
|
} else {
|
||||||
*clause = sp_sql_clause(pt);
|
*clause = sp_sql_clause(pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
sp_dispose(pt);
|
sp_dispose(pt);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* open sqlite database
|
* open sqlite database
|
||||||
*
|
*
|
||||||
|
@ -620,7 +620,7 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) {
|
||||||
|
|
||||||
|
|
||||||
/* Always an add if in song scan on full reload */
|
/* Always an add if in song scan on full reload */
|
||||||
if((!db_sql_reload)||(!db_sql_in_scan)) {
|
if((!db_sql_reload)||(!db_sql_in_scan)) {
|
||||||
err=db_sql_fetch_int(NULL,&count,"select count(*) from songs where "
|
err=db_sql_fetch_int(NULL,&count,"select count(*) from songs where "
|
||||||
"path='%q'",pmp3->path);
|
"path='%q'",pmp3->path);
|
||||||
|
|
||||||
|
@ -630,7 +630,7 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) {
|
||||||
DPRINTF(E_LOG,L_DB,"Error: %s\n",pe);
|
DPRINTF(E_LOG,L_DB,"Error: %s\n",pe);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pmp3->play_count=0;
|
pmp3->play_count=0;
|
||||||
|
@ -731,7 +731,7 @@ int db_sql_add(char **pe, MP3FILE *pmp3, int *id) {
|
||||||
|
|
||||||
if(id)
|
if(id)
|
||||||
*id = insertid;
|
*id = insertid;
|
||||||
|
|
||||||
DPRINTF(E_SPAM,L_DB,"Exiting db_sql_add\n");
|
DPRINTF(E_SPAM,L_DB,"Exiting db_sql_add\n");
|
||||||
return DB_E_SUCCESS;
|
return DB_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -931,6 +931,7 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
||||||
char query_count[255];
|
char query_count[255];
|
||||||
char query_rest[4096];
|
char query_rest[4096];
|
||||||
char *where_clause;
|
char *where_clause;
|
||||||
|
char *filter;
|
||||||
|
|
||||||
int is_smart;
|
int is_smart;
|
||||||
int have_clause=0;
|
int have_clause=0;
|
||||||
|
@ -980,13 +981,13 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
||||||
if(is_smart) {
|
if(is_smart) {
|
||||||
if(!db_sql_parse_smart(NULL,&where_clause,temprow[1]))
|
if(!db_sql_parse_smart(NULL,&where_clause,temprow[1]))
|
||||||
where_clause = strdup("0");
|
where_clause = strdup("0");
|
||||||
|
|
||||||
if(!where_clause) {
|
if(!where_clause) {
|
||||||
db_sql_enum_end_fn(NULL);
|
db_sql_enum_end_fn(NULL);
|
||||||
db_get_error(pe,DB_E_PARSE);
|
db_get_error(pe,DB_E_PARSE);
|
||||||
return DB_E_PARSE;
|
return DB_E_PARSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(query_select,"select * from songs ");
|
sprintf(query_select,"select * from songs ");
|
||||||
sprintf(query_count,"select count(id) from songs ");
|
sprintf(query_count,"select count(id) from songs ");
|
||||||
sprintf(query_rest,"where (%s)",where_clause);
|
sprintf(query_rest,"where (%s)",where_clause);
|
||||||
|
@ -1048,18 +1049,25 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply the query/filter */
|
/* Apply the query/filter */
|
||||||
if(pinfo->whereclause) {
|
if(pinfo->pt) {
|
||||||
if(have_clause)
|
filter = sp_sql_clause(pinfo->pt);
|
||||||
strcat(query_rest," and ");
|
|
||||||
else
|
|
||||||
strcpy(query_rest," where ");
|
|
||||||
|
|
||||||
strcat(query_rest,"(");
|
if(filter) {
|
||||||
strcat(query_rest,pinfo->whereclause);
|
if(have_clause) {
|
||||||
strcat(query_rest,")");
|
strcat(query_rest," and ");
|
||||||
|
} else {
|
||||||
|
strcpy(query_rest," where ");
|
||||||
|
}
|
||||||
|
strcat(query_rest,"(");
|
||||||
|
|
||||||
|
strcat(query_rest,filter);
|
||||||
|
strcat(query_rest,")");
|
||||||
|
free(filter);
|
||||||
|
} else {
|
||||||
|
DPRINTF(E_LOG,L_DB,"Error getting sql for parse tree\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(pinfo->index_type == indexTypeLast) {
|
if(pinfo->index_type == indexTypeLast) {
|
||||||
/* We don't really care how many items unless we are
|
/* We don't really care how many items unless we are
|
||||||
* doing a "last n items" query */
|
* doing a "last n items" query */
|
||||||
|
@ -1355,14 +1363,14 @@ int db_sql_get_size(DBQUERYINFO *pinfo, SQL_ROW valarray) {
|
||||||
if(ISSTR(valarray[37]) && db_wantsmeta(pinfo->meta, metaSongCodecType))
|
if(ISSTR(valarray[37]) && db_wantsmeta(pinfo->meta, metaSongCodecType))
|
||||||
/* ascd */
|
/* ascd */
|
||||||
size += 12;
|
size += 12;
|
||||||
|
|
||||||
if(db_wantsmeta(pinfo->meta,metaSongContentRating))
|
if(db_wantsmeta(pinfo->meta,metaSongContentRating))
|
||||||
/* ascr */
|
/* ascr */
|
||||||
size += 9;
|
size += 9;
|
||||||
if(db_wantsmeta(pinfo->meta,metaItunesHasVideo))
|
if(db_wantsmeta(pinfo->meta,metaItunesHasVideo))
|
||||||
/* aeHV */
|
/* aeHV */
|
||||||
size += 9;
|
size += 9;
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1596,10 +1604,10 @@ M3UFILE *db_sql_fetch_playlist(char **pe, char *path, int index) {
|
||||||
db_get_error(pe,DB_E_INVALID_PLAYLIST);
|
db_get_error(pe,DB_E_INVALID_PLAYLIST);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL; /* sql error or something */
|
return NULL; /* sql error or something */
|
||||||
}
|
}
|
||||||
|
|
||||||
pm3u=(M3UFILE*)malloc(sizeof(M3UFILE));
|
pm3u=(M3UFILE*)malloc(sizeof(M3UFILE));
|
||||||
if(!pm3u)
|
if(!pm3u)
|
||||||
DPRINTF(E_FATAL,L_MISC,"malloc error: db_sql_fetch_playlist\n");
|
DPRINTF(E_FATAL,L_MISC,"malloc error: db_sql_fetch_playlist\n");
|
||||||
|
@ -1760,7 +1768,7 @@ int db_sql_get_count(char **pe, int *count, CountType_t type) {
|
||||||
*/
|
*/
|
||||||
int db_sql_playcount_increment(char **pe, int id) {
|
int db_sql_playcount_increment(char **pe, int id) {
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
|
||||||
return db_sql_exec_fn(pe,E_INF,"update songs set play_count=play_count + 1"
|
return db_sql_exec_fn(pe,E_INF,"update songs set play_count=play_count + 1"
|
||||||
", time_played=%d where id=%d",now,id);
|
", time_played=%d where id=%d",now,id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ int daap_auth(char *username, char *password) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(strcasecmp(password,readpassword)) {
|
if(strcasecmp(password,readpassword)) {
|
||||||
DPRINTF(E_LOG,L_DAAP | L_WS,"Bad password attempt\n");
|
DPRINTF(E_LOG,L_DAAP | L_WS,"Bad password attempt\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,13 +152,20 @@ void daap_handler(WS_CONNINFO *pwsc) {
|
||||||
|
|
||||||
memset(pqi,0x00,sizeof(DBQUERYINFO));
|
memset(pqi,0x00,sizeof(DBQUERYINFO));
|
||||||
|
|
||||||
|
/* we could really pre-parse this to make sure it works */
|
||||||
query=ws_getvar(pwsc,"query");
|
query=ws_getvar(pwsc,"query");
|
||||||
if(!query) query=ws_getvar(pwsc,"filter");
|
if(!query) query=ws_getvar(pwsc,"filter");
|
||||||
if(query) {
|
if(query) {
|
||||||
DPRINTF(E_DBG,L_DAAP,"Getting sql clause for %s\n",query);
|
pqi->pt = sp_init();
|
||||||
pqi->whereclause = query_build_sql(query);
|
if(!sp_parse(&pqi->pt,query,SP_TYPE_QUERY)) {
|
||||||
|
DPRINTF(E_LOG,L_DAAP,"Ignoring bad query/filter (%s): %s\n",
|
||||||
|
query,sp_get_error(pqi->pt));
|
||||||
|
sp_dispose(pqi->pt);
|
||||||
|
pqi->pt = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add some default headers */
|
/* Add some default headers */
|
||||||
ws_addresponseheader(pwsc,"Accept-Ranges","bytes");
|
ws_addresponseheader(pwsc,"Accept-Ranges","bytes");
|
||||||
ws_addresponseheader(pwsc,"DAAP-Server","mt-daapd/" VERSION);
|
ws_addresponseheader(pwsc,"DAAP-Server","mt-daapd/" VERSION);
|
||||||
|
|
|
@ -11,19 +11,23 @@
|
||||||
#include "smart-parser.h"
|
#include "smart-parser.h"
|
||||||
|
|
||||||
void usage(void) {
|
void usage(void) {
|
||||||
printf("Usage:\n\n parser [-d <debug level>] \"phrase\"\n\n");
|
printf("Usage:\n\n parser [-t <type (0/1)>] [-d <debug level>] \"phrase\"\n\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int option;
|
int option;
|
||||||
|
int type=0;
|
||||||
PARSETREE pt;
|
PARSETREE pt;
|
||||||
|
|
||||||
while((option = getopt(argc, argv, "d:")) != -1) {
|
while((option = getopt(argc, argv, "d:t:")) != -1) {
|
||||||
switch(option) {
|
switch(option) {
|
||||||
case 'd':
|
case 'd':
|
||||||
err_setlevel(atoi(optarg));
|
err_setlevel(atoi(optarg));
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
type = atoi(optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr,"Error: unknown option (%c)\n\n",option);
|
fprintf(stderr,"Error: unknown option (%c)\n\n",option);
|
||||||
usage();
|
usage();
|
||||||
|
@ -34,7 +38,7 @@ int main(int argc, char *argv[]) {
|
||||||
printf("Parsing %s\n",argv[optind]);
|
printf("Parsing %s\n",argv[optind]);
|
||||||
|
|
||||||
pt=sp_init();
|
pt=sp_init();
|
||||||
if(!sp_parse(pt,argv[optind])) {
|
if(!sp_parse(pt,argv[optind],type)) {
|
||||||
printf("%s\n",sp_get_error(pt));
|
printf("%s\n",sp_get_error(pt));
|
||||||
} else {
|
} else {
|
||||||
printf("SQL: %s\n",sp_sql_clause(pt));
|
printf("SQL: %s\n",sp_sql_clause(pt));
|
||||||
|
|
|
@ -147,6 +147,10 @@ typedef struct tag_sp_node {
|
||||||
#define T_ENDSWITH 0x001d
|
#define T_ENDSWITH 0x001d
|
||||||
#define T_LAST 0x001e
|
#define T_LAST 0x001e
|
||||||
|
|
||||||
|
/* specific to query extensions */
|
||||||
|
#define T_GREATERAND 0x001f
|
||||||
|
#define T_EXPRQUOTE 0x0020
|
||||||
|
|
||||||
#define T_EOF 0x00fd
|
#define T_EOF 0x00fd
|
||||||
#define T_BOF 0x00fe
|
#define T_BOF 0x00fe
|
||||||
#define T_ERROR 0x00ff
|
#define T_ERROR 0x00ff
|
||||||
|
@ -211,6 +215,15 @@ FIELDLOOKUP sp_symbols_0[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
FIELDLOOKUP sp_symbols_1[] = {
|
FIELDLOOKUP sp_symbols_1[] = {
|
||||||
|
{ T_OPENPAREN, "(", NULL },
|
||||||
|
{ T_CLOSEPAREN, ")", NULL },
|
||||||
|
{ T_EXPRQUOTE, "'", NULL },
|
||||||
|
{ T_GREATERAND, "+", NULL },
|
||||||
|
{ T_GREATERAND, " ", NULL },
|
||||||
|
{ T_LESS,"-", NULL },
|
||||||
|
{ T_OR, ",", NULL },
|
||||||
|
{ T_EQUAL, ":", NULL },
|
||||||
|
{ T_NOT, "!", NULL },
|
||||||
{ 0, NULL, NULL }
|
{ 0, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -283,31 +296,31 @@ FIELDLOOKUP sp_fields_0[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
FIELDLOOKUP sp_fields_1[] = {
|
FIELDLOOKUP sp_fields_1[] = {
|
||||||
{ T_STRING_FIELD, "dmap.itemname", "title" },
|
{ T_STRING_FIELD, "dmap.itemname", "title" },
|
||||||
{ T_INT_FIELD, "dmap.itemid", "id" },
|
{ T_INT_FIELD, "dmap.itemid", "id" },
|
||||||
{ T_STRING_FIELD, "daap.songalbum", "album" },
|
{ T_STRING_FIELD, "daap.songalbum", "album" },
|
||||||
{ T_STRING_FIELD, "daap.songartist", "artist" },
|
{ T_STRING_FIELD, "daap.songartist", "artist" },
|
||||||
{ T_INT_FIELD, "daap.songbitrate", "bitrate" },
|
{ T_INT_FIELD, "daap.songbitrate", "bitrate" },
|
||||||
{ T_STRING_FIELD, "daap.songcomment", "comment" },
|
{ T_STRING_FIELD, "daap.songcomment", "comment" },
|
||||||
{ T_INT_FIELD, "daap.songcompilation", "compilation" },
|
{ T_INT_FIELD, "daap.songcompilation", "compilation" },
|
||||||
{ T_STRING_FIELD, "daap.songcomposer", "composer" },
|
{ T_STRING_FIELD, "daap.songcomposer", "composer" },
|
||||||
{ T_INT_FIELD, "daap.songdatakind", "data_kind" },
|
{ T_INT_FIELD, "daap.songdatakind", "data_kind" },
|
||||||
{ T_STRING_FIELD, "daap.songdataurl", "url" },
|
{ T_STRING_FIELD, "daap.songdataurl", "url" },
|
||||||
{ T_INT_FIELD, "daap.songdateadded", "time_added" },
|
{ T_INT_FIELD, "daap.songdateadded", "time_added" },
|
||||||
{ T_INT_FIELD, "daap.songdatemodified","time_modified" },
|
{ T_INT_FIELD, "daap.songdatemodified", "time_modified" },
|
||||||
{ T_STRING_FIELD, "daap.songdescription", "description" },
|
{ T_STRING_FIELD, "daap.songdescription", "description" },
|
||||||
{ T_INT_FIELD, "daap.songdisccount", "total_discs" },
|
{ T_INT_FIELD, "daap.songdisccount", "total_discs" },
|
||||||
{ T_INT_FIELD, "daap.songdiscnumber", "disc" },
|
{ T_INT_FIELD, "daap.songdiscnumber", "disc" },
|
||||||
{ T_STRING_FIELD, "daap.songformat", "type" },
|
{ T_STRING_FIELD, "daap.songformat", "type" },
|
||||||
{ T_STRING_FIELD, "daap.songgenre", "genre" },
|
{ T_STRING_FIELD, "daap.songgenre", "genre" },
|
||||||
{ T_INT_FIELD, "daap.songsamplerate", "samplerate" },
|
{ T_INT_FIELD, "daap.songsamplerate", "samplerate" },
|
||||||
{ T_INT_FIELD, "daap.songsize", "file_size" },
|
{ T_INT_FIELD, "daap.songsize", "file_size" },
|
||||||
// { T_INT_FIELD, "daap.songstarttime", 0 },
|
// { T_INT_FIELD, "daap.songstarttime", 0 },
|
||||||
{ T_INT_FIELD, "daap.songstoptime", "song_length" },
|
{ T_INT_FIELD, "daap.songstoptime", "song_length" },
|
||||||
{ T_INT_FIELD, "daap.songtime", "song_length" },
|
{ T_INT_FIELD, "daap.songtime", "song_length" },
|
||||||
{ T_INT_FIELD, "daap.songtrackcount", "total_tracks" },
|
{ T_INT_FIELD, "daap.songtrackcount", "total_tracks" },
|
||||||
{ T_INT_FIELD, "daap.songtracknumber", "track" },
|
{ T_INT_FIELD, "daap.songtracknumber", "track" },
|
||||||
{ T_INT_FIELD, "daap.songyear", "year" },
|
{ T_INT_FIELD, "daap.songyear", "year" },
|
||||||
|
|
||||||
{ 0, NULL, NULL }
|
{ 0, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
@ -341,6 +354,7 @@ typedef struct tag_parsetree {
|
||||||
#define SP_E_BEFOREAFTER 0x0a
|
#define SP_E_BEFOREAFTER 0x0a
|
||||||
#define SP_E_TIMEINTERVAL 0x0b
|
#define SP_E_TIMEINTERVAL 0x0b
|
||||||
#define SP_E_DATE 0x0c
|
#define SP_E_DATE 0x0c
|
||||||
|
#define SP_E_EXPRQUOTE 0x0d
|
||||||
|
|
||||||
char *sp_errorstrings[] = {
|
char *sp_errorstrings[] = {
|
||||||
"Success",
|
"Success",
|
||||||
|
@ -355,7 +369,8 @@ char *sp_errorstrings[] = {
|
||||||
"Expecting date comparison operator (<,<=,>,>=)",
|
"Expecting date comparison operator (<,<=,>,>=)",
|
||||||
"Expecting interval comparison (before, after)",
|
"Expecting interval comparison (before, after)",
|
||||||
"Expecting time interval (days, weeks, months, years)",
|
"Expecting time interval (days, weeks, months, years)",
|
||||||
"Expecting date"
|
"Expecting date",
|
||||||
|
"Expecting ' (single quote)\n"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Forwards */
|
/* Forwards */
|
||||||
|
@ -431,7 +446,10 @@ time_t sp_isdate(char *string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scan the input, returning the next available token.
|
* scan the input, returning the next available token. This is
|
||||||
|
* kind of a mess, and looking at it with new eyes would probably
|
||||||
|
* yield a better way of tokenizing the stream, but this seems to
|
||||||
|
* work.
|
||||||
*
|
*
|
||||||
* @param tree current working parse tree.
|
* @param tree current working parse tree.
|
||||||
* @returns next token (token, not the value)
|
* @returns next token (token, not the value)
|
||||||
|
@ -446,6 +464,7 @@ int sp_scan(PARSETREE tree, int hint) {
|
||||||
int is_qstr;
|
int is_qstr;
|
||||||
time_t tval;
|
time_t tval;
|
||||||
char *qstr;
|
char *qstr;
|
||||||
|
char *token_string;
|
||||||
|
|
||||||
if(tree->token.token_id & 0x2000) {
|
if(tree->token.token_id & 0x2000) {
|
||||||
if(tree->token.data.cvalue)
|
if(tree->token.data.cvalue)
|
||||||
|
@ -483,7 +502,7 @@ int sp_scan(PARSETREE tree, int hint) {
|
||||||
|
|
||||||
|
|
||||||
DPRINTF(E_SPAM,L_PARSE,"Starting scan - in_string: %d, hint: %d\n",
|
DPRINTF(E_SPAM,L_PARSE,"Starting scan - in_string: %d, hint: %d\n",
|
||||||
tree->in_string, hint);
|
tree->in_string, hint);
|
||||||
|
|
||||||
/* check symbols */
|
/* check symbols */
|
||||||
if(!tree->in_string) {
|
if(!tree->in_string) {
|
||||||
|
@ -501,17 +520,21 @@ int sp_scan(PARSETREE tree, int hint) {
|
||||||
|
|
||||||
qstr = sp_terminators[tree->token_list][3];
|
qstr = sp_terminators[tree->token_list][3];
|
||||||
is_qstr = (strchr(qstr,*(tree->current)) != NULL);
|
is_qstr = (strchr(qstr,*(tree->current)) != NULL);
|
||||||
|
|
||||||
|
DPRINTF(E_SPAM,L_PARSE,"qstr: %s -- is_quoted: %d\n",qstr,is_qstr);
|
||||||
|
|
||||||
if(strlen(qstr)) { /* strings ARE quoted */
|
if(strlen(qstr)) { /* strings ARE quoted */
|
||||||
if(hint == SP_HINT_STRING) { /* MUST be a quote */
|
if(hint == SP_HINT_STRING) { /* MUST be a quote */
|
||||||
if(!is_qstr) {
|
if(!is_qstr) {
|
||||||
|
tree->token.token_id = T_ERROR;
|
||||||
return T_ERROR;
|
return T_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(is_qstr) {
|
if(is_qstr) {
|
||||||
tree->in_string = 1; /* guess we're in a string */
|
tree->in_string = 1; /* guess we're in a string */
|
||||||
terminator=sp_terminators[tree->token_list][1];
|
terminator=sp_terminators[tree->token_list][1];
|
||||||
tree->current++;
|
tree->current++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,7 +557,7 @@ int sp_scan(PARSETREE tree, int hint) {
|
||||||
/* find it in the token list */
|
/* find it in the token list */
|
||||||
pfield=sp_fields[tree->token_list];
|
pfield=sp_fields[tree->token_list];
|
||||||
while(pfield->name) {
|
while(pfield->name) {
|
||||||
DPRINTF(E_SPAM,L_PARSE,"Comparing to %s\n",pfield->name);
|
DPRINTF(E_SPAM,L_PARSE,"Comparing to %s\n",pfield->name);
|
||||||
if(strlen(pfield->name) == len) {
|
if(strlen(pfield->name) == len) {
|
||||||
if(strncasecmp(pfield->name,tree->current,len) == 0) {
|
if(strncasecmp(pfield->name,tree->current,len) == 0) {
|
||||||
found=1;
|
found=1;
|
||||||
|
@ -552,12 +575,20 @@ int sp_scan(PARSETREE tree, int hint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tree->token.token_id & 0x2000) {
|
if(tree->token.token_id & 0x2000) {
|
||||||
|
token_string=tree->current;
|
||||||
|
if(found) {
|
||||||
|
if(pfield->xlat) {
|
||||||
|
len = strlen(pfield->xlat);
|
||||||
|
token_string = pfield->xlat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tree->token.data.cvalue = malloc(len + 1);
|
tree->token.data.cvalue = malloc(len + 1);
|
||||||
if(!tree->token.data.cvalue) {
|
if(!tree->token.data.cvalue) {
|
||||||
/* fail on malloc error */
|
/* fail on malloc error */
|
||||||
DPRINTF(E_FATAL,L_PARSE,"Malloc error.\n");
|
DPRINTF(E_FATAL,L_PARSE,"Malloc error.\n");
|
||||||
}
|
}
|
||||||
strncpy(tree->token.data.cvalue,tree->current,len);
|
strncpy(tree->token.data.cvalue,token_string,len);
|
||||||
tree->token.data.cvalue[len] = '\x0';
|
tree->token.data.cvalue[len] = '\x0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,15 +622,15 @@ int sp_scan(PARSETREE tree, int hint) {
|
||||||
|
|
||||||
is_qstr = (strchr(qstr,*tree->current) != NULL);
|
is_qstr = (strchr(qstr,*tree->current) != NULL);
|
||||||
if((!found) && strlen(qstr) && (tree->in_string)) {
|
if((!found) && strlen(qstr) && (tree->in_string)) {
|
||||||
if(is_qstr) {
|
if(is_qstr) {
|
||||||
tree->current++; /* absorb it */
|
tree->current++; /* absorb it */
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(E_INF,L_PARSE,"Missing closing quotes\n");
|
DPRINTF(E_INF,L_PARSE,"Missing closing quotes\n");
|
||||||
if(tree->token.token_id & 0x2000) {
|
if(tree->token.token_id & 0x2000) {
|
||||||
free(tree->token.data.cvalue);
|
free(tree->token.data.cvalue);
|
||||||
}
|
}
|
||||||
tree->token.token_id = T_ERROR;
|
tree->token.token_id = T_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_PARSE,"%*s Returning token %04x\n",tree->level," ",
|
DPRINTF(E_DBG,L_PARSE,"%*s Returning token %04x\n",tree->level," ",
|
||||||
|
@ -652,10 +683,11 @@ PARSETREE sp_init(void) {
|
||||||
* @param term term or phrase to parse
|
* @param term term or phrase to parse
|
||||||
* @returns 1 if successful, 0 if not
|
* @returns 1 if successful, 0 if not
|
||||||
*/
|
*/
|
||||||
int sp_parse(PARSETREE tree, char *term) {
|
int sp_parse(PARSETREE tree, char *term, int type) {
|
||||||
tree->term = strdup(term); /* will be destroyed by parsing */
|
tree->term = strdup(term); /* will be destroyed by parsing */
|
||||||
tree->current=tree->term;
|
tree->current=tree->term;
|
||||||
tree->token.token_id=T_BOF;
|
tree->token.token_id=T_BOF;
|
||||||
|
tree->token_list = type;
|
||||||
|
|
||||||
if(tree->tree)
|
if(tree->tree)
|
||||||
sp_free_node(tree->tree);
|
sp_free_node(tree->tree);
|
||||||
|
@ -716,7 +748,8 @@ SP_NODE *sp_parse_aexpr(PARSETREE tree) {
|
||||||
|
|
||||||
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) ||
|
||||||
|
(tree->token.token_id == T_GREATERAND))) {
|
||||||
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");
|
||||||
|
@ -829,6 +862,15 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||||
|
|
||||||
sp_enter_exit(tree,"sp_parse_criterion",1,expr);
|
sp_enter_exit(tree,"sp_parse_criterion",1,expr);
|
||||||
|
|
||||||
|
if(tree->token_list == 1) {
|
||||||
|
if(tree->token.token_id != T_EXPRQUOTE) {
|
||||||
|
sp_set_error(tree,SP_E_EXPRQUOTE);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
sp_scan(tree,SP_HINT_NONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
@ -849,6 +891,16 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(tree->token_list == 1) {
|
||||||
|
if(tree->token.token_id != T_EXPRQUOTE) {
|
||||||
|
sp_set_error(tree,SP_E_EXPRQUOTE);
|
||||||
|
sp_free_node(expr);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
sp_scan(tree,SP_HINT_NONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sp_enter_exit(tree,"sp_parse_criterion",0,expr);
|
sp_enter_exit(tree,"sp_parse_criterion",0,expr);
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
@ -872,7 +924,7 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||||
memset(pnew,0x00,sizeof(SP_NODE));
|
memset(pnew,0x00,sizeof(SP_NODE));
|
||||||
pnew->left.field = strdup(tree->token.data.cvalue);
|
pnew->left.field = strdup(tree->token.data.cvalue);
|
||||||
|
|
||||||
sp_scan(tree,SP_HINT_NONE);/* 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) {
|
if(tree->token.token_id == T_NOT) {
|
||||||
pnew->not_flag=1;
|
pnew->not_flag=1;
|
||||||
|
@ -895,11 +947,22 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result) {
|
if(result) {
|
||||||
sp_scan(tree,SP_HINT_NONE);
|
sp_scan(tree,SP_HINT_STRING);
|
||||||
/* should be sitting on string literal */
|
/* should be sitting on string literal */
|
||||||
if(tree->token.token_id == T_STRING) {
|
if(tree->token.token_id == T_STRING) {
|
||||||
result = 1;
|
result = 1;
|
||||||
pnew->right.cvalue=strdup(tree->token.data.cvalue);
|
pnew->right.cvalue=strdup(tree->token.data.cvalue);
|
||||||
|
if(tree->token_list == 1) {
|
||||||
|
if(pnew->right.cvalue[0]=='*') {
|
||||||
|
pnew->op = T_ENDSWITH;
|
||||||
|
memcpy(pnew->right.cvalue,&pnew->right.cvalue[1],
|
||||||
|
(int)strlen(pnew->right.cvalue)); /* with zt */
|
||||||
|
}
|
||||||
|
if(pnew->right.cvalue[strlen(pnew->right.cvalue)-1] == '*') {
|
||||||
|
pnew->op = (pnew->op==T_ENDSWITH)?T_INCLUDES:T_STARTSWITH;
|
||||||
|
pnew->right.cvalue[strlen(pnew->right.cvalue)-1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
sp_scan(tree,SP_HINT_NONE);
|
sp_scan(tree,SP_HINT_NONE);
|
||||||
} else {
|
} else {
|
||||||
sp_set_error(tree,SP_E_OPENQUOTE);
|
sp_set_error(tree,SP_E_OPENQUOTE);
|
||||||
|
@ -954,6 +1017,11 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||||
pnew->op=tree->token.token_id;
|
pnew->op=tree->token.token_id;
|
||||||
pnew->op_type = SP_OPTYPE_INT;
|
pnew->op_type = SP_OPTYPE_INT;
|
||||||
break;
|
break;
|
||||||
|
case T_GREATERAND:
|
||||||
|
result = 1;
|
||||||
|
pnew->op = T_GREATER;
|
||||||
|
pnew->op_type = SP_OPTYPE_INT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* Error: expecting legal int comparison operator */
|
/* Error: expecting legal int comparison operator */
|
||||||
sp_set_error(tree,SP_E_INTCMP);
|
sp_set_error(tree,SP_E_INTCMP);
|
||||||
|
@ -963,7 +1031,7 @@ SP_NODE *sp_parse_criterion(PARSETREE tree) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result) {
|
if(result) {
|
||||||
sp_scan(tree,SP_HINT_NONE);
|
sp_scan(tree,SP_HINT_INT);
|
||||||
/* should be sitting on a literal string */
|
/* should be sitting on a literal string */
|
||||||
if(tree->token.token_id == T_NUMBER) {
|
if(tree->token.token_id == T_NUMBER) {
|
||||||
result = 1;
|
result = 1;
|
||||||
|
@ -1023,6 +1091,11 @@ SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
|
||||||
pnew->op=tree->token.token_id;
|
pnew->op=tree->token.token_id;
|
||||||
pnew->op_type = SP_OPTYPE_DATE;
|
pnew->op_type = SP_OPTYPE_DATE;
|
||||||
break;
|
break;
|
||||||
|
case T_GREATERAND:
|
||||||
|
result = 1;
|
||||||
|
pnew->op=T_GREATER;
|
||||||
|
pnew->op_type = SP_OPTYPE_DATE;
|
||||||
|
break;
|
||||||
case T_BEFORE:
|
case T_BEFORE:
|
||||||
result = 1;
|
result = 1;
|
||||||
pnew->op_type = SP_OPTYPE_DATE;
|
pnew->op_type = SP_OPTYPE_DATE;
|
||||||
|
@ -1042,7 +1115,7 @@ SP_NODE *sp_parse_date_criterion(PARSETREE tree) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result) {
|
if(result) {
|
||||||
sp_scan(tree,SP_HINT_NONE);
|
sp_scan(tree,SP_HINT_DATE);
|
||||||
/* should be sitting on a date */
|
/* should be sitting on a date */
|
||||||
if((pnew->right.tvalue = sp_parse_date(tree))) {
|
if((pnew->right.tvalue = sp_parse_date(tree))) {
|
||||||
result=1;
|
result=1;
|
||||||
|
|
|
@ -8,10 +8,13 @@
|
||||||
typedef void* PARSETREE;
|
typedef void* PARSETREE;
|
||||||
|
|
||||||
extern PARSETREE sp_init(void);
|
extern PARSETREE sp_init(void);
|
||||||
extern int sp_parse(PARSETREE *tree, char *term);
|
extern int sp_parse(PARSETREE *tree, char *term, int type);
|
||||||
extern int sp_dispose(PARSETREE tree);
|
extern int sp_dispose(PARSETREE tree);
|
||||||
extern char *sp_get_error(PARSETREE tree);
|
extern char *sp_get_error(PARSETREE tree);
|
||||||
extern char *sp_sql_clause(PARSETREE tree);
|
extern char *sp_sql_clause(PARSETREE tree);
|
||||||
|
|
||||||
|
#define SP_TYPE_PLAYLIST 0
|
||||||
|
#define SP_TYPE_QUERY 1
|
||||||
|
|
||||||
#endif /* _SMART_PARSER_H_ */
|
#endif /* _SMART_PARSER_H_ */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue