# HG changeset patch # User Matti Hamalainen # Date 1543311070 -7200 # Node ID 750a7e1255464e02db2f601c5f6f1f94de549836 # Parent b137d324e13f79a740ebc8abc017b90fe640a255 Add in several string helper functions from th-libs. diff -r b137d324e13f -r 750a7e125546 src/dmlib.h --- a/src/dmlib.h Fri Oct 26 09:56:25 2018 +0300 +++ b/src/dmlib.h Tue Nov 27 11:31:10 2018 +0200 @@ -408,14 +408,30 @@ void * dmMemset(void *ptr, const int c, size_t n); #endif + +/** String trimming option flags for dm_strdup_trim() + */ +enum +{ + DM_TRIM_START = 1, + DM_TRIM_END = 2, + DM_TRIM_BOTH = 3 +}; + + + char * dm_strdup(const char *str); char * dm_strndup(const char *str, const size_t n); +char * dm_strdup_trim(const char *src, const int flags); +char * dm_strndup_trim(const char *src, const size_t n, const int flags); char * dm_strdup_vprintf_len(const char *fmt, va_list args, int *len); char * dm_strdup_vprintf(const char *fmt, va_list args); char * dm_strdup_printf(const char *fmt, ...); char * dm_basefilename(const char *filename); char * dm_strdup_fext(const char *filename, const char *fmt); +int dm_strcasecmp(const char *haystack, const char *needle); +int dm_strncasecmp(const char *haystack, const char *needle, size_t n); char * dm_strrcasecmp(char *str, const char *needle); BOOL dmGetIntVal(const char *str, unsigned int *value, BOOL *neg); diff -r b137d324e13f -r 750a7e125546 src/dmstring.c --- a/src/dmstring.c Fri Oct 26 09:56:25 2018 +0300 +++ b/src/dmstring.c Tue Nov 27 11:31:10 2018 +0200 @@ -42,6 +42,53 @@ } +/* Compare two strings ignoring case [strcasecmp, strncasecmp] + */ +int dm_strcasecmp(const char *haystack, const char *needle) +{ + const char *s1 = haystack, *s2 = needle; + assert(haystack != NULL); + assert(needle != NULL); + + if (haystack == needle) + return 0; + + while (*s1 && *s2) + { + int k = tolower(*s1) - tolower(*s2); + if (k != 0) + return k; + s1++; + s2++; + } + + return 0; +} + + +int dm_strncasecmp(const char *haystack, const char *needle, size_t n) +{ + const char *s1 = haystack, *s2 = needle; + assert(haystack != NULL); + assert(needle != NULL); + + if (haystack == needle) + return 0; + + while (n > 0 && *s1 && *s2) + { + int k = tolower(*s1) - tolower(*s2); + if (k != 0) + return k; + s1++; + s2++; + n--; + } + + return 0; +} + + /* Check if end of the given string str matches needle * case-insensitively, return pointer to start of the match, * if found, NULL otherwise. @@ -58,7 +105,7 @@ if (slen < nlen) return NULL; - if (strcasecmp(str - nlen - 1, needle) == 0) + if (dm_strcasecmp(str - nlen - 1, needle) == 0) return str - nlen - 1; else return NULL; @@ -83,26 +130,85 @@ /* Implementation of strndup() with NULL check */ -char *dm_strndup(const char *s, const size_t n) +char *dm_strndup(const char *str, const size_t n) { char *res; - if (s == NULL) + if (str == NULL) return NULL; - size_t len = strlen(s); + size_t len = strlen(str); if (len > n) len = n; if ((res = dmMalloc(len + 1)) == NULL) return NULL; - memcpy(res, s, len); + memcpy(res, str, len); res[len] = 0; return res; } +/* Like strdup, but trims whitespace from the string according to specified flags. + * See DM_TRIM_* in dmlib.h. If the resulting string would be empty (length 0), + * NULL is returned. + */ +static char * dm_strdup_trim_do(const char *src, size_t len, const int flags) +{ + char *res; + size_t start, end; + + if (len == 0) + return NULL; + + // Trim start: find first non-whitespace character + if (flags & DM_TRIM_START) + for (start = 0; start < len && isspace(src[start]); start++); + else + start = 0; + + // Trim end: find last non-whitespace character + if (flags & DM_TRIM_END) + for (end = len - 1; end > start && isspace(src[end]); end--); + else + end = len; + + // Allocate memory for result + if (src[end] == 0 || isspace(src[end])) + return NULL; + + len = end - start + 1; + if ((res = dmMalloc(len + 1)) == NULL) + return NULL; + + memcpy(res, src + start, len); + res[len] = 0; + return res; +} + + +char *dm_strdup_trim(const char *src, const int flags) +{ + if (src == NULL) + return NULL; + + return dm_strdup_trim_do(src, strlen(src), flags); +} + + +char *dm_strndup_trim(const char *src, const size_t n, const int flags) +{ + size_t len; + if (src == NULL || n == 0) + return NULL; + + for (len = 0; len < n && src[len]; len++); + + return dm_strdup_trim_do(src, len, flags); +} + + /* Simulate a sprintf() that allocates memory */ char *dm_strdup_vprintf_len(const char *fmt, va_list args, int *len)