xref: /freebsd/sys/compat/linuxkpi/common/include/linux/string.h (revision 039eac2463d7b0b1b863a57c78cb2e054c210197)
1  /*-
2   * Copyright (c) 2010 Isilon Systems, Inc.
3   * Copyright (c) 2010 iX Systems, Inc.
4   * Copyright (c) 2010 Panasas, Inc.
5   * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
6   * All rights reserved.
7   *
8   * Redistribution and use in source and binary forms, with or without
9   * modification, are permitted provided that the following conditions
10   * are met:
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice unmodified, this list of conditions, and the following
13   *    disclaimer.
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in the
16   *    documentation and/or other materials provided with the distribution.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28   */
29  #ifndef	_LINUXKPI_LINUX_STRING_H_
30  #define	_LINUXKPI_LINUX_STRING_H_
31  
32  #include <sys/ctype.h>
33  
34  #include <linux/types.h>
35  #include <linux/gfp.h>
36  #include <linux/slab.h>
37  #include <linux/uaccess.h>
38  #include <linux/err.h>
39  #include <linux/bitops.h> /* for BITS_PER_LONG */
40  #include <linux/overflow.h>
41  #include <linux/stdarg.h>
42  
43  #include <sys/libkern.h>
44  
45  #define	strnicmp(...) strncasecmp(__VA_ARGS__)
46  
47  static inline int
match_string(const char * const * table,int n,const char * key)48  match_string(const char *const *table, int n, const char *key)
49  {
50  	int i;
51  
52  	for (i = 0; i != n && table[i] != NULL; i++) {
53  		if (strcmp(table[i], key) == 0)
54  			return (i);
55  	}
56  	return (-EINVAL);
57  }
58  
59  static inline void *
memdup_user(const void * ptr,size_t len)60  memdup_user(const void *ptr, size_t len)
61  {
62  	void *retval;
63  	int error;
64  
65  	retval = malloc(len, M_KMALLOC, M_WAITOK);
66  	error = linux_copyin(ptr, retval, len);
67  	if (error != 0) {
68  		free(retval, M_KMALLOC);
69  		return (ERR_PTR(error));
70  	}
71  	return (retval);
72  }
73  
74  static inline void *
memdup_user_nul(const void * ptr,size_t len)75  memdup_user_nul(const void *ptr, size_t len)
76  {
77  	char *retval;
78  	int error;
79  
80  	retval = malloc(len + 1, M_KMALLOC, M_WAITOK);
81  	error = linux_copyin(ptr, retval, len);
82  	if (error != 0) {
83  		free(retval, M_KMALLOC);
84  		return (ERR_PTR(error));
85  	}
86  	retval[len] = '\0';
87  	return (retval);
88  }
89  
90  static inline void *
kmemdup(const void * src,size_t len,gfp_t gfp)91  kmemdup(const void *src, size_t len, gfp_t gfp)
92  {
93  	void *dst;
94  
95  	dst = kmalloc(len, gfp);
96  	if (dst != NULL)
97  		memcpy(dst, src, len);
98  	return (dst);
99  }
100  
101  /* See slab.h for kvmalloc/kvfree(). */
102  static inline void *
kvmemdup(const void * src,size_t len,gfp_t gfp)103  kvmemdup(const void *src, size_t len, gfp_t gfp)
104  {
105  	void *dst;
106  
107  	dst = kvmalloc(len, gfp);
108  	if (dst != NULL)
109  		memcpy(dst, src, len);
110  	return (dst);
111  }
112  
113  static inline char *
strndup_user(const char __user * ustr,long n)114  strndup_user(const char __user *ustr, long n)
115  {
116  	if (n < 1)
117  		return (ERR_PTR(-EINVAL));
118  
119  	return (memdup_user_nul(ustr, n - 1));
120  }
121  
122  static inline char *
kstrdup(const char * string,gfp_t gfp)123  kstrdup(const char *string, gfp_t gfp)
124  {
125  	char *retval;
126  	size_t len;
127  
128  	if (string == NULL)
129  		return (NULL);
130  	len = strlen(string) + 1;
131  	retval = kmalloc(len, gfp);
132  	if (retval != NULL)
133  		memcpy(retval, string, len);
134  	return (retval);
135  }
136  
137  static inline char *
kstrndup(const char * string,size_t len,gfp_t gfp)138  kstrndup(const char *string, size_t len, gfp_t gfp)
139  {
140  	char *retval;
141  
142  	if (string == NULL)
143  		return (NULL);
144  	retval = kmalloc(len + 1, gfp);
145  	if (retval != NULL)
146  		strncpy(retval, string, len);
147  	return (retval);
148  }
149  
150  static inline const char *
kstrdup_const(const char * src,gfp_t gfp)151  kstrdup_const(const char *src, gfp_t gfp)
152  {
153  	return (kmemdup(src, strlen(src) + 1, gfp));
154  }
155  
156  static inline char *
skip_spaces(const char * str)157  skip_spaces(const char *str)
158  {
159  	while (isspace(*str))
160  		++str;
161  	return (__DECONST(char *, str));
162  }
163  
164  /*
165   * This function trims whitespaces at the end of a string and returns a pointer
166   * to the first non-whitespace character.
167   */
168  static inline char *
strim(char * str)169  strim(char *str)
170  {
171  	char *end;
172  
173  	end = str + strlen(str);
174  	while (end >= str && (*end == '\0' || isspace(*end))) {
175  		*end = '\0';
176  		end--;
177  	}
178  
179  	return (skip_spaces(str));
180  }
181  
182  static inline void *
memchr_inv(const void * start,int c,size_t length)183  memchr_inv(const void *start, int c, size_t length)
184  {
185  	const u8 *ptr;
186  	const u8 *end;
187  	u8 ch;
188  
189  	ch = c;
190  	ptr = start;
191  	end = ptr + length;
192  
193  	while (ptr != end) {
194  		if (*ptr != ch)
195  			return (__DECONST(void *, ptr));
196  		ptr++;
197  	}
198  	return (NULL);
199  }
200  
201  static inline size_t
str_has_prefix(const char * str,const char * prefix)202  str_has_prefix(const char *str, const char *prefix)
203  {
204  	size_t len;
205  
206  	len = strlen(prefix);
207  	return (strncmp(str, prefix, len) == 0 ? len : 0);
208  }
209  
210  static inline char *
strreplace(char * str,char old,char new)211  strreplace(char *str, char old, char new)
212  {
213  	char *p;
214  
215  	p = strchrnul(str, old);
216  	while (p != NULL && *p != '\0') {
217  		*p = new;
218  		p = strchrnul(str, old);
219  	}
220  	return (p);
221  }
222  
223  static inline ssize_t
strscpy(char * dst,const char * src,size_t len)224  strscpy(char* dst, const char* src, size_t len)
225  {
226  	size_t i;
227  
228  	if (len <= INT_MAX) {
229  		for (i = 0; i < len; i++)
230  			if ('\0' == (dst[i] = src[i]))
231  				return ((ssize_t)i);
232  		if (i != 0)
233  			dst[--i] = '\0';
234  	}
235  
236  	return (-E2BIG);
237  }
238  
239  static inline ssize_t
strscpy_pad(char * dst,const char * src,size_t len)240  strscpy_pad(char* dst, const char* src, size_t len)
241  {
242  
243  	bzero(dst, len);
244  
245  	return (strscpy(dst, src, len));
246  }
247  
248  static inline char *
strnchr(const char * cp,size_t n,int ch)249  strnchr(const char *cp, size_t n, int ch)
250  {
251  	char *p;
252  
253  	for (p = __DECONST(char *, cp); n--; ++p) {
254  		if (*p == ch)
255  			return (p);
256  		if (*p == '\0')
257  			break;
258  	}
259  
260  	return (NULL);
261  }
262  
263  static inline void *
memset32(uint32_t * b,uint32_t c,size_t len)264  memset32(uint32_t *b, uint32_t c, size_t len)
265  {
266  	uint32_t *dst = b;
267  
268  	while (len--)
269  		*dst++ = c;
270  	return (b);
271  }
272  
273  static inline void *
memset64(uint64_t * b,uint64_t c,size_t len)274  memset64(uint64_t *b, uint64_t c, size_t len)
275  {
276  	uint64_t *dst = b;
277  
278  	while (len--)
279  		*dst++ = c;
280  	return (b);
281  }
282  
283  static inline void *
memset_p(void ** p,void * v,size_t n)284  memset_p(void **p, void *v, size_t n)
285  {
286  
287  	if (BITS_PER_LONG == 32)
288  		return (memset32((uint32_t *)p, (uintptr_t)v, n));
289  	else
290  		return (memset64((uint64_t *)p, (uintptr_t)v, n));
291  }
292  
293  static inline void
memcpy_and_pad(void * dst,size_t dstlen,const void * src,size_t len,int ch)294  memcpy_and_pad(void *dst, size_t dstlen, const void *src, size_t len, int ch)
295  {
296  
297  	if (len >= dstlen) {
298  		memcpy(dst, src, dstlen);
299  	} else {
300  		memcpy(dst, src, len);
301  		/* Pad with given padding character. */
302  		memset((char *)dst + len, ch, dstlen - len);
303  	}
304  }
305  
306  #define	memset_startat(ptr, bytepat, smember)				\
307  ({									\
308  	uint8_t *_ptr = (uint8_t *)(ptr);				\
309  	int _c = (int)(bytepat);					\
310  	size_t _o = offsetof(typeof(*(ptr)), smember);			\
311  	memset(_ptr + _o, _c, sizeof(*(ptr)) - _o);			\
312  })
313  
314  #define	memset_after(ptr, bytepat, smember)				\
315  ({									\
316  	uint8_t *_ptr = (uint8_t *)(ptr);				\
317  	int _c = (int)(bytepat);					\
318  	size_t _o = offsetofend(typeof(*(ptr)), smember);		\
319  	memset(_ptr + _o, _c, sizeof(*(ptr)) - _o);			\
320  })
321  
322  static inline void
memzero_explicit(void * p,size_t s)323  memzero_explicit(void *p, size_t s)
324  {
325  	memset(p, 0, s);
326  	__asm__ __volatile__("": :"r"(p) :"memory");
327  }
328  
329  #endif	/* _LINUXKPI_LINUX_STRING_H_ */
330