159 lines
4.7 KiB
C
159 lines
4.7 KiB
C
/* NetHack 3.7 strutil.c $NHDT-Date: 1709571807 2024/03/04 17:03:27 $ $NHDT-Branch: keni-mdlib-followup $:$NHDT-Revision: 1.0 $ */
|
|
/* Copyright (c) Robert Patrick Rankin, 1991 */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h" /* for config.h+extern.h */
|
|
|
|
/* strbuf_init() initializes strbuf state for use */
|
|
void
|
|
strbuf_init(strbuf_t *strbuf)
|
|
{
|
|
strbuf->str = NULL;
|
|
strbuf->len = 0;
|
|
}
|
|
|
|
/* strbuf_append() appends given str to strbuf->str */
|
|
void
|
|
strbuf_append(strbuf_t *strbuf, const char *str)
|
|
{
|
|
int len = (int) strlen(str) + 1;
|
|
|
|
strbuf_reserve(strbuf,
|
|
len + (strbuf->str ? (int) strlen(strbuf->str) : 0));
|
|
Strcat(strbuf->str, str);
|
|
}
|
|
|
|
/* strbuf_reserve() ensure strbuf->str has storage for len characters */
|
|
void
|
|
strbuf_reserve(strbuf_t *strbuf, int len)
|
|
{
|
|
if (strbuf->str == NULL) {
|
|
strbuf->str = strbuf->buf;
|
|
strbuf->str[0] = '\0';
|
|
strbuf->len = (int) sizeof strbuf->buf;
|
|
}
|
|
|
|
if (len > strbuf->len) {
|
|
char *oldbuf = strbuf->str;
|
|
|
|
strbuf->len = len + (int) sizeof strbuf->buf;
|
|
strbuf->str = (char *) alloc(strbuf->len);
|
|
Strcpy(strbuf->str, oldbuf);
|
|
if (oldbuf != strbuf->buf)
|
|
free((genericptr_t) oldbuf);
|
|
}
|
|
}
|
|
|
|
/* strbuf_empty() frees allocated memory and set strbuf to initial state */
|
|
void
|
|
strbuf_empty(strbuf_t *strbuf)
|
|
{
|
|
if (strbuf->str != NULL && strbuf->str != strbuf->buf)
|
|
free((genericptr_t) strbuf->str);
|
|
strbuf_init(strbuf);
|
|
}
|
|
|
|
/* strbuf_nl_to_crlf() converts all occurrences of \n to \r\n */
|
|
void
|
|
strbuf_nl_to_crlf(strbuf_t *strbuf)
|
|
{
|
|
if (strbuf->str) {
|
|
int len = (int) strlen(strbuf->str);
|
|
int count = 0;
|
|
char *cp = strbuf->str;
|
|
|
|
while (*cp)
|
|
if (*cp++ == '\n')
|
|
count++;
|
|
if (count) {
|
|
strbuf_reserve(strbuf, len + count + 1);
|
|
for (cp = strbuf->str + len + count; count; --cp)
|
|
if ((*cp = cp[-count]) == '\n') {
|
|
*--cp = '\r';
|
|
--count;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* strlen() but returns unsigned and panics if string is unreasonably long;
|
|
used by dlb as well as by nethack */
|
|
unsigned
|
|
Strlen_(
|
|
const char *str,
|
|
const char *file,
|
|
int line)
|
|
{
|
|
const char *p;
|
|
size_t len;
|
|
|
|
/* strnlen(str, LARGEST_INT) w/o requiring posix.1 headers or libraries */
|
|
for (p = str, len = 0; len < LARGEST_INT; ++len)
|
|
if (*p++ == '\0')
|
|
break;
|
|
|
|
if (len == LARGEST_INT)
|
|
panic("%s:%d string too long", file, line);
|
|
return (unsigned) len;
|
|
}
|
|
|
|
staticfn boolean pmatch_internal(const char *, const char *, boolean,
|
|
const char *);
|
|
/* guts of pmatch(), pmatchi(), and pmatchz();
|
|
match a string against a pattern */
|
|
staticfn boolean
|
|
pmatch_internal(const char *patrn, const char *strng,
|
|
boolean ci, /* True => case-insensitive,
|
|
False => case-sensitive */
|
|
const char *sk) /* set of characters to skip */
|
|
{
|
|
char s, p;
|
|
/*
|
|
* Simple pattern matcher: '*' matches 0 or more characters, '?' matches
|
|
* any single character. Returns TRUE if 'strng' matches 'patrn'.
|
|
*/
|
|
pmatch_top:
|
|
if (!sk) {
|
|
s = *strng++;
|
|
p = *patrn++; /* get next chars and pre-advance */
|
|
} else {
|
|
/* fuzzy match variant of pmatch; particular characters are ignored */
|
|
do {
|
|
s = *strng++;
|
|
} while (strchr(sk, s));
|
|
do {
|
|
p = *patrn++;
|
|
} while (strchr(sk, p));
|
|
}
|
|
if (!p) /* end of pattern */
|
|
return (boolean) (s == '\0'); /* matches iff end of string too */
|
|
else if (p == '*') /* wildcard reached */
|
|
return (boolean) ((!*patrn
|
|
|| pmatch_internal(patrn, strng - 1, ci, sk))
|
|
? TRUE
|
|
: s ? pmatch_internal(patrn - 1, strng, ci, sk)
|
|
: FALSE);
|
|
else if ((ci ? lowc(p) != lowc(s) : p != s) /* check single character */
|
|
&& (p != '?' || !s)) /* & single-char wildcard */
|
|
return FALSE; /* doesn't match */
|
|
else /* return pmatch_internal(patrn, strng, ci, sk); */
|
|
goto pmatch_top; /* optimize tail recursion */
|
|
}
|
|
|
|
/* case-sensitive wildcard match */
|
|
boolean
|
|
pmatch(const char *patrn, const char *strng)
|
|
{
|
|
return pmatch_internal(patrn, strng, FALSE, (const char *) 0);
|
|
}
|
|
|
|
/* case-insensitive wildcard match */
|
|
boolean
|
|
pmatchi(const char *patrn, const char *strng)
|
|
{
|
|
return pmatch_internal(patrn, strng, TRUE, (const char *) 0);
|
|
}
|
|
|
|
|
|
/*strutil.c*/
|