REMOVED USER_STD macros, code formating, csv changes, few file functions

This commit is contained in:
VaclavT 2021-02-15 23:20:20 +01:00
parent 125c73ac33
commit c1532e78b1
15 changed files with 10550 additions and 2101 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ build
/cmake-build-debug/
.idea
ml
.DS_Store

View File

@ -20,6 +20,7 @@ set(PROJECT_NAME ml)
set(SOURCE
ml.cpp
ml_io.cpp
clib/csvparser.cpp
clib/sslclient.cpp
clib/json11.cpp)

View File

@ -1,13 +1,13 @@
### TODO
- support for strings with " included
- move system_cmd into ml_io
- logical operators
- documentation
- add url of source/inspiration to clib/*.cpp
- load std lib when starting
- add more command line args
- split into more files
- prejmenovat ivaluize
- add stdtest
- rename ivaluize
- add benchmark
- add some debug support??
- add instrumentation (time, nr of evals, debug info, debug environment etc)

View File

@ -12,11 +12,13 @@ CsvParser::CsvParser(bool skip_hdr, char field_sep, char quote_ch, char line_sep
header_skiped = false;
}
void CsvParser::parseCSV(const std::string &csvSource, std::vector< std::vector<std::string> > &lines) {
MlValue CsvParser::parseCSV(const std::string &csvSource) {
bool inQuote(false);
bool newLine(false);
std::string field;
lines.clear();
// PERF optimize it for memory usage and performance
std::vector<std::vector<std::string>> parsed_data; // TODO some default size here
std::vector<std::string> line;
std::string::const_iterator aChar = csvSource.begin();
@ -38,7 +40,7 @@ void CsvParser::parseCSV(const std::string &csvSource, std::vector< std::vector<
} else {
if (newLine == false) {
line.push_back(field);
addLine(line, lines);
addLine(line, parsed_data);
field.clear();
line.clear();
newLine = true;
@ -55,7 +57,9 @@ void CsvParser::parseCSV(const std::string &csvSource, std::vector< std::vector<
if (field.size())
line.push_back(field);
addLine(line, lines);
addLine(line, parsed_data);
return ivalualize(parsed_data);
}
MlValue CsvParser::ivalualize(std::vector<std::vector<std::string> > &parsed_data) const {

View File

@ -17,14 +17,17 @@ private:
bool header_skiped;
public:
CsvParser(bool skip_hdr = false, char field_sep = ',', char quote_ch = '"', char line_sep = '\r', char line_sep2 = '\n');
CsvParser(bool skip_hdr = false, char field_sep = ',', char quote_ch = '"', char line_sep = '\r',
char line_sep2 = '\n');
void parseCSV(const std::string &csvSource, std::vector< std::vector<std::string> > &lines);
MlValue parseCSV(const std::string &csvSource);
MlValue ivalualize(std::vector< std::vector<std::string> > &parsed_data) const;
private:
void addLine(const std::vector<std::string> &line, std::vector<std::vector<std::string> > &lines);
MlValue ivalualize(std::vector<std::vector<std::string> > &parsed_data) const;
bool is_string_int(const std::string &str) const;
bool is_string_float(const std::string &str) const;
};

8319
clib/date.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@ namespace json11 {
*/
struct NullStruct {
bool operator==(NullStruct) const { return true; }
bool operator<(NullStruct) const { return false; }
};
@ -177,34 +178,6 @@ namespace json11 {
}
/* * * * * * * * * * * * * * * * * * * *
* Value wrappers
*/
@ -215,6 +188,7 @@ namespace json11 {
// Constructors
explicit Value(const T &value) : m_value(value) {}
explicit Value(T &&value) : m_value(move(value)) {}
// Get type tag
@ -226,11 +200,13 @@ namespace json11 {
bool equals(const JsonValue *other) const override {
return m_value == static_cast<const Value<tag, T> *>(other)->m_value;
}
bool less(const JsonValue *other) const override {
return m_value < static_cast<const Value<tag, T> *>(other)->m_value;
}
const T m_value;
void dump(string &out) const override { json11::dump(m_value, out); }
MlValue ivalualize() const override { return json11::ivalualize(m_value); }
@ -238,48 +214,65 @@ namespace json11 {
class JsonDouble final : public Value<Json::NUMBER, double> {
double number_value() const override { return m_value; }
int int_value() const override { return static_cast<int>(m_value); }
bool equals(const JsonValue *other) const override { return m_value == other->number_value(); }
bool less(const JsonValue *other) const override { return m_value < other->number_value(); }
public:
explicit JsonDouble(double value) : Value(value) {}
};
class JsonInt final : public Value<Json::NUMBER, int> {
double number_value() const override { return m_value; }
int int_value() const override { return m_value; }
bool equals(const JsonValue *other) const override { return m_value == other->number_value(); }
bool less(const JsonValue *other) const override { return m_value < other->number_value(); }
public:
explicit JsonInt(int value) : Value(value) {}
};
class JsonBoolean final : public Value<Json::BOOL, bool> {
bool bool_value() const override { return m_value; }
public:
explicit JsonBoolean(bool value) : Value(value) {}
};
class JsonString final : public Value<Json::STRING, string> {
const string &string_value() const override { return m_value; }
public:
explicit JsonString(const string &value) : Value(value) {}
explicit JsonString(string &&value) : Value(move(value)) {}
};
class JsonArray final : public Value<Json::ARRAY, Json::array> {
const Json::array &array_items() const override { return m_value; }
const Json &operator[](size_t i) const override;
public:
explicit JsonArray(const Json::array &value) : Value(value) {}
explicit JsonArray(Json::array &&value) : Value(move(value)) {}
};
class JsonObject final : public Value<Json::OBJECT, Json::object> {
const Json::object &object_items() const override { return m_value; }
const Json &operator[](const string &key) const override;
public:
explicit JsonObject(const Json::object &value) : Value(value) {}
explicit JsonObject(Json::object &&value) : Value(move(value)) {}
};
@ -298,6 +291,7 @@ namespace json11 {
const string empty_string;
const vector<Json> empty_vector;
const map<string, Json> empty_map;
Statics() {}
};
@ -317,16 +311,27 @@ namespace json11 {
*/
Json::Json() noexcept: m_ptr(statics().null) {}
Json::Json(std::nullptr_t) noexcept: m_ptr(statics().null) {}
Json::Json(double value) : m_ptr(make_shared<JsonDouble>(value)) {}
Json::Json(int value) : m_ptr(make_shared<JsonInt>(value)) {}
Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
Json::Json(const string &value) : m_ptr(make_shared<JsonString>(value)) {}
Json::Json(string &&value) : m_ptr(make_shared<JsonString>(move(value))) {}
Json::Json(const char *value) : m_ptr(make_shared<JsonString>(value)) {}
Json::Json(const Json::array &values) : m_ptr(make_shared<JsonArray>(values)) {}
Json::Json(Json::array &&values) : m_ptr(make_shared<JsonArray>(move(values))) {}
Json::Json(const Json::object &values) : m_ptr(make_shared<JsonObject>(values)) {}
Json::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(move(values))) {}
/* * * * * * * * * * * * * * * * * * * *
@ -334,28 +339,44 @@ namespace json11 {
*/
Json::Type Json::type() const { return m_ptr->type(); }
double Json::number_value() const { return m_ptr->number_value(); }
int Json::int_value() const { return m_ptr->int_value(); }
bool Json::bool_value() const { return m_ptr->bool_value(); }
const string &Json::string_value() const { return m_ptr->string_value(); }
const vector<Json> &Json::array_items() const { return m_ptr->array_items(); }
const map<string, Json> &Json::object_items() const { return m_ptr->object_items(); }
const Json &Json::operator[](size_t i) const { return (*m_ptr)[i]; }
const Json &Json::operator[](const string &key) const { return (*m_ptr)[key]; }
double JsonValue::number_value() const { return 0; }
int JsonValue::int_value() const { return 0; }
bool JsonValue::bool_value() const { return false; }
const string &JsonValue::string_value() const { return statics().empty_string; }
const vector<Json> &JsonValue::array_items() const { return statics().empty_vector; }
const map<string, Json> &JsonValue::object_items() const { return statics().empty_map; }
const Json &JsonValue::operator[](size_t) const { return static_null(); }
const Json &JsonValue::operator[](const string &) const { return static_null(); }
const Json &JsonObject::operator[](const string &key) const {
auto iter = m_value.find(key);
return (iter == m_value.end()) ? static_null() : iter->second;
}
const Json &JsonArray::operator[](size_t i) const {
if (i >= m_value.size()) return static_null();
else return m_value[i];
@ -462,8 +483,7 @@ namespace json11 {
i++;
}
comment_found = true;
}
else if (str[i] == '*') { // multiline comment
} else if (str[i] == '*') { // multiline comment
i++;
if (i > str.size() - 2)
return fail("unexpected end of input inside multi-line comment", false);
@ -476,8 +496,7 @@ namespace json11 {
}
i += 2;
comment_found = true;
}
else
} else
return fail("malformed comment", false);
}
return comment_found;
@ -495,8 +514,7 @@ namespace json11 {
comment_found = consume_comment();
if (failed) return;
consume_whitespace();
}
while(comment_found);
} while (comment_found);
}
}
@ -699,7 +717,8 @@ namespace json11 {
i += expected.length();
return res;
} else {
return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
return fail(
"parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
}
}

