430 lines
9.3 KiB
C
430 lines
9.3 KiB
C
/*
|
|
* $Id: str_cnv.c 415 2011-03-25 16:02:04Z hyunghwan.chung $
|
|
*
|
|
Copyright 2006-2009 Chung, Hyung-Hwan.
|
|
This file is part of QSE.
|
|
|
|
QSE is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as
|
|
published by the Free Software Foundation, either version 3 of
|
|
the License, or (at your option) any later version.
|
|
|
|
QSE is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <qse/cmn/str.h>
|
|
#include <qse/cmn/chr.h>
|
|
|
|
int qse_strtoi (const qse_char_t* str)
|
|
{
|
|
int v;
|
|
QSE_STRTONUM (v, str, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
long qse_strtol (const qse_char_t* str)
|
|
{
|
|
long v;
|
|
QSE_STRTONUM (v, str, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
unsigned int qse_strtoui (const qse_char_t* str)
|
|
{
|
|
unsigned int v;
|
|
QSE_STRTONUM (v, str, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
unsigned long qse_strtoul (const qse_char_t* str)
|
|
{
|
|
unsigned long v;
|
|
QSE_STRTONUM (v, str, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
int qse_strxtoi (const qse_char_t* str, qse_size_t len)
|
|
{
|
|
int v;
|
|
QSE_STRXTONUM (v, str, len, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
long qse_strxtol (const qse_char_t* str, qse_size_t len)
|
|
{
|
|
long v;
|
|
QSE_STRXTONUM (v, str, len, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
unsigned int qse_strxtoui (const qse_char_t* str, qse_size_t len)
|
|
{
|
|
unsigned int v;
|
|
QSE_STRXTONUM (v, str, len, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
unsigned long qse_strxtoul (const qse_char_t* str, qse_size_t len)
|
|
{
|
|
unsigned long v;
|
|
QSE_STRXTONUM (v, str, len, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
qse_int_t qse_strtoint (const qse_char_t* str)
|
|
{
|
|
qse_int_t v;
|
|
QSE_STRTONUM (v, str, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
qse_long_t qse_strtolong (const qse_char_t* str)
|
|
{
|
|
qse_long_t v;
|
|
QSE_STRTONUM (v, str, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
qse_uint_t qse_strtouint (const qse_char_t* str)
|
|
{
|
|
qse_uint_t v;
|
|
QSE_STRTONUM (v, str, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
qse_ulong_t qse_strtoulong (const qse_char_t* str)
|
|
{
|
|
qse_ulong_t v;
|
|
QSE_STRTONUM (v, str, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
qse_int_t qse_strxtoint (const qse_char_t* str, qse_size_t len)
|
|
{
|
|
qse_int_t v;
|
|
QSE_STRXTONUM (v, str, len, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
qse_long_t qse_strxtolong (const qse_char_t* str, qse_size_t len)
|
|
{
|
|
qse_long_t v;
|
|
QSE_STRXTONUM (v, str, len, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
qse_uint_t qse_strxtouint (const qse_char_t* str, qse_size_t len)
|
|
{
|
|
qse_uint_t v;
|
|
QSE_STRXTONUM (v, str, len, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
qse_ulong_t qse_strxtoulong (const qse_char_t* str, qse_size_t len)
|
|
{
|
|
qse_ulong_t v;
|
|
QSE_STRXTONUM (v, str, len, QSE_NULL, 10);
|
|
return v;
|
|
}
|
|
|
|
qse_size_t qse_mbstowcslen (const qse_mchar_t* mcs, qse_size_t* wcslen)
|
|
{
|
|
qse_wchar_t wc;
|
|
qse_size_t n, ml, wl = 0;
|
|
const qse_mchar_t* p = mcs;
|
|
|
|
while (*p != '\0') p++;
|
|
ml = p - mcs;
|
|
|
|
for (p = mcs; ml > 0; p += n, ml -= n)
|
|
{
|
|
n = qse_mbtowc (p, ml, &wc);
|
|
/* insufficient input or wrong sequence */
|
|
if (n == 0 || n > ml) break;
|
|
wl++;
|
|
}
|
|
|
|
if (wcslen) *wcslen = wl;
|
|
return p - mcs;
|
|
}
|
|
|
|
qse_size_t qse_mbsntowcsnlen (const qse_mchar_t* mcs, qse_size_t mcslen, qse_size_t* wcslen)
|
|
{
|
|
qse_wchar_t wc;
|
|
qse_size_t n, ml = mcslen, wl = 0;
|
|
const qse_mchar_t* p = mcs;
|
|
|
|
for (p = mcs; ml > 0; p += n, ml -= n)
|
|
{
|
|
n = qse_mbtowc (p, ml, &wc);
|
|
/* insufficient or invalid sequence */
|
|
if (n == 0 || n > ml) break;
|
|
wl++;
|
|
}
|
|
|
|
if (wcslen) *wcslen = wl;
|
|
return mcslen - ml;
|
|
}
|
|
|
|
qse_size_t qse_mbstowcs (
|
|
const qse_mchar_t* mbs, qse_wchar_t* wcs, qse_size_t* wcslen)
|
|
{
|
|
qse_size_t wlen, mlen;
|
|
const qse_mchar_t* mp;
|
|
|
|
/* get the length of mbs and pass it to qse_mbsntowcsn as
|
|
* qse_mbtowc called by qse_mbsntowcsn needs it. */
|
|
wlen = *wcslen;
|
|
if (wlen <= 0)
|
|
{
|
|
/* buffer too small. also cannot null-terminate it */
|
|
*wcslen = 0;
|
|
return 0; /* 0 byte processed */
|
|
}
|
|
|
|
for (mp = mbs; *mp != '\0'; mp++);
|
|
mlen = qse_mbsntowcsn (mbs, mp - mbs, wcs, &wlen);
|
|
if (wlen < *wcslen)
|
|
{
|
|
/* null-terminate wcs if it is large enough. */
|
|
wcs[wlen] = L'\0';
|
|
}
|
|
|
|
/* if null-terminated properly, the input wcslen must be less than
|
|
* the output wcslen. (input length includs the terminating null
|
|
* while the output length excludes the terminating null) */
|
|
*wcslen = wlen;
|
|
|
|
return mlen;
|
|
}
|
|
|
|
qse_size_t qse_mbsntowcsn (
|
|
const qse_mchar_t* mbs, qse_size_t mbslen,
|
|
qse_wchar_t* wcs, qse_size_t* wcslen)
|
|
{
|
|
qse_size_t mlen = mbslen, n;
|
|
const qse_mchar_t* p;
|
|
qse_wchar_t* q, * qend ;
|
|
|
|
qend = wcs + *wcslen;
|
|
|
|
for (p = mbs, q = wcs; mlen > 0 && q < qend; p += n, mlen -= n)
|
|
{
|
|
n = qse_mbtowc (p, mlen, q);
|
|
if (n == 0 || n > mlen)
|
|
{
|
|
/* wrong sequence or insufficient input */
|
|
break;
|
|
}
|
|
|
|
q++;
|
|
}
|
|
|
|
*wcslen = q - wcs;
|
|
return p - mbs; /* returns the number of bytes processed */
|
|
}
|
|
|
|
qse_size_t qse_wcstombslen (const qse_wchar_t* wcs, qse_size_t* mbslen)
|
|
{
|
|
const qse_wchar_t* p = wcs;
|
|
qse_mchar_t mbs[32];
|
|
qse_size_t mlen = 0;
|
|
|
|
while (*p != QSE_WT('\0'))
|
|
{
|
|
qse_size_t n = qse_wctomb (*p, mbs, QSE_COUNTOF(mbs));
|
|
if (n == 0) break; /* illegal character */
|
|
|
|
/* it assumes that mbs is large enough to hold a character */
|
|
QSE_ASSERT (n <= QSE_COUNTOF(mbs));
|
|
|
|
p++; mlen += n;
|
|
}
|
|
|
|
/* this length holds the number of resulting multi-byte characters
|
|
* excluding the terminating null character */
|
|
*mbslen = mlen;
|
|
|
|
/* returns the number of characters handled.
|
|
* if the function has encountered an illegal character in
|
|
* the while loop above, wcs[p-wcs] will not be a null character */
|
|
return p - wcs;
|
|
}
|
|
|
|
qse_size_t qse_wcsntombsnlen (
|
|
const qse_wchar_t* wcs, qse_size_t wcslen, qse_size_t* mbslen)
|
|
{
|
|
const qse_wchar_t* p = wcs;
|
|
const qse_wchar_t* end = wcs + wcslen;
|
|
qse_mchar_t mbs[32];
|
|
qse_size_t mlen = 0;
|
|
|
|
while (p < end)
|
|
{
|
|
qse_size_t n = qse_wctomb (*p, mbs, QSE_COUNTOF(mbs));
|
|
if (n == 0) break; /* illegal character */
|
|
|
|
/* it assumes that mbs is large enough to hold a character */
|
|
QSE_ASSERT (n <= QSE_COUNTOF(mbs));
|
|
|
|
p++; mlen += n;
|
|
}
|
|
|
|
/* this length excludes the terminating null character. */
|
|
*mbslen = mlen;
|
|
|
|
/* returns the number of characters handled.
|
|
* if the function has encountered an illegal character in
|
|
* the while loop above, wcs[p-wcs] will not be a null character */
|
|
return p - wcs;
|
|
}
|
|
|
|
qse_size_t qse_wcstombs (
|
|
const qse_wchar_t* wcs, qse_mchar_t* mbs, qse_size_t* mbslen)
|
|
{
|
|
const qse_wchar_t* p = wcs;
|
|
qse_size_t rem = *mbslen;
|
|
|
|
while (*p != QSE_WT('\0') && rem > 1)
|
|
{
|
|
qse_size_t n = qse_wctomb (*p, mbs, rem);
|
|
if (n == 0 || n > rem)
|
|
{
|
|
/* illegal character or buffer not enough */
|
|
break;
|
|
}
|
|
|
|
if (rem == n)
|
|
{
|
|
/* the buffer is full without the space for a
|
|
* terminating null. should stop processing further
|
|
* excluding this last character emitted. */
|
|
break;
|
|
}
|
|
|
|
mbs += n; rem -= n; p++;
|
|
}
|
|
|
|
/* update mbslen to the length of the mbs string converted excluding
|
|
* terminating null */
|
|
*mbslen -= rem;
|
|
|
|
/* null-terminate the multibyte sequence if it has sufficient space */
|
|
if (rem > 0) *mbs = QSE_MT('\0');
|
|
|
|
/* returns the number of characters handled. */
|
|
return p - wcs;
|
|
}
|
|
|
|
qse_size_t qse_wcsntombsn (
|
|
const qse_wchar_t* wcs, qse_size_t wcslen,
|
|
qse_mchar_t* mbs, qse_size_t* mbslen)
|
|
{
|
|
const qse_wchar_t* p = wcs;
|
|
const qse_wchar_t* end = wcs + wcslen;
|
|
qse_size_t len = *mbslen;
|
|
|
|
while (p < end && len > 0)
|
|
{
|
|
qse_size_t n = qse_wctomb (*p, mbs, len);
|
|
if (n == 0 || n > len)
|
|
{
|
|
/* illegal character or buffer not enough */
|
|
break;
|
|
}
|
|
mbs += n; len -= n; p++;
|
|
}
|
|
|
|
*mbslen -= len;
|
|
|
|
/* returns the number of characters handled.
|
|
* the caller can check if the return value is as large is wcslen
|
|
* for an error. */
|
|
return p - wcs;
|
|
}
|
|
|
|
int qse_mbstowcs_strict (
|
|
const qse_mchar_t* mbs, qse_wchar_t* wcs, qse_size_t wcslen)
|
|
{
|
|
qse_size_t n;
|
|
qse_size_t wn = wcslen;
|
|
|
|
n = qse_mbstowcs (mbs, wcs, &wn);
|
|
if (wn >= wcslen)
|
|
{
|
|
/* wcs not big enough to be null-terminated.
|
|
* if it has been null-terminated properly,
|
|
* wn should be less than wcslen. */
|
|
return -1;
|
|
}
|
|
if (mbs[n] != QSE_MT('\0'))
|
|
{
|
|
/* incomplete sequence or invalid sequence */
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int qse_wcstombs_strict (
|
|
const qse_wchar_t* wcs, qse_mchar_t* mbs, qse_size_t mbslen)
|
|
{
|
|
qse_size_t n;
|
|
qse_size_t mn = mbslen;
|
|
|
|
n = qse_wcstombs (wcs, mbs, &mn);
|
|
if (mn >= mbslen)
|
|
{
|
|
/* mbs not big enough to be null-terminated.
|
|
* if it has been null-terminated properly,
|
|
* mn should be less than mbslen. */
|
|
return -1;
|
|
}
|
|
if (wcs[n] != QSE_WT('\0'))
|
|
{
|
|
/* if qse_wcstombs() processed all wide characters,
|
|
* the character at position 'n' should be a null character
|
|
* as 'n' is the number of wide characters processed. */
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* case conversion */
|
|
|
|
qse_size_t qse_mbslwr (qse_mchar_t* str)
|
|
{
|
|
qse_mchar_t* p = str;
|
|
for (p = str; *p != QSE_MT('\0'); p++) *p = QSE_TOMLOWER (*p);
|
|
return p - str;
|
|
}
|
|
|
|
qse_size_t qse_mbsupr (qse_mchar_t* str)
|
|
{
|
|
qse_mchar_t* p = str;
|
|
for (p = str; *p != QSE_MT('\0'); p++) *p = QSE_TOMUPPER (*p);
|
|
return p - str;
|
|
}
|
|
|
|
qse_size_t qse_wcslwr (qse_wchar_t* str)
|
|
{
|
|
qse_wchar_t* p = str;
|
|
for (p = str; *p != QSE_WT('\0'); p++) *p = QSE_TOWLOWER (*p);
|
|
return p - str;
|
|
}
|
|
|
|
qse_size_t qse_wcsupr (qse_wchar_t* str)
|
|
{
|
|
qse_wchar_t* p = str;
|
|
for (p = str; *p != QSE_WT('\0'); p++) *p = QSE_TOWUPPER (*p);
|
|
return p - str;
|
|
}
|