79 |
|
|
80 |
#define MODULE_SELF_NAME "!myself!" |
#define MODULE_SELF_NAME "!myself!" |
81 |
|
|
|
typedef struct { |
|
|
m4_builtin *builtin_table; |
|
|
m4_macro *macro_table; |
|
|
} module_data; |
|
|
|
|
82 |
static const char* module_dlerror (void); |
static const char* module_dlerror (void); |
83 |
static int module_remove (m4 *context, lt_dlhandle handle, |
static int module_remove (m4 *context, lt_dlhandle handle, |
84 |
m4_obstack *obs); |
m4_obstack *obs); |
85 |
static void module_close (m4 *context, lt_dlhandle handle, |
static void module_close (m4 *context, lt_dlhandle handle, |
86 |
m4_obstack *obs); |
m4_obstack *obs); |
87 |
|
|
88 |
static void set_module_macro_table (m4*, lt_dlhandle, const m4_macro*); |
static const m4_builtin * install_builtin_table (m4*, lt_dlhandle); |
89 |
static void set_module_builtin_table (m4*, lt_dlhandle, const m4_builtin*); |
static const m4_macro * install_macro_table (m4*, lt_dlhandle); |
90 |
|
|
91 |
static lt_dlcaller_id caller_id = 0; |
static lt_dlcaller_id caller_id = 0; |
92 |
|
|
102 |
return info ? info->name : 0; |
return info ? info->name : 0; |
103 |
} |
} |
104 |
|
|
105 |
m4_builtin * |
void * |
106 |
m4_get_module_builtin_table (lt_dlhandle handle) |
m4_module_import (m4 *context, const char *module_name, |
107 |
|
const char *symbol_name, m4_obstack *obs) |
108 |
{ |
{ |
109 |
module_data *data; |
lt_dlhandle handle = lt_dlhandle_find (module_name); |
110 |
|
lt_ptr symbol_address = 0; |
111 |
|
|
112 |
assert (handle); |
/* Try to load the module if it is not yet available (errors are |
113 |
|
diagnosed by m4_module_load). */ |
114 |
|
if (!handle) |
115 |
|
handle = m4_module_load (context, module_name, obs); |
116 |
|
|
117 |
data = lt_dlcaller_get_data (caller_id, handle); |
if (handle) |
118 |
|
{ |
119 |
|
symbol_address = lt_dlsym (handle, symbol_name); |
120 |
|
|
121 |
return data ? data->builtin_table : 0; |
if (!symbol_address) |
122 |
|
M4ERROR ((m4_get_warning_status_opt (context), 0, |
123 |
|
_("Warning: cannot load symbol `%s' from module `%s'"), |
124 |
|
symbol_name, module_name)); |
125 |
|
} |
126 |
|
|
127 |
|
return (void *) symbol_address; |
128 |
} |
} |
129 |
|
|
130 |
static void |
static const m4_builtin * |
131 |
set_module_builtin_table (m4 *context, lt_dlhandle handle, |
install_builtin_table (m4 *context, lt_dlhandle handle) |
|
const m4_builtin *table) |
|
132 |
{ |
{ |
133 |
const m4_builtin *bp; |
const m4_builtin *bp; |
134 |
|
|
135 |
assert (context); |
assert (context); |
136 |
assert (handle); |
assert (handle); |
|
assert (table); |
|
137 |
|
|
138 |
for (bp = table; bp->name != NULL; bp++) |
bp = (const m4_builtin *) lt_dlsym (handle, BUILTIN_SYMBOL); |
139 |
|
if (bp) |
140 |
{ |
{ |
141 |
m4_symbol_value *value = m4_symbol_value_create (); |
for (; bp->name != NULL; bp++) |
|
char * name; |
|
|
|
|
|
m4_set_symbol_value_func (value, bp->func); |
|
|
VALUE_HANDLE (value) = handle; |
|
|
VALUE_MIN_ARGS (value) = bp->min_args; |
|
|
VALUE_MAX_ARGS (value) = bp->max_args; |
|
|
|
|
|
if (bp->groks_macro_args) |
|
|
BIT_SET (VALUE_FLAGS (value), VALUE_MACRO_ARGS_BIT); |
|
|
if (bp->blind_if_no_args) |
|
|
BIT_SET (VALUE_FLAGS (value), VALUE_BLIND_ARGS_BIT); |
|
|
|
|
|
if (m4_get_prefix_builtins_opt (context)) |
|
142 |
{ |
{ |
143 |
static const char prefix[] = "m4_"; |
m4_symbol_value *value = m4_symbol_value_create (); |
144 |
size_t len = strlen (prefix) + strlen (bp->name); |
char * name; |
145 |
|
|
146 |
name = (char *) xmalloc (1+ len); |
m4_set_symbol_value_func (value, bp->func); |
147 |
snprintf (name, 1+ len, "%s%s", prefix, bp->name); |
VALUE_HANDLE (value) = handle; |
148 |
} |
VALUE_MIN_ARGS (value) = bp->min_args; |
149 |
else |
VALUE_MAX_ARGS (value) = bp->max_args; |
150 |
name = (char *) bp->name; |
|
151 |
|
if (bp->groks_macro_args) |
152 |
|
BIT_SET (VALUE_FLAGS (value), VALUE_MACRO_ARGS_BIT); |
153 |
|
if (bp->blind_if_no_args) |
154 |
|
BIT_SET (VALUE_FLAGS (value), VALUE_BLIND_ARGS_BIT); |
155 |
|
|
156 |
|
if (m4_get_prefix_builtins_opt (context)) |
157 |
|
{ |
158 |
|
static const char prefix[] = "m4_"; |
159 |
|
size_t len = strlen (prefix) + strlen (bp->name); |
160 |
|
|
161 |
m4_symbol_pushdef (M4SYMTAB, name, value); |
name = (char *) xmalloc (1+ len); |
162 |
|
snprintf (name, 1+ len, "%s%s", prefix, bp->name); |
163 |
|
} |
164 |
|
else |
165 |
|
name = (char *) bp->name; |
166 |
|
|
167 |
if (m4_get_prefix_builtins_opt (context)) |
m4_symbol_pushdef (M4SYMTAB, name, value); |
|
xfree (name); |
|
|
} |
|
|
} |
|
168 |
|
|
169 |
m4_macro * |
if (m4_get_prefix_builtins_opt (context)) |
170 |
m4_get_module_macro_table (lt_dlhandle handle) |
xfree (name); |
171 |
{ |
} |
|
module_data *data; |
|
|
|
|
|
assert (handle); |
|
172 |
|
|
173 |
data = lt_dlcaller_get_data (caller_id, handle); |
#ifdef DEBUG_MODULES |
174 |
|
M4_DEBUG_MESSAGE1("module %s: builtins loaded", |
175 |
|
m4_get_module_name (handle)); |
176 |
|
#endif /* DEBUG_MODULES */ |
177 |
|
} |
178 |
|
|
179 |
return data ? data->macro_table : 0; |
return bp; |
180 |
} |
} |
181 |
|
|
182 |
static void |
static const m4_macro * |
183 |
set_module_macro_table (m4 *context, lt_dlhandle handle, |
install_macro_table (m4 *context, lt_dlhandle handle) |
|
const m4_macro *table) |
|
184 |
{ |
{ |
185 |
const m4_macro *mp; |
const m4_macro *mp; |
186 |
|
|
187 |
assert (context); |
assert (context); |
188 |
assert (handle); |
assert (handle); |
|
assert (table); |
|
189 |
|
|
190 |
for (mp = table; mp->name != NULL; mp++) |
mp = (const m4_macro *) lt_dlsym (handle, MACRO_SYMBOL); |
191 |
|
|
192 |
|
if (mp) |
193 |
{ |
{ |
194 |
m4_symbol_value *value = m4_symbol_value_create (); |
for (; mp->name != NULL; mp++) |
195 |
|
{ |
196 |
|
m4_symbol_value *value = m4_symbol_value_create (); |
197 |
|
|
198 |
|
m4_set_symbol_value_text (value, xstrdup (mp->value)); |
199 |
|
VALUE_HANDLE (value) = handle; |
200 |
|
|
201 |
m4_set_symbol_value_text (value, xstrdup (mp->value)); |
m4_symbol_pushdef (M4SYMTAB, mp->name, value); |
202 |
VALUE_HANDLE (value) = handle; |
} |
203 |
|
|
204 |
m4_symbol_pushdef (M4SYMTAB, mp->name, value); |
#ifdef DEBUG_MODULES |
205 |
|
M4_DEBUG_MESSAGE1("module %s: macros loaded", |
206 |
|
m4_get_module_name (handle)); |
207 |
|
#endif /* DEBUG_MODULES */ |
208 |
} |
} |
209 |
|
|
210 |
|
return mp; |
211 |
} |
} |
212 |
|
|
213 |
lt_dlhandle |
lt_dlhandle |
215 |
{ |
{ |
216 |
const lt_dlhandle handle = m4__module_open (context, name, obs); |
const lt_dlhandle handle = m4__module_open (context, name, obs); |
217 |
|
|
|
/* If name is not set we are getting a reflective handle, but we |
|
|
might need to display an error message later so we set an appropriate |
|
|
value here. */ |
|
|
if (!name) |
|
|
name = MODULE_SELF_NAME; |
|
|
|
|
218 |
if (handle) |
if (handle) |
219 |
{ |
{ |
220 |
const lt_dlinfo *info = lt_dlgetinfo (handle); |
const lt_dlinfo *info = lt_dlgetinfo (handle); |
221 |
|
|
222 |
if (!info) |
if (!info) |
223 |
{ |
{ |
224 |
|
/* If name is not set we are getting a reflective handle, but we |
225 |
|
need to display an error message so we set an appropriate |
226 |
|
value here. */ |
227 |
|
if (!name) |
228 |
|
name = MODULE_SELF_NAME; |
229 |
|
|
230 |
M4ERROR ((m4_get_warning_status_opt (context), 0, |
M4ERROR ((m4_get_warning_status_opt (context), 0, |
231 |
_("Warning: cannot load module `%s': %s"), |
_("Warning: cannot load module `%s': %s"), |
232 |
name, module_dlerror ())); |
name, module_dlerror ())); |
233 |
} |
} |
234 |
else if (info->ref_count == 1) |
else if (info->ref_count == 1) |
235 |
{ |
{ |
236 |
const m4_builtin *builtin_table |
install_builtin_table (context, handle); |
237 |
= m4_get_module_builtin_table (handle); |
install_macro_table (context, handle); |
|
const m4_macro *macro_table |
|
|
= m4_get_module_macro_table (handle); |
|
|
|
|
|
/* Install the macro functions. */ |
|
|
if (builtin_table) |
|
|
{ |
|
|
set_module_builtin_table (context, handle, builtin_table); |
|
|
#ifdef DEBUG_MODULES |
|
|
M4_DEBUG_MESSAGE1("module %s: builtins loaded", name); |
|
|
#endif /* DEBUG_MODULES */ |
|
|
} |
|
|
|
|
|
/* Install the user macros. */ |
|
|
if (macro_table) |
|
|
{ |
|
|
set_module_macro_table (context, handle, macro_table); |
|
|
#ifdef DEBUG_MODULES |
|
|
M4_DEBUG_MESSAGE1("module %s: macros loaded", name); |
|
|
#endif /* DEBUG_MODULES */ |
|
|
} |
|
238 |
} |
} |
239 |
} |
} |
240 |
|
|
248 |
lt_dlhandle handle = 0; |
lt_dlhandle handle = 0; |
249 |
int errors = 0; |
int errors = 0; |
250 |
|
|
251 |
/* Scan the list for the first module with a matching name. */ |
assert (context); |
252 |
while ((handle = lt_dlhandle_next (handle))) |
|
253 |
{ |
if (name) |
254 |
if (name && (strcmp (name, m4_get_module_name (handle)) == 0)) |
handle = lt_dlhandle_find (name); |
|
break; |
|
|
} |
|
255 |
|
|
256 |
if (!handle) |
if (!handle) |
257 |
{ |
{ |
350 |
m4__module_open (m4 *context, const char *name, m4_obstack *obs) |
m4__module_open (m4 *context, const char *name, m4_obstack *obs) |
351 |
{ |
{ |
352 |
lt_dlhandle handle = lt_dlopenext (name); |
lt_dlhandle handle = lt_dlopenext (name); |
353 |
m4_module_init_func *init_func = 0; |
m4_module_init_func * init_func = 0; |
354 |
m4_builtin *builtin_table = 0; |
|
355 |
m4_macro *macro_table = 0; |
assert (context); |
356 |
|
assert (caller_id); |
357 |
|
|
358 |
if (handle) |
if (handle) |
359 |
{ |
{ |
|
#ifdef DEBUG_MODULES |
|
360 |
const lt_dlinfo *info = lt_dlgetinfo (handle); |
const lt_dlinfo *info = lt_dlgetinfo (handle); |
|
M4_DEBUG_MESSAGE2("module %s: opening at %s", name, info->filename); |
|
|
#endif |
|
361 |
|
|
362 |
/* Find the builtin table in the opened module. */ |
/* If we have a handle, there must be handle info. */ |
363 |
builtin_table = (m4_builtin *) lt_dlsym (handle, BUILTIN_SYMBOL); |
assert (info); |
364 |
|
|
365 |
/* Find the macro table in the opened module. */ |
#ifdef DEBUG_MODULES |
366 |
macro_table = (m4_macro *) lt_dlsym (handle, MACRO_SYMBOL); |
M4_DEBUG_MESSAGE2("module %s: opening at %s", |
367 |
|
name ? name : MODULE_SELF_NAME, info->filename); |
368 |
|
#endif |
369 |
|
|
370 |
/* Find and run any initialising function in the opened module, |
/* Find and run any initialising function in the opened module, |
371 |
each time the module is opened. */ |
each time the module is opened. */ |
378 |
M4_DEBUG_MESSAGE1("module %s: init hook called", name); |
M4_DEBUG_MESSAGE1("module %s: init hook called", name); |
379 |
#endif /* DEBUG_MODULES */ |
#endif /* DEBUG_MODULES */ |
380 |
} |
} |
381 |
|
|
382 |
|
if (!init_func |
383 |
|
&& !lt_dlsym (handle, FINISH_SYMBOL) |
384 |
|
&& !lt_dlsym (handle, BUILTIN_SYMBOL) |
385 |
|
&& !lt_dlsym (handle, MACRO_SYMBOL)) |
386 |
|
{ |
387 |
|
M4ERROR ((EXIT_FAILURE, 0, |
388 |
|
_("module `%s' has no entry points"), |
389 |
|
name)); |
390 |
|
} |
391 |
|
|
392 |
|
#ifdef DEBUG_MODULES |
393 |
|
M4_DEBUG_MESSAGE1("module %s: opened", name); |
394 |
|
#endif /* DEBUG_MODULES */ |
395 |
} |
} |
396 |
else |
else |
397 |
{ |
{ |
401 |
name, module_dlerror ())); |
name, module_dlerror ())); |
402 |
} |
} |
403 |
|
|
|
if (!builtin_table && !macro_table && !init_func) |
|
|
{ |
|
|
/* Since we don't use it here, only check for the finish hook |
|
|
if we were about to diagnose a module with no entry points. */ |
|
|
if (!lt_dlsym (handle, FINISH_SYMBOL)) |
|
|
M4ERROR ((EXIT_FAILURE, 0, |
|
|
_("module `%s' has no entry points"), |
|
|
name)); |
|
|
} |
|
|
|
|
|
/* If the module was correctly opened and has the necessary |
|
|
symbols, then store some client data for the new module |
|
|
on the first open only. */ |
|
|
if (handle) |
|
|
{ |
|
|
const lt_dlinfo *info = lt_dlgetinfo (handle); |
|
|
|
|
|
if (info && (info->ref_count == 1)) |
|
|
{ |
|
|
module_data *data = XMALLOC (module_data, 1); |
|
|
module_data *stale = 0; |
|
|
|
|
|
data->builtin_table = builtin_table; |
|
|
data->macro_table = macro_table; |
|
|
|
|
|
stale = lt_dlcaller_set_data (caller_id, handle, data); |
|
|
|
|
|
if (stale) |
|
|
{ |
|
|
xfree (stale); |
|
|
|
|
|
M4ERROR ((m4_get_warning_status_opt (context), 0, |
|
|
_("Warning: overiding stale caller data in module `%s'"), |
|
|
name)); |
|
|
} |
|
|
|
|
|
#ifdef DEBUG_MODULES |
|
|
M4_DEBUG_MESSAGE1("module %s: opened", name); |
|
|
#endif /* DEBUG_MODULES */ |
|
|
} |
|
|
} |
|
|
|
|
404 |
return handle; |
return handle; |
405 |
} |
} |
406 |
|
|
415 |
lt_dlhandle pending = handle; |
lt_dlhandle pending = handle; |
416 |
const lt_dlinfo *info = lt_dlgetinfo (pending); |
const lt_dlinfo *info = lt_dlgetinfo (pending); |
417 |
|
|
|
/* We are *really* shutting down here, so freeing the module |
|
|
data is required. */ |
|
|
if (info) |
|
|
{ |
|
|
module_data *stale |
|
|
= lt_dlcaller_set_data (caller_id, handle, 0); |
|
|
XFREE (stale); |
|
|
} |
|
|
|
|
418 |
/* If we are about to unload the final reference, move on to the |
/* If we are about to unload the final reference, move on to the |
419 |
next handle before we unload the current one. */ |
next handle before we unload the current one. */ |
420 |
if (info->ref_count <= 1) |
if (info->ref_count <= 1) |
474 |
|
|
475 |
if (!lt_dlisresident (handle)) |
if (!lt_dlisresident (handle)) |
476 |
{ |
{ |
|
const lt_dlinfo *info = lt_dlgetinfo (handle); |
|
|
|
|
|
/* When we are about to unload the module for the final |
|
|
time, be sure to release any client data memory. */ |
|
|
if (info && (info->ref_count == 1)) |
|
|
{ |
|
|
module_data *stale |
|
|
= lt_dlcaller_set_data (caller_id, handle, 0); |
|
|
XFREE (stale); |
|
|
} |
|
|
|
|
477 |
errors = lt_dlclose (handle); |
errors = lt_dlclose (handle); |
478 |
if (!errors) |
if (!errors) |
479 |
{ |
{ |