diff options
Diffstat (limited to 'libpsn00b/libc/string.c')
| -rw-r--r-- | libpsn00b/libc/string.c | 604 |
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 |
