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