changed qse_tio_t to accept buffer specified externally.
removed the internal buffer from qse_tio_t. added the WriteFile/WriteConsoleW hack into qse_sio_putwcs()/qse_sio_wcsn() as a partial solution to the WriteFile issue with UTF8 strings on the UTF8 console on win32
This commit is contained in:
@ -189,11 +189,11 @@ int qse_fio_init (
|
||||
}
|
||||
else creation_disposition = OPEN_EXISTING;
|
||||
|
||||
if (flags & QSE_FIO_NOSHRD)
|
||||
if (flags & QSE_FIO_NOSHREAD)
|
||||
share_mode &= ~FILE_SHARE_READ;
|
||||
if (flags & QSE_FIO_NOSHWR)
|
||||
if (flags & QSE_FIO_NOSHWRITE)
|
||||
share_mode &= ~FILE_SHARE_WRITE;
|
||||
if (flags & QSE_FIO_NOSHDL)
|
||||
if (flags & QSE_FIO_NOSHDELETE)
|
||||
share_mode &= ~FILE_SHARE_DELETE;
|
||||
|
||||
if (!(mode & QSE_FIO_WUSR))
|
||||
@ -302,11 +302,11 @@ int qse_fio_init (
|
||||
if (flags & QSE_FIO_SYNC)
|
||||
open_mode |= OPEN_FLAGS_WRITE_THROUGH;
|
||||
|
||||
if ((flags & QSE_FIO_NOSHRD) && (flags & QSE_FIO_NOSHWR))
|
||||
if ((flags & QSE_FIO_NOSHREAD) && (flags & QSE_FIO_NOSHWRITE))
|
||||
open_mode |= OPEN_SHARE_DENYREADWRITE;
|
||||
else if (flags & QSE_FIO_NOSHRD)
|
||||
else if (flags & QSE_FIO_NOSHREAD)
|
||||
open_mode |= OPEN_SHARE_DENYREAD;
|
||||
else if (flags & QSE_FIO_NOSHWR)
|
||||
else if (flags & QSE_FIO_NOSHWRITE)
|
||||
open_mode |= OPEN_SHARE_DENYWRITE;
|
||||
else
|
||||
open_mode |= OPEN_SHARE_DENYNONE;
|
||||
@ -511,12 +511,13 @@ int qse_fio_init (
|
||||
int opt = 0;
|
||||
|
||||
if (fio->flags & QSE_FIO_IGNOREMBWCERR) opt |= QSE_TIO_IGNOREMBWCERR;
|
||||
if (fio->flags & QSE_FIO_NOAUTOFLUSH) opt |= QSE_TIO_NOAUTOFLUSH;
|
||||
|
||||
tio = qse_tio_open (fio->mmgr, 0, opt);
|
||||
if (tio == QSE_NULL) QSE_THROW_ERR (tio);
|
||||
|
||||
if (qse_tio_attachin (tio, fio_input, fio) <= -1 ||
|
||||
qse_tio_attachout (tio, fio_output, fio) <= -1)
|
||||
if (qse_tio_attachin (tio, fio_input, fio, QSE_NULL, 4096) <= -1 ||
|
||||
qse_tio_attachout (tio, fio_output, fio, QSE_NULL, 4096) <= -1)
|
||||
{
|
||||
qse_tio_close (tio);
|
||||
QSE_THROW_ERR (tio);
|
||||
@ -991,7 +992,7 @@ static qse_ssize_t fio_input (qse_tio_cmd_t cmd, void* arg, void* buf, qse_size_
|
||||
{
|
||||
qse_fio_t* fio = (qse_fio_t*)arg;
|
||||
QSE_ASSERT (fio != QSE_NULL);
|
||||
if (cmd == QSE_TIO_IO_DATA) return fio_read (fio, buf, size);
|
||||
if (cmd == QSE_TIO_DATA) return fio_read (fio, buf, size);
|
||||
|
||||
/* take no actions for OPEN and CLOSE as they are handled
|
||||
* by fio */
|
||||
@ -1002,7 +1003,7 @@ static qse_ssize_t fio_output (qse_tio_cmd_t cmd, void* arg, void* buf, qse_size
|
||||
{
|
||||
qse_fio_t* fio = (qse_fio_t*)arg;
|
||||
QSE_ASSERT (fio != QSE_NULL);
|
||||
if (cmd == QSE_TIO_IO_DATA) return fio_write (fio, buf, size);
|
||||
if (cmd == QSE_TIO_DATA) return fio_write (fio, buf, size);
|
||||
|
||||
/* take no actions for OPEN and CLOSE as they are handled
|
||||
* by fio */
|
||||
|
@ -991,8 +991,8 @@ int qse_pio_init (
|
||||
}
|
||||
|
||||
r = (i == QSE_PIO_IN)?
|
||||
qse_tio_attachout (tio[i], pio_output, &pio->pin[i]):
|
||||
qse_tio_attachin (tio[i], pio_input, &pio->pin[i]);
|
||||
qse_tio_attachout (tio[i], pio_output, &pio->pin[i], QSE_NULL, 4096):
|
||||
qse_tio_attachin (tio[i], pio_input, &pio->pin[i], QSE_NULL, 4096);
|
||||
|
||||
if (r <= -1) goto oops;
|
||||
|
||||
@ -1563,7 +1563,7 @@ static qse_ssize_t pio_input (qse_tio_cmd_t cmd, void* arg, void* buf, qse_size_
|
||||
{
|
||||
qse_pio_pin_t* pin = (qse_pio_pin_t*)arg;
|
||||
QSE_ASSERT (pin != QSE_NULL);
|
||||
if (cmd == QSE_TIO_IO_DATA)
|
||||
if (cmd == QSE_TIO_DATA)
|
||||
{
|
||||
QSE_ASSERT (pin->self != QSE_NULL);
|
||||
return pio_read (pin->self, buf, size, pin->handle);
|
||||
@ -1578,7 +1578,7 @@ static qse_ssize_t pio_output (qse_tio_cmd_t cmd, void* arg, void* buf, qse_size
|
||||
{
|
||||
qse_pio_pin_t* pin = (qse_pio_pin_t*)arg;
|
||||
QSE_ASSERT (pin != QSE_NULL);
|
||||
if (cmd == QSE_TIO_IO_DATA)
|
||||
if (cmd == QSE_TIO_DATA)
|
||||
{
|
||||
QSE_ASSERT (pin->self != QSE_NULL);
|
||||
return pio_write (pin->self, buf, size, pin->handle);
|
||||
|
@ -25,10 +25,7 @@ static qse_ssize_t __sio_input (qse_tio_cmd_t cmd, void* arg, void* buf, qse_siz
|
||||
static qse_ssize_t __sio_output (qse_tio_cmd_t cmd, void* arg, void* buf, qse_size_t size);
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
#elif defined(__OS2__)
|
||||
# define INCL_DOSFILEMGR
|
||||
# include <os2.h>
|
||||
# include <windows.h> /* for the UGLY hack */
|
||||
#endif
|
||||
|
||||
qse_sio_t* qse_sio_open (
|
||||
@ -61,10 +58,22 @@ qse_sio_t* qse_sio_open (
|
||||
qse_sio_t* qse_sio_openstd (
|
||||
qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_sio_std_t std, int flags)
|
||||
{
|
||||
qse_sio_t* sio;
|
||||
qse_fio_hnd_t hnd;
|
||||
|
||||
if (qse_getstdfiohandle (std, &hnd) <= -1) return QSE_NULL;
|
||||
return qse_sio_open (mmgr, xtnsize,
|
||||
sio = qse_sio_open (mmgr, xtnsize,
|
||||
(const qse_char_t*)&hnd, flags | QSE_SIO_HANDLE | QSE_SIO_NOCLOSE);
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (sio)
|
||||
{
|
||||
QSE_ASSERT (std >= 0 && std < QSE_TYPE_MAX(int));
|
||||
sio->status = std + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return sio;
|
||||
}
|
||||
|
||||
void qse_sio_close (qse_sio_t* sio)
|
||||
@ -87,7 +96,12 @@ int qse_sio_init (
|
||||
mode = QSE_FIO_RUSR | QSE_FIO_WUSR |
|
||||
QSE_FIO_RGRP | QSE_FIO_ROTH;
|
||||
|
||||
if (qse_fio_init (&sio->fio, mmgr, file, flags, mode) <= -1) return -1;
|
||||
/* sio flags redefines most fio flags. fio can be opened in the
|
||||
* text mode. that way, fio is also buffered. since sio performs
|
||||
* its own buffering, i don't want a caller to specify text mode
|
||||
* flags accidentally. i mask off those bits here to avoid mishap. */
|
||||
if (qse_fio_init (&sio->fio, mmgr, file,
|
||||
(flags & ~(QSE_FIO_TEXT|QSE_FIO_NOAUTOFLUSH)), mode) <= -1) return -1;
|
||||
|
||||
if (flags & QSE_SIO_IGNOREMBWCERR) topt |= QSE_TIO_IGNOREMBWCERR;
|
||||
if (flags & QSE_SIO_NOAUTOFLUSH) topt |= QSE_TIO_NOAUTOFLUSH;
|
||||
@ -98,8 +112,8 @@ int qse_sio_init (
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qse_tio_attachin(&sio->tio, __sio_input, sio) <= -1 ||
|
||||
qse_tio_attachout(&sio->tio, __sio_output, sio) <= -1)
|
||||
if (qse_tio_attachin (&sio->tio, __sio_input, sio, sio->inbuf, QSE_COUNTOF(sio->inbuf)) <= -1 ||
|
||||
qse_tio_attachout (&sio->tio, __sio_output, sio, sio->outbuf, QSE_COUNTOF(sio->outbuf)) <= -1)
|
||||
{
|
||||
qse_tio_fini (&sio->tio);
|
||||
qse_fio_fini (&sio->fio);
|
||||
@ -112,10 +126,22 @@ int qse_sio_init (
|
||||
int qse_sio_initstd (
|
||||
qse_sio_t* sio, qse_mmgr_t* mmgr, qse_sio_std_t std, int flags)
|
||||
{
|
||||
int n;
|
||||
qse_fio_hnd_t hnd;
|
||||
|
||||
if (qse_getstdfiohandle (std, &hnd) <= -1) return -1;
|
||||
return qse_sio_init (sio, mmgr,
|
||||
(const qse_char_t*)&hnd, flags | QSE_SIO_HANDLE);
|
||||
n = qse_sio_init (sio, mmgr,
|
||||
(const qse_char_t*)&hnd, flags | QSE_SIO_HANDLE | QSE_SIO_NOCLOSE);
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (n >= 0)
|
||||
{
|
||||
QSE_ASSERT (std >= 0 && std < QSE_TYPE_MAX(int));
|
||||
sio->status = std + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void qse_sio_fini (qse_sio_t* sio)
|
||||
@ -163,7 +189,14 @@ qse_ssize_t qse_sio_getmbs (
|
||||
qse_ssize_t n;
|
||||
|
||||
if (size <= 0) return 0;
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* Using ReadConsoleA() didn't help at all.
|
||||
* so I don't implement any hack here */
|
||||
#endif
|
||||
|
||||
n = qse_tio_readmbs (&sio->tio, buf, size - 1);
|
||||
|
||||
if (n <= -1) return -1;
|
||||
buf[n] = QSE_MT('\0');
|
||||
return n;
|
||||
@ -172,6 +205,11 @@ qse_ssize_t qse_sio_getmbs (
|
||||
qse_ssize_t qse_sio_getmbsn (
|
||||
qse_sio_t* sio, qse_mchar_t* buf, qse_size_t size)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
/* Using ReadConsoleA() didn't help at all.
|
||||
* so I don't implement any hack here */
|
||||
#endif
|
||||
|
||||
return qse_tio_readmbs (&sio->tio, buf, size);
|
||||
}
|
||||
|
||||
@ -181,7 +219,14 @@ qse_ssize_t qse_sio_getwcs (
|
||||
qse_ssize_t n;
|
||||
|
||||
if (size <= 0) return 0;
|
||||
|
||||
#if defined(_WIN32)
|
||||
/* Using ReadConsoleA() didn't help at all.
|
||||
* so I don't implement any hack here */
|
||||
#endif
|
||||
|
||||
n = qse_tio_readwcs (&sio->tio, buf, size - 1);
|
||||
|
||||
if (n <= -1) return -1;
|
||||
buf[n] = QSE_WT('\0');
|
||||
return n;
|
||||
@ -190,6 +235,10 @@ qse_ssize_t qse_sio_getwcs (
|
||||
qse_ssize_t qse_sio_getwcsn (
|
||||
qse_sio_t* sio, qse_wchar_t* buf, qse_size_t size)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
/* Using ReadConsoleW() didn't help at all.
|
||||
* so I don't implement any hack here */
|
||||
#endif
|
||||
return qse_tio_readwcs (&sio->tio, buf, size);
|
||||
}
|
||||
|
||||
@ -205,23 +254,99 @@ qse_ssize_t qse_sio_putwc (qse_sio_t* sio, qse_wchar_t c)
|
||||
|
||||
qse_ssize_t qse_sio_putmbs (qse_sio_t* sio, const qse_mchar_t* str)
|
||||
{
|
||||
return qse_tio_writembs (&sio->tio, str, (qse_size_t)-1);
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
/* Using WriteConsoleA() didn't help at all.
|
||||
* so I don't implement any hack here */
|
||||
#endif
|
||||
|
||||
qse_ssize_t qse_sio_putwcs (qse_sio_t* sio, const qse_wchar_t* str)
|
||||
{
|
||||
return qse_tio_writewcs (&sio->tio, str, (qse_size_t)-1);
|
||||
return qse_tio_writembs (&sio->tio, str, (qse_size_t)-1);
|
||||
}
|
||||
|
||||
qse_ssize_t qse_sio_putmbsn (
|
||||
qse_sio_t* sio, const qse_mchar_t* str, qse_size_t size)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
/* Using WriteConsoleA() didn't help at all.
|
||||
* so I don't implement any hack here */
|
||||
#endif
|
||||
|
||||
return qse_tio_writembs (&sio->tio, str, size);
|
||||
}
|
||||
|
||||
qse_ssize_t qse_sio_putwcs (qse_sio_t* sio, const qse_wchar_t* str)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
/* DAMN UGLY: See comment in qse_sio_putwcsn() */
|
||||
if (sio->status)
|
||||
{
|
||||
DWORD mode;
|
||||
|
||||
if (GetConsoleMode (sio->fio.handle, &mode) == FALSE)
|
||||
{
|
||||
return qse_tio_writewcs (&sio->tio, str, (qse_size_t)-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD count, left;
|
||||
const qse_wchar_t* cur;
|
||||
if (qse_sio_flush (sio) <= -1) return -1; /* can't do buffering */
|
||||
for (cur = str, left = qse_wcslen(str); left > 0; cur += count, left -= count)
|
||||
{
|
||||
if (WriteConsoleW (
|
||||
sio->fio.handle, cur, left,
|
||||
&count, QSE_NULL) == FALSE) return -1;
|
||||
if (count == 0) break;
|
||||
}
|
||||
return cur - str;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return qse_tio_writewcs (&sio->tio, str, (qse_size_t)-1);
|
||||
}
|
||||
|
||||
qse_ssize_t qse_sio_putwcsn (
|
||||
qse_sio_t* sio, const qse_wchar_t* str, qse_size_t size)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
/* DAMN UGLY:
|
||||
* WriteFile returns wrong number of bytes written if it is
|
||||
* requested to write a utf8 string on utf8 console (codepage 65001).
|
||||
* it seems to return a number of characters written instead. so
|
||||
* i have to use an alternate API for console output for
|
||||
* wide-character strings. Conversion to either an OEM codepage or
|
||||
* the utf codepage is handled by the API. This hack at least
|
||||
* lets you do proper utf8 output on utf8 console using wide-character.
|
||||
*
|
||||
* Note that the multibyte functions qse_sio_putmbs() and
|
||||
* qse_sio_putmbsn() doesn't handle this. So you may still suffer.
|
||||
*/
|
||||
if (sio->status)
|
||||
{
|
||||
DWORD mode;
|
||||
|
||||
if (GetConsoleMode (sio->fio.handle, &mode) == FALSE)
|
||||
{
|
||||
return qse_tio_writewcs (&sio->tio, str, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD count, left;
|
||||
const qse_wchar_t* cur;
|
||||
|
||||
if (qse_sio_flush (sio) <= -1) return -1; /* can't do buffering */
|
||||
for (cur = str, left = size; left > 0; cur += count, left -= count)
|
||||
{
|
||||
if (WriteConsoleW (
|
||||
sio->fio.handle, cur, left,
|
||||
&count, QSE_NULL) == FALSE) return -1;
|
||||
if (count == 0) break;
|
||||
}
|
||||
return cur - str;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return qse_tio_writewcs (&sio->tio, str, size);
|
||||
}
|
||||
|
||||
@ -271,7 +396,7 @@ static qse_ssize_t __sio_input (
|
||||
|
||||
QSE_ASSERT (sio != QSE_NULL);
|
||||
|
||||
if (cmd == QSE_TIO_IO_DATA)
|
||||
if (cmd == QSE_TIO_DATA)
|
||||
{
|
||||
return qse_fio_read (&sio->fio, buf, size);
|
||||
}
|
||||
@ -286,7 +411,7 @@ static qse_ssize_t __sio_output (
|
||||
|
||||
QSE_ASSERT (sio != QSE_NULL);
|
||||
|
||||
if (cmd == QSE_TIO_IO_DATA)
|
||||
if (cmd == QSE_TIO_DATA)
|
||||
{
|
||||
return qse_fio_write (&sio->fio, buf, size);
|
||||
}
|
||||
|
@ -30,10 +30,10 @@ qse_ssize_t qse_tio_readmbs (qse_tio_t* tio, qse_mchar_t* buf, qse_size_t size)
|
||||
qse_size_t nread;
|
||||
qse_ssize_t n;
|
||||
|
||||
/*QSE_ASSERT (tio->input_func != QSE_NULL);*/
|
||||
if (tio->input_func == QSE_NULL)
|
||||
/*QSE_ASSERT (tio->in.fun != QSE_NULL);*/
|
||||
if (tio->in.fun == QSE_NULL)
|
||||
{
|
||||
tio->errnum = QSE_TIO_ENOINF;
|
||||
tio->errnum = QSE_TIO_ENINPF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -49,13 +49,14 @@ qse_ssize_t qse_tio_readmbs (qse_tio_t* tio, qse_mchar_t* buf, qse_size_t size)
|
||||
{
|
||||
if (tio->inbuf_cur >= tio->inbuf_len)
|
||||
{
|
||||
n = tio->input_func (
|
||||
QSE_TIO_IO_DATA, tio->input_arg,
|
||||
tio->inbuf, QSE_COUNTOF(tio->inbuf));
|
||||
n = tio->in.fun (
|
||||
QSE_TIO_DATA, tio->in.arg,
|
||||
tio->in.buf.ptr,
|
||||
tio->in.buf.capa);
|
||||
if (n == 0) break;
|
||||
if (n <= -1)
|
||||
{
|
||||
tio->errnum = QSE_TIO_EINPUT;
|
||||
tio->errnum = QSE_TIO_EIOERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -65,7 +66,7 @@ qse_ssize_t qse_tio_readmbs (qse_tio_t* tio, qse_mchar_t* buf, qse_size_t size)
|
||||
|
||||
do
|
||||
{
|
||||
buf[nread] = tio->inbuf[tio->inbuf_cur++];
|
||||
buf[nread] = tio->in.buf.ptr[tio->inbuf_cur++];
|
||||
/* TODO: support a different line terminator */
|
||||
if (buf[nread++] == QSE_MT('\n')) goto done;
|
||||
}
|
||||
@ -92,9 +93,10 @@ static QSE_INLINE qse_ssize_t tio_read_widechars (
|
||||
if (tio->input_status & STATUS_EOF) n = 0;
|
||||
else
|
||||
{
|
||||
n = tio->input_func (
|
||||
QSE_TIO_IO_DATA, tio->input_arg,
|
||||
&tio->inbuf[tio->inbuf_len], QSE_COUNTOF(tio->inbuf) - tio->inbuf_len);
|
||||
n = tio->in.fun (
|
||||
QSE_TIO_DATA, tio->in.arg,
|
||||
&tio->in.buf.ptr[tio->inbuf_len],
|
||||
tio->in.buf.capa - tio->inbuf_len);
|
||||
}
|
||||
if (n == 0)
|
||||
{
|
||||
@ -120,7 +122,7 @@ static QSE_INLINE qse_ssize_t tio_read_widechars (
|
||||
}
|
||||
if (n <= -1)
|
||||
{
|
||||
tio->errnum = QSE_TIO_EINPUT;
|
||||
tio->errnum = QSE_TIO_EIOERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -130,7 +132,9 @@ static QSE_INLINE qse_ssize_t tio_read_widechars (
|
||||
mlen = tio->inbuf_len - tio->inbuf_cur;
|
||||
wlen = bufsize;
|
||||
|
||||
x = qse_mbsntowcsnupto (&tio->inbuf[tio->inbuf_cur], &mlen, buf, &wlen, QSE_WT('\n'));
|
||||
x = qse_mbsntowcsnupto (
|
||||
&tio->in.buf.ptr[tio->inbuf_cur],
|
||||
&mlen, buf, &wlen, QSE_WT('\n'));
|
||||
tio->inbuf_cur += mlen;
|
||||
|
||||
if (x == -3)
|
||||
@ -142,9 +146,9 @@ static QSE_INLINE qse_ssize_t tio_read_widechars (
|
||||
* shift bytes in the buffer to the head. */
|
||||
QSE_ASSERT (mlen <= 0);
|
||||
tio->inbuf_len = tio->inbuf_len - tio->inbuf_cur;
|
||||
QSE_MEMCPY (&tio->inbuf[0],
|
||||
&tio->inbuf[tio->inbuf_cur],
|
||||
tio->inbuf_len * QSE_SIZEOF(tio->inbuf[0]));
|
||||
QSE_MEMCPY (&tio->in.buf.ptr[0],
|
||||
&tio->in.buf.ptr[tio->inbuf_cur],
|
||||
tio->inbuf_len * QSE_SIZEOF(tio->in.buf.ptr[0]));
|
||||
tio->inbuf_cur = 0;
|
||||
goto getc_conv; /* and read more */
|
||||
}
|
||||
@ -192,10 +196,10 @@ qse_ssize_t qse_tio_readwcs (qse_tio_t* tio, qse_wchar_t* buf, qse_size_t size)
|
||||
qse_size_t nread = 0;
|
||||
qse_ssize_t n;
|
||||
|
||||
/*QSE_ASSERT (tio->input_func != QSE_NULL);*/
|
||||
if (tio->input_func == QSE_NULL)
|
||||
/*QSE_ASSERT (tio->in.fun != QSE_NULL);*/
|
||||
if (tio->in.fun == QSE_NULL)
|
||||
{
|
||||
tio->errnum = QSE_TIO_ENOINF;
|
||||
tio->errnum = QSE_TIO_ENINPF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
qse_ssize_t qse_tio_writembs (
|
||||
qse_tio_t* tio, const qse_mchar_t* mptr, qse_size_t mlen)
|
||||
{
|
||||
if (tio->outbuf_len >= QSE_COUNTOF(tio->outbuf))
|
||||
if (tio->outbuf_len >= tio->out.buf.capa)
|
||||
{
|
||||
/* maybe, previous flush operation has failed a few
|
||||
* times previously. so the buffer is full.
|
||||
@ -41,8 +41,8 @@ qse_ssize_t qse_tio_writembs (
|
||||
{
|
||||
while (mptr[pos])
|
||||
{
|
||||
tio->outbuf[tio->outbuf_len++] = mptr[pos++];
|
||||
if (tio->outbuf_len >= QSE_COUNTOF(tio->outbuf) &&
|
||||
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;
|
||||
}
|
||||
@ -52,8 +52,8 @@ qse_ssize_t qse_tio_writembs (
|
||||
int nl = 0;
|
||||
while (mptr[pos])
|
||||
{
|
||||
tio->outbuf[tio->outbuf_len++] = mptr[pos];
|
||||
if (tio->outbuf_len >= QSE_COUNTOF(tio->outbuf))
|
||||
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;
|
||||
@ -79,10 +79,10 @@ qse_ssize_t qse_tio_writembs (
|
||||
xptr = mptr;
|
||||
|
||||
/* handle the parts that can't fit into the internal buffer */
|
||||
while (mlen >= (capa = QSE_COUNTOF(tio->outbuf) - tio->outbuf_len))
|
||||
while (mlen >= (capa = tio->out.buf.capa - tio->outbuf_len))
|
||||
{
|
||||
for (xend = xptr + capa; xptr < xend; xptr++)
|
||||
tio->outbuf[tio->outbuf_len++] = *xptr;
|
||||
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
|
||||
if (qse_tio_flush (tio) <= -1) return -1;
|
||||
mlen -= capa;
|
||||
}
|
||||
@ -91,7 +91,7 @@ qse_ssize_t qse_tio_writembs (
|
||||
{
|
||||
/* handle the last part that can fit into the internal buffer */
|
||||
for (xend = xptr + mlen; xptr < xend; xptr++)
|
||||
tio->outbuf[tio->outbuf_len++] = *xptr;
|
||||
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -99,14 +99,14 @@ qse_ssize_t qse_tio_writembs (
|
||||
for (xend = xptr + mlen; xptr < xend; xptr++)
|
||||
{
|
||||
/* TODO: support different line terminating characeter */
|
||||
tio->outbuf[tio->outbuf_len++] = *xptr;
|
||||
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
|
||||
if (*xptr == QSE_MT('\n'))
|
||||
{
|
||||
nl = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (xptr < xend) tio->outbuf[tio->outbuf_len++] = *xptr++;
|
||||
while (xptr < xend) tio->out.buf.ptr[tio->outbuf_len++] = *xptr++;
|
||||
}
|
||||
|
||||
/* if the last part contains a new line, flush the internal
|
||||
@ -124,7 +124,7 @@ qse_ssize_t qse_tio_writewcs (
|
||||
qse_size_t capa, wcnt, mcnt, xwlen;
|
||||
int n, nl = 0;
|
||||
|
||||
if (tio->outbuf_len >= QSE_COUNTOF(tio->outbuf))
|
||||
if (tio->outbuf_len >= tio->out.buf.capa)
|
||||
{
|
||||
/* maybe, previous flush operation has failed a few
|
||||
* times previously. so the buffer is full.
|
||||
@ -139,11 +139,11 @@ qse_ssize_t qse_tio_writewcs (
|
||||
xwlen = wlen;
|
||||
while (xwlen > 0)
|
||||
{
|
||||
capa = QSE_COUNTOF(tio->outbuf) - tio->outbuf_len;
|
||||
capa = tio->out.buf.capa - tio->outbuf_len;
|
||||
wcnt = xwlen; mcnt = capa;
|
||||
|
||||
n = qse_wcsntombsn (
|
||||
wptr, &wcnt, &tio->outbuf[tio->outbuf_len], &mcnt);
|
||||
wptr, &wcnt, &tio->out.buf.ptr[tio->outbuf_len], &mcnt);
|
||||
tio->outbuf_len += mcnt;
|
||||
|
||||
if (n == -2)
|
||||
@ -157,7 +157,7 @@ qse_ssize_t qse_tio_writewcs (
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tio->outbuf_len >= QSE_COUNTOF(tio->outbuf))
|
||||
if (tio->outbuf_len >= tio->out.buf.capa)
|
||||
{
|
||||
/* flush the full buffer regardless of conversion
|
||||
* result. */
|
||||
@ -172,8 +172,8 @@ qse_ssize_t qse_tio_writewcs (
|
||||
{
|
||||
/* insert a question mark for an illegal
|
||||
* character. */
|
||||
QSE_ASSERT (tio->outbuf_len < QSE_COUNTOF(tio->outbuf));
|
||||
tio->outbuf[tio->outbuf_len++] = QSE_MT('?');
|
||||
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 */
|
||||
|
@ -23,6 +23,9 @@
|
||||
|
||||
QSE_IMPLEMENT_COMMON_FUNCTIONS (tio)
|
||||
|
||||
static int detach_in (qse_tio_t* tio, int fini);
|
||||
static int detach_out (qse_tio_t* tio, int fini);
|
||||
|
||||
qse_tio_t* qse_tio_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, int flags)
|
||||
{
|
||||
qse_tio_t* tio;
|
||||
@ -63,7 +66,8 @@ int qse_tio_init (qse_tio_t* tio, qse_mmgr_t* mmgr, int flags)
|
||||
QSE_MEMSET (tio, 0, QSE_SIZEOF(*tio));
|
||||
|
||||
tio->mmgr = mmgr;
|
||||
tio->flags = flags;
|
||||
/* mask off internal bits when storing the flags for safety */
|
||||
tio->flags = flags & ~(QSE_TIO_DYNINBUF | QSE_TIO_DYNOUTBUF);
|
||||
|
||||
/*
|
||||
tio->input_func = QSE_NULL;
|
||||
@ -83,10 +87,13 @@ int qse_tio_init (qse_tio_t* tio, qse_mmgr_t* mmgr, int flags)
|
||||
|
||||
int qse_tio_fini (qse_tio_t* tio)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
qse_tio_flush (tio); /* don't care about the result */
|
||||
if (qse_tio_detachin(tio) == -1) return -1;
|
||||
if (qse_tio_detachout(tio) == -1) return -1;
|
||||
return 0;
|
||||
if (detach_in (tio, 1) <= -1) ret = -1;
|
||||
if (detach_out (tio, 1) <= -1) ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
qse_tio_errnum_t qse_tio_geterrnum (qse_tio_t* tio)
|
||||
@ -100,18 +107,14 @@ const qse_char_t* qse_tio_geterrmsg (qse_tio_t* tio)
|
||||
{
|
||||
QSE_T("no error"),
|
||||
QSE_T("out of memory"),
|
||||
QSE_T("invalid parameter"),
|
||||
QSE_T("no more space"),
|
||||
QSE_T("illegal multibyte sequence"),
|
||||
QSE_T("incomplete multibyte sequence"),
|
||||
QSE_T("illegal wide character"),
|
||||
QSE_T("no input function attached"),
|
||||
QSE_T("input function returned an error"),
|
||||
QSE_T("input function failed to open"),
|
||||
QSE_T("input function failed to closed"),
|
||||
QSE_T("no output function attached"),
|
||||
QSE_T("output function returned an error"),
|
||||
QSE_T("output function failed to open"),
|
||||
QSE_T("output function failed to closed"),
|
||||
QSE_T("I/O error"),
|
||||
QSE_T("unknown error")
|
||||
};
|
||||
|
||||
@ -120,112 +123,219 @@ const qse_char_t* qse_tio_geterrmsg (qse_tio_t* tio)
|
||||
QSE_COUNTOF(__errmsg) - 1: tio->errnum];
|
||||
}
|
||||
|
||||
int qse_tio_attachin (qse_tio_t* tio, qse_tio_io_t input, void* arg)
|
||||
int qse_tio_attachin (
|
||||
qse_tio_t* tio, qse_tio_io_fun_t input, void* arg,
|
||||
qse_mchar_t* bufptr, qse_size_t bufcapa)
|
||||
{
|
||||
if (qse_tio_detachin(tio) == -1) return -1;
|
||||
qse_mchar_t* xbufptr;
|
||||
|
||||
QSE_ASSERT (tio->input_func == QSE_NULL);
|
||||
|
||||
if (input(QSE_TIO_IO_OPEN, arg, QSE_NULL, 0) == -1)
|
||||
if (input == QSE_NULL || bufcapa < QSE_TIO_MININBUFCAPA)
|
||||
{
|
||||
tio->errnum = QSE_TIO_EINPOP;
|
||||
tio->errnum = QSE_TIO_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tio->input_func = input;
|
||||
tio->input_arg = arg;
|
||||
if (qse_tio_detachin(tio) <= -1) return -1;
|
||||
|
||||
QSE_ASSERT (tio->in.fun == QSE_NULL);
|
||||
|
||||
xbufptr = bufptr;
|
||||
if (xbufptr == QSE_NULL)
|
||||
{
|
||||
xbufptr = QSE_MMGR_ALLOC (
|
||||
tio->mmgr, QSE_SIZEOF(qse_mchar_t) * bufcapa);
|
||||
if (xbufptr == QSE_NULL)
|
||||
{
|
||||
tio->errnum = QSE_TIO_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (input (QSE_TIO_OPEN, arg, QSE_NULL, 0) <= -1)
|
||||
{
|
||||
if (xbufptr != bufptr) QSE_MMGR_FREE (tio->mmgr, xbufptr);
|
||||
tio->errnum = QSE_TIO_EIOERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if i defined tio->io[2] instead of tio->in and tio-out,
|
||||
* i would be able to shorten code amount. but fields to initialize
|
||||
* are not symmetric between input and output.
|
||||
* so it's just a bit clumsy that i repeat almost the same code
|
||||
* in qse_tio_attachout().
|
||||
*/
|
||||
|
||||
tio->in.fun = input;
|
||||
tio->in.arg = arg;
|
||||
tio->in.buf.ptr = xbufptr;
|
||||
tio->in.buf.capa = bufcapa;
|
||||
|
||||
tio->input_status = 0;
|
||||
tio->inbuf_cur = 0;
|
||||
tio->inbuf_len = 0;
|
||||
|
||||
if (xbufptr != bufptr) tio->flags |= QSE_TIO_DYNINBUF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int detach_in (qse_tio_t* tio, int fini)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (tio->in.fun)
|
||||
{
|
||||
if (tio->in.fun (
|
||||
QSE_TIO_CLOSE, tio->in.arg, QSE_NULL, 0) <= -1)
|
||||
{
|
||||
tio->errnum = QSE_TIO_EIOERR;
|
||||
|
||||
/* returning with an error here allows you to retry detaching */
|
||||
if (!fini) return -1;
|
||||
|
||||
/* otherwise, you can't retry since the input handler information
|
||||
* is reset below */
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (tio->flags & QSE_TIO_DYNINBUF)
|
||||
{
|
||||
QSE_MMGR_FREE (tio->mmgr, tio->in.buf.ptr);
|
||||
tio->flags &= ~QSE_TIO_DYNINBUF;
|
||||
}
|
||||
|
||||
tio->in.fun = QSE_NULL;
|
||||
tio->in.arg = QSE_NULL;
|
||||
tio->in.buf.ptr = QSE_NULL;
|
||||
tio->in.buf.capa = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qse_tio_detachin (qse_tio_t* tio)
|
||||
{
|
||||
if (tio->input_func != QSE_NULL)
|
||||
{
|
||||
if (tio->input_func (
|
||||
QSE_TIO_IO_CLOSE, tio->input_arg, QSE_NULL, 0) == -1)
|
||||
{
|
||||
tio->errnum = QSE_TIO_EINPCL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tio->input_func = QSE_NULL;
|
||||
tio->input_arg = QSE_NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return detach_in (tio, 0);
|
||||
}
|
||||
|
||||
int qse_tio_attachout (qse_tio_t* tio, qse_tio_io_t output, void* arg)
|
||||
int qse_tio_attachout (
|
||||
qse_tio_t* tio, qse_tio_io_fun_t output, void* arg,
|
||||
qse_mchar_t* bufptr, qse_size_t bufcapa)
|
||||
{
|
||||
if (qse_tio_detachout(tio) == -1) return -1;
|
||||
qse_mchar_t* xbufptr;
|
||||
|
||||
QSE_ASSERT (tio->output_func == QSE_NULL);
|
||||
|
||||
if (output(QSE_TIO_IO_OPEN, arg, QSE_NULL, 0) == -1)
|
||||
if (output == QSE_NULL || bufcapa < QSE_TIO_MINOUTBUFCAPA)
|
||||
{
|
||||
tio->errnum = QSE_TIO_EOUTOP;
|
||||
tio->errnum = QSE_TIO_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tio->output_func = output;
|
||||
tio->output_arg = arg;
|
||||
if (qse_tio_detachout(tio) == -1) return -1;
|
||||
|
||||
QSE_ASSERT (tio->out.fun == QSE_NULL);
|
||||
|
||||
xbufptr = bufptr;
|
||||
if (xbufptr == QSE_NULL)
|
||||
{
|
||||
xbufptr = QSE_MMGR_ALLOC (
|
||||
tio->mmgr, QSE_SIZEOF(qse_mchar_t) * bufcapa);
|
||||
if (xbufptr == QSE_NULL)
|
||||
{
|
||||
tio->errnum = QSE_TIO_ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (output (QSE_TIO_OPEN, arg, QSE_NULL, 0) == -1)
|
||||
{
|
||||
if (xbufptr != bufptr) QSE_MMGR_FREE (tio->mmgr, xbufptr);
|
||||
tio->errnum = QSE_TIO_EIOERR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tio->out.fun = output;
|
||||
tio->out.arg = arg;
|
||||
tio->out.buf.ptr = xbufptr;
|
||||
tio->out.buf.capa = bufcapa;
|
||||
|
||||
tio->outbuf_len = 0;
|
||||
|
||||
if (xbufptr != bufptr) tio->flags |= QSE_TIO_DYNOUTBUF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int detach_out (qse_tio_t* tio, int fini)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (tio->out.fun)
|
||||
{
|
||||
qse_tio_flush (tio); /* don't care about the result */
|
||||
|
||||
if (tio->out.fun (
|
||||
QSE_TIO_CLOSE, tio->out.arg, QSE_NULL, 0) <= -1)
|
||||
{
|
||||
tio->errnum = QSE_TIO_EIOERR;
|
||||
/* returning with an error here allows you to retry detaching */
|
||||
if (!fini) return -1;
|
||||
|
||||
/* otherwise, you can't retry since the input handler information
|
||||
* is reset below */
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (tio->flags & QSE_TIO_DYNOUTBUF)
|
||||
{
|
||||
QSE_MMGR_FREE (tio->mmgr, tio->out.buf.ptr);
|
||||
tio->flags &= ~QSE_TIO_DYNOUTBUF;
|
||||
}
|
||||
|
||||
tio->out.fun = QSE_NULL;
|
||||
tio->out.arg = QSE_NULL;
|
||||
tio->out.buf.ptr = QSE_NULL;
|
||||
tio->out.buf.capa = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qse_tio_detachout (qse_tio_t* tio)
|
||||
{
|
||||
if (tio->output_func != QSE_NULL)
|
||||
{
|
||||
qse_tio_flush (tio); /* don't care about the result */
|
||||
|
||||
if (tio->output_func (
|
||||
QSE_TIO_IO_CLOSE, tio->output_arg, QSE_NULL, 0) == -1)
|
||||
{
|
||||
tio->errnum = QSE_TIO_EOUTCL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tio->output_func = QSE_NULL;
|
||||
tio->output_arg = QSE_NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return detach_out (tio, 0);
|
||||
}
|
||||
|
||||
qse_ssize_t qse_tio_flush (qse_tio_t* tio)
|
||||
{
|
||||
qse_size_t left, count;
|
||||
qse_ssize_t n;
|
||||
qse_mchar_t* cur;
|
||||
|
||||
if (tio->output_func == QSE_NULL)
|
||||
if (tio->out.fun == QSE_NULL)
|
||||
{
|
||||
tio->errnum = QSE_TIO_ENOUTF;
|
||||
return (qse_ssize_t)-1;
|
||||
}
|
||||
|
||||
left = tio->outbuf_len;
|
||||
cur = tio->out.buf.ptr;
|
||||
while (left > 0)
|
||||
{
|
||||
qse_ssize_t n;
|
||||
|
||||
n = tio->output_func (
|
||||
QSE_TIO_IO_DATA, tio->output_arg, tio->outbuf, left);
|
||||
n = tio->out.fun (
|
||||
QSE_TIO_DATA, tio->out.arg, cur, left);
|
||||
if (n <= -1)
|
||||
{
|
||||
QSE_MEMCPY (tio->out.buf.ptr, cur, left);
|
||||
tio->outbuf_len = left;
|
||||
tio->errnum = QSE_TIO_EOUTPT;
|
||||
tio->errnum = QSE_TIO_EIOERR;
|
||||
return -1;
|
||||
}
|
||||
if (n == 0) break;
|
||||
if (n == 0)
|
||||
{
|
||||
QSE_MEMCPY (tio->out.buf.ptr, cur, left);
|
||||
break;
|
||||
}
|
||||
|
||||
left -= n;
|
||||
QSE_MEMCPY (tio->outbuf, &tio->inbuf[n], left);
|
||||
cur += n;
|
||||
}
|
||||
|
||||
count = tio->outbuf_len - left;
|
||||
|
Reference in New Issue
Block a user