mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Fixes to the Python scripting by M. Levinson
This commit is contained in:
parent
29fb051fc9
commit
6c8f532692
3
AUTHORS
3
AUTHORS
@ -331,6 +331,9 @@ Len Lattanzi <Len_Lattanzi@StanfordAlumni.org>
|
|||||||
M. K. Srikant <srix@vsnl.com>
|
M. K. Srikant <srix@vsnl.com>
|
||||||
Small fix in forms
|
Small fix in forms
|
||||||
|
|
||||||
|
M. Levinson <levinsm@users.sourceforge.net>
|
||||||
|
Python scripting fixes
|
||||||
|
|
||||||
Marco Bodrato <bodrato@linuz.sns.it>
|
Marco Bodrato <bodrato@linuz.sns.it>
|
||||||
Twinterm support
|
Twinterm support
|
||||||
|
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
If you want to use Python scripting with ELinks add
|
If you want to use Python scripting with ELinks, add --with-python to the
|
||||||
--with-python to the configure invocation copy hooks.py to ~/.elinks
|
configure invocation and copy hooks.py to your ~/.elinks directory.
|
||||||
When your Python installation is your own build, you could give prefix
|
|
||||||
to the configure, eg.
|
|
||||||
--with-python=/usr/local when Python binary is placed in /usr/local/bin, etc.
|
|
||||||
|
|
||||||
When 'configure' cannot find -lpython make symbolic link to the appropriate
|
If configure cannot find Python you can supply a path, e.g.
|
||||||
library, eg.
|
--with-python=/usr/local/bin if your Python binary is in /usr/local/bin, etc.
|
||||||
# cd /usr/local/lib
|
|
||||||
# ln -s libpython2.4.so.1.0 libpython.so
|
|
||||||
|
|
||||||
For the present hooks.py is not very usable. You are welcome to make it better.
|
For the present hooks.py is not very usable. You are welcome to make it better.
|
||||||
Good Luck!
|
Good Luck!
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "scripting/python/core.h"
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -14,24 +13,91 @@
|
|||||||
|
|
||||||
#include "config/home.h"
|
#include "config/home.h"
|
||||||
#include "main/module.h"
|
#include "main/module.h"
|
||||||
|
#include "scripting/scripting.h"
|
||||||
|
#include "scripting/python/core.h"
|
||||||
|
#include "scripting/python/python.h"
|
||||||
#include "util/env.h"
|
#include "util/env.h"
|
||||||
#include "util/file.h"
|
#include "util/file.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
|
|
||||||
PyObject *pDict, *pModule;
|
PyObject *pDict = NULL, *pModule = NULL;
|
||||||
|
|
||||||
|
/* Error reporting. */
|
||||||
|
|
||||||
|
void
|
||||||
|
alert_python_error(struct session *ses)
|
||||||
|
{
|
||||||
|
unsigned char *msg = "(no traceback available)";
|
||||||
|
PyObject *err_type = NULL, *err_value = NULL, *err_traceback = NULL;
|
||||||
|
PyObject *tb_module = NULL;
|
||||||
|
PyObject *tb_dict;
|
||||||
|
PyObject *format_function;
|
||||||
|
PyObject *msg_list = NULL;
|
||||||
|
PyObject *empty_string = NULL;
|
||||||
|
PyObject *join_method = NULL;
|
||||||
|
PyObject *msg_string = NULL;
|
||||||
|
unsigned char *temp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieve the current error indicator and use the format_exception()
|
||||||
|
* function in Python's traceback module to produce an informative
|
||||||
|
* error message. It returns a list of Python string objects.
|
||||||
|
*/
|
||||||
|
PyErr_Fetch(&err_type, &err_value, &err_traceback);
|
||||||
|
PyErr_NormalizeException(&err_type, &err_value, &err_traceback);
|
||||||
|
if (!err_traceback) goto end;
|
||||||
|
|
||||||
|
tb_module = PyImport_ImportModule("traceback");
|
||||||
|
if (!tb_module) goto end;
|
||||||
|
|
||||||
|
tb_dict = PyModule_GetDict(tb_module);
|
||||||
|
format_function = PyDict_GetItemString(tb_dict, "format_exception");
|
||||||
|
if (!format_function || !PyCallable_Check(format_function)) goto end;
|
||||||
|
|
||||||
|
msg_list = PyObject_CallFunction(format_function, "OOO",
|
||||||
|
err_type, err_value, err_traceback);
|
||||||
|
if (!msg_list) goto end;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use the join() method of an empty Python string to join the list
|
||||||
|
* of strings into one Python string containing the entire error
|
||||||
|
* message. Then get the contents of the Python string.
|
||||||
|
*/
|
||||||
|
empty_string = PyString_FromString("");
|
||||||
|
if (!empty_string) goto end;
|
||||||
|
|
||||||
|
join_method = PyObject_GetAttrString(empty_string, "join");
|
||||||
|
if (!join_method || !PyCallable_Check(join_method)) goto end;
|
||||||
|
|
||||||
|
msg_string = PyObject_CallFunction(join_method, "O", msg_list);
|
||||||
|
if (!msg_string) goto end;
|
||||||
|
|
||||||
|
temp = (unsigned char *)PyString_AsString(msg_string);
|
||||||
|
if (temp) msg = temp;
|
||||||
|
|
||||||
|
end:
|
||||||
|
report_scripting_error(&python_scripting_module, ses, msg);
|
||||||
|
|
||||||
|
Py_XDECREF(err_type);
|
||||||
|
Py_XDECREF(err_value);
|
||||||
|
Py_XDECREF(err_traceback);
|
||||||
|
Py_XDECREF(tb_module);
|
||||||
|
Py_XDECREF(msg_list);
|
||||||
|
Py_XDECREF(empty_string);
|
||||||
|
Py_XDECREF(join_method);
|
||||||
|
Py_XDECREF(msg_string);
|
||||||
|
|
||||||
|
/* In case another error occurred while reporting the original error: */
|
||||||
|
PyErr_Clear();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cleanup_python(struct module *module)
|
cleanup_python(struct module *module)
|
||||||
{
|
{
|
||||||
if (Py_IsInitialized()) {
|
if (Py_IsInitialized()) {
|
||||||
if (pModule) {
|
Py_XDECREF(pDict);
|
||||||
Py_DECREF(pModule);
|
Py_XDECREF(pModule);
|
||||||
}
|
|
||||||
if (PyErr_Occurred()) {
|
|
||||||
PyErr_Print();
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
Py_Finalize();
|
Py_Finalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,15 +110,25 @@ init_python(struct module *module)
|
|||||||
if (!python_path) return;
|
if (!python_path) return;
|
||||||
env_set("PYTHONPATH", python_path, -1);
|
env_set("PYTHONPATH", python_path, -1);
|
||||||
mem_free(python_path);
|
mem_free(python_path);
|
||||||
|
|
||||||
|
/* Treat warnings as errors so they can be caught and handled;
|
||||||
|
* otherwise they would be printed to stderr.
|
||||||
|
*
|
||||||
|
* NOTE: PySys_ResetWarnOptions() and PySys_AddWarnOption() have been
|
||||||
|
* available and stable for many years but they're not officially
|
||||||
|
* documented as part of Python's public API, so in theory these two
|
||||||
|
* functions might no longer be available in some hypothetical future
|
||||||
|
* version of Python. */
|
||||||
|
PySys_ResetWarnOptions();
|
||||||
|
PySys_AddWarnOption("error");
|
||||||
|
|
||||||
Py_Initialize();
|
Py_Initialize();
|
||||||
pModule = PyImport_ImportModule("hooks");
|
pModule = PyImport_ImportModule("hooks");
|
||||||
|
|
||||||
if (pModule) {
|
if (pModule) {
|
||||||
pDict = PyModule_GetDict(pModule);
|
pDict = PyModule_GetDict(pModule);
|
||||||
|
Py_INCREF(pDict);
|
||||||
} else {
|
} else {
|
||||||
if (PyErr_Occurred()) {
|
alert_python_error(NULL);
|
||||||
PyErr_Print();
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
#define EL__SCRIPTING_PYTHON_CORE_H
|
#define EL__SCRIPTING_PYTHON_CORE_H
|
||||||
|
|
||||||
struct module;
|
struct module;
|
||||||
|
struct session;
|
||||||
|
|
||||||
|
void alert_python_error(struct session *ses);
|
||||||
void init_python(struct module *module);
|
void init_python(struct module *module);
|
||||||
void cleanup_python(struct module *module);
|
void cleanup_python(struct module *module);
|
||||||
|
|
||||||
|
@ -32,29 +32,29 @@ do_script_hook_goto_url(struct session *ses, unsigned char **url)
|
|||||||
|
|
||||||
if (pFunc && PyCallable_Check(pFunc)) {
|
if (pFunc && PyCallable_Check(pFunc)) {
|
||||||
PyObject *pValue;
|
PyObject *pValue;
|
||||||
unsigned char *str;
|
unsigned char *current_url;
|
||||||
|
|
||||||
if (!ses || !have_location(ses)) {
|
if (!ses || !have_location(ses)) {
|
||||||
str = NULL;
|
current_url = NULL;
|
||||||
} else {
|
} else {
|
||||||
str = struri(cur_loc(ses)->vs.uri);
|
current_url = struri(cur_loc(ses)->vs.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
pValue = PyObject_CallFunction(pFunc, "ss", *url, str);
|
pValue = PyObject_CallFunction(pFunc, "ss", *url, current_url);
|
||||||
if (pValue && (pValue != Py_None)) {
|
if (pValue) {
|
||||||
const unsigned char *res = PyString_AsString(pValue);
|
if (pValue != Py_None) {
|
||||||
|
const unsigned char *str;
|
||||||
|
unsigned char *new_url;
|
||||||
|
|
||||||
if (res) {
|
str = PyString_AsString(pValue);
|
||||||
unsigned char *new_url = stracpy((unsigned char *)res);
|
if (str) {
|
||||||
|
new_url = stracpy((unsigned char *)str);
|
||||||
if (new_url) mem_free_set(url, new_url);
|
if (new_url) mem_free_set(url, new_url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Py_DECREF(pValue);
|
Py_DECREF(pValue);
|
||||||
} else {
|
} else {
|
||||||
if (PyErr_Occurred()) {
|
alert_python_error(ses);
|
||||||
PyErr_Print();
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,26 +72,26 @@ script_hook_goto_url(va_list ap, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_script_hook_follow_url(unsigned char **url)
|
do_script_hook_follow_url(struct session *ses, unsigned char **url)
|
||||||
{
|
{
|
||||||
PyObject *pFunc = PyDict_GetItemString(pDict, "follow_url_hook");
|
PyObject *pFunc = PyDict_GetItemString(pDict, "follow_url_hook");
|
||||||
|
|
||||||
if (pFunc && PyCallable_Check(pFunc)) {
|
if (pFunc && PyCallable_Check(pFunc)) {
|
||||||
PyObject *pValue = PyObject_CallFunction(pFunc, "s", *url);
|
PyObject *pValue = PyObject_CallFunction(pFunc, "s", *url);
|
||||||
if (pValue && (pValue != Py_None)) {
|
if (pValue) {
|
||||||
const unsigned char *str = PyString_AsString(pValue);
|
if (pValue != Py_None) {
|
||||||
unsigned char *new_url;
|
const unsigned char *str;
|
||||||
|
unsigned char *new_url;
|
||||||
|
|
||||||
if (str) {
|
str = PyString_AsString(pValue);
|
||||||
new_url = stracpy((unsigned char *)str);
|
if (str) {
|
||||||
if (new_url) mem_free_set(url, new_url);
|
new_url = stracpy((unsigned char *)str);
|
||||||
|
if (new_url) mem_free_set(url, new_url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Py_DECREF(pValue);
|
Py_DECREF(pValue);
|
||||||
} else {
|
} else {
|
||||||
if (PyErr_Occurred()) {
|
alert_python_error(ses);
|
||||||
PyErr_Print();
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,15 +100,17 @@ static enum evhook_status
|
|||||||
script_hook_follow_url(va_list ap, void *data)
|
script_hook_follow_url(va_list ap, void *data)
|
||||||
{
|
{
|
||||||
unsigned char **url = va_arg(ap, unsigned char **);
|
unsigned char **url = va_arg(ap, unsigned char **);
|
||||||
|
struct session *ses = va_arg(ap, struct session *);
|
||||||
|
|
||||||
if (pDict && *url)
|
if (pDict && *url)
|
||||||
do_script_hook_follow_url(url);
|
do_script_hook_follow_url(ses, url);
|
||||||
|
|
||||||
return EVENT_HOOK_STATUS_NEXT;
|
return EVENT_HOOK_STATUS_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_script_hook_pre_format_html(unsigned char *url, struct cache_entry *cached,
|
do_script_hook_pre_format_html(struct session *ses, unsigned char *url,
|
||||||
|
struct cache_entry *cached,
|
||||||
struct fragment *fragment)
|
struct fragment *fragment)
|
||||||
{
|
{
|
||||||
PyObject *pFunc = PyDict_GetItemString(pDict, "pre_format_html_hook");
|
PyObject *pFunc = PyDict_GetItemString(pDict, "pre_format_html_hook");
|
||||||
@ -118,21 +120,21 @@ do_script_hook_pre_format_html(unsigned char *url, struct cache_entry *cached,
|
|||||||
fragment->data,
|
fragment->data,
|
||||||
fragment->length);
|
fragment->length);
|
||||||
|
|
||||||
if (pValue && (pValue != Py_None)) {
|
if (pValue) {
|
||||||
const unsigned char *str = PyString_AsString(pValue);
|
if (pValue != Py_None) {
|
||||||
|
const unsigned char *str;
|
||||||
|
int len;
|
||||||
|
|
||||||
if (str) {
|
str = PyString_AsString(pValue);
|
||||||
int len = PyString_Size(pValue); /* strlen(str); */
|
if (str) {
|
||||||
|
len = PyString_Size(pValue);
|
||||||
add_fragment(cached, 0, str, len);
|
add_fragment(cached, 0, str, len);
|
||||||
normalize_cache_entry(cached, len);
|
normalize_cache_entry(cached, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Py_DECREF(pValue);
|
Py_DECREF(pValue);
|
||||||
} else {
|
} else {
|
||||||
if (PyErr_Occurred()) {
|
alert_python_error(ses);
|
||||||
PyErr_Print();
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,7 +148,7 @@ script_hook_pre_format_html(va_list ap, void *data)
|
|||||||
unsigned char *url = struri(cached->uri);
|
unsigned char *url = struri(cached->uri);
|
||||||
|
|
||||||
if (pDict && ses && url && cached->length && *fragment->data)
|
if (pDict && ses && url && cached->length && *fragment->data)
|
||||||
do_script_hook_pre_format_html(url, cached, fragment);
|
do_script_hook_pre_format_html(ses, url, cached, fragment);
|
||||||
|
|
||||||
return EVENT_HOOK_STATUS_NEXT;
|
return EVENT_HOOK_STATUS_NEXT;
|
||||||
}
|
}
|
||||||
@ -159,20 +161,21 @@ do_script_hook_get_proxy(unsigned char **new_proxy_url, unsigned char *url)
|
|||||||
if (pFunc && PyCallable_Check(pFunc)) {
|
if (pFunc && PyCallable_Check(pFunc)) {
|
||||||
PyObject *pValue = PyObject_CallFunction(pFunc, "s", url);
|
PyObject *pValue = PyObject_CallFunction(pFunc, "s", url);
|
||||||
|
|
||||||
if (pValue && (pValue != Py_None)) {
|
if (pValue) {
|
||||||
const unsigned char *str = PyString_AsString(pValue);
|
if (pValue != Py_None) {
|
||||||
|
const unsigned char *str;
|
||||||
|
unsigned char *new_url;
|
||||||
|
|
||||||
if (str) {
|
str = PyString_AsString(pValue);
|
||||||
unsigned char *new_url = stracpy((unsigned char *)str);
|
if (str) {
|
||||||
|
new_url = stracpy((unsigned char *)str);
|
||||||
if (new_url) mem_free_set(new_proxy_url, new_url);
|
if (new_url) mem_free_set(new_proxy_url,
|
||||||
|
new_url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Py_DECREF(pValue);
|
Py_DECREF(pValue);
|
||||||
} else {
|
} else {
|
||||||
if (PyErr_Occurred()) {
|
alert_python_error(NULL);
|
||||||
PyErr_Print();
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,14 +201,9 @@ do_script_hook_quit(void)
|
|||||||
PyObject *pValue = PyObject_CallFunction(pFunc, NULL);
|
PyObject *pValue = PyObject_CallFunction(pFunc, NULL);
|
||||||
|
|
||||||
if (pValue) {
|
if (pValue) {
|
||||||
if (pValue != Py_None) {
|
Py_DECREF(pValue);
|
||||||
Py_DECREF(pValue);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (PyErr_Occurred()) {
|
alert_python_error(NULL);
|
||||||
PyErr_Print();
|
|
||||||
PyErr_Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,10 +24,14 @@
|
|||||||
#include "scripting/ruby/ruby.h"
|
#include "scripting/ruby/ruby.h"
|
||||||
#include "scripting/smjs/smjs.h"
|
#include "scripting/smjs/smjs.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Error reporting. */
|
/* Error reporting. */
|
||||||
|
|
||||||
#if defined(CONFIG_SCRIPTING_RUBY) || defined(CONFIG_SCRIPTING_SPIDERMONKEY)
|
#if defined(CONFIG_SCRIPTING_RUBY) || defined(CONFIG_SCRIPTING_SPIDERMONKEY) || defined(CONFIG_SCRIPTING_PYTHON)
|
||||||
void
|
void
|
||||||
report_scripting_error(struct module *module, struct session *ses,
|
report_scripting_error(struct module *module, struct session *ses,
|
||||||
unsigned char *msg)
|
unsigned char *msg)
|
||||||
@ -38,6 +42,7 @@ report_scripting_error(struct module *module, struct session *ses,
|
|||||||
if (!ses) {
|
if (!ses) {
|
||||||
if (list_empty(terminals)) {
|
if (list_empty(terminals)) {
|
||||||
usrerror("[%s error] %s", module->name, msg);
|
usrerror("[%s error] %s", module->name, msg);
|
||||||
|
sleep(3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user