1
0
Fork 0
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:
Michiel Van Der Kolk 2005-04-28 12:33:38 +00:00
parent a7f7781dca
commit 9369d4867d
12 changed files with 738 additions and 2 deletions

View file

@ -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)

View file

@ -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) */

View file

@ -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)

View 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)

View 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,&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;
}

View 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);

View 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;
}

View 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);

View 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;
}

View 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

View 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;
}
}

View 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);