view th_string.c @ 77:e8c9d7d13866

Handle certain key sequences better.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 13 Dec 2008 11:19:19 +0200
parents e47955d42b55
children e36df57c5b0f
line wrap: on
line source

/*
 * 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);
}


char *th_strncpy(char * dst, const char * src, size_t n)
{
	const char *s = src;
	char *d = dst;
	size_t i;
	assert(src != NULL);
	assert(dst != NULL);

	/* Copy to the destination */
	i = n;
	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 != NULL);
	assert(str2 != NULL);

	/* 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 != NULL);
	assert(str2 != NULL);

	/* 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 != NULL);
	assert(str2 != NULL);

	/* 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 != 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, char * str)
{
	assert(result != NULL);

	/* Check the string pointers */
	if (str == NULL)
		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 != NULL);

	/* Check the string pointers */
	if (str == NULL)
		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 != NULL);

	/* 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 != NULL);

	/* 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 != NULL);

	/* 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 = TRUE, isAnyMode = FALSE, isEnd = FALSE;
	char *tmpPattern = NULL;

	/* Check given pattern and string */
	if (str == NULL || pattern == NULL)
		return 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 = TRUE, isAnyMode = FALSE, isEnd = FALSE;
	char *tmpPattern = 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
				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;
}