Mercurial > audlegacy
annotate Plugins/Input/sid/xs_stil.c @ 1399:57de7a460283 trunk
[svn] Add missing file.
author | chainsaw |
---|---|
date | Thu, 13 Jul 2006 16:41:48 -0700 |
parents | d0e9693d2115 |
children | f12d7e208b43 |
rev | line source |
---|---|
269 | 1 /* |
2 XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS) | |
3 | |
4 STIL-database handling functions | |
5 | |
6 Programmed and designed by Matti 'ccr' Hamalainen <ccr@tnsp.org> | |
7 (C) Copyright 1999-2005 Tecnic Software productions (TNSP) | |
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 #include "xs_stil.h" | |
24 #include "xs_support.h" | |
25 #include "xs_config.h" | |
26 #include <stdio.h> | |
27 #include <stdlib.h> | |
28 #include <ctype.h> | |
29 | |
30 | |
31 /* Database handling functions | |
32 */ | |
33 static t_xs_stil_node *xs_stildb_node_new(gchar * pcFilename) | |
34 { | |
35 t_xs_stil_node *pResult; | |
36 | |
37 /* Allocate memory for new node */ | |
38 pResult = (t_xs_stil_node *) g_malloc0(sizeof(t_xs_stil_node)); | |
39 if (!pResult) | |
40 return NULL; | |
41 | |
42 pResult->pcFilename = g_strdup(pcFilename); | |
43 if (!pResult->pcFilename) { | |
44 g_free(pResult); | |
45 return NULL; | |
46 } | |
47 | |
48 return pResult; | |
49 } | |
50 | |
51 | |
52 static void xs_stildb_node_free(t_xs_stil_node * pNode) | |
53 { | |
54 gint i; | |
55 | |
56 if (pNode) { | |
57 /* Free subtune information */ | |
58 for (i = 0; i <= XS_STIL_MAXENTRY; i++) { | |
59 g_free(pNode->subTunes[i].pName); | |
60 g_free(pNode->subTunes[i].pAuthor); | |
61 g_free(pNode->subTunes[i].pInfo); | |
62 } | |
63 | |
64 g_free(pNode->pcFilename); | |
65 g_free(pNode); | |
66 } | |
67 } | |
68 | |
69 | |
70 /* Insert given node to db linked list | |
71 */ | |
72 static void xs_stildb_node_insert(t_xs_stildb * db, t_xs_stil_node * pNode) | |
73 { | |
74 assert(db); | |
75 | |
76 if (db->pNodes) { | |
77 /* The first node's pPrev points to last node */ | |
78 LPREV = db->pNodes->pPrev; /* New node's prev = Previous last node */ | |
79 db->pNodes->pPrev->pNext = pNode; /* Previous last node's next = New node */ | |
80 db->pNodes->pPrev = pNode; /* New last node = New node */ | |
81 LNEXT = NULL; /* But next is NULL! */ | |
82 } else { | |
83 db->pNodes = pNode; /* First node ... */ | |
84 LPREV = pNode; /* ... it's also last */ | |
85 LNEXT = NULL; /* But next is NULL! */ | |
86 } | |
87 } | |
88 | |
89 | |
90 /* Read database (additively) to given db-structure | |
91 */ | |
92 #define XS_STILDB_MULTI if (isMulti) { isMulti = FALSE; xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), "\n"); } | |
93 | |
94 | |
95 gint xs_stildb_read(t_xs_stildb * db, gchar * dbFilename) | |
96 { | |
97 FILE *inFile; | |
98 gchar inLine[XS_BUF_SIZE + 16]; /* Since we add some chars here and there */ | |
99 guint lineNum, linePos, eolPos; | |
100 t_xs_stil_node *tmpNode; | |
101 gboolean isError, isMulti; | |
102 gint subEntry; | |
103 assert(db); | |
104 | |
105 /* Try to open the file */ | |
106 if ((inFile = fopen(dbFilename, "ra")) == NULL) { | |
107 XSERR("Could not open STILDB '%s'\n", dbFilename); | |
108 return -1; | |
109 } | |
110 | |
111 /* Read and parse the data */ | |
112 lineNum = 0; | |
113 isError = FALSE; | |
114 isMulti = FALSE; | |
115 tmpNode = NULL; | |
116 subEntry = 0; | |
117 | |
118 while (!feof(inFile) && !isError) { | |
119 fgets(inLine, XS_BUF_SIZE, inFile); | |
120 inLine[XS_BUF_SIZE - 1] = 0; | |
121 linePos = eolPos = 0; | |
122 xs_findeol(inLine, &eolPos); | |
123 inLine[eolPos] = 0; | |
124 lineNum++; | |
125 | |
126 switch (inLine[0]) { | |
127 case '/': | |
128 /* Check if we are already parsing entry */ | |
129 isMulti = FALSE; | |
130 if (tmpNode) { | |
131 XSERR("New entry ('%s') before end of current ('%s')! Possibly malformed STIL-file!\n", | |
132 inLine, tmpNode->pcFilename); | |
133 | |
134 xs_stildb_node_free(tmpNode); | |
135 } | |
136 | |
137 /* A new node */ | |
138 subEntry = 0; | |
139 tmpNode = xs_stildb_node_new(inLine); | |
140 if (!tmpNode) { | |
141 /* Allocation failed */ | |
142 XSERR("Could not allocate new STILdb-node for '%s'!\n", inLine); | |
143 isError = TRUE; | |
144 } | |
145 break; | |
146 | |
147 case '(': | |
148 /* A new sub-entry */ | |
149 isMulti = FALSE; | |
150 linePos++; | |
151 if (inLine[linePos] == '#') { | |
152 linePos++; | |
153 if (inLine[linePos]) { | |
154 xs_findnum(inLine, &linePos); | |
155 inLine[linePos] = 0; | |
156 subEntry = atol(&inLine[2]); | |
157 | |
158 /* Sanity check */ | |
159 if ((subEntry < 1) || (subEntry > XS_STIL_MAXENTRY)) { | |
160 XSERR("Number of subEntry (%i) for '%s' is invalid\n", subEntry, | |
161 tmpNode->pcFilename); | |
162 subEntry = 0; | |
163 } | |
164 } | |
165 } | |
166 | |
167 break; | |
168 | |
169 case 0: | |
170 case '#': | |
171 case '\n': | |
172 case '\r': | |
173 /* End of entry/field */ | |
174 isMulti = FALSE; | |
175 if (tmpNode) { | |
176 /* Insert to database */ | |
177 xs_stildb_node_insert(db, tmpNode); | |
178 tmpNode = NULL; | |
179 } | |
180 break; | |
181 | |
182 default: | |
183 /* Check if we are parsing an entry */ | |
184 if (!tmpNode) { | |
185 XSERR("Entry data encountered outside of entry!\n"); | |
186 break; | |
187 } | |
188 | |
189 /* Some other type */ | |
190 if (strncmp(inLine, " NAME:", 8) == 0) { | |
191 XS_STILDB_MULTI g_free(tmpNode->subTunes[subEntry].pName); | |
192 tmpNode->subTunes[subEntry].pName = g_strdup(&inLine[9]); | |
193 } else if (strncmp(inLine, " AUTHOR:", 8) == 0) { | |
194 XS_STILDB_MULTI g_free(tmpNode->subTunes[subEntry].pAuthor); | |
195 tmpNode->subTunes[subEntry].pAuthor = g_strdup(&inLine[9]); | |
196 } else if (strncmp(inLine, " TITLE:", 8) == 0) { | |
197 XS_STILDB_MULTI inLine[eolPos++] = '\n'; | |
198 inLine[eolPos++] = 0; | |
199 xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), &inLine[2]); | |
200 } else if (strncmp(inLine, " ARTIST:", 8) == 0) { | |
201 XS_STILDB_MULTI inLine[eolPos++] = '\n'; | |
202 inLine[eolPos++] = 0; | |
203 xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), &inLine[1]); | |
204 } else if (strncmp(inLine, "COMMENT:", 8) == 0) { | |
205 XS_STILDB_MULTI isMulti = TRUE; | |
206 xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), inLine); | |
207 } else if (strncmp(inLine, " ", 8) == 0) { | |
208 xs_pstrcat(&(tmpNode->subTunes[subEntry].pInfo), &inLine[8]); | |
209 } | |
210 break; | |
211 } | |
212 | |
213 } /* while */ | |
214 | |
215 /* Check if there is one remaining node */ | |
216 if (tmpNode) | |
217 xs_stildb_node_insert(db, tmpNode); | |
218 | |
219 /* Close the file */ | |
220 fclose(inFile); | |
221 | |
222 return 0; | |
223 } | |
224 | |
225 | |
226 /* Compare two nodes | |
227 */ | |
228 static gint xs_stildb_cmp(const void *pNode1, const void *pNode2) | |
229 { | |
230 /* We assume here that we never ever get NULL-pointers or similar */ | |
231 return strcmp((*(t_xs_stil_node **) pNode1)->pcFilename, (*(t_xs_stil_node **) pNode2)->pcFilename); | |
232 } | |
233 | |
234 | |
235 /* (Re)create index | |
236 */ | |
237 gint xs_stildb_index(t_xs_stildb * db) | |
238 { | |
239 t_xs_stil_node *pCurr; | |
240 gint i; | |
241 | |
242 /* Free old index */ | |
243 if (db->ppIndex) { | |
244 g_free(db->ppIndex); | |
245 db->ppIndex = NULL; | |
246 } | |
247 | |
248 /* Get size of db */ | |
249 pCurr = db->pNodes; | |
250 db->n = 0; | |
251 while (pCurr) { | |
252 db->n++; | |
253 pCurr = pCurr->pNext; | |
254 } | |
255 | |
256 /* Check number of nodes */ | |
257 if (db->n > 0) { | |
258 /* Allocate memory for index-table */ | |
259 db->ppIndex = (t_xs_stil_node **) g_malloc(sizeof(t_xs_stil_node *) * db->n); | |
260 if (!db->ppIndex) | |
261 return -1; | |
262 | |
263 /* Get node-pointers to table */ | |
264 i = 0; | |
265 pCurr = db->pNodes; | |
266 while (pCurr && (i < db->n)) { | |
267 db->ppIndex[i++] = pCurr; | |
268 pCurr = pCurr->pNext; | |
269 } | |
270 | |
271 /* Sort the indexes */ | |
272 qsort(db->ppIndex, db->n, sizeof(t_xs_stil_node *), xs_stildb_cmp); | |
273 } | |
274 | |
275 return 0; | |
276 } | |
277 | |
278 /* Free a given STIL database | |
279 */ | |
280 void xs_stildb_free(t_xs_stildb * db) | |
281 { | |
282 t_xs_stil_node *pCurr, *pNext; | |
283 | |
284 if (!db) | |
285 return; | |
286 | |
287 /* Free the memory allocated for nodes */ | |
288 pCurr = db->pNodes; | |
289 while (pCurr) { | |
290 pNext = pCurr->pNext; | |
291 xs_stildb_node_free(pCurr); | |
292 pCurr = pNext; | |
293 } | |
294 | |
295 db->pNodes = NULL; | |
296 | |
297 /* Free memory allocated for index */ | |
298 if (db->ppIndex) { | |
299 g_free(db->ppIndex); | |
300 db->ppIndex = NULL; | |
301 } | |
302 | |
303 /* Free structure */ | |
304 db->n = 0; | |
305 g_free(db); | |
306 } | |
307 | |
308 | |
309 /* Get STIL information node from database | |
310 */ | |
311 static t_xs_stil_node *xs_stildb_get_node(t_xs_stildb * db, gchar * pcFilename) | |
312 { | |
313 gint iStartNode, iEndNode, iQNode, r, i; | |
314 gboolean iFound; | |
315 t_xs_stil_node *pResult; | |
316 | |
317 /* Check the database pointers */ | |
318 if (!db || !db->pNodes || !db->ppIndex) | |
319 return NULL; | |
320 | |
321 /* Look-up via index using binary search */ | |
322 pResult = NULL; | |
323 iStartNode = 0; | |
324 iEndNode = (db->n - 1); | |
325 iQNode = (iEndNode / 2); | |
326 iFound = FALSE; | |
327 | |
328 while ((!iFound) && ((iEndNode - iStartNode) > XS_BIN_BAILOUT)) { | |
329 r = strcmp(pcFilename, db->ppIndex[iQNode]->pcFilename); | |
330 if (r < 0) { | |
331 /* Hash was in the <- LEFT side */ | |
332 iEndNode = iQNode; | |
333 iQNode = iStartNode + ((iEndNode - iStartNode) / 2); | |
334 } else if (r > 0) { | |
335 /* Hash was in the RIGHT -> side */ | |
336 iStartNode = iQNode; | |
337 iQNode = iStartNode + ((iEndNode - iStartNode) / 2); | |
338 } else | |
339 iFound = TRUE; | |
340 } | |
341 | |
342 /* If not found already */ | |
343 if (!iFound) { | |
344 /* Search the are linearly */ | |
345 iFound = FALSE; | |
346 i = iStartNode; | |
347 while ((i <= iEndNode) && (!iFound)) { | |
348 if (strcmp(pcFilename, db->ppIndex[i]->pcFilename) == 0) | |
349 iFound = TRUE; | |
350 else | |
351 i++; | |
352 } | |
353 | |
354 /* Check the result */ | |
355 if (iFound) | |
356 pResult = db->ppIndex[i]; | |
357 | |
358 } else { | |
359 /* Found via binary search */ | |
360 pResult = db->ppIndex[iQNode]; | |
361 } | |
362 | |
363 return pResult; | |
364 } | |
365 | |
366 | |
367 /* | |
368 * These should be moved out of this module some day ... | |
369 */ | |
370 static t_xs_stildb *xs_stildb_db = NULL; | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
371 GStaticMutex xs_stildb_db_mutex = G_STATIC_MUTEX_INIT; |
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
372 extern GStaticMutex xs_cfg_mutex; |
269 | 373 |
374 gint xs_stil_init(void) | |
375 { | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
376 g_static_mutex_lock(&xs_cfg_mutex); |
269 | 377 |
378 if (!xs_cfg.stilDBPath) { | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
379 g_static_mutex_unlock(&xs_cfg_mutex); |
269 | 380 return -1; |
381 } | |
382 | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
383 g_static_mutex_lock(&xs_stildb_db_mutex); |
269 | 384 |
385 /* Check if already initialized */ | |
386 if (xs_stildb_db) | |
387 xs_stildb_free(xs_stildb_db); | |
388 | |
389 /* Allocate database */ | |
390 xs_stildb_db = (t_xs_stildb *) g_malloc0(sizeof(t_xs_stildb)); | |
391 if (!xs_stildb_db) { | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
392 g_static_mutex_unlock(&xs_cfg_mutex); |
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
393 g_static_mutex_unlock(&xs_stildb_db_mutex); |
269 | 394 return -2; |
395 } | |
396 | |
397 /* Read the database */ | |
398 if (xs_stildb_read(xs_stildb_db, xs_cfg.stilDBPath) != 0) { | |
399 xs_stildb_free(xs_stildb_db); | |
400 xs_stildb_db = NULL; | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
401 g_static_mutex_unlock(&xs_cfg_mutex); |
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
402 g_static_mutex_unlock(&xs_stildb_db_mutex); |
269 | 403 return -3; |
404 } | |
405 | |
406 /* Create index */ | |
407 if (xs_stildb_index(xs_stildb_db) != 0) { | |
408 xs_stildb_free(xs_stildb_db); | |
409 xs_stildb_db = NULL; | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
410 g_static_mutex_unlock(&xs_cfg_mutex); |
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
411 g_static_mutex_unlock(&xs_stildb_db_mutex); |
269 | 412 return -4; |
413 } | |
414 | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
415 g_static_mutex_unlock(&xs_cfg_mutex); |
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
416 g_static_mutex_unlock(&xs_stildb_db_mutex); |
269 | 417 return 0; |
418 } | |
419 | |
420 | |
421 void xs_stil_close(void) | |
422 { | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
423 g_static_mutex_lock(&xs_stildb_db_mutex); |
269 | 424 xs_stildb_free(xs_stildb_db); |
425 xs_stildb_db = NULL; | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
426 g_static_mutex_unlock(&xs_stildb_db_mutex); |
269 | 427 } |
428 | |
429 | |
430 t_xs_stil_node *xs_stil_get(gchar * pcFilename) | |
431 { | |
432 t_xs_stil_node *pResult; | |
433 gchar *tmpFilename; | |
434 | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
435 g_static_mutex_lock(&xs_stildb_db_mutex); |
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
436 g_static_mutex_lock(&xs_cfg_mutex); |
269 | 437 |
438 if (xs_cfg.stilDBEnable && xs_stildb_db) { | |
439 if (xs_cfg.hvscPath) { | |
440 /* Remove postfixed directory separator from HVSC-path */ | |
441 tmpFilename = xs_strrchr(xs_cfg.hvscPath, '/'); | |
442 if (tmpFilename && (tmpFilename[1] == 0)) | |
443 tmpFilename[0] = 0; | |
444 | |
445 /* Remove HVSC location-prefix from filename */ | |
446 tmpFilename = strstr(pcFilename, xs_cfg.hvscPath); | |
447 if (tmpFilename) | |
448 tmpFilename += strlen(xs_cfg.hvscPath); | |
449 else | |
450 tmpFilename = pcFilename; | |
451 } else | |
452 tmpFilename = pcFilename; | |
453 | |
454 pResult = xs_stildb_get_node(xs_stildb_db, tmpFilename); | |
455 } else | |
456 pResult = NULL; | |
457 | |
304
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
458 g_static_mutex_unlock(&xs_stildb_db_mutex); |
d0e9693d2115
[svn] Convert to configdb. GThreadify and peel off layer of threading macro madness.
chainsaw
parents:
269
diff
changeset
|
459 g_static_mutex_unlock(&xs_cfg_mutex); |
269 | 460 |
461 return pResult; | |
462 } |