diff options
| -rw-r--r-- | include/str.h | 147 |
1 files changed, 126 insertions, 21 deletions
diff --git a/include/str.h b/include/str.h index a6fbfefd..0c34256d 100644 --- a/include/str.h +++ b/include/str.h @@ -3,7 +3,13 @@ #ifndef SHIM_STR_H #define SHIM_STR_H -static inline __attribute__((unused)) unsigned long +#ifdef SHIM_UNIT_TEST +#pragma GCC diagnostic error "-Wnonnull-compare" +#else +#pragma GCC diagnostic ignored "-Wnonnull-compare" +#endif + +static inline UNUSED NONNULL(1) unsigned long strnlena(const CHAR8 *s, unsigned long n) { unsigned long i; @@ -13,9 +19,7 @@ strnlena(const CHAR8 *s, unsigned long n) return i; } -static inline -__attribute__((unused)) -CHAR8 * +static inline UNUSED RETURNS_NONNULL NONNULL(1, 2) CHAR8 * strncpya(CHAR8 *dest, const CHAR8 *src, unsigned long n) { unsigned long i; @@ -28,9 +32,7 @@ strncpya(CHAR8 *dest, const CHAR8 *src, unsigned long n) return dest; } -static inline -__attribute__((unused)) -CHAR8 * +static inline UNUSED RETURNS_NONNULL NONNULL(1, 2) CHAR8 * strcata(CHAR8 *dest, const CHAR8 *src) { unsigned long dest_len = strlena(dest); @@ -43,16 +45,24 @@ strcata(CHAR8 *dest, const CHAR8 *src) return dest; } -static inline -__attribute__((unused)) -CHAR8 * -strndupa(const CHAR8 * const src, const UINTN srcmax) +static inline UNUSED NONNULL(1) CHAR8 * +strdup(const CHAR8 * const src) { UINTN len; CHAR8 *news = NULL; - if (!src || !srcmax) - return news; + len = strlena(src); + news = AllocateZeroPool(len + 1); + if (news) + strncpya(news, src, len); + return news; +} + +static inline UNUSED NONNULL(1) CHAR8 * +strndupa(const CHAR8 * const src, const UINTN srcmax) +{ + UINTN len; + CHAR8 *news = NULL; len = strnlena(src, srcmax); news = AllocateZeroPool(len + 1); @@ -61,9 +71,17 @@ strndupa(const CHAR8 * const src, const UINTN srcmax) return news; } -static inline -__attribute__((unused)) -CHAR8 * +static inline UNUSED RETURNS_NONNULL NONNULL(1, 2) char * +stpcpy(char *dest, const char * const src) +{ + size_t i = 0; + for (i = 0; src[i]; i++) + dest[i] = src[i]; + dest[i] = '\000'; + return &dest[i]; +} + +static inline UNUSED CHAR8 * translate_slashes(CHAR8 *out, const char *str) { int i; @@ -83,21 +101,18 @@ translate_slashes(CHAR8 *out, const char *str) return out; } -static inline UNUSED CHAR8 * +static inline UNUSED RETURNS_NONNULL NONNULL(1) CHAR8 * strchrnula(const CHAR8 *s, int c) { unsigned int i; - if (s == NULL) - return NULL; - for (i = 0; s[i] != '\000' && s[i] != c; i++) ; return (CHAR8 *)&s[i]; } -static inline UNUSED CHAR8 * +static inline UNUSED NONNULL(1) CHAR8 * strchra(const CHAR8 *s, int c) { const CHAR8 *s1; @@ -109,4 +124,94 @@ strchra(const CHAR8 *s, int c) return (CHAR8 *)s1; } +static inline UNUSED RETURNS_NONNULL NONNULL(1) char * +strnchrnul(const char *s, size_t max, int c) +{ + unsigned int i; + + if (!s || !max) + return (char *)s; + + for (i = 0; i < max && s[i] != '\0' && s[i] != c; i++) + ; + + if (i == max) + i--; + + return (char *)&s[i]; +} + +/** + * strntoken: tokenize a string, with a limit + * str: your string (will be modified) + * max: maximum number of bytes to ever touch + * delims: string of one character delimeters, any of which will tokenize + * *token: the token we're passing back (must be a pointer to NULL initially) + * state: a pointer to one char of state for between calls + * + * Ensure that both token and state are preserved across calls. Do: + * char state = 0; + * char *token = NULL; + * for (...) { + * valid = strntoken(...) + * not: + * char state = 0; + * for (...) { + * char *token = NULL; + * valid = strntoken(...) + * + * - it will not test bytes beyond str[max-1] + * - it will not set *token to an address beyond &str[max-1] + * - it will set *token to &str[max-1] without testing &str[max-2] for + * &str[max-1] == str + * - sequences of multiple delimeters will result in empty (pointer to '\0') + * tokens. + * - it expects you to update str and max on successive calls. + * + * return: + * true means it hasn't tested str[max-1] yet and token is valid + * false means it got to a NUL or str[max-1] and token is invalid + */ +static inline UNUSED NONNULL(1, 3, 4) int +strntoken(char *str, size_t max, const char *delims, char **token, char *state) +{ + char *tokend; + const char *delim; + int isdelim = 0; + int state_is_delim = 0; + + if (!str || !max || !delims || !token || !state) + return 0; + + tokend = &str[max-1]; + if (!str || max == 0 || !delims || !token) + return 0; + + /* + * the very special case of "" with max=1, where we have no prior + * state to let us know this is the same as right after a delim + */ + if (*token == NULL && max == 1 && *str == '\0') { + state_is_delim = 1; + } + + for (delim = delims; *delim; delim++) { + char *tmp = NULL; + if (*token && *delim == *state) + state_is_delim = 1; + tmp = strnchrnul(str, max, *delim); + if (tmp < tokend) + tokend = tmp; + if (*tokend == *delim) + isdelim = 1; + } + *token = str; + if (isdelim) { + *state = *tokend; + *tokend = '\0'; + return 1; + } + return state_is_delim; +} + #endif /* SHIM_STR_H */ |
