Mercurial > hg > th-libs
view th_string.c @ 175:3d0a1f87e393
Rename some variables.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 01 Mar 2015 05:35:15 +0200 |
parents | 7d5707438333 |
children | 1ee46a95aa8c |
line wrap: on
line source
/* * Miscellaneous string-handling related utility-functions * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2002-2015 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ #include "th_util.h" #include "th_string.h" /* Implementation of strdup() with a NULL check */ char *th_strdup(const char *s) { char *res; if (s == NULL) return NULL; if ((res = th_malloc(strlen(s) + 1)) == NULL) return NULL; strcpy(res, s); return res; } /* Implementation of strndup() with NULL check */ char *th_strndup(const char *s, const size_t n) { char *res; size_t len; if (s == NULL) return NULL; len = strlen(s); if (len > n) len = n; if ((res = th_malloc(len + 1)) == NULL) return NULL; memcpy(res, s, len); res[len] = 0; return res; } /* Like strdup, but trims whitespace from the string * according to specified flags. See TH_TRIM_* in * th_string.h */ char *th_strdup_trim(const char *s, const int flags) { char *res; size_t start, end, len; if (s == NULL) return NULL; len = strlen(s); // Trim start: find first non-whitespace character if (flags & TH_TRIM_START) for (start = 0; start < len && th_isspace(s[start]); start++); else start = 0; // Trim end: find last non-whitespace character if (flags & TH_TRIM_END) for (end = len; end > start && th_isspace(s[end]); end--); else end = len; // Allocate memory for result len = end - start + 1; if ((res = th_malloc(len + 1)) == NULL) return NULL; memcpy(res, s, len); res[len] = 0; return res; } /* Simulate a sprintf() that allocates memory */ char *th_strdup_vprintf(const char *fmt, va_list args) { int size = 64; char *buf, *tmp; if ((buf = th_malloc(size)) == NULL) return NULL; while (1) { int n; va_list ap; va_copy(ap, args); n = vsnprintf(buf, size, fmt, ap); va_end(ap); if (n > -1 && n < size) return buf; if (n > -1) size = n + 1; else size *= 2; if ((tmp = th_realloc(buf, size)) == NULL) { th_free(buf); return NULL; } else buf = tmp; } } char *th_strdup_printf(const char *fmt, ...) { char *res; va_list ap; va_start(ap, fmt); res = th_strdup_vprintf(fmt, ap); va_end(ap); return res; } void th_pstr_vprintf(char **buf, const char *fmt, va_list ap) { char *tmp = th_strdup_vprintf(fmt, ap); th_free(*buf); *buf = tmp; } void th_pstr_printf(char **buf, const char *fmt, ...) { char *tmp; va_list ap; va_start(ap, fmt); tmp = th_strdup_vprintf(fmt, ap); va_end(ap); th_free(*buf); *buf = tmp; } /* Compare two strings ignoring case [strcasecmp, strncasecmp] */ int th_strcasecmp(const char *str1, const char *str2) { const char *s1 = str1, *s2 = str2; assert(str1 != NULL); assert(str2 != NULL); if (str1 == str2) return 0; while (*s1 && *s2 && th_tolower(*s1) == th_tolower(*s2)) { s1++; s2++; } return th_tolower(*s1) - th_tolower(*s2); } int th_strncasecmp(const char *str1, const char *str2, size_t n) { const char *s1 = str1, *s2 = str2; assert(str1 != NULL); assert(str2 != NULL); if (str1 == str2) return 0; while (n > 0 && *s1 && *s2 && th_tolower(*s1) == th_tolower(*s2)) { s1++; s2++; n--; } return n > 0 ? (th_tolower(*s1) - th_tolower(*s2)) : 0; } /* Check if end of the given string str matches needle * case-insensitively, return pointer to start of the match, * if found, NULL otherwise. */ char *th_strrcasecmp(char *str, const char *needle) { if (str == NULL || needle == NULL) return NULL; const size_t slen = strlen(str), nlen = strlen(needle); if (slen < nlen) return NULL; if (th_strcasecmp(str - nlen - 1, needle) == 0) return str - nlen - 1; else return NULL; } /* Remove all occurences of control characters, in-place. * Resulting string is always shorter or same length than original. */ void th_strip_ctrlchars(char *str) { char *i, *j; assert(str != NULL); i = str; j = str; while (*i) { if (!th_iscntrl(*i)) *(j++) = *i; i++; } *j = 0; } /* Copy a given string over in *result. */ int th_pstrcpy(char **result, const char *str) { assert(result != NULL); if (str == NULL) return -1; th_free(*result); if ((*result = th_malloc(strlen(str) + 1)) == NULL) return -2; strcpy(*result, str); return 0; } /* Concatenates a given string into string pointed by *result. */ int th_pstrcat(char **result, const char *str) { assert(result != NULL); if (str == NULL) return -1; if (*result != NULL) { *result = th_realloc(*result, strlen(*result) + strlen(str) + 1); if (*result == NULL) return -1; strcat(*result, str); } else { *result = th_malloc(strlen(str) + 1); if (*result == NULL) return -1; strcpy(*result, str); } return 0; } /* Find next non-whitespace character in string. * Updates iPos into the position of such character and * returns pointer to the string. */ const char *th_findnext(const char *str, size_t *pos) { assert(str != NULL); // Terminating NULL-character is not whitespace! while (th_isspace(str[*pos])) (*pos)++; return &str[*pos]; } /* Find next sep-character from string */ const char *th_findsep(const char *str, size_t *pos, char sep) { assert(str != NULL); while (str[*pos] && str[*pos] != sep) (*pos)++; return &str[*pos]; } /* Find next sep- or whitespace from string */ const char *th_findseporspace(const char *str, size_t *pos, char sep) { assert(str != NULL); while (!th_isspace(str[*pos]) && str[*pos] != sep) (*pos)++; return &str[*pos]; } /* Compare a string to a pattern. Case-SENSITIVE version. * The matching pattern can consist of any normal characters plus * wildcards ? and *. "?" matches any character and "*" matches * any number of characters. */ BOOL th_strmatch(const char *str, const char *pattern) { BOOL matched = TRUE, any = FALSE, end = FALSE; const char *tmp = NULL; // Check given pattern and string if (str == NULL || pattern == NULL) return FALSE; // Start comparision do { matched = FALSE; switch (*pattern) { case '?': // Any single character matches if (*str) { matched = TRUE; pattern++; str++; } break; case '*': matched = TRUE; pattern++; if (!*pattern) end = TRUE; any = TRUE; tmp = pattern; break; case 0: if (any) { if (*str) str++; else end = TRUE; } else { if (*str) { if (tmp) { any = TRUE; pattern = tmp; } else matched = FALSE; } else end = TRUE; } break; default: if (any) { if (*pattern == *str) { any = FALSE; matched = TRUE; } else { if (*str) { matched = TRUE; str++; } } } else { if (*pattern == *str) { matched = TRUE; if (*pattern) pattern++; if (*str) str++; } else { if (tmp) { matched = TRUE; any = TRUE; pattern = tmp; } } } if (!*str && !*pattern) end = TRUE; break; } // switch } while (matched && !end); return matched; } /* Compare a string to a pattern. Case-INSENSITIVE version. */ BOOL th_strcasematch(const char *str, const char *pattern) { BOOL matched = TRUE, any = FALSE, end = FALSE; const char *tmp = NULL; // Check given pattern and string if (str == NULL || pattern == NULL) return FALSE; // Start comparision do { switch (*pattern) { case '?': // Any single character matches if (*str) { pattern++; str++; } else matched = FALSE; break; case '*': pattern++; if (!*pattern || *pattern == '?') end = TRUE; any = TRUE; tmp = pattern; break; case 0: if (any) { if (*str) str++; else end = TRUE; } else { if (*str) { if (tmp) { any = TRUE; pattern = tmp; } else matched = FALSE; } else end = TRUE; } break; default: if (any) { if (th_tolower(*pattern) == th_tolower(*str)) { any = FALSE; } else { if (*str) str++; else matched = FALSE; } } else { if (th_tolower(*pattern) == th_tolower(*str)) { if (*pattern) pattern++; if (*str) str++; } else { if (tmp) { any = TRUE; pattern = tmp; } else matched = FALSE; } } if (!*str && !*pattern) end = TRUE; break; } // switch } while (matched && !end); return matched; } int th_get_hex_triplet(const char *str) { const char *p = str; int len, val = 0; for (len = 0; *p && len < 6; p++, len++) { if (*p >= '0' && *p <= '9') { val *= 16; val += (*p - '0'); } else if (*p >= 'A' && *p <= 'F') { val *= 16; val += (*p - 'A') + 10; } else if (*p >= 'a' && *p <= 'f') { val *= 16; val += (*p - 'a') + 10; } else return -1; } return (len == 6) ? val : -1; } BOOL th_get_boolean(const char *str, BOOL *value) { if (!th_strcasecmp(str, "yes") || !th_strcasecmp(str, "on") || !th_strcasecmp(str, "true") || !th_strcasecmp(str, "1")) { *value = TRUE; return TRUE; } else if (!th_strcasecmp(str, "no") || !th_strcasecmp(str, "off") || !th_strcasecmp(str, "false") || !th_strcasecmp(str, "0")) { *value = FALSE; return TRUE; } else return FALSE; } static void th_pad(FILE *outFile, int count) { while (count--) fputc(' ', outFile); } void th_print_wrap(FILE *fh, const char *str, int spad, int rpad, int width) { size_t pos = 0; BOOL first = TRUE; while (str[pos]) { // Pre-pad line int linelen = first ? spad : rpad; th_pad(fh, first ? 0 : rpad); first = FALSE; // Skip whitespace at line start while (th_isspace(str[pos]) || str[pos] == '\n') pos++; // Handle each word while (str[pos] && str[pos] != '\n') { size_t next; int wlen; // Find word length and next break for (wlen = 0, next = pos; str[next] && !th_isspace(str[next]) && str[next] != '\n'; next++, wlen++); // Check if we have too much of text? if (linelen + wlen >= width) break; // Print what we have for (;pos < next; pos++, linelen++) fputc(str[pos], fh); // Check if we are at end of input or hard linefeed if (str[next] == '\n' || str[next] == 0) break; else { fputc(str[pos], fh); pos++; linelen++; } } fprintf(fh, "\n"); } }