hio/lib/utl-str.m4

1745 lines
39 KiB
Plaintext

dnl ---------------------------------------------------------------------------
changequote(`[[', `]]')dnl
dnl ---------------------------------------------------------------------------
define([[fn_comp_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_chau_type_]], $3)pushdef([[_to_lower_]], $4)dnl
int _fn_name_ (const _char_type_* str1, hio_oow_t len1, const _char_type_* str2, hio_oow_t len2, int ignorecase)
{
_chau_type_ c1, c2;
const _char_type_* end1 = str1 + len1;
const _char_type_* end2 = str2 + len2;
if (ignorecase)
{
while (str1 < end1)
{
c1 = _to_lower_()(*str1);
if (str2 < end2)
{
c2 = _to_lower_()(*str2);
if (c1 > c2) return 1;
if (c1 < c2) return -1;
}
else return 1;
str1++; str2++;
}
}
else
{
while (str1 < end1)
{
c1 = *str1;
if (str2 < end2)
{
c2 = *str2;
if (c1 > c2) return 1;
if (c1 < c2) return -1;
}
else return 1;
str1++; str2++;
}
}
return (str2 < end2)? -1: 0;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_chau_type_]])popdef([[_to_lower_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_comp_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_chau_type_]], $3)pushdef([[_to_lower_]], $4)dnl
int _fn_name_ (const _char_type_* str1, const _char_type_* str2, int ignorecase)
{
if (ignorecase)
{
while (_to_lower_()(*str1) == _to_lower_()(*str2))
{
if (*str1 == '\0') return 0;
str1++; str2++;
}
return ((_chau_type_)_to_lower_()(*str1) > (_chau_type_)_to_lower_()(*str2))? 1: -1;
}
else
{
while (*str1 == *str2)
{
if (*str1 == '\0') return 0;
str1++; str2++;
}
return ((_chau_type_)*str1 > (_chau_type_)*str2)? 1: -1;
}
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_chau_type_]])popdef([[_to_lower_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_comp_cstr_limited]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_chau_type_]], $3)pushdef([[_to_lower_]], $4)dnl
int _fn_name_ (const _char_type_* str1, const _char_type_* str2, hio_oow_t maxlen, int ignorecase)
{
if (maxlen == 0) return 0;
if (ignorecase)
{
while (_to_lower_()(*str1) == _to_lower_()(*str2))
{
if (*str1 == '\0' || maxlen == 1) return 0;
str1++; str2++; maxlen--;
}
return ((_chau_type_)_to_lower_()(*str1) > (_chau_type_)_to_lower_()(*str2))? 1: -1;
}
else
{
while (*str1 == *str2)
{
if (*str1 == '\0' || maxlen == 1) return 0;
str1++; str2++; maxlen--;
}
return ((_chau_type_)*str1 > (_chau_type_)*str2)? 1: -1;
}
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_chau_type_]])popdef([[_to_lower_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_comp_chars_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_chau_type_]], $3)pushdef([[_to_lower_]], $4)dnl
int _fn_name_ (const _char_type_* str1, hio_oow_t len, const _char_type_* str2, int ignorecase)
{
/* for "abc\0" of length 4 vs "abc", the fourth character
* of the first string is equal to the terminating null of
* the second string. the first string is still considered
* bigger */
if (ignorecase)
{
const _char_type_* end = str1 + len;
_char_type_ c1;
_char_type_ c2;
while (str1 < end && *str2 != '\0')
{
c1 = _to_lower_()(*str1);
c2 = _to_lower_()(*str2);
if (c1 != c2) return ((_chau_type_)c1 > (_chau_type_)c2)? 1: -1;
str1++; str2++;
}
return (str1 < end)? 1: (*str2 == '\0'? 0: -1);
}
else
{
const _char_type_* end = str1 + len;
while (str1 < end && *str2 != '\0')
{
if (*str1 != *str2) return ((_chau_type_)*str1 > (_chau_type_)*str2)? 1: -1;
str1++; str2++;
}
return (str1 < end)? 1: (*str2 == '\0'? 0: -1);
}
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_chau_type_]])popdef([[_to_lower_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_concat_chars_to_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_count_str_]], $3)dnl
hio_oow_t _fn_name_ (_char_type_* buf, hio_oow_t bsz, const _char_type_* str, hio_oow_t len)
{
_char_type_* p, * p2;
const _char_type_* end;
hio_oow_t blen;
blen = _count_str_()(buf);
if (blen >= bsz) return blen; /* something wrong */
p = buf + blen;
p2 = buf + bsz - 1;
end = str + len;
while (p < p2)
{
if (str >= end) break;
*p++ = *str++;
}
if (bsz > 0) *p = '\0';
return p - buf;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_count_str_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_concat_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_count_str_]], $3)dnl
hio_oow_t _fn_name_ (_char_type_* buf, hio_oow_t bsz, const _char_type_* str)
{
_char_type_* p, * p2;
hio_oow_t blen;
blen = _count_str_()(buf);
if (blen >= bsz) return blen; /* something wrong */
p = buf + blen;
p2 = buf + bsz - 1;
while (p < p2)
{
if (*str == '\0') break;
*p++ = *str++;
}
if (bsz > 0) *p = '\0';
return p - buf;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_count_str_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_copy_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
void _fn_name_ (_char_type_* dst, const _char_type_* src, hio_oow_t len)
{
/* take note of no forced null termination */
hio_oow_t i;
for (i = 0; i < len; i++) dst[i] = src[i];
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_copy_chars_to_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
hio_oow_t _fn_name_ (_char_type_* dst, hio_oow_t dlen, const _char_type_* src, hio_oow_t slen)
{
hio_oow_t i;
if (dlen <= 0) return 0;
if (dlen <= slen) slen = dlen - 1;
for (i = 0; i < slen; i++) dst[i] = src[i];
dst[i] = '\0';
return i;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_copy_chars_to_cstr_unlimited]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
hio_oow_t _fn_name_ (_char_type_* dst, const _char_type_* src, hio_oow_t len)
{
hio_oow_t i;
for (i = 0; i < len; i++) dst[i] = src[i];
dst[i] = '\0';
return i;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_copy_cstr_to_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
hio_oow_t _fn_name_ (_char_type_* dst, hio_oow_t len, const _char_type_* src)
{
/* no null termination */
_char_type_* p, * p2;
p = dst; p2 = dst + len - 1;
while (p < p2)
{
if (*src == '\0') break;
*p++ = *src++;
}
return p - dst;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_copy_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
hio_oow_t _fn_name_ (_char_type_* dst, hio_oow_t len, const _char_type_* src)
{
_char_type_* p, * p2;
p = dst; p2 = dst + len - 1;
while (p < p2)
{
if (*src == '\0') break;
*p++ = *src++;
}
if (len > 0) *p = '\0';
return p - dst;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_copy_cstr_unlimited]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
hio_oow_t _fn_name_ (_char_type_* dst, const _char_type_* src)
{
_char_type_* org = dst;
while ((*dst++ = *src++) != '\0');
return dst - org - 1;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_copy_fmt_cstrs_to_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
hio_oow_t _fn_name_ (_char_type_* buf, hio_oow_t bsz, const _char_type_* fmt, const _char_type_* str[])
{
_char_type_* b = buf;
_char_type_* end = buf + bsz - 1;
const _char_type_* f = fmt;
if (bsz <= 0) return 0;
while (*f != '\0')
{
if (*f == '\\')
{
/* get the escaped character and treat it normally.
* if the escaper is the last character, treat it
* normally also. */
if (f[1] != '\0') f++;
}
else if (*f == '$')
{
if (f[1] == '{' && (f[2] >= '0' && f[2] <= '9'))
{
const _char_type_* tmp;
hio_oow_t idx = 0;
tmp = f;
f += 2;
do idx = idx * 10 + (*f++ - '0');
while (*f >= '0' && *f <= '9');
if (*f != '}')
{
f = tmp;
goto normal;
}
f++;
tmp = str[idx];
while (*tmp != '\0')
{
if (b >= end) goto fini;
*b++ = *tmp++;
}
continue;
}
else if (f[1] == '$') f++;
}
normal:
if (b >= end) break;
*b++ = *f++;
}
fini:
*b = '\0';
return b - buf;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_copy_fmt_cses_to_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_cs_type_]], $3)dnl
hio_oow_t _fn_name_ (_char_type_* buf, hio_oow_t bsz, const _char_type_* fmt, const _cs_type_ str[])
{
_char_type_* b = buf;
_char_type_* end = buf + bsz - 1;
const _char_type_* f = fmt;
if (bsz <= 0) return 0;
while (*f != '\0')
{
if (*f == '\\')
{
/* get the escaped character and treat it normally.
* if the escaper is the last character, treat it
* normally also. */
if (f[1] != '\0') f++;
}
else if (*f == '$')
{
if (f[1] == '{' && (f[2] >= '0' && f[2] <= '9'))
{
const _char_type_* tmp, * tmpend;
hio_oow_t idx = 0;
tmp = f;
f += 2;
do idx = idx * 10 + (*f++ - '0');
while (*f >= '0' && *f <= '9');
if (*f != '}')
{
f = tmp;
goto normal;
}
f++;
tmp = str[idx].ptr;
tmpend = tmp + str[idx].len;
while (tmp < tmpend)
{
if (b >= end) goto fini;
*b++ = *tmp++;
}
continue;
}
else if (f[1] == '$') f++;
}
normal:
if (b >= end) break;
*b++ = *f++;
}
fini:
*b = '\0';
return b - buf;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_cs_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_count_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
hio_oow_t _fn_name_ (const _char_type_* str)
{
const _char_type_* ptr = str;
while (*ptr != '\0') ptr++;
return ptr - str;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_count_cstr_limited]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
hio_oow_t _fn_name_ (const _char_type_* str, hio_oow_t maxlen)
{
hio_oow_t i;
for (i = 0; i < maxlen; i++)
{
if (str[i] == '\0') break;
}
return i;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_equal_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
int _fn_name_ (const _char_type_* str1, const _char_type_* str2, hio_oow_t len)
{
hio_oow_t i;
/* NOTE: you should call this function after having ensured that
* str1 and str2 are in the same length */
for (i = 0; i < len; i++)
{
if (str1[i] != str2[i]) return 0;
}
return 1;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_fill_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
void _fn_name_ (_char_type_* dst, _char_type_ ch, hio_oow_t len)
{
hio_oow_t i;
for (i = 0; i < len; i++) dst[i] = ch;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_find_char_in_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
_char_type_* _fn_name_ (const _char_type_* ptr, hio_oow_t len, _char_type_ c)
{
const _char_type_* end;
end = ptr + len;
while (ptr < end)
{
if (*ptr == c) return (_char_type_*)ptr;
ptr++;
}
return HIO_NULL;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_rfind_char_in_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
_char_type_* _fn_name_ (const _char_type_* ptr, hio_oow_t len, _char_type_ c)
{
const _char_type_* cur;
cur = ptr + len;
while (cur > ptr)
{
--cur;
if (*cur == c) return (_char_type_*)cur;
}
return HIO_NULL;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_find_char_in_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
_char_type_* _fn_name_ (const _char_type_* ptr, _char_type_ c)
{
while (*ptr != '\0')
{
if (*ptr == c) return (_char_type_*)ptr;
ptr++;
}
return HIO_NULL;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_rfind_char_in_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
_char_type_* _fn_name_ (const _char_type_* str, _char_type_ c)
{
const _char_type_* ptr = str;
while (*ptr != '\0') ptr++;
while (ptr > str)
{
--ptr;
if (*ptr == c) return (_char_type_*)ptr;
}
return HIO_NULL;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_find_chars_in_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_to_lower_]], $3)dnl
_char_type_* _fn_name_ (const _char_type_* str, hio_oow_t strsz, const _char_type_* sub, hio_oow_t subsz, int ignorecase)
{
const _char_type_* end, * subp;
if (subsz == 0) return (_char_type_*)str;
if (strsz < subsz) return HIO_NULL;
end = str + strsz - subsz;
subp = sub + subsz;
if (HIO_UNLIKELY(ignorecase))
{
while (str <= end)
{
const _char_type_* x = str;
const _char_type_* y = sub;
while (1)
{
if (y >= subp) return (_char_type_*)str;
if (_to_lower_()(*x) != _to_lower_()(*y)) break;
x++; y++;
}
str++;
}
}
else
{
while (str <= end)
{
const _char_type_* x = str;
const _char_type_* y = sub;
while (1)
{
if (y >= subp) return (_char_type_*)str;
if (*x != *y) break;
x++; y++;
}
str++;
}
}
return HIO_NULL;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_to_lower_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_rfind_chars_in_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_to_lower_]], $3)dnl
_char_type_* _fn_name_ (const _char_type_* str, hio_oow_t strsz, const _char_type_* sub, hio_oow_t subsz, int ignorecase)
{
const _char_type_* p = str + strsz;
const _char_type_* subp = sub + subsz;
if (subsz == 0) return (_char_type_*)p;
if (strsz < subsz) return HIO_NULL;
p = p - subsz;
if (HIO_UNLIKELY(ignorecase))
{
while (p >= str)
{
const _char_type_* x = p;
const _char_type_* y = sub;
while (1)
{
if (y >= subp) return (_char_type_*)p;
if (_to_lower_()(*x) != _to_lower_()(*y)) break;
x++; y++;
}
p--;
}
}
else
{
while (p >= str)
{
const _char_type_* x = p;
const _char_type_* y = sub;
while (1)
{
if (y >= subp) return (_char_type_*)p;
if (*x != *y) break;
x++; y++;
}
p--;
}
}
return HIO_NULL;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_to_lower_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_compact_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_is_space_]], $3)dnl
hio_oow_t _fn_name_ (_char_type_* str, hio_oow_t len)
{
_char_type_* p = str, * q = str, * end = str + len;
int followed_by_space = 0;
int state = 0;
while (p < end)
{
if (state == 0)
{
if (!_is_space_()(*p))
{
*q++ = *p;
state = 1;
}
}
else if (state == 1)
{
if (_is_space_()(*p))
{
if (!followed_by_space)
{
followed_by_space = 1;
*q++ = *p;
}
}
else
{
followed_by_space = 0;
*q++ = *p;
}
}
p++;
}
return (followed_by_space) ? (q - str -1): (q - str);
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_is_space_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_rotate_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)dnl
hio_oow_t _fn_name_ (_char_type_* str, hio_oow_t len, int dir, hio_oow_t n)
{
hio_oow_t first, last, count, index, nk;
_char_type_ c;
if (dir == 0 || len == 0) return len;
if ((n %= len) == 0) return len;
if (dir > 0) n = len - n;
first = 0; nk = len - n; count = 0;
while (count < n)
{
last = first + nk;
index = first;
c = str[first];
do
{
count++;
while (index < nk)
{
str[index] = str[index + n];
index += n;
}
if (index == last) break;
str[index] = str[index - nk];
index -= nk;
}
while (1);
str[last] = c; first++;
}
return len;
}
popdef([[_fn_name_]])popdef([[_char_type_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_trim_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_is_space_]], $3)pushdef([[_prefix_]], $4)dnl
_char_type_* _fn_name_ (const _char_type_* str, hio_oow_t* len, int flags)
{
const _char_type_* p = str, * end = str + *len;
if (p < end)
{
const _char_type_* s = HIO_NULL, * e = HIO_NULL;
do
{
if (!_is_space_()(*p))
{
if (s == HIO_NULL) s = p;
e = p;
}
p++;
}
while (p < end);
if (e)
{
if (flags & _prefix_()_RIGHT)
{
*len -= end - e - 1;
}
if (flags & _prefix_()_LEFT)
{
*len -= s - str;
str = s;
}
}
else
{
/* the entire string need to be deleted */
if ((flags & _prefix_()_RIGHT) ||
(flags & _prefix_()_LEFT)) *len = 0;
}
}
return (_char_type_*)str;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_is_space_]])popdef([[_prefix_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_split_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_is_space_]], $3)pushdef([[_copy_str_unlimited_]], $4)dnl
int _fn_name_ (_char_type_* s, const _char_type_* delim, _char_type_ lquote, _char_type_ rquote, _char_type_ escape)
{
_char_type_* p = s, *d;
_char_type_* sp = HIO_NULL, * ep = HIO_NULL;
int delim_mode;
int cnt = 0;
if (delim == HIO_NULL) delim_mode = 0;
else
{
delim_mode = 1;
for (d = (_char_type_*)delim; *d != '\0'; d++)
if (!_is_space_()(*d)) delim_mode = 2;
}
if (delim_mode == 0)
{
/* skip preceding space characters */
while (_is_space_()(*p)) p++;
/* when 0 is given as "delim", it has an effect of cutting
preceding and trailing space characters off "s". */
if (lquote != '\0' && *p == lquote)
{
_copy_str_unlimited_ (p, p + 1);
for (;;)
{
if (*p == '\0') return -1;
if (escape != '\0' && *p == escape)
{
_copy_str_unlimited_ (p, p + 1);
}
else
{
if (*p == rquote)
{
p++;
break;
}
}
if (sp == 0) sp = p;
ep = p;
p++;
}
while (_is_space_()(*p)) p++;
if (*p != '\0') return -1;
if (sp == 0 && ep == 0) s[0] = '\0';
else
{
ep[1] = '\0';
if (s != (_char_type_*)sp) _copy_str_unlimited_ (s, sp);
cnt++;
}
}
else
{
while (*p)
{
if (!_is_space_()(*p))
{
if (sp == 0) sp = p;
ep = p;
}
p++;
}
if (sp == 0 && ep == 0) s[0] = '\0';
else
{
ep[1] = '\0';
if (s != (_char_type_*)sp) _copy_str_unlimited_ (s, sp);
cnt++;
}
}
}
else if (delim_mode == 1)
{
_char_type_* o;
while (*p)
{
o = p;
while (_is_space_()(*p)) p++;
if (o != p) { _copy_str_unlimited_ (o, p); p = o; }
if (lquote != '\0' && *p == lquote)
{
_copy_str_unlimited_ (p, p + 1);
for (;;)
{
if (*p == '\0') return -1;
if (escape != '\0' && *p == escape)
{
_copy_str_unlimited_ (p, p + 1);
}
else
{
if (*p == rquote)
{
*p++ = '\0';
cnt++;
break;
}
}
p++;
}
}
else
{
o = p;
for (;;)
{
if (*p == '\0')
{
if (o != p) cnt++;
break;
}
if (_is_space_()(*p))
{
*p++ = '\0';
cnt++;
break;
}
p++;
}
}
}
}
else /* if (delim_mode == 2) */
{
_char_type_* o;
int ok;
while (*p != '\0')
{
o = p;
while (_is_space_()(*p)) p++;
if (o != p) { _copy_str_unlimited_ (o, p); p = o; }
if (lquote != '\0' && *p == lquote)
{
_copy_str_unlimited_ (p, p + 1);
for (;;)
{
if (*p == '\0') return -1;
if (escape != '\0' && *p == escape)
{
_copy_str_unlimited_ (p, p + 1);
}
else
{
if (*p == rquote)
{
*p++ = '\0';
cnt++;
break;
}
}
p++;
}
ok = 0;
while (_is_space_()(*p)) p++;
if (*p == '\0') ok = 1;
for (d = (_char_type_*)delim; *d != '\0'; d++)
{
if (*p == *d)
{
ok = 1;
_copy_str_unlimited_ (p, p + 1);
break;
}
}
if (ok == 0) return -1;
}
else
{
o = p; sp = ep = 0;
for (;;)
{
if (*p == '\0')
{
if (ep)
{
ep[1] = '\0';
p = &ep[1];
}
cnt++;
break;
}
for (d = (_char_type_*)delim; *d != '\0'; d++)
{
if (*p == *d)
{
if (sp == HIO_NULL)
{
_copy_str_unlimited_ (o, p); p = o;
*p++ = '\0';
}
else
{
_copy_str_unlimited_ (&ep[1], p);
_copy_str_unlimited_ (o, sp);
o[ep - sp + 1] = '\0';
p = &o[ep - sp + 2];
}
cnt++;
/* last empty field after delim */
if (*p == '\0') cnt++;
goto exit_point;
}
}
if (!_is_space_()(*p))
{
if (sp == HIO_NULL) sp = p;
ep = p;
}
p++;
}
exit_point:
;
}
}
}
return cnt;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_is_space_]])popdef([[_copy_str_unlimited_]])dnl
]])dnl
define([[fn_tokenize_chars]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_cs_type_]], $3)pushdef([[_is_space_]], $4)pushdef([[_to_lower_]], $5)dnl
_char_type_* _fn_name_ (const _char_type_* s, hio_oow_t len, const _char_type_* delim, hio_oow_t delim_len, _cs_type_* tok, int ignorecase)
{
const _char_type_* p = s, *d;
const _char_type_* end = s + len;
const _char_type_* sp = HIO_NULL, * ep = HIO_NULL;
const _char_type_* delim_end = delim + delim_len;
_char_type_ c;
int delim_mode;
#define __DELIM_NULL 0
#define __DELIM_EMPTY 1
#define __DELIM_SPACES 2
#define __DELIM_NOSPACES 3
#define __DELIM_COMPOSITE 4
if (delim == HIO_NULL) delim_mode = __DELIM_NULL;
else
{
delim_mode = __DELIM_EMPTY;
for (d = delim; d < delim_end; d++)
{
if (_is_space_()(*d))
{
if (delim_mode == __DELIM_EMPTY)
delim_mode = __DELIM_SPACES;
else if (delim_mode == __DELIM_NOSPACES)
{
delim_mode = __DELIM_COMPOSITE;
break;
}
}
else
{
if (delim_mode == __DELIM_EMPTY)
delim_mode = __DELIM_NOSPACES;
else if (delim_mode == __DELIM_SPACES)
{
delim_mode = __DELIM_COMPOSITE;
break;
}
}
}
/* TODO: verify the following statement... */
if (delim_mode == __DELIM_SPACES && delim_len == 1 && delim[0] != ' ') delim_mode = __DELIM_NOSPACES;
}
if (delim_mode == __DELIM_NULL)
{
/* when HIO_NULL is given as "delim", it trims off the
* leading and trailing spaces characters off the source
* string "s" eventually. */
while (p < end && _is_space_()(*p)) p++;
while (p < end)
{
c = *p;
if (!_is_space_()(c))
{
if (sp == HIO_NULL) sp = p;
ep = p;
}
p++;
}
}
else if (delim_mode == __DELIM_EMPTY)
{
/* each character in the source string "s" becomes a token. */
if (p < end)
{
c = *p;
sp = p;
ep = p++;
}
}
else if (delim_mode == __DELIM_SPACES)
{
/* each token is delimited by space characters. all leading
* and trailing spaces are removed. */
while (p < end && _is_space_()(*p)) p++;
while (p < end)
{
c = *p;
if (_is_space_()(c)) break;
if (sp == HIO_NULL) sp = p;
ep = p++;
}
while (p < end && _is_space_()(*p)) p++;
}
else if (delim_mode == __DELIM_NOSPACES)
{
/* each token is delimited by one of charaters
* in the delimeter set "delim". */
if (ignorecase)
{
while (p < end)
{
c = _to_lower_()(*p);
for (d = delim; d < delim_end; d++)
{
if (c == _to_lower_()(*d)) goto exit_loop;
}
if (sp == HIO_NULL) sp = p;
ep = p++;
}
}
else
{
while (p < end)
{
c = *p;
for (d = delim; d < delim_end; d++)
{
if (c == *d) goto exit_loop;
}
if (sp == HIO_NULL) sp = p;
ep = p++;
}
}
}
else /* if (delim_mode == __DELIM_COMPOSITE) */
{
/* each token is delimited by one of non-space charaters
* in the delimeter set "delim". however, all space characters
* surrounding the token are removed */
while (p < end && _is_space_()(*p)) p++;
if (ignorecase)
{
while (p < end)
{
c = _to_lower_()(*p);
if (_is_space_()(c))
{
p++;
continue;
}
for (d = delim; d < delim_end; d++)
{
if (c == _to_lower_()(*d)) goto exit_loop;
}
if (sp == HIO_NULL) sp = p;
ep = p++;
}
}
else
{
while (p < end)
{
c = *p;
if (_is_space_()(c))
{
p++;
continue;
}
for (d = delim; d < delim_end; d++)
{
if (c == *d) goto exit_loop;
}
if (sp == HIO_NULL) sp = p;
ep = p++;
}
}
}
exit_loop:
if (sp == HIO_NULL)
{
tok->ptr = HIO_NULL;
tok->len = (hio_oow_t)0;
}
else
{
tok->ptr = (_char_type_*)sp;
tok->len = ep - sp + 1;
}
/* if HIO_NULL is returned, this function should not be called again */
if (p >= end) return HIO_NULL;
if (delim_mode == __DELIM_EMPTY || delim_mode == __DELIM_SPACES) return (_char_type_*)p;
return (_char_type_*)++p;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_cs_type_]])popdef([[_is_space_]])popdef([[_to_lower_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_byte_to_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_prefix_]], $3)dnl
hio_oow_t _fn_name_ (hio_uint8_t byte, _char_type_* buf, hio_oow_t size, int flagged_radix, _char_type_ fill)
{
_char_type_ tmp[(HIO_SIZEOF(hio_uint8_t) * HIO_BITS_PER_BYTE)];
_char_type_* p = tmp, * bp = buf, * be = buf + size - 1;
int radix;
_char_type_ radix_char;
radix = (flagged_radix & _prefix_()_RADIXMASK);
radix_char = (flagged_radix & _prefix_()_LOWERCASE)? 'a': 'A';
if (radix < 2 || radix > 36 || size <= 0) return 0;
do
{
hio_uint8_t digit = byte % radix;
if (digit < 10) *p++ = digit + '0';
else *p++ = digit + radix_char - 10;
byte /= radix;
}
while (byte > 0);
if (fill != '\0')
{
while (size - 1 > p - tmp)
{
*bp++ = fill;
size--;
}
}
while (p > tmp && bp < be) *bp++ = *--p;
*bp = '\0';
return bp - buf;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_cs_type_]])popdef([[_prefix_]])dnl
dnl ---------------------------------------------------------------------------
]])dnl
define([[fn_int_to_cstr]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_int_type_]], $3)pushdef([[_count_cstr_]], $4)dnl
hio_oow_t _fn_name_ (_int_type_ value, int radix, const _char_type_* prefix, _char_type_* buf, hio_oow_t size)
{
_int_type_ t, rem;
hio_oow_t len, ret, i;
hio_oow_t prefix_len;
prefix_len = (prefix != HIO_NULL)? _count_cstr_()(prefix): 0;
t = value;
if (t == 0)
{
/* zero */
if (buf == HIO_NULL)
{
/* if buf is not given,
* return the number of bytes required */
return prefix_len + 1;
}
if (size < prefix_len+1)
{
/* buffer too small */
return (hio_oow_t)-1;
}
for (i = 0; i < prefix_len; i++) buf[i] = prefix[i];
buf[prefix_len] = '0';
if (size > prefix_len+1) buf[prefix_len+1] = '\0';
return prefix_len+1;
}
/* non-zero values */
len = prefix_len;
if (t < 0) { t = -t; len++; }
while (t > 0) { len++; t /= radix; }
if (buf == HIO_NULL)
{
/* if buf is not given, return the number of bytes required */
return len;
}
if (size < len) return (hio_oow_t)-1; /* buffer too small */
if (size > len) buf[len] = '\0';
ret = len;
t = value;
if (t < 0) t = -t;
while (t > 0)
{
rem = t % radix;
if (rem >= 10)
buf[--len] = (_char_type_)rem + 'a' - 10;
else
buf[--len] = (_char_type_)rem + '0';
t /= radix;
}
if (value < 0)
{
for (i = 1; i <= prefix_len; i++)
{
buf[i] = prefix[i-1];
len--;
}
buf[--len] = '-';
}
else
{
for (i = 0; i < prefix_len; i++) buf[i] = prefix[i];
}
return ret;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_int_type_]])popdef([[_count_cstr_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_chars_to_int]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_int_type_]], $3)pushdef([[_is_space_]], $4)pushdef([[_prefix_]], $5)dnl
_int_type_ _fn_name_ (const _char_type_* str, hio_oow_t len, int option, const _char_type_** endptr, int* is_sober)
{
_int_type_ n = 0;
const _char_type_* p, * pp;
const _char_type_* end;
hio_oow_t rem;
int digit, negative = 0;
int base = _prefix_()_GET_OPTION_BASE(option);
p = str;
end = str + len;
if (_prefix_()_GET_OPTION_LTRIM(option))
{
/* strip off leading spaces */
while (p < end && _is_space_()(*p)) p++;
}
/* check for a sign */
while (p < end)
{
if (*p == '-')
{
negative = ~negative;
p++;
}
else if (*p == '+') p++;
else break;
}
/* check for a binary/octal/hexadecimal notation */
rem = end - p;
if (base == 0)
{
if (rem >= 1 && *p == '0')
{
p++;
if (rem == 1) base = 8;
else if (*p == 'x' || *p == 'X')
{
p++; base = 16;
}
else if (*p == 'b' || *p == 'B')
{
p++; base = 2;
}
else base = 8;
}
else base = 10;
}
else if (rem >= 2 && base == 16)
{
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) p += 2;
}
else if (rem >= 2 && base == 2)
{
if (*p == '0' && (*(p + 1) == 'b' || *(p + 1) == 'B')) p += 2;
}
/* process the digits */
pp = p;
while (p < end)
{
digit = HIO_ZDIGIT_TO_NUM(*p, base);
if (digit >= base) break;
n = n * base + digit;
p++;
}
if (_prefix_()_GET_OPTION_E(option))
{
if (*p == 'E' || *p == 'e')
{
_int_type_ e = 0, i;
int e_neg = 0;
p++;
if (*p == '+')
{
p++;
}
else if (*p == '-')
{
p++; e_neg = 1;
}
while (p < end)
{
digit = HIO_ZDIGIT_TO_NUM(*p, base);
if (digit >= base) break;
e = e * base + digit;
p++;
}
if (e_neg)
for (i = 0; i < e; i++) n /= 10;
else
for (i = 0; i < e; i++) n *= 10;
}
}
/* base 8: at least a zero digit has been seen.
* other case: p > pp to be able to have at least 1 meaningful digit. */
if (is_sober) *is_sober = (base == 8 || p > pp);
if (_prefix_()_GET_OPTION_RTRIM(option))
{
/* consume trailing spaces */
while (p < end && _is_space_()(*p)) p++;
}
if (endptr) *endptr = p;
return (negative)? -n: n;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_int_type_]])popdef([[_is_space_]])popdef([[_prefix_]])dnl
]])dnl
dnl ---------------------------------------------------------------------------
define([[fn_chars_to_uint]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_int_type_]], $3)pushdef([[_is_space_]], $4)pushdef([[_prefix_]], $5)dnl
_int_type_ _fn_name_ (const _char_type_* str, hio_oow_t len, int option, const _char_type_** endptr, int* is_sober)
{
_int_type_ n = 0;
const _char_type_* p, * pp;
const _char_type_* end;
hio_oow_t rem;
int digit;
int base = _prefix_()_GET_OPTION_BASE(option);
p = str;
end = str + len;
if (_prefix_()_GET_OPTION_LTRIM(option))
{
/* strip off leading spaces */
while (p < end && _is_space_()(*p)) p++;
}
/* check for a sign */
while (p < end)
{
if (*p == '+') p++;
else break;
}
/* check for a binary/octal/hexadecimal notation */
rem = end - p;
if (base == 0)
{
if (rem >= 1 && *p == '0')
{
p++;
if (rem == 1) base = 8;
else if (*p == 'x' || *p == 'X')
{
p++; base = 16;
}
else if (*p == 'b' || *p == 'B')
{
p++; base = 2;
}
else base = 8;
}
else base = 10;
}
else if (rem >= 2 && base == 16)
{
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) p += 2;
}
else if (rem >= 2 && base == 2)
{
if (*p == '0' && (*(p + 1) == 'b' || *(p + 1) == 'B')) p += 2;
}
/* process the digits */
pp = p;
while (p < end)
{
digit = HIO_ZDIGIT_TO_NUM(*p, base);
if (digit >= base) break;
n = n * base + digit;
p++;
}
if (_prefix_()_GET_OPTION_E(option))
{
if (*p == 'E' || *p == 'e')
{
_int_type_ e = 0, i;
int e_neg = 0;
p++;
if (*p == '+')
{
p++;
}
else if (*p == '-')
{
p++; e_neg = 1;
}
while (p < end)
{
digit = HIO_ZDIGIT_TO_NUM(*p, base);
if (digit >= base) break;
e = e * base + digit;
p++;
}
if (e_neg)
for (i = 0; i < e; i++) n /= 10;
else
for (i = 0; i < e; i++) n *= 10;
}
}
/* base 8: at least a zero digit has been seen.
* other case: p > pp to be able to have at least 1 meaningful digit. */
if (is_sober) *is_sober = (base == 8 || p > pp);
if (_prefix_()_GET_OPTION_RTRIM(option))
{
/* consume trailing spaces */
while (p < end && _is_space_()(*p)) p++;
}
if (endptr) *endptr = p;
return n;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_int_type_]])popdef([[_is_space_]])popdef([[_prefix_]])dnl
]])
dnl ---------------------------------------------------------------------------
define([[fn_fnmat]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)pushdef([[_to_lower_]], $3)pushdef([[_match_ch_class_]], $4)dnl
int _fn_name_ (const _char_type_* str, hio_oow_t slen, const _char_type_* ptn, hio_oow_t plen, int flags, int no_first_period)
{
const _char_type_* sp = str;
const _char_type_* pp = ptn;
const _char_type_* se = str + slen;
const _char_type_* pe = ptn + plen;
_char_type_ sc, pc, pc2;
while (1)
{
if (pp < pe && HIO_FNMAT_IS_ESC(*pp) && !(flags & HIO_FNMAT_NOESCAPE))
{
/* pattern is escaped and escaping is allowed. */
if ((++pp) >= pe)
{
/*
* the last character of the pattern is an WCS_ESC.
* matching is performed as if the end of the pattern is
* reached just without an WCS_ESC.
*/
if (sp < se) return 0;
return 1;
}
if (sp >= se) return 0; /* premature string termination */
sc = *sp; pc = *pp; /* pc is just a normal character */
if ((flags & HIO_FNMAT_IGNORECASE) != 0)
{
/* make characters to lower-case */
sc = _to_lower_()(sc);
pc = _to_lower_()(pc);
}
if (sc != pc) return 0;
sp++; pp++;
continue;
}
if (pp >= pe)
{
/*
* the end of the pattern has been reached.
* the string must terminate too.
*/
return sp >= se;
}
if (sp >= se)
{
/* the string terminats prematurely */
while (pp < pe && *pp == '*') pp++;
return pp >= pe;
}
sc = *sp; pc = *pp;
if (sc == '.' && (flags & HIO_FNMAT_PERIOD))
{
/*
* a leading period in the staring must match
* a period in the pattern explicitly
*/
if ((!no_first_period && sp == str) ||
(HIO_FNMAT_IS_SEP(sp[-1]) && (flags & HIO_FNMAT_PATHNAME)))
{
if (pc != '.') return 0;
sp++; pp++;
continue;
}
}
else if (HIO_FNMAT_IS_SEP(sc) && (flags & HIO_FNMAT_PATHNAME))
{
while (pc == '*')
{
if ((++pp) >= pe) return 0;
pc = *pp;
}
/* a path separator must be matched explicitly */
if (!HIO_FNMAT_IS_SEP(pc)) return 0;
sp++; pp++;
continue;
}
/* the handling of special pattern characters begins here */
if (pc == '?')
{
/* match any single character */
sp++; pp++;
}
else if (pc == '*')
{
/* match zero or more characters */
/* compact asterisks */
do { pp++; } while (pp < pe && *pp == '*');
if (pp >= pe)
{
/*
* if the last character in the pattern is an asterisk,
* the string should not have any directory separators
* when HIO_FNMAT_PATHNAME is set.
*/
if (flags & HIO_FNMAT_PATHNAME)
{
const _char_type_* s = sp;
for (s = sp; s < se; s++)
{
if (HIO_FNMAT_IS_SEP(*s)) return 0;
}
}
return 1;
}
else
{
do
{
if (_fn_name_()(sp, se - sp, pp, pe - pp, flags, 1)) return 1;
if (HIO_FNMAT_IS_SEP(*sp) && (flags & HIO_FNMAT_PATHNAME)) break;
sp++;
}
while (sp < se);
return 0;
}
}
else if (pc == '[')
{
/* match range */
int negate = 0;
int matched = 0;
if ((++pp) >= pe) return 0;
if (*pp == '!') { negate = 1; pp++; }
while (pp < pe && *pp != ']')
{
if (*pp == '[')
{
hio_oow_t pl = pe - pp;
if (pl >= 9) /* assumption that [:class:] is at least 9 in _match_ch_class_ */
{
int x = _match_ch_class_()(pp, sc, &matched);
if (x > 0)
{
pp += x;
continue;
}
}
/*
* characters in an invalid class name are
* just treated as normal characters
*/
}
if (HIO_FNMAT_IS_ESC(*pp) && !(flags & HIO_FNMAT_NOESCAPE)) pp++;
else if (*pp == ']') break;
if (pp >= pe) break;
pc = *pp;
if ((flags & HIO_FNMAT_IGNORECASE) != 0)
{
sc = _to_lower_()(sc);
pc = _to_lower_()(pc);
}
if (pp + 1 < pe && pp[1] == '-')
{
pp += 2; /* move the a character next to a dash */
if (pp >= pe)
{
if (sc >= pc) matched = 1;
break;
}
if (HIO_FNMAT_IS_ESC(*pp) && !(flags & HIO_FNMAT_NOESCAPE))
{
if ((++pp) >= pe)
{
if (sc >= pc) matched = 1;
break;
}
}
else if (*pp == ']')
{
if (sc >= pc) matched = 1;
break;
}
pc2 = *pp;
if ((flags & HIO_FNMAT_IGNORECASE) != 0)
pc2 = _to_lower_()(pc2);
if (sc >= pc && sc <= pc2) matched = 1;
pp++;
}
else
{
if (sc == pc) matched = 1;
pp++;
}
}
if (negate) matched = !matched;
if (!matched) return 0;
sp++; if (pp < pe) pp++;
}
else
{
/* a normal character */
if ((flags & HIO_FNMAT_IGNORECASE) != 0)
{
sc = _to_lower_()(sc);
pc = _to_lower_()(pc);
}
if (sc != pc) return 0;
sp++; pp++;
}
}
/* will never reach here. but make some immature compilers happy... */
return 0;
}
popdef([[_fn_name_]])popdef([[_char_type_]])popdef([[_int_type_]])popdef([[_match_ch_class_]])dnl
]])