2704 lines
63 KiB
C
2704 lines
63 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
Copyright (c) 2006-2019 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 "std.h"
|
|
#include <qse/awk/stdawk.h>
|
|
#include <qse/cmn/str.h>
|
|
#include <qse/cmn/mbwc.h>
|
|
#include <qse/cmn/time.h>
|
|
#include <qse/cmn/path.h>
|
|
#include <qse/cmn/htb.h>
|
|
#include <qse/cmn/env.h>
|
|
#include <qse/si/sio.h>
|
|
#include <qse/si/pio.h>
|
|
#include <qse/si/nwio.h>
|
|
#include <qse/si/fs.h>
|
|
#include "../cmn/mem-prv.h"
|
|
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#if defined(HAVE_QUADMATH_H)
|
|
# include <quadmath.h>
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
# include <windows.h>
|
|
# include <tchar.h>
|
|
# if defined(QSE_HAVE_CONFIG_H) && defined(QSE_ENABLE_LIBLTDL)
|
|
# include <ltdl.h>
|
|
# define USE_LTDL
|
|
# endif
|
|
#elif defined(__OS2__)
|
|
# define INCL_DOSMODULEMGR
|
|
# define INCL_DOSPROCESS
|
|
# define INCL_DOSERRORS
|
|
# include <os2.h>
|
|
#elif defined(__DOS__)
|
|
/* nothing to include */
|
|
#else
|
|
# include <unistd.h>
|
|
# if defined(QSE_ENABLE_LIBLTDL)
|
|
# include <ltdl.h>
|
|
# define USE_LTDL
|
|
# elif defined(HAVE_DLFCN_H)
|
|
# include <dlfcn.h>
|
|
# define USE_DLFCN
|
|
# else
|
|
# error UNSUPPORTED DYNAMIC LINKER
|
|
# endif
|
|
#endif
|
|
|
|
#if !defined(QSE_HAVE_CONFIG_H)
|
|
# if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
|
# define HAVE_POW
|
|
# define HAVE_FMOD
|
|
# endif
|
|
#endif
|
|
|
|
typedef struct xtn_t
|
|
{
|
|
struct
|
|
{
|
|
struct
|
|
{
|
|
qse_awk_parsestd_t* x;
|
|
qse_size_t xindex;
|
|
|
|
union
|
|
{
|
|
/* nothing to maintain here for file */
|
|
|
|
struct
|
|
{
|
|
const qse_char_t* ptr;
|
|
const qse_char_t* end;
|
|
} str;
|
|
struct
|
|
{
|
|
const qse_mchar_t* ptr;
|
|
const qse_mchar_t* end;
|
|
} mbs;
|
|
struct
|
|
{
|
|
const qse_wchar_t* ptr;
|
|
const qse_wchar_t* end;
|
|
} wcs;
|
|
} u;
|
|
} in;
|
|
|
|
struct
|
|
{
|
|
qse_awk_parsestd_t* x;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
qse_sio_t* sio;
|
|
} file;
|
|
struct
|
|
{
|
|
qse_str_t* buf;
|
|
} str;
|
|
struct
|
|
{
|
|
qse_mbs_t* buf;
|
|
} mbs;
|
|
struct
|
|
{
|
|
qse_wcs_t* buf;
|
|
} wcs;
|
|
} u;
|
|
} out;
|
|
} s; /* script/source handling */
|
|
|
|
int gbl_argc;
|
|
int gbl_argv;
|
|
int gbl_environ;
|
|
|
|
qse_awk_ecb_t ecb;
|
|
int stdmod_up;
|
|
} xtn_t;
|
|
|
|
typedef struct rxtn_t
|
|
{
|
|
struct
|
|
{
|
|
struct {
|
|
const qse_char_t*const* files;
|
|
qse_size_t index;
|
|
qse_size_t count;
|
|
} in;
|
|
|
|
struct
|
|
{
|
|
const qse_char_t*const* files;
|
|
qse_size_t index;
|
|
qse_size_t count;
|
|
} out;
|
|
|
|
qse_cmgr_t* cmgr;
|
|
} c; /* console */
|
|
|
|
int cmgrtab_inited;
|
|
qse_htb_t cmgrtab;
|
|
|
|
qse_awk_rtx_ecb_t ecb;
|
|
} rxtn_t;
|
|
|
|
typedef struct ioattr_t
|
|
{
|
|
qse_cmgr_t* cmgr;
|
|
qse_char_t cmgr_name[64]; /* i assume that the cmgr name never exceeds this length */
|
|
qse_ntime_t tmout[4];
|
|
} ioattr_t;
|
|
|
|
#if defined(QSE_HAVE_INLINE)
|
|
static QSE_INLINE xtn_t* GET_XTN(qse_awk_t* awk) { return (xtn_t*)((qse_uint8_t*)qse_awk_getxtn(awk) - QSE_SIZEOF(xtn_t)); }
|
|
static QSE_INLINE rxtn_t* GET_RXTN(qse_awk_rtx_t* rtx) { return (rxtn_t*)((qse_uint8_t*)qse_awk_rtx_getxtn(rtx) - QSE_SIZEOF(rxtn_t)); }
|
|
#else
|
|
#define GET_XTN(awk) ((xtn_t*)((qse_uint8_t*)qse_awk_getxtn(awk) - QSE_SIZEOF(xtn_t)))
|
|
#define GET_RXTN(rtx) ((rxtn_t*)((qse_uint8_t*)qse_awk_rtx_getxtn(rtx) - QSE_SIZEOF(rxtn_t)))
|
|
#endif
|
|
|
|
|
|
static ioattr_t* get_ioattr (qse_htb_t* tab, const qse_char_t* ptr, qse_size_t len);
|
|
|
|
qse_awk_flt_t qse_awk_stdmathpow (qse_awk_t* awk, qse_awk_flt_t x, qse_awk_flt_t y)
|
|
{
|
|
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_POWQ)
|
|
return powq (x, y);
|
|
#elif defined(HAVE_POWL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
|
|
return powl (x, y);
|
|
#elif defined(HAVE_POW)
|
|
return pow (x, y);
|
|
#elif defined(HAVE_POWF)
|
|
return powf (x, y);
|
|
#else
|
|
#error ### no pow function available ###
|
|
#endif
|
|
}
|
|
|
|
qse_awk_flt_t qse_awk_stdmathmod (qse_awk_t* awk, qse_awk_flt_t x, qse_awk_flt_t y)
|
|
{
|
|
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_FMODQ)
|
|
return fmodq (x, y);
|
|
#elif defined(HAVE_FMODL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
|
|
return fmodl (x, y);
|
|
#elif defined(HAVE_FMOD)
|
|
return fmod (x, y);
|
|
#elif defined(HAVE_FMODF)
|
|
return fmodf (x, y);
|
|
#else
|
|
#error ### no fmod function available ###
|
|
#endif
|
|
}
|
|
|
|
/* [IMPORTANT]
|
|
* qse_awk_stdmodXXXX() functions must not access the extension
|
|
* area of 'awk'. they are used in StdAwk.cpp which instantiates
|
|
* an awk object with qse_awk_open() instead of qse_awk_openstd(). */
|
|
|
|
int qse_awk_stdmodstartup (qse_awk_t* awk)
|
|
{
|
|
#if defined(USE_LTDL)
|
|
|
|
/* lt_dlinit() can be called more than once and
|
|
* lt_dlexit() shuts down libltdl if it's called as many times as
|
|
* corresponding lt_dlinit(). so it's safe to call lt_dlinit()
|
|
* and lt_dlexit() at the library level. */
|
|
return lt_dlinit() != 0? -1: 0;
|
|
|
|
#else
|
|
return 0;
|
|
#endif
|
|
|
|
}
|
|
|
|
void qse_awk_stdmodshutdown (qse_awk_t* awk)
|
|
{
|
|
#if defined(USE_LTDL)
|
|
lt_dlexit ();
|
|
#else
|
|
/* do nothing */
|
|
#endif
|
|
}
|
|
|
|
static void* std_mod_open_checked (qse_awk_t* awk, const qse_awk_mod_spec_t* spec)
|
|
{
|
|
xtn_t* xtn = GET_XTN(awk);
|
|
|
|
if (!xtn->stdmod_up)
|
|
{
|
|
/* qse_awk_stdmodstartup() must have failed upon start-up.
|
|
* return failure immediately */
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOIMPL, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
return qse_awk_stdmodopen (awk, spec);
|
|
}
|
|
|
|
void* qse_awk_stdmodopen (qse_awk_t* awk, const qse_awk_mod_spec_t* spec)
|
|
{
|
|
#if defined(USE_LTDL)
|
|
void* h;
|
|
lt_dladvise adv;
|
|
qse_mchar_t* modpath;
|
|
const qse_char_t* tmp[4];
|
|
int count;
|
|
|
|
count = 0;
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = QSE_NULL;
|
|
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
modpath = qse_mbsadup (tmp, QSE_NULL, qse_awk_getmmgr(awk));
|
|
#else
|
|
modpath = qse_wcsatombsdupwithcmgr(tmp, QSE_NULL, qse_awk_getmmgr(awk), qse_awk_getcmgr(awk));
|
|
#endif
|
|
if (!modpath)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
if (lt_dladvise_init (&adv) != 0)
|
|
{
|
|
/* the only failure of lt_dladvise_init() seems to be caused
|
|
* by memory allocation failured */
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
lt_dladvise_ext (&adv);
|
|
/*lt_dladvise_resident (&adv); useful for debugging with valgrind */
|
|
|
|
h = lt_dlopenadvise (modpath, adv);
|
|
|
|
lt_dladvise_destroy (&adv);
|
|
|
|
QSE_MMGR_FREE (qse_awk_getmmgr(awk), modpath);
|
|
|
|
return h;
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
HMODULE h;
|
|
qse_char_t* modpath;
|
|
const qse_char_t* tmp[4];
|
|
int count;
|
|
|
|
count = 0;
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = QSE_NULL;
|
|
|
|
modpath = qse_stradup (tmp, QSE_NULL, qse_awk_getmmgr(awk));
|
|
if (!modpath)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
h = LoadLibrary (modpath);
|
|
|
|
QSE_MMGR_FREE (qse_awk_getmmgr(awk), modpath);
|
|
|
|
QSE_ASSERT (QSE_SIZEOF(h) <= QSE_SIZEOF(void*));
|
|
return h;
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
HMODULE h;
|
|
qse_mchar_t* modpath;
|
|
const qse_char_t* tmp[4];
|
|
int count;
|
|
char errbuf[CCHMAXPATH];
|
|
APIRET rc;
|
|
|
|
count = 0;
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = QSE_NULL;
|
|
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
modpath = qse_mbsadup (tmp, QSE_NULL, qse_awk_getmmgr(awk));
|
|
#else
|
|
modpath = qse_wcsatombsdupwithcmgr(tmp, QSE_NULL, qse_awk_getmmgr(awk), qse_awk_getcmgr(awk));
|
|
#endif
|
|
if (!modpath)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
/* DosLoadModule() seems to have severe limitation on
|
|
* the file name it can load (max-8-letters.xxx) */
|
|
rc = DosLoadModule (errbuf, QSE_COUNTOF(errbuf) - 1, modpath, &h);
|
|
if (rc != NO_ERROR) h = QSE_NULL;
|
|
|
|
QSE_MMGR_FREE (qse_awk_getmmgr(awk), modpath);
|
|
|
|
QSE_ASSERT (QSE_SIZEOF(h) <= QSE_SIZEOF(void*));
|
|
return h;
|
|
|
|
#elif defined(__DOS__) && defined(QSE_ENABLE_DOS_DYNAMIC_MODULE)
|
|
|
|
/* the DOS code here is not generic enough. it's for a specific
|
|
* dos-extender only. the best is not to use dynamic loading
|
|
* when building for DOS. */
|
|
void* h;
|
|
qse_mchar_t* modpath;
|
|
const qse_char_t* tmp[4];
|
|
int count;
|
|
|
|
count = 0;
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = QSE_NULL;
|
|
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
modpath = qse_mbsadup(tmp, QSE_NULL, qse_awk_getmmgr(awk));
|
|
#else
|
|
modpath = qse_wcsatombsdupwithcmgr(tmp, QSE_NULL, qse_awk_getmmgr(awk), qse_awk_getcmgr(awk));
|
|
#endif
|
|
if (!modpath)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
h = LoadModule (modpath);
|
|
|
|
QSE_MMGR_FREE (qse_awk_getmmgr(awk), modpath);
|
|
|
|
QSE_ASSERT (QSE_SIZEOF(h) <= QSE_SIZEOF(void*));
|
|
return h;
|
|
|
|
#elif defined(USE_DLFCN)
|
|
|
|
void* h;
|
|
qse_mchar_t* modpath;
|
|
const qse_char_t* tmp[4];
|
|
int count;
|
|
|
|
count = 0;
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = QSE_NULL;
|
|
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
modpath = qse_mbsadup(tmp, QSE_NULL, qse_awk_getmmgr(awk));
|
|
#else
|
|
modpath = qse_wcsatombsdupwithcmgr(tmp, QSE_NULL, qse_awk_getmmgr(awk), qse_awk_getcmgr(awk));
|
|
#endif
|
|
if (!modpath)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
h = dlopen(modpath, RTLD_NOW);
|
|
if (!h)
|
|
{
|
|
qse_awk_seterrfmt (awk, QSE_AWK_ESYSERR, QSE_NULL, QSE_T("%hs"), dlerror());
|
|
}
|
|
|
|
QSE_MMGR_FREE (qse_awk_getmmgr(awk), modpath);
|
|
|
|
return h;
|
|
|
|
#else
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOIMPL, QSE_NULL);
|
|
return QSE_NULL;
|
|
#endif
|
|
}
|
|
|
|
void qse_awk_stdmodclose (qse_awk_t* awk, void* handle)
|
|
{
|
|
#if defined(USE_LTDL)
|
|
lt_dlclose (handle);
|
|
#elif defined(_WIN32)
|
|
FreeLibrary ((HMODULE)handle);
|
|
#elif defined(__OS2__)
|
|
DosFreeModule ((HMODULE)handle);
|
|
#elif defined(__DOS__) && defined(QSE_ENABLE_DOS_DYNAMIC_MODULE)
|
|
FreeModule (handle);
|
|
#elif defined(USE_DLFCN)
|
|
dlclose (handle);
|
|
#else
|
|
/* nothing to do */
|
|
#endif
|
|
}
|
|
|
|
void* qse_awk_stdmodsym (qse_awk_t* awk, void* handle, const qse_char_t* name)
|
|
{
|
|
void* s;
|
|
qse_mchar_t* mname;
|
|
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
mname = (qse_mchar_t*)name;
|
|
#else
|
|
mname = qse_wcstombsdupwithcmgr(name, QSE_NULL, qse_awk_getmmgr(awk), qse_awk_getcmgr(awk));
|
|
if (!mname)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_LTDL)
|
|
s = lt_dlsym (handle, mname);
|
|
|
|
#elif defined(_WIN32)
|
|
s = GetProcAddress ((HMODULE)handle, mname);
|
|
|
|
#elif defined(__OS2__)
|
|
if (DosQueryProcAddr ((HMODULE)handle, 0, mname, (PFN*)&s) != NO_ERROR) s = QSE_NULL;
|
|
|
|
#elif defined(__DOS__) && defined(QSE_ENABLE_DOS_DYNAMIC_MODULE)
|
|
s = GetProcAddress (handle, mname);
|
|
|
|
#elif defined(USE_DLFCN)
|
|
s = dlsym (handle, mname);
|
|
|
|
#else
|
|
s = QSE_NULL;
|
|
#endif
|
|
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
/* nothing to do */
|
|
#else
|
|
QSE_MMGR_FREE (qse_awk_getmmgr(awk), mname);
|
|
#endif
|
|
|
|
return s;
|
|
}
|
|
|
|
static int add_globals (qse_awk_t* awk);
|
|
static int add_functions (qse_awk_t* awk);
|
|
|
|
qse_awk_t* qse_awk_openstd (qse_size_t xtnsize, qse_awk_errnum_t* errnum)
|
|
{
|
|
return qse_awk_openstdwithmmgr (QSE_MMGR_GETDFL(), xtnsize, errnum);
|
|
}
|
|
|
|
static void fini_xtn (qse_awk_t* awk)
|
|
{
|
|
xtn_t* xtn = GET_XTN(awk);
|
|
if (xtn->stdmod_up)
|
|
{
|
|
qse_awk_stdmodshutdown (awk);
|
|
xtn->stdmod_up = 0;
|
|
}
|
|
}
|
|
|
|
static void clear_xtn (qse_awk_t* awk)
|
|
{
|
|
/* nothing to do */
|
|
}
|
|
|
|
qse_awk_t* qse_awk_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_awk_errnum_t* errnum)
|
|
{
|
|
qse_awk_t* awk;
|
|
qse_awk_prm_t prm;
|
|
xtn_t* xtn;
|
|
|
|
prm.math.pow = qse_awk_stdmathpow;
|
|
prm.math.mod = qse_awk_stdmathmod;
|
|
|
|
prm.modopen = std_mod_open_checked;
|
|
prm.modclose = qse_awk_stdmodclose;
|
|
prm.modsym = qse_awk_stdmodsym;
|
|
|
|
/* create an object */
|
|
awk = qse_awk_open(mmgr, QSE_SIZEOF(xtn_t) + xtnsize, &prm, errnum);
|
|
if (!awk) return QSE_NULL;
|
|
|
|
/* adjust the object size by the sizeof xtn_t so that qse_getxtn() returns the right pointer. */
|
|
awk->_instsize += QSE_SIZEOF(xtn_t);
|
|
|
|
#if defined(USE_DLFCN)
|
|
if (qse_awk_setopt(awk, QSE_AWK_MODPOSTFIX, QSE_T(".so")) <= -1)
|
|
{
|
|
if (errnum) *errnum = qse_awk_geterrnum(awk);
|
|
goto oops;
|
|
}
|
|
#endif
|
|
|
|
/* initialize extension */
|
|
xtn = GET_XTN(awk);
|
|
/* the extension area has been cleared in qse_awk_open().
|
|
* QSE_MEMSET (xtn, 0, QSE_SIZEOF(*xtn));*/
|
|
|
|
/* add intrinsic global variables and functions */
|
|
if (add_globals(awk) <= -1 || add_functions(awk) <= -1)
|
|
{
|
|
if (errnum) *errnum = qse_awk_geterrnum(awk);
|
|
goto oops;
|
|
}
|
|
|
|
if (qse_awk_stdmodstartup(awk) <= -1)
|
|
{
|
|
xtn->stdmod_up = 0;
|
|
/* carry on regardless of failure */
|
|
}
|
|
else
|
|
{
|
|
xtn->stdmod_up = 1;
|
|
}
|
|
|
|
xtn->ecb.close = fini_xtn;
|
|
xtn->ecb.clear = clear_xtn;
|
|
qse_awk_pushecb (awk, &xtn->ecb);
|
|
|
|
return awk;
|
|
|
|
oops:
|
|
if (awk) qse_awk_close (awk);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
static qse_sio_t* open_sio (qse_awk_t* awk, const qse_char_t* file, int flags)
|
|
{
|
|
qse_sio_t* sio;
|
|
sio = qse_sio_open (qse_awk_getmmgr(awk), 0, file, flags);
|
|
if (sio == QSE_NULL)
|
|
{
|
|
qse_cstr_t errarg;
|
|
errarg.ptr = (qse_char_t*)file;
|
|
errarg.len = qse_strlen(file);
|
|
qse_awk_seterrnum (awk, QSE_AWK_EOPEN, &errarg);
|
|
}
|
|
return sio;
|
|
}
|
|
|
|
static qse_sio_t* open_sio_rtx (qse_awk_rtx_t* rtx, const qse_char_t* file, int flags)
|
|
{
|
|
qse_sio_t* sio;
|
|
sio = qse_sio_open (qse_awk_rtx_getmmgr(rtx), 0, file, flags);
|
|
if (sio == QSE_NULL)
|
|
{
|
|
qse_cstr_t errarg;
|
|
errarg.ptr = (qse_char_t*)file;
|
|
errarg.len = qse_strlen(file);
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EOPEN, &errarg);
|
|
}
|
|
return sio;
|
|
}
|
|
|
|
static qse_cstr_t sio_std_names[] =
|
|
{
|
|
{ QSE_T("stdin"), 5 },
|
|
{ QSE_T("stdout"), 6 },
|
|
{ QSE_T("stderr"), 6 }
|
|
};
|
|
|
|
static qse_sio_t* open_sio_std (qse_awk_t* awk, qse_sio_std_t std, int flags)
|
|
{
|
|
qse_sio_t* sio;
|
|
sio = qse_sio_openstd (qse_awk_getmmgr(awk), 0, std, flags);
|
|
if (sio == QSE_NULL) qse_awk_seterrnum (awk, QSE_AWK_EOPEN, &sio_std_names[std]);
|
|
return sio;
|
|
}
|
|
|
|
static qse_sio_t* open_sio_std_rtx (qse_awk_rtx_t* rtx, qse_sio_std_t std, int flags)
|
|
{
|
|
qse_sio_t* sio;
|
|
|
|
sio = qse_sio_openstd (qse_awk_rtx_getmmgr(rtx), 0, std, flags);
|
|
if (sio == QSE_NULL) qse_awk_rtx_seterrnum (rtx, QSE_AWK_EOPEN, &sio_std_names[std]);
|
|
return sio;
|
|
}
|
|
|
|
/*** PARSESTD ***/
|
|
|
|
static int open_parsestd (qse_awk_t* awk, qse_awk_sio_arg_t* arg, xtn_t* xtn, qse_size_t index)
|
|
{
|
|
qse_awk_parsestd_t* psin = &xtn->s.in.x[index];
|
|
|
|
switch (psin->type)
|
|
{
|
|
/* normal source files */
|
|
|
|
case QSE_AWK_PARSESTD_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 (awk, QSE_SIO_STDIN, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR);
|
|
if (tmp == QSE_NULL) return -1;
|
|
|
|
if (index >= 1 && xtn->s.in.x[index-1].type == QSE_AWK_PARSESTD_FILE)
|
|
qse_sio_close (arg->handle);
|
|
|
|
arg->handle = tmp;
|
|
}
|
|
else
|
|
{
|
|
qse_sio_t* tmp;
|
|
|
|
tmp = open_sio (awk, psin->u.file.path, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR | QSE_SIO_KEEPPATH);
|
|
if (tmp == QSE_NULL) return -1;
|
|
|
|
if (index >= 1 && xtn->s.in.x[index-1].type == QSE_AWK_PARSESTD_FILE)
|
|
qse_sio_close (arg->handle);
|
|
arg->handle = tmp;
|
|
}
|
|
if (psin->u.file.cmgr) qse_sio_setcmgr (arg->handle, psin->u.file.cmgr);
|
|
return 0;
|
|
|
|
case QSE_AWK_PARSESTD_STR:
|
|
if (index >= 1 && xtn->s.in.x[index-1].type == QSE_AWK_PARSESTD_FILE)
|
|
qse_sio_close (arg->handle);
|
|
|
|
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;
|
|
|
|
case QSE_AWK_PARSESTD_MBS:
|
|
if (index >= 1 && xtn->s.in.x[index-1].type == QSE_AWK_PARSESTD_FILE)
|
|
qse_sio_close (arg->handle);
|
|
|
|
xtn->s.in.u.mbs.ptr = psin->u.mbs.ptr;
|
|
xtn->s.in.u.mbs.end = psin->u.mbs.ptr + psin->u.mbs.len;
|
|
return 0;
|
|
|
|
case QSE_AWK_PARSESTD_WCS:
|
|
if (index >= 1 && xtn->s.in.x[index-1].type == QSE_AWK_PARSESTD_FILE)
|
|
qse_sio_close (arg->handle);
|
|
|
|
xtn->s.in.u.wcs.ptr = psin->u.wcs.ptr;
|
|
xtn->s.in.u.wcs.end = psin->u.wcs.ptr + psin->u.wcs.len;
|
|
return 0;
|
|
|
|
default:
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static qse_ssize_t sf_in_open (qse_awk_t* awk, qse_awk_sio_arg_t* arg, xtn_t* xtn)
|
|
{
|
|
if (arg->prev == QSE_NULL)
|
|
{
|
|
/* handle normal source input streams specified
|
|
* to qse_awk_parsestd() */
|
|
|
|
qse_ssize_t x;
|
|
|
|
QSE_ASSERT (arg == &awk->sio.arg);
|
|
|
|
x = open_parsestd (awk, arg, xtn, 0);
|
|
if (x >= 0)
|
|
{
|
|
xtn->s.in.xindex = 0; /* update the current stream index */
|
|
/* perform some manipulation about the top-level input information */
|
|
if (xtn->s.in.x[0].type == QSE_AWK_PARSESTD_FILE)
|
|
{
|
|
arg->name = xtn->s.in.x[0].u.file.path;
|
|
if (arg->name == QSE_NULL) arg->name = sio_std_names[QSE_SIO_STDIN].ptr;
|
|
}
|
|
else arg->name = QSE_NULL;
|
|
}
|
|
|
|
return x;
|
|
}
|
|
else
|
|
{
|
|
/* handle the included source file - @include */
|
|
const qse_char_t* path;
|
|
qse_char_t fbuf[64];
|
|
qse_char_t* dbuf = QSE_NULL;
|
|
qse_fattr_t fattr;
|
|
|
|
QSE_ASSERT (arg->name != QSE_NULL);
|
|
|
|
path = arg->name;
|
|
if (arg->prev->handle)
|
|
{
|
|
const qse_char_t* outer;
|
|
|
|
outer = qse_sio_getpath(arg->prev->handle);
|
|
if (outer)
|
|
{
|
|
const qse_char_t* base;
|
|
|
|
base = qse_basename(outer);
|
|
if (base != outer && arg->name[0] != QSE_T('/'))
|
|
{
|
|
qse_size_t tmplen, totlen, dirlen;
|
|
|
|
dirlen = base - outer;
|
|
totlen = qse_strlen(arg->name) + dirlen;
|
|
if (totlen >= QSE_COUNTOF(fbuf))
|
|
{
|
|
dbuf = qse_awk_allocmem(awk, QSE_SIZEOF(qse_char_t) * (totlen + 1));
|
|
if (!dbuf) return -1;
|
|
path = dbuf;
|
|
}
|
|
else path = fbuf;
|
|
|
|
tmplen = qse_strncpy ((qse_char_t*)path, outer, dirlen);
|
|
qse_strcpy ((qse_char_t*)path + tmplen, arg->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
arg->handle = qse_sio_open (
|
|
qse_awk_getmmgr(awk), 0, path, QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR | QSE_SIO_KEEPPATH
|
|
);
|
|
|
|
if (dbuf) qse_awk_freemem (awk, dbuf);
|
|
if (!arg->handle)
|
|
{
|
|
qse_cstr_t ea;
|
|
ea.ptr = (qse_char_t*)arg->name;
|
|
ea.len = qse_strlen(ea.ptr);
|
|
qse_awk_seterrnum (awk, QSE_AWK_EOPEN, &ea);
|
|
return -1;
|
|
}
|
|
|
|
/* TODO: use the system handle(file descriptor) instead of the path? */
|
|
/*syshnd = qse_sio_gethnd(arg->handle);*/
|
|
if (qse_get_file_attr_with_mmgr(path, 0, &fattr, qse_awk_getmmgr(awk)) >= 0)
|
|
{
|
|
struct
|
|
{
|
|
qse_uintptr_t ino;
|
|
qse_uintptr_t dev;
|
|
} tmp;
|
|
tmp.ino = fattr.ino;
|
|
tmp.dev = fattr.dev;
|
|
QSE_MEMCPY (&arg->unique_id[0], &tmp, (QSE_SIZEOF(tmp) > QSE_SIZEOF(arg->unique_id)? QSE_SIZEOF(arg->unique_id): QSE_SIZEOF(fattr.ino)));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static qse_ssize_t sf_in_close (qse_awk_t* awk, qse_awk_sio_arg_t* arg, xtn_t* xtn)
|
|
{
|
|
if (arg->prev == QSE_NULL)
|
|
{
|
|
switch (xtn->s.in.x[xtn->s.in.xindex].type)
|
|
{
|
|
case QSE_AWK_PARSESTD_FILE:
|
|
QSE_ASSERT (arg->handle != QSE_NULL);
|
|
qse_sio_close (arg->handle);
|
|
break;
|
|
|
|
case QSE_AWK_PARSESTD_STR:
|
|
case QSE_AWK_PARSESTD_MBS:
|
|
case QSE_AWK_PARSESTD_WCS:
|
|
/* 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_awk_t* awk, qse_awk_sio_arg_t* arg, qse_char_t* data, qse_size_t size, xtn_t* xtn)
|
|
{
|
|
if (arg->prev == QSE_NULL)
|
|
{
|
|
qse_ssize_t n;
|
|
|
|
QSE_ASSERT (arg == &awk->sio.arg);
|
|
|
|
again:
|
|
switch (xtn->s.in.x[xtn->s.in.xindex].type)
|
|
{
|
|
case QSE_AWK_PARSESTD_FILE:
|
|
QSE_ASSERT (arg->handle != QSE_NULL);
|
|
n = qse_sio_getstrn (arg->handle, data, size);
|
|
if (n <= -1)
|
|
{
|
|
qse_cstr_t ea;
|
|
ea.ptr = (qse_char_t*)xtn->s.in.x[xtn->s.in.xindex].u.file.path;
|
|
if (ea.ptr == QSE_NULL) ea.ptr = sio_std_names[QSE_SIO_STDIN].ptr;
|
|
ea.len = qse_strlen(ea.ptr);
|
|
qse_awk_seterrnum (awk, QSE_AWK_EREAD, &ea);
|
|
}
|
|
break;
|
|
|
|
case QSE_AWK_PARSESTD_STR:
|
|
parsestd_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;
|
|
|
|
case QSE_AWK_PARSESTD_MBS:
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
goto parsestd_str;
|
|
#else
|
|
{
|
|
int m;
|
|
qse_size_t mbslen, wcslen;
|
|
|
|
mbslen = xtn->s.in.u.mbs.end - xtn->s.in.u.mbs.ptr;
|
|
wcslen = size;
|
|
if ((m = qse_mbsntowcsnwithcmgr(xtn->s.in.u.mbs.ptr, &mbslen, data, &wcslen, qse_awk_getcmgr(awk))) <= -1 && m != -2)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
|
|
n = -1;
|
|
}
|
|
else
|
|
{
|
|
xtn->s.in.u.mbs.ptr += mbslen;
|
|
n = wcslen;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
case QSE_AWK_PARSESTD_WCS:
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
{
|
|
int m;
|
|
qse_size_t mbslen, wcslen;
|
|
|
|
wcslen = xtn->s.in.u.wcs.end - xtn->s.in.u.wcs.ptr;
|
|
mbslen = size;
|
|
if ((m = qse_wcsntombsnwithcmgr(xtn->s.in.u.wcs.ptr, &wcslen, data, &mbslen, qse_awk_getcmgr(awk))) <= -1 && m != -2)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
|
|
n = -1;
|
|
}
|
|
else
|
|
{
|
|
xtn->s.in.u.wcs.ptr += wcslen;
|
|
n = mbslen;
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
goto parsestd_str;
|
|
#endif
|
|
|
|
default:
|
|
/* this should never happen */
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINTERN, QSE_NULL);
|
|
n = -1;
|
|
break;
|
|
}
|
|
|
|
if (n == 0)
|
|
{
|
|
/* reached end of the current stream. */
|
|
qse_size_t next = xtn->s.in.xindex + 1;
|
|
if (xtn->s.in.x[next].type != QSE_AWK_PARSESTD_NULL)
|
|
{
|
|
/* open the next stream if available. */
|
|
if (open_parsestd (awk, arg, xtn, next) <= -1) n = -1;
|
|
else
|
|
{
|
|
xtn->s.in.xindex = next; /* update the next to the current */
|
|
|
|
/* update the I/O object name */
|
|
if (xtn->s.in.x[next].type == QSE_AWK_PARSESTD_FILE)
|
|
{
|
|
arg->name = xtn->s.in.x[next].u.file.path;
|
|
if (arg->name == QSE_NULL) arg->name = sio_std_names[QSE_SIO_STDIN].ptr;
|
|
}
|
|
else
|
|
arg->name = QSE_NULL;
|
|
|
|
arg->line = 0; /* reset the line number */
|
|
arg->colm = 0;
|
|
goto again;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = (qse_char_t*)arg->name;
|
|
ea.len = qse_strlen(ea.ptr);
|
|
qse_awk_seterrnum (awk, QSE_AWK_EREAD, &ea);
|
|
}
|
|
return n;
|
|
}
|
|
}
|
|
|
|
static qse_ssize_t sf_in (qse_awk_t* awk, qse_awk_sio_cmd_t cmd, qse_awk_sio_arg_t* arg, qse_char_t* data, qse_size_t size)
|
|
{
|
|
xtn_t* xtn = GET_XTN(awk);
|
|
|
|
switch (cmd)
|
|
{
|
|
case QSE_AWK_SIO_OPEN:
|
|
return sf_in_open(awk, arg, xtn);
|
|
|
|
case QSE_AWK_SIO_CLOSE:
|
|
return sf_in_close(awk, arg, xtn);
|
|
|
|
case QSE_AWK_SIO_READ:
|
|
return sf_in_read(awk, arg, data, size, xtn);
|
|
|
|
default:
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static qse_ssize_t sf_out (qse_awk_t* awk, qse_awk_sio_cmd_t cmd, qse_awk_sio_arg_t* arg, qse_char_t* data, qse_size_t size)
|
|
{
|
|
xtn_t* xtn = GET_XTN(awk);
|
|
|
|
switch (cmd)
|
|
{
|
|
case QSE_AWK_SIO_OPEN:
|
|
{
|
|
switch (xtn->s.out.x->type)
|
|
{
|
|
case QSE_AWK_PARSESTD_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 (
|
|
awk, QSE_SIO_STDOUT,
|
|
QSE_SIO_WRITE | QSE_SIO_IGNOREMBWCERR | QSE_SIO_LINEBREAK
|
|
);
|
|
if (xtn->s.out.u.file.sio == QSE_NULL) return -1;
|
|
}
|
|
else
|
|
{
|
|
xtn->s.out.u.file.sio = open_sio (
|
|
awk, 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_AWK_PARSESTD_STR:
|
|
xtn->s.out.u.str.buf = qse_str_open(qse_awk_getmmgr(awk), 0, 512);
|
|
if (xtn->s.out.u.str.buf == QSE_NULL)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
return 1;
|
|
|
|
case QSE_AWK_PARSESTD_MBS:
|
|
xtn->s.out.u.mbs.buf = qse_mbs_open(qse_awk_getmmgr(awk), 0, 512);
|
|
if (xtn->s.out.u.mbs.buf == QSE_NULL)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
return 1;
|
|
|
|
case QSE_AWK_PARSESTD_WCS:
|
|
xtn->s.out.u.wcs.buf = qse_wcs_open(qse_awk_getmmgr(awk), 0, 512);
|
|
if (xtn->s.out.u.wcs.buf == QSE_NULL)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case QSE_AWK_SIO_CLOSE:
|
|
{
|
|
switch (xtn->s.out.x->type)
|
|
{
|
|
case QSE_AWK_PARSESTD_FILE:
|
|
qse_sio_close (xtn->s.out.u.file.sio);
|
|
return 0;
|
|
|
|
case QSE_AWK_PARSESTD_STR:
|
|
case QSE_AWK_PARSESTD_MBS:
|
|
case QSE_AWK_PARSESTD_WCS:
|
|
/* i don't close xtn->s.out.u.str.buf intentionally here.
|
|
* it will be closed at the end of qse_awk_parsestd() */
|
|
return 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case QSE_AWK_SIO_WRITE:
|
|
{
|
|
switch (xtn->s.out.x->type)
|
|
{
|
|
case QSE_AWK_PARSESTD_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;
|
|
ea.ptr = (qse_char_t*)xtn->s.out.x->u.file.path;
|
|
if (ea.ptr == QSE_NULL) ea.ptr = sio_std_names[QSE_SIO_STDOUT].ptr;
|
|
ea.len = qse_strlen(ea.ptr);
|
|
qse_awk_seterrnum (awk, QSE_AWK_EWRITE, &ea);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
case QSE_AWK_PARSESTD_STR:
|
|
parsestd_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_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
return size;
|
|
|
|
case QSE_AWK_PARSESTD_MBS:
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
goto parsestd_str;
|
|
#else
|
|
{
|
|
qse_size_t mbslen, wcslen;
|
|
qse_size_t orglen;
|
|
|
|
wcslen = size;
|
|
if (qse_wcsntombsnwithcmgr(data, &wcslen, QSE_NULL, &mbslen, qse_awk_getcmgr(awk)) <= -1)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
if (mbslen > QSE_TYPE_MAX(qse_ssize_t)) mbslen = QSE_TYPE_MAX(qse_ssize_t);
|
|
|
|
orglen = qse_mbs_getlen(xtn->s.out.u.mbs.buf);
|
|
if (qse_mbs_setlen(xtn->s.out.u.mbs.buf, orglen + mbslen) == (qse_size_t)-1)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
wcslen = size;
|
|
qse_wcsntombsnwithcmgr(data, &wcslen, QSE_MBS_CPTR(xtn->s.out.u.mbs.buf, orglen), &mbslen, qse_awk_getcmgr(awk));
|
|
size = wcslen;
|
|
|
|
return size;
|
|
}
|
|
#endif
|
|
|
|
case QSE_AWK_PARSESTD_WCS:
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
{
|
|
qse_size_t mbslen, wcslen;
|
|
qse_size_t orglen;
|
|
|
|
mbslen = size;
|
|
if (qse_mbsntowcsnwithcmgr(data, &mbslen, QSE_NULL, &wcslen, qse_awk_getcmgr(awk)) <= -1)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
if (wcslen > QSE_TYPE_MAX(qse_ssize_t)) wcslen = QSE_TYPE_MAX(qse_ssize_t);
|
|
|
|
orglen = qse_mbs_getlen(xtn->s.out.u.wcs.buf);
|
|
if (qse_wcs_setlen(xtn->s.out.u.wcs.buf, orglen + wcslen) == (qse_size_t)-1)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
mbslen = size;
|
|
qse_mbsntowcsnwithcmgr(data, &mbslen, QSE_MBS_CPTR(xtn->s.out.u.wcs.buf, orglen), &wcslen, qse_awk_getcmgr(awk));
|
|
size = mbslen;
|
|
|
|
return size;
|
|
}
|
|
#else
|
|
goto parsestd_str;
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
/* other code must not trigger this function */
|
|
break;
|
|
}
|
|
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
int qse_awk_parsestd (qse_awk_t* awk, qse_awk_parsestd_t in[], qse_awk_parsestd_t* out)
|
|
{
|
|
qse_awk_sio_t sio;
|
|
xtn_t* xtn = GET_XTN(awk);
|
|
int n;
|
|
|
|
if (in == QSE_NULL || (in[0].type != QSE_AWK_PARSESTD_FILE &&
|
|
in[0].type != QSE_AWK_PARSESTD_STR &&
|
|
in[0].type != QSE_AWK_PARSESTD_MBS &&
|
|
in[0].type != QSE_AWK_PARSESTD_WCS))
|
|
{
|
|
/* the input is a must. at least 1 file or 1 string
|
|
* must be specified */
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
sio.in = sf_in;
|
|
xtn->s.in.x = in;
|
|
|
|
if (out == QSE_NULL) sio.out = QSE_NULL;
|
|
else
|
|
{
|
|
if (out->type != QSE_AWK_PARSESTD_FILE &&
|
|
out->type != QSE_AWK_PARSESTD_STR &&
|
|
out->type != QSE_AWK_PARSESTD_MBS &&
|
|
out->type != QSE_AWK_PARSESTD_WCS)
|
|
{
|
|
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
|
|
return -1;
|
|
}
|
|
sio.out = sf_out;
|
|
xtn->s.out.x = out;
|
|
}
|
|
|
|
n = qse_awk_parse(awk, &sio);
|
|
|
|
if (out)
|
|
{
|
|
switch (out->type)
|
|
{
|
|
case QSE_AWK_PARSESTD_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);
|
|
break;
|
|
|
|
case QSE_AWK_PARSESTD_MBS:
|
|
if (n >= 0)
|
|
{
|
|
QSE_ASSERT (xtn->s.out.u.mbs.buf != QSE_NULL);
|
|
qse_mbs_yield (xtn->s.out.u.mbs.buf, &out->u.mbs, 0);
|
|
}
|
|
if (xtn->s.out.u.mbs.buf) qse_mbs_close (xtn->s.out.u.mbs.buf);
|
|
break;
|
|
|
|
case QSE_AWK_PARSESTD_WCS:
|
|
if (n >= 0)
|
|
{
|
|
QSE_ASSERT (xtn->s.out.u.wcs.buf != QSE_NULL);
|
|
qse_wcs_yield (xtn->s.out.u.wcs.buf, &out->u.wcs, 0);
|
|
}
|
|
if (xtn->s.out.u.wcs.buf) qse_wcs_close (xtn->s.out.u.wcs.buf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
/*** RTX_OPENSTD ***/
|
|
|
|
static qse_ssize_t nwio_handler_open (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod, int flags, qse_nwad_t* nwad, qse_nwio_tmout_t* tmout)
|
|
{
|
|
qse_nwio_t* handle;
|
|
|
|
handle = qse_nwio_open (
|
|
qse_awk_rtx_getmmgr(rtx), 0, nwad,
|
|
flags | QSE_NWIO_TEXT | QSE_NWIO_IGNOREMBWCERR |
|
|
QSE_NWIO_REUSEADDR | QSE_NWIO_READNORETRY | QSE_NWIO_WRITENORETRY,
|
|
tmout
|
|
);
|
|
if (handle == QSE_NULL) return -1;
|
|
|
|
#if defined(QSE_CHAR_IS_WCHAR)
|
|
{
|
|
qse_cmgr_t* cmgr = qse_awk_rtx_getiocmgrstd(rtx, riod->name);
|
|
if (cmgr) qse_nwio_setcmgr (handle, cmgr);
|
|
}
|
|
#endif
|
|
|
|
riod->handle = (void*)handle;
|
|
riod->uflags = 1; /* nwio indicator */
|
|
return 1;
|
|
}
|
|
|
|
static qse_ssize_t nwio_handler_rest (qse_awk_rtx_t* rtx, qse_awk_rio_cmd_t cmd, qse_awk_rio_arg_t* riod, void* data, qse_size_t size)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case QSE_AWK_RIO_OPEN:
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
|
|
case QSE_AWK_RIO_CLOSE:
|
|
qse_nwio_close ((qse_nwio_t*)riod->handle);
|
|
return 0;
|
|
|
|
case QSE_AWK_RIO_READ:
|
|
return qse_nwio_read((qse_nwio_t*)riod->handle, data, size);
|
|
|
|
case QSE_AWK_RIO_WRITE:
|
|
return qse_nwio_write((qse_nwio_t*)riod->handle, data, size);
|
|
|
|
case QSE_AWK_RIO_WRITE_BYTES:
|
|
return qse_nwio_writebytes((qse_nwio_t*)riod->handle, data, size);
|
|
|
|
case QSE_AWK_RIO_FLUSH:
|
|
/*if (riod->mode == QSE_AWK_RIO_PIPE_READ) return -1;*/
|
|
return qse_nwio_flush((qse_nwio_t*)riod->handle);
|
|
|
|
case QSE_AWK_RIO_NEXT:
|
|
break;
|
|
}
|
|
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
static int parse_rwpipe_uri (const qse_char_t* uri, int* flags, qse_nwad_t* nwad)
|
|
{
|
|
static struct
|
|
{
|
|
const qse_char_t* prefix;
|
|
qse_size_t len;
|
|
int flags;
|
|
} x[] =
|
|
{
|
|
{ QSE_T("tcp://"), 6, QSE_NWIO_TCP },
|
|
{ QSE_T("udp://"), 6, QSE_NWIO_UDP },
|
|
{ QSE_T("tcpd://"), 7, QSE_NWIO_TCP | QSE_NWIO_PASSIVE },
|
|
{ QSE_T("udpd://"), 7, QSE_NWIO_UDP | QSE_NWIO_PASSIVE }
|
|
};
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < QSE_COUNTOF(x); i++)
|
|
{
|
|
if (qse_strzcmp (uri, x[i].prefix, x[i].len) == 0)
|
|
{
|
|
if (qse_strtonwad (uri + x[i].len, nwad) <= -1) return -1;
|
|
*flags = x[i].flags;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static qse_ssize_t pio_handler_open (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod)
|
|
{
|
|
qse_pio_t* handle;
|
|
int flags;
|
|
|
|
if (riod->mode == QSE_AWK_RIO_PIPE_READ)
|
|
{
|
|
/* TODO: should ERRTOOUT be unset? */
|
|
flags = QSE_PIO_READOUT | QSE_PIO_ERRTOOUT;
|
|
}
|
|
else if (riod->mode == QSE_AWK_RIO_PIPE_WRITE)
|
|
{
|
|
flags = QSE_PIO_WRITEIN;
|
|
}
|
|
else if (riod->mode == QSE_AWK_RIO_PIPE_RW)
|
|
{
|
|
flags = QSE_PIO_READOUT | QSE_PIO_ERRTOOUT | QSE_PIO_WRITEIN;
|
|
}
|
|
else
|
|
{
|
|
/* this must not happen */
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
handle = qse_pio_open (
|
|
qse_awk_rtx_getmmgr(rtx),
|
|
0,
|
|
riod->name,
|
|
QSE_NULL,
|
|
flags | QSE_PIO_SHELL | QSE_PIO_TEXT | QSE_PIO_IGNOREMBWCERR
|
|
);
|
|
if (handle == QSE_NULL) return -1;
|
|
|
|
#if defined(QSE_CHAR_IS_WCHAR)
|
|
{
|
|
qse_cmgr_t* cmgr = qse_awk_rtx_getiocmgrstd(rtx, riod->name);
|
|
if (cmgr)
|
|
{
|
|
qse_pio_setcmgr (handle, QSE_PIO_IN, cmgr);
|
|
qse_pio_setcmgr (handle, QSE_PIO_OUT, cmgr);
|
|
qse_pio_setcmgr (handle, QSE_PIO_ERR, cmgr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
riod->handle = (void*)handle;
|
|
riod->uflags = 0; /* pio indicator */
|
|
return 1;
|
|
}
|
|
|
|
static qse_ssize_t pio_handler_rest (qse_awk_rtx_t* rtx, qse_awk_rio_cmd_t cmd, qse_awk_rio_arg_t* riod, void* data, qse_size_t size)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case QSE_AWK_RIO_OPEN:
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
|
|
case QSE_AWK_RIO_CLOSE:
|
|
{
|
|
qse_pio_t* pio = (qse_pio_t*)riod->handle;
|
|
if (riod->mode == QSE_AWK_RIO_PIPE_RW)
|
|
{
|
|
/* specialy treatment is needed for rwpipe.
|
|
* inspect rwcmode to see if partial closing is
|
|
* requested. */
|
|
if (riod->rwcmode == QSE_AWK_RIO_CLOSE_READ)
|
|
{
|
|
qse_pio_end (pio, QSE_PIO_IN);
|
|
return 0;
|
|
}
|
|
if (riod->rwcmode == QSE_AWK_RIO_CLOSE_WRITE)
|
|
{
|
|
qse_pio_end (pio, QSE_PIO_OUT);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
qse_pio_close (pio);
|
|
return 0;
|
|
}
|
|
|
|
case QSE_AWK_RIO_READ:
|
|
return qse_pio_read ((qse_pio_t*)riod->handle, QSE_PIO_OUT, data, size);
|
|
|
|
case QSE_AWK_RIO_WRITE:
|
|
return qse_pio_write((qse_pio_t*)riod->handle, QSE_PIO_IN, data, size);
|
|
|
|
case QSE_AWK_RIO_WRITE_BYTES:
|
|
return qse_pio_writebytes((qse_pio_t*)riod->handle, QSE_PIO_IN, data, size);
|
|
|
|
case QSE_AWK_RIO_FLUSH:
|
|
/*if (riod->mode == QSE_AWK_RIO_PIPE_READ) return -1;*/
|
|
return qse_pio_flush ((qse_pio_t*)riod->handle, QSE_PIO_IN);
|
|
|
|
case QSE_AWK_RIO_NEXT:
|
|
break;
|
|
}
|
|
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
static qse_ssize_t awk_rio_pipe (qse_awk_rtx_t* rtx, qse_awk_rio_cmd_t cmd, qse_awk_rio_arg_t* riod, void* data, qse_size_t size)
|
|
{
|
|
if (cmd == QSE_AWK_RIO_OPEN)
|
|
{
|
|
int flags;
|
|
qse_nwad_t nwad;
|
|
|
|
if (riod->mode != QSE_AWK_RIO_PIPE_RW ||
|
|
parse_rwpipe_uri (riod->name, &flags, &nwad) <= -1)
|
|
{
|
|
return pio_handler_open (rtx, riod);
|
|
}
|
|
else
|
|
{
|
|
qse_nwio_tmout_t tmout_buf;
|
|
qse_nwio_tmout_t* tmout = QSE_NULL;
|
|
ioattr_t* ioattr;
|
|
rxtn_t* rxtn;
|
|
|
|
rxtn = GET_RXTN(rtx);
|
|
|
|
ioattr = get_ioattr(&rxtn->cmgrtab, riod->name, qse_strlen(riod->name));
|
|
if (ioattr)
|
|
{
|
|
tmout = &tmout_buf;
|
|
tmout->r = ioattr->tmout[0];
|
|
tmout->w = ioattr->tmout[1];
|
|
tmout->c = ioattr->tmout[2];
|
|
tmout->a = ioattr->tmout[3];
|
|
}
|
|
|
|
return nwio_handler_open(rtx, riod, flags, &nwad, tmout);
|
|
}
|
|
}
|
|
else if (riod->uflags > 0)
|
|
return nwio_handler_rest(rtx, cmd, riod, data, size);
|
|
else
|
|
return pio_handler_rest(rtx, cmd, riod, data, size);
|
|
}
|
|
|
|
static qse_ssize_t awk_rio_file (qse_awk_rtx_t* rtx, qse_awk_rio_cmd_t cmd, qse_awk_rio_arg_t* riod, void* data, qse_size_t size)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case QSE_AWK_RIO_OPEN:
|
|
{
|
|
qse_sio_t* handle;
|
|
int flags = QSE_SIO_IGNOREMBWCERR;
|
|
|
|
switch (riod->mode)
|
|
{
|
|
case QSE_AWK_RIO_FILE_READ:
|
|
flags |= QSE_SIO_READ;
|
|
break;
|
|
case QSE_AWK_RIO_FILE_WRITE:
|
|
flags |= QSE_SIO_WRITE | QSE_SIO_CREATE | QSE_SIO_TRUNCATE;
|
|
break;
|
|
case QSE_AWK_RIO_FILE_APPEND:
|
|
flags |= QSE_SIO_APPEND | QSE_SIO_CREATE;
|
|
break;
|
|
default:
|
|
/* this must not happen */
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
handle = qse_sio_open (qse_awk_rtx_getmmgr(rtx), 0, riod->name, flags);
|
|
if (handle == QSE_NULL)
|
|
{
|
|
qse_cstr_t errarg;
|
|
errarg.ptr = riod->name;
|
|
errarg.len = qse_strlen(riod->name);
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EOPEN, &errarg);
|
|
return -1;
|
|
}
|
|
|
|
#if defined(QSE_CHAR_IS_WCHAR)
|
|
{
|
|
qse_cmgr_t* cmgr = qse_awk_rtx_getiocmgrstd(rtx, riod->name);
|
|
if (cmgr) qse_sio_setcmgr(handle, cmgr);
|
|
}
|
|
#endif
|
|
|
|
riod->handle = (void*)handle;
|
|
return 1;
|
|
}
|
|
|
|
case QSE_AWK_RIO_CLOSE:
|
|
qse_sio_close ((qse_sio_t*)riod->handle);
|
|
riod->handle = QSE_NULL;
|
|
return 0;
|
|
|
|
case QSE_AWK_RIO_READ:
|
|
return qse_sio_getstrn((qse_sio_t*)riod->handle, data, size);
|
|
|
|
case QSE_AWK_RIO_WRITE:
|
|
return qse_sio_putstrn((qse_sio_t*)riod->handle, data, size);
|
|
|
|
case QSE_AWK_RIO_WRITE_BYTES:
|
|
return qse_sio_putmbsn((qse_sio_t*)riod->handle, data, size);
|
|
|
|
case QSE_AWK_RIO_FLUSH:
|
|
return qse_sio_flush((qse_sio_t*)riod->handle);
|
|
|
|
case QSE_AWK_RIO_NEXT:
|
|
return -1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod)
|
|
{
|
|
rxtn_t* rxtn = GET_RXTN(rtx);
|
|
qse_sio_t* sio;
|
|
|
|
if (riod->mode == QSE_AWK_RIO_CONSOLE_READ)
|
|
{
|
|
xtn_t* xtn = (xtn_t*)GET_XTN(rtx->awk);
|
|
|
|
if (rxtn->c.in.files == QSE_NULL)
|
|
{
|
|
/* if no input files is specified,
|
|
* open the standard input */
|
|
QSE_ASSERT (rxtn->c.in.index == 0);
|
|
|
|
if (rxtn->c.in.count == 0)
|
|
{
|
|
sio = open_sio_std_rtx (
|
|
rtx, QSE_SIO_STDIN,
|
|
QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR
|
|
);
|
|
if (sio == QSE_NULL) return -1;
|
|
|
|
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
|
|
|
|
riod->handle = sio;
|
|
rxtn->c.in.count++;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
/* a temporary variable sio is used here not to change
|
|
* any fields of riod when the open operation fails */
|
|
const qse_char_t* file;
|
|
qse_awk_val_t* argv;
|
|
qse_htb_t* map;
|
|
qse_htb_pair_t* pair;
|
|
qse_char_t ibuf[128];
|
|
qse_size_t ibuflen;
|
|
qse_awk_val_t* v;
|
|
qse_cstr_t as;
|
|
|
|
nextfile:
|
|
file = rxtn->c.in.files[rxtn->c.in.index];
|
|
|
|
if (file == QSE_NULL)
|
|
{
|
|
/* no more input file */
|
|
|
|
if (rxtn->c.in.count == 0)
|
|
{
|
|
/* all ARGVs are empty strings.
|
|
* so no console files were opened.
|
|
* open the standard input here.
|
|
*
|
|
* 'BEGIN { ARGV[1]=""; ARGV[2]=""; }
|
|
* { print $0; }' file1 file2
|
|
*/
|
|
sio = open_sio_std_rtx (
|
|
rtx, QSE_SIO_STDIN,
|
|
QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR
|
|
);
|
|
if (sio == QSE_NULL) return -1;
|
|
|
|
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
|
|
|
|
riod->handle = sio;
|
|
rxtn->c.in.count++;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* handle special case when ARGV[x] has been altered.
|
|
* so from here down, the file name gotten from
|
|
* rxtn->c.in.files is not important and is overridden
|
|
* from ARGV.
|
|
* 'BEGIN { ARGV[1]="file3"; }
|
|
* { print $0; }' file1 file2
|
|
*/
|
|
argv = qse_awk_rtx_getgbl(rtx, xtn->gbl_argv);
|
|
QSE_ASSERT (argv != QSE_NULL);
|
|
if (QSE_AWK_RTX_GETVALTYPE(rtx, argv) != QSE_AWK_VAL_MAP)
|
|
{
|
|
/* with FLEXMAP on, you can change ARGV to a scalar.
|
|
* BEGIN { ARGV="xxx"; }
|
|
* you must not do this. */
|
|
qse_awk_rtx_seterrfmt (rtx, QSE_AWK_EINVAL, QSE_NULL, QSE_T("phony value in ARGV"));
|
|
return -1;
|
|
}
|
|
|
|
map = ((qse_awk_val_map_t*)argv)->map;
|
|
QSE_ASSERT (map != QSE_NULL);
|
|
|
|
ibuflen = qse_awk_inttostr (
|
|
rtx->awk, rxtn->c.in.index + 1, 10, QSE_NULL,
|
|
ibuf, QSE_COUNTOF(ibuf));
|
|
|
|
pair = qse_htb_search (map, ibuf, ibuflen);
|
|
QSE_ASSERT (pair != QSE_NULL);
|
|
|
|
v = QSE_HTB_VPTR(pair);
|
|
QSE_ASSERT (v != QSE_NULL);
|
|
|
|
as.ptr = qse_awk_rtx_getvalstr (rtx, v, &as.len);
|
|
if (as.ptr == QSE_NULL) return -1;
|
|
|
|
if (as.len == 0)
|
|
{
|
|
/* the name is empty */
|
|
qse_awk_rtx_freevalstr (rtx, v, as.ptr);
|
|
rxtn->c.in.index++;
|
|
goto nextfile;
|
|
}
|
|
|
|
if (qse_strlen(as.ptr) < as.len)
|
|
{
|
|
/* the name contains one or more '\0' */
|
|
qse_cstr_t errarg;
|
|
|
|
errarg.ptr = as.ptr;
|
|
/* use this length not to contains '\0'
|
|
* in an error message */
|
|
errarg.len = qse_strlen(as.ptr);
|
|
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EIONMNL, &errarg);
|
|
|
|
qse_awk_rtx_freevalstr (rtx, v, as.ptr);
|
|
return -1;
|
|
}
|
|
|
|
file = as.ptr;
|
|
|
|
sio = (file[0] == QSE_T('-') && file[1] == QSE_T('\0'))?
|
|
open_sio_std_rtx (rtx, QSE_SIO_STDIN,
|
|
QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR):
|
|
open_sio_rtx (rtx, file,
|
|
QSE_SIO_READ | QSE_SIO_IGNOREMBWCERR);
|
|
if (sio == QSE_NULL)
|
|
{
|
|
qse_awk_rtx_freevalstr (rtx, v, as.ptr);
|
|
return -1;
|
|
}
|
|
|
|
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
|
|
|
|
if (qse_awk_rtx_setfilename (
|
|
rtx, file, qse_strlen(file)) <= -1)
|
|
{
|
|
qse_sio_close (sio);
|
|
qse_awk_rtx_freevalstr (rtx, v, as.ptr);
|
|
return -1;
|
|
}
|
|
|
|
qse_awk_rtx_freevalstr (rtx, v, as.ptr);
|
|
riod->handle = sio;
|
|
|
|
/* increment the counter of files successfully opened */
|
|
rxtn->c.in.count++;
|
|
rxtn->c.in.index++;
|
|
return 1;
|
|
}
|
|
|
|
}
|
|
else if (riod->mode == QSE_AWK_RIO_CONSOLE_WRITE)
|
|
{
|
|
if (rxtn->c.out.files == QSE_NULL)
|
|
{
|
|
QSE_ASSERT (rxtn->c.out.index == 0);
|
|
|
|
if (rxtn->c.out.count == 0)
|
|
{
|
|
sio = open_sio_std_rtx (
|
|
rtx, QSE_SIO_STDOUT,
|
|
QSE_SIO_WRITE | QSE_SIO_IGNOREMBWCERR | QSE_SIO_LINEBREAK
|
|
);
|
|
if (sio == QSE_NULL) return -1;
|
|
|
|
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
|
|
|
|
riod->handle = sio;
|
|
rxtn->c.out.count++;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
/* a temporary variable sio is used here not to change
|
|
* any fields of riod when the open operation fails */
|
|
qse_sio_t* sio;
|
|
const qse_char_t* file;
|
|
|
|
file = rxtn->c.out.files[rxtn->c.out.index];
|
|
|
|
if (file == QSE_NULL)
|
|
{
|
|
/* no more input file */
|
|
return 0;
|
|
}
|
|
|
|
sio = (file[0] == QSE_T('-') && file[1] == QSE_T('\0'))?
|
|
open_sio_std_rtx (
|
|
rtx, QSE_SIO_STDOUT,
|
|
QSE_SIO_WRITE | QSE_SIO_IGNOREMBWCERR | QSE_SIO_LINEBREAK):
|
|
open_sio_rtx (
|
|
rtx, file,
|
|
QSE_SIO_WRITE | QSE_SIO_CREATE |
|
|
QSE_SIO_TRUNCATE | QSE_SIO_IGNOREMBWCERR);
|
|
if (sio == QSE_NULL) return -1;
|
|
|
|
if (rxtn->c.cmgr) qse_sio_setcmgr (sio, rxtn->c.cmgr);
|
|
|
|
if (qse_awk_rtx_setofilename (
|
|
rtx, file, qse_strlen(file)) <= -1)
|
|
{
|
|
qse_sio_close (sio);
|
|
return -1;
|
|
}
|
|
|
|
riod->handle = sio;
|
|
rxtn->c.out.index++;
|
|
rxtn->c.out.count++;
|
|
return 1;
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static qse_ssize_t awk_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_cmd_t cmd, qse_awk_rio_arg_t* riod, void* data, qse_size_t size)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case QSE_AWK_RIO_OPEN:
|
|
return open_rio_console (rtx, riod);
|
|
|
|
case QSE_AWK_RIO_CLOSE:
|
|
if (riod->handle) qse_sio_close ((qse_sio_t*)riod->handle);
|
|
return 0;
|
|
|
|
case QSE_AWK_RIO_READ:
|
|
{
|
|
qse_ssize_t nn;
|
|
|
|
while ((nn = qse_sio_getstrn((qse_sio_t*)riod->handle, data, size)) == 0)
|
|
{
|
|
int n;
|
|
qse_sio_t* sio = (qse_sio_t*)riod->handle;
|
|
|
|
n = open_rio_console(rtx, riod);
|
|
if (n <= -1) return -1;
|
|
|
|
if (n == 0)
|
|
{
|
|
/* no more input console */
|
|
return 0;
|
|
}
|
|
|
|
if (sio) qse_sio_close (sio);
|
|
|
|
/* reset FNR to 0 here since the caller doesn't know that the file has changed. */
|
|
qse_awk_rtx_setgbl(rtx, QSE_AWK_GBL_FNR, qse_awk_rtx_makeintval(rtx, 0));
|
|
|
|
}
|
|
|
|
return nn;
|
|
}
|
|
|
|
case QSE_AWK_RIO_WRITE:
|
|
return qse_sio_putstrn((qse_sio_t*)riod->handle, data, size);
|
|
|
|
case QSE_AWK_RIO_WRITE_BYTES:
|
|
return qse_sio_putmbsn((qse_sio_t*)riod->handle, data, size);
|
|
|
|
case QSE_AWK_RIO_FLUSH:
|
|
return qse_sio_flush((qse_sio_t*)riod->handle);
|
|
|
|
case QSE_AWK_RIO_NEXT:
|
|
{
|
|
int n;
|
|
qse_sio_t* sio = (qse_sio_t*)riod->handle;
|
|
|
|
n = open_rio_console (rtx, riod);
|
|
if (n <= -1) return -1;
|
|
|
|
if (n == 0)
|
|
{
|
|
/* if there is no more file, keep the previous handle */
|
|
return 0;
|
|
}
|
|
|
|
if (sio) qse_sio_close (sio);
|
|
return n;
|
|
}
|
|
|
|
}
|
|
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_EINTERN, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
static void fini_rxtn (qse_awk_rtx_t* rtx)
|
|
{
|
|
rxtn_t* rxtn = GET_RXTN(rtx);
|
|
/*xtn_t* xtn = (xtn_t*)GET_XTN(rtx->awk);*/
|
|
|
|
if (rxtn->cmgrtab_inited)
|
|
{
|
|
qse_htb_fini (&rxtn->cmgrtab);
|
|
rxtn->cmgrtab_inited = 0;
|
|
}
|
|
}
|
|
|
|
static int build_argcv (
|
|
qse_awk_rtx_t* rtx, int argc_id, int argv_id,
|
|
const qse_char_t* id, const qse_char_t*const icf[])
|
|
{
|
|
const qse_char_t*const* p;
|
|
qse_size_t argc;
|
|
qse_awk_val_t* v_argc;
|
|
qse_awk_val_t* v_argv;
|
|
qse_awk_val_t* v_tmp;
|
|
qse_char_t key[QSE_SIZEOF(qse_awk_int_t)*8+2];
|
|
qse_size_t key_len;
|
|
|
|
v_argv = qse_awk_rtx_makemapval (rtx);
|
|
if (v_argv == QSE_NULL) return -1;
|
|
|
|
qse_awk_rtx_refupval (rtx, v_argv);
|
|
|
|
/* make ARGV[0] */
|
|
v_tmp = qse_awk_rtx_makestrvalwithstr (rtx, id);
|
|
if (v_tmp == QSE_NULL)
|
|
{
|
|
qse_awk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
/* increment reference count of v_tmp in advance as if
|
|
* it has successfully been assigned into ARGV. */
|
|
qse_awk_rtx_refupval (rtx, v_tmp);
|
|
|
|
key_len = qse_strxcpy (key, QSE_COUNTOF(key), QSE_T("0"));
|
|
if (qse_htb_upsert (
|
|
((qse_awk_val_map_t*)v_argv)->map,
|
|
key, key_len, v_tmp, 0) == QSE_NULL)
|
|
{
|
|
/* if the assignment operation fails, decrements
|
|
* the reference of v_tmp to free it */
|
|
qse_awk_rtx_refdownval (rtx, v_tmp);
|
|
|
|
/* the values previously assigned into the
|
|
* map will be freeed when v_argv is freed */
|
|
qse_awk_rtx_refdownval (rtx, v_argv);
|
|
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
if (icf)
|
|
{
|
|
for (argc = 1, p = icf; *p; p++, argc++)
|
|
{
|
|
/* the argument must compose a numeric string if it can be.
|
|
* so call qse_awk_rtx_makenstrvalwithstr() instead of
|
|
* qse_awk_rtx_makestrvalwithstr(). */
|
|
v_tmp = qse_awk_rtx_makenstrvalwithstr (rtx, *p);
|
|
if (v_tmp == QSE_NULL)
|
|
{
|
|
qse_awk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
key_len = qse_awk_inttostr (
|
|
rtx->awk, argc, 10,
|
|
QSE_NULL, key, QSE_COUNTOF(key));
|
|
QSE_ASSERT (key_len != (qse_size_t)-1);
|
|
|
|
qse_awk_rtx_refupval (rtx, v_tmp);
|
|
|
|
if (qse_htb_upsert (
|
|
((qse_awk_val_map_t*)v_argv)->map,
|
|
key, key_len, v_tmp, 0) == QSE_NULL)
|
|
{
|
|
qse_awk_rtx_refdownval (rtx, v_tmp);
|
|
qse_awk_rtx_refdownval (rtx, v_argv);
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
else argc = 1;
|
|
|
|
v_argc = qse_awk_rtx_makeintval(rtx, (qse_awk_int_t)argc);
|
|
if (v_argc == QSE_NULL)
|
|
{
|
|
qse_awk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
qse_awk_rtx_refupval (rtx, v_argc);
|
|
|
|
if (qse_awk_rtx_setgbl(rtx, argc_id, v_argc) <= -1)
|
|
{
|
|
qse_awk_rtx_refdownval (rtx, v_argc);
|
|
qse_awk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
if (qse_awk_rtx_setgbl(rtx, argv_id, v_argv) <= -1)
|
|
{
|
|
qse_awk_rtx_refdownval (rtx, v_argc);
|
|
qse_awk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
qse_awk_rtx_refdownval (rtx, v_argc);
|
|
qse_awk_rtx_refdownval (rtx, v_argv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __build_environ (qse_awk_rtx_t* rtx, int gbl_id, qse_env_char_t* envarr[])
|
|
{
|
|
qse_awk_val_t* v_env;
|
|
qse_awk_val_t* v_tmp;
|
|
|
|
v_env = qse_awk_rtx_makemapval (rtx);
|
|
if (v_env == QSE_NULL) return -1;
|
|
|
|
qse_awk_rtx_refupval (rtx, v_env);
|
|
|
|
if (envarr)
|
|
{
|
|
qse_env_char_t* eq;
|
|
qse_char_t* kptr, * vptr;
|
|
qse_size_t klen, count;
|
|
|
|
for (count = 0; envarr[count]; count++)
|
|
{
|
|
#if ((defined(QSE_ENV_CHAR_IS_MCHAR) && defined(QSE_CHAR_IS_MCHAR)) || \
|
|
(defined(QSE_ENV_CHAR_IS_WCHAR) && defined(QSE_CHAR_IS_WCHAR)))
|
|
eq = qse_strchr (envarr[count], QSE_T('='));
|
|
if (eq == QSE_NULL || eq == envarr[count]) continue;
|
|
|
|
kptr = envarr[count];
|
|
klen = eq - envarr[count];
|
|
vptr = eq + 1;
|
|
#elif defined(QSE_ENV_CHAR_IS_MCHAR)
|
|
eq = qse_mbschr (envarr[count], QSE_MT('='));
|
|
if (eq == QSE_NULL || eq == envarr[count]) continue;
|
|
|
|
*eq = QSE_MT('\0');
|
|
|
|
/* mbstowcsdup() may fail for invalid encoding. as the environment
|
|
* variaables are not under control, call mbstowcsalldup() instead
|
|
* to go on despite encoding failure */
|
|
kptr = qse_mbstowcsalldupwithcmgr(envarr[count], &klen, qse_awk_rtx_getmmgr(rtx), qse_awk_rtx_getcmgr(rtx));
|
|
vptr = qse_mbstowcsalldupwithcmgr(eq + 1, QSE_NULL, qse_awk_rtx_getmmgr(rtx), qse_awk_rtx_getcmgr(rtx));
|
|
if (kptr == QSE_NULL || vptr == QSE_NULL)
|
|
{
|
|
if (kptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), kptr);
|
|
if (vptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), vptr);
|
|
qse_awk_rtx_refdownval (rtx, v_env);
|
|
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
*eq = QSE_MT('=');
|
|
#else
|
|
eq = qse_wcschr(envarr[count], QSE_WT('='));
|
|
if (eq == QSE_NULL || eq == envarr[count]) continue;
|
|
|
|
*eq = QSE_WT('\0');
|
|
|
|
kptr = qse_wcstombsdupwithcmgr(envarr[count], &klen, qse_awk_rtx_getmmgr(rtx), qse_awk_rtx_getcmgr(rtx));
|
|
vptr = qse_wcstombsdupwithcmgr(eq + 1, QSE_NULL, qse_awk_rtx_getmmgr(rtx), qse_awk_rtx_getcmgr(rtx));
|
|
if (kptr == QSE_NULL || vptr == QSE_NULL)
|
|
{
|
|
if (kptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), kptr);
|
|
if (vptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), vptr);
|
|
qse_awk_rtx_refdownval (rtx, v_env);
|
|
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
*eq = QSE_WT('=');
|
|
#endif
|
|
|
|
/* the string in ENVIRON should be a numeric string if
|
|
* it can be converted to a number. call makenstrval()
|
|
* instead of makestrval() */
|
|
v_tmp = qse_awk_rtx_makenstrvalwithstr (rtx, vptr);
|
|
if (v_tmp == QSE_NULL)
|
|
{
|
|
#if ((defined(QSE_ENV_CHAR_IS_MCHAR) && defined(QSE_CHAR_IS_MCHAR)) || \
|
|
(defined(QSE_ENV_CHAR_IS_WCHAR) && defined(QSE_CHAR_IS_WCHAR)))
|
|
/* nothing to do */
|
|
#else
|
|
if (vptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), vptr);
|
|
if (kptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), kptr);
|
|
#endif
|
|
qse_awk_rtx_refdownval (rtx, v_env);
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* increment reference count of v_tmp in advance as if
|
|
* it has successfully been assigned into ARGV. */
|
|
qse_awk_rtx_refupval (rtx, v_tmp);
|
|
|
|
if (qse_htb_upsert (
|
|
((qse_awk_val_map_t*)v_env)->map,
|
|
kptr, klen, v_tmp, 0) == QSE_NULL)
|
|
{
|
|
/* if the assignment operation fails, decrements
|
|
* the reference of v_tmp to free it */
|
|
qse_awk_rtx_refdownval (rtx, v_tmp);
|
|
|
|
#if ((defined(QSE_ENV_CHAR_IS_MCHAR) && defined(QSE_CHAR_IS_MCHAR)) || \
|
|
(defined(QSE_ENV_CHAR_IS_WCHAR) && defined(QSE_CHAR_IS_WCHAR)))
|
|
/* nothing to do */
|
|
#else
|
|
if (vptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), vptr);
|
|
if (kptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), kptr);
|
|
#endif
|
|
|
|
/* the values previously assigned into the
|
|
* map will be freeed when v_env is freed */
|
|
qse_awk_rtx_refdownval (rtx, v_env);
|
|
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
#if ((defined(QSE_ENV_CHAR_IS_MCHAR) && defined(QSE_CHAR_IS_MCHAR)) || \
|
|
(defined(QSE_ENV_CHAR_IS_WCHAR) && defined(QSE_CHAR_IS_WCHAR)))
|
|
/* nothing to do */
|
|
#else
|
|
if (vptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), vptr);
|
|
if (kptr) QSE_MMGR_FREE (qse_awk_rtx_getmmgr(rtx), kptr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (qse_awk_rtx_setgbl (rtx, gbl_id, v_env) == -1)
|
|
{
|
|
qse_awk_rtx_refdownval (rtx, v_env);
|
|
return -1;
|
|
}
|
|
|
|
qse_awk_rtx_refdownval (rtx, v_env);
|
|
return 0;
|
|
}
|
|
|
|
static int build_environ (qse_awk_rtx_t* rtx, int gbl_id)
|
|
{
|
|
qse_env_t env;
|
|
int xret;
|
|
|
|
if (qse_env_init(&env, qse_awk_rtx_getmmgr(rtx), 1) <= -1)
|
|
{
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return -1;
|
|
}
|
|
|
|
xret = __build_environ (rtx, gbl_id, qse_env_getarr(&env));
|
|
|
|
qse_env_fini (&env);
|
|
return xret;
|
|
}
|
|
|
|
static int make_additional_globals (
|
|
qse_awk_rtx_t* rtx, xtn_t* xtn,
|
|
const qse_char_t* id, const qse_char_t*const icf[])
|
|
{
|
|
if (build_argcv (rtx, xtn->gbl_argc, xtn->gbl_argv, id, icf) <= -1 ||
|
|
build_environ (rtx, xtn->gbl_environ) <= -1) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static qse_awk_rtx_t* open_rtx_std (
|
|
qse_awk_t* awk,
|
|
qse_size_t xtnsize,
|
|
const qse_char_t* id,
|
|
const qse_char_t* icf[],
|
|
const qse_char_t* ocf[],
|
|
qse_cmgr_t* cmgr)
|
|
{
|
|
qse_awk_rtx_t* rtx;
|
|
qse_awk_rio_t rio;
|
|
rxtn_t* rxtn;
|
|
xtn_t* xtn;
|
|
|
|
xtn = GET_XTN(awk);
|
|
|
|
rio.pipe = awk_rio_pipe;
|
|
rio.file = awk_rio_file;
|
|
rio.console = awk_rio_console;
|
|
|
|
rtx = qse_awk_rtx_open(awk, QSE_SIZEOF(rxtn_t) + xtnsize, &rio);
|
|
if (!rtx) return QSE_NULL;
|
|
|
|
rtx->_instsize += QSE_SIZEOF(rxtn_t);
|
|
|
|
rxtn = GET_RXTN(rtx);
|
|
|
|
if (rtx->awk->opt.trait & QSE_AWK_RIO)
|
|
{
|
|
if (qse_htb_init(&rxtn->cmgrtab, qse_awk_getmmgr(awk), 256, 70, QSE_SIZEOF(qse_char_t), 1) <= -1)
|
|
{
|
|
qse_awk_rtx_close (rtx);
|
|
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
qse_htb_setstyle (&rxtn->cmgrtab, qse_gethtbstyle(QSE_HTB_STYLE_INLINE_COPIERS));
|
|
rxtn->cmgrtab_inited = 1;
|
|
}
|
|
|
|
rxtn->ecb.close = fini_rxtn;
|
|
qse_awk_rtx_pushecb (rtx, &rxtn->ecb);
|
|
|
|
rxtn->c.in.files = icf;
|
|
rxtn->c.in.index = 0;
|
|
rxtn->c.in.count = 0;
|
|
rxtn->c.out.files = ocf;
|
|
rxtn->c.out.index = 0;
|
|
rxtn->c.out.count = 0;
|
|
rxtn->c.cmgr = cmgr;
|
|
|
|
/* FILENAME can be set when the input console is opened.
|
|
* so we skip setting it here even if an explicit console file
|
|
* is specified. So the value of FILENAME is empty in the
|
|
* BEGIN block unless getline is ever met.
|
|
*
|
|
* However, OFILENAME is different. The output
|
|
* console is treated as if it's already open upon start-up.
|
|
* otherwise, 'BEGIN { print OFILENAME; }' prints an empty
|
|
* string regardless of output console files specified.
|
|
* That's because OFILENAME is evaluated before the output
|
|
* console file is opened.
|
|
*/
|
|
if (ocf && ocf[0])
|
|
{
|
|
if (qse_awk_rtx_setofilename(rtx, ocf[0], qse_strlen(ocf[0])) <= -1)
|
|
{
|
|
awk->errinf = rtx->errinf; /* transfer error info */
|
|
qse_awk_rtx_close (rtx);
|
|
return QSE_NULL;
|
|
}
|
|
}
|
|
|
|
if (make_additional_globals(rtx, xtn, id, icf) <= -1)
|
|
{
|
|
awk->errinf = rtx->errinf; /* transfer error info */
|
|
qse_awk_rtx_close (rtx);
|
|
return QSE_NULL;
|
|
}
|
|
|
|
return rtx;
|
|
}
|
|
|
|
qse_awk_rtx_t* qse_awk_rtx_openstdwithmbs (
|
|
qse_awk_t* awk,
|
|
qse_size_t xtnsize,
|
|
const qse_mchar_t* id,
|
|
const qse_mchar_t* icf[],
|
|
const qse_mchar_t* ocf[],
|
|
qse_cmgr_t* cmgr)
|
|
{
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
return open_rtx_std(awk, xtnsize, id, icf, ocf, cmgr);
|
|
#else
|
|
qse_awk_rtx_t* rtx = QSE_NULL;
|
|
qse_size_t wcslen, i;
|
|
qse_wchar_t* wid = QSE_NULL, ** wicf = QSE_NULL, ** wocf = QSE_NULL;
|
|
|
|
wid = qse_awk_mbstowcsdup(awk, id, &wcslen);
|
|
if (!wid) return QSE_NULL;
|
|
|
|
if (icf)
|
|
{
|
|
for (i = 0; icf[i]; i++) ;
|
|
|
|
wicf = (qse_wchar_t**)qse_awk_callocmem(awk, QSE_SIZEOF(*wicf) * (i + 1));
|
|
if (!wicf) goto done;
|
|
|
|
for (i = 0; icf[i]; i++)
|
|
{
|
|
wicf[i] = qse_awk_mbstowcsdup(awk, icf[i], &wcslen);
|
|
if (!wicf[i]) goto done;
|
|
}
|
|
wicf[i] = QSE_NULL;
|
|
}
|
|
|
|
if (ocf)
|
|
{
|
|
for (i = 0; ocf[i]; i++) ;
|
|
|
|
wocf = (qse_wchar_t**)qse_awk_callocmem(awk, QSE_SIZEOF(*wocf) * (i + 1));
|
|
if (!wocf) goto done;
|
|
|
|
for (i = 0; ocf[i]; i++)
|
|
{
|
|
wocf[i] = qse_awk_mbstowcsdup(awk, ocf[i], &wcslen);
|
|
if (!wocf[i]) goto done;
|
|
}
|
|
wocf[i] = QSE_NULL;
|
|
}
|
|
|
|
rtx = open_rtx_std(awk, xtnsize, wid, (const qse_wchar_t**)wicf, (const qse_wchar_t**)wocf, cmgr);
|
|
|
|
done:
|
|
if (wocf)
|
|
{
|
|
for (i = 0; wocf[i]; i++) qse_awk_freemem (awk, wocf[i]);
|
|
qse_awk_freemem (awk, wocf);
|
|
}
|
|
if (wicf)
|
|
{
|
|
for (i = 0; wicf[i]; i++) qse_awk_freemem (awk, wicf[i]);
|
|
qse_awk_freemem (awk, wicf);
|
|
}
|
|
if (wid) qse_awk_freemem (awk, wid);
|
|
|
|
return rtx;
|
|
#endif
|
|
}
|
|
|
|
qse_awk_rtx_t* qse_awk_rtx_openstdwithwcs (
|
|
qse_awk_t* awk,
|
|
qse_size_t xtnsize,
|
|
const qse_wchar_t* id,
|
|
const qse_wchar_t* icf[],
|
|
const qse_wchar_t* ocf[],
|
|
qse_cmgr_t* cmgr)
|
|
{
|
|
#if defined(QSE_CHAR_IS_MCHAR)
|
|
qse_awk_rtx_t* rtx = QSE_NULL;
|
|
qse_size_t mbslen, i;
|
|
qse_mchar_t* mid = QSE_NULL, ** micf = QSE_NULL, ** mocf = QSE_NULL;
|
|
|
|
mid = qse_awk_wcstombsdup(awk, id, &mbslen);
|
|
if (!mid) return QSE_NULL;
|
|
|
|
if (icf)
|
|
{
|
|
for (i = 0; icf[i]; i++) ;
|
|
|
|
micf = (qse_mchar_t**)qse_awk_callocmem(awk, QSE_SIZEOF(*micf) * (i + 1));
|
|
if (!micf) goto done;
|
|
|
|
for (i = 0; icf[i]; i++)
|
|
{
|
|
micf[i] = qse_awk_wcstombsdup(awk, icf[i], &mbslen);
|
|
if (!micf[i]) goto done;
|
|
}
|
|
micf[i] = QSE_NULL;
|
|
}
|
|
|
|
if (ocf)
|
|
{
|
|
for (i = 0; ocf[i]; i++) ;
|
|
|
|
mocf = (qse_wchar_t**)qse_awk_callocmem(awk, QSE_SIZEOF(*mocf) * (i + 1));
|
|
if (!mocf) goto done;
|
|
|
|
for (i = 0; ocf[i]; i++)
|
|
{
|
|
mocf[i] = qse_awk_wcstombsdup(awk, ocf[i], &mbslen);
|
|
if (!mocf[i]) goto done;
|
|
}
|
|
mocf[i] = QSE_NULL;
|
|
}
|
|
|
|
rtx = open_rtx_std(awk, xtnsize, mid, (const qse_mchar_t**)micf, (const qse_mchar_t**)mocf, cmgr);
|
|
|
|
done:
|
|
if (mocf)
|
|
{
|
|
for (i = 0; mocf[i]; i++) qse_awk_freemem (awk, mocf[i]);
|
|
qse_awk_freemem (awk, mocf);
|
|
}
|
|
if (micf)
|
|
{
|
|
for (i = 0; micf[i]; i++) qse_awk_freemem (awk, micf[i]);
|
|
qse_awk_freemem (awk, micf);
|
|
}
|
|
if (mid) qse_awk_freemem (awk, mid);
|
|
|
|
return rtx;
|
|
#else
|
|
return open_rtx_std(awk, xtnsize, id, icf, ocf, cmgr);
|
|
#endif
|
|
}
|
|
|
|
|
|
static int timeout_code (const qse_char_t* name)
|
|
{
|
|
if (qse_strcasecmp(name, QSE_T("rtimeout")) == 0) return 0;
|
|
if (qse_strcasecmp(name, QSE_T("wtimeout")) == 0) return 1;
|
|
if (qse_strcasecmp(name, QSE_T("ctimeout")) == 0) return 2;
|
|
if (qse_strcasecmp(name, QSE_T("atimeout")) == 0) return 3;
|
|
return -1;
|
|
}
|
|
|
|
static QSE_INLINE void init_ioattr (ioattr_t* ioattr)
|
|
{
|
|
int i;
|
|
QSE_MEMSET (ioattr, 0, QSE_SIZEOF(*ioattr));
|
|
for (i = 0; i < QSE_COUNTOF(ioattr->tmout); i++)
|
|
{
|
|
/* a negative number for no timeout */
|
|
ioattr->tmout[i].sec = -999;
|
|
ioattr->tmout[i].nsec = 0;
|
|
}
|
|
}
|
|
|
|
static ioattr_t* get_ioattr (
|
|
qse_htb_t* tab, const qse_char_t* ptr, qse_size_t len)
|
|
{
|
|
qse_htb_pair_t* pair;
|
|
|
|
pair = qse_htb_search (tab, ptr, len);
|
|
if (pair) return QSE_HTB_VPTR(pair);
|
|
|
|
return QSE_NULL;
|
|
}
|
|
|
|
static ioattr_t* find_or_make_ioattr (
|
|
qse_awk_rtx_t* rtx, qse_htb_t* tab, const qse_char_t* ptr, qse_size_t len)
|
|
{
|
|
qse_htb_pair_t* pair;
|
|
|
|
pair = qse_htb_search (tab, ptr, len);
|
|
if (pair == QSE_NULL)
|
|
{
|
|
ioattr_t ioattr;
|
|
|
|
init_ioattr (&ioattr);
|
|
|
|
pair = qse_htb_insert (tab, (void*)ptr, len, (void*)&ioattr, QSE_SIZEOF(ioattr));
|
|
if (pair == QSE_NULL)
|
|
{
|
|
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
|
|
return QSE_NULL;
|
|
}
|
|
}
|
|
|
|
return (ioattr_t*)QSE_HTB_VPTR(pair);
|
|
}
|
|
|
|
static int fnc_setioattr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
|
|
{
|
|
rxtn_t* rxtn;
|
|
qse_awk_val_t* v[3];
|
|
qse_char_t* ptr[3];
|
|
qse_size_t len[3];
|
|
int i, ret = 0, fret = 0;
|
|
int tmout;
|
|
|
|
rxtn = GET_RXTN(rtx);
|
|
QSE_ASSERT (rxtn->cmgrtab_inited == 1);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
v[i] = qse_awk_rtx_getarg (rtx, i);
|
|
ptr[i] = qse_awk_rtx_getvalstr (rtx, v[i], &len[i]);
|
|
if (ptr[i] == QSE_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
|
|
if (qse_strxchr (ptr[i], len[i], QSE_T('\0')))
|
|
{
|
|
fret = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if ((tmout = timeout_code (ptr[1])) >= 0)
|
|
{
|
|
ioattr_t* ioattr;
|
|
|
|
qse_awk_int_t l;
|
|
qse_awk_flt_t r;
|
|
int x;
|
|
|
|
/* no error is returned by qse_awk_rtx_strnum() if the strict option
|
|
* of the second parameter is 0. so i don't check for an error */
|
|
x = qse_awk_rtx_strtonum(rtx, QSE_AWK_RTX_STRTONUM_MAKE_OPTION(0, 0), ptr[2], len[2], &l, &r);
|
|
if (x == 0) r = (qse_awk_flt_t)l;
|
|
|
|
ioattr = find_or_make_ioattr(rtx, &rxtn->cmgrtab, ptr[0], len[0]);
|
|
if (ioattr == QSE_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
|
|
if (x == 0)
|
|
{
|
|
ioattr->tmout[tmout].sec = l;
|
|
ioattr->tmout[tmout].nsec = 0;
|
|
}
|
|
else if (x >= 1)
|
|
{
|
|
qse_awk_flt_t nsec;
|
|
ioattr->tmout[tmout].sec = (qse_awk_int_t)r;
|
|
nsec = r - ioattr->tmout[tmout].sec;
|
|
ioattr->tmout[tmout].nsec = QSE_SEC_TO_NSEC(nsec);
|
|
}
|
|
}
|
|
#if defined(QSE_CHAR_IS_WCHAR)
|
|
else if (qse_strcasecmp (ptr[1], QSE_T("codepage")) == 0 ||
|
|
qse_strcasecmp (ptr[1], QSE_T("encoding")) == 0)
|
|
{
|
|
ioattr_t* ioattr;
|
|
qse_cmgr_t* cmgr;
|
|
|
|
if (ptr[2][0] == QSE_T('\0'))
|
|
{
|
|
cmgr = QSE_NULL;
|
|
}
|
|
else
|
|
{
|
|
cmgr = qse_findcmgr(ptr[2]);
|
|
if (cmgr == QSE_NULL)
|
|
{
|
|
fret = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
ioattr = find_or_make_ioattr(rtx, &rxtn->cmgrtab, ptr[0], len[0]);
|
|
if (ioattr == QSE_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
|
|
ioattr->cmgr = cmgr;
|
|
qse_strxcpy (ioattr->cmgr_name, QSE_COUNTOF(ioattr->cmgr_name), ptr[2]);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* unknown attribute name */
|
|
fret = -1;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
while (i > 0)
|
|
{
|
|
i--;
|
|
qse_awk_rtx_freevalstr (rtx, v[i], ptr[i]);
|
|
}
|
|
|
|
if (ret >= 0)
|
|
{
|
|
v[0] = qse_awk_rtx_makeintval (rtx, (qse_awk_int_t)fret);
|
|
if (v[0] == QSE_NULL) return -1;
|
|
qse_awk_rtx_setretval (rtx, v[0]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int fnc_getioattr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
|
|
{
|
|
rxtn_t* rxtn;
|
|
qse_awk_val_t* v[2];
|
|
qse_char_t* ptr[2];
|
|
qse_size_t len[2];
|
|
int i, ret = 0;
|
|
int tmout;
|
|
qse_awk_val_t* rv = QSE_NULL;
|
|
|
|
ioattr_t* ioattr;
|
|
ioattr_t ioattr_buf;
|
|
|
|
rxtn = GET_RXTN(rtx);
|
|
QSE_ASSERT (rxtn->cmgrtab_inited == 1);
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
v[i] = qse_awk_rtx_getarg (rtx, i);
|
|
ptr[i] = qse_awk_rtx_getvalstr (rtx, v[i], &len[i]);
|
|
if (ptr[i] == QSE_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
|
|
if (qse_strxchr (ptr[i], len[i], QSE_T('\0'))) goto done;
|
|
}
|
|
|
|
ioattr = get_ioattr (&rxtn->cmgrtab, ptr[0], len[0]);
|
|
if (ioattr == QSE_NULL)
|
|
{
|
|
init_ioattr (&ioattr_buf);
|
|
ioattr = &ioattr_buf;
|
|
}
|
|
|
|
if ((tmout = timeout_code (ptr[1])) >= 0)
|
|
{
|
|
if (ioattr->tmout[tmout].nsec == 0)
|
|
rv = qse_awk_rtx_makeintval (rtx, ioattr->tmout[tmout].sec);
|
|
else
|
|
rv = qse_awk_rtx_makefltval (rtx, (qse_awk_flt_t)ioattr->tmout[tmout].sec + QSE_NSEC_TO_SEC((qse_awk_flt_t)ioattr->tmout[tmout].nsec));
|
|
if (rv == QSE_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
#if defined(QSE_CHAR_IS_WCHAR)
|
|
else if (qse_strcasecmp (ptr[1], QSE_T("codepage")) == 0 ||
|
|
qse_strcasecmp (ptr[1], QSE_T("encoding")) == 0)
|
|
{
|
|
rv = qse_awk_rtx_makestrvalwithstr (rtx, ioattr->cmgr_name);
|
|
if (rv == QSE_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* unknown attribute name */
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
while (i > 0)
|
|
{
|
|
i--;
|
|
qse_awk_rtx_freevalstr (rtx, v[i], ptr[i]);
|
|
}
|
|
|
|
if (ret >= 0)
|
|
{
|
|
if (rv)
|
|
{
|
|
qse_awk_rtx_refupval (rtx, rv);
|
|
ret = qse_awk_rtx_setrefval (rtx, (qse_awk_val_ref_t*)qse_awk_rtx_getarg (rtx, 2), rv);
|
|
qse_awk_rtx_refdownval (rtx, rv);
|
|
if (ret >= 0) qse_awk_rtx_setretval (rtx, QSE_AWK_VAL_ZERO);
|
|
}
|
|
else
|
|
{
|
|
qse_awk_rtx_setretval (rtx, QSE_AWK_VAL_NEGONE);
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
qse_cmgr_t* qse_awk_rtx_getiocmgrstd (qse_awk_rtx_t* rtx, const qse_char_t* ioname)
|
|
{
|
|
#if defined(QSE_CHAR_IS_WCHAR)
|
|
rxtn_t* rxtn = GET_RXTN(rtx);
|
|
ioattr_t* ioattr;
|
|
|
|
QSE_ASSERT (rxtn->cmgrtab_inited == 1);
|
|
|
|
ioattr = get_ioattr(&rxtn->cmgrtab, ioname, qse_strlen(ioname));
|
|
if (ioattr) return ioattr->cmgr;
|
|
#endif
|
|
return QSE_NULL;
|
|
}
|
|
|
|
static int add_globals (qse_awk_t* awk)
|
|
{
|
|
xtn_t* xtn = GET_XTN(awk);
|
|
|
|
xtn->gbl_argc = qse_awk_addgbl(awk, QSE_T("ARGC"));
|
|
xtn->gbl_argv = qse_awk_addgbl(awk, QSE_T("ARGV"));
|
|
xtn->gbl_environ = qse_awk_addgbl(awk, QSE_T("ENVIRON"));
|
|
|
|
return (xtn->gbl_argc <= -1 ||
|
|
xtn->gbl_argv <= -1 ||
|
|
xtn->gbl_environ <= -1)? -1: 0;
|
|
}
|
|
|
|
struct fnctab_t
|
|
{
|
|
const qse_char_t* name;
|
|
qse_awk_fnc_spec_t spec;
|
|
};
|
|
|
|
static struct fnctab_t fnctab[] =
|
|
{
|
|
/* additional aliases to module functions */
|
|
{ QSE_T("rand"), { {1, 0, QSE_T("math")}, QSE_NULL, 0 } },
|
|
{ QSE_T("srand"), { {1, 0, QSE_T("math")}, QSE_NULL, 0 } },
|
|
{ QSE_T("system"), { {1, 0, QSE_T("sys")}, QSE_NULL , 0 } },
|
|
|
|
/* additional functions */
|
|
{ QSE_T("setioattr"), { {3, 3, QSE_NULL}, fnc_setioattr, QSE_AWK_RIO } },
|
|
{ QSE_T("getioattr"), { {3, 3, QSE_T("vvr")}, fnc_getioattr, QSE_AWK_RIO } }
|
|
};
|
|
|
|
static int add_functions (qse_awk_t* awk)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < QSE_COUNTOF(fnctab); i++)
|
|
{
|
|
if (qse_awk_addfnc (awk, fnctab[i].name, &fnctab[i].spec) == QSE_NULL) return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|