/*
* stringutil.c -- string utilities
*/
#include "copyright.h"
#include "config.h"
#include "mudconf.h"
#include "config.h"
#include "externs.h"
#include "alloc.h"
#include "ansi.h"
#ifdef __linux__
char *___strtok;
#endif
/**
* Convert raw character sequences into MUX substitutions (type = 1)
* or strips them (type = 0).
*/
char *translate_string(const char *str, int type)
{
char old[LBUF_SIZE];
static char new[LBUF_SIZE];
char *j, *c, *bp;
int i;
bp = new;
StringCopy(old, str);
for(j = old; *j != '\0'; j++) {
switch (*j) {
case ESC_CHAR:
c = strchr(j, 'm');
if(c) {
if(!type) {
j = c;
break;
}
*c = '\0';
i = atoi(j + 2);
switch (i) {
case 0:
safe_str("%cn", new, &bp);
break;
case 1:
safe_str("%ch", new, &bp);
break;
case 5:
safe_str("%cf", new, &bp);
break;
case 7:
safe_str("%ci", new, &bp);
break;
case 30:
safe_str("%cx", new, &bp);
break;
case 31:
safe_str("%cr", new, &bp);
break;
case 32:
safe_str("%cg", new, &bp);
break;
case 33:
safe_str("%cy", new, &bp);
break;
case 34:
safe_str("%cb", new, &bp);
break;
case 35:
safe_str("%cm", new, &bp);
break;
case 36:
safe_str("%cc", new, &bp);
break;
case 37:
safe_str("%cw", new, &bp);
break;
case 40:
safe_str("%cX", new, &bp);
break;
case 41:
safe_str("%cR", new, &bp);
break;
case 42:
safe_str("%cG", new, &bp);
break;
case 43:
safe_str("%cY", new, &bp);
break;
case 44:
safe_str("%cB", new, &bp);
break;
case 45:
safe_str("%cM", new, &bp);
break;
case 46:
safe_str("%cC", new, &bp);
break;
case 47:
safe_str("%cW", new, &bp);
break;
}
j = c;
} else {
safe_chr(*j, new, &bp);
}
break;
case ' ':
if((*(j + 1) == ' ') && type)
safe_str("%b", new, &bp);
else
safe_chr(' ', new, &bp);
break;
case '\\':
if(type)
safe_str("\\", new, &bp);
else
safe_chr('\\', new, &bp);
break;
case '%':
if(type)
safe_str("%%", new, &bp);
else
safe_chr('%', new, &bp);
break;
case '[':
if(type)
safe_str("%[", new, &bp);
else
safe_chr('[', new, &bp);
break;
case ']':
if(type)
safe_str("%]", new, &bp);
else
safe_chr(']', new, &bp);
break;
case '{':
if(type)
safe_str("%{", new, &bp);
else
safe_chr('{', new, &bp);
break;
case '}':
if(type)
safe_str("%}", new, &bp);
else
safe_chr('}', new, &bp);
break;
case '(':
if(type)
safe_str("%(", new, &bp);
else
safe_chr('(', new, &bp);
break;
case ')':
if(type)
safe_str("%)", new, &bp);
else
safe_chr(')', new, &bp);
break;
case '\r':
break;
case '\n':
if(type)
safe_str("%r", new, &bp);
else
safe_chr(' ', new, &bp);
break;
default:
safe_chr(*j, new, &bp);
}
}
*bp = '\0';
return new;
}
/*
* capitalizes an entire string
*/
char *upcasestr(char *s)
{
char *p;
for(p = s; p && *p; p++)
*p = ToUpper(*p);
return s;
}
/*
* returns a pointer to the non-space character in s, or a NULL if s == NULL
* or *s == NULL or s has only spaces.
*/
char *skip_space(const char *s)
{
char *cp;
cp = (char *) s;
while (cp && *cp && isspace(*cp))
cp++;
return (cp);
}
/**
* returns a pointer to the next character in s matching c, or a pointer to
* the \0 at the end of s. Yes, this is a lot like index, but not exactly.
*/
char *seek_char(const char *s, char c)
{
char *cp;
cp = (char *) s;
while (cp && *cp && (*cp != c))
cp++;
return (cp);
}
/**
* Compress multiple spaces to one space, also remove leading and
* trailing spaces.
*/
char *munge_space(char *string)
{
char *buffer, *p, *q;
buffer = alloc_lbuf("munge_space");
p = string;
q = buffer;
while (p && *p && isspace(*p))
p++; /*
* remove inital spaces
*/
while (p && *p) {
while (*p && !isspace(*p))
*q++ = *p++;
while (*p && isspace(*++p));
if(*p)
*q++ = ' ';
}
*q = '\0'; /*
* remove terminal spaces and terminate * * *
*
* * string
*/
return (buffer);
}
/**
* Remove leading and trailing spaces.
*/
char *trim_spaces(char *string)
{
char *buffer, *p, *q;
buffer = alloc_lbuf("trim_spaces");
p = string;
q = buffer;
while (p && *p && isspace(*p)) /*
* remove inital spaces
*/
p++;
while (p && *p) {
while (*p && !isspace(*p)) /*
* copy nonspace chars
*/
*q++ = *p++;
while (*p && isspace(*p)) /*
* compress spaces
*/
p++;
if(*p)
*q++ = ' '; /*
* leave one space
*/
}
*q = '\0'; /*
* terminate string
*/
return (buffer);
}
/**
* Return portion of a string up to the indicated character. Also
* returns a modified pointer to the string ready for another call.
*/
char *grabto(char **str, char targ)
{
char *savec, *cp;
if(!str || !*str || !**str)
return NULL;
savec = cp = *str;
while (*cp && *cp != targ)
cp++;
if(*cp)
*cp++ = '\0';
*str = cp;
return savec;
}
int string_compare(const char *s1, const char *s2)
{
if(!mudconf.space_compress) {
while (*s1 && *s2 && ToLower(*s1) == ToLower(*s2))
s1++, s2++;
return (ToLower(*s1) - ToLower(*s2));
} else {
while (isspace(*s1))
s1++;
while (isspace(*s2))
s2++;
while (*s1 && *s2 && ((ToLower(*s1) == ToLower(*s2)) ||
(isspace(*s1) && isspace(*s2)))) {
if(isspace(*s1) && isspace(*s2)) { /*
* skip all
* other
* spaces
*/
while (isspace(*s1))
s1++;
while (isspace(*s2))
s2++;
} else {
s1++;
s2++;
}
}
if((*s1) && (*s2))
return (1);
if(isspace(*s1)) {
while (isspace(*s1))
s1++;
return (*s1);
}
if(isspace(*s2)) {
while (isspace(*s2))
s2++;
return (*s2);
}
if((*s1) || (*s2))
return (1);
return (0);
}
}
int string_prefix(const char *string, const char *prefix)
{
int count = 0;
while (*string && *prefix && ToLower(*string) == ToLower(*prefix))
string++, prefix++, count++;
if(*prefix == '\0') /*
* Matched all of prefix
*/
return (count);
else
return (0);
}
/**
* Accepts only nonempty matches starting at the beginning of a word
*/
const char *string_match(const char *src, const char *sub)
{
if((*sub != '\0') && (src)) {
while (*src) {
if(string_prefix(src, sub))
return src;
/*
* else scan to beginning of next word
*/
while (*src && isalnum(*src))
src++;
while (*src && !isalnum(*src))
src++;
}
}
return 0;
}
/**
* Returns an lbuf containing string STRING with all occurances
* of OLD replaced by NEW. OLD and NEW may be different lengths.
*/
char *replace_string(const char *old, const char *new, const char *string)
{
char *result, *r, *s;
int olen;
if(string == NULL)
return NULL;
s = (char *) string;
olen = strlen(old);
r = result = alloc_lbuf("replace_string");
while (*s) {
/*
* Copy up to the next occurrence of the first char of OLD
*/
while (*s && *s != *old) {
safe_chr(*s, result, &r);
s++;
}
/*
* If we are really at an OLD, append NEW to the result and *
*
* * * * * * bump the input string past the occurrence of
* OLD. * * * * Otherwise, copy the char and try again.
*/
if(*s) {
if(!strncmp(old, s, olen)) {
safe_str((char *) new, result, &r);
s += olen;
} else {
safe_chr(*s, result, &r);
s++;
}
}
}
*r = '\0';
return result;
}
/**
* Returns string STRING with all occurances * of OLD replaced by NEW. OLD
* and NEW may be different lengths. Modifies string, so: Note - STRING must
* already be allocated large enough to handle the new size. (mitch 1 feb 91)
*/
char *replace_string_inplace(const char *old, const char *new, char *string)
{
char *s;
s = replace_string(old, new, string);
StringCopy(string, s);
free_lbuf(s);
return string;
}
/**
* Counts occurances of C in STR. - mnp 7 feb 91
*/
int count_chars(const char *str, const char c)
{
int out = 0;
const char *p = str;
if(p)
while (*p != '\0')
if(*p++ == c)
out++;
return out;
}
/**
* returns the number of identical characters in the two strings
*/
int prefix_match(const char *s1, const char *s2)
{
int count = 0;
while (*s1 && *s2 && (ToLower(*s1) == ToLower(*s2)))
s1++, s2++, count++;
/*
* If the whole string matched, count the null. (Yes really.)
*/
if(!*s1 && !*s2)
count++;
return count;
}
int minmatch(char *str, char *target, int min)
{
while (*str && *target && (ToLower(*str) == ToLower(*target))) {
str++;
target++;
min--;
}
if(*str)
return 0;
if(!*target)
return 1;
return ((min <= 0) ? 1 : 0);
}
char *strsave(const char *s)
{
char *p;
p = (char *) XMALLOC(sizeof(char) * (strlen(s) + 1), "strsave");
if(p)
StringCopy(p, s);
return p;
}
/**
* Copy buffers, watching for overflows.
*/
int safe_copy_str(char *src, char *buff, char **bufp, int max)
{
char *tp;
tp = *bufp;
if(src == NULL)
return 0;
while (*src && ((tp - buff) < max))
*tp++ = *src++;
*bufp = tp;
return strlen(src);
}
/**
* Copy buffers, watching for overflows.
*/
int safe_copy_chr(char src, char *buff, char **bufp, int max)
{
char *tp;
int retval;
tp = *bufp;
retval = 0;
if((tp - buff) < max) {
*tp++ = src;
} else {
retval = 1;
}
*bufp = tp;
return retval;
}
int matches_exit_from_list(char *str, char *pattern)
{
char *s;
while (*pattern) {
for(s = str; /*
* check out this one
*/
(*s && (ToLower(*s) == ToLower(*pattern)) && *pattern &&
(*pattern != EXIT_DELIMITER)); s++, pattern++);
/*
* Did we match it all?
*/
if(*s == '\0') {
/*
* Make sure nothing afterwards
*/
while (*pattern && isspace(*pattern))
pattern++;
/*
* Did we get it?
*/
if(!*pattern || (*pattern == EXIT_DELIMITER))
return 1;
}
/*
* We didn't get it, find next string to test
*/
while (*pattern && *pattern++ != EXIT_DELIMITER);
while (isspace(*pattern))
pattern++;
}
return 0;
}