286 lines
4.7 KiB
C
286 lines
4.7 KiB
C
// Basic string routines. Not hardware optimized, but not shabby.
|
|
|
|
#include <inc/string.h>
|
|
|
|
// Using assembly for memset/memmove
|
|
// makes some difference on real hardware,
|
|
// but it makes an even bigger difference on bochs.
|
|
// Primespipe runs 3x faster this way.
|
|
#define ASM 1
|
|
|
|
int
|
|
strlen(const char *s)
|
|
{
|
|
int n;
|
|
|
|
for (n = 0; *s != '\0'; s++)
|
|
n++;
|
|
return n;
|
|
}
|
|
|
|
int
|
|
strnlen(const char *s, size_t size)
|
|
{
|
|
int n;
|
|
|
|
for (n = 0; size > 0 && *s != '\0'; s++, size--)
|
|
n++;
|
|
return n;
|
|
}
|
|
|
|
char *
|
|
strcpy(char *dst, const char *src)
|
|
{
|
|
char *ret;
|
|
|
|
ret = dst;
|
|
while ((*dst++ = *src++) != '\0')
|
|
/* do nothing */;
|
|
return ret;
|
|
}
|
|
|
|
char *
|
|
strcat(char *dst, const char *src)
|
|
{
|
|
int len = strlen(dst);
|
|
strcpy(dst + len, src);
|
|
return dst;
|
|
}
|
|
|
|
char *
|
|
strncpy(char *dst, const char *src, size_t size) {
|
|
size_t i;
|
|
char *ret;
|
|
|
|
ret = dst;
|
|
for (i = 0; i < size; i++) {
|
|
*dst++ = *src;
|
|
// If strlen(src) < size, null-pad 'dst' out to 'size' chars
|
|
if (*src != '\0')
|
|
src++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
size_t
|
|
strlcpy(char *dst, const char *src, size_t size)
|
|
{
|
|
char *dst_in;
|
|
|
|
dst_in = dst;
|
|
if (size > 0) {
|
|
while (--size > 0 && *src != '\0')
|
|
*dst++ = *src++;
|
|
*dst = '\0';
|
|
}
|
|
return dst - dst_in;
|
|
}
|
|
|
|
int
|
|
strcmp(const char *p, const char *q)
|
|
{
|
|
while (*p && *p == *q)
|
|
p++, q++;
|
|
return (int) ((unsigned char) *p - (unsigned char) *q);
|
|
}
|
|
|
|
int
|
|
strncmp(const char *p, const char *q, size_t n)
|
|
{
|
|
while (n > 0 && *p && *p == *q)
|
|
n--, p++, q++;
|
|
if (n == 0)
|
|
return 0;
|
|
else
|
|
return (int) ((unsigned char) *p - (unsigned char) *q);
|
|
}
|
|
|
|
// Return a pointer to the first occurrence of 'c' in 's',
|
|
// or a null pointer if the string has no 'c'.
|
|
char *
|
|
strchr(const char *s, char c)
|
|
{
|
|
for (; *s; s++)
|
|
if (*s == c)
|
|
return (char *) s;
|
|
return 0;
|
|
}
|
|
|
|
// Return a pointer to the first occurrence of 'c' in 's',
|
|
// or a pointer to the string-ending null character if the string has no 'c'.
|
|
char *
|
|
strfind(const char *s, char c)
|
|
{
|
|
for (; *s; s++)
|
|
if (*s == c)
|
|
break;
|
|
return (char *) s;
|
|
}
|
|
|
|
#if ASM
|
|
void *
|
|
memset(void *v, int c, size_t n)
|
|
{
|
|
char *p;
|
|
|
|
if (n == 0)
|
|
return v;
|
|
if ((int)v%4 == 0 && n%4 == 0) {
|
|
c &= 0xFF;
|
|
c = (c<<24)|(c<<16)|(c<<8)|c;
|
|
asm volatile("cld; rep stosl\n"
|
|
:: "D" (v), "a" (c), "c" (n/4)
|
|
: "cc", "memory");
|
|
} else
|
|
asm volatile("cld; rep stosb\n"
|
|
:: "D" (v), "a" (c), "c" (n)
|
|
: "cc", "memory");
|
|
return v;
|
|
}
|
|
|
|
void *
|
|
memmove(void *dst, const void *src, size_t n)
|
|
{
|
|
const char *s;
|
|
char *d;
|
|
|
|
s = src;
|
|
d = dst;
|
|
if (s < d && s + n > d) {
|
|
s += n;
|
|
d += n;
|
|
if ((int)s%4 == 0 && (int)d%4 == 0 && n%4 == 0)
|
|
asm volatile("std; rep movsl\n"
|
|
:: "D" (d-4), "S" (s-4), "c" (n/4) : "cc", "memory");
|
|
else
|
|
asm volatile("std; rep movsb\n"
|
|
:: "D" (d-1), "S" (s-1), "c" (n) : "cc", "memory");
|
|
// Some versions of GCC rely on DF being clear
|
|
asm volatile("cld" ::: "cc");
|
|
} else {
|
|
if ((int)s%4 == 0 && (int)d%4 == 0 && n%4 == 0)
|
|
asm volatile("cld; rep movsl\n"
|
|
:: "D" (d), "S" (s), "c" (n/4) : "cc", "memory");
|
|
else
|
|
asm volatile("cld; rep movsb\n"
|
|
:: "D" (d), "S" (s), "c" (n) : "cc", "memory");
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
#else
|
|
|
|
void *
|
|
memset(void *v, int c, size_t n)
|
|
{
|
|
char *p;
|
|
int m;
|
|
|
|
p = v;
|
|
m = n;
|
|
while (--m >= 0)
|
|
*p++ = c;
|
|
|
|
return v;
|
|
}
|
|
|
|
void *
|
|
memmove(void *dst, const void *src, size_t n)
|
|
{
|
|
const char *s;
|
|
char *d;
|
|
|
|
s = src;
|
|
d = dst;
|
|
if (s < d && s + n > d) {
|
|
s += n;
|
|
d += n;
|
|
while (n-- > 0)
|
|
*--d = *--s;
|
|
} else
|
|
while (n-- > 0)
|
|
*d++ = *s++;
|
|
|
|
return dst;
|
|
}
|
|
#endif
|
|
|
|
void *
|
|
memcpy(void *dst, const void *src, size_t n)
|
|
{
|
|
return memmove(dst, src, n);
|
|
}
|
|
|
|
int
|
|
memcmp(const void *v1, const void *v2, size_t n)
|
|
{
|
|
const uint8_t *s1 = (const uint8_t *) v1;
|
|
const uint8_t *s2 = (const uint8_t *) v2;
|
|
|
|
while (n-- > 0) {
|
|
if (*s1 != *s2)
|
|
return (int) *s1 - (int) *s2;
|
|
s1++, s2++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *
|
|
memfind(const void *s, int c, size_t n)
|
|
{
|
|
const void *ends = (const char *) s + n;
|
|
for (; s < ends; s++)
|
|
if (*(const unsigned char *) s == (unsigned char) c)
|
|
break;
|
|
return (void *) s;
|
|
}
|
|
|
|
long
|
|
strtol(const char *s, char **endptr, int base)
|
|
{
|
|
int neg = 0;
|
|
long val = 0;
|
|
|
|
// gobble initial whitespace
|
|
while (*s == ' ' || *s == '\t')
|
|
s++;
|
|
|
|
// plus/minus sign
|
|
if (*s == '+')
|
|
s++;
|
|
else if (*s == '-')
|
|
s++, neg = 1;
|
|
|
|
// hex or octal base prefix
|
|
if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x'))
|
|
s += 2, base = 16;
|
|
else if (base == 0 && s[0] == '0')
|
|
s++, base = 8;
|
|
else if (base == 0)
|
|
base = 10;
|
|
|
|
// digits
|
|
while (1) {
|
|
int dig;
|
|
|
|
if (*s >= '0' && *s <= '9')
|
|
dig = *s - '0';
|
|
else if (*s >= 'a' && *s <= 'z')
|
|
dig = *s - 'a' + 10;
|
|
else if (*s >= 'A' && *s <= 'Z')
|
|
dig = *s - 'A' + 10;
|
|
else
|
|
break;
|
|
if (dig >= base)
|
|
break;
|
|
s++, val = (val * base) + dig;
|
|
// we don't properly detect overflow!
|
|
}
|
|
|
|
if (endptr)
|
|
*endptr = (char *) s;
|
|
return (neg ? -val : val);
|
|
}
|
|
|