added aio files. some file restructuring in progress

This commit is contained in:
2016-04-27 14:57:50 +00:00
parent 632a4d7181
commit 61a6cf281f
68 changed files with 7385 additions and 143 deletions

View File

@ -44,7 +44,6 @@ libqsecmn_la_SOURCES = \
env.c \
gdl.c \
htb.c \
fio.c \
fma.c \
fmt-intmax.c \
fmt-out.c \
@ -68,19 +67,16 @@ libqsecmn_la_SOURCES = \
nwad-skad.c \
nwif.c \
nwif-cfg.c \
nwio.c \
oht.c \
opt.c \
path-base.c \
path-canon.c \
path-core.c \
path-merge.c \
pio.c \
pma.c \
rbt.c \
rex.c \
sck.c \
sio.c \
sll.c \
slmb.c \
str-beg.c \
@ -113,9 +109,7 @@ libqsecmn_la_SOURCES = \
str-tok.c \
str-trm.c \
str-word.c \
task.c \
time.c \
tio.c \
tmr.c \
tre.c \
tre-ast.c \

View File

@ -133,37 +133,37 @@ am__DEPENDENCIES_1 =
libqsecmn_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
am__libqsecmn_la_SOURCES_DIST = alg-base64.c alg-rand.c alg-search.c \
alg-sort.c assert.c chr.c dir.c dll.c env.c gdl.c htb.c fio.c \
fma.c fmt-intmax.c fmt-out.c fs.c fs-attr.c fs-copy.c \
fs-delete.c fs-err.c fs-make.c fs-move.c glob.c hton.c ipad.c \
lda.c main.c mb8.c mbwc.c mbwc-str.c mem.c nwad.c nwad-skad.c \
nwif.c nwif-cfg.c nwio.c oht.c opt.c path-base.c path-canon.c \
path-core.c path-merge.c pio.c pma.c rbt.c rex.c sck.c sio.c \
sll.c slmb.c str-beg.c str-cat.c str-chr.c str-cnv.c str-cmp.c \
str-cpy.c str-del.c str-dup.c str-dyn.c str-end.c str-excl.c \
str-fcpy.c str-fmt.c str-fnmat.c str-incl.c str-join.c \
str-len.c str-pac.c str-pbrk.c str-put.c str-rev.c str-rot.c \
str-set.c str-spl.c str-spn.c str-str.c str-subst.c str-tok.c \
str-trm.c str-word.c task.c time.c tio.c tmr.c tre.c tre-ast.c \
tre-compile.c tre-match-bt.c tre-match-pa.c tre-parse.c \
tre-stack.c uri.c utf8.c xma.c uni.c cp949.c cp950.c
alg-sort.c assert.c chr.c dir.c dll.c env.c gdl.c htb.c fma.c \
fmt-intmax.c fmt-out.c fs.c fs-attr.c fs-copy.c fs-delete.c \
fs-err.c fs-make.c fs-move.c glob.c hton.c ipad.c lda.c main.c \
mb8.c mbwc.c mbwc-str.c mem.c nwad.c nwad-skad.c nwif.c \
nwif-cfg.c oht.c opt.c path-base.c path-canon.c path-core.c \
path-merge.c pma.c rbt.c rex.c sck.c sll.c slmb.c str-beg.c \
str-cat.c str-chr.c str-cnv.c str-cmp.c str-cpy.c str-del.c \
str-dup.c str-dyn.c str-end.c str-excl.c str-fcpy.c str-fmt.c \
str-fnmat.c str-incl.c str-join.c str-len.c str-pac.c \
str-pbrk.c str-put.c str-rev.c str-rot.c str-set.c str-spl.c \
str-spn.c str-str.c str-subst.c str-tok.c str-trm.c str-word.c \
time.c tmr.c tre.c tre-ast.c tre-compile.c tre-match-bt.c \
tre-match-pa.c tre-parse.c tre-stack.c uri.c utf8.c xma.c \
uni.c cp949.c cp950.c
@ENABLE_BUNDLED_UNICODE_TRUE@am__objects_1 = uni.lo
@ENABLE_XCMGRS_TRUE@am__objects_2 = cp949.lo cp950.lo
am_libqsecmn_la_OBJECTS = alg-base64.lo alg-rand.lo alg-search.lo \
alg-sort.lo assert.lo chr.lo dir.lo dll.lo env.lo gdl.lo \
htb.lo fio.lo fma.lo fmt-intmax.lo fmt-out.lo fs.lo fs-attr.lo \
htb.lo fma.lo fmt-intmax.lo fmt-out.lo fs.lo fs-attr.lo \
fs-copy.lo fs-delete.lo fs-err.lo fs-make.lo fs-move.lo \
glob.lo hton.lo ipad.lo lda.lo main.lo mb8.lo mbwc.lo \
mbwc-str.lo mem.lo nwad.lo nwad-skad.lo nwif.lo nwif-cfg.lo \
nwio.lo oht.lo opt.lo path-base.lo path-canon.lo path-core.lo \
path-merge.lo pio.lo pma.lo rbt.lo rex.lo sck.lo sio.lo sll.lo \
slmb.lo str-beg.lo str-cat.lo str-chr.lo str-cnv.lo str-cmp.lo \
oht.lo opt.lo path-base.lo path-canon.lo path-core.lo \
path-merge.lo pma.lo rbt.lo rex.lo sck.lo sll.lo slmb.lo \
str-beg.lo str-cat.lo str-chr.lo str-cnv.lo str-cmp.lo \
str-cpy.lo str-del.lo str-dup.lo str-dyn.lo str-end.lo \
str-excl.lo str-fcpy.lo str-fmt.lo str-fnmat.lo str-incl.lo \
str-join.lo str-len.lo str-pac.lo str-pbrk.lo str-put.lo \
str-rev.lo str-rot.lo str-set.lo str-spl.lo str-spn.lo \
str-str.lo str-subst.lo str-tok.lo str-trm.lo str-word.lo \
task.lo time.lo tio.lo tmr.lo tre.lo tre-ast.lo tre-compile.lo \
time.lo tmr.lo tre.lo tre-ast.lo tre-compile.lo \
tre-match-bt.lo tre-match-pa.lo tre-parse.lo tre-stack.lo \
uri.lo utf8.lo xma.lo $(am__objects_1) $(am__objects_2)
libqsecmn_la_OBJECTS = $(am_libqsecmn_la_OBJECTS)
@ -474,20 +474,20 @@ noinst_HEADERS = \
uni-trait.h
libqsecmn_la_SOURCES = alg-base64.c alg-rand.c alg-search.c alg-sort.c \
assert.c chr.c dir.c dll.c env.c gdl.c htb.c fio.c fma.c \
assert.c chr.c dir.c dll.c env.c gdl.c htb.c fma.c \
fmt-intmax.c fmt-out.c fs.c fs-attr.c fs-copy.c fs-delete.c \
fs-err.c fs-make.c fs-move.c glob.c hton.c ipad.c lda.c main.c \
mb8.c mbwc.c mbwc-str.c mem.c nwad.c nwad-skad.c nwif.c \
nwif-cfg.c nwio.c oht.c opt.c path-base.c path-canon.c \
path-core.c path-merge.c pio.c pma.c rbt.c rex.c sck.c sio.c \
sll.c slmb.c str-beg.c str-cat.c str-chr.c str-cnv.c str-cmp.c \
str-cpy.c str-del.c str-dup.c str-dyn.c str-end.c str-excl.c \
str-fcpy.c str-fmt.c str-fnmat.c str-incl.c str-join.c \
str-len.c str-pac.c str-pbrk.c str-put.c str-rev.c str-rot.c \
str-set.c str-spl.c str-spn.c str-str.c str-subst.c str-tok.c \
str-trm.c str-word.c task.c time.c tio.c tmr.c tre.c tre-ast.c \
tre-compile.c tre-match-bt.c tre-match-pa.c tre-parse.c \
tre-stack.c uri.c utf8.c xma.c $(am__append_1) $(am__append_2)
nwif-cfg.c oht.c opt.c path-base.c path-canon.c path-core.c \
path-merge.c pma.c rbt.c rex.c sck.c sll.c slmb.c str-beg.c \
str-cat.c str-chr.c str-cnv.c str-cmp.c str-cpy.c str-del.c \
str-dup.c str-dyn.c str-end.c str-excl.c str-fcpy.c str-fmt.c \
str-fnmat.c str-incl.c str-join.c str-len.c str-pac.c \
str-pbrk.c str-put.c str-rev.c str-rot.c str-set.c str-spl.c \
str-spn.c str-str.c str-subst.c str-tok.c str-trm.c str-word.c \
time.c tmr.c tre.c tre-ast.c tre-compile.c tre-match-bt.c \
tre-match-pa.c tre-parse.c tre-stack.c uri.c utf8.c xma.c \
$(am__append_1) $(am__append_2)
libqsecmn_la_LDFLAGS = -version-info 1:0:0 -no-undefined
libqsecmn_la_LIBADD = $(SOCKET_LIBS) $(QUADMATH_LIBS)
@ENABLE_CXX_TRUE@libqsecmnxx_la_SOURCES = \
@ -594,7 +594,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dir.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dll.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/env.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fma.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt-intmax.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmt-out.Plo@am__quote@
@ -620,19 +619,16 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nwad.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nwif-cfg.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nwif.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nwio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oht.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-base.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-canon.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-core.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path-merge.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pma.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rbt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rex.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sck.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sll.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slmb.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-beg.Plo@am__quote@
@ -665,9 +661,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-tok.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-trm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str-word.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tmr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tre-ast.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tre-compile.Plo@am__quote@

