aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/libc/string.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpsn00b/libc/string.c')
-rw-r--r--libpsn00b/libc/string.c604
1 files changed, 359 insertions, 245 deletions
diff --git a/libpsn00b/libc/string.c b/libpsn00b/libc/string.c
index a1a9a05..dbc2621 100644
--- a/libpsn00b/libc/string.c
+++ b/libpsn00b/libc/string.c
@@ -1,295 +1,457 @@
/*
- * string.c
- *
- * Inherited from PSXSDK C library
+ * PSn00bSDK standard library
+ * (C) 2019-2023 PSXSDK authors, Lameguy64, spicyjpeg - MPL licensed
*/
-#include <stdio.h>
-#include <string.h>
+#include <stdint.h>
+#include <stddef.h>
#include <stdlib.h>
+#include <string.h>
// Uncomment to enable strtod(), strtold() and strtof(). Note that these
// functions use extremely slow software floats.
//#define ALLOW_FLOAT
-int tolower(int chr)
-{
- return (chr >='A' && chr<='Z') ? (chr + 32) : (chr);
+/* Character manipulation */
+
+int isprint(int ch) {
+ return (ch >= ' ') && (ch <= '~');
}
-int toupper(int chr)
-{
- return (chr >='a' && chr<='z') ? (chr - 32) : (chr);
+int isgraph(int ch) {
+ return (ch > ' ') && (ch <= '~');
}
-// Need to be replaced with MIPS assembler equivalents
+int isspace(int ch) {
+ return (ch == ' ') || ((ch >= '\t') && (ch <= '\r'));
+}
-void *memchr(void *s , int c , int n)
-{
- while(n--)
- {
- if(*((unsigned char*)s) == (unsigned char)c)
- return s;
-
- s++;
- }
-
- return NULL;
+int isblank(int ch) {
+ return (ch == ' ') || (ch == '\t');
}
-char *strncpy(char *dst, const char *src, int len)
-{
- char *odst=dst;
+int isalpha(int ch) {
+ return ((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z'));
+}
- while(*src && len)
- {
- *(dst++) = *(src++);
- len--;
- }
-
- *dst = 0;
-
- return odst;
+int isdigit(int ch) {
+ return (ch >= '0') && (ch <= '9');
}
-char *strcpy(char *dst, const char *src)
-{
- char *odst = dst;
+int tolower(int ch) {
+ if ((ch >= 'A') && (ch <= 'Z'))
+ ch += 'a' - 'A';
- while(*(dst++) = *(src++));
- return odst;
+ return ch;
}
-char *strcat(char *dst, const char *src)
-{
- char *o=dst;
-
- while(*dst)
- dst++;
-
- strcpy(dst, src);
-
- return o;
+int toupper(int ch) {
+ if ((ch >= 'a') && (ch <= 'z'))
+ ch += 'A' - 'a';
+
+ return ch;
}
-char *strncat(char *s, const char *append, int len)
-{
- char *o=s;
-
- while(*s)
- s++;
-
- strncpy(s, append, len);
-
- return o;
+/* Memory buffer manipulation */
+
+// TODO: replace more of these with optimized assembly implementations
+
+/*void *memset(void *dest, int ch, size_t count) {
+ uint8_t *_dest = (uint8_t *) dest;
+
+ for (; count; count--)
+ *(_dest++) = (uint8_t) ch;
+
+ return dest;
+}*/
+
+void *memcpy(void *restrict dest, const void *restrict src, size_t count) {
+ uint8_t *_dest = (uint8_t *) dest;
+ const uint8_t *_src = (const uint8_t *) src;
+
+ for (; count; count--)
+ *(_dest++) = *(_src++);
+
+ return dest;
}
-int strlen(const char *str)
-{
- int i = 0;
- while(*(str++))i++;
- return i;
+void *memccpy(void *restrict dest, const void *restrict src, int ch, size_t count) {
+ uint8_t *_dest = (uint8_t *) dest;
+ const uint8_t *_src = (const uint8_t *) src;
+
+ for (; count; count--) {
+ uint8_t a = *(_src++);
+
+ *(_dest++) = a;
+ if (a == ch)
+ return (void *) _dest;
+ }
+
+ return 0;
}
-char *strchr(const char *s, int c)
-{
- int x;
+void *memmove(void *dest, const void *src, size_t count) {
+ uint8_t *_dest = (uint8_t *) dest;
+ const uint8_t *_src = (const uint8_t *) src;
- for(x = 0; x <= strlen(s); x++)
- if(s[x] == c) return (char*)&s[x];
+ if (_dest == _src)
+ return dest;
+ if ((_dest >= &_src[count]) || (&_dest[count] <= _src))
+ return memcpy(dest, src, count);
- return NULL;
+ if (_dest < _src) { // Copy forwards
+ for (; count; count--)
+ *(_dest++) = *(_src++);
+ } else { // Copy backwards
+ _src += count;
+ _dest += count;
+
+ for (; count; count--)
+ *(--_dest) = *(--_src);
+ }
+
+ return dest;
}
-char *strrchr(const char *s, int c)
-{
- int x;
+int memcmp(const void *lhs, const void *rhs, size_t count) {
+ const uint8_t *_lhs = (const uint8_t *) lhs;
+ const uint8_t *_rhs = (const uint8_t *) rhs;
+
+ for (; count; count--) {
+ uint8_t a = *(_lhs++), b = *(_rhs++);
- for(x = strlen(s); x>=0; x--)
- if(s[x] == c) return (char*)&s[x];
+ if (a != b)
+ return a - b;
+ }
- return NULL;
+ return 0;
}
-char *strpbrk(const char *s, const char *charset)
-{
- int x,y;
+void *memchr(const void *ptr, int ch, size_t count) {
+ const uint8_t *_ptr = (const uint8_t *) ptr;
- for(x = 0; x < strlen(s); x++)
- for(y = 0; y < strlen(charset); y++)
- if(s[x] == charset[y]) return (char*)&s[x];
+ for (; count; count--, _ptr++) {
+ if (*_ptr == ch)
+ return (void *) _ptr;
+ }
- return NULL;
+ return 0;
}
-char *strstr(const char *big, const char *little)
-{
- int ls = strlen(little);
- int bs = strlen(big);
- int x;
+/* String manipulation */
- if(ls == 0)
- return (char*)big;
-
- if(ls > bs)
- return NULL;
+char *strcpy(char *restrict dest, const char *restrict src) {
+ char *_dest = dest;
- for(x = 0; x <= bs-ls; x++)
- if(memcmp(little, &big[x], ls) == 0)
- return (char*)&big[x];
+ while (*src)
+ *(_dest++) = *(src++);
- return NULL;
+ *_dest = 0;
+ return dest;
}
-int strcmp(const char *s1, const char *s2)
-{
- while((*s1) && (*s2) && (*s1 == *s2))
- {
- s1++;
- s2++;
+char *strncpy(char *restrict dest, const char *restrict src, size_t count) {
+ char *_dest = dest;
+
+ for (; count && *src; count--)
+ *(_dest++) = *(src++);
+ for (; count; count--)
+ *(_dest++) = 0;
+
+ return dest;
+}
+
+int strcmp(const char *lhs, const char *rhs) {
+ for (;;) {
+ char a = *(lhs++), b = *(rhs++);
+
+ if (a != b)
+ return a - b;
+ if (!a && !b)
+ return 0;
+ }
+}
+
+int strncmp(const char *lhs, const char *rhs, size_t count) {
+ for (; count && *lhs && *rhs; count--) {
+ char a = *(lhs++), b = *(rhs++);
+
+ if (a != b)
+ return a - b;
}
- return(*s1-*s2);
+ return 0;
}
-int strncmp(const char *s1, const char *s2, int len)
-{
- int p = 0;
+char *strchr(const char *str, int ch) {
+ for (; *str; str++) {
+ if (*str == ch)
+ return (char *) str;
+ }
- while(*s1 && *s2 && (*s1 == *s2) && p<len)
- {
- p++;
+ return 0;
+}
+
+char *strrchr(const char *str, int ch) {
+ size_t length = strlen(str);
+
+ for (str += length; length; length--) {
+ str--;
+ if (*str == ch)
+ return (char *) str;
+ }
+
+ return 0;
+}
+
+char *strpbrk(const char *str, const char *breakset) {
+ for (; *str; str++) {
+ char a = *str;
- if(p<len)
- {
- s1++;
- s2++;
+ for (const char *ch = breakset; *ch; ch++) {
+ if (a == *ch)
+ return (char *) str;
}
}
- return *s1-*s2;
+ return 0;
}
-// Requires a malloc implementation
-char *strdup(const char *str)
-{
- char *ns = (void*)malloc(strlen(str) + 1);
+char *strstr(const char *str, const char *substr) {
+ size_t length = strlen(substr);
- if(ns == NULL)
- return NULL;
-
- strcpy(ns, str);
- return ns;
+ if (!length)
+ return (char *) str;
+
+ for (; *str; str++) {
+ if (!memcmp(str, substr, length))
+ return (char *) str;
+ }
+
+ return 0;
}
-char *strndup(const char *str, int len)
-{
- int n=strlen(str);
- char *ns = (void*)malloc((n+1)>len?len:(n+1));
+size_t strlen(const char *str) {
+ size_t length = 0;
- if(ns == NULL)
- return NULL;
-
- strncpy(ns, str, (n+1)>len?len:(n+1));
- return ns;
+ for (; *str; str++)
+ length++;
+
+ return length;
}
-
-long long strtoll(const char *nptr, char **endptr, int base)
-{
- int r = 0;
- int t = 0;
- int n = 0;
-
- if(*nptr == '-')
- {
- nptr++;
- n = 1;
+
+// Non-standard, used internally
+size_t strnlen(const char *str, size_t count) {
+ size_t length = 0;
+
+ for (; *str && (length < count); str++)
+ length++;
+
+ return length;
+}
+
+char *strcat(char *restrict dest, const char *restrict src) {
+ char *_dest = &dest[strlen(dest)];
+
+ while (*src)
+ *(_dest++) = *(src++);
+
+ *_dest = 0;
+ return dest;
+}
+
+char *strncat(char *restrict dest, const char *restrict src, size_t count) {
+ char *_dest = &dest[strlen(dest)];
+
+ for (; count && *src; count--)
+ *(_dest++) = *(src++);
+
+ *_dest = 0;
+ return dest;
+}
+
+char *strdup(const char *str) {
+ size_t length = strlen(str) + 1;
+ char *copy = malloc(length);
+
+ if (!copy)
+ return 0;
+
+ memcpy(copy, str, length);
+ return copy;
+}
+
+char *strndup(const char *str, size_t count) {
+ size_t length = strnlen(str, count) + 1;
+ char *copy = malloc(length);
+
+ if (!copy)
+ return 0;
+
+ memcpy(copy, str, length);
+ return copy;
+}
+
+/* String tokenizer */
+
+static char *_strtok_ptr = 0, *_strtok_end_ptr = 0;
+
+char *strtok(char *restrict str, const char *restrict delim) {
+ if (str) {
+ _strtok_ptr = str;
+ _strtok_end_ptr = &str[strlen(str)];
}
- if(base == 0)
- if(*nptr == '0')
- base = 8;
- else
- base = 10;
+ if (_strtok_ptr >= _strtok_end_ptr)
+ return 0;
+ if (!(*_strtok_ptr))
+ return 0;
+
+ char *split = strstr(_strtok_ptr, delim);
+ char *token = _strtok_ptr;
+
+ if (split) {
+ *(split++) = 0;
+ _strtok_ptr = split;
+ } else {
+ _strtok_ptr += strlen(token);
+ }
- if(!(base >= 2 && base <= 36))
+ return token;
+}
+
+/* Number parsers */
+
+long long strtoll(const char *restrict str, char **restrict str_end, int base) {
+ if (!str)
return 0;
- if(base == 16 && *nptr == '0')
- {
- if(*(nptr+1) == 'x' || *(nptr+1) == 'X')
- nptr+=2;
+ while (isspace(*str))
+ str++;
+
+ int negative = (*str == '-');
+ if (negative)
+ str++;
+
+ while (isspace(*str))
+ str++;
+
+ // Parse any base prefix if present. If a base was specified make sure it
+ // matches, otherwise use it to determine which base the value is in.
+ long long value = 0;
+
+ if (*str == '0') {
+ int _base;
+
+ switch (str[1]) {
+ case 0:
+ goto _exit_loop;
+
+ case 'X':
+ case 'x':
+ _base = 16;
+ str += 2;
+ break;
+
+ case 'O':
+ case 'o':
+ _base = 8;
+ str += 2;
+ break;
+
+ case 'B':
+ case 'b':
+ _base = 2;
+ str += 2;
+ break;
+
+ default:
+ // Numbers starting with a zero are *not* interpreted as octal
+ // unless base = 8.
+ _base = 0;
+ str++;
+ }
+
+ if (!base)
+ base = _base;
+ else if (base != _base)
+ return 0;
}
- while(*nptr)
- {
- switch(*nptr)
- {
- case '0'...'9':
- t = *nptr - '0';
- break;
- case 'a' ... 'z':
- t = (*nptr - 'a') + 10;
- break;
+ if (!base)
+ base = 10;
+ else if ((base < 2) || (base > 36))
+ return 0;
+
+ // Parse the actual value.
+ for (; *str; str++) {
+ char ch = *str;
+ int digit;
+
+ switch (ch) {
+ case '0' ... '9':
+ digit = ch - '0';
+ break;
+
case 'A' ... 'Z':
- t = (*nptr - 'A') + 10;
- break;
+ digit = (ch - 'A') + 10;
+ break;
+
+ case 'a' ... 'z':
+ digit = (ch - 'a') + 10;
+ break;
+
default:
- t = 1000;
- break;
+ goto _exit_loop;
}
- if(t>=base)
- break;
-
- r*=base;
- r+=t;
- nptr++;
+ value = (value * base) + digit;
}
- if(endptr)*endptr = (char*)nptr;
- return n?-r:r;
+_exit_loop:
+ if (str_end)
+ *str_end = (char *) str;
+
+ return negative ? (-value) : value;
}
-long strtol(const char *nptr, char **endptr, int base)
-{
- return (long)strtoll(nptr, endptr, base);
+long strtol(const char *restrict str, char **restrict str_end, int base) {
+ return (long) strtoll(str, str_end, base);
}
#ifdef ALLOW_FLOAT
-double strtod(const char *nptr, char **endptr)
-{
+double strtod(const char *restrict str, char **restrict str_end) {
char strbuf[64];
int x = 0;
int y;
double i=0, d=0;
int s=1;
- if(*nptr == '-')
+ if(*str == '-')
{
- nptr++;
+ str++;
s=-1;
}
- while(*nptr >= '0' && *nptr <= '9' && x < 18)
- strbuf[x++] = *(nptr++);
+ while(*str >= '0' && *str <= '9' && x < 18)
+ strbuf[x++] = *(str++);
strbuf[x] = 0;
i = (double)strtoll(strbuf, NULL, 10);
- if(*nptr == '.')
+ if(*str == '.')
{
- nptr++;
+ str++;
x = 0;
- while(*nptr >= '0' && *nptr <= '9' && x < 7)
- strbuf[x++] = *(nptr++);
+ while(*str >= '0' && *str <= '9' && x < 7)
+ strbuf[x++] = *(str++);
strbuf[x] = 0;
- if(endptr != NULL) *endptr = (char*)nptr;
+ if(str_end != NULL) *str_end = (char*)str;
y=1;
@@ -301,67 +463,19 @@ double strtod(const char *nptr, char **endptr)
}
else
{
- if(endptr != NULL)
- *endptr = (char*)nptr;
+ if(str_end != NULL)
+ *str_end = (char*)str;
}
return (i + d)*s;
}
-#endif
-
-/* implementation by Lameguy64, behaves like OpenWatcom's strtok() */
-/* BIOS strtok seemed either bugged, or designed for wide chars */
-
-static char *_strtok_curpos;
-static char *_strtok_endpos;
-
-char *strtok( char *s1, char *s2 )
-{
- char *c,*t;
-
- if( s1 )
- {
- _strtok_curpos = s1;
- _strtok_endpos = s1+strlen( s1 );
- }
- else
- {
- if( _strtok_curpos >= _strtok_endpos )
- return( NULL );
- }
-
- if( !*_strtok_curpos )
- return( NULL );
-
- if( c = strstr( _strtok_curpos, s2 ) )
- {
- *c = 0;
- t = _strtok_curpos;
- _strtok_curpos = c+1;
- return( t );
- }
- else
- {
- t = _strtok_curpos;
- _strtok_curpos += strlen( t );
- return( t );
- }
-
- return( NULL );
-
-} /* strtok */
-
-#ifdef ALLOW_FLOAT
-
-long double strtold(const char *nptr, char **endptr)
-{
- return (long double)strtod(nptr, endptr);
+long double strtold(const char *restrict str, char **restrict str_end) {
+ return (long double) strtod(str, str_end);
}
-float strtof(const char *nptr, char **endptr)
-{
- return (float)strtod(nptr, endptr);
+float strtof(const char *restrict str, char **restrict str_end) {
+ return (float) strtod(str, str_end);
}
#endif