os-k/kaleid/crtlib/string.c

331 lines
6.7 KiB
C

//----------------------------------------------------------------------------//
// GNU GPL OS/K //
// //
// Authors: spectral` //
// NeoX //
// //
// Desc: String-related functions //
//----------------------------------------------------------------------------//
#include <kalbase.h>
//
// Compare two strings
//
int strcmp(const char *str1, const char *str2)
{
while (*str1 == *str2 && *str2) str1++, str2++;
return *(uchar *)str1 - *(uchar *)str2;
}
//
// Compare at most n bytes of two strings
//
int strncmp(const char *str1, const char *str2, size_t n)
{
size_t it = 0;
while (*str1 == *str2 && *str2 && it < n) str1++, str2++, it++;
return *(uchar *)str1 - *(uchar *)str2;
}
//
// Return str's length
//
size_t strlen(const char *str)
{
const char *base = str;
while (*str) str++;
return str - base;
}
//
// Return a pointer to the first occurence of ch in str,
// or str's null-terminator if none is found
//
char *strchrnul(const char *str, int ch)
{
while ((*str && *str != (char)ch)) str++;
return (char *)str;
}
//
// Return a pointer to the first occurence of ch in str,
// NULL if none is found
//
char *strchr(const char *str, int ch)
{
while ((*str && *str != (char)ch)) str++;
return *str ? (char *)str : NULL;
}
//
// Return a point to the last occurence of ch in str,
// NULL if none is found
//
char *strrchr(const char *str, int ch)
{
char *ptr = NULL;
while (*str) {
if (*str == ch) {
ptr = (char *)str;
}
str++;
}
return ptr;
}
//
// Return the length of the longest inital segment of str
// that only contains characters in acc
//
size_t strspn(const char *str, const char *acc)
{
const char *ptr = str;
while (*ptr && strchr(acc, *ptr) != NULL) ptr++;
return ptr - str;
}
//
// Return the length of the longest initial segment of str
// that does not contain any character in rej
//
size_t strcspn(const char *str, const char *rej)
{
const char *ptr = str;
while (*ptr && strchr(rej, *ptr) == NULL) ptr++;
return ptr - str;
}
//
// Return the first occurence in str of any byte in acc
//
char *strpbrk(const char *str, const char *acc)
{
str += strcspn(str, acc);
return *str ? (char *)str : NULL;
}
//
// Return the first occurence of the substring needle
// in the string haystack, NULL if none is found
// Null-terminators aren't compared
//
char *strstr(const char *haystack, const char *needle)
{
const size_t needle_size = strlen(needle);
//
// Moves haystack to first occurence of the needle's first byte
//
while ((haystack = strchr(haystack, *needle)) != NULL) {
if (strncmp(haystack, needle, needle_size) == 0) {
return (char *)haystack;
}
}
return NULL;
}
//
// Tokenize a string, using saveptr as a savestate
// We let a segmentation fault happen if *saveptr == NULL
//
char *strtok_r(char *restrict str, const char *restrict delim, char **restrict saveptr)
{
assert(*saveptr != NULL);
if (str == NULL) str = *saveptr;
//
// Skip initial segments composed only of delimiters
//
str += strspn(str, delim);
//
// If str is empty, store it in saveptr so that next call
// still finds an empty strings and returns NULL
//
if (*str == 0) {
*saveptr = str;
return NULL;
}
char *ptr = str, *tok_end = strpbrk(str, delim);
//
// If we found the last token, set *saveptr to a str's null-terminator
// Otherwise, null-terminate token and save next byte
//
if (tok_end == NULL) {
while (*ptr) ptr++;
*saveptr = ptr;
}
else {
*tok_end = 0;
*saveptr = tok_end + 1;
}
return str;
}
//
// Tokenize a string in a very thread-unsafe way
//
char *strtok(char *restrict str, const char *restrict delim)
{
static char *saveptr = NULL;
KalAssert(FALSE);
if (str) saveptr = str;
return strtok_r(str, delim, &saveptr);
}
//
// Copy the string src into dest
//
char *strcpy(char *restrict dest, const char *restrict src)
{
char *base = dest;
while ((*dest++ = *src++));
return base;
}
//
// strcpy() but always writes n bytes
// Will not null-terminate for strings longer than n bytes
//
char *strncpy(char *restrict dest, const char *restrict src, size_t n)
{
size_t it;
for (it = 0; it < n && src[it]; it++) {
dest[it] = src[it];
}
while (it < n) dest[it++] = 0;
return dest;
}
//
// Copies at most n-1 bytes from src to dest
// Always null-terminates dest, but doesn't fill
// dest's contents past the null-terminator
//
// Returns the number of bytes written
//
size_t strnzcpy(char *restrict dest, const char *restrict src, size_t n)
{
size_t it;
for (it = 0; it < n - 1 && src[it]; it++) {
dest[it] = src[it];
}
dest[it++] = 0;
return it;
}
//
// Appends a copy of src at the end of dest
//
char *strcat(char *restrict dest, const char *restrict src)
{
char *base = dest;
while (*dest) dest++;
while ((*dest++ = *src++));
return base;
}
//
// Appends a copy of at most n bytes of src at the end of dest
//
char *strncat(char *restrict dest, const char *restrict src, size_t n)
{
size_t it, off = 0;
while (dest[off]) off++;
for (it = 0; it < n && src[it]; it++) {
dest[it+off] = src[it];
}
while (it++ < n) dest[it+off] = 0;
return dest;
}
//
// Appends a copy of at most n bytes of src at the end of dest
// Always null-terminates, and returne TRUE or FALSE depending on whether
// regular strcat() would have null-terminated this string, or not
//
size_t strnzcat(char *restrict dest, const char *restrict src, size_t n)
{
size_t it, off = 0;
while (dest[off]) off++;
for (it = 0; it < n - 1 && src[it]; it++) {
dest[it+off] = src[it];
}
dest[it+off] = 0;
return it+1;
}
//
// Reverses the string src, putting the result into dest
//
char *strrev(char *restrict dest, const char *restrict src)
{
char *orig = dest;
size_t n = strlen(src);
dest[n--] = '\0';
while ((*dest++ = src[n--]));
return orig;
}
//
// Reverses a string, modifying it
//
char *strrev2(char *str)
{
char ch, *orig = str;
size_t n = strlen(str);
char *temp = str + n - 1;
while (temp > str) {
ch = *temp;
*temp-- = *str;
*str++ = ch;
}
return orig;
}