Mercurial > hg > sidinfo
changeset 241:c9b57c8fd058
Begin work on STIL database parsing and handling.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 04 Jan 2020 19:00:09 +0200 |
parents | 217f294deea5 |
children | 537420ccd05b |
files | sidlib.c sidlib.h |
diffstat | 2 files changed, 319 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/sidlib.c Sat Jan 04 17:30:48 2020 +0200 +++ b/sidlib.c Sat Jan 04 19:00:09 2020 +0200 @@ -580,3 +580,287 @@ return (item != NULL) ? *item : NULL; } + + +/* STIL database handling functions + */ +int sidlib_stildb_new(SIDLibSTILDB **pdbh) +{ + SIDLibSTILDB *dbh; + if ((dbh = *pdbh = (SIDLibSTILDB *) th_malloc0(sizeof(SIDLibSTILDB))) == NULL) + return THERR_MALLOC; + + return THERR_OK; +} + + +static int sidlib_stildb_node_realloc(SIDLibSTILNode *node, const int nsubTunes) +{ + if (node == NULL) + return THERR_NULLPTR; + + if (nsubTunes <= 0) + return THERR_INVALID_ARGS; + + // Re-allocate subTune structure if needed + if (nsubTunes > node->nsubTunes) + { + size_t clearIndex, clearLength; + + node->subTunes = (SIDLibSTILSubNode **) th_realloc(node->subTunes, (nsubTunes + 1) * sizeof(SIDLibSTILSubNode **)); + if (node->subTunes == NULL) + return THERR_MALLOC; + + // Clear the newly allocated memory + if (node->nsubTunes == 0) + { + clearIndex = 0; + clearLength = nsubTunes + 1; + } + else + { + clearIndex = node->nsubTunes + 1; + clearLength = nsubTunes - clearIndex + 1; + } + + memset(&(node->subTunes[clearIndex]), 0, clearLength * sizeof(SIDLibSTILSubNode **)); + + node->nsubTunes = nsubTunes; + } + + // Allocate memory for subTune + if (node->subTunes[nsubTunes] == NULL) + { + node->subTunes[nsubTunes] = (SIDLibSTILSubNode *) th_malloc0(sizeof(SIDLibSTILSubNode)); + if (node->subTunes[nsubTunes] == NULL) + return THERR_MALLOC; + } + + return THERR_OK; +} + + +static void sidlib_stildb_node_free(SIDLibSTILNode *node) +{ + if (node != NULL) + { + for (int i = 0; i <= node->nsubTunes; i++) + { + SIDLibSTILSubNode *subTune = node->subTunes[i]; + if (subTune != NULL) + { + for (int field = 0; field < STF_LAST; field++) + th_free(subTune->fields[field]); + + th_free(subTune); + } + } + + th_free(node->subTunes); + th_free(node->filename); + th_free(node); + } +} + + +static int sidlib_stildb_node_new(SIDLibSTILNode **pnode, const char *filename) +{ + // Allocate memory for new node + SIDLibSTILNode *node; + int res; + + if ((node = *pnode = (SIDLibSTILNode *) th_malloc0(sizeof(SIDLibSTILNode))) == NULL) + return THERR_MALLOC; + + // Allocate filename and initial space for one subtune + if ((node->filename = th_strdup(filename)) == NULL) + return THERR_MALLOC; + + if ((res = sidlib_stildb_node_realloc(node, 1)) != THERR_OK) + { + sidlib_stildb_node_free(node); + return res; + } + + return res; +} + + +/* Read database (additively) to given db-structure + */ +enum +{ + PM_EOF, + PM_ERROR, + PM_IDLE, + PM_COMMENT, + PM_NEXT, + PM_ENTRY, + PM_FIELD_NAME, + PM_FIELD_DATA, + PM_SUBTUNE, + + PM_LAST +}; + + +static const char *sidlib_stil_fields[STF_LAST] = +{ + "NAME", + "AUTHOR", + "TITLE", + "INFO", + + // STF_LAST +}; + + +typedef struct +{ + size_t lineNum; + int ch, prevMode, nextMode, parseMode; + BOOL lineStart; +} SIDLibSTILParserCtx; + + +static int sidlib_stildb_get_field(const char *name) +{ + for (int n = 0; n < STF_LAST; n++) + { + if (strcmp(sidlib_stil_fields[n], name) == 0) + return n; + } + + return -1; +} + + +static void sidlib_stildb_set_parsemode(SIDLibSTILParserCtx *ctx, const int mode) +{ + ctx->prevMode = ctx->parseMode; + ctx->parseMode = mode; +} + + +static void sidlib_stildb_set_next_parsemode(SIDLibSTILParserCtx *ctx, const int mode) +{ + sidlib_stildb_set_parsemode(ctx, PM_NEXT); + ctx->nextMode = mode; +} + + +#define VADDCH(ch) if (strPos < SIDLIB_BUFFER_SIZE) { tmpStr[strPos++] = ch; } + + +int sidlib_stildb_read(th_ioctx *fh, SIDLibSTILDB *dbh) +{ + int ret = THERR_OK; + SIDLibSTILParserCtx ctx; + char *tmpStr = NULL; + size_t strPos; + + if (fh == NULL || dbh == NULL) + return THERR_NULLPTR; + + if ((tmpStr = th_malloc(SIDLIB_BUFFER_SIZE + 1)) == NULL) + return THERR_MALLOC; + + // Initialize values + memset(&ctx, 0, sizeof(ctx)); + ctx.nextMode = ctx.prevMode = ctx.parseMode = PM_IDLE; + ctx.ch = -1; + ctx.lineStart = TRUE; + strPos = 0; + + // Parse the STIL database + +out: + th_free(tmpStr); + + if (ret == THERR_OK && ctx.parseMode == PM_ERROR) + ret = THERR_INVALID_DATA; + + return ret; +} + + +/* Compare two nodes + */ +static int sidlib_stildb_cmp(const void *node1, const void *node2) +{ + // We assume here that we never ever get NULL-pointers or similar + return strcmp( + (*(SIDLibSTILNode * *) node1)->filename, + (*(SIDLibSTILNode * *) node2)->filename); +} + + +/* (Re)create index + */ +int sidlib_stildb_build_index(SIDLibSTILDB *dbh) +{ + if (dbh == NULL) + return THERR_NULLPTR; + + // Free old index + th_free_r(&(dbh->pindex)); + + // Get size of db + dbh->nnodes = th_llist_length((th_llist_t *) dbh->nodes); + + // Check number of nodes + if (dbh->nnodes > 0) + { + SIDLibSTILNode *node; + size_t i; + + // XXX TODO Check number of nodes? + + // Allocate memory for index-table + dbh->pindex = (SIDLibSTILNode **) th_malloc(sizeof(SIDLibSTILNode *) * dbh->nnodes); + if (dbh->pindex == NULL) + return THERR_MALLOC; + + // Get node-pointers to table + for (i = 0, node = dbh->nodes; node != NULL && i < dbh->nnodes; + node = (SIDLibSTILNode *) node->node.next) + dbh->pindex[i++] = node; + + // Sort the indexes + qsort(dbh->pindex, dbh->nnodes, sizeof(SIDLibSTILNode *), sidlib_stildb_cmp); + } + + return THERR_OK; +} + + +/* Free a given STIL database + */ +void sidlib_stildb_free(SIDLibSTILDB *dbh) +{ + if (dbh != NULL) + { + th_llist_free_func((th_llist_t *) dbh->nodes, + (void (*)(void *)) sidlib_stildb_node_free); + + dbh->nodes = NULL; + dbh->nnodes = 0; + + th_free_r(&dbh->pindex); + th_free(dbh); + } +} + + +/* Get STIL information node from database + */ +SIDLibSTILNode *sidlib_stildb_get_node(SIDLibSTILDB *dbh, const char *filename) +{ + SIDLibSTILNode keyItem, *key, **item; + + keyItem.filename = (char *) filename; + key = &keyItem; + item = bsearch(&key, dbh->pindex, dbh->nnodes, sizeof(SIDLibSTILNode *), sidlib_stildb_cmp); + + return item != NULL ? *item : NULL; +}
--- a/sidlib.h Sat Jan 04 17:30:48 2020 +0200 +++ b/sidlib.h Sat Jan 04 19:00:09 2020 +0200 @@ -47,6 +47,18 @@ }; +// STIL database subtune fields, see SIDLibSTILSubNode +enum +{ + STF_NAME, + STF_AUTHOR, + STF_TITLE, + STF_INFO, + + STF_LAST +}; + + // // Structures // @@ -69,6 +81,29 @@ typedef struct { + char *fields[STF_LAST]; +} SIDLibSTILSubNode; + + +typedef struct +{ + th_llist_t node; + + char *filename; + int nsubTunes; + SIDLibSTILSubNode **subTunes; +} SIDLibSTILNode; + + +typedef struct +{ + SIDLibSTILNode *nodes, **pindex; + size_t nnodes; +} SIDLibSTILDB; + + +typedef struct +{ char magic[SIDLIB_PSID_MAGIC_LEN + 1]; // "PSID" / "RSID" magic identifier uint16_t version, // Version number