]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - include/strutils.h
include/pidfd-utils: small cleanup
[thirdparty/util-linux.git] / include / strutils.h
index 123907fc98e3ebd46f1e9e138aabbacfd34ed938..fc3bb0c1c79e8cddfc78417dc5bc88a80b44669e 100644 (file)
@@ -1,33 +1,53 @@
 #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>
 
-/* default strtoxx_or_err() exit code */
-#ifndef STRTOXX_EXIT_CODE
-# define STRTOXX_EXIT_CODE EXIT_FAILURE
-#endif
-
+/* 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 int16_t strtos16_or_err(const char *str, const char *errmesg);
 extern uint16_t strtou16_or_err(const char *str, const char *errmesg);
+extern uint16_t strtox16_or_err(const char *str, const char *errmesg);
 
 extern int32_t strtos32_or_err(const char *str, const char *errmesg);
 extern uint32_t strtou32_or_err(const char *str, const char *errmesg);
+extern uint32_t strtox32_or_err(const char *str, const char *errmesg);
 
 extern int64_t strtos64_or_err(const char *str, const char *errmesg);
 extern uint64_t strtou64_or_err(const char *str, const char *errmesg);
+extern uint64_t strtox64_or_err(const char *str, const char *errmesg);
 
 extern double strtod_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 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
@@ -45,14 +65,129 @@ static inline void xstrncpy(char *dest, const char *src, size_t n)
        dest[n-1] = 0;
 }
 
-extern void strmode(mode_t mode, char *str);
+/* 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 *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 *mem2strcpy(char *dest, const void *src, size_t n, size_t nmax)
+{
+       if (n + 1 > nmax)
+               n = nmax - 1;
+
+       memcpy(dest, src, n);
+       dest[nmax-1] = '\0';
+       return dest;
+}
+
+/* Reallocate @str according to @newstr and copy @newstr to @str; returns new @str */
+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) {
+               free(str);
+               goto nothing;
+       }
+
+       osz = strlen(str);
+       nsz = strlen(newstr);
+
+       if (nsz > osz) {
+               char *tmp = realloc(str, nsz + 1);
+               if (!tmp)
+                       goto nothing;
+               str = tmp;
+       }
+
+       memcpy(str, newstr, nsz + 1);
+       return str;
+
+nothing:
+       free(str);
+       return NULL;
+}
+
+/* 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,
-        SIZE_SUFFIX_SPACE   = 2
+       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);
@@ -60,7 +195,7 @@ 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, int *ary_pos,
+                                size_t arysz, size_t *ary_pos,
                                 int (name2id)(const char *, size_t));
 
 extern int string_to_bitarray(const char *list, char *ary,
@@ -71,6 +206,136 @@ extern int string_to_bitmask(const char *list,
                             long (*name2flag)(const char *, size_t));
 extern int parse_range(const char *str, int *lower, int *upper, int def);
 
-extern int streq_except_trailing_slash(const char *s1, const char *s2);
+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;
+}
+
+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 *strnappend(const char *s, const char *suffix, size_t b);
+extern char *strappend(const char *s, const char *suffix);
+extern char *strfappend(const char *s, const char *format, ...)
+                __attribute__ ((__format__ (__printf__, 2, 0)));
+extern const char *split(const char **state, size_t *l, const char *separator, int quoted);
+
+extern int skip_fline(FILE *fp);
 
 #endif