3590 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3590 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|     Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     Redistribution and use in source and binary forms, with or without
 | |
|     modification, are permitted provided that the following conditions
 | |
|     are met:
 | |
|     1. Redistributions of source code must retain the above copyright
 | |
|        notice, this list of conditions and the following disclaimer.
 | |
|     2. Redistributions in binary form must reproduce the above copyright
 | |
|        notice, this list of conditions and the following disclaimer in the
 | |
|        documentation and/or other materials provided with the distribution.
 | |
| 
 | |
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | |
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Do NOT edit utl-str.c. Edit utl-str.c.m4 instead.
 | |
|  *
 | |
|  * Generate utl-str.c with m4
 | |
|  *   $ m4 utl-str.c.m4 > utl-str.c
 | |
|  */
 | |
| 
 | |
| #include "hawk-prv.h"
 | |
| #include <hawk-chr.h>
 | |
| 
 | |
| static int match_uch_class (const hawk_uch_t* pp, hawk_uch_t sc, int* matched)
 | |
| {
 | |
| 	if (hawk_comp_ucstr_bcstr_limited(pp, "[:upper:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_upper(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:lower:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_lower(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:alpha:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_alpha(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:digit:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_digit(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:xdigit:]", 10, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_xdigit(sc);
 | |
| 		return 10;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:alnum:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_alnum(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:space:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_space(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:print:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_print(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:graph:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_graph(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:cntrl:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_cntrl(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_ucstr_bcstr_limited(pp, "[:punct:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_uch_punct(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int match_bch_class (const hawk_bch_t* pp, hawk_bch_t sc, int* matched)
 | |
| {
 | |
| 	if (hawk_comp_bcstr_limited(pp, "[:upper:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_upper(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:lower:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_lower(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:alpha:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_alpha(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:digit:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_digit(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:xdigit:]", 10, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_xdigit(sc);
 | |
| 		return 10;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:alnum:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_alnum(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:space:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_space(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:print:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_print(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:graph:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_graph(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:cntrl:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_cntrl(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 	else if (hawk_comp_bcstr_limited(pp, "[:punct:]", 9, 0) == 0)
 | |
| 	{
 | |
| 		*matched = hawk_is_bch_punct(sc);
 | |
| 		return 9;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| int hawk_comp_uchars (const hawk_uch_t* str1, hawk_oow_t len1, const hawk_uch_t* str2, hawk_oow_t len2, int ignorecase)
 | |
| {
 | |
| 	hawk_uchu_t c1, c2;
 | |
| 	const hawk_uch_t* end1 = str1 + len1;
 | |
| 	const hawk_uch_t* end2 = str2 + len2;
 | |
| 
 | |
| 	if (ignorecase)
 | |
| 	{
 | |
| 		while (str1 < end1)
 | |
| 		{
 | |
| 			c1 = hawk_to_uch_lower(*str1);
 | |
| 			if (str2 < end2)
 | |
| 			{
 | |
| 				c2 = hawk_to_uch_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;
 | |
| }
 | |
| 
 | |
| int hawk_comp_bchars (const hawk_bch_t* str1, hawk_oow_t len1, const hawk_bch_t* str2, hawk_oow_t len2, int ignorecase)
 | |
| {
 | |
| 	hawk_bchu_t c1, c2;
 | |
| 	const hawk_bch_t* end1 = str1 + len1;
 | |
| 	const hawk_bch_t* end2 = str2 + len2;
 | |
| 
 | |
| 	if (ignorecase)
 | |
| 	{
 | |
| 		while (str1 < end1)
 | |
| 		{
 | |
| 			c1 = hawk_to_bch_lower(*str1);
 | |
| 			if (str2 < end2)
 | |
| 			{
 | |
| 				c2 = hawk_to_bch_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;
 | |
| }
 | |
| 
 | |
| int hawk_comp_ucstr (const hawk_uch_t* str1, const hawk_uch_t* str2, int ignorecase)
 | |
| {
 | |
| 	if (ignorecase)
 | |
| 	{
 | |
| 		while (hawk_to_uch_lower(*str1) == hawk_to_uch_lower(*str2))
 | |
| 		{
 | |
| 			if (*str1 == '\0') return 0;
 | |
| 			str1++; str2++;
 | |
| 		}
 | |
| 
 | |
| 		return ((hawk_uchu_t)hawk_to_uch_lower(*str1) > (hawk_uchu_t)hawk_to_uch_lower(*str2))? 1: -1;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		while (*str1 == *str2)
 | |
| 		{
 | |
| 			if (*str1 == '\0') return 0;
 | |
| 			str1++; str2++;
 | |
| 		}
 | |
| 
 | |
| 		return ((hawk_uchu_t)*str1 > (hawk_uchu_t)*str2)? 1: -1;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_comp_bcstr (const hawk_bch_t* str1, const hawk_bch_t* str2, int ignorecase)
 | |
| {
 | |
| 	if (ignorecase)
 | |
| 	{
 | |
| 		while (hawk_to_bch_lower(*str1) == hawk_to_bch_lower(*str2))
 | |
| 		{
 | |
| 			if (*str1 == '\0') return 0;
 | |
| 			str1++; str2++;
 | |
| 		}
 | |
| 
 | |
| 		return ((hawk_bchu_t)hawk_to_bch_lower(*str1) > (hawk_bchu_t)hawk_to_bch_lower(*str2))? 1: -1;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		while (*str1 == *str2)
 | |
| 		{
 | |
| 			if (*str1 == '\0') return 0;
 | |
| 			str1++; str2++;
 | |
| 		}
 | |
| 
 | |
| 		return ((hawk_bchu_t)*str1 > (hawk_bchu_t)*str2)? 1: -1;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_comp_ucstr_limited (const hawk_uch_t* str1, const hawk_uch_t* str2, hawk_oow_t maxlen, int ignorecase)
 | |
| {
 | |
| 	if (maxlen == 0) return 0;
 | |
| 
 | |
| 	if (ignorecase)
 | |
| 	{
 | |
| 		while (hawk_to_uch_lower(*str1) == hawk_to_uch_lower(*str2))
 | |
| 		{
 | |
| 			 if (*str1 == '\0' || maxlen == 1) return 0;
 | |
| 			 str1++; str2++; maxlen--;
 | |
| 		}
 | |
| 
 | |
| 		return ((hawk_uchu_t)hawk_to_uch_lower(*str1) > (hawk_uchu_t)hawk_to_uch_lower(*str2))? 1: -1;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		while (*str1 == *str2)
 | |
| 		{
 | |
| 			 if (*str1 == '\0' || maxlen == 1) return 0;
 | |
| 			 str1++; str2++; maxlen--;
 | |
| 		}
 | |
| 
 | |
| 		return ((hawk_uchu_t)*str1 > (hawk_uchu_t)*str2)? 1: -1;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_comp_bcstr_limited (const hawk_bch_t* str1, const hawk_bch_t* str2, hawk_oow_t maxlen, int ignorecase)
 | |
| {
 | |
| 	if (maxlen == 0) return 0;
 | |
| 
 | |
| 	if (ignorecase)
 | |
| 	{
 | |
| 		while (hawk_to_bch_lower(*str1) == hawk_to_bch_lower(*str2))
 | |
| 		{
 | |
| 			 if (*str1 == '\0' || maxlen == 1) return 0;
 | |
| 			 str1++; str2++; maxlen--;
 | |
| 		}
 | |
| 
 | |
| 		return ((hawk_bchu_t)hawk_to_bch_lower(*str1) > (hawk_bchu_t)hawk_to_bch_lower(*str2))? 1: -1;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		while (*str1 == *str2)
 | |
| 		{
 | |
| 			 if (*str1 == '\0' || maxlen == 1) return 0;
 | |
| 			 str1++; str2++; maxlen--;
 | |
| 		}
 | |
| 
 | |
| 		return ((hawk_bchu_t)*str1 > (hawk_bchu_t)*str2)? 1: -1;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_comp_uchars_ucstr (const hawk_uch_t* str1, hawk_oow_t len, const hawk_uch_t* 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 hawk_uch_t* end = str1 + len;
 | |
| 		hawk_uch_t c1;
 | |
| 		hawk_uch_t c2;
 | |
| 		while (str1 < end && *str2 != '\0')
 | |
| 		{
 | |
| 			c1 = hawk_to_uch_lower(*str1);
 | |
| 			c2 = hawk_to_uch_lower(*str2);
 | |
| 			if (c1 != c2) return ((hawk_uchu_t)c1 > (hawk_uchu_t)c2)? 1: -1;
 | |
| 			str1++; str2++;
 | |
| 		}
 | |
| 		return (str1 < end)? 1: (*str2 == '\0'? 0: -1);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		const hawk_uch_t* end = str1 + len;
 | |
| 		while (str1 < end && *str2 != '\0')
 | |
| 		{
 | |
| 			if (*str1 != *str2) return ((hawk_uchu_t)*str1 > (hawk_uchu_t)*str2)? 1: -1;
 | |
| 			str1++; str2++;
 | |
| 		}
 | |
| 		return (str1 < end)? 1: (*str2 == '\0'? 0: -1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_comp_bchars_bcstr (const hawk_bch_t* str1, hawk_oow_t len, const hawk_bch_t* 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 hawk_bch_t* end = str1 + len;
 | |
| 		hawk_bch_t c1;
 | |
| 		hawk_bch_t c2;
 | |
| 		while (str1 < end && *str2 != '\0')
 | |
| 		{
 | |
| 			c1 = hawk_to_bch_lower(*str1);
 | |
| 			c2 = hawk_to_bch_lower(*str2);
 | |
| 			if (c1 != c2) return ((hawk_bchu_t)c1 > (hawk_bchu_t)c2)? 1: -1;
 | |
| 			str1++; str2++;
 | |
| 		}
 | |
| 		return (str1 < end)? 1: (*str2 == '\0'? 0: -1);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		const hawk_bch_t* end = str1 + len;
 | |
| 		while (str1 < end && *str2 != '\0')
 | |
| 		{
 | |
| 			if (*str1 != *str2) return ((hawk_bchu_t)*str1 > (hawk_bchu_t)*str2)? 1: -1;
 | |
| 			str1++; str2++;
 | |
| 		}
 | |
| 		return (str1 < end)? 1: (*str2 == '\0'? 0: -1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_concat_uchars_to_ucstr (hawk_uch_t* buf, hawk_oow_t bsz, const hawk_uch_t* str, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_uch_t* p, * p2;
 | |
| 	const hawk_uch_t* end;
 | |
| 	hawk_oow_t blen;
 | |
| 
 | |
| 	blen = hawk_count_ucstr(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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_concat_bchars_to_bcstr (hawk_bch_t* buf, hawk_oow_t bsz, const hawk_bch_t* str, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_bch_t* p, * p2;
 | |
| 	const hawk_bch_t* end;
 | |
| 	hawk_oow_t blen;
 | |
| 
 | |
| 	blen = hawk_count_bcstr(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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_concat_ucstr (hawk_uch_t* buf, hawk_oow_t bsz, const hawk_uch_t* str)
 | |
| {
 | |
| 	hawk_uch_t* p, * p2;
 | |
| 	hawk_oow_t blen;
 | |
| 
 | |
| 	blen = hawk_count_ucstr(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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_concat_bcstr (hawk_bch_t* buf, hawk_oow_t bsz, const hawk_bch_t* str)
 | |
| {
 | |
| 	hawk_bch_t* p, * p2;
 | |
| 	hawk_oow_t blen;
 | |
| 
 | |
| 	blen = hawk_count_bcstr(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;
 | |
| }
 | |
| 
 | |
| void hawk_copy_uchars (hawk_uch_t* dst, const hawk_uch_t* src, hawk_oow_t len)
 | |
| {
 | |
| 	/* take note of no forced null termination */
 | |
| 	hawk_oow_t i;
 | |
| 	for (i = 0; i < len; i++) dst[i] = src[i];
 | |
| }
 | |
| 
 | |
| void hawk_copy_bchars (hawk_bch_t* dst, const hawk_bch_t* src, hawk_oow_t len)
 | |
| {
 | |
| 	/* take note of no forced null termination */
 | |
| 	hawk_oow_t i;
 | |
| 	for (i = 0; i < len; i++) dst[i] = src[i];
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_uchars_to_ucstr (hawk_uch_t* dst, hawk_oow_t dlen, const hawk_uch_t* src, hawk_oow_t slen)
 | |
| {
 | |
| 	hawk_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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_bchars_to_bcstr (hawk_bch_t* dst, hawk_oow_t dlen, const hawk_bch_t* src, hawk_oow_t slen)
 | |
| {
 | |
| 	hawk_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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_uchars_to_ucstr_unlimited (hawk_uch_t* dst, const hawk_uch_t* src, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_oow_t i;
 | |
| 	for (i = 0; i < len; i++) dst[i] = src[i];
 | |
| 	dst[i] = '\0';
 | |
| 	return i;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_bchars_to_bcstr_unlimited (hawk_bch_t* dst, const hawk_bch_t* src, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_oow_t i;
 | |
| 	for (i = 0; i < len; i++) dst[i] = src[i];
 | |
| 	dst[i] = '\0';
 | |
| 	return i;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_ucstr_to_uchars (hawk_uch_t* dst, hawk_oow_t len, const hawk_uch_t* src)
 | |
| {
 | |
| 	/* no null termination */
 | |
| 	hawk_uch_t* p, * p2;
 | |
| 
 | |
| 	p = dst; p2 = dst + len - 1;
 | |
| 
 | |
| 	while (p < p2)
 | |
| 	{
 | |
| 		if (*src == '\0') break;
 | |
| 		*p++ = *src++;
 | |
| 	}
 | |
| 
 | |
| 	return p - dst;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_bcstr_to_bchars (hawk_bch_t* dst, hawk_oow_t len, const hawk_bch_t* src)
 | |
| {
 | |
| 	/* no null termination */
 | |
| 	hawk_bch_t* p, * p2;
 | |
| 
 | |
| 	p = dst; p2 = dst + len - 1;
 | |
| 
 | |
| 	while (p < p2)
 | |
| 	{
 | |
| 		if (*src == '\0') break;
 | |
| 		*p++ = *src++;
 | |
| 	}
 | |
| 
 | |
| 	return p - dst;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_ucstr (hawk_uch_t* dst, hawk_oow_t len, const hawk_uch_t* src)
 | |
| {
 | |
| 	hawk_uch_t* 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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_bcstr (hawk_bch_t* dst, hawk_oow_t len, const hawk_bch_t* src)
 | |
| {
 | |
| 	hawk_bch_t* 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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_ucstr_unlimited (hawk_uch_t* dst, const hawk_uch_t* src)
 | |
| {
 | |
| 	hawk_uch_t* org = dst;
 | |
| 	while ((*dst++ = *src++) != '\0');
 | |
| 	return dst - org - 1;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_bcstr_unlimited (hawk_bch_t* dst, const hawk_bch_t* src)
 | |
| {
 | |
| 	hawk_bch_t* org = dst;
 | |
| 	while ((*dst++ = *src++) != '\0');
 | |
| 	return dst - org - 1;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_fmt_ucstrs_to_ucstr (hawk_uch_t* buf, hawk_oow_t bsz, const hawk_uch_t* fmt, const hawk_uch_t* str[])
 | |
| {
 | |
| 	hawk_uch_t* b = buf;
 | |
| 	hawk_uch_t* end = buf + bsz - 1;
 | |
| 	const hawk_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 hawk_uch_t* tmp;
 | |
| 				hawk_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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_fmt_bcstrs_to_bcstr (hawk_bch_t* buf, hawk_oow_t bsz, const hawk_bch_t* fmt, const hawk_bch_t* str[])
 | |
| {
 | |
| 	hawk_bch_t* b = buf;
 | |
| 	hawk_bch_t* end = buf + bsz - 1;
 | |
| 	const hawk_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 hawk_bch_t* tmp;
 | |
| 				hawk_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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_fmt_ucses_to_ucstr (hawk_uch_t* buf, hawk_oow_t bsz, const hawk_uch_t* fmt, const hawk_ucs_t str[])
 | |
| {
 | |
| 	hawk_uch_t* b = buf;
 | |
| 	hawk_uch_t* end = buf + bsz - 1;
 | |
| 	const hawk_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 hawk_uch_t* tmp, * tmpend;
 | |
| 				hawk_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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_copy_fmt_bcses_to_bcstr (hawk_bch_t* buf, hawk_oow_t bsz, const hawk_bch_t* fmt, const hawk_bcs_t str[])
 | |
| {
 | |
| 	hawk_bch_t* b = buf;
 | |
| 	hawk_bch_t* end = buf + bsz - 1;
 | |
| 	const hawk_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 hawk_bch_t* tmp, * tmpend;
 | |
| 				hawk_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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_count_ucstr (const hawk_uch_t* str)
 | |
| {
 | |
| 	const hawk_uch_t* ptr = str;
 | |
| 	while (*ptr != '\0') ptr++;
 | |
| 	return ptr - str;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_count_bcstr (const hawk_bch_t* str)
 | |
| {
 | |
| 	const hawk_bch_t* ptr = str;
 | |
| 	while (*ptr != '\0') ptr++;
 | |
| 	return ptr - str;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_count_ucstr_limited (const hawk_uch_t* str, hawk_oow_t maxlen)
 | |
| {
 | |
| 	hawk_oow_t i;
 | |
| 	for (i = 0; i < maxlen; i++)
 | |
| 	{
 | |
| 		if (str[i] == '\0') break;
 | |
| 	}
 | |
| 	return i;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_count_bcstr_limited (const hawk_bch_t* str, hawk_oow_t maxlen)
 | |
| {
 | |
| 	hawk_oow_t i;
 | |
| 	for (i = 0; i < maxlen; i++)
 | |
| 	{
 | |
| 		if (str[i] == '\0') break;
 | |
| 	}
 | |
| 	return i;
 | |
| }
 | |
| 
 | |
| int hawk_equal_uchars (const hawk_uch_t* str1, const hawk_uch_t* str2, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_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;
 | |
| }
 | |
| 
 | |
| int hawk_equal_bchars (const hawk_bch_t* str1, const hawk_bch_t* str2, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_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;
 | |
| }
 | |
| 
 | |
| void hawk_fill_uchars (hawk_uch_t* dst, hawk_uch_t ch, hawk_oow_t len)
 | |
| {
 | |
|         hawk_oow_t i;
 | |
|         for (i = 0; i < len; i++) dst[i] = ch;
 | |
| }
 | |
| 
 | |
| void hawk_fill_bchars (hawk_bch_t* dst, hawk_bch_t ch, hawk_oow_t len)
 | |
| {
 | |
|         hawk_oow_t i;
 | |
|         for (i = 0; i < len; i++) dst[i] = ch;
 | |
| }
 | |
| 
 | |
| hawk_uch_t* hawk_find_uchar_in_uchars (const hawk_uch_t* ptr, hawk_oow_t len, hawk_uch_t c)
 | |
| {
 | |
| 	const hawk_uch_t* end;
 | |
| 
 | |
| 	end = ptr + len;
 | |
| 	while (ptr < end)
 | |
| 	{
 | |
| 		if (*ptr == c) return (hawk_uch_t*)ptr;
 | |
| 		ptr++;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_find_bchar_in_bchars (const hawk_bch_t* ptr, hawk_oow_t len, hawk_bch_t c)
 | |
| {
 | |
| 	const hawk_bch_t* end;
 | |
| 
 | |
| 	end = ptr + len;
 | |
| 	while (ptr < end)
 | |
| 	{
 | |
| 		if (*ptr == c) return (hawk_bch_t*)ptr;
 | |
| 		ptr++;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_uch_t* hawk_rfind_uchar_in_uchars (const hawk_uch_t* ptr, hawk_oow_t len, hawk_uch_t c)
 | |
| {
 | |
| 	const hawk_uch_t* cur;
 | |
| 
 | |
| 	cur = ptr + len;
 | |
| 	while (cur > ptr)
 | |
| 	{
 | |
| 		--cur;
 | |
| 		if (*cur == c) return (hawk_uch_t*)cur;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_rfind_bchar_in_bchars (const hawk_bch_t* ptr, hawk_oow_t len, hawk_bch_t c)
 | |
| {
 | |
| 	const hawk_bch_t* cur;
 | |
| 
 | |
| 	cur = ptr + len;
 | |
| 	while (cur > ptr)
 | |
| 	{
 | |
| 		--cur;
 | |
| 		if (*cur == c) return (hawk_bch_t*)cur;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_uch_t* hawk_find_uchar_in_ucstr (const hawk_uch_t* ptr, hawk_uch_t c)
 | |
| {
 | |
| 	while (*ptr != '\0')
 | |
| 	{
 | |
| 		if (*ptr == c) return (hawk_uch_t*)ptr;
 | |
| 		ptr++;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_find_bchar_in_bcstr (const hawk_bch_t* ptr, hawk_bch_t c)
 | |
| {
 | |
| 	while (*ptr != '\0')
 | |
| 	{
 | |
| 		if (*ptr == c) return (hawk_bch_t*)ptr;
 | |
| 		ptr++;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_uch_t* hawk_rfind_uchar_in_ucstr (const hawk_uch_t* str, hawk_uch_t c)
 | |
| {
 | |
| 	const hawk_uch_t* ptr = str;
 | |
| 	while (*ptr != '\0') ptr++;
 | |
| 
 | |
| 	while (ptr > str)
 | |
| 	{
 | |
| 		--ptr;
 | |
| 		if (*ptr == c) return (hawk_uch_t*)ptr;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_rfind_bchar_in_bcstr (const hawk_bch_t* str, hawk_bch_t c)
 | |
| {
 | |
| 	const hawk_bch_t* ptr = str;
 | |
| 	while (*ptr != '\0') ptr++;
 | |
| 
 | |
| 	while (ptr > str)
 | |
| 	{
 | |
| 		--ptr;
 | |
| 		if (*ptr == c) return (hawk_bch_t*)ptr;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_uch_t* hawk_find_uchars_in_uchars (const hawk_uch_t* str, hawk_oow_t strsz, const hawk_uch_t* sub, hawk_oow_t subsz, int ignorecase)
 | |
| {
 | |
| 	const hawk_uch_t* end, * subp;
 | |
| 
 | |
| 	if (subsz == 0) return (hawk_uch_t*)str;
 | |
| 	if (strsz < subsz) return HAWK_NULL;
 | |
| 
 | |
| 	end = str + strsz - subsz;
 | |
| 	subp = sub + subsz;
 | |
| 
 | |
| 	if (HAWK_UNLIKELY(ignorecase))
 | |
| 	{
 | |
| 		while (str <= end)
 | |
| 		{
 | |
| 			const hawk_uch_t* x = str;
 | |
| 			const hawk_uch_t* y = sub;
 | |
| 
 | |
| 			while (1)
 | |
| 			{
 | |
| 				if (y >= subp) return (hawk_uch_t*)str;
 | |
| 				if (hawk_to_uch_lower(*x) != hawk_to_uch_lower(*y)) break;
 | |
| 				x++; y++;
 | |
| 			}
 | |
| 
 | |
| 			str++;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		while (str <= end)
 | |
| 		{
 | |
| 			const hawk_uch_t* x = str;
 | |
| 			const hawk_uch_t* y = sub;
 | |
| 
 | |
| 			while (1)
 | |
| 			{
 | |
| 				if (y >= subp) return (hawk_uch_t*)str;
 | |
| 				if (*x != *y) break;
 | |
| 				x++; y++;
 | |
| 			}
 | |
| 
 | |
| 			str++;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_find_bchars_in_bchars (const hawk_bch_t* str, hawk_oow_t strsz, const hawk_bch_t* sub, hawk_oow_t subsz, int ignorecase)
 | |
| {
 | |
| 	const hawk_bch_t* end, * subp;
 | |
| 
 | |
| 	if (subsz == 0) return (hawk_bch_t*)str;
 | |
| 	if (strsz < subsz) return HAWK_NULL;
 | |
| 
 | |
| 	end = str + strsz - subsz;
 | |
| 	subp = sub + subsz;
 | |
| 
 | |
| 	if (HAWK_UNLIKELY(ignorecase))
 | |
| 	{
 | |
| 		while (str <= end)
 | |
| 		{
 | |
| 			const hawk_bch_t* x = str;
 | |
| 			const hawk_bch_t* y = sub;
 | |
| 
 | |
| 			while (1)
 | |
| 			{
 | |
| 				if (y >= subp) return (hawk_bch_t*)str;
 | |
| 				if (hawk_to_bch_lower(*x) != hawk_to_bch_lower(*y)) break;
 | |
| 				x++; y++;
 | |
| 			}
 | |
| 
 | |
| 			str++;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		while (str <= end)
 | |
| 		{
 | |
| 			const hawk_bch_t* x = str;
 | |
| 			const hawk_bch_t* y = sub;
 | |
| 
 | |
| 			while (1)
 | |
| 			{
 | |
| 				if (y >= subp) return (hawk_bch_t*)str;
 | |
| 				if (*x != *y) break;
 | |
| 				x++; y++;
 | |
| 			}
 | |
| 
 | |
| 			str++;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_uch_t* hawk_rfind_uchars_in_uchars (const hawk_uch_t* str, hawk_oow_t strsz, const hawk_uch_t* sub, hawk_oow_t subsz, int ignorecase)
 | |
| {
 | |
| 	const hawk_uch_t* p = str + strsz;
 | |
| 	const hawk_uch_t* subp = sub + subsz;
 | |
| 
 | |
| 	if (subsz == 0) return (hawk_uch_t*)p;
 | |
| 	if (strsz < subsz) return HAWK_NULL;
 | |
| 
 | |
| 	p = p - subsz;
 | |
| 
 | |
| 	if (HAWK_UNLIKELY(ignorecase))
 | |
| 	{
 | |
| 		while (p >= str)
 | |
| 		{
 | |
| 			const hawk_uch_t* x = p;
 | |
| 			const hawk_uch_t* y = sub;
 | |
| 
 | |
| 			while (1)
 | |
| 			{
 | |
| 				if (y >= subp) return (hawk_uch_t*)p;
 | |
| 				if (hawk_to_uch_lower(*x) != hawk_to_uch_lower(*y)) break;
 | |
| 				x++; y++;
 | |
| 			}
 | |
| 
 | |
| 			p--;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		while (p >= str)
 | |
| 		{
 | |
| 			const hawk_uch_t* x = p;
 | |
| 			const hawk_uch_t* y = sub;
 | |
| 
 | |
| 			while (1)
 | |
| 			{
 | |
| 				if (y >= subp) return (hawk_uch_t*)p;
 | |
| 				if (*x != *y) break;
 | |
| 				x++; y++;
 | |
| 			}
 | |
| 
 | |
| 			p--;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_rfind_bchars_in_bchars (const hawk_bch_t* str, hawk_oow_t strsz, const hawk_bch_t* sub, hawk_oow_t subsz, int ignorecase)
 | |
| {
 | |
| 	const hawk_bch_t* p = str + strsz;
 | |
| 	const hawk_bch_t* subp = sub + subsz;
 | |
| 
 | |
| 	if (subsz == 0) return (hawk_bch_t*)p;
 | |
| 	if (strsz < subsz) return HAWK_NULL;
 | |
| 
 | |
| 	p = p - subsz;
 | |
| 
 | |
| 	if (HAWK_UNLIKELY(ignorecase))
 | |
| 	{
 | |
| 		while (p >= str)
 | |
| 		{
 | |
| 			const hawk_bch_t* x = p;
 | |
| 			const hawk_bch_t* y = sub;
 | |
| 
 | |
| 			while (1)
 | |
| 			{
 | |
| 				if (y >= subp) return (hawk_bch_t*)p;
 | |
| 				if (hawk_to_bch_lower(*x) != hawk_to_bch_lower(*y)) break;
 | |
| 				x++; y++;
 | |
| 			}
 | |
| 
 | |
| 			p--;
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		while (p >= str)
 | |
| 		{
 | |
| 			const hawk_bch_t* x = p;
 | |
| 			const hawk_bch_t* y = sub;
 | |
| 
 | |
| 			while (1)
 | |
| 			{
 | |
| 				if (y >= subp) return (hawk_bch_t*)p;
 | |
| 				if (*x != *y) break;
 | |
| 				x++; y++;
 | |
| 			}
 | |
| 
 | |
| 			p--;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_compact_uchars (hawk_uch_t* str, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_uch_t* p = str, * q = str, * end = str + len;
 | |
| 	int followed_by_space = 0;
 | |
| 	int state = 0;
 | |
| 
 | |
| 	while (p < end)
 | |
| 	{
 | |
| 		if (state == 0)
 | |
| 		{
 | |
| 			if (!hawk_is_uch_space(*p))
 | |
| 			{
 | |
| 				*q++ = *p;
 | |
| 				state = 1;
 | |
| 			}
 | |
| 		}
 | |
| 		else if (state == 1)
 | |
| 		{
 | |
| 			if (hawk_is_uch_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);
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_compact_bchars (hawk_bch_t* str, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_bch_t* p = str, * q = str, * end = str + len;
 | |
| 	int followed_by_space = 0;
 | |
| 	int state = 0;
 | |
| 
 | |
| 	while (p < end)
 | |
| 	{
 | |
| 		if (state == 0)
 | |
| 		{
 | |
| 			if (!hawk_is_bch_space(*p))
 | |
| 			{
 | |
| 				*q++ = *p;
 | |
| 				state = 1;
 | |
| 			}
 | |
| 		}
 | |
| 		else if (state == 1)
 | |
| 		{
 | |
| 			if (hawk_is_bch_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);
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_rotate_uchars (hawk_uch_t* str, hawk_oow_t len, int dir, hawk_oow_t n)
 | |
| {
 | |
| 	hawk_oow_t first, last, count, index, nk;
 | |
| 	hawk_uch_t 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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_rotate_bchars (hawk_bch_t* str, hawk_oow_t len, int dir, hawk_oow_t n)
 | |
| {
 | |
| 	hawk_oow_t first, last, count, index, nk;
 | |
| 	hawk_bch_t 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;
 | |
| }
 | |
| 
 | |
| hawk_uch_t* hawk_trim_uchars (const hawk_uch_t* str, hawk_oow_t* len, int flags)
 | |
| {
 | |
| 	const hawk_uch_t* p = str, * end = str + *len;
 | |
| 
 | |
| 	if (p < end)
 | |
| 	{
 | |
| 		const hawk_uch_t* s = HAWK_NULL, * e = HAWK_NULL;
 | |
| 
 | |
| 		do
 | |
| 		{
 | |
| 			if (!hawk_is_uch_space(*p))
 | |
| 			{
 | |
| 				if (s == HAWK_NULL) s = p;
 | |
| 				e = p;
 | |
| 			}
 | |
| 			p++;
 | |
| 		}
 | |
| 		while (p < end);
 | |
| 
 | |
| 		if (e)
 | |
| 		{
 | |
| 			if (flags & HAWK_TRIM_UCHARS_RIGHT)
 | |
| 			{
 | |
| 				*len -= end - e - 1;
 | |
| 			}
 | |
| 			if (flags & HAWK_TRIM_UCHARS_LEFT)
 | |
| 			{
 | |
| 				*len -= s - str;
 | |
| 				str = s;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			/* the entire string need to be deleted */
 | |
| 			if ((flags & HAWK_TRIM_UCHARS_RIGHT) ||
 | |
| 			    (flags & HAWK_TRIM_UCHARS_LEFT)) *len = 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return (hawk_uch_t*)str;
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_trim_bchars (const hawk_bch_t* str, hawk_oow_t* len, int flags)
 | |
| {
 | |
| 	const hawk_bch_t* p = str, * end = str + *len;
 | |
| 
 | |
| 	if (p < end)
 | |
| 	{
 | |
| 		const hawk_bch_t* s = HAWK_NULL, * e = HAWK_NULL;
 | |
| 
 | |
| 		do
 | |
| 		{
 | |
| 			if (!hawk_is_bch_space(*p))
 | |
| 			{
 | |
| 				if (s == HAWK_NULL) s = p;
 | |
| 				e = p;
 | |
| 			}
 | |
| 			p++;
 | |
| 		}
 | |
| 		while (p < end);
 | |
| 
 | |
| 		if (e)
 | |
| 		{
 | |
| 			if (flags & HAWK_TRIM_BCHARS_RIGHT)
 | |
| 			{
 | |
| 				*len -= end - e - 1;
 | |
| 			}
 | |
| 			if (flags & HAWK_TRIM_BCHARS_LEFT)
 | |
| 			{
 | |
| 				*len -= s - str;
 | |
| 				str = s;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			/* the entire string need to be deleted */
 | |
| 			if ((flags & HAWK_TRIM_BCHARS_RIGHT) ||
 | |
| 			    (flags & HAWK_TRIM_BCHARS_LEFT)) *len = 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return (hawk_bch_t*)str;
 | |
| }
 | |
| 
 | |
| int hawk_split_ucstr (hawk_uch_t* s, const hawk_uch_t* delim, hawk_uch_t lquote, hawk_uch_t rquote, hawk_uch_t escape)
 | |
| {
 | |
| 	hawk_uch_t* p = s, *d;
 | |
| 	hawk_uch_t* sp = HAWK_NULL, * ep = HAWK_NULL;
 | |
| 	int delim_mode;
 | |
| 	int cnt = 0;
 | |
| 
 | |
| 	if (delim == HAWK_NULL) delim_mode = 0;
 | |
| 	else
 | |
| 	{
 | |
| 		delim_mode = 1;
 | |
| 		for (d = (hawk_uch_t*)delim; *d != '\0'; d++)
 | |
| 			if (!hawk_is_uch_space(*d)) delim_mode = 2;
 | |
| 	}
 | |
| 
 | |
| 	if (delim_mode == 0)
 | |
| 	{
 | |
| 		/* skip preceding space characters */
 | |
| 		while (hawk_is_uch_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)
 | |
| 		{
 | |
| 			hawk_copy_ucstr_unlimited (p, p + 1);
 | |
| 
 | |
| 			for (;;)
 | |
| 			{
 | |
| 				if (*p == '\0') return -1;
 | |
| 
 | |
| 				if (escape != '\0' && *p == escape)
 | |
| 				{
 | |
| 					hawk_copy_ucstr_unlimited (p, p + 1);
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					if (*p == rquote)
 | |
| 					{
 | |
| 						p++;
 | |
| 						break;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				if (sp == 0) sp = p;
 | |
| 				ep = p;
 | |
| 				p++;
 | |
| 			}
 | |
| 			while (hawk_is_uch_space(*p)) p++;
 | |
| 			if (*p != '\0') return -1;
 | |
| 
 | |
| 			if (sp == 0 && ep == 0) s[0] = '\0';
 | |
| 			else
 | |
| 			{
 | |
| 				ep[1] = '\0';
 | |
| 				if (s != (hawk_uch_t*)sp) hawk_copy_ucstr_unlimited (s, sp);
 | |
| 				cnt++;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			while (*p)
 | |
| 			{
 | |
| 				if (!hawk_is_uch_space(*p))
 | |
| 				{
 | |
| 					if (sp == 0) sp = p;
 | |
| 					ep = p;
 | |
| 				}
 | |
| 				p++;
 | |
| 			}
 | |
| 
 | |
| 			if (sp == 0 && ep == 0) s[0] = '\0';
 | |
| 			else
 | |
| 			{
 | |
| 				ep[1] = '\0';
 | |
| 				if (s != (hawk_uch_t*)sp) hawk_copy_ucstr_unlimited (s, sp);
 | |
| 				cnt++;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else if (delim_mode == 1)
 | |
| 	{
 | |
| 		hawk_uch_t* o;
 | |
| 
 | |
| 		while (*p)
 | |
| 		{
 | |
| 			o = p;
 | |
| 			while (hawk_is_uch_space(*p)) p++;
 | |
| 			if (o != p) { hawk_copy_ucstr_unlimited (o, p); p = o; }
 | |
| 
 | |
| 			if (lquote != '\0' && *p == lquote)
 | |
| 			{
 | |
| 				hawk_copy_ucstr_unlimited (p, p + 1);
 | |
| 
 | |
| 				for (;;)
 | |
| 				{
 | |
| 					if (*p == '\0') return -1;
 | |
| 
 | |
| 					if (escape != '\0' && *p == escape)
 | |
| 					{
 | |
| 						hawk_copy_ucstr_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 (hawk_is_uch_space(*p))
 | |
| 					{
 | |
| 						*p++ = '\0';
 | |
| 						cnt++;
 | |
| 						break;
 | |
| 					}
 | |
| 					p++;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else /* if (delim_mode == 2) */
 | |
| 	{
 | |
| 		hawk_uch_t* o;
 | |
| 		int ok;
 | |
| 
 | |
| 		while (*p != '\0')
 | |
| 		{
 | |
| 			o = p;
 | |
| 			while (hawk_is_uch_space(*p)) p++;
 | |
| 			if (o != p) { hawk_copy_ucstr_unlimited (o, p); p = o; }
 | |
| 
 | |
| 			if (lquote != '\0' && *p == lquote)
 | |
| 			{
 | |
| 				hawk_copy_ucstr_unlimited (p, p + 1);
 | |
| 
 | |
| 				for (;;)
 | |
| 				{
 | |
| 					if (*p == '\0') return -1;
 | |
| 
 | |
| 					if (escape != '\0' && *p == escape)
 | |
| 					{
 | |
| 						hawk_copy_ucstr_unlimited (p, p + 1);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if (*p == rquote)
 | |
| 						{
 | |
| 							*p++ = '\0';
 | |
| 							cnt++;
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 					p++;
 | |
| 				}
 | |
| 
 | |
| 				ok = 0;
 | |
| 				while (hawk_is_uch_space(*p)) p++;
 | |
| 				if (*p == '\0') ok = 1;
 | |
| 				for (d = (hawk_uch_t*)delim; *d != '\0'; d++)
 | |
| 				{
 | |
| 					if (*p == *d)
 | |
| 					{
 | |
| 						ok = 1;
 | |
| 						hawk_copy_ucstr_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 = (hawk_uch_t*)delim; *d != '\0'; d++)
 | |
| 					{
 | |
| 						if (*p == *d)
 | |
| 						{
 | |
| 							if (sp == HAWK_NULL)
 | |
| 							{
 | |
| 								hawk_copy_ucstr_unlimited (o, p); p = o;
 | |
| 								*p++ = '\0';
 | |
| 							}
 | |
| 							else
 | |
| 							{
 | |
| 								hawk_copy_ucstr_unlimited (&ep[1], p);
 | |
| 								hawk_copy_ucstr_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 (!hawk_is_uch_space(*p))
 | |
| 					{
 | |
| 						if (sp == HAWK_NULL) sp = p;
 | |
| 						ep = p;
 | |
| 					}
 | |
| 					p++;
 | |
| 				}
 | |
| exit_point:
 | |
| 				;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return cnt;
 | |
| }
 | |
| 
 | |
| int hawk_split_bcstr (hawk_bch_t* s, const hawk_bch_t* delim, hawk_bch_t lquote, hawk_bch_t rquote, hawk_bch_t escape)
 | |
| {
 | |
| 	hawk_bch_t* p = s, *d;
 | |
| 	hawk_bch_t* sp = HAWK_NULL, * ep = HAWK_NULL;
 | |
| 	int delim_mode;
 | |
| 	int cnt = 0;
 | |
| 
 | |
| 	if (delim == HAWK_NULL) delim_mode = 0;
 | |
| 	else
 | |
| 	{
 | |
| 		delim_mode = 1;
 | |
| 		for (d = (hawk_bch_t*)delim; *d != '\0'; d++)
 | |
| 			if (!hawk_is_bch_space(*d)) delim_mode = 2;
 | |
| 	}
 | |
| 
 | |
| 	if (delim_mode == 0)
 | |
| 	{
 | |
| 		/* skip preceding space characters */
 | |
| 		while (hawk_is_bch_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)
 | |
| 		{
 | |
| 			hawk_copy_bcstr_unlimited (p, p + 1);
 | |
| 
 | |
| 			for (;;)
 | |
| 			{
 | |
| 				if (*p == '\0') return -1;
 | |
| 
 | |
| 				if (escape != '\0' && *p == escape)
 | |
| 				{
 | |
| 					hawk_copy_bcstr_unlimited (p, p + 1);
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					if (*p == rquote)
 | |
| 					{
 | |
| 						p++;
 | |
| 						break;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				if (sp == 0) sp = p;
 | |
| 				ep = p;
 | |
| 				p++;
 | |
| 			}
 | |
| 			while (hawk_is_bch_space(*p)) p++;
 | |
| 			if (*p != '\0') return -1;
 | |
| 
 | |
| 			if (sp == 0 && ep == 0) s[0] = '\0';
 | |
| 			else
 | |
| 			{
 | |
| 				ep[1] = '\0';
 | |
| 				if (s != (hawk_bch_t*)sp) hawk_copy_bcstr_unlimited (s, sp);
 | |
| 				cnt++;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			while (*p)
 | |
| 			{
 | |
| 				if (!hawk_is_bch_space(*p))
 | |
| 				{
 | |
| 					if (sp == 0) sp = p;
 | |
| 					ep = p;
 | |
| 				}
 | |
| 				p++;
 | |
| 			}
 | |
| 
 | |
| 			if (sp == 0 && ep == 0) s[0] = '\0';
 | |
| 			else
 | |
| 			{
 | |
| 				ep[1] = '\0';
 | |
| 				if (s != (hawk_bch_t*)sp) hawk_copy_bcstr_unlimited (s, sp);
 | |
| 				cnt++;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else if (delim_mode == 1)
 | |
| 	{
 | |
| 		hawk_bch_t* o;
 | |
| 
 | |
| 		while (*p)
 | |
| 		{
 | |
| 			o = p;
 | |
| 			while (hawk_is_bch_space(*p)) p++;
 | |
| 			if (o != p) { hawk_copy_bcstr_unlimited (o, p); p = o; }
 | |
| 
 | |
| 			if (lquote != '\0' && *p == lquote)
 | |
| 			{
 | |
| 				hawk_copy_bcstr_unlimited (p, p + 1);
 | |
| 
 | |
| 				for (;;)
 | |
| 				{
 | |
| 					if (*p == '\0') return -1;
 | |
| 
 | |
| 					if (escape != '\0' && *p == escape)
 | |
| 					{
 | |
| 						hawk_copy_bcstr_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 (hawk_is_bch_space(*p))
 | |
| 					{
 | |
| 						*p++ = '\0';
 | |
| 						cnt++;
 | |
| 						break;
 | |
| 					}
 | |
| 					p++;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else /* if (delim_mode == 2) */
 | |
| 	{
 | |
| 		hawk_bch_t* o;
 | |
| 		int ok;
 | |
| 
 | |
| 		while (*p != '\0')
 | |
| 		{
 | |
| 			o = p;
 | |
| 			while (hawk_is_bch_space(*p)) p++;
 | |
| 			if (o != p) { hawk_copy_bcstr_unlimited (o, p); p = o; }
 | |
| 
 | |
| 			if (lquote != '\0' && *p == lquote)
 | |
| 			{
 | |
| 				hawk_copy_bcstr_unlimited (p, p + 1);
 | |
| 
 | |
| 				for (;;)
 | |
| 				{
 | |
| 					if (*p == '\0') return -1;
 | |
| 
 | |
| 					if (escape != '\0' && *p == escape)
 | |
| 					{
 | |
| 						hawk_copy_bcstr_unlimited (p, p + 1);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if (*p == rquote)
 | |
| 						{
 | |
| 							*p++ = '\0';
 | |
| 							cnt++;
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 					p++;
 | |
| 				}
 | |
| 
 | |
| 				ok = 0;
 | |
| 				while (hawk_is_bch_space(*p)) p++;
 | |
| 				if (*p == '\0') ok = 1;
 | |
| 				for (d = (hawk_bch_t*)delim; *d != '\0'; d++)
 | |
| 				{
 | |
| 					if (*p == *d)
 | |
| 					{
 | |
| 						ok = 1;
 | |
| 						hawk_copy_bcstr_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 = (hawk_bch_t*)delim; *d != '\0'; d++)
 | |
| 					{
 | |
| 						if (*p == *d)
 | |
| 						{
 | |
| 							if (sp == HAWK_NULL)
 | |
| 							{
 | |
| 								hawk_copy_bcstr_unlimited (o, p); p = o;
 | |
| 								*p++ = '\0';
 | |
| 							}
 | |
| 							else
 | |
| 							{
 | |
| 								hawk_copy_bcstr_unlimited (&ep[1], p);
 | |
| 								hawk_copy_bcstr_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 (!hawk_is_bch_space(*p))
 | |
| 					{
 | |
| 						if (sp == HAWK_NULL) sp = p;
 | |
| 						ep = p;
 | |
| 					}
 | |
| 					p++;
 | |
| 				}
 | |
| exit_point:
 | |
| 				;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return cnt;
 | |
| }
 | |
| 
 | |
| hawk_uch_t* hawk_tokenize_uchars (const hawk_uch_t* s, hawk_oow_t len, const hawk_uch_t* delim, hawk_oow_t delim_len, hawk_ucs_t* tok, int ignorecase)
 | |
| {
 | |
| 	const hawk_uch_t* p = s, *d;
 | |
| 	const hawk_uch_t* end = s + len;
 | |
| 	const hawk_uch_t* sp = HAWK_NULL, * ep = HAWK_NULL;
 | |
| 	const hawk_uch_t* delim_end = delim + delim_len;
 | |
| 	hawk_uch_t 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 == HAWK_NULL) delim_mode = __DELIM_NULL;
 | |
| 	else
 | |
| 	{
 | |
| 		delim_mode = __DELIM_EMPTY;
 | |
| 
 | |
| 		for (d = delim; d < delim_end; d++)
 | |
| 		{
 | |
| 			if (hawk_is_uch_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 HAWK_NULL is given as "delim", it trims off the
 | |
| 		 * leading and trailing spaces characters off the source
 | |
| 		 * string "s" eventually. */
 | |
| 
 | |
| 		while (p < end && hawk_is_uch_space(*p)) p++;
 | |
| 		while (p < end)
 | |
| 		{
 | |
| 			c = *p;
 | |
| 
 | |
| 			if (!hawk_is_uch_space(c))
 | |
| 			{
 | |
| 				if (sp == HAWK_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 && hawk_is_uch_space(*p)) p++;
 | |
| 		while (p < end)
 | |
| 		{
 | |
| 			c = *p;
 | |
| 			if (hawk_is_uch_space(c)) break;
 | |
| 			if (sp == HAWK_NULL) sp = p;
 | |
| 			ep = p++;
 | |
| 		}
 | |
| 		while (p < end && hawk_is_uch_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 = hawk_to_uch_lower(*p);
 | |
| 				for (d = delim; d < delim_end; d++)
 | |
| 				{
 | |
| 					if (c == hawk_to_uch_lower(*d)) goto exit_loop;
 | |
| 				}
 | |
| 
 | |
| 				if (sp == HAWK_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 == HAWK_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 && hawk_is_uch_space(*p)) p++;
 | |
| 		if (ignorecase)
 | |
| 		{
 | |
| 			while (p < end)
 | |
| 			{
 | |
| 				c = hawk_to_uch_lower(*p);
 | |
| 				if (hawk_is_uch_space(c))
 | |
| 				{
 | |
| 					p++;
 | |
| 					continue;
 | |
| 				}
 | |
| 				for (d = delim; d < delim_end; d++)
 | |
| 				{
 | |
| 					if (c == hawk_to_uch_lower(*d)) goto exit_loop;
 | |
| 				}
 | |
| 				if (sp == HAWK_NULL) sp = p;
 | |
| 				ep = p++;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			while (p < end)
 | |
| 			{
 | |
| 				c = *p;
 | |
| 				if (hawk_is_uch_space(c))
 | |
| 				{
 | |
| 					p++;
 | |
| 					continue;
 | |
| 				}
 | |
| 				for (d = delim; d < delim_end; d++)
 | |
| 				{
 | |
| 					if (c == *d) goto exit_loop;
 | |
| 				}
 | |
| 				if (sp == HAWK_NULL) sp = p;
 | |
| 				ep = p++;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| exit_loop:
 | |
| 	if (sp == HAWK_NULL)
 | |
| 	{
 | |
| 		tok->ptr = HAWK_NULL;
 | |
| 		tok->len = (hawk_oow_t)0;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		tok->ptr = (hawk_uch_t*)sp;
 | |
| 		tok->len = ep - sp + 1;
 | |
| 	}
 | |
| 
 | |
| 	/* if HAWK_NULL is returned, this function should not be called again */
 | |
| 	if (p >= end) return HAWK_NULL;
 | |
| 	if (delim_mode == __DELIM_EMPTY || delim_mode == __DELIM_SPACES) return (hawk_uch_t*)p;
 | |
| 	return (hawk_uch_t*)++p;
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_tokenize_bchars (const hawk_bch_t* s, hawk_oow_t len, const hawk_bch_t* delim, hawk_oow_t delim_len, hawk_bcs_t* tok, int ignorecase)
 | |
| {
 | |
| 	const hawk_bch_t* p = s, *d;
 | |
| 	const hawk_bch_t* end = s + len;
 | |
| 	const hawk_bch_t* sp = HAWK_NULL, * ep = HAWK_NULL;
 | |
| 	const hawk_bch_t* delim_end = delim + delim_len;
 | |
| 	hawk_bch_t 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 == HAWK_NULL) delim_mode = __DELIM_NULL;
 | |
| 	else
 | |
| 	{
 | |
| 		delim_mode = __DELIM_EMPTY;
 | |
| 
 | |
| 		for (d = delim; d < delim_end; d++)
 | |
| 		{
 | |
| 			if (hawk_is_bch_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 HAWK_NULL is given as "delim", it trims off the
 | |
| 		 * leading and trailing spaces characters off the source
 | |
| 		 * string "s" eventually. */
 | |
| 
 | |
| 		while (p < end && hawk_is_bch_space(*p)) p++;
 | |
| 		while (p < end)
 | |
| 		{
 | |
| 			c = *p;
 | |
| 
 | |
| 			if (!hawk_is_bch_space(c))
 | |
| 			{
 | |
| 				if (sp == HAWK_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 && hawk_is_bch_space(*p)) p++;
 | |
| 		while (p < end)
 | |
| 		{
 | |
| 			c = *p;
 | |
| 			if (hawk_is_bch_space(c)) break;
 | |
| 			if (sp == HAWK_NULL) sp = p;
 | |
| 			ep = p++;
 | |
| 		}
 | |
| 		while (p < end && hawk_is_bch_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 = hawk_to_bch_lower(*p);
 | |
| 				for (d = delim; d < delim_end; d++)
 | |
| 				{
 | |
| 					if (c == hawk_to_bch_lower(*d)) goto exit_loop;
 | |
| 				}
 | |
| 
 | |
| 				if (sp == HAWK_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 == HAWK_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 && hawk_is_bch_space(*p)) p++;
 | |
| 		if (ignorecase)
 | |
| 		{
 | |
| 			while (p < end)
 | |
| 			{
 | |
| 				c = hawk_to_bch_lower(*p);
 | |
| 				if (hawk_is_bch_space(c))
 | |
| 				{
 | |
| 					p++;
 | |
| 					continue;
 | |
| 				}
 | |
| 				for (d = delim; d < delim_end; d++)
 | |
| 				{
 | |
| 					if (c == hawk_to_bch_lower(*d)) goto exit_loop;
 | |
| 				}
 | |
| 				if (sp == HAWK_NULL) sp = p;
 | |
| 				ep = p++;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			while (p < end)
 | |
| 			{
 | |
| 				c = *p;
 | |
| 				if (hawk_is_bch_space(c))
 | |
| 				{
 | |
| 					p++;
 | |
| 					continue;
 | |
| 				}
 | |
| 				for (d = delim; d < delim_end; d++)
 | |
| 				{
 | |
| 					if (c == *d) goto exit_loop;
 | |
| 				}
 | |
| 				if (sp == HAWK_NULL) sp = p;
 | |
| 				ep = p++;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| exit_loop:
 | |
| 	if (sp == HAWK_NULL)
 | |
| 	{
 | |
| 		tok->ptr = HAWK_NULL;
 | |
| 		tok->len = (hawk_oow_t)0;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		tok->ptr = (hawk_bch_t*)sp;
 | |
| 		tok->len = ep - sp + 1;
 | |
| 	}
 | |
| 
 | |
| 	/* if HAWK_NULL is returned, this function should not be called again */
 | |
| 	if (p >= end) return HAWK_NULL;
 | |
| 	if (delim_mode == __DELIM_EMPTY || delim_mode == __DELIM_SPACES) return (hawk_bch_t*)p;
 | |
| 	return (hawk_bch_t*)++p;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_byte_to_ucstr (hawk_uint8_t byte, hawk_uch_t* buf, hawk_oow_t size, int flagged_radix, hawk_uch_t fill)
 | |
| {
 | |
| 	hawk_uch_t tmp[(HAWK_SIZEOF(hawk_uint8_t) * HAWK_BITS_PER_BYTE)];
 | |
| 	hawk_uch_t* p = tmp, * bp = buf, * be = buf + size - 1;
 | |
| 	int radix;
 | |
| 	hawk_uch_t radix_char;
 | |
| 
 | |
| 	radix = (flagged_radix & HAWK_BYTE_TO_UCSTR_RADIXMASK);
 | |
| 	radix_char = (flagged_radix & HAWK_BYTE_TO_UCSTR_LOWERCASE)? 'a': 'A';
 | |
| 	if (radix < 2 || radix > 36 || size <= 0) return 0;
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		hawk_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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_byte_to_bcstr (hawk_uint8_t byte, hawk_bch_t* buf, hawk_oow_t size, int flagged_radix, hawk_bch_t fill)
 | |
| {
 | |
| 	hawk_bch_t tmp[(HAWK_SIZEOF(hawk_uint8_t) * HAWK_BITS_PER_BYTE)];
 | |
| 	hawk_bch_t* p = tmp, * bp = buf, * be = buf + size - 1;
 | |
| 	int radix;
 | |
| 	hawk_bch_t radix_char;
 | |
| 
 | |
| 	radix = (flagged_radix & HAWK_BYTE_TO_BCSTR_RADIXMASK);
 | |
| 	radix_char = (flagged_radix & HAWK_BYTE_TO_BCSTR_LOWERCASE)? 'a': 'A';
 | |
| 	if (radix < 2 || radix > 36 || size <= 0) return 0;
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		hawk_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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_int_to_ucstr (hawk_int_t value, int radix, const hawk_uch_t* prefix, hawk_uch_t* buf, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_int_t t, rem;
 | |
| 	hawk_oow_t len, ret, i;
 | |
| 	hawk_oow_t prefix_len;
 | |
| 
 | |
| 	prefix_len = (prefix != HAWK_NULL)? hawk_count_ucstr(prefix): 0;
 | |
| 
 | |
| 	t = value;
 | |
| 	if (t == 0)
 | |
| 	{
 | |
| 		/* zero */
 | |
| 		if (buf == HAWK_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 (hawk_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 == HAWK_NULL)
 | |
| 	{
 | |
| 		/* if buf is not given, return the number of bytes required */
 | |
| 		return len;
 | |
| 	}
 | |
| 
 | |
| 	if (size < len) return (hawk_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] = (hawk_uch_t)rem + 'a' - 10;
 | |
| 		else
 | |
| 			buf[--len] = (hawk_uch_t)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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_int_to_bcstr (hawk_int_t value, int radix, const hawk_bch_t* prefix, hawk_bch_t* buf, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_int_t t, rem;
 | |
| 	hawk_oow_t len, ret, i;
 | |
| 	hawk_oow_t prefix_len;
 | |
| 
 | |
| 	prefix_len = (prefix != HAWK_NULL)? hawk_count_bcstr(prefix): 0;
 | |
| 
 | |
| 	t = value;
 | |
| 	if (t == 0)
 | |
| 	{
 | |
| 		/* zero */
 | |
| 		if (buf == HAWK_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 (hawk_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 == HAWK_NULL)
 | |
| 	{
 | |
| 		/* if buf is not given, return the number of bytes required */
 | |
| 		return len;
 | |
| 	}
 | |
| 
 | |
| 	if (size < len) return (hawk_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] = (hawk_bch_t)rem + 'a' - 10;
 | |
| 		else
 | |
| 			buf[--len] = (hawk_bch_t)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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_uint_to_ucstr (hawk_uint_t value, int radix, const hawk_uch_t* prefix, hawk_uch_t* buf, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_uint_t t, rem;
 | |
| 	hawk_oow_t len, ret, i;
 | |
| 	hawk_oow_t prefix_len;
 | |
| 
 | |
| 	prefix_len = (prefix != HAWK_NULL)? hawk_count_ucstr(prefix): 0;
 | |
| 
 | |
| 	t = value;
 | |
| 	if (t == 0)
 | |
| 	{
 | |
| 		/* zero */
 | |
| 		if (buf == HAWK_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 (hawk_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++; } not needed for an unsigned number */
 | |
| 	while (t > 0) { len++; t /= radix; }
 | |
| 
 | |
| 	if (buf == HAWK_NULL)
 | |
| 	{
 | |
| 		/* if buf is not given, return the number of bytes required */
 | |
| 		return len;
 | |
| 	}
 | |
| 
 | |
| 	if (size < len) return (hawk_oow_t)-1; /* buffer too small */
 | |
| 	if (size > len) buf[len] = '\0';
 | |
| 	ret = len;
 | |
| 
 | |
| 	t = value;
 | |
| 	/*if (t < 0) t = -t; not needed for an unsigned number */
 | |
| 
 | |
| 	while (t > 0)
 | |
| 	{
 | |
| 		rem = t % radix;
 | |
| 		if (rem >= 10)
 | |
| 			buf[--len] = (hawk_uch_t)rem + 'a' - 10;
 | |
| 		else
 | |
| 			buf[--len] = (hawk_uch_t)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;
 | |
| }
 | |
| 
 | |
| hawk_oow_t hawk_uint_to_bcstr (hawk_uint_t value, int radix, const hawk_bch_t* prefix, hawk_bch_t* buf, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_uint_t t, rem;
 | |
| 	hawk_oow_t len, ret, i;
 | |
| 	hawk_oow_t prefix_len;
 | |
| 
 | |
| 	prefix_len = (prefix != HAWK_NULL)? hawk_count_bcstr(prefix): 0;
 | |
| 
 | |
| 	t = value;
 | |
| 	if (t == 0)
 | |
| 	{
 | |
| 		/* zero */
 | |
| 		if (buf == HAWK_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 (hawk_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 == HAWK_NULL)
 | |
| 	{
 | |
| 		/* if buf is not given, return the number of bytes required */
 | |
| 		return len;
 | |
| 	}
 | |
| 
 | |
| 	if (size < len) return (hawk_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] = (hawk_bch_t)rem + 'a' - 10;
 | |
| 		else
 | |
| 			buf[--len] = (hawk_bch_t)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;
 | |
| }
 | |
| 
 | |
| hawk_int_t hawk_uchars_to_int (const hawk_uch_t* str, hawk_oow_t len, int option, const hawk_uch_t** endptr, int* is_sober)
 | |
| {
 | |
| 	hawk_int_t n = 0;
 | |
| 	const hawk_uch_t* p, * pp;
 | |
| 	const hawk_uch_t* end;
 | |
| 	hawk_oow_t rem;
 | |
| 	int digit, negative = 0;
 | |
| 	int base = HAWK_UCHARS_TO_INTMAX_GET_OPTION_BASE(option);
 | |
| 
 | |
| 	p = str;
 | |
| 	end = str + len;
 | |
| 
 | |
| 	if (HAWK_UCHARS_TO_INTMAX_GET_OPTION_LTRIM(option))
 | |
| 	{
 | |
| 		/* strip off leading spaces */
 | |
| 		while (p < end && hawk_is_uch_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 = HAWK_ZDIGIT_TO_NUM(*p, base);
 | |
| 		if (digit >= base) break;
 | |
| 		n = n * base + digit;
 | |
| 		p++;
 | |
| 	}
 | |
| 
 | |
| 	if (HAWK_UCHARS_TO_INTMAX_GET_OPTION_E(option))
 | |
| 	{
 | |
| 		if (*p == 'E' || *p == 'e')
 | |
| 		{
 | |
| 			hawk_int_t e = 0, i;
 | |
| 			int e_neg = 0;
 | |
| 			p++;
 | |
| 			if (*p == '+')
 | |
| 			{
 | |
| 				p++;
 | |
| 			}
 | |
| 			else if (*p == '-')
 | |
| 			{
 | |
| 				p++; e_neg = 1;
 | |
| 			}
 | |
| 			while (p < end)
 | |
| 			{
 | |
| 				digit = HAWK_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 (HAWK_UCHARS_TO_INTMAX_GET_OPTION_RTRIM(option))
 | |
| 	{
 | |
| 		/* consume trailing spaces */
 | |
| 		while (p < end && hawk_is_uch_space(*p)) p++;
 | |
| 	}
 | |
| 
 | |
| 	if (endptr) *endptr = p;
 | |
| 	return (negative)? -n: n;
 | |
| }
 | |
| 
 | |
| hawk_int_t hawk_bchars_to_int (const hawk_bch_t* str, hawk_oow_t len, int option, const hawk_bch_t** endptr, int* is_sober)
 | |
| {
 | |
| 	hawk_int_t n = 0;
 | |
| 	const hawk_bch_t* p, * pp;
 | |
| 	const hawk_bch_t* end;
 | |
| 	hawk_oow_t rem;
 | |
| 	int digit, negative = 0;
 | |
| 	int base = HAWK_BCHARS_TO_INTMAX_GET_OPTION_BASE(option);
 | |
| 
 | |
| 	p = str;
 | |
| 	end = str + len;
 | |
| 
 | |
| 	if (HAWK_BCHARS_TO_INTMAX_GET_OPTION_LTRIM(option))
 | |
| 	{
 | |
| 		/* strip off leading spaces */
 | |
| 		while (p < end && hawk_is_bch_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 = HAWK_ZDIGIT_TO_NUM(*p, base);
 | |
| 		if (digit >= base) break;
 | |
| 		n = n * base + digit;
 | |
| 		p++;
 | |
| 	}
 | |
| 
 | |
| 	if (HAWK_BCHARS_TO_INTMAX_GET_OPTION_E(option))
 | |
| 	{
 | |
| 		if (*p == 'E' || *p == 'e')
 | |
| 		{
 | |
| 			hawk_int_t e = 0, i;
 | |
| 			int e_neg = 0;
 | |
| 			p++;
 | |
| 			if (*p == '+')
 | |
| 			{
 | |
| 				p++;
 | |
| 			}
 | |
| 			else if (*p == '-')
 | |
| 			{
 | |
| 				p++; e_neg = 1;
 | |
| 			}
 | |
| 			while (p < end)
 | |
| 			{
 | |
| 				digit = HAWK_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 (HAWK_BCHARS_TO_INTMAX_GET_OPTION_RTRIM(option))
 | |
| 	{
 | |
| 		/* consume trailing spaces */
 | |
| 		while (p < end && hawk_is_bch_space(*p)) p++;
 | |
| 	}
 | |
| 
 | |
| 	if (endptr) *endptr = p;
 | |
| 	return (negative)? -n: n;
 | |
| }
 | |
| 
 | |
| hawk_uint_t hawk_uchars_to_uint (const hawk_uch_t* str, hawk_oow_t len, int option, const hawk_uch_t** endptr, int* is_sober)
 | |
| {
 | |
| 	hawk_uint_t n = 0;
 | |
| 	const hawk_uch_t* p, * pp;
 | |
| 	const hawk_uch_t* end;
 | |
| 	hawk_oow_t rem;
 | |
| 	int digit;
 | |
| 	int base = HAWK_UCHARS_TO_UINTMAX_GET_OPTION_BASE(option);
 | |
| 
 | |
| 	p = str;
 | |
| 	end = str + len;
 | |
| 
 | |
| 	if (HAWK_UCHARS_TO_UINTMAX_GET_OPTION_LTRIM(option))
 | |
| 	{
 | |
| 		/* strip off leading spaces */
 | |
| 		while (p < end && hawk_is_uch_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 = HAWK_ZDIGIT_TO_NUM(*p, base);
 | |
| 		if (digit >= base) break;
 | |
| 		n = n * base + digit;
 | |
| 		p++;
 | |
| 	}
 | |
| 
 | |
| 	if (HAWK_UCHARS_TO_UINTMAX_GET_OPTION_E(option))
 | |
| 	{
 | |
| 		if (*p == 'E' || *p == 'e')
 | |
| 		{
 | |
| 			hawk_uint_t e = 0, i;
 | |
| 			int e_neg = 0;
 | |
| 			p++;
 | |
| 			if (*p == '+')
 | |
| 			{
 | |
| 				p++;
 | |
| 			}
 | |
| 			else if (*p == '-')
 | |
| 			{
 | |
| 				p++; e_neg = 1;
 | |
| 			}
 | |
| 			while (p < end)
 | |
| 			{
 | |
| 				digit = HAWK_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 (HAWK_UCHARS_TO_UINTMAX_GET_OPTION_RTRIM(option))
 | |
| 	{
 | |
| 		/* consume trailing spaces */
 | |
| 		while (p < end && hawk_is_uch_space(*p)) p++;
 | |
| 	}
 | |
| 
 | |
| 	if (endptr) *endptr = p;
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| hawk_uint_t hawk_bchars_to_uint (const hawk_bch_t* str, hawk_oow_t len, int option, const hawk_bch_t** endptr, int* is_sober)
 | |
| {
 | |
| 	hawk_uint_t n = 0;
 | |
| 	const hawk_bch_t* p, * pp;
 | |
| 	const hawk_bch_t* end;
 | |
| 	hawk_oow_t rem;
 | |
| 	int digit;
 | |
| 	int base = HAWK_BCHARS_TO_UINTMAX_GET_OPTION_BASE(option);
 | |
| 
 | |
| 	p = str;
 | |
| 	end = str + len;
 | |
| 
 | |
| 	if (HAWK_BCHARS_TO_UINTMAX_GET_OPTION_LTRIM(option))
 | |
| 	{
 | |
| 		/* strip off leading spaces */
 | |
| 		while (p < end && hawk_is_bch_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 = HAWK_ZDIGIT_TO_NUM(*p, base);
 | |
| 		if (digit >= base) break;
 | |
| 		n = n * base + digit;
 | |
| 		p++;
 | |
| 	}
 | |
| 
 | |
| 	if (HAWK_BCHARS_TO_UINTMAX_GET_OPTION_E(option))
 | |
| 	{
 | |
| 		if (*p == 'E' || *p == 'e')
 | |
| 		{
 | |
| 			hawk_uint_t e = 0, i;
 | |
| 			int e_neg = 0;
 | |
| 			p++;
 | |
| 			if (*p == '+')
 | |
| 			{
 | |
| 				p++;
 | |
| 			}
 | |
| 			else if (*p == '-')
 | |
| 			{
 | |
| 				p++; e_neg = 1;
 | |
| 			}
 | |
| 			while (p < end)
 | |
| 			{
 | |
| 				digit = HAWK_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 (HAWK_BCHARS_TO_UINTMAX_GET_OPTION_RTRIM(option))
 | |
| 	{
 | |
| 		/* consume trailing spaces */
 | |
| 		while (p < end && hawk_is_bch_space(*p)) p++;
 | |
| 	}
 | |
| 
 | |
| 	if (endptr) *endptr = p;
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| int hawk_fnmat_uchars_i (const hawk_uch_t* str, hawk_oow_t slen, const hawk_uch_t* ptn, hawk_oow_t plen, int flags, int no_first_period)
 | |
| {
 | |
| 	const hawk_uch_t* sp = str;
 | |
| 	const hawk_uch_t* pp = ptn;
 | |
| 	const hawk_uch_t* se = str + slen;
 | |
| 	const hawk_uch_t* pe = ptn + plen;
 | |
| 	hawk_uch_t sc, pc, pc2;
 | |
| 
 | |
| 	while (1)
 | |
| 	{
 | |
| 		if (pp < pe && HAWK_FNMAT_IS_ESC(*pp) && !(flags & HAWK_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 & HAWK_FNMAT_IGNORECASE) != 0)
 | |
| 			{
 | |
| 				/* make characters to lower-case */
 | |
| 				sc = hawk_to_uch_lower(sc);
 | |
| 				pc = hawk_to_uch_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 & HAWK_FNMAT_PERIOD))
 | |
| 		{
 | |
| 			/*
 | |
| 			 * a leading period in the staring must match
 | |
| 			 * a period in the pattern explicitly
 | |
| 			 */
 | |
| 			if ((!no_first_period && sp == str) ||
 | |
| 			    (HAWK_FNMAT_IS_SEP(sp[-1]) && (flags & HAWK_FNMAT_PATHNAME)))
 | |
| 			{
 | |
| 				if (pc != '.') return 0;
 | |
| 				sp++; pp++;
 | |
| 				continue;
 | |
| 			}
 | |
| 		}
 | |
| 		else if (HAWK_FNMAT_IS_SEP(sc) && (flags & HAWK_FNMAT_PATHNAME))
 | |
| 		{
 | |
| 			while (pc == '*')
 | |
| 			{
 | |
| 				if ((++pp) >= pe) return 0;
 | |
| 				pc = *pp;
 | |
| 			}
 | |
| 
 | |
| 			/* a path separator must be matched explicitly */
 | |
| 			if (!HAWK_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 HAWK_FNMAT_PATHNAME is set.
 | |
| 				 */
 | |
| 				if (flags & HAWK_FNMAT_PATHNAME)
 | |
| 				{
 | |
| 					const hawk_uch_t* s = sp;
 | |
| 					for (s = sp; s < se; s++)
 | |
| 					{
 | |
| 						if (HAWK_FNMAT_IS_SEP(*s)) return 0;
 | |
| 					}
 | |
| 				}
 | |
| 				return 1;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				do
 | |
| 				{
 | |
| 					if (hawk_fnmat_uchars_i(sp, se - sp, pp, pe - pp, flags, 1)) return 1;
 | |
| 					if (HAWK_FNMAT_IS_SEP(*sp) && (flags & HAWK_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 == '[')
 | |
| 				{
 | |
| 					hawk_oow_t pl = pe - pp;
 | |
| 
 | |
| 					if (pl >= 9)  /* assumption that [:class:] is at least 9 in match_uch_class */
 | |
| 					{
 | |
| 						int x = match_uch_class(pp, sc, &matched);
 | |
| 						if (x > 0)
 | |
| 						{
 | |
| 							pp += x;
 | |
| 							continue;
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					/*
 | |
| 					 * characters in an invalid class name are
 | |
| 					 * just treated as normal characters
 | |
| 					 */
 | |
| 				}
 | |
| 
 | |
| 				if (HAWK_FNMAT_IS_ESC(*pp) && !(flags & HAWK_FNMAT_NOESCAPE)) pp++;
 | |
| 				else if (*pp == ']') break;
 | |
| 
 | |
| 				if (pp >= pe) break;
 | |
| 
 | |
| 				pc = *pp;
 | |
| 				if ((flags & HAWK_FNMAT_IGNORECASE) != 0)
 | |
| 				{
 | |
| 					sc = hawk_to_uch_lower(sc);
 | |
| 					pc = hawk_to_uch_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 (HAWK_FNMAT_IS_ESC(*pp) && !(flags & HAWK_FNMAT_NOESCAPE))
 | |
| 					{
 | |
| 						if ((++pp) >= pe)
 | |
| 						{
 | |
| 							if (sc >= pc) matched = 1;
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 					else if (*pp == ']')
 | |
| 					{
 | |
| 						if (sc >= pc) matched = 1;
 | |
| 						break;
 | |
| 					}
 | |
| 
 | |
| 					pc2 = *pp;
 | |
| 					if ((flags & HAWK_FNMAT_IGNORECASE) != 0)
 | |
| 						pc2 = hawk_to_uch_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 & HAWK_FNMAT_IGNORECASE) != 0)
 | |
| 			{
 | |
| 				sc = hawk_to_uch_lower(sc);
 | |
| 				pc = hawk_to_uch_lower(pc);
 | |
| 			}
 | |
| 
 | |
| 			if (sc != pc) return 0;
 | |
| 			sp++; pp++;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* will never reach here. but make some immature compilers happy... */
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int hawk_fnmat_bchars_i (const hawk_bch_t* str, hawk_oow_t slen, const hawk_bch_t* ptn, hawk_oow_t plen, int flags, int no_first_period)
 | |
| {
 | |
| 	const hawk_bch_t* sp = str;
 | |
| 	const hawk_bch_t* pp = ptn;
 | |
| 	const hawk_bch_t* se = str + slen;
 | |
| 	const hawk_bch_t* pe = ptn + plen;
 | |
| 	hawk_bch_t sc, pc, pc2;
 | |
| 
 | |
| 	while (1)
 | |
| 	{
 | |
| 		if (pp < pe && HAWK_FNMAT_IS_ESC(*pp) && !(flags & HAWK_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 & HAWK_FNMAT_IGNORECASE) != 0)
 | |
| 			{
 | |
| 				/* make characters to lower-case */
 | |
| 				sc = hawk_to_bch_lower(sc);
 | |
| 				pc = hawk_to_bch_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 & HAWK_FNMAT_PERIOD))
 | |
| 		{
 | |
| 			/*
 | |
| 			 * a leading period in the staring must match
 | |
| 			 * a period in the pattern explicitly
 | |
| 			 */
 | |
| 			if ((!no_first_period && sp == str) ||
 | |
| 			    (HAWK_FNMAT_IS_SEP(sp[-1]) && (flags & HAWK_FNMAT_PATHNAME)))
 | |
| 			{
 | |
| 				if (pc != '.') return 0;
 | |
| 				sp++; pp++;
 | |
| 				continue;
 | |
| 			}
 | |
| 		}
 | |
| 		else if (HAWK_FNMAT_IS_SEP(sc) && (flags & HAWK_FNMAT_PATHNAME))
 | |
| 		{
 | |
| 			while (pc == '*')
 | |
| 			{
 | |
| 				if ((++pp) >= pe) return 0;
 | |
| 				pc = *pp;
 | |
| 			}
 | |
| 
 | |
| 			/* a path separator must be matched explicitly */
 | |
| 			if (!HAWK_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 HAWK_FNMAT_PATHNAME is set.
 | |
| 				 */
 | |
| 				if (flags & HAWK_FNMAT_PATHNAME)
 | |
| 				{
 | |
| 					const hawk_bch_t* s = sp;
 | |
| 					for (s = sp; s < se; s++)
 | |
| 					{
 | |
| 						if (HAWK_FNMAT_IS_SEP(*s)) return 0;
 | |
| 					}
 | |
| 				}
 | |
| 				return 1;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				do
 | |
| 				{
 | |
| 					if (hawk_fnmat_bchars_i(sp, se - sp, pp, pe - pp, flags, 1)) return 1;
 | |
| 					if (HAWK_FNMAT_IS_SEP(*sp) && (flags & HAWK_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 == '[')
 | |
| 				{
 | |
| 					hawk_oow_t pl = pe - pp;
 | |
| 
 | |
| 					if (pl >= 9)  /* assumption that [:class:] is at least 9 in match_bch_class */
 | |
| 					{
 | |
| 						int x = match_bch_class(pp, sc, &matched);
 | |
| 						if (x > 0)
 | |
| 						{
 | |
| 							pp += x;
 | |
| 							continue;
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					/*
 | |
| 					 * characters in an invalid class name are
 | |
| 					 * just treated as normal characters
 | |
| 					 */
 | |
| 				}
 | |
| 
 | |
| 				if (HAWK_FNMAT_IS_ESC(*pp) && !(flags & HAWK_FNMAT_NOESCAPE)) pp++;
 | |
| 				else if (*pp == ']') break;
 | |
| 
 | |
| 				if (pp >= pe) break;
 | |
| 
 | |
| 				pc = *pp;
 | |
| 				if ((flags & HAWK_FNMAT_IGNORECASE) != 0)
 | |
| 				{
 | |
| 					sc = hawk_to_bch_lower(sc);
 | |
| 					pc = hawk_to_bch_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 (HAWK_FNMAT_IS_ESC(*pp) && !(flags & HAWK_FNMAT_NOESCAPE))
 | |
| 					{
 | |
| 						if ((++pp) >= pe)
 | |
| 						{
 | |
| 							if (sc >= pc) matched = 1;
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 					else if (*pp == ']')
 | |
| 					{
 | |
| 						if (sc >= pc) matched = 1;
 | |
| 						break;
 | |
| 					}
 | |
| 
 | |
| 					pc2 = *pp;
 | |
| 					if ((flags & HAWK_FNMAT_IGNORECASE) != 0)
 | |
| 						pc2 = hawk_to_bch_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 & HAWK_FNMAT_IGNORECASE) != 0)
 | |
| 			{
 | |
| 				sc = hawk_to_bch_lower(sc);
 | |
| 				pc = hawk_to_bch_lower(pc);
 | |
| 			}
 | |
| 
 | |
| 			if (sc != pc) return 0;
 | |
| 			sp++; pp++;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* will never reach here. but make some immature compilers happy... */
 | |
| 	return 0;
 | |
| }
 | |
| 
 |