214 lines
5.5 KiB
C
214 lines
5.5 KiB
C
/*
|
|
* $Id: tio-put.c 566 2011-09-11 12:44:56Z hyunghwan.chung $
|
|
*
|
|
Copyright 2006-2011 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/tio.h>
|
|
#include <qse/cmn/mbwc.h>
|
|
|
|
qse_ssize_t qse_tio_writembs (
|
|
qse_tio_t* tio, const qse_mchar_t* mptr, qse_size_t mlen)
|
|
{
|
|
if (tio->outbuf_len >= tio->out.buf.capa)
|
|
{
|
|
/* maybe, previous flush operation has failed a few
|
|
* times previously. so the buffer is full.
|
|
*/
|
|
tio->errnum = QSE_TIO_ENOSPC;
|
|
return -1;
|
|
}
|
|
|
|
if (mlen == (qse_size_t)-1)
|
|
{
|
|
qse_size_t pos = 0;
|
|
|
|
if (tio->flags & QSE_TIO_NOAUTOFLUSH)
|
|
{
|
|
while (mptr[pos])
|
|
{
|
|
tio->out.buf.ptr[tio->outbuf_len++] = mptr[pos++];
|
|
if (tio->outbuf_len >= tio->out.buf.capa &&
|
|
qse_tio_flush (tio) <= -1) return -1;
|
|
if (pos >= QSE_TYPE_MAX(qse_ssize_t)) break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nl = 0;
|
|
while (mptr[pos])
|
|
{
|
|
tio->out.buf.ptr[tio->outbuf_len++] = mptr[pos];
|
|
if (tio->outbuf_len >= tio->out.buf.capa)
|
|
{
|
|
if (qse_tio_flush (tio) <= -1) return -1;
|
|
nl = 0;
|
|
}
|
|
else if (mptr[pos] == QSE_T('\n')) nl = 1;
|
|
/* TODO: different line terminator */
|
|
if (++pos >= QSE_TYPE_MAX(qse_ssize_t)) break;
|
|
}
|
|
if (nl && qse_tio_flush(tio) <= -1) return -1;
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
else
|
|
{
|
|
const qse_mchar_t* xptr, * xend;
|
|
qse_size_t capa;
|
|
int nl = 0;
|
|
|
|
/* adjust mlen for the type difference between the parameter
|
|
* and the return value */
|
|
if (mlen > QSE_TYPE_MAX(qse_ssize_t)) mlen = QSE_TYPE_MAX(qse_ssize_t);
|
|
xptr = mptr;
|
|
|
|
/* handle the parts that can't fit into the internal buffer */
|
|
while (mlen >= (capa = tio->out.buf.capa - tio->outbuf_len))
|
|
{
|
|
for (xend = xptr + capa; xptr < xend; xptr++)
|
|
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
|
|
if (qse_tio_flush (tio) <= -1) return -1;
|
|
mlen -= capa;
|
|
}
|
|
|
|
if (tio->flags & QSE_TIO_NOAUTOFLUSH)
|
|
{
|
|
/* handle the last part that can fit into the internal buffer */
|
|
for (xend = xptr + mlen; xptr < xend; xptr++)
|
|
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
|
|
}
|
|
else
|
|
{
|
|
/* handle the last part that can fit into the internal buffer */
|
|
for (xend = xptr + mlen; xptr < xend; xptr++)
|
|
{
|
|
/* TODO: support different line terminating characeter */
|
|
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
|
|
if (*xptr == QSE_MT('\n'))
|
|
{
|
|
nl = 1;
|
|
break;
|
|
}
|
|
}
|
|
while (xptr < xend) tio->out.buf.ptr[tio->outbuf_len++] = *xptr++;
|
|
}
|
|
|
|
/* if the last part contains a new line, flush the internal
|
|
* buffer. note that this flushes characters after nl also.*/
|
|
if (nl && qse_tio_flush (tio) <= -1) return -1;
|
|
|
|
/* returns the number multi-bytes characters handled */
|
|
return xptr - mptr;
|
|
}
|
|
}
|
|
|
|
qse_ssize_t qse_tio_writewcs (
|
|
qse_tio_t* tio, const qse_wchar_t* wptr, qse_size_t wlen)
|
|
{
|
|
qse_size_t capa, wcnt, mcnt, xwlen;
|
|
int n, nl = 0;
|
|
|
|
if (tio->outbuf_len >= tio->out.buf.capa)
|
|
{
|
|
/* maybe, previous flush operation has failed a few
|
|
* times previously. so the buffer is full.
|
|
*/
|
|
tio->errnum = QSE_TIO_ENOSPC;
|
|
return -1;
|
|
}
|
|
|
|
if (wlen == (qse_size_t)-1) wlen = qse_wcslen(wptr);
|
|
if (wlen > QSE_TYPE_MAX(qse_ssize_t)) wlen = QSE_TYPE_MAX(qse_ssize_t);
|
|
|
|
xwlen = wlen;
|
|
while (xwlen > 0)
|
|
{
|
|
capa = tio->out.buf.capa - tio->outbuf_len;
|
|
wcnt = xwlen; mcnt = capa;
|
|
|
|
n = qse_wcsntombsnwithcmgr (
|
|
wptr, &wcnt, &tio->out.buf.ptr[tio->outbuf_len], &mcnt, tio->cmgr);
|
|
tio->outbuf_len += mcnt;
|
|
|
|
if (n == -2)
|
|
{
|
|
/* the buffer is not large enough to
|
|
* convert more. so flush now and continue.
|
|
* note that the buffer may not be full though
|
|
* it not large enough in this case */
|
|
if (qse_tio_flush (tio) <= -1) return -1;
|
|
nl = 0;
|
|
}
|
|
else
|
|
{
|
|
if (tio->outbuf_len >= tio->out.buf.capa)
|
|
{
|
|
/* flush the full buffer regardless of conversion
|
|
* result. */
|
|
if (qse_tio_flush (tio) <= -1) return -1;
|
|
nl = 0;
|
|
}
|
|
|
|
if (n <= -1)
|
|
{
|
|
/* an invalid wide-character is encountered. */
|
|
if (tio->flags & QSE_TIO_IGNOREMBWCERR)
|
|
{
|
|
/* insert a question mark for an illegal
|
|
* character. */
|
|
QSE_ASSERT (tio->outbuf_len < tio->out.buf.capa);
|
|
tio->out.buf.ptr[tio->outbuf_len++] = QSE_MT('?');
|
|
wcnt++; /* skip this illegal character */
|
|
/* don't need to increment mcnt since
|
|
* it's not used below */
|
|
}
|
|
else
|
|
{
|
|
tio->errnum = QSE_TIO_EILCHR;
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(tio->flags & QSE_TIO_NOAUTOFLUSH) && !nl)
|
|
{
|
|
/* checking for a newline this way looks damn ugly.
|
|
* TODO: how can i do this more elegantly? */
|
|
qse_size_t i = wcnt;
|
|
while (i > 0)
|
|
{
|
|
/* scan backward assuming a line terminator
|
|
* is typically at the back */
|
|
if (wptr[--i] == QSE_WT('\n'))
|
|
{
|
|
/* TOOD: differetn line terminator */
|
|
nl = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
wptr += wcnt; xwlen -= wcnt;
|
|
}
|
|
|
|
if (nl && qse_tio_flush (tio) <= -1) return -1;
|
|
return wlen;
|
|
}
|