@@ 14,6 14,7 @@ struct _KilnModule
char *name;
GModule *module;
KilnModuleOpenFunc open_in_context;
+ void *userdata;
};
G_DEFINE_BOXED_TYPE (KilnModule, kiln_module, kiln_module_ref, kiln_module_unref);
@@ 22,24 23,28 @@ G_DEFINE_BOXED_TYPE (KilnModule, kiln_module, kiln_module_ref, kiln_module_unref
static KilnModule*
kiln_module_new (const char *name,
GModule *module,
- KilnModuleOpenFunc open_in_context)
+ KilnModuleOpenFunc open_in_context,
+ void *userdata)
{
g_assert (name);
- g_assert (module);
g_assert (open_in_context);
KilnModule *self = g_rc_box_new0 (KilnModule);
self->name = g_strdup (name);
self->module = module;
self->open_in_context = open_in_context;
+ self->userdata = userdata;
+
+ if (self->module) {
+ /*
+ * Ideally we would use GTypeModule, and allow plug-ins to register
+ * types which can be loaded and unloaded; but it's simpler to keep
+ * modules around and allow them to register types normally, without
+ * having to worry about the GModule being unloaded.
+ */
+ g_module_make_resident (self->module);
+ }
- /*
- * Ideally we would use GTypeModule, and allow plug-ins to register
- * types which can be loaded and unloaded; but it's simpler to keep
- * modules around and allow them to register types normally, without
- * having to worry about the GModule being unloaded.
- */
- g_module_make_resident (self->module);
return self;
}
@@ 133,7 138,7 @@ kiln_module_open (const KilnModule *self,
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (JSC_IS_CONTEXT (context), NULL);
- return (*self->open_in_context) (context, error);
+ return (*self->open_in_context) (context, error, self->userdata);
}
@@ 384,6 389,10 @@ kiln_loader_find_module (KilnLoader *self,
g_return_val_if_fail (KILN_IS_LOADER (self), NULL);
g_return_val_if_fail (module_name, NULL);
+ KilnModule *module = g_hash_table_lookup (self->modules, module_name);
+ if (module)
+ return module;
+
/*
* TODO: Validate that the module name only contains characters
* in the [A-Za-z0-9_] set.
@@ 398,10 407,6 @@ kiln_loader_find_module (KilnLoader *self,
return NULL;
}
- KilnModule *module = g_hash_table_lookup (self->modules, module_name);
- if (module)
- return module;
-
for (GList *iter = g_list_first (self->module_paths); iter; iter = g_list_next (iter)) {
g_autofree char *module_path = g_module_build_path (iter->data,
module_name);
@@ 423,7 428,7 @@ kiln_loader_find_module (KilnLoader *self,
continue;
}
- module = kiln_module_new (module_name, gmodule, fn);
+ module = kiln_module_new (module_name, gmodule, fn, NULL);
g_hash_table_insert (self->modules,
g_strdup (module_name),
module);
@@ 516,3 521,46 @@ kiln_loader_open_module (KilnLoader *self,
jsc_context_set_value (self->context, module_name, ns_value);
return TRUE;
}
+
+/**
+ * kiln_loader_add_module:
+ * @loader: A #KilnLoader
+ * @module_name: Name of the module to add and optionally open.
+ * @callback: Module initialization function.
+ * @userdata: User data passed to the callback.
+ * @error: (nullable): Location where to store an error, if any.
+ *
+ * Register a module with the loader, which will use the provided @callback
+ * function to initialize the module in a #JSCContext when loaded.
+ *
+ * If the module cannot be added because another module with the same
+ * name already exists, @NULL is returned and @error will be filled
+ * in, if provided.
+ *
+ * Returns: (transfer none) (nullable): A #KilnModule
+ */
+KilnModule*
+kiln_loader_add_module (KilnLoader *self,
+ const char *module_name,
+ KilnModuleOpenFunc callback,
+ void *userdata,
+ GError **error)
+{
+ g_return_val_if_fail (KILN_IS_LOADER (self), NULL);
+ g_return_val_if_fail (module_name, NULL);
+ g_return_val_if_fail (callback, NULL);
+
+ KilnModule *module = g_hash_table_lookup (self->modules, module_name);
+ if (module) {
+ g_set_error (error,
+ KILN_LOADER_ERROR,
+ KILN_LOADER_ERROR_NS_EXISTS,
+ "Module '%s' already exists",
+ module_name);
+ return NULL;
+ }
+
+ module = kiln_module_new (module_name, NULL, callback, userdata);
+ g_hash_table_insert (self->modules, g_strdup (module_name), module);
+ return module;
+}
@@ 39,7 39,7 @@ typedef enum {
KILN_LOADER_ERROR_NS_EXISTS,
} KilnLoaderError;
-typedef JSCValue* (*KilnModuleOpenFunc) (JSCContext*, GError**);
+typedef JSCValue* (*KilnModuleOpenFunc) (JSCContext*, GError**, void*);
#define KILN_TYPE_LOADER (kiln_loader_get_type ())
#define KILN_LOADER_ERROR (kiln_loader_error_quark ())
@@ 75,4 75,10 @@ gboolean kiln_loader_open_module (KilnLoader *self,
const char *module_name,
GError **error);
+KilnModule* kiln_loader_add_module (KilnLoader *self,
+ const char *module_name,
+ KilnModuleOpenFunc callback,
+ void *userdata,
+ GError **error);
+
G_END_DECLS
@@ 112,6 112,32 @@ open_builtin_modules (KilnLoader *loader,
return true;
}
+static void
+js_print (GPtrArray *values)
+{
+ for (unsigned i = 0; i < values->len; ++i) {
+ if (i > 0)
+ g_print (" \t");
+ JSCValue *value = g_ptr_array_index (values, i);
+ g_autofree char *value_string = jsc_value_to_string (value);
+ g_print ("%s", value_string);
+ }
+ g_print ("\n");
+}
+
+static JSCValue*
+open_print_module (JSCContext *context,
+ GError **error G_GNUC_UNUSED,
+ void *userdata G_GNUC_UNUSED)
+{
+ return jsc_value_new_function_variadic (context,
+ "print",
+ G_CALLBACK (js_print),
+ NULL, /* userdata */
+ NULL, /* destroy_notify */
+ G_TYPE_NONE);
+}
+
int
main (int argc, char *argv[])
{
@@ 124,6 150,14 @@ main (int argc, char *argv[])
g_autoptr(JSCContext) js_context = jsc_context_new ();
g_autoptr(KilnLoader) kn_loader = kiln_loader_new (js_context);
+
+ if (!kiln_loader_add_module (kn_loader, "print", open_print_module, NULL, &error) ||
+ !kiln_loader_open_module (kn_loader, "print", &error))
+ {
+ g_printerr ("%s: %s\n", argv[0], error->message);
+ return EXIT_FAILURE;
+ }
+
for (unsigned i = 0; opt_module_paths && opt_module_paths[i]; ++i) {
/* TODO: Check whether the path is actually a directory. */
kiln_loader_append_path (kn_loader, opt_module_paths[i]);