diff th_string.c @ 0:728243125263

Import.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 20 Mar 2008 00:15:03 +0000
parents
children ecfa4e3597e3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/th_string.c	Thu Mar 20 00:15:03 2008 +0000
@@ -0,0 +1,926 @@
+/*
+ * 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_t *th_stralloc(const size_t l)
+{
+	assert(l > 0);
+	return th_malloc(sizeof(char_t) * l);
+}
+
+
+char_t *th_strrealloc(char_t * s, const size_t l)
+{
+	assert(l > 0);
+	return th_realloc(s, sizeof(char_t) * l);
+}
+
+
+/* Calculate the length of a string [strlen]
+ */
+size_t th_strlen(char_t * pStr)
+{
+	size_t l = 0;
+	char_t *s = pStr;
+	assert(pStr);
+
+	while (*s) {
+		s++;
+		l++;
+	}
+
+	return l;
+}
+
+
+/* Duplicate a string [strdup]
+ */
+char_t *th_strdup(char_t * pStr)
+{
+	char_t *pResult, *s, *d;
+
+	if (!pStr) return NULL;
+	
+	/* Allocate memory for destination */
+	pResult = th_stralloc(th_strlen(pStr) + 1);
+	if (!pResult)
+		return NULL;
+
+	/* Copy to the destination */
+	s = pStr;
+	d = pResult;
+	while (*s) {
+		*(d++) = *(s++);
+	}
+	*d = 0;
+
+	return pResult;
+}
+
+
+/* Concatenate a string [strcat]
+ */
+char_t *th_strcat(char_t * pDest, char_t * pSource)
+{
+	char_t *s, *d;
+	assert(pSource);
+	assert(pDest);
+
+	/* Copy to the destination */
+	s = pSource;
+	d = pDest;
+
+	while (*d) d++;
+
+	while (*s) {
+		*(d++) = *(s++);
+	}
+	*d = 0;
+
+	return pDest;
+}
+
+
+/* Copy a string [strcpy, strncpy]
+ */
+char_t *th_strcpy(char_t * pDest, char_t * pSource)
+{
+	char_t *s, *d;
+	assert(pSource);
+	assert(pDest);
+
+	/* Copy to the destination */
+	s = pSource;
+	d = pDest;
+
+	while (*s) {
+		*(d++) = *(s++);
+	}
+	*d = 0;
+
+	return pDest;
+}
+
+
+char_t *th_strncpy(char_t * pDest, char_t * pSource, size_t n)
+{
+	char_t *s, *d;
+	size_t i;
+	assert(pSource);
+	assert(pDest);
+
+	/* Copy to the destination */
+	i = n;
+	s = pSource;
+	d = pDest;
+	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 */
+	pDest[n - 1] = 0;
+
+	return pDest;
+}
+
+
+/* Compare given strings [strcmp, strncmp]
+ */
+int th_strcmp(char_t * pStr1, char_t * pStr2)
+{
+	char_t *s1, *s2;
+	assert(pStr1);
+	assert(pStr2);
+
+	/* Check the string pointers */
+	if (pStr1 == pStr2)
+		return 0;
+
+	/* Go through the string */
+	s1 = pStr1;
+	s2 = pStr2;
+	while (*s1 && *s2 && (*s1 == *s2)) {
+		s1++;
+		s2++;
+	}
+
+	return ((*s1) - (*s2));
+}
+
+
+int th_strncmp(char_t * pStr1, char_t * pStr2, size_t n)
+{
+	char_t *s1, *s2;
+	assert(pStr1);
+	assert(pStr2);
+
+	/* Check the string pointers */
+	if (pStr1 == pStr2)
+		return 0;
+
+	/* Go through the string */
+	s1 = pStr1;
+	s2 = pStr2;
+	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_t * pStr1, char_t * pStr2)
+{
+	char_t *s1, *s2;
+	assert(pStr1);
+	assert(pStr2);
+
+	/* Check the string pointers */
+	if (pStr1 == pStr2)
+		return 0;
+
+	/* Go through the string */
+	s1 = pStr1;
+	s2 = pStr2;
+	while (*s1 && *s2 && (th_tolower(*s1) == th_tolower(*s2))) {
+		s1++;
+		s2++;
+	}
+
+	return (th_tolower(*s1) - th_tolower(*s2));
+}
+
+
+int th_strncasecmp(char_t * pStr1, char_t * pStr2, size_t n)
+{
+	char_t *s1, *s2;
+	assert(pStr1);
+	assert(pStr2);
+
+	/* Check the string pointers */
+	if (pStr1 == pStr2)
+		return 0;
+
+	/* Go through the string */
+	s1 = pStr1;
+	s2 = pStr2;
+	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_t * pStr)
+{
+	char_t *i, *j;
+	assert(pStr);
+
+	i = pStr;
+	j = pStr;
+	while (*i) {
+		if (!th_iscntrl(*i))
+			*(j++) = *i;
+		i++;
+	}
+
+	*j = 0;
+}
+
+
+/* Locate a substring [strstr]
+ */
+char_t *th_strstr(char_t * haystack, char_t * needle)
+{
+	char_t *h, *n, *s;
+	assert(haystack);
+	assert(needle);
+
+	/* If 'needle' is empty, we return 'haystack' */
+	if (!*needle)
+		return haystack;
+
+	/* Search for 'needle' in 'haystack' */
+	h = haystack;
+	n = needle;
+	while (*h) {
+		/* Find possible start of 'needle' */
+		while (*h && (*h != *n))
+			h++;
+
+		if (*h == *n) {
+			/* Found, check rest */
+			s = h;
+			n = needle;
+			while (*h) {
+				if (!*n)
+					return s;
+				else
+				if (*h != *n)
+					break;
+				n++;
+				h++;
+			}
+			h = s;
+			h++;
+		}
+	}
+
+	return NULL;
+}
+
+
+/* Copy a given string over in *ppResult.
+ */
+int th_pstrcpy(char_t ** ppResult, char_t * pStr)
+{
+	assert(ppResult);
+
+	/* Check the string pointers */
+	if (!pStr)
+		return -1;
+
+	/* Allocate memory for destination */
+	th_free(*ppResult);
+	*ppResult = th_stralloc(th_strlen(pStr) + 1);
+	if (!*ppResult)
+		return -2;
+
+	/* Copy to the destination */
+	th_strcpy(*ppResult, pStr);
+
+	return 0;
+}
+
+
+/* Concatenates a given string into string pointed by *ppResult.
+ */
+int th_pstrcat(char_t ** ppResult, char_t * pStr)
+{
+	assert(ppResult);
+
+	/* Check the string pointers */
+	if (!pStr)
+		return -1;
+
+	if (*ppResult != NULL) {
+		*ppResult = th_strrealloc(*ppResult, th_strlen(*ppResult) + th_strlen(pStr) + 1);
+		if (*ppResult == NULL)
+			return -1;
+
+		th_strcat(*ppResult, pStr);
+	} else {
+		*ppResult = th_stralloc(th_strlen(pStr) + 1);
+		if (*ppResult == NULL)
+			return -1;
+
+		th_strcpy(*ppResult, pStr);
+	}
+
+	return 0;
+}
+
+
+/* Find next non-whitespace character in string.
+ * Updates iPos into the position of such character and
+ * returns pointer to the string.
+ */
+char_t *th_findnext(char_t * pStr, size_t * iPos)
+{
+	assert(pStr);
+
+	/* Terminating NULL-character is not whitespace! */
+	while (th_isspace(pStr[*iPos]))
+		(*iPos)++;
+	return &pStr[*iPos];
+}
+
+
+/* Find next chSep-character from string
+ */
+char_t *th_findsep(char_t * pStr, size_t * iPos, char_t chSep)
+{
+	assert(pStr);
+
+	/* Terminating NULL-character is not digit! */
+	while (pStr[*iPos] && (pStr[*iPos] != chSep))
+		(*iPos)++;
+	return &pStr[*iPos];
+}
+
+
+/* Find next chSep- or whitespace from string
+ */
+char_t *th_findseporspace(char_t * pStr, size_t * iPos, char_t chSep)
+{
+	assert(pStr);
+
+	/* Terminating NULL-character is not digit! */
+	while (!th_isspace(pStr[*iPos]) && (pStr[*iPos] != chSep))
+		(*iPos)++;
+	return &pStr[*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_t * pStr, char_t * pPattern)
+{
+	BOOL didMatch, isAnyMode, isEnd;
+	char_t *tmpPattern;
+
+	/* Check given pattern and string */
+	if (!pStr)
+		return FALSE;
+	if (!pPattern)
+		return FALSE;
+
+	/* Initialize */
+	tmpPattern = NULL;
+	didMatch = TRUE;
+	isEnd = FALSE;
+	isAnyMode = FALSE;
+
+	/* Start comparision */
+	do {
+		didMatch = FALSE;
+		switch (*pPattern) {
+		case '?':
+			/* Any single character matches */
+			if (*pStr) {
+				didMatch = TRUE;
+				pPattern++;
+				pStr++;
+			}
+			break;
+
+		case '*':
+			didMatch = TRUE;
+			pPattern++;
+			if (!*pPattern)
+				isEnd = TRUE;
+			isAnyMode = TRUE;
+			tmpPattern = pPattern;
+			break;
+
+		case 0:
+			if (isAnyMode) {
+				if (*pStr)
+					pStr++;
+				else
+					isEnd = TRUE;
+			} else {
+				if (*pStr) {
+					if (tmpPattern) {
+						isAnyMode = TRUE;
+						pPattern = tmpPattern;
+					} else
+						didMatch = FALSE;
+				} else
+					isEnd = TRUE;
+			}
+			break;
+		default:
+			if (isAnyMode) {
+				if ((*pPattern) == (*pStr)) {
+					isAnyMode = FALSE;
+					didMatch = TRUE;
+				} else {
+					if (*pStr) {
+						didMatch = TRUE;
+						pStr++;
+					}
+				}
+			} else {
+				if ((*pPattern) == (*pStr)) {
+					didMatch = TRUE;
+					if (*pPattern)
+						pPattern++;
+					if (*pStr)
+						pStr++;
+				} else {
+					if (tmpPattern) {
+						didMatch = TRUE;
+						isAnyMode = TRUE;
+						pPattern = tmpPattern;
+					}
+				}
+			}
+
+			if (!*pStr && !*pPattern)
+				isEnd = TRUE;
+			break;
+
+		}		/* switch */
+
+	} while ((didMatch) && (!isEnd));
+
+	return didMatch;
+}
+
+
+/* Compare a string to a pattern. Case-INSENSITIVE version.
+ */
+BOOL th_strcasematch(char_t * pStr, char_t * pPattern)
+{
+	BOOL didMatch, isAnyMode, isEnd;
+	char_t *tmpPattern;
+
+	/* Check given pattern and string */
+	if (!pStr)
+		return FALSE;
+	if (!pPattern)
+		return FALSE;
+
+	/* Initialize */
+	tmpPattern = NULL;
+	didMatch = TRUE;
+	isEnd = FALSE;
+	isAnyMode = FALSE;
+
+	/* Start comparision */
+	do {
+		switch (*pPattern) {
+		case '?':
+			/* Any single character matches */
+			if (*pStr) {
+				pPattern++;
+				pStr++;
+			} else
+				didMatch = FALSE;
+			break;
+
+		case '*':
+			pPattern++;
+			if (!*pPattern || (*pPattern == '?'))
+				isEnd = TRUE;
+			isAnyMode = TRUE;
+			tmpPattern = pPattern;
+			break;
+
+		case 0:
+			if (isAnyMode) {
+				if (*pStr)
+					pStr++;
+				else
+					isEnd = TRUE;
+			} else {
+				if (*pStr) {
+					if (tmpPattern) {
+						isAnyMode = TRUE;
+						pPattern = tmpPattern;
+					} else
+						didMatch = FALSE;
+				} else
+					isEnd = TRUE;
+			}
+			break;
+
+		default:
+			if (isAnyMode) {
+				if (th_tolower(*pPattern) == th_tolower(*pStr)) {
+					isAnyMode = FALSE;
+				} else {
+					if (*pStr)
+						pStr++;
+					else
+						didMatch = FALSE;
+				}
+			} else {
+				if (th_tolower(*pPattern) == th_tolower(*pStr)) {
+					if (*pPattern)
+						pPattern++;
+					if (*pStr)
+						pStr++;
+				} else {
+					if (tmpPattern) {
+						isAnyMode = TRUE;
+						pPattern = tmpPattern;
+					} else
+						didMatch = FALSE;
+				}
+			}
+
+			if (!*pStr && !*pPattern)
+				isEnd = TRUE;
+			break;
+
+		}		/* switch */
+
+	} while ((didMatch) && (!isEnd));
+
+	return didMatch;
+}
+
+
+/*
+ * Handling of string-lists and hashes
+ */
+t_str_node *th_strnode_new(char_t * pcStr, ulint_t nUsed, void *pData)
+{
+	t_str_node *pResult;
+
+	/* Allocate memory for new node */
+	pResult = (t_str_node *) th_calloc(1, sizeof(t_str_node));
+	if (!pResult)
+		return NULL;
+
+	/* Set fields */
+	th_pstrcpy(&pResult->pcStr, pcStr);
+	pResult->nUsed = nUsed;
+	pResult->pData = pData;
+
+	return pResult;
+}
+
+
+void th_strnode_free(t_str_node * pNode)
+{
+	assert(pNode);
+
+	th_free(pNode->pcStr);
+	th_free(pNode);
+}
+
+
+/* Insert a new node into strlist
+ */
+void th_strlist_insert(t_str_node ** strList, t_str_node * pNode)
+{
+	assert(strList);
+	assert(pNode);
+
+	/* Insert into linked list */
+	if (*strList) {
+		/* The first node's pPrev points to last node */
+		LPREV = (*strList)->pPrev;	/* New node's prev = Previous last node */
+		(*strList)->pPrev->pNext = pNode;	/* Previous last node's next = New node */
+		(*strList)->pPrev = pNode;	/* New last node = New node */
+		LNEXT = NULL;	/* But next is NULL! */
+	} else {
+		(*strList) = pNode;	/* First node ... */
+		LPREV = pNode;	/* ... it's also last */
+		LNEXT = NULL;	/* But next is NULL! */
+	}
+
+}
+
+
+/* Free a given strlist
+ */
+void th_strlist_free(t_str_node * strList)
+{
+	t_str_node *pNode, *nNode;
+
+	pNode = strList;
+	while (pNode) {
+		nNode = pNode->pNext;
+		th_strnode_free(pNode);
+		pNode = nNode;
+	}
+}
+
+
+/* Create a strIndex from strlist
+ */
+t_str_index *th_strlist_makeindex(t_str_node * strList)
+{
+	t_str_index *pResult;
+	t_str_node *pCurr;
+	ulint_t n;
+	assert(strList);
+
+	/* Computer number of nodes */
+	for (n = 0, pCurr = strList; pCurr; pCurr = pCurr->pNext)
+		n++;
+
+	/* Check number of nodes */
+	if (n == 0)
+		return NULL;
+
+	/* Allocate memory for index */
+	pResult = (t_str_index *) th_calloc(1, sizeof(t_str_index));
+	if (!pResult)
+		return NULL;
+
+	pResult->n = n;
+	pResult->ppIndex = (t_str_node **) th_calloc(n, sizeof(t_str_node *));
+	if (!pResult->ppIndex) {
+		th_free(pResult);
+		return NULL;
+	}
+
+	/* Create the index */
+	for (n = 0, pCurr = strList; pCurr && (n < pResult->n); pCurr = pCurr->pNext)
+		pResult->ppIndex[n++] = pCurr;
+
+	return pResult;
+}
+
+
+/* Insert a node into given strhash
+ */
+int th_strhash_insert(t_str_hash strHash, t_str_node * pNode, BOOL ignoreCase)
+{
+	int i;
+	assert(strHash);
+	assert(pNode);
+	assert(pNode->pcStr);
+
+	if (ignoreCase)
+		i = th_tolower(pNode->pcStr[0]);
+	else
+		i = pNode->pcStr[0];
+
+	/* Check the hashcode */
+	if ((i < 0) && (i >= SET_HASH_MAXINDEX))
+		return -1;
+
+	if (strHash[i]) {
+		/* The first node's pPrev points to last node */
+		pNode->pPrev = strHash[i]->pPrev;	/* New node's prev = Previous last node */
+		strHash[i]->pPrev->pNext = pNode;	/* Previous last node's next = New node */
+		strHash[i]->pPrev = pNode;	/* New last node = New node */
+		pNode->pNext = NULL;	/* But next is NULL! */
+	} else {
+		strHash[i] = pNode;	/* First node */
+		pNode->pPrev = pNode;	/* But also last */
+		pNode->pNext = NULL;	/* But next is NULL! */
+	}
+
+	return 0;
+}
+
+
+/* Free a given strhash
+ */
+void th_strhash_free(t_str_hash strHash)
+{
+	int i;
+	assert(strHash);
+
+	for (i = 0; i < SET_HASH_MAXINDEX; i++)
+		th_strlist_free(strHash[i]);
+}
+
+
+/* Change pData for matching entries to new value
+ */
+void th_strhash_change_pdata(t_str_hash strHash, void *pFind, void *pNew)
+{
+	t_str_node *pCurr;
+	int i;
+	assert(strHash);
+
+	for (i = 0; i < SET_HASH_MAXINDEX; i++) {
+		/* Find from linked list */
+		pCurr = strHash[i];
+		while (pCurr) {
+			if (pCurr->pData == pFind)
+				pCurr->pData = pNew;
+
+			pCurr = pCurr->pNext;
+		}
+	}
+}
+
+
+/* Search a string from a given stringhash, either case-sensitive or insensitive
+ */
+t_str_node *th_strhash_search(t_str_hash strHash, char_t * findStr, BOOL ignoreCase)
+{
+	t_str_node *pCurr;
+	int i;
+	BOOL isFound;
+	assert(strHash);
+	assert(findStr);
+
+	isFound = FALSE;
+	pCurr = NULL;
+
+	/* Check hashcode */
+	if (ignoreCase)
+		i = ((unsigned char) th_tolower(findStr[0]));
+	else
+		i = ((unsigned char) findStr[0]);
+
+	if ((i < 0) && (i >= SET_HASH_MAXINDEX))
+		return NULL;
+
+	/* Find from linked list */
+	pCurr = strHash[i];
+
+	if (ignoreCase) {
+		/* Case in-sensitive search */
+		while (pCurr && !isFound) {
+			if (th_strcasecmp(findStr, pCurr->pcStr) == 0)
+				isFound = TRUE;
+			else
+				pCurr = pCurr->pNext;
+		}
+	} else {
+		/* Case sensitive search */
+		while (pCurr && !isFound) {
+			if (th_strcmp(findStr, pCurr->pcStr) == 0)
+				isFound = TRUE;
+			else
+				pCurr = pCurr->pNext;
+		}
+	}
+
+	/* Return result */
+	if (isFound)
+		return pCurr;
+	else
+		return NULL;
+}
+
+
+/* Create a strIndex from strHash
+ */
+t_str_index *th_strhash_makeindex(t_str_hash strHash)
+{
+	t_str_index *pResult;
+	t_str_node *pCurr;
+	unsigned int n, i;
+	assert(strHash);
+
+	/* Computer number of nodes */
+	for (n = i = 0; i < SET_HASH_MAXINDEX; i++) {
+		pCurr = strHash[i];
+		while (pCurr) {
+			n++;
+			pCurr = pCurr->pNext;
+		}
+	}
+
+	/* Check number of nodes */
+	if (n <= 0)
+		return NULL;
+
+	/* Allocate memory for index */
+	pResult = (t_str_index *) th_calloc(1, sizeof(t_str_index));
+	if (!pResult)
+		return NULL;
+
+	pResult->n = n;
+	pResult->ppIndex = (t_str_node **) th_calloc(n, sizeof(t_str_node *));
+	if (!pResult->ppIndex) {
+		th_free(pResult);
+		return NULL;
+	}
+
+	/* Create the index */
+	for (n = i = 0; (i < SET_HASH_MAXINDEX) && (n < pResult->n); i++) {
+		pCurr = strHash[i];
+		while (pCurr && (n < pResult->n)) {
+			pResult->ppIndex[n++] = pCurr;
+			pCurr = pCurr->pNext;
+		}
+	}
+
+	return pResult;
+}
+
+
+/* Free a given strIndex
+ */
+void th_strindex_free(t_str_index * strIndex)
+{
+	if (strIndex) {
+		th_free(strIndex->ppIndex);
+		th_free(strIndex);
+	}
+}
+
+
+/* Compare two t_str_nodes by nUsed
+ */
+int th_strindex_cmp_used(const void *pNode1, const void *pNode2)
+{
+	t_str_node *pStr1, *pStr2;
+
+	pStr1 = *(t_str_node **) pNode1;
+	pStr2 = *(t_str_node **) pNode2;
+
+	if (pStr1->nUsed > pStr2->nUsed)
+		return -1;
+	else if (pStr1->nUsed < pStr2->nUsed)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* Sort an strIndex by nUsed, using th_strindex_cmp_used()
+ */
+void th_strindex_sort_nused(t_str_index * strIndex)
+{
+	assert(strIndex);
+	assert(strIndex->ppIndex);
+
+	qsort(strIndex->ppIndex, strIndex->n, sizeof(t_str_node *), th_strindex_cmp_used);
+}
+
+
+/* Compare two t_str_nodes via strcmp()
+ */
+int th_strindex_cmp_alpha(const void *pNode1, const void *pNode2)
+{
+	t_str_node *pStr1, *pStr2;
+
+	pStr1 = *(t_str_node **) pNode1;
+	pStr2 = *(t_str_node **) pNode2;
+
+	return th_strcmp(pStr1->pcStr, pStr2->pcStr);
+}
+
+
+/* Sort an strIndex by nUsed, using th_strindex_cmp_used()
+ */
+void th_strindex_sort_alpha(t_str_index * strIndex)
+{
+	assert(strIndex);
+	assert(strIndex->ppIndex);
+
+	qsort(strIndex->ppIndex, strIndex->n, sizeof(t_str_node *), th_strindex_cmp_alpha);
+}