forked from len0rd/rockbox
Search engine core for database v2, has an hardcoded "songs for year >= 1980 and year < 1990" at the moment.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6367 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
a7f7781dca
commit
9369d4867d
12 changed files with 738 additions and 2 deletions
|
|
@ -45,6 +45,7 @@
|
||||||
#include "powermgmt.h"
|
#include "powermgmt.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
|
#include "database.h"
|
||||||
#if (CONFIG_HWCODEC == MASNONE)
|
#if (CONFIG_HWCODEC == MASNONE)
|
||||||
#include "pcm_playback.h"
|
#include "pcm_playback.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -319,6 +320,11 @@ static const struct plugin_api rockbox_api = {
|
||||||
#ifdef HAVE_LCD_BITMAP
|
#ifdef HAVE_LCD_BITMAP
|
||||||
read_bmp_file,
|
read_bmp_file,
|
||||||
#endif
|
#endif
|
||||||
|
&tagdbheader,
|
||||||
|
&tagdb_fd,
|
||||||
|
&tagdb_initialized,
|
||||||
|
tagdb_init,
|
||||||
|
strcasestr,
|
||||||
};
|
};
|
||||||
|
|
||||||
int plugin_load(const char* plugin, void* parameter)
|
int plugin_load(const char* plugin, void* parameter)
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* increase this every time the api struct changes */
|
/* increase this every time the api struct changes */
|
||||||
#define PLUGIN_API_VERSION 38
|
#define PLUGIN_API_VERSION 39
|
||||||
|
|
||||||
/* update this to latest version if a change to the api struct breaks
|
/* update this to latest version if a change to the api struct breaks
|
||||||
backwards compatibility (and please take the opportunity to sort in any
|
backwards compatibility (and please take the opportunity to sort in any
|
||||||
|
|
@ -375,6 +375,11 @@ struct plugin_api {
|
||||||
int (*read_bmp_file)(char* filename, int *get_width, int *get_height,
|
int (*read_bmp_file)(char* filename, int *get_width, int *get_height,
|
||||||
char *bitmap, int maxsize);
|
char *bitmap, int maxsize);
|
||||||
#endif
|
#endif
|
||||||
|
struct tagdb_header *tagdbheader;
|
||||||
|
int *tagdb_fd;
|
||||||
|
int *tagdb_initialized;
|
||||||
|
int (*tagdb_init) (void);
|
||||||
|
char *(*strcasestr) (const char* phaystack, const char* pneedle);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* defined by the plugin loader (plugin.c) */
|
/* defined by the plugin loader (plugin.c) */
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ DIRS = .
|
||||||
|
|
||||||
#for any recorder and iRiver model
|
#for any recorder and iRiver model
|
||||||
ifneq (,$(strip $(foreach tgt,RECORDER IRIVER,$(findstring $(tgt),$(TARGET)))))
|
ifneq (,$(strip $(foreach tgt,RECORDER IRIVER,$(findstring $(tgt),$(TARGET)))))
|
||||||
SUBDIRS += rockboy
|
SUBDIRS += rockboy searchengine
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: $(SUBDIRS)
|
.PHONY: $(SUBDIRS)
|
||||||
|
|
|
||||||
105
apps/plugins/searchengine/Makefile
Normal file
105
apps/plugins/searchengine/Makefile
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
# __________ __ ___.
|
||||||
|
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
# \/ \/ \/ \/ \/
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
|
||||||
|
INCLUDES = -I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \
|
||||||
|
-I$(FIRMDIR)/common -I$(FIRMDIR)/drivers
|
||||||
|
CFLAGS = $(GCCOPTS) -O3 $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) \
|
||||||
|
-DMEM=${MEMORYSIZE} -DPLUGIN
|
||||||
|
|
||||||
|
ifdef APPEXTRA
|
||||||
|
INCLUDES += -I$(APPSDIR)/$(APPEXTRA)
|
||||||
|
endif
|
||||||
|
|
||||||
|
LINKFILE := $(OBJDIR)/link.lds
|
||||||
|
DEPFILE = $(OBJDIR)/dep-searchengine
|
||||||
|
SRC = searchengine.c parser.c token.c dbinterface.c
|
||||||
|
|
||||||
|
SOURCES = $(SRC)
|
||||||
|
OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
|
||||||
|
DIRS = .
|
||||||
|
|
||||||
|
|
||||||
|
ifndef SIMVER
|
||||||
|
ifneq (,$(findstring RECORDER,$(TARGET))) ## Archos recorder targets
|
||||||
|
OUTPUT = $(OUTDIR)/searchengine.rock
|
||||||
|
else ## iRiver target
|
||||||
|
LDS := ../plugin.lds
|
||||||
|
OUTPUT = $(OUTDIR)/searchengine.rock
|
||||||
|
endif
|
||||||
|
else ## simulators
|
||||||
|
OUTPUT = $(OUTDIR)/searchengine.rock
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(OUTPUT)
|
||||||
|
|
||||||
|
ifndef SIMVER
|
||||||
|
$(OBJDIR)/searchengine.elf: $(OBJS) $(LINKFILE) $(OUTDIR)/libplugin.a
|
||||||
|
@echo "LD $@"
|
||||||
|
@$(CC) $(GCCOPTS) -O -nostdlib -o $@ $(OBJS) -L$(OUTDIR) -lplugin -lgcc \
|
||||||
|
-T$(LINKFILE) -Wl,-Map,$(OBJDIR)/searchengine.map
|
||||||
|
|
||||||
|
$(OUTPUT): $(OBJDIR)/searchengine.elf
|
||||||
|
@echo "OBJCOPY $<"
|
||||||
|
@$(OC) -O binary $< $@
|
||||||
|
else
|
||||||
|
|
||||||
|
ifeq ($(SIMVER), x11)
|
||||||
|
###################################################
|
||||||
|
# This is the X11 simulator version
|
||||||
|
|
||||||
|
$(OUTPUT): $(OBJS) $(OUTDIR)/libplugin.a
|
||||||
|
@echo "LD $@"
|
||||||
|
@$(CC) $(CFLAGS) -shared $(OBJS) -L$(OUTDIR) -lplugin -o $@
|
||||||
|
ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
|
||||||
|
# 'x' must be kept or you'll have "Win32 error 5"
|
||||||
|
# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
|
||||||
|
# #define ERROR_ACCESS_DENIED 5L
|
||||||
|
else
|
||||||
|
@chmod -x $@
|
||||||
|
endif
|
||||||
|
|
||||||
|
else # end of x11-simulator
|
||||||
|
###################################################
|
||||||
|
# This is the win32 simulator version
|
||||||
|
DLLTOOLFLAGS = --export-all
|
||||||
|
DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin
|
||||||
|
|
||||||
|
$(OUTPUT): $(OBJS) $(OUTDIR)/libplugin.a
|
||||||
|
@echo "DLL $@"
|
||||||
|
@$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS)
|
||||||
|
@$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \
|
||||||
|
$(OUTDIR)/libplugin.a -o $@
|
||||||
|
ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
|
||||||
|
# 'x' must be kept or you'll have "Win32 error 5"
|
||||||
|
# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
|
||||||
|
# #define ERROR_ACCESS_DENIED 5L
|
||||||
|
else
|
||||||
|
@chmod -x $@
|
||||||
|
endif
|
||||||
|
endif # end of win32-simulator
|
||||||
|
|
||||||
|
endif # end of simulator section
|
||||||
|
|
||||||
|
|
||||||
|
include $(TOOLSDIR)/make.inc
|
||||||
|
|
||||||
|
# MEM should be passed on to this makefile with the chosen memory size given
|
||||||
|
# in number of MB
|
||||||
|
$(LINKFILE): $(LDS)
|
||||||
|
@echo "build $@"
|
||||||
|
@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) \
|
||||||
|
-E -P - >$@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo "cleaning searchengine"
|
||||||
|
@rm -rf $(OBJDIR)/searchengine
|
||||||
|
@rm -f $(OBJDIR)/searchengine.* $(DEPFILE)
|
||||||
|
|
||||||
|
-include $(DEPFILE)
|
||||||
|
|
||||||
97
apps/plugins/searchengine/dbinterface.c
Normal file
97
apps/plugins/searchengine/dbinterface.c
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include "searchengine.h"
|
||||||
|
#include "dbinterface.h"
|
||||||
|
|
||||||
|
#undef SONGENTRY_SIZE
|
||||||
|
#undef FILEENTRY_SIZE
|
||||||
|
#undef ALBUMENTRY_SIZE
|
||||||
|
#undef ARTISTENTRY_SIZE
|
||||||
|
#undef FILERECORD2OFFSET
|
||||||
|
|
||||||
|
#define SONGENTRY_SIZE (rb->tagdbheader->songlen+12+rb->tagdbheader->genrelen+4)
|
||||||
|
#define FILEENTRY_SIZE (rb->tagdbheader->filelen+12)
|
||||||
|
#define ALBUMENTRY_SIZE (rb->tagdbheader->albumlen+4+rb->tagdbheader->songarraylen*4)
|
||||||
|
#define ARTISTENTRY_SIZE (rb->tagdbheader->artistlen+rb->tagdbheader->albumarraylen*4)
|
||||||
|
|
||||||
|
#define FILERECORD2OFFSET(_x_) (rb->tagdbheader->filestart + _x_ * FILEENTRY_SIZE)
|
||||||
|
|
||||||
|
struct entry *currententry;
|
||||||
|
|
||||||
|
static struct entry *entryarray;
|
||||||
|
|
||||||
|
int database_init() {
|
||||||
|
char *p;
|
||||||
|
unsigned int i;
|
||||||
|
// allocate room for all entries
|
||||||
|
entryarray=(struct entry *)my_malloc(sizeof(struct entry)*rb->tagdbheader->filecount);
|
||||||
|
p=(char *)entryarray;
|
||||||
|
// zero all entries.
|
||||||
|
for(i=0;i<sizeof(struct entry)*rb->tagdbheader->filecount;i++)
|
||||||
|
*(p++)=0;
|
||||||
|
if(*rb->tagdb_initialized!=1) {
|
||||||
|
if(!rb->tagdb_init()) {
|
||||||
|
// failed loading db
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadentry(int filerecord) {
|
||||||
|
if(entryarray[filerecord].loadedfiledata==0) {
|
||||||
|
rb->lseek(*rb->tagdb_fd,FILERECORD2OFFSET(filerecord),SEEK_SET);
|
||||||
|
entryarray[filerecord].filename=(char *)my_malloc(rb->tagdbheader->filelen);
|
||||||
|
rb->read(*rb->tagdb_fd,entryarray[filerecord].filename,rb->tagdbheader->filelen);
|
||||||
|
rb->read(*rb->tagdb_fd,&entryarray[filerecord].hash,4);
|
||||||
|
rb->read(*rb->tagdb_fd,&entryarray[filerecord].songentry,4);
|
||||||
|
rb->read(*rb->tagdb_fd,&entryarray[filerecord].rundbentry,4);
|
||||||
|
entryarray[filerecord].loadedfiledata=1;
|
||||||
|
}
|
||||||
|
currententry=&entryarray[filerecord];
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadsongdata() {
|
||||||
|
if(currententry->loadedsongdata ||
|
||||||
|
!currententry->loadedfiledata)
|
||||||
|
return;
|
||||||
|
currententry->title=(char *)my_malloc(rb->tagdbheader->songlen);
|
||||||
|
currententry->genre=(char *)my_malloc(rb->tagdbheader->genrelen);
|
||||||
|
rb->lseek(*rb->tagdb_fd,currententry->songentry,SEEK_SET);
|
||||||
|
rb->read(*rb->tagdb_fd,currententry->title,rb->tagdbheader->songlen);
|
||||||
|
rb->read(*rb->tagdb_fd,¤tentry->artistoffset,4);
|
||||||
|
rb->read(*rb->tagdb_fd,¤tentry->albumoffset,4);
|
||||||
|
rb->lseek(*rb->tagdb_fd,4,SEEK_CUR);
|
||||||
|
rb->read(*rb->tagdb_fd,currententry->genre,rb->tagdbheader->genrelen);
|
||||||
|
rb->read(*rb->tagdb_fd,¤tentry->bitrate,2);
|
||||||
|
rb->read(*rb->tagdb_fd,¤tentry->year,2);
|
||||||
|
currententry->loadedsongdata=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadrundbdata() {
|
||||||
|
// we don't do this yet.
|
||||||
|
currententry->loadedrundbdata=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadartistname() {
|
||||||
|
/* memory optimization possible, only malloc for an album name once, then
|
||||||
|
* write that pointer to the entrys using it.
|
||||||
|
*/
|
||||||
|
currententry->artistname=(char *)my_malloc(rb->tagdbheader->artistlen);
|
||||||
|
rb->lseek(*rb->tagdb_fd,currententry->artistoffset,SEEK_SET);
|
||||||
|
rb->read(*rb->tagdb_fd,currententry->artistname,rb->tagdbheader->artistlen);
|
||||||
|
currententry->loadedartistname=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadalbumname() {
|
||||||
|
/* see the note at loadartistname */
|
||||||
|
currententry->albumname=(char *)my_malloc(rb->tagdbheader->albumlen);
|
||||||
|
rb->lseek(*rb->tagdb_fd,currententry->albumoffset,SEEK_SET);
|
||||||
|
rb->read(*rb->tagdb_fd,currententry->albumname,rb->tagdbheader->albumlen);
|
||||||
|
currententry->loadedalbumname=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *getfilename(int entry) {
|
||||||
|
if(entryarray[entry].loadedfiledata==0)
|
||||||
|
return "error O.o;;;";
|
||||||
|
else
|
||||||
|
return entryarray[entry].filename;
|
||||||
|
}
|
||||||
32
apps/plugins/searchengine/dbinterface.h
Normal file
32
apps/plugins/searchengine/dbinterface.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
struct entry {
|
||||||
|
int loadedfiledata,
|
||||||
|
loadedsongdata,
|
||||||
|
loadedrundbdata,
|
||||||
|
loadedalbumname,
|
||||||
|
loadedartistname;
|
||||||
|
char *filename;
|
||||||
|
int hash;
|
||||||
|
int songentry;
|
||||||
|
int rundbentry;
|
||||||
|
short year;
|
||||||
|
short bitrate;
|
||||||
|
int rating;
|
||||||
|
int playcount;
|
||||||
|
char *title;
|
||||||
|
char *genre;
|
||||||
|
int artistoffset;
|
||||||
|
int albumoffset;
|
||||||
|
char *artistname;
|
||||||
|
char *albumname;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct entry *currententry;
|
||||||
|
extern struct entry *entryarray;
|
||||||
|
|
||||||
|
int database_init(void);
|
||||||
|
void loadentry(int filerecord);
|
||||||
|
void loadsongdata(void);
|
||||||
|
void loadrundbdata(void);
|
||||||
|
void loadartistname(void);
|
||||||
|
void loadalbumname(void);
|
||||||
|
char *getfilename(int entry);
|
||||||
240
apps/plugins/searchengine/parser.c
Normal file
240
apps/plugins/searchengine/parser.c
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
#include "searchengine.h"
|
||||||
|
#include "token.h"
|
||||||
|
#include "dbinterface.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
struct token *tokenbuffer,*currentToken;
|
||||||
|
int currentindex;
|
||||||
|
int syntaxerror;
|
||||||
|
char errormsg[250];
|
||||||
|
|
||||||
|
unsigned char *parse(struct token *tokenbuf) {
|
||||||
|
unsigned char *ret=0;
|
||||||
|
currentindex=0;
|
||||||
|
syntaxerror=0;
|
||||||
|
tokenbuffer=tokenbuf;
|
||||||
|
database_init();
|
||||||
|
currentToken=&tokenbuffer[currentindex];
|
||||||
|
PUTS("parse");
|
||||||
|
ret=parseMExpr();
|
||||||
|
if(syntaxerror) {
|
||||||
|
PUTS("Syntaxerror");
|
||||||
|
rb->splash(HZ*3,true,errormsg);
|
||||||
|
}
|
||||||
|
parser_accept(TOKEN_EOF);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parser_acceptIt(void) {
|
||||||
|
if(syntaxerror) return;
|
||||||
|
currentToken=&tokenbuffer[++currentindex];
|
||||||
|
}
|
||||||
|
|
||||||
|
int parser_accept(unsigned char kind) {
|
||||||
|
if(currentToken->kind!=kind) {
|
||||||
|
syntaxerror=1;
|
||||||
|
rb->snprintf(errormsg,250,"'%d' found where '%d' expected\n",currentToken->kind,kind);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parser_acceptIt();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *parseCompareNum() {
|
||||||
|
struct token *number1,*number2;
|
||||||
|
unsigned char *ret;
|
||||||
|
int i,n1=-1,n2=-1;
|
||||||
|
int op;
|
||||||
|
if(syntaxerror) return 0;
|
||||||
|
PUTS("parseCompareNum");
|
||||||
|
if(currentToken->kind==TOKEN_NUM ||
|
||||||
|
currentToken->kind==TOKEN_NUMIDENTIFIER) {
|
||||||
|
number1=currentToken;
|
||||||
|
parser_acceptIt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
syntaxerror=1;
|
||||||
|
rb->snprintf(errormsg,250,"'%d' found where NUM/NUMID expected\n",currentToken->kind);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(currentToken->kind>=TOKEN_GT && currentToken->kind <= TOKEN_NE) {
|
||||||
|
op=currentToken->kind;
|
||||||
|
parser_acceptIt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
syntaxerror=1;
|
||||||
|
rb->snprintf(errormsg,250,"'%d' found where NUMOP expected\n",currentToken->kind);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(currentToken->kind==TOKEN_NUM ||
|
||||||
|
currentToken->kind==TOKEN_NUMIDENTIFIER) {
|
||||||
|
number2=currentToken;
|
||||||
|
parser_acceptIt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
syntaxerror=1;
|
||||||
|
rb->snprintf(errormsg,250,"'%d' found where NUM/NUMID expected\n",currentToken->kind);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ret=my_malloc(sizeof(unsigned char)*rb->tagdbheader->filecount);
|
||||||
|
if(number1->kind==TOKEN_NUM)
|
||||||
|
n1=getvalue(number1);
|
||||||
|
if(number2->kind==TOKEN_NUM)
|
||||||
|
n2=getvalue(number2);
|
||||||
|
for(i=0;i<rb->tagdbheader->filecount;i++) {
|
||||||
|
loadentry(i);
|
||||||
|
if(number1->kind==TOKEN_NUMIDENTIFIER)
|
||||||
|
n1=getvalue(number1);
|
||||||
|
if(number2->kind==TOKEN_NUMIDENTIFIER)
|
||||||
|
n2=getvalue(number2);
|
||||||
|
switch(op) {
|
||||||
|
case TOKEN_GT:
|
||||||
|
ret[i]=n1 > n2;
|
||||||
|
break;
|
||||||
|
case TOKEN_GTE:
|
||||||
|
ret[i]=n1 >= n2;
|
||||||
|
break;
|
||||||
|
case TOKEN_LT:
|
||||||
|
ret[i]=n1 < n2;
|
||||||
|
break;
|
||||||
|
case TOKEN_LTE:
|
||||||
|
ret[i]=n1 <= n2;
|
||||||
|
break;
|
||||||
|
case TOKEN_EQ:
|
||||||
|
ret[i]=n1 == n2;
|
||||||
|
break;
|
||||||
|
case TOKEN_NE:
|
||||||
|
ret[i]=n1 != n2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *parseCompareString() {
|
||||||
|
struct token *string1,*string2;
|
||||||
|
unsigned char *ret;
|
||||||
|
char *s1=NULL,*s2=NULL;
|
||||||
|
int i,contains;
|
||||||
|
if(syntaxerror) return 0;
|
||||||
|
PUTS("parseCompareString");
|
||||||
|
if(currentToken->kind==TOKEN_STRING ||
|
||||||
|
currentToken->kind==TOKEN_STRINGIDENTIFIER) {
|
||||||
|
string1=currentToken;
|
||||||
|
parser_acceptIt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
syntaxerror=1;
|
||||||
|
rb->snprintf(errormsg,250,"'%d' found where STRING/STRINGID expected\n",currentToken->kind);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
contains=currentToken->kind==TOKEN_CONTAINS;
|
||||||
|
if(currentToken->kind==TOKEN_CONTAINS ||
|
||||||
|
currentToken->kind==TOKEN_EQUALS)
|
||||||
|
parser_acceptIt();
|
||||||
|
else {
|
||||||
|
syntaxerror=1;
|
||||||
|
rb->snprintf(errormsg,250,"'%d' found where CONTAINS/EQUALS expected\n",currentToken->kind);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentToken->kind==TOKEN_STRING ||
|
||||||
|
currentToken->kind==TOKEN_STRINGIDENTIFIER) {
|
||||||
|
string2=currentToken;
|
||||||
|
parser_acceptIt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
syntaxerror=1;
|
||||||
|
rb->snprintf(errormsg,250,"'%d' found where STRING/STRINGID expected\n",currentToken->kind);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ret=my_malloc(sizeof(unsigned char)*rb->tagdbheader->filecount);
|
||||||
|
if(string1->kind==TOKEN_STRING)
|
||||||
|
s1=getstring(string1);
|
||||||
|
if(string2->kind==TOKEN_STRING)
|
||||||
|
s2=getstring(string2);
|
||||||
|
for(i=0;i<rb->tagdbheader->filecount;i++) {
|
||||||
|
loadentry(i);
|
||||||
|
if(string1->kind==TOKEN_STRINGIDENTIFIER)
|
||||||
|
s1=getstring(string1);
|
||||||
|
if(string2->kind==TOKEN_STRINGIDENTIFIER)
|
||||||
|
s2=getstring(string2);
|
||||||
|
if(contains)
|
||||||
|
ret[i]=rb->strcasestr(s1,s2)!=0;
|
||||||
|
else
|
||||||
|
ret[i]=rb->strcasecmp(s1,s2)==0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *parseExpr() {
|
||||||
|
unsigned char *ret;
|
||||||
|
int i;
|
||||||
|
if(syntaxerror) return 0;
|
||||||
|
PUTS("parseExpr");
|
||||||
|
switch(currentToken->kind) {
|
||||||
|
case TOKEN_NOT:
|
||||||
|
parser_accept(TOKEN_NOT);
|
||||||
|
PUTS("parseNot");
|
||||||
|
ret = parseExpr();
|
||||||
|
if(ret==NULL) return 0;
|
||||||
|
for(i=0;i<rb->tagdbheader->filecount;i++)
|
||||||
|
ret[i]=!ret[i];
|
||||||
|
break;
|
||||||
|
case TOKEN_LPAREN:
|
||||||
|
parser_accept(TOKEN_LPAREN);
|
||||||
|
ret = parseMExpr();
|
||||||
|
if(ret==NULL) return 0;
|
||||||
|
parser_accept(TOKEN_RPAREN);
|
||||||
|
break;
|
||||||
|
case TOKEN_NUM:
|
||||||
|
case TOKEN_NUMIDENTIFIER:
|
||||||
|
ret = parseCompareNum();
|
||||||
|
if(ret==NULL) return 0;
|
||||||
|
break;
|
||||||
|
case TOKEN_STRING:
|
||||||
|
case TOKEN_STRINGIDENTIFIER:
|
||||||
|
ret = parseCompareString();
|
||||||
|
if(ret==NULL) return 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// error, unexpected symbol
|
||||||
|
syntaxerror=1;
|
||||||
|
rb->snprintf(errormsg,250,"unexpected '%d' found at parseExpr\n",currentToken->kind);
|
||||||
|
ret=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *parseMExpr() {
|
||||||
|
unsigned char *ret,*ret2;
|
||||||
|
int i;
|
||||||
|
if(syntaxerror) return 0;
|
||||||
|
PUTS("parseMExpr");
|
||||||
|
ret=parseExpr();
|
||||||
|
while(currentToken->kind==TOKEN_AND||currentToken->kind==TOKEN_OR) {
|
||||||
|
switch(currentToken->kind) {
|
||||||
|
case TOKEN_AND:
|
||||||
|
parser_accept(TOKEN_AND);
|
||||||
|
PUTS("parseAnd");
|
||||||
|
ret2 = parseExpr();
|
||||||
|
if(ret2==NULL) return 0;
|
||||||
|
for(i=0;i<rb->tagdbheader->filecount;i++)
|
||||||
|
ret[i]=ret[i] && ret2[i];
|
||||||
|
break;
|
||||||
|
case TOKEN_OR:
|
||||||
|
parser_accept(TOKEN_OR);
|
||||||
|
PUTS("parseOr");
|
||||||
|
ret2 = parseExpr();
|
||||||
|
if(ret2==NULL) return 0;
|
||||||
|
for(i=0;i<rb->tagdbheader->filecount;i++)
|
||||||
|
ret[i]=ret[i] || ret2[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
12
apps/plugins/searchengine/parser.h
Normal file
12
apps/plugins/searchengine/parser.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
extern struct token *tokenbuffer,*currentToken;
|
||||||
|
|
||||||
|
extern int syntaxerror;
|
||||||
|
extern char errormsg[250];
|
||||||
|
|
||||||
|
unsigned char *parse(struct token *tokenbuf);
|
||||||
|
void parser_acceptIt(void);
|
||||||
|
int parser_accept(unsigned char kind);
|
||||||
|
unsigned char *parseCompareNum(void);
|
||||||
|
unsigned char *parseCompareString(void);
|
||||||
|
unsigned char *parseExpr(void);
|
||||||
|
unsigned char *parseMExpr(void);
|
||||||
101
apps/plugins/searchengine/searchengine.c
Normal file
101
apps/plugins/searchengine/searchengine.c
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 by Michiel van der Kolk
|
||||||
|
*
|
||||||
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "searchengine.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "token.h"
|
||||||
|
#include "dbinterface.h"
|
||||||
|
|
||||||
|
void *audio_bufferbase;
|
||||||
|
void *audio_bufferpointer;
|
||||||
|
unsigned int audio_buffer_free;
|
||||||
|
struct plugin_api* rb;
|
||||||
|
int w, h, y;
|
||||||
|
|
||||||
|
void *my_malloc(size_t size)
|
||||||
|
{
|
||||||
|
void *alloc;
|
||||||
|
|
||||||
|
if (!audio_bufferbase)
|
||||||
|
{
|
||||||
|
audio_bufferbase = audio_bufferpointer
|
||||||
|
= rb->plugin_get_audio_buffer(&audio_buffer_free);
|
||||||
|
}
|
||||||
|
if (size + 4 > audio_buffer_free)
|
||||||
|
return 0;
|
||||||
|
alloc = audio_bufferpointer;
|
||||||
|
audio_bufferpointer += size + 4;
|
||||||
|
audio_buffer_free -= size + 4;
|
||||||
|
return alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setmallocpos(void *pointer)
|
||||||
|
{
|
||||||
|
audio_bufferpointer = pointer;
|
||||||
|
audio_buffer_free = audio_bufferpointer - audio_bufferbase;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct token tokenstream[10];
|
||||||
|
|
||||||
|
/* this is the plugin entry point */
|
||||||
|
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
||||||
|
{
|
||||||
|
unsigned char *result,buf[500];
|
||||||
|
/* this macro should be called as the first thing you do in the plugin.
|
||||||
|
it test that the api version and model the plugin was compiled for
|
||||||
|
matches the machine it is running on */
|
||||||
|
TEST_PLUGIN_API(api);
|
||||||
|
|
||||||
|
(void)parameter;
|
||||||
|
|
||||||
|
/* if you are using a global api pointer, don't forget to copy it!
|
||||||
|
otherwise you will get lovely "I04: IllInstr" errors... :-) */
|
||||||
|
rb = api;
|
||||||
|
|
||||||
|
audio_bufferbase=audio_bufferpointer=0;
|
||||||
|
audio_buffer_free=0;
|
||||||
|
|
||||||
|
/* now go ahead and have fun! */
|
||||||
|
rb->splash(HZ*2, true, "SearchEngine v0.1");
|
||||||
|
tokenstream[0].kind=TOKEN_NUMIDENTIFIER;
|
||||||
|
tokenstream[0].intvalue=INTVALUE_YEAR;
|
||||||
|
tokenstream[1].kind=TOKEN_GTE;
|
||||||
|
tokenstream[2].kind=TOKEN_NUM;
|
||||||
|
tokenstream[2].intvalue=1980;
|
||||||
|
tokenstream[3].kind=TOKEN_AND;
|
||||||
|
tokenstream[4].kind=TOKEN_NUMIDENTIFIER;
|
||||||
|
tokenstream[4].intvalue=INTVALUE_YEAR;
|
||||||
|
tokenstream[5].kind=TOKEN_LT;
|
||||||
|
tokenstream[6].kind=TOKEN_NUM;
|
||||||
|
tokenstream[6].intvalue=1990;
|
||||||
|
tokenstream[7].kind=TOKEN_EOF;
|
||||||
|
result=parse(tokenstream);
|
||||||
|
rb->snprintf(buf,250,"Retval: 0x%x",result);
|
||||||
|
PUTS(buf);
|
||||||
|
if(result!=0) {
|
||||||
|
int fd=rb->open("/search.m3u", O_WRONLY|O_CREAT|O_TRUNC);
|
||||||
|
int i;
|
||||||
|
for(i=0;i<rb->tagdbheader->filecount;i++)
|
||||||
|
if(result[i])
|
||||||
|
rb->fdprintf(fd,"%s\n",getfilename(i));
|
||||||
|
/* rb->write(fd,result,rb->tagdbheader->filecount);*/
|
||||||
|
rb->close(fd);
|
||||||
|
}
|
||||||
|
rb->sleep(HZ*10);
|
||||||
|
return PLUGIN_OK;
|
||||||
|
}
|
||||||
37
apps/plugins/searchengine/searchengine.h
Normal file
37
apps/plugins/searchengine/searchengine.h
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 by Michiel van der Kolk
|
||||||
|
*
|
||||||
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef SEARCHENGINE_H
|
||||||
|
#define SEARCHENGINE_H
|
||||||
|
#include <plugin.h>
|
||||||
|
#include <database.h>
|
||||||
|
|
||||||
|
extern int w, h, y;
|
||||||
|
#define PUTS(str) do { \
|
||||||
|
rb->lcd_putsxy(1, y, str); \
|
||||||
|
rb->lcd_getstringsize(str, &w, &h); \
|
||||||
|
y += h + 1; \
|
||||||
|
} while (0); \
|
||||||
|
rb->lcd_update()
|
||||||
|
|
||||||
|
extern struct plugin_api* rb;
|
||||||
|
|
||||||
|
void *my_malloc(size_t size);
|
||||||
|
void setmallocpos(void *pointer);
|
||||||
|
|
||||||
|
#endif
|
||||||
61
apps/plugins/searchengine/token.c
Normal file
61
apps/plugins/searchengine/token.c
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
#include "token.h"
|
||||||
|
#include "dbinterface.h"
|
||||||
|
|
||||||
|
#define REQUIRESONGDATA() if(!currententry->loadedsongdata) loadsongdata();
|
||||||
|
#define REQUIRERUNDBDATA() if(!currententry->loadedrundbdata) loadrundbdata();
|
||||||
|
#define REQUIREALBUMNAME() if(!currententry->loadedalbumname) { REQUIRESONGDATA(); loadalbumname(); }
|
||||||
|
#define REQUIREARTISTNAME() if(!currententry->loadedartistname) { REQUIRESONGDATA(); loadartistname(); }
|
||||||
|
|
||||||
|
char *getstring(struct token *token) {
|
||||||
|
switch(token->kind) {
|
||||||
|
case TOKEN_STRING:
|
||||||
|
return token->spelling;
|
||||||
|
case TOKEN_STRINGIDENTIFIER:
|
||||||
|
switch(token->intvalue) {
|
||||||
|
case INTVALUE_TITLE:
|
||||||
|
REQUIRESONGDATA();
|
||||||
|
return currententry->title;
|
||||||
|
case INTVALUE_ARTIST:
|
||||||
|
REQUIREARTISTNAME();
|
||||||
|
return currententry->artistname;
|
||||||
|
case INTVALUE_ALBUM:
|
||||||
|
REQUIREALBUMNAME();
|
||||||
|
return currententry->albumname;
|
||||||
|
case INTVALUE_GENRE:
|
||||||
|
REQUIRESONGDATA();
|
||||||
|
return currententry->genre;
|
||||||
|
case INTVALUE_FILENAME:
|
||||||
|
return currententry->filename;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// report error
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getvalue(struct token *token) {
|
||||||
|
switch(token->kind) {
|
||||||
|
case TOKEN_NUM:
|
||||||
|
return token->intvalue;
|
||||||
|
case TOKEN_NUMIDENTIFIER:
|
||||||
|
switch(token->intvalue) {
|
||||||
|
case INTVALUE_YEAR:
|
||||||
|
REQUIRESONGDATA();
|
||||||
|
return currententry->year;
|
||||||
|
case INTVALUE_RATING:
|
||||||
|
REQUIRERUNDBDATA();
|
||||||
|
return currententry->rating;
|
||||||
|
case INTVALUE_PLAYCOUNT:
|
||||||
|
REQUIRERUNDBDATA();
|
||||||
|
return currententry->playcount;
|
||||||
|
default:
|
||||||
|
// report error.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
apps/plugins/searchengine/token.h
Normal file
40
apps/plugins/searchengine/token.h
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#define TOKEN_INVALID -1
|
||||||
|
#define TOKEN_EOF 0 // EOF
|
||||||
|
#define TOKEN_NOT 1 // "not"
|
||||||
|
#define TOKEN_AND 2 // "and"
|
||||||
|
#define TOKEN_OR 3 // "or"
|
||||||
|
#define TOKEN_GT 4 // '>'
|
||||||
|
#define TOKEN_GTE 5 // '>='
|
||||||
|
#define TOKEN_LT 6 // '<'
|
||||||
|
#define TOKEN_LTE 7 // '<='
|
||||||
|
#define TOKEN_EQ 8 // '=='
|
||||||
|
#define TOKEN_NE 9 // '!='
|
||||||
|
#define TOKEN_CONTAINS 10 // "contains"
|
||||||
|
#define TOKEN_EQUALS 11 // "equals"
|
||||||
|
#define TOKEN_LPAREN 12 // '('
|
||||||
|
#define TOKEN_RPAREN 13 // ')'
|
||||||
|
#define TOKEN_NUM 14 // (0..9)+
|
||||||
|
#define TOKEN_NUMIDENTIFIER 15 // year, trackid, bpm, etc.
|
||||||
|
#define TOKEN_STRING 16 // (?)+
|
||||||
|
#define TOKEN_STRINGIDENTIFIER 17 // album, artist, title, genre ...
|
||||||
|
|
||||||
|
#define INTVALUE_YEAR 1
|
||||||
|
#define INTVALUE_RATING 2
|
||||||
|
#define INTVALUE_PLAYCOUNT 3
|
||||||
|
#define INTVALUE_TITLE 4
|
||||||
|
#define INTVALUE_ARTIST 5
|
||||||
|
#define INTVALUE_ALBUM 6
|
||||||
|
#define INTVALUE_GENRE 7
|
||||||
|
#define INTVALUE_FILENAME 8
|
||||||
|
|
||||||
|
static char *spelling[] = { "not", "and", "or",">",">=","<", "<=","==","!=",
|
||||||
|
"contains","(",")" };
|
||||||
|
|
||||||
|
struct token {
|
||||||
|
unsigned char kind;
|
||||||
|
char spelling[256];
|
||||||
|
int intvalue;
|
||||||
|
};
|
||||||
|
|
||||||
|
char *getstring(struct token *token);
|
||||||
|
int getvalue(struct token *token);
|
||||||
Loading…
Add table
Add a link
Reference in a new issue