os-k/kaleid/libc/string.c

330 lines
7.9 KiB
C

//----------------------------------------------------------------------------//
// GNU GPL OS/K //
// //
// Desc: String manipulation utilities //
// //
// //
// Copyright © 2018-2019 The OS/K Team //
// //
// This file is part of OS/K. //
// //
// OS/K is free software: you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation, either version 3 of the License, or //
// any later version. //
// //
// OS/K is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY//without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with OS/K. If not, see <https://www.gnu.org/licenses/>. //
//----------------------------------------------------------------------------//
#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;
// Avoid this function if possible
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)
{
char *base = dest;
while (n-- && (*dest++ = *src++));
while (n--) *dest++ = 0;
return base;
}
//
// 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 a pointer to the last character of src copied
// (In particular it points to src's null-terminator if
// and only if every character of src was successfuly copied)
//
char *strnzcpy(char *restrict dest, const char *restrict src, size_t n)
{
while (n-- > 1 && (*dest = *src)) dest++, src++;
if (*src) *++dest = 0;
return (char *)src;
}
//
// 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)
{
char *base = dest;
while (*dest) dest++;
while (n-- && (*dest++ = *src++));
while (n--) *dest++ = 0;
return base;
}
//
// Appends 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 a pointer to the last character of src copied
// (In particular it points to src's null-terminator if
// and only if every character of src was successfuly copied)
//
char *strnzcat(char *restrict dest, const char *restrict src, size_t n)
{
while (*dest) dest++;
while (n-- > 1 && (*dest = *src)) dest++, src++;
if (*src) *++dest = 0;
return (char *)src;
}
//
// 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;
}