/*
 * $Header: /san01/cvs/ashpool/csrc/continuity/mecha/Attic/str.c,v 1.21 2004/04/30 13:41:56 aleigh Exp $ 
 */

/*
 * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved
 * 
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 * 
 * Disclosure, copying, distribution, or transmission of this code without
 * express permission is prohibited.
 */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>

#include "mecha.h"

#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif

void strFstrip_crlf(char *s, const size_t len)
{
    char *p;

    for (p = s + len; p != s; p--) {
        if (*p == '\r' || *p == '\n' || *p == '\0') {
            *p = '\0';
        } else {
            return;
        }
    }
}

void strFtoupper(char *s)
{
    char *p;

    for (p = s; *p != '\0'; p++) {
        *p = toupper(*p);
    }
}

void strFtolower(char *s)
{
    char *p;

    for (p = s; *p != '\0'; p++) {
        *p = tolower(*p);
    }
}

/*
 * Duplicate the string s, and write back the length of the string into len.
 * The duplicate string is returned.
 */
char *strFdup_size(const char *s, size_t * len)
{
    char *t;
    size_t l_len;

    assert(s != NULL);

    l_len = strlen(s);

    t = (char *) malloc(l_len + 1);

    /* we know the length so we can use memcpy instead of strcpy */
    memcpy(t, s, l_len);

    /* add the trailing null */
    t[l_len] = 0;

    *len = l_len;

    return t;
}

/*
 * duplicate the length of the string, and write the strlen back into the
 * pointer provided by len. If the input string is NULL,  nothing will be
 * written into len.
 */
char *strFcopy_size(const char *s, size_t * len)
{
    return (s == NULL ? NULL : strFdup_size(s, len));
}

/* TODO: strFdup() and strFcopy() are now functionally identical. */

/*
 * Duplicate the string and return the duplicate, or, return NULL if the
 * provided string was NULL
 */
char *strFcopy(const char *s)
{
    size_t unused;

    return (strFcopy_size(s, &unused));
}

char *strFncopy(const char *s, size_t len) {
    assert(s!=NULL);

    return (char *)memFdup(s,len);
}

/* from thttpd */
static int str_alloc_count = 0;
static long str_alloc_size = 0;

void strFrealloc(char **strP, int *maxsizeP, int size)
{
    if (*maxsizeP == 0) {
        *maxsizeP = MAX(200, size);     /* arbitrary */
        *strP = (char *) malloc(*maxsizeP + 1);
        ++str_alloc_count;
        str_alloc_size += *maxsizeP;
    } else if (size > *maxsizeP) {
        str_alloc_size -= *maxsizeP;
        *maxsizeP = MAX(*maxsizeP * 2, size * 5 / 4);
        *strP = (char *) realloc(*strP, *maxsizeP + 1);
        str_alloc_size += *maxsizeP;
    } else
        return;
    if (*strP == (char *) 0) {
        /* logFmsgid(1,"CON",15,"strFrealloc"); */
        abort();
    }
}

const char *strFcasestr(const char *haystack, const char *needle)
{
    const char *hptr, *hlast;
    const char *nptr;

    hptr = haystack;
    nptr = needle;

    while (*hptr) {
        if (tolower(*hptr++) == tolower(*nptr)) {
            hlast = hptr;

            while (*nptr && tolower(*hptr++) == tolower(*++nptr))
                continue;

            if (*nptr) {
                hptr = hlast;
                nptr = needle;
            } else
                return hlast - 1;
        }
    }
    return (NULL);
}

int strFis_whitespace(char c)
{
    if (c == '\n' || c == '\r' || c == ' ' || c == '\t')
        return 1;
    return 0;
}

int strFis_blank(char *s)
{
    char *p;

    for (p = s; *p != 0; p++) {
        if (strFis_whitespace(*p) == 0)
            return 0;
    }

    return 1;
}


#define CM_COPY 1
#define CM_WHITE 2
dynTstring *strFcollapse_whitespace(char *str)
{
    dynTstring *new = dynFinit();
    char *p;
    int mode = CM_COPY;

    assert(str != NULL);

    for (p = str; *p != '\0'; p++) {
        switch (mode) {
        case CM_COPY:
            if (*p == '\r')
                continue;

            if (strFis_whitespace(*p) == 1) {
                dynFappend(new, " ", 1);
                mode = CM_WHITE;
                continue;
            }
            dynFappend(new, p, 1);

            break;

        case CM_WHITE:
            if (strFis_whitespace(*p) == 1)
                continue;
            dynFappend(new, p, 1);
            mode = CM_COPY;
            break;
        }
    }
    return new;
}

#define P_SEARCH 3
#define P_NAME 1
#define P_VAL 2

lstTset *strFattrib_parser(const char *str)
{
    int mode = P_SEARCH;
    const char *p;
    char nbuf[128];
    int nbufc = 0;
    char vbuf[128];
    int vbufc = 0;
    lstTset *set = lstFset_init();

    assert(str != NULL);
    assert(set != NULL);

    for (p = str; *p != 0; p++) {
        switch (mode) {
        case P_SEARCH:
            if (strFis_whitespace(*p) == 1)
                break;
            mode = P_NAME;

        case P_NAME:
            if (*p == '=') {
                nbuf[nbufc] = 0;
                mode = P_VAL;
                p++;
                break;
            }
            nbuf[nbufc] = *p;
            nbufc++;
            break;

        case P_VAL:
            if (*p == '"') {
                mode = P_SEARCH;
                vbuf[vbufc] = 0;
                lstFset_add(set, nbuf, vbuf);
                /* printf("Got %s %s\n", nbuf, vbuf); */
                vbufc = 0;
                nbufc = 0;
                break;
            }
            vbuf[vbufc] = *p;
            vbufc++;
            break;
        }
    }
    return set;
}


unsigned int strFsplit(char *str, char **list, unsigned int list_size,
                       const char delim, const char quotechar)
{
    register char *p, *sp;
    register unsigned int listc = 0;
    register short inquote = 0;

    assert(str != NULL);
    assert(list != NULL);
    assert(list_size > 0);

    list_size--;

    if (quotechar == 0)
        inquote = 3;

    for (sp = p = str; *p != 0; p++) {
        if (inquote == 1) {
            if (*p == quotechar)
                inquote = 0;
            continue;
        }
        if (inquote == 0)
            if (*p == quotechar) {
                inquote = 1;
                continue;
            }
        if (*p == delim) {
            *p = '\0';
            list[listc] = sp;
            if (listc == list_size)
                return listc + 1;
            listc++;
            sp = (p + 1);
        }
    }

    list[listc] = sp;
    return listc + 1;
}

const char *strFskip_whitespace(const char *p)
{
    while (isspace(*p)) p++;
    return p;
}

const char *strFskip_token(const char *p) 
{
    while (isspace(*p)) p++;
    while (*p && !isspace(*p)) p++;
    return p;
}
