/*
 * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
 * You may copy, distribute, and use this software as long as this
 * copyright statement is not removed.
 */

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "malloc.h"

#ifndef lint
static
char rcs_hdr[] = "$Id: string.c,v 1.2 2006-07-25 10:10:03 rt Exp $";
#endif

int malloc_checking = 0;

char *
strcat(str1,str2)
    register char   * str1;
    register char   * str2;
{
    char        * rtn;
    int   len;

    /*
     * check pointers agains malloc region.  The malloc* functions
     * will properly handle the case where a pointer does not
     * point into malloc space.
     */
    malloc_checking = 1;

    len = strlen(str2);
    malloc_check_str("strcat", str2);

    len += strlen(str1) + 1;
    malloc_checking = 0;

    malloc_check_data("strcat", str1, len);

    rtn = str1;

    while( *str1 )
    {
        str1++;
    }

    while( (*str1 = *str2) != '\0' )
    {
        str1++;
        str2++;
    }

    return(rtn);
}

char *
strdup(str1)
    register char   * str1;
{
    char        * malloc();
    char        * rtn;
    register char   * str2;

    malloc_check_str("strdup", str1);

    rtn = str2 = malloc((unsigned)strlen(str1)+1);

    if( rtn != (char *) 0)
    {
        while( (*str2 = *str1) != '\0' )
        {
            str1++;
            str2++;
        }
    }

    return(rtn);
}

char *
strncat(str1,str2,len)
    register char   * str1;
    register char   * str2;
    register int      len;
{
    int           len1;
    int           len2;
    char        * rtn;

    malloc_check_strn("strncat", str2, len);

    malloc_checking = 1;

    len2 = strlen(str2) + 1;
    len1 = strlen(str1);

    malloc_checking = 0;


    if( (len+1) < len2 )
    {
        len1 += len + 1;
    }
    else
    {
        len1 += len2;
    }
    malloc_check_data("strncat", str1, len1);

    rtn = str1;

    while( *str1 )
    {
        str1++;
    }

    while( len-- && ((*str1++ = *str2++) != '\0') )
    {
    }

    if( ! len )
    {
        *str1 = '\0';
    }

    return(rtn);
}

int
strcmp(str1,str2)
    register char   * str1;
    register char   * str2;
{
    malloc_check_str("strcmp", str1);
    malloc_check_str("strcmp", str2);

    while( *str1 && (*str1 == *str2) )
    {
        str1++;
        str2++;
    }


    /*
     * in order to deal with the case of a negative last char of either
     * string when the other string has a null
     */
    if( (*str2 == '\0') && (*str1 == '\0') )
    {
        return(0);
    }
    else if( *str2 == '\0' )
    {
        return(1);
    }
    else if( *str1 == '\0' )
    {
        return(-1);
    }

    return( *str1 - *str2 );
}

int
strncmp(str1,str2,len)
    register char   * str1;
    register char   * str2;
    register int      len;
{
    malloc_check_strn("strncmp", str1, len);
    malloc_check_strn("strncmp", str2, len);

    while( --len >= 0 && *str1 && (*str1 == *str2) )
    {
        str1++;
        str2++;
    }

    if( len < 0 )
    {
        return(0);
    }
    /*
     * in order to deal with the case of a negative last char of either
     * string when the other string has a null
     */
    if( (*str2 == '\0') && (*str1 == '\0') )
    {
        return(0);
    }
    else if( *str2 == '\0' )
    {
        return(1);
    }
    else if( *str1 == '\0' )
    {
        return(-1);
    }

    return( *str1 - *str2 );
}

char *
strcpy(str1,str2)
    register char   * str1;
    register char   * str2;
{
    char        * rtn;
    int       len;

    malloc_checking = 1;
    len = strlen(str2) + 1;
    malloc_checking = 0;

    malloc_check_data("strcpy", str1, len);
    malloc_check_data("strcpy", str2, len);

    rtn = str1;

    while( (*str1++ = *str2++) != '\0')
    {
    }

    return(rtn);
}

char *
strncpy(str1,str2,len)
    register char   * str1;
    register char   * str2;
    register int      len;
{
    extern int    malloc_checking;
    char        * rtn;

    malloc_check_data("strncpy", str1, len);
    malloc_check_strn("strncpy", str2, len);

    rtn = str1;

    while((len-- > 0) && (*str1++ = *str2++) != '\0')
    {
    }
    while( (len-- > 0) )
    {
        *str1++ = '\0';
    }

    return(rtn);
}

int
strlen(str1)
    register char   * str1;
{
    register char   * s;

    if(! malloc_checking )
    {
        malloc_check_str("strlen", str1);
    }

    for( s = str1; *s; s++)
    {
    }

    return( s - str1 );
}

