/* Copyright (c) 1993 Stephen F. White */

#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>

#include "config.h"
#include "cool.h"
#include "proto.h"
#include "sys_proto.h"

char  *
strndup(const char *s, int n)
{
    char	*r;

    if (!s || !*s || n <= 0) {
	r = MALLOC(char, 1);
	*r = '\0';
    } else {
	r = MALLOC(char, n + 1);
	strncpy(r, s, n);
	r[n] = '\0';
    }
    return  r;
}

char  *
str_dup(const char *s)
{
    char	*r;

    if (!s || !*s) {
	r = MALLOC(char, 1);
	*r = '\0';
    } else {
	r = MALLOC(char, strlen(s) + 1);
	strcpy(r, s);
    }
    return  r;
}

int
hasparent(Object *o, Objid pid)
{
    int		 i, r = 0;
    Object	*p;
    List	*parents = list_dup(o->parents);

    for (i = 0; i < parents->len; i++) {
	if (parents->el[i].v.obj.id == pid.id) {
	    r = 1; break;
	} else if ((p = retrieve(parents->el[i].v.obj))
	       && hasparent(p, pid)) {
	    r = 1; break;
	}
    }
    list_free(parents);
    return r;
}

Error
check_parents(Objid player, Object *o, List *newparents)
{
    int		 i, j;
    Objid	 parent;
    Object	*p;

#ifdef ROOT_OBJ
    if (newparents->len == 0) {
	if (o->id.id != ROOT_OBJ) {
	    return E_RANGE;
	}
    }
#endif /* ROOT_OBJ */
    for (i = 0; i < newparents->len; i++) {
	parent = newparents->el[i].v.obj;
	if (parent.server) {
	  /* parent is not local */
	    return E_INVIND;
	} else if (!(p = retrieve(parent))) {
	    return E_OBJNF;
	} else if (p->id.id == o->id.id) {
	      /* parent is this! */
	    return E_MAXREC;
	} else if (!can_clone(player, parent)) {
	    return E_PERM;
	}
	for (j = 0; j < newparents->len; j++) {
	    if (hasparent(p, newparents->el[j].v.obj)) {
		  /* parents form a loop */
		return E_MAXREC;
	    }
	}
    }
    return E_NONE;
}

/*
 * NB: These versions of strcasecmp() and strncasecmp() depend on ASCII.
 */

static char  cmap[257] = "\
\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\
\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\
\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\
\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\
\100\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\
\160\161\162\163\164\165\166\167\170\171\172\133\134\135\136\137\
\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\
\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\
\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\
\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\
\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\
\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\
\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\
\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\
\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\
\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377";

#ifndef STRCASE
int
cool_strcasecmp(register const char *s, register const char *t)
{
    register char	*c = cmap;

    while (c[*s] == c[*t++]) {
	if (!*s++)
	    return 0;
    }
    return(c[*s] - c[*--t]);
}

int
cool_strncasecmp(register const char *s, register const char *t,
		   register int n)
{
    register char	*c = cmap;
    
    if (!n) return 0;
    while (c[*s] == c[*t++]) {
	if (!*s++ || !--n)
	    return 0;
    }
    return(c[*s] - c[*--t]);
}
#endif

int
match (register const char *template, register const char *tomatch,
	    char marker)
{
    register const char	*t;
    register int	 l;

    while (*tomatch == marker) {	/* skip leading markers in string */
	tomatch++;
    }
    if ((t = index(tomatch, marker))) {
	l = t - tomatch;
    } else {
	l = strlen(tomatch);
    }
    while (template && *template) {
/*
 * skip leading markers in template
 */
	while (*template == marker) {	/* skip tokens in template */
	    template++;
	}
/*
 * if this word in template matches word, return 1
 */
	if (!cool_strncasecmp(template, tomatch, l)) {
	    return 1;
	}
/*
 * skip to next marker
 */
	template = index(template, marker);
    }
    return 0;
}

