slow and steady

This commit is contained in:
Ron Pedde 2005-10-13 07:38:22 +00:00
parent edf3885e0b
commit fb7931ad30
1 changed files with 170 additions and 61 deletions

View File

@ -16,16 +16,15 @@
#include "err.h" #include "err.h"
typedef struct tag_token {
typedef struct tag_tokens {
int token_id; int token_id;
int token_type;
union { union {
char *cvalue; char *cvalue;
int ivalue; int ivalue;
} data; } data;
} SP_TOKENS; } SP_TOKEN;
/*
#define T_ID 0x00 #define T_ID 0x00
#define T_PATH 0x01 #define T_PATH 0x01
#define T_TITLE 0x02 #define T_TITLE 0x02
@ -63,76 +62,186 @@ typedef struct tag_tokens {
#define T_FORCE_UPDATE 0x1f #define T_FORCE_UPDATE 0x1f
#define T_CODECTYPE 0x20 #define T_CODECTYPE 0x20
#define T_IDX 0x21 #define T_IDX 0x21
*/
/**
* high 4 bits:
*
* 0x8000 -
* 0x4000 -
* 0x2000 - data is string
* 0x1000 - data is int
*/
#define TT_INT 0 #define T_STRING 0x2001
#define TT_STRING 1 #define T_INT_FIELD 0x1002
#define TT_DATE 2 #define T_STRING_FIELD 0x2003
#define T_DATE_FIELD 0x1004
SP_TOKENS sp_tokenlist[] = { #define T_OPENPAREN 0x0005
{ T_ID, TT_INT, { "id" } }, #define T_CLOSEPAREN 0x0006
{ T_PATH, TT_STRING, { "path" } }, #define T_QUOTE 0x0007
{ T_TITLE, TT_STRING, { "title" } }, #define T_LESS 0x0008
{ T_ARTIST, TT_STRING, { "artist" } }, #define T_LESSEQUAL 0x0009
{ T_ALBUM, TT_STRING, { "album" } }, #define T_GREATER 0x000A
{ T_GENRE, TT_STRING, { "genre" } }, #define T_GREATEREQUAL 0x000B
{ T_COMMENT, TT_STRING, { "comment" } }, #define T_EQUAL 0x000C
{ T_TYPE, TT_STRING, { "type" } },
{ T_COMPOSER, TT_STRING, { "composer" } }, #define T_EOF 0x000D
{ T_ORCHESTRA, TT_STRING, { "orchestra" } }, #define T_BOF 0x000E
{ T_GROUPING, TT_STRING, { "grouping" } },
{ T_URL, TT_STRING, { "url" } }, typedef struct tag_fieldlookup {
{ T_BITRATE, TT_INT, { "bitrate" } }, int type;
{ T_SAMPLERATE, TT_INT, { "samplerate" } }, char *name;
{ T_SONG_LENGTH, TT_INT, { "songlength" } }, } FIELDLOOKUP;
{ T_FILE_SIZE, TT_INT, { "filesize" } },
{ T_YEAR, TT_INT, { "year" } }, FIELDLOOKUP sp_fields[] = {
{ T_TRACK, TT_INT, { "track" } }, { T_INT_FIELD, "id" },
{ T_TOTAL_TRACKS, TT_INT, { "totaltracks" } }, { T_STRING_FIELD, "path" },
{ T_DISC, TT_INT, { "disc" } }, { T_STRING_FIELD, "title" },
{ T_TOTAL_DISCS, TT_INT, { "totaldiscs" } }, { T_STRING_FIELD, "artist" },
{ T_BPM, TT_INT, { "bpm" } }, { T_STRING_FIELD, "album" },
{ T_COMPILATION, TT_INT, { "compilation" } }, { T_STRING_FIELD, "genre" },
{ T_RATING, TT_INT, { "rating" } }, { T_STRING_FIELD, "comment" },
{ T_PLAYCOUNT, TT_INT, { "playcount"} }, { T_STRING_FIELD, "type" },
{ T_DATA_KIND, TT_INT, { "datakind" } }, { T_STRING_FIELD, "composer" },
{ T_ITEM_KIND, TT_INT, { "itemkind" } }, { T_STRING_FIELD, "orchestra" },
{ T_DESCRIPTION, TT_STRING, { "description" } }, { T_STRING_FIELD, "grouping" },
{ 0, 0, { NULL } } { T_STRING_FIELD, "url" },
{ T_INT_FIELD, "bitrate" },
{ T_INT_FIELD, "samplerate" },
{ T_INT_FIELD, "songlength" },
{ T_INT_FIELD, "filesize" },
{ T_INT_FIELD, "year" },
{ T_INT_FIELD, "track" },
{ T_INT_FIELD, "totaltracks" },
{ T_INT_FIELD, "disc" },
{ T_INT_FIELD, "totaldiscs" },
{ T_INT_FIELD, "bpm" },
{ T_INT_FIELD, "compilation" },
{ T_INT_FIELD, "rating" },
{ T_INT_FIELD, "playcount" },
{ T_INT_FIELD, "datakind" },
{ T_INT_FIELD, "itemkind" },
{ T_STRING_FIELD, "description" },
{ 0, NULL },
}; };
typedef struct tag_parsetree { typedef struct tag_parsetree {
char *term; char *term;
char *current; char *current;
int token; SP_TOKEN token;
int next_token; SP_TOKEN next_token;
} PARSESTRUCT, *PARSETREE; } PARSESTRUCT, *PARSETREE;
#define SP_TOK_BOF 0x0 /**
#define SP_TOK_EOF 0x1 * scan the input, returning the next available token.
*
* @param tree current working parse tree.
* @returns next token (token, not the value)
*/
int sp_scan(PARSETREE tree) { int sp_scan(PARSETREE tree) {
char *tail; char *tail;
int done=0; int advance=0;
FIELDLOOKUP *pfield=sp_fields;
int len;
if(tree->token.token_id & 0x2000) {
if(tree->token.data.cvalue)
free(tree->token.data.cvalue);
}
tree->token=tree->next_token; tree->token=tree->next_token;
if(tree->token == SP_TOK_EOF) if(tree->token.token_id == T_EOF)
return SP_TOK_EOF; return T_EOF;
/* keep advancing until we have a token */ /* keep advancing until we have a token */
while(strchr(" \t\n\r",*current)) while(strchr(" \t\n\r",*(tree->current)))
current++; tree->current++;
if(!current) { if(!*(tree->current)) {
tree->next_token = SP_TOK_EOF; tree->next_token.token_id = T_EOF;
return tree->token; return tree->token.token_id;
} }
/* check singletons */ /* check singletons */
switch(*(tree->current)) {
case '=':
advance=1;
tree->next_token.token_id = T_EQUAL;
break;
case '<':
if((*(tree->current + 1)) == '=') {
advance = 2;
tree->next_token.token_id = T_LESSEQUAL;
} else {
advance = 1;
tree->next_token.token_id = T_LESS;
}
break;
case '>':
if((*(tree->current + 1)) == '=') {
advance = 2;
tree->next_token.token_id = T_GREATEREQUAL;
} else {
advance = 1;
tree->next_token.token_id = T_GREATER;
}
break;
case '(':
advance=1;
tree->next_token.token_id = T_OPENPAREN;
break;
return tree->token; case ')':
advance=1;
tree->next_token.token_id = T_CLOSEPAREN;
break;
case '"':
advance=1;
tree->next_token.token_id = T_QUOTE;
break;
}
if(advance) {
tree->current += advance;
} else { /* either a keyword token or a quoted string */
/* walk to a terminator */
tail = tree->current;
while((*tail) && (!strchr(" \t\n\r\"=()",*tail))) {
tail++;
}
tree->current = tail;
/* let's see what we have... */
pfield=sp_fields;
len = tail - tree->current;
while(pfield->name) {
if(strlen(pfield->name) == len) {
if(strncasecmp(pfield->name,tree->current,len) == 0)
break;
}
pfield++;
}
if(pfield->name) {
tree->next_token.token_id = pfield->type;
tree->next_token.data.cvalue = malloc(len + 1);
if(!tree->next_token.data.cvalue) {
/* fail on malloc error */
DPRINTF(E_FATAL,L_PARSE,"Malloc error.\n");
}
strncpy(tree->next_token.data.cvalue,tree->current,len);
tree->next_token.data.cvalue[len] = '\x0';
}
}
return tree->token.token_id;
} }
@ -162,10 +271,10 @@ PARSETREE sp_init(void) {
int sp_parse(PARSETREE tree, char *term) { int sp_parse(PARSETREE tree, char *term) {
tree->term = strdup(term); /* will be destroyed by parsing */ tree->term = strdup(term); /* will be destroyed by parsing */
tree->current=tree->term; tree->current=tree->term;
tree->token=SP_TOK_BOF; tree->token.token_id=T_BOF;
tree->next_token=SP_TOK_BOF; tree->next_token.token_id=T_BOF;
while(sp_scan(tree)) { while(sp_scan(tree)) {
if(tree->token == SP_TOK_EOF) if((tree->token.token_id = T_EOF))
return 1; /* valid tree! */ return 1; /* valid tree! */
/* otherwise, keep scanning until done or error */ /* otherwise, keep scanning until done or error */