diff th_string.c @ 0:bd61a80a6c54

Initial import into Mercurial repository. Discarding old cvs/svn history here, because it's cluttered and commit messages are mostly crap.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 26 Mar 2008 04:41:58 +0200
parents
children 41885619fc79
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/th_string.c	Wed Mar 26 04:41:58 2008 +0200
@@ -0,0 +1,462 @@
+/*
+ * Miscellaneous string-handling related utility-functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2002-2008 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "th_string.h"
+
+#define LPREV (pNode->pPrev)
+#define LNEXT (pNode->pNext)
+
+/* Allocate memory for a string with given length
+ */
+char *th_stralloc(const size_t l)
+{
+	assert(l > 0);
+	return th_malloc(sizeof(char) * l);
+}
+
+
+char *th_strrealloc(char * s, const size_t l)
+{
+	assert(l > 0);
+	return th_realloc(s, sizeof(char) * l);
+}
+
+
+/* Duplicate a string [strdup]
+ */
+char *th_strdup(char * str)
+{
+	char *result, *s, *d;
+
+	if (!str) return NULL;
+	
+	/* Allocate memory for destination */
+	result = th_stralloc(strlen(str) + 1);
+	if (!result)
+		return NULL;
+
+	/* Copy to the destination */
+	s = str;
+	d = result;
+	while (*s) {
+		*(d++) = *(s++);
+	}
+	*d = 0;
+
+	return result;
+}
+
+
+char *th_strncpy(char * dst, char * src, size_t n)
+{
+	char *s, *d;
+	size_t i;
+	assert(src);
+	assert(dst);
+
+	/* Copy to the destination */
+	i = n;
+	s = src;
+	d = dst;
+	while (*s && (i > 0)) {
+		*(d++) = *(s++);
+		i--;
+	}
+
+	/* Fill rest of space with zeros */
+	while (i > 0) {
+		*(d++) = 0;
+		i--;
+	}
+
+	/* Ensure that last is always zero */
+	dst[n - 1] = 0;
+
+	return dst;
+}
+
+
+int th_strncmp(char * str1, char * str2, size_t n)
+{
+	char *s1, *s2;
+	assert(str1);
+	assert(str2);
+
+	/* Check the string pointers */
+	if (str1 == str2)
+		return 0;
+
+	/* Go through the string */
+	s1 = str1;
+	s2 = str2;
+	while ((n > 0) && *s1 && *s2 && (*s1 == *s2)) {
+		s1++;
+		s2++;
+		n--;
+	}
+
+	if (n > 0)
+		return ((*s1) - (*s2));
+	else
+		return 0;
+}
+
+
+/* Compare two strings ignoring case [strcasecmp, strncasecmp]
+ */
+int th_strcasecmp(char * str1, char * str2)
+{
+	char *s1 = str1, *s2 = str2;
+	assert(str1);
+	assert(str2);
+
+	/* Check the string pointers */
+	if (str1 == str2)
+		return 0;
+
+	/* Go through the string */
+	while (*s1 && *s2 && (th_tolower(*s1) == th_tolower(*s2))) {
+		s1++;
+		s2++;
+	}
+
+	return (th_tolower(*s1) - th_tolower(*s2));
+}
+
+
+int th_strncasecmp(char * str1, char * str2, size_t n)
+{
+	char *s1 = str1, *s2 = str2;
+	assert(str1);
+	assert(str2);
+
+	/* Check the string pointers */
+	if (str1 == str2)
+		return 0;
+
+	/* Go through the string */
+	while ((n > 0) && *s1 && *s2 && (th_tolower(*s1) == th_tolower(*s2))) {
+		s1++;
+		s2++;
+		n--;
+	}
+
+	if (n > 0)
+		return (th_tolower(*s1) - th_tolower(*s2));
+	else
+		return 0;
+}
+
+
+/* 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);
+
+	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, char * str)
+{
+	assert(result);
+
+	/* Check the string pointers */
+	if (!str)
+		return -1;
+
+	/* Allocate memory for destination */
+	th_free(*result);
+	*result = th_stralloc(strlen(str) + 1);
+	if (!*result)
+		return -2;
+
+	/* Copy to the destination */
+	strcpy(*result, str);
+
+	return 0;
+}
+
+
+/* Concatenates a given string into string pointed by *result.
+ */
+int th_pstrcat(char ** result, char * str)
+{
+	assert(result);
+
+	/* Check the string pointers */
+	if (!str)
+		return -1;
+
+	if (*result != NULL) {
+		*result = th_strrealloc(*result, strlen(*result) + strlen(str) + 1);
+		if (*result == NULL)
+			return -1;
+
+		strcat(*result, str);
+	} else {
+		*result = th_stralloc(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.
+ */
+char *th_findnext(char * str, size_t * iPos)
+{
+	assert(str);
+
+	/* Terminating NULL-character is not whitespace! */
+	while (th_isspace(str[*iPos]))
+		(*iPos)++;
+	return &str[*iPos];
+}
+
+
+/* Find next chSep-character from string
+ */
+char *th_findsep(char * str, size_t * iPos, char chSep)
+{
+	assert(str);
+
+	/* Terminating NULL-character is not digit! */
+	while (str[*iPos] && (str[*iPos] != chSep))
+		(*iPos)++;
+	return &str[*iPos];
+}
+
+
+/* Find next chSep- or whitespace from string
+ */
+char *th_findseporspace(char * str, size_t * iPos, char chSep)
+{
+	assert(str);
+
+	/* Terminating NULL-character is not digit! */
+	while (!th_isspace(str[*iPos]) && (str[*iPos] != chSep))
+		(*iPos)++;
+	return &str[*iPos];
+}
+
+
+/* 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(char * str, char * pattern)
+{
+	BOOL didMatch, isAnyMode, isEnd;
+	char *tmpPattern;
+
+	/* Check given pattern and string */
+	if (!str)
+		return FALSE;
+	if (!pattern)
+		return FALSE;
+
+	/* Initialize */
+	tmpPattern = NULL;
+	didMatch = TRUE;
+	isEnd = FALSE;
+	isAnyMode = FALSE;
+
+	/* Start comparision */
+	do {
+		didMatch = FALSE;
+		switch (*pattern) {
+		case '?':
+			/* Any single character matches */
+			if (*str) {
+				didMatch = TRUE;
+				pattern++;
+				str++;
+			}
+			break;
+
+		case '*':
+			didMatch = TRUE;
+			pattern++;
+			if (!*pattern)
+				isEnd = TRUE;
+			isAnyMode = TRUE;
+			tmpPattern = pattern;
+			break;
+
+		case 0:
+			if (isAnyMode) {
+				if (*str)
+					str++;
+				else
+					isEnd = TRUE;
+			} else {
+				if (*str) {
+					if (tmpPattern) {
+						isAnyMode = TRUE;
+						pattern = tmpPattern;
+					} else
+						didMatch = FALSE;
+				} else
+					isEnd = TRUE;
+			}
+			break;
+		default:
+			if (isAnyMode) {
+				if ((*pattern) == (*str)) {
+					isAnyMode = FALSE;
+					didMatch = TRUE;
+				} else {
+					if (*str) {
+						didMatch = TRUE;
+						str++;
+					}
+				}
+			} else {
+				if ((*pattern) == (*str)) {
+					didMatch = TRUE;
+					if (*pattern)
+						pattern++;
+					if (*str)
+						str++;
+				} else {
+					if (tmpPattern) {
+						didMatch = TRUE;
+						isAnyMode = TRUE;
+						pattern = tmpPattern;
+					}
+				}
+			}
+
+			if (!*str && !*pattern)
+				isEnd = TRUE;
+			break;
+
+		}		/* switch */
+
+	} while ((didMatch) && (!isEnd));
+
+	return didMatch;
+}
+
+
+/* Compare a string to a pattern. Case-INSENSITIVE version.
+ */
+BOOL th_strcasematch(char * str, char * pattern)
+{
+	BOOL didMatch, isAnyMode, isEnd;
+	char *tmpPattern;
+
+	/* Check given pattern and string */
+	if (!str)
+		return FALSE;
+	if (!pattern)
+		return FALSE;
+
+	/* Initialize */
+	tmpPattern = NULL;
+	didMatch = TRUE;
+	isEnd = FALSE;
+	isAnyMode = FALSE;
+
+	/* Start comparision */
+	do {
+		switch (*pattern) {
+		case '?':
+			/* Any single character matches */
+			if (*str) {
+				pattern++;
+				str++;
+			} else
+				didMatch = FALSE;
+			break;
+
+		case '*':
+			pattern++;
+			if (!*pattern || (*pattern == '?'))
+				isEnd = TRUE;
+			isAnyMode = TRUE;
+			tmpPattern = pattern;
+			break;
+
+		case 0:
+			if (isAnyMode) {
+				if (*str)
+					str++;
+				else
+					isEnd = TRUE;
+			} else {
+				if (*str) {
+					if (tmpPattern) {
+						isAnyMode = TRUE;
+						pattern = tmpPattern;
+					} else
+						didMatch = FALSE;
+				} else
+					isEnd = TRUE;
+			}
+			break;
+
+		default:
+			if (isAnyMode) {
+				if (th_tolower(*pattern) == th_tolower(*str)) {
+					isAnyMode = FALSE;
+				} else {
+					if (*str)
+						str++;
+					else
+						didMatch = FALSE;
+				}
+			} else {
+				if (th_tolower(*pattern) == th_tolower(*str)) {
+					if (*pattern)
+						pattern++;
+					if (*str)
+						str++;
+				} else {
+					if (tmpPattern) {
+						isAnyMode = TRUE;
+						pattern = tmpPattern;
+					} else
+						didMatch = FALSE;
+				}
+			}
+
+			if (!*str && !*pattern)
+				isEnd = TRUE;
+			break;
+
+		}		/* switch */
+
+	} while ((didMatch) && (!isEnd));
+
+	return didMatch;
+}
+