int
match_full (register const char *template, register const char *tomatch,
	    char marker)
{
    register const char	*t;
    register int	 l1, l2;

    while (*tomatch == marker) {	/* skip leading markers in string */
	tomatch++;
    }
    l1 = strlen(tomatch);
    while (template && *template) {
	while (*template == marker) {	/* skip leading markers in template */
	    template++;
	}
	if ((t = index(template, marker))) {
	    l2 = t - template;
	} else {
	    l2 = strlen(template);
	}
	if (l1 == l2 &&
	    !cool_strncasecmp(template, tomatch, l2)) {	/* got a match */
	    return 1;
	}
	template = t;	/* skip to next marker */
    }
    return 0;
}
int
str_in(const char *s1, const char *s2)
{
    const char	*t2;
    int		 len = strlen(s1);

    for(t2 = s2; *t2; t2++) {
	if (!cool_strncasecmp(s1, t2, len)) {
	    return t2 - s2 + 1;
	}
    }
    return 0;
}

int
verb_match(register const char *verb, register const char *word)
{
    register const char	*w;
    register short	star;
    register char	*c = cmap;

    while(*verb) {
	w = word;
	star = 0;
	while (1) {
	    if (*verb == '*') {
		verb++;
		star = 1;
	    }
	    if (!*verb || isspace(*verb) || !*w || c[*w] != c[*verb]) break;
	    w++; verb++;
	}
	if (star && !*w) return 1;
	if (!*w && (!*verb || isspace(*verb)))
	    return 1;
	while (*verb && !isspace(*verb))
	    verb++;
	while (isspace(*verb))
	    verb++;
    }
    return 0;
}

int
prep_match(const char *preplist, const char *argstr,
	   const char **dobj, const char **prep, const char **iobj,
	   int *dobjlen, int *preplen)
{
    register const char	*c = cmap;
    register const char	*p;
    register const char	*a = argstr;
    register const char	*dend, *pstart;
    int			 dobj_quoted = 0;

    while (isspace(*a)) {
	a++;
    }
    if (*a == '"') {
	*dobj = ++a;
	while (*a && *a != '"') {	/* skip quoted dobj */
	    a++;
	}
	dend = a;
	dobj_quoted = 1;
    } else {
	*dobj = a;
    }

    while(*a) {
	if (!dobj_quoted) {
	    dend = a;
	}
	while (isspace(*a))		/* skip whitespace before prep */
	    a++;
	pstart = a;
	p = preplist;
	while (*p) {
	    a = pstart;
	    while (isspace(*p))		/* skip whitespace */
		p++;
	    while (c[*p++] == c[*a++]) {
		if (*p == '_') {
		    while isspace(*a)
			a++;
		    p++;
		}
		if (isspace(*p) || (!*p && isspace(*a)) || !*a) {
		    *prep = pstart;
		    *preplen = a - pstart;
		    *dobjlen = dend - *dobj;
		    while (isspace(*a))
			a++;
		    *iobj = a;
		    return 1;		/* found a match, quit */
		}
	    }
	    while (*p && !isspace(*p))	/* skip to next preposition */
		p++;
	}
	while (*a && !isspace(*a))	/* no match, skip to next word */
	    a++;
    }
    return 0;
}

int
valid_ident(const char *s)
{
    if (!isalpha(s[0]) && *s != '_') {
	return 0;
    }
    for (++s; *s; s++) {
	if (!isalnum(*s) && *s != '_') {
	    return 0;
	}
    }
    return 1;
}

String *
strsub(const char *source, const char *what, const char *with, int case_matters)
{
    register const char	*s;
    String	*r;
    int		lwhat = strlen(what);

    r = string_new(0);
    s = source;

    while (*s) {
	if (case_matters ? !strncmp(s, what, lwhat)
			 : !cool_strncasecmp(s, what, lwhat)) {
	    r = string_cat(r, with);
	    s += lwhat;
	} else {
	    r = string_catc(r, *s);
	    s++;
	}
    }
    return r;
}

const char *
addr_htoa(unsigned long l)
{
    static char	buf[32];

    sprintf(buf, "%ld.%ld.%ld.%ld",
	(l >> 24) & 0xFF, (l >> 16) & 0xFF, (l >> 8) & 0xFF, l & 0xFF);
    return buf;
}

int
count_words(const char *s, char sep)
{
    int		nwords = 0;

    while (*s) {
	while (*s == sep)	/* skip leading separators */
	    s++;
	if (!*s)		/* if that's it, bug out */
	    return nwords;
	while (*s && *s != sep)	/* skip to next separator */
	    s++;
	nwords++;
    }
    return nwords;
}