Phasor 3.1.1
Stack VM based Programming Language
Loading...
Searching...
No Matches
file.cpp
Go to the documentation of this file.
1#include <filesystem>
2#include <vector>
3
4#include "StdLib.hpp"
6
7namespace Phasor
8{
9
32
33Value StdLib::file_absolute(const std::vector<Value> &args, VM *vm)
34{
35 checkArgCount(args, 1, "fabsolute");
36 std::filesystem::path path = args[0].asString();
37 std::filesystem::path fullPath = std::filesystem::weakly_canonical(path);
38 return fullPath.string();
39}
40
41Value StdLib::file_read(const std::vector<Value> &args, VM *vm)
42{
43 checkArgCount(args, 1, "fread");
44 std::filesystem::path path = args[0].asString();
45 std::ifstream file(path);
46 if (!file.is_open())
47 {
48 return Value(); // Return null if file cannot be opened
49 }
50 std::stringstream buffer;
51 buffer << file.rdbuf();
52 return buffer.str();
53}
54
55Value StdLib::file_read_line(const std::vector<Value> &args, VM *vm)
56{
57 checkArgCount(args, 2, "freadln");
58 std::filesystem::path path = args[0].asString();
59 int64_t lineNum = args[1].asInt();
60 std::ifstream file(path);
61 if (!file.is_open())
62 {
63 throw std::runtime_error("Could not open file: " + path.string());
64 }
65 std::string lineContent;
66 int currentLine = 0;
67 while (std::getline(file, lineContent) && currentLine < lineNum)
68 {
69 currentLine++;
70 }
71 return lineContent;
72}
73
74Value StdLib::file_write_line(const std::vector<Value> &args, VM *vm)
75{
76 checkArgCount(args, 3, "fwriteln");
77 std::filesystem::path path = args[0].asString();
78 int64_t lineNum = args[1].asInt();
79 std::string content = args[2].asString();
80
81 // Read all lines first
82 std::ifstream inFile(path);
83 if (!inFile.is_open())
84 {
85 throw std::runtime_error("Could not open file for reading: " + path.string());
86 }
87
88 std::vector<std::string> lines;
89 std::string line;
90 while (std::getline(inFile, line))
91 {
92 lines.push_back(line);
93 }
94 inFile.close();
95
96 // Ensure we have enough lines
97 while (lines.size() <= static_cast<size_t>(lineNum))
98 {
99 lines.emplace_back("");
100 }
101
102 // Update the line
103 lines[lineNum] = content;
104
105 // Write back to file
106 std::ofstream outFile(path);
107 if (!outFile.is_open())
108 {
109 throw std::runtime_error("Could not open file for writing: " + path.string());
110 }
111
112 for (size_t i = 0; i < lines.size(); ++i)
113 {
114 outFile << lines[i];
115 if (i != lines.size() - 1)
116 {
117 outFile << '\n';
118 }
119 }
120
121 return true;
122}
123
124Value StdLib::file_write(const std::vector<Value> &args, VM *vm)
125{
126 checkArgCount(args, 2, "fwrite");
127 std::filesystem::path path = args[0].asString();
128 std::ofstream file(path);
129 if (!file.is_open())
130 {
131 throw std::runtime_error("Could not open file for writing: " + path.string());
132 }
133 file << args[1].asString();
134 return true;
135}
136
137Value StdLib::file_exists(const std::vector<Value> &args, VM *vm)
138{
139 checkArgCount(args, 1, "fexists");
140 return std::filesystem::exists(args[0].asString());
141}
142
143Value StdLib::file_append(const std::vector<Value> &args, VM *vm)
144{
145 checkArgCount(args, 2, "fappend");
146 std::filesystem::path path = args[0].asString();
147 std::ofstream file(path, std::ios::app);
148 if (!file.is_open())
149 {
150 throw std::runtime_error("Could not open file for writing: " + path.string());
151 }
152 file << args[1].asString();
153 return true;
154}
155
156Value StdLib::file_delete(const std::vector<Value> &args, VM *vm)
157{
158 checkArgCount(args, 1, "frm");
159 std::filesystem::path path = args[0].asString();
160 if (std::filesystem::exists(path))
161 {
162 std::filesystem::remove(path);
163 return true;
164 }
165 return false;
166}
167
168Value StdLib::file_rename(const std::vector<Value> &args, VM *vm)
169{
170 checkArgCount(args, 2, "frn");
171 std::filesystem::path src = args[0].asString();
172 std::string dest = args[1].asString();
173 if (std::filesystem::exists(src))
174 {
175 std::filesystem::rename(src, dest);
176 return true;
177 }
178 return false;
179}
180
181Value StdLib::file_current_directory(const std::vector<Value> &args, VM *vm)
182{
183 // If no arguments, return current directory
184 if (args.empty())
185 {
186 return std::filesystem::current_path().string();
187 }
188 checkArgCount(args, 1, "fcd");
189 std::filesystem::path dest = args[0].asString();
190 if (std::filesystem::exists(dest) && std::filesystem::is_directory(dest))
191 {
192 std::filesystem::current_path(dest);
193 return std::filesystem::current_path().string();
194 }
195
196 return false;
197}
198
199Value StdLib::file_copy(const std::vector<Value> &args, VM *vm)
200{
201 checkArgCount(args, 2, "fcp", true);
202 bool overwrite = false;
203 if (args.size() <= 3 && args.size() >= 2)
204 {
205 overwrite = args[2].asBool();
206 }
207 std::filesystem::path src = args[0].asString();
208 std::filesystem::path dest = args[1].asString();
209
210 if (!std::filesystem::exists(src))
211 {
212 vm->logerr("Source file doesn't exist.");
213 vm->flusherr();
214 return false;
215 }
216
217 if (std::filesystem::exists(dest) && !overwrite)
218 {
219 vm->logerr("Destination file already exists.");
220 vm->flusherr();
221 return false;
222 }
223
224 std::ifstream source(src, std::ios::binary | std::ios::in);
225 if (!source.is_open())
226 {
227 vm->logerr("Failed to open source file.");
228 vm->flusherr();
229 return false;
230 }
231
232 std::ofstream destination(dest, std::ios::binary | std::ios::out | std::ios::trunc);
233 if (!destination.is_open())
234 {
235 vm->logerr("Failed to open destination file.");
236 vm->flusherr();
237 return false;
238 }
239
240 destination << source.rdbuf();
241
242 if (source.fail() || destination.fail())
243 {
244 vm->logerr("Error during file copy.");
245 vm->flusherr();
246 return false;
247 }
248
249 return true;
250}
251
252Value StdLib::file_move(const std::vector<Value> &args, VM *vm)
253{
254 checkArgCount(args, 2, "fmv");
255 std::filesystem::path src = args[0].asString();
256 std::filesystem::path dest = args[1].asString();
257 bool status;
258 status = std::filesystem::copy_file(src, dest);
259 if (!status)
260 {
261 vm->logerr("Failed to copy file during move.");
262 vm->flusherr();
263 return false;
264 }
265 status = std::filesystem::remove(src);
266 return status;
267}
268
269Value StdLib::file_property_edit(const std::vector<Value> &args, VM *vm)
270{
271 checkArgCount(args, 3, "fpropedit");
272 if (args[2].isInt() && args[2].asInt() < 0)
273 {
274 throw std::runtime_error("epoch must be a non-negative integer");
275 }
276 std::filesystem::path path = args[0].asString();
277 char param = args[1].asString()[0];
278 int64_t epoch = args[2].asInt();
279 return PHASORstd_file_setProperties(const_cast<char *>(path.string().c_str()), param, epoch);
280}
281
282Value StdLib::file_property_get(const std::vector<Value> &args, VM *vm)
283{
284 checkArgCount(args, 2, "fpropget");
285 std::filesystem::path path = args[0].asString();
286 char param = args[1].asString()[0];
287 return PHASORstd_file_getProperties(const_cast<char *>(path.string().c_str()), param);
288}
289
290Value StdLib::file_create(const std::vector<Value> &args, VM *vm)
291{
292 checkArgCount(args, 1, "fcreate");
293 std::filesystem::path path = args[0].asString();
294 std::ofstream file(path);
295 if (!file.is_open())
296 {
297 throw std::runtime_error("Could not open file: " + path.string());
298 }
299 file.close();
300 return true;
301}
302
303Value StdLib::file_read_directory(const std::vector<Value> &args, VM *vm)
304{
305 checkArgCount(args, 1, "freaddir");
306 std::string path = args[0].asString();
307 std::string result;
308 try
309 {
310 for (const auto &entry : std::filesystem::directory_iterator(path))
311 {
312 if (!result.empty())
313 result += "\n";
314 result += entry.path().filename().string();
315 }
316 return result;
317 }
318 catch (const std::exception &e)
319 {
320 return Value(e.what()); // Return null on error
321 }
322}
323
324Value StdLib::file_statistics(const std::vector<Value> &args, VM *vm)
325{
326 checkArgCount(args, 1, "fstat");
327 std::string path = args[0].asString();
328 uid_t uid = 0;
329 gid_t gid = 0;
330 nlink_t nlink = PHASORstd_file_getLinksCount(path.c_str());
331 PHASORstd_file_getOwnerId(path.c_str(), &uid, &gid);
332 try
333 {
334 auto status = std::filesystem::status(path);
335 auto perms = status.permissions();
336
338 stat.structName = "FileStat";
339
340 // Convert permissions to mode_t style
341 int mode = 0;
342
343 // Set file type bits
344 if (std::filesystem::is_directory(status))
345 {
346 mode |= 0x4000; // Directory
347 }
348 else if (std::filesystem::is_symlink(status))
349 {
350 mode |= 0xA000; // Symbolic link
351 }
352 else
353 {
354 mode |= 0x8000; // Default to regular file
355 }
356
357 // Set permission bits
358 mode |= ((perms & std::filesystem::perms::owner_read) != std::filesystem::perms::none) ? 0x100 : 0;
359 mode |= ((perms & std::filesystem::perms::owner_write) != std::filesystem::perms::none) ? 0x80 : 0;
360 mode |= ((perms & std::filesystem::perms::owner_exec) != std::filesystem::perms::none) ? 0x40 : 0;
361 mode |= ((perms & std::filesystem::perms::group_read) != std::filesystem::perms::none) ? 0x20 : 0;
362 mode |= ((perms & std::filesystem::perms::group_write) != std::filesystem::perms::none) ? 0x10 : 0;
363 mode |= ((perms & std::filesystem::perms::group_exec) != std::filesystem::perms::none) ? 0x8 : 0;
364 mode |= ((perms & std::filesystem::perms::others_read) != std::filesystem::perms::none) ? 0x4 : 0;
365 mode |= ((perms & std::filesystem::perms::others_write) != std::filesystem::perms::none) ? 0x2 : 0;
366 mode |= ((perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none) ? 0x1 : 0;
367
368 // Set file stats
369 stat.fields["mode"] = Value(static_cast<int64_t>(mode));
370 stat.fields["nlink"] = Value(static_cast<int64_t>(nlink));
371 stat.fields["uid"] = Value(static_cast<int64_t>(uid));
372 stat.fields["gid"] = Value(static_cast<int64_t>(gid));
373 stat.fields["size"] = Value(static_cast<int64_t>(std::filesystem::file_size(path)));
374
375 return Value(std::make_shared<Value::StructInstance>(std::move(stat)));
376 }
377 catch (const std::exception &e)
378 {
379 vm->logerr(std::format("fstat error: {}", e.what()));
380 vm->flusherr();
381 return Value(); // Return null on error
382 }
383}
384
385Value StdLib::file_create_directory(const std::vector<Value> &args, VM *vm)
386{
387 checkArgCount(args, 1, "fmkdir");
388 std::filesystem::path path = args[0].asString();
389 if (std::filesystem::exists(path))
390 return false;
391 std::filesystem::create_directory(path);
392 return true;
393}
394
395Value StdLib::file_remove_directory(const std::vector<Value> &args, VM *vm)
396{
397 checkArgCount(args, 2, "frmdir");
398 std::filesystem::path path = args[0].asString();
399 bool recursive = args[1].asBool();
400 if (std::filesystem::exists(path))
401 {
402 if (recursive)
403 {
404 if (std::filesystem::remove_all(path) > 0)
405 return true;
406 else
407 return false;
408 } else {
409 return std::filesystem::remove(path);
410 }
411 }
412 return true;
413}
414} // namespace Phasor
static Value file_current_directory(const std::vector< Value > &args, VM *vm)
Get/set working directory.
Definition file.cpp:181
static Value file_write_line(const std::vector< Value > &args, VM *vm)
Write a line to file.
Definition file.cpp:74
static Value file_read_line(const std::vector< Value > &args, VM *vm)
Read a line from file.
Definition file.cpp:55
static void registerFileFunctions(VM *vm)
Definition file.cpp:10
static Value file_absolute(const std::vector< Value > &args, VM *vm)
Get full path to relative path.
Definition file.cpp:33
static Value file_remove_directory(const std::vector< Value > &args, VM *vm)
Definition file.cpp:395
static Value file_rename(const std::vector< Value > &args, VM *vm)
Rename file.
Definition file.cpp:168
static Value file_property_get(const std::vector< Value > &args, VM *vm)
Definition file.cpp:282
static Value file_exists(const std::vector< Value > &args, VM *vm)
Check if file exists.
Definition file.cpp:137
static void checkArgCount(const std::vector< Value > &args, size_t minimumArguments, const std::string &name, bool allowMoreArguments=false)
Definition StdLib.cpp:44
static Value file_read_directory(const std::vector< Value > &args, VM *vm)
Definition file.cpp:303
static Value file_property_edit(const std::vector< Value > &args, VM *vm)
Definition file.cpp:269
static Value file_read(const std::vector< Value > &args, VM *vm)
Read file.
Definition file.cpp:41
static Value file_delete(const std::vector< Value > &args, VM *vm)
Delete file.
Definition file.cpp:156
static Value file_statistics(const std::vector< Value > &args, VM *vm)
Definition file.cpp:324
static Value file_copy(const std::vector< Value > &args, VM *vm)
Copy file.
Definition file.cpp:199
static Value file_create_directory(const std::vector< Value > &args, VM *vm)
Definition file.cpp:385
static Value file_write(const std::vector< Value > &args, VM *vm)
Write to file.
Definition file.cpp:124
static Value file_create(const std::vector< Value > &args, VM *vm)
Definition file.cpp:290
static Value file_append(const std::vector< Value > &args, VM *vm)
Append to file.
Definition file.cpp:143
static Value file_move(const std::vector< Value > &args, VM *vm)
Move file.
Definition file.cpp:252
Virtual Machine.
Definition VM.hpp:30
void logerr(const Value &msg)
Log a Value to stderr.
Definition Utility.cpp:182
void registerNativeFunction(const std::string &name, NativeFunction fn)
Register a native function.
Definition Native.cpp:5
void flusherr()
Flush stderr.
Definition Utility.cpp:193
A value in the Phasor VM.
Definition Value.hpp:67
nlink_t PHASORstd_file_getLinksCount(const char *path)
Retrieves the number of hard links to a file.
int64_t PHASORstd_file_getProperties(char *path, char param)
Get file metadata time property.
bool PHASORstd_file_getOwnerId(const char *path, uid_t *uid, gid_t *gid)
Retrieves the owner identifier of a file.
bool PHASORstd_file_setProperties(char *path, char param, int64_t epoch)
Set file metadata time property.
The Phasor Programming Language and Runtime.
Definition AST.hpp:11
std::unordered_map< std::string, Value > fields
Definition Value.hpp:72