From cfa01e2eded5e91a9272d1578e48540199c8b2d8 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Sat, 9 Aug 2008 14:41:29 +0200 Subject: - Rename list to lookup, and change it, so a generic lookup callback that will be called with the retrieved data can be specified. - Add filepath to the database schema. --- dbschema.sql | 1 + include/mp3fs.h | 18 +++++++----- src/mp3_subr.c | 91 ++++++++++++++++++++++++++++++++++++--------------------- src/mp3_vnops.c | 18 +++++++----- 4 files changed, 79 insertions(+), 49 deletions(-) diff --git a/dbschema.sql b/dbschema.sql index 7528591..efa89f5 100644 --- a/dbschema.sql +++ b/dbschema.sql @@ -11,6 +11,7 @@ CREATE TABLE song ( album varchar(200), artistname varchar(200), genrename varchar(200), + filepath varchar(255), year int, PRIMARY KEY(title, artistname, year) ); diff --git a/include/mp3fs.h b/include/mp3fs.h index 46d4deb..aac7435 100644 --- a/include/mp3fs.h +++ b/include/mp3fs.h @@ -17,7 +17,7 @@ void traverse_hierarchy(char *, traverse_fn_t); traverse_fn_t mp3_scan; /* - * Data passed to mp3_list. + * Data passed to mp3_lookup. */ struct filler_data { void *buf; @@ -27,13 +27,17 @@ struct filler_data { #define LIST_DATATYPE_STRING 1 #define LIST_DATATYPE_INT 2 -struct listhandle; -struct listhandle *mp3_list_start(int, struct filler_data *, const char *); -void mp3_list_insert(struct listhandle *, void *, int); -void mp3_list_finish(struct listhandle *); +typedef void lookup_fn_t(void *, const char *); +lookup_fn_t mp3_lookup_list; +struct lookuphandle; -void mp3_list_artist(const char *, struct filler_data *); -void mp3_list_genre(const char *, struct filler_data *); +struct lookuphandle *mp3_lookup_start(int, void *, lookup_fn_t *, const char *); +void mp3_lookup_insert(struct lookuphandle *, void *, int); +void mp3_lookup_finish(struct lookuphandle *); + +void mp3_lookup_artist(const char *, struct filler_data *); +void mp3_lookup_genre(const char *, struct filler_data *); char *mp3_gettoken(const char *, int); int mp3_numtoken(const char *); + #endif diff --git a/src/mp3_subr.c b/src/mp3_subr.c index 896bbba..e6a0ba6 100644 --- a/src/mp3_subr.c +++ b/src/mp3_subr.c @@ -16,14 +16,14 @@ #include #include -struct listhandle { +struct lookuphandle { sqlite3 *handle; sqlite3_stmt *st; const char *query; int field; int count; - void *buf; - fuse_fill_dir_t filler; + void *priv; + lookup_fn_t *lookup; }; sqlite3 *handle; @@ -209,7 +209,8 @@ mp3_scan(char *filepath) break; /* Now, finally insert it. */ ret = sqlite3_prepare_v2(handle, "INSERT INTO song(title, " - "artistname, album, genrename, year) VALUES(?, ?, ?, ?, ?)", + "artistname, album, genrename, year, filepath) " + "VALUES(?, ?, ?, ?, ?, ?)", -1, &st, NULL); if (ret != SQLITE_OK) { warnx("Error preparing insert statement: %s\n", @@ -221,6 +222,7 @@ mp3_scan(char *filepath) sqlite3_bind_text(st, 3, album, -1, SQLITE_STATIC); sqlite3_bind_text(st, 4, genre, -1, SQLITE_STATIC); sqlite3_bind_int(st, 5, year); + sqlite3_bind_text(st, 6, filepath, -1, SQLITE_STATIC); ret = sqlite3_step(st); sqlite3_finalize(st); if (ret != SQLITE_DONE) { @@ -237,18 +239,18 @@ mp3_scan(char *filepath) * Create a handle for listing music with a certain query. Allocate the * resources and return the handle. */ -struct listhandle * -mp3_list_start(int field, struct filler_data *fd, const char *query) +struct lookuphandle * +mp3_lookup_start(int field, void *data, lookup_fn_t *fn, const char *query) { - struct listhandle *lh; + struct lookuphandle *lh; int ret, error; lh = malloc(sizeof(*lh)); if (lh == NULL) return (NULL); - lh->filler = fd->filler; - lh->buf = fd->buf; lh->field = field; + lh->lookup = fn; + lh->priv = data; /* Open database. */ error = sqlite3_open(DBNAME, &lh->handle); if (error) { @@ -269,10 +271,10 @@ mp3_list_start(int field, struct filler_data *fd, const char *query) /* * Insert data that should be searched for in the list. The data is assumed to - * be dynamically allocated, and will be free'd when mp3_list_finish is called! + * be dynamically allocated, and will be free'd when mp3_lookup_finish is called! */ void -mp3_list_insert(struct listhandle *lh, void *data, int type) +mp3_lookup_insert(struct lookuphandle *lh, void *data, int type) { char *str; int val; @@ -290,11 +292,11 @@ mp3_list_insert(struct listhandle *lh, void *data, int type) } /* - * Finish a statement buildup and use the filler to put the returned query data. - * Free the handle when done. + * Finish a statement buildup and use the lookup function to operate on the + * returned data. Free the handle when done. */ void -mp3_list_finish(struct listhandle *lh) +mp3_lookup_finish(struct lookuphandle *lh) { char buf[1024]; const unsigned char *value; @@ -309,11 +311,11 @@ mp3_list_finish(struct listhandle *lh) case SQLITE_INTEGER: val = sqlite3_column_int(lh->st, lh->field); snprintf(buf, sizeof(buf), "%d", val); - lh->filler(lh->buf, (const char *)buf, NULL, 0); + lh->lookup(lh->priv, (const char *)buf); break; case SQLITE_TEXT: value = sqlite3_column_text(lh->st, lh->field); - lh->filler(lh->buf, (const char *)value, NULL, 0); + lh->lookup(lh->priv, (const char *)value); break; // default: // lh->filler(lh->buf, "UNKNOWN TYPE", NULL, 0); @@ -401,24 +403,26 @@ mp3_gettoken(const char *str, int toknum) * List artist given a path. */ void -mp3_list_artist(const char *path, struct filler_data *fd) +mp3_lookup_artist(const char *path, struct filler_data *fd) { - struct listhandle *lh; + struct lookuphandle *lh; char *name, *album; switch (mp3_numtoken(path)) { case 1: - lh = mp3_list_start(0, fd, "SELECT name FROM artist"); + lh = mp3_lookup_start(0, fd, mp3_lookup_list, + "SELECT name FROM artist"); break; case 2: /* So, now we got to find out the artist and list its albums. */ name = mp3_gettoken(path, 2); if (name == NULL) break; - lh = mp3_list_start(0, fd, "SELECT DISTINCT album FROM song, " + lh = mp3_lookup_start(0, fd, mp3_lookup_list, + "SELECT DISTINCT album FROM song, " "artist WHERE song.artistname = artist.name AND artist.name" " LIKE ?"); - mp3_list_insert(lh, name, LIST_DATATYPE_STRING); + mp3_lookup_insert(lh, name, LIST_DATATYPE_STRING); break; case 3: /* List songs in an album. */ @@ -428,34 +432,40 @@ mp3_list_artist(const char *path, struct filler_data *fd) album = mp3_gettoken(path, 3); if (album == NULL) break; - lh = mp3_list_start(0, fd, "SELECT title FROM song, artist " + lh = mp3_lookup_start(0, fd, mp3_lookup_list, + "SELECT title FROM song, artist " "WHERE song.artistname = artist.name AND artist.name " "LIKE ? AND song.album LIKE ?"); - mp3_list_insert(lh, name, LIST_DATATYPE_STRING); - mp3_list_insert(lh, album, LIST_DATATYPE_STRING); + mp3_lookup_insert(lh, name, LIST_DATATYPE_STRING); + mp3_lookup_insert(lh, album, LIST_DATATYPE_STRING); break; } - mp3_list_finish(lh); + mp3_lookup_finish(lh); } +/* + * Looks up tracks given a genre, or all genres. + */ void -mp3_list_genre(const char *path, struct filler_data *fd) +mp3_lookup_genre(const char *path, struct filler_data *fd) { - struct listhandle *lh; + struct lookuphandle *lh; char *genre, *album; switch (mp3_numtoken(path)) { case 1: - lh = mp3_list_start(0, fd, "SELECT name FROM genre"); + lh = mp3_lookup_start(0, fd, mp3_lookup_list, + "SELECT name FROM genre"); break; case 2: genre = mp3_gettoken(path, 2); if (genre == NULL) break; - lh = mp3_list_start(0, fd, "SELECT DISTINCT album FROM song, " + lh = mp3_lookup_start(0, fd, mp3_lookup_list, + "SELECT DISTINCT album FROM song, " "genre WHERE song.genrename = genre.name AND genre.name " "LIKE ?"); - mp3_list_insert(lh, genre, LIST_DATATYPE_STRING); + mp3_lookup_insert(lh, genre, LIST_DATATYPE_STRING); break; case 3: genre = mp3_gettoken(path, 2); @@ -464,12 +474,25 @@ mp3_list_genre(const char *path, struct filler_data *fd) album = mp3_gettoken(path, 3); if (album == NULL) break; - lh = mp3_list_start(0, fd, "SELECT title FROM song, genre WHERE" + lh = mp3_lookup_start(0, fd, mp3_lookup_list, + "SELECT title FROM song, genre WHERE" " song.genrename = genre.name AND genre.name LIKE ? " " AND song.album LIKE ?"); - mp3_list_insert(lh, genre, LIST_DATATYPE_STRING); - mp3_list_insert(lh, album, LIST_DATATYPE_STRING); + mp3_lookup_insert(lh, genre, LIST_DATATYPE_STRING); + mp3_lookup_insert(lh, album, LIST_DATATYPE_STRING); break; } - mp3_list_finish(lh); + mp3_lookup_finish(lh); +} + +/* + * Lookup function for filling given data into a filler. + */ +void +mp3_lookup_list(void *data, const char *str) +{ + struct filler_data *fd; + + fd = (struct filler_data *)data; + fd->filler(fd->buf, str, NULL, 0); } diff --git a/src/mp3_vnops.c b/src/mp3_vnops.c index 1b5c031..fd90883 100755 --- a/src/mp3_vnops.c +++ b/src/mp3_vnops.c @@ -61,7 +61,7 @@ static int mp3_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { struct filler_data fd; - struct listhandle *lh; + struct lookuphandle *lh; filler (buf, ".", NULL, 0); filler (buf, "..", NULL, 0); @@ -82,18 +82,20 @@ static int mp3_readdir (const char *path, void *buf, fuse_fill_dir_t filler, * 3. Return the list of those mp3s. */ if (strncmp(path, "/Artists", 8) == 0) { - mp3_list_artist(path, &fd); + mp3_lookup_artist(path, &fd); return (0); } else if (strncmp(path, "/Genres", 7) == 0) { - mp3_list_genre(path, &fd); + mp3_lookup_genre(path, &fd); return (0); } else if (strcmp(path, "/Tracks") == 0) { - lh = mp3_list_start(0, &fd, "SELECT title FROM song"); - mp3_list_finish(lh); + lh = mp3_lookup_start(0, &fd, mp3_lookup_list, + "SELECT title FROM song"); + mp3_lookup_finish(lh); return (0); } else if (strcmp(path, "/Albums") == 0) { - lh = mp3_list_start(0, &fd, "SELECT DISTINCT album FROM song"); - mp3_list_finish(lh); + lh = mp3_lookup_start(0, &fd, mp3_lookup_list, + "SELECT DISTINCT album FROM song"); + mp3_lookup_finish(lh); return (0); } @@ -102,7 +104,7 @@ static int mp3_readdir (const char *path, void *buf, fuse_fill_dir_t filler, static int mp3_open (const char *path, struct fuse_file_info *fi) { - if (strcmp (path, "/Artists") == 0) + if (strcmp (path, "/Tracks") == 0) return 0; /* * 1. Have a lookup cache for names?. -- cgit v1.2.3