added aio files. some file restructuring in progress
This commit is contained in:
@ -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 \
|
||||
|
@ -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@
|
||||
|
@ -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)
|
||||
|
1668
qse/lib/cmn/fio.c
1668
qse/lib/cmn/fio.c
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
|
1608
qse/lib/cmn/nwio.c
1608
qse/lib/cmn/nwio.c
File diff suppressed because it is too large
Load Diff
2519
qse/lib/cmn/pio.c
2519
qse/lib/cmn/pio.c
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
Reference in New Issue
Block a user