|
16 | 16 | #include <unistd.h> |
17 | 17 | #include <utility> |
18 | 18 |
|
| 19 | +#include "runtime-common/core/allocator/script-allocator.h" |
19 | 20 | #include "runtime-common/core/runtime-core.h" |
| 21 | +#include "runtime-common/core/std/containers.h" |
20 | 22 | #include "runtime-common/stdlib/array/array-functions.h" |
21 | 23 | #include "runtime-common/stdlib/string/string-functions.h" |
22 | 24 | #include "runtime-light/coroutine/task.h" |
@@ -61,7 +63,7 @@ inline string f$basename(const string& path, const string& suffix = {}) noexcept |
61 | 63 |
|
62 | 64 | inline Optional<int64_t> f$filesize(const string& filename) noexcept { |
63 | 65 | struct stat stat {}; |
64 | | - if (auto errc{k2::stat({filename.c_str(), filename.size()}, std::addressof(stat))}; errc != k2::errno_ok) [[unlikely]] { |
| 66 | + if (auto stat_result{k2::stat({filename.c_str(), filename.size()}, std::addressof(stat))}; !stat_result.has_value()) [[unlikely]] { |
65 | 67 | return false; |
66 | 68 | } |
67 | 69 | return static_cast<int64_t>(stat.st_size); |
@@ -201,6 +203,57 @@ inline Optional<string> f$file_get_contents(const string& stream) noexcept { |
201 | 203 | return false; |
202 | 204 | } |
203 | 205 |
|
| 206 | +inline Optional<array<string>> f$file(const string& name) noexcept { |
| 207 | + struct stat stat_buf {}; |
| 208 | + |
| 209 | + auto expected_file{kphp::fs::file::open(name.c_str(), "r")}; |
| 210 | + if (!expected_file.has_value()) { |
| 211 | + return false; |
| 212 | + } |
| 213 | + if (!k2::stat(name.c_str(), std::addressof(stat_buf)).has_value()) { |
| 214 | + return false; |
| 215 | + } |
| 216 | + if (!S_ISREG(stat_buf.st_mode)) { |
| 217 | + kphp::log::warning("regular file expected as first argument in function file, \"{}\" is given", name.c_str()); |
| 218 | + return false; |
| 219 | + } |
| 220 | + |
| 221 | + const size_t size{static_cast<size_t>(stat_buf.st_size)}; |
| 222 | + if (size > string::max_size()) { |
| 223 | + kphp::log::warning("file \"{}\" is too large", name.c_str()); |
| 224 | + return false; |
| 225 | + } |
| 226 | + |
| 227 | + kphp::stl::vector<std::byte, kphp::memory::script_allocator> file_content; |
| 228 | + file_content.resize(size); |
| 229 | + { |
| 230 | + auto file{std::move(*expected_file)}; |
| 231 | + if (auto expected_read_result{file.read(file_content)}; !expected_read_result.has_value() || *expected_read_result < size) { |
| 232 | + return false; |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + array<string> result; |
| 237 | + int32_t prev{-1}; |
| 238 | + for (size_t i{0}; i < size; i++) { |
| 239 | + if (static_cast<char>(file_content[i]) == '\n' || i + 1 == size) { |
| 240 | + result.push_back(string{reinterpret_cast<char*>(file_content.data()) + prev + 1, static_cast<string::size_type>(i - prev)}); |
| 241 | + prev = i; |
| 242 | + } |
| 243 | + } |
| 244 | + |
| 245 | + return result; |
| 246 | +} |
| 247 | + |
| 248 | +inline bool f$is_file(const string& name) noexcept { |
| 249 | + struct stat stat_buf {}; |
| 250 | + // TODO: the semantics in PHP are different: PHP expects stat |
| 251 | + if (!k2::lstat(name.c_str(), std::addressof(stat_buf)).has_value()) { |
| 252 | + return false; |
| 253 | + } |
| 254 | + return S_ISREG(stat_buf.st_mode); |
| 255 | +} |
| 256 | + |
204 | 257 | inline Optional<int64_t> f$file_put_contents(const string& stream, const mixed& content_var, int64_t flags = 0) noexcept { |
205 | 258 | string content{content_var.is_array() ? f$implode(string{}, content_var.to_array()) : content_var.to_string()}; |
206 | 259 |
|
|
0 commit comments