view th_string.c @ 100:ed4067c10a8a

Remove useless buffer usage from error reporting function.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 17 Nov 2009 23:09:10 +0200
parents 69aed051f84d
children fe4d5f3b486c
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)


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


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