summaryrefslogtreecommitdiffstats
path: root/include/strutils.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/strutils.h')
-rw-r--r--include/strutils.h397
1 files changed, 397 insertions, 0 deletions
diff --git a/include/strutils.h b/include/strutils.h
new file mode 100644
index 0000000..ea10272
--- /dev/null
+++ b/include/strutils.h
@@ -0,0 +1,397 @@
+#ifndef UTIL_LINUX_STRUTILS
+#define UTIL_LINUX_STRUTILS
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+
+#include "c.h"
+
+/* initialize a custom exit code for all *_or_err functions */
+extern void strutils_set_exitcode(int exit_code);
+
+extern int parse_size(const char *str, uintmax_t *res, int *power);
+extern int strtosize(const char *str, uintmax_t *res);
+extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
+
+extern int ul_strtos64(const char *str, int64_t *num, int base);
+extern int ul_strtou64(const char *str, uint64_t *num, int base);
+extern int ul_strtos32(const char *str, int32_t *num, int base);
+extern int ul_strtou32(const char *str, uint32_t *num, int base);
+
+extern int64_t str2num_or_err(const char *str, int base, const char *errmesg, int64_t low, int64_t up);
+extern uint64_t str2unum_or_err(const char *str, int base, const char *errmesg, uint64_t up);
+
+#define strtos64_or_err(_s, _e) str2num_or_err(_s, 10, _e, 0, 0)
+#define strtou64_or_err(_s, _e) str2unum_or_err(_s, 10, _e, 0)
+#define strtox64_or_err(_s, _e) str2unum_or_err(_s, 16, _e, 0)
+
+#define strtos32_or_err(_s, _e) (int32_t) str2num_or_err(_s, 10, _e, INT32_MIN, INT32_MAX)
+#define strtou32_or_err(_s, _e) (uint32_t) str2unum_or_err(_s, 10, _e, UINT32_MAX)
+#define strtox32_or_err(_s, _e) (uint32_t) str2unum_or_err(_s, 16, _e, UINT32_MAX)
+
+#define strtos16_or_err(_s, _e) (int16_t) str2num_or_err(_s, 10, _e, INT16_MIN, INT16_MAX)
+#define strtou16_or_err(_s, _e) (uint16_t) str2unum_or_err(_s, 10, _e, UINT16_MAX)
+#define strtox16_or_err(_s, _e) (uint16_t) str2unum_or_err(_s, 16, _e, UINT16_MAX)
+
+extern double strtod_or_err(const char *str, const char *errmesg);
+extern long double strtold_or_err(const char *str, const char *errmesg);
+
+extern long strtol_or_err(const char *str, const char *errmesg);
+extern unsigned long strtoul_or_err(const char *str, const char *errmesg);
+
+extern void strtotimeval_or_err(const char *str, struct timeval *tv,
+ const char *errmesg);
+extern time_t strtotime_or_err(const char *str, const char *errmesg);
+
+extern int isdigit_strend(const char *str, const char **end);
+#define isdigit_string(_s) isdigit_strend(_s, NULL)
+
+extern int isxdigit_strend(const char *str, const char **end);
+#define isxdigit_string(_s) isxdigit_strend(_s, NULL)
+
+
+extern int parse_switch(const char *arg, const char *errmesg, ...);
+
+#ifndef HAVE_MEMPCPY
+extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n);
+#endif
+#ifndef HAVE_STRNLEN
+extern size_t strnlen(const char *s, size_t maxlen);
+#endif
+#ifndef HAVE_STRNDUP
+extern char *strndup(const char *s, size_t n);
+#endif
+#ifndef HAVE_STRNCHR
+extern char *strnchr(const char *s, size_t maxlen, int c);
+#endif
+
+/* caller guarantees n > 0 */
+static inline void xstrncpy(char *dest, const char *src, size_t n)
+{
+ size_t len = src ? strlen(src) : 0;
+
+ if (!len)
+ return;
+ len = min(len, n - 1);
+ memcpy(dest, src, len);
+ dest[len] = 0;
+}
+
+/* This is like strncpy(), but based on memcpy(), so compilers and static
+ * analyzers do not complain when sizeof(destination) is the same as 'n' and
+ * result is not terminated by zero.
+ *
+ * Use this function to copy string to logs with fixed sizes (wtmp/utmp. ...)
+ * where string terminator is optional.
+ */
+static inline void * __attribute__((nonnull (1)))
+str2memcpy(void *dest, const char *src, size_t n)
+{
+ size_t bytes = strlen(src) + 1;
+
+ if (bytes > n)
+ bytes = n;
+
+ memcpy(dest, src, bytes);
+ return dest;
+}
+
+static inline char * __attribute__((nonnull (1)))
+mem2strcpy(char *dest, const void *src, size_t n, size_t nmax)
+{
+ if (n + 1 > nmax)
+ n = nmax - 1;
+
+ memset(dest, '\0', nmax);
+ memcpy(dest, src, n);
+ return dest;
+}
+
+/* Reallocate @str according to @newstr and copy @newstr to @str; returns new @str.
+ * The @str is not modified if reallocation failed (like classic realloc()).
+ */
+static inline char * __attribute__((warn_unused_result))
+strrealloc(char *str, const char *newstr)
+{
+ size_t nsz, osz;
+
+ if (!str)
+ return newstr ? strdup(newstr) : NULL;
+ if (!newstr)
+ return NULL;
+
+ osz = strlen(str);
+ nsz = strlen(newstr);
+
+ if (nsz > osz)
+ str = realloc(str, nsz + 1);
+ if (str)
+ memcpy(str, newstr, nsz + 1);
+ return str;
+}
+
+/* Copy string @str to struct @stru to member addressed by @offset */
+static inline int strdup_to_offset(void *stru, size_t offset, const char *str)
+{
+ char **o;
+ char *p = NULL;
+
+ if (!stru)
+ return -EINVAL;
+
+ o = (char **) ((char *) stru + offset);
+ if (str) {
+ p = strdup(str);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(*o);
+ *o = p;
+ return 0;
+}
+
+/* Copy string __str to struct member _m of the struct _s */
+#define strdup_to_struct_member(_s, _m, _str) \
+ strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str)
+
+/* Copy string addressed by @offset between two structs */
+static inline int strdup_between_offsets(void *stru_dst, void *stru_src, size_t offset)
+{
+ char **src;
+ char **dst;
+ char *p = NULL;
+
+ if (!stru_src || !stru_dst)
+ return -EINVAL;
+
+ src = (char **) ((char *) stru_src + offset);
+ dst = (char **) ((char *) stru_dst + offset);
+
+ if (*src) {
+ p = strdup(*src);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(*dst);
+ *dst = p;
+ return 0;
+}
+
+/* Copy string addressed by struct member between two instances of the same
+ * struct type */
+#define strdup_between_structs(_dst, _src, _m) \
+ strdup_between_offsets((void *)_dst, (void *)_src, offsetof(__typeof__(*(_src)), _m))
+
+
+extern char *xstrmode(mode_t mode, char *str);
+
+/* Options for size_to_human_string() */
+enum
+{
+ SIZE_SUFFIX_1LETTER = 0,
+ SIZE_SUFFIX_3LETTER = (1 << 0),
+ SIZE_SUFFIX_SPACE = (1 << 1),
+ SIZE_DECIMAL_2DIGITS = (1 << 2)
+};
+
+extern char *size_to_human_string(int options, uint64_t bytes);
+
+extern int string_to_idarray(const char *list, int ary[], size_t arysz,
+ int (name2id)(const char *, size_t));
+extern int string_add_to_idarray(const char *list, int ary[],
+ size_t arysz, size_t *ary_pos,
+ int (name2id)(const char *, size_t));
+
+extern int string_to_bitarray(const char *list, char *ary,
+ int (*name2bit)(const char *, size_t));
+
+extern int string_to_bitmask(const char *list,
+ unsigned long *mask,
+ long (*name2flag)(const char *, size_t));
+extern int parse_range(const char *str, int *lower, int *upper, int def);
+
+extern int streq_paths(const char *a, const char *b);
+
+/*
+ * Match string beginning.
+ */
+static inline const char *startswith(const char *s, const char *prefix)
+{
+ size_t sz = prefix ? strlen(prefix) : 0;
+
+ if (s && sz && strncmp(s, prefix, sz) == 0)
+ return s + sz;
+ return NULL;
+}
+
+/*
+ * Case insensitive match string beginning.
+ */
+static inline const char *startswith_no_case(const char *s, const char *prefix)
+{
+ size_t sz = prefix ? strlen(prefix) : 0;
+
+ if (s && sz && strncasecmp(s, prefix, sz) == 0)
+ return s + sz;
+ return NULL;
+}
+
+/*
+ * Match string ending.
+ */
+static inline const char *endswith(const char *s, const char *postfix)
+{
+ size_t sl = s ? strlen(s) : 0;
+ size_t pl = postfix ? strlen(postfix) : 0;
+
+ if (pl == 0)
+ return s + sl;
+ if (sl < pl)
+ return NULL;
+ if (memcmp(s + sl - pl, postfix, pl) != 0)
+ return NULL;
+ return s + sl - pl;
+}
+
+/*
+ * Skip leading white space.
+ */
+static inline const char *skip_space(const char *p)
+{
+ while (isspace(*p))
+ ++p;
+ return p;
+}
+
+static inline const char *skip_blank(const char *p)
+{
+ while (isblank(*p))
+ ++p;
+ return p;
+}
+
+
+/* Removes whitespace from the right-hand side of a string (trailing
+ * whitespace).
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t rtrim_whitespace(unsigned char *str)
+{
+ size_t i;
+
+ if (!str)
+ return 0;
+ i = strlen((char *) str);
+ while (i) {
+ i--;
+ if (!isspace(str[i])) {
+ i++;
+ break;
+ }
+ }
+ str[i] = '\0';
+ return i;
+}
+
+/* Removes whitespace from the left-hand side of a string.
+ *
+ * Returns size of the new string (without \0).
+ */
+static inline size_t ltrim_whitespace(unsigned char *str)
+{
+ size_t len;
+ unsigned char *p;
+
+ if (!str)
+ return 0;
+ for (p = str; *p && isspace(*p); p++);
+
+ len = strlen((char *) p);
+
+ if (p > str)
+ memmove(str, p, len + 1);
+
+ return len;
+}
+
+/* Removes left-hand, right-hand and repeating whitespaces.
+ */
+static inline size_t __normalize_whitespace(
+ const unsigned char *src,
+ size_t sz,
+ unsigned char *dst,
+ size_t len)
+{
+ size_t i, x = 0;
+ int nsp = 0, intext = 0;
+
+ if (!sz)
+ goto done;
+
+ for (i = 0, x = 0; i < sz && x < len - 1; ) {
+ if (isspace(src[i]))
+ nsp++;
+ else
+ nsp = 0, intext = 1;
+
+ if (nsp > 1 || (nsp && !intext))
+ i++;
+ else
+ dst[x++] = src[i++];
+ }
+ if (nsp && x > 0) /* tailing space */
+ x--;
+done:
+ dst[x] = '\0';
+ return x;
+}
+
+static inline size_t normalize_whitespace(unsigned char *str)
+{
+ size_t sz = strlen((char *) str);
+ return __normalize_whitespace(str, sz, str, sz + 1);
+}
+
+static inline void strrep(char *s, int find, int replace)
+{
+ while (s && *s && (s = strchr(s, find)) != NULL)
+ *s++ = replace;
+}
+
+static inline void strrem(char *s, int rem)
+{
+ char *p;
+
+ if (!s)
+ return;
+ for (p = s; *s; s++) {
+ if (*s != rem)
+ *p++ = *s;
+ }
+ *p = '\0';
+}
+
+extern char *strnconcat(const char *s, const char *suffix, size_t b);
+extern char *strconcat(const char *s, const char *suffix);
+extern char *strfconcat(const char *s, const char *format, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
+
+extern int strappend(char **a, const char *b);
+
+extern const char *split(const char **state, size_t *l, const char *separator, int quoted);
+
+extern char *ul_strchr_escaped(const char *s, int c);
+
+extern int skip_fline(FILE *fp);
+extern int ul_stralnumcmp(const char *p1, const char *p2);
+
+#endif