diff --git a/Makefile b/Makefile index 03fdec5..2a24a36 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Wextra -Isrc/include -Iinclude -LDFLAGS = +LDFLAGS = -ldl -rdynamic # Install paths PREFIX ?= /usr/local @@ -17,7 +17,7 @@ OBJ_DIR = $(BUILD_DIR)/obj # Output names EXECUTABLE = $(BIN_DIR)/ground SHARED_LIB = $(LIB_DIR)/libgroundvm.so -HEADER = $(INC_DIR)/groundvm.h +HEADERS = $(INC_DIR)/groundvm.h $(INC_DIR)/groundext.h # Source files LIB_SOURCES = $(filter-out $(SRC_DIR)/main.c, $(wildcard $(SRC_DIR)/*.c)) @@ -37,7 +37,7 @@ executable: $(EXECUTABLE) # Build shared library .PHONY: library -library: $(SHARED_LIB) $(HEADER) +library: $(SHARED_LIB) $(HEADERS) # Build both .PHONY: both @@ -52,7 +52,7 @@ $(SHARED_LIB): $(LIB_OBJECTS) | $(LIB_DIR) $(CC) -shared $(LIB_OBJECTS) -o $@ $(LDFLAGS) # Copy header for library distribution -$(HEADER): include/groundvm.h | $(INC_DIR) +$(INC_DIR)/%.h: include/%.h | $(INC_DIR) cp $< $@ # Compile object files for executable @@ -80,7 +80,7 @@ install: both mkdir -p $(DESTDIR)$(PREFIX)/include cp $(EXECUTABLE) $(DESTDIR)$(PREFIX)/bin/ cp $(SHARED_LIB) $(DESTDIR)$(PREFIX)/lib/ - cp $(HEADER) $(DESTDIR)$(PREFIX)/include/ + cp $(HEADERS) $(DESTDIR)$(PREFIX)/include/ ldconfig # Debug: print variables diff --git a/libs/README.md b/libs/README.md new file mode 100644 index 0000000..47008ad --- /dev/null +++ b/libs/README.md @@ -0,0 +1,95 @@ +# Ground Libraries + +This repo folder details the process for creating libraries with Ground, as well as some core libraries that are preinstalled with Ground. + +## Building Libraries + +Ground comes with the `groundvm.h` and `groundext.h` header files for interfacing with Ground. If you're building something that wraps Ground, use `groundvm.h`. If you're building something that Ground itself uses (a library), use `groundext.h` (it includes `groundvm.h` but also has some extlib-specific things). + +You can build your library in C or C++, or whichever language you can convince to interop with C code. + +Note: C++ Ground extlibs and CGround extlibs are not compatible. Update your code for CGround. + +### Making a Function for CGround + +Create a function with the following signature: + +```c +GroundValue myFn(GroundScope* scope, List args) {} +``` + +* `GroundScope* scope`: For now does nothing. Will do something when structs are added. +* `List args`: A list of args. + +The `List` struct and associated structures look like this: + +```c + typedef enum GroundValueType { + INT, DOUBLE, STRING, CHAR, BOOL, LIST, FUNCTION, CUSTOM, NONE + } GroundValueType; + + typedef struct List { + size_t size; + struct GroundValue* values; + } List; + + typedef struct GroundValue { + GroundValueType type; + union { + int64_t intVal; + double doubleVal; + char* stringVal; + char charVal; + bool boolVal; + List listVal; + struct GroundFunction* fnVal; + void* customVal; + } data; + } GroundValue; +``` + +Your function needs to return a `GroundValue`. This can easily be created with the `groundCreateValue()` function, used like this: + +```c +// TYPE is one of the enum values from the GroundValueType enum. +// CONTENT is the associated data type (char* for string, int64_t for int, etc, etc) +groundCreateValue(TYPE, content); + +// Real use: +groundCreateValue(STRING, "dingus"); +groundCreateValue(INT, 32); +``` + +Once you've created your functions, you can create a `ground_init()` function to let Ground know about your functions. Use the `groundAddNativeFunction()` function to add your functions to Ground. + +If your function fails, print some debug stuff to the console and return `groundCreateValue(NONE)`. Proper error handling will be added soon. + +```c + +GroundValue say_hi(GroundScope* scope, List args) { + char* greeting = "Hello, "; + if (list.size < 1) { + printf("Expecting an argument!"); + return groundCreateValue(NONE); + } + if (list.values[0].type != STRING) { + printf("Expecting a string"); + return groundCreateValue(NONE); + } + // Insert stupid memory stuff here + return groundCreateValue(STRING, greeting); +} + +// ground_init takes a GroundScope* so it can add your functions to Ground +void ground_init(GroundScope* scope) { + // groundAddNativeFunction(scope, "namespace_FnName", name_of_function, RETURNTYPE, + // amountOfArgs, ARGTYPE, "argName", ARGTYPE, "argName", ...) + groundAddNativeFunction(scope, "utility_SayHi", say_hi, STRING, 1, STRING, "name"); +} +``` + +### Notes + +When naming your functions, give them a prefix namespace like in C. Use `camelCase` for the namespace and `CamelCase` for the function name. + +Document your functions somewhere! We want to be able to use them! diff --git a/libs/fileio/fileio.c b/libs/fileio/fileio.c new file mode 100644 index 0000000..3e576b2 --- /dev/null +++ b/libs/fileio/fileio.c @@ -0,0 +1,57 @@ +#include +#include +#include "groundext.h" + +GroundValue native_file_read(GroundScope* scope, List args) { + if (args.size < 1 || args.values[0].type != STRING) { + return groundCreateValue(NONE); + } + + char* path = args.values[0].data.stringVal; + FILE* f = fopen(path, "r"); + if (!f) { + return groundCreateValue(NONE); + } + + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + char* content = malloc(fsize + 1); + if (!content) { + fclose(f); + return groundCreateValue(NONE); + } + + fread(content, 1, fsize, f); + fclose(f); + content[fsize] = 0; + + GroundValue val = groundCreateValue(STRING, content); + free(content); + return val; +} + +GroundValue native_file_write(GroundScope* scope, List args) { + if (args.size < 2 || args.values[0].type != STRING || args.values[1].type != STRING) { + return groundCreateValue(BOOL, 0); + } + + char* path = args.values[0].data.stringVal; + char* content = args.values[1].data.stringVal; + + FILE* f = fopen(path, "w"); + if (!f) { + return groundCreateValue(BOOL, 0); + } + + fprintf(f, "%s", content); + fclose(f); + + return groundCreateValue(BOOL, 1); +} + +void ground_init(GroundScope* scope) { + groundAddNativeFunction(scope, "file_Read", native_file_read, STRING, 1, STRING, "path"); + groundAddNativeFunction(scope, "file_Write", native_file_write, BOOL, 2, STRING, "path", STRING, "content"); +}