Mercurial > hg > xmms-sid
view src/xs_stil.c @ 40:1788f4ce6a44
Numerous changes towards 0.8
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 19 Jun 2003 22:38:01 +0000 |
parents | 183e7cbc1036 |
children | 0d1df20745dd |
line wrap: on
line source
/* xmms-sid - SIDPlay input plugin for X MultiMedia System (XMMS) STIL-database parsing functions Mostly written by Matti "ccr" Hamalainen <ccr@tnsp.org>, some parts written by Willem Monsuwe <willem@stack.nl> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "xmms-sid.h" #include <glib.h> #include <stdio.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <ctype.h> /* Variables and constants */ #define XMMS_SID_MAX_BUFSIZE 2048 struct T_sid_stil_info xs_stil_info; /* * Utility routines */ int xs_strcalloc(gchar **result, gchar *str) { if ((result == NULL) || (str == NULL)) return -1; if (*result != NULL) g_free(*result); *result = (gchar *) g_malloc(strlen(str)+1); if (*result == NULL) return -2; strcpy(*result, str); return 0; } int xs_strcat(gchar **result, gchar *str) { if ((result == NULL) || (str == NULL)) return -1; *result = (gchar *) g_realloc(*result, strlen(*result) + strlen(str) + 1); if (*result == NULL) return -2; strcat(*result, str); return 0; } /* * Make lowercase, strip evt. extension */ static gchar * uncase_strip_fn(gchar *str) { gchar *res; gint i, l; l = str ? strlen(str) : 0; res = strrchr(str, '/'); if (res) res = strrchr(res, '.'); if (res) l = (res - str); res = g_new(gchar, l + 1); for (i = 0; i < l; i++) { res[i] = tolower(str[i]); } res[i] = '\0'; return res; } static gchar * xs_get_hvscname(gchar *fname) { gchar *p, *q, *r; p = xs_cfg.stilpath; q = r = fname; while (*p == *q) { if (*q == '/') r = q + 1; p++; q++; } return r; } /* * Get line (string) from given file to given buffer. * Takes care of winDOS CR/LF and *NIX LF formats. */ void stil_get_line(gchar *buf, gint bufsize, FILE *f) { gint i; /* Get the string */ fgets(buf, bufsize-1, f); /* The file may be in DOS CR-LF format, so check for the line endings and remove the \n and \r accordingly */ i = strlen(buf); if (i > 0) { if (buf[i-2] == '\r') buf[i-2] = '\0'; else buf[i-1] = '\0'; } } /* xs_token_skipsp(buf, j); token2 = xs_token_getcopy(buf, j, ')'); */ gint stil_token_skipsp(gchar *buf, gint i) { gint len = strlen(buf); while ((i < len) && ((buf[i] == 32) || (buf[i] == '\t'))) i++; return i; } gchar * stil_token_get(gchar *buf, gint i, gchar c) { gint j, len = strlen(buf); gchar *res; /* Find out the end place */ j = i; while ((buf[j] != c) && (j < len)) j++; /* Malloc some memory */ len = (j - i); res = (gchar *) g_malloc(len+1); if (res == NULL) return NULL; /* Return the token */ strncpy(res, &buf[i], len); res[len] = '\0'; return res; } /* * Clear the informations */ void xs_stil_clearone(T_sid_stil_subtune *tune) { xs_strcalloc(&tune->title, "\0"); xs_strcalloc(&tune->name, "\0"); xs_strcalloc(&tune->artist, "\0"); xs_strcalloc(&tune->comment, "\0"); } void xs_stil_clear(void) { int i; for (i = 0; i < XMMS_SID_STIL_MAXENTRY; i++) xs_stil_clearone(&xs_stil_info.subtune[i]); } /* * Simple string-list handling functions */ typedef struct { gint nitems; gchar * * items; } T_stringlist; int sl_insert(T_stringlist *list, gchar *str) { gchar *res; /* Check the list pointer */ if (list == NULL) return -1; if (str == NULL) return -2; /* Increase the space in pointer list */ list->nitems++; list->items = (gchar * *) g_realloc(list->items, (sizeof(gchar **) * list->nitems)); if (list->items == NULL) return -3; /* Allocate space for the string */ res = (gchar *) g_malloc(strlen(str) + 1); if (res == NULL) return -4; /* Put the data in */ strcpy(res, str); list->items[(list->nitems - 1)] = res; /* Return number of items */ return (list->nitems); } gchar * sl_getitem(T_stringlist *list, gint n) { /* Check the list pointer */ if (list == NULL) return NULL; if (list->items == NULL) return NULL; /* Check the argument */ if ((n >= 0) && (n < list->nitems)) return (list->items[n]); return NULL; } int sl_clear(T_stringlist *list) { /* Check the list pointer */ if (list == NULL) return -1; /* Clear the variables */ list->nitems = 0; list->items = NULL; return 0; } int sl_free(T_stringlist *list) { gint i; /* Check the list pointer */ if (list == NULL) return -1; /* Check the items */ if (list->items != NULL) { /* Free all strings in list, if any */ for (i = 0; i < list->nitems; i++) { if (list->items[i] != NULL) free(list->items[i]); } /* Free the list itself */ free(list->items); } /* Clear the data */ list->nitems = 0; list->items = NULL; return 0; } /* * "Submit" all gathered "lists" to given tunedef */ void xs_stil_submit(T_sid_stil_subtune *tune, T_stringlist *iartist, T_stringlist *icomment, T_stringlist *iname, T_stringlist *ititle) { gchar *tmpstr; gint i, ok; /* Clear the data */ xs_stil_clearone(tune); /* "Submit" lists to tunedata */ if ((iartist->nitems > 1) || (icomment->nitems > 1) || (iname->nitems > 1) || (ititle->nitems > 1)) { /* Multiple items per category */ i = 0; ok = 1; while (ok) { /* Clear the flag */ ok = 0; /* Get items from lists */ tmpstr = sl_getitem(iartist, i); if (tmpstr != NULL) { xs_strcat(&tune->comment, "\nArtist: "); xs_strcat(&tune->comment, tmpstr); ok = 1; } tmpstr = sl_getitem(icomment, i); if (tmpstr != NULL) { xs_strcat(&tune->comment, "\nComment: "); xs_strcat(&tune->comment, tmpstr); ok = 1; } tmpstr = sl_getitem(iname, i); if (tmpstr != NULL) { xs_strcat(&tune->comment, "\nName: "); xs_strcat(&tune->comment, tmpstr); ok = 1; } tmpstr = sl_getitem(ititle, i); if (tmpstr != NULL) { xs_strcat(&tune->comment, "\nTitle: "); xs_strcat(&tune->comment, tmpstr); ok = 1; } /* Next one */ i++; } } else { /* Only one item or none */ tmpstr = sl_getitem(iartist, 0); if (tmpstr != NULL) xs_strcalloc(&tune->artist, tmpstr); tmpstr = sl_getitem(icomment, 0); if (tmpstr != NULL) xs_strcalloc(&tune->comment, tmpstr); tmpstr = sl_getitem(iname, 0); if (tmpstr != NULL) xs_strcalloc(&tune->name, tmpstr); tmpstr = sl_getitem(ititle, 0); if (tmpstr != NULL) xs_strcalloc(&tune->title, tmpstr); } /* Free the lists */ sl_free(iartist); sl_free(icomment); sl_free(iname); sl_free(ititle); } /* * Parse all STIL data for one song (subsongs, etc) */ int xs_stil_parse_entry(FILE *stilf, gchar *buf, gint bufsize) { T_stringlist iartist, icomment, iname, ititle; gchar *token1, *token2, *tmpbuf; gint ntune, found, found2; gint i, j; XSDEBUG("token '%s':\n", buf); /* Clear and initialize variables */ ntune = 0; sl_clear(&iartist); sl_clear(&icomment); sl_clear(&iname); sl_clear(&ititle); tmpbuf = NULL; /* Ok, it was found! Now get and parse the data */ found = ntune = 0; while ((!feof(stilf)) && (found == 0)) { /* Get line from file */ stil_get_line(buf, bufsize, stilf); nreadln: /* Check for empty (end of STIL record) */ if (buf[0] == '\0') found = 1; else { /* Skip whitespaces and get first token */ j = 0; token1 = (gchar *) (buf); /* Check for data types and act accordingly */ if (token1[0] == '(') { j = stil_token_skipsp(buf, j+1); if (buf[j] == '#') { token2 = stil_token_get(buf, j+1, ')'); i = atoi(token2); if ((i >= 1) || (i < XMMS_SID_STIL_MAXENTRY)) { xs_stil_submit(&xs_stil_info.subtune[ntune], &iartist, &icomment, &iname, &ititle); ntune = i; XSDEBUG("tune_num: '%d'\n", ntune); } g_free(token2); } } else if (!strncmp(token1, "COMMENT:", 8)) { j = stil_token_skipsp(buf, j + 8); token1 = (gchar *) (buf + j); if (xs_strcalloc(&tmpbuf, token1)) return -4; found2 = 0; while ((!feof(stilf)) && (found2 == 0)) { /* Read next entry line */ j = 0; stil_get_line(buf, bufsize, stilf); /* Check if the comment continues? */ if (strncmp(" ", buf, 9) != 0) { found2 = 1; } else { /* Get the comment line and parse it */ j = stil_token_skipsp(buf, j + 9); token1 = (gchar *) (buf + j); /* Cat to the end */ if (xs_strcat(&tmpbuf, " ") < 0) return -4; if (xs_strcat(&tmpbuf, token1) < 0) return -4; } /* if..else */ } /* while */ /* Insert the result */ XSDEBUG("comment: '%s'\n", tmpbuf); sl_insert(&icomment, tmpbuf); if (tmpbuf != NULL) free(tmpbuf); tmpbuf = NULL; goto nreadln; /* EVIL GOTO! */ } else if (!strncmp(token1, " TITLE:", 8)) { j = stil_token_skipsp(buf, j + 8); token1 = (gchar *) (buf + j); XSDEBUG("title : '%s'\n", token1); sl_insert(&ititle, token1); } else if (!strncmp(token1, " ARTIST:", 8)) { j = stil_token_skipsp(buf, j + 8); token1 = (gchar *) (buf + j); XSDEBUG("artist : '%s'\n", token1); sl_insert(&iartist, token1); } else if (!strncmp(token1, " NAME:", 8)) { j = stil_token_skipsp(buf, j + 8); token1 = (gchar *) (buf + j); XSDEBUG("name : '%s'\n", token1); sl_insert(&iname, token1); } } } /* while */ /* Submit the last entry */ xs_stil_submit(&xs_stil_info.subtune[ntune], &iartist, &icomment, &iname, &ititle); XSDEBUG("end of tunedef.\n"); return 0; } /* * Main routine for searching the STIL-database file */ int xs_stil_get(gchar *sidfn) { FILE *stilf; gchar *e, *a, *buf; guint bufsize; gint found, i, result; struct stat stilst; /* Clear the STIL info */ xs_stil_clear(); /* Check the given STIL database filename */ if ((!xs_cfg.stilpath || !xs_cfg.stilpath[0])) return -1; /* Check if the STIL database file exists */ if (stat(xs_cfg.stilpath, &stilst) < 0) return -1; /* Try to allocate the temporary buffer */ bufsize = (XMMS_SID_MAX_BUFSIZE + 1); buf = (gchar *) g_malloc(bufsize); if (buf == NULL) return -2; /* Try to open the STIL database file */ stilf = fopen(xs_cfg.stilpath, "r"); if (!stilf) return -3; /* -- */ e = uncase_strip_fn(xs_get_hvscname(sidfn)); XSDEBUG("sfn = '%s'\n", e); result = found = 0; while ((!feof(stilf)) && (found == 0)) { stil_get_line(buf, bufsize, stilf); /* Ignore everything else until a filename is found */ if (buf[0] == '/') { /* Check against our sidname */ a = uncase_strip_fn((gchar *) (buf+1)); i = strcmp(a, e); g_free(a); /* Parse entry if found */ if (!i) { result = xs_stil_parse_entry(stilf, buf, bufsize); found = 1; } } /* if (buf[0]... */ } /* while */ /* Shutdown & close */ g_free(e); g_free(buf); if (!fclose(stilf)) return -3; /* Successful return ?? */ if ((found) && (result >= 0)) return 0; else return 1; }