/* tag: Tom Lord Tue Dec 4 14:41:42 2001 (unichar-str.c)
*/
/* unichar-str.c -
*
****************************************************************
* Copyright (C) 2000 Tom Lord
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "hackerlab/mem/mem.h"
#include "hackerlab/hash/hash-utils.h"
#include "hackerlab/unidata/unidata.h"
#include "hackerlab/unicode/unichar-str.h"
/************************************************************************
*(h1 "UTF-16 String Processing")
*
*
*
*/
/************************************************************************
*(h2 "String Length")
*
*
*
*/
/*(c unichar_str_length)
* size_t unichar_str_length (const t_unichar * x);
*
* Return the length of the 0-terminated string `x'. The length does
* not include the 0-byte itself.
*/
size_t
unichar_str_length (const t_unichar * x)
{
size_t q;
if (!x)
return 0;
q = 0;
while (*x)
++x, ++q;
return q;
}
/*(c unichar_str_length_n)
* size_t unichar_str_length_n (const t_unichar * x, size_t n);
*
* Return the length of the 0-terminated string `x' but not more than
* `n'. The length does not include the 0-byte itself.
*
* If `x' is longer than `n' code units, return `n'.
*/
size_t
unichar_str_length_n (const t_unichar * x, size_t n)
{
size_t q;
if (!x)
return 0;
q = 0;
while ((q < n) && *x)
++x, ++q;
return q;
}
/************************************************************************
*(h2 "Computing Hash Values From Strings")
*
*/
/*(c unichar_str_hash_n)
* unsigned long unichar_str_hash_n (const t_unichar * chr, size_t len);
*
* Compute an `unsigned long' hash value for a string.
*/
unsigned long
unichar_str_hash_n (const t_unichar * chr, size_t len)
{
return hash_mem ((t_uchar *)chr, len * sizeof (t_unichar));
}
/************************************************************************
*(h2 "Simple String Searching")
*
*/
/*(c unichar_str_chr_index)
* t_unichar * unichar_str_chr_index (const t_unichar * s, int c);
*
* Return the position in 0-terminated string `s' of the first
* occurence of `c'. Return 0 if `c' does not occur in `s'.
*/
t_unichar *
unichar_str_chr_index (const t_unichar * s, fix this -- should be t_unicode int c)
{
while (*s)
{
broken -- should look for code points!
if (*s == c)
return (t_unichar *)s;
++s;
}
if (c == 0)
return (t_unichar *)s;
return 0;
}
/*(c unichar_str_chr_rindex)
* t_unichar * unichar_str_chr_rindex (const t_unichar * s, int c);
*
* Return the position in 0-terminated string `s' of the last
* occurence of `c'. Return 0 if `c' does not occur in `s'.
*/
t_unichar *
unichar_str_chr_rindex (const t_unichar * s, int c)
{
const t_unichar * best;
best = 0;
while (*s)
{
if (*s == c)
best = s;
++s;
}
if (c == 0)
return (t_unichar *)s;
return (t_unichar *)best;
}
/*(c unichar_str_chr_index_n)
* t_unichar * unichar_str_chr_index_n (const t_unichar * s, size_t n, int c);
*
* Return the position in length `n' string `s' of the first occurence
* of `c'. Return 0 if `c' does not occur in `s'.
*/
t_unichar *
unichar_str_chr_index_n (const t_unichar * s, size_t n, int c)
{
while (n)
{
if (*s == c)
return (t_unichar *)s;
if (!*s)
return 0;
++s;
--n;
}
return 0;
}
/*(c unichar_str_chr_rindex_n)
* t_unichar * unichar_str_chr_rindex_n (const t_unichar * s, size_t n, int c);
*
* Return the position in length `n' string `s' of the last occurence
* of `c'. Return 0 if `c' does not occur in `s'.
*/
t_unichar *
unichar_str_chr_rindex_n (const t_unichar * s, size_t n, int c)
{
s += n - 1;
while (n)
{
if (*s == c)
return (t_unichar *)s;
--s;
--n;
}
return 0;
}
/************************************************************************
*(h2 "String Comparisons")
*
*
*
*/
/*(c unichar_str_cmp)
* int unichar_str_cmp (const t_unichar * a, const t_unichar * b);
*
* Compare strings `a' and `b' returning -1 if `a' is lexically first,
* 0 if the two strings are equal, 1 if `b' is lexically first.
*/
int
unichar_str_cmp (const t_unichar * a, const t_unichar * b)
{
if ((!a || !*a) && (!b || !*b))
return 0;
if (!b || !*b)
return 1;
if (!a || !a)
return -1;
while ((*a == *b) && *a)
{
++a;
++b;
}
if (*a == *b)
return 0;
else if (*a < *b)
return -1;
else
return 1;
}
/*(c unichar_str_cmp_n)
* int unichar_str_cmp_n (const t_unichar * a, size_t a_l, const t_unichar * b, size_t b_l);
*
* Compare strings `a' (length `a_l') and `b' (length `b_l') returning
* -1 if `a' is lexically first, 0 if the two strings are equal, 1 if
* `b' is lexically first.
*
*/
int
unichar_str_cmp_n (const t_unichar * a, size_t a_l, const t_unichar * b, size_t b_l)
{
size_t l;
l = ((a_l < b_l) ? a_l : b_l);
while (l)
{
t_unichar ac;
t_unichar bc;
ac = *a++;
bc = *b++;
if (ac < bc)
return -1;
else if (ac > bc)
return 1;
else if (!ac)
return 0;
--l;
}
if (a_l < b_l)
return -1;
else if (b_l < a_l)
return 1;
else
return 0;
}
/*(c unichar_str_cmp_prefix)
* int unichar_str_cmp_prefix (const t_unichar * prefix, const t_unichar * s);
*
* Compare strings `prefix' and `s'. If `prefix' is a prefix of `s',
* return 0. Otherwise, if `prefix' is lexically first, return -1;
* if `s' is lexically first, return 1.
*/
int
unichar_str_cmp_prefix (const t_unichar * prefix, const t_unichar * s)
{
if (!prefix)
return 0;
if (!s)
{
if (!*prefix)
return 0;
else
return 1;
}
while (*prefix)
{
if (*s < *prefix)
return 1;
else if (*s > *prefix)
return -1;
else
++prefix, ++s;
}
return 0;
}
/************************************************************************
*(h2 "String Comparisons Ignoring Case")
*
*/
/*(c unichar_str_casecmp)
* int unichar_str_casecmp (const t_unichar * a, const t_unichar * b);
*
* Compare strings `a' and `b' ignoring case, returning -1 if `a' is
* lexically first, 0 if the two strings are equal, 1 if `b' is
* lexically first.
*/
int
unichar_str_casecmp (const t_unichar * a, const t_unichar * b)
{
if ((!a || !*a) && (!b || !*b))
return 0;
if (!b || !*b)
return 1;
if (!a || !*a)
return -1;
while ((unidata_to_lower(*a) == unidata_to_lower(*b)) && *a)
{
++a;
++b;
}
if (unidata_to_lower(*a) == unidata_to_lower(*b))
return 0;
else if (unidata_to_lower(*a) < unidata_to_lower(*b))
return -1;
else
return 1;
}
/*(c unichar_str_casecmp_n)
* int unichar_str_casecmp_n (const t_unichar * a, size_t a_l,
* const t_unichar * b, size_t b_l);
*
* Compare strings `a' (length `a_l') and `b' (length `b_l') ignoring
* case returning -1 if `a' is lexically first, 0 if the two strings
* are equal, 1 if `b' is lexically first.
*/
int
unichar_str_casecmp_n (const t_unichar * a, size_t a_l,
const t_unichar * b, size_t b_l)
{
size_t l;
l = ((a_l < b_l) ? a_l : b_l);
while (l)
{
t_unichar ac;
t_unichar bc;
ac = unidata_to_lower(*a++);
bc = unidata_to_lower(*b++);
if (ac < bc)
return -1;
else if (ac > bc)
return 1;
else if (!ac)
return 0;
--l;
}
if (a_l < b_l)
return -1;
else if (b_l < a_l)
return 1;
else
return 0;
}
/*(c unichar_str_casecmp_prefix)
* int unichar_str_casecmp_prefix (const t_unichar * prefix, const t_unichar * s);
*
* Compare strings `prefix' and `s', ignoring case. If `prefix' is a
* prefix of `s', return 0. Otherwise, if `prefix' is lexically
* first, return -1; if `s' is lexically first, return 1.
*/
int
unichar_str_casecmp_prefix (const t_unichar * prefix, const t_unichar * s)
{
if (!prefix)
return 0;
if (!s)
{
if (!*prefix)
return 0;
else
return 1;
}
while (*prefix)
{
if (unidata_to_lower(*s) < unidata_to_lower(*prefix))
return 1;
else if (unidata_to_lower(*s) > unidata_to_lower(*prefix))
return -1;
else
++prefix, ++s;
}
return 0;
}
/************************************************************************
*(h2 "String Copying")
*
*/
/*(c unichar_str_cpy)
* t_unichar * unichar_str_cpy (t_unichar * to, const t_unichar * from);
*
* Copy the 0-terminated string `from' to `to'. `from' and `to'
* should not overlap.
*
* Returns `to'.
*/
size_t fix this
unichar_str_cpy (t_unichar * to, const t_unichar * from)
{
t_unichar * answer;
answer = to;
if (from)
{
while (*from)
*to++ = *from++;
}
*to = 0;
return answer;
}
/*(c unichar_str_cpy_n)
* t_unichar * unichar_str_cpy_n (t_unichar * to,
* const t_unichar * from,
* size_t n);
*
* Copy up-to `n' characters from `from' to `to'.
*
* \Warning:/ This function is different from `strncpy'. `strncpy'
* always stores exactly `n' characters in `to', padding the result
* with 0 if a 0 character is encountered in `from' before `n'
* characters are written. This function stores up to `n+1' characters:
* up to `n' non-0 characters from `from', plus a final 0.
*
* Returns `to'.
*/
void
unichar_str_cpy_n (t_unichar * to,
const t_unichar * from,
size_t n)
{
t_unichar * answer;
answer = to;
if (from)
{
while (n && *from)
{
*to++ = *from++;
--n;
}
}
*to++ = 0;
return answer;
}
/************************************************************************
*(h2 "String Concatenation")
*
*
*
*/
/*(c unichar_str_cat)
* t_unichar * unichar_str_cat (t_unichar * to, const t_unichar * from);
*
* Append the 0-terminated string `from' to the 0-terminated string
* `to'. The strings should not overlap.
*
* Returns `to'.
*/
size_t fix this
unichar_str_cat (t_unichar * to, const t_unichar * from)
{
t_unichar * answer;
answer = to;
if (from)
{
while (*to)
++to;
while (*from)
*to++ = *from++;
*to = 0;
}
return answer;
}
/*(c unichar_str_cat_n)
* t_unichar * unichar_str_cat_n (t_unichar * to,
* const t_unichar * from,
* size_t n);
*
* Append at most `n' characters of the 0-terminated string `from' to
* the 0-terminated string `to'. The strings should not overlap.
* Add a final 0 (thus writing up to `n + 1' characters in `to',
* starting from the position of the final 0 in `to' on entry).
*
* Returns `to'.
*/
t_unichar *
unichar_str_cat_n (t_unichar * to,
const t_unichar * from,
size_t n)
{
t_unichar * answer;
answer = to;
while (*to)
++to;
while (n && *from)
{
*to++ = *from++;
--n;
}
*to = 0;
return answer;
}
/************************************************************************
*(h2 "String Allocators")
*
*
*/
/*(c unichar_str_save)
* t_unichar * strsav (alloc_limits limits, const t_unichar * str);
*
* Allocate a copy of the 0-terminated string `str'.
*
* Allocate storage according to `limits'. (See xref:"Allocation
* With Limitations".)
*/
t_unichar *
unichar_str_save (alloc_limits limits, const t_unichar * str)
{
t_unichar * it;
size_t len;
len = unichar_str_length (str);
it = (t_unichar *)lim_malloc (limits, sizeof (t_unichar) * (len + 1));
if (!it)
return 0;
unichar_str_cpy (it, str);
return it;
}
/*(c unichar_str_save_n)
* t_unichar * unichar_str_save_n (alloc_limits limits,
* const t_unichar * str,
* size_t len);
*
* Allocate a copy of the n-byte string `str'.
* Add one byte to the new string and store 0 in that byte.
*
* Allocate storage according to `limits'. (See xref:"Allocation
* With Limitations".)
*/
t_unichar *
unichar_str_save_n (alloc_limits limits,
const t_unichar * str,
size_t len)
{
t_unichar * it;
it = (t_unichar *)lim_malloc (limits, sizeof (t_unichar) * (len + 1));
if (!it)
return 0;
mem_move ((t_uchar *)it, (t_uchar *)str, len);
it[len] = 0;
return it;
}
/*(c unichar_str_alloc_cat)
* t_unichar * unichar_str_alloc_cat (alloc_limits limits,
* const t_unichar * str1,
* const t_unichar * str2);
*
* Allocate a new string large enough to hold the concatenation of
* 0-terminated strings `str1' and `str2' (including a final 0).
* Initialize the new string with the concatenation of `str1' and
* `str2'.
*
* Allocate storage according to `limits'. (See xref:"Allocation
* With Limitations".)
*/
t_unichar *
unichar_str_alloc_cat (alloc_limits limits,
const t_unichar * str1,
const t_unichar * str2)
{
if (!str1 && !str2)
return 0;
if (!str1)
return unichar_str_save (limits, str2);
if (!str2)
return unichar_str_save (limits, str1);
{
t_unichar * it;
size_t len;
len = unichar_str_length (str1) + unichar_str_length (str2) + 1;
it = (t_unichar *)lim_malloc (limits, sizeof (t_unichar) * len);
if (!it)
return 0;
unichar_str_cpy (it, str1);
unichar_str_cat (it, str2);
return it;
}
}
/*(c unichar_str_alloc_cat_n)
* t_unichar * unichar_str_alloc_cat (alloc_limits limits,
* const t_unichar * str1,
* const t_unichar * str2,
* size_t n);
*
* Allocate a new 0-terminated string large enough to hold the
* concatenation of 0-terminated strings `str1' and `str2',
* considering at most `n' characters from `str2'.
*
* Initialize the new string with the concatenation of `str1' and
* up to `n' characters of `str2'. Append a final 0.
*
* Allocate storage according to `limits'. (See xref:"Allocation
* With Limitations".)
*/
t_unichar *
unichar_str_alloc_cat_n (alloc_limits limits,
const t_unichar * str1,
const t_unichar * str2,
size_t n)
{
if (!str1 && !str2)
return 0;
if (!str1)
return unichar_str_save_n (limits, str2, n);
if (!str2)
return unichar_str_save (limits, str1);
{
t_unichar * it;
size_t len;
len = unichar_str_length (str1) + unichar_str_length_n (str2, n) + 1;
it = (t_unichar *)lim_malloc (limits, sizeof (t_unichar) * len);
if (!it)
return 0;
unichar_str_cpy (it, str1);
unichar_str_cat_n (it, str2, n);
return it;
}
}
syntax highlighted by Code2HTML, v. 0.9.1