/* * libc string functions * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License version 2. */ #include "libcflat.h" #include "ctype.h" #include "stdlib.h" #include "linux/compiler.h" size_t strlen(const char *buf) { size_t len = 0; while (*buf++) ++len; return len; } size_t strnlen(const char *buf, size_t maxlen) { const char *sc; for (sc = buf; maxlen-- && *sc != '\0'; ++sc) /* nothing */ ; return sc - buf; } char *strcat(char *dest, const char *src) { char *p = dest; while (*p) ++p; while ((*p++ = *src++) != 0) ; return dest; } char *strcpy(char *dest, const char *src) { *dest = 0; return strcat(dest, src); } int strncmp(const char *a, const char *b, size_t n) { for (; n--; ++a, ++b) if (*a != *b || *a == '\0') return *a - *b; return 0; } int strncasecmp(const char *a, const char *b, size_t n) { for (; n--; ++a, ++b) if (tolower(*a) != tolower(*b) || *a == '\0') return tolower(*a) - tolower(*b); return 0; } int strcmp(const char *a, const char *b) { return strncmp(a, b, SIZE_MAX); } int strcasecmp(const char *a, const char *b) { return strncasecmp(a, b, SIZE_MAX); } char *strchr(const char *s, int c) { while (*s != (char)c) if (*s++ == '\0') return NULL; return (char *)s; } char *strrchr(const char *s, int c) { const char *last = NULL; do { if (*s == (char)c) last = s; } while (*s++); return (char *)last; } char *strchrnul(const char *s, int c) { while (*s && *s != (char)c) s++; return (char *)s; } char *strstr(const char *s1, const char *s2) { size_t l1, l2; l2 = strlen(s2); if (!l2) return (char *)s1; l1 = strlen(s1); while (l1 >= l2) { l1--; if (!memcmp(s1, s2, l2)) return (char *)s1; s1++; } return NULL; } void *memset(void *s, int c, size_t n) { size_t i; char *a = s; for (i = 0; i < n; ++i) a[i] = c; return s; } void *memcpy(void *dest, const void *src, size_t n) { size_t i; char *a = dest; const char *b = src; for (i = 0; i < n; ++i) a[i] = b[i]; return dest; } int memcmp(const void *s1, const void *s2, size_t n) { const unsigned char *a = s1, *b = s2; int ret = 0; while (n--) { ret = *a - *b; if (ret) break; ++a, ++b; } return ret; } void *memmove(void *dest, const void *src, size_t n) { const unsigned char *s = src; unsigned char *d = dest; if (d <= s) { while (n--) *d++ = *s++; } else { d += n, s += n; while (n--) *--d = *--s; } return dest; } void *memchr(const void *s, int c, size_t n) { const unsigned char *str = s, chr = (unsigned char)c; while (n--) if (*str++ == chr) return (void *)(str - 1); return NULL; } static unsigned long long __strtoll(const char *nptr, char **endptr, int base, bool is_signed, bool is_longlong) { unsigned long long ull = 0; const char *s = nptr; int neg, c; assert(base == 0 || (base >= 2 && base <= 36)); while (isspace(*s)) s++; if (*s == '-') { neg = 1; s++; } else { neg = 0; if (*s == '+') s++; } if (base == 0 || base == 16) { if (*s == '0') { s++; if (*s == 'x' || *s == 'X') { s++; base = 16; } else if (base == 0) base = 8; } else if (base == 0) base = 10; } while (*s) { if (*s >= '0' && *s < '0' + base && *s <= '9') c = *s - '0'; else if (*s >= 'a' && *s < 'a' + base - 10) c = *s - 'a' + 10; else if (*s >= 'A' && *s < 'A' + base - 10) c = *s - 'A' + 10; else break; if (!is_longlong) { if (is_signed) { long sl = (long)ull; assert(!check_mul_overflow(sl, base)); assert(!check_add_overflow(sl * base, c)); } else { unsigned long ul = (unsigned long)ull; assert(!check_mul_overflow(ul, base)); assert(!check_add_overflow(ul * base, c)); } } else { if (is_signed) { long long sll = (long long)ull; assert(!check_mul_overflow(sll, base)); assert(!check_add_overflow(sll * base, c)); } else { assert(!check_mul_overflow(ull, base)); assert(!check_add_overflow(ull * base, c)); } } ull = ull * base + c; s++; } if (neg) ull = -ull; if (endptr) *endptr = (char *)s; return ull; } long int strtol(const char *nptr, char **endptr, int base) { return __strtoll(nptr, endptr, base, true, false); } unsigned long int strtoul(const char *nptr, char **endptr, int base) { return __strtoll(nptr, endptr, base, false, false); } long long int strtoll(const char *nptr, char **endptr, int base) { return __strtoll(nptr, endptr, base, true, true); } unsigned long long int strtoull(const char *nptr, char **endptr, int base) { return __strtoll(nptr, endptr, base, false, true); } long atol(const char *ptr) { return strtol(ptr, NULL, 10); } extern char **environ; char *getenv(const char *name) { char **envp = environ, *delim; int len; while (*envp) { delim = strchr(*envp, '='); assert(delim); len = delim - *envp; if (memcmp(name, *envp, len) == 0 && !name[len]) return delim + 1; ++envp; } return NULL; } /* Very simple glob matching. Allows '*' at beginning and end of pattern. */ bool simple_glob(const char *text, const char *pattern) { bool star_start = false; bool star_end = false; size_t n = strlen(pattern); char copy[n + 1]; if (pattern[0] == '*') { pattern += 1; n -= 1; star_start = true; } strcpy(copy, pattern); if (n > 0 && pattern[n - 1] == '*') { n -= 1; copy[n] = '\0'; star_end = true; } if (star_start && star_end) return strstr(text, copy); if (star_end) return strstr(text, copy) == text; if (star_start) { size_t text_len = strlen(text); const char *suffix; if (n > text_len) return false; suffix = text + text_len - n; return !strcmp(suffix, copy); } return !strcmp(text, copy); }