Mercurial > hg > xmms-sid
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 } |