summaryrefslogtreecommitdiff
path: root/libseed/seed-builtins.c
diff options
context:
space:
mode:
Diffstat (limited to 'libseed/seed-builtins.c')
-rw-r--r--libseed/seed-builtins.c557
1 files changed, 557 insertions, 0 deletions
diff --git a/libseed/seed-builtins.c b/libseed/seed-builtins.c
new file mode 100644
index 0000000..b5b14fc
--- /dev/null
+++ b/libseed/seed-builtins.c
@@ -0,0 +1,557 @@
+/* -*- mode: C; indent-tabs-mode: t; tab-width: 8; c-basic-offset: 2; -*- */
+
+/*
+ * This file is part of Seed, the GObject Introspection<->Javascript bindings.
+ *
+ * Seed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2 of
+ * the License, or (at your option) any later version.
+ * Seed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Seed. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) Robert Carr 2009 <carrr@rpi.edu>
+ */
+
+#include <unistd.h>
+#include "seed-private.h"
+#include <sys/mman.h>
+#include <stdio.h>
+#include <signal.h>
+
+JSValueRef seed_print_ref;
+JSValueRef seed_printerr_ref;
+
+static JSValueRef
+seed_include (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef * exception)
+{
+ JSStringRef file_contents, file_name;
+
+ GDir *dir;
+ gchar *import_file, *abs_path;
+ gchar *buffer, *walk;
+ guint i, len;
+
+ if (argumentCount != 1)
+ {
+ seed_make_exception (ctx, exception, "ArgumentError",
+ "Seed.include expected 1 argument, "
+ "got %zd", argumentCount);
+ return JSValueMakeNull (ctx);
+ }
+
+ import_file = seed_value_to_string (ctx, arguments[0], exception);
+
+ /* just try current dir if no path set, or use the absolute path */
+ if (!eng->search_path || g_path_is_absolute (import_file))
+ g_file_get_contents (import_file, &buffer, 0, NULL);
+ else /* A search path is set and path given is not absolute. */
+ {
+ len = g_strv_length (eng->search_path);
+ for (i = 0; i < len; ++i)
+ {
+ dir = g_dir_open (eng->search_path[i], 0, NULL);
+
+ if (!dir) /* skip bad path entries */
+ continue;
+
+ abs_path =
+ g_build_filename (eng->search_path[i], import_file, NULL);
+
+ if (g_file_get_contents (abs_path, &buffer, 0, NULL))
+ {
+ g_free (abs_path);
+ g_dir_close (dir);
+ break;
+ }
+
+ g_dir_close (dir);
+ g_free (abs_path);
+ }
+ }
+
+ if (!buffer)
+ {
+ seed_make_exception (ctx, exception, "FileNotFound",
+ "File not found: %s", import_file);
+
+ g_free (import_file);
+ g_free (buffer);
+ return JSValueMakeNull (ctx);
+ }
+
+ walk = buffer;
+
+ if (*walk == '#')
+ {
+ while (*walk != '\n')
+ walk++;
+ walk++;
+ }
+
+ walk = g_strdup (walk);
+ g_free (buffer);
+
+ file_contents = JSStringCreateWithUTF8CString (walk);
+ file_name = JSStringCreateWithUTF8CString (import_file);
+
+ JSEvaluateScript (ctx, file_contents, NULL, file_name, 0, exception);
+
+ JSStringRelease (file_contents);
+ JSStringRelease (file_name);
+ g_free (import_file);
+ g_free (walk);
+
+ return JSValueMakeUndefined (ctx);
+}
+
+static JSValueRef
+seed_scoped_include (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef * exception)
+{
+ JSContextRef nctx;
+ JSObjectRef global;
+ JSStringRef file_contents, file_name;
+ GDir *dir;
+ gchar *import_file, *abs_path;
+ gchar *buffer, *walk;
+ guint i;
+
+ if (argumentCount != 1)
+ {
+ seed_make_exception (ctx, exception, "ArgumentError",
+ "Seed.include expected 1 argument, "
+ "got %zd", argumentCount);
+ return JSValueMakeNull (ctx);
+ }
+
+ import_file = seed_value_to_string (ctx, arguments[0], exception);
+
+ /* just try current dir if no path set, or use the absolute path */
+ if (!eng->search_path || g_path_is_absolute (import_file))
+ g_file_get_contents (import_file, &buffer, 0, NULL);
+ else /* A search path is set and path given is not absolute. */
+ {
+ for (i = 0; i < g_strv_length (eng->search_path); ++i)
+ {
+ dir = g_dir_open (eng->search_path[i], 0, NULL);
+
+ if (!dir) /* skip bad path entries */
+ continue;
+
+ abs_path =
+ g_build_filename (eng->search_path[i], import_file, NULL);
+
+ if (g_file_get_contents (abs_path, &buffer, 0, NULL))
+ {
+ g_free (abs_path);
+ break;
+ }
+
+ g_dir_close (dir);
+ g_free (abs_path);
+ }
+ }
+
+ if (!buffer)
+ {
+ seed_make_exception (ctx, exception, "FileNotFound",
+ "File not found: %s", import_file);
+
+ g_free (import_file);
+ g_free (buffer);
+ return JSValueMakeNull (ctx);
+ }
+
+ walk = buffer;
+
+ if (*walk == '#')
+ {
+ while (*walk != '\n')
+ walk++;
+ walk++;
+ }
+
+ walk = g_strdup (walk);
+ g_free (buffer);
+
+ file_contents = JSStringCreateWithUTF8CString (walk);
+ file_name = JSStringCreateWithUTF8CString (import_file);
+
+
+ nctx = JSGlobalContextCreateInGroup (context_group, 0);
+ seed_prepare_global_context (nctx);
+
+ JSEvaluateScript (nctx, file_contents, NULL, file_name, 0, exception);
+
+ global = JSContextGetGlobalObject (nctx);
+
+ JSGlobalContextRelease ((JSGlobalContextRef) nctx);
+
+ JSStringRelease (file_contents);
+ JSStringRelease (file_name);
+ g_free (import_file);
+ g_free (walk);
+
+ return global;
+}
+
+static JSValueRef
+seed_print (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef * exception)
+{
+ gchar *buf;
+ if (argumentCount != 1)
+ {
+ seed_make_exception (ctx, exception, "ArgumentError",
+ "print expected 1 argument, got %zd",
+ argumentCount);
+ return JSValueMakeNull (ctx);
+ }
+
+ buf = seed_value_to_string (ctx, arguments[0], exception);
+
+ g_print ("%s\n", buf);
+ g_free (buf);
+
+ return JSValueMakeUndefined (ctx);
+}
+
+static JSValueRef
+seed_printerr (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef *exception)
+{
+ gchar *buf;
+ if (argumentCount != 1)
+ {
+ seed_make_exception (ctx, exception, "ArgumentError",
+ "printerr expected 1 argument, got %zd",
+ argumentCount);
+ return JSValueMakeNull (ctx);
+ }
+
+ buf = seed_value_to_string (ctx, arguments[0], exception);
+
+ g_printerr ("%s\n", buf);
+ g_free (buf);
+
+ return JSValueMakeUndefined (ctx);
+}
+
+const gchar *
+seed_g_type_name_to_string (GITypeInfo * type)
+{
+ GITypeTag type_tag = g_type_info_get_tag (type);
+
+ const gchar *type_name;
+ GIBaseInfo *interface;
+
+ if (type_tag == GI_TYPE_TAG_INTERFACE)
+ {
+ interface = g_type_info_get_interface (type);
+
+ type_name = g_base_info_get_name (interface);
+ g_base_info_unref (interface);
+ }
+ else
+ {
+ type_name = g_type_tag_to_string (type_tag);
+ }
+
+ return type_name;
+}
+
+static JSValueRef
+seed_introspect (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef * exception)
+{
+ // TODO: LEAKY!
+
+ GICallableInfo *info;
+ JSObjectRef data_obj, args_obj, argument;
+ guint i, nargs;
+
+ if (argumentCount != 1)
+ {
+ seed_make_exception (ctx, exception, "ArgumentError",
+ "Seed.introspect expected 1 argument, "
+ "got %zd", argumentCount);
+ return JSValueMakeNull (ctx);
+ }
+
+ if (!JSValueIsObject (ctx, arguments[0]))
+ return JSValueMakeNull (ctx);
+ if (!JSValueIsObjectOfClass (ctx, arguments[0], gobject_method_class))
+ return JSValueMakeNull (ctx);
+
+ info = (GICallableInfo *) JSObjectGetPrivate ((JSObjectRef) arguments[0]);
+ data_obj = JSObjectMake (ctx, NULL, NULL);
+
+ seed_object_set_property (ctx, data_obj, "name", (JSValueRef)
+ seed_value_from_string (ctx, g_base_info_get_name
+ ((GIBaseInfo *) info),
+ exception));
+
+ seed_object_set_property (ctx, data_obj, "return_type",
+ seed_value_from_string
+ (ctx, seed_g_type_name_to_string
+ (g_callable_info_get_return_type (info)),
+ exception));
+
+ args_obj = JSObjectMake (ctx, NULL, NULL);
+
+ seed_object_set_property (ctx, data_obj, "args", args_obj);
+
+ nargs = g_callable_info_get_n_args (info);
+ for (i = 0; i < nargs; ++i)
+ {
+ argument = JSObjectMake (ctx, NULL, NULL);
+ GIArgInfo* arg_info = g_callable_info_get_arg (info, i);
+ const gchar *arg_type = seed_g_type_name_to_string (
+ g_arg_info_get_type(arg_info));
+ const gchar *arg_name = g_base_info_get_name((GIBaseInfo*) arg_info);
+ GIDirection dir = g_arg_info_get_direction (arg_info);
+
+
+ seed_object_set_property (ctx, argument, "type",
+ seed_value_from_string (ctx,
+ arg_type, exception));
+ seed_object_set_property (ctx, argument, "name",
+ seed_value_from_string (ctx,
+ arg_name, exception));
+
+ seed_object_set_property (ctx, argument, "allow_none",
+ seed_value_from_boolean (ctx,
+ g_arg_info_may_be_null (arg_info) ? 1 : 0, exception));
+
+
+ seed_object_set_property (ctx, argument, "direction",
+ seed_value_from_string (ctx,
+ dir == GI_DIRECTION_OUT ? "out" :
+ (dir == GI_DIRECTION_IN ? "in" : "inout")
+ , exception));
+
+ JSObjectSetPropertyAtIndex (ctx, args_obj, i, argument, NULL);
+ }
+
+ return data_obj;
+}
+
+static JSValueRef
+seed_check_syntax (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef * exception)
+{
+ JSStringRef jsstr;
+ if (argumentCount == 1)
+ {
+ jsstr = JSValueToStringCopy (ctx, arguments[0], exception);
+
+ JSCheckScriptSyntax (ctx, jsstr, 0, 0, exception);
+ if (jsstr)
+ JSStringRelease (jsstr);
+ }
+ else
+ {
+ seed_make_exception (ctx, exception, "ArgumentError",
+ "Seed.check_syntax expected "
+ "1 argument, got %zd", argumentCount);
+ }
+ return JSValueMakeNull (ctx);
+}
+
+static JSValueRef
+seed_spawn (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef * exception)
+{
+ gchar *line, *stdoutstr, *stderrstr;
+ JSObjectRef ret;
+ GError *error = NULL;
+
+ if (argumentCount != 1)
+ {
+ // I am so lazy
+ seed_make_exception (ctx, exception, "ArgumentError",
+ "Seed.spawn expected 1 argument");
+ return JSValueMakeNull (ctx);
+ }
+
+ line = seed_value_to_string (ctx, arguments[0], exception);
+ g_spawn_command_line_sync (line, &stdoutstr, &stderrstr, NULL, &error);
+ if (error)
+ {
+ seed_make_exception_from_gerror (ctx, exception, error);
+
+ g_free (line);
+ g_error_free (error);
+ return JSValueMakeNull (ctx);
+ }
+
+ ret = JSObjectMake (ctx, NULL, NULL);
+ seed_object_set_property (ctx, ret, "stdout",
+ seed_value_from_string (ctx, stdoutstr,
+ exception));
+ seed_object_set_property (ctx, ret, "stderr",
+ seed_value_from_string (ctx, stderrstr,
+ exception));
+
+ g_free (line);
+ g_free (stdoutstr);
+ g_free (stderrstr);
+
+ return ret;
+}
+
+static JSValueRef
+seed_quit (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef * exception)
+{
+ if (argumentCount == 1)
+ {
+ exit (seed_value_to_int (ctx, arguments[0], NULL));
+ }
+ else if (argumentCount > 1)
+ {
+ seed_make_exception (ctx, exception, "ArgumentError",
+ "Seed.quit expected " "1 argument, got %zd",
+ argumentCount);
+ }
+
+ exit (EXIT_SUCCESS);
+}
+
+static JSValueRef
+seed_breakpoint (JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef this_object,
+ size_t argumentCount,
+ const JSValueRef arguments[], JSValueRef * exception)
+{
+ G_BREAKPOINT ();
+ return JSValueMakeUndefined (ctx);
+}
+
+
+static JSValueRef
+seed_argv_get_property (JSContextRef ctx,
+ JSObjectRef object,
+ JSStringRef property_name, JSValueRef * exception)
+{
+ SeedArgvPrivates *priv;
+ gchar *cproperty_name;
+ gsize length;
+ guint index;
+
+ priv = JSObjectGetPrivate (object);
+ if (!priv->argc)
+ return JSValueMakeUndefined (ctx);
+ length = JSStringGetMaximumUTF8CStringSize (property_name);
+ cproperty_name = g_alloca (length * sizeof (gchar));
+ JSStringGetUTF8CString (property_name, cproperty_name, length);
+
+ if (!g_strcmp0 (cproperty_name, "length"))
+ {
+ return seed_value_from_int (ctx, priv->argc, exception);
+ }
+ index = atoi (cproperty_name);
+ return seed_value_from_string (ctx, priv->argv[index], exception);
+}
+
+JSClassDefinition seed_argv_def = {
+ 0, /* Version, always 0 */
+ kJSClassAttributeNoAutomaticPrototype, /* JSClassAttributes */
+ "argv_array", /* Class Name */
+ NULL, /* Parent Class */
+ NULL, /* Static Values */
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* Has Property */
+ seed_argv_get_property, /* Get Property */
+ NULL,
+ NULL, /* Delete Property */
+ NULL, /* Get Property Names */
+ NULL, /* Call As Function */
+ NULL, /* Call As Constructor */
+ NULL, /* Has Instance */
+ NULL /* Convert To Type */
+};
+
+JSClassRef seed_argv_class;
+
+void
+seed_init_builtins (SeedEngine * local_eng, gint * argc, gchar *** argv)
+{
+ SeedArgvPrivates *priv;
+ JSObjectRef arrayObj;
+ JSObjectRef obj =
+ (JSObjectRef) seed_object_get_property (local_eng->context,
+ local_eng->global,
+ "Seed");
+
+ seed_create_function (local_eng->context, "include", &seed_include, obj);
+ seed_create_function (local_eng->context, "scoped_include",
+ &seed_scoped_include, obj);
+
+ seed_print_ref =
+ JSObjectMakeFunctionWithCallback (local_eng->context, NULL, &seed_print);
+ seed_object_set_property (local_eng->context, obj, "print", seed_print_ref);
+ seed_object_set_property (local_eng->context, local_eng->global, "print",
+ seed_print_ref);
+ JSValueProtect (local_eng->context, seed_print_ref);
+
+ seed_printerr_ref =
+ JSObjectMakeFunctionWithCallback (local_eng->context, NULL, &seed_printerr);
+ seed_object_set_property (local_eng->context, obj, "printerr", seed_printerr_ref);
+ seed_object_set_property (local_eng->context, local_eng->global, "printerr",
+ seed_printerr_ref);
+ JSValueProtect (local_eng->context, seed_printerr_ref);
+
+ seed_create_function (local_eng->context,
+ "check_syntax", &seed_check_syntax, obj);
+ seed_create_function (local_eng->context,
+ "introspect", &seed_introspect, obj);
+ seed_create_function (local_eng->context, "spawn", &seed_spawn, obj);
+ seed_create_function (local_eng->context, "quit", &seed_quit, obj);
+ seed_create_function (local_eng->context, "breakpoint",
+ &seed_breakpoint, obj);
+
+ priv = g_new0 (SeedArgvPrivates, 1);
+ priv->argv = argv ? *argv : 0;
+ priv->argc = argc ? *argc : 0;
+
+ seed_argv_class = JSClassCreate (&seed_argv_def);
+ arrayObj = JSObjectMake (local_eng->context, seed_argv_class, priv);
+
+ seed_object_set_property (local_eng->context, obj, "argv", arrayObj);
+
+}