| // Basic string routines.  Not hardware optimized, but not shabby. | 
 |  | 
 | #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++) { | 
 | 		*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) | 
 | { | 
 | 	if (size > 0) { | 
 | 		while (--size > 0 && *src != '\0') | 
 | 			*dst++ = *src++; | 
 | 		*dst = '\0'; | 
 | 	} | 
 |  | 
 | 	return strlen(src); | 
 | } | 
 |  | 
 | size_t strlcat(char *dst, const char *src, size_t size) | 
 | { | 
 | 	size_t rem;	/* Buffer space remaining after null in dst. */ | 
 |  | 
 | 	/* We must find the terminating NUL byte in dst, but abort the | 
 | 	 * search if we go past 'size' bytes.  At the end of this loop, | 
 | 	 * 'dst' will point to either the NUL byte in the original | 
 | 	 * destination or to one byte beyond the end of the buffer. | 
 | 	 * | 
 | 	 * 'rem' will be the amount of 'size' remaining beyond the NUL byte; | 
 | 	 * potentially zero. This implies that 'size - rem' is equal to the | 
 | 	 * distance from the beginning of the destination buffer to 'dst'. | 
 | 	 * | 
 | 	 * The return value of strlcat is the sum of the length of the | 
 | 	 * original destination buffer (size - rem) plus the size of the | 
 | 	 * src string (the return value of strlcpy). */ | 
 | 	rem = size; | 
 | 	while ((rem > 0) && (*dst != '\0')) { | 
 | 		rem--; | 
 | 		dst++; | 
 | 	} | 
 |  | 
 | 	return (size - rem) + strlcpy(dst, src, rem); | 
 | } | 
 |  | 
 | 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(const 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 *v, int c, size_t _n) | 
 | { | 
 | 	char *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 *dst, const void *src, size_t _n) | 
 | { | 
 | #ifdef CONFIG_X86 | 
 | 	bcopy(src, dst, _n); | 
 | 	return dst; | 
 | #else | 
 | 	const char *s; | 
 | 	char *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 *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; | 
 | 	const void *s = _s; | 
 | 	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); | 
 | } | 
 |  | 
 | 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; | 
 | } |