char *
strchr(str1,c)
    register char   * str1;
    register int      c;
{
    malloc_check_str("strchr", str1);

    while( *str1 && (*str1 != (char) c) )
    {
        str1++;
    }

    if(*str1 != (char) c)
    {
        str1 = (char *) 0;
    }

    return(str1);
}

char *
strrchr(str1,c)
    register char   * str1;
    register int      c;
{
    register char   * rtn = (char *) 0;

    malloc_check_str("strrchr", str1);

    while( *str1 )
    {
        if(*str1 == (char) c )
        {
            rtn = str1;
        }
        str1++;
    }

    if( *str1 == (char) c)
    {
        rtn = str1;
    }

    return(rtn);
}

char *
index(str1,c)
    char        * str1;
    char          c;
{
    return( strchr(str1,c) );
}

char *
rindex(str1,c)
    char        * str1;
    char          c;
{
    return( strrchr(str1,c) );
}

char *
strpbrk(str1,str2)
    register char   * str1;
    register char   * str2;
{
    register char   * tmp;

    malloc_check_str("strpbrk", str1);
    malloc_check_str("strpbrk", str2);

    while(*str1)
    {
        for( tmp=str2; *tmp && *tmp != *str1; tmp++)
        {
        }
        if( *tmp )
        {
            break;
        }
        str1++;
    }

    if( ! *str1 )
    {
        str1 = (char *) 0;
    }

    return(str1);
}

int
strspn(str1,str2)
    register char   * str1;
    register char   * str2;
{
    register char   * tmp;
    char        * orig = str1;

    malloc_check_str("strspn", str1);
    malloc_check_str("strspn", str2);

    while(*str1)
    {
        for( tmp=str2; *tmp && *tmp != *str1; tmp++)
        {
        }
        if(! *tmp )
        {
            break;
        }
        str1++;
    }

    return( (int) (str1 - orig) );
}

int
strcspn(str1,str2)
    register char   * str1;
    register char   * str2;
{
    register char   * tmp;
    char        * orig = str1;

    malloc_check_str("strcspn", str1);
    malloc_check_str("strcspn", str2);

    while(*str1)
    {
        for( tmp=str2; *tmp && *tmp != *str1; tmp++)
        {
        }
        if( *tmp )
        {
            break;
        }
        str1++;
    }

    return( (int) (str1 - orig) );
}

/*
 * strtok() source taken from that posted to comp.lang.c by Chris Torek
 * in Jan 1990.
 */

/*
 * Copyright (c) 1989 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/*
 * Get next token from string s (NULL on 2nd, 3rd, etc. calls),
 * where tokens are nonempty strings separated by runs of
 * chars from delim.  Writes NULs into s to end tokens.  delim need not
 * remain constant from call to call.
 *
 * Modified by cpc:     changed variable names to conform with naming
 *          conventions used in rest of code.  Added malloc pointer
 *          check calls.
 */
char *
strtok(str1, str2)
    char    * str1;
    char    * str2;
{
    static char     * last;
    char        * strtoken();

    if( str1 )
    {
        malloc_check_str("strtok", str1);
        last = str1;
    }
    malloc_check_str("strtok", str2);

    return (strtoken(&last, str2, 1));
}


/*
 * Get next token from string *stringp, where tokens are (possibly empty)
 * strings separated by characters from delim.  Tokens are separated
 * by exactly one delimiter iff the skip parameter is false; otherwise
 * they are separated by runs of characters from delim, because we
 * skip over any initial `delim' characters.
 *
 * Writes NULs into the string at *stringp to end tokens.
 * delim will usually, but need not, remain constant from call to call.
 * On return, *stringp points past the last NUL written (if there might
 * be further tokens), or is NULL (if there are definitely no more tokens).
 *
 * If *stringp is NULL, strtoken returns NULL.
 */
char *
strtoken(stringp, delim, skip)
    register char **stringp;
    register char *delim;
    int skip;
{
    register char *s;
    register char *spanp;
    register int c, sc;
    char *tok;

    if ((s = *stringp) == NULL)
        return (NULL);

    if (skip) {
        /*
         * Skip (span) leading delimiters (s += strspn(s, delim)).
         */
    cont:
        c = *s;
        for (spanp = delim; (sc = *spanp++) != 0;) {
            if (c == sc) {
                s++;
                goto cont;
            }
        }
        if (c == 0) {       /* no token found */
            *stringp = NULL;
            return (NULL);
        }
    }

    /*
     * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
     * Note that delim must have one NUL; we stop if we see that, too.
     */
    for (tok = s;;) {
        c = *s++;
        spanp = delim;
        do {
            if ((sc = *spanp++) == c) {
                if (c == 0)
                    s = NULL;
                else
                    s[-1] = 0;
                *stringp = s;
                return (tok);
            }
        } while (sc != 0);
    }
    /* NOTREACHED */
}

