]> git.draconx.ca Git - upkg.git/blob - src/module.c
libupkg: Add signed integer unpacking to fix incorrect signedness issue.
[upkg.git] / src / module.c
1 /*
2  *  upkg: tool for manipulating Unreal Tournament packages.
3  *  Copyright (C) 2009 Nick Bowler
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <glib-object.h>
25 #include <ltdl.h>
26
27 #include "module.h"
28 #include "avl.h"
29
30 static unsigned initialized;
31 static struct avl_table *package_tree;
32
33 static char *str_cpy_lower(char *dst, const char *src)
34 {
35         size_t i;
36
37         for (i = 0; src[i]; i++)
38                 dst[i] = tolower(src[i]);
39         dst[i] = 0;
40
41         return dst;
42 }
43
44 G_DEFINE_TYPE(UPkgModule, upkg_module, G_TYPE_TYPE_MODULE);
45
46 static void dl_print_errors(const char *prefix)
47 {
48         const char *err;
49         while ((err = lt_dlerror())) {
50                 if (prefix) fprintf(stderr, "%s: ", prefix);
51                 puts(err);
52         }
53 }
54
55 static gboolean module_load(GTypeModule *m)
56 {
57         UPkgModule *mod = UPKG_MODULE(m);
58         int (*init_func)(GTypeModule *);
59
60         mod->dl = lt_dlopenext(G_TYPE_MODULE(m)->name);
61         if (!mod->dl) {
62                 dl_print_errors(G_TYPE_MODULE(m)->name);
63                 return FALSE;
64         }
65
66         init_func = lt_dlsym(mod->dl, "init");
67         if (!init_func || init_func(m) != 0) {
68                 dl_print_errors(__func__);
69                 lt_dlclose(mod->dl);
70                 return FALSE;
71         }
72
73         return TRUE;
74 }
75
76 static void module_unload(GTypeModule *m)
77 {
78         UPkgModule *mod = UPKG_MODULE(m);
79
80         if (lt_dlclose(mod->dl) != 0) {
81                 dl_print_errors(__func__);
82         }
83 }
84
85 static void upkg_module_init(UPkgModule *mod)
86 {
87 }
88
89 static void upkg_module_class_init(UPkgModuleClass *class)
90 {
91         GTypeModuleClass *modclass = G_TYPE_MODULE_CLASS(class);
92
93         modclass->load   = module_load;
94         modclass->unload = module_unload;
95 }
96
97 UPkgModule *upkg_module_new(const char *name)
98 {
99         char *name2;
100
101         if (!name) {
102                 return NULL;
103         }
104
105         name2 = malloc(strlen(name)+1);
106         if (!name2) {
107                 return NULL;
108         }
109
110         UPkgModule *mod = g_object_new(UPKG_MODULE_TYPE, NULL);
111         if (!mod) {
112                 free(name2);
113                 return NULL;
114         }
115
116         G_TYPE_MODULE(mod)->name = str_cpy_lower(name2, name);
117         return mod;
118 }
119
120 static int modcmp(const void *a, const void *b, void *_data)
121 {
122         const GTypeModule *ma = a;
123         const GTypeModule *mb = b;
124
125         return strcmp(ma->name, mb->name);
126 }
127
128 int module_init(void)
129 {
130         if (!initialized) {
131                 package_tree = avl_create(modcmp, NULL, NULL);
132                 if (!package_tree) {
133                         fprintf(stderr, "%s: failed to create package tree.\n", __func__);
134                         return -1;
135                 }
136
137                 if (lt_dlinit() != 0) {
138                         avl_destroy(package_tree, NULL);
139                         dl_print_errors(__func__);
140                         return -1;
141                 }
142
143                 g_type_init();
144         }
145
146         initialized++;
147         return 0;
148 }
149
150 int module_exit(void)
151 {
152         if (--initialized)
153                 return 0;
154
155         if (lt_dlexit() != 0) {
156                 dl_print_errors(__func__);
157                 return -1;
158         }
159
160         return 0;
161 }
162
163 GType module_get_class(const char *package, const char *class)
164 {
165         char buf[strlen(package) + strlen(class) + 1];
166         GTypeModule search = { .name = str_cpy_lower(buf, package) };
167
168         GTypeModule *mod = avl_find(package_tree, &search);
169         if (!mod) {
170                 void **p;
171
172                 mod = G_TYPE_MODULE(upkg_module_new(package));
173                 if (!mod) {
174                         return 0;
175                 }
176
177                 p = avl_probe(package_tree, mod);
178                 if (!p) {
179                         g_object_unref(mod);
180                         return 0;
181                 }
182         }
183
184         if (!g_type_module_use(mod))
185                 return 0;
186
187         str_cpy_lower(buf+strlen(package), class);
188         buf[0] = toupper(buf[0]);
189         buf[strlen(package)] = toupper(buf[strlen(package)]);
190         return g_type_from_name(buf);
191 }