#include <ctype.h>
#include <string.h>
#include "defines.h"
#include "str.h"
#include "memory.h"
#include "buf.h"
static bool range_match(char, const char **, const char *);
static bool star_match(const char *, const char *, const char *, const char *);
char *
Str_concati(const char *s1, const char *e1, const char *s2, const char *e2,
int sep)
{
size_t len1, len2;
char *result;
len1 = e1 - s1;
len2 = e2 - s2;
if (sep)
len1++;
result = emalloc(len1 + len2 + 1);
memcpy(result, s1, len1);
if (sep)
result[len1-1] = sep;
memcpy(result + len1, s2, len2);
result[len1+len2] = '\0';
return result;
}
char **
brk_string(const char *str, int *store_argc, char **buffer)
{
int argc;
char ch;
char inquote;
const char *p;
char *start, *t;
size_t len;
int argmax = 50;
size_t curlen = 0;
char **argv = ereallocarray(NULL, argmax + 1, sizeof(char *));
for (; *str == ' ' || *str == '\t'; ++str)
continue;
if ((len = strlen(str) + 1) > curlen)
*buffer = emalloc(curlen = len);
argc = 0;
inquote = '\0';
for (p = str, start = t = *buffer;; ++p) {
switch (ch = *p) {
case '"':
case '\'':
if (inquote) {
if (inquote == ch)
inquote = '\0';
else
break;
} else {
inquote = ch;
if (start == NULL && p[1] == inquote) {
start = t + 1;
break;
}
}
continue;
case ' ':
case '\t':
case '\n':
if (inquote)
break;
if (!start)
continue;
case '\0':
if (!start)
goto done;
*t++ = '\0';
if (argc == argmax) {
argmax *= 2;
argv = ereallocarray(argv,
(argmax + 1), sizeof(char *));
}
argv[argc++] = start;
start = NULL;
if (ch == '\n' || ch == '\0')
goto done;
continue;
case '\\':
switch (ch = *++p) {
case '\0':
case '\n':
ch = '\\';
--p;
break;
case 'b':
ch = '\b';
break;
case 'f':
ch = '\f';
break;
case 'n':
ch = '\n';
break;
case 'r':
ch = '\r';
break;
case 't':
ch = '\t';
break;
}
break;
}
if (!start)
start = t;
*t++ = ch;
}
done:
argv[argc] = NULL;
*store_argc = argc;
return argv;
}
const char *
iterate_words(const char **end)
{
const char *start, *p;
char state = 0;
start = *end;
while (ISSPACE(*start))
start++;
if (*start == '\0')
return NULL;
for (p = start;; p++)
switch(*p) {
case '\\':
if (p[1] != '\0')
p++;
break;
case '\'':
case '"':
if (state == *p)
state = 0;
else if (state == 0)
state = *p;
break;
case ' ':
case '\t':
if (state != 0)
break;
case '\0':
*end = p;
return start;
default:
break;
}
}
static bool
star_match(const char *string, const char *estring,
const char *pattern, const char *epattern)
{
pattern++;
while (pattern != epattern &&
(*pattern == '?' || *pattern == '*')) {
if (*pattern == '?') {
if (string == estring)
return false;
else
string++;
}
pattern++;
}
if (pattern == epattern)
return true;
for (; string != estring; string++)
if (Str_Matchi(string, estring, pattern,
epattern))
return true;
return false;
}
static bool
range_match(char c, const char **ppat, const char *epattern)
{
if (*ppat == epattern) {
if (c == '[')
return true;
else
return false;
}
if (**ppat == '!' || **ppat == '^') {
(*ppat)++;
return !range_match(c, ppat, epattern);
}
for (;;) {
if (**ppat == '\\') {
if (++(*ppat) == epattern)
return false;
}
if (**ppat == c)
break;
if ((*ppat)[1] == '-') {
if (*ppat + 2 == epattern)
return false;
if (**ppat < c && c <= (*ppat)[2])
break;
if ((*ppat)[2] <= c && c < **ppat)
break;
*ppat += 3;
} else
(*ppat)++;
if (*ppat == epattern || **ppat == ']')
return false;
}
while (**ppat != ']') {
if (**ppat == '\\')
(*ppat)++;
if (*ppat == epattern)
break;
(*ppat)++;
}
return true;
}
bool
Str_Matchi(const char *string, const char *estring,
const char *pattern, const char *epattern)
{
while (pattern != epattern) {
if (*pattern == '*')
return star_match(string, estring, pattern, epattern);
else if (string == estring)
return false;
else if (*pattern == '[') {
pattern++;
if (!range_match(*string, &pattern, epattern))
return false;
}
else if (*pattern != '?') {
if (*pattern == '\\') {
if (++pattern == epattern)
return false;
}
if (*pattern != *string)
return false;
}
pattern++;
string++;
}
if (string == estring)
return true;
else
return false;
}
const char *
Str_SYSVMatch(const char *word, const char *pattern, size_t *len)
{
const char *p = pattern;
const char *w = word;
const char *m;
if (*p == '\0') {
*len = strlen(w);
return w;
}
if ((m = strchr(p, '%')) != NULL) {
for (; p != m && *w && *w == *p; w++, p++)
continue;
if (p != m)
return NULL;
if (*++p == '\0') {
*len = strlen(w);
return w;
}
}
m = w;
do {
if (strcmp(p, w) == 0) {
*len = w - m;
return m;
}
} while (*w++ != '\0');
return NULL;
}
void
Str_SYSVSubst(Buffer buf, const char *pat, const char *src, size_t len)
{
const char *m;
if ((m = strchr(pat, '%')) != NULL) {
Buf_Addi(buf, pat, m);
pat = m + 1;
}
Buf_AddChars(buf, len, src);
Buf_AddString(buf, pat);
}
char *
Str_dupi(const char *begin, const char *end)
{
char *s;
s = emalloc(end - begin + 1);
memcpy(s, begin, end - begin);
s[end-begin] = '\0';
return s;
}
char *
escape_dupi(const char *begin, const char *end, const char *set)
{
char *s, *t;
t = s = emalloc(end - begin + 1);
while (begin != end) {
if (*begin == '\\') {
begin++;
if (begin == end) {
*t++ = '\\';
break;
}
if (strchr(set, *begin) == NULL)
*t++ = '\\';
}
*t++ = *begin++;
}
*t++ = '\0';
return s;
}
char *
Str_rchri(const char *begin, const char *end, int c)
{
if (begin != end)
do {
if (*--end == c)
return (char *)end;
} while (end != begin);
return NULL;
}