blob: 829c1b6e51f9494b5a3c92a7500e87f203e080fd [file] [log] [blame] [edit]
// Basic string routines. Not hardware optimized, but not shabby.
#ifdef __SHARC__
#pragma nosharc
#endif
#include <stdio.h>
#include <string.h>
#include <ros/memlayout.h>
#include <assert.h>
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;
}
/* zra: These aren't being used, and they are dangerous, so I'm rm'ing them
char *
strcpy(char *dst, const char *src)
{
char *ret;
ret = dst;
while ((*dst++ = *src++) != '\0')
;
return ret;
}
char *
strcat(char *dst, const char *src)
{
strcpy(dst+strlen(dst),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++) {
// TODO: ivy bitches about this
*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 last occurrence of 'c' in 's',
// or a null pointer if the string has no 'c'.
char *
strrchr(const char *s, char c)
{
char *lastc = NULL;
for (; *s; s++)
if (*s == c){
lastc = (char*)s;
}
return lastc;
}
void *
memchr(void* mem, int chr, int len)
{
char* s = (char*)mem;
for(int i = 0; i < len; i++)
if(s[i] == (char)chr)
return s+i;
return NULL;
}
// 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;
}
// memset aligned words.
static inline void *
memsetw(long* _v, long c, size_t n)
{
long *start, *end, *v;
start = _v;
end = _v + n/sizeof(long);
v = _v;
c = c & 0xff;
c = c | c<<8;
c = c | c<<16;
#if NUM_ADDR_BITS == 64
c = c | c<<32;
#elif NUM_ADDR_BITS != 32
# error
#endif
while(v < end - (8-1))
{
v[3] = v[2] = v[1] = v[0] = c;
v += 4;
v[3] = v[2] = v[1] = v[0] = c;
v += 4;
}
while(v < end)
*v++ = c;
return start;
}
// copy aligned words.
// unroll 9 ways to get multiple misses in flight
#define memcpyw(type, _dst, _src, n) \
do { \
type* restrict src = (type*)(_src); \
type* restrict dst = (type*)(_dst); \
type* srcend = src + (n)/sizeof(type); \
type* dstend = dst + (n)/sizeof(type); \
while (dst < dstend - (9-1)) { \
dst[0] = src[0]; \
dst[1] = src[1]; \
dst[2] = src[2]; \
dst[3] = src[3]; \
dst[4] = src[4]; \
dst[5] = src[5]; \
dst[6] = src[6]; \
dst[7] = src[7]; \
dst[8] = src[8]; \
src += 9; \
dst += 9; \
} \
while(dst < dstend) \
*dst++ = *src++; \
} while(0)
void *
memset(void *COUNT(_n) v, int c, size_t _n)
{
char *BND(v,v+_n) p;
size_t n0;
size_t n = _n;
if (n == 0) return NULL; // zra: complain here?
p = v;
while (n > 0 && ((uintptr_t)p & (sizeof(long)-1)))
{
*p++ = c;
n--;
}
if (n >= sizeof(long))
{
n0 = n / sizeof(long) * sizeof(long);
memsetw((long*)p, c, n0);
n -= n0;
p += n0;
}
while (n > 0)
{
*p++ = c;
n--;
}
return v;
}
void *
memcpy(void* dst, const void* src, size_t _n)
{
const char* s;
char* d;
size_t n0 = 0;
size_t n = _n;
int align = sizeof(long)-1;
s = src;
d = dst;
if ((((uintptr_t)s | (uintptr_t)d) & (sizeof(long)-1)) == 0)
{
n0 = n / sizeof(long) * sizeof(long);
memcpyw(long, d, s, n0);
}
else if ((((uintptr_t)s | (uintptr_t)d) & (sizeof(int)-1)) == 0)
{
n0 = n / sizeof(int) * sizeof(int);
memcpyw(int, d, s, n0);
}
else if ((((uintptr_t)s | (uintptr_t)d) & (sizeof(short)-1)) == 0)
{
n0 = n / sizeof(short) * sizeof(short);
memcpyw(short, d, s, n0);
}
n -= n0;
s += n0;
d += n0;
while (n-- > 0)
*d++ = *s++;
return dst;
}
void *
memmove(void *COUNT(_n) dst, const void *COUNT(_n) src, size_t _n)
{
#ifdef CONFIG_X86
bcopy(src, dst, _n);
return dst;
#else
const char *BND(src,src+_n) s;
char *BND(dst,dst+_n) d;
size_t n = _n;
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
}
int
memcmp(const void *COUNT(n) v1, const void *COUNT(n) v2, size_t n)
{
const uint8_t *BND(v1,v1+n) s1 = (const uint8_t *) v1;
const uint8_t *BND(v2,v2+n) s2 = (const uint8_t *) v2;
while (n-- > 0) {
if (*s1 != *s2)
return (int) *s1 - (int) *s2;
s1++, s2++;
}
return 0;
}
void *
memfind(const void *COUNT(n) _s, int c, size_t n)
{
const void *SNT ends = (const char *) _s + n;
const void *BND(_s,_s + n) s = _s;
for (; s < ends; s++)
if (*(const unsigned char *) s == (unsigned char) c)
break;
return (void *BND(_s,_s+n)) 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);
}
unsigned long
strtoul(const char *s, char **endptr, int base)
{
int neg = 0;
unsigned 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);
}
int atoi(const char *s)
{
if (!s)
return 0;
if (s[0] == '0' && s[1] == 'x')
warn("atoi() used on a hex string!");
// no overflow detection
return (int)strtol(s,NULL,10);
}
int sigchecksum(void *address, int length)
{
uint8_t *p, sum;
sum = 0;
for (p = address; length-- > 0; p++)
sum += *p;
return sum;
}
void *sigscan(uint8_t *address, int length, char *signature)
{
uint8_t *e, *p;
int siglength;
e = address + length;
siglength = strlen(signature);
for (p = address; p + siglength < e; p += 16) {
if (memcmp(p, signature, siglength))
continue;
return p;
}
return NULL;
}