added lib/xli/std.c
This commit is contained in:
parent
d5efa32446
commit
5584375bf3
570
qse/lib/xli/std.c
Normal file
570
qse/lib/xli/std.c
Normal file
@ -0,0 +1,570 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
Copyright 2006-2012 Chung, Hyung-Hwan.
|
||||
This file is part of QSE.
|
||||
|
||||
QSE is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
QSE is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "xli.h"
|
||||
#include <qse/xli/stdxli.h>
|
||||
#include <qse/cmn/path.h>
|
||||
#include "../cmn/mem.h"
|
||||
|
||||
typedef struct xtn_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
qse_xli_iostd_t* x;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
qse_sio_t* sio; /* the handle to an open file */
|
||||
qse_cstr_t dir;
|
||||
} file;
|
||||
struct
|
||||
{
|
||||
const qse_char_t* ptr;
|
||||
const qse_char_t* end;
|
||||
} str;
|
||||
} u;
|
||||
} in;
|
||||
|
||||
struct
|
||||
{
|
||||
qse_xli_iostd_t* x;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
qse_sio_t* sio;
|
||||
} file;
|
||||
struct
|
||||
{
|
||||
qse_str_t* buf;
|
||||
} str;
|
||||
} u;
|
||||
} out;
|
||||
} s;
|
||||
|
||||
qse_xli_ecb_t ecb;
|
||||
} xtn_t;
|
||||
|
||||
qse_xli_t* qse_xli_openstd (qse_size_t xtnsize)
|
||||
{
|
||||
return qse_xli_openstdwithmmgr (QSE_MMGR_GETDFL(), xtnsize);
|
||||
}
|
||||
|
||||
static void fini_xtn (qse_xli_t* xli)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
static void clear_xtn (qse_xli_t* xli)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
qse_xli_t* qse_xli_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize)
|
||||
{
|
||||
qse_xli_t* xli;
|
||||
xtn_t* xtn;
|
||||
|
||||
/* create an object */
|
||||
xli = qse_xli_open (mmgr, QSE_SIZEOF(xtn_t) + xtnsize);
|
||||
if (xli == QSE_NULL) goto oops;
|
||||
|
||||
/* initialize extension */
|
||||
xtn = (xtn_t*) QSE_XTN (xli);
|
||||
|
||||
xtn->ecb.close = fini_xtn;
|
||||
xtn->ecb.clear = clear_xtn;
|
||||
qse_xli_pushecb (xli, &xtn->ecb);
|
||||
|
||||
return xli;
|
||||
|
||||
oops:
|
||||
if (xli) qse_xli_close (xli);
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
void* qse_xli_getxtnstd (qse_xli_t* xli)
|
||||
{
|
||||
return (void*)((xtn_t*)QSE_XTN(xli) + 1);
|
||||
}
|
||||
|
||||
static qse_sio_t* open_sio (qse_xli_t* xli, const qse_char_t* file, int flags)
|
||||
{
|
||||
qse_sio_t* sio;
|
||||
sio = qse_sio_open (xli->mmgr, 0, file, flags);
|
||||
if (sio == QSE_NULL)
|
||||
{
|
||||
qse_cstr_t errarg;
|
||||
errarg.ptr = file;
|
||||
errarg.len = qse_strlen(file);
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &errarg);
|
||||
}
|
||||
return sio;
|
||||
}
|
||||
|
||||
struct sio_std_name_t
|
||||
{
|
||||
const qse_char_t* ptr;
|
||||
qse_size_t len;
|
||||
};
|
||||
|
||||
static struct sio_std_name_t sio_std_names[] =
|
||||
{
|
||||
{ QSE_T("stdin"), 5 },
|
||||
{ QSE_T("stdout"), 6 },
|
||||
{ QSE_T("stderr"), 6 }
|
||||
};
|
||||
|
||||
static qse_sio_t* open_sio_std (qse_xli_t* xli, qse_sio_std_t std, int flags)
|
||||
{
|
||||
qse_sio_t* sio;
|
||||
sio = qse_sio_openstd (xli->mmgr, 0, std, flags);
|
||||
if (sio == QSE_NULL)
|
||||
{
|
||||
qse_cstr_t ea;
|
||||
ea.ptr = sio_std_names[std].ptr;
|
||||
ea.len = sio_std_names[std].len;
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
|
||||
}
|
||||
return sio;
|
||||
}
|
||||
|
||||
static int open_readstd (qse_xli_t* xli, xtn_t* xtn)
|
||||
{
|
||||
qse_xli_iostd_t* psin = xtn->s.in.x;
|
||||
|
||||
switch (psin->type)
|
||||
{
|
||||
/* normal source files */
|
||||
|
||||
case QSE_XLI_IOSTD_FILE:
|
||||
if (psin->u.file.path == QSE_NULL ||
|
||||
(psin->u.file.path[0] == QSE_T('-') &&
|
||||
psin->u.file.path[1] == QSE_T('\0')))
|
||||
{
|
||||
/* no path name or - -> stdin */
|
||||
qse_sio_t* tmp;
|
||||
|
||||
tmp = open_sio_std (xli, QSE_SIO_STDIN, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR);
|
||||
if (tmp == QSE_NULL) return -1;
|
||||
|
||||
xtn->s.in.u.file.sio = tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
qse_sio_t* tmp;
|
||||
const qse_char_t* base;
|
||||
|
||||
tmp = open_sio (xli, psin->u.file.path, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR);
|
||||
if (tmp == QSE_NULL) return -1;
|
||||
|
||||
xtn->s.in.u.file.sio = tmp;
|
||||
|
||||
base = qse_basename (psin->u.file.path);
|
||||
if (base != psin->u.file.path)
|
||||
{
|
||||
xtn->s.in.u.file.dir.ptr = psin->u.file.path;
|
||||
xtn->s.in.u.file.dir.len = base - psin->u.file.path;
|
||||
}
|
||||
|
||||
}
|
||||
if (psin->u.file.cmgr)
|
||||
qse_sio_setcmgr (xtn->s.in.u.file.sio, psin->u.file.cmgr);
|
||||
return 0;
|
||||
|
||||
case QSE_XLI_IOSTD_STR:
|
||||
xtn->s.in.u.str.ptr = psin->u.str.ptr;
|
||||
xtn->s.in.u.str.end = psin->u.str.ptr + psin->u.str.len;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static qse_ssize_t sf_in_open (
|
||||
qse_xli_t* xli, qse_xli_io_arg_t* arg, xtn_t* xtn)
|
||||
{
|
||||
if (arg == QSE_NULL || !(arg->flags & QSE_XLI_IO_INCLUDED))
|
||||
{
|
||||
/* handle normal source input streams specified
|
||||
* to qse_xli_readstd() */
|
||||
|
||||
qse_ssize_t x;
|
||||
|
||||
x = open_readstd (xli, xtn);
|
||||
if (x >= 0)
|
||||
{
|
||||
/* perform some manipulation about the top-level input information */
|
||||
if (xtn->s.in.x->type == QSE_XLI_IOSTD_FILE)
|
||||
xli->sio.arg.name = xtn->s.in.x->u.file.path;
|
||||
else
|
||||
xli->sio.arg.name = QSE_NULL;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* handle the included file - @include */
|
||||
const qse_char_t* file;
|
||||
qse_char_t fbuf[64];
|
||||
qse_char_t* dbuf = QSE_NULL;
|
||||
|
||||
QSE_ASSERT (arg->name != QSE_NULL);
|
||||
|
||||
file = arg->name;
|
||||
if (xtn->s.in.u.file.dir.len > 0 && arg->name[0] != QSE_T('/'))
|
||||
{
|
||||
qse_size_t tmplen, totlen;
|
||||
|
||||
totlen = qse_strlen(arg->name) + xtn->s.in.u.file.dir.len;
|
||||
if (totlen >= QSE_COUNTOF(fbuf))
|
||||
{
|
||||
dbuf = qse_xli_allocmem (
|
||||
xli, QSE_SIZEOF(qse_char_t) * (totlen + 1)
|
||||
);
|
||||
if (dbuf == QSE_NULL) return -1;
|
||||
|
||||
file = dbuf;
|
||||
}
|
||||
else file = fbuf;
|
||||
|
||||
tmplen = qse_strncpy (
|
||||
(qse_char_t*)file,
|
||||
xtn->s.in.u.file.dir.ptr,
|
||||
xtn->s.in.u.file.dir.len
|
||||
);
|
||||
qse_strcpy ((qse_char_t*)file + tmplen, arg->name);
|
||||
}
|
||||
|
||||
arg->handle = qse_sio_open (
|
||||
xli->mmgr, 0, file, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR
|
||||
);
|
||||
|
||||
if (dbuf) QSE_MMGR_FREE (xli->mmgr, dbuf);
|
||||
if (arg->handle == QSE_NULL)
|
||||
{
|
||||
qse_cstr_t ea;
|
||||
ea.ptr = arg->name;
|
||||
ea.len = qse_strlen(ea.ptr);
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static qse_ssize_t sf_in_close (
|
||||
qse_xli_t* xli, qse_xli_io_arg_t* arg, xtn_t* xtn)
|
||||
{
|
||||
if (arg == QSE_NULL || !(arg->flags & QSE_XLI_IO_INCLUDED))
|
||||
{
|
||||
switch (xtn->s.in.x->type)
|
||||
{
|
||||
case QSE_XLI_IOSTD_FILE:
|
||||
qse_sio_close (xtn->s.in.u.file.sio);
|
||||
break;
|
||||
|
||||
case QSE_XLI_IOSTD_STR:
|
||||
/* nothing to close */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* nothing to close */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* handle the included source file - @include */
|
||||
QSE_ASSERT (arg->handle != QSE_NULL);
|
||||
qse_sio_close (arg->handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static qse_ssize_t sf_in_read (
|
||||
qse_xli_t* xli, qse_xli_io_arg_t* arg,
|
||||
qse_char_t* data, qse_size_t size, xtn_t* xtn)
|
||||
{
|
||||
|
||||
if (arg == QSE_NULL || !(arg->flags & QSE_XLI_IO_INCLUDED))
|
||||
{
|
||||
qse_ssize_t n;
|
||||
|
||||
switch (xtn->s.in.x->type)
|
||||
{
|
||||
case QSE_XLI_IOSTD_FILE:
|
||||
QSE_ASSERT (xtn->s.in.u.file.sio != QSE_NULL);
|
||||
n = qse_sio_getstrn (xtn->s.in.u.file.sio, data, size);
|
||||
if (n <= -1)
|
||||
{
|
||||
qse_cstr_t ea;
|
||||
if (xtn->s.in.x->u.file.path)
|
||||
{
|
||||
ea.ptr = xtn->s.in.x->u.file.path;
|
||||
ea.len = qse_strlen(ea.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ea.ptr = sio_std_names[QSE_SIO_STDIN].ptr;
|
||||
ea.len = sio_std_names[QSE_SIO_STDIN].len;
|
||||
}
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
|
||||
}
|
||||
break;
|
||||
|
||||
case QSE_XLI_IOSTD_STR:
|
||||
n = 0;
|
||||
while (n < size && xtn->s.in.u.str.ptr < xtn->s.in.u.str.end)
|
||||
{
|
||||
data[n++] = *xtn->s.in.u.str.ptr++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* this should never happen */
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
|
||||
n = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* handle the included source file - @include */
|
||||
qse_ssize_t n;
|
||||
|
||||
QSE_ASSERT (arg->name != QSE_NULL);
|
||||
QSE_ASSERT (arg->handle != QSE_NULL);
|
||||
|
||||
n = qse_sio_getstrn (arg->handle, data, size);
|
||||
if (n <= -1)
|
||||
{
|
||||
qse_cstr_t ea;
|
||||
ea.ptr = arg->name;
|
||||
ea.len = qse_strlen(ea.ptr);
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
static qse_ssize_t sf_in (
|
||||
qse_xli_t* xli, qse_xli_io_cmd_t cmd,
|
||||
qse_xli_io_arg_t* arg, qse_char_t* data, qse_size_t size)
|
||||
{
|
||||
xtn_t* xtn = QSE_XTN (xli);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case QSE_XLI_IO_OPEN:
|
||||
return sf_in_open (xli, arg, xtn);
|
||||
|
||||
case QSE_XLI_IO_CLOSE:
|
||||
return sf_in_close (xli, arg, xtn);
|
||||
|
||||
case QSE_XLI_IO_READ:
|
||||
return sf_in_read (xli, arg, data, size, xtn);
|
||||
|
||||
default:
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static qse_ssize_t sf_out (
|
||||
qse_xli_t* xli, qse_xli_io_cmd_t cmd,
|
||||
qse_xli_io_arg_t* arg, qse_char_t* data, qse_size_t size)
|
||||
{
|
||||
xtn_t* xtn = QSE_XTN (xli);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case QSE_XLI_IO_OPEN:
|
||||
{
|
||||
switch (xtn->s.out.x->type)
|
||||
{
|
||||
case QSE_XLI_IOSTD_FILE:
|
||||
if (xtn->s.out.x->u.file.path == QSE_NULL ||
|
||||
(xtn->s.out.x->u.file.path[0] == QSE_T('-') &&
|
||||
xtn->s.out.x->u.file.path[1] == QSE_T('\0')))
|
||||
|
||||
{
|
||||
/* no path name or - -> stdout */
|
||||
xtn->s.out.u.file.sio = open_sio_std (
|
||||
xli, QSE_SIO_STDOUT,
|
||||
QSE_SIO_WRITE | QSE_SIO_IGNOREMBWCERR
|
||||
);
|
||||
if (xtn->s.out.u.file.sio == QSE_NULL) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
xtn->s.out.u.file.sio = open_sio (
|
||||
xli, xtn->s.out.x->u.file.path,
|
||||
QSE_SIO_WRITE | QSE_SIO_CREATE |
|
||||
QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR
|
||||
);
|
||||
if (xtn->s.out.u.file.sio == QSE_NULL) return -1;
|
||||
}
|
||||
|
||||
if (xtn->s.out.x->u.file.cmgr)
|
||||
qse_sio_setcmgr (xtn->s.out.u.file.sio, xtn->s.out.x->u.file.cmgr);
|
||||
return 1;
|
||||
|
||||
case QSE_XLI_IOSTD_STR:
|
||||
xtn->s.out.u.str.buf = qse_str_open (xli->mmgr, 0, 512);
|
||||
if (xtn->s.out.u.str.buf == QSE_NULL)
|
||||
{
|
||||
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case QSE_XLI_IO_CLOSE:
|
||||
{
|
||||
switch (xtn->s.out.x->type)
|
||||
{
|
||||
case QSE_XLI_IOSTD_FILE:
|
||||
qse_sio_close (xtn->s.out.u.file.sio);
|
||||
return 0;
|
||||
|
||||
case QSE_XLI_IOSTD_STR:
|
||||
/* i don't close xtn->s.out.u.str.buf intentionally here.
|
||||
* it will be closed at the end of qse_xli_readstd() */
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case QSE_XLI_IO_WRITE:
|
||||
{
|
||||
switch (xtn->s.out.x->type)
|
||||
{
|
||||
case QSE_XLI_IOSTD_FILE:
|
||||
{
|
||||
qse_ssize_t n;
|
||||
QSE_ASSERT (xtn->s.out.u.file.sio != QSE_NULL);
|
||||
n = qse_sio_putstrn (xtn->s.out.u.file.sio, data, size);
|
||||
if (n <= -1)
|
||||
{
|
||||
qse_cstr_t ea;
|
||||
if (xtn->s.out.x->u.file.path)
|
||||
{
|
||||
ea.ptr = xtn->s.out.x->u.file.path;
|
||||
ea.len = qse_strlen(ea.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ea.ptr = sio_std_names[QSE_SIO_STDOUT].ptr;
|
||||
ea.len = sio_std_names[QSE_SIO_STDOUT].len;
|
||||
}
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
case QSE_XLI_IOSTD_STR:
|
||||
{
|
||||
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
|
||||
if (qse_str_ncat (xtn->s.out.u.str.buf, data, size) == (qse_size_t)-1)
|
||||
{
|
||||
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
/* other code must not trigger this function */
|
||||
break;
|
||||
}
|
||||
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EINTERN, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int qse_xli_readstd (qse_xli_t* xli, qse_xli_iostd_t* in)
|
||||
{
|
||||
xtn_t* xtn = (xtn_t*) QSE_XTN (xli);
|
||||
|
||||
if (in == QSE_NULL || (in->type != QSE_XLI_IOSTD_FILE &&
|
||||
in->type != QSE_XLI_IOSTD_STR))
|
||||
{
|
||||
/* the input is a must. at least 1 file or 1 string
|
||||
* must be specified */
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xtn->s.in.x = in;
|
||||
return qse_xli_read (xli, sf_in);
|
||||
}
|
||||
|
||||
int qse_xli_writestd (qse_xli_t* xli, qse_xli_iostd_t* out)
|
||||
{
|
||||
int n;
|
||||
xtn_t* xtn = (xtn_t*) QSE_XTN (xli);
|
||||
|
||||
if (out == QSE_NULL || (out->type != QSE_XLI_IOSTD_FILE &&
|
||||
out->type != QSE_XLI_IOSTD_STR))
|
||||
{
|
||||
/* the input is a must. at least 1 file or 1 string
|
||||
* must be specified */
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xtn->s.out.x = out;
|
||||
n = qse_xli_write (xli, sf_out);
|
||||
|
||||
if (out->type == QSE_XLI_IOSTD_STR)
|
||||
{
|
||||
if (n >= 0)
|
||||
{
|
||||
QSE_ASSERT (xtn->s.out.u.str.buf != QSE_NULL);
|
||||
qse_str_yield (xtn->s.out.u.str.buf, &out->u.str, 0);
|
||||
}
|
||||
if (xtn->s.out.u.str.buf) qse_str_close (xtn->s.out.u.str.buf);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
Loading…
Reference in New Issue
Block a user