damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

str.h (6195B)


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