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