(root)/
util-linux-2.39/
include/
strutils.h
       1  /*
       2   * No copyright is claimed.  This code is in the public domain; do with
       3   * it what you wish.
       4   */
       5  #ifndef UTIL_LINUX_STRUTILS
       6  #define UTIL_LINUX_STRUTILS
       7  
       8  #include <stdlib.h>
       9  #include <inttypes.h>
      10  #include <string.h>
      11  #include <sys/types.h>
      12  #include <ctype.h>
      13  #include <stdio.h>
      14  #include <errno.h>
      15  #include <time.h>
      16  
      17  #include "c.h"
      18  
      19  /* initialize a custom exit code for all *_or_err functions */
      20  extern void strutils_set_exitcode(int exit_code);
      21  
      22  extern int parse_size(const char *str, uintmax_t *res, int *power);
      23  extern int strtosize(const char *str, uintmax_t *res);
      24  extern uintmax_t strtosize_or_err(const char *str, const char *errmesg);
      25  
      26  extern int ul_strtos64(const char *str, int64_t *num, int base);
      27  extern int ul_strtou64(const char *str, uint64_t *num, int base);
      28  extern int ul_strtos32(const char *str, int32_t *num, int base);
      29  extern int ul_strtou32(const char *str, uint32_t *num, int base);
      30  
      31  extern int64_t str2num_or_err(const char *str, int base, const char *errmesg, int64_t low, int64_t up);
      32  extern uint64_t str2unum_or_err(const char *str, int base, const char *errmesg, uint64_t up);
      33  
      34  #define strtos64_or_err(_s, _e)	str2num_or_err(_s, 10, _e, 0, 0)
      35  #define strtou64_or_err(_s, _e)	str2unum_or_err(_s, 10, _e, 0)
      36  #define strtox64_or_err(_s, _e)	str2unum_or_err(_s, 16, _e, 0)
      37  
      38  #define strtos32_or_err(_s, _e)	(int32_t) str2num_or_err(_s, 10, _e, INT32_MIN, INT32_MAX)
      39  #define strtou32_or_err(_s, _e)	(uint32_t) str2unum_or_err(_s, 10, _e, UINT32_MAX)
      40  #define strtox32_or_err(_s, _e)	(uint32_t) str2unum_or_err(_s, 16, _e, UINT32_MAX)
      41  
      42  #define strtos16_or_err(_s, _e)	(int16_t) str2num_or_err(_s, 10, _e, INT16_MIN, INT16_MAX)
      43  #define strtou16_or_err(_s, _e)	(uint16_t) str2unum_or_err(_s, 10, _e, UINT16_MAX)
      44  #define strtox16_or_err(_s, _e)	(uint16_t) str2unum_or_err(_s, 16, _e, UINT16_MAX)
      45  
      46  extern double strtod_or_err(const char *str, const char *errmesg);
      47  extern long double strtold_or_err(const char *str, const char *errmesg);
      48  
      49  #define strtol_or_err(_s, _e)	(long) str2num_or_err(_s, 10, _e, LONG_MIN, LONG_MAX)
      50  #define strtopid_or_err(_s, _e)	(pid_t) str2num_or_err(_s, 10, _e, 1, SINT_MAX(pid_t))
      51  #define strtoul_or_err(_s, _e)	(unsigned long) str2unum_or_err(_s, 10, _e, ULONG_MAX)
      52  
      53  extern void strtotimeval_or_err(const char *str, struct timeval *tv,
      54  		const char *errmesg);
      55  extern void strtotimespec_or_err(const char *str, struct timespec *ts,
      56  		const char *errmesg);
      57  extern time_t strtotime_or_err(const char *str, const char *errmesg);
      58  
      59  extern int isdigit_strend(const char *str, const char **end);
      60  #define isdigit_string(_s)	isdigit_strend(_s, NULL)
      61  
      62  extern int isxdigit_strend(const char *str, const char **end);
      63  #define isxdigit_string(_s)	isxdigit_strend(_s, NULL)
      64  
      65  
      66  extern int parse_switch(const char *arg, const char *errmesg, ...);
      67  
      68  #ifndef HAVE_MEMPCPY
      69  extern void *mempcpy(void *restrict dest, const void *restrict src, size_t n);
      70  #endif
      71  #ifndef HAVE_STRNLEN
      72  extern size_t strnlen(const char *s, size_t maxlen);
      73  #endif
      74  #ifndef HAVE_STRNDUP
      75  extern char *strndup(const char *s, size_t n);
      76  #endif
      77  #ifndef HAVE_STRNCHR
      78  extern char *strnchr(const char *s, size_t maxlen, int c);
      79  #endif
      80  
      81  /* caller guarantees n > 0 */
      82  static inline void xstrncpy(char *dest, const char *src, size_t n)
      83  {
      84  	size_t len = src ? strlen(src) : 0;
      85  
      86  	if (!len)
      87  		return;
      88  	len = min(len, n - 1);
      89  	memcpy(dest, src, len);
      90  	dest[len] = 0;
      91  }
      92  
      93  /* This is like strncpy(), but based on memcpy(), so compilers and static
      94   * analyzers do not complain when sizeof(destination) is the same as 'n' and
      95   * result is not terminated by zero.
      96   *
      97   * Use this function to copy string to logs with fixed sizes (wtmp/utmp. ...)
      98   * where string terminator is optional.
      99   */
     100  static inline void * __attribute__((nonnull (1)))
     101  str2memcpy(void *dest, const char *src, size_t n)
     102  {
     103  	size_t bytes = strlen(src) + 1;
     104  
     105  	if (bytes > n)
     106  		bytes = n;
     107  
     108  	memcpy(dest, src, bytes);
     109  	return dest;
     110  }
     111  
     112  static inline char * __attribute__((nonnull (1)))
     113  mem2strcpy(char *dest, const void *src, size_t n, size_t nmax)
     114  {
     115  	if (n + 1 > nmax)
     116  		n = nmax - 1;
     117  
     118  	memset(dest, '\0', nmax);
     119  	memcpy(dest, src, n);
     120  	return dest;
     121  }
     122  
     123  /* Reallocate @str according to @newstr and copy @newstr to @str; returns new @str.
     124   * The @str is not modified if reallocation failed (like classic realloc()).
     125   */
     126  static inline char * __attribute__((warn_unused_result))
     127  strrealloc(char *str, const char *newstr)
     128  {
     129  	size_t nsz, osz;
     130  
     131  	if (!str)
     132  		return newstr ? strdup(newstr) : NULL;
     133  	if (!newstr)
     134  		return NULL;
     135  
     136  	osz = strlen(str);
     137  	nsz = strlen(newstr);
     138  
     139  	if (nsz > osz)
     140  		str = realloc(str, nsz + 1);
     141  	if (str)
     142  		memcpy(str, newstr, nsz + 1);
     143  	return str;
     144  }
     145  
     146  /* Copy string @str to struct @stru to member addressed by @offset */
     147  static inline int strdup_to_offset(void *stru, size_t offset, const char *str)
     148  {
     149  	char **o;
     150  	char *p = NULL;
     151  
     152  	if (!stru)
     153  		return -EINVAL;
     154  
     155  	o = (char **) ((char *) stru + offset);
     156  	if (str) {
     157  		p = strdup(str);
     158  		if (!p)
     159  			return -ENOMEM;
     160  	}
     161  
     162  	free(*o);
     163  	*o = p;
     164  	return 0;
     165  }
     166  
     167  /* Copy string __str to struct member _m of the struct _s */
     168  #define strdup_to_struct_member(_s, _m, _str) \
     169  		strdup_to_offset((void *) _s, offsetof(__typeof__(*(_s)), _m), _str)
     170  
     171  /* Copy string addressed by @offset between two structs */
     172  static inline int strdup_between_offsets(void *stru_dst, void *stru_src, size_t offset)
     173  {
     174  	char **src;
     175  	char **dst;
     176  	char *p = NULL;
     177  
     178  	if (!stru_src || !stru_dst)
     179  		return -EINVAL;
     180  
     181  	src = (char **) ((char *) stru_src + offset);
     182  	dst = (char **) ((char *) stru_dst + offset);
     183  
     184  	if (*src) {
     185  		p = strdup(*src);
     186  		if (!p)
     187  			return -ENOMEM;
     188  	}
     189  
     190  	free(*dst);
     191  	*dst = p;
     192  	return 0;
     193  }
     194  
     195  /* Copy string addressed by struct member between two instances of the same
     196   * struct type */
     197  #define strdup_between_structs(_dst, _src, _m) \
     198  		strdup_between_offsets((void *)_dst, (void *)_src, offsetof(__typeof__(*(_src)), _m))
     199  
     200  
     201  extern char *xstrmode(mode_t mode, char *str);
     202  
     203  /* Options for size_to_human_string() */
     204  enum
     205  {
     206  	SIZE_SUFFIX_1LETTER  = 0,
     207  	SIZE_SUFFIX_3LETTER  = (1 << 0),
     208  	SIZE_SUFFIX_SPACE    = (1 << 1),
     209  	SIZE_DECIMAL_2DIGITS = (1 << 2)
     210  };
     211  
     212  extern char *size_to_human_string(int options, uint64_t bytes);
     213  
     214  extern int string_to_idarray(const char *list, int ary[], size_t arysz,
     215  			   int (name2id)(const char *, size_t));
     216  extern int string_add_to_idarray(const char *list, int ary[],
     217  				 size_t arysz, size_t *ary_pos,
     218  				 int (name2id)(const char *, size_t));
     219  
     220  extern int string_to_bitarray(const char *list, char *ary,
     221  			    int (*name2bit)(const char *, size_t),
     222  			    size_t allow_range);
     223  
     224  extern int string_to_bitmask(const char *list,
     225  			     unsigned long *mask,
     226  			     long (*name2flag)(const char *, size_t));
     227  extern int parse_range(const char *str, int *lower, int *upper, int def);
     228  
     229  extern int streq_paths(const char *a, const char *b);
     230  
     231  /*
     232   * Match string beginning.
     233   */
     234  static inline const char *startswith(const char *s, const char *prefix)
     235  {
     236  	size_t sz = prefix ? strlen(prefix) : 0;
     237  
     238          if (s && sz && strncmp(s, prefix, sz) == 0)
     239                  return s + sz;
     240  	return NULL;
     241  }
     242  
     243  /*
     244   * Case insensitive match string beginning.
     245   */
     246  static inline const char *startswith_no_case(const char *s, const char *prefix)
     247  {
     248  	size_t sz = prefix ? strlen(prefix) : 0;
     249  
     250          if (s && sz && strncasecmp(s, prefix, sz) == 0)
     251                  return s + sz;
     252  	return NULL;
     253  }
     254  
     255  /*
     256   * Match string ending.
     257   */
     258  static inline const char *endswith(const char *s, const char *postfix)
     259  {
     260  	size_t sl = s ? strlen(s) : 0;
     261  	size_t pl = postfix ? strlen(postfix) : 0;
     262  
     263  	if (pl == 0)
     264  		return s + sl;
     265  	if (sl < pl)
     266  		return NULL;
     267  	if (memcmp(s + sl - pl, postfix, pl) != 0)
     268  		return NULL;
     269  	return s + sl - pl;
     270  }
     271  
     272  /*
     273   * Skip leading white space.
     274   */
     275  static inline const char *skip_space(const char *p)
     276  {
     277  	while (isspace(*p))
     278  		++p;
     279  	return p;
     280  }
     281  
     282  static inline const char *skip_blank(const char *p)
     283  {
     284  	while (isblank(*p))
     285  		++p;
     286  	return p;
     287  }
     288  
     289  
     290  /* Removes whitespace from the right-hand side of a string (trailing
     291   * whitespace).
     292   *
     293   * Returns size of the new string (without \0).
     294   */
     295  static inline size_t rtrim_whitespace(unsigned char *str)
     296  {
     297  	size_t i;
     298  
     299  	if (!str)
     300  		return 0;
     301  	i = strlen((char *) str);
     302  	while (i) {
     303  		i--;
     304  		if (!isspace(str[i])) {
     305  			i++;
     306  			break;
     307  		}
     308  	}
     309  	str[i] = '\0';
     310  	return i;
     311  }
     312  
     313  /* Removes whitespace from the left-hand side of a string.
     314   *
     315   * Returns size of the new string (without \0).
     316   */
     317  static inline size_t ltrim_whitespace(unsigned char *str)
     318  {
     319  	size_t len;
     320  	unsigned char *p;
     321  
     322  	if (!str)
     323  		return 0;
     324  	for (p = str; *p && isspace(*p); p++);
     325  
     326  	len = strlen((char *) p);
     327  
     328  	if (p > str)
     329  		memmove(str, p, len + 1);
     330  
     331  	return len;
     332  }
     333  
     334  /* Removes left-hand, right-hand and repeating whitespaces.
     335   */
     336  static inline size_t __normalize_whitespace(
     337  				const unsigned char *src,
     338  				size_t sz,
     339  				unsigned char *dst,
     340  				size_t len)
     341  {
     342  	size_t i, x = 0;
     343  	int nsp = 0, intext = 0;
     344  
     345  	if (!sz)
     346  		goto done;
     347  
     348  	for (i = 0, x = 0; i < sz && x < len - 1;  ) {
     349  		if (isspace(src[i]))
     350  			nsp++;
     351  		else
     352  			nsp = 0, intext = 1;
     353  
     354  		if (nsp > 1 || (nsp && !intext))
     355  			i++;
     356  		else
     357  			dst[x++] = src[i++];
     358  	}
     359  	if (nsp && x > 0)		/* tailing space */
     360  		x--;
     361  done:
     362  	dst[x] = '\0';
     363  	return x;
     364  }
     365  
     366  static inline size_t normalize_whitespace(unsigned char *str)
     367  {
     368  	size_t sz = strlen((char *) str);
     369  	return __normalize_whitespace(str, sz, str, sz + 1);
     370  }
     371  
     372  static inline void strrep(char *s, int find, int replace)
     373  {
     374  	while (s && *s && (s = strchr(s, find)) != NULL)
     375  		*s++ = replace;
     376  }
     377  
     378  static inline void strrem(char *s, int rem)
     379  {
     380  	char *p;
     381  
     382  	if (!s)
     383  		return;
     384  	for (p = s; *s; s++) {
     385  		if (*s != rem)
     386  			*p++ = *s;
     387  	}
     388  	*p = '\0';
     389  }
     390  
     391  extern char *strnconcat(const char *s, const char *suffix, size_t b);
     392  extern char *strconcat(const char *s, const char *suffix);
     393  extern char *strfconcat(const char *s, const char *format, ...)
     394  		 __attribute__ ((__format__ (__printf__, 2, 3)));
     395  
     396  extern int strappend(char **a, const char *b);
     397  
     398  extern const char *split(const char **state, size_t *l, const char *separator, int quoted);
     399  
     400  extern char *ul_strchr_escaped(const char *s, int c);
     401  
     402  extern int skip_fline(FILE *fp);
     403  extern int ul_stralnumcmp(const char *p1, const char *p2);
     404  
     405  extern int ul_optstr_next(char **optstr, char **name, size_t *namesz, char **value, size_t *valsz);
     406  
     407  #endif