1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * lt-ext-module.c
4  * Copyright (C) 2011-2012 Akira TAGOH
5  *
6  * Authors:
7  *   Akira TAGOH  <akira@tagoh.org>
8  *
9  * You may distribute under the terms of either the GNU
10  * Lesser General Public License or the Mozilla Public
11  * License, as specified in the README file.
12  */
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16 
17 #include <ctype.h>
18 #if HAVE_DIRENT_H
19 #include <dirent.h>
20 #endif
21 #if HAVE_DLFCN_H
22 #include <dlfcn.h>
23 #endif
24 #if HAVE_LIBGEN_H
25 #include <libgen.h>
26 #endif
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include "lt-mem.h"
32 #include "lt-messages.h"
33 #include "lt-ext-module-data.h"
34 #include "lt-ext-module.h"
35 #include "lt-ext-module-private.h"
36 #include "lt-lock.h"
37 #include "lt-utils.h"
38 
39 
40 /**
41  * SECTION: lt-ext-module
42  * @Short_Description: A module class to extend features in #lt_extension_t.
43  * @Title: Module - Accessor
44  *
45  * This class provides functionality to extend features in #lt_extension_t,
46  * such as validating tags more strictly.
47  */
48 struct _lt_ext_module_t {
49 	lt_mem_t                     parent;
50 	char                        *name;
51 	lt_pointer_t                 module;
52 	const lt_ext_module_funcs_t *funcs;
53 };
54 
55 typedef struct _lt_ext_default_data_t {
56 	lt_ext_module_data_t  parent;
57 	lt_string_t          *tags;
58 } lt_ext_default_data_t;
59 
60 static lt_ext_module_data_t *_lt_ext_default_create_data (void);
61 static lt_bool_t             _lt_ext_default_precheck_tag(lt_ext_module_data_t  *data,
62 							  const lt_tag_t        *tag,
63 							  lt_error_t           **error);
64 static lt_bool_t             _lt_ext_default_parse_tag   (lt_ext_module_data_t  *data,
65 							  const char            *subtag,
66 							  lt_error_t           **error);
67 static char                 *_lt_ext_default_get_tag     (lt_ext_module_data_t  *data);
68 static lt_bool_t             _lt_ext_default_validate_tag(lt_ext_module_data_t  *data);
69 static lt_ext_module_data_t *_lt_ext_eaw_create_data     (void);
70 static lt_bool_t             _lt_ext_eaw_precheck_tag    (lt_ext_module_data_t  *data,
71 							  const lt_tag_t        *tag,
72 							  lt_error_t           **error);
73 static lt_bool_t             _lt_ext_eaw_parse_tag       (lt_ext_module_data_t  *data,
74 							  const char            *subtag,
75 							  lt_error_t           **error);
76 static char                 *_lt_ext_eaw_get_tag         (lt_ext_module_data_t  *data);
77 static lt_bool_t             _lt_ext_eaw_validate_tag    (lt_ext_module_data_t  *data);
78 
79 #if !ENABLE_MODULE
80 extern const lt_ext_module_funcs_t *LT_MODULE_SYMBOL_ (lt_module_ext_t, get_funcs) (void);
81 extern const lt_ext_module_funcs_t *LT_MODULE_SYMBOL_ (lt_module_ext_u, get_funcs) (void);
82 #endif
83 
84 static lt_ext_module_t *__lt_ext_modules[LT_MAX_EXT_MODULES + 1];
85 static lt_ext_module_t *__lt_ext_default_handler;
86 static lt_bool_t __lt_ext_module_initialized = FALSE;
87 static const lt_ext_module_funcs_t __default_funcs = {
88 	NULL,
89 	_lt_ext_default_create_data,
90 	_lt_ext_default_precheck_tag,
91 	_lt_ext_default_parse_tag,
92 	_lt_ext_default_get_tag,
93 	_lt_ext_default_validate_tag,
94 };
95 static const lt_ext_module_funcs_t __empty_and_wildcard_funcs = {
96 	NULL,
97 	_lt_ext_eaw_create_data,
98 	_lt_ext_eaw_precheck_tag,
99 	_lt_ext_eaw_parse_tag,
100 	_lt_ext_eaw_get_tag,
101 	_lt_ext_eaw_validate_tag,
102 };
103 LT_LOCK_DEFINE_STATIC (extmod);
104 
105 /*< private >*/
106 static void
_lt_ext_default_destroy_data(lt_pointer_t data)107 _lt_ext_default_destroy_data(lt_pointer_t data)
108 {
109 	lt_ext_default_data_t *d = data;
110 
111 	lt_string_unref(d->tags);
112 }
113 
114 static lt_ext_module_data_t *
_lt_ext_default_create_data(void)115 _lt_ext_default_create_data(void)
116 {
117 	lt_ext_module_data_t *retval = lt_ext_module_data_new(sizeof (lt_ext_default_data_t),
118 							      _lt_ext_default_destroy_data);
119 
120 	if (retval) {
121 		lt_ext_default_data_t *data = (lt_ext_default_data_t *)retval;
122 
123 		data->tags = lt_string_new(NULL);
124 	}
125 
126 	return retval;
127 }
128 
129 static lt_bool_t
_lt_ext_default_precheck_tag(lt_ext_module_data_t * data,const lt_tag_t * tag,lt_error_t ** error)130 _lt_ext_default_precheck_tag(lt_ext_module_data_t  *data,
131 			     const lt_tag_t        *tag,
132 			     lt_error_t           **error)
133 {
134 	return TRUE;
135 }
136 
137 static lt_bool_t
_lt_ext_default_parse_tag(lt_ext_module_data_t * data,const char * subtag,lt_error_t ** error)138 _lt_ext_default_parse_tag(lt_ext_module_data_t  *data,
139 			  const char            *subtag,
140 			  lt_error_t           **error)
141 {
142 	lt_ext_default_data_t *d = (lt_ext_default_data_t *)data;
143 
144 	if (lt_string_length(d->tags) > 0)
145 		lt_string_append_printf(d->tags, "-%s", subtag);
146 	else
147 		lt_string_append(d->tags, subtag);
148 
149 	return TRUE;
150 }
151 
152 static char *
_lt_ext_default_get_tag(lt_ext_module_data_t * data)153 _lt_ext_default_get_tag(lt_ext_module_data_t *data)
154 {
155 	lt_ext_default_data_t *d = (lt_ext_default_data_t *)data;
156 
157 	return strdup(lt_string_value(d->tags));
158 }
159 
160 static lt_bool_t
_lt_ext_default_validate_tag(lt_ext_module_data_t * data)161 _lt_ext_default_validate_tag(lt_ext_module_data_t *data)
162 {
163 	return TRUE;
164 }
165 
166 static void
_lt_ext_eaw_destroy_data(lt_pointer_t data)167 _lt_ext_eaw_destroy_data(lt_pointer_t data)
168 {
169 }
170 
171 static lt_ext_module_data_t *
_lt_ext_eaw_create_data(void)172 _lt_ext_eaw_create_data(void)
173 {
174 	lt_ext_module_data_t *retval = lt_ext_module_data_new(sizeof (lt_ext_module_data_t),
175 							      _lt_ext_eaw_destroy_data);
176 
177 	return retval;
178 }
179 
180 static lt_bool_t
_lt_ext_eaw_precheck_tag(lt_ext_module_data_t * data,const lt_tag_t * tag,lt_error_t ** error)181 _lt_ext_eaw_precheck_tag(lt_ext_module_data_t  *data,
182 			 const lt_tag_t        *tag,
183 			 lt_error_t           **error)
184 {
185 	/* not allowed to process any extensions */
186 
187 	return FALSE;
188 }
189 
190 static lt_bool_t
_lt_ext_eaw_parse_tag(lt_ext_module_data_t * data,const char * subtag,lt_error_t ** error)191 _lt_ext_eaw_parse_tag(lt_ext_module_data_t  *data,
192 		      const char            *subtag,
193 		      lt_error_t           **error)
194 {
195 	/* not allowed to add any tags */
196 
197 	return FALSE;
198 }
199 
200 static char *
_lt_ext_eaw_get_tag(lt_ext_module_data_t * data)201 _lt_ext_eaw_get_tag(lt_ext_module_data_t *data)
202 {
203 	return strdup("");
204 }
205 
206 static lt_bool_t
_lt_ext_eaw_validate_tag(lt_ext_module_data_t * data)207 _lt_ext_eaw_validate_tag(lt_ext_module_data_t *data)
208 {
209 	return TRUE;
210 }
211 
212 #if ENABLE_MODULE
213 static lt_bool_t
lt_ext_module_load(lt_ext_module_t * module)214 lt_ext_module_load(lt_ext_module_t *module)
215 {
216 	lt_bool_t retval = FALSE;
217 	lt_string_t *fullname = lt_string_new(NULL);
218 	char *filename = lt_strdup_printf("liblangtag-ext-%s." LT_MODULE_SUFFIX,
219 					  module->name);
220 	char *path_list, *p, *s, *path;
221 	const char *env = lt_getenv("LANGTAG_EXT_MODULE_PATH");
222 	size_t len;
223 
224 	if (!env) {
225 		path_list = strdup(
226 #ifdef ENABLE_DEBUG
227 			BUILDDIR LT_DIR_SEPARATOR_S "extensions" LT_SEARCHPATH_SEPARATOR_S
228 			BUILDDIR LT_DIR_SEPARATOR_S "extensions" LT_DIR_SEPARATOR_S ".libs" LT_SEARCHPATH_SEPARATOR_S
229 #endif
230 			LANGTAG_EXT_MODULE_PATH);
231 	} else {
232 		path_list = strdup(env);
233 	}
234 
235 	s = path_list;
236 	do {
237 		if (!s)
238 			break;
239 		p = strchr(s, LT_SEARCHPATH_SEPARATOR);
240 		if (p == s) {
241 			s++;
242 			continue;
243 		}
244 		path = s;
245 		if (p) {
246 			*p = 0;
247 			p++;
248 		}
249 		s = p;
250 		while (*path && isspace((int)*path))
251 			path++;
252 		len = strlen(path);
253 		while (len > 0 && isspace((int)path[len - 1]))
254 			len--;
255 		path[len] = 0;
256 		if (path[0] != 0) {
257 			lt_string_clear(fullname);
258 			lt_string_append_filename(fullname, path, filename, NULL);
259 			module->module = dlopen(lt_string_value(fullname),
260 						RTLD_LAZY|RTLD_LOCAL);
261 			if (module->module) {
262 				lt_pointer_t func;
263 
264 				lt_mem_add_ref(&module->parent, module->module,
265 					       (lt_destroy_func_t)dlclose);
266 				func = dlsym(module->module, "module_get_version");
267 				if (!func) {
268 					lt_warning("%s", dlerror());
269 					break;
270 				}
271 				if (((lt_ext_module_version_func_t)func)() != LT_EXT_MODULE_VERSION) {
272 					lt_warning("`%s' isn't satisfied the required module version.",
273 						   filename);
274 					break;
275 				}
276 				func = dlsym(module->module, "module_get_funcs");
277 				if (!func) {
278 					lt_warning("%s", dlerror());
279 					break;
280 				}
281 				if (!(module->funcs = ((lt_ext_module_get_funcs_func_t)func)())) {
282 					lt_warning("No function table for `%s'",
283 						   filename);
284 					break;
285 				}
286 				lt_debug(LT_MSGCAT_MODULE,
287 					 "Loading the external extension handler module: %s",
288 					 lt_string_value(fullname));
289 				retval = TRUE;
290 			}
291 		}
292 	} while (1);
293 	if (!retval)
294 		lt_warning("No such modules: %s", module->name);
295 
296 	lt_string_unref(fullname);
297 	free(filename);
298 	free(path_list);
299 
300 	return retval;
301 }
302 #endif /* ENABLE_MODULE */
303 
304 static lt_ext_module_t *
lt_ext_module_new_with_data(const char * name,const lt_ext_module_funcs_t * funcs)305 lt_ext_module_new_with_data(const char                  *name,
306 			    const lt_ext_module_funcs_t *funcs)
307 {
308 	lt_ext_module_t *retval;
309 
310 	lt_return_val_if_fail (name != NULL, NULL);
311 	lt_return_val_if_fail (funcs != NULL, NULL);
312 
313 	retval = lt_mem_alloc_object(sizeof (lt_ext_module_t));
314 	if (retval) {
315 		retval->name = strdup(name);
316 		lt_mem_add_ref(&retval->parent, retval->name,
317 			       (lt_destroy_func_t)free);
318 		retval->funcs = funcs;
319 
320 		lt_debug(LT_MSGCAT_MODULE, "Loading the internal extension handler: %s", name);
321 	}
322 
323 	return retval;
324 }
325 
326 /*< protected >*/
327 lt_bool_t
lt_ext_module_validate_singleton(char singleton)328 lt_ext_module_validate_singleton(char singleton)
329 {
330 	return (singleton >= '0' && singleton <= '9') ||
331 		(singleton >= 'A' && singleton <= 'W') ||
332 		(singleton >= 'Y' && singleton <= 'Z') ||
333 		(singleton >= 'a' && singleton <= 'w') ||
334 		(singleton >= 'y' && singleton <= 'z') ||
335 		singleton == ' ' ||
336 		singleton == '*';
337 }
338 
339 int
lt_ext_module_singleton_char_to_int(char singleton_c)340 lt_ext_module_singleton_char_to_int(char singleton_c)
341 {
342 	int retval = -1;
343 
344 	lt_return_val_if_fail (lt_ext_module_validate_singleton(singleton_c), -1);
345 
346 	if (singleton_c >= '0' && singleton_c <= '9') {
347 		retval = singleton_c - '0';
348 	} else if ((singleton_c >= 'a' && singleton_c <= 'z') ||
349 		   (singleton_c >= 'A' && singleton_c <= 'Z')) {
350 		retval = tolower((int)singleton_c) - 'a' + 10;
351 	} else if (singleton_c == ' ') {
352 		retval = LT_MAX_EXT_MODULES - 2;
353 	} else if (singleton_c == '*') {
354 		retval = LT_MAX_EXT_MODULES - 1;
355 	}
356 
357 	return retval;
358 }
359 
360 char
lt_ext_module_singleton_int_to_char(int singleton)361 lt_ext_module_singleton_int_to_char(int singleton)
362 {
363 	char retval;
364 
365 	lt_return_val_if_fail (singleton >= 0, 0);
366 	lt_return_val_if_fail (singleton < LT_MAX_EXT_MODULES, 0);
367 
368 	if ((singleton - 10) < 0)
369 		retval = singleton + '0';
370 	else if (singleton == (LT_MAX_EXT_MODULES - 2))
371 		retval = ' ';
372 	else if (singleton == LT_MAX_EXT_MODULES - 1)
373 		retval = '*';
374 	else
375 		retval = singleton - 10 + 'a';
376 
377 	return retval;
378 }
379 
380 lt_ext_module_t *
lt_ext_module_new(const char * name)381 lt_ext_module_new(const char *name)
382 {
383 	lt_ext_module_t *retval = NULL;
384 
385 	lt_return_val_if_fail (name != NULL, NULL);
386 
387 #if ENABLE_MODULE
388 	retval = lt_mem_alloc_object(sizeof (lt_ext_module_t));
389 
390 	if (retval) {
391 		char *n = strdup(name);
392 		char *filename = basename(n), *module = NULL;
393 		static const char *prefix = "liblangtag-ext-";
394 		static size_t prefix_len = 0;
395 		char singleton_c;
396 		int singleton;
397 
398 		if (prefix_len == 0)
399 			prefix_len = strlen(prefix);
400 
401 		if (strncmp(filename, prefix, prefix_len) == 0) {
402 			size_t len = strlen(&filename[prefix_len]);
403 			size_t suffix_len = strlen(LT_MODULE_SUFFIX) + 1;
404 
405 			if (len > suffix_len &&
406 			    lt_strcmp0(&filename[prefix_len + len - suffix_len], "." LT_MODULE_SUFFIX) == 0) {
407 				module = lt_strndup(&filename[prefix_len], len - suffix_len);
408 				module[len - suffix_len] = 0;
409 			}
410 		}
411 		if (!module)
412 			module = strdup(filename);
413 		retval->name = module;
414 		lt_mem_add_ref(&retval->parent, retval->name,
415 			       (lt_destroy_func_t)free);
416 
417 		free(n);
418 
419 		if (!lt_ext_module_load(retval)) {
420 			lt_ext_module_unref(retval);
421 			return NULL;
422 		}
423 		singleton_c = lt_ext_module_get_singleton(retval);
424 		if (singleton_c == ' ' ||
425 		    singleton_c == '*') {
426 			lt_warning("Not allowed to override the internal handlers for special singleton.");
427 			lt_ext_module_unref(retval);
428 			return NULL;
429 		}
430 		singleton = lt_ext_module_singleton_char_to_int(singleton_c);
431 		if (singleton < 0) {
432 			lt_warning("Invalid singleton: `%c' - `%s'",
433 				   singleton_c,
434 				   retval->name);
435 			lt_ext_module_unref(retval);
436 			return NULL;
437 		}
438 		if (__lt_ext_modules[singleton]) {
439 			lt_warning("Duplicate extension module: %s",
440 				  retval->name);
441 			lt_ext_module_unref(retval);
442 			return NULL;
443 		}
444 		__lt_ext_modules[singleton] = retval;
445 		lt_mem_add_weak_pointer(&retval->parent,
446 					(lt_pointer_t *)&__lt_ext_modules[singleton]);
447 	}
448 #endif /* ENABLE_MODULE */
449 
450 	return retval;
451 }
452 
453 lt_ext_module_t *
lt_ext_module_lookup(char singleton_c)454 lt_ext_module_lookup(char singleton_c)
455 {
456 	int singleton = lt_ext_module_singleton_char_to_int(singleton_c);
457 
458 	lt_return_val_if_fail (singleton >= 0, NULL);
459 	lt_return_val_if_fail (singleton < LT_MAX_EXT_MODULES, NULL);
460 	lt_return_val_if_fail (__lt_ext_module_initialized, NULL);
461 
462 	if (!__lt_ext_modules[singleton])
463 		return lt_ext_module_ref(__lt_ext_default_handler);
464 
465 	return lt_ext_module_ref(__lt_ext_modules[singleton]);
466 }
467 
468 const char *
lt_ext_module_get_name(lt_ext_module_t * module)469 lt_ext_module_get_name(lt_ext_module_t *module)
470 {
471 	lt_return_val_if_fail (module != NULL, NULL);
472 
473 	return module->name;
474 }
475 
476 char
lt_ext_module_get_singleton(lt_ext_module_t * module)477 lt_ext_module_get_singleton(lt_ext_module_t *module)
478 {
479 	lt_return_val_if_fail (module != NULL, 0);
480 	lt_return_val_if_fail (module->funcs != NULL, 0);
481 	lt_return_val_if_fail (module->funcs->get_singleton != NULL, 0);
482 
483 	return module->funcs->get_singleton();
484 }
485 
486 lt_ext_module_data_t *
lt_ext_module_create_data(lt_ext_module_t * module)487 lt_ext_module_create_data(lt_ext_module_t *module)
488 {
489 	lt_return_val_if_fail (module != NULL, NULL);
490 	lt_return_val_if_fail (module->funcs != NULL, NULL);
491 	lt_return_val_if_fail (module->funcs->create_data != NULL, NULL);
492 
493 	return module->funcs->create_data();
494 }
495 
496 lt_bool_t
lt_ext_module_parse_tag(lt_ext_module_t * module,lt_ext_module_data_t * data,const char * subtag,lt_error_t ** error)497 lt_ext_module_parse_tag(lt_ext_module_t       *module,
498 			lt_ext_module_data_t  *data,
499 			const char            *subtag,
500 			lt_error_t           **error)
501 {
502 	lt_return_val_if_fail (module != NULL, FALSE);
503 	lt_return_val_if_fail (data != NULL, FALSE);
504 	lt_return_val_if_fail (subtag != NULL, FALSE);
505 	lt_return_val_if_fail (module->funcs != NULL, FALSE);
506 	lt_return_val_if_fail (module->funcs->parse_tag != NULL, FALSE);
507 
508 	return module->funcs->parse_tag(data, subtag, error);
509 }
510 
511 char *
lt_ext_module_get_tag(lt_ext_module_t * module,lt_ext_module_data_t * data)512 lt_ext_module_get_tag(lt_ext_module_t      *module,
513 		      lt_ext_module_data_t *data)
514 {
515 	lt_return_val_if_fail (module != NULL, NULL);
516 	lt_return_val_if_fail (data != NULL, NULL);
517 	lt_return_val_if_fail (module->funcs != NULL, NULL);
518 	lt_return_val_if_fail (module->funcs->get_tag != NULL, NULL);
519 
520 	return module->funcs->get_tag(data);
521 }
522 
523 lt_bool_t
lt_ext_module_validate_tag(lt_ext_module_t * module,lt_ext_module_data_t * data)524 lt_ext_module_validate_tag(lt_ext_module_t      *module,
525 			   lt_ext_module_data_t *data)
526 {
527 	lt_return_val_if_fail (module != NULL, FALSE);
528 	lt_return_val_if_fail (data != NULL, FALSE);
529 	lt_return_val_if_fail (module->funcs != NULL, FALSE);
530 	lt_return_val_if_fail (module->funcs->validate_tag != NULL, FALSE);
531 
532 	return module->funcs->validate_tag(data);
533 }
534 
535 lt_bool_t
lt_ext_module_precheck_tag(lt_ext_module_t * module,lt_ext_module_data_t * data,const lt_tag_t * tag,lt_error_t ** error)536 lt_ext_module_precheck_tag(lt_ext_module_t       *module,
537 			   lt_ext_module_data_t  *data,
538 			   const lt_tag_t        *tag,
539 			   lt_error_t           **error)
540 {
541 	lt_error_t *err = NULL;
542 	lt_bool_t retval;
543 
544 	lt_return_val_if_fail (module != NULL, FALSE);
545 	lt_return_val_if_fail (data != NULL, FALSE);
546 	lt_return_val_if_fail (module->funcs != NULL, FALSE);
547 	lt_return_val_if_fail (module->funcs->precheck_tag != NULL, FALSE);
548 
549 	retval = module->funcs->precheck_tag(data, tag, &err);
550 	if (lt_error_is_set(err, LT_ERR_ANY)) {
551 		if (error)
552 			*error = lt_error_ref(err);
553 		else
554 			lt_error_print(err, LT_ERR_ANY);
555 		lt_error_unref(err);
556 		retval = FALSE;
557 	}
558 
559 	return retval;
560 }
561 
562 /*< public >*/
563 /**
564  * lt_ext_modules_load:
565  *
566  * Load all of the modules on the system, including the internal accessor.
567  * This has to be invoked before processing something with #lt_extension_t.
568  * or lt_db_initialize() does.
569  */
570 void
lt_ext_modules_load(void)571 lt_ext_modules_load(void)
572 {
573 #if ENABLE_MODULE
574 	const char *env = lt_getenv("LANGTAG_EXT_MODULE_PATH");
575 	char *path_list, *s, *p, *path;
576 	size_t suffix_len = strlen(LT_MODULE_SUFFIX) + 1;
577 
578 	if (__lt_ext_module_initialized)
579 		return;
580 	if (!env) {
581 		path_list = strdup(
582 #ifdef ENABLE_DEBUG
583 			BUILDDIR LT_DIR_SEPARATOR_S "extensions" LT_SEARCHPATH_SEPARATOR_S
584 			BUILDDIR LT_DIR_SEPARATOR_S "extensions" LT_DIR_SEPARATOR_S ".libs" LT_SEARCHPATH_SEPARATOR_S
585 #endif
586 			LANGTAG_EXT_MODULE_PATH);
587 	} else {
588 		path_list = strdup(env);
589 	}
590 	s = path_list;
591 	do {
592 		DIR *dir;
593 
594 		if (!s)
595 			break;
596 		p = strchr(s, LT_SEARCHPATH_SEPARATOR);
597 		if (s == p) {
598 			s++;
599 			continue;
600 		}
601 		path = s;
602 		if (p) {
603 			*p = 0;
604 			p++;
605 		}
606 		s = p;
607 
608 		dir = opendir(path);
609 		if (dir) {
610 			struct dirent *dent, *p;
611 
612 			LT_LOCK (extmod);
613 			while ((dent = readdir (dir))) {
614 				size_t len = strlen (dent->d_name);
615 				size_t dentlen = offsetof (struct dirent, d_name) + len + 1;
616 
617 				dentlen = ((dentlen + ALIGNOF_VOID_P - 1) & ~(ALIGNOF_VOID_P - 1));
618 				p = (struct dirent *)malloc(dentlen);
619 				if (!p) {
620 					perror (__FUNCTION__);
621 					LT_UNLOCK (extmod);
622 					closedir(dir);
623 					free(path_list);
624 					return;
625 				}
626 				memcpy(p, dent, dentlen);
627 				if (len > suffix_len &&
628 				    lt_strcmp0(&(p->d_name[len - suffix_len]),
629 					       "." LT_MODULE_SUFFIX) == 0) {
630 					lt_ext_module_new(p->d_name);
631 				}
632 				free(p);
633 			}
634 			LT_UNLOCK (extmod);
635 			closedir(dir);
636 		}
637 	} while (1);
638 
639 	free(path_list);
640 #else /* !ENABLE_MODULE */
641 	const lt_ext_module_funcs_t *f;
642 	int c;
643 
644 #define REGISTER(_ext_)							\
645 	f = LT_MODULE_SYMBOL_ (lt_module_ext_##_ext_, get_funcs) ();	\
646 	c = lt_ext_module_singleton_char_to_int(f->get_singleton());	\
647 	__lt_ext_modules[c] = lt_ext_module_new_with_data(#_ext_, f);	\
648 	lt_mem_add_weak_pointer(&__lt_ext_modules[c]->parent,		\
649 				(lt_pointer_t *)&__lt_ext_modules[c]);
650 
651 	REGISTER (t);
652 	REGISTER (u);
653 
654 #undef REGISTER
655 #endif /* ENABLE_MODULE */
656 	__lt_ext_default_handler = lt_ext_module_new_with_data("default",
657 							       &__default_funcs);
658 	lt_mem_add_weak_pointer(&__lt_ext_default_handler->parent,
659 				(lt_pointer_t *)&__lt_ext_default_handler);
660 	__lt_ext_modules[LT_MAX_EXT_MODULES - 2] = lt_ext_module_new_with_data("empty",
661 									       &__empty_and_wildcard_funcs);
662 	lt_mem_add_weak_pointer(&__lt_ext_modules[LT_MAX_EXT_MODULES - 2]->parent,
663 				(lt_pointer_t *)&__lt_ext_modules[LT_MAX_EXT_MODULES - 2]);
664 	__lt_ext_modules[LT_MAX_EXT_MODULES - 1] = lt_ext_module_new_with_data("wildcard",
665 									   &__empty_and_wildcard_funcs);
666 	lt_mem_add_weak_pointer(&__lt_ext_modules[LT_MAX_EXT_MODULES - 1]->parent,
667 				(lt_pointer_t *)&__lt_ext_modules[LT_MAX_EXT_MODULES - 1]);
668 	__lt_ext_module_initialized = TRUE;
669 }
670 
671 /**
672  * lt_ext_modules_unload:
673  *
674  * Unload all of the modules already loaded.
675  */
676 void
lt_ext_modules_unload(void)677 lt_ext_modules_unload(void)
678 {
679 	int i;
680 
681 	if (!__lt_ext_module_initialized)
682 		return;
683 	for (i = 0; i < LT_MAX_EXT_MODULES; i++) {
684 		if (__lt_ext_modules[i])
685 			lt_ext_module_unref(__lt_ext_modules[i]);
686 	}
687 	lt_ext_module_unref(__lt_ext_default_handler);
688 	__lt_ext_module_initialized = FALSE;
689 }
690 
691 /**
692  * lt_ext_module_ref:
693  * @module: a #lt_ext_module_t.
694  *
695  * Increases the reference count of @module.
696  *
697  * Returns: (transfer none): the same @module object.
698  */
699 lt_ext_module_t *
lt_ext_module_ref(lt_ext_module_t * module)700 lt_ext_module_ref(lt_ext_module_t *module)
701 {
702 	lt_return_val_if_fail (module != NULL, NULL);
703 
704 	return lt_mem_ref(&module->parent);
705 }
706 
707 /**
708  * lt_ext_module_unref:
709  * @module: a #lt_ext_module_t.
710  *
711  * Decreases the reference count of @module. when its reference count
712  * drops to 0, the object is finalized (i.e. its memory is freed).
713  */
714 void
lt_ext_module_unref(lt_ext_module_t * module)715 lt_ext_module_unref(lt_ext_module_t *module)
716 {
717 	if (module)
718 		lt_mem_unref(&module->parent);
719 }
720