]> git.draconx.ca Git - upkg.git/blob - src/uobject/package.c
Stop using gnulib's flexmember module.
[upkg.git] / src / uobject / package.c
1 /*
2  * upkg: tool for manipulating Unreal Tournament packages.
3  * Copyright © 2009-2011, 2022 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 3 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, see <https://www.gnu.org/licenses/>.
17  */
18
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <ctype.h>
24
25 #include <glib-object.h>
26 #include <ltdl.h>
27
28 #include <uobject/package.h>
29 #include <uobject/vfs.h>
30 #include "upkg.h"
31
32 #define U_PKG_GET_PRIV(o) \
33         G_TYPE_INSTANCE_GET_PRIVATE(o, U_PKG_TYPE, struct upkg_priv)
34
35 struct upkg_priv {
36         lt_dlhandle native;
37 };
38
39 G_DEFINE_TYPE(UPkg, u_pkg, G_TYPE_TYPE_MODULE);
40
41 static char *str_cpy_lower(char *dst, const char *src)
42 {
43         size_t i;
44
45         for (i = 0; src[i]; i++)
46                 dst[i] = tolower(src[i]);
47         dst[i] = 0;
48
49         return dst;
50 }
51
52 static void dl_print_errors(const char *prefix)
53 {
54         const char *err;
55         while ((err = lt_dlerror())) {
56                 if (prefix) fprintf(stderr, "%s: ", prefix);
57                 fprintf(stderr, "%s\n", err);
58         }
59 }
60
61 static gboolean u_pkg_load(GTypeModule *m)
62 {
63         struct upkg_priv *priv = U_PKG_GET_PRIV(m);
64         int (*init_func)(GTypeModule *);
65
66         /* Ignore failure here until we get rid of native-only packages. */
67         U_PKG(m)->pkg = u_pkg_vfs_open_by_name(m->name);
68
69         priv->native = lt_dlopenext(m->name);
70         if (priv->native) {
71                 init_func = lt_dlsym(priv->native, "init");
72                 if (!init_func || init_func(m) != 0) {
73                         dl_print_errors(__func__);
74                         lt_dlclose(priv->native);
75                         upkg_close(U_PKG(m)->pkg);
76                         return FALSE;
77                 }
78         }
79
80         return TRUE;
81 }
82
83 static void u_pkg_unload(GTypeModule *m)
84 {
85         struct upkg_priv *priv = U_PKG_GET_PRIV(m);
86         void (*exit_func)(GTypeModule *);
87         UPkg *upkg = U_PKG(m);
88
89         if (priv->native) {
90                 exit_func = lt_dlsym(priv->native, "exit");
91                 if (exit_func) {
92                         exit_func(m);
93                 }
94
95                 if (lt_dlclose(priv->native) != 0) {
96                         dl_print_errors(__func__);
97                 }
98
99                 priv->native = NULL;
100         }
101
102         if (upkg->pkg) {
103                 upkg_close(upkg->pkg);
104                 upkg->pkg = NULL;
105         }
106 }
107
108 static void u_pkg_init(UPkg *pkg)
109 {
110
111 }
112
113 static void u_pkg_finalize(GObject *o)
114 {
115         u_pkg_unload(G_TYPE_MODULE(o));
116 }
117
118 static void u_pkg_class_init(UPkgClass *class)
119 {
120         GTypeModuleClass *modclass = G_TYPE_MODULE_CLASS(class);
121         GObjectClass *objclass = G_OBJECT_CLASS(class);
122
123         const char *modpath = getenv("UOBJECT_MODULE_PATH");
124
125         g_type_class_add_private(class, sizeof (struct upkg_priv));
126
127         if (lt_dlinit() != 0) {
128                 dl_print_errors(__func__);
129         }
130
131         if (modpath && lt_dlsetsearchpath(modpath) != 0) {
132                 dl_print_errors(__func__);
133         }
134         if (lt_dladdsearchdir(PKGLIBDIR) != 0) {
135                 dl_print_errors(__func__);
136         }
137
138         modclass->load     = u_pkg_load;
139         modclass->unload   = u_pkg_unload;
140         objclass->finalize = u_pkg_finalize;
141 }
142
143 GTypeModule *u_pkg_open(const char *name)
144 {
145         g_return_val_if_fail(name != NULL, NULL);
146
147         char *pkgname = malloc(strlen(name)+1);
148         if (!pkgname) {
149                 return NULL;
150         }
151
152         GTypeModule *mod = g_object_new(U_PKG_TYPE, NULL);
153         if (!mod) {
154                 free(pkgname);
155                 return NULL;
156         }
157
158         mod->name = str_cpy_lower(pkgname, name);
159         return mod;
160 }
161
162 int u_pkg_is_native(GTypeModule *m)
163 {
164         struct upkg_priv *priv = U_PKG_GET_PRIV(m);
165
166         return !!priv->native;
167 }