diff --git a/src/cbaselib.c b/src/cbaselib.c index 53afa46..95ba39d 100644 --- a/src/cbaselib.c +++ b/src/cbaselib.c @@ -258,28 +258,54 @@ int cosmoB_sSplit(CState *state, int nargs, CValue *args) { return 1; } -// string.charAt -int cosmoB_sCharAt(CState *state, int nargs, CValue *args) { - if (nargs != 2) { - cosmoV_error(state, "string.charAt() expected 2 arguments, got %d!", nargs); +// string.byte +int cosmoB_sByte(CState *state, int nargs, CValue *args) { + if (nargs != 1) { + cosmoV_error(state, "string.byte() expected 1 argument, got %d!", nargs); return 0; } - if (!IS_STRING(args[0]) || !IS_NUMBER(args[1])) { - cosmoV_typeError(state, "string.charAt", ", ", "%s, %s", cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1])); + if (!IS_STRING(args[0])) { + cosmoV_typeError(state, "string.byte", "", "%s", cosmoV_typeStr(args[0])); return 0; } - + CObjString *str = cosmoV_readString(args[0]); - int indx = (int)cosmoV_readNumber(args[1]); - if (indx >= str->length || indx < 0) { - cosmoV_error(state, "string.charAt() expected index to be 0-%d, got %d!", str->length - 1, indx); + if (str->length < 1) { + // the length of the string is less than 1, in the future I might throw an error for this, but + // for now im going to copy lua and just return a nil return 0; } - // returns character number - cosmoV_pushNumber(state, (int)str->str[indx]); + // push the character byte and return + cosmoV_pushNumber(state, (int)str->str[0]); + return 1; +} + +// string.char +int cosmoB_sChar(CState *state, int nargs, CValue *args) { + if (nargs != 1) { + cosmoV_error(state, "string.char() expected 1 argument, got %d!", nargs); + return 0; + } + + if (!IS_NUMBER(args[0])) { + cosmoV_typeError(state, "string.char", "", "%s", cosmoV_typeStr(args[0])); + return 0; + } + + // small side effect of truncating the number, but ignoring the decimal instead of throwing an error is the better option imo + int num = (int)cosmoV_readNumber(args[0]); + char c = num; + + if (num > 255 || num < 0) { + cosmoV_error(state, "Character expected to be in range 0-255, got %d!", num); + return 0; + } + + // basically, treat the c value on the stack as an """"array"""" with a length of 1 + cosmoV_pushLString(state, &c, 1); return 1; } @@ -288,14 +314,16 @@ void cosmoB_loadStrLib(CState *state) { "sub", "find", "split", - "charAt" + "byte", + "char" }; CosmoCFunction strLib[] = { cosmoB_sSub, cosmoB_sFind, cosmoB_sSplit, - cosmoB_sCharAt + cosmoB_sByte, + cosmoB_sChar }; // make string library object diff --git a/src/cbaselib.h b/src/cbaselib.h index 39920d4..3b486cd 100644 --- a/src/cbaselib.h +++ b/src/cbaselib.h @@ -14,7 +14,8 @@ COSMO_API void cosmoB_loadLibrary(CState *state); - string.sub - stirng.find - string.split - - string.charAt + - string.byte + - string.char The base proto object for strings is also set, allowing you to invoke the string.* api through string objects, eg. `"hello world":split(" ")` is equivalent to `string.split("hello world", " ")` diff --git a/src/cobj.c b/src/cobj.c index 7430dc1..2901fd9 100644 --- a/src/cobj.c +++ b/src/cobj.c @@ -213,7 +213,7 @@ CObjString *cosmoO_copyString(CState *state, const char *str, size_t length) { return cosmoO_allocateString(state, buf, length, hash); } -// length shouldn't include the null terminator! (char array should also have been allocated using cosmoM_xmalloc!) +// length shouldn't include the null terminator! str should be a null terminated string! (char array should also have been allocated using cosmoM_xmalloc!) CObjString *cosmoO_takeString(CState *state, char *str, size_t length) { uint32_t hash = hashString(str, length); diff --git a/src/cobj.h b/src/cobj.h index 22ee177..08ca358 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -44,7 +44,7 @@ typedef struct CObjString { CommonHeader; // "is a" CObj bool isIString; int length; - char *str; + char *str; // NULL termincated string uint32_t hash; // for hashtable lookup } CObjString; @@ -168,12 +168,14 @@ int cosmoO_getUserI(CState *state, CObjObject *object); // internal string bool cosmoO_getIString(CState *state, CObjObject *object, int flag, CValue *val); -// copies the *str buffer to the heap and returns a CObjString struct which is also on the heap -CObjString *cosmoO_copyString(CState *state, const char *str, size_t sz); -// pass an already allocated str buffer! -CObjString *cosmoO_takeString(CState *state, char *str, size_t sz); +// copies the *str buffer to the heap and returns a CObjString struct which is also on the heap (length should not include the null terminator) +CObjString *cosmoO_copyString(CState *state, const char *str, size_t length); + +// length shouldn't include the null terminator! str should be a null terminated string! (char array should also have been allocated using cosmoM_xmalloc!) +CObjString *cosmoO_takeString(CState *state, char *str, size_t length); + // allocates a CObjStruct pointing directly to *str -CObjString *cosmoO_allocateString(CState *state, const char *str, size_t sz, uint32_t hash); +CObjString *cosmoO_allocateString(CState *state, const char *str, size_t length, uint32_t hash); /* formats strings to push onto the VM stack, formatting supported: