| /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| /* Utility functions for Chrome EC */ |
| |
| #include "util.h" |
| |
| int strlen(const char *s) |
| { |
| int len = 0; |
| |
| while (*s++) |
| len++; |
| |
| return len; |
| } |
| |
| |
| int isspace(int c) |
| { |
| return c == ' ' || c == '\t' || c == '\r' || c == '\n'; |
| } |
| |
| |
| int isdigit(int c) |
| { |
| return c >= '0' && c <= '9'; |
| } |
| |
| |
| int isalpha(int c) |
| { |
| return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); |
| } |
| |
| int isprint(int c) |
| { |
| return c >= ' ' && c <= '~'; |
| } |
| |
| int tolower(int c) |
| { |
| return c >= 'A' && c <= 'Z' ? c + 'a' - 'A' : c; |
| } |
| |
| |
| int strcasecmp(const char *s1, const char *s2) |
| { |
| int diff; |
| do { |
| diff = tolower(*s1) - tolower(*s2); |
| if (diff) |
| return diff; |
| } while (*(s1++) && *(s2++)); |
| return 0; |
| } |
| |
| |
| int strncasecmp(const char *s1, const char *s2, int size) |
| { |
| int diff; |
| |
| if (!size) |
| return 0; |
| |
| do { |
| diff = tolower(*s1) - tolower(*s2); |
| if (diff) |
| return diff; |
| } while (*(s1++) && *(s2++) && --size); |
| return 0; |
| } |
| |
| |
| int atoi(const char *nptr) |
| { |
| int result = 0; |
| int neg = 0; |
| char c = '\0'; |
| |
| while ((c = *nptr++) && isspace(c)) {} |
| |
| if (c == '-') { |
| neg = 1; |
| c = *nptr++; |
| } |
| |
| while (isdigit(c)) { |
| result = result * 10 + (c - '0'); |
| c = *nptr++; |
| } |
| |
| return neg ? -result : result; |
| } |
| |
| |
| /* Like strtol(), but for integers */ |
| int strtoi(const char *nptr, char **endptr, int base) |
| { |
| int result = 0; |
| int neg = 0; |
| int c = '\0'; |
| |
| if (endptr) |
| *endptr = (char *)nptr; |
| |
| while((c = *nptr++) && isspace(c)) {} |
| |
| if (c == '0' && *nptr == 'x') { |
| base = 16; |
| c = nptr[1]; |
| nptr += 2; |
| } else if (base == 0) { |
| base = 10; |
| if (c == '-') { |
| neg = 1; |
| c = *nptr++; |
| } |
| } |
| |
| while (c) { |
| if (c >= '0' && c < '0' + MIN(base, 10)) |
| result = result * base + (c - '0'); |
| else if (c >= 'A' && c < 'A' + base - 10) |
| result = result * base + (c - 'A' + 10); |
| else if (c >= 'a' && c < 'a' + base - 10) |
| result = result * base + (c - 'a' + 10); |
| else |
| break; |
| |
| if (endptr) |
| *endptr = (char *)nptr; |
| c = *nptr++; |
| } |
| |
| return neg ? -result : result; |
| } |
| |
| |
| int memcmp(const void *s1, const void *s2, int len) |
| { |
| const char *sa = s1; |
| const char *sb = s2; |
| |
| int diff = 0; |
| while (len-- > 0) { |
| diff = *(sa++) - *(sb++); |
| if (diff) |
| return diff; |
| } |
| |
| return 0; |
| } |
| |
| |
| void *memcpy(void *dest, const void *src, int len) |
| { |
| /* TODO: optimized version using LDM/STM would be much faster */ |
| char *d = (char *)dest; |
| const char *s = (const char *)src; |
| while (len > 0) { |
| *(d++) = *(s++); |
| len--; |
| } |
| return dest; |
| } |
| |
| |
| void *memset(void *dest, int c, int len) |
| { |
| /* TODO: optimized version using STM would be much faster */ |
| char *d = (char *)dest; |
| while (len > 0) { |
| *(d++) = c; |
| len--; |
| } |
| return dest; |
| } |
| |
| |
| void *memmove(void *dest, const void *src, int len) |
| { |
| if ((uint32_t)dest <= (uint32_t)src || |
| (uint32_t)dest >= (uint32_t)src + len) { |
| /* Start of destination doesn't overlap source, so just use |
| * memcpy(). */ |
| return memcpy(dest, src, len); |
| } else { |
| /* Copy from end, so we don't overwrite the source */ |
| char *d = (char *)dest + len; |
| const char *s = (const char *)src + len; |
| /* TODO: optimized version using LDM/STM would be much faster */ |
| while (len > 0) { |
| *(--d) = *(--s); |
| len--; |
| } |
| return dest; |
| } |
| } |
| |
| |
| char *strzcpy(char *dest, const char *src, int len) |
| { |
| char *d = dest; |
| if (len <= 0) |
| return dest; |
| while (len > 1 && *src) { |
| *(d++) = *(src++); |
| len--; |
| } |
| *d = '\0'; |
| return dest; |
| } |
| |
| |
| int uint64divmod(uint64_t *n, int d) |
| { |
| uint64_t q = 0, mask; |
| int r = 0; |
| |
| /* Divide-by-zero returns zero */ |
| if (!d) { |
| *n = 0; |
| return 0; |
| } |
| |
| /* Common powers of 2 = simple shifts */ |
| if (d == 2) { |
| r = *n & 1; |
| *n >>= 1; |
| return r; |
| } else if (d == 16) { |
| r = *n & 0xf; |
| *n >>= 4; |
| return r; |
| } |
| |
| /* If v fits in 32-bit, we're done. */ |
| if (*n <= 0xffffffff) { |
| uint32_t v32 = *n; |
| r = v32 % d; |
| *n = v32 / d; |
| return r; |
| } |
| |
| /* Otherwise do integer division the slow way. */ |
| for (mask = (1ULL << 63); mask; mask >>= 1) { |
| r <<= 1; |
| if (*n & mask) |
| r |= 1; |
| if (r >= d) { |
| r -= d; |
| q |= mask; |
| } |
| } |
| *n = q; |
| return r; |
| } |