View File

@ -26,7 +26,7 @@
#include <qse/types.h>
#include <qse/macros.h>
#include <qse/cmn/sio.h>
#include <qse/io/sio.h>
#include "mem.h"
#if defined(HAVE_EXECINFO_H)

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@
#include <qse/cmn/nwif.h>
#include <qse/cmn/str.h>
#include <qse/cmn/mbwc.h>
#include <qse/cmn/sio.h>
#include <qse/io/sio.h>
#include "mem.h"
#if defined(_WIN32)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,982 +0,0 @@
/*
* $Id$
*
Copyright (c) 2006-2014 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.
*/
#include <qse/cmn/sio.h>
#include <qse/cmn/mbwc.h>
#include "mem.h"
#include "fmt.h"
#if defined(_WIN32)
# include <windows.h> /* for the UGLY hack */
#elif defined(__OS2__)
/* nothing */
#elif defined(__DOS__)
/* nothing */
#else
# include "syscall.h"
#endif
/* internal status codes */
enum
{
STATUS_UTF8_CONSOLE = (1 << 0),
STATUS_LINE_BREAK = (1 << 1)
};
static qse_ssize_t file_input (
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size);
static qse_ssize_t file_output (
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size);
static qse_sio_errnum_t fio_errnum_to_sio_errnum (qse_fio_t* fio)
{
switch (fio->errnum)
{
case QSE_FIO_ENOMEM:
return QSE_SIO_ENOMEM;
case QSE_FIO_EINVAL:
return QSE_SIO_EINVAL;
case QSE_FIO_EACCES:
return QSE_SIO_EACCES;
case QSE_FIO_ENOENT:
return QSE_SIO_ENOENT;
case QSE_FIO_EEXIST:
return QSE_SIO_EEXIST;
case QSE_FIO_EINTR:
return QSE_SIO_EINTR;
case QSE_FIO_EPIPE:
return QSE_SIO_EPIPE;
case QSE_FIO_EAGAIN:
return QSE_SIO_EAGAIN;
case QSE_FIO_ESYSERR:
return QSE_SIO_ESYSERR;
case QSE_FIO_ENOIMPL:
return QSE_SIO_ENOIMPL;
default:
return QSE_SIO_EOTHER;
}
}
static qse_sio_errnum_t tio_errnum_to_sio_errnum (qse_tio_t* tio)
{
switch (tio->errnum)
{
case QSE_TIO_ENOMEM:
return QSE_SIO_ENOMEM;
case QSE_TIO_EINVAL:
return QSE_SIO_EINVAL;
case QSE_TIO_EACCES:
return QSE_SIO_EACCES;
case QSE_TIO_ENOENT:
return QSE_SIO_ENOENT;
case QSE_TIO_EILSEQ:
return QSE_SIO_EILSEQ;
case QSE_TIO_EICSEQ:
return QSE_SIO_EICSEQ;
case QSE_TIO_EILCHR:
return QSE_SIO_EILCHR;
default:
return QSE_SIO_EOTHER;
}
}
qse_sio_t* qse_sio_open (
qse_mmgr_t* mmgr, qse_size_t xtnsize, const qse_char_t* file, int flags)
{
qse_sio_t* sio;
sio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_sio_t) + xtnsize);
if (sio)
{
if (qse_sio_init (sio, mmgr, file, flags) <= -1)
{
QSE_MMGR_FREE (mmgr, sio);
return QSE_NULL;
}
else QSE_MEMSET (QSE_XTN(sio), 0, xtnsize);
}
return sio;
}
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;
/* Is this necessary?
if (flags & QSE_SIO_KEEPATH)
{
sio->errnum = QSE_SIO_EINVAL;
return QSE_NULL;
}
*/
if (qse_getstdfiohandle (std, &hnd) <= -1) return QSE_NULL;
sio = qse_sio_open (mmgr, xtnsize,
(const qse_char_t*)&hnd, flags | QSE_SIO_HANDLE | QSE_SIO_NOCLOSE);
#if defined(_WIN32)
if (sio)
{
DWORD mode;
if (GetConsoleMode (sio->file.handle, &mode) == TRUE &&
GetConsoleOutputCP() == CP_UTF8)
{
sio->status |= STATUS_UTF8_CONSOLE;
}
}
#endif
return sio;
}
void qse_sio_close (qse_sio_t* sio)
{
qse_sio_fini (sio);
QSE_MMGR_FREE (sio->mmgr, sio);
}
int qse_sio_init (
qse_sio_t* sio, qse_mmgr_t* mmgr, const qse_char_t* path, int flags)
{
int mode;
int topt = 0;
QSE_MEMSET (sio, 0, QSE_SIZEOF(*sio));
sio->mmgr = mmgr;
mode = QSE_FIO_RUSR | QSE_FIO_WUSR |
QSE_FIO_RGRP | QSE_FIO_ROTH;
/* sio flag enumerators redefines most fio flag enumerators and
* compose a superset of fio flag enumerators. when a user calls
* this function, a user can specify a sio flag enumerator not
* present in the fio flag enumerator. mask off such an enumerator. */
if (qse_fio_init (
&sio->file, mmgr, path,
(flags & ~QSE_FIO_RESERVED), mode) <= -1)
{
sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
goto oops00;
}
if (flags & QSE_SIO_IGNOREMBWCERR) topt |= QSE_TIO_IGNOREMBWCERR;
if (flags & QSE_SIO_NOAUTOFLUSH) topt |= QSE_TIO_NOAUTOFLUSH;
if ((flags & QSE_SIO_KEEPPATH) && !(flags & QSE_SIO_HANDLE))
{
sio->path = qse_strdup (path, sio->mmgr);
if (sio->path == QSE_NULL)
{
sio->errnum = QSE_SIO_ENOMEM;
goto oops01;
}
}
if (qse_tio_init(&sio->tio.io, mmgr, topt) <= -1)
{
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
goto oops02;
}
/* store the back-reference to sio in the extension area.*/
QSE_ASSERT (QSE_XTN(&sio->tio.io) == &sio->tio.xtn);
*(qse_sio_t**)QSE_XTN(&sio->tio.io) = sio;
if (qse_tio_attachin (&sio->tio.io, file_input, sio->inbuf, QSE_COUNTOF(sio->inbuf)) <= -1 ||
qse_tio_attachout (&sio->tio.io, file_output, sio->outbuf, QSE_COUNTOF(sio->outbuf)) <= -1)
{
if (sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
goto oops03;
}
#if defined(__OS2__)
if (flags & QSE_SIO_LINEBREAK) sio->status |= STATUS_LINE_BREAK;
#endif
return 0;
oops03:
qse_tio_fini (&sio->tio.io);
oops02:
if (sio->path) QSE_MMGR_FREE (sio->mmgr, sio->path);
oops01:
qse_fio_fini (&sio->file);
oops00:
return -1;
}
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;
n = qse_sio_init (sio, mmgr,
(const qse_char_t*)&hnd, flags | QSE_SIO_HANDLE | QSE_SIO_NOCLOSE);
#if defined(_WIN32)
if (n >= 0)
{
DWORD mode;
if (GetConsoleMode (sio->file.handle, &mode) == TRUE &&
GetConsoleOutputCP() == CP_UTF8)
{
sio->status |= STATUS_UTF8_CONSOLE;
}
}
#endif
return n;
}
void qse_sio_fini (qse_sio_t* sio)
{
/*if (qse_sio_flush (sio) <= -1) return -1;*/
qse_sio_flush (sio);
qse_tio_fini (&sio->tio.io);
qse_fio_fini (&sio->file);
if (sio->path) QSE_MMGR_FREE (sio->mmgr, sio->path);
}
qse_mmgr_t* qse_sio_getmmgr (qse_sio_t* sio)
{
return sio->mmgr;
}
void* qse_sio_getxtn (qse_sio_t* sio)
{
return QSE_XTN (sio);
}
qse_sio_errnum_t qse_sio_geterrnum (const qse_sio_t* sio)
{
return sio->errnum;
}
qse_cmgr_t* qse_sio_getcmgr (qse_sio_t* sio)
{
return qse_tio_getcmgr (&sio->tio.io);
}
void qse_sio_setcmgr (qse_sio_t* sio, qse_cmgr_t* cmgr)
{
qse_tio_setcmgr (&sio->tio.io, cmgr);
}
qse_sio_hnd_t qse_sio_gethandle (const qse_sio_t* sio)
{
/*return qse_fio_gethandle (&sio->file);*/
return QSE_FIO_HANDLE(&sio->file);
}
const qse_char_t* qse_sio_getpath (qse_sio_t* sio)
{
/* this path is valid if QSE_SIO_HANDLE is off and QSE_SIO_KEEPPATH is on */
return sio->path;
}
qse_ssize_t qse_sio_flush (qse_sio_t* sio)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_flush (&sio->tio.io);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
void qse_sio_drain (qse_sio_t* sio)
{
qse_tio_drain (&sio->tio.io);
}
qse_ssize_t qse_sio_getmb (qse_sio_t* sio, qse_mchar_t* c)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readmbs (&sio->tio.io, c, 1);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_getwc (qse_sio_t* sio, qse_wchar_t* c)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readwcs (&sio->tio.io, c, 1);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_getmbs (
qse_sio_t* sio, qse_mchar_t* buf, qse_size_t size)
{
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
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readmbs (&sio->tio.io, buf, size - 1);
if (n <= -1)
{
if (sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return -1;
}
buf[n] = QSE_MT('\0');
return n;
}
qse_ssize_t qse_sio_getmbsn (
qse_sio_t* sio, qse_mchar_t* buf, qse_size_t size)
{
qse_ssize_t n;
#if defined(_WIN32)
/* Using ReadConsoleA() didn't help at all.
* so I don't implement any hack here */
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readmbs (&sio->tio.io, buf, size);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_getwcs (
qse_sio_t* sio, qse_wchar_t* buf, qse_size_t size)
{
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
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readwcs (&sio->tio.io, buf, size - 1);
if (n <= -1)
{
if (sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return -1;
}
buf[n] = QSE_WT('\0');
return n;
}
qse_ssize_t qse_sio_getwcsn (
qse_sio_t* sio, qse_wchar_t* buf, qse_size_t size)
{
qse_ssize_t n;
#if defined(_WIN32)
/* Using ReadConsoleW() didn't help at all.
* so I don't implement any hack here */
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readwcs (&sio->tio.io, buf, size);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putmb (qse_sio_t* sio, qse_mchar_t c)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
#if defined(__OS2__)
if (c == QSE_MT('\n') && (sio->status & STATUS_LINE_BREAK))
n = qse_tio_writembs (&sio->tio.io, QSE_MT("\r\n"), 2);
else
n = qse_tio_writembs (&sio->tio.io, &c, 1);
#else
n = qse_tio_writembs (&sio->tio.io, &c, 1);
#endif
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putwc (qse_sio_t* sio, qse_wchar_t c)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
#if defined(__OS2__)
if (c == QSE_WT('\n') && (sio->status & STATUS_LINE_BREAK))
n = qse_tio_writewcs (&sio->tio.io, QSE_WT("\r\n"), 2);
else
n = qse_tio_writewcs (&sio->tio.io, &c, 1);
#else
n = qse_tio_writewcs (&sio->tio.io, &c, 1);
#endif
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putmbs (qse_sio_t* sio, const qse_mchar_t* str)
{
qse_ssize_t n;
#if defined(_WIN32)
/* Using WriteConsoleA() didn't help at all.
* so I don't implement any hacks here */
#elif defined(__OS2__)
if (sio->status & STATUS_LINE_BREAK)
{
for (n = 0; n < QSE_TYPE_MAX(qse_ssize_t) && str[n] != QSE_MT('\0'); n++)
{
if ((n = qse_sio_putmb (sio, str[n])) <= -1) return n;
}
return n;
}
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_writembs (&sio->tio.io, str, (qse_size_t)-1);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putmbsn (
qse_sio_t* sio, const qse_mchar_t* str, qse_size_t size)
{
qse_ssize_t n;
#if defined(_WIN32)
/* Using WriteConsoleA() didn't help at all.
* so I don't implement any hacks here */
#elif defined(__OS2__)
if (sio->status & STATUS_LINE_BREAK)
{
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
for (n = 0; n < size; n++)
{
if (qse_sio_putmb (sio, str[n]) <= -1) return -1;
}
return n;
}
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_writembs (&sio->tio.io, str, size);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putwcs (qse_sio_t* sio, const qse_wchar_t* str)
{
qse_ssize_t n;
#if defined(_WIN32)
/* DAMN UGLY: See comment in qse_sio_putwcsn() */
if (sio->status & STATUS_UTF8_CONSOLE)
{
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->file.handle, cur, left,
&count, QSE_NULL) == FALSE)
{
sio->errnum = QSE_SIO_ESYSERR;
return -1;
}
if (count == 0) break;
if (count > left)
{
sio->errnum = QSE_SIO_ESYSERR;
return -1;
}
}
return cur - str;
}
#elif defined(__OS2__)
if (sio->status & STATUS_LINE_BREAK)
{
for (n = 0; n < QSE_TYPE_MAX(qse_ssize_t) && str[n] != QSE_WT('\0'); n++)
{
if (qse_sio_putwc (sio, str[n]) <= -1) return -1;
}
return n;
}
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_writewcs (&sio->tio.io, str, (qse_size_t)-1);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putwcsn (
qse_sio_t* sio, const qse_wchar_t* str, qse_size_t size)
{
qse_ssize_t n;
#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 & STATUS_UTF8_CONSOLE)
{
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->file.handle, cur, left,
&count, QSE_NULL) == FALSE)
{
sio->errnum = QSE_SIO_ESYSERR;
return -1;
}
if (count == 0) break;
/* Note:
* WriteConsoleW() in unicosw.dll on win 9x/me returns
* the number of bytes via 'count'. If a double byte
* string is given, 'count' can be greater than 'left'.
* this case is a miserable failure. however, i don't
* think there is CP_UTF8 codepage for console on win9x/me.
* so let me make this function fail if that ever happens.
*/
if (count > left)
{
sio->errnum = QSE_SIO_ESYSERR;
return -1;
}
}
return cur - str;
}
#elif defined(__OS2__)
if (sio->status & STATUS_LINE_BREAK)
{
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
for (n = 0; n < size; n++)
{
if (qse_sio_putwc (sio, str[n]) <= -1) return -1;
}
return n;
}
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_writewcs (&sio->tio.io, str, size);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
static int put_wchar (qse_wchar_t c, void* ctx)
{
return qse_sio_putwc ((qse_sio_t*)ctx, c);
}
static int put_mchar (qse_mchar_t c, void* ctx)
{
return qse_sio_putmb ((qse_sio_t*)ctx, c);
}
static int wcs_to_mbs (
const qse_wchar_t* wcs, qse_size_t* wcslen,
qse_mchar_t* mbs, qse_size_t* mbslen, void* ctx)
{
return qse_wcsntombsnwithcmgr (wcs, wcslen, mbs, mbslen, qse_sio_getcmgr ((qse_sio_t*)ctx));
}
static int mbs_to_wcs (
const qse_mchar_t* mbs, qse_size_t* mbslen,
qse_wchar_t* wcs, qse_size_t* wcslen, void* ctx)
{
return qse_mbsntowcsnwithcmgr (mbs, mbslen, wcs, wcslen, qse_sio_getcmgr ((qse_sio_t*)ctx));
}
qse_ssize_t qse_sio_putmbsf (qse_sio_t* sio, const qse_mchar_t* fmt, ...)
{
va_list ap;
qse_ssize_t x;
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
va_start (ap, fmt);
x = qse_mfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_sio_putwcsf (qse_sio_t* sio, const qse_wchar_t* fmt, ...)
{
va_list ap;
int x;
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
va_start (ap, fmt);
x = qse_wfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_sio_putmbsvf (qse_sio_t* sio, const qse_mchar_t* fmt, va_list ap)
{
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
return (qse_mfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
qse_ssize_t qse_sio_putwcsvf (qse_sio_t* sio, const qse_wchar_t* fmt, va_list ap)
{
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
return (qse_wfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
int qse_sio_getpos (qse_sio_t* sio, qse_sio_pos_t* pos)
{
qse_fio_off_t off;
if (qse_sio_flush(sio) <= -1) return -1;
off = qse_fio_seek (&sio->file, 0, QSE_FIO_CURRENT);
if (off == (qse_fio_off_t)-1)
{
sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
return -1;
}
*pos = off;
return 0;
}
int qse_sio_setpos (qse_sio_t* sio, qse_sio_pos_t pos)
{
qse_fio_off_t off;
if (qse_sio_flush(sio) <= -1) return -1;
off = qse_fio_seek (&sio->file, pos, QSE_FIO_BEGIN);
if (off == (qse_fio_off_t)-1)
{
sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
return -1;
}
return 0;
}
int qse_sio_truncate (qse_sio_t* sio, qse_sio_pos_t pos)
{
if (qse_sio_flush(sio) <= -1) return -1;
return qse_fio_truncate (&sio->file, pos);
}
int qse_sio_seek (qse_sio_t* sio, qse_sio_pos_t* pos, qse_sio_ori_t origin)
{
qse_fio_off_t x;
if (qse_sio_flush(sio) <= -1) return -1;
x = qse_fio_seek (&sio->file, *pos, origin);
if (x == (qse_fio_off_t)-1) return -1;
*pos = x;
return 0;
}
static qse_ssize_t file_input (
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size)
{
if (cmd == QSE_TIO_DATA)
{
qse_ssize_t n;
qse_sio_t* sio;
sio = *(qse_sio_t**)QSE_XTN(tio);
QSE_ASSERT (sio != QSE_NULL);
n = qse_fio_read (&sio->file, buf, size);
if (n <= -1) sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
return n;
}
return 0;
}
static qse_ssize_t file_output (
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size)
{
if (cmd == QSE_TIO_DATA)
{
qse_ssize_t n;
qse_sio_t* sio;
sio = *(qse_sio_t**)QSE_XTN(tio);
QSE_ASSERT (sio != QSE_NULL);
n = qse_fio_write (&sio->file, buf, size);
if (n <= -1) sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
return n;
}
return 0;
}
/* ---------------------------------------------------------- */
static qse_sio_t* sio_stdout = QSE_NULL;
static qse_sio_t* sio_stderr = QSE_NULL;
/* TODO: add sio_stdin, qse_getmbs, etc */
int qse_openstdsios (void)
{
if (sio_stdout == QSE_NULL)
{
sio_stdout = qse_sio_openstd (QSE_MMGR_GETDFL(), 0, QSE_SIO_STDOUT, QSE_SIO_LINEBREAK);
}
if (sio_stderr == QSE_NULL)
{
sio_stderr = qse_sio_openstd (QSE_MMGR_GETDFL(), 0, QSE_SIO_STDERR, QSE_SIO_LINEBREAK);
}
if (sio_stdout == QSE_NULL || sio_stderr == QSE_NULL)
{
qse_closestdsios ();
return -1;
}
return 0;
}
void qse_closestdsios (void)
{
if (sio_stderr)
{
qse_sio_close (sio_stderr);
sio_stderr = QSE_NULL;
}
if (sio_stdout)
{
qse_sio_close (sio_stdout);
sio_stdout = QSE_NULL;
}
}
qse_sio_t* qse_getstdout (void)
{
return sio_stdout;
}
qse_sio_t* qse_getstderr (void)
{
return sio_stderr;
}
qse_ssize_t qse_putmbsf (const qse_mchar_t* fmt, ...)
{
va_list ap;
int x;
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stdout;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
va_start (ap, fmt);
x = qse_mfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_putwcsf (const qse_wchar_t* fmt, ...)
{
va_list ap;
int x;
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stdout;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
va_start (ap, fmt);
x = qse_wfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_putmbsvf (const qse_mchar_t* fmt, va_list ap)
{
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stdout;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
return (qse_mfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
qse_ssize_t qse_putwcsvf (const qse_wchar_t* fmt, va_list ap)
{
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stdout;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
return (qse_wfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
qse_ssize_t qse_errputmbsf (const qse_mchar_t* fmt, ...)
{
va_list ap;
int x;
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stderr;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
va_start (ap, fmt);
x = qse_mfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_errputwcsf (const qse_wchar_t* fmt, ...)
{
va_list ap;
int x;
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stderr;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
va_start (ap, fmt);
x = qse_wfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_errputmbsvf (const qse_mchar_t* fmt, va_list ap)
{
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stderr;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
return (qse_mfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
qse_ssize_t qse_errputwcsvf (const qse_wchar_t* fmt, va_list ap)
{
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stderr;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
return (qse_wfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}

View File

@ -1,644 +0,0 @@
/*
* $Id$
*
Copyright (c) 2006-2014 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.
*/
#include <qse/cmn/task.h>
#include "mem.h"
#if defined(_WIN64)
# if !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0400
# endif
# include <windows.h>
#else
# include <setjmp.h>
# if defined(HAVE_UCONTEXT_H)
# include <ucontext.h>
# endif
# if defined(HAVE_MAKECONTEXT) && defined(HAVE_SWAPCONTEXT) && \
defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT)
# define USE_UCONTEXT
# endif
#endif
struct qse_task_t
{
qse_mmgr_t* mmgr;
qse_task_slice_t* dead;
qse_task_slice_t* current;
qse_size_t count;
qse_task_slice_t* head;
qse_task_slice_t* tail;
#if defined(_WIN64)
void* fiber;
#elif defined(USE_UCONTEXT)
ucontext_t uctx;
#else
jmp_buf backjmp;
#endif
};
struct qse_task_slice_t
{
#if defined(_WIN64)
void* fiber;
#elif defined(USE_UCONTEXT)
ucontext_t uctx;
#else
jmp_buf jmpbuf;
#endif
qse_task_t* task;
int id;
qse_task_fnc_t fnc;
void* ctx;
qse_size_t stksize;
qse_task_slice_t* prev;
qse_task_slice_t* next;
};
int qse_task_init (qse_task_t* task, qse_mmgr_t* mmgr);
void qse_task_fini (qse_task_t* task);
static void purge_slice (qse_task_t* task, qse_task_slice_t* slice);
static void purge_dead_slices (qse_task_t* task);
static void purge_current_slice (qse_task_slice_t* slice, qse_task_slice_t* to);
qse_task_t* qse_task_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
{
qse_task_t* task;
task = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(*task) + xtnsize);
if (task == QSE_NULL) return QSE_NULL;
if (qse_task_init (task, mmgr) <= -1)
{
QSE_MMGR_FREE (task->mmgr, task);
return QSE_NULL;
}
QSE_MEMSET (task + 1, 0, xtnsize);
return task;
}
void qse_task_close (qse_task_t* task)
{
qse_task_fini (task);
QSE_MMGR_FREE (task->mmgr, task);
}
int qse_task_init (qse_task_t* task, qse_mmgr_t* mmgr)
{
QSE_MEMSET (task, 0, QSE_SIZEOF(*task));
task->mmgr = mmgr;
return 0;
}
void qse_task_fini (qse_task_t* task)
{
QSE_ASSERT (task->dead == QSE_NULL);
QSE_ASSERT (task->current == QSE_NULL);
if (task->count > 0)
{
/* am i closing after boot failure? */
qse_task_slice_t* slice, * next;
slice = task->head;
while (slice)
{
next = slice->next;
purge_slice (task, slice);
slice = next;
}
task->count = 0;
task->head = QSE_NULL;
task->tail = QSE_NULL;
}
}
qse_mmgr_t* qse_task_getmmgr (qse_task_t* task)
{
return task->mmgr;
}
void* qse_task_getxtn (qse_task_t* task)
{
return (void*)(task + 1);
}
static qse_task_slice_t* alloc_slice (
qse_task_t* task, qse_task_fnc_t fnc,
void* ctx, qse_size_t stksize)
{
qse_task_slice_t* slice;
slice = QSE_MMGR_ALLOC (task->mmgr, QSE_SIZEOF(*slice) + stksize);
if (slice == QSE_NULL) return QSE_NULL;
QSE_MEMSET (slice, 0, QSE_SIZEOF(*slice));
slice->task = task;
slice->fnc = fnc;
slice->ctx = ctx;
slice->stksize = stksize;
return slice;
}
static void link_task (qse_task_t* task, qse_task_slice_t* slice)
{
if (task->head)
{
slice->next = task->head;
task->head->prev = slice;
task->head = slice;
}
else
{
task->head = slice;
task->tail = slice;
}
task->count++;
}
#if defined(_WIN64)
# define __CALL_BACK__ __stdcall
#else
# define __CALL_BACK__
#endif
#if defined(USE_UCONTEXT) && \
(QSE_SIZEOF_INT == QSE_SIZEOF_INT32_T) && \
(QSE_SIZEOF_VOID_P == (QSE_SIZEOF_INT32_T * 2))
static void __CALL_BACK__ execute_current_slice (qse_uint32_t ptr1, qse_uint32_t ptr2)
{
qse_task_slice_t* slice;
qse_task_slice_t* to;
slice = (qse_task_slice_t*)(((qse_uintptr_t)ptr1 << 32) | ptr2);
QSE_ASSERT (slice->task->current == slice);
to = slice->fnc (slice->task, slice, slice->ctx);
/* the task function is now terminated. we need to
* purge it from the slice list and switch to the next
* slice. */
purge_current_slice (slice, to);
QSE_ASSERT (!"must never reach here...");
}
#else
static void __CALL_BACK__ execute_current_slice (qse_task_slice_t* slice)
{
qse_task_slice_t* to;
QSE_ASSERT (slice->task->current == slice);
to = slice->fnc (slice->task, slice, slice->ctx);
/* the task function is now terminated. we need to
* purge it from the slice list and switch to the next
* slice. */
purge_current_slice (slice, to);
QSE_ASSERT (!"must never reach here...");
}
#endif
#if defined(__WATCOMC__)
/* for watcom, i support i386/32bit only */
extern void* prepare_sp (void*);
#pragma aux prepare_sp = \
"mov dword ptr[eax+4], esp" \
"mov esp, eax" \
"mov eax, dword ptr[esp+0]" \
parm [eax] value [eax] modify [esp]
extern void* restore_sp (void);
#pragma aux restore_sp = \
"mov esp, dword ptr[esp+4]" \
modify [esp]
extern void* get_slice (void);
#pragma aux get_slice = \
"mov eax, dword ptr[esp+0]" \
value [eax]
#endif
qse_task_slice_t* qse_task_create (
qse_task_t* task, qse_task_fnc_t fnc,
void* ctx, qse_size_t stksize)
{
qse_task_slice_t* slice;
register void* tmp;
stksize = ((stksize + QSE_SIZEOF(void*) - 1) / QSE_SIZEOF(void*)) * QSE_SIZEOF(void*);
#if defined(_WIN64)
slice = alloc_slice (task, fnc, ctx, 0);
if (slice == QSE_NULL) return QSE_NULL;
slice->fiber = CreateFiberEx (
stksize, stksize, FIBER_FLAG_FLOAT_SWITCH,
execute_current_slice, slice);
if (slice->fiber == QSE_NULL)
{
QSE_MMGR_FREE (task->mmgr, slice);
return QSE_NULL;
}
#elif defined(USE_UCONTEXT)
slice = alloc_slice (task, fnc, ctx, stksize);
if (slice == QSE_NULL) return QSE_NULL;
if (getcontext (&slice->uctx) <= -1)
{
QSE_MMGR_FREE (task->mmgr, slice);
return QSE_NULL;
}
slice->uctx.uc_stack.ss_sp = slice + 1;
slice->uctx.uc_stack.ss_size = stksize;
slice->uctx.uc_link = QSE_NULL;
#if (QSE_SIZEOF_INT == QSE_SIZEOF_INT32_T) && \
(QSE_SIZEOF_VOID_P == (QSE_SIZEOF_INT32_T * 2))
/* limited work around for unclear makecontext parameters */
makecontext (&slice->uctx, execute_current_slice, 2,
(qse_uint32_t)(((qse_uintptr_t)slice) >> 32),
(qse_uint32_t)((qse_uintptr_t)slice & 0xFFFFFFFFu));
#else
makecontext (&slice->uctx, execute_current_slice, 1, slice);
#endif
#else
if (stksize < QSE_SIZEOF(void*) * 3)
stksize = QSE_SIZEOF(void*) * 3; /* for t1 & t2 */
slice = alloc_slice (task, fnc, ctx, stksize);
if (slice == QSE_NULL) return QSE_NULL;
/* setjmp() doesn't allow different stacks for
* each execution content. let me use some assembly
* to change the stack pointer so that setjmp() remembers
* the new stack pointer for longjmp() later.
*
* this stack is used for the task function when
* longjmp() is made. */
tmp = ((qse_uint8_t*)(slice + 1)) + stksize - QSE_SIZEOF(void*);
tmp = (qse_uint8_t*)tmp - QSE_SIZEOF(void*);
*(void**)tmp = QSE_NULL; /* t1 */
tmp = (qse_uint8_t*)tmp - QSE_SIZEOF(void*);
*(void**)tmp = slice; /* t2 */
#if defined(__WATCOMC__)
tmp = prepare_sp (tmp);
#elif defined(__GNUC__) && (defined(__x86_64) || defined(__amd64))
__asm__ volatile (
"movq %%rsp, 8(%1)\n\t" /* t1 = %rsp */
"movq %1, %%rsp\n\t" /* %rsp = tmp */
"movq 0(%%rsp), %0\n" /* tmp = t2 */
: "=r"(tmp)
: "0"(tmp)
: "%rsp", "memory"
);
#elif defined(__GNUC__) && (defined(__i386) || defined(i386))
__asm__ volatile (
"movl %%esp, 4(%1)\n\t" /* t1 = %esp */
"movl %1, %%esp\n\t" /* %esp = tmp */
"movl 0(%%esp), %0\n" /* tmp = t2 */
: "=r"(tmp)
: "0"(tmp)
: "%esp", "memory"
);
#elif defined(__GNUC__) && (defined(__mips) || defined(mips))
__asm__ volatile (
"sw $sp, 4(%1)\n\t" /* t1 = $sp */
"move $sp, %1\n\t" /* %sp = tmp */
"lw %0, 0($sp)\n" /* tmp = t2 */
: "=r"(tmp)
: "0"(tmp)
: "$sp", "memory"
);
#elif defined(__GNUC__) && defined(__arm__)
__asm__ volatile (
"str sp, [%1, #4]\n\t" /* t1 = sp */
"mov sp, %1\n" /* sp = tmp */
"ldr %0, [sp, #0]\n" /* tmp = t2 */
: "=r"(tmp)
: "0"(tmp)
: "sp", "memory"
);
#else
/* TODO: support more architecture */
QSE_MMGR_FREE (task->mmgr, task);
return QSE_NULL;
#endif /* __WATCOMC__ */
/*
* automatic variables like 'task' and 'newsp' exist
* in the old stack. i can't access them.
* i access some key informaton via the global
* variables stored before stack pointer switching.
*
* this approach makes this function thread-unsafe.
*/
/* when qse_task_create() is called,
* setjmp() saves the context and return 0.
*
* subsequently, when longjmp() is made
* for this saved context, setjmp() returns
* a non-zero value.
*/
if (setjmp (((qse_task_slice_t*)tmp)->jmpbuf) != 0)
{
/* longjmp() is made to here. */
#if defined(__WATCOMC__)
tmp = get_slice ();
#elif defined(__GNUC__) && (defined(__x86_64) || defined(__amd64))
__asm__ volatile (
"movq 0(%%rsp), %0\n" /* tmp = t2 */
: "=r"(tmp)
);
#elif defined(__GNUC__) && (defined(__i386) || defined(i386))
__asm__ volatile (
"movl 0(%%esp), %0\n" /* tmp = t2 */
: "=r"(tmp)
);
#elif defined(__GNUC__) && (defined(__mips) || defined(mips))
__asm__ volatile (
"lw %0, 0($sp)\n" /* tmp = t2 */
: "=r"(tmp)
);
#elif defined(__GNUC__) && defined(__arm__)
__asm__ volatile (
"ldr %0, [sp, #0]\n" /* tmp = t2 */
: "=r"(tmp)
);
#endif /* __WATCOMC__ */
execute_current_slice ((qse_task_slice_t*)tmp);
QSE_ASSERT (!"must never reach here....\n");
}
/* restore the stack pointer once i finish saving the longjmp() context.
* this part is reached only when qse_task_create() is invoked. */
#if defined(__WATCOMC__)
restore_sp ();
#elif defined(__GNUC__) && (defined(__x86_64) || defined(__amd64))
/* i assume that %rsp didn't change after the call to setjmp() */
__asm__ volatile (
"movq 8(%%rsp), %%rsp\n" /* %rsp = t1 */
:
:
: "%rsp"
);
#elif defined(__GNUC__) && (defined(__i386) || defined(i386))
__asm__ volatile (
"movl 4(%%esp), %%esp\n" /* %esp = t1 */
:
:
: "%esp"
);
#elif defined(__GNUC__) && (defined(__mips) || defined(mips))
__asm__ volatile (
"lw $sp, 4($sp)\n" /* $sp = t1 */
:
:
: "$sp"
);
#elif defined(__GNUC__) && defined(__arm__)
__asm__ volatile (
"ldr sp, [sp, #4]\n" /* sp = t1 */
:
:
: "sp"
);
#endif /* __WATCOMC__ */
#endif
link_task (task, slice);
return slice;
}
int qse_task_boot (qse_task_t* task, qse_task_slice_t* to)
{
QSE_ASSERT (task->current == QSE_NULL);
if (to == QSE_NULL) to = task->head;
#if defined(_WIN64)
task->fiber = ConvertThreadToFiberEx (QSE_NULL, FIBER_FLAG_FLOAT_SWITCH);
if (task->fiber == QSE_NULL) return -1;
task->current = to;
SwitchToFiber (task->current->fiber);
ConvertFiberToThread ();
#elif defined(USE_UCONTEXT)
task->current = to;
if (swapcontext (&task->uctx, &task->current->uctx) <= -1)
{
task->current = QSE_NULL;
return -1;
}
#else
if (setjmp (task->backjmp) != 0)
{
/* longjmp() back */
goto done;
}
task->current = to;
longjmp (task->current->jmpbuf, 1);
QSE_ASSERT (!"must never reach here");
done:
#endif
QSE_ASSERT (task->current == QSE_NULL);
QSE_ASSERT (task->count == 0);
if (task->dead) purge_dead_slices (task);
return 0;
}
/* NOTE for __WATCOMC__.
when the number of parameters is more than 2 for qse_task_schedule(),
this setjmp()/longjmp() based tasking didn't work.
if i change this to
void qse_task_schedule (qse_task_slice_t* from, qse_task_slice_t* to)
{
qse_task_t* task = from->task
....
}
it worked. i stopped investigating this problem. so i don't know the
real cause of this problem. let me get back to this later when i have
time for this.
*/
void qse_task_schedule (
qse_task_t* task, qse_task_slice_t* from, qse_task_slice_t* to)
{
QSE_ASSERT (from != QSE_NULL);
if (to == QSE_NULL)
{
/* round-robin if the target is not specified */
to = from->next? from->next: task->head;
}
QSE_ASSERT (task == to->task);
QSE_ASSERT (task == from->task);
QSE_ASSERT (task->current == from);
if (to == from) return;
task->current = to;
#if defined(_WIN64)
/* current->fiber is handled by SwitchToFiber() implicitly */
SwitchToFiber (to->fiber);
if (task->dead) purge_dead_slices (task);
#elif defined(USE_UCONTEXT)
swapcontext (&from->uctx, &to->uctx);
if (task->dead) purge_dead_slices (task);
#else
if (setjmp (from->jmpbuf) != 0)
{
if (task->dead) purge_dead_slices (task);
return;
}
longjmp (to->jmpbuf, 1);
#endif
}
static void purge_dead_slices (qse_task_t* task)
{
qse_task_slice_t* slice;
while (task->dead)
{
slice = task->dead;
task->dead = slice->next;
purge_slice (task, slice);
}
}
static void purge_slice (qse_task_t* task, qse_task_slice_t* slice)
{
#if defined(_WIN64)
if (slice->fiber) DeleteFiber (slice->fiber);
#endif
QSE_MMGR_FREE (task->mmgr, slice);
}
static void purge_current_slice (qse_task_slice_t* slice, qse_task_slice_t* to)
{
qse_task_t* task = slice->task;
QSE_ASSERT (task->current == slice);
if (task->count == 1)
{
/* to purge later */
slice->next = task->dead;
task->dead = slice;
task->current = QSE_NULL;
task->head = QSE_NULL;
task->tail = QSE_NULL;
task->count = 0;
#if defined(_WIN64)
SwitchToFiber (task->fiber);
#elif defined(USE_UCONTEXT)
setcontext (&task->uctx);
#else
longjmp (task->backjmp, 1);
#endif
QSE_ASSERT (!"must not reach here....");
}
task->current = (to && to != slice)? to: (slice->next? slice->next: task->head);
if (slice->prev) slice->prev->next = slice->next;
if (slice->next) slice->next->prev = slice->prev;
if (slice == task->head) task->head = slice->next;
if (slice == task->tail) task->tail = slice->prev;
task->count--;
/* to purge later */
slice->next = task->dead;
task->dead = slice;
#if defined(_WIN64)
SwitchToFiber (task->current->fiber);
#elif defined(USE_UCONTEXT)
setcontext (&task->current->uctx);
#else
longjmp (task->current->jmpbuf, 1);
#endif
}

View File

@ -1,759 +0,0 @@
/*
* $Id$
*
Copyright (c) 2006-2014 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.
*/
#include <qse/cmn/tio.h>
#include <qse/cmn/mbwc.h>
#include "mem.h"
#define STATUS_OUTPUT_DYNBUF (1 << 0)
#define STATUS_INPUT_DYNBUF (1 << 1)
#define STATUS_INPUT_ILLSEQ (1 << 2)
#define STATUS_INPUT_EOF (1 << 3)
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;
tio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_tio_t) + xtnsize);
if (tio)
{
if (qse_tio_init (tio, mmgr, flags) <= -1)
{
QSE_MMGR_FREE (mmgr, tio);
return QSE_NULL;
}
else QSE_MEMSET (QSE_XTN(tio), 0, xtnsize);
}
return tio;
}
int qse_tio_close (qse_tio_t* tio)
{
int n = qse_tio_fini (tio);
QSE_MMGR_FREE (tio->mmgr, tio);
return n;
}
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->cmgr = qse_getdflcmgr();
tio->flags = flags;
/*
tio->input_func = QSE_NULL;
tio->input_arg = QSE_NULL;
tio->output_func = QSE_NULL;
tio->output_arg = QSE_NULL;
tio->status = 0;
tio->inbuf_cur = 0;
tio->inbuf_len = 0;
tio->outbuf_len = 0;
*/
tio->errnum = QSE_TIO_ENOERR;
return 0;
}
int qse_tio_fini (qse_tio_t* tio)
{
int ret = 0;
qse_tio_flush (tio); /* don't care about the result */
if (detach_in (tio, 1) <= -1) ret = -1;
if (detach_out (tio, 1) <= -1) ret = -1;
return ret;
}
qse_mmgr_t* qse_tio_getmmgr (qse_tio_t* tio)
{
return tio->mmgr;
}
void* qse_tio_getxtn (qse_tio_t* tio)
{
return QSE_XTN (tio);
}
qse_tio_errnum_t qse_tio_geterrnum (const qse_tio_t* tio)
{
return tio->errnum;
}
void qse_tio_seterrnum (qse_tio_t* tio, qse_tio_errnum_t errnum)
{
tio->errnum = errnum;
}
qse_cmgr_t* qse_tio_getcmgr (qse_tio_t* tio)
{
return tio->cmgr;
}
void qse_tio_setcmgr (qse_tio_t* tio, qse_cmgr_t* cmgr)
{
tio->cmgr = cmgr;
}
int qse_tio_attachin (
qse_tio_t* tio, qse_tio_io_impl_t input,
qse_mchar_t* bufptr, qse_size_t bufcapa)
{
qse_mchar_t* xbufptr;
if (input == QSE_NULL || bufcapa < QSE_TIO_MININBUFCAPA)
{
tio->errnum = QSE_TIO_EINVAL;
return -1;
}
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;
}
}
tio->errnum = QSE_TIO_ENOERR;
if (input (tio, QSE_TIO_OPEN, QSE_NULL, 0) <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
if (xbufptr != bufptr) QSE_MMGR_FREE (tio->mmgr, xbufptr);
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.buf.ptr = xbufptr;
tio->in.buf.capa = bufcapa;
tio->status &= ~(STATUS_INPUT_ILLSEQ | STATUS_INPUT_EOF);
tio->inbuf_cur = 0;
tio->inbuf_len = 0;
if (xbufptr != bufptr) tio->status |= STATUS_INPUT_DYNBUF;
return 0;
}
static int detach_in (qse_tio_t* tio, int fini)
{
int ret = 0;
if (tio->in.fun)
{
tio->errnum = QSE_TIO_ENOERR;
if (tio->in.fun (tio, QSE_TIO_CLOSE, QSE_NULL, 0) <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
/* 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->status & STATUS_INPUT_DYNBUF)
{
QSE_MMGR_FREE (tio->mmgr, tio->in.buf.ptr);
tio->status &= ~STATUS_INPUT_DYNBUF;
}
tio->in.fun = QSE_NULL;
tio->in.buf.ptr = QSE_NULL;
tio->in.buf.capa = 0;
}
return ret;
}
int qse_tio_detachin (qse_tio_t* tio)
{
return detach_in (tio, 0);
}
int qse_tio_attachout (
qse_tio_t* tio, qse_tio_io_impl_t output,
qse_mchar_t* bufptr, qse_size_t bufcapa)
{
qse_mchar_t* xbufptr;
if (output == QSE_NULL || bufcapa < QSE_TIO_MINOUTBUFCAPA)
{
tio->errnum = QSE_TIO_EINVAL;
return -1;
}
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;
}
}
tio->errnum = QSE_TIO_ENOERR;
if (output (tio, QSE_TIO_OPEN, QSE_NULL, 0) <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
if (xbufptr != bufptr) QSE_MMGR_FREE (tio->mmgr, xbufptr);
return -1;
}
tio->out.fun = output;
tio->out.buf.ptr = xbufptr;
tio->out.buf.capa = bufcapa;
tio->outbuf_len = 0;
if (xbufptr != bufptr) tio->status |= STATUS_OUTPUT_DYNBUF;
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 */
tio->errnum = QSE_TIO_ENOERR;
if (tio->out.fun (tio, QSE_TIO_CLOSE, QSE_NULL, 0) <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
/* 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->status & STATUS_OUTPUT_DYNBUF)
{
QSE_MMGR_FREE (tio->mmgr, tio->out.buf.ptr);
tio->status &= ~STATUS_OUTPUT_DYNBUF;
}
tio->out.fun = QSE_NULL;
tio->out.buf.ptr = QSE_NULL;
tio->out.buf.capa = 0;
}
return ret;
}
int qse_tio_detachout (qse_tio_t* tio)
{
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->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)
{
tio->errnum = QSE_TIO_ENOERR;
n = tio->out.fun (tio, QSE_TIO_DATA, cur, left);
if (n <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
if (cur != tio->out.buf.ptr)
{
QSE_MEMCPY (tio->out.buf.ptr, cur, left);
tio->outbuf_len = left;
}
return -1;
}
if (n == 0)
{
if (cur != tio->out.buf.ptr)
QSE_MEMCPY (tio->out.buf.ptr, cur, left);
break;
}
left -= n;
cur += n;
}
count = tio->outbuf_len - left;
tio->outbuf_len = left;
return (qse_ssize_t)count;
}
void qse_tio_drain (qse_tio_t* tio)
{
tio->status &= ~(STATUS_INPUT_ILLSEQ | STATUS_INPUT_EOF);
tio->inbuf_cur = 0;
tio->inbuf_len = 0;
tio->outbuf_len = 0;
tio->errnum = QSE_TIO_ENOERR;
}
/* ------------------------------------------------------------- */
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->in.fun != QSE_NULL);*/
if (tio->in.fun == QSE_NULL)
{
tio->errnum = QSE_TIO_ENINPF;
return -1;
}
/* note that this function doesn't check if
* tio->status is set with STATUS_INPUT_ILLSEQ
* since this function can simply return the next
* available byte. */
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
nread = 0;
while (nread < size)
{
if (tio->inbuf_cur >= tio->inbuf_len)
{
tio->errnum = QSE_TIO_ENOERR;
n = tio->in.fun (
tio, QSE_TIO_DATA,
tio->in.buf.ptr, tio->in.buf.capa);
if (n == 0) break;
if (n <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
return -1;
}
tio->inbuf_cur = 0;
tio->inbuf_len = (qse_size_t)n;
}
do
{
buf[nread] = tio->in.buf.ptr[tio->inbuf_cur++];
/* TODO: support a different line terminator */
if (buf[nread++] == QSE_MT('\n')) goto done;
}
while (tio->inbuf_cur < tio->inbuf_len && nread < size);
}
done:
return nread;
}
static QSE_INLINE qse_ssize_t tio_read_widechars (
qse_tio_t* tio, qse_wchar_t* buf, qse_size_t bufsize)
{
qse_size_t mlen, wlen;
qse_ssize_t n;
int x;
if (tio->inbuf_cur >= tio->inbuf_len)
{
tio->inbuf_cur = 0;
tio->inbuf_len = 0;
getc_conv:
if (tio->status & STATUS_INPUT_EOF) n = 0;
else
{
tio->errnum = QSE_TIO_ENOERR;
n = tio->in.fun (
tio, QSE_TIO_DATA,
&tio->in.buf.ptr[tio->inbuf_len],
tio->in.buf.capa - tio->inbuf_len);
}
if (n == 0)
{
tio->status |= STATUS_INPUT_EOF;
if (tio->inbuf_cur < tio->inbuf_len)
{
/* no more input from the underlying input handler.
* but some incomplete bytes in the buffer. */
if (tio->flags & QSE_TIO_IGNOREMBWCERR)
{
/* tread them as illegal sequence */
goto ignore_illseq;
}
else
{
tio->errnum = QSE_TIO_EICSEQ;
return -1;
}
}
return 0;
}
if (n <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
return -1;
}
tio->inbuf_len += n;
}
mlen = tio->inbuf_len - tio->inbuf_cur;
wlen = bufsize;
x = qse_mbsntowcsnuptowithcmgr (
&tio->in.buf.ptr[tio->inbuf_cur],
&mlen, buf, &wlen, QSE_WT('\n'), tio->cmgr);
tio->inbuf_cur += mlen;
if (x == -3)
{
/* incomplete sequence */
if (wlen <= 0)
{
/* not even a single character was handled.
* shift bytes in the buffer to the head. */
QSE_ASSERT (mlen <= 0);
tio->inbuf_len = tio->inbuf_len - tio->inbuf_cur;
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 */
}
/* get going if some characters are handled */
}
else if (x == -2)
{
/* buffer not large enough */
QSE_ASSERT (wlen > 0);
/* the wide-character buffer is not just large enough to
* hold the entire conversion result. lets's go on so long as
* 1 wide-character is produced though it may be inefficient.
*/
}
else if (x <= -1)
{
/* illegal sequence */
if (tio->flags & QSE_TIO_IGNOREMBWCERR)
{
ignore_illseq:
tio->inbuf_cur++; /* skip one byte */
buf[wlen++] = QSE_WT('?');
}
else if (wlen <= 0)
{
tio->errnum = QSE_TIO_EILSEQ;
return -1;
}
else
{
/* some characters are already handled.
* mark that an illegal sequence encountered
* and carry on. */
tio->status |= STATUS_INPUT_ILLSEQ;
}
}
return wlen;
}
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->in.fun != QSE_NULL);*/
if (tio->in.fun == QSE_NULL)
{
tio->errnum = QSE_TIO_ENINPF;
return -1;
}
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
while (nread < size)
{
if (tio->status & STATUS_INPUT_ILLSEQ)
{
tio->status &= ~STATUS_INPUT_ILLSEQ;
tio->errnum = QSE_TIO_EILSEQ;
return -1;
}
n = tio_read_widechars (tio, &buf[nread], size - nread);
if (n == 0) break;
if (n <= -1) return -1;
nread += n;
if (buf[nread-1] == QSE_WT('\n')) break;
}
return nread;
}
/* ------------------------------------------------------------- */
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] != QSE_MT('\0'))
{
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] != QSE_MT('\0'))
{
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 */
if (*xptr == QSE_MT('\n'))
{
nl = 1;
break;
}
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
}
/* continue copying without checking for nl */
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-byte 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 is 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;
}