View File

@ -66,34 +66,45 @@ namespace json11 {
Type type() const;
bool is_null() const { return type() == NUL; }
bool is_number() const { return type() == NUMBER; }
bool is_bool() const { return type() == BOOL; }
bool is_string() const { return type() == STRING; }
bool is_array() const { return type() == ARRAY; }
bool is_object() const { return type() == OBJECT; }
// Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not
// distinguish between integer and non-integer numbers - number_value() and int_value()
// can both be applied to a NUMBER-typed object.
double number_value() const;
int int_value() const;
// Return the enclosed value if this is a boolean, false otherwise.
bool bool_value() const;
// Return the enclosed string if this is a string, "" otherwise.
const std::string &string_value() const;
// Return the enclosed std::vector if this is an array, or an empty vector otherwise.
const array &array_items() const;
// Return the enclosed std::map if this is an object, or an empty map otherwise.
const object &object_items() const;
// Return a reference to arr[i] if this is an array, Json() otherwise.
const Json &operator[](size_t i) const;
// Return a reference to obj[key] if this is an object, Json() otherwise.
const Json &operator[](const std::string &key) const;
// Serialize.
void dump(std::string &out) const;
std::string dump() const {
std::string out;
dump(out);
@ -106,6 +117,7 @@ namespace json11 {
static Json parse(const std::string &in,
std::string &err,
JsonParse strategy = JsonParse::STANDARD);
static Json parse(const char *in,
std::string &err,
JsonParse strategy = JsonParse::STANDARD) {
@ -116,6 +128,7 @@ namespace json11 {
return nullptr;
}
}
// Parse multiple objects, concatenated or separated by whitespace
static std::vector<Json> parse_multi(
const std::string &in,
@ -132,10 +145,15 @@ namespace json11 {
}
bool operator==(const Json &rhs) const;
bool operator<(const Json &rhs) const;
bool operator!=(const Json &rhs) const { return !(*this == rhs); }
bool operator<=(const Json &rhs) const { return !(rhs < *this); }
bool operator>(const Json &rhs) const { return (rhs < *this); }
bool operator>=(const Json &rhs) const { return !(*this < rhs); }
/* has_shape(types, err)
@ -144,6 +162,7 @@ namespace json11 {
* the given type. If not, return false and set err to a descriptive message.
*/
typedef std::initializer_list<std::pair<std::string, Type>> shape;
bool has_shape(const shape &types, std::string &err) const;
private:
@ -154,21 +173,37 @@ namespace json11 {
class JsonValue {
protected:
friend class Json;
friend class JsonInt;
friend class JsonDouble;
virtual Json::Type type() const = 0;
virtual bool equals(const JsonValue *other) const = 0;
virtual bool less(const JsonValue *other) const = 0;
virtual void dump(std::string &out) const = 0;
virtual MlValue ivalualize() const = 0;
virtual double number_value() const;
virtual int int_value() const;
virtual bool bool_value() const;
virtual const std::string &string_value() const;
virtual const Json::array &array_items() const;
virtual const Json &operator[](size_t i) const;
virtual const Json::object &object_items() const;
virtual const Json &operator[](const std::string &key) const;
virtual ~JsonValue() {}
};

View File

@ -19,7 +19,8 @@
HttpClient::HttpClient() {};
std::pair<int, std::string> HttpClient::doGetRequest(const std::string &url, const std::unordered_map<std::string, std::string> &headers) {
std::pair<int, std::string>
HttpClient::doGetRequest(const std::string &url, const std::unordered_map<std::string, std::string> &headers) {
// https://stackoverflow.com/questions/25896916/parse-http-headers-in-c
std::regex rgx{R"(^(?:((?:https?|s?ftp):)//)([^:/\s]+)(?::(\d*))?(?:/([^\s?#]+)?([?][^?#]*)?(#.*)?)?)"};

View File

@ -20,13 +20,17 @@ private:
public:
HttpClient();
std::pair<int, std::string> doGetRequest(const std::string &url, const std::unordered_map<std::string, std::string> &headers);
std::pair<int, std::string>
doGetRequest(const std::string &url, const std::unordered_map<std::string, std::string> &headers);
private:
std::string inetAddress(std::string hostname);
int sslRecvPacket();
int sslSendPacket(std::string buf);
int sslRequest(const std::string &server_name, const std::string &request);
void log_ssl();
};

View File

@ -61,8 +61,15 @@
(define pdate (second (first (filter (lambda (x) (= (first x) "payment_Date")) e))))
(define rdate (second (first (filter (lambda (x) (= (first x) "record_Date")) e))))
(print symbol edate pdate divrate)
;(print symbol edate pdate divrate)
'(symbol edate pdate divrate)
)
(print (ls-dir "/tmp"))
(print (is-file? "/tmp/file"))
(print (is-file? "/tmp/hovinko"))
(print (is-dir? "/tmp/powerlog"))
(print "Debug ends")

134
ml.cpp
View File

@ -1,39 +1,23 @@
// Comment this define out to drop support for standard library functions.
// This allows the program to run without a runtime.
#ifdef HAS_LIBM
#include <cmath>
#else
#define NO_LIBM_SUPPORT "no libm support"
#endif
#include "ml.h"
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <exception>
#ifdef USE_STD
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <ctime>
#endif
#include "ml_io.h"
#include "csvparser.h"
#include "sslclient.h"
#include "json11.h"
#include <cmath>
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <ctime>
#define TOO_FEW_ARGS "too few arguments to function"
#define TOO_MANY_ARGS "too many arguments to function"
#define INVALID_ARGUMENT "invalid argument"
@ -62,29 +46,6 @@
#ifdef USE_STD
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");
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;
}
#else
#define NO_STD "no standard library support"
#endif
// Convert an object to a string using a stringstream conveniently
#define to_string(x) static_cast<std::ostringstream>((std::ostringstream() << std::dec << x )).str()
@ -103,8 +64,6 @@ bool is_symbol(char ch) {
}
MlValue::MlValue() : type(UNIT) {}
MlValue::MlValue(int i) : type(INT) { stack_data.i = i; }
@ -526,21 +485,12 @@ MlValue MlValue::operator%(const MlValue &other) const {
switch (type) {
// If we support libm, we can find the remainder of floating point values.
#ifdef HAS_LIBM
case FLOAT:
return MlValue(fmod(stack_data.f, other.cast_to_float().stack_data.f));
case INT:
if (other.type == FLOAT)
return MlValue(fmod(cast_to_float().stack_data.f, other.stack_data.f));
else return MlValue(stack_data.i % other.stack_data.i);
#else
case INT:
// If we do not support libm, we have to throw errors for floating point values.
if (other.type != INT)
throw MlError(other, MlEnvironment(), NO_LIBM_SUPPORT);
return MlValue(stack_data.i % other.stack_data.i);
#endif
case UNIT:
// Unit types consume all arithmetic operations.
return *this;
@ -1026,7 +976,6 @@ namespace builtin {
return MlValue(v);
}
#ifdef USE_STD
// Exit the program with an integer code
MlValue exit(std::vector<MlValue> args, MlEnvironment &env) {
@ -1089,12 +1038,8 @@ namespace builtin {
if (args.size() != 1)
throw MlError(MlValue("parse-csv", parse_csv), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
// PERF optimize it for memory usage and performance
CsvParser csv(true);
std::vector<std::vector<std::string> > parsed_data; // TODO some default size here
csv.parseCSV(args[0].as_string(), parsed_data);
return csv.ivalualize(parsed_data);
return csv.parseCSV(args[0].as_string());
}
// Get the contents of a file
@ -1112,7 +1057,8 @@ namespace builtin {
eval_args(args, env);
if (args.size() != 2)
throw MlError(MlValue("write-file", write_file), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
throw MlError(MlValue("write-file", write_file), env,
args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
std::ofstream f;
// The first argument is the file name
@ -1177,7 +1123,8 @@ namespace builtin {
// TODO add support for more params constructing options as one string
// TODO add support for stderr
if (args.size() != 1)
throw MlError(MlValue("system-cmd", system_cmd), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
throw MlError(MlValue("system-cmd", system_cmd), env,
args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
std::string cmd = args[0].as_string();
@ -1211,6 +1158,37 @@ namespace builtin {
return lst;
}
// list directory
MlValue ls_dir(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
if (args.size() != 1)
throw MlError(MlValue("ls-dir", ls_dir), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
return list_dir(args[0].as_string());
}
// is_path file
MlValue is_file(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
// TODO add suppor for more params and list params
if (args.size() != 1)
throw MlError(MlValue("is-file?", is_file), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
return MlValue(is_path_file(args[0].as_string()));
}
// is_path directory
MlValue is_dir(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
// TODO add suppor for more params and list params
if (args.size() != 1)
throw MlError(MlValue("is-dir?", is_dir), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
return MlValue(is_path_dir(args[0].as_string()));
}
// Read a file and execute its code
MlValue include(std::vector<MlValue> args, MlEnvironment &env) {
@ -1227,7 +1205,6 @@ namespace builtin {
return result;
}
#endif
// Evaluate a value as code
MlValue eval(std::vector<MlValue> args, MlEnvironment &env) {
@ -1367,7 +1344,8 @@ namespace builtin {
eval_args(args, env);
if (args.size() != 1)
throw MlError(MlValue(FLOAT_TYPE, cast_to_float), env, args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
throw MlError(MlValue(FLOAT_TYPE, cast_to_float), env,
args.size() > 1 ? TOO_MANY_ARGS : TOO_FEW_ARGS);
return args[0].cast_to_float();
}
@ -1590,7 +1568,6 @@ namespace builtin {
}
void repl(MlEnvironment &env) {
#ifdef USE_STD
std::string code;
std::string input;
MlValue tmp;
@ -1622,7 +1599,6 @@ void repl(MlEnvironment &env) {
}
}
}
#endif
}
// Does this environment, or its parent environment, have a variable?
@ -1694,7 +1670,6 @@ MlValue MlEnvironment::get(const std::string& name) const {
if (name == "reduce") return MlValue("reduce", builtin::reduce_list);
// IO operations
#ifdef USE_STD
if (name == "exit") return MlValue("exit", builtin::exit);
if (name == "quit") return MlValue("quit", builtin::exit);
if (name == "print") return MlValue("print", builtin::print);
@ -1707,7 +1682,9 @@ MlValue MlEnvironment::get(const std::string& name) const {
if (name == "read-url") return MlValue("read-url", builtin::read_url);
if (name == "read-json") return MlValue("read-json", builtin::read_json);
if (name == "system-cmd") return MlValue("system-cmd", builtin::system_cmd);
#endif
if (name == "ls-dir") return MlValue("ls-dir", builtin::ls_dir);
if (name == "is-file?") return MlValue("is-file?", builtin::is_file);
if (name == "is-dir?") return MlValue("is-der?", builtin::is_dir);
// String operations
if (name == "debug") return MlValue("debug", builtin::debug);
@ -1749,7 +1726,6 @@ int main(int argc, const char **argv) {
args.push_back(MlValue::string(argv[i]));
env.set("cmd-args", MlValue(args));
#ifdef USE_STD
srand(time(NULL));
try {
// Load std library
@ -1767,10 +1743,6 @@ int main(int argc, const char **argv) {
} catch (std::runtime_error &e) {
std::cerr << e.what() << std::endl;
}
#else
if (argc == 3 && std::string(argv[1]) == "-c")
run(argv[2], env);
#endif
return 0;
}

20
ml.h
View File

@ -1,11 +1,5 @@
#pragma once
// Comment this define out to drop support for standard library functions.
// This allows the program to run without a runtime.
#define USE_STD
// Comment this define out to drop support for libm functions
#define HAS_LIBM
#include <map>
#include <string>
@ -14,7 +8,7 @@
#include <exception>
// // Forward declaration for MlEnvironment class definition
// Forward declaration for MlEnvironment class definition
class MlValue;
@ -29,8 +23,10 @@ public:
// This is only used to determine which atoms to capture when
// creating a lambda function.
bool has(std::string name) const;
// Get the value associated with this name in this scope
MlValue get(const std::string &name) const;
// Set the value associated with this name in this scope
void set(std::string name, MlValue value);
@ -42,6 +38,7 @@ public:
// Output this scope in readable form to a stream.
friend std::ostream &operator<<(std::ostream &os, MlEnvironment const &v);
private:
// The definitions in the scope.
@ -50,20 +47,21 @@ private:
};
// An exception thrown by the lisp
class MlError {
public:
// Create an error with the value that caused the error,
// the scope where the error was found, and the message.
MlError(const MlValue &v, MlEnvironment const &env, const char *msg);
// Copy constructor is needed to prevent double frees
MlError(MlError const &other);
~MlError();
// Get the printable error description.
std::string description();
private:
MlValue *cause;
MlEnvironment env;
@ -71,7 +69,6 @@ private:
};
// The type for a builtin function, which takes a list of values,
// and the environment to run the function in.
typedef MlValue (*Builtin)(std::vector<MlValue>, MlEnvironment &);
@ -85,8 +82,10 @@ typedef MlValue (*Builtin)(std::vector<MlValue>, MlEnvironment &);
// Constructs an integer
MlValue(int i);
// Constructs a floating point value
MlValue(double f);
// Constructs a list
MlValue(const std::vector<MlValue> &list);
@ -112,6 +111,7 @@ typedef MlValue (*Builtin)(std::vector<MlValue>, MlEnvironment &);
// Apply this as a function to a list of arguments in a given environment.
MlValue apply(std::vector<MlValue> args, MlEnvironment &env);
// Evaluate this value as lisp code.
MlValue eval(MlEnvironment &env);

62
ml_io.cpp Normal file
View File

@ -0,0 +1,62 @@
#include "ml_io.h"
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
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");
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;
}
MlValue list_dir(const std::string &path) {
std::vector<MlValue> entries;
DIR *dirp = opendir(path.c_str());
if (dirp == NULL) {
// handle error - probably not a dir or non existing 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) {
std::ifstream ifile(path.c_str());
return (bool) ifile;
}
bool is_path_dir(const std::string &path) {
struct stat buf;
stat(path.c_str(), &buf);
return (bool) S_ISDIR(buf.st_mode);
}
int mk_dir(const std::string &path) {
int r = ::mkdir(path.c_str(), 0755);
return r;
}
int rm_dir(const std::string &path) {
int r = ::rmdir(path.c_str());
return r;
}

21
ml_io.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include "../ml.h"
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
std::string read_file_contents(const std::string &filename);
MlValue list_dir(const std::string &path);
bool is_path_file(const std::string &path);
bool is_path_dir(const std::string &path);
int mk_dir(const std::string &path);
int rm_dir(const std::string &path);