forked from ground/ground
Organisation, documentation, mathlib
This commit is contained in:
9
extlibs/compiling.md
Normal file
9
extlibs/compiling.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
## Compiling External Libraries
|
||||||
|
|
||||||
|
On Linux:
|
||||||
|
|
||||||
|
`g++ -shared -fPIC -o filename.so filename.cpp`
|
||||||
|
|
||||||
|
On macOS:
|
||||||
|
|
||||||
|
`g++ -shared -fPIC -o filename.dylib filename.cpp`
|
9
extlibs/exec/README.md
Normal file
9
extlibs/exec/README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# exec library
|
||||||
|
|
||||||
|
This library allows executing third party executables via the C++ "system" command.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
### fun -int !exec -string &command
|
||||||
|
|
||||||
|
Runs a command on a system. Returns the status code of that command.
|
193
extlibs/exec/ground_lib.h
Normal file
193
extlibs/exec/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
|
13
extlibs/file/README.md
Normal file
13
extlibs/file/README.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# file library
|
||||||
|
|
||||||
|
This library allows reading from and writing to files on the system.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
### fun -string !readFile -string &fileName
|
||||||
|
|
||||||
|
This function reads all content from a file and returns it.
|
||||||
|
|
||||||
|
### fun -bool !writeFile -string &fileName -string &content
|
||||||
|
|
||||||
|
This function overwrites a file with specified content. If successful, returns true. If not successful, returns false, and prints out a reason why it didn't work.
|
193
extlibs/file/ground_lib.h
Normal file
193
extlibs/file/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/math/README.md
Normal file
45
extlibs/math/README.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# math library
|
||||||
|
|
||||||
|
This library adds extra math functions to Ground.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
### fun -double !sinVal -double &input
|
||||||
|
|
||||||
|
Gets the sin of input.
|
||||||
|
|
||||||
|
### fun -double !cosVal -double &input
|
||||||
|
|
||||||
|
Gets the cos of input.
|
||||||
|
|
||||||
|
### fun -double !tanVal -double &input
|
||||||
|
|
||||||
|
Gets the tan of input.
|
||||||
|
|
||||||
|
### fun -double !sqrtVal -double &input
|
||||||
|
|
||||||
|
Gets the square root of input.
|
||||||
|
|
||||||
|
### fun -int !modVal -int &a -int &b
|
||||||
|
|
||||||
|
Gets the remainder of a divided by b.
|
||||||
|
|
||||||
|
### fun -double !floorVal -double &input
|
||||||
|
|
||||||
|
Gets the floor of input.
|
||||||
|
|
||||||
|
### fun -double !ceilVal -double &input
|
||||||
|
|
||||||
|
Gets the ceil of input.
|
||||||
|
|
||||||
|
### fun -double !roundVal -double &input
|
||||||
|
|
||||||
|
Rounds the input to the nearest integer.
|
||||||
|
|
||||||
|
### fun -int !randomInt -int &min -int &max
|
||||||
|
|
||||||
|
Gets a random integer between min and max (inclusive).
|
||||||
|
|
||||||
|
### fun -double !randomDouble -double &min -double &max
|
||||||
|
|
||||||
|
Gets a random double between min and max (inclusive).
|
193
extlibs/math/ground_lib.h
Normal file
193
extlibs/math/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
|
79
extlibs/math/math.cpp
Normal file
79
extlibs/math/math.cpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#include "ground_lib.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
// Math functions
|
||||||
|
GroundValue sinVal(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||||
|
return GROUND_DOUBLE_VAL(sin(GET_DOUBLE(args[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue cosVal(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||||
|
return GROUND_DOUBLE_VAL(cos(GET_DOUBLE(args[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue tanVal(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||||
|
return GROUND_DOUBLE_VAL(tan(GET_DOUBLE(args[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue sqrtVal(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||||
|
return GROUND_DOUBLE_VAL(sqrt(GET_DOUBLE(args[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue modVal(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_2(GROUND_INT, GROUND_INT);
|
||||||
|
return GROUND_INT_VAL(GET_INT(args[0]) % GET_INT(args[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue floorVal(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||||
|
return GROUND_DOUBLE_VAL(floor(GET_DOUBLE(args[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue ceilVal(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||||
|
return GROUND_DOUBLE_VAL(ceil(GET_DOUBLE(args[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue roundVal(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||||
|
return GROUND_DOUBLE_VAL(round(GET_DOUBLE(args[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue randomInt(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_2(GROUND_INT, GROUND_INT);
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::uniform_int_distribution<> distrib(GET_INT(args[0]), GET_INT(args[1]));
|
||||||
|
return GROUND_INT_VAL(distrib(gen));
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue randomDouble(GroundValue* args, int arg_count) {
|
||||||
|
VALIDATE_ARGS_2(GROUND_DOUBLE, GROUND_DOUBLE);
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::uniform_real_distribution<> distrib(GET_DOUBLE(args[0]), GET_DOUBLE(args[1]));
|
||||||
|
return GROUND_DOUBLE_VAL(distrib(gen));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Library setup
|
||||||
|
GROUND_LIBRARY_INTERFACE()
|
||||||
|
|
||||||
|
GROUND_LIBRARY_INIT()
|
||||||
|
REGISTER_GROUND_FUNCTION(sinVal);
|
||||||
|
REGISTER_GROUND_FUNCTION(cosVal);
|
||||||
|
REGISTER_GROUND_FUNCTION(tanVal);
|
||||||
|
REGISTER_GROUND_FUNCTION(sqrtVal);
|
||||||
|
REGISTER_GROUND_FUNCTION(modVal);
|
||||||
|
REGISTER_GROUND_FUNCTION(floorVal);
|
||||||
|
REGISTER_GROUND_FUNCTION(ceilVal);
|
||||||
|
REGISTER_GROUND_FUNCTION(roundVal);
|
||||||
|
REGISTER_GROUND_FUNCTION(randomInt);
|
||||||
|
REGISTER_GROUND_FUNCTION(randomDouble);
|
||||||
|
GROUND_LIBRARY_INIT_END()
|
||||||
|
|
||||||
|
GROUND_LIBRARY_CLEANUP()
|
||||||
|
GROUND_LIBRARY_CLEANUP_END()
|
13
extlibs/request/README.md
Normal file
13
extlibs/request/README.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# request library
|
||||||
|
|
||||||
|
This library allows various web requests from within Ground.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
### fun -string !simpleRequest -string &url
|
||||||
|
|
||||||
|
Makes a web request to a URL, and returns the contents. If the request is not successful, returns a response beginning with "Error code", and prints it to the console.
|
||||||
|
|
||||||
|
### fun -bool !saveContents -string &url -string &location
|
||||||
|
|
||||||
|
Makes a web request to a URL, and saves the contents to a file. If successful, returns true. If not, returns false.
|
193
extlibs/request/ground_lib.h
Normal file
193
extlibs/request/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
|
@@ -4,12 +4,17 @@
|
|||||||
#include <cpr/interface.h>
|
#include <cpr/interface.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
void error(std::string status) {
|
||||||
|
std::cout << "Request error: " << status << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
GroundValue simpleRequest(GroundValue* args, int arg_count) {
|
GroundValue simpleRequest(GroundValue* args, int arg_count) {
|
||||||
VALIDATE_ARGS_1(GROUND_STRING);
|
VALIDATE_ARGS_1(GROUND_STRING);
|
||||||
|
|
||||||
cpr::Response r = cpr::Get(cpr::Url(GET_STRING(args[0])));
|
cpr::Response r = cpr::Get(cpr::Url(GET_STRING(args[0])));
|
||||||
|
|
||||||
if (!(r.status_code >= 200 && r.status_code < 300)) {
|
if (!(r.status_code >= 200 && r.status_code < 300)) {
|
||||||
|
error("Non zero HTTP code " + std::to_string(r.status_code));
|
||||||
return ground_string_val("Error code " + std::to_string(r.status_code));
|
return ground_string_val("Error code " + std::to_string(r.status_code));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,10 +29,12 @@ GroundValue saveContents(GroundValue* args, int arg_count) {
|
|||||||
if (file.good()) {
|
if (file.good()) {
|
||||||
cpr::Response r = cpr::Download(file, cpr::Url{GET_STRING(args[0])});
|
cpr::Response r = cpr::Download(file, cpr::Url{GET_STRING(args[0])});
|
||||||
|
|
||||||
if (r.status_code >= 200 && r.status_code < 300) {
|
if (!(r.status_code >= 200 && r.status_code < 300)) {
|
||||||
|
error("Non zero HTTP code " + std::to_string(r.status_code));
|
||||||
return GROUND_BOOL_VAL(false);
|
return GROUND_BOOL_VAL(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
error(std::string("Cannot open file ") + GET_STRING(args[1]) + " for writing");
|
||||||
return GROUND_BOOL_VAL(false);
|
return GROUND_BOOL_VAL(false);
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue
Block a user