Update of /cvsroot/rockbox/apps/plugins/searchengine
In directory labb:/tmp/cvs-serv22417/plugins/searchengine
Added Files:
Makefile dbinterface.c dbinterface.h parser.c parser.h
searchengine.c searchengine.h token.c token.h
Log Message:
Search engine core for database v2, has an hardcoded "songs for year >= 1980
and year < 1990" at the moment.
--- NEW FILE: dbinterface.c ---
#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;
}
--- NEW FILE: token.c ---
#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;
}
}
--- NEW FILE: dbinterface.h ---
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);
--- NEW FILE: Makefile ---
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id: Makefile,v 1.1 2005/04/28 12:33:38 hcl Exp $
#
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)
--- NEW FILE: token.h ---
#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);
--- NEW FILE: parser.c ---
#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;
}
--- NEW FILE: searchengine.c ---
/***************************************************************************
* __________ __ ___.
* 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;
}
--- NEW FILE: parser.h ---
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);
--- NEW FILE: searchengine.h ---
/***************************************************************************
* __________ __ ___.
* 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
_______________________________________________
http://cool.haxx.se/mailman/listinfo/rockbox-cvs
|