/* stringutil.c */
#include "copyright.h"
/* String utilities */
#include <ctype.h>
#include <stdio.h>
#ifndef VMS
#include <strings.h>
#else
#include <string.h>
#endif
#include <sys/types.h>
#include "mudconf.h"
#include "config.h"
#include "externs.h"
/*
* 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 = (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 strchr, but not exactly.
*/
char *seek_char(const char *s, char c)
{
char *cp = (char *)s;
while (cp && *cp && (*cp != c))
cp++;
return (cp);
}
/* ---------------------------------------------------------------------------
* munge_space: 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);
}
/* ---------------------------------------------------------------------------
* trim_spaces: 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);
}
/* ---------------------------------------------------------------------------
* grabto: 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)
{
#ifndef STANDALONE
if(!mudconf.space_compress) {
while (*s1 && *s2 && ToLower(*s1) == ToLower(*s2))
s1++, s2++;
return (ToLower(*s1) - ToLower(*s2));
} else {
#endif
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);
#ifndef STANDALONE
}
#endif
}
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;
}
/* ---------------------------------------------------------------------------
* replace_string: Returns an lbuf containing string STRING with all occurances
* of OLD replaced by NEW. OLD and NEW may be different lengths.
* (mitch 1 feb 91)
*/
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);
strcpy(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)
{
register out = 0;
register const char *p = str;
if (p)
while (*p != '\0')
if (*p++ == c)
out++;
return out;
}
/*
* Returns an allocated, null-terminated array of strings, broken on SEP. The
* array returned points into the original, >> modified << string. - mnp 7
* feb 91
*/
char **string2list(char *str, const char sep)
{
int count = 0;
char **out = NULL;
char *end, *beg = str;
if (str) {
if (!(out = (char **) XMALLOC(sizeof(char *)*strlen(str),"string2list"))) {
perror("NO MEM in string2list()");
return NULL;
}
for (;;) {
while (*beg == sep)
beg++;
if (*beg == '\0')
break;
out[count++] = beg;
for (end = beg; *end != '\0' && *end != sep; end++) ;
if (*end == '\0')
break;
*end++ = '\0';
beg = end;
}
out[count] = NULL;
}
if (out)
out = (char **) realloc((char *) out, sizeof(char *) * count + 1);
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)
strcpy(p,s);
return p;
}
/* ---------------------------------------------------------------------------
* safe_copy_str, safe_copy_chr - 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);
}
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;
}