diff --git a/src/klib.c b/src/klib.c new file mode 100644 index 0000000..e91b81d --- /dev/null +++ b/src/klib.c @@ -0,0 +1,161 @@ +#include "klib.h" +#include "string.h" + +/* ---- character classification -------------------------------------- */ + +bool isDigit(int c) { return c >= '0' && c <= '9'; } +bool isUpper(int c) { return c >= 'A' && c <= 'Z'; } +bool isLower(int c) { return c >= 'a' && c <= 'z'; } +bool isAlpha(int c) { return isUpper(c) || isLower(c); } +bool isAlnum(int c) { return isAlpha(c) || isDigit(c); } +bool isSpace(int c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f'; } +bool isHexDigit(int c) { return isDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } + +int toUpper(int c) { return isLower(c) ? c - 'a' + 'A' : c; } +int toLower(int c) { return isUpper(c) ? c - 'A' + 'a' : c; } + +/* ---- string manipulation --------------------------------------------- */ + +char* strcpy(char* dest, const char* src) +{ + char* out = dest; + while ((*out++ = *src++) != 0) + ; + return dest; +} + +char* strncpy(char* dest, const char* src, usize count) +{ + usize i = 0; + for (; i < count && src[i]; i++) + dest[i] = src[i]; + for (; i < count; i++) + dest[i] = 0; + return dest; +} + +char* strcat(char* dest, const char* src) +{ + strcpy(dest + strlen(dest), src); + return dest; +} + +char* strncat(char* dest, const char* src, usize count) +{ + char* end = dest + strlen(dest); + usize i = 0; + for (; i < count && src[i]; i++) + end[i] = src[i]; + end[i] = 0; + return dest; +} + +char* strchr(const char* str, int c) +{ + for (;; str++) { + if (*str == (char)c) + return (char*)str; + if (*str == 0) + return nullptr; + } +} + +char* strrchr(const char* str, int c) +{ + const char* last = nullptr; + for (;; str++) { + if (*str == (char)c) + last = str; + if (*str == 0) + return (char*)last; + } +} + +char* strstr(const char* haystack, const char* needle) +{ + if (!*needle) + return (char*)haystack; + usize needleLen = strlen(needle); + for (; *haystack; haystack++) { + if (memcmp(haystack, needle, needleLen) == 0) + return (char*)haystack; + } + return nullptr; +} + +usize strspn(const char* str, const char* accept) +{ + usize count = 0; + for (; str[count]; count++) { + if (!strchr(accept, str[count])) + break; + } + return count; +} + +usize strcspn(const char* str, const char* reject) +{ + usize count = 0; + for (; str[count]; count++) { + if (strchr(reject, str[count])) + break; + } + return count; +} + +char* strTokR(char* str, const char* delim, char** savePtr) +{ + char* cursor = str ? str : *savePtr; + if (cursor == nullptr) + return nullptr; + + cursor += strspn(cursor, delim); + if (*cursor == 0) { + *savePtr = nullptr; + return nullptr; + } + + char* tokenEnd = cursor + strcspn(cursor, delim); + if (*tokenEnd) { + *tokenEnd = 0; + *savePtr = tokenEnd + 1; + } else { + *savePtr = nullptr; + } + return cursor; +} + +/* ---- number parsing ---------------------------------------------------- */ + +static int digitValue(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'z') + return c - 'a' + 10; + if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + return -1; +} + +uint64 strtoul(const char* str, char** endPtr, int base) +{ + const char* cursor = str; + while (isSpace((unsigned char)*cursor)) + cursor++; + + bool negative = false; + if (*cursor == '+' || *cursor == '-') { + negative = (*cursor == '-'); + cursor++; + } + + if ((base == 0 || base == 16) && cursor[0] == '0' && (cursor[1] == 'x' || cursor[1] == 'X')) { + cursor += 2; + base = 16; + } else if (base == 0 && cursor[0] == '0') { + base = 8; + } else if (base == 0) { + base = 10; + } +