Added test for uploading big files.
[elinks.git] / src / scripting / python / core.c
blob4459122599b5a59b41ce54fcf8ca28f9794f2d7f
1 /* Python scripting engine */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <Python.h>
8 #include <osdefs.h>
10 #include <stdlib.h>
12 #include "elinks.h"
14 #include "config/home.h"
15 #include "main/module.h"
16 #include "scripting/python/core.h"
17 #include "scripting/python/dialogs.h"
18 #include "scripting/python/document.h"
19 #include "scripting/python/keybinding.h"
20 #include "scripting/python/load.h"
21 #include "scripting/python/menu.h"
22 #include "scripting/python/open.h"
23 #include "scripting/python/python.h"
24 #include "scripting/scripting.h"
25 #include "session/session.h"
26 #include "util/env.h"
27 #include "util/string.h"
29 struct session *python_ses = NULL;
31 PyObject *python_elinks_err = NULL;
32 PyObject *python_hooks = NULL;
34 /* Error reporting. */
36 void
37 alert_python_error(void)
39 unsigned char *msg = "(no traceback available)";
40 PyObject *err_type = NULL, *err_value = NULL, *err_traceback = NULL;
41 PyObject *tb_module = NULL;
42 PyObject *msg_list = NULL;
43 PyObject *empty_string = NULL;
44 PyObject *msg_string = NULL;
45 unsigned char *temp;
48 * Retrieve the current error indicator and use the format_exception()
49 * function in Python's traceback module to produce an informative
50 * error message. It returns a list of Python string objects.
52 PyErr_Fetch(&err_type, &err_value, &err_traceback);
53 PyErr_NormalizeException(&err_type, &err_value, &err_traceback);
54 if (!err_type) goto end;
56 tb_module = PyImport_ImportModule("traceback");
57 if (!tb_module) goto end;
59 msg_list = PyObject_CallMethod(tb_module, "format_exception", "OOO",
60 err_type,
61 err_value ? err_value : Py_None,
62 err_traceback ? err_traceback : Py_None);
63 if (!msg_list) goto end;
66 * Use the join() method of an empty Python string to join the list
67 * of strings into one Python string containing the entire error
68 * message. Then get the contents of the Python string.
70 empty_string = PyString_FromString("");
71 if (!empty_string) goto end;
73 msg_string = PyObject_CallMethod(empty_string, "join", "O", msg_list);
74 if (!msg_string) goto end;
76 temp = (unsigned char *) PyString_AsString(msg_string);
77 if (temp) msg = temp;
79 end:
80 report_scripting_error(&python_scripting_module, python_ses, msg);
82 Py_XDECREF(err_type);
83 Py_XDECREF(err_value);
84 Py_XDECREF(err_traceback);
85 Py_XDECREF(tb_module);
86 Py_XDECREF(msg_list);
87 Py_XDECREF(empty_string);
88 Py_XDECREF(msg_string);
90 /* In case another error occurred while reporting the original error: */
91 PyErr_Clear();
94 /* Prepend ELinks directories to Python's search path. */
96 static int
97 set_python_search_path(void)
99 struct string new_python_path;
100 unsigned char *old_python_path;
101 int result = -1;
103 if (!init_string(&new_python_path)) return result;
105 if (elinks_home && !add_format_to_string(&new_python_path, "%s%c",
106 elinks_home, DELIM))
107 goto end;
109 if (!add_to_string(&new_python_path, CONFDIR))
110 goto end;
112 old_python_path = (unsigned char *) getenv("PYTHONPATH");
113 if (old_python_path && !add_format_to_string(&new_python_path, "%c%s",
114 DELIM, old_python_path))
115 goto end;
117 result = env_set("PYTHONPATH", new_python_path.source, -1);
119 end:
120 done_string(&new_python_path);
121 return result;
124 /* Determine whether or not a user-supplied hooks module exists. */
126 static int
127 hooks_module_exists(void)
129 PyObject *imp_module = NULL, *result = NULL;
130 int found_hooks = 0;
133 * Use the find_module() function in Python's imp module to look for
134 * the hooks module in Python's search path. An ImportError exception
135 * indicates that no such module was found; any other exception will
136 * be reported as an error.
138 imp_module = PyImport_ImportModule("imp");
139 if (!imp_module) goto python_error;
141 result = PyObject_CallMethod(imp_module, "find_module", "s", "hooks");
142 if (result) {
143 found_hooks = 1;
144 goto end;
145 } else if (PyErr_ExceptionMatches(PyExc_ImportError)) {
146 PyErr_Clear();
147 goto end;
150 python_error:
151 alert_python_error();
153 end:
154 Py_XDECREF(imp_module);
155 Py_XDECREF(result);
156 return found_hooks;
159 /* Module-level documentation for the Python interpreter's elinks module. */
161 static char module_doc[] =
162 PYTHON_DOCSTRING("Interface to the ELinks web browser.\n\
164 Functions:\n\
166 bind_key() -- Bind a keystroke to a callable object.\n\
167 current_document() -- Return the body of the document being viewed.\n\
168 current_header() -- Return the header of the document being viewed.\n\
169 current_link_url() -- Return the URL of the currently selected link.\n\
170 current_title() -- Return the title of the document being viewed.\n\
171 current_url() -- Return the URL of the document being viewed.\n\
172 info_box() -- Display information to the user.\n\
173 input_box() -- Prompt for user input.\n\
174 load() -- Load a document into the ELinks cache.\n\
175 menu() -- Display a menu.\n\
176 open() -- View a document.\n\
178 Exception classes:\n\
180 error -- Errors internal to ELinks.\n\
182 Other public objects:\n\
184 home -- A string containing the pathname of the ~/.elinks directory, or\n\
185 None if ELinks has no configuration directory.\n");
187 void
188 init_python(struct module *module)
190 PyObject *elinks_module, *module_dict, *module_name;
192 if (set_python_search_path() != 0) return;
194 /* Treat warnings as errors so they can be caught and handled;
195 * otherwise they would be printed to stderr.
197 * NOTE: PySys_ResetWarnOptions() and PySys_AddWarnOption() have been
198 * available and stable for many years but they're not officially
199 * documented as part of Python's public API, so in theory these two
200 * functions might no longer be available in some hypothetical future
201 * version of Python. */
202 PySys_ResetWarnOptions();
203 PySys_AddWarnOption("error");
205 Py_Initialize();
207 if (!hooks_module_exists()) return;
209 elinks_module = Py_InitModule3("elinks", NULL, module_doc);
210 if (!elinks_module) goto python_error;
212 /* If @elinks_home is NULL, Py_BuildValue() returns a None reference. */
213 if (PyModule_AddObject(elinks_module, "home",
214 Py_BuildValue("s", elinks_home)) != 0)
215 goto python_error;
217 python_elinks_err = PyErr_NewException("elinks.error", NULL, NULL);
218 if (!python_elinks_err) goto python_error;
220 if (PyModule_AddObject(elinks_module, "error", python_elinks_err) != 0)
221 goto python_error;
223 module_dict = PyModule_GetDict(elinks_module);
224 if (!module_dict) goto python_error;
225 module_name = PyString_FromString("elinks");
226 if (!module_name) goto python_error;
228 if (python_init_dialogs_interface(module_dict, module_name) != 0
229 || python_init_document_interface(module_dict, module_name) != 0
230 || python_init_keybinding_interface(module_dict, module_name) != 0
231 || python_init_load_interface(module_dict, module_name) != 0
232 || python_init_menu_interface(module_dict, module_name) != 0
233 || python_init_open_interface(module_dict, module_name) != 0)
234 goto python_error;
236 python_hooks = PyImport_ImportModule("hooks");
237 if (!python_hooks) goto python_error;
239 return;
241 python_error:
242 alert_python_error();
245 void
246 cleanup_python(struct module *module)
248 if (Py_IsInitialized()) {
249 PyObject *temp;
251 python_done_keybinding_interface();
253 /* This is equivalent to Py_CLEAR(), but it works with older
254 * versions of Python predating that macro: */
255 temp = python_hooks;
256 python_hooks = NULL;
257 Py_XDECREF(temp);
259 Py_Finalize();
263 /* Add methods to a Python extension module. */
266 add_python_methods(PyObject *dict, PyObject *name, PyMethodDef *methods)
268 PyMethodDef *method;
270 for (method = methods; method && method->ml_name; method++) {
271 PyObject *function = PyCFunction_NewEx(method, NULL, name);
272 int result;
274 if (!function) return -1;
275 result = PyDict_SetItemString(dict, method->ml_name, function);
276 Py_DECREF(function);
277 if (result != 0) return -1;
279 return 0;