1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
/* CC0 (Public domain) - see LICENSE.CC0 file for details */
#ifndef CCAN_STR_H
#define CCAN_STR_H
#include "config.h"
#include <string.h>
#include <stdbool.h>
#include <limits.h>
#include <ctype.h>
/**
* streq - Are two strings equal?
* @a: first string
* @b: first string
*
* This macro is arguably more readable than "!strcmp(a, b)".
*
* Example:
* if (streq(somestring, ""))
* printf("String is empty!\n");
*/
#define streq(a,b) (strcmp((a),(b)) == 0)
/**
* strstarts - Does this string start with this prefix?
* @str: string to test
* @prefix: prefix to look for at start of str
*
* Example:
* if (strstarts(somestring, "foo"))
* printf("String %s begins with 'foo'!\n", somestring);
*/
#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
/**
* strends - Does this string end with this postfix?
* @str: string to test
* @postfix: postfix to look for at end of str
*
* Example:
* if (strends(somestring, "foo"))
* printf("String %s end with 'foo'!\n", somestring);
*/
static inline bool strends(const char *str, const char *postfix)
{
if (strlen(str) < strlen(postfix))
return false;
return streq(str + strlen(str) - strlen(postfix), postfix);
}
/**
* stringify - Turn expression into a string literal
* @expr: any C expression
*
* Example:
* #define PRINT_COND_IF_FALSE(cond) \
* ((cond) || printf("%s is false!", stringify(cond)))
*/
#define stringify(expr) stringify_1(expr)
/* Double-indirection required to stringify expansions */
#define stringify_1(expr) #expr
/**
* strcount - Count number of (non-overlapping) occurrences of a substring.
* @haystack: a C string
* @needle: a substring
*
* Example:
* assert(strcount("aaa aaa", "a") == 6);
* assert(strcount("aaa aaa", "ab") == 0);
* assert(strcount("aaa aaa", "aa") == 2);
*/
size_t strcount(const char *haystack, const char *needle);
/**
* STR_MAX_CHARS - Maximum possible size of numeric string for this type.
* @type_or_expr: a pointer or integer type or expression.
*
* This provides enough space for a nul-terminated string which represents the
* largest possible value for the type or expression.
*
* Note: The implementation adds extra space so hex values or negative
* values will fit (eg. sprintf(... "%p"). )
*
* Example:
* char str[STR_MAX_CHARS(int)];
*
* sprintf(str, "%i", 7);
*/
#define STR_MAX_CHARS(type_or_expr) \
((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \
+ STR_MAX_CHARS_TCHECK_(type_or_expr))
#if HAVE_TYPEOF
/* Only a simple type can have 0 assigned, so test that. */
#define STR_MAX_CHARS_TCHECK_(type_or_expr) \
({ typeof(type_or_expr) x = 0; (void)x; 0; })
#else
#define STR_MAX_CHARS_TCHECK_(type_or_expr) 0
#endif
/**
* cisalnum - isalnum() which takes a char (and doesn't accept EOF)
* @c: a character
*
* Surprisingly, the standard ctype.h isalnum() takes an int, which
* must have the value of EOF (-1) or an unsigned char. This variant
* takes a real char, and doesn't accept EOF.
*/
static inline bool cisalnum(char c)
{
return isalnum((unsigned char)c);
}
static inline bool cisalpha(char c)
{
return isalpha((unsigned char)c);
}
static inline bool cisascii(char c)
{
return isascii((unsigned char)c);
}
#if HAVE_ISBLANK
static inline bool cisblank(char c)
{
return isblank((unsigned char)c);
}
#endif
static inline bool ciscntrl(char c)
{
return iscntrl((unsigned char)c);
}
static inline bool cisdigit(char c)
{
return isdigit((unsigned char)c);
}
static inline bool cisgraph(char c)
{
return isgraph((unsigned char)c);
}
static inline bool cislower(char c)
{
return islower((unsigned char)c);
}
static inline bool cisprint(char c)
{
return isprint((unsigned char)c);
}
static inline bool cispunct(char c)
{
return ispunct((unsigned char)c);
}
static inline bool cisspace(char c)
{
return isspace((unsigned char)c);
}
static inline bool cisupper(char c)
{
return isupper((unsigned char)c);
}
static inline bool cisxdigit(char c)
{
return isxdigit((unsigned char)c);
}
#include <ccan/str_debug.h>
/* These checks force things out of line, hence they are under DEBUG. */
#ifdef CCAN_STR_DEBUG
#include <ccan/build_assert.h>
/* These are commonly misused: they take -1 or an *unsigned* char value. */
#undef isalnum
#undef isalpha
#undef isascii
#undef isblank
#undef iscntrl
#undef isdigit
#undef isgraph
#undef islower
#undef isprint
#undef ispunct
#undef isspace
#undef isupper
#undef isxdigit
/* You can use a char if char is unsigned. */
#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
#define str_check_arg_(i) \
((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \
char) \
|| (char)255 > 0))
#else
#define str_check_arg_(i) (i)
#endif
#define isalnum(i) str_isalnum(str_check_arg_(i))
#define isalpha(i) str_isalpha(str_check_arg_(i))
#define isascii(i) str_isascii(str_check_arg_(i))
#if HAVE_ISBLANK
#define isblank(i) str_isblank(str_check_arg_(i))
#endif
#define iscntrl(i) str_iscntrl(str_check_arg_(i))
#define isdigit(i) str_isdigit(str_check_arg_(i))
#define isgraph(i) str_isgraph(str_check_arg_(i))
#define islower(i) str_islower(str_check_arg_(i))
#define isprint(i) str_isprint(str_check_arg_(i))
#define ispunct(i) str_ispunct(str_check_arg_(i))
#define isspace(i) str_isspace(str_check_arg_(i))
#define isupper(i) str_isupper(str_check_arg_(i))
#define isxdigit(i) str_isxdigit(str_check_arg_(i))
#if HAVE_TYPEOF
/* With GNU magic, we can make const-respecting standard string functions. */
#undef strstr
#undef strchr
#undef strrchr
/* + 0 is needed to decay array into pointer. */
#define strstr(haystack, needle) \
((typeof((haystack) + 0))str_strstr((haystack), (needle)))
#define strchr(haystack, c) \
((typeof((haystack) + 0))str_strchr((haystack), (c)))
#define strrchr(haystack, c) \
((typeof((haystack) + 0))str_strrchr((haystack), (c)))
#endif
#endif /* CCAN_STR_DEBUG */
#endif /* CCAN_STR_H */
|