#include "util.h" #include #include #include #include #include #define EXPORT __attribute__((visibility("default"))) static const char *ERR_OOM = "Out of memory"; static int report_error(const char *msg) { fprintf(stderr, "%s\n", msg); fflush(stderr); return -1; } static int report_code(const char *preamble, const char* msg, int code) { fprintf(stderr, "%s: %s\n", preamble, msg); fflush(stderr); return code; } #define EXE "@executable_path/.." static void set_env_vars(const char **ENV_VARS, const char **ENV_VAR_VALS, const char* exe_path) { int i = 0; char buf[3*PATH_MAX]; const char *env_var, *val; while(1) { env_var = ENV_VARS[i]; if (env_var == NULL) break; val = ENV_VAR_VALS[i++]; if (strstr(val, EXE) == val && strlen(val) >= strlen(EXE)+1) { strncpy(buf, exe_path, 3*PATH_MAX-150); strncpy(buf+strlen(exe_path), val+strlen(EXE), 150); setenv(env_var, buf, 1); } else setenv(env_var, val, 1); } return; } void initialize_interpreter(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM, const char *MODULE, const char *FUNCTION, const char *PYVER, int IS_GUI, const char* exe_path, const char *rpath, int argc, const char **argv) { PyObject *pargv, *v; int i; Py_OptimizeFlag = 2; Py_NoSiteFlag = 1; Py_DontWriteBytecodeFlag = 1; Py_IgnoreEnvironmentFlag = 1; Py_NoUserSiteDirectory = 1; Py_HashRandomizationFlag = 1; //Py_VerboseFlag = 1; //Py_DebugFlag = 1; Py_SetProgramName(PROGRAM); char pyhome[1000]; snprintf(pyhome, 1000, "%s/Python", rpath); Py_SetPythonHome(pyhome); set_env_vars(ENV_VARS, ENV_VAR_VALS, exe_path); //printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath()); Py_Initialize(); char *dummy_argv[1] = {""}; PySys_SetArgv(1, dummy_argv); //printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath()); char path[3000]; snprintf(path, 3000, "%s/lib/python%s:%s/lib/python%s/lib-dynload:%s/site-packages", pyhome, PYVER, pyhome, PYVER, pyhome); PySys_SetPath(path); //printf("Path set by me: %s\r\n\n", path); PySys_SetObject("calibre_basename", PyBytes_FromString(PROGRAM)); PySys_SetObject("calibre_module", PyBytes_FromString(MODULE)); PySys_SetObject("calibre_function", PyBytes_FromString(FUNCTION)); PySys_SetObject("calibre_is_gui_app", ((IS_GUI) ? Py_True : Py_False)); PySys_SetObject("resourcepath", PyBytes_FromString(rpath)); snprintf(path, 3000, "%s/site-packages", pyhome); PySys_SetObject("site_packages", PyBytes_FromString(pyhome)); pargv = PyList_New(argc); if (pargv == NULL) exit(report_error(ERR_OOM)); for (i = 0; i < argc; i++) { v = PyBytes_FromString(argv[i]); if (v == NULL) exit(report_error(ERR_OOM)); PyList_SetItem(pargv, i, v); } PySys_SetObject("argv", pargv); } int pyobject_to_int(PyObject *res) { int ret; PyObject *tmp; tmp = PyNumber_Int(res); if (tmp == NULL) ret = (PyObject_IsTrue(res)) ? 1 : 0; else ret = (int)PyInt_AS_LONG(tmp); return ret; } int handle_sysexit(PyObject *e) { PyObject *code; code = PyObject_GetAttrString(e, "code"); if (!code) return 0; if (!PyInt_Check(code)) { PyObject_Print(code, stderr, Py_PRINT_RAW); fflush(stderr); } return pyobject_to_int(code); } int calibre_show_python_error(const char *preamble, int code) { PyObject *exc, *val, *tb, *str; int ret, issysexit = 0; char *i; if (!PyErr_Occurred()) return code; issysexit = PyErr_ExceptionMatches(PyExc_SystemExit); PyErr_Fetch(&exc, &val, &tb); if (exc != NULL) { PyErr_NormalizeException(&exc, &val, &tb); if (issysexit) { return (val) ? handle_sysexit(val) : 0; } if (val != NULL) { str = PyObject_Unicode(val); if (str == NULL) { PyErr_Clear(); str = PyObject_Str(val); } i = PyString_AsString(str); ret = report_code(preamble, (i==NULL)?ERR_OOM:i, code); if (tb != NULL) { PyErr_Restore(exc, val, tb); PyErr_Print(); } return ret; } } return report_code(preamble, "", code); } EXPORT int run(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM, const char *MODULE, const char *FUNCTION, const char *PYVER, int IS_GUI, int argc, const char **argv, const char **envp) { char *pathPtr = NULL, *t = NULL; char buf[3*PATH_MAX]; int ret = 0, i; PyObject *site, *mainf, *res; uint32_t buf_size = PATH_MAX+1; char *ebuf = calloc(buf_size, sizeof(char)); ret = _NSGetExecutablePath(ebuf, &buf_size); if (ret == -1) { free(ebuf); ebuf = calloc(buf_size, sizeof(char)); if (_NSGetExecutablePath(ebuf, &buf_size) != 0) return report_error("Failed to find real path of executable."); } pathPtr = realpath(ebuf, buf); if (pathPtr == NULL) { return report_error(strerror(errno)); } for (i = 0; i < 3; i++) { t = rindex(pathPtr, '/'); if (t == NULL) return report_error("Failed to determine bundle path."); *t = '\0'; } if (strstr(pathPtr, "/calibre.app/Contents/") != NULL) { // We are one of the duplicate executables created to workaround codesign's limitations for (i = 0; i < 2; i++) { t = rindex(pathPtr, '/'); if (t == NULL) return report_error("Failed to resolve bundle path in dummy executable"); *t = '\0'; } } char rpath[PATH_MAX+1], exe_path[PATH_MAX+1]; snprintf(exe_path, PATH_MAX+1, "%s/Contents", pathPtr); snprintf(rpath, PATH_MAX+1, "%s/Resources", exe_path); initialize_interpreter(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, IS_GUI, exe_path, rpath, argc, argv); site = PyImport_ImportModule("site"); if (site == NULL) ret = calibre_show_python_error("Failed to import site module", -1); else { Py_XINCREF(site); mainf = PyObject_GetAttrString(site, "main"); if (mainf == NULL || !PyCallable_Check(mainf)) ret = calibre_show_python_error("site module has no main function", -1); else { Py_XINCREF(mainf); res = PyObject_CallObject(mainf, NULL); if (res == NULL) ret = calibre_show_python_error("Python function terminated unexpectedly", -1); else { } } } PyErr_Clear(); Py_Finalize(); //printf("11111 Returning: %d\r\n", ret); return ret; }