diff --git a/docs/stdlib.md b/docs/stdlib.md index 3811616..7b62747 100644 --- a/docs/stdlib.md +++ b/docs/stdlib.md @@ -59,7 +59,7 @@ Includes functions that interact with the operating system. | Name | Type | Behavior | Example | | ------------ | ------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------ | -| os.open | `(path)` -> `, ` | Opens a file at `path` and returns a file object. If the file does not exist, it will be created. | `os.open("test.txt")` -> `true, ` | +| os.open | `(path[, mode])` -> `, ` | Opens a file at `path` and returns a file object. Specify mode to be "r" or "w" optionally, defaults to "r". | `os.open("test.txt")` -> `true, ` | | os.time | `()` -> `` | Returns the system time in Epoch format | `os.time()` -> `1.61691e+09` | | os.system | `(cmd)` -> `` | Runs a system command as if it were a terminal and returns the exit code | `os.system("mkdir test")` -> `0` | > -> means 'returns' @@ -67,4 +67,6 @@ Includes functions that interact with the operating system. File objects have the following methods: | Name | Type | Behavior | Example | | ------------ | ------------------------------------------------ | ------------------------------------------------------------------------ | ------------------------ | -| file:read | `(amt or "a")` -> `` | Reads `amt` bytes from the file and returns them as a string. If `"a"` is passed, the entire file is read. | `file:read("a")` -> `"Hello world!"` | \ No newline at end of file +| file:read | `(amt or "a")` -> `` | Reads `amt` bytes from the file and returns them as a string. If `"a"` is passed, the entire file is read. | `file:read("a")` -> `"Hello world!"` | +| file:write | `(data)` -> `` | Writes `data` to file. | `file:write("hello world!")` -> `` | +> -> means 'returns' diff --git a/examples/reader.cosmo b/examples/reader.cosmo index cf3b440..7f3f65f 100644 --- a/examples/reader.cosmo +++ b/examples/reader.cosmo @@ -1,9 +1,6 @@ - local err, file = os.open("LICENSE.md") -print("made file") if err then print("failed to open file") end -print(file) print(file:read("a")) diff --git a/examples/writer.cosmo b/examples/writer.cosmo new file mode 100644 index 0000000..6da434a --- /dev/null +++ b/examples/writer.cosmo @@ -0,0 +1,6 @@ +local err, file = os.open("test.md", "w") +if err then + print("failed to open file") +end + +file:write("hello world") \ No newline at end of file diff --git a/src/cbaselib.c b/src/cbaselib.c index 10ec7bb..e584408 100644 --- a/src/cbaselib.c +++ b/src/cbaselib.c @@ -262,6 +262,7 @@ int fileB_read(CState *state, int nargs, CValue *args) // read the data fread(buffer, sizeof(char), length, file); + buffer[(int)length] = '\0'; // write the NULL terminator // push the read data CValue temp = cosmoV_newRef(cosmoO_takeString(state, buffer, length)); @@ -278,7 +279,6 @@ int fileB_read(CState *state, int nargs, CValue *args) // read the data fread(buffer, sizeof(char), length, file); - buffer[length] = '\0'; // write the NULL terminator // push the read data @@ -296,6 +296,30 @@ int fileB_read(CState *state, int nargs, CValue *args) return 1; } +int fileB_write(CState *state, int nargs, CValue *args) { + if (nargs != 2) { + cosmoV_error(state, "file:write() expected 2 arguments, got %d!", nargs); + } + + if (!cosmoV_isValueUserType(state, args[0], COSMO_USER_FILE)) { + cosmoV_typeError(state, "file:write()", ", ", "%s, %s", + cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1])); + } + + if (!IS_STRING(args[1])) { + cosmoV_typeError(state, "file:write()", ", ", "%s, %s", + cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1])); + } + + CObjObject *fileObj = cosmoV_readObject(args[0]); + FILE *file = cosmoO_getUserP(fileObj); + + CObjString *str = cosmoV_readString(args[1]); + fwrite(str->str, sizeof(char), str->length, file); + + return 0; +} + int fileB_gc(CState *state, int nargs, CValue *args) { if (nargs != 1) { cosmoV_error(state, "file:read() expected 1 argument, got %d!", nargs); @@ -320,7 +344,7 @@ CObjObject *pushFileObj(CState *state, FILE *file) cosmoO_setUserP(fileObj, file); cosmoO_setUserT(fileObj, COSMO_USER_FILE); - // grab and set proto + // grab and set proto from the registry cosmoV_pushRef(state, (CObj *)fileObj); cosmoV_pushString(state, "file"); cosmoV_getRegistry(state); @@ -332,18 +356,29 @@ CObjObject *pushFileObj(CState *state, FILE *file) int cosmoB_osOpen(CState *state, int nargs, CValue *args) { + const char *mode = "rb"; FILE *file; - if (nargs != 1) { - cosmoV_error(state, "os.open() expected 1 argument, got %d!", nargs); - } + if (nargs >= 1) { + if (!IS_STRING(args[0])) { + cosmoV_typeError(state, "os.open()", "", "%s", cosmoV_typeStr(args[0])); + } - if (!IS_STRING(args[0])) { - cosmoV_typeError(state, "os.open()", "", "%s", cosmoV_typeStr(args[0])); + if (nargs == 2) { + if (!IS_STRING(args[1])) { + cosmoV_typeError(state, "os.open()", ", ", "%s, %s", cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1])); + } + + mode = cosmoV_readCString(args[1]); + } else if (nargs > 2) { + cosmoV_error(state, "os.open() expected 1 or 2 arguments, got %d!", nargs); + } + } else { + cosmoV_error(state, "os.open() expected 1 or 2 arguments, got %d!", nargs); } const char *filePath = cosmoV_readCString(args[0]); - file = fopen(filePath, "rb"); + file = fopen(filePath, mode); if (file == NULL) { cosmoV_pushBoolean(state, true); cosmoV_pushFString(state, "Failed to open %s!", filePath); @@ -411,6 +446,11 @@ COSMO_API void cosmoB_loadOS(CState *state) cosmoV_pushCFunction(state, fileB_read); cosmoV_set(state); + cosmoV_pushRef(state, (CObj *)fileProto); + cosmoV_pushString(state, "write"); + cosmoV_pushCFunction(state, fileB_write); + cosmoV_set(state); + cosmoV_pushRef(state, (CObj *)fileProto); cosmoV_pushString(state, "__gc"); cosmoV_pushCFunction(state, fileB_gc);