this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include <unistd.h>
3
4#include <climits>
5#include <cstdarg>
6
7#include "cpython-data.h"
8
9#include "api-handle.h"
10#include "list-builtins.h"
11#include "module-builtins.h"
12#include "os.h"
13#include "runtime.h"
14#include "str-builtins.h"
15#include "sys-module.h"
16
17namespace py {
18
19PY_EXPORT size_t _PySys_GetSizeOf(PyObject* o) {
20 Thread* thread = Thread::current();
21 HandleScope scope(thread);
22 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(o)));
23 Object result_obj(&scope,
24 thread->invokeFunction1(ID(sys), ID(getsizeof), obj));
25 if (result_obj.isError()) {
26 // Pass through a pending exception if any exists.
27 return static_cast<size_t>(-1);
28 }
29 DCHECK(thread->runtime()->isInstanceOfInt(*result_obj),
30 "sys.getsizeof() should return an int");
31 Int result(&scope, intUnderlying(*result_obj));
32 return static_cast<size_t>(result.asWord());
33}
34
35PY_EXPORT PyObject* PySys_GetObject(const char* name) {
36 DCHECK(name != nullptr, "name must not be nullptr");
37 Thread* thread = Thread::current();
38 Runtime* runtime = thread->runtime();
39 HandleScope scope(thread);
40 Module module(&scope, runtime->findModuleById(ID(sys)));
41 Object name_obj(&scope, Runtime::internStrFromCStr(thread, name));
42 Object result(&scope, moduleAt(module, name_obj));
43 if (result.isErrorNotFound()) return nullptr;
44 return ApiHandle::borrowedReference(runtime, *result);
45}
46
47PY_EXPORT void PySys_AddWarnOption(const wchar_t* /* s */) {
48 UNIMPLEMENTED("PySys_AddWarnOption");
49}
50
51PY_EXPORT void PySys_AddWarnOptionUnicode(PyObject* /* n */) {
52 UNIMPLEMENTED("PySys_AddWarnOptionUnicode");
53}
54
55PY_EXPORT void PySys_AddXOption(const wchar_t* /* s */) {
56 UNIMPLEMENTED("PySys_AddXOption");
57}
58
59PY_EXPORT int PySys_Audit(const char* /* event */, const char* /* argFormat */,
60 ...) {
61 return 0; // TODO(T86943617): implement
62}
63
64PY_EXPORT void PySys_FormatStderr(const char* /* t */, ...) {
65 UNIMPLEMENTED("PySys_FormatStderr");
66}
67
68PY_EXPORT void PySys_FormatStdout(const char* /* t */, ...) {
69 UNIMPLEMENTED("PySys_FormatStdout");
70}
71
72PY_EXPORT PyObject* PySys_GetXOptions() { UNIMPLEMENTED("PySys_GetXOptions"); }
73
74PY_EXPORT int PySys_HasWarnOptions() { UNIMPLEMENTED("PySys_HasWarnOptions"); }
75
76PY_EXPORT void PySys_ResetWarnOptions() {
77 UNIMPLEMENTED("PySys_ResetWarnOptions");
78}
79
80static void sysUpdatePath(Thread* thread, const Str& arg0) {
81 Runtime* runtime = thread->runtime();
82 HandleScope scope(thread);
83 List path(&scope, runtime->lookupNameInModule(thread, ID(sys), ID(path)));
84
85 char* arg0_cstr = arg0.toCStr();
86 char* script_path = arg0_cstr;
87
88 if (std::strcmp(script_path, "-c") == 0) {
89 Str empty(&scope, Str::empty());
90 listInsert(thread, path, empty, 0);
91 std::free(arg0_cstr);
92 return;
93 }
94
95 if (std::strcmp(script_path, "-m") == 0) {
96 char buf[PATH_MAX];
97 if (::getcwd(buf, PATH_MAX) == nullptr) {
98 return;
99 }
100 Str cwd(&scope, runtime->newStrFromCStr(buf));
101 listInsert(thread, path, cwd, 0);
102 std::free(arg0_cstr);
103 return;
104 }
105
106 char* buf = nullptr;
107 // Follow symlink, if it exists
108 char* link = OS::readLink(script_path);
109 if (link != nullptr) {
110 // It's a symlink
111 if (link[0] == '/') {
112 script_path = link; // Link to absolute path
113 } else if (std::strchr(link, '/') == nullptr) {
114 ; // Link without path
115 } else {
116 // Link has partial path, must join(dirname(script_path), link)
117 char* last_sep = std::strrchr(script_path, '/');
118 if (last_sep == nullptr) {
119 script_path = link; // script_path has no path
120 } else {
121 // Must make a copy
122 int dir_len = last_sep - script_path + 1;
123 int link_len = std::strlen(link);
124 buf = static_cast<char*>(std::malloc(dir_len + link_len + 1));
125 std::strncpy(buf, script_path, dir_len);
126 last_sep = buf + (last_sep - script_path);
127 std::strncpy(last_sep + 1, link, link_len + 1);
128 script_path = buf;
129 }
130 }
131 }
132
133 // Resolve the real path. Allow realpath to allocate to avoid PATH_MAX issues
134 char* fullpath = ::realpath(script_path, nullptr);
135 if (fullpath != nullptr) {
136 script_path = fullpath;
137 }
138
139 char* last_sep = std::strrchr(script_path, '/');
140 word path_len = 0;
141 if (last_sep != nullptr) {
142 path_len = last_sep - script_path + 1;
143 if (path_len > 1) {
144 path_len--; // Drop trailing separator
145 }
146 }
147
148 auto script_path_data = reinterpret_cast<const byte*>(script_path);
149 View<byte> script_path_view(script_path_data, path_len);
150 Object path_element(&scope, runtime->newStrWithAll(script_path_view));
151 listInsert(thread, path, path_element, 0);
152
153 std::free(fullpath);
154 std::free(link);
155 std::free(buf);
156 std::free(arg0_cstr);
157}
158
159PY_EXPORT void PySys_SetArgv(int argc, wchar_t** argv) {
160 PySys_SetArgvEx(argc, argv, Py_IsolatedFlag == 0);
161}
162
163PY_EXPORT void PySys_SetArgvEx(int argc, wchar_t** argv, int updatepath) {
164 CHECK(argc >= 0, "Unexpected argc");
165
166 Thread* thread = Thread::current();
167 Runtime* runtime = thread->runtime();
168 HandleScope scope(thread);
169 List args(&scope, runtime->newList());
170
171 Str arg(&scope, Str::empty());
172 if (argc == 0 || argv == nullptr) {
173 // Ensure at least one (empty) argument is given in sys.argv
174 // This will also ensure the first element of sys.path is an empty string
175 runtime->listAdd(thread, args, arg);
176 } else {
177 for (int i = 0; i < argc; i++) {
178 RawObject result = newStrFromWideChar(thread, argv[i]);
179 CHECK(!result.isErrorException(), "Invalid unicode character in argv");
180 arg = result;
181 runtime->listAdd(thread, args, arg);
182 }
183 }
184 Module sys_module(&scope, runtime->findModuleById(ID(sys)));
185 moduleAtPutById(thread, sys_module, ID(argv), args);
186
187 if (updatepath == 0) {
188 return;
189 }
190
191 arg = args.at(0);
192 sysUpdatePath(thread, arg);
193}
194
195PY_EXPORT int PySys_SetObject(const char* /* e */, PyObject* /* v */) {
196 UNIMPLEMENTED("PySys_SetObject");
197}
198
199PY_EXPORT void PySys_SetPath(const wchar_t* /* h */) {
200 UNIMPLEMENTED("PySys_SetPath");
201}
202
203PY_EXPORT void PySys_WriteStderr(const char* format, ...) {
204 va_list va;
205 va_start(va, format);
206 writeStderrV(Thread::current(), format, va);
207 va_end(va);
208}
209
210PY_EXPORT void PySys_WriteStdout(const char* format, ...) {
211 va_list va;
212 va_start(va, format);
213 writeStdoutV(Thread::current(), format, va);
214 va_end(va);
215}
216
217} // namespace py