|  | // 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; | 
|  | } |