medit/moo/mooutils/mooscript/mooscript-builtin.c

538 lines
12 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
*
* mooscript-builtin.c
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#include "mooscript-context.h"
#include "mooscript-parser.h"
#include "mooscript-zenity.h"
#include "mooutils/moopython.h"
#include "mooutils/mooprefs.h"
#include <string.h>
static MSValue*
print_func (MSValue **args,
guint n_args,
MSContext *ctx)
{
guint i;
for (i = 0; i < n_args; ++i)
{
char *s = ms_value_print (args[i]);
ctx->print_func (s, ctx);
g_free (s);
}
ctx->print_func ("\n", ctx);
return ms_value_none ();
}
static MSValue *
len_func (MSValue *val,
MSContext *ctx)
{
switch (val->klass->type)
{
case MS_VALUE_STRING:
return ms_value_int (g_utf8_strlen (val->str, -1));
case MS_VALUE_LIST:
return ms_value_int (val->list.n_elms);
case MS_VALUE_DICT:
return ms_value_int (g_hash_table_size (val->hash));
default:
return ms_context_set_error (ctx, MS_ERROR_TYPE, NULL);
}
}
static MSValue*
abort_func (MSContext *ctx)
{
return ms_context_format_error (ctx, MS_ERROR_RUNTIME, "Aborted");
}
static MSValue*
str_func (MSValue *arg,
G_GNUC_UNUSED MSContext *ctx)
{
char *str;
MSValue *ret;
str = ms_value_print (arg);
ret = ms_value_take_string (str);
return ret;
}
static MSValue*
int_func (MSValue *arg,
MSContext *ctx)
{
int ival;
if (!ms_value_get_int (arg, &ival))
{
char *str = ms_value_repr (arg);
ms_context_format_error (ctx, MS_ERROR_TYPE,
"could not convert %s to int",
str);
g_free (str);
return NULL;
}
return ms_value_int (ival);
}
static MSValue*
python_func (MSValue *arg,
MSContext *ctx)
{
char *script;
MSValue *ret;
script = ms_value_print (arg);
ret = ms_context_run_python (ctx, script);
g_free (script);
return ret;
}
static MSValue*
include_func (MSValue *arg,
MSContext *ctx)
{
char *file = NULL, *script = NULL;
GError *error = NULL;
MSNode *node = NULL;
MSValue *ret;
file = ms_value_print (arg);
if (!g_file_get_contents (file, &script, NULL, &error))
{
ms_context_format_error (ctx, MS_ERROR_RUNTIME,
"%s", error->message);
goto error;
}
node = ms_script_parse (script);
if (!node)
{
ms_context_format_error (ctx, MS_ERROR_RUNTIME,
"%s", error->message);
goto error;
}
ret = ms_top_node_eval (node, ctx);
g_free (file);
g_free (script);
ms_node_unref (node);
return ret;
error:
g_error_free (error);
g_free (file);
g_free (script);
if (node)
g_object_unref (node);
return NULL;
}
static MSValue*
prefs_get_func (MSValue *arg,
MSContext *ctx)
{
char *key = NULL;
const char *val;
MSValue *ret = NULL;
key = ms_value_print (arg);
if (!key || !key[0])
{
ms_context_format_error (ctx, MS_ERROR_VALUE,
"empty prefs key");
goto out;
}
if (!moo_prefs_key_registered (key))
moo_prefs_new_key_string (key, NULL);
val = moo_prefs_get_string (key);
if (val)
ret = ms_value_string (val);
else
ret = ms_value_none ();
out:
g_free (key);
return ret;
}
static MSValue*
prefs_set_func (MSValue *arg1,
MSValue *arg2,
MSContext *ctx)
{
char *key = NULL, *val = NULL;
MSValue *ret = NULL;
key = ms_value_print (arg1);
if (!ms_value_is_none (arg2))
val = ms_value_print (arg2);
if (!key || !key[0])
{
ms_context_format_error (ctx, MS_ERROR_VALUE,
"empty prefs key");
goto out;
}
if (!moo_prefs_key_registered (key))
moo_prefs_new_key_string (key, NULL);
moo_prefs_set_string (key, val);
ret = ms_value_none ();
out:
g_free (key);
g_free (val);
return ret;
}
static MSValue*
exec_func (MSValue *arg,
MSContext *ctx)
{
char *cmd = NULL, *cmd_out = NULL;
MSValue *ret = NULL;
GError *error = NULL;
cmd = ms_value_print (arg);
if (!cmd || !cmd[0])
{
ms_context_format_error (ctx, MS_ERROR_VALUE,
"empty command");
goto out;
}
if (!g_spawn_command_line_sync (cmd, &cmd_out, NULL, NULL, &error))
{
ms_context_format_error (ctx, MS_ERROR_RUNTIME,
"%s", error->message);
g_error_free (error);
goto out;
}
if (cmd_out)
{
guint len = strlen (cmd_out);
if (len && cmd_out[len-1] == '\n')
{
if (len > 1 && cmd_out[len-2] == '\r')
cmd_out[len-2] = 0;
else
cmd_out[len-1] = 0;
}
}
if (cmd_out)
ret = ms_value_string (cmd_out);
else
ret = ms_value_string ("");
out:
g_free (cmd);
g_free (cmd_out);
return ret;
}
static MSValue*
file_exists_func (MSValue *arg,
MSContext *ctx)
{
char *filename;
MSValue *ret = NULL;
filename = ms_value_print (arg);
if (g_file_test (filename, G_FILE_TEST_EXISTS))
ret = ms_value_true ();
else
ret = ms_value_false ();
g_free (filename);
return ret;
}
#define ADD_FUNC(type_,func_,name_) \
G_STMT_START { \
MSFunc *msfunc__; \
msfunc__ = type_ (func_); \
ms_context_set_func (ctx, name_, msfunc__); \
g_object_unref (msfunc__); \
} G_STMT_END
#define ADD_FUNC_OBJ(factory_,name_) \
G_STMT_START { \
MSFunc *msfunc__; \
msfunc__ = factory_ (); \
ms_context_set_func (ctx, name_, msfunc__); \
g_object_unref (msfunc__); \
} G_STMT_END
#define ADD_CONSTANT(func_,name_) \
G_STMT_START { \
MSVariable *var_; \
MSValue *val_; \
val_ = func_ (); \
var_ = ms_variable_new_value (val_); \
ms_context_set_var (ctx, name_, var_); \
ms_variable_unref (var_); \
ms_value_unref (val_); \
} G_STMT_END;
void
_ms_context_add_builtin (MSContext *ctx)
{
guint i;
ADD_CONSTANT (ms_value_none, "none");
ADD_CONSTANT (ms_value_true, "true");
ADD_CONSTANT (ms_value_false, "false");
for (i = 0; i < MS_BINARY_OP_LAST; ++i)
ADD_FUNC (ms_cfunc_new_2,
ms_binary_op_cfunc (i),
ms_binary_op_name (i));
for (i = 0; i < MS_UNARY_OP_LAST; ++i)
ADD_FUNC (ms_cfunc_new_1,
ms_unary_op_cfunc (i),
ms_unary_op_name (i));
ADD_FUNC (ms_cfunc_new_1, str_func, "Str");
ADD_FUNC (ms_cfunc_new_1, int_func, "Int");
ADD_FUNC (ms_cfunc_new_1, len_func, "Len");
ADD_FUNC (ms_cfunc_new_var, print_func, "Print");
ADD_FUNC (ms_cfunc_new_1, python_func, "Python");
ADD_FUNC (ms_cfunc_new_1, include_func, "Include");
ADD_FUNC (ms_cfunc_new_0, abort_func, "Abort");
ADD_FUNC (ms_cfunc_new_1, exec_func, "Exec");
ADD_FUNC (ms_cfunc_new_1, file_exists_func, "FileExists");
ADD_FUNC (ms_cfunc_new_1, prefs_get_func, "PrefsGet");
ADD_FUNC (ms_cfunc_new_2, prefs_set_func, "PrefsSet");
ADD_FUNC_OBJ (ms_zenity_text, "Text");
ADD_FUNC_OBJ (ms_zenity_entry, "Entry");
ADD_FUNC_OBJ (ms_zenity_history_entry, "HistoryEntry");
ADD_FUNC_OBJ (ms_zenity_info, "Info");
ADD_FUNC_OBJ (ms_zenity_error, "Error");
ADD_FUNC_OBJ (ms_zenity_question, "Question");
ADD_FUNC_OBJ (ms_zenity_warning, "Warning");
ADD_FUNC_OBJ (ms_zenity_choose_file, "ChooseFile");
ADD_FUNC_OBJ (ms_zenity_choose_files, "ChooseFiles");
ADD_FUNC_OBJ (ms_zenity_choose_dir, "ChooseDir");
ADD_FUNC_OBJ (ms_zenity_choose_file_save, "ChooseFileSave");
}
/**********************************************************************/
/* Methods
*/
static void
add_meth (MSValueClass *klass,
const char *name,
MSFunc *func)
{
ms_value_class_add_method (klass, name, func);
g_object_unref (func);
}
#define add_meth0(type, name, cfunc) \
add_meth (&types[type], name, ms_cfunc_new_1 (cfunc))
#define add_meth1(type, name, cfunc) \
add_meth (&types[type], name, ms_cfunc_new_2 (cfunc))
static void
dict_add_key (const char *key,
G_GNUC_UNUSED gpointer val,
gpointer user_data)
{
MSValue *vkey;
struct {
MSValue *list;
guint i;
} *data = user_data;
vkey = ms_value_string (key);
ms_value_list_set_elm (data->list, data->i++, vkey);
ms_value_unref (vkey);
}
static MSValue *
dict_keys_func (MSValue *dict,
G_GNUC_UNUSED MSContext *ctx)
{
guint n_keys;
struct {
MSValue *list;
guint i;
} data;
n_keys = g_hash_table_size (dict->hash);
data.list = ms_value_list (n_keys);
data.i = 0;
g_hash_table_foreach (dict->hash, (GHFunc) dict_add_key, &data);
return data.list;
}
static MSValue *
dict_has_key_func (MSValue *dict,
MSValue *key,
G_GNUC_UNUSED MSContext *ctx)
{
MSValue *val, *ret;
if (MS_VALUE_TYPE (key) != MS_VALUE_STRING)
return ms_value_false ();
val = ms_value_dict_get_elm (dict, key->str);
ret = val ? ms_value_true () : ms_value_false ();
ms_value_unref (val);
return ret;
}
static MSValue *
str_len_func (MSValue *val,
G_GNUC_UNUSED MSContext *ctx)
{
return ms_value_int (g_utf8_strlen (val->str, -1));
}
static MSValue *
dict_len_func (MSValue *val,
G_GNUC_UNUSED MSContext *ctx)
{
return ms_value_int (g_hash_table_size (val->hash));
}
static MSValue *
list_len_func (MSValue *val,
G_GNUC_UNUSED MSContext *ctx)
{
return ms_value_int (val->list.n_elms);
}
static MSValue *
list_max_func (MSValue *val,
MSContext *ctx)
{
guint i;
MSValue *max;
if (!val->list.n_elms)
return ms_context_format_error (ctx, MS_ERROR_VALUE,
"requested MAX of empty list");
max = val->list.elms[0];
for (i = 1; i < val->list.n_elms; ++i)
if (ms_value_cmp (max, val->list.elms[i]) < 0)
max = val->list.elms[i];
return ms_value_ref (max);
}
static MSValue *
list_min_func (MSValue *val,
MSContext *ctx)
{
guint i;
MSValue *min;
if (!val->list.n_elms)
return ms_context_format_error (ctx, MS_ERROR_VALUE,
"requested MIN of empty list");
min = val->list.elms[0];
for (i = 1; i < val->list.n_elms; ++i)
if (ms_value_cmp (min, val->list.elms[i]) > 0)
min = val->list.elms[i];
return ms_value_ref (min);
}
static MSValue *
list_copy_func (MSValue *val,
G_GNUC_UNUSED MSContext *ctx)
{
MSValue *copy;
guint i;
copy = ms_value_list (val->list.n_elms);
for (i = 0; i < val->list.n_elms; ++i)
ms_value_list_set_elm (copy, i, val->list.elms[i]);
return copy;
}
void
_ms_type_init_builtin (MSValueClass *types)
{
add_meth0 (MS_VALUE_STRING, "len", str_len_func);
add_meth0 (MS_VALUE_LIST, "len", list_len_func);
add_meth0 (MS_VALUE_LIST, "max", list_max_func);
add_meth0 (MS_VALUE_LIST, "min", list_min_func);
add_meth0 (MS_VALUE_LIST, "copy", list_copy_func);
// add_meth0 (MS_VALUE_LIST, "deep_copy", list_deep_copy_func);
add_meth0 (MS_VALUE_DICT, "len", dict_len_func);
add_meth0 (MS_VALUE_DICT, "keys", dict_keys_func);
add_meth1 (MS_VALUE_DICT, "has_key", dict_has_key_func);
// add_meth0 (MS_VALUE_DICT, "copy", dict_copy_func);
// add_meth0 (MS_VALUE_DICT, "deep_copy", dict_deep_copy_func);
}