diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-03-26 16:20:17 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-03-26 16:20:17 +0000 |
commit | e005be81997d31fdc7e18a079e97ebe3fffe370d (patch) | |
tree | e8f80d9942a0c078dd51984b782d608060065b01 | |
parent | 34b4812d8902ae2bb8ca2340ad51955a50e40ec0 (diff) | |
download | libextractor-e005be81997d31fdc7e18a079e97ebe3fffe370d.tar.gz libextractor-e005be81997d31fdc7e18a079e97ebe3fffe370d.zip |
-LRN: Divide-extractor.c.patch was the first thing i did, once i
realized that extractor.c is just too long.
-rw-r--r-- | src/main/Makefile.am | 2 | ||||
-rw-r--r-- | src/main/extractor.c | 908 |
2 files changed, 4 insertions, 906 deletions
diff --git a/src/main/Makefile.am b/src/main/Makefile.am index 916f1f6..a99dd90 100644 --- a/src/main/Makefile.am +++ b/src/main/Makefile.am | |||
@@ -36,6 +36,8 @@ libextractor_la_CPPFLAGS = -DPLUGINDIR=\"@RPLUGINDIR@\" -DPLUGININSTDIR=\"${plug | |||
36 | 36 | ||
37 | libextractor_la_SOURCES = \ | 37 | libextractor_la_SOURCES = \ |
38 | extractor.c \ | 38 | extractor.c \ |
39 | extractor_plugpath.c \ | ||
40 | extractor_plugins.c \ | ||
39 | extractor_metatypes.c \ | 41 | extractor_metatypes.c \ |
40 | extractor_print.c | 42 | extractor_print.c |
41 | 43 | ||
diff --git a/src/main/extractor.c b/src/main/extractor.c index df75e21..17ba1d2 100644 --- a/src/main/extractor.c +++ b/src/main/extractor.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include <zlib.h> | 38 | #include <zlib.h> |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | #include "extractor_plugpath.h" | ||
42 | #include "extractor_plugins.h" | ||
41 | 43 | ||
42 | 44 | ||
43 | /** | 45 | /** |
@@ -65,912 +67,6 @@ | |||
65 | 67 | ||
66 | 68 | ||
67 | /** | 69 | /** |
68 | * Linked list of extractor plugins. An application builds this list | ||
69 | * by telling libextractor to load various keyword-extraction | ||
70 | * plugins. Libraries can also be unloaded (removed from this list, | ||
71 | * see EXTRACTOR_plugin_remove). | ||
72 | */ | ||
73 | struct EXTRACTOR_PluginList | ||
74 | { | ||
75 | /** | ||
76 | * This is a linked list. | ||
77 | */ | ||
78 | struct EXTRACTOR_PluginList *next; | ||
79 | |||
80 | /** | ||
81 | * Pointer to the plugin (as returned by lt_dlopen). | ||
82 | */ | ||
83 | void * libraryHandle; | ||
84 | |||
85 | /** | ||
86 | * Name of the library (i.e., 'libextractor_foo.so') | ||
87 | */ | ||
88 | char *libname; | ||
89 | |||
90 | /** | ||
91 | * Name of the library (i.e., 'libextractor_foo.so') | ||
92 | */ | ||
93 | char *short_libname; | ||
94 | |||
95 | /** | ||
96 | * Pointer to the function used for meta data extraction. | ||
97 | */ | ||
98 | EXTRACTOR_ExtractMethod extractMethod; | ||
99 | |||
100 | /** | ||
101 | * Options for the plugin. | ||
102 | */ | ||
103 | char * plugin_options; | ||
104 | |||
105 | /** | ||
106 | * Special options for the plugin | ||
107 | * (as returned by the plugin's "options" method; | ||
108 | * typically NULL). | ||
109 | */ | ||
110 | const char *specials; | ||
111 | |||
112 | /** | ||
113 | * Flags to control how the plugin is executed. | ||
114 | */ | ||
115 | enum EXTRACTOR_Options flags; | ||
116 | |||
117 | /** | ||
118 | * Process ID of the child process for this plugin. 0 for | ||
119 | * none. | ||
120 | */ | ||
121 | #ifndef WINDOWS | ||
122 | int cpid; | ||
123 | #else | ||
124 | HANDLE hProcess; | ||
125 | #endif | ||
126 | |||
127 | /** | ||
128 | * Pipe used to send information about shared memory segments to | ||
129 | * the child process. NULL if not initialized. | ||
130 | */ | ||
131 | FILE *cpipe_in; | ||
132 | |||
133 | /** | ||
134 | * Pipe used to read information about extracted meta data from | ||
135 | * the child process. -1 if not initialized. | ||
136 | */ | ||
137 | int cpipe_out; | ||
138 | }; | ||
139 | |||
140 | |||
141 | /** | ||
142 | * Remove a trailing '/bin' from in (if present). | ||
143 | */ | ||
144 | static char * | ||
145 | cut_bin(char * in) { | ||
146 | size_t p; | ||
147 | |||
148 | if (in == NULL) | ||
149 | return NULL; | ||
150 | p = strlen(in); | ||
151 | if (p > 4) { | ||
152 | if ( (in[p-1] == '/') || | ||
153 | (in[p-1] == '\\') ) | ||
154 | in[--p] = '\0'; | ||
155 | if (0 == strcmp(&in[p-3], | ||
156 | "bin")) { | ||
157 | in[p-3] = '\0'; | ||
158 | p -= 3; | ||
159 | } | ||
160 | } | ||
161 | return in; | ||
162 | } | ||
163 | |||
164 | #if LINUX | ||
165 | /** | ||
166 | * Try to determine path by reading /proc/PID/exe or | ||
167 | * /proc/PID/maps. | ||
168 | * | ||
169 | * Note that this may fail if LE is installed in one directory | ||
170 | * and the binary linking against it sits elsewhere. | ||
171 | */ | ||
172 | static char * | ||
173 | get_path_from_proc_exe() { | ||
174 | char fn[64]; | ||
175 | char line[1024]; | ||
176 | char dir[1024]; | ||
177 | char * lnk; | ||
178 | char * ret; | ||
179 | char * lestr; | ||
180 | ssize_t size; | ||
181 | FILE * f; | ||
182 | |||
183 | snprintf(fn, | ||
184 | sizeof (fn), | ||
185 | "/proc/%u/maps", | ||
186 | getpid()); | ||
187 | f = FOPEN(fn, "r"); | ||
188 | if (f != NULL) { | ||
189 | while (NULL != fgets(line, 1024, f)) { | ||
190 | if ( (1 == sscanf(line, | ||
191 | "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%s", | ||
192 | dir)) && | ||
193 | (NULL != (lestr = strstr(dir, | ||
194 | "libextractor")) ) ) { | ||
195 | lestr[0] = '\0'; | ||
196 | fclose(f); | ||
197 | return strdup(dir); | ||
198 | } | ||
199 | } | ||
200 | fclose(f); | ||
201 | } | ||
202 | snprintf(fn, | ||
203 | sizeof (fn), | ||
204 | "/proc/%u/exe", | ||
205 | getpid()); | ||
206 | lnk = malloc(1029); /* 1024 + 5 for "lib/" catenation */ | ||
207 | if (lnk == NULL) | ||
208 | return NULL; | ||
209 | size = readlink(fn, lnk, 1023); | ||
210 | if ( (size <= 0) || (size >= 1024) ) { | ||
211 | free(lnk); | ||
212 | return NULL; | ||
213 | } | ||
214 | lnk[size] = '\0'; | ||
215 | while ( (lnk[size] != '/') && | ||
216 | (size > 0) ) | ||
217 | size--; | ||
218 | if ( (size < 4) || | ||
219 | (lnk[size-4] != '/') ) { | ||
220 | /* not installed in "/bin/" -- binary path probably useless */ | ||
221 | free(lnk); | ||
222 | return NULL; | ||
223 | } | ||
224 | lnk[size] = '\0'; | ||
225 | lnk = cut_bin(lnk); | ||
226 | ret = realloc(lnk, strlen(lnk) + 5); | ||
227 | if (ret == NULL) | ||
228 | { | ||
229 | free (lnk); | ||
230 | return NULL; | ||
231 | } | ||
232 | strcat(ret, "lib/"); /* guess "lib/" as the library dir */ | ||
233 | return ret; | ||
234 | } | ||
235 | #endif | ||
236 | |||
237 | #if WINDOWS | ||
238 | /** | ||
239 | * Try to determine path with win32-specific function | ||
240 | */ | ||
241 | static char * | ||
242 | get_path_from_module_filename() { | ||
243 | char * path; | ||
244 | char * ret; | ||
245 | char * idx; | ||
246 | |||
247 | path = malloc(4103); /* 4096+nil+6 for "/lib/" catenation */ | ||
248 | if (path == NULL) | ||
249 | return NULL; | ||
250 | GetModuleFileName(NULL, path, 4096); | ||
251 | idx = path + strlen(path); | ||
252 | while ( (idx > path) && | ||
253 | (*idx != '\\') && | ||
254 | (*idx != '/') ) | ||
255 | idx--; | ||
256 | *idx = '\0'; | ||
257 | path = cut_bin(path); | ||
258 | ret = realloc(path, strlen(path) + 6); | ||
259 | if (ret == NULL) | ||
260 | { | ||
261 | free (path); | ||
262 | return NULL; | ||
263 | } | ||
264 | strcat(ret, "/lib/"); /* guess "lib/" as the library dir */ | ||
265 | return ret; | ||
266 | } | ||
267 | #endif | ||
268 | |||
269 | #if DARWIN | ||
270 | static char * get_path_from_dyld_image() { | ||
271 | const char * path; | ||
272 | char * p, * s; | ||
273 | int i; | ||
274 | int c; | ||
275 | |||
276 | p = NULL; | ||
277 | c = _dyld_image_count(); | ||
278 | for (i = 0; i < c; i++) { | ||
279 | if (_dyld_get_image_header(i) == &_mh_dylib_header) { | ||
280 | path = _dyld_get_image_name(i); | ||
281 | if (path != NULL && strlen(path) > 0) { | ||
282 | p = strdup(path); | ||
283 | if (p == NULL) | ||
284 | return NULL; | ||
285 | s = p + strlen(p); | ||
286 | while ( (s > p) && (*s != '/') ) | ||
287 | s--; | ||
288 | s++; | ||
289 | *s = '\0'; | ||
290 | } | ||
291 | break; | ||
292 | } | ||
293 | } | ||
294 | return p; | ||
295 | } | ||
296 | #endif | ||
297 | |||
298 | /** | ||
299 | * This may also fail -- for example, if extract | ||
300 | * is not also installed. | ||
301 | */ | ||
302 | static char * | ||
303 | get_path_from_PATH() { | ||
304 | struct stat sbuf; | ||
305 | char * path; | ||
306 | char * pos; | ||
307 | char * end; | ||
308 | char * buf; | ||
309 | char * ret; | ||
310 | const char * p; | ||
311 | |||
312 | p = getenv("PATH"); | ||
313 | if (p == NULL) | ||
314 | return NULL; | ||
315 | path = strdup(p); /* because we write on it */ | ||
316 | if (path == NULL) | ||
317 | return NULL; | ||
318 | buf = malloc(strlen(path) + 20); | ||
319 | if (buf == NULL) | ||
320 | { | ||
321 | free (path); | ||
322 | return NULL; | ||
323 | } | ||
324 | pos = path; | ||
325 | |||
326 | while (NULL != (end = strchr(pos, ':'))) { | ||
327 | *end = '\0'; | ||
328 | sprintf(buf, "%s/%s", pos, "extract"); | ||
329 | if (0 == stat(buf, &sbuf)) { | ||
330 | pos = strdup(pos); | ||
331 | free(buf); | ||
332 | free(path); | ||
333 | if (pos == NULL) | ||
334 | return NULL; | ||
335 | pos = cut_bin(pos); | ||
336 | ret = realloc(pos, strlen(pos) + 5); | ||
337 | if (ret == NULL) | ||
338 | { | ||
339 | free (pos); | ||
340 | return NULL; | ||
341 | } | ||
342 | strcat(ret, "lib/"); | ||
343 | return ret; | ||
344 | } | ||
345 | pos = end + 1; | ||
346 | } | ||
347 | sprintf(buf, "%s/%s", pos, "extract"); | ||
348 | if (0 == stat(buf, &sbuf)) { | ||
349 | pos = strdup(pos); | ||
350 | free(buf); | ||
351 | free(path); | ||
352 | if (pos == NULL) | ||
353 | return NULL; | ||
354 | pos = cut_bin(pos); | ||
355 | ret = realloc(pos, strlen(pos) + 5); | ||
356 | if (ret == NULL) | ||
357 | { | ||
358 | free (pos); | ||
359 | return NULL; | ||
360 | } | ||
361 | strcat(ret, "lib/"); | ||
362 | return ret; | ||
363 | } | ||
364 | free(buf); | ||
365 | free(path); | ||
366 | return NULL; | ||
367 | } | ||
368 | |||
369 | |||
370 | /** | ||
371 | * Function to call on paths. | ||
372 | * | ||
373 | * @param cls closure | ||
374 | * @param path a directory path | ||
375 | */ | ||
376 | typedef void (*PathProcessor)(void *cls, | ||
377 | const char *path); | ||
378 | |||
379 | |||
380 | /** | ||
381 | * Create a filename by appending 'fname' to 'path'. | ||
382 | * | ||
383 | * @param path the base path | ||
384 | * @param fname the filename to append | ||
385 | * @return '$path/$fname' | ||
386 | */ | ||
387 | static char * | ||
388 | append_to_dir (const char *path, | ||
389 | const char *fname) | ||
390 | { | ||
391 | char *ret; | ||
392 | size_t slen; | ||
393 | |||
394 | slen = strlen (path); | ||
395 | if (slen == 0) | ||
396 | return NULL; | ||
397 | if (fname[0] == DIR_SEPARATOR) | ||
398 | fname++; | ||
399 | ret = malloc (slen + strlen(fname) + 2); | ||
400 | if (ret == NULL) | ||
401 | return NULL; | ||
402 | #ifdef MINGW | ||
403 | if (path[slen-1] == '\\') | ||
404 | sprintf (ret, | ||
405 | "%s%s", | ||
406 | path, | ||
407 | fname); | ||
408 | else | ||
409 | sprintf (ret, | ||
410 | "%s\\%s", | ||
411 | path, | ||
412 | fname); | ||
413 | #else | ||
414 | if (path[slen-1] == '/') | ||
415 | sprintf (ret, | ||
416 | "%s%s", | ||
417 | path, | ||
418 | fname); | ||
419 | else | ||
420 | sprintf (ret, | ||
421 | "%s/%s", | ||
422 | path, | ||
423 | fname); | ||
424 | #endif | ||
425 | return ret; | ||
426 | } | ||
427 | |||
428 | |||
429 | /** | ||
430 | * Iterate over all paths where we expect to find GNU libextractor | ||
431 | * plugins. | ||
432 | * | ||
433 | * @param pp function to call for each path | ||
434 | * @param pp_cls cls argument for pp. | ||
435 | */ | ||
436 | static void | ||
437 | get_installation_paths (PathProcessor pp, | ||
438 | void *pp_cls) | ||
439 | { | ||
440 | const char *p; | ||
441 | char * path; | ||
442 | char * prefix; | ||
443 | char * d; | ||
444 | |||
445 | prefix = NULL; | ||
446 | p = getenv("LIBEXTRACTOR_PREFIX"); | ||
447 | if (p != NULL) | ||
448 | { | ||
449 | d = strdup (p); | ||
450 | if (d == NULL) | ||
451 | return; | ||
452 | prefix = strtok (d, PATH_SEPARATOR_STR); | ||
453 | while (NULL != prefix) | ||
454 | { | ||
455 | pp (pp_cls, prefix); | ||
456 | prefix = strtok (NULL, PATH_SEPARATOR_STR); | ||
457 | } | ||
458 | free (d); | ||
459 | return; | ||
460 | } | ||
461 | #if LINUX | ||
462 | if (prefix == NULL) | ||
463 | prefix = get_path_from_proc_exe(); | ||
464 | #endif | ||
465 | #if WINDOWS | ||
466 | if (prefix == NULL) | ||
467 | prefix = get_path_from_module_filename(); | ||
468 | #endif | ||
469 | #if DARWIN | ||
470 | if (prefix == NULL) | ||
471 | prefix = get_path_from_dyld_image(); | ||
472 | #endif | ||
473 | if (prefix == NULL) | ||
474 | prefix = get_path_from_PATH(); | ||
475 | pp (pp_cls, PLUGININSTDIR); | ||
476 | if (prefix == NULL) | ||
477 | return; | ||
478 | path = append_to_dir (prefix, PLUGINDIR); | ||
479 | if (path != NULL) | ||
480 | { | ||
481 | if (0 != strcmp (path, | ||
482 | PLUGININSTDIR)) | ||
483 | pp (pp_cls, path); | ||
484 | free (path); | ||
485 | } | ||
486 | free (prefix); | ||
487 | } | ||
488 | |||
489 | |||
490 | struct SearchContext | ||
491 | { | ||
492 | const char *short_name; | ||
493 | char *path; | ||
494 | }; | ||
495 | |||
496 | |||
497 | /** | ||
498 | * Load all plugins from the given directory. | ||
499 | * | ||
500 | * @param cls pointer to the "struct EXTRACTOR_PluginList*" to extend | ||
501 | * @param path path to a directory with plugins | ||
502 | */ | ||
503 | static void | ||
504 | find_plugin_in_path (void *cls, | ||
505 | const char *path) | ||
506 | { | ||
507 | struct SearchContext *sc = cls; | ||
508 | DIR *dir; | ||
509 | struct dirent *ent; | ||
510 | const char *la; | ||
511 | const char *sym_name; | ||
512 | char *sym; | ||
513 | char *dot; | ||
514 | |||
515 | if (sc->path != NULL) | ||
516 | return; | ||
517 | dir = OPENDIR (path); | ||
518 | if (NULL == dir) | ||
519 | return; | ||
520 | while (NULL != (ent = READDIR (dir))) | ||
521 | { | ||
522 | if (ent->d_name[0] == '.') | ||
523 | continue; | ||
524 | if ( (NULL != (la = strstr (ent->d_name, ".la"))) && | ||
525 | (la[3] == '\0') ) | ||
526 | continue; /* only load '.so' and '.dll' */ | ||
527 | sym_name = strstr (ent->d_name, "_"); | ||
528 | if (sym_name == NULL) | ||
529 | continue; | ||
530 | sym_name++; | ||
531 | sym = strdup (sym_name); | ||
532 | if (sym == NULL) | ||
533 | { | ||
534 | CLOSEDIR (dir); | ||
535 | return; | ||
536 | } | ||
537 | dot = strstr (sym, "."); | ||
538 | if (dot != NULL) | ||
539 | *dot = '\0'; | ||
540 | if (0 == strcmp (sym, sc->short_name)) | ||
541 | { | ||
542 | sc->path = append_to_dir (path, ent->d_name); | ||
543 | free (sym); | ||
544 | break; | ||
545 | } | ||
546 | free (sym); | ||
547 | } | ||
548 | #if DEBUG | ||
549 | if (sc->path == NULL) | ||
550 | fprintf (stderr, | ||
551 | "Failed to find plugin `%s' in `%s'\n", | ||
552 | sc->short_name, | ||
553 | path); | ||
554 | #endif | ||
555 | CLOSEDIR (dir); | ||
556 | } | ||
557 | |||
558 | |||
559 | |||
560 | /** | ||
561 | * Given a short name of a library (i.e. "mime"), find | ||
562 | * the full path of the respective plugin. | ||
563 | */ | ||
564 | static char * | ||
565 | find_plugin (const char *short_name) | ||
566 | { | ||
567 | struct SearchContext sc; | ||
568 | |||
569 | sc.path = NULL; | ||
570 | sc.short_name = short_name; | ||
571 | get_installation_paths (&find_plugin_in_path, | ||
572 | &sc); | ||
573 | return sc.path; | ||
574 | } | ||
575 | |||
576 | |||
577 | |||
578 | struct DefaultLoaderContext | ||
579 | { | ||
580 | struct EXTRACTOR_PluginList *res; | ||
581 | enum EXTRACTOR_Options flags; | ||
582 | }; | ||
583 | |||
584 | |||
585 | /** | ||
586 | * Load all plugins from the given directory. | ||
587 | * | ||
588 | * @param cls pointer to the "struct EXTRACTOR_PluginList*" to extend | ||
589 | * @param path path to a directory with plugins | ||
590 | */ | ||
591 | static void | ||
592 | load_plugins_from_dir (void *cls, | ||
593 | const char *path) | ||
594 | { | ||
595 | struct DefaultLoaderContext *dlc = cls; | ||
596 | DIR *dir; | ||
597 | struct dirent *ent; | ||
598 | const char *la; | ||
599 | const char *sym_name; | ||
600 | char *sym; | ||
601 | char *dot; | ||
602 | |||
603 | dir = opendir (path); | ||
604 | if (NULL == dir) | ||
605 | return; | ||
606 | while (NULL != (ent = readdir (dir))) | ||
607 | { | ||
608 | if (ent->d_name[0] == '.') | ||
609 | continue; | ||
610 | if ( ( (NULL != (la = strstr (ent->d_name, ".la"))) && | ||
611 | (la[3] == '\0') ) || | ||
612 | ( (NULL != (la = strstr (ent->d_name, ".a"))) && | ||
613 | (la[2] == '\0')) ) | ||
614 | continue; /* only load '.so' and '.dll' */ | ||
615 | |||
616 | sym_name = strstr (ent->d_name, "_"); | ||
617 | if (sym_name == NULL) | ||
618 | continue; | ||
619 | sym_name++; | ||
620 | sym = strdup (sym_name); | ||
621 | if (NULL == sym) | ||
622 | { | ||
623 | closedir (dir); | ||
624 | return; | ||
625 | } | ||
626 | dot = strstr (sym, "."); | ||
627 | if (dot != NULL) | ||
628 | *dot = '\0'; | ||
629 | #if DEBUG > 1 | ||
630 | fprintf (stderr, | ||
631 | "Adding default plugin `%s'\n", | ||
632 | sym); | ||
633 | #endif | ||
634 | dlc->res = EXTRACTOR_plugin_add (dlc->res, | ||
635 | sym, | ||
636 | NULL, | ||
637 | dlc->flags); | ||
638 | free (sym); | ||
639 | } | ||
640 | closedir (dir); | ||
641 | } | ||
642 | |||
643 | |||
644 | /** | ||
645 | * Load the default set of plugins. The default can be changed | ||
646 | * by setting the LIBEXTRACTOR_LIBRARIES environment variable. | ||
647 | * If it is set to "env", then this function will return | ||
648 | * EXTRACTOR_plugin_add_config (NULL, env, flags). Otherwise, | ||
649 | * it will load all of the installed plugins and return them. | ||
650 | * | ||
651 | * @param flags options for all of the plugins loaded | ||
652 | * @return the default set of plugins, NULL if no plugins were found | ||
653 | */ | ||
654 | struct EXTRACTOR_PluginList * | ||
655 | EXTRACTOR_plugin_add_defaults(enum EXTRACTOR_Options flags) | ||
656 | { | ||
657 | struct DefaultLoaderContext dlc; | ||
658 | char *env; | ||
659 | |||
660 | env = getenv ("LIBEXTRACTOR_LIBRARIES"); | ||
661 | if (env != NULL) | ||
662 | return EXTRACTOR_plugin_add_config (NULL, env, flags); | ||
663 | dlc.res = NULL; | ||
664 | dlc.flags = flags; | ||
665 | get_installation_paths (&load_plugins_from_dir, | ||
666 | &dlc); | ||
667 | return dlc.res; | ||
668 | } | ||
669 | |||
670 | |||
671 | /** | ||
672 | * Try to resolve a plugin function. | ||
673 | * | ||
674 | * @param lib_handle library to search for the symbol | ||
675 | * @param prefix prefix to add | ||
676 | * @param sym_name base name for the symbol | ||
677 | * @param options set to special options requested by the plugin | ||
678 | * @return NULL on error, otherwise pointer to the symbol | ||
679 | */ | ||
680 | static void * | ||
681 | get_symbol_with_prefix(void *lib_handle, | ||
682 | const char *template, | ||
683 | const char *prefix, | ||
684 | const char **options) | ||
685 | { | ||
686 | char *name; | ||
687 | void *symbol; | ||
688 | const char *sym_name; | ||
689 | char *sym; | ||
690 | char *dot; | ||
691 | const char *(*opt_fun)(void); | ||
692 | |||
693 | if (NULL != options) *options = NULL; | ||
694 | sym_name = strstr (prefix, "_"); | ||
695 | if (sym_name == NULL) | ||
696 | return NULL; | ||
697 | sym_name++; | ||
698 | sym = strdup (sym_name); | ||
699 | if (sym == NULL) | ||
700 | return NULL; | ||
701 | dot = strstr (sym, "."); | ||
702 | if (dot != NULL) | ||
703 | *dot = '\0'; | ||
704 | name = malloc(strlen(sym) + strlen(template) + 1); | ||
705 | if (name == NULL) | ||
706 | { | ||
707 | free (sym); | ||
708 | return NULL; | ||
709 | } | ||
710 | sprintf(name, | ||
711 | template, | ||
712 | sym); | ||
713 | /* try without '_' first */ | ||
714 | symbol = lt_dlsym(lib_handle, name + 1); | ||
715 | if (symbol==NULL) | ||
716 | { | ||
717 | /* now try with the '_' */ | ||
718 | #if DEBUG | ||
719 | char *first_error = strdup (lt_dlerror()); | ||
720 | #endif | ||
721 | symbol = lt_dlsym(lib_handle, name); | ||
722 | #if DEBUG | ||
723 | if (NULL == symbol) | ||
724 | { | ||
725 | fprintf(stderr, | ||
726 | "Resolving symbol `%s' failed, " | ||
727 | "so I tried `%s', but that failed also. Errors are: " | ||
728 | "`%s' and `%s'.\n", | ||
729 | name+1, | ||
730 | name, | ||
731 | first_error == NULL ? "out of memory" : first_error, | ||
732 | lt_dlerror()); | ||
733 | } | ||
734 | if (first_error != NULL) | ||
735 | free(first_error); | ||
736 | #endif | ||
737 | } | ||
738 | |||
739 | if ( (symbol != NULL) && | ||
740 | (NULL != options) ) | ||
741 | { | ||
742 | /* get special options */ | ||
743 | sprintf(name, | ||
744 | "_EXTRACTOR_%s_options", | ||
745 | sym); | ||
746 | /* try without '_' first */ | ||
747 | opt_fun = lt_dlsym(lib_handle, name + 1); | ||
748 | if (opt_fun == NULL) | ||
749 | opt_fun = lt_dlsym(lib_handle, name); | ||
750 | if (opt_fun != NULL) | ||
751 | *options = opt_fun (); | ||
752 | } | ||
753 | free (sym); | ||
754 | free(name); | ||
755 | |||
756 | return symbol; | ||
757 | } | ||
758 | |||
759 | |||
760 | /** | ||
761 | * Load a plugin. | ||
762 | * | ||
763 | * @param plugin plugin to load | ||
764 | * @return 0 on success, -1 on error | ||
765 | */ | ||
766 | static int | ||
767 | plugin_load (struct EXTRACTOR_PluginList *plugin) | ||
768 | { | ||
769 | #if WINDOWS | ||
770 | wchar_t wlibname[4097]; | ||
771 | char llibname[4097]; | ||
772 | #endif | ||
773 | lt_dladvise advise; | ||
774 | |||
775 | if (plugin->libname == NULL) | ||
776 | plugin->libname = find_plugin (plugin->short_libname); | ||
777 | if (plugin->libname == NULL) | ||
778 | { | ||
779 | #if DEBUG | ||
780 | fprintf (stderr, | ||
781 | "Failed to find plugin `%s'\n", | ||
782 | plugin->short_libname); | ||
783 | #endif | ||
784 | plugin->flags = EXTRACTOR_OPTION_DISABLED; | ||
785 | return -1; | ||
786 | } | ||
787 | lt_dladvise_init (&advise); | ||
788 | lt_dladvise_ext (&advise); | ||
789 | lt_dladvise_local (&advise); | ||
790 | #if WINDOWS | ||
791 | wlibname[0] = L'\0'; | ||
792 | llibname[0] = '\0'; | ||
793 | if (MultiByteToWideChar (CP_UTF8, 0, plugin->libname, -1, wlibname, 4097) <= 0 | ||
794 | || WideCharToMultiByte (CP_ACP, 0, wlibname, -1, llibname, 4097, NULL, NULL) < 0) | ||
795 | { | ||
796 | #if DEBUG | ||
797 | fprintf (stderr, | ||
798 | "Loading `%s' plugin failed: %s\n", | ||
799 | plugin->short_libname, | ||
800 | "can't convert plugin name to local encoding"); | ||
801 | free (plugin->libname); | ||
802 | plugin->libname = NULL; | ||
803 | plugin->flags = EXTRACTOR_OPTION_DISABLED; | ||
804 | return -1; | ||
805 | #endif | ||
806 | } | ||
807 | plugin->libraryHandle = lt_dlopenadvise (llibname, | ||
808 | advise); | ||
809 | #else | ||
810 | plugin->libraryHandle = lt_dlopenadvise (plugin->libname, | ||
811 | advise); | ||
812 | #endif | ||
813 | lt_dladvise_destroy(&advise); | ||
814 | if (plugin->libraryHandle == NULL) | ||
815 | { | ||
816 | #if DEBUG | ||
817 | fprintf (stderr, | ||
818 | "Loading `%s' plugin failed: %s\n", | ||
819 | plugin->short_libname, | ||
820 | lt_dlerror ()); | ||
821 | #endif | ||
822 | free (plugin->libname); | ||
823 | plugin->libname = NULL; | ||
824 | plugin->flags = EXTRACTOR_OPTION_DISABLED; | ||
825 | return -1; | ||
826 | } | ||
827 | plugin->extractMethod = get_symbol_with_prefix (plugin->libraryHandle, | ||
828 | "_EXTRACTOR_%s_extract", | ||
829 | plugin->libname, | ||
830 | &plugin->specials); | ||
831 | if (plugin->extractMethod == NULL) | ||
832 | { | ||
833 | #if DEBUG | ||
834 | fprintf (stderr, | ||
835 | "Resolving `extract' method of plugin `%s' failed: %s\n", | ||
836 | plugin->short_libname, | ||
837 | lt_dlerror ()); | ||
838 | #endif | ||
839 | lt_dlclose (plugin->libraryHandle); | ||
840 | free (plugin->libname); | ||
841 | plugin->libname = NULL; | ||
842 | plugin->flags = EXTRACTOR_OPTION_DISABLED; | ||
843 | return -1; | ||
844 | } | ||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | |||
849 | |||
850 | |||
851 | /** | ||
852 | * Add a library for keyword extraction. | ||
853 | * | ||
854 | * @param prev the previous list of libraries, may be NULL | ||
855 | * @param library the name of the library | ||
856 | * @param flags options to use | ||
857 | * @return the new list of libraries, equal to prev iff an error occured | ||
858 | */ | ||
859 | struct EXTRACTOR_PluginList * | ||
860 | EXTRACTOR_plugin_add (struct EXTRACTOR_PluginList * prev, | ||
861 | const char *library, | ||
862 | const char *options, | ||
863 | enum EXTRACTOR_Options flags) | ||
864 | { | ||
865 | struct EXTRACTOR_PluginList *result; | ||
866 | char *libname; | ||
867 | |||
868 | libname = find_plugin (library); | ||
869 | if (libname == NULL) | ||
870 | { | ||
871 | fprintf (stderr, | ||
872 | "Could not load `%s'\n", | ||
873 | library); | ||
874 | return prev; | ||
875 | } | ||
876 | result = calloc (1, sizeof (struct EXTRACTOR_PluginList)); | ||
877 | if (result == NULL) | ||
878 | return prev; | ||
879 | result->next = prev; | ||
880 | result->short_libname = strdup (library); | ||
881 | if (result->short_libname == NULL) | ||
882 | { | ||
883 | free (result); | ||
884 | return NULL; | ||
885 | } | ||
886 | result->libname = libname; | ||
887 | result->flags = flags; | ||
888 | if (NULL != options) | ||
889 | result->plugin_options = strdup (options); | ||
890 | else | ||
891 | result->plugin_options = NULL; | ||
892 | return result; | ||
893 | } | ||
894 | |||
895 | |||
896 | /** | ||
897 | * Load multiple libraries as specified by the user. | ||
898 | * | ||
899 | * @param config a string given by the user that defines which | ||
900 | * libraries should be loaded. Has the format | ||
901 | * "[[-]LIBRARYNAME[(options)][:[-]LIBRARYNAME[(options)]]]*". | ||
902 | * For example, 'mp3:ogg.so' loads the | ||
903 | * mp3 and the ogg library. The '-' before the LIBRARYNAME | ||
904 | * indicates that the library should be removed from | ||
905 | * the library list. | ||
906 | * @param prev the previous list of libraries, may be NULL | ||
907 | * @param flags options to use | ||
908 | * @return the new list of libraries, equal to prev iff an error occured | ||
909 | * or if config was empty (or NULL). | ||
910 | */ | ||
911 | struct EXTRACTOR_PluginList * | ||
912 | EXTRACTOR_plugin_add_config (struct EXTRACTOR_PluginList * prev, | ||
913 | const char *config, | ||
914 | enum EXTRACTOR_Options flags) | ||
915 | { | ||
916 | char *cpy; | ||
917 | size_t pos; | ||
918 | size_t last; | ||
919 | ssize_t lastconf; | ||
920 | size_t len; | ||
921 | |||
922 | if (config == NULL) | ||
923 | return prev; | ||
924 | len = strlen(config); | ||
925 | cpy = strdup(config); | ||
926 | if (cpy == NULL) | ||
927 | return prev; | ||
928 | pos = 0; | ||
929 | last = 0; | ||
930 | lastconf = 0; | ||
931 | while (pos < len) | ||
932 | { | ||
933 | while ((cpy[pos] != ':') && (cpy[pos] != '\0') && | ||
934 | (cpy[pos] != '(')) | ||
935 | pos++; | ||
936 | if( cpy[pos] == '(' ) { | ||
937 | cpy[pos++] = '\0'; /* replace '(' by termination */ | ||
938 | lastconf = pos; /* start config from here, after (. */ | ||
939 | while ((cpy[pos] != '\0') && (cpy[pos] != ')')) | ||
940 | pos++; /* config until ) or EOS. */ | ||
941 | if( cpy[pos] == ')' ) { | ||
942 | cpy[pos++] = '\0'; /* write end of config here. */ | ||
943 | while ((cpy[pos] != ':') && (cpy[pos] != '\0')) | ||
944 | pos++; /* forward until real end of string found. */ | ||
945 | cpy[pos++] = '\0'; | ||
946 | } else { | ||
947 | cpy[pos++] = '\0'; /* end of string. */ | ||
948 | } | ||
949 | } else { | ||
950 | lastconf = -1; /* NULL config when no (). */ | ||
951 | cpy[pos++] = '\0'; /* replace ':' by termination */ | ||
952 | } | ||
953 | if (cpy[last] == '-') | ||
954 | { | ||
955 | last++; | ||
956 | prev = EXTRACTOR_plugin_remove (prev, | ||
957 | &cpy[last]); | ||
958 | } | ||
959 | else | ||
960 | { | ||
961 | prev = EXTRACTOR_plugin_add (prev, | ||
962 | &cpy[last], | ||
963 | (lastconf != -1) ? &cpy[lastconf] : NULL, | ||
964 | flags); | ||
965 | } | ||
966 | last = pos; | ||
967 | } | ||
968 | free (cpy); | ||
969 | return prev; | ||
970 | } | ||
971 | |||
972 | |||
973 | /** | ||
974 | * Stop the child process of this plugin. | 70 | * Stop the child process of this plugin. |
975 | */ | 71 | */ |
976 | static void | 72 | static void |