/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Python 3 │ │ https://docs.python.org/3/license.html │ ╚─────────────────────────────────────────────────────────────────────────────*/ #define PY_SSIZE_T_CLEAN #include "libc/calls/calls.h" #include "libc/calls/internal.h" #include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/sigset.h" #include "libc/calls/ucontext.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/safemacros.internal.h" #include "libc/intrin/weaken.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.internal.h" #include "libc/mem/gc.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/runtime/symbols.internal.h" #include "libc/stdio/stdio.h" #include "libc/str/locale.h" #include "libc/str/str.h" #include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/sig.h" #include "libc/time.h" #include "libc/x/x.h" #include "libc/x/xasprintf.h" #include "third_party/linenoise/linenoise.h" #include "third_party/python/Include/abstract.h" #include "third_party/python/Include/ceval.h" #include "third_party/python/Include/dictobject.h" #include "third_party/python/Include/fileutils.h" #include "third_party/python/Include/funcobject.h" #include "third_party/python/Include/import.h" #include "third_party/python/Include/listobject.h" #include "third_party/python/Include/moduleobject.h" #include "third_party/python/Include/object.h" #include "third_party/python/Include/pydebug.h" #include "third_party/python/Include/pyerrors.h" #include "third_party/python/Include/pylifecycle.h" #include "third_party/python/Include/pymem.h" #include "third_party/python/Include/pyport.h" #include "third_party/python/Include/pythonrun.h" #include "third_party/python/Include/unicodeobject.h" #include "third_party/python/Include/yoink.h" #include "libc/runtime/stack.h" #include "third_party/xed/x86.h" STATIC_STACK_SIZE(0x100000); __static_yoink("__die"); __static_yoink("zipos"); PYTHON_YOINK("cosmo"); PYTHON_YOINK("_locale"); PYTHON_YOINK("_bootlocale"); PYTHON_YOINK("encodings.aliases"); PYTHON_YOINK("encodings.latin_1"); PYTHON_YOINK("encodings.utf_8"); extern char kLaunchPythonModuleName[]; /* optionally generated by pyobj */ const struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules; struct _inittab *PyImport_Inittab = (void *)_PyImport_Inittab; static int g_gotint; static void OnKeyboardInterrupt(int sig) { g_gotint = sig; } static void AddCompletion(linenoiseCompletions *c, char *s) { char **p = c->cvec; size_t n = c->len + 1; if ((p = realloc(p, n * sizeof(*p)))) { p[n - 1] = s; c->cvec = p; c->len = n; } } static void CompleteModule(const char *s, const char *p, linenoiseCompletions *c) { const char *name; struct _inittab *it; Py_ssize_t plen, namelen; PyObject *m, *f, *g, *i, *v, *n; plen = strlen(p); for (it = PyImport_Inittab; it->name; ++it) { if (startswithi(it->name, p)) { AddCompletion(c, xasprintf("%s%s", s, it->name + plen)); } } if ((m = PyImport_ImportModule("pkgutil"))) { if ((f = PyObject_GetAttrString(m, "iter_modules"))) { if ((g = PyObject_CallFunctionObjArgs(f, 0))) { if ((i = PyObject_GetIter(g))) { while ((v = PyIter_Next(i))) { if ((n = PyObject_GetAttrString(v, "name"))) { if (((name = PyUnicode_AsUTF8AndSize(n, &namelen)) && namelen >= plen && !memcasecmp(name, p, plen))) { AddCompletion(c, xasprintf("%s%s", s, name + plen)); } Py_DECREF(n); } Py_DECREF(v); } Py_DECREF(i); } Py_DECREF(g); } Py_DECREF(f); } Py_DECREF(m); } } static void CompleteDict(const char *b, const char *q, const char *p, linenoiseCompletions *c, PyObject *o) { const char *s; PyObject *k, *v; Py_ssize_t i, m; for (i = 0; PyDict_Next(o, &i, &k, &v);) { if ((v != Py_None && PyUnicode_Check(k) && (s = PyUnicode_AsUTF8AndSize(k, &m)) && m >= q - p && !memcasecmp(s, p, q - p))) { AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); } } } static void CompleteDir(const char *b, const char *q, const char *p, linenoiseCompletions *c, PyObject *o) { Py_ssize_t m; const char *s; PyObject *d, *i, *k; if ((d = PyObject_Dir(o))) { if ((i = PyObject_GetIter(d))) { while ((k = PyIter_Next(i))) { if (((s = PyUnicode_AsUTF8AndSize(k, &m)) && m >= q - p && !memcasecmp(s, p, q - p) && !(q - p == 0 && m > 4 && (s[0+0] == '_' && s[0+1] == '_' && s[m-1] == '_' && s[m-2] == '_')))) { AddCompletion(c, xasprintf("%.*s%.*s", p - b, b, m, s)); } Py_DECREF(k); } Py_DECREF(i); } Py_DECREF(d); } } static void Complete(const char *p, linenoiseCompletions *c) { char *s; PyObject *o, *t; const char *q, *b; if (startswith(p, "import ")) { for (q = p + 7; *q; ++q) { if (!isalnum(*q) && *q != '_') { return; } } CompleteModule(p, p + 7, c); return; } for (b = p, p += strlen(p); p > b; --p) { if (!isalnum(p[-1]) && p[-1] != '.' && p[-1] != '_') { break; } } o = PyModule_GetDict(PyImport_AddModule("__main__")); if (!*(q = strchrnul(p, '.'))) { CompleteDict(b, q, p, c, o); CompleteDir(b, q, p, c, PyDict_GetItemString(o, "__builtins__")); } else { s = strndup(p, q - p); if ((t = PyDict_GetItemString(o, s))) { Py_INCREF(t); } else { o = PyDict_GetItemString(o, "__builtins__"); if (PyObject_HasAttrString(o, s)) { t = PyObject_GetAttrString(o, s); } } while ((p = q + 1), (o = t)) { if (*(q = strchrnul(p, '.'))) { t = PyObject_GetAttrString(o, gc(strndup(p, q - p))); Py_DECREF(o); } else { CompleteDir(b, q, p, c, o); Py_DECREF(o); break; } } free((void *)s); } } static void TerminalCompletion(const char *p, linenoiseCompletions *c) { PyGILState_STATE gilstate; gilstate = PyGILState_Ensure(); Complete(p, c); PyGILState_Release(gilstate); if (PyErr_Occurred()) { PyErr_Clear(); } } static char * TerminalHint(const char *p, const char **ansi1, const char **ansi2) { char *h = 0; linenoiseCompletions c = {0}; TerminalCompletion(p, &c); if (c.len == 1) h = strdup(c.cvec[0] + strlen(p)); linenoiseFreeCompletions(&c); return h; } static char * ReinterpretCommand(const char *line) { size_t n; n = strlen(line); if (n && line[n - 1] == '?') { return xstrcat("help(", gc(strndup(gc(line), n - 1)), ')'); } else { return xstrdup(line); } } static char * TerminalReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) { size_t n; char *p, *q; PyOS_sighandler_t saint; saint = PyOS_setsig(SIGINT, OnKeyboardInterrupt); p = linenoiseWithHistory(prompt, "python"); PyOS_setsig(SIGINT, saint); if (g_gotint) { PyOS_setsig(SIGINT, saint); g_gotint = 0; q = 0; } else if (p) { p = ReinterpretCommand(p); n = strlen(p); q = PyMem_RawMalloc(n + 2); strcpy(mempcpy(q, p, n), "\n"); clearerr(sys_stdin); } else if ((q = PyMem_RawMalloc(1))) { *q = 0; } free(p); return q; } int RunPythonModule(int argc, char **argv) { char *launchargs[4]; wchar_t **argv_copy; /* We need a second copy, as Python might modify the first one. */ wchar_t **argv_copy2; int i, res; char *oldloc; if (argc == 1 && _weaken(kLaunchPythonModuleName)) { launchargs[0] = argv[0]; launchargs[1] = strdup("-m"); launchargs[2] = strdup(kLaunchPythonModuleName); launchargs[3] = 0; argc = 3; argv = launchargs; } PyOS_ReadlineFunctionPointer = TerminalReadline; linenoiseSetCompletionCallback(TerminalCompletion); linenoiseSetHintsCallback(TerminalHint); linenoiseSetFreeHintsCallback(free); #if IsModeDbg() /* Force malloc() allocator to bootstrap Python */ _PyMem_SetupAllocators("malloc"); #endif argv_copy = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); argv_copy2 = (wchar_t **)PyMem_RawMalloc(sizeof(wchar_t*) * (argc+1)); if (!argv_copy || !argv_copy2) { fprintf(stderr, "out of memory\n"); return 1; } /* 754 requires that FP exceptions run in "no stop" mode by default, * and until C vendors implement C99's ways to control FP exceptions, * Python requires non-stop mode. Alas, some platforms enable FP * exceptions by default. Here we disable them. */ #ifdef __FreeBSD__ fedisableexcept(FE_OVERFLOW); #endif oldloc = _PyMem_RawStrdup(setlocale(LC_ALL, NULL)); if (!oldloc) { fprintf(stderr, "out of memory\n"); return 1; } setlocale(LC_ALL, ""); for (i = 0; i < argc; i++) { argv_copy[i] = Py_DecodeLocale(argv[i], NULL); if (!argv_copy[i]) { PyMem_RawFree(oldloc); fprintf(stderr, "Fatal Python error: " "unable to decode the command line argument #%i\n", i + 1); return 1; } argv_copy2[i] = argv_copy[i]; } argv_copy2[argc] = argv_copy[argc] = NULL; setlocale(LC_ALL, oldloc); PyMem_RawFree(oldloc); res = Py_Main(argc, argv_copy); #if IsModeDbg() /* Force again malloc() allocator to release memory blocks allocated before Py_Main() */ _PyMem_SetupAllocators("malloc"); #endif for (i = 0; i < argc; i++) { PyMem_RawFree(argv_copy2[i]); } PyMem_RawFree(argv_copy); PyMem_RawFree(argv_copy2); return res; }