From 59e36d1a18e15ba4a2d48c527cd3a1bd07f96f26 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 12 Jun 2022 14:26:27 +0000 Subject: [PATCH] added some more string functions --- hio/lib/utl-str.c | 480 +++++++++++++++++++++++++++++++++++++++++++ hio/lib/utl-str.c.m4 | 26 ++- hio/lib/utl-str.m4 | 262 ++++++++++++++++++++++- 3 files changed, 762 insertions(+), 6 deletions(-) diff --git a/hio/lib/utl-str.c b/hio/lib/utl-str.c index 9af25e5..20c6384 100644 --- a/hio/lib/utl-str.c +++ b/hio/lib/utl-str.c @@ -495,6 +495,246 @@ hio_oow_t hio_copy_bcstr_unlimited (hio_bch_t* dst, const hio_bch_t* src) return dst - org - 1; } +hio_oow_t hio_copy_fmt_ucstrs_to_ucstr (hio_uch_t* buf, hio_oow_t bsz, const hio_uch_t* fmt, const hio_uch_t* str[]) +{ + hio_uch_t* b = buf; + hio_uch_t* end = buf + bsz - 1; + const hio_uch_t* 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 hio_uch_t* 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; +} + +hio_oow_t hio_copy_fmt_bcstrs_to_bcstr (hio_bch_t* buf, hio_oow_t bsz, const hio_bch_t* fmt, const hio_bch_t* str[]) +{ + hio_bch_t* b = buf; + hio_bch_t* end = buf + bsz - 1; + const hio_bch_t* 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 hio_bch_t* 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; +} + +hio_oow_t hio_copy_fmt_ucses_to_ucstr (hio_uch_t* buf, hio_oow_t bsz, const hio_uch_t* fmt, const hio_ucs_t str[]) +{ + hio_uch_t* b = buf; + hio_uch_t* end = buf + bsz - 1; + const hio_uch_t* 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 hio_uch_t* 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; +} + +hio_oow_t hio_copy_fmt_bcses_to_bcstr (hio_bch_t* buf, hio_oow_t bsz, const hio_bch_t* fmt, const hio_bcs_t str[]) +{ + hio_bch_t* b = buf; + hio_bch_t* end = buf + bsz - 1; + const hio_bch_t* 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 hio_bch_t* 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; +} + hio_oow_t hio_count_ucstr (const hio_uch_t* str) { const hio_uch_t* ptr = str; @@ -509,6 +749,26 @@ hio_oow_t hio_count_bcstr (const hio_bch_t* str) return ptr - str; } +hio_oow_t hio_count_ucstr_limited (const hio_uch_t* str, hio_oow_t maxlen) +{ + hio_oow_t i; + for (i = 0; i < maxlen; i++) + { + if (str[i] == '\0') break; + } + return i; +} + +hio_oow_t hio_count_bcstr_limited (const hio_uch_t* str, hio_oow_t maxlen) +{ + hio_oow_t i; + for (i = 0; i < maxlen; i++) + { + if (str[i] == '\0') break; + } + return i; +} + int hio_equal_uchars (const hio_uch_t* str1, const hio_uch_t* str2, hio_oow_t len) { hio_oow_t i; @@ -629,6 +889,226 @@ hio_bch_t* hio_find_bchar_in_bcstr (const hio_bch_t* ptr, hio_bch_t c) return HIO_NULL; } +hio_uch_t* hio_rfind_uchar_in_ucstr (const hio_uch_t* str, hio_uch_t c) +{ + const hio_uch_t* ptr = str; + while (*ptr != '\0') ptr++; + + while (ptr > str) + { + --ptr; + if (*ptr == c) return (hio_uch_t*)ptr; + } + + return HIO_NULL; +} + +hio_bch_t* hio_rfind_bchar_in_bcstr (const hio_bch_t* str, hio_bch_t c) +{ + const hio_bch_t* ptr = str; + while (*ptr != '\0') ptr++; + + while (ptr > str) + { + --ptr; + if (*ptr == c) return (hio_bch_t*)ptr; + } + + return HIO_NULL; +} + +hio_uch_t* hio_find_uchars_in_uchars (const hio_uch_t* str, hio_oow_t strsz, const hio_uch_t* sub, hio_oow_t subsz, int ignorecase) +{ + const hio_uch_t* end, * subp; + + if (subsz == 0) return (hio_uch_t*)str; + if (strsz < subsz) return HIO_NULL; + + end = str + strsz - subsz; + subp = sub + subsz; + + if (HIO_UNLIKELY(ignorecase)) + { + while (str <= end) + { + const hio_uch_t* x = str; + const hio_uch_t* y = sub; + + while (1) + { + if (y >= subp) return (hio_uch_t*)str; + if (hio_to_uch_lower(*x) != hio_to_uch_lower(*y)) break; + x++; y++; + } + + str++; + } + } + else + { + while (str <= end) + { + const hio_uch_t* x = str; + const hio_uch_t* y = sub; + + while (1) + { + if (y >= subp) return (hio_uch_t*)str; + if (*x != *y) break; + x++; y++; + } + + str++; + } + } + + return HIO_NULL; +} + +hio_bch_t* hio_find_bchars_in_bchars (const hio_bch_t* str, hio_oow_t strsz, const hio_bch_t* sub, hio_oow_t subsz, int ignorecase) +{ + const hio_bch_t* end, * subp; + + if (subsz == 0) return (hio_bch_t*)str; + if (strsz < subsz) return HIO_NULL; + + end = str + strsz - subsz; + subp = sub + subsz; + + if (HIO_UNLIKELY(ignorecase)) + { + while (str <= end) + { + const hio_bch_t* x = str; + const hio_bch_t* y = sub; + + while (1) + { + if (y >= subp) return (hio_bch_t*)str; + if (hio_to_bch_lower(*x) != hio_to_bch_lower(*y)) break; + x++; y++; + } + + str++; + } + } + else + { + while (str <= end) + { + const hio_bch_t* x = str; + const hio_bch_t* y = sub; + + while (1) + { + if (y >= subp) return (hio_bch_t*)str; + if (*x != *y) break; + x++; y++; + } + + str++; + } + } + + return HIO_NULL; +} + +hio_uch_t* hio_rfind_uchars_in_uchars (const hio_uch_t* str, hio_oow_t strsz, const hio_uch_t* sub, hio_oow_t subsz, int ignorecase) +{ + const hio_uch_t* p = str + strsz; + const hio_uch_t* subp = sub + subsz; + + if (subsz == 0) return (hio_uch_t*)p; + if (strsz < subsz) return HIO_NULL; + + p = p - subsz; + + if (HIO_UNLIKELY(ignorecase)) + { + while (p >= str) + { + const hio_uch_t* x = p; + const hio_uch_t* y = sub; + + while (1) + { + if (y >= subp) return (hio_uch_t*)p; + if (hio_to_uch_lower(*x) != hio_to_uch_lower(*y)) break; + x++; y++; + } + + p--; + } + } + else + { + while (p >= str) + { + const hio_uch_t* x = p; + const hio_uch_t* y = sub; + + while (1) + { + if (y >= subp) return (hio_uch_t*)p; + if (*x != *y) break; + x++; y++; + } + + p--; + } + } + + return HIO_NULL; +} + +hio_bch_t* hio_rfind_bchars_in_bchars (const hio_bch_t* str, hio_oow_t strsz, const hio_bch_t* sub, hio_oow_t subsz, int ignorecase) +{ + const hio_bch_t* p = str + strsz; + const hio_bch_t* subp = sub + subsz; + + if (subsz == 0) return (hio_bch_t*)p; + if (strsz < subsz) return HIO_NULL; + + p = p - subsz; + + if (HIO_UNLIKELY(ignorecase)) + { + while (p >= str) + { + const hio_bch_t* x = p; + const hio_bch_t* y = sub; + + while (1) + { + if (y >= subp) return (hio_bch_t*)p; + if (hio_to_bch_lower(*x) != hio_to_bch_lower(*y)) break; + x++; y++; + } + + p--; + } + } + else + { + while (p >= str) + { + const hio_bch_t* x = p; + const hio_bch_t* y = sub; + + while (1) + { + if (y >= subp) return (hio_bch_t*)p; + if (*x != *y) break; + x++; y++; + } + + p--; + } + } + + return HIO_NULL; +} + hio_oow_t hio_rotate_uchars (hio_uch_t* str, hio_oow_t len, int dir, hio_oow_t n) { hio_oow_t first, last, count, index, nk; diff --git a/hio/lib/utl-str.c.m4 b/hio/lib/utl-str.c.m4 index 679485b..5e64a8d 100644 --- a/hio/lib/utl-str.c.m4 +++ b/hio/lib/utl-str.c.m4 @@ -72,24 +72,42 @@ dnl -- fn_copy_cstr_unlimited(hio_copy_ucstr_unlimited, hio_uch_t) fn_copy_cstr_unlimited(hio_copy_bcstr_unlimited, hio_bch_t) dnl -- +fn_copy_fmt_cstrs_to_cstr(hio_copy_fmt_ucstrs_to_ucstr, hio_uch_t) +fn_copy_fmt_cstrs_to_cstr(hio_copy_fmt_bcstrs_to_bcstr, hio_bch_t) +dnl -- +fn_copy_fmt_cses_to_cstr(hio_copy_fmt_ucses_to_ucstr, hio_uch_t, hio_ucs_t) +fn_copy_fmt_cses_to_cstr(hio_copy_fmt_bcses_to_bcstr, hio_bch_t, hio_bcs_t) +dnl -- fn_count_cstr(hio_count_ucstr, hio_uch_t) fn_count_cstr(hio_count_bcstr, hio_bch_t) dnl -- +fn_count_cstr_limited(hio_count_ucstr_limited, hio_uch_t) +fn_count_cstr_limited(hio_count_bcstr_limited, hio_bch_t) +dnl -- fn_equal_chars(hio_equal_uchars, hio_uch_t) fn_equal_chars(hio_equal_bchars, hio_bch_t) dnl -- fn_fill_chars(hio_fill_uchars, hio_uch_t) fn_fill_chars(hio_fill_bchars, hio_bch_t) dnl -- -fn_find_char(hio_find_uchar, hio_uch_t) -fn_find_char(hio_find_bchar, hio_bch_t) +fn_find_char_in_chars(hio_find_uchar, hio_uch_t) +fn_find_char_in_chars(hio_find_bchar, hio_bch_t) dnl -- -fn_rfind_char(hio_rfind_uchar, hio_uch_t) -fn_rfind_char(hio_rfind_bchar, hio_bch_t) +fn_rfind_char_in_chars(hio_rfind_uchar, hio_uch_t) +fn_rfind_char_in_chars(hio_rfind_bchar, hio_bch_t) dnl -- fn_find_char_in_cstr(hio_find_uchar_in_ucstr, hio_uch_t) fn_find_char_in_cstr(hio_find_bchar_in_bcstr, hio_bch_t) dnl -- +fn_rfind_char_in_cstr(hio_rfind_uchar_in_ucstr, hio_uch_t) +fn_rfind_char_in_cstr(hio_rfind_bchar_in_bcstr, hio_bch_t) +dnl -- +fn_find_chars_in_chars(hio_find_uchars_in_uchars, hio_uch_t, hio_to_uch_lower) +fn_find_chars_in_chars(hio_find_bchars_in_bchars, hio_bch_t, hio_to_bch_lower) +dnl -- +fn_rfind_chars_in_chars(hio_rfind_uchars_in_uchars, hio_uch_t, hio_to_uch_lower) +fn_rfind_chars_in_chars(hio_rfind_bchars_in_bchars, hio_bch_t, hio_to_bch_lower) +dnl -- fn_rotate_chars(hio_rotate_uchars, hio_uch_t) fn_rotate_chars(hio_rotate_bchars, hio_bch_t) dnl -- diff --git a/hio/lib/utl-str.m4 b/hio/lib/utl-str.m4 index 44e32f6..3e0eb13 100644 --- a/hio/lib/utl-str.m4 +++ b/hio/lib/utl-str.m4 @@ -269,6 +269,132 @@ hio_oow_t _fn_name_ (_char_type_* dst, const _char_type_* src) 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_t_]], $3)dnl +hio_oow_t _fn_name_ (_char_type_* buf, hio_oow_t bsz, const _char_type_* fmt, const _cs_t_ 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_t_]])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) { @@ -279,6 +405,19 @@ hio_oow_t _fn_name_ (const _char_type_* 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 hio_uch_t* 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) { @@ -306,7 +445,7 @@ void _fn_name_ (_char_type_* dst, _char_type_ ch, hio_oow_t len) popdef([[_fn_name_]])popdef([[_char_type_]])dnl ]])dnl dnl --------------------------------------------------------------------------- -define([[fn_find_char]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)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; @@ -323,7 +462,7 @@ _char_type_* _fn_name_ (const _char_type_* ptr, hio_oow_t len, _char_type_ c) popdef([[_fn_name_]])popdef([[_char_type_]])dnl ]])dnl dnl --------------------------------------------------------------------------- -define([[fn_rfind_char]], [[pushdef([[_fn_name_]], $1)pushdef([[_char_type_]], $2)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; @@ -354,6 +493,125 @@ _char_type_* _fn_name_ (const _char_type_* ptr, _char_type_ c) 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_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) {