3318 lines
80 KiB
C
3318 lines
80 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
Copyright (c) 2006-2020 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 "hawk-prv.h"
|
|
#include "std-prv.h"
|
|
|
|
#include <hawk-pio.h>
|
|
#include <hawk-sio.h>
|
|
|
|
#include <stdio.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(HAWK_HAVE_CFG_H) && defined(HAWK_ENABLE_LIBLTDL)
|
|
# include <ltdl.h>
|
|
# define USE_LTDL
|
|
# endif
|
|
# include <io.h>
|
|
#elif defined(__OS2__)
|
|
# define INCL_DOSMODULEMGR
|
|
# define INCL_DOSPROCESS
|
|
# define INCL_DOSERRORS
|
|
# include <os2.h>
|
|
#elif defined(__DOS__)
|
|
/* nothing to include */
|
|
#else
|
|
# include "syscall.h"
|
|
# if defined(HAWK_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(HAWK_HAVE_CFG_H)
|
|
# if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
|
# define HAVE_POW
|
|
# define HAVE_FMOD
|
|
# endif
|
|
#endif
|
|
|
|
enum logfd_flag_t
|
|
{
|
|
LOGFD_TTY = (1 << 0),
|
|
LOGFD_OPENED_HERE = (1 << 1)
|
|
};
|
|
|
|
typedef struct xtn_t
|
|
{
|
|
struct
|
|
{
|
|
struct
|
|
{
|
|
hawk_parsestd_t* x;
|
|
hawk_oow_t xindex;
|
|
|
|
union
|
|
{
|
|
/* nothing to maintain here for file */
|
|
|
|
struct
|
|
{
|
|
const hawk_ooch_t* ptr;
|
|
const hawk_ooch_t* end;
|
|
} oocs;
|
|
struct
|
|
{
|
|
const hawk_bch_t* ptr;
|
|
const hawk_bch_t* end;
|
|
} bcs;
|
|
struct
|
|
{
|
|
const hawk_uch_t* ptr;
|
|
const hawk_uch_t* end;
|
|
} ucs;
|
|
} u;
|
|
} in;
|
|
|
|
struct
|
|
{
|
|
hawk_parsestd_t* x;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
hawk_sio_t* sio;
|
|
} file;
|
|
struct
|
|
{
|
|
hawk_ooecs_t* buf;
|
|
} oocs;
|
|
struct
|
|
{
|
|
hawk_becs_t* buf;
|
|
} bcs;
|
|
struct
|
|
{
|
|
hawk_uecs_t* buf;
|
|
} ucs;
|
|
} u;
|
|
} out;
|
|
} s; /* script/source handling */
|
|
|
|
int gbl_argc;
|
|
int gbl_argv;
|
|
int gbl_environ;
|
|
|
|
hawk_ecb_t ecb;
|
|
int stdmod_up;
|
|
|
|
struct
|
|
{
|
|
int fd;
|
|
int fd_flag; /* bitwise OR'ed fo logfd_flag_t bits */
|
|
|
|
struct
|
|
{
|
|
hawk_bch_t buf[4096];
|
|
hawk_oow_t len;
|
|
} out;
|
|
} log;
|
|
} xtn_t;
|
|
|
|
typedef struct rxtn_t
|
|
{
|
|
struct
|
|
{
|
|
struct
|
|
{
|
|
hawk_ooch_t** files;
|
|
hawk_oow_t index;
|
|
hawk_oow_t count; /* number of files opened so far */
|
|
} in;
|
|
|
|
struct
|
|
{
|
|
hawk_ooch_t** files;
|
|
hawk_oow_t index;
|
|
hawk_oow_t count;
|
|
} out;
|
|
|
|
hawk_cmgr_t* cmgr;
|
|
} c; /* console */
|
|
|
|
int cmgrtab_inited;
|
|
hawk_htb_t cmgrtab;
|
|
|
|
hawk_rtx_ecb_t ecb;
|
|
} rxtn_t;
|
|
|
|
typedef struct ioattr_t
|
|
{
|
|
hawk_cmgr_t* cmgr;
|
|
hawk_ooch_t cmgr_name[64]; /* i assume that the cmgr name never exceeds this length */
|
|
hawk_ntime_t tmout[4];
|
|
} ioattr_t;
|
|
|
|
#if defined(HAWK_HAVE_INLINE)
|
|
static HAWK_INLINE xtn_t* GET_XTN(hawk_t* hawk) { return (xtn_t*)((hawk_uint8_t*)hawk_getxtn(hawk) - HAWK_SIZEOF(xtn_t)); }
|
|
static HAWK_INLINE rxtn_t* GET_RXTN(hawk_rtx_t* rtx) { return (rxtn_t*)((hawk_uint8_t*)hawk_rtx_getxtn(rtx) - HAWK_SIZEOF(rxtn_t)); }
|
|
#else
|
|
#define GET_XTN(hawk) ((xtn_t*)((hawk_uint8_t*)hawk_getxtn(hawk) - HAWK_SIZEOF(xtn_t)))
|
|
#define GET_RXTN(rtx) ((rxtn_t*)((hawk_uint8_t*)hawk_rtx_getxtn(rtx) - HAWK_SIZEOF(rxtn_t)))
|
|
#endif
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
static void* sys_alloc (hawk_mmgr_t* mmgr, hawk_oow_t size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
static void* sys_realloc (hawk_mmgr_t* mmgr, void* ptr, hawk_oow_t size)
|
|
{
|
|
return realloc(ptr, size);
|
|
}
|
|
|
|
static void sys_free (hawk_mmgr_t* mmgr, void* ptr)
|
|
{
|
|
free (ptr);
|
|
}
|
|
|
|
static hawk_mmgr_t sys_mmgr =
|
|
{
|
|
sys_alloc,
|
|
sys_realloc,
|
|
sys_free,
|
|
HAWK_NULL
|
|
};
|
|
|
|
|
|
hawk_mmgr_t* hawk_get_sys_mmgr (void)
|
|
{
|
|
return &sys_mmgr;
|
|
}
|
|
/* ----------------------------------------------------------------------- */
|
|
|
|
|
|
hawk_flt_t hawk_stdmathpow (hawk_t* hawk, hawk_flt_t x, hawk_flt_t y)
|
|
{
|
|
#if defined(HAWK_USE_FLTMAX) && defined(HAVE_POWQ)
|
|
return powq(x, y);
|
|
#elif defined(HAVE_POWL) && (HAWK_SIZEOF_LONG_DOUBLE > HAWK_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
|
|
}
|
|
|
|
hawk_flt_t hawk_stdmathmod (hawk_t* hawk, hawk_flt_t x, hawk_flt_t y)
|
|
{
|
|
#if defined(HAWK_USE_FLTMAX) && defined(HAVE_FMODQ)
|
|
return fmodq(x, y);
|
|
#elif defined(HAVE_FMODL) && (HAWK_SIZEOF_LONG_DOUBLE > HAWK_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]
|
|
* hawk_stdmodXXXX() functions must not access the extension
|
|
* area of 'hawk'. they are used in StdAwk.cpp which instantiates
|
|
* an hawk object with hawk_open() instead of hawk_openstd(). */
|
|
|
|
int hawk_stdmodstartup (hawk_t* hawk)
|
|
{
|
|
#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 hawk_stdmodshutdown (hawk_t* hawk)
|
|
{
|
|
#if defined(USE_LTDL)
|
|
lt_dlexit ();
|
|
#else
|
|
/* do nothing */
|
|
#endif
|
|
}
|
|
|
|
static void* std_mod_open_checked (hawk_t* hawk, const hawk_mod_spec_t* spec)
|
|
{
|
|
xtn_t* xtn = GET_XTN(hawk);
|
|
|
|
if (!xtn->stdmod_up)
|
|
{
|
|
/* hawk_stdmodstartup() must have failed upon start-up.
|
|
* return failure immediately */
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_ENOIMPL);
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
return hawk_stdmodopen(hawk, spec);
|
|
}
|
|
|
|
void* hawk_stdmodopen (hawk_t* hawk, const hawk_mod_spec_t* spec)
|
|
{
|
|
#if defined(USE_LTDL)
|
|
void* h;
|
|
lt_dladvise adv;
|
|
hawk_bch_t* modpath;
|
|
const hawk_ooch_t* tmp[6];
|
|
int count;
|
|
static hawk_ooch_t ds[] = { '/', '\0' };
|
|
|
|
count = 0;
|
|
if (spec->libdir)
|
|
{
|
|
hawk_oow_t len;
|
|
|
|
tmp[count++] = spec->libdir;
|
|
len = hawk_count_oocstr(spec->libdir);
|
|
if (len > 0 && spec->libdir[len - 1] != '/') tmp[count++] = ds;
|
|
}
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = HAWK_NULL;
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
modpath = hawk_dupbcstrarr(hawk, tmp, HAWK_NULL);
|
|
#else
|
|
modpath = hawk_dupucstrarrtobcstr(hawk, tmp, HAWK_NULL)
|
|
#endif
|
|
if (!modpath) return HAWK_NULL;
|
|
|
|
if (lt_dladvise_init(&adv) != 0)
|
|
{
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_ESYSERR, HAWK_T("%hs"), lt_dlerror());
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
lt_dladvise_ext (&adv);
|
|
/*lt_dladvise_resident (&adv); useful for debugging with valgrind */
|
|
|
|
h = lt_dlopenadvise(modpath, adv);
|
|
|
|
lt_dladvise_destroy (&adv);
|
|
|
|
HAWK_MMGR_FREE (hawk_getmmgr(hawk), modpath);
|
|
|
|
return h;
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
HMODULE h;
|
|
hawk_ooch_t* modpath;
|
|
const hawk_ooch_t* tmp[6];
|
|
int count;
|
|
static hawk_ooch_t ds[][2] = { { '\\', '\0' }, { '/', '\0' } }
|
|
false 0 treu 1
|
|
count = 0;
|
|
if (spec->libdir)
|
|
{
|
|
hawk_oow_t len;
|
|
|
|
tmp[count++] = spec->libdir;
|
|
len = hawk_count_oocstr(spec->libdir);
|
|
if (len > 0 && (spec->libdir[len - 1] != '/' && spec->libdir[len - 1] != '\\'))
|
|
{
|
|
tmp[count++] = ds[hawk_find_oochar_in_oocstr(spec->libdir, '/') != HAWK_NULL];
|
|
}
|
|
}
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = HAWK_NULL;
|
|
|
|
modpath = hawk_dupoocstrarr(hawk, tmp, HAWK_NULL);
|
|
if (!modpath) return HAWK_NULL;
|
|
|
|
h = LoadLibrary (modpath);
|
|
if (!h) hawk_seterrnum (hawk, HAWK_NULL, hawk_syserr_to_errnum(GetLastError());
|
|
|
|
hawk_freemem (hawk, modpath);
|
|
|
|
HAWK_ASSERT (HAWK_SIZEOF(h) <= HAWK_SIZEOF(void*));
|
|
return h;
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
HMODULE h;
|
|
hawk_bch_t* modpath;
|
|
const hawk_ooch_t* tmp[6];
|
|
int count;
|
|
char errbuf[CCHMAXPATH];
|
|
APIRET rc;
|
|
static hawk_ooch_t ds[] = { '\\', '\0' };
|
|
|
|
count = 0;
|
|
if (spec->libdir)
|
|
{
|
|
hawk_oow_t len;
|
|
|
|
tmp[count++] = spec->libdir;
|
|
len = hawk_count_oocstr(spec->libdir);
|
|
if (len > 0 && spec->libdir[len - 1] != '\\') tmp[count++] = ds;
|
|
}
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = HAWK_NULL;
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
modpath = hawk_dupbcstrarr(hawk, tmp, HAWK_NULL);
|
|
#else
|
|
modpath = hawk_dupucstrarrtobcstr(hawk, tmp, HAWK_NULL);
|
|
#endif
|
|
if (!modpath) return HAWK_NULL;
|
|
|
|
/* DosLoadModule() seems to have severe limitation on
|
|
* the file name it can load (max-8-letters.xxx) */
|
|
rc = DosLoadModule (errbuf, HAWK_COUNTOF(errbuf) - 1, modpath, &h);
|
|
if (rc != NO_ERROR)
|
|
{
|
|
h = HAWK_NULL;
|
|
hawk_seterrnum (hawk, HAWK_NULL, hawk_syserr_to_errnum(rc));
|
|
}
|
|
|
|
hawk_freemem (hawk, modpath);
|
|
|
|
HAWK_ASSERT (HAWK_SIZEOF(h) <= HAWK_SIZEOF(void*));
|
|
return h;
|
|
|
|
#elif defined(__DOS__) && defined(HAWK_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;
|
|
hawk_bch_t* modpath;
|
|
const hawk_ooch_t* tmp[6];
|
|
int count;
|
|
static hawk_ooch_t ds[] = { '\\', '\0' };
|
|
|
|
count = 0;
|
|
if (spec->libdir)
|
|
{
|
|
hawk_oow_t len;
|
|
|
|
tmp[count++] = spec->libdir;
|
|
len = hawk_count_oocstr(spec->libdir);
|
|
if (len > 0 && spec->libdir[len - 1] != '/') tmp[count++] = ds;
|
|
}
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = HAWK_NULL;
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
modpath = hawk_dupbcstrarr(hawk, tmp, HAWK_NULL);
|
|
#else
|
|
modpath = hawk_dupucstrarrtobcstr(hawk, tmp, HAWK_NULL);
|
|
#endif
|
|
if (!modpath) return HAWK_NULL;
|
|
|
|
h = LoadModule(modpath);
|
|
if (!h) hawk_seterrnum (hawk, HAWK_NULL, HAWK_ESYSERR);
|
|
|
|
hawk_freemem (hawk, modpath);
|
|
|
|
HAWK_ASSERT (HAWK_SIZEOF(h) <= HAWK_SIZEOF(void*));
|
|
return h;
|
|
|
|
#elif defined(USE_DLFCN)
|
|
void* h;
|
|
hawk_bch_t* modpath;
|
|
const hawk_ooch_t* tmp[6];
|
|
int count;
|
|
static hawk_ooch_t ds[] = { '/', '\0' };
|
|
|
|
count = 0;
|
|
if (spec->libdir)
|
|
{
|
|
hawk_oow_t len;
|
|
|
|
tmp[count++] = spec->libdir;
|
|
len = hawk_count_oocstr(spec->libdir);
|
|
if (len > 0 && spec->libdir[len - 1] != '/') tmp[count++] = ds;
|
|
}
|
|
if (spec->prefix) tmp[count++] = spec->prefix;
|
|
tmp[count++] = spec->name;
|
|
if (spec->postfix) tmp[count++] = spec->postfix;
|
|
tmp[count] = HAWK_NULL;
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
modpath = hawk_dupbcstrarr(hawk, tmp, HAWK_NULL);
|
|
#else
|
|
modpath = hawk_dupucstrarrtobcstr(hawk, tmp, HAWK_NULL);
|
|
#endif
|
|
if (!modpath) return HAWK_NULL;
|
|
|
|
h = dlopen(modpath, RTLD_NOW | RTLD_LOCAL);
|
|
if (!h) hawk_seterrfmt (hawk, HAWK_NULL, HAWK_ESYSERR, HAWK_T("%hs"), dlerror());
|
|
|
|
hawk_freemem (hawk, modpath);
|
|
|
|
return h;
|
|
|
|
#else
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_ENOIMPL);
|
|
return HAWK_NULL;
|
|
#endif
|
|
}
|
|
|
|
void hawk_stdmodclose (hawk_t* hawk, 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(HAWK_ENABLE_DOS_DYNAMIC_MODULE)
|
|
FreeModule (handle);
|
|
#elif defined(USE_DLFCN)
|
|
dlclose (handle);
|
|
#else
|
|
/* nothing to do */
|
|
#endif
|
|
}
|
|
|
|
void* hawk_stdmodgetsym (hawk_t* hawk, void* handle, const hawk_ooch_t* name)
|
|
{
|
|
void* s;
|
|
hawk_bch_t* mname;
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
mname = (hawk_bch_t*)name;
|
|
#else
|
|
mname = hawk_duputobcstr(hawk, name, HAWK_NULL);
|
|
if (!mname) return HAWK_NULL;
|
|
#endif
|
|
|
|
#if defined(USE_LTDL)
|
|
s = lt_dlsym(handle, mname);
|
|
if (!s) hawk_seterrfmt (hawk, HAWK_NULL, HAWK_ESYSERR, HAWK_T("%hs"), lt_dlerror());
|
|
|
|
#elif defined(_WIN32)
|
|
s = GetProcAddress((HMODULE)handle, mname);
|
|
if (!s) hawk_seterrnum (hawk, HAWK_NULL, hawk_syserr_to_errnum(GetLastError());
|
|
|
|
#elif defined(__OS2__)
|
|
{
|
|
APIRET rc;
|
|
rc = DosQueryProcAddr((HMODULE)handle, 0, mname, (PFN*)&s);
|
|
if (rc != NO_ERROR)
|
|
{
|
|
s = HAWK_NULL;
|
|
hawk_seterrnum (hawk, HAWK_NULL, hawk_syserr_to_errnum(rc));
|
|
}
|
|
}
|
|
|
|
#elif defined(__DOS__) && defined(HAWK_ENABLE_DOS_DYNAMIC_MODULE)
|
|
s = GetProcAddress(handle, mname);
|
|
if (!s) hawk_seterrnum (hawk, HAWK_NULL, HAWK_ESYSERR);
|
|
|
|
#elif defined(USE_DLFCN)
|
|
s = dlsym(handle, mname);
|
|
if (!s) hawk_seterrfmt (hawk, HAWK_NULL, HAWK_ESYSERR, HAWK_T("%hs"), dlerror());
|
|
|
|
#else
|
|
s = HAWK_NULL;
|
|
#endif
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
/* nothing to do */
|
|
#else
|
|
hawk_freemem (hawk, mname);
|
|
#endif
|
|
|
|
return s;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------- */
|
|
|
|
static HAWK_INLINE void reset_log_to_default (xtn_t* xtn)
|
|
{
|
|
#if defined(ENABLE_LOG_INITIALLY)
|
|
xtn->log.fd = 2;
|
|
xtn->log.fd_flag = 0;
|
|
#if defined(HAVE_ISATTY)
|
|
if (isatty(xtn->log.fd)) xtn->log.fd_flag |= LOGFD_TTY;
|
|
#endif
|
|
#else
|
|
xtn->log.fd = -1;
|
|
xtn->log.fd_flag = 0;
|
|
#endif
|
|
}
|
|
|
|
#if defined(EMSCRIPTEN)
|
|
EM_JS(int, write_all, (int, const hawk_bch_t* ptr, hawk_oow_t len), {
|
|
// UTF8ToString() doesn't handle a null byte in the middle of an array.
|
|
// Use the heap memory and pass the right portion to UTF8Decoder.
|
|
//console.log ("%s", UTF8ToString(ptr, len));
|
|
console.log ("%s", UTF8Decoder.decode(HEAPU8.subarray(ptr, ptr + len)));
|
|
return 0;
|
|
});
|
|
|
|
#else
|
|
|
|
static int write_all (int fd, const hawk_bch_t* ptr, hawk_oow_t len)
|
|
{
|
|
#if defined(EMSCRIPTEN)
|
|
EM_ASM_ ({
|
|
// UTF8ToString() doesn't handle a null byte in the middle of an array.
|
|
// Use the heap memory and pass the right portion to UTF8Decoder.
|
|
//console.log ("%s", UTF8ToString($0, $1));
|
|
console.log ("%s", UTF8Decoder.decode(HEAPU8.subarray($0, $0 + $1)));
|
|
}, ptr, len);
|
|
#else
|
|
while (len > 0)
|
|
{
|
|
hawk_ooi_t wr;
|
|
|
|
wr = write(fd, ptr, len);
|
|
|
|
if (wr <= -1)
|
|
{
|
|
#if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN == EWOULDBLOCK)
|
|
if (errno == EAGAIN) continue;
|
|
#else
|
|
#if defined(EAGAIN)
|
|
if (errno == EAGAIN) continue;
|
|
#elif defined(EWOULDBLOCK)
|
|
if (errno == EWOULDBLOCK) continue;
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(EINTR)
|
|
/* TODO: would this interfere with non-blocking nature of this VM? */
|
|
if (errno == EINTR) continue;
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
ptr += wr;
|
|
len -= wr;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int write_log (hawk_t* hawk, int fd, const hawk_bch_t* ptr, hawk_oow_t len)
|
|
{
|
|
xtn_t* xtn = GET_XTN(hawk);
|
|
|
|
while (len > 0)
|
|
{
|
|
if (xtn->log.out.len > 0)
|
|
{
|
|
hawk_oow_t rcapa, cplen;
|
|
|
|
rcapa = HAWK_COUNTOF(xtn->log.out.buf) - xtn->log.out.len;
|
|
cplen = (len >= rcapa)? rcapa: len;
|
|
|
|
HAWK_MEMCPY (&xtn->log.out.buf[xtn->log.out.len], ptr, cplen);
|
|
xtn->log.out.len += cplen;
|
|
ptr += cplen;
|
|
len -= cplen;
|
|
|
|
if (xtn->log.out.len >= HAWK_COUNTOF(xtn->log.out.buf))
|
|
{
|
|
int n;
|
|
n = write_all(fd, xtn->log.out.buf, xtn->log.out.len);
|
|
xtn->log.out.len = 0;
|
|
if (n <= -1) return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hawk_oow_t rcapa;
|
|
|
|
rcapa = HAWK_COUNTOF(xtn->log.out.buf);
|
|
if (len >= rcapa)
|
|
{
|
|
if (write_all(fd, ptr, rcapa) <= -1) return -1;
|
|
ptr += rcapa;
|
|
len -= rcapa;
|
|
}
|
|
else
|
|
{
|
|
HAWK_MEMCPY (xtn->log.out.buf, ptr, len);
|
|
xtn->log.out.len += len;
|
|
ptr += len;
|
|
len -= len;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void flush_log (hawk_t* hawk, int fd)
|
|
{
|
|
xtn_t* xtn = GET_XTN(hawk);
|
|
if (xtn->log.out.len > 0)
|
|
{
|
|
write_all (fd, xtn->log.out.buf, xtn->log.out.len);
|
|
xtn->log.out.len = 0;
|
|
}
|
|
}
|
|
|
|
static void log_write (hawk_t* hawk, hawk_bitmask_t mask, const hawk_ooch_t* msg, hawk_oow_t len)
|
|
{
|
|
xtn_t* xtn = GET_XTN(hawk);
|
|
hawk_bch_t buf[256];
|
|
hawk_oow_t ucslen, bcslen, msgidx;
|
|
int n, logfd;
|
|
|
|
if (mask & HAWK_LOG_STDERR) logfd = 2;
|
|
else if (mask & HAWK_LOG_STDOUT) logfd = 1;
|
|
else
|
|
{
|
|
logfd = xtn->log.fd;
|
|
#if !defined(EMSCRIPTEN)
|
|
if (logfd <= -1)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* TODO: beautify the log message.
|
|
* do classification based on mask. */
|
|
if (!(mask & (HAWK_LOG_STDOUT | HAWK_LOG_STDERR)))
|
|
{
|
|
#if defined(_WIN32)
|
|
TIME_ZONE_INFORMATION tzi;
|
|
SYSTEMTIME now;
|
|
#else
|
|
time_t now;
|
|
struct tm tm, *tmp;
|
|
#endif
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
char ts[32 * HAWK_BCSIZE_MAX];
|
|
#else
|
|
char ts[32];
|
|
#endif
|
|
hawk_oow_t tslen;
|
|
|
|
#if defined(_WIN32)
|
|
/* %z for strftime() in win32 seems to produce a long non-numeric timezone name.
|
|
* i don't use strftime() for time formatting. */
|
|
GetLocalTime (&now);
|
|
if (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID)
|
|
{
|
|
tzi.Bias = -tzi.Bias;
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d %+02.2d%02.2d ",
|
|
(int)now.wYear, (int)now.wMonth, (int)now.wDay,
|
|
(int)now.wHour, (int)now.wMinute, (int)now.wSecond,
|
|
(int)(tzi.Bias / 60), (int)(tzi.Bias % 60));
|
|
}
|
|
else
|
|
{
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ",
|
|
(int)now.wYear, (int)now.wMonth, (int)now.wDay,
|
|
(int)now.wHour, (int)now.wMinute, (int)now.wSecond);
|
|
}
|
|
#elif defined(__OS2__)
|
|
now = time(HAWK_NULL);
|
|
|
|
#if defined(__WATCOMC__)
|
|
tmp = _localtime(&now, &tm);
|
|
#else
|
|
tmp = localtime(&now);
|
|
#endif
|
|
|
|
#if defined(__BORLANDC__)
|
|
/* the borland compiler doesn't handle %z properly - it showed 00 all the time */
|
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %Z ", tmp);
|
|
#else
|
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %z ", tmp);
|
|
#endif
|
|
if (tslen == 0)
|
|
{
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
|
}
|
|
|
|
#elif defined(__DOS__)
|
|
now = time(HAWK_NULL);
|
|
tmp = localtime(&now);
|
|
/* since i know that %z/%Z is not available in strftime, i switch to sprintf immediately */
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
|
#else
|
|
now = time(HAWK_NULL);
|
|
#if defined(HAVE_LOCALTIME_R)
|
|
tmp = localtime_r(&now, &tm);
|
|
#else
|
|
tmp = localtime(&now);
|
|
#endif
|
|
|
|
#if defined(HAVE_STRFTIME_SMALL_Z)
|
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %z ", tmp);
|
|
#else
|
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %Z ", tmp);
|
|
#endif
|
|
if (tslen == 0)
|
|
{
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
|
}
|
|
#endif
|
|
|
|
write_log (hawk, logfd, ts, tslen);
|
|
}
|
|
|
|
if (logfd == xtn->log.fd && (xtn->log.fd_flag & LOGFD_TTY))
|
|
{
|
|
if (mask & HAWK_LOG_FATAL) write_log (hawk, logfd, "\x1B[1;31m", 7);
|
|
else if (mask & HAWK_LOG_ERROR) write_log (hawk, logfd, "\x1B[1;32m", 7);
|
|
else if (mask & HAWK_LOG_WARN) write_log (hawk, logfd, "\x1B[1;33m", 7);
|
|
}
|
|
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
msgidx = 0;
|
|
while (len > 0)
|
|
{
|
|
ucslen = len;
|
|
bcslen = HAWK_COUNTOF(buf);
|
|
|
|
/*n = hawk_convootobchars(hawk, &msg[msgidx], &ucslen, buf, &bcslen);*/
|
|
n = hawk_conv_uchars_to_bchars_with_cmgr(&msg[msgidx], &ucslen, buf, &bcslen, hawk_getcmgr(hawk));
|
|
if (n == 0 || n == -2)
|
|
{
|
|
/* n = 0:
|
|
* converted all successfully
|
|
* n == -2:
|
|
* buffer not sufficient. not all got converted yet.
|
|
* write what have been converted this round. */
|
|
|
|
HAWK_ASSERT (ucslen > 0); /* if this fails, the buffer size must be increased */
|
|
|
|
/* attempt to write all converted characters */
|
|
if (write_log(hawk, logfd, buf, bcslen) <= -1) break;
|
|
|
|
if (n == 0) break;
|
|
else
|
|
{
|
|
msgidx += ucslen;
|
|
len -= ucslen;
|
|
}
|
|
}
|
|
else if (n <= -1)
|
|
{
|
|
/* conversion error but i just stop here but don't treat it as a hard error. */
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
write_log (hawk, logfd, msg, len);
|
|
#endif
|
|
|
|
if (logfd == xtn->log.fd && (xtn->log.fd_flag & LOGFD_TTY))
|
|
{
|
|
if (mask & (HAWK_LOG_FATAL | HAWK_LOG_ERROR | HAWK_LOG_WARN)) write_log (hawk, logfd, "\x1B[0m", 4);
|
|
}
|
|
|
|
flush_log (hawk, logfd);
|
|
}
|
|
/* ----------------------------------------------------------------------- */
|
|
|
|
static int add_globals (hawk_t* hawk);
|
|
static int add_functions (hawk_t* hawk);
|
|
|
|
hawk_t* hawk_openstd (hawk_oow_t xtnsize, hawk_errnum_t* errnum)
|
|
{
|
|
return hawk_openstdwithmmgr(&sys_mmgr, xtnsize, hawk_get_cmgr_by_id(HAWK_CMGR_UTF8), errnum);
|
|
}
|
|
|
|
static void fini_xtn (hawk_t* hawk)
|
|
{
|
|
xtn_t* xtn = GET_XTN(hawk);
|
|
if (xtn->stdmod_up)
|
|
{
|
|
hawk_stdmodshutdown (hawk);
|
|
xtn->stdmod_up = 0;
|
|
}
|
|
|
|
if ((xtn->log.fd_flag & LOGFD_OPENED_HERE) && xtn->log.fd >= 0) close (xtn->log.fd);
|
|
reset_log_to_default (xtn);
|
|
}
|
|
|
|
static void clear_xtn (hawk_t* hawk)
|
|
{
|
|
/* nothing to do */
|
|
}
|
|
|
|
hawk_t* hawk_openstdwithmmgr (hawk_mmgr_t* mmgr, hawk_oow_t xtnsize, hawk_cmgr_t* cmgr, hawk_errnum_t* errnum)
|
|
{
|
|
hawk_t* hawk;
|
|
hawk_prm_t prm;
|
|
xtn_t* xtn;
|
|
|
|
prm.math.pow = hawk_stdmathpow;
|
|
prm.math.mod = hawk_stdmathmod;
|
|
|
|
prm.modopen = std_mod_open_checked;
|
|
prm.modclose = hawk_stdmodclose;
|
|
prm.modgetsym = hawk_stdmodgetsym;
|
|
|
|
prm.logwrite = log_write;
|
|
|
|
if (!mmgr) mmgr = &sys_mmgr;
|
|
if (!cmgr) cmgr = hawk_get_cmgr_by_id(HAWK_CMGR_UTF8);
|
|
|
|
/* create an object */
|
|
hawk = hawk_open(mmgr, HAWK_SIZEOF(xtn_t) + xtnsize, cmgr, &prm, errnum);
|
|
if (HAWK_UNLIKELY(!hawk)) return HAWK_NULL;
|
|
|
|
/* adjust the object size by the sizeof xtn_t so that hawk_getxtn() returns the right pointer. */
|
|
hawk->_instsize += HAWK_SIZEOF(xtn_t);
|
|
|
|
/*
|
|
#if defined(USE_DLFCN)
|
|
if (hawk_setopt(hawk, HAWK_OPT_MODPOSTFIX, HAWK_T(".so")) <= -1)
|
|
{
|
|
if (errnum) *errnum = hawk_geterrnum(hawk);
|
|
goto oops;
|
|
}
|
|
#endif
|
|
*/
|
|
|
|
/* initialize extension */
|
|
xtn = GET_XTN(hawk);
|
|
|
|
reset_log_to_default (xtn);
|
|
|
|
/* add intrinsic global variables and functions */
|
|
if (add_globals(hawk) <= -1 || add_functions(hawk) <= -1)
|
|
{
|
|
if (errnum) *errnum = hawk_geterrnum(hawk);
|
|
goto oops;
|
|
}
|
|
|
|
if (hawk_stdmodstartup(hawk) <= -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;
|
|
hawk_pushecb (hawk, &xtn->ecb);
|
|
|
|
return hawk;
|
|
|
|
oops:
|
|
if (hawk) hawk_close (hawk);
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
static hawk_sio_t* open_sio (hawk_t* hawk, const hawk_ooch_t* file, int flags)
|
|
{
|
|
hawk_sio_t* sio;
|
|
sio = hawk_sio_open(hawk_getgem(hawk), 0, file, flags);
|
|
if (sio == HAWK_NULL)
|
|
{
|
|
const hawk_ooch_t* bem = hawk_backuperrmsg(hawk);
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_EOPEN, HAWK_T("unable to open %js - %js"), file, bem);
|
|
}
|
|
return sio;
|
|
}
|
|
|
|
static hawk_sio_t* open_sio_rtx (hawk_rtx_t* rtx, const hawk_ooch_t* file, int flags)
|
|
{
|
|
hawk_sio_t* sio;
|
|
sio = hawk_sio_open(hawk_rtx_getgem(rtx), 0, file, flags);
|
|
if (sio == HAWK_NULL)
|
|
{
|
|
const hawk_ooch_t* bem = hawk_rtx_backuperrmsg(rtx);
|
|
hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_EOPEN, HAWK_T("unable to open %js - %js"), file, bem);
|
|
}
|
|
return sio;
|
|
}
|
|
|
|
static hawk_oocs_t sio_std_names[] =
|
|
{
|
|
{ HAWK_T("stdin"), 5 },
|
|
{ HAWK_T("stdout"), 6 },
|
|
{ HAWK_T("stderr"), 6 }
|
|
};
|
|
|
|
static hawk_sio_t* open_sio_std (hawk_t* hawk, hawk_sio_std_t std, int flags)
|
|
{
|
|
hawk_sio_t* sio;
|
|
sio = hawk_sio_openstd(hawk_getgem(hawk), 0, std, flags);
|
|
if (sio == HAWK_NULL)
|
|
{
|
|
const hawk_ooch_t* bem = hawk_backuperrmsg(hawk);
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_EOPEN, HAWK_T("unable to open %js - %js"), &sio_std_names[std], bem);
|
|
}
|
|
return sio;
|
|
}
|
|
|
|
static hawk_sio_t* open_sio_std_rtx (hawk_rtx_t* rtx, hawk_sio_std_t std, int flags)
|
|
{
|
|
hawk_sio_t* sio;
|
|
|
|
sio = hawk_sio_openstd(hawk_rtx_getgem(rtx), 0, std, flags);
|
|
if (sio == HAWK_NULL)
|
|
{
|
|
const hawk_ooch_t* bem = hawk_rtx_backuperrmsg(rtx);
|
|
hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_EOPEN, HAWK_T("unable to open %js - %js"), &sio_std_names[std], bem);
|
|
}
|
|
return sio;
|
|
}
|
|
|
|
/*** PARSESTD ***/
|
|
|
|
static int is_psin_file (hawk_parsestd_t* psin)
|
|
{
|
|
return psin->type == HAWK_PARSESTD_FILE ||
|
|
psin->type == HAWK_PARSESTD_FILEB ||
|
|
psin->type == HAWK_PARSESTD_FILEU;
|
|
}
|
|
|
|
static int open_parsestd (hawk_t* hawk, hawk_sio_arg_t* arg, xtn_t* xtn, hawk_oow_t index)
|
|
{
|
|
hawk_parsestd_t* psin = &xtn->s.in.x[index];
|
|
|
|
switch (psin->type)
|
|
{
|
|
/* normal source files */
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
case HAWK_PARSESTD_FILE:
|
|
HAWK_ASSERT (&psin->u.fileb.path == &psin->u.file.path);
|
|
HAWK_ASSERT (&psin->u.fileb.cmgr == &psin->u.file.cmgr);
|
|
#endif
|
|
case HAWK_PARSESTD_FILEB:
|
|
{
|
|
hawk_sio_t* tmp;
|
|
hawk_ooch_t* path = HAWK_NULL;
|
|
|
|
if (psin->u.fileb.path == HAWK_NULL || (psin->u.fileb.path[0] == '-' && psin->u.fileb.path[1] == '\0'))
|
|
{
|
|
/* no path name or - -> stdin */
|
|
path = HAWK_NULL;
|
|
tmp = open_sio_std(hawk, HAWK_SIO_STDIN, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR);
|
|
}
|
|
else
|
|
{
|
|
path = hawk_addsionamewithbchars(hawk, psin->u.fileb.path, hawk_count_bcstr(psin->u.fileb.path));
|
|
if (!path) return -1;
|
|
tmp = open_sio(hawk, path, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR | HAWK_SIO_KEEPPATH);
|
|
}
|
|
if (tmp == HAWK_NULL) return -1;
|
|
|
|
if (index >= 1 && is_psin_file(&xtn->s.in.x[index - 1])) hawk_sio_close (arg->handle);
|
|
|
|
arg->handle = tmp;
|
|
arg->path = path;
|
|
if (psin->u.fileb.cmgr) hawk_sio_setcmgr (arg->handle, psin->u.fileb.cmgr);
|
|
return 0;
|
|
}
|
|
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
case HAWK_PARSESTD_FILE:
|
|
HAWK_ASSERT (&psin->u.fileu.path == &psin->u.file.path);
|
|
HAWK_ASSERT (&psin->u.fileu.cmgr == &psin->u.file.cmgr);
|
|
#endif
|
|
case HAWK_PARSESTD_FILEU:
|
|
{
|
|
hawk_sio_t* tmp;
|
|
hawk_ooch_t* path;
|
|
|
|
if (psin->u.fileu.path == HAWK_NULL || (psin->u.fileu.path[0] == '-' && psin->u.fileu.path[1] == '\0'))
|
|
{
|
|
/* no path name or - -> stdin */
|
|
path = HAWK_NULL;
|
|
tmp = open_sio_std(hawk, HAWK_SIO_STDIN, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR);
|
|
}
|
|
else
|
|
{
|
|
path = hawk_addsionamewithuchars(hawk, psin->u.fileu.path, hawk_count_ucstr(psin->u.fileu.path));
|
|
if (!path) return -1;
|
|
tmp = open_sio(hawk, path, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR | HAWK_SIO_KEEPPATH);
|
|
}
|
|
if (tmp == HAWK_NULL) return -1;
|
|
|
|
if (index >= 1 && is_psin_file(&xtn->s.in.x[index - 1])) hawk_sio_close (arg->handle);
|
|
|
|
arg->handle = tmp;
|
|
arg->path = path;
|
|
if (psin->u.fileu.cmgr) hawk_sio_setcmgr (arg->handle, psin->u.fileu.cmgr);
|
|
return 0;
|
|
}
|
|
|
|
case HAWK_PARSESTD_OOCS:
|
|
if (index >= 1 && is_psin_file(&xtn->s.in.x[index - 1])) hawk_sio_close (arg->handle);
|
|
xtn->s.in.u.oocs.ptr = psin->u.oocs.ptr;
|
|
xtn->s.in.u.oocs.end = psin->u.oocs.ptr + psin->u.oocs.len;
|
|
return 0;
|
|
|
|
case HAWK_PARSESTD_BCS:
|
|
if (index >= 1 && is_psin_file(&xtn->s.in.x[index - 1])) hawk_sio_close (arg->handle);
|
|
xtn->s.in.u.bcs.ptr = psin->u.bcs.ptr;
|
|
xtn->s.in.u.bcs.end = psin->u.bcs.ptr + psin->u.bcs.len;
|
|
return 0;
|
|
|
|
case HAWK_PARSESTD_UCS:
|
|
if (index >= 1 && is_psin_file(&xtn->s.in.x[index - 1])) hawk_sio_close (arg->handle);
|
|
xtn->s.in.u.ucs.ptr = psin->u.ucs.ptr;
|
|
xtn->s.in.u.ucs.end = psin->u.ucs.ptr + psin->u.ucs.len;
|
|
return 0;
|
|
|
|
default:
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static int fill_sio_arg_unique_id (hawk_t* hawk, hawk_sio_arg_t* arg, const hawk_ooch_t* path)
|
|
{
|
|
#if defined(_WIN32)
|
|
return -1;
|
|
|
|
#elif defined(__OS2__)
|
|
return -1;
|
|
|
|
#elif defined(__DOS__)
|
|
return -1;
|
|
|
|
#else
|
|
hawk_stat_t st;
|
|
int x;
|
|
struct
|
|
{
|
|
hawk_uintptr_t ino;
|
|
hawk_uintptr_t dev;
|
|
} tmp;
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
x = HAWK_STAT(path, &st);
|
|
if (x <= -1) return -1;
|
|
#else
|
|
hawk_bch_t* bpath;
|
|
|
|
bpath= hawk_duputobcstr(hawk, path, HAWK_NULL);
|
|
if (!bpath) return -1;
|
|
|
|
x = HAWK_STAT(bpath, &st);
|
|
hawk_freemem (hawk, bpath);
|
|
if (x <= -1) return -1;
|
|
#endif
|
|
|
|
tmp.ino = st.st_ino;
|
|
tmp.dev = st.st_dev;
|
|
|
|
HAWK_MEMCPY (arg->unique_id, &tmp, (HAWK_SIZEOF(tmp) > HAWK_SIZEOF(arg->unique_id)? HAWK_SIZEOF(arg->unique_id): HAWK_SIZEOF(tmp)));
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static hawk_ooi_t sf_in_open (hawk_t* hawk, hawk_sio_arg_t* arg, xtn_t* xtn)
|
|
{
|
|
if (arg->prev == HAWK_NULL)
|
|
{
|
|
/* handle top-level source input stream specified to hawk_parsestd() */
|
|
hawk_ooi_t x;
|
|
|
|
HAWK_ASSERT (arg == &hawk->sio.arg);
|
|
|
|
x = open_parsestd(hawk, arg, xtn, 0);
|
|
if (x >= 0) xtn->s.in.xindex = 0; /* update the current stream index */
|
|
|
|
return x;
|
|
}
|
|
else
|
|
{
|
|
/* handle the included source file - @include */
|
|
hawk_ooch_t* xpath;
|
|
|
|
HAWK_ASSERT (arg->name != HAWK_NULL);
|
|
|
|
if (arg->prev->handle)
|
|
{
|
|
const hawk_ooch_t* outer;
|
|
const hawk_ooch_t* path;
|
|
hawk_ooch_t fbuf[64];
|
|
hawk_ooch_t* dbuf = HAWK_NULL;
|
|
|
|
path = arg->name;
|
|
|
|
outer = hawk_sio_getpath(arg->prev->handle);
|
|
if (outer)
|
|
{
|
|
const hawk_ooch_t* base;
|
|
|
|
base = hawk_get_base_name_oocstr(outer);
|
|
if (base != outer && arg->name[0] != HAWK_T('/'))
|
|
{
|
|
hawk_oow_t tmplen, totlen, dirlen;
|
|
|
|
dirlen = base - outer;
|
|
totlen = hawk_count_oocstr(arg->name) + dirlen;
|
|
if (totlen >= HAWK_COUNTOF(fbuf))
|
|
{
|
|
dbuf = hawk_allocmem(hawk, HAWK_SIZEOF(hawk_ooch_t) * (totlen + 1));
|
|
if (!dbuf) return -1;
|
|
path = dbuf;
|
|
}
|
|
else path = fbuf;
|
|
|
|
tmplen = hawk_copy_oochars_to_oocstr_unlimited((hawk_ooch_t*)path, outer, dirlen);
|
|
hawk_copy_oocstr_unlimited ((hawk_ooch_t*)path + tmplen, arg->name);
|
|
}
|
|
}
|
|
|
|
xpath = hawk_addsionamewithoochars(hawk, path, hawk_count_oocstr(path));
|
|
if (dbuf) hawk_freemem (hawk, dbuf);
|
|
}
|
|
else
|
|
{
|
|
xpath = hawk_addsionamewithoochars(hawk, arg->name, hawk_count_oocstr(arg->name));
|
|
}
|
|
if (!xpath) goto fail;
|
|
|
|
arg->handle = hawk_sio_open(hawk_getgem(hawk), 0, xpath, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR | HAWK_SIO_KEEPPATH);
|
|
if (!arg->handle)
|
|
{
|
|
const hawk_ooch_t* bem;
|
|
fail:
|
|
bem = hawk_backuperrmsg(hawk);
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_EOPEN, HAWK_T("unable to open %js - %js"), arg->name, bem);
|
|
return -1;
|
|
}
|
|
|
|
arg->path = xpath;
|
|
/* TODO: use the system handle(file descriptor) instead of the path? */
|
|
/*syshnd = hawk_sio_gethnd(arg->handle);*/
|
|
fill_sio_arg_unique_id(hawk, arg, xpath); /* ignore failure */
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static hawk_ooi_t sf_in_close (hawk_t* hawk, hawk_sio_arg_t* arg, xtn_t* xtn)
|
|
{
|
|
if (arg->prev == HAWK_NULL)
|
|
{
|
|
switch (xtn->s.in.x[xtn->s.in.xindex].type)
|
|
{
|
|
case HAWK_PARSESTD_FILE:
|
|
case HAWK_PARSESTD_FILEB:
|
|
case HAWK_PARSESTD_FILEU:
|
|
HAWK_ASSERT (arg->handle != HAWK_NULL);
|
|
hawk_sio_close (arg->handle);
|
|
break;
|
|
|
|
case HAWK_PARSESTD_OOCS:
|
|
case HAWK_PARSESTD_BCS:
|
|
case HAWK_PARSESTD_UCS:
|
|
/* nothing to close */
|
|
break;
|
|
|
|
default:
|
|
/* nothing to close */
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* handle the included source file - @include */
|
|
HAWK_ASSERT (arg->handle != HAWK_NULL);
|
|
hawk_sio_close (arg->handle);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static hawk_ooi_t sf_in_read (hawk_t* hawk, hawk_sio_arg_t* arg, hawk_ooch_t* data, hawk_oow_t size, xtn_t* xtn)
|
|
{
|
|
if (arg->prev == HAWK_NULL)
|
|
{
|
|
hawk_ooi_t n;
|
|
|
|
HAWK_ASSERT (arg == &hawk->sio.arg);
|
|
|
|
again:
|
|
switch (xtn->s.in.x[xtn->s.in.xindex].type)
|
|
{
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
case HAWK_PARSESTD_FILE:
|
|
#endif
|
|
case HAWK_PARSESTD_FILEU:
|
|
HAWK_ASSERT (arg->handle != HAWK_NULL);
|
|
n = hawk_sio_getoochars(arg->handle, data, size);
|
|
if (n <= -1)
|
|
{
|
|
const hawk_ooch_t* bem = hawk_backuperrmsg(hawk);
|
|
const hawk_uch_t* path;
|
|
path = xtn->s.in.x[xtn->s.in.xindex].u.fileu.path;
|
|
if (path)
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_EREAD, HAWK_T("unable to read %ls - %js"), path, bem);
|
|
else
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_EREAD, HAWK_T("unable to read %js - %js"), sio_std_names[HAWK_SIO_STDIN].ptr, bem);
|
|
}
|
|
break;
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
case HAWK_PARSESTD_FILE:
|
|
#endif
|
|
case HAWK_PARSESTD_FILEB:
|
|
HAWK_ASSERT (arg->handle != HAWK_NULL);
|
|
n = hawk_sio_getoochars(arg->handle, data, size);
|
|
if (n <= -1)
|
|
{
|
|
const hawk_ooch_t* bem = hawk_backuperrmsg(hawk);
|
|
const hawk_bch_t* path;
|
|
path = xtn->s.in.x[xtn->s.in.xindex].u.fileb.path;
|
|
if (path)
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_EREAD, HAWK_T("unable to read %hs - %js"), path, bem);
|
|
else
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_EREAD, HAWK_T("unable to read %js - %js"), sio_std_names[HAWK_SIO_STDIN].ptr, bem);
|
|
}
|
|
break;
|
|
|
|
|
|
case HAWK_PARSESTD_OOCS:
|
|
parsestd_str:
|
|
n = 0;
|
|
while (n < size && xtn->s.in.u.oocs.ptr < xtn->s.in.u.oocs.end)
|
|
{
|
|
data[n++] = *xtn->s.in.u.oocs.ptr++;
|
|
}
|
|
break;
|
|
|
|
case HAWK_PARSESTD_BCS:
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
goto parsestd_str;
|
|
#else
|
|
{
|
|
int m;
|
|
hawk_oow_t mbslen, wcslen;
|
|
|
|
mbslen = xtn->s.in.u.bcs.end - xtn->s.in.u.bcs.ptr;
|
|
wcslen = size;
|
|
if ((m = hawk_conv_bchars_to_uchars_with_cmgr(xtn->s.in.u.bcs.ptr, &mbslen, data, &wcslen, hawk_getcmgr(hawk), 0)) <= -1 && m != -2)
|
|
{
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_EINVAL);
|
|
n = -1;
|
|
}
|
|
else
|
|
{
|
|
xtn->s.in.u.bcs.ptr += mbslen;
|
|
n = wcslen;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
case HAWK_PARSESTD_UCS:
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
{
|
|
int m;
|
|
hawk_oow_t mbslen, wcslen;
|
|
|
|
wcslen = xtn->s.in.u.ucs.end - xtn->s.in.u.ucs.ptr;
|
|
mbslen = size;
|
|
if ((m = hawk_conv_uchars_to_bchars_with_cmgr(xtn->s.in.u.ucs.ptr, &wcslen, data, &mbslen, hawk_getcmgr(hawk))) <= -1 && m != -2)
|
|
{
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_EINVAL);
|
|
n = -1;
|
|
}
|
|
else
|
|
{
|
|
xtn->s.in.u.ucs.ptr += wcslen;
|
|
n = mbslen;
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
goto parsestd_str;
|
|
#endif
|
|
|
|
default:
|
|
/* this should never happen */
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_EINTERN);
|
|
n = -1;
|
|
break;
|
|
}
|
|
|
|
if (n == 0)
|
|
{
|
|
/* reached end of the current stream. */
|
|
hawk_oow_t next = xtn->s.in.xindex + 1;
|
|
if (xtn->s.in.x[next].type != HAWK_PARSESTD_NULL)
|
|
{
|
|
/* open the next stream if available. */
|
|
if (open_parsestd(hawk, arg, xtn, next) <= -1) n = -1;
|
|
else
|
|
{
|
|
xtn->s.in.xindex = next; /* update the next to the current */
|
|
arg->line = 0; /* reset the line number */
|
|
arg->colm = 0;
|
|
goto again;
|
|
}
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
else
|
|
{
|
|
/* handle the included source file - @include */
|
|
hawk_ooi_t n;
|
|
|
|
HAWK_ASSERT (arg->name != HAWK_NULL);
|
|
HAWK_ASSERT (arg->handle != HAWK_NULL);
|
|
|
|
n = hawk_sio_getoochars(arg->handle, data, size);
|
|
|
|
if (n <= -1)
|
|
{
|
|
const hawk_ooch_t* bem = hawk_backuperrmsg(hawk);
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_EREAD, HAWK_T("unable to read %js - %js"), arg->name, bem);
|
|
}
|
|
return n;
|
|
}
|
|
}
|
|
|
|
static hawk_ooi_t sf_in (hawk_t* hawk, hawk_sio_cmd_t cmd, hawk_sio_arg_t* arg, hawk_ooch_t* data, hawk_oow_t size)
|
|
{
|
|
xtn_t* xtn = GET_XTN(hawk);
|
|
|
|
switch (cmd)
|
|
{
|
|
case HAWK_SIO_CMD_OPEN:
|
|
return sf_in_open(hawk, arg, xtn);
|
|
|
|
case HAWK_SIO_CMD_CLOSE:
|
|
return sf_in_close(hawk, arg, xtn);
|
|
|
|
case HAWK_SIO_CMD_READ:
|
|
return sf_in_read(hawk, arg, data, size, xtn);
|
|
|
|
default:
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static hawk_ooi_t sf_out (hawk_t* hawk, hawk_sio_cmd_t cmd, hawk_sio_arg_t* arg, hawk_ooch_t* data, hawk_oow_t size)
|
|
{
|
|
xtn_t* xtn = GET_XTN(hawk);
|
|
|
|
switch (cmd)
|
|
{
|
|
case HAWK_SIO_CMD_OPEN:
|
|
{
|
|
switch (xtn->s.out.x->type)
|
|
{
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
case HAWK_PARSESTD_FILE:
|
|
HAWK_ASSERT (&xtn->s.out.x->u.fileb.path == &xtn->s.out.x->u.file.path);
|
|
HAWK_ASSERT (&xtn->s.out.x->u.fileb.cmgr == &xtn->s.out.x->u.file.cmgr);
|
|
#endif
|
|
case HAWK_PARSESTD_FILEB:
|
|
if (xtn->s.out.x->u.fileb.path == HAWK_NULL || (xtn->s.out.x->u.fileb.path[0] == '-' && xtn->s.out.x->u.fileb.path[1] == '\0'))
|
|
{
|
|
/* no path name or - -> stdout */
|
|
xtn->s.out.u.file.sio = open_sio_std(hawk, HAWK_SIO_STDOUT, HAWK_SIO_WRITE | HAWK_SIO_IGNOREECERR | HAWK_SIO_LINEBREAK);
|
|
if (xtn->s.out.u.file.sio == HAWK_NULL) return -1;
|
|
}
|
|
else
|
|
{
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
hawk_uch_t* upath;
|
|
upath = hawk_dupbtoucstr(hawk, xtn->s.out.x->u.fileb.path, HAWK_NULL, 1);
|
|
if (!upath) return -1;
|
|
xtn->s.out.u.file.sio = open_sio(hawk, upath, HAWK_SIO_WRITE | HAWK_SIO_CREATE | HAWK_SIO_TRUNCATE | HAWK_SIO_IGNOREECERR);
|
|
hawk_freemem (hawk, upath);
|
|
#else
|
|
xtn->s.out.u.file.sio = open_sio(hawk, xtn->s.out.x->u.fileb.path, HAWK_SIO_WRITE | HAWK_SIO_CREATE | HAWK_SIO_TRUNCATE | HAWK_SIO_IGNOREECERR);
|
|
#endif
|
|
if (xtn->s.out.u.file.sio == HAWK_NULL) return -1;
|
|
}
|
|
|
|
if (xtn->s.out.x->u.fileb.cmgr) hawk_sio_setcmgr (xtn->s.out.u.file.sio, xtn->s.out.x->u.fileb.cmgr);
|
|
return 1;
|
|
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
case HAWK_PARSESTD_FILE:
|
|
HAWK_ASSERT (&xtn->s.out.x->u.fileu.path == &xtn->s.out.x->u.file.path);
|
|
HAWK_ASSERT (&xtn->s.out.x->u.fileu.cmgr == &xtn->s.out.x->u.file.cmgr);
|
|
#endif
|
|
case HAWK_PARSESTD_FILEU:
|
|
if (xtn->s.out.x->u.fileu.path == HAWK_NULL || (xtn->s.out.x->u.fileu.path[0] == '-' && xtn->s.out.x->u.fileu.path[1] == '\0'))
|
|
{
|
|
/* no path name or - -> stdout */
|
|
xtn->s.out.u.file.sio = open_sio_std(hawk, HAWK_SIO_STDOUT, HAWK_SIO_WRITE | HAWK_SIO_IGNOREECERR | HAWK_SIO_LINEBREAK);
|
|
if (xtn->s.out.u.file.sio == HAWK_NULL) return -1;
|
|
}
|
|
else
|
|
{
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
xtn->s.out.u.file.sio = open_sio(hawk, xtn->s.out.x->u.fileu.path, HAWK_SIO_WRITE | HAWK_SIO_CREATE | HAWK_SIO_TRUNCATE | HAWK_SIO_IGNOREECERR);
|
|
#else
|
|
hawk_bch_t* bpath;
|
|
bpath = hawk_duputobcstr(hawk, xtn->s.out.x->u.fileu.path, HAWK_NULL);
|
|
if (!bpath) return -1;
|
|
xtn->s.out.u.file.sio = open_sio(hawk, bpath, HAWK_SIO_WRITE | HAWK_SIO_CREATE | HAWK_SIO_TRUNCATE | HAWK_SIO_IGNOREECERR);
|
|
hawk_freemem (hawk, bpath);
|
|
#endif
|
|
if (xtn->s.out.u.file.sio == HAWK_NULL) return -1;
|
|
}
|
|
|
|
if (xtn->s.out.x->u.fileu.cmgr) hawk_sio_setcmgr (xtn->s.out.u.file.sio, xtn->s.out.x->u.fileu.cmgr);
|
|
return 1;
|
|
|
|
case HAWK_PARSESTD_OOCS:
|
|
xtn->s.out.u.oocs.buf = hawk_ooecs_open(hawk_getgem(hawk), 0, 512);
|
|
if (xtn->s.out.u.oocs.buf == HAWK_NULL) return -1;
|
|
return 1;
|
|
|
|
case HAWK_PARSESTD_BCS:
|
|
xtn->s.out.u.bcs.buf = hawk_becs_open(hawk_getgem(hawk), 0, 512);
|
|
if (xtn->s.out.u.bcs.buf == HAWK_NULL) return -1;
|
|
return 1;
|
|
|
|
case HAWK_PARSESTD_UCS:
|
|
xtn->s.out.u.ucs.buf = hawk_uecs_open(hawk_getgem(hawk), 0, 512);
|
|
if (xtn->s.out.u.ucs.buf == HAWK_NULL) return -1;
|
|
return 1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case HAWK_SIO_CMD_CLOSE:
|
|
{
|
|
switch (xtn->s.out.x->type)
|
|
{
|
|
case HAWK_PARSESTD_FILE:
|
|
case HAWK_PARSESTD_FILEB:
|
|
case HAWK_PARSESTD_FILEU:
|
|
hawk_sio_close (xtn->s.out.u.file.sio);
|
|
return 0;
|
|
|
|
case HAWK_PARSESTD_OOCS:
|
|
case HAWK_PARSESTD_BCS:
|
|
case HAWK_PARSESTD_UCS:
|
|
/* i don't close xtn->s.out.u.oocs.buf intentionally here.
|
|
* it will be closed at the end of hawk_parsestd() */
|
|
return 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case HAWK_SIO_CMD_WRITE:
|
|
{
|
|
switch (xtn->s.out.x->type)
|
|
{
|
|
case HAWK_PARSESTD_FILE:
|
|
case HAWK_PARSESTD_FILEB:
|
|
case HAWK_PARSESTD_FILEU:
|
|
{
|
|
hawk_ooi_t n;
|
|
HAWK_ASSERT (xtn->s.out.u.file.sio != HAWK_NULL);
|
|
n = hawk_sio_putoochars(xtn->s.out.u.file.sio, data, size);
|
|
if (n <= -1)
|
|
{
|
|
const hawk_ooch_t* ioname;
|
|
const hawk_ooch_t* bem = hawk_backuperrmsg(hawk);
|
|
ioname = xtn->s.out.x->u.file.path;
|
|
if (!ioname) ioname = sio_std_names[HAWK_SIO_STDOUT].ptr;
|
|
hawk_seterrfmt (hawk, HAWK_NULL, HAWK_EWRITE, HAWK_T("unable to write to %js - %js"), ioname, bem);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
case HAWK_PARSESTD_OOCS:
|
|
parsestd_str:
|
|
if (size > HAWK_TYPE_MAX(hawk_ooi_t)) size = HAWK_TYPE_MAX(hawk_ooi_t);
|
|
if (hawk_ooecs_ncat(xtn->s.out.u.oocs.buf, data, size) == (hawk_oow_t)-1) return -1;
|
|
return size;
|
|
|
|
case HAWK_PARSESTD_BCS:
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
goto parsestd_str;
|
|
#else
|
|
{
|
|
hawk_oow_t mbslen, wcslen;
|
|
hawk_oow_t orglen;
|
|
|
|
wcslen = size;
|
|
if (hawk_convutobchars(hawk, data, &wcslen, HAWK_NULL, &mbslen) <= -1) return -1;
|
|
if (mbslen > HAWK_TYPE_MAX(hawk_ooi_t)) mbslen = HAWK_TYPE_MAX(hawk_ooi_t);
|
|
|
|
orglen = hawk_becs_getlen(xtn->s.out.u.bcs.buf);
|
|
if (hawk_becs_setlen(xtn->s.out.u.bcs.buf, orglen + mbslen) == (hawk_oow_t)-1) return -1;
|
|
|
|
wcslen = size;
|
|
hawk_convutobchars (hawk, data, &wcslen, HAWK_BECS_CPTR(xtn->s.out.u.bcs.buf, orglen), &mbslen);
|
|
size = wcslen;
|
|
|
|
return size;
|
|
}
|
|
#endif
|
|
|
|
case HAWK_PARSESTD_UCS:
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
{
|
|
hawk_oow_t mbslen, wcslen;
|
|
hawk_oow_t orglen;
|
|
|
|
mbslen = size;
|
|
if (hawk_convbtouchars(hawk, data, &mbslen, HAWK_NULL, &wcslen, 0) <= -1) return -1;
|
|
if (wcslen > HAWK_TYPE_MAX(hawk_ooi_t)) wcslen = HAWK_TYPE_MAX(hawk_ooi_t);
|
|
|
|
orglen = hawk_becs_getlen(xtn->s.out.u.ucs.buf);
|
|
if (hawk_uecs_setlen(xtn->s.out.u.ucs.buf, orglen + wcslen) == (hawk_oow_t)-1) return -1;
|
|
|
|
mbslen = size;
|
|
hawk_convbtouchars (hawk, data, &mbslen, HAWK_UECS_CPTR(xtn->s.out.u.ucs.buf, orglen), &wcslen, 0);
|
|
size = mbslen;
|
|
|
|
return size;
|
|
}
|
|
#else
|
|
goto parsestd_str;
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
/* other code must not trigger this function */
|
|
break;
|
|
}
|
|
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
}
|
|
|
|
int hawk_parsestd (hawk_t* hawk, hawk_parsestd_t in[], hawk_parsestd_t* out)
|
|
{
|
|
hawk_sio_cbs_t sio;
|
|
xtn_t* xtn = GET_XTN(hawk);
|
|
int n;
|
|
|
|
if (in == HAWK_NULL || (in[0].type != HAWK_PARSESTD_FILE &&
|
|
in[0].type != HAWK_PARSESTD_FILEB &&
|
|
in[0].type != HAWK_PARSESTD_FILEU &&
|
|
in[0].type != HAWK_PARSESTD_OOCS &&
|
|
in[0].type != HAWK_PARSESTD_BCS &&
|
|
in[0].type != HAWK_PARSESTD_UCS))
|
|
{
|
|
/* the input is a must. at least 1 file or 1 string
|
|
* must be specified */
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_EINVAL);
|
|
return -1;
|
|
}
|
|
|
|
sio.in = sf_in;
|
|
xtn->s.in.x = in;
|
|
|
|
if (out == HAWK_NULL) sio.out = HAWK_NULL;
|
|
else
|
|
{
|
|
if (out->type != HAWK_PARSESTD_FILE &&
|
|
out->type != HAWK_PARSESTD_FILEB &&
|
|
out->type != HAWK_PARSESTD_FILEU &&
|
|
out->type != HAWK_PARSESTD_OOCS &&
|
|
out->type != HAWK_PARSESTD_BCS &&
|
|
out->type != HAWK_PARSESTD_UCS)
|
|
{
|
|
hawk_seterrnum (hawk, HAWK_NULL, HAWK_EINVAL);
|
|
return -1;
|
|
}
|
|
sio.out = sf_out;
|
|
xtn->s.out.x = out;
|
|
}
|
|
|
|
n = hawk_parse(hawk, &sio);
|
|
|
|
if (out)
|
|
{
|
|
switch (out->type)
|
|
{
|
|
case HAWK_PARSESTD_OOCS:
|
|
if (n >= 0)
|
|
{
|
|
HAWK_ASSERT (xtn->s.out.u.oocs.buf != HAWK_NULL);
|
|
hawk_ooecs_yield (xtn->s.out.u.oocs.buf, &out->u.oocs, 0);
|
|
}
|
|
if (xtn->s.out.u.oocs.buf) hawk_ooecs_close (xtn->s.out.u.oocs.buf);
|
|
break;
|
|
|
|
case HAWK_PARSESTD_BCS:
|
|
if (n >= 0)
|
|
{
|
|
HAWK_ASSERT (xtn->s.out.u.bcs.buf != HAWK_NULL);
|
|
hawk_becs_yield (xtn->s.out.u.bcs.buf, &out->u.bcs, 0);
|
|
}
|
|
if (xtn->s.out.u.bcs.buf) hawk_becs_close (xtn->s.out.u.bcs.buf);
|
|
break;
|
|
|
|
case HAWK_PARSESTD_UCS:
|
|
if (n >= 0)
|
|
{
|
|
HAWK_ASSERT (xtn->s.out.u.ucs.buf != HAWK_NULL);
|
|
hawk_uecs_yield (xtn->s.out.u.ucs.buf, &out->u.ucs, 0);
|
|
}
|
|
if (xtn->s.out.u.ucs.buf) hawk_uecs_close (xtn->s.out.u.ucs.buf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static int check_var_assign (hawk_rtx_t* rtx, const hawk_ooch_t* str)
|
|
{
|
|
hawk_ooch_t* eq, * dstr;
|
|
int n;
|
|
|
|
eq = hawk_find_oochar_in_oocstr(str, '=');
|
|
if (!eq || eq <= str) return 0; /* not assignment */
|
|
|
|
dstr = hawk_rtx_dupoocstr(rtx, str, HAWK_NULL);
|
|
if (HAWK_UNLIKELY(!dstr)) return -1;
|
|
|
|
eq = dstr + (eq - str);
|
|
*eq = '\0';
|
|
|
|
if (hawk_isvalidident(hawk_rtx_gethawk(rtx), dstr))
|
|
{
|
|
hawk_unescape_oocstr (eq + 1);
|
|
n = (hawk_rtx_setgbltostrbyname(rtx, dstr, eq + 1) <= -1)? -1: 1;
|
|
}
|
|
else
|
|
{
|
|
n = 0;
|
|
}
|
|
|
|
hawk_rtx_freemem (rtx, dstr);
|
|
return n;
|
|
}
|
|
|
|
/*** RTX_OPENSTD ***/
|
|
|
|
static ioattr_t* get_ioattr (hawk_htb_t* tab, const hawk_ooch_t* ptr, hawk_oow_t len);
|
|
|
|
#if defined(ENABLE_NWIO)
|
|
static hawk_ooi_t nwio_handler_open (hawk_rtx_t* rtx, hawk_rio_arg_t* riod, int flags, hawk_nwad_t* nwad, hawk_nwio_tmout_t* tmout)
|
|
{
|
|
hawk_nwio_t* handle;
|
|
|
|
handle = hawk_nwio_open (
|
|
hawk_rtx_getmmgr(rtx), 0, nwad,
|
|
flags | HAWK_NWIO_TEXT | HAWK_NWIO_IGNOREECERR |
|
|
HAWK_NWIO_REUSEADDR | HAWK_NWIO_READNORETRY | HAWK_NWIO_WRITENORETRY,
|
|
tmout
|
|
);
|
|
if (handle == HAWK_NULL) return -1;
|
|
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
{
|
|
hawk_cmgr_t* cmgr = hawk_rtx_getiocmgrstd(rtx, riod->name);
|
|
if (cmgr) hawk_nwio_setcmgr (handle, cmgr);
|
|
}
|
|
#endif
|
|
|
|
riod->handle = (void*)handle;
|
|
riod->uflags = 1; /* nwio indicator */
|
|
return 1;
|
|
}
|
|
|
|
static hawk_ooi_t nwio_handler_rest (hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_rio_arg_t* riod, void* data, hawk_oow_t size)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case HAWK_RIO_CMD_OPEN:
|
|
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
|
|
case HAWK_RIO_CMD_CLOSE:
|
|
hawk_nwio_close ((hawk_nwio_t*)riod->handle);
|
|
return 0;
|
|
|
|
case HAWK_RIO_CMD_READ:
|
|
return hawk_nwio_read((hawk_nwio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_READBYTES:
|
|
return hawk_nwio_readbytes(((hawk_nwio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_WRITE:
|
|
return hawk_nwio_write((hawk_nwio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_WRITE_BYTES:
|
|
return hawk_nwio_writebytes((hawk_nwio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_FLUSH:
|
|
/*if (riod->mode == HAWK_RIO_PIPE_READ) return -1;*/
|
|
return hawk_nwio_flush((hawk_nwio_t*)riod->handle);
|
|
|
|
case HAWK_RIO_CMD_NEXT:
|
|
break;
|
|
}
|
|
|
|
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
}
|
|
|
|
static int parse_rwpipe_uri (const hawk_ooch_t* uri, int* flags, hawk_nwad_t* nwad)
|
|
{
|
|
static struct
|
|
{
|
|
const hawk_ooch_t* prefix;
|
|
hawk_oow_t len;
|
|
int flags;
|
|
} x[] =
|
|
{
|
|
{ HAWK_T("tcp://"), 6, HAWK_NWIO_TCP },
|
|
{ HAWK_T("udp://"), 6, HAWK_NWIO_UDP },
|
|
{ HAWK_T("tcpd://"), 7, HAWK_NWIO_TCP | HAWK_NWIO_PASSIVE },
|
|
{ HAWK_T("udpd://"), 7, HAWK_NWIO_UDP | HAWK_NWIO_PASSIVE }
|
|
};
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < HAWK_COUNTOF(x); i++)
|
|
{
|
|
if (hawk_strzcmp (uri, x[i].prefix, x[i].len) == 0)
|
|
{
|
|
if (hawk_strtonwad (uri + x[i].len, nwad) <= -1) return -1;
|
|
*flags = x[i].flags;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
static hawk_ooi_t pio_handler_open (hawk_rtx_t* rtx, hawk_rio_arg_t* riod)
|
|
{
|
|
hawk_pio_t* handle;
|
|
int flags;
|
|
|
|
if (riod->mode == HAWK_RIO_PIPE_READ)
|
|
{
|
|
/* TODO: should ERRTOOUT be unset? */
|
|
flags = HAWK_PIO_READOUT | HAWK_PIO_ERRTOOUT;
|
|
}
|
|
else if (riod->mode == HAWK_RIO_PIPE_WRITE)
|
|
{
|
|
flags = HAWK_PIO_WRITEIN;
|
|
}
|
|
else if (riod->mode == HAWK_RIO_PIPE_RW)
|
|
{
|
|
flags = HAWK_PIO_READOUT | HAWK_PIO_ERRTOOUT | HAWK_PIO_WRITEIN;
|
|
}
|
|
else
|
|
{
|
|
/* this must not happen */
|
|
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
}
|
|
|
|
handle = hawk_pio_open(
|
|
hawk_rtx_getgem(rtx),
|
|
0,
|
|
riod->name,
|
|
flags | HAWK_PIO_SHELL | HAWK_PIO_TEXT | HAWK_PIO_IGNOREECERR
|
|
);
|
|
if (handle == HAWK_NULL) return -1;
|
|
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
{
|
|
hawk_cmgr_t* cmgr = hawk_rtx_getiocmgrstd(rtx, riod->name);
|
|
if (cmgr)
|
|
{
|
|
hawk_pio_setcmgr (handle, HAWK_PIO_IN, cmgr);
|
|
hawk_pio_setcmgr (handle, HAWK_PIO_OUT, cmgr);
|
|
hawk_pio_setcmgr (handle, HAWK_PIO_ERR, cmgr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
riod->handle = (void*)handle;
|
|
riod->uflags = 0; /* pio indicator */
|
|
return 1;
|
|
}
|
|
|
|
static hawk_ooi_t pio_handler_rest (hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_rio_arg_t* riod, void* data, hawk_oow_t size)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case HAWK_RIO_CMD_OPEN:
|
|
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
|
|
case HAWK_RIO_CMD_CLOSE:
|
|
{
|
|
hawk_pio_t* pio = (hawk_pio_t*)riod->handle;
|
|
if (riod->mode == HAWK_RIO_PIPE_RW)
|
|
{
|
|
/* specialy treatment is needed for rwpipe.
|
|
* inspect rwcmode to see if partial closing is
|
|
* requested. */
|
|
if (riod->rwcmode == HAWK_RIO_CMD_CLOSE_READ)
|
|
{
|
|
hawk_pio_end (pio, HAWK_PIO_IN);
|
|
return 0;
|
|
}
|
|
if (riod->rwcmode == HAWK_RIO_CMD_CLOSE_WRITE)
|
|
{
|
|
hawk_pio_end (pio, HAWK_PIO_OUT);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
hawk_pio_close (pio);
|
|
return 0;
|
|
}
|
|
|
|
case HAWK_RIO_CMD_READ:
|
|
return hawk_pio_read((hawk_pio_t*)riod->handle, HAWK_PIO_OUT, data, size);
|
|
|
|
case HAWK_RIO_CMD_READ_BYTES:
|
|
return hawk_pio_readbytes((hawk_pio_t*)riod->handle, HAWK_PIO_OUT, data, size);
|
|
|
|
case HAWK_RIO_CMD_WRITE:
|
|
return hawk_pio_write((hawk_pio_t*)riod->handle, HAWK_PIO_IN, data, size);
|
|
|
|
case HAWK_RIO_CMD_WRITE_BYTES:
|
|
return hawk_pio_writebytes((hawk_pio_t*)riod->handle, HAWK_PIO_IN, data, size);
|
|
|
|
case HAWK_RIO_CMD_FLUSH:
|
|
/*if (riod->mode == HAWK_RIO_PIPE_READ) return -1;*/
|
|
return hawk_pio_flush ((hawk_pio_t*)riod->handle, HAWK_PIO_IN);
|
|
|
|
case HAWK_RIO_CMD_NEXT:
|
|
break;
|
|
}
|
|
|
|
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
}
|
|
|
|
static hawk_ooi_t hawk_rio_pipe (hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_rio_arg_t* riod, void* data, hawk_oow_t size)
|
|
{
|
|
if (cmd == HAWK_RIO_CMD_OPEN)
|
|
{
|
|
#if defined(ENABLE_NWIO)
|
|
int flags;
|
|
hawk_nwad_t nwad;
|
|
|
|
if (riod->mode != HAWK_RIO_PIPE_RW ||
|
|
parse_rwpipe_uri(riod->name, &flags, &nwad) <= -1)
|
|
{
|
|
return pio_handler_open (rtx, riod);
|
|
}
|
|
else
|
|
{
|
|
hawk_nwio_tmout_t tmout_buf;
|
|
hawk_nwio_tmout_t* tmout = HAWK_NULL;
|
|
ioattr_t* ioattr;
|
|
rxtn_t* rxtn;
|
|
|
|
rxtn = GET_RXTN(rtx);
|
|
|
|
ioattr = get_ioattr(&rxtn->cmgrtab, riod->name, hawk_count_oocstr(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
|
|
return pio_handler_open (rtx, riod);
|
|
#endif
|
|
}
|
|
#if defined(ENABLE_NWIO)
|
|
else if (riod->uflags > 0)
|
|
return nwio_handler_rest(rtx, cmd, riod, data, size);
|
|
#endif
|
|
else
|
|
return pio_handler_rest(rtx, cmd, riod, data, size);
|
|
}
|
|
|
|
static hawk_ooi_t hawk_rio_file (hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_rio_arg_t* riod, void* data, hawk_oow_t size)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case HAWK_RIO_CMD_OPEN:
|
|
{
|
|
hawk_sio_t* handle;
|
|
int flags = HAWK_SIO_IGNOREECERR;
|
|
|
|
switch (riod->mode)
|
|
{
|
|
case HAWK_RIO_FILE_READ:
|
|
flags |= HAWK_SIO_READ;
|
|
break;
|
|
case HAWK_RIO_FILE_WRITE:
|
|
flags |= HAWK_SIO_WRITE | HAWK_SIO_CREATE | HAWK_SIO_TRUNCATE;
|
|
break;
|
|
case HAWK_RIO_FILE_APPEND:
|
|
flags |= HAWK_SIO_APPEND | HAWK_SIO_CREATE;
|
|
break;
|
|
default:
|
|
/* this must not happen */
|
|
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
}
|
|
|
|
if (riod->name[0] == '-' && riod->name[1] == '\0')
|
|
{
|
|
if (riod->mode == HAWK_RIO_FILE_READ)
|
|
handle = open_sio_std_rtx(rtx, HAWK_SIO_STDIN, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR);
|
|
else
|
|
handle = open_sio_std_rtx(rtx, HAWK_SIO_STDOUT, HAWK_SIO_WRITE | HAWK_SIO_IGNOREECERR | HAWK_SIO_LINEBREAK);
|
|
}
|
|
else
|
|
{
|
|
handle = hawk_sio_open(hawk_rtx_getgem(rtx), 0, riod->name, flags);
|
|
}
|
|
if (!handle)
|
|
{
|
|
const hawk_ooch_t* bem = hawk_rtx_backuperrmsg(rtx);
|
|
hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_EOPEN, HAWK_T("unable to open %js - %js"), riod->name, bem);
|
|
return -1;
|
|
}
|
|
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
{
|
|
hawk_cmgr_t* cmgr = hawk_rtx_getiocmgrstd(rtx, riod->name);
|
|
if (cmgr) hawk_sio_setcmgr(handle, cmgr);
|
|
}
|
|
#endif
|
|
|
|
riod->handle = (void*)handle;
|
|
return 1;
|
|
}
|
|
|
|
case HAWK_RIO_CMD_CLOSE:
|
|
hawk_sio_close ((hawk_sio_t*)riod->handle);
|
|
riod->handle = HAWK_NULL;
|
|
return 0;
|
|
|
|
case HAWK_RIO_CMD_READ:
|
|
return hawk_sio_getoochars((hawk_sio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_READ_BYTES:
|
|
return hawk_sio_getbchars((hawk_sio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_WRITE:
|
|
return hawk_sio_putoochars((hawk_sio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_WRITE_BYTES:
|
|
return hawk_sio_putbchars((hawk_sio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_FLUSH:
|
|
{
|
|
int n;
|
|
|
|
n = hawk_sio_flush((hawk_sio_t*)riod->handle);
|
|
if (HAWK_UNLIKELY(n <= -1))
|
|
{
|
|
/* if flushing fails, discard the buffered data
|
|
* keeping the unflushed data causes causes subsequent write or close() to
|
|
* flush again and again */
|
|
hawk_sio_drain ((hawk_sio_t*)riod->handle);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
case HAWK_RIO_CMD_NEXT:
|
|
return -1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int open_rio_console (hawk_rtx_t* rtx, hawk_rio_arg_t* riod)
|
|
{
|
|
rxtn_t* rxtn = GET_RXTN(rtx);
|
|
hawk_sio_t* sio;
|
|
|
|
if (riod->mode == HAWK_RIO_CONSOLE_READ)
|
|
{
|
|
#if 1
|
|
/* this part is more complex than the code in the else part.
|
|
* it handles simple assignemnt as well as open files
|
|
* via in ARGV instead of rxtn->c.in.files */
|
|
xtn_t* xtn = (xtn_t*)GET_XTN(hawk_rtx_gethawk(rtx));
|
|
hawk_val_t* v_argc, * v_argv, * v_pair;
|
|
hawk_int_t i_argc;
|
|
const hawk_ooch_t* file;
|
|
hawk_map_t* map;
|
|
hawk_map_pair_t* pair;
|
|
hawk_ooch_t ibuf[128];
|
|
hawk_oow_t ibuflen;
|
|
hawk_oocs_t as;
|
|
int x;
|
|
|
|
v_argc = hawk_rtx_getgbl(rtx, xtn->gbl_argc);
|
|
HAWK_ASSERT (v_argc != HAWK_NULL);
|
|
if (hawk_rtx_valtoint(rtx, v_argc, &i_argc) <= -1) return -1;
|
|
|
|
/* 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
|
|
*/
|
|
v_argv = hawk_rtx_getgbl(rtx, xtn->gbl_argv);
|
|
HAWK_ASSERT (v_argv != HAWK_NULL);
|
|
if (HAWK_RTX_GETVALTYPE(rtx, v_argv) != HAWK_VAL_MAP)
|
|
{
|
|
/* with flexmap on, you can change ARGV to a scalar.
|
|
* BEGIN { ARGV="xxx"; }
|
|
* you must not do this. */
|
|
hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_EINVAL, HAWK_T("phony value in ARGV"));
|
|
return -1;
|
|
}
|
|
|
|
map = ((hawk_val_map_t*)v_argv)->map;
|
|
HAWK_ASSERT (map != HAWK_NULL);
|
|
|
|
nextfile:
|
|
if (rxtn->c.in.index >= (i_argc - 1)) /* ARGV is a kind of 0-based array unlike other normal arrays or substring indexing scheme */
|
|
{
|
|
/* reached the last ARGV */
|
|
|
|
if (rxtn->c.in.count <= 0) /* but no file has been ever opened */
|
|
{
|
|
console_open_stdin:
|
|
/* open stdin */
|
|
sio = open_sio_std_rtx (rtx, HAWK_SIO_STDIN, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR);
|
|
if (HAWK_UNLIKELY(!sio)) return -1;
|
|
|
|
if (rxtn->c.cmgr) hawk_sio_setcmgr (sio, rxtn->c.cmgr);
|
|
|
|
riod->handle = sio;
|
|
rxtn->c.in.count++;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ibuflen = hawk_int_to_oocstr(rxtn->c.in.index + 1, 10, HAWK_NULL, ibuf, HAWK_COUNTOF(ibuf));
|
|
|
|
pair = hawk_map_search(map, ibuf, ibuflen);
|
|
if (!pair)
|
|
{
|
|
/* the key doesn't exist any more */
|
|
if (rxtn->c.in.count <= 0) goto console_open_stdin;
|
|
return 0; /* end of console */
|
|
}
|
|
|
|
v_pair = HAWK_HTB_VPTR(pair);
|
|
HAWK_ASSERT (v_pair != HAWK_NULL);
|
|
|
|
as.ptr = hawk_rtx_getvaloocstr(rtx, v_pair, &as.len);
|
|
if (HAWK_UNLIKELY(!as.ptr)) return -1;
|
|
|
|
if (as.len == 0)
|
|
{
|
|
/* the name is empty */
|
|
hawk_rtx_freevaloocstr (rtx, v_pair, as.ptr);
|
|
rxtn->c.in.index++;
|
|
goto nextfile;
|
|
}
|
|
|
|
if (hawk_count_oocstr(as.ptr) < as.len)
|
|
{
|
|
/* the name contains one or more '\0' */
|
|
hawk_rtx_seterrfmt (rtx, HAWK_NULL, HAWK_EIONMNL, HAWK_T("invalid I/O name of length %zu containing '\\0'"), as.len);
|
|
hawk_rtx_freevaloocstr (rtx, v_pair, as.ptr);
|
|
return -1;
|
|
}
|
|
|
|
file = as.ptr;
|
|
|
|
/*
|
|
* this is different from the -v option.
|
|
* if an argument has a special form of var=val, it is treated specially
|
|
*
|
|
* on the command-line
|
|
* hawk -f a.hawk a=20 /etc/passwd
|
|
* or via ARGV
|
|
* hawk 'BEGIN { ARGV[1] = "a=20"; }
|
|
* { print a $1; }' dummy /etc/hosts
|
|
*/
|
|
if ((x = check_var_assign(rtx, file)) != 0)
|
|
{
|
|
hawk_rtx_freevaloocstr (rtx, v_pair, as.ptr);
|
|
if (HAWK_UNLIKELY(x <= -1)) return -1;
|
|
rxtn->c.in.index++;
|
|
goto nextfile;
|
|
}
|
|
|
|
/* a temporary variable sio is used here not to change
|
|
* any fields of riod when the open operation fails */
|
|
sio = (file[0] == HAWK_T('-') && file[1] == HAWK_T('\0'))?
|
|
open_sio_std_rtx(rtx, HAWK_SIO_STDIN, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR):
|
|
open_sio_rtx(rtx, file, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR);
|
|
if (HAWK_UNLIKELY(!sio))
|
|
{
|
|
hawk_rtx_freevaloocstr (rtx, v_pair, as.ptr);
|
|
return -1;
|
|
}
|
|
|
|
if (rxtn->c.cmgr) hawk_sio_setcmgr (sio, rxtn->c.cmgr);
|
|
|
|
if (hawk_rtx_setfilenamewithoochars(rtx, file, hawk_count_oocstr(file)) <= -1)
|
|
{
|
|
hawk_sio_close (sio);
|
|
hawk_rtx_freevaloocstr (rtx, v_pair, as.ptr);
|
|
return -1;
|
|
}
|
|
|
|
hawk_rtx_freevaloocstr (rtx, v_pair, as.ptr);
|
|
riod->handle = sio;
|
|
|
|
/* increment the counter of files successfully opened */
|
|
rxtn->c.in.count++;
|
|
rxtn->c.in.index++;
|
|
return 1;
|
|
#else
|
|
/* simple console open implementation.
|
|
* no var=val handling. no ARGV handling */
|
|
|
|
if (!rxtn->c.in.files)
|
|
{
|
|
/* if no input files is specified,
|
|
* open the standard input */
|
|
HAWK_ASSERT (rxtn->c.in.index == 0);
|
|
|
|
if (rxtn->c.in.count == 0)
|
|
{
|
|
console_open_stdin:
|
|
sio = open_sio_std_rtx(rtx, HAWK_SIO_STDIN, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR);
|
|
if (sio == HAWK_NULL) return -1;
|
|
|
|
if (rxtn->c.cmgr) hawk_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 hawk_ooch_t* file;
|
|
|
|
nextfile:
|
|
file = rxtn->c.in.files[rxtn->c.in.index];
|
|
if (!file)
|
|
{
|
|
/* no more input file */
|
|
if (rxtn->c.in.count == 0) goto console_open_stdin;
|
|
return 0;
|
|
}
|
|
|
|
if (file[0] == '\0')
|
|
{
|
|
rxtn->c.in.index++;
|
|
goto nextfile;
|
|
}
|
|
|
|
sio = (file[0] == '-' && file[1] == '\0')?
|
|
open_sio_std_rtx(rtx, HAWK_SIO_STDIN, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR):
|
|
open_sio_rtx(rtx, file, HAWK_SIO_READ | HAWK_SIO_IGNOREECERR);
|
|
if (HAWK_UNLIKELY(!sio)) return -1;
|
|
|
|
if (rxtn->c.cmgr) hawk_sio_setcmgr (sio, rxtn->c.cmgr);
|
|
|
|
if (hawk_rtx_setfilenamewithoochars(rtx, file, hawk_count_oocstr(file)) <= -1)
|
|
{
|
|
hawk_sio_close (sio);
|
|
return -1;
|
|
}
|
|
|
|
riod->handle = sio;
|
|
|
|
/* increment the counter of files successfully opened */
|
|
rxtn->c.in.count++;
|
|
rxtn->c.in.index++;
|
|
return 1;
|
|
}
|
|
#endif
|
|
}
|
|
else if (riod->mode == HAWK_RIO_CONSOLE_WRITE)
|
|
{
|
|
if (rxtn->c.out.files == HAWK_NULL)
|
|
{
|
|
HAWK_ASSERT (rxtn->c.out.index == 0);
|
|
|
|
if (rxtn->c.out.count == 0)
|
|
{
|
|
sio = open_sio_std_rtx (
|
|
rtx, HAWK_SIO_STDOUT,
|
|
HAWK_SIO_WRITE | HAWK_SIO_IGNOREECERR | HAWK_SIO_LINEBREAK
|
|
);
|
|
if (sio == HAWK_NULL) return -1;
|
|
|
|
if (rxtn->c.cmgr) hawk_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 */
|
|
hawk_sio_t* sio;
|
|
const hawk_ooch_t* file;
|
|
|
|
file = rxtn->c.out.files[rxtn->c.out.index];
|
|
|
|
if (file == HAWK_NULL)
|
|
{
|
|
/* no more input file */
|
|
return 0;
|
|
}
|
|
|
|
sio = (file[0] == HAWK_T('-') && file[1] == HAWK_T('\0'))?
|
|
open_sio_std_rtx(rtx, HAWK_SIO_STDOUT, HAWK_SIO_WRITE | HAWK_SIO_IGNOREECERR | HAWK_SIO_LINEBREAK):
|
|
open_sio_rtx(rtx, file, HAWK_SIO_WRITE | HAWK_SIO_CREATE | HAWK_SIO_TRUNCATE | HAWK_SIO_IGNOREECERR);
|
|
if (sio == HAWK_NULL) return -1;
|
|
|
|
if (rxtn->c.cmgr) hawk_sio_setcmgr (sio, rxtn->c.cmgr);
|
|
|
|
if (hawk_rtx_setofilenamewithoochars(rtx, file, hawk_count_oocstr(file)) <= -1)
|
|
{
|
|
hawk_sio_close (sio);
|
|
return -1;
|
|
}
|
|
|
|
riod->handle = sio;
|
|
rxtn->c.out.index++;
|
|
rxtn->c.out.count++;
|
|
return 1;
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static hawk_ooi_t hawk_rio_console (hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_rio_arg_t* riod, void* data, hawk_oow_t size)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case HAWK_RIO_CMD_OPEN:
|
|
return open_rio_console(rtx, riod);
|
|
|
|
case HAWK_RIO_CMD_CLOSE:
|
|
if (riod->handle) hawk_sio_close ((hawk_sio_t*)riod->handle);
|
|
return 0;
|
|
|
|
case HAWK_RIO_CMD_READ:
|
|
{
|
|
hawk_ooi_t nn;
|
|
|
|
while ((nn = hawk_sio_getoochars((hawk_sio_t*)riod->handle, data, size)) == 0)
|
|
{
|
|
int n;
|
|
hawk_sio_t* sio = (hawk_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) hawk_sio_close (sio);
|
|
|
|
/* reset FNR to 0 here since the caller doesn't know that the file has changed. */
|
|
hawk_rtx_setgbl(rtx, HAWK_GBL_FNR, hawk_rtx_makeintval(rtx, 0));
|
|
}
|
|
return nn;
|
|
}
|
|
|
|
case HAWK_RIO_CMD_READ_BYTES:
|
|
{
|
|
hawk_ooi_t nn;
|
|
|
|
while ((nn = hawk_sio_getbchars((hawk_sio_t*)riod->handle, data, size)) == 0)
|
|
{
|
|
int n;
|
|
hawk_sio_t* sio = (hawk_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) hawk_sio_close (sio);
|
|
hawk_rtx_setgbl(rtx, HAWK_GBL_FNR, hawk_rtx_makeintval(rtx, 0));
|
|
}
|
|
|
|
return nn;
|
|
}
|
|
|
|
case HAWK_RIO_CMD_WRITE:
|
|
return hawk_sio_putoochars((hawk_sio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_WRITE_BYTES:
|
|
return hawk_sio_putbchars((hawk_sio_t*)riod->handle, data, size);
|
|
|
|
case HAWK_RIO_CMD_FLUSH:
|
|
{
|
|
int n;
|
|
|
|
n = hawk_sio_flush((hawk_sio_t*)riod->handle);
|
|
if (HAWK_UNLIKELY(n <= -1))
|
|
{
|
|
/* if flushing fails, discard the buffered data
|
|
* keeping the unflushed data causes causes subsequent write or close() to
|
|
* flush again and again */
|
|
hawk_sio_drain ((hawk_sio_t*)riod->handle);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
case HAWK_RIO_CMD_NEXT:
|
|
{
|
|
int n;
|
|
hawk_sio_t* sio = (hawk_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) hawk_sio_close (sio);
|
|
return n;
|
|
}
|
|
|
|
}
|
|
|
|
hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINTERN);
|
|
return -1;
|
|
}
|
|
|
|
static void fini_rxtn (hawk_rtx_t* rtx)
|
|
{
|
|
rxtn_t* rxtn = GET_RXTN(rtx);
|
|
/*xtn_t* xtn = (xtn_t*)GET_XTN(hawk_rtx_gethawk(rtx));*/
|
|
|
|
if (rxtn->c.in.files)
|
|
{
|
|
hawk_oow_t i;
|
|
for (i = 0; rxtn->c.in.files[i]; i++) hawk_rtx_freemem(rtx, rxtn->c.in.files[i]);
|
|
hawk_rtx_freemem (rtx, rxtn->c.in.files);
|
|
rxtn->c.in.files = HAWK_NULL;
|
|
rxtn->c.in.count = 0;
|
|
rxtn->c.in.index = 0;
|
|
}
|
|
|
|
if (rxtn->c.out.files)
|
|
{
|
|
hawk_oow_t i;
|
|
for (i = 0; rxtn->c.out.files[i]; i++) hawk_rtx_freemem(rtx, rxtn->c.out.files[i]);
|
|
hawk_rtx_freemem (rtx, rxtn->c.out.files);
|
|
rxtn->c.out.files = HAWK_NULL;
|
|
rxtn->c.out.count = 0;
|
|
rxtn->c.out.index = 0;
|
|
}
|
|
|
|
if (rxtn->cmgrtab_inited)
|
|
{
|
|
hawk_htb_fini (&rxtn->cmgrtab);
|
|
rxtn->cmgrtab_inited = 0;
|
|
}
|
|
}
|
|
|
|
static int build_argcv (hawk_rtx_t* rtx, int argc_id, int argv_id, const hawk_ooch_t* id, hawk_ooch_t* icf[])
|
|
{
|
|
hawk_ooch_t** p;
|
|
hawk_oow_t argc;
|
|
hawk_val_t* v_argc;
|
|
hawk_val_t* v_argv;
|
|
hawk_val_t* v_tmp;
|
|
hawk_ooch_t key[HAWK_SIZEOF(hawk_int_t)*8+2];
|
|
hawk_oow_t key_len;
|
|
|
|
v_argv = hawk_rtx_makemapval(rtx);
|
|
if (v_argv == HAWK_NULL) return -1;
|
|
|
|
hawk_rtx_refupval (rtx, v_argv);
|
|
|
|
/* make ARGV[0] */
|
|
v_tmp = hawk_rtx_makestrvalwithoocstr(rtx, id);
|
|
if (v_tmp == HAWK_NULL)
|
|
{
|
|
hawk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
/* increment reference count of v_tmp in advance as if
|
|
* it has successfully been assigned into ARGV. */
|
|
hawk_rtx_refupval (rtx, v_tmp);
|
|
|
|
key_len = hawk_copy_oocstr(key, HAWK_COUNTOF(key), HAWK_T("0"));
|
|
if (hawk_map_upsert(((hawk_val_map_t*)v_argv)->map, key, key_len, v_tmp, 0) == HAWK_NULL)
|
|
{
|
|
/* if the assignment operation fails, decrements
|
|
* the reference of v_tmp to free it */
|
|
hawk_rtx_refdownval (rtx, v_tmp);
|
|
|
|
/* the values previously assigned into the
|
|
* map will be freeed when v_argv is freed */
|
|
hawk_rtx_refdownval (rtx, v_argv);
|
|
|
|
return -1;
|
|
}
|
|
|
|
if (icf)
|
|
{
|
|
for (argc = 1, p = icf; *p; p++, argc++)
|
|
{
|
|
/* the argument must compose a numeric value if possible */
|
|
/*v_tmp = hawk_rtx_makenstrvalwithoocstr(rtx, *p); */
|
|
v_tmp = hawk_rtx_makenumorstrvalwithoochars(rtx, *p, hawk_count_oocstr(*p));
|
|
if (HAWK_UNLIKELY(!v_tmp))
|
|
{
|
|
hawk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
key_len = hawk_int_to_oocstr(argc, 10, HAWK_NULL, key, HAWK_COUNTOF(key));
|
|
HAWK_ASSERT (key_len != (hawk_oow_t)-1);
|
|
|
|
hawk_rtx_refupval (rtx, v_tmp);
|
|
|
|
if (hawk_map_upsert(((hawk_val_map_t*)v_argv)->map, key, key_len, v_tmp, 0) == HAWK_NULL)
|
|
{
|
|
hawk_rtx_refdownval (rtx, v_tmp);
|
|
hawk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
else argc = 1;
|
|
|
|
v_argc = hawk_rtx_makeintval(rtx, (hawk_int_t)argc);
|
|
if (v_argc == HAWK_NULL)
|
|
{
|
|
hawk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
hawk_rtx_refupval (rtx, v_argc);
|
|
|
|
if (hawk_rtx_setgbl(rtx, argc_id, v_argc) <= -1)
|
|
{
|
|
hawk_rtx_refdownval (rtx, v_argc);
|
|
hawk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
if (hawk_rtx_setgbl(rtx, argv_id, v_argv) <= -1)
|
|
{
|
|
hawk_rtx_refdownval (rtx, v_argc);
|
|
hawk_rtx_refdownval (rtx, v_argv);
|
|
return -1;
|
|
}
|
|
|
|
hawk_rtx_refdownval (rtx, v_argc);
|
|
hawk_rtx_refdownval (rtx, v_argv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* TODO: use wenviron where it's available */
|
|
typedef hawk_bch_t env_char_t;
|
|
#define ENV_CHAR_IS_BCH
|
|
extern char **environ;
|
|
|
|
static int build_environ (hawk_rtx_t* rtx, int gbl_id, env_char_t* envarr[])
|
|
{
|
|
hawk_val_t* v_env;
|
|
hawk_val_t* v_tmp;
|
|
|
|
v_env = hawk_rtx_makemapval(rtx);
|
|
if (v_env == HAWK_NULL) return -1;
|
|
|
|
hawk_rtx_refupval (rtx, v_env);
|
|
|
|
if (envarr)
|
|
{
|
|
env_char_t* eq;
|
|
hawk_ooch_t* kptr, * vptr;
|
|
hawk_oow_t klen, vlen, count;
|
|
|
|
for (count = 0; envarr[count]; count++)
|
|
{
|
|
#if ((defined(ENV_CHAR_IS_BCH) && defined(HAWK_OOCH_IS_BCH)) || \
|
|
(defined(ENV_CHAR_IS_UCH) && defined(HAWK_OOCH_IS_UCH)))
|
|
eq = hawk_find_oochar_in_oocstr(envarr[count], '=');
|
|
if (HAWK_UNLIKELY(!eq || eq == envarr[count])) continue;
|
|
|
|
kptr = envarr[count];
|
|
klen = eq - envarr[count];
|
|
vptr = eq + 1;
|
|
vlen = hawk_count_oocstr(vptr);
|
|
#elif defined(ENV_CHAR_IS_BCH)
|
|
eq = hawk_find_bchar_in_bcstr(envarr[count], '=');
|
|
if (HAWK_UNLIKELY(!eq || eq == envarr[count])) continue;
|
|
|
|
*eq = '\0';
|
|
|
|
/* dupbtoucstr() may fail for invalid encoding. as the environment
|
|
* variaables are not under control, call mbstowcsalldup() instead
|
|
* to go on despite encoding failure */
|
|
|
|
kptr = hawk_rtx_dupbtoucstr(rtx, envarr[count], &klen, 1);
|
|
vptr = hawk_rtx_dupbtoucstr(rtx, eq + 1, &vlen, 1);
|
|
if (HAWK_UNLIKELY(!kptr || !vptr))
|
|
{
|
|
if (kptr) hawk_rtx_freemem (rtx, kptr);
|
|
if (vptr) hawk_rtx_freemem (rtx, vptr);
|
|
hawk_rtx_refdownval (rtx, v_env);
|
|
return -1;
|
|
}
|
|
|
|
*eq = '=';
|
|
#else
|
|
eq = hawk_find_uchar_in_ucstr(envarr[count], '=');
|
|
if (HAWK_UNLIKELY(!eq || eq == envarr[count])) continue;
|
|
|
|
*eq = '\0';
|
|
|
|
kptr = hawk_rtx_duputobcstr(rtx, envarr[count], &klen);
|
|
vptr = hawk_rtx_duputobcstr(rtx, eq + 1, &vlen);
|
|
if (HAWK_UNLIKELY(!kptr || !vptr))
|
|
{
|
|
if (kptr) hawk_rtx_freemem (rtx, kptr);
|
|
if (vptr) hawk_rtx_freeme (rtx, vptr):
|
|
hawk_rtx_refdownval (rtx, v_env);
|
|
return -1;
|
|
}
|
|
|
|
*eq = '=';
|
|
#endif
|
|
|
|
/* the string in ENVIRON should be a numeric value if
|
|
* it can be converted to a number.
|
|
*v_tmp = hawk_rtx_makenstrvalwithoocstr(rtx, vptr);*/
|
|
v_tmp = hawk_rtx_makenumorstrvalwithoochars(rtx, vptr, vlen);
|
|
if (HAWK_UNLIKELY(!v_tmp))
|
|
{
|
|
#if ((defined(ENV_CHAR_IS_BCH) && defined(HAWK_OOCH_IS_BCH)) || \
|
|
(defined(ENV_CHAR_IS_UCH) && defined(HAWK_OOCH_IS_UCH)))
|
|
/* nothing to do */
|
|
#else
|
|
if (vptr) hawk_rtx_freemem (rtx, vptr);
|
|
if (kptr) hawk_rtx_freemem (rtx, kptr);
|
|
#endif
|
|
hawk_rtx_refdownval (rtx, v_env);
|
|
return -1;
|
|
}
|
|
|
|
/* increment reference count of v_tmp in advance as if
|
|
* it has successfully been assigned into ARGV. */
|
|
hawk_rtx_refupval (rtx, v_tmp);
|
|
|
|
if (hawk_map_upsert(((hawk_val_map_t*)v_env)->map, kptr, klen, v_tmp, 0) == HAWK_NULL)
|
|
{
|
|
/* if the assignment operation fails, decrements
|
|
* the reference of v_tmp to free it */
|
|
hawk_rtx_refdownval (rtx, v_tmp);
|
|
|
|
#if ((defined(ENV_CHAR_IS_BCH) && defined(HAWK_OOCH_IS_BCH)) || \
|
|
(defined(ENV_CHAR_IS_UCH) && defined(HAWK_OOCH_IS_UCH)))
|
|
/* nothing to do */
|
|
#else
|
|
if (vptr) hawk_rtx_freemem (rtx, vptr);
|
|
if (kptr) hawk_rtx_freemem (rtx, kptr);
|
|
#endif
|
|
|
|
/* the values previously assigned into the
|
|
* map will be freeed when v_env is freed */
|
|
hawk_rtx_refdownval (rtx, v_env);
|
|
|
|
return -1;
|
|
}
|
|
|
|
#if ((defined(ENV_CHAR_IS_BCH) && defined(HAWK_OOCH_IS_BCH)) || \
|
|
(defined(ENV_CHAR_IS_UCH) && defined(HAWK_OOCH_IS_UCH)))
|
|
/* nothing to do */
|
|
#else
|
|
if (vptr) hawk_rtx_freemem (rtx, vptr);
|
|
if (kptr) hawk_rtx_freemem (rtx, kptr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (hawk_rtx_setgbl(rtx, gbl_id, v_env) == -1)
|
|
{
|
|
hawk_rtx_refdownval (rtx, v_env);
|
|
return -1;
|
|
}
|
|
|
|
hawk_rtx_refdownval (rtx, v_env);
|
|
return 0;
|
|
}
|
|
|
|
static int make_additional_globals (hawk_rtx_t* rtx, xtn_t* xtn, const hawk_ooch_t* id, hawk_ooch_t* icf[])
|
|
{
|
|
if (build_argcv(rtx, xtn->gbl_argc, xtn->gbl_argv, id, icf) <= -1 ||
|
|
build_environ(rtx, xtn->gbl_environ, environ) <= -1) return -1;
|
|
return 0;
|
|
}
|
|
|
|
static hawk_rtx_t* open_rtx_std (
|
|
hawk_t* hawk,
|
|
hawk_oow_t xtnsize,
|
|
const hawk_ooch_t* id,
|
|
hawk_ooch_t* icf[],
|
|
hawk_ooch_t* ocf[],
|
|
hawk_cmgr_t* cmgr)
|
|
{
|
|
hawk_rtx_t* rtx;
|
|
hawk_rio_cbs_t rio;
|
|
rxtn_t* rxtn;
|
|
xtn_t* xtn;
|
|
|
|
xtn = GET_XTN(hawk);
|
|
|
|
rio.pipe = hawk_rio_pipe;
|
|
rio.file = hawk_rio_file;
|
|
rio.console = hawk_rio_console;
|
|
|
|
rtx = hawk_rtx_open(hawk, HAWK_SIZEOF(rxtn_t) + xtnsize, &rio);
|
|
if (HAWK_UNLIKELY(!rtx)) return HAWK_NULL;
|
|
|
|
rtx->_instsize += HAWK_SIZEOF(rxtn_t);
|
|
|
|
rxtn = GET_RXTN(rtx);
|
|
|
|
if (rtx->hawk->opt.trait & HAWK_RIO)
|
|
{
|
|
if (hawk_htb_init(&rxtn->cmgrtab, hawk_getgem(hawk), 256, 70, HAWK_SIZEOF(hawk_ooch_t), 1) <= -1)
|
|
{
|
|
hawk_rtx_close (rtx);
|
|
return HAWK_NULL;
|
|
}
|
|
hawk_htb_setstyle (&rxtn->cmgrtab, hawk_get_htb_style(HAWK_HTB_STYLE_INLINE_COPIERS));
|
|
rxtn->cmgrtab_inited = 1;
|
|
}
|
|
|
|
rxtn->ecb.close = fini_rxtn;
|
|
hawk_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 (hawk_rtx_setofilenamewithoochars(rtx, ocf[0], hawk_count_oocstr(ocf[0])) <= -1)
|
|
{
|
|
hawk_rtx_errortohawk (rtx, hawk);
|
|
hawk_rtx_close (rtx);
|
|
return HAWK_NULL;
|
|
}
|
|
}
|
|
|
|
if (make_additional_globals(rtx, xtn, id, icf) <= -1)
|
|
{
|
|
hawk_rtx_errortohawk (rtx, hawk);
|
|
hawk_rtx_close (rtx);
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
return rtx;
|
|
}
|
|
|
|
hawk_rtx_t* hawk_rtx_openstdwithbcstr (
|
|
hawk_t* hawk,
|
|
hawk_oow_t xtnsize,
|
|
const hawk_bch_t* id,
|
|
hawk_bch_t* icf[],
|
|
hawk_bch_t* ocf[],
|
|
hawk_cmgr_t* cmgr)
|
|
{
|
|
hawk_rtx_t* rtx = HAWK_NULL;
|
|
hawk_oow_t wcslen, i;
|
|
hawk_ooch_t* xid, ** xicf = HAWK_NULL, ** xocf = HAWK_NULL;
|
|
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
xid = hawk_dupbtoucstr(hawk, id, &wcslen, 0);
|
|
if (HAWK_UNLIKELY(!xid)) return HAWK_NULL;
|
|
#else
|
|
xid = (hawk_ooch_t*)id;
|
|
#endif
|
|
|
|
if (icf)
|
|
{
|
|
for (i = 0; icf[i]; i++) ;
|
|
|
|
xicf = (hawk_ooch_t**)hawk_callocmem(hawk, HAWK_SIZEOF(*xicf) * (i + 1));
|
|
if (!xicf) goto done;
|
|
|
|
for (i = 0; icf[i]; i++)
|
|
{
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
xicf[i] = hawk_dupbtoucstr(hawk, icf[i], &wcslen, 0);
|
|
#else
|
|
xicf[i] = hawk_dupbcstr(hawk, icf[i], HAWK_NULL);
|
|
#endif
|
|
if (!xicf[i]) goto done;
|
|
}
|
|
xicf[i] = HAWK_NULL;
|
|
}
|
|
|
|
if (ocf)
|
|
{
|
|
for (i = 0; ocf[i]; i++) ;
|
|
|
|
xocf = (hawk_ooch_t**)hawk_callocmem(hawk, HAWK_SIZEOF(*xocf) * (i + 1));
|
|
if (!xocf) goto done;
|
|
|
|
for (i = 0; ocf[i]; i++)
|
|
{
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
xocf[i] = hawk_dupbtoucstr(hawk, ocf[i], &wcslen, 0);
|
|
#else
|
|
xocf[i] = hawk_dupucstr(hawk, ocf[i], HAWK_NULL);
|
|
#endif
|
|
if (!xocf[i]) goto done;
|
|
}
|
|
xocf[i] = HAWK_NULL;
|
|
}
|
|
|
|
rtx = open_rtx_std(hawk, xtnsize, xid, xicf, xocf, cmgr);
|
|
|
|
done:
|
|
if (!rtx)
|
|
{
|
|
if (xocf)
|
|
{
|
|
for (i = 0; xocf[i]; i++) hawk_freemem (hawk, xocf[i]);
|
|
hawk_freemem (hawk, xocf);
|
|
}
|
|
if (xicf)
|
|
{
|
|
for (i = 0; xicf[i]; i++) hawk_freemem (hawk, xicf[i]);
|
|
hawk_freemem (hawk, xicf);
|
|
}
|
|
}
|
|
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
hawk_freemem (hawk, xid);
|
|
#endif
|
|
|
|
return rtx;
|
|
}
|
|
|
|
hawk_rtx_t* hawk_rtx_openstdwithucstr (
|
|
hawk_t* hawk,
|
|
hawk_oow_t xtnsize,
|
|
const hawk_uch_t* id,
|
|
hawk_uch_t* icf[],
|
|
hawk_uch_t* ocf[],
|
|
hawk_cmgr_t* cmgr)
|
|
{
|
|
hawk_rtx_t* rtx = HAWK_NULL;
|
|
hawk_oow_t mbslen, i;
|
|
hawk_ooch_t* xid, ** xicf = HAWK_NULL, ** xocf = HAWK_NULL;
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
xid = hawk_duputobcstr(hawk, id, &mbslen);
|
|
if (!xid) return HAWK_NULL;
|
|
#else
|
|
xid = (hawk_ooch_t*)id;
|
|
#endif
|
|
|
|
if (icf)
|
|
{
|
|
for (i = 0; icf[i]; i++) ;
|
|
|
|
xicf = (hawk_ooch_t**)hawk_callocmem(hawk, HAWK_SIZEOF(*xicf) * (i + 1));
|
|
if (!xicf) goto done;
|
|
|
|
for (i = 0; icf[i]; i++)
|
|
{
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
xicf[i] = hawk_duputobcstr(hawk, icf[i], &mbslen);
|
|
#else
|
|
xicf[i] = hawk_dupucstr(hawk, icf[i], HAWK_NULL);
|
|
#endif
|
|
if (HAWK_UNLIKELY(!xicf[i])) goto done;
|
|
}
|
|
xicf[i] = HAWK_NULL;
|
|
}
|
|
|
|
if (ocf)
|
|
{
|
|
for (i = 0; ocf[i]; i++) ;
|
|
|
|
xocf = (hawk_ooch_t**)hawk_callocmem(hawk, HAWK_SIZEOF(*xocf) * (i + 1));
|
|
if (!xocf) goto done;
|
|
|
|
for (i = 0; ocf[i]; i++)
|
|
{
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
xocf[i] = hawk_dupbtoucstr(hawk, ocf[i], &mbslen, 0);
|
|
#else
|
|
xocf[i] = hawk_dupucstr(hawk, ocf[i], HAWK_NULL);
|
|
#endif
|
|
if (!xocf[i]) goto done;
|
|
}
|
|
xocf[i] = HAWK_NULL;
|
|
}
|
|
|
|
rtx = open_rtx_std(hawk, xtnsize, xid, xicf, xocf, cmgr);
|
|
|
|
done:
|
|
if (!rtx)
|
|
{
|
|
if (xocf)
|
|
{
|
|
for (i = 0; xocf[i]; i++) hawk_freemem (hawk, xocf[i]);
|
|
hawk_freemem (hawk, xocf);
|
|
}
|
|
if (xicf)
|
|
{
|
|
for (i = 0; xicf[i]; i++) hawk_freemem (hawk, xicf[i]);
|
|
hawk_freemem (hawk, xicf);
|
|
}
|
|
}
|
|
|
|
#if defined(HAWK_OOCH_IS_BCH)
|
|
hawk_freemem (hawk, xid);
|
|
#endif
|
|
|
|
return rtx;
|
|
}
|
|
|
|
static int timeout_code (const hawk_ooch_t* name)
|
|
{
|
|
if (hawk_comp_oocstr(name, HAWK_T("rtimeout"), 1) == 0) return 0;
|
|
if (hawk_comp_oocstr(name, HAWK_T("wtimeout"), 1) == 0) return 1;
|
|
if (hawk_comp_oocstr(name, HAWK_T("ctimeout"), 1) == 0) return 2;
|
|
if (hawk_comp_oocstr(name, HAWK_T("atimeout"), 1) == 0) return 3;
|
|
return -1;
|
|
}
|
|
|
|
static HAWK_INLINE void init_ioattr (ioattr_t* ioattr)
|
|
{
|
|
int i;
|
|
HAWK_MEMSET (ioattr, 0, HAWK_SIZEOF(*ioattr));
|
|
for (i = 0; i < HAWK_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 (hawk_htb_t* tab, const hawk_ooch_t* ptr, hawk_oow_t len)
|
|
{
|
|
hawk_htb_pair_t* pair;
|
|
|
|
pair = hawk_htb_search(tab, ptr, len);
|
|
if (pair) return HAWK_HTB_VPTR(pair);
|
|
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
static ioattr_t* find_or_make_ioattr (hawk_rtx_t* rtx, hawk_htb_t* tab, const hawk_ooch_t* ptr, hawk_oow_t len)
|
|
{
|
|
hawk_htb_pair_t* pair;
|
|
|
|
pair = hawk_htb_search(tab, ptr, len);
|
|
if (pair == HAWK_NULL)
|
|
{
|
|
ioattr_t ioattr;
|
|
|
|
init_ioattr (&ioattr);
|
|
|
|
pair = hawk_htb_insert(tab, (void*)ptr, len, (void*)&ioattr, HAWK_SIZEOF(ioattr));
|
|
if (pair == HAWK_NULL) return HAWK_NULL;
|
|
}
|
|
|
|
return (ioattr_t*)HAWK_HTB_VPTR(pair);
|
|
}
|
|
|
|
static int fnc_setioattr (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
/*hawk_t* hawk = hawk_rtx_gethawk(rtx);*/
|
|
rxtn_t* rxtn;
|
|
hawk_val_t* v[3];
|
|
hawk_ooch_t* ptr[3];
|
|
hawk_oow_t len[3];
|
|
int i, ret = 0, fret = 0;
|
|
int tmout;
|
|
|
|
rxtn = GET_RXTN(rtx);
|
|
HAWK_ASSERT (rxtn->cmgrtab_inited == 1);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
v[i] = hawk_rtx_getarg(rtx, i);
|
|
ptr[i] = hawk_rtx_getvaloocstr(rtx, v[i], &len[i]);
|
|
if (ptr[i] == HAWK_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
|
|
if (hawk_find_oochar(ptr[i], len[i], HAWK_T('\0')))
|
|
{
|
|
fret = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if ((tmout = timeout_code(ptr[1])) >= 0)
|
|
{
|
|
ioattr_t* ioattr;
|
|
|
|
hawk_int_t l;
|
|
hawk_flt_t r;
|
|
int x;
|
|
|
|
/* no error is returned by hawk_rtx_strnum() if the strict option
|
|
* of the second parameter is 0. so i don't check for an error */
|
|
x = hawk_oochars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr[2], len[2], &l, &r);
|
|
if (x == 0) r = (hawk_flt_t)l;
|
|
|
|
ioattr = find_or_make_ioattr(rtx, &rxtn->cmgrtab, ptr[0], len[0]);
|
|
if (ioattr == HAWK_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
|
|
if (x == 0)
|
|
{
|
|
ioattr->tmout[tmout].sec = l;
|
|
ioattr->tmout[tmout].nsec = 0;
|
|
}
|
|
else if (x >= 1)
|
|
{
|
|
hawk_flt_t nsec;
|
|
ioattr->tmout[tmout].sec = (hawk_int_t)r;
|
|
nsec = r - ioattr->tmout[tmout].sec;
|
|
ioattr->tmout[tmout].nsec = HAWK_SEC_TO_NSEC(nsec);
|
|
}
|
|
}
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
else if (hawk_comp_oocstr(ptr[1], HAWK_T("codepage"), 1) == 0 ||
|
|
hawk_comp_oocstr(ptr[1], HAWK_T("encoding"), 1) == 0)
|
|
{
|
|
ioattr_t* ioattr;
|
|
hawk_cmgr_t* cmgr;
|
|
|
|
if (ptr[2][0] == HAWK_T('\0'))
|
|
{
|
|
cmgr = HAWK_NULL;
|
|
}
|
|
else
|
|
{
|
|
cmgr = hawk_get_cmgr_by_name(ptr[2]);
|
|
if (cmgr == HAWK_NULL)
|
|
{
|
|
fret = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
ioattr = find_or_make_ioattr(rtx, &rxtn->cmgrtab, ptr[0], len[0]);
|
|
if (ioattr == HAWK_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
|
|
ioattr->cmgr = cmgr;
|
|
hawk_copy_oocstr (ioattr->cmgr_name, HAWK_COUNTOF(ioattr->cmgr_name), ptr[2]);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* unknown attribute name */
|
|
fret = -1;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
while (i > 0)
|
|
{
|
|
i--;
|
|
hawk_rtx_freevaloocstr (rtx, v[i], ptr[i]);
|
|
}
|
|
|
|
if (ret >= 0)
|
|
{
|
|
v[0] = hawk_rtx_makeintval (rtx, (hawk_int_t)fret);
|
|
if (v[0] == HAWK_NULL) return -1;
|
|
hawk_rtx_setretval (rtx, v[0]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int fnc_getioattr (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
|
|
{
|
|
rxtn_t* rxtn;
|
|
hawk_val_t* v[2];
|
|
hawk_ooch_t* ptr[2];
|
|
hawk_oow_t len[2];
|
|
int i, ret = 0;
|
|
int tmout;
|
|
hawk_val_t* rv = HAWK_NULL;
|
|
|
|
ioattr_t* ioattr;
|
|
ioattr_t ioattr_buf;
|
|
|
|
rxtn = GET_RXTN(rtx);
|
|
HAWK_ASSERT (rxtn->cmgrtab_inited == 1);
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
v[i] = hawk_rtx_getarg (rtx, i);
|
|
ptr[i] = hawk_rtx_getvaloocstr (rtx, v[i], &len[i]);
|
|
if (ptr[i] == HAWK_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
|
|
if (hawk_find_oochar(ptr[i], len[i], HAWK_T('\0'))) goto done;
|
|
}
|
|
|
|
ioattr = get_ioattr(&rxtn->cmgrtab, ptr[0], len[0]);
|
|
if (ioattr == HAWK_NULL)
|
|
{
|
|
init_ioattr (&ioattr_buf);
|
|
ioattr = &ioattr_buf;
|
|
}
|
|
|
|
if ((tmout = timeout_code (ptr[1])) >= 0)
|
|
{
|
|
if (ioattr->tmout[tmout].nsec == 0)
|
|
rv = hawk_rtx_makeintval(rtx, ioattr->tmout[tmout].sec);
|
|
else
|
|
rv = hawk_rtx_makefltval(rtx, (hawk_flt_t)ioattr->tmout[tmout].sec + HAWK_NSEC_TO_SEC((hawk_flt_t)ioattr->tmout[tmout].nsec));
|
|
if (rv == HAWK_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
else if (hawk_comp_oocstr(ptr[1], HAWK_T("codepage"), 1) == 0 ||
|
|
hawk_comp_oocstr(ptr[1], HAWK_T("encoding"), 1) == 0)
|
|
{
|
|
rv = hawk_rtx_makestrvalwithoocstr(rtx, ioattr->cmgr_name);
|
|
if (rv == HAWK_NULL)
|
|
{
|
|
ret = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
/* unknown attribute name */
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
while (i > 0)
|
|
{
|
|
i--;
|
|
hawk_rtx_freevaloocstr (rtx, v[i], ptr[i]);
|
|
}
|
|
|
|
if (ret >= 0)
|
|
{
|
|
if (rv)
|
|
{
|
|
hawk_rtx_refupval (rtx, rv);
|
|
ret = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 2), rv);
|
|
hawk_rtx_refdownval (rtx, rv);
|
|
if (ret >= 0) hawk_rtx_setretval (rtx, HAWK_VAL_ZERO);
|
|
}
|
|
else
|
|
{
|
|
hawk_rtx_setretval (rtx, HAWK_VAL_NEGONE);
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
hawk_cmgr_t* hawk_rtx_getiocmgrstd (hawk_rtx_t* rtx, const hawk_ooch_t* ioname)
|
|
{
|
|
#if defined(HAWK_OOCH_IS_UCH)
|
|
rxtn_t* rxtn = GET_RXTN(rtx);
|
|
ioattr_t* ioattr;
|
|
|
|
HAWK_ASSERT (rxtn->cmgrtab_inited == 1);
|
|
|
|
ioattr = get_ioattr(&rxtn->cmgrtab, ioname, hawk_count_oocstr(ioname));
|
|
if (ioattr) return ioattr->cmgr;
|
|
#endif
|
|
return HAWK_NULL;
|
|
}
|
|
|
|
static int add_globals (hawk_t* hawk)
|
|
{
|
|
xtn_t* xtn = GET_XTN(hawk);
|
|
|
|
xtn->gbl_argc = hawk_addgblwithoocstr(hawk, HAWK_T("ARGC"));
|
|
xtn->gbl_argv = hawk_addgblwithoocstr(hawk, HAWK_T("ARGV"));
|
|
xtn->gbl_environ = hawk_addgblwithoocstr(hawk, HAWK_T("ENVIRON"));
|
|
|
|
return (HAWK_UNLIKELY(xtn->gbl_argc <= -1 || xtn->gbl_argv <= -1 || xtn->gbl_environ <= -1))? -1: 0;
|
|
}
|
|
|
|
struct fnctab_t
|
|
{
|
|
const hawk_ooch_t* name;
|
|
hawk_fnc_spec_t spec;
|
|
};
|
|
|
|
static struct fnctab_t fnctab[] =
|
|
{
|
|
/* additional aliases to module functions */
|
|
{ HAWK_T("rand"), { {1, 0, HAWK_T("math")}, HAWK_NULL, 0 } },
|
|
{ HAWK_T("srand"), { {1, 0, HAWK_T("math")}, HAWK_NULL, 0 } },
|
|
{ HAWK_T("system"), { {1, 0, HAWK_T("sys")}, HAWK_NULL , 0 } },
|
|
|
|
/* additional functions */
|
|
{ HAWK_T("setioattr"), { {3, 3, HAWK_NULL}, fnc_setioattr, HAWK_RIO } },
|
|
{ HAWK_T("getioattr"), { {3, 3, HAWK_T("vvr")}, fnc_getioattr, HAWK_RIO } }
|
|
};
|
|
|
|
static int add_functions (hawk_t* hawk)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < HAWK_COUNTOF(fnctab); i++)
|
|
{
|
|
if (hawk_addfnc (hawk, fnctab[i].name, &fnctab[i].spec) == HAWK_NULL) return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|