summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/str.h147
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 */