libproff/str.c

/* [<][>]
[^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following functions.
  1. strerror
  2. strExchange
  3. strLower
  4. strUpper
  5. strSnip
  6. strCaseEq
  7. strnCaseEq
  8. strcasecmp
  9. strncasecmp
  10. strCaseStr
  11. strnCaseStr
  12. strStripLeftRight
  13. strStripEOL
  14. strnStripEOL
  15. strMakeEOLn
  16. strMakeEOLrn
  17. strHash
  18. lp_strListAdd
  19. strListFree
  20. lp_strStackAdd
  21. lp_strnStackAdd
  22. strStackFree
  23. strToi
  24. strKToi

/* $Id: str.c,v 1.2 2000/06/11 19:28:49 proff Exp $ */

#include "libproff.h"

#include "mmalloc.h"

#define TRUE 1
#define FALSE 0
#define bool int

#ifndef HAVE_STRERROR
extern char *sys_errlist;
EXPORT char *strerror(int n)
/* [<][>][^][v][top][bottom][index][help] */
{
        return sys_errlist[n];
}
#endif /* HAVE_STRERROR */

EXPORT int strExchange (char *s, char c1, char c2)
/* [<][>][^][v][top][bottom][index][help] */
{
        char *head = s;
        for (; *s; s++)
                if (*s == c1)
                        *s = c2;
        return s - head;
}

EXPORT int strLower (char *s)
/* [<][>][^][v][top][bottom][index][help] */
{
        char *head = s;
        for (; *s; s++)
                *s = tolower (*s);
        return s - head;
}

EXPORT int strUpper (char *s)
/* [<][>][^][v][top][bottom][index][help] */
{
        char *head = s;
        for (; *s; s++)
                *s = toupper (*s);
        return s - head;
}

/* start is a \0 terminated list of starting characters
 * end is a \0 terminated list of ending characters
 * 
 * the string stored in buf does not include the starting or ending terminators
 * and is null terminated.
 *
 * returns length of snipped string.
 *
 * buf[0] = '\0' if no string was snipped
 */

EXPORT int strSnip (char *s, int len, char *start, char *end, char *buf, int blen)
/* [<][>][^][v][top][bottom][index][help] */
{
        int n = 0;
        char *endp;
        buf[0] = '\0';
        for (endp = s+len; (!len || s<endp) && *s; s++)
        {
                char *p;
                for (p = start; *p; p++)
                        if (*s == *p)
                                goto hit;
        }
        goto ret;
hit:
        s++;
        for (; (!len || s<endp) && *s; s++, n++)
        {
                char *p;
                for (p = end; *p; p++)
                        if (*s == *p)
                                goto ret;
                *buf++=*s;
        }
        buf[0] = '\0';
        return 0;
ret:
        buf[n] = '\0';
        return n;
}

/* gcc has strcmp built-in (fast) so we use macros if we can. */

#ifndef HAVE_STRCASECMP
EXPORT int strCaseEq (char *s, char *s2)
/* [<][>][^][v][top][bottom][index][help] */
{
        do
        {
                if (tolower (*s) != tolower (*s2))
                        return FALSE;
        } while (*s++ && *s2++);
        return TRUE;
}

EXPORT int strnCaseEq (char *s, char *s2, int n)
/* [<][>][^][v][top][bottom][index][help] */
{
        do
        {
                if (tolower (*s) != tolower (*s2))
                        return FALSE;
        } while (--n<0);
        return TRUE;
}

EXPORT int strcasecmp (char *s, char *s2)
/* [<][>][^][v][top][bottom][index][help] */
{
        do
        {
                char c1=tolower(*s);
                char c2=tolower(*s2);
                if (c1>c2)
                        return 1;
                if (c1<c2)
                        return -1;
        } while (*s++ && *s2++);
        return 0;
}

EXPORT int strncasecmp (char *s, char *s2, int n)
/* [<][>][^][v][top][bottom][index][help] */
{
        do
        {
                char c1=tolower(*s);
                char c2=tolower(*s2);
                if (c1>c2)
                        return 1;
                if (c1<c2)
                        return -1;
        } while (--n);
        return 0;
}
#endif

EXPORT char *strCaseStr (char *s, char *find)
/* [<][>][^][v][top][bottom][index][help] */
{
        char c, sc;
        size_t len;

        if ((c = *find++) != 0) {
                len = strlen(find);
                do {
                        do {
                                if ((sc = *s++) == 0)
                                        return NULL;
                        } while (sc != c);
                } while (!strnCaseEq(s, find, len));
                s--;
        }
        return (char *)s;
}

EXPORT char *strnCaseStr (char *s, char *find, int slen)
/* [<][>][^][v][top][bottom][index][help] */
{
        char c, sc;
        size_t len;
        char *send = s+slen;

        if ((c = *find++) != 0) {
                len = strlen(find);
                do {
                        do {
                                if ((sc = *s++) == 0 || s>=send)
                                        return NULL;
                        } while (sc != c);
                } while (!strnCaseEq(s, find, len));
                s--;
        }
        return ((char *)s);
}

