summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorMichiel Van Der Kolk <not.valid@email.address>2005-04-28 12:33:38 +0000
committerMichiel Van Der Kolk <not.valid@email.address>2005-04-28 12:33:38 +0000
commit9369d4867d3bf033e0e3bbcff05cd7f0a9bb83e8 (patch)
tree0276c6299a3b26705b028f399ceadf3ac7867b2f /apps/plugins
parenta7f7781dca4db172a507e7e6f73bee03fc7deb2f (diff)
downloadrockbox-9369d4867d3bf033e0e3bbcff05cd7f0a9bb83e8.zip
rockbox-9369d4867d3bf033e0e3bbcff05cd7f0a9bb83e8.tar.gz
rockbox-9369d4867d3bf033e0e3bbcff05cd7f0a9bb83e8.tar.bz2
rockbox-9369d4867d3bf033e0e3bbcff05cd7f0a9bb83e8.tar.xz
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
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/Makefile2
-rw-r--r--apps/plugins/searchengine/Makefile105
-rw-r--r--apps/plugins/searchengine/dbinterface.c97
-rw-r--r--apps/plugins/searchengine/dbinterface.h32
-rw-r--r--apps/plugins/searchengine/parser.c240
-rw-r--r--apps/plugins/searchengine/parser.h12
-rw-r--r--apps/plugins/searchengine/searchengine.c101
-rw-r--r--apps/plugins/searchengine/searchengine.h37
-rw-r--r--apps/plugins/searchengine/token.c61
-rw-r--r--apps/plugins/searchengine/token.h40
10 files changed, 726 insertions, 1 deletions
diff --git a/apps/plugins/Makefile b/apps/plugins/Makefile
index 9c3ff4a..8361727 100644
--- a/apps/plugins/Makefile
+++ b/apps/plugins/Makefile
@@ -37,7 +37,7 @@ DIRS = .
#for any recorder and iRiver model
ifneq (,$(strip $(foreach tgt,RECORDER IRIVER,$(findstring $(tgt),$(TARGET)))))
- SUBDIRS += rockboy
+ SUBDIRS += rockboy searchengine
endif
.PHONY: $(SUBDIRS)
diff --git a/apps/plugins/searchengine/Makefile b/apps/plugins/searchengine/Makefile
new file mode 100644
index 0000000..d7253e2
--- /dev/null
+++ b/apps/plugins/searchengine/Makefile
@@ -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)
+
diff --git a/apps/plugins/searchengine/dbinterface.c b/apps/plugins/searchengine/dbinterface.c
new file mode 100644
index 0000000..bf2a6cf
--- /dev/null
+++ b/apps/plugins/searchengine/dbinterface.c
@@ -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,&currententry->artistoffset,4);
+ rb->read(*rb->tagdb_fd,&currententry->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,&currententry->bitrate,2);
+ rb->read(*rb->tagdb_fd,&currententry->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;
+}
diff --git a/apps/plugins/searchengine/dbinterface.h b/apps/plugins/searchengine/dbinterface.h
new file mode 100644
index 0000000..32363b1
--- /dev/null
+++ b/apps/plugins/searchengine/dbinterface.h
@@ -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);
diff --git a/apps/plugins/searchengine/parser.c b/apps/plugins/searchengine/parser.c
new file mode 100644
index 0000000..fe10452
--- /dev/null
+++ b/apps/plugins/searchengine/parser.c
@@ -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;
+}
diff --git a/apps/plugins/searchengine/parser.h b/apps/plugins/searchengine/parser.h
new file mode 100644
index 0000000..e63f15f
--- /dev/null
+++ b/apps/plugins/searchengine/parser.h
@@ -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);
diff --git a/apps/plugins/searchengine/searchengine.c b/apps/plugins/searchengine/searchengine.c
new file mode 100644
index 0000000..4b14836
--- /dev/null
+++ b/apps/plugins/searchengine/searchengine.c
@@ -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;
+}
diff --git a/apps/plugins/searchengine/searchengine.h b/apps/plugins/searchengine/searchengine.h
new file mode 100644
index 0000000..3f7e4c6
--- /dev/null
+++ b/apps/plugins/searchengine/searchengine.h
@@ -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
diff --git a/apps/plugins/searchengine/token.c b/apps/plugins/searchengine/token.c
new file mode 100644
index 0000000..d2da94a
--- /dev/null
+++ b/apps/plugins/searchengine/token.c
@@ -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;
+ }
+}
diff --git a/apps/plugins/searchengine/token.h b/apps/plugins/searchengine/token.h
new file mode 100644
index 0000000..b858f4f
--- /dev/null
+++ b/apps/plugins/searchengine/token.h
@@ -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);