summaryrefslogtreecommitdiff
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
parenta7f7781dca4db172a507e7e6f73bee03fc7deb2f (diff)
downloadrockbox-9369d4867d3bf033e0e3bbcff05cd7f0a9bb83e8.tar.gz
rockbox-9369d4867d3bf033e0e3bbcff05cd7f0a9bb83e8.zip
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
-rw-r--r--apps/plugin.c6
-rw-r--r--apps/plugin.h7
-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
12 files changed, 738 insertions, 2 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index 76c9ddb8bf..384ab22ede 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -45,6 +45,7 @@
45#include "powermgmt.h" 45#include "powermgmt.h"
46#include "system.h" 46#include "system.h"
47#include "sound.h" 47#include "sound.h"
48#include "database.h"
48#if (CONFIG_HWCODEC == MASNONE) 49#if (CONFIG_HWCODEC == MASNONE)
49#include "pcm_playback.h" 50#include "pcm_playback.h"
50#endif 51#endif
@@ -319,6 +320,11 @@ static const struct plugin_api rockbox_api = {
319#ifdef HAVE_LCD_BITMAP 320#ifdef HAVE_LCD_BITMAP
320 read_bmp_file, 321 read_bmp_file,
321#endif 322#endif
323 &tagdbheader,
324 &tagdb_fd,
325 &tagdb_initialized,
326 tagdb_init,
327 strcasestr,
322}; 328};
323 329
324int plugin_load(const char* plugin, void* parameter) 330int plugin_load(const char* plugin, void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index 0bb57b27f1..2604cae4f9 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -78,7 +78,7 @@
78#endif 78#endif
79 79
80/* increase this every time the api struct changes */ 80/* increase this every time the api struct changes */
81#define PLUGIN_API_VERSION 38 81#define PLUGIN_API_VERSION 39
82 82
83/* update this to latest version if a change to the api struct breaks 83/* update this to latest version if a change to the api struct breaks
84 backwards compatibility (and please take the opportunity to sort in any 84 backwards compatibility (and please take the opportunity to sort in any
@@ -375,6 +375,11 @@ struct plugin_api {
375 int (*read_bmp_file)(char* filename, int *get_width, int *get_height, 375 int (*read_bmp_file)(char* filename, int *get_width, int *get_height,
376 char *bitmap, int maxsize); 376 char *bitmap, int maxsize);
377#endif 377#endif
378 struct tagdb_header *tagdbheader;
379 int *tagdb_fd;
380 int *tagdb_initialized;
381 int (*tagdb_init) (void);
382 char *(*strcasestr) (const char* phaystack, const char* pneedle);
378}; 383};
379 384
380/* defined by the plugin loader (plugin.c) */ 385/* defined by the plugin loader (plugin.c) */
diff --git a/apps/plugins/Makefile b/apps/plugins/Makefile
index 9c3ff4adc2..83617278d5 100644
--- a/apps/plugins/Makefile
+++ b/apps/plugins/Makefile
@@ -37,7 +37,7 @@ DIRS = .
37 37
38#for any recorder and iRiver model 38#for any recorder and iRiver model
39ifneq (,$(strip $(foreach tgt,RECORDER IRIVER,$(findstring $(tgt),$(TARGET))))) 39ifneq (,$(strip $(foreach tgt,RECORDER IRIVER,$(findstring $(tgt),$(TARGET)))))
40 SUBDIRS += rockboy 40 SUBDIRS += rockboy searchengine
41endif 41endif
42 42
43.PHONY: $(SUBDIRS) 43.PHONY: $(SUBDIRS)
diff --git a/apps/plugins/searchengine/Makefile b/apps/plugins/searchengine/Makefile
new file mode 100644
index 0000000000..d7253e2e10
--- /dev/null
+++ b/apps/plugins/searchengine/Makefile
@@ -0,0 +1,105 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9
10INCLUDES = -I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \
11 -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers
12CFLAGS = $(GCCOPTS) -O3 $(INCLUDES) $(TARGET) $(EXTRA_DEFINES) \
13 -DMEM=${MEMORYSIZE} -DPLUGIN
14
15ifdef APPEXTRA
16 INCLUDES += -I$(APPSDIR)/$(APPEXTRA)
17endif
18
19LINKFILE := $(OBJDIR)/link.lds
20DEPFILE = $(OBJDIR)/dep-searchengine
21SRC = searchengine.c parser.c token.c dbinterface.c
22
23SOURCES = $(SRC)
24OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
25DIRS = .
26
27
28ifndef SIMVER
29ifneq (,$(findstring RECORDER,$(TARGET))) ## Archos recorder targets
30 OUTPUT = $(OUTDIR)/searchengine.rock
31else ## iRiver target
32 LDS := ../plugin.lds
33 OUTPUT = $(OUTDIR)/searchengine.rock
34endif
35else ## simulators
36 OUTPUT = $(OUTDIR)/searchengine.rock
37endif
38
39all: $(OUTPUT)
40
41ifndef SIMVER
42$(OBJDIR)/searchengine.elf: $(OBJS) $(LINKFILE) $(OUTDIR)/libplugin.a
43 @echo "LD $@"
44 @$(CC) $(GCCOPTS) -O -nostdlib -o $@ $(OBJS) -L$(OUTDIR) -lplugin -lgcc \
45 -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/searchengine.map
46
47$(OUTPUT): $(OBJDIR)/searchengine.elf
48 @echo "OBJCOPY $<"
49 @$(OC) -O binary $< $@
50else
51
52ifeq ($(SIMVER), x11)
53###################################################
54# This is the X11 simulator version
55
56$(OUTPUT): $(OBJS) $(OUTDIR)/libplugin.a
57 @echo "LD $@"
58 @$(CC) $(CFLAGS) -shared $(OBJS) -L$(OUTDIR) -lplugin -o $@
59ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
60# 'x' must be kept or you'll have "Win32 error 5"
61# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
62# #define ERROR_ACCESS_DENIED 5L
63else
64 @chmod -x $@
65endif
66
67else # end of x11-simulator
68###################################################
69# This is the win32 simulator version
70DLLTOOLFLAGS = --export-all
71DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin
72
73$(OUTPUT): $(OBJS) $(OUTDIR)/libplugin.a
74 @echo "DLL $@"
75 @$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS)
76 @$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \
77 $(OUTDIR)/libplugin.a -o $@
78ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
79# 'x' must be kept or you'll have "Win32 error 5"
80# $ fgrep 5 /usr/include/w32api/winerror.h | head -1
81# #define ERROR_ACCESS_DENIED 5L
82else
83 @chmod -x $@
84endif
85endif # end of win32-simulator
86
87endif # end of simulator section
88
89
90include $(TOOLSDIR)/make.inc
91
92# MEM should be passed on to this makefile with the chosen memory size given
93# in number of MB
94$(LINKFILE): $(LDS)
95 @echo "build $@"
96 @cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) \
97 -E -P - >$@
98
99clean:
100 @echo "cleaning searchengine"
101 @rm -rf $(OBJDIR)/searchengine
102 @rm -f $(OBJDIR)/searchengine.* $(DEPFILE)
103
104-include $(DEPFILE)
105
diff --git a/apps/plugins/searchengine/dbinterface.c b/apps/plugins/searchengine/dbinterface.c
new file mode 100644
index 0000000000..bf2a6cfa5c
--- /dev/null
+++ b/apps/plugins/searchengine/dbinterface.c
@@ -0,0 +1,97 @@
1#include "searchengine.h"
2#include "dbinterface.h"
3
4#undef SONGENTRY_SIZE
5#undef FILEENTRY_SIZE
6#undef ALBUMENTRY_SIZE
7#undef ARTISTENTRY_SIZE
8#undef FILERECORD2OFFSET
9
10#define SONGENTRY_SIZE (rb->tagdbheader->songlen+12+rb->tagdbheader->genrelen+4)
11#define FILEENTRY_SIZE (rb->tagdbheader->filelen+12)
12#define ALBUMENTRY_SIZE (rb->tagdbheader->albumlen+4+rb->tagdbheader->songarraylen*4)
13#define ARTISTENTRY_SIZE (rb->tagdbheader->artistlen+rb->tagdbheader->albumarraylen*4)
14
15#define FILERECORD2OFFSET(_x_) (rb->tagdbheader->filestart + _x_ * FILEENTRY_SIZE)
16
17struct entry *currententry;
18
19static struct entry *entryarray;
20
21int database_init() {
22 char *p;
23 unsigned int i;
24 // allocate room for all entries
25 entryarray=(struct entry *)my_malloc(sizeof(struct entry)*rb->tagdbheader->filecount);
26 p=(char *)entryarray;
27 // zero all entries.
28 for(i=0;i<sizeof(struct entry)*rb->tagdbheader->filecount;i++)
29 *(p++)=0;
30 if(*rb->tagdb_initialized!=1) {
31 if(!rb->tagdb_init()) {
32 // failed loading db
33 return -1;
34 }
35 }
36 return 0;
37}
38
39void loadentry(int filerecord) {
40 if(entryarray[filerecord].loadedfiledata==0) {
41 rb->lseek(*rb->tagdb_fd,FILERECORD2OFFSET(filerecord),SEEK_SET);
42 entryarray[filerecord].filename=(char *)my_malloc(rb->tagdbheader->filelen);
43 rb->read(*rb->tagdb_fd,entryarray[filerecord].filename,rb->tagdbheader->filelen);
44 rb->read(*rb->tagdb_fd,&entryarray[filerecord].hash,4);
45 rb->read(*rb->tagdb_fd,&entryarray[filerecord].songentry,4);
46 rb->read(*rb->tagdb_fd,&entryarray[filerecord].rundbentry,4);
47 entryarray[filerecord].loadedfiledata=1;
48 }
49 currententry=&entryarray[filerecord];
50}
51
52void loadsongdata() {
53 if(currententry->loadedsongdata ||
54 !currententry->loadedfiledata)
55 return;
56 currententry->title=(char *)my_malloc(rb->tagdbheader->songlen);
57 currententry->genre=(char *)my_malloc(rb->tagdbheader->genrelen);
58 rb->lseek(*rb->tagdb_fd,currententry->songentry,SEEK_SET);
59 rb->read(*rb->tagdb_fd,currententry->title,rb->tagdbheader->songlen);
60 rb->read(*rb->tagdb_fd,&currententry->artistoffset,4);
61 rb->read(*rb->tagdb_fd,&currententry->albumoffset,4);
62 rb->lseek(*rb->tagdb_fd,4,SEEK_CUR);
63 rb->read(*rb->tagdb_fd,currententry->genre,rb->tagdbheader->genrelen);
64 rb->read(*rb->tagdb_fd,&currententry->bitrate,2);
65 rb->read(*rb->tagdb_fd,&currententry->year,2);
66 currententry->loadedsongdata=1;
67}
68
69void loadrundbdata() {
70 // we don't do this yet.
71 currententry->loadedrundbdata=1;
72}
73
74void loadartistname() {
75 /* memory optimization possible, only malloc for an album name once, then
76 * write that pointer to the entrys using it.
77 */
78 currententry->artistname=(char *)my_malloc(rb->tagdbheader->artistlen);
79 rb->lseek(*rb->tagdb_fd,currententry->artistoffset,SEEK_SET);
80 rb->read(*rb->tagdb_fd,currententry->artistname,rb->tagdbheader->artistlen);
81 currententry->loadedartistname=1;
82}
83
84void loadalbumname() {
85 /* see the note at loadartistname */
86 currententry->albumname=(char *)my_malloc(rb->tagdbheader->albumlen);
87 rb->lseek(*rb->tagdb_fd,currententry->albumoffset,SEEK_SET);
88 rb->read(*rb->tagdb_fd,currententry->albumname,rb->tagdbheader->albumlen);
89 currententry->loadedalbumname=1;
90}
91
92char *getfilename(int entry) {
93 if(entryarray[entry].loadedfiledata==0)
94 return "error O.o;;;";
95 else
96 return entryarray[entry].filename;
97}
diff --git a/apps/plugins/searchengine/dbinterface.h b/apps/plugins/searchengine/dbinterface.h
new file mode 100644
index 0000000000..32363b11c6
--- /dev/null
+++ b/apps/plugins/searchengine/dbinterface.h
@@ -0,0 +1,32 @@
1struct entry {
2 int loadedfiledata,
3 loadedsongdata,
4 loadedrundbdata,
5 loadedalbumname,
6 loadedartistname;
7 char *filename;
8 int hash;
9 int songentry;
10 int rundbentry;
11 short year;
12 short bitrate;
13 int rating;
14 int playcount;
15 char *title;
16 char *genre;
17 int artistoffset;
18 int albumoffset;
19 char *artistname;
20 char *albumname;
21};
22
23extern struct entry *currententry;
24extern struct entry *entryarray;
25
26int database_init(void);
27void loadentry(int filerecord);
28void loadsongdata(void);
29void loadrundbdata(void);
30void loadartistname(void);
31void loadalbumname(void);
32char *getfilename(int entry);
diff --git a/apps/plugins/searchengine/parser.c b/apps/plugins/searchengine/parser.c
new file mode 100644
index 0000000000..fe10452c17
--- /dev/null
+++ b/apps/plugins/searchengine/parser.c
@@ -0,0 +1,240 @@
1#include "searchengine.h"
2#include "token.h"
3#include "dbinterface.h"
4#include "parser.h"
5
6struct token *tokenbuffer,*currentToken;
7int currentindex;
8int syntaxerror;
9char errormsg[250];
10
11unsigned char *parse(struct token *tokenbuf) {
12 unsigned char *ret=0;
13 currentindex=0;
14 syntaxerror=0;
15 tokenbuffer=tokenbuf;
16 database_init();
17 currentToken=&tokenbuffer[currentindex];
18 PUTS("parse");
19 ret=parseMExpr();
20 if(syntaxerror) {
21 PUTS("Syntaxerror");
22 rb->splash(HZ*3,true,errormsg);
23 }
24 parser_accept(TOKEN_EOF);
25 return ret;
26}
27
28void parser_acceptIt(void) {
29 if(syntaxerror) return;
30 currentToken=&tokenbuffer[++currentindex];
31}
32
33int parser_accept(unsigned char kind) {
34 if(currentToken->kind!=kind) {
35 syntaxerror=1;
36 rb->snprintf(errormsg,250,"'%d' found where '%d' expected\n",currentToken->kind,kind);
37 return 0;
38 }
39 else {
40 parser_acceptIt();
41 return 1;
42 }
43}
44
45unsigned char *parseCompareNum() {
46 struct token *number1,*number2;
47 unsigned char *ret;
48 int i,n1=-1,n2=-1;
49 int op;
50 if(syntaxerror) return 0;
51 PUTS("parseCompareNum");
52 if(currentToken->kind==TOKEN_NUM ||
53 currentToken->kind==TOKEN_NUMIDENTIFIER) {
54 number1=currentToken;
55 parser_acceptIt();
56 }
57 else {
58 syntaxerror=1;
59 rb->snprintf(errormsg,250,"'%d' found where NUM/NUMID expected\n",currentToken->kind);
60 return 0;
61 }
62 if(currentToken->kind>=TOKEN_GT && currentToken->kind <= TOKEN_NE) {
63 op=currentToken->kind;
64 parser_acceptIt();
65 }
66 else {
67 syntaxerror=1;
68 rb->snprintf(errormsg,250,"'%d' found where NUMOP expected\n",currentToken->kind);
69 return 0;
70 }
71 if(currentToken->kind==TOKEN_NUM ||
72 currentToken->kind==TOKEN_NUMIDENTIFIER) {
73 number2=currentToken;
74 parser_acceptIt();
75 }
76 else {
77 syntaxerror=1;
78 rb->snprintf(errormsg,250,"'%d' found where NUM/NUMID expected\n",currentToken->kind);
79 return 0;
80 }
81 ret=my_malloc(sizeof(unsigned char)*rb->tagdbheader->filecount);
82 if(number1->kind==TOKEN_NUM)
83 n1=getvalue(number1);
84 if(number2->kind==TOKEN_NUM)
85 n2=getvalue(number2);
86 for(i=0;i<rb->tagdbheader->filecount;i++) {
87 loadentry(i);
88 if(number1->kind==TOKEN_NUMIDENTIFIER)
89 n1=getvalue(number1);
90 if(number2->kind==TOKEN_NUMIDENTIFIER)
91 n2=getvalue(number2);
92 switch(op) {
93 case TOKEN_GT:
94 ret[i]=n1 > n2;
95 break;
96 case TOKEN_GTE:
97 ret[i]=n1 >= n2;
98 break;
99 case TOKEN_LT:
100 ret[i]=n1 < n2;
101 break;
102 case TOKEN_LTE:
103 ret[i]=n1 <= n2;
104 break;
105 case TOKEN_EQ:
106 ret[i]=n1 == n2;
107 break;
108 case TOKEN_NE:
109 ret[i]=n1 != n2;
110 break;
111 }
112 }
113 return ret;
114}
115
116unsigned char *parseCompareString() {
117 struct token *string1,*string2;
118 unsigned char *ret;
119 char *s1=NULL,*s2=NULL;
120 int i,contains;
121 if(syntaxerror) return 0;
122 PUTS("parseCompareString");
123 if(currentToken->kind==TOKEN_STRING ||
124 currentToken->kind==TOKEN_STRINGIDENTIFIER) {
125 string1=currentToken;
126 parser_acceptIt();
127 }
128 else {
129 syntaxerror=1;
130 rb->snprintf(errormsg,250,"'%d' found where STRING/STRINGID expected\n",currentToken->kind);
131 return 0;
132 }
133
134 contains=currentToken->kind==TOKEN_CONTAINS;
135 if(currentToken->kind==TOKEN_CONTAINS ||
136 currentToken->kind==TOKEN_EQUALS)
137 parser_acceptIt();
138 else {
139 syntaxerror=1;
140 rb->snprintf(errormsg,250,"'%d' found where CONTAINS/EQUALS expected\n",currentToken->kind);
141 return 0;
142 }
143
144 if(currentToken->kind==TOKEN_STRING ||
145 currentToken->kind==TOKEN_STRINGIDENTIFIER) {
146 string2=currentToken;
147 parser_acceptIt();
148 }
149 else {
150 syntaxerror=1;
151 rb->snprintf(errormsg,250,"'%d' found where STRING/STRINGID expected\n",currentToken->kind);
152 return 0;
153 }
154 ret=my_malloc(sizeof(unsigned char)*rb->tagdbheader->filecount);
155 if(string1->kind==TOKEN_STRING)
156 s1=getstring(string1);
157 if(string2->kind==TOKEN_STRING)
158 s2=getstring(string2);
159 for(i=0;i<rb->tagdbheader->filecount;i++) {
160 loadentry(i);
161 if(string1->kind==TOKEN_STRINGIDENTIFIER)
162 s1=getstring(string1);
163 if(string2->kind==TOKEN_STRINGIDENTIFIER)
164 s2=getstring(string2);
165 if(contains)
166 ret[i]=rb->strcasestr(s1,s2)!=0;
167 else
168 ret[i]=rb->strcasecmp(s1,s2)==0;
169 }
170 return ret;
171}
172
173unsigned char *parseExpr() {
174 unsigned char *ret;
175 int i;
176 if(syntaxerror) return 0;
177 PUTS("parseExpr");
178 switch(currentToken->kind) {
179 case TOKEN_NOT:
180 parser_accept(TOKEN_NOT);
181 PUTS("parseNot");
182 ret = parseExpr();
183 if(ret==NULL) return 0;
184 for(i=0;i<rb->tagdbheader->filecount;i++)
185 ret[i]=!ret[i];
186 break;
187 case TOKEN_LPAREN:
188 parser_accept(TOKEN_LPAREN);
189 ret = parseMExpr();
190 if(ret==NULL) return 0;
191 parser_accept(TOKEN_RPAREN);
192 break;
193 case TOKEN_NUM:
194 case TOKEN_NUMIDENTIFIER:
195 ret = parseCompareNum();
196 if(ret==NULL) return 0;
197 break;
198 case TOKEN_STRING:
199 case TOKEN_STRINGIDENTIFIER:
200 ret = parseCompareString();
201 if(ret==NULL) return 0;
202 break;
203 default:
204 // error, unexpected symbol
205 syntaxerror=1;
206 rb->snprintf(errormsg,250,"unexpected '%d' found at parseExpr\n",currentToken->kind);
207 ret=0;
208 break;
209 }
210 return ret;
211}
212
213unsigned char *parseMExpr() {
214 unsigned char *ret,*ret2;
215 int i;
216 if(syntaxerror) return 0;
217 PUTS("parseMExpr");
218 ret=parseExpr();
219 while(currentToken->kind==TOKEN_AND||currentToken->kind==TOKEN_OR) {
220 switch(currentToken->kind) {
221 case TOKEN_AND:
222 parser_accept(TOKEN_AND);
223 PUTS("parseAnd");
224 ret2 = parseExpr();
225 if(ret2==NULL) return 0;
226 for(i=0;i<rb->tagdbheader->filecount;i++)
227 ret[i]=ret[i] && ret2[i];
228 break;
229 case TOKEN_OR:
230 parser_accept(TOKEN_OR);
231 PUTS("parseOr");
232 ret2 = parseExpr();
233 if(ret2==NULL) return 0;
234 for(i=0;i<rb->tagdbheader->filecount;i++)
235 ret[i]=ret[i] || ret2[i];
236 break;
237 }
238 }
239 return ret;
240}
diff --git a/apps/plugins/searchengine/parser.h b/apps/plugins/searchengine/parser.h
new file mode 100644
index 0000000000..e63f15f39b
--- /dev/null
+++ b/apps/plugins/searchengine/parser.h
@@ -0,0 +1,12 @@
1extern struct token *tokenbuffer,*currentToken;
2
3extern int syntaxerror;
4extern char errormsg[250];
5
6unsigned char *parse(struct token *tokenbuf);
7void parser_acceptIt(void);
8int parser_accept(unsigned char kind);
9unsigned char *parseCompareNum(void);
10unsigned char *parseCompareString(void);
11unsigned char *parseExpr(void);
12unsigned char *parseMExpr(void);
diff --git a/apps/plugins/searchengine/searchengine.c b/apps/plugins/searchengine/searchengine.c
new file mode 100644
index 0000000000..4b14836ddc
--- /dev/null
+++ b/apps/plugins/searchengine/searchengine.c
@@ -0,0 +1,101 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id
9 *
10 * Copyright (C) 2005 by Michiel van der Kolk
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "searchengine.h"
20#include "parser.h"
21#include "token.h"
22#include "dbinterface.h"
23
24void *audio_bufferbase;
25void *audio_bufferpointer;
26unsigned int audio_buffer_free;
27struct plugin_api* rb;
28int w, h, y;
29
30void *my_malloc(size_t size)
31{
32 void *alloc;
33
34 if (!audio_bufferbase)
35 {
36 audio_bufferbase = audio_bufferpointer
37 = rb->plugin_get_audio_buffer(&audio_buffer_free);
38 }
39 if (size + 4 > audio_buffer_free)
40 return 0;
41 alloc = audio_bufferpointer;
42 audio_bufferpointer += size + 4;
43 audio_buffer_free -= size + 4;
44 return alloc;
45}
46
47void setmallocpos(void *pointer)
48{
49 audio_bufferpointer = pointer;
50 audio_buffer_free = audio_bufferpointer - audio_bufferbase;
51}
52
53struct token tokenstream[10];
54
55/* this is the plugin entry point */
56enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
57{
58 unsigned char *result,buf[500];
59 /* this macro should be called as the first thing you do in the plugin.
60 it test that the api version and model the plugin was compiled for
61 matches the machine it is running on */
62 TEST_PLUGIN_API(api);
63
64 (void)parameter;
65
66 /* if you are using a global api pointer, don't forget to copy it!
67 otherwise you will get lovely "I04: IllInstr" errors... :-) */
68 rb = api;
69
70 audio_bufferbase=audio_bufferpointer=0;
71 audio_buffer_free=0;
72
73 /* now go ahead and have fun! */
74 rb->splash(HZ*2, true, "SearchEngine v0.1");
75 tokenstream[0].kind=TOKEN_NUMIDENTIFIER;
76 tokenstream[0].intvalue=INTVALUE_YEAR;
77 tokenstream[1].kind=TOKEN_GTE;
78 tokenstream[2].kind=TOKEN_NUM;
79 tokenstream[2].intvalue=1980;
80 tokenstream[3].kind=TOKEN_AND;
81 tokenstream[4].kind=TOKEN_NUMIDENTIFIER;
82 tokenstream[4].intvalue=INTVALUE_YEAR;
83 tokenstream[5].kind=TOKEN_LT;
84 tokenstream[6].kind=TOKEN_NUM;
85 tokenstream[6].intvalue=1990;
86 tokenstream[7].kind=TOKEN_EOF;
87 result=parse(tokenstream);
88 rb->snprintf(buf,250,"Retval: 0x%x",result);
89 PUTS(buf);
90 if(result!=0) {
91 int fd=rb->open("/search.m3u", O_WRONLY|O_CREAT|O_TRUNC);
92 int i;
93 for(i=0;i<rb->tagdbheader->filecount;i++)
94 if(result[i])
95 rb->fdprintf(fd,"%s\n",getfilename(i));
96/* rb->write(fd,result,rb->tagdbheader->filecount);*/
97 rb->close(fd);
98 }
99 rb->sleep(HZ*10);
100 return PLUGIN_OK;
101}
diff --git a/apps/plugins/searchengine/searchengine.h b/apps/plugins/searchengine/searchengine.h
new file mode 100644
index 0000000000..3f7e4c609e
--- /dev/null
+++ b/apps/plugins/searchengine/searchengine.h
@@ -0,0 +1,37 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id
9 *
10 * Copyright (C) 2005 by Michiel van der Kolk
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef SEARCHENGINE_H
20#define SEARCHENGINE_H
21#include <plugin.h>
22#include <database.h>
23
24extern int w, h, y;
25#define PUTS(str) do { \
26 rb->lcd_putsxy(1, y, str); \
27 rb->lcd_getstringsize(str, &w, &h); \
28 y += h + 1; \
29} while (0); \
30rb->lcd_update()
31
32extern struct plugin_api* rb;
33
34void *my_malloc(size_t size);
35void setmallocpos(void *pointer);
36
37#endif
diff --git a/apps/plugins/searchengine/token.c b/apps/plugins/searchengine/token.c
new file mode 100644
index 0000000000..d2da94ab52
--- /dev/null
+++ b/apps/plugins/searchengine/token.c
@@ -0,0 +1,61 @@
1#include "token.h"
2#include "dbinterface.h"
3
4#define REQUIRESONGDATA() if(!currententry->loadedsongdata) loadsongdata();
5#define REQUIRERUNDBDATA() if(!currententry->loadedrundbdata) loadrundbdata();
6#define REQUIREALBUMNAME() if(!currententry->loadedalbumname) { REQUIRESONGDATA(); loadalbumname(); }
7#define REQUIREARTISTNAME() if(!currententry->loadedartistname) { REQUIRESONGDATA(); loadartistname(); }
8
9char *getstring(struct token *token) {
10 switch(token->kind) {
11 case TOKEN_STRING:
12 return token->spelling;
13 case TOKEN_STRINGIDENTIFIER:
14 switch(token->intvalue) {
15 case INTVALUE_TITLE:
16 REQUIRESONGDATA();
17 return currententry->title;
18 case INTVALUE_ARTIST:
19 REQUIREARTISTNAME();
20 return currententry->artistname;
21 case INTVALUE_ALBUM:
22 REQUIREALBUMNAME();
23 return currententry->albumname;
24 case INTVALUE_GENRE:
25 REQUIRESONGDATA();
26 return currententry->genre;
27 case INTVALUE_FILENAME:
28 return currententry->filename;
29 default:
30 return 0;
31 }
32 break;
33 default:
34 // report error
35 return 0;
36 }
37}
38
39int getvalue(struct token *token) {
40 switch(token->kind) {
41 case TOKEN_NUM:
42 return token->intvalue;
43 case TOKEN_NUMIDENTIFIER:
44 switch(token->intvalue) {
45 case INTVALUE_YEAR:
46 REQUIRESONGDATA();
47 return currententry->year;
48 case INTVALUE_RATING:
49 REQUIRERUNDBDATA();
50 return currententry->rating;
51 case INTVALUE_PLAYCOUNT:
52 REQUIRERUNDBDATA();
53 return currententry->playcount;
54 default:
55 // report error.
56 return 0;
57 }
58 default:
59 return 0;
60 }
61}
diff --git a/apps/plugins/searchengine/token.h b/apps/plugins/searchengine/token.h
new file mode 100644
index 0000000000..b858f4f217
--- /dev/null
+++ b/apps/plugins/searchengine/token.h
@@ -0,0 +1,40 @@
1#define TOKEN_INVALID -1
2#define TOKEN_EOF 0 // EOF
3#define TOKEN_NOT 1 // "not"
4#define TOKEN_AND 2 // "and"
5#define TOKEN_OR 3 // "or"
6#define TOKEN_GT 4 // '>'
7#define TOKEN_GTE 5 // '>='
8#define TOKEN_LT 6 // '<'
9#define TOKEN_LTE 7 // '<='
10#define TOKEN_EQ 8 // '=='
11#define TOKEN_NE 9 // '!='
12#define TOKEN_CONTAINS 10 // "contains"
13#define TOKEN_EQUALS 11 // "equals"
14#define TOKEN_LPAREN 12 // '('
15#define TOKEN_RPAREN 13 // ')'
16#define TOKEN_NUM 14 // (0..9)+
17#define TOKEN_NUMIDENTIFIER 15 // year, trackid, bpm, etc.
18#define TOKEN_STRING 16 // (?)+
19#define TOKEN_STRINGIDENTIFIER 17 // album, artist, title, genre ...
20
21#define INTVALUE_YEAR 1
22#define INTVALUE_RATING 2
23#define INTVALUE_PLAYCOUNT 3
24#define INTVALUE_TITLE 4
25#define INTVALUE_ARTIST 5
26#define INTVALUE_ALBUM 6
27#define INTVALUE_GENRE 7
28#define INTVALUE_FILENAME 8
29
30static char *spelling[] = { "not", "and", "or",">",">=","<", "<=","==","!=",
31 "contains","(",")" };
32
33struct token {
34 unsigned char kind;
35 char spelling[256];
36 int intvalue;
37};
38
39char *getstring(struct token *token);
40int getvalue(struct token *token);