mlisp/ml_io.cpp

143 lines
3.6 KiB
C++

#include "ml_io.h"
#include <cstring>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <iostream>
#include <fstream>
std::string read_file_contents(const std::string &filename) {
std::ifstream f;
f.open(filename.c_str());
if (!f)
throw std::runtime_error("could not open file (" + filename + ")");
f.seekg(0, std::ios::end);
std::string contents;
contents.reserve(f.tellg());
f.seekg(0, std::ios::beg);
contents.assign(std::istreambuf_iterator<char>(f),
std::istreambuf_iterator<char>());
f.close();
return contents;
}
bool write_file_contents(const std::string &filename, const std::string &content) {
std::ofstream f(filename.c_str());
if (f) {
f << content;
f.close();
return true;
}
return false;
}
MlValue list_dir(const std::string &path) {
std::vector<MlValue> entries;
DIR *dirp = opendir(path.c_str());
if (dirp == NULL) {
throw std::runtime_error("could not open dir (" + path + ")");
}
struct dirent *dp;
while ((dp = readdir(dirp)) != NULL) {
entries.push_back(MlValue::string(dp->d_name));
}
closedir(dirp);
return MlValue(entries);
}
bool is_path_file(const std::string &path) {
struct stat buf{};
stat(path.c_str(), &buf);
return (bool) S_ISREG(buf.st_mode) ||
(bool) S_ISBLK(buf.st_mode) ||
(bool) S_ISCHR(buf.st_mode) ||
(bool) S_ISFIFO(buf.st_mode) ||
(bool) S_ISSOCK(buf.st_mode);
}
bool is_path_dir(const std::string &path) {
struct stat buf{};
stat(path.c_str(), &buf);
return (bool) S_ISDIR(buf.st_mode);
}
bool mk_path_dir(const std::string &path) {
auto r = ::mkdir(path.c_str(), 0755);
if (r == -1) {
std::string err_msg = std::strerror(errno);
std::cerr << "mkdir failed: " << std::strerror(errno) << std::endl;
}
return r == 0;
}
bool rm_path_dir(const std::string &path) {
auto r = ::rmdir(path.c_str());
if (r == -1) {
std::string err_msg = std::strerror(errno);
std::cerr << "rmdir failed: " << std::strerror(errno) << std::endl;
}
return r == 0;
}
MlValue exec_system_cmd(const std::string &cmd) {
// TODO handle reading of stderr
// https://stackoverflow.com/questions/478898/how-do-i-execute-a-command-and-get-the-output-of-the-command-within-c-using-po
// https://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/
std::string cmd_output;
int stat;
char buffer[128];
FILE *pipe = popen(cmd.c_str(), "r");
if (!pipe)
throw std::runtime_error("popen() failed!");
try {
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != nullptr)
cmd_output += buffer;
}
} catch (...) {
stat = pclose(pipe);
throw;
}
stat = pclose(pipe);
int cmd_retval = WEXITSTATUS(stat);
return std::vector<MlValue> { MlValue((long)cmd_retval), MlValue::string(cmd_output) };
}
MlValue exec_system_cmd_fork(const std::vector<std::string> &args) {
int pid = fork();
if (pid == 0) {
// Child process, execute the command
std::vector<char*> exec_args;
exec_args.reserve(args.size());
for (auto const& a : args)
exec_args.emplace_back(const_cast<char*>(a.c_str()));
exec_args.push_back(nullptr); // exec must end with null
execvp(args[0].c_str(), exec_args.data());
std::cerr << "execvp error: " << errno << ", " << strerror(errno) << std::endl;
exit(1); // indicate error, if here
} else if (pid > 0) {
// Parent process, child process is now independent
return std::vector<MlValue> { MlValue((long)0), MlValue::string("") };
} else {
// Fork error, still in parent process (there are no child process at this point)
return std::vector<MlValue> { MlValue((long)errno), MlValue::string(strerror(errno) ) };
}
}