1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-09-28 03:06:20 -04:00

Fixes to the Python scripting by M. Levinson

This commit is contained in:
Witold Filipczyk 2006-07-24 18:52:25 +02:00 committed by Witold Filipczyk
parent 29fb051fc9
commit 6c8f532692
6 changed files with 158 additions and 79 deletions

View File

@ -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

View File

@ -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!

View File

@ -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();
}
} }
} }

View File

@ -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);

View File

@ -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;
if (res) { unsigned char *new_url;
unsigned char *new_url = stracpy((unsigned char *)res);
str = PyString_AsString(pValue);
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) {
const unsigned char *str;
unsigned char *new_url; unsigned char *new_url;
str = PyString_AsString(pValue);
if (str) { if (str) {
new_url = stracpy((unsigned char *)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();
}
} }
} }
} }
@ -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;
str = PyString_AsString(pValue);
if (str) { if (str) {
int len = PyString_Size(pValue); /* strlen(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;
str = PyString_AsString(pValue);
if (str) { if (str) {
unsigned char *new_url = stracpy((unsigned char *)str); new_url = stracpy((unsigned char *)str);
if (new_url) mem_free_set(new_proxy_url,
if (new_url) mem_free_set(new_proxy_url, new_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();
}
} }
} }
} }

View File

@ -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;
} }