forked from ground/ground
Simple file and request libraries
This commit is contained in:
43
extlibs/file.cpp
Normal file
43
extlibs/file.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include "ground_lib.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
GroundValue readFile(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_1(GROUND_STRING);
|
||||||
|
|
||||||
|
std::ifstream ffile(GET_STRING(args[0]));
|
||||||
|
|
||||||
|
std::string tmp;
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
while (std::getline(ffile, tmp)) {
|
||||||
|
out += tmp + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ground_string_val(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue writeFile(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_2(GROUND_STRING, GROUND_STRING);
|
||||||
|
|
||||||
|
std::ofstream file(GET_STRING(args[0]));
|
||||||
|
if (file.good()) {
|
||||||
|
file << GET_STRING(args[1]);
|
||||||
|
} else {
|
||||||
|
std::cout << "File isn't good for writing in" << std::endl;
|
||||||
|
return GROUND_BOOL_VAL(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GROUND_BOOL_VAL(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
GROUND_LIBRARY_INTERFACE()
|
||||||
|
|
||||||
|
GROUND_LIBRARY_INIT()
|
||||||
|
REGISTER_GROUND_FUNCTION(readFile);
|
||||||
|
REGISTER_GROUND_FUNCTION(writeFile);
|
||||||
|
GROUND_LIBRARY_INIT_END()
|
||||||
|
|
||||||
|
GROUND_LIBRARY_CLEANUP()
|
||||||
|
GROUND_LIBRARY_CLEANUP_END()
|
193
extlibs/ground_lib.h
Normal file
193
extlibs/ground_lib.h
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
#ifndef GROUND_LIB_H
|
||||||
|
#define GROUND_LIB_H
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// Ground types - must match the interpreter
|
||||||
|
typedef enum {
|
||||||
|
GROUND_INT,
|
||||||
|
GROUND_DOUBLE,
|
||||||
|
GROUND_BOOL,
|
||||||
|
GROUND_STRING,
|
||||||
|
GROUND_CHAR
|
||||||
|
} GroundType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GroundType type;
|
||||||
|
union {
|
||||||
|
int int_val;
|
||||||
|
double double_val;
|
||||||
|
int bool_val;
|
||||||
|
char* string_val;
|
||||||
|
char char_val;
|
||||||
|
} data;
|
||||||
|
} GroundValue;
|
||||||
|
|
||||||
|
// Helper macros for creating GroundValue objects
|
||||||
|
#define GROUND_INT_VAL(x) ({ GroundValue v; v.type = GROUND_INT; v.data.int_val = (x); v; })
|
||||||
|
#define GROUND_DOUBLE_VAL(x) ({ GroundValue v; v.type = GROUND_DOUBLE; v.data.double_val = (x); v; })
|
||||||
|
#define GROUND_BOOL_VAL(x) ({ GroundValue v; v.type = GROUND_BOOL; v.data.bool_val = (x) ? 1 : 0; v; })
|
||||||
|
#define GROUND_CHAR_VAL(x) ({ GroundValue v; v.type = GROUND_CHAR; v.data.char_val = (x); v; })
|
||||||
|
|
||||||
|
// Helper function for creating string values
|
||||||
|
inline GroundValue ground_string_val(const std::string& str) {
|
||||||
|
GroundValue v;
|
||||||
|
v.type = GROUND_STRING;
|
||||||
|
char* result_str = new char[str.length() + 1];
|
||||||
|
std::strcpy(result_str, str.c_str());
|
||||||
|
v.data.string_val = result_str;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function for creating string values from C strings
|
||||||
|
inline GroundValue ground_cstring_val(const char* str) {
|
||||||
|
GroundValue v;
|
||||||
|
v.type = GROUND_STRING;
|
||||||
|
if (str) {
|
||||||
|
size_t len = std::strlen(str);
|
||||||
|
char* result_str = new char[len + 1];
|
||||||
|
std::strcpy(result_str, str);
|
||||||
|
v.data.string_val = result_str;
|
||||||
|
} else {
|
||||||
|
v.data.string_val = nullptr;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper macros for type checking
|
||||||
|
#define IS_INT(v) ((v).type == GROUND_INT)
|
||||||
|
#define IS_DOUBLE(v) ((v).type == GROUND_DOUBLE)
|
||||||
|
#define IS_BOOL(v) ((v).type == GROUND_BOOL)
|
||||||
|
#define IS_STRING(v) ((v).type == GROUND_STRING)
|
||||||
|
#define IS_CHAR(v) ((v).type == GROUND_CHAR)
|
||||||
|
|
||||||
|
// Helper macros for extracting values
|
||||||
|
#define GET_INT(v) ((v).data.int_val)
|
||||||
|
#define GET_DOUBLE(v) ((v).data.double_val)
|
||||||
|
#define GET_BOOL(v) ((v).data.bool_val != 0)
|
||||||
|
#define GET_STRING(v) ((v).data.string_val)
|
||||||
|
#define GET_CHAR(v) ((v).data.char_val)
|
||||||
|
|
||||||
|
// Helper macros for argument validation
|
||||||
|
#define REQUIRE_ARGS(count) \
|
||||||
|
if (arg_count < (count)) { \
|
||||||
|
std::cerr << "Error: Expected at least " << (count) << " arguments, got " << arg_count << std::endl; \
|
||||||
|
return GROUND_BOOL_VAL(false); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define REQUIRE_TYPE(arg_index, expected_type) \
|
||||||
|
if (args[arg_index].type != expected_type) { \
|
||||||
|
std::cerr << "Error: Argument " << (arg_index + 1) << " must be of type " << #expected_type << std::endl; \
|
||||||
|
return GROUND_BOOL_VAL(false); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience macro for checking both arg count and types
|
||||||
|
#define VALIDATE_ARGS_1(type1) \
|
||||||
|
REQUIRE_ARGS(1); \
|
||||||
|
REQUIRE_TYPE(0, type1);
|
||||||
|
|
||||||
|
#define VALIDATE_ARGS_2(type1, type2) \
|
||||||
|
REQUIRE_ARGS(2); \
|
||||||
|
REQUIRE_TYPE(0, type1); \
|
||||||
|
REQUIRE_TYPE(1, type2);
|
||||||
|
|
||||||
|
#define VALIDATE_ARGS_3(type1, type2, type3) \
|
||||||
|
REQUIRE_ARGS(3); \
|
||||||
|
REQUIRE_TYPE(0, type1); \
|
||||||
|
REQUIRE_TYPE(1, type2); \
|
||||||
|
REQUIRE_TYPE(2, type3);
|
||||||
|
|
||||||
|
// Function registration helpers
|
||||||
|
class GroundLibrary {
|
||||||
|
private:
|
||||||
|
std::vector<std::string> function_names;
|
||||||
|
std::vector<void*> function_pointers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void register_function(const std::string& name, void* ptr) {
|
||||||
|
function_names.push_back(name);
|
||||||
|
function_pointers.push_back(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char** get_function_names() {
|
||||||
|
static std::vector<const char*> names;
|
||||||
|
names.clear();
|
||||||
|
for (const auto& name : function_names) {
|
||||||
|
names.push_back(name.c_str());
|
||||||
|
}
|
||||||
|
names.push_back(nullptr); // Null terminator
|
||||||
|
return names.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* get_function(const char* name) {
|
||||||
|
for (size_t i = 0; i < function_names.size(); i++) {
|
||||||
|
if (function_names[i] == name) {
|
||||||
|
return function_pointers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global library instance
|
||||||
|
extern GroundLibrary ground_lib_registry;
|
||||||
|
|
||||||
|
// Macro to register functions easily
|
||||||
|
#define REGISTER_GROUND_FUNCTION(func_name) \
|
||||||
|
ground_lib_registry.register_function(#func_name, (void*)func_name)
|
||||||
|
|
||||||
|
// Macro to define the library interface
|
||||||
|
#define GROUND_LIBRARY_INTERFACE() \
|
||||||
|
GroundLibrary ground_lib_registry; \
|
||||||
|
extern "C" { \
|
||||||
|
const char** ground_get_functions() { \
|
||||||
|
return ground_lib_registry.get_function_names(); \
|
||||||
|
} \
|
||||||
|
void* ground_get_function(const char* name) { \
|
||||||
|
return ground_lib_registry.get_function(name); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional initialization macro
|
||||||
|
#define GROUND_LIBRARY_INIT() \
|
||||||
|
extern "C" { \
|
||||||
|
void ground_lib_init() {
|
||||||
|
|
||||||
|
#define GROUND_LIBRARY_INIT_END() \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional cleanup macro
|
||||||
|
#define GROUND_LIBRARY_CLEANUP() \
|
||||||
|
extern "C" { \
|
||||||
|
void ground_lib_cleanup() {
|
||||||
|
|
||||||
|
#define GROUND_LIBRARY_CLEANUP_END() \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility function to print GroundValue for debugging
|
||||||
|
inline void debug_print_ground_value(const GroundValue& v) {
|
||||||
|
switch (v.type) {
|
||||||
|
case GROUND_INT:
|
||||||
|
std::cout << "INT: " << v.data.int_val << std::endl;
|
||||||
|
break;
|
||||||
|
case GROUND_DOUBLE:
|
||||||
|
std::cout << "DOUBLE: " << v.data.double_val << std::endl;
|
||||||
|
break;
|
||||||
|
case GROUND_BOOL:
|
||||||
|
std::cout << "BOOL: " << (v.data.bool_val ? "true" : "false") << std::endl;
|
||||||
|
break;
|
||||||
|
case GROUND_STRING:
|
||||||
|
std::cout << "STRING: " << (v.data.string_val ? v.data.string_val : "(null)") << std::endl;
|
||||||
|
break;
|
||||||
|
case GROUND_CHAR:
|
||||||
|
std::cout << "CHAR: '" << v.data.char_val << "'" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GROUND_LIB_H
|
45
extlibs/request.cpp
Normal file
45
extlibs/request.cpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#include "ground_lib.h"
|
||||||
|
|
||||||
|
#include <cpr/cpr.h>
|
||||||
|
#include <cpr/interface.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
GroundValue simpleRequest(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_1(GROUND_STRING);
|
||||||
|
|
||||||
|
cpr::Response r = cpr::Get(cpr::Url(GET_STRING(args[0])));
|
||||||
|
|
||||||
|
if (!(r.status_code >= 200 && r.status_code < 300)) {
|
||||||
|
return ground_string_val("Error code " + std::to_string(r.status_code));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ground_string_val(r.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue saveContents(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_2(GROUND_STRING, GROUND_STRING);
|
||||||
|
|
||||||
|
std::ofstream file(GET_STRING(args[1]), std::ios::binary);
|
||||||
|
|
||||||
|
if (file.good()) {
|
||||||
|
cpr::Response r = cpr::Download(file, cpr::Url{GET_STRING(args[0])});
|
||||||
|
|
||||||
|
if (r.status_code >= 200 && r.status_code < 300) {
|
||||||
|
return GROUND_BOOL_VAL(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return GROUND_BOOL_VAL(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GROUND_BOOL_VAL(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
GROUND_LIBRARY_INTERFACE()
|
||||||
|
|
||||||
|
GROUND_LIBRARY_INIT()
|
||||||
|
REGISTER_GROUND_FUNCTION(simpleRequest);
|
||||||
|
REGISTER_GROUND_FUNCTION(saveContents);
|
||||||
|
GROUND_LIBRARY_INIT_END()
|
||||||
|
|
||||||
|
GROUND_LIBRARY_CLEANUP()
|
||||||
|
GROUND_LIBRARY_CLEANUP_END()
|
Reference in New Issue
Block a user