EXPORT int strStripLeftRight (char *s)
/* [<][>][^][v][top][bottom][index][help] */
{
        char *p;
        int n;
        
        for (p = s; *p; p++)
                if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
                        continue;
                else
                        break;
        if (p!=s)
                strcpy (s, p);
        n = strlen (s);
        if (*p)
        {
                for (p = s + n - 1; p >= s && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'); p--) ;
                *(p + 1) = '\0';
                return p - s + 1;
        }
        return n;
}

EXPORT int strStripEOL (char *s)
/* [<][>][^][v][top][bottom][index][help] */
{
        char *head = s;
        for (; *s; s++)
                if (*s == '\r' || *s == '\n')
                {
                        *s = '\0';
                        break;
                }
        return s - head;
}

/*
 * as above, but n = size of string
 */

EXPORT int strnStripEOL (char *s, int n)
/* [<][>][^][v][top][bottom][index][help] */
{
        n--;
        while (n>=0 && (s[n] == '\r' || s[n] == '\n'))
                s[n--]='\0';
        return n+1;
}


EXPORT int strMakeEOLn (char *s)
/* [<][>][^][v][top][bottom][index][help] */
{
        char *head = s;
        for (;; s++)
                if (!*s || *s == '\r')
                {
                        *s++ = '\n';
                        *s = '\0';
                        break;
                }
        return s - head;
}

EXPORT int strMakeEOLrn (char *s)
/* [<][>][^][v][top][bottom][index][help] */
{
        char *head = s;
        for (;; s++)
                if (!*s || *s == '\n' || *s == '\r')
                {
                        *s++ = '\r';
                        *s++ = '\n';
                        *s = '\0';
                        break;
                }
        return s - head;
}

EXPORT n_u32 strHash (n_u32 h, char *s)
/* [<][>][^][v][top][bottom][index][help] */
{
        int n;
        for (n = 0; s[n]; n++)
                h = (((h << 5) | (h >> (32 - 5))) ^ (s[n] & 0xff) ^ n) & 0xffffffff;
        return h;
}

EXPORT struct strList * lp_strListAdd (struct strList *l, char *s, char *desc)
/* [<][>][^][v][top][bottom][index][help] */
{
        if (l)
        {
                l->next = (struct strList *) lp_Smalloc (sizeof *l, desc);
                l->next->head = l->head;
                l = l->next;
        } else
        {
                l = (struct strList *) lp_Smalloc (sizeof *l, desc);
                l->head = l;
        }
        l->next = NULL;
        l->data = lp_Sstrdup (s, desc);
        return l;
}

EXPORT void strListFree (struct strList *l)
/* [<][>][^][v][top][bottom][index][help] */
{
        l = l->head;
        while (l)
        {
                struct strList *t = l;
                t = l;
                l = l->next;
                free (t->data);
                free (t);
        }
}

#define STRSTACK_BLOCK_SIZE 4096 /* page size divisible */

/*
 * l->used includes the terminating null
 */

EXPORT struct strStack *lp_strStackAdd (struct strStack *l, char *s, char *desc)
/* [<][>][^][v][top][bottom][index][help] */
{
        int len;
        len = strlen (s);
        if (!l)
        {
                l = Smalloc (sizeof *l);
                l->used = 1; /* the nil */
                l->len = (len/STRSTACK_BLOCK_SIZE + 1) * STRSTACK_BLOCK_SIZE;
                l->data = lp_Smalloc(l->len, desc);
        }
        if (l->used + len > l->len)
        {
                l->len += len;
                l->len = (l->len/STRSTACK_BLOCK_SIZE + 1) * STRSTACK_BLOCK_SIZE;
                l->data = lp_Srealloc (l->data, l->len, desc);
        }
        memcpy (l->data + l->used - 1, s, len+1);
        l->used += len;
        return l;
}

EXPORT struct strStack *lp_strnStackAdd (struct strStack *l, char *s, int len, char *desc)
/* [<][>][^][v][top][bottom][index][help] */
{
        if (!l)
        {
                l = Smalloc (sizeof *l);
                l->used = 1; /* the nil */
                l->len = (len/STRSTACK_BLOCK_SIZE + 1) * STRSTACK_BLOCK_SIZE;
                l->data = lp_Smalloc (l->len, desc);
        }
        if (l->used + len > l->len)
        {
                l->len += len;
                l->len = (l->len/STRSTACK_BLOCK_SIZE + 1) * STRSTACK_BLOCK_SIZE;
                l->data = lp_Srealloc (l->data, l->len, desc);
        }
        memcpy (l->data + l->used - 1, s, len);
        l->used += len;
        l->data[l->used-1] = '\0';
        return l;
}

EXPORT void strStackFree (struct strStack *l)
/* [<][>][^][v][top][bottom][index][help] */
{
        free (l->data);
        free (l);
}

/*
 * no negatives, -1 is error, must have at least one digit, skips leading white space
 */

EXPORT int strToi (char *s)
/* [<][>][^][v][top][bottom][index][help] */
{
        int i=0;
        for (;isspace(*s); s++) ;
        if (!isdigit(*s))
                return -1;
        do
        {
                i*=10;
                i+=*s-'0';
        } while (isdigit (*++s));
        return i;
}

EXPORT bool strKToi(char *s, int *i)
/* [<][>][^][v][top][bottom][index][help] */
{
        char c;
        char *p;
        int k;
        for (p = s; *p && isspace (*p); p++) {}
        for (; isdigit(*p) || *p == 'x' || *p == 'X'; p++) {}
        c = *p;
        *p = '\0';
        if (sscanf (s, "%i", &k)!=1)
        {
                *p=c;
                *i=0;
                return FALSE;
        }
        switch (tolower(c))
        {
        case 'g':
                k*=1024;
        case 'm':
                k*=1024;
        case 'k':
                k*=1024;
        default:
                break;
        }
        *p = c;
        *i = k;
        return TRUE;
}

/* [<][>][^][v][top][bottom][index][help] */