comparison src/xs_stil.c @ 1:183e7cbc1036

Initial revision
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 03 Jun 2003 10:23:04 +0000
parents
children 1788f4ce6a44
comparison
equal deleted inserted replaced
0:5ce0a94edc2e 1:183e7cbc1036
1 /*
2 xmms-sid - SIDPlay input plugin for X MultiMedia System (XMMS)
3
4 STIL-database parsing functions
5
6 Mostly written by Matti "ccr" Hamalainen <mhamalai@ratol.fi>,
7 some parts written by Willem Monsuwe <willem@stack.nl>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 #include "xmms-sid.h"
25 #include <glib.h>
26 #include <stdio.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32
33
34 /* Variables and constants */
35 #define XMMS_SID_MAX_BUFSIZE 2048
36 struct T_sid_stil_info xs_stil_info;
37
38 /*
39 * Utility routines
40 */
41 int xs_strcalloc(gchar **result, gchar *str)
42 {
43 if ((result == NULL) || (str == NULL)) return -1;
44
45 if (*result != NULL) g_free(*result);
46
47 *result = (gchar *) g_malloc(strlen(str)+1);
48
49 if (*result == NULL) return -2;
50
51 strcpy(*result, str);
52
53 return 0;
54 }
55
56
57 int xs_strcat(gchar **result, gchar *str)
58 {
59 if ((result == NULL) || (str == NULL)) return -1;
60
61 *result = (gchar *) g_realloc(*result, strlen(*result) + strlen(str) + 1);
62
63 if (*result == NULL) return -2;
64
65 strcat(*result, str);
66
67 return 0;
68 }
69
70
71 /*
72 * Make lowercase, strip evt. extension
73 */
74 static gchar * uncase_strip_fn(gchar *str)
75 {
76 gchar *res;
77 gint i, l;
78
79 l = str ? strlen(str) : 0;
80
81 res = strrchr(str, '/');
82
83 if (res) res = strrchr(res, '.');
84
85 if (res) l = (res - str);
86
87 res = g_new(gchar, l + 1);
88
89 for (i = 0; i < l; i++) {
90 res[i] = tolower(str[i]);
91 }
92
93 res[i] = '\0';
94
95 return res;
96 }
97
98
99 static gchar * xs_get_hvscname(gchar *fname)
100 {
101 gchar *p, *q, *r;
102
103 p = xs_cfg.stilpath;
104
105 q = r = fname;
106
107 while (*p == *q) {
108 if (*q == '/') r = q + 1;
109 p++; q++;
110 }
111
112 return r;
113 }
114
115
116 /*
117 * Get line (string) from given file to given buffer.
118 * Takes care of winDOS CR/LF and *NIX LF formats.
119 */
120 void stil_get_line(gchar *buf, gint bufsize, FILE *f)
121 {
122 gint i;
123
124 /* Get the string */
125 fgets(buf, bufsize-1, f);
126
127 /* The file may be in DOS CR-LF format,
128 so check for the line endings and
129 remove the \n and \r accordingly
130 */
131 i = strlen(buf);
132 if (i > 0) {
133 if (buf[i-2] == '\r')
134 buf[i-2] = '\0';
135 else
136 buf[i-1] = '\0';
137 }
138 }
139
140
141 /*
142 xs_token_skipsp(buf, j);
143 token2 = xs_token_getcopy(buf, j, ')');
144 */
145 gint stil_token_skipsp(gchar *buf, gint i)
146 {
147 gint len = strlen(buf);
148
149 while ((i < len) && ((buf[i] == 32) || (buf[i] == '\t'))) i++;
150
151 return i;
152 }
153
154
155 gchar * stil_token_get(gchar *buf, gint i, gchar c)
156 {
157 gint j, len = strlen(buf);
158 gchar *res;
159
160 /* Find out the end place */
161 j = i;
162 while ((buf[j] != c) && (j < len)) j++;
163
164 /* Malloc some memory */
165 len = (j - i);
166 res = (gchar *) g_malloc(len+1);
167 if (res == NULL) return NULL;
168
169 /* Return the token */
170 strncpy(res, &buf[i], len);
171 res[len] = '\0';
172
173 return res;
174 }
175
176
177 /*
178 * Clear the informations
179 */
180 void xs_stil_clearone(T_sid_stil_subtune *tune)
181 {
182 xs_strcalloc(&tune->title, "\0");
183 xs_strcalloc(&tune->name, "\0");
184 xs_strcalloc(&tune->artist, "\0");
185 xs_strcalloc(&tune->comment, "\0");
186 }
187
188 void xs_stil_clear(void)
189 {
190 int i;
191
192 for (i = 0; i < XMMS_SID_STIL_MAXENTRY; i++)
193 xs_stil_clearone(&xs_stil_info.subtune[i]);
194 }
195
196
197 /*
198 * Simple string-list handling functions
199 */
200 typedef struct {
201 gint nitems;
202 gchar * * items;
203 } T_stringlist;
204
205
206 int sl_insert(T_stringlist *list, gchar *str)
207 {
208 gchar *res;
209
210 /* Check the list pointer */
211 if (list == NULL) return -1;
212 if (str == NULL) return -2;
213
214 /* Increase the space in pointer list */
215 list->nitems++;
216
217 list->items = (gchar * *) g_realloc(list->items, (sizeof(gchar **) * list->nitems));
218 if (list->items == NULL) return -3;
219
220 /* Allocate space for the string */
221 res = (gchar *) g_malloc(strlen(str) + 1);
222 if (res == NULL) return -4;
223
224 /* Put the data in */
225 strcpy(res, str);
226 list->items[(list->nitems - 1)] = res;
227
228 /* Return number of items */
229 return (list->nitems);
230 }
231
232
233 gchar * sl_getitem(T_stringlist *list, gint n)
234 {
235 /* Check the list pointer */
236 if (list == NULL) return NULL;
237 if (list->items == NULL) return NULL;
238
239 /* Check the argument */
240 if ((n >= 0) && (n < list->nitems)) return (list->items[n]);
241
242 return NULL;
243 }
244
245
246 int sl_clear(T_stringlist *list)
247 {
248 /* Check the list pointer */
249 if (list == NULL) return -1;
250
251 /* Clear the variables */
252 list->nitems = 0;
253 list->items = NULL;
254
255 return 0;
256 }
257
258
259 int sl_free(T_stringlist *list)
260 {
261 gint i;
262
263 /* Check the list pointer */
264 if (list == NULL) return -1;
265
266 /* Check the items */
267 if (list->items != NULL)
268 {
269 /* Free all strings in list, if any */
270 for (i = 0; i < list->nitems; i++)
271 {
272 if (list->items[i] != NULL)
273 free(list->items[i]);
274 }
275
276 /* Free the list itself */
277 free(list->items);
278 }
279
280 /* Clear the data */
281 list->nitems = 0;
282 list->items = NULL;
283
284 return 0;
285 }
286
287
288 /*
289 * "Submit" all gathered "lists" to given tunedef
290 */
291 void xs_stil_submit(T_sid_stil_subtune *tune, T_stringlist *iartist,
292 T_stringlist *icomment, T_stringlist *iname, T_stringlist *ititle)
293 {
294 gchar *tmpstr;
295 gint i, ok;
296
297 /* Clear the data */
298 xs_stil_clearone(tune);
299
300 /* "Submit" lists to tunedata */
301 if ((iartist->nitems > 1) ||
302 (icomment->nitems > 1) ||
303 (iname->nitems > 1) ||
304 (ititle->nitems > 1))
305 {
306 /* Multiple items per category */
307 i = 0;
308 ok = 1;
309 while (ok) {
310 /* Clear the flag */
311 ok = 0;
312
313 /* Get items from lists */
314 tmpstr = sl_getitem(iartist, i);
315 if (tmpstr != NULL) {
316 xs_strcat(&tune->comment, "\nArtist: ");
317 xs_strcat(&tune->comment, tmpstr);
318 ok = 1;
319 }
320
321 tmpstr = sl_getitem(icomment, i);
322 if (tmpstr != NULL) {
323 xs_strcat(&tune->comment, "\nComment: ");
324 xs_strcat(&tune->comment, tmpstr);
325 ok = 1;
326 }
327
328 tmpstr = sl_getitem(iname, i);
329 if (tmpstr != NULL) {
330 xs_strcat(&tune->comment, "\nName: ");
331 xs_strcat(&tune->comment, tmpstr);
332 ok = 1;
333 }
334
335 tmpstr = sl_getitem(ititle, i);
336 if (tmpstr != NULL) {
337 xs_strcat(&tune->comment, "\nTitle: ");
338 xs_strcat(&tune->comment, tmpstr);
339 ok = 1;
340 }
341
342 /* Next one */
343 i++;
344 }
345 } else
346 {
347 /* Only one item or none */
348 tmpstr = sl_getitem(iartist, 0);
349 if (tmpstr != NULL) xs_strcalloc(&tune->artist, tmpstr);
350
351 tmpstr = sl_getitem(icomment, 0);
352 if (tmpstr != NULL) xs_strcalloc(&tune->comment, tmpstr);
353
354 tmpstr = sl_getitem(iname, 0);
355 if (tmpstr != NULL) xs_strcalloc(&tune->name, tmpstr);
356
357 tmpstr = sl_getitem(ititle, 0);
358 if (tmpstr != NULL) xs_strcalloc(&tune->title, tmpstr);
359 }
360
361 /* Free the lists */
362 sl_free(iartist);
363 sl_free(icomment);
364 sl_free(iname);
365 sl_free(ititle);
366 }
367
368
369 /*
370 * Parse all STIL data for one song (subsongs, etc)
371 */
372 int xs_stil_parse_entry(FILE *stilf, gchar *buf, gint bufsize)
373 {
374 T_stringlist iartist, icomment, iname, ititle;
375 gchar *token1, *token2, *tmpbuf;
376 gint ntune, found, found2;
377 gint i, j;
378
379 XSDEBUG("token '%s':\n", buf);
380
381 /* Clear and initialize variables */
382 ntune = 0;
383
384 sl_clear(&iartist);
385 sl_clear(&icomment);
386 sl_clear(&iname);
387 sl_clear(&ititle);
388
389 tmpbuf = NULL;
390
391 /* Ok, it was found! Now get and parse the data */
392 found = ntune = 0;
393
394 while ((!feof(stilf)) && (found == 0)) {
395 /* Get line from file */
396 stil_get_line(buf, bufsize, stilf);
397
398 nreadln:
399
400 /* Check for empty (end of STIL record) */
401 if (buf[0] == '\0') found = 1; else
402
403 {
404 /* Skip whitespaces and get first token */
405 j = 0;
406 token1 = (gchar *) (buf);
407
408 /* Check for data types and act accordingly */
409 if (token1[0] == '(') {
410 j = stil_token_skipsp(buf, j+1);
411 if (buf[j] == '#') {
412 token2 = stil_token_get(buf, j+1, ')');
413 i = atoi(token2);
414
415 if ((i >= 1) || (i < XMMS_SID_STIL_MAXENTRY)) {
416
417 xs_stil_submit(&xs_stil_info.subtune[ntune],
418 &iartist,
419 &icomment,
420 &iname,
421 &ititle);
422
423 ntune = i;
424
425 XSDEBUG("tune_num: '%d'\n", ntune);
426 }
427
428 g_free(token2);
429 }
430 } else
431
432 if (!strncmp(token1, "COMMENT:", 8)) {
433 j = stil_token_skipsp(buf, j + 8);
434 token1 = (gchar *) (buf + j);
435
436 if (xs_strcalloc(&tmpbuf, token1)) return -4;
437
438 found2 = 0;
439 while ((!feof(stilf)) && (found2 == 0)) {
440
441 /* Read next entry line */
442 j = 0;
443 stil_get_line(buf, bufsize, stilf);
444
445 /* Check if the comment continues? */
446 if (strncmp(" ", buf, 9) != 0) {
447 found2 = 1;
448 } else {
449
450 /* Get the comment line and parse it */
451 j = stil_token_skipsp(buf, j + 9);
452 token1 = (gchar *) (buf + j);
453
454 /* Cat to the end */
455 if (xs_strcat(&tmpbuf, " ") < 0) return -4;
456 if (xs_strcat(&tmpbuf, token1) < 0) return -4;
457
458 } /* if..else */
459 } /* while */
460
461
462 /* Insert the result */
463 XSDEBUG("comment: '%s'\n", tmpbuf);
464 sl_insert(&icomment, tmpbuf);
465
466 if (tmpbuf != NULL) free(tmpbuf);
467 tmpbuf = NULL;
468
469 goto nreadln; /* EVIL GOTO! */
470 } else
471
472 if (!strncmp(token1, " TITLE:", 8)) {
473 j = stil_token_skipsp(buf, j + 8);
474 token1 = (gchar *) (buf + j);
475
476 XSDEBUG("title : '%s'\n", token1);
477 sl_insert(&ititle, token1);
478 } else
479
480 if (!strncmp(token1, " ARTIST:", 8)) {
481 j = stil_token_skipsp(buf, j + 8);
482 token1 = (gchar *) (buf + j);
483
484 XSDEBUG("artist : '%s'\n", token1);
485 sl_insert(&iartist, token1);
486 } else
487
488 if (!strncmp(token1, " NAME:", 8)) {
489 j = stil_token_skipsp(buf, j + 8);
490 token1 = (gchar *) (buf + j);
491
492 XSDEBUG("name : '%s'\n", token1);
493 sl_insert(&iname, token1);
494 }
495 }
496
497 } /* while */
498
499
500 /* Submit the last entry */
501 xs_stil_submit(&xs_stil_info.subtune[ntune],
502 &iartist,
503 &icomment,
504 &iname,
505 &ititle);
506
507
508 XSDEBUG("end of tunedef.\n");
509 return 0;
510 }
511
512
513 /*
514 * Main routine for searching the STIL-database file
515 */
516 int xs_stil_get(gchar *sidfn)
517 {
518 FILE *stilf;
519 gchar *e, *a, *buf;
520 guint bufsize;
521 gint found, i, result;
522 struct stat stilst;
523
524
525 /* Clear the STIL info */
526 xs_stil_clear();
527
528 /* Check the given STIL database filename */
529 if ((!xs_cfg.stilpath || !xs_cfg.stilpath[0])) return -1;
530
531 /* Check if the STIL database file exists */
532 if (stat(xs_cfg.stilpath, &stilst) < 0) return -1;
533
534 /* Try to allocate the temporary buffer */
535 bufsize = (XMMS_SID_MAX_BUFSIZE + 1);
536 buf = (gchar *) g_malloc(bufsize);
537 if (buf == NULL) return -2;
538
539
540 /* Try to open the STIL database file */
541 stilf = fopen(xs_cfg.stilpath, "r");
542 if (!stilf) return -3;
543
544 /* -- */
545 e = uncase_strip_fn(xs_get_hvscname(sidfn));
546 XSDEBUG("sfn = '%s'\n", e);
547
548 result = found = 0;
549
550 while ((!feof(stilf)) && (found == 0)) {
551
552 stil_get_line(buf, bufsize, stilf);
553
554 /* Ignore everything else until a filename is found */
555 if (buf[0] == '/') {
556
557 /* Check against our sidname */
558 a = uncase_strip_fn((gchar *) (buf+1));
559 i = strcmp(a, e);
560 g_free(a);
561
562 /* Parse entry if found */
563 if (!i) {
564 result = xs_stil_parse_entry(stilf, buf, bufsize);
565 found = 1;
566 }
567
568 } /* if (buf[0]... */
569
570 } /* while */
571
572 /* Shutdown & close */
573 g_free(e);
574 g_free(buf);
575
576 if (!fclose(stilf)) return -3;
577
578 /* Successful return ?? */
579 if ((found) && (result >= 0))
580 return 0;
581 else
582 return 1;
583 }