]> git.draconx.ca Git - upkg.git/blob - src/module.c
eec80e73a5db14ef985a7305b092635ac98b976b
[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 <uobject/module.h>
28 #include "avl.h"
29
30 #define UPKG_MODULE_TYPE (upkg_module_get_type())
31 #define UPKG_MODULE(obj) \
32         G_TYPE_CHECK_INSTANCE_CAST(obj, UPKG_MODULE_TYPE, UPkgModule)
33 #define UPKG_MODULE_CLASS(class) \
34         G_TYPE_CHECK_CLASS_CAST(class, UPKG_MODULE_TYPE, UPkgModuleClass)
35 #define IS_UPKG_MODULE(obj) \
36         G_TYPE_CHECK_INSTANCE_TYPE(obj, UPKG_MODULE_TYPE)
37 #define IS_UPKG_MODULE_CLASS(class) \
38         G_TYPE_CHECK_CLASS_TYPE(class, UPKG_MODULE_TYPE, UPkgModuleClass)
39
40 typedef struct UPkgModule      UPkgModule;
41 typedef struct UPkgModuleClass UPkgModuleClass;
42
43 struct UPkgModule {
44         GTypeModule parent;
45
46         lt_dlhandle dl;
47 };
48
49 struct UPkgModuleClass {
50         GTypeModuleClass parent;
51 };
52
53 static unsigned initialized;
54 static struct avl_table *package_tree;
55
56 static char *str_cpy_lower(char *dst, const char *src)
57 {
58         size_t i;
59
60         for (i = 0; src[i]; i++)
61                 dst[i] = tolower(src[i]);
62         dst[i] = 0;
63
64         return dst;
65 }
66
67 G_DEFINE_TYPE(UPkgModule, upkg_module, G_TYPE_TYPE_MODULE);
68
69 static void dl_print_errors(const char *prefix)
70 {
71         const char *err;
72         while ((err = lt_dlerror())) {
73                 if (prefix) fprintf(stderr, "%s: ", prefix);
74                 puts(err);
75         }
76 }
77
78 static gboolean module_load(GTypeModule *m)
79 {
80         UPkgModule *mod = UPKG_MODULE(m);
81         int (*init_func)(GTypeModule *);
82
83         mod->dl = lt_dlopenext(G_TYPE_MODULE(m)->name);
84         if (!mod->dl) {
85                 dl_print_errors(G_TYPE_MODULE(m)->name);
86                 return FALSE;
87         }
88
89         init_func = lt_dlsym(mod->dl, "init");
90         if (!init_func || init_func(m) != 0) {
91                 dl_print_errors(__func__);
92                 lt_dlclose(mod->dl);
93                 return FALSE;
94         }
95
96         return TRUE;
97 }
98
99 static void module_unload(GTypeModule *m)
100 {
101         UPkgModule *mod = UPKG_MODULE(m);
102
103         if (lt_dlclose(mod->dl) != 0) {
104                 dl_print_errors(__func__);
105         }
106 }
107
108 static void upkg_module_init(UPkgModule *mod)
109 {
110 }
111
112 static void upkg_module_class_init(UPkgModuleClass *class)
113 {
114         GTypeModuleClass *modclass = G_TYPE_MODULE_CLASS(class);
115
116         modclass->load   = module_load;
117         modclass->unload = module_unload;
118 }
119
120 static UPkgModule *uobject_module_new(const char *name)
121 {
122         char *name2;
123
124         if (!name) {
125                 return NULL;
126         }
127
128         name2 = malloc(strlen(name)+1);
129         if (!name2) {
130                 return NULL;
131         }
132
133         UPkgModule *mod = g_object_new(UPKG_MODULE_TYPE, NULL);
134         if (!mod) {
135                 free(name2);
136                 return NULL;
137         }
138
139         G_TYPE_MODULE(mod)->name = str_cpy_lower(name2, name);
140         return mod;
141 }
142
143 static int modcmp(const void *a, const void *b, void *_data)
144 {
145         const GTypeModule *ma = a;
146         const GTypeModule *mb = b;
147
148         return strcmp(ma->name, mb->name);
149 }
150
151 int uobject_module_init(void)
152 {
153         if (!initialized) {
154                 package_tree = avl_create(modcmp, NULL, NULL);
155                 if (!package_tree) {
156                         fprintf(stderr, "%s: failed to create package tree.\n", __func__);
157                         return -1;
158                 }
159
160                 if (lt_dlinit() != 0) {
161                         avl_destroy(package_tree, NULL);
162                         dl_print_errors(__func__);
163                         return -1;
164                 }
165
166                 g_type_init();
167         }
168
169         initialized++;
170         return 0;
171 }
172
173 int uobject_module_exit(void)
174 {
175         if (--initialized)
176                 return 0;
177
178         if (lt_dlexit() != 0) {
179                 dl_print_errors(__func__);
180                 return -1;
181         }
182
183         return 0;
184 }
185
186 GType uobject_module_get_class(const char *package, const char *class)
187 {
188         char buf[strlen(package) + strlen(class) + 1];
189         GTypeModule search = { .name = str_cpy_lower(buf, package) };
190
191         GTypeModule *mod = avl_find(package_tree, &search);
192         if (!mod) {
193                 void **p;
194
195                 mod = G_TYPE_MODULE(uobject_module_new(package));
196                 if (!mod) {
197                         return 0;
198                 }
199
200                 p = avl_probe(package_tree, mod);
201                 if (!p) {
202                         g_object_unref(mod);
203                         return 0;
204                 }
205         }
206
207         if (!g_type_module_use(mod))
208                 return 0;
209
210         str_cpy_lower(buf+strlen(package), class);
211         buf[0] = toupper(buf[0]);
212         buf[strlen(package)] = toupper(buf[strlen(package)]);
213         return g_type_from_name(buf);
214 }