Reorganized the directory structure

This commit is contained in:
2022-09-25 09:23:29 +09:00
parent 1bac167e2d
commit 84d1c4c55f
864 changed files with 11 additions and 12 deletions

2455
lib/awk/Awk.cpp Normal file

File diff suppressed because it is too large Load Diff

123
lib/awk/Makefile.am Normal file
View File

@ -0,0 +1,123 @@
AUTOMAKE_OPTIONS = nostdinc
##AM_CFLAGS = $(PTHREAD_CFLAGS)
CPPFLAGS_ALL_COMMON = \
-I$(top_builddir)/include \
-I$(top_srcdir)/include
if ENABLE_STATIC_MODULE
LDFLAGS_ALL_COMMON = -L../awkmod -L../cmn -L../si
else
LDFLAGS_ALL_COMMON = -L. -L../cmn -L../si
endif
##################################################
# MAIN LIBRARY
##################################################
CPPFLAGS_LIB_COMMON = $(CPPFLAGS_ALL_COMMON) $(LTDLINCL)
LDFLAGS_LIB_COMMON = $(LDFLAGS_ALL_COMMON) -version-info 1:0:0 -no-undefined
LIBADD_LIB_COMMON = -lqsecmn -lqsesi $(LIBM)
DEPENDENCIES_LIB_COMMON = ../../lib/cmn/libqsecmn.la ../../lib/si/libqsesi.la
if ENABLE_LIBLTDL
LIBADD_LIB_COMMON += $(LTDL_LIBS)
else
LIBADD_LIB_COMMON += $(DL_LIBS)
endif
if WIN32
# you must adjust the value of DEFAULT_MODPOSTFIX according
# to the first number in -version-info above
CPPFLAGS_LIB_COMMON += -DQSE_AWK_DEFAULT_MODPREFIX=\"libqseawk-\" -DQSE_AWK_DEFAULT_MODPOSTFIX=\"-1\"
else
CPPFLAGS_LIB_COMMON += -DQSE_AWK_DEFAULT_MODPREFIX=\"$(libdir)/libqseawk-\" -DQSE_AWK_DEFAULT_MODPOSTFIX=\"\"
endif
noinst_HEADERS = awk-prv.h err.h rio.h val.h fnc.h misc.h parse.h run.h tree.h std.h
lib_LTLIBRARIES = libqseawk.la
libqseawk_la_SOURCES = awk.c err.c tree.c parse.c run.c rec.c val.c val-imp.h fnc.c imap-imp.h misc.c misc-imp.h rio.c std.c
libqseawk_la_CPPFLAGS = $(CPPFLAGS_LIB_COMMON)
libqseawk_la_LDFLAGS = $(LDFLAGS_LIB_COMMON)
libqseawk_la_LIBADD = $(LIBADD_LIB_COMMON)
libqseawk_la_DEPENDENCIES = $(DEPENDENCIES_LIB_COMMON)
if ENABLE_CXX
libqseawk_la_SOURCES += Awk.cpp StdAwk.cpp
endif
if ENABLE_STATIC_MODULE
##################################################
# STATIC MODULES BUILT INTO MAIN LIBRARY
##################################################
libqseawk_la_SOURCES += \
mod-dir.c mod-dir.h \
mod-math.c mod-math.h \
mod-str.c mod-str.h \
mod-sys.c mod-sys.h
##libqseawk_la_LIBADD +=
if ENABLE_AWKMOD_MPI
libqseawk_la_LIBADD += -lqseawk-mpi
libqseawk_la_DEPENDENCIES += ../awkmod/libqseawk-mpi.la
endif
if ENABLE_AWKMOD_MYSQL
libqseawk_la_LIBADD += -lqseawk-mysql
libqseawk_la_DEPENDENCIES += ../awkmod/libqseawk-mysql.la
endif
if ENABLE_AWKMOD_SED
libqseawk_la_LIBADD += -lqseawk-sed
libqseawk_la_DEPENDENCIES += ../awkmod/libqseawk-sed.la
endif
if ENABLE_AWKMOD_UCI
libqseawk_la_LIBADD += -lqseawk-uci
libqseawk_la_DEPENDENCIES += ../awkmod/libqseawk-uci.la
endif
else
##################################################
# DYNAMIC MODULES
##################################################
CPPFLAGS_MOD_COMMON = $(CPPFLAGS_ALL_COMMON)
LDFLAGS_MOD_COMMON = $(LDFLAGS_ALL_COMMON)
LIBADD_MOD_COMMON = -lqseawk -lqsecmn
DEPENDENCIES_MOD_COMMON = libqseawk.la ../../lib/cmn/libqsecmn.la
modexecdir = $(libdir)
modexec_LTLIBRARIES = libqseawk-dir.la
libqseawk_dir_la_SOURCES = mod-dir.c mod-dir.h
libqseawk_dir_la_CPPFLAGS = $(CPPFLAGS_MOD_COMMON)
libqseawk_dir_la_LDFLAGS = $(LDFLAGS_MOD_COMMON) -L../si
libqseawk_dir_la_LIBADD = $(LIBADD_MOD_COMMON) -lqsesi
libqseawk_dir_la_DEPENDENCIES = $(DEPENDENCIES_MOD_COMMON) ../../lib/si/libqsesi.la
modexec_LTLIBRARIES += libqseawk-math.la
libqseawk_math_la_SOURCES = mod-math.c mod-math.h
libqseawk_math_la_CPPFLAGS = $(CPPFLAGS_MOD_COMMON)
libqseawk_math_la_LDFLAGS = $(LDFLAGS_MOD_COMMON)
libqseawk_math_la_LIBADD = $(LIBADD_MOD_COMMON)
libqseawk_math_la_DEPENDENCIES = $(DEPENDENCIES_MOD_COMMON)
modexec_LTLIBRARIES += libqseawk-str.la
libqseawk_str_la_SOURCES = mod-str.c mod-str.h
libqseawk_str_la_CPPFLAGS = $(CPPFLAGS_MOD_COMMON)
libqseawk_str_la_LDFLAGS = $(LDFLAGS_MOD_COMMON)
libqseawk_str_la_LIBADD = $(LIBADD_MOD_COMMON)
libqseawk_str_la_DEPENDENCIES = $(DEPENDENCIES_MOD_COMMON)
modexec_LTLIBRARIES += libqseawk-sys.la
libqseawk_sys_la_SOURCES = mod-sys.c mod-sys.h
libqseawk_sys_la_CPPFLAGS = $(CPPFLAGS_MOD_COMMON)
libqseawk_sys_la_LDFLAGS = $(LDFLAGS_MOD_COMMON) -L../si
libqseawk_sys_la_LIBADD = $(LIBADD_MOD_COMMON) -lqsesi
libqseawk_sys_la_DEPENDENCIES = $(DEPENDENCIES_MOD_COMMON) ../../lib/si/libqsesi.la
endif

1162
lib/awk/Makefile.in Normal file

File diff suppressed because it is too large Load Diff

1401
lib/awk/StdAwk.cpp Normal file

File diff suppressed because it is too large Load Diff

489
lib/awk/awk-prv.h Normal file
View File

@ -0,0 +1,489 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_AWK_PRV_H_
#define _QSE_LIB_AWK_AWK_PRV_H_
#include "../cmn/mem-prv.h"
#include <qse/cmn/chr.h>
#include <qse/cmn/str.h>
#include <qse/cmn/htb.h>
#include <qse/cmn/arr.h>
#include <qse/cmn/rex.h>
#include <qse/cmn/rbt.h>
typedef struct qse_awk_chain_t qse_awk_chain_t;
typedef struct qse_awk_tree_t qse_awk_tree_t;
#include <qse/awk/awk.h>
#include <qse/cmn/chr.h>
#include "tree.h"
#include "fnc.h"
#include "parse.h"
#include "run.h"
#include "rio.h"
#include "val.h"
#include "err.h"
#include "misc.h"
#define ENABLE_FEATURE_SCACHE
#define FEATURE_SCACHE_NUM_BLOCKS 16
#define FEATURE_SCACHE_BLOCK_UNIT 16
#define FEATURE_SCACHE_BLOCK_SIZE 128
/* [NOTE] the function value support implemented is very limited.
* it supports very primitive way to call a function via a variable.
* only user-defined functions are supported. neither builtin functions
* nor module functions are not supported yet.
* -----------------------------------------------------
* function x(a,b,c) { print a, b, c; }
* BEGIN { q = x; q(1, 2, 3); } # this works
* BEGIN { q[1]=x; q[1](1,2,3); } # this doesn't work. same as q[1] %% (1, 2, 3) or q[1] %% 3
* BEGIN { q[1]=x; y=q[1]; y(1,2,3); } # this works.
* -----------------------------------------------------
* function __printer(a,b,c) { print a, b, c; }
* function show(printer, a,b,c) { printer(a, b, c); }
* BEGIN { show(__printer, 10, 20, 30); } ## passing the function value as an argumnet is ok.
*/
#define ENABLE_FEATURE_FUN_AS_VALUE
#define QSE_AWK_MAX_GBLS 9999
#define QSE_AWK_MAX_LCLS 9999
#define QSE_AWK_MAX_PARAMS 9999
#define QSE_AWK_DFL_RTX_STACK_LIMIT 5120
#define QSE_AWK_MIN_RTX_STACK_LIMIT 512
#if (QSE_SIZEOF_VOID_P <= 4)
# define QSE_AWK_MAX_RTX_STACK_LIMIT ((qse_size_t)1 << (QSE_SIZEOF_VOID_P * 4 + 1))
#else
# define QSE_AWK_MAX_RTX_STACK_LIMIT ((qse_size_t)1 << (QSE_SIZEOF_VOID_P * 4))
#endif
#define QSE_AWK_ALLOC(awk,size) QSE_MMGR_ALLOC(qse_awk_getmmgr(awk),size)
#define QSE_AWK_REALLOC(awk,ptr,size) QSE_MMGR_REALLOC(qse_awk_getmmgr(awk),ptr,size)
#define QSE_AWK_FREE(awk,ptr) QSE_MMGR_FREE(qse_awk_getmmgr(awk),ptr)
#define QSE_AWK_ISUPPER(awk,c) QSE_ISUPPER(c)
#define QSE_AWK_ISLOWER(awk,c) QSE_ISLOWER(c)
#define QSE_AWK_ISALPHA(awk,c) QSE_ISALPHA(c)
#define QSE_AWK_ISDIGIT(awk,c) QSE_ISDIGIT(c)
#define QSE_AWK_ISXDIGIT(awk,c) QSE_ISXDIGIT(c)
#define QSE_AWK_ISALNUM(awk,c) QSE_ISALNUM(c)
#define QSE_AWK_ISSPACE(awk,c) QSE_ISSPACE(c)
#define QSE_AWK_ISPRINT(awk,c) QSE_ISPRINT(c)
#define QSE_AWK_ISGRAPH(awk,c) QSE_ISGRAPH(c)
#define QSE_AWK_ISCNTRL(awk,c) QSE_ISCNTRL(c)
#define QSE_AWK_ISPUNCT(awk,c) QSE_ISPUNCT(c)
#define QSE_AWK_TOUPPER(awk,c) QSE_TOUPPER(c)
#define QSE_AWK_TOLOWER(awk,c) QSE_TOLOWER(c)
#define QSE_AWK_ISMUPPER(awk,c) QSE_ISMUPPER(c)
#define QSE_AWK_ISMLOWER(awk,c) QSE_ISMLOWER(c)
#define QSE_AWK_ISMALPHA(awk,c) QSE_ISMALPHA(c)
#define QSE_AWK_ISMDIGIT(awk,c) QSE_ISMDIGIT(c)
#define QSE_AWK_ISMXDIGIT(awk,c) QSE_ISMXDIGIT(c)
#define QSE_AWK_ISMALNUM(awk,c) QSE_ISMALNUM(c)
#define QSE_AWK_ISMSPACE(awk,c) QSE_ISMSPACE(c)
#define QSE_AWK_ISMPRINT(awk,c) QSE_ISMPRINT(c)
#define QSE_AWK_ISMGRAPH(awk,c) QSE_ISMGRAPH(c)
#define QSE_AWK_ISMCNTRL(awk,c) QSE_ISMCNTRL(c)
#define QSE_AWK_ISMPUNCT(awk,c) QSE_ISMPUNCT(c)
#define QSE_AWK_TOMUPPER(awk,c) QSE_TOMUPPER(c)
#define QSE_AWK_TOMLOWER(awk,c) QSE_TOMLOWER(c)
#define QSE_AWK_ISWUPPER(awk,c) QSE_ISWUPPER(c)
#define QSE_AWK_ISWLOWER(awk,c) QSE_ISWLOWER(c)
#define QSE_AWK_ISWALPHA(awk,c) QSE_ISWALPHA(c)
#define QSE_AWK_ISWDIGIT(awk,c) QSE_ISWDIGIT(c)
#define QSE_AWK_ISWXDIGIT(awk,c) QSE_ISWXDIGIT(c)
#define QSE_AWK_ISWALNUM(awk,c) QSE_ISWALNUM(c)
#define QSE_AWK_ISWSPACE(awk,c) QSE_ISWSPACE(c)
#define QSE_AWK_ISWPRINT(awk,c) QSE_ISWPRINT(c)
#define QSE_AWK_ISWGRAPH(awk,c) QSE_ISWGRAPH(c)
#define QSE_AWK_ISWCNTRL(awk,c) QSE_ISWCNTRL(c)
#define QSE_AWK_ISWPUNCT(awk,c) QSE_ISWPUNCT(c)
#define QSE_AWK_TOWUPPER(awk,c) QSE_TOWUPPER(c)
#define QSE_AWK_TOWLOWER(awk,c) QSE_TOWLOWER(c)
#define QSE_AWK_STRDUP(awk,str) (qse_strdup(str,qse_awk_getmmgr(awk)))
#define QSE_AWK_STRXDUP(awk,str,len) (qse_strxdup(str,len,qse_awk_getmmgr(awk)))
#define QSE_AWK_BYTE_PRINTABLE(x) ((x) <= 0x7F && (x) != '\\' && QSE_ISMPRINT(x))
enum qse_awk_rio_type_t
{
/* rio types available */
QSE_AWK_RIO_PIPE,
QSE_AWK_RIO_FILE,
QSE_AWK_RIO_CONSOLE,
/* reserved for internal use only */
QSE_AWK_RIO_NUM
};
struct qse_awk_tree_t
{
qse_size_t ngbls; /* total number of globals */
qse_size_t ngbls_base; /* number of intrinsic globals */
qse_cstr_t cur_fun;
qse_htb_t* funs; /* awk function map */
qse_awk_nde_t* begin;
qse_awk_nde_t* begin_tail;
qse_awk_nde_t* end;
qse_awk_nde_t* end_tail;
qse_awk_chain_t* chain;
qse_awk_chain_t* chain_tail;
qse_size_t chain_size; /* number of nodes in the chain */
int ok;
};
typedef struct qse_awk_tok_t qse_awk_tok_t;
struct qse_awk_tok_t
{
int type;
qse_str_t* name;
qse_awk_loc_t loc;
};
struct qse_awk_t
{
/* exposed fields via qse_awk_alt_t */
QSE_AWK_HDR;
/* primitive functions */
qse_awk_prm_t prm;
/* options */
struct
{
int trait;
qse_cstr_t mod[2];
qse_cstr_t incldirs;
union
{
qse_size_t a[7];
struct
{
qse_size_t incl;
qse_size_t block_parse;
qse_size_t block_run;
qse_size_t expr_parse;
qse_size_t expr_run;
qse_size_t rex_build;
qse_size_t rex_match;
} s;
} depth;
qse_size_t rtx_stack_limit;
} opt;
/* parse tree */
qse_awk_tree_t tree;
/* temporary information that the parser needs */
struct
{
struct
{
int block;
int loop;
int stmt; /* statement */
} id;
struct
{
qse_size_t block;
qse_size_t loop;
qse_size_t expr; /* expression */
qse_size_t incl;
} depth;
/* current pragma values */
struct
{
int trait;
qse_size_t rtx_stack_limit;
} pragma;
/* function calls */
qse_htb_t* funs;
/* named variables */
qse_htb_t* named;
/* global variables */
qse_arr_t* gbls;
/* local variables */
qse_arr_t* lcls;
/* parameters to a function */
qse_arr_t* params;
/* maximum number of local variables */
qse_size_t nlcls_max;
/* some data to find if an expression is
* enclosed in parentheses or not.
* see parse_primary_lparen() and parse_print() in parse.c
*/
qse_size_t lparen_seq;
qse_size_t lparen_last_closed;
struct
{
qse_uint8_t* ptr;
qse_size_t count;
qse_size_t capa;
} incl_hist;
} parse;
/* source code management */
struct
{
qse_awk_sio_impl_t inf;
qse_awk_sio_impl_t outf;
qse_awk_sio_lxc_t last;
qse_size_t nungots;
qse_awk_sio_lxc_t ungot[5];
qse_awk_sio_arg_t arg; /* for the top level source */
qse_awk_sio_arg_t* inp; /* current input argument. */
} sio;
qse_link_t* sio_names;
/* previous token */
qse_awk_tok_t ptok;
/* current token */
qse_awk_tok_t tok;
/* look-ahead token */
qse_awk_tok_t ntok;
/* intrinsic functions */
struct
{
qse_awk_fnc_t* sys;
qse_htb_t* user;
} fnc;
struct
{
qse_char_t fmt[1024];
} tmp;
/* housekeeping */
qse_awk_errstr_t errstr;
qse_awk_errinf_t errinf;
qse_char_t errmsg_backup[QSE_AWK_ERRINF_MSG_SIZE];
#if defined(QSE_CHAR_IS_MCHAR)
qse_wchar_t werrmsg[QSE_AWK_ERRINF_MSG_SIZE];
#else
qse_mchar_t merrmsg[QSE_AWK_ERRINF_MSG_SIZE * 2];
#endif
int haltall;
qse_awk_ecb_t* ecb;
qse_rbt_t* modtab;
};
struct qse_awk_chain_t
{
qse_awk_nde_t* pattern;
qse_awk_nde_t* action;
qse_awk_chain_t* next;
};
#define RTX_STACK_AT(rtx,n) ((rtx)->stack[(rtx)->stack_base+(n)])
#define RTX_STACK_NARGS(rtx) RTX_STACK_AT(rtx,3)
#define RTX_STACK_ARG(rtx,n) RTX_STACK_AT(rtx,3+1+(n))
#define RTX_STACK_LCL(rtx,n) RTX_STACK_AT(rtx,3+(qse_size_t)RTX_STACK_NARGS(rtx)+1+(n))
#define RTX_STACK_RETVAL(rtx) RTX_STACK_AT(rtx,2)
#define RTX_STACK_GBL(rtx,n) ((rtx)->stack[(n)])
#define RTX_STACK_RETVAL_GBL(rtx) ((rtx)->stack[(rtx)->awk->tree.ngbls+2])
struct qse_awk_rtx_t
{
QSE_AWK_RTX_HDR;
qse_htb_t* named;
void** stack;
qse_size_t stack_top;
qse_size_t stack_base;
qse_size_t stack_limit;
int exit_level;
qse_awk_val_ref_t* rcache[128];
qse_size_t rcache_count;
#ifdef ENABLE_FEATURE_SCACHE
qse_awk_val_str_t* scache
[FEATURE_SCACHE_NUM_BLOCKS][FEATURE_SCACHE_BLOCK_SIZE];
qse_size_t scache_count[FEATURE_SCACHE_NUM_BLOCKS];
#endif
struct
{
qse_awk_val_int_t* ifree;
qse_awk_val_chunk_t* ichunk;
qse_awk_val_flt_t* rfree;
qse_awk_val_chunk_t* rchunk;
} vmgr;
qse_awk_nde_blk_t* active_block;
qse_byte_t* pattern_range_state;
struct
{
qse_char_t buf[1024];
qse_size_t buf_pos;
qse_size_t buf_len;
int eof;
qse_str_t line; /* entire line */
qse_str_t linew; /* line for manipulation, if necessary */
qse_str_t lineg; /* line buffer for getline */
qse_awk_val_t* d0; /* $0 */
qse_size_t maxflds;
qse_size_t nflds; /* NF */
struct
{
const qse_char_t* ptr;
qse_size_t len;
qse_awk_val_t* val; /* $1 .. $NF */
}* flds;
} inrec;
qse_awk_nrflt_t nrflt;
struct
{
void* rs[2];
void* fs[2];
int ignorecase;
int striprecspc;
qse_awk_int_t nr;
qse_awk_int_t fnr;
qse_cstr_t convfmt;
qse_cstr_t ofmt;
qse_cstr_t ofs;
qse_cstr_t ors;
qse_cstr_t subsep;
} gbl;
/* rio chain */
struct
{
qse_awk_rio_impl_t handler[QSE_AWK_RIO_NUM];
qse_awk_rio_arg_t* chain;
} rio;
struct
{
qse_str_t fmt;
qse_str_t out;
struct
{
qse_char_t* ptr;
qse_size_t len; /* length */
qse_size_t inc; /* increment */
} tmp;
} format;
struct
{
qse_mbs_t fmt;
qse_mbs_t out;
struct
{
qse_mchar_t* ptr;
qse_size_t len; /* length */
qse_size_t inc; /* increment */
} tmp;
} formatmbs;
struct
{
qse_size_t block;
qse_size_t expr; /* expression */
} depth;
qse_awk_errinf_t errinf;
qse_char_t errmsg_backup[QSE_AWK_ERRINF_MSG_SIZE];
#if defined(QSE_CHAR_IS_MCHAR)
qse_wchar_t werrmsg[QSE_AWK_ERRINF_MSG_SIZE];
#else
qse_mchar_t merrmsg[QSE_AWK_ERRINF_MSG_SIZE * 2];
#endif
qse_awk_rtx_ecb_t* ecb;
};
typedef struct qse_awk_mod_data_t qse_awk_mod_data_t;
struct qse_awk_mod_data_t
{
void* handle;
qse_awk_mod_t mod;
};
#define QSE_AWK_RTX_INIT_REF_VAL(refval, _id, _adr, _nrefs) \
do { \
(refval)->v_type = QSE_AWK_VAL_REF; \
(refval)->ref = (_nrefs); \
(refval)->stat = 0; \
(refval)->nstr = 0; \
(refval)->fcb = 0; \
(refval)->id = (_id); \
(refval)->adr = (_adr); \
} while(0);
#if defined(__cplusplus)
extern "C" {
#endif
int qse_awk_init (qse_awk_t* awk, qse_mmgr_t* mmgr, const qse_awk_prm_t* prm);
void qse_awk_fini (qse_awk_t* awk);
#if defined(__cplusplus)
}
#endif
#endif

546
lib/awk/awk.c Normal file
View File

@ -0,0 +1,546 @@
/*
* $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 "awk-prv.h"
#include <qse/cmn/mbwc.h>
static void free_fun (qse_htb_t* map, void* vptr, qse_size_t vlen)
{
qse_awk_t* awk = *(qse_awk_t**)QSE_XTN(map);
qse_awk_fun_t* f = (qse_awk_fun_t*)vptr;
/* f->name doesn't have to be freed */
/*qse_awk_freemem (awk, f->name);*/
if (f->argspec) qse_awk_freemem (awk, f->argspec);
qse_awk_clrpt (awk, f->body);
qse_awk_freemem (awk, f);
}
static void free_fnc (qse_htb_t* map, void* vptr, qse_size_t vlen)
{
qse_awk_t* awk = *(qse_awk_t**)QSE_XTN(map);
qse_awk_fnc_t* f = (qse_awk_fnc_t*)vptr;
qse_awk_freemem (awk, f);
}
static int init_token (qse_mmgr_t* mmgr, qse_awk_tok_t* tok)
{
tok->name = qse_str_open (mmgr, 0, 128);
if (tok->name == QSE_NULL) return -1;
tok->type = 0;
tok->loc.file = QSE_NULL;
tok->loc.line = 0;
tok->loc.colm = 0;
return 0;
}
static void fini_token (qse_awk_tok_t* tok)
{
if (tok->name)
{
qse_str_close (tok->name);
tok->name = QSE_NULL;
}
}
static void clear_token (qse_awk_tok_t* tok)
{
if (tok->name) qse_str_clear (tok->name);
tok->type = 0;
tok->loc.file = QSE_NULL;
tok->loc.line = 0;
tok->loc.colm = 0;
}
qse_awk_t* qse_awk_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, const qse_awk_prm_t* prm, qse_awk_errnum_t* errnum)
{
qse_awk_t* awk;
awk = (qse_awk_t*)QSE_MMGR_ALLOC(mmgr, QSE_SIZEOF(qse_awk_t) + xtnsize);
if (awk)
{
int xret;
xret = qse_awk_init(awk, mmgr, prm);
if (xret <= -1)
{
if (errnum) *errnum = qse_awk_geterrnum(awk);
QSE_MMGR_FREE (mmgr, awk);
awk = QSE_NULL;
}
else QSE_MEMSET (QSE_XTN(awk), 0, xtnsize);
}
else if (errnum) *errnum = QSE_AWK_ENOMEM;
return awk;
}
void qse_awk_close (qse_awk_t* awk)
{
qse_awk_fini (awk);
QSE_MMGR_FREE (awk->_mmgr, awk);
}
int qse_awk_init (qse_awk_t* awk, qse_mmgr_t* mmgr, const qse_awk_prm_t* prm)
{
static qse_htb_style_t treefuncbs =
{
{
QSE_HTB_COPIER_INLINE,
QSE_HTB_COPIER_DEFAULT
},
{
QSE_HTB_FREEER_DEFAULT,
free_fun
},
QSE_HTB_COMPER_DEFAULT,
QSE_HTB_KEEPER_DEFAULT,
QSE_HTB_SIZER_DEFAULT,
QSE_HTB_HASHER_DEFAULT
};
static qse_htb_style_t fncusercbs =
{
{
QSE_HTB_COPIER_INLINE,
QSE_HTB_COPIER_DEFAULT
},
{
QSE_HTB_FREEER_DEFAULT,
free_fnc
},
QSE_HTB_COMPER_DEFAULT,
QSE_HTB_KEEPER_DEFAULT,
QSE_HTB_SIZER_DEFAULT,
QSE_HTB_HASHER_DEFAULT
};
/* zero out the object */
QSE_MEMSET (awk, 0, QSE_SIZEOF(*awk));
/* remember the memory manager */
awk->_instsize = QSE_SIZEOF(*awk);
awk->_mmgr = mmgr;
awk->_cmgr = qse_getdflcmgr();
/* initialize error handling fields */
awk->errinf.num = QSE_AWK_ENOERR;
awk->errinf.loc.line = 0;
awk->errinf.loc.colm = 0;
awk->errinf.loc.file = QSE_NULL;
awk->errstr = qse_awk_dflerrstr;
awk->haltall = 0;
/* progagate the primitive functions */
QSE_ASSERT (prm != QSE_NULL);
QSE_ASSERT (prm->math.pow != QSE_NULL);
QSE_ASSERT (prm->math.mod != QSE_NULL);
if (prm == QSE_NULL ||
prm->math.pow == QSE_NULL ||
prm->math.mod == QSE_NULL)
{
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
goto oops;
}
awk->prm = *prm;
if (init_token(mmgr, &awk->ptok) <= -1 ||
init_token(mmgr, &awk->tok) <= -1 ||
init_token(mmgr, &awk->ntok) <= -1)
{
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
goto oops;
}
awk->opt.trait = QSE_AWK_MODERN;
#if defined(__OS2__) || defined(_WIN32) || defined(__DOS__)
awk->opt.trait |= QSE_AWK_CRLF;
#endif
awk->opt.rtx_stack_limit = QSE_AWK_DFL_RTX_STACK_LIMIT;
awk->tree.ngbls = 0;
awk->tree.ngbls_base = 0;
awk->tree.begin = QSE_NULL;
awk->tree.begin_tail = QSE_NULL;
awk->tree.end = QSE_NULL;
awk->tree.end_tail = QSE_NULL;
awk->tree.chain = QSE_NULL;
awk->tree.chain_tail = QSE_NULL;
awk->tree.chain_size = 0;
/* TODO: initial map size?? */
awk->tree.funs = qse_htb_open (mmgr, QSE_SIZEOF(awk), 512, 70, QSE_SIZEOF(qse_char_t), 1);
awk->parse.funs = qse_htb_open (mmgr, QSE_SIZEOF(awk), 256, 70, QSE_SIZEOF(qse_char_t), 1);
awk->parse.named = qse_htb_open (mmgr, QSE_SIZEOF(awk), 256, 70, QSE_SIZEOF(qse_char_t), 1);
awk->parse.gbls = qse_arr_open (mmgr, QSE_SIZEOF(awk), 128);
awk->parse.lcls = qse_arr_open (mmgr, QSE_SIZEOF(awk), 64);
awk->parse.params = qse_arr_open (mmgr, QSE_SIZEOF(awk), 32);
awk->fnc.sys = QSE_NULL;
awk->fnc.user = qse_htb_open (mmgr, QSE_SIZEOF(awk), 512, 70, QSE_SIZEOF(qse_char_t), 1);
awk->modtab = qse_rbt_open (mmgr, 0, QSE_SIZEOF(qse_char_t), 1);
if (awk->tree.funs == QSE_NULL ||
awk->parse.funs == QSE_NULL ||
awk->parse.named == QSE_NULL ||
awk->parse.gbls == QSE_NULL ||
awk->parse.lcls == QSE_NULL ||
awk->parse.params == QSE_NULL ||
awk->fnc.user == QSE_NULL ||
awk->modtab == QSE_NULL)
{
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
goto oops;
}
*(qse_awk_t**)QSE_XTN(awk->tree.funs) = awk;
qse_htb_setstyle (awk->tree.funs, &treefuncbs);
*(qse_awk_t**)QSE_XTN(awk->parse.funs) = awk;
qse_htb_setstyle (awk->parse.funs, qse_gethtbstyle(QSE_HTB_STYLE_INLINE_KEY_COPIER));
*(qse_awk_t**)QSE_XTN(awk->parse.named) = awk;
qse_htb_setstyle (awk->parse.named, qse_gethtbstyle(QSE_HTB_STYLE_INLINE_KEY_COPIER));
*(qse_awk_t**)QSE_XTN(awk->parse.gbls) = awk;
qse_arr_setscale (awk->parse.gbls, QSE_SIZEOF(qse_char_t));
qse_arr_setcopier (awk->parse.gbls, QSE_ARR_COPIER_INLINE);
*(qse_awk_t**)QSE_XTN(awk->parse.lcls) = awk;
qse_arr_setscale (awk->parse.lcls, QSE_SIZEOF(qse_char_t));
qse_arr_setcopier (awk->parse.lcls, QSE_ARR_COPIER_INLINE);
*(qse_awk_t**)QSE_XTN(awk->parse.params) = awk;
qse_arr_setscale (awk->parse.params, QSE_SIZEOF(qse_char_t));
qse_arr_setcopier (awk->parse.params, QSE_ARR_COPIER_INLINE);
*(qse_awk_t**)QSE_XTN(awk->fnc.user) = awk;
qse_htb_setstyle (awk->fnc.user, &fncusercbs);
qse_rbt_setstyle (awk->modtab, qse_getrbtstyle(QSE_RBT_STYLE_INLINE_COPIERS));
if (qse_awk_initgbls (awk) <= -1)
{
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
goto oops;
}
return 0;
oops:
if (awk->modtab) qse_rbt_close (awk->modtab);
if (awk->fnc.user) qse_htb_close (awk->fnc.user);
if (awk->parse.params) qse_arr_close (awk->parse.params);
if (awk->parse.lcls) qse_arr_close (awk->parse.lcls);
if (awk->parse.gbls) qse_arr_close (awk->parse.gbls);
if (awk->parse.named) qse_htb_close (awk->parse.named);
if (awk->parse.funs) qse_htb_close (awk->parse.funs);
if (awk->tree.funs) qse_htb_close (awk->tree.funs);
fini_token (&awk->ntok);
fini_token (&awk->tok);
fini_token (&awk->ptok);
return -1;
}
void qse_awk_fini (qse_awk_t* awk)
{
qse_awk_ecb_t* ecb;
int i;
qse_awk_clear (awk);
/*qse_awk_clrfnc (awk);*/
for (ecb = awk->ecb; ecb; ecb = ecb->next)
if (ecb->close) ecb->close (awk);
qse_rbt_close (awk->modtab);
qse_htb_close (awk->fnc.user);
qse_arr_close (awk->parse.params);
qse_arr_close (awk->parse.lcls);
qse_arr_close (awk->parse.gbls);
qse_htb_close (awk->parse.named);
qse_htb_close (awk->parse.funs);
qse_htb_close (awk->tree.funs);
fini_token (&awk->ntok);
fini_token (&awk->tok);
fini_token (&awk->ptok);
if (awk->parse.incl_hist.ptr) qse_awk_freemem (awk, awk->parse.incl_hist.ptr);
qse_awk_clearsionames (awk);
/* destroy dynamically allocated options */
for (i = 0; i < QSE_COUNTOF(awk->opt.mod); i++)
{
if (awk->opt.mod[i].ptr) qse_awk_freemem (awk, awk->opt.mod[i].ptr);
}
}
static qse_rbt_walk_t unload_module (qse_rbt_t* rbt, qse_rbt_pair_t* pair, void* ctx)
{
qse_awk_t* awk = (qse_awk_t*)ctx;
qse_awk_mod_data_t* md;
md = QSE_RBT_VPTR(pair);
if (md->mod.unload) md->mod.unload (&md->mod, awk);
if (md->handle) awk->prm.modclose (awk, md->handle);
return QSE_RBT_WALK_FORWARD;
}
void qse_awk_clear (qse_awk_t* awk)
{
qse_awk_ecb_t* ecb;
for (ecb = awk->ecb; ecb; ecb = ecb->next)
{
if (ecb->clear) ecb->clear (awk);
}
awk->haltall = 0;
clear_token (&awk->tok);
clear_token (&awk->ntok);
clear_token (&awk->ptok);
/* clear all loaded modules */
qse_rbt_walk (awk->modtab, unload_module, awk);
qse_rbt_clear (awk->modtab);
QSE_ASSERT (QSE_ARR_SIZE(awk->parse.gbls) == awk->tree.ngbls);
/* delete all non-builtin global variables */
qse_arr_delete (
awk->parse.gbls, awk->tree.ngbls_base,
QSE_ARR_SIZE(awk->parse.gbls) - awk->tree.ngbls_base);
qse_arr_clear (awk->parse.lcls);
qse_arr_clear (awk->parse.params);
qse_htb_clear (awk->parse.named);
qse_htb_clear (awk->parse.funs);
awk->parse.nlcls_max = 0;
awk->parse.depth.block = 0;
awk->parse.depth.loop = 0;
awk->parse.depth.expr = 0;
awk->parse.depth.incl = 0;
awk->parse.pragma.trait = (awk->opt.trait & QSE_AWK_IMPLICIT);
awk->parse.pragma.rtx_stack_limit = 0;
awk->parse.incl_hist.count =0;
/* clear parse trees */
/*awk->tree.ngbls_base = 0;
awk->tree.ngbls = 0; */
awk->tree.ngbls = awk->tree.ngbls_base;
awk->tree.cur_fun.ptr = QSE_NULL;
awk->tree.cur_fun.len = 0;
qse_htb_clear (awk->tree.funs);
if (awk->tree.begin)
{
/*QSE_ASSERT (awk->tree.begin->next == QSE_NULL);*/
qse_awk_clrpt (awk, awk->tree.begin);
awk->tree.begin = QSE_NULL;
awk->tree.begin_tail = QSE_NULL;
}
if (awk->tree.end)
{
/*QSE_ASSERT (awk->tree.end->next == QSE_NULL);*/
qse_awk_clrpt (awk, awk->tree.end);
awk->tree.end = QSE_NULL;
awk->tree.end_tail = QSE_NULL;
}
while (awk->tree.chain)
{
qse_awk_chain_t* next = awk->tree.chain->next;
if (awk->tree.chain->pattern != QSE_NULL)
qse_awk_clrpt (awk, awk->tree.chain->pattern);
if (awk->tree.chain->action != QSE_NULL)
qse_awk_clrpt (awk, awk->tree.chain->action);
qse_awk_freemem (awk, awk->tree.chain);
awk->tree.chain = next;
}
awk->tree.chain_tail = QSE_NULL;
awk->tree.chain_size = 0;
/* this table must not be cleared here as there can be a reference
* to an entry of this table from errinf.loc.file when qse_awk_parse()
* failed. this table is cleared in qse_awk_parse().
* qse_awk_claersionames (awk);
*/
}
void qse_awk_getprm (qse_awk_t* awk, qse_awk_prm_t* prm)
{
*prm = awk->prm;
}
void qse_awk_setprm (qse_awk_t* awk, const qse_awk_prm_t* prm)
{
awk->prm = *prm;
}
static int dup_str_opt (qse_awk_t* awk, const void* value, qse_cstr_t* tmp)
{
if (value)
{
tmp->ptr = qse_strdup(value, qse_awk_getmmgr(awk));
if (!tmp->ptr)
{
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
tmp->len = qse_strlen(tmp->ptr);
}
else
{
tmp->ptr = QSE_NULL;
tmp->len = 0;
}
return 0;
}
int qse_awk_setopt (qse_awk_t* awk, qse_awk_opt_t id, const void* value)
{
switch (id)
{
case QSE_AWK_TRAIT:
awk->opt.trait = *(const int*)value;
return 0;
case QSE_AWK_MODPREFIX:
case QSE_AWK_MODPOSTFIX:
{
qse_cstr_t tmp;
int idx;
if (dup_str_opt (awk, value, &tmp) <= -1) return -1;
idx = id - QSE_AWK_MODPREFIX;
if (awk->opt.mod[idx].ptr) qse_awk_freemem (awk, awk->opt.mod[idx].ptr);
awk->opt.mod[idx] = tmp;
return 0;
}
case QSE_AWK_INCLUDEDIRS:
{
qse_cstr_t tmp;
if (dup_str_opt (awk, value, &tmp) <= -1) return -1;
if (awk->opt.incldirs.ptr) qse_awk_freemem (awk, awk->opt.incldirs.ptr);
awk->opt.incldirs = tmp;
return 0;
}
case QSE_AWK_DEPTH_INCLUDE:
case QSE_AWK_DEPTH_BLOCK_PARSE:
case QSE_AWK_DEPTH_BLOCK_RUN:
case QSE_AWK_DEPTH_EXPR_PARSE:
case QSE_AWK_DEPTH_EXPR_RUN:
case QSE_AWK_DEPTH_REX_BUILD:
case QSE_AWK_DEPTH_REX_MATCH:
awk->opt.depth.a[id - QSE_AWK_DEPTH_INCLUDE] = *(const qse_size_t*)value;
return 0;
case QSE_AWK_RTX_STACK_LIMIT:
awk->opt.rtx_stack_limit = *(const qse_size_t*)value;
if (awk->opt.rtx_stack_limit < QSE_AWK_MIN_RTX_STACK_LIMIT) awk->opt.rtx_stack_limit = QSE_AWK_MIN_RTX_STACK_LIMIT;
else if (awk->opt.rtx_stack_limit > QSE_AWK_MAX_RTX_STACK_LIMIT) awk->opt.rtx_stack_limit = QSE_AWK_MAX_RTX_STACK_LIMIT;
return 0;
}
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
return -1;
}
int qse_awk_getopt (qse_awk_t* awk, qse_awk_opt_t id, void* value)
{
switch (id)
{
case QSE_AWK_TRAIT:
*(int*)value = awk->opt.trait;
return 0;
case QSE_AWK_MODPREFIX:
case QSE_AWK_MODPOSTFIX:
*(const qse_char_t**)value = awk->opt.mod[id - QSE_AWK_MODPREFIX].ptr;
return 0;
case QSE_AWK_INCLUDEDIRS:
*(const qse_char_t**)value = awk->opt.incldirs.ptr;
return 0;
case QSE_AWK_DEPTH_INCLUDE:
case QSE_AWK_DEPTH_BLOCK_PARSE:
case QSE_AWK_DEPTH_BLOCK_RUN:
case QSE_AWK_DEPTH_EXPR_PARSE:
case QSE_AWK_DEPTH_EXPR_RUN:
case QSE_AWK_DEPTH_REX_BUILD:
case QSE_AWK_DEPTH_REX_MATCH:
*(qse_size_t*)value = awk->opt.depth.a[id - QSE_AWK_DEPTH_INCLUDE];
return 0;
case QSE_AWK_RTX_STACK_LIMIT:
*(qse_size_t*)value = awk->opt.rtx_stack_limit;
return 0;
};
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
return -1;
}
void qse_awk_haltall (qse_awk_t* awk)
{
awk->haltall = 1;
qse_awk_seterrnum (awk, QSE_AWK_EINVAL, QSE_NULL);
}
qse_awk_ecb_t* qse_awk_popecb (qse_awk_t* awk)
{
qse_awk_ecb_t* top = awk->ecb;
if (top) awk->ecb = top->next;
return top;
}
void qse_awk_pushecb (qse_awk_t* awk, qse_awk_ecb_t* ecb)
{
ecb->next = awk->ecb;
awk->ecb = ecb;
}

71
lib/awk/awk.txt Normal file
View File

@ -0,0 +1,71 @@
Programs
pattern { action }
function name (parameter-list) { statement }
Patterns
BEGIN
END
expresion
/regular expression/
pattern && pattern
pattern || pattern
!pattern
(pattern)
pattern, pattern -> range pattern
Actions
break
continue
delete array-element
do statement while (expression)
exit [expression]
expression
if (expression) statement [else statement]
input-output statement
for (expression; expression; expression) statement
for (variable in array) statement
next
return [expression]
while (expression) statement
{ statements }
Variables
global variables (enabled when awk->opt & QSE_AWK_OPT_VARDCL)
global x;
global x, y;
local variables (enabled when awk->opt & QSE_AWK_OPT_VARDCL)
local x;
local x, y;
function arguments (enabled always)
function funca (x, y)
local variables in function declaration (enabled when awk->opt & QSE_AWK_OPT_FUNCLOCAL)
function funca (x, y, v1, v2)
variables without any declarations (enabled when awk->opt & QSE_AWK_OPT_NAMEDVAR)
x = 10; // x is put into the global hash table.
Optimization
constant folding
2 * 10 => 20
loop
remove while (0) { ... }
if
remove if (0) {}
use else_part only

422
lib/awk/err.c Normal file
View File

@ -0,0 +1,422 @@
/*
* $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 "awk-prv.h"
#include <qse/cmn/mbwc.h>
const qse_char_t* qse_awk_dflerrstr (qse_awk_t* awk, qse_awk_errnum_t errnum)
{
static const qse_char_t* errstr[] =
{
QSE_T("no error"),
QSE_T("other error"),
QSE_T("not implemented"),
QSE_T("subsystem error"),
QSE_T("internal error that should never have happened"),
QSE_T("insufficient memory"),
QSE_T("invalid parameter or data"),
QSE_T("access denied"),
QSE_T("operation not allowed"),
QSE_T("not supported"),
QSE_T("'${0}' not found"),
QSE_T("'${0}' already exists"),
QSE_T("I/O error"),
QSE_T("cannot open '${0}'"),
QSE_T("cannot read '${0}'"),
QSE_T("cannot write '${0}'"),
QSE_T("cannot close '${0}'"),
QSE_T("block nested too deeply"),
QSE_T("expression nested too deeply"),
QSE_T("invalid character '${0}'"),
QSE_T("invalid digit '${0}'"),
QSE_T("unexpected end of input"),
QSE_T("comment not closed properly"),
QSE_T("string or regular expression not closed"),
QSE_T("invalid mbs character '${0}'"),
QSE_T("left brace expected in place of '${0}'"),
QSE_T("left parenthesis expected in place of '${0}'"),
QSE_T("right parenthesis expected in place of '${0}'"),
QSE_T("right bracket expected in place of '${0}'"),
QSE_T("comma expected in place of '${0}'"),
QSE_T("semicolon expected in place of '${0}'"),
QSE_T("colon expected in place of '${0}'"),
QSE_T("integer literal expected in place of '${0}'"),
QSE_T("statement not ending with a semicolon"),
QSE_T("keyword 'in' expected in place of '${0}'"),
QSE_T("right-hand side of 'in' not a variable"),
QSE_T("expression not recognized around '${0}'"),
QSE_T("keyword 'function' expected in place of '${0}'"),
QSE_T("keyword 'while' expected in place of '${0}'"),
QSE_T("invalid assignment statement"),
QSE_T("identifier expected in place of '${0}'"),
QSE_T("'${0}' not a valid function name"),
QSE_T("BEGIN not followed by left bracket on the same line"),
QSE_T("END not followed by left bracket on the same line"),
QSE_T("keyword '${0}' redefined"),
QSE_T("intrinsic function '${0}' redefined"),
QSE_T("function '${0}' redefined"),
QSE_T("global variable '${0}' redefined"),
QSE_T("parameter '${0}' redefined"),
QSE_T("variable '${0}' redefined"),
QSE_T("duplicate parameter name '${0}'"),
QSE_T("duplicate global variable '${0}'"),
QSE_T("duplicate local variable '${0}'"),
QSE_T("'${0}' not a valid parameter name"),
QSE_T("'${0}' not a valid variable name"),
QSE_T("variable name missing"),
QSE_T("undefined identifier '${0}'"),
QSE_T("l-value required"),
QSE_T("too many global variables"),
QSE_T("too many local variables"),
QSE_T("too many parameters"),
QSE_T("too many segments"),
QSE_T("segment '${0}' too long"),
QSE_T("bad argument"),
QSE_T("no argument provided"),
QSE_T("'break' outside a loop"),
QSE_T("'continue' outside a loop"),
QSE_T("'next' illegal in the BEGIN block"),
QSE_T("'next' illegal in the END block"),
QSE_T("'nextfile' illegal in the BEGIN block"),
QSE_T("'nextfile' illegal in the END block"),
QSE_T("both prefix and postfix increment/decrement operator present"),
QSE_T("illegal operand for increment/decrement operator"),
QSE_T("'@include' not followed by a string"),
QSE_T("include level too deep"),
QSE_T("'${0}' not recognized"),
QSE_T("@ not followed by a valid word"),
QSE_T("stack error"),
QSE_T("divide by zero"),
QSE_T("invalid operand"),
QSE_T("wrong position index"),
QSE_T("too few arguments"),
QSE_T("too many arguments"),
QSE_T("function '${0}' not found"),
QSE_T("non-function value in '${0}'"),
QSE_T("'${0}' not deletable"),
QSE_T("value not a map"),
QSE_T("right-hand side of the 'in' operator not a map"),
QSE_T("right-hand side of the 'in' operator not a map nor nil"),
QSE_T("value not referenceable"),
QSE_T("cannot return a map"), /* EMAPRET */
QSE_T("cannot assign a map to a positional"), /* EMAPTOPOS */
QSE_T("cannot assign a map to an indexed variable"),/* EMAPTOIDX */
QSE_T("cannot assign a map to a variable '${0}'"), /* EMAPTONVAR */
QSE_T("cannot change a map to a scalar"), /* EMAPTOSCALAR */
QSE_T("cannot change a scalar to a map"), /* ESCALARTOMAP */
QSE_T("cannot change a map '${0}' to another map"),/* ENMAPTOMAP */
QSE_T("cannot change a map '${0}' to a scalar"), /* ENMAPTOSCALAR */
QSE_T("cannot change a scalar '${0}' to a map"), /* ENSCALARTOMAP */
QSE_T("invalid value to convert to a string"),
QSE_T("invalid value to convert to a number"),
QSE_T("invalid value to a character"),
QSE_T("invalid value for hashing"),
QSE_T("'next' called from BEGIN block"),
QSE_T("'next' called from END block"),
QSE_T("'nextfile' called from BEGIN block"),
QSE_T("'nextfile' called from END block"),
QSE_T("intrinsic function handler for '${0}' failed"),
QSE_T("wrong implementation of user-defined I/O handler"),
QSE_T("I/O handler returned an error"),
QSE_T("no such I/O name found"),
QSE_T("I/O name empty"),
QSE_T("I/O name '${0}' containing '\\0'"),
QSE_T("not sufficient arguments to formatting sequence"),
QSE_T("recursion detected in format conversion"),
QSE_T("invalid character in CONVFMT"),
QSE_T("invalid character in OFMT"),
QSE_T("failed to build regular expression"),
QSE_T("failed to match regular expression"),
QSE_T("recursion too deep in regular expression"),
QSE_T("right parenthesis expected in regular expression"),
QSE_T("right bracket expected in regular expression"),
QSE_T("right brace expected in regular expression"),
QSE_T("colon expected in regular expression"),
QSE_T("invalid character range in regular expression"),
QSE_T("invalid character class in regular expression"),
QSE_T("invalid occurrence bound in regular expression"),
QSE_T("special character at wrong position"),
QSE_T("premature end of regular expression")
};
return (errnum >= 0 && errnum < QSE_COUNTOF(errstr))?
errstr[errnum]: QSE_T("unknown error");
}
qse_awk_errstr_t qse_awk_geterrstr (qse_awk_t* awk)
{
return awk->errstr;
}
void qse_awk_seterrstr (qse_awk_t* awk, qse_awk_errstr_t errstr)
{
awk->errstr = errstr;
}
qse_awk_errnum_t qse_awk_geterrnum (qse_awk_t* awk)
{
return awk->errinf.num;
}
const qse_awk_loc_t* qse_awk_geterrloc (qse_awk_t* awk)
{
return &awk->errinf.loc;
}
const qse_mchar_t* qse_awk_geterrmsgasmbs (qse_awk_t* awk)
{
#if defined(QSE_CHAR_IS_MCHAR)
return (awk->errinf.msg[0] == QSE_T('\0'))?
qse_awk_geterrstr(awk)(awk,awk->errinf.num): awk->errinf.msg;
#else
const qse_char_t* msg;
qse_size_t wcslen, mbslen;
msg = (awk->errinf.msg[0] == QSE_T('\0'))?
qse_awk_geterrstr(awk)(awk,awk->errinf.num): awk->errinf.msg;
mbslen = QSE_COUNTOF(awk->merrmsg);
qse_wcstombswithcmgr(msg, &wcslen, awk->merrmsg, &mbslen, qse_awk_getcmgr(awk));
return awk->merrmsg;
#endif
}
const qse_wchar_t* qse_awk_geterrmsgaswcs (qse_awk_t* awk)
{
#if defined(QSE_CHAR_IS_MCHAR)
const qse_char_t* msg;
qse_size_t wcslen, mbslen;
msg = (awk->errinf.msg[0] == QSE_T('\0'))?
qse_awk_geterrstr(awk)(awk,awk->errinf.num): awk->errinf.msg;
wcslen = QSE_COUNTOF(awk->werrmsg);
qse_mbstowcsallwithcmgr (msg, &mbslen, awk->werrmsg, &wcslen, qse_awk_getcmgr(awk));
return awk->werrmsg;
#else
return (awk->errinf.msg[0] == QSE_T('\0'))?
qse_awk_geterrstr(awk)(awk,awk->errinf.num): awk->errinf.msg;
#endif
}
void qse_awk_geterrinf (qse_awk_t* awk, qse_awk_errinf_t* errinf)
{
QSE_MEMCPY (errinf, &awk->errinf, QSE_SIZEOF(*errinf));
if (errinf->msg[0] == QSE_T('\0'))
{
qse_strxcpy (errinf->msg, QSE_COUNTOF(errinf->msg),
qse_awk_geterrstr(awk)(awk,awk->errinf.num));
}
}
void qse_awk_geterror (qse_awk_t* awk, qse_awk_errnum_t* errnum, const qse_char_t** errmsg, qse_awk_loc_t* errloc)
{
if (errnum) *errnum = awk->errinf.num;
if (errmsg)
{
*errmsg = (awk->errinf.msg[0] == QSE_T('\0'))?
qse_awk_geterrstr(awk)(awk,awk->errinf.num):
awk->errinf.msg;
}
if (errloc) *errloc = awk->errinf.loc;
}
const qse_char_t* qse_awk_backuperrmsg (qse_awk_t* awk)
{
qse_strxcpy (awk->errmsg_backup, QSE_COUNTOF(awk->errmsg_backup), qse_awk_geterrmsg(awk));
return awk->errmsg_backup;
}
void qse_awk_seterrnum (qse_awk_t* awk, qse_awk_errnum_t errnum, const qse_cstr_t* errarg)
{
qse_awk_seterror (awk, errnum, errarg, QSE_NULL);
}
void qse_awk_seterrinf (qse_awk_t* awk, const qse_awk_errinf_t* errinf)
{
QSE_MEMCPY (&awk->errinf, errinf, QSE_SIZEOF(*errinf));
}
void qse_awk_seterrfmt (qse_awk_t* awk, qse_awk_errnum_t errnum, qse_awk_loc_t* errloc, const qse_char_t* errfmt, ...)
{
va_list ap;
QSE_MEMSET (&awk->errinf, 0, QSE_SIZEOF(awk->errinf));
awk->errinf.num = errnum;
va_start (ap, errfmt);
qse_strxvfmt (awk->errinf.msg, QSE_COUNTOF(awk->errinf.msg), errfmt, ap);
va_end (ap);
if (errloc) awk->errinf.loc = *errloc;
}
void qse_awk_seterror (qse_awk_t* awk, qse_awk_errnum_t errnum, const qse_cstr_t* errarg, const qse_awk_loc_t* errloc)
{
const qse_char_t* errfmt;
QSE_MEMSET (&awk->errinf, 0, QSE_SIZEOF(awk->errinf));
awk->errinf.num = errnum;
errfmt = qse_awk_geterrstr(awk)(awk,errnum);
QSE_ASSERT (errfmt != QSE_NULL);
qse_strxfncpy (awk->errinf.msg, QSE_COUNTOF(awk->errinf.msg), errfmt, errarg);
if (errloc != QSE_NULL) awk->errinf.loc = *errloc;
}
qse_awk_errnum_t qse_awk_rtx_geterrnum (qse_awk_rtx_t* rtx)
{
return rtx->errinf.num;
}
const qse_awk_loc_t* qse_awk_rtx_geterrloc (qse_awk_rtx_t* rtx)
{
return &rtx->errinf.loc;
}
const qse_mchar_t* qse_awk_rtx_geterrmsgasmbs (qse_awk_rtx_t* rtx)
{
#if defined(QSE_CHAR_IS_MCHAR)
return (rtx->errinf.msg[0] == QSE_T('\0')) ?
qse_awk_geterrstr(rtx->awk)(rtx->awk,rtx->errinf.num): rtx->errinf.msg;
#else
const qse_char_t* msg;
qse_size_t wcslen, mbslen;
msg = (rtx->errinf.msg[0] == QSE_T('\0')) ?
qse_awk_geterrstr(rtx->awk)(rtx->awk, rtx->errinf.num): rtx->errinf.msg;
mbslen = QSE_COUNTOF(rtx->merrmsg);
qse_wcstombswithcmgr(msg, &wcslen, rtx->merrmsg, &mbslen, qse_awk_rtx_getcmgr(rtx));
return rtx->merrmsg;
#endif
}
const qse_wchar_t* qse_awk_rtx_geterrmsgaswcs (qse_awk_rtx_t* rtx)
{
#if defined(QSE_CHAR_IS_MCHAR)
const qse_char_t* msg;
qse_size_t wcslen, mbslen;
msg = (rtx->errinf.msg[0] == QSE_T('\0')) ?
qse_awk_geterrstr(rtx->awk)(rtx->awk,rtx->errinf.num): rtx->errinf.msg;
wcslen = QSE_COUNTOF(rtx->werrmsg);
qse_mbstowcsallwithcmgr (msg, &mbslen, rtx->werrmsg, &wcslen, qse_awk_rtx_getcmgr(rtx));
return rtx->werrmsg;
#else
return (rtx->errinf.msg[0] == QSE_T('\0')) ?
qse_awk_geterrstr(rtx->awk)(rtx->awk,rtx->errinf.num): rtx->errinf.msg;
#endif
}
void qse_awk_rtx_geterrinf (qse_awk_rtx_t* rtx, qse_awk_errinf_t* errinf)
{
QSE_MEMCPY (errinf, &rtx->errinf, QSE_SIZEOF(*errinf));
if (errinf->msg[0] == QSE_T('\0'))
{
qse_strxcpy (errinf->msg, QSE_COUNTOF(errinf->msg),
qse_awk_geterrstr(rtx->awk)(rtx->awk,rtx->errinf.num));
}
}
void qse_awk_rtx_geterror (
qse_awk_rtx_t* rtx, qse_awk_errnum_t* errnum,
const qse_char_t** errmsg, qse_awk_loc_t* errloc)
{
if (errnum != QSE_NULL) *errnum = rtx->errinf.num;
if (errloc != QSE_NULL) *errloc = rtx->errinf.loc;
if (errmsg != QSE_NULL)
{
*errmsg = (rtx->errinf.msg[0] == QSE_T('\0'))?
qse_awk_geterrstr(rtx->awk)(rtx->awk,rtx->errinf.num): rtx->errinf.msg;
}
}
const qse_char_t* qse_awk_rtx_backuperrmsg (qse_awk_rtx_t* rtx)
{
qse_strxcpy (rtx->errmsg_backup, QSE_COUNTOF(rtx->errmsg_backup), qse_awk_rtx_geterrmsg(rtx));
return rtx->errmsg_backup;
}
void qse_awk_rtx_seterrnum (
qse_awk_rtx_t* rtx, qse_awk_errnum_t errnum, const qse_cstr_t* errarg)
{
qse_awk_rtx_seterror (rtx, errnum, errarg, 0);
}
void qse_awk_rtx_seterrinf (qse_awk_rtx_t* rtx, const qse_awk_errinf_t* errinf)
{
QSE_MEMCPY (&rtx->errinf, errinf, QSE_SIZEOF(*errinf));
}
void qse_awk_rtx_seterrfmt (qse_awk_rtx_t* rtx, qse_awk_errnum_t errnum, const qse_awk_loc_t* errloc, const qse_char_t* errfmt, ...)
{
va_list ap;
QSE_MEMSET (&rtx->errinf, 0, QSE_SIZEOF(rtx->errinf));
rtx->errinf.num = errnum;
va_start (ap, errfmt);
qse_strxvfmt (rtx->errinf.msg, QSE_COUNTOF(rtx->errinf.msg), errfmt, ap);
va_end (ap);
if (errloc) rtx->errinf.loc = *errloc;
}
void qse_awk_rtx_seterror (qse_awk_rtx_t* rtx, qse_awk_errnum_t errnum, const qse_cstr_t* errarg, const qse_awk_loc_t* errloc)
{
const qse_char_t* errfmt;
QSE_MEMSET (&rtx->errinf, 0, QSE_SIZEOF(rtx->errinf));
rtx->errinf.num = errnum;
errfmt = qse_awk_geterrstr(rtx->awk)(rtx->awk,errnum);
QSE_ASSERT (errfmt != QSE_NULL);
qse_strxfncpy (
rtx->errinf.msg, QSE_COUNTOF(rtx->errinf.msg),
errfmt, errarg
);
if (errloc != QSE_NULL) rtx->errinf.loc = *errloc;
}

41
lib/awk/err.h Normal file
View File

@ -0,0 +1,41 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_ERR_H_
#define _QSE_LIB_AWK_ERR_H_
#if defined(__cplusplus)
extern "C" {
#endif
const qse_char_t* qse_awk_dflerrstr (qse_awk_t* awk, qse_awk_errnum_t errnum);
#if defined(__cplusplus)
}
#endif
#endif

1888
lib/awk/fnc.c Normal file

File diff suppressed because it is too large Load Diff

77
lib/awk/fnc.h Normal file
View File

@ -0,0 +1,77 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_FNC_H_
#define _QSE_LIB_AWK_FNC_H_
struct qse_awk_fnc_t
{
struct
{
qse_char_t* ptr;
qse_size_t len;
} name;
int dfl0; /* if set, ($0) is assumed if () is missing.
* this ia mainly for the weird length() function */
qse_awk_fnc_spec_t spec;
const qse_char_t* owner; /* set this to a module name if a built-in function is located in a module */
qse_awk_mod_t* mod; /* set by the engine to a valid pointer if it's associated to a module */
};
#if defined(__cplusplus)
extern "C" {
#endif
qse_awk_fnc_t* qse_awk_findfncwithmcstr (qse_awk_t* awk, const qse_mcstr_t* name);
qse_awk_fnc_t* qse_awk_findfncwithwcstr (qse_awk_t* awk, const qse_wcstr_t* name);
#if defined(QSE_CHAR_IS_MCHAR)
# define qse_awk_findfncwithcstr qse_awk_findfncwithmcstr
#else
# define qse_awk_findfncwithcstr qse_awk_findfncwithwcstr
#endif
/* EXPORT is required for linking on windows as they are referenced by mod-str.c */
QSE_EXPORT int qse_awk_fnc_gsub (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_index (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_length (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_match (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_rindex (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_split (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_sprintf (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_sub (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_substr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_tolower (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
QSE_EXPORT int qse_awk_fnc_toupper (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi);
#if defined(__cplusplus)
}
#endif
#endif

33
lib/awk/generrcode.awk Normal file
View File

@ -0,0 +1,33 @@
#
# generrcode.awk
#
# qseawk -f generrcode.awk awk.h
#
BEGIN {
collect=0;
tab3="\t\t";
tab4="\t\t\t";
}
/^[[:space:]]*enum[[:space:]]+qse_awk_errnum_t[[:space:]]*$/ {
collect=1;
print tab3 "// generated by generrcode.awk";
print tab3 "enum ErrorNumber";
print tab3 "{";
}
collect && /^[[:space:]]*};[[:space:]]*$/ {
print tab3 "};";
print tab3 "// end of enum ErrorNumber";
print "";
collect=0;
}
collect && /^[[:space:]]*QSE_AWK_E[[:alnum:]]+/ {
split ($1, flds, ",");
name=flds[1];
print tab4 "ERR_" substr (name,10,length(name)-9) " = " name ",";
}

33
lib/awk/genoptcode.awk Normal file
View File

@ -0,0 +1,33 @@
#
# genoptcode.awk
#
# qseawk -f generror.awk awk.h
#
BEGIN {
collect=0;
tab3="\t\t";
tab4="\t\t\t";
}
/^[[:space:]]*enum[[:space:]]+qse_awk_option_t[[:space:]]*$/ {
collect=1;
print tab3 "// generated by genoptcode.awk";
print tab3 "enum Option";
print tab3 "{";
}
collect && /^[[:space:]]*};[[:space:]]*$/ {
print tab3 "};";
print tab3 "// end of enum Option";
print "";
collect=0;
}
collect && /^[[:space:]]*QSE_AWK_[[:alnum:]]+/ {
split ($1, flds, ",");
name=flds[1];
print tab4 "OPT_" substr (name,9,length(name)-8) " = " name ",";
}

156
lib/awk/imap-imp.h Normal file
View File

@ -0,0 +1,156 @@
/*
* $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.
*/
/* THIS FILE IS SUPPOSED TO BE INCLUDED BY MODULE SOURCE THAT MAINTAINS MAPPING BETWEEN ID AND DATA */
typedef struct __IMAP_NODE_T __IMAP_NODE_T;
struct __IMAP_NODE_T
{
__IMAP_NODE_T* prev;
__IMAP_NODE_T* next;
int id;
__IMAP_NODE_T_DATA
};
typedef struct __IMAP_LIST_T __IMAP_LIST_T;
struct __IMAP_LIST_T
{
__IMAP_NODE_T* head;
__IMAP_NODE_T* tail;
__IMAP_NODE_T* free;
/* mapping table to map 'id' to 'node' */
struct
{
__IMAP_NODE_T** tab;
int capa;
int high;
} map;
__IMAP_LIST_T_DATA
};
static __IMAP_NODE_T* __MAKE_IMAP_NODE (qse_awk_rtx_t* rtx, __IMAP_LIST_T* list)
{
/* create a new context node and append it to the list tail */
__IMAP_NODE_T* node;
node = QSE_NULL;
if (list->free)
{
node = list->free;
list->free = node->next;
}
else
{
node = qse_awk_rtx_callocmem(rtx, QSE_SIZEOF(*node));
if (!node) goto oops;
if (list->map.high <= list->map.capa)
{
qse_size_t newcapa, inc;
__IMAP_NODE_T** tmp;
inc = QSE_TYPE_MAX(int) - list->map.capa;
if (inc == 0) goto oops; /* too many nodes */
if (inc > 64) inc = 64;
newcapa = (qse_size_t)list->map.capa + inc;
tmp = (__IMAP_NODE_T**)qse_awk_rtx_reallocmem(rtx, list->map.tab, QSE_SIZEOF(*tmp) * newcapa);
if (!tmp) goto oops;
QSE_MEMSET (&tmp[list->map.capa], 0, QSE_SIZEOF(*tmp) * (newcapa - list->map.capa));
list->map.tab = tmp;
list->map.capa = newcapa;
}
node->id = list->map.high;
list->map.high++;
}
QSE_ASSERT (list->map.tab[node->id] == QSE_NULL);
list->map.tab[node->id] = node;
/* append it to the tail */
node->next = QSE_NULL;
node->prev = list->tail;
if (list->tail) list->tail->next = node;
else list->head = node;
list->tail = node;
return node;
oops:
if (node) qse_awk_rtx_freemem (rtx, node);
return QSE_NULL;
}
static void __FREE_IMAP_NODE (qse_awk_rtx_t* rtx, __IMAP_LIST_T* list, __IMAP_NODE_T* node)
{
if (node->prev) node->prev->next = node->next;
if (node->next) node->next->prev = node->prev;
if (list->head == node) list->head = node->next;
if (list->tail == node) list->tail = node->prev;
list->map.tab[node->id] = QSE_NULL;
if (list->map.high == node->id + 1)
{
/* destroy the actual node if the node to be freed has the
* highest id */
qse_awk_rtx_freemem (rtx, node);
list->map.high--;
}
else
{
/* otherwise, chain the node to the free list */
node->next = list->free;
list->free = node;
}
/* however, i destroy the whole free list when all the nodes are
* chanined to the free list */
if (list->head == QSE_NULL)
{
__IMAP_NODE_T* curnode;
while (list->free)
{
curnode = list->free;
list->free = list->free->next;
qse_awk_rtx_freemem (rtx, curnode);
}
qse_awk_rtx_freemem (rtx, list->map.tab);
list->map.high = 0;
list->map.capa = 0;
list->map.tab = QSE_NULL;
}
}

530
lib/awk/misc-imp.h Normal file
View File

@ -0,0 +1,530 @@
/*
* $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.
*/
/* this file is supposed to be included by misc.c */
qse_awk_int_t awk_strxtoint (qse_awk_t* awk, const char_t* str, qse_size_t len, int base, const char_t** endptr)
{
qse_awk_int_t n = 0;
const char_t* p;
const char_t* end;
qse_size_t rem;
int digit, negative = 0;
QSE_ASSERT (base < 37);
p = str;
end = str + len;
if (awk->opt.trait & QSE_AWK_STRIPSTRSPC)
{
/* strip off leading spaces */
while (p < end && AWK_ISSPACE(awk,*p)) p++;
}
/* check for a sign */
while (p < end)
{
if (*p == _T('-'))
{
negative = ~negative;
p++;
}
else if (*p == _T('+')) p++;
else break;
}
/* check for a binary/octal/hexadecimal notation */
rem = end - p;
if (base == 0)
{
if (rem >= 1 && *p == _T('0'))
{
p++;
if (rem == 1) base = 8;
else if (*p == _T('x') || *p == _T('X'))
{
p++; base = 16;
}
else if (*p == _T('b') || *p == _T('B'))
{
p++; base = 2;
}
else base = 8;
}
else base = 10;
}
else if (rem >= 2 && base == 16)
{
if (*p == _T('0') &&
(*(p+1) == _T('x') || *(p+1) == _T('X'))) p += 2;
}
else if (rem >= 2 && base == 2)
{
if (*p == _T('0') &&
(*(p+1) == _T('b') || *(p+1) == _T('B'))) p += 2;
}
/* process the digits */
while (p < end)
{
if (*p >= _T('0') && *p <= _T('9'))
digit = *p - _T('0');
else if (*p >= _T('A') && *p <= _T('Z'))
digit = *p - _T('A') + 10;
else if (*p >= _T('a') && *p <= _T('z'))
digit = *p - _T('a') + 10;
else break;
if (digit >= base) break;
n = n * base + digit;
p++;
}
if (endptr) *endptr = p;
return (negative)? -n: n;
}
/*
* qse_awk_strtoflt is almost a replica of strtod.
*
* strtod.c --
*
* Source code for the "strtod" library procedure.
*
* Copyright (c) 1988-1993 The Regents of the University of California.
* Copyright (c) 1994 Sun Microsystems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
/*
* double(64bits) extended(80-bits) quadruple(128-bits)
* exponent 11 bits 15 bits 15 bits
* fraction 52 bits 63 bits 112 bits
* sign 1 bit 1 bit 1 bit
* integer 1 bit
*/
#define MAX_EXPONENT 511
qse_awk_flt_t awk_strtoflt (qse_awk_t* awk, const char_t* str)
{
/*
* Table giving binary powers of 10. Entry is 10^2^i.
* Used to convert decimal exponents into floating-point numbers.
*/
static qse_awk_flt_t powers_of_10[] =
{
10., 100., 1.0e4, 1.0e8, 1.0e16,
1.0e32, 1.0e64, 1.0e128, 1.0e256
};
qse_awk_flt_t fraction, dbl_exp, * d;
const char_t* p;
cint_t c;
int exp = 0; /* Exponent read from "EX" field */
/*
* Exponent that derives from the fractional part. Under normal
* circumstatnces, it is the negative of the number of digits in F.
* However, if I is very long, the last digits of I get dropped
* (otherwise a long I with a large negative exponent could cause an
* unnecessary overflow on I alone). In this case, frac_exp is
* incremented one for each dropped digit.
*/
int frac_exp;
int mant_size; /* Number of digits in mantissa. */
int dec_pt; /* Number of mantissa digits BEFORE decimal point */
const char_t *pexp; /* Temporarily holds location of exponent in string */
int negative = 0, exp_negative = 0;
p = str;
if (awk->opt.trait & QSE_AWK_STRIPSTRSPC)
{
/* strip off leading spaces */
while (AWK_ISSPACE(awk,*p)) p++;
}
/* check for a sign */
while (*p != _T('\0'))
{
if (*p == _T('-'))
{
negative = ~negative;
p++;
}
else if (*p == _T('+')) p++;
else break;
}
/* Count the number of digits in the mantissa (including the decimal
* point), and also locate the decimal point. */
dec_pt = -1;
for (mant_size = 0; ; mant_size++)
{
c = *p;
if (!AWK_ISDIGIT(awk, c))
{
if ((c != _T('.')) || (dec_pt >= 0)) break;
dec_pt = mant_size;
}
p++;
}
/*
* Now suck up the digits in the mantissa. Use two integers to
* collect 9 digits each (this is faster than using floating-point).
* If the mantissa has more than 18 digits, ignore the extras, since
* they can't affect the value anyway.
*/
pexp = p;
p -= mant_size;
if (dec_pt < 0)
{
dec_pt = mant_size;
}
else
{
mant_size--; /* One of the digits was the point */
}
if (mant_size > 18)
{
frac_exp = dec_pt - 18;
mant_size = 18;
}
else
{
frac_exp = dec_pt - mant_size;
}
if (mant_size == 0)
{
fraction = 0.0;
/*p = str;*/
p = pexp;
goto done;
}
else
{
int frac1, frac2;
frac1 = 0;
for ( ; mant_size > 9; mant_size--)
{
c = *p;
p++;
if (c == _T('.'))
{
c = *p;
p++;
}
frac1 = 10 * frac1 + (c - _T('0'));
}
frac2 = 0;
for (; mant_size > 0; mant_size--) {
c = *p;
p++;
if (c == _T('.'))
{
c = *p;
p++;
}
frac2 = 10*frac2 + (c - _T('0'));
}
fraction = (1.0e9 * frac1) + frac2;
}
/* Skim off the exponent */
p = pexp;
if ((*p == _T('E')) || (*p == _T('e')))
{
p++;
if (*p == _T('-'))
{
exp_negative = 1;
p++;
}
else
{
if (*p == _T('+')) p++;
exp_negative = 0;
}
if (!AWK_ISDIGIT(awk, *p))
{
/* p = pexp; */
/* goto done; */
goto no_exp;
}
while (AWK_ISDIGIT(awk, *p))
{
exp = exp * 10 + (*p - _T('0'));
p++;
}
}
no_exp:
if (exp_negative) exp = frac_exp - exp;
else exp = frac_exp + exp;
/*
* Generate a floating-point number that represents the exponent.
* Do this by processing the exponent one bit at a time to combine
* many powers of 2 of 10. Then combine the exponent with the
* fraction.
*/
if (exp < 0)
{
exp_negative = 1;
exp = -exp;
}
else exp_negative = 0;
if (exp > MAX_EXPONENT) exp = MAX_EXPONENT;
dbl_exp = 1.0;
for (d = powers_of_10; exp != 0; exp >>= 1, d++)
{
if (exp & 01) dbl_exp *= *d;
}
if (exp_negative) fraction /= dbl_exp;
else fraction *= dbl_exp;
done:
return (negative)? -fraction: fraction;
}
qse_awk_flt_t awk_strxtoflt (qse_awk_t* awk, const char_t* str, qse_size_t len, const char_t** endptr)
{
/*
* Table giving binary powers of 10. Entry is 10^2^i.
* Used to convert decimal exponents into floating-point numbers.
*/
static qse_awk_flt_t powers_of_10[] =
{
10., 100., 1.0e4, 1.0e8, 1.0e16,
1.0e32, 1.0e64, 1.0e128, 1.0e256
};
qse_awk_flt_t fraction, dbl_exp, * d;
const char_t* p, * end;
cint_t c;
int exp = 0; /* Exponent read from "EX" field */
/*
* Exponent that derives from the fractional part. Under normal
* circumstatnces, it is the negative of the number of digits in F.
* However, if I is very long, the last digits of I get dropped
* (otherwise a long I with a large negative exponent could cause an
* unnecessary overflow on I alone). In this case, frac_exp is
* incremented one for each dropped digit.
*/
int frac_exp;
int mant_size; /* Number of digits in mantissa. */
int dec_pt; /* Number of mantissa digits BEFORE decimal point */
const char_t *pexp; /* Temporarily holds location of exponent in string */
int negative = 0, exp_negative = 0;
p = str;
end = str + len;
/* Strip off leading blanks and check for a sign */
/*while (AWK_ISSPACE(awk,*p)) p++;*/
/*while (*p != _T('\0')) */
while (p < end)
{
if (*p == _T('-'))
{
negative = ~negative;
p++;
}
else if (*p == _T('+')) p++;
else break;
}
/* Count the number of digits in the mantissa (including the decimal
* point), and also locate the decimal point. */
dec_pt = -1;
/*for (mant_size = 0; ; mant_size++) */
for (mant_size = 0; p < end; mant_size++)
{
c = *p;
if (!AWK_ISDIGIT(awk, c))
{
if (c != _T('.') || dec_pt >= 0) break;
dec_pt = mant_size;
}
p++;
}
/*
* Now suck up the digits in the mantissa. Use two integers to
* collect 9 digits each (this is faster than using floating-point).
* If the mantissa has more than 18 digits, ignore the extras, since
* they can't affect the value anyway.
*/
pexp = p;
p -= mant_size;
if (dec_pt < 0)
{
dec_pt = mant_size;
}
else
{
mant_size--; /* One of the digits was the point */
}
if (mant_size > 18) /* TODO: is 18 correct for qse_awk_flt_t??? */
{
frac_exp = dec_pt - 18;
mant_size = 18;
}
else
{
frac_exp = dec_pt - mant_size;
}
if (mant_size == 0)
{
fraction = 0.0;
/*p = str;*/
p = pexp;
goto done;
}
else
{
int frac1, frac2;
frac1 = 0;
for ( ; mant_size > 9; mant_size--)
{
c = *p;
p++;
if (c == _T('.'))
{
c = *p;
p++;
}
frac1 = 10 * frac1 + (c - _T('0'));
}
frac2 = 0;
for (; mant_size > 0; mant_size--) {
c = *p++;
if (c == _T('.'))
{
c = *p;
p++;
}
frac2 = 10 * frac2 + (c - _T('0'));
}
fraction = (1.0e9 * frac1) + frac2;
}
/* Skim off the exponent */
p = pexp;
if (p < end && (*p == _T('E') || *p == _T('e')))
{
p++;
if (p < end)
{
if (*p == _T('-'))
{
exp_negative = 1;
p++;
}
else
{
if (*p == _T('+')) p++;
exp_negative = 0;
}
}
else exp_negative = 0;
if (!(p < end && AWK_ISDIGIT(awk, *p)))
{
/*p = pexp;*/
/*goto done;*/
goto no_exp;
}
while (p < end && AWK_ISDIGIT(awk, *p))
{
exp = exp * 10 + (*p - _T('0'));
p++;
}
}
no_exp:
if (exp_negative) exp = frac_exp - exp;
else exp = frac_exp + exp;
/*
* Generate a floating-point number that represents the exponent.
* Do this by processing the exponent one bit at a time to combine
* many powers of 2 of 10. Then combine the exponent with the
* fraction.
*/
if (exp < 0)
{
exp_negative = 1;
exp = -exp;
}
else exp_negative = 0;
if (exp > MAX_EXPONENT) exp = MAX_EXPONENT;
dbl_exp = 1.0;
for (d = powers_of_10; exp != 0; exp >>= 1, d++)
{
if (exp & 01) dbl_exp *= *d;
}
if (exp_negative) fraction /= dbl_exp;
else fraction *= dbl_exp;
done:
if (endptr != QSE_NULL) *endptr = p;
return (negative)? -fraction: fraction;
}

1121
lib/awk/misc.c Normal file

File diff suppressed because it is too large Load Diff

100
lib/awk/misc.h Normal file
View File

@ -0,0 +1,100 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_MISC_H_
#define _QSE_LIB_AWK_MISC_H_
#if defined(__cplusplus)
extern "C" {
#endif
qse_char_t* qse_awk_rtx_strtok (
qse_awk_rtx_t* rtx, const qse_char_t* s,
const qse_char_t* delim, qse_cstr_t* tok);
qse_char_t* qse_awk_rtx_strxtok (
qse_awk_rtx_t* rtx, const qse_char_t* s, qse_size_t len,
const qse_char_t* delim, qse_cstr_t* tok);
qse_char_t* qse_awk_rtx_strntok (
qse_awk_rtx_t* rtx, const qse_char_t* s,
const qse_char_t* delim, qse_size_t delim_len, qse_cstr_t* tok);
qse_char_t* qse_awk_rtx_strxntok (
qse_awk_rtx_t* rtx, const qse_char_t* s, qse_size_t len,
const qse_char_t* delim, qse_size_t delim_len, qse_cstr_t* tok);
qse_char_t* qse_awk_rtx_strxntokbyrex (
qse_awk_rtx_t* rtx,
const qse_char_t* str,
qse_size_t len,
const qse_char_t* substr,
qse_size_t sublen,
void* rex,
qse_cstr_t* tok,
qse_awk_errnum_t* errnum
);
qse_char_t* qse_awk_rtx_strxnfld (
qse_awk_rtx_t* rtx,
qse_char_t* str,
qse_size_t len,
qse_char_t fs,
qse_char_t lq,
qse_char_t rq,
qse_char_t ec,
qse_cstr_t* tok
);
int qse_awk_buildrex (
qse_awk_t* awk,
const qse_char_t* ptn,
qse_size_t len,
qse_awk_errnum_t* errnum,
void** code,
void** icode
);
int qse_awk_matchrex (
qse_awk_t* awk, void* code, int icase,
const qse_cstr_t* str, const qse_cstr_t* substr,
qse_cstr_t* match, qse_cstr_t submat[9], qse_awk_errnum_t* errnum
);
void qse_awk_freerex (qse_awk_t* awk, void* code, void* icode);
int qse_awk_rtx_matchrex (
qse_awk_rtx_t* rtx, qse_awk_val_t* val,
const qse_cstr_t* str, const qse_cstr_t* substr,
qse_cstr_t* match, qse_cstr_t submat[9]
);
#if defined(__cplusplus)
}
#endif
#endif

569
lib/awk/mod-dir.c Normal file
View File

@ -0,0 +1,569 @@
/*
* $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.
*/
/*
BEGIN {
x = dir::open ("/etc", dir::SORT); # dir::open ("/etc", 0)
if (x <= -1) {
print "cannot open";
return -1;
}
while (dir::read(x, q) > 0) {
print q;
}
dir::close (x);
}
*/
#include "mod-dir.h"
#include <qse/si/dir.h>
#include <qse/cmn/str.h>
#include <qse/cmn/rbt.h>
#include "../cmn/mem-prv.h"
enum
{
DIR_ENOERR,
DIR_EOTHER,
DIR_ESYSERR,
DIR_ENOMEM,
DIR_EINVAL,
DIR_EACCES,
DIR_EPERM,
DIR_ENOENT,
DIR_EMAPTOSCALAR
};
static int dir_err_to_errnum (qse_dir_errnum_t num)
{
switch (num)
{
case QSE_DIR_ESYSERR:
return DIR_ESYSERR;
case QSE_DIR_ENOMEM:
return DIR_ENOMEM;
case QSE_DIR_EINVAL:
return DIR_EINVAL;
case QSE_DIR_EACCES:
return DIR_EACCES;
case QSE_DIR_EPERM:
return DIR_EPERM;
case QSE_DIR_ENOENT:
return DIR_ENOENT;
default:
return DIR_EOTHER;
}
}
static int awk_err_to_errnum (qse_awk_errnum_t num)
{
switch (num)
{
case QSE_AWK_ESYSERR:
return DIR_ESYSERR;
case QSE_AWK_ENOMEM:
return DIR_ENOMEM;
case QSE_AWK_EINVAL:
return DIR_EINVAL;
case QSE_AWK_EACCES:
return DIR_EACCES;
case QSE_AWK_EPERM:
return DIR_EPERM;
case QSE_AWK_ENOENT:
return DIR_ENOENT;
case QSE_AWK_EMAPTOSCALAR:
return DIR_EMAPTOSCALAR;
default:
return DIR_EOTHER;
}
}
#define __IMAP_NODE_T_DATA qse_dir_t* ctx;
#define __IMAP_LIST_T_DATA int errnum;
#define __IMAP_LIST_T dir_list_t
#define __IMAP_NODE_T dir_node_t
#define __MAKE_IMAP_NODE __new_dir_node
#define __FREE_IMAP_NODE __free_dir_node
#include "imap-imp.h"
static dir_node_t* new_dir_node (qse_awk_rtx_t* rtx, dir_list_t* list, const qse_char_t* path, qse_awk_int_t flags)
{
dir_node_t* node;
qse_dir_errnum_t oe;
node = __new_dir_node(rtx, list);
if (!node)
{
list->errnum = DIR_ENOMEM;
return QSE_NULL;
}
node->ctx = qse_dir_open(qse_awk_rtx_getmmgr(rtx), 0, path, flags, &oe);
if (!node->ctx)
{
list->errnum = dir_err_to_errnum(oe);
__free_dir_node (rtx, list, node);
return QSE_NULL;
}
return node;
}
static void free_dir_node (qse_awk_rtx_t* rtx, dir_list_t* list, dir_node_t* node)
{
if (node->ctx)
{
qse_dir_close(node->ctx);
node->ctx = QSE_NULL;
}
__free_dir_node (rtx, list, node);
}
/* ------------------------------------------------------------------------ */
static int close_byid (qse_awk_rtx_t* rtx, dir_list_t* list, qse_awk_int_t id)
{
if (id >= 0 && id < list->map.high && list->map.tab[id])
{
free_dir_node (rtx, list, list->map.tab[id]);
return 0;
}
else
{
list->errnum = DIR_EINVAL;
return -1;
}
}
static int reset_byid (qse_awk_rtx_t* rtx, dir_list_t* list, qse_awk_int_t id, const qse_char_t* path)
{
if (id >= 0 && id < list->map.high && list->map.tab[id])
{
if (qse_dir_reset(list->map.tab[id]->ctx, path) <= -1)
{
list->errnum = dir_err_to_errnum (qse_dir_geterrnum (list->map.tab[id]->ctx));
return -1;
}
return 0;
}
else
{
list->errnum = DIR_EINVAL;
return -1;
}
}
static int read_byid (qse_awk_rtx_t* rtx, dir_list_t* list, qse_awk_int_t id, qse_awk_val_ref_t* ref)
{
if (id >= 0 && id < list->map.high && list->map.tab[id])
{
int y;
qse_dir_ent_t ent;
qse_awk_val_t* tmp;
y = qse_dir_read(list->map.tab[id]->ctx, &ent);
if (y <= -1)
{
list->errnum = dir_err_to_errnum(qse_dir_geterrnum (list->map.tab[id]->ctx));
return -1;
}
if (y == 0) return 0; /* no more entry */
tmp = qse_awk_rtx_makestrvalwithstr(rtx, ent.name);
if (!tmp)
{
list->errnum = awk_err_to_errnum(qse_awk_rtx_geterrnum (rtx));
return -1;
}
else
{
int n;
qse_awk_rtx_refupval (rtx, tmp);
n = qse_awk_rtx_setrefval (rtx, ref, tmp);
qse_awk_rtx_refdownval (rtx, tmp);
if (n <= -1) return -9999;
}
return 1; /* has entry */
}
else
{
list->errnum = DIR_EINVAL;
return -1;
}
}
/* ------------------------------------------------------------------------ */
static QSE_INLINE dir_list_t* rtx_to_list (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
qse_rbt_pair_t* pair;
pair = qse_rbt_search((qse_rbt_t*)fi->mod->ctx, &rtx, QSE_SIZEOF(rtx));
QSE_ASSERT (pair != QSE_NULL);
return (dir_list_t*)QSE_RBT_VPTR(pair);
}
static int fnc_dir_errno (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
dir_list_t* list;
qse_awk_val_t* retv;
list = rtx_to_list(rtx, fi);
retv = qse_awk_rtx_makeintval (rtx, list->errnum);
if (retv == QSE_NULL) return -1;
qse_awk_rtx_setretval (rtx, retv);
return 0;
}
static qse_char_t* errmsg[] =
{
QSE_T("no error"),
QSE_T("other error"),
QSE_T("system error"),
QSE_T("insufficient memory"),
QSE_T("invalid data"),
QSE_T("access denied"),
QSE_T("operation not permitted"),
QSE_T("no entry"),
QSE_T("cannot change a map to a scalar"),
QSE_T("unknown error")
};
static int fnc_dir_errstr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
dir_list_t* list;
qse_awk_val_t* retv;
qse_awk_int_t errnum;
list = rtx_to_list(rtx, fi);
if (qse_awk_rtx_getnargs(rtx) <= 0 ||
qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg (rtx, 0), &errnum) <= -1)
{
errnum = list->errnum;
}
if (errnum < 0 || errnum >= QSE_COUNTOF(errmsg)) errnum = QSE_COUNTOF(errmsg) - 1;
retv = qse_awk_rtx_makestrvalwithstr(rtx, errmsg[errnum]);
if (retv == QSE_NULL) return -1;
qse_awk_rtx_setretval (rtx, retv);
return 0;
}
static int fnc_dir_open (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
dir_list_t* list;
dir_node_t* node = QSE_NULL;
qse_awk_int_t ret;
qse_char_t* path;
qse_awk_val_t* retv;
qse_awk_val_t* a0;
qse_awk_int_t flags = 0;
list = rtx_to_list(rtx, fi);
a0 = qse_awk_rtx_getarg(rtx, 0);
path = qse_awk_rtx_getvalstr(rtx, a0, QSE_NULL);
if (path)
{
if (qse_awk_rtx_getnargs(rtx) >= 2 &&
qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg(rtx, 1), &flags) <= -1)
{
qse_awk_rtx_freevalstr (rtx, a0, path);
goto oops;
}
node = new_dir_node(rtx, list, path, flags);
if (node) ret = node->id;
else ret = -1;
qse_awk_rtx_freevalstr (rtx, a0, path);
}
else
{
oops:
list->errnum = awk_err_to_errnum(qse_awk_rtx_geterrnum(rtx));
ret = -1;
}
/* ret may not be a statically managed number.
* error checking is required */
retv = qse_awk_rtx_makeintval(rtx, ret);
if (retv == QSE_NULL)
{
if (node) free_dir_node (rtx, list, node);
return -1;
}
qse_awk_rtx_setretval (rtx, retv);
return 0;
}
static int fnc_dir_close (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
dir_list_t* list;
qse_awk_int_t id;
int ret;
list = rtx_to_list(rtx, fi);
ret = qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg(rtx, 0), &id);
if (ret <= -1)
{
list->errnum = awk_err_to_errnum(qse_awk_rtx_geterrnum(rtx));
ret = -1;
}
else
{
ret = close_byid(rtx, list, id);
}
qse_awk_rtx_setretval (rtx, qse_awk_rtx_makeintval(rtx, ret));
return 0;
}
static int fnc_dir_reset (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
dir_list_t* list;
qse_awk_int_t id;
int ret;
qse_char_t* path;
list = rtx_to_list(rtx, fi);
ret = qse_awk_rtx_valtoint (rtx, qse_awk_rtx_getarg (rtx, 0), &id);
if (ret <= -1)
{
list->errnum = awk_err_to_errnum (qse_awk_rtx_geterrnum (rtx));
}
else
{
qse_awk_val_t* a1;
a1 = qse_awk_rtx_getarg (rtx, 1);
path = qse_awk_rtx_getvalstr (rtx, a1, QSE_NULL);
if (path)
{
ret = reset_byid (rtx, list, id, path);
qse_awk_rtx_freevalstr (rtx, a1, path);
}
else
{
list->errnum = awk_err_to_errnum (qse_awk_rtx_geterrnum (rtx));
ret = -1;
}
}
/* no error check for qse_awk_rtx_makeintval() here since ret
* is 0 or -1. it will never fail for those numbers */
qse_awk_rtx_setretval (rtx, qse_awk_rtx_makeintval (rtx, ret));
return 0;
}
static int fnc_dir_read (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
dir_list_t* list;
qse_awk_int_t id;
int ret;
list = rtx_to_list(rtx, fi);
ret = qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg (rtx, 0), &id);
if (ret <= -1)
{
list->errnum = awk_err_to_errnum(qse_awk_rtx_geterrnum (rtx));
}
else
{
ret = read_byid(rtx, list, id, (qse_awk_val_ref_t*)qse_awk_rtx_getarg(rtx, 1));
if (ret == -9999) return -1;
}
/* no error check for qse_awk_rtx_makeintval() here since ret
* is 0, 1, -1. it will never fail for those numbers */
qse_awk_rtx_setretval (rtx, qse_awk_rtx_makeintval(rtx, ret));
return 0;
}
/* ------------------------------------------------------------------------ */
typedef struct fnctab_t fnctab_t;
struct fnctab_t
{
const qse_char_t* name;
qse_awk_mod_sym_fnc_t info;
};
typedef struct inttab_t inttab_t;
struct inttab_t
{
const qse_char_t* name;
qse_awk_mod_sym_int_t info;
};
static fnctab_t fnctab[] =
{
{ QSE_T("close"), { { 1, 1, QSE_NULL }, fnc_dir_close, 0 } },
{ QSE_T("errno"), { { 0, 0, QSE_NULL }, fnc_dir_errno, 0 } },
{ QSE_T("errstr"), { { 0, 1, QSE_NULL }, fnc_dir_errstr, 0 } },
{ QSE_T("open"), { { 1, 2, QSE_NULL }, fnc_dir_open, 0 } },
{ QSE_T("read"), { { 2, 2, QSE_T("vr") }, fnc_dir_read, 0 } },
{ QSE_T("reset"), { { 2, 2, QSE_NULL }, fnc_dir_reset, 0 } },
};
static inttab_t inttab[] =
{
/* keep this table sorted for binary search in query(). */
{ QSE_T("SORT"), { QSE_DIR_SORT } }
};
/* ------------------------------------------------------------------------ */
static int query (qse_awk_mod_t* mod, qse_awk_t* awk, const qse_char_t* name, qse_awk_mod_sym_t* sym)
{
qse_cstr_t ea;
int left, right, mid, n;
left = 0; right = QSE_COUNTOF(fnctab) - 1;
while (left <= right)
{
mid = left + (right - left) / 2;
n = qse_strcmp (fnctab[mid].name, name);
if (n > 0) right = mid - 1;
else if (n < 0) left = mid + 1;
else
{
sym->type = QSE_AWK_MOD_FNC;
sym->u.fnc = fnctab[mid].info;
return 0;
}
}
left = 0; right = QSE_COUNTOF(inttab) - 1;
while (left <= right)
{
mid = left + (right - left) / 2;
n = qse_strcmp (inttab[mid].name, name);
if (n > 0) right = mid - 1;
else if (n < 0) left = mid + 1;
else
{
sym->type = QSE_AWK_MOD_INT;
sym->u.in = inttab[mid].info;
return 0;
}
}
ea.ptr = (qse_char_t*)name;
ea.len = qse_strlen(name);
qse_awk_seterror (awk, QSE_AWK_ENOENT, &ea, QSE_NULL);
return -1;
}
static int init (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx)
{
qse_rbt_t* rbt;
dir_list_t list;
rbt = (qse_rbt_t*)mod->ctx;
QSE_MEMSET (&list, 0, QSE_SIZEOF(list));
if (qse_rbt_insert (rbt, &rtx, QSE_SIZEOF(rtx), &list, QSE_SIZEOF(list)) == QSE_NULL)
{
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
return 0;
}
static void fini (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx)
{
qse_rbt_t* rbt;
qse_rbt_pair_t* pair;
rbt = (qse_rbt_t*)mod->ctx;
/* garbage clean-up */
pair = qse_rbt_search(rbt, &rtx, QSE_SIZEOF(rtx));
if (pair)
{
dir_list_t* list;
dir_node_t* node, * next;
list = QSE_RBT_VPTR(pair);
node = list->head;
while (node)
{
next = node->next;
free_dir_node (rtx, list, node);
node = next;
}
qse_rbt_delete (rbt, &rtx, QSE_SIZEOF(rtx));
}
}
static void unload (qse_awk_mod_t* mod, qse_awk_t* awk)
{
qse_rbt_t* rbt;
rbt = (qse_rbt_t*)mod->ctx;
QSE_ASSERT (QSE_RBT_SIZE(rbt) == 0);
qse_rbt_close (rbt);
}
int qse_awk_mod_dir (qse_awk_mod_t* mod, qse_awk_t* awk)
{
qse_rbt_t* rbt;
mod->query = query;
mod->unload = unload;
mod->init = init;
mod->fini = fini;
rbt = qse_rbt_open(qse_awk_getmmgr(awk), 0, 1, 1);
if (rbt == QSE_NULL)
{
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
qse_rbt_setstyle (rbt, qse_getrbtstyle(QSE_RBT_STYLE_INLINE_COPIERS));
mod->ctx = rbt;
return 0;
}

43
lib/awk/mod-dir.h Normal file
View File

@ -0,0 +1,43 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_MOD_DIR_H_
#define _QSE_LIB_AWK_MOD_DIR_H_
#include <qse/awk/awk.h>
#if defined(__cplusplus)
extern "C" {
#endif
QSE_EXPORT int qse_awk_mod_dir (qse_awk_mod_t* mod, qse_awk_t* awk);
#if defined(__cplusplus)
}
#endif
#endif

730
lib/awk/mod-math.c Normal file
View File

@ -0,0 +1,730 @@
/*
* $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 "mod-math.h"
#include <qse/cmn/str.h>
#include <qse/cmn/chr.h>
#include <qse/cmn/alg.h>
#include <qse/cmn/time.h>
#include "../cmn/mem-prv.h"
#include "fnc.h"
#include <math.h>
#if defined(HAVE_QUADMATH_H)
# include <quadmath.h>
#elif defined(QSE_USE_AWK_FLTMAX) && (QSE_AWK_SIZEOF_FLT_T == 16) && defined(QSE_FLTMAX_REQUIRE_QUADMATH)
# error QUADMATH.H NOT AVAILABLE or NOT COMPILABLE
#endif
#if !defined(QSE_HAVE_CONFIG_H)
# if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
# define HAVE_CEIL
# define HAVE_FLOOR
# if !defined(__WATCOMC__) && !defined(__BORLANDC__)
# define HAVE_ROUND
# endif
# define HAVE_SINH
# define HAVE_COSH
# define HAVE_TANH
# define HAVE_ASIN
# define HAVE_ACOS
# define HAVE_SIN
# define HAVE_COS
# define HAVE_TAN
# define HAVE_ATAN
# define HAVE_ATAN2
# define HAVE_LOG
# define HAVE_LOG10
# define HAVE_EXP
# define HAVE_SQRT
# endif
#endif
typedef struct modctx_t
{
qse_awk_int_t seed;
qse_awk_uint_t prand; /* last random value returned */
} modctx_t;
static int fnc_math_1 (
qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi, qse_awk_math1_t f)
{
qse_size_t nargs;
qse_awk_val_t* a0;
qse_awk_flt_t rv;
qse_awk_val_t* r;
int n;
nargs = qse_awk_rtx_getnargs (rtx);
QSE_ASSERT (nargs == 1);
a0 = qse_awk_rtx_getarg (rtx, 0);
n = qse_awk_rtx_valtoflt (rtx, a0, &rv);
if (n <= -1) return -1;
r = qse_awk_rtx_makefltval (rtx, f (qse_awk_rtx_getawk(rtx), rv));
if (r == QSE_NULL) return -1;
qse_awk_rtx_setretval (rtx, r);
return 0;
}
static int fnc_math_2 (
qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi, qse_awk_math2_t f)
{
qse_size_t nargs;
qse_awk_val_t* a0, * a1;
qse_awk_flt_t rv0, rv1;
qse_awk_val_t* r;
int n;
nargs = qse_awk_rtx_getnargs (rtx);
QSE_ASSERT (nargs == 2);
a0 = qse_awk_rtx_getarg (rtx, 0);
a1 = qse_awk_rtx_getarg (rtx, 1);
n = qse_awk_rtx_valtoflt (rtx, a0, &rv0);
if (n <= -1) return -1;
n = qse_awk_rtx_valtoflt (rtx, a1, &rv1);
if (n <= -1) return -1;
r = qse_awk_rtx_makefltval (rtx, f (qse_awk_rtx_getawk(rtx), rv0, rv1));
if (r == QSE_NULL) return -1;
qse_awk_rtx_setretval (rtx, r);
return 0;
}
static qse_awk_flt_t math_ceil (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_CEILQ)
return ceilq (x);
#elif defined(HAVE_CEILL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return ceill (x);
#elif defined(HAVE_CEIL)
return ceil (x);
#elif defined(HAVE_CEILF)
return ceilf (x);
#else
#error ### no ceil function available ###
#endif
}
static qse_awk_flt_t math_floor (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_FLOORQ)
return floorq (x);
#elif defined(HAVE_FLOORL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return floorl (x);
#elif defined(HAVE_FLOOR)
return floor (x);
#elif defined(HAVE_FLOORF)
return floorf (x);
#else
#error ### no floor function available ###
#endif
}
static qse_awk_flt_t math_round (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_ROUNDQ)
return roundq (x);
#elif defined(HAVE_ROUNDL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return roundl (x);
#elif defined(HAVE_ROUND)
return round (x);
#elif defined(HAVE_ROUNDF)
return roundf (x);
#else
qse_flt_t f, d;
f = math_floor (awk, x);
d = x - f; /* get fraction */
if (d > (qse_awk_flt_t)0.5)
{
/* round up to the nearest */
f = f + (qse_awk_flt_t)1.0;
}
else if (d == (qse_awk_flt_t)0.5)
{
#if 1
/* round half away from zero */
if (x >= 0)
{
f = x + (qse_awk_flt_t)0.5;
}
else
{
f = x - (qse_awk_flt_t)0.5;
}
#else
/* round half to even - C99's rint() does this, i guess. */
d = f - (qse_awk_flt_t)2.0 * math_floor(awk, f * (qse_awk_flt_t)0.5);
if (d == (qse_awk_flt_t)1.0) f = f + (qse_awk_flt_t)1.0;
#endif
}
/* this implementation doesn't keep the signbit for -0.0.
* The signbit() function defined in C99 may get used to
* preserve the sign bit. but this is a fall-back rountine
* for a system without round also defined in C99.
* don't get annoyed by the lost sign bit for the value of 0.0.
*/
return f;
#endif
}
static qse_awk_flt_t math_sinh (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_SINHQ)
return sinhq (x);
#elif defined(HAVE_SINHL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return sinhl (x);
#elif defined(HAVE_SINH)
return sinh (x);
#elif defined(HAVE_SINHF)
return sinhf (x);
#else
#error ### no sinh function available ###
#endif
}
static qse_awk_flt_t math_cosh (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_COSHQ)
return coshq (x);
#elif defined(HAVE_COSHL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return coshl (x);
#elif defined(HAVE_COSH)
return cosh (x);
#elif defined(HAVE_COSHF)
return coshf (x);
#else
#error ### no cosh function available ###
#endif
}
static qse_awk_flt_t math_tanh (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_TANHQ)
return tanhq (x);
#elif defined(HAVE_TANHL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return tanhl (x);
#elif defined(HAVE_TANH)
return tanh (x);
#elif defined(HAVE_TANHF)
return tanhf (x);
#else
#error ### no tanh function available ###
#endif
}
static qse_awk_flt_t math_asin (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_ASINQ)
return asinq (x);
#elif defined(HAVE_ASINL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return asinl (x);
#elif defined(HAVE_ASIN)
return asin (x);
#elif defined(HAVE_ASINF)
return asinf (x);
#else
#error ### no asin function available ###
#endif
}
static qse_awk_flt_t math_acos (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_ACOSQ)
return acosq (x);
#elif defined(HAVE_ACOSL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return acosl (x);
#elif defined(HAVE_ACOS)
return acos (x);
#elif defined(HAVE_ACOSF)
return acosf (x);
#else
#error ### no acos function available ###
#endif
}
/* ----------------------------------------------------------------------- */
static qse_awk_flt_t math_sin (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_SINQ)
return sinq (x);
#elif defined(HAVE_SINL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return sinl (x);
#elif defined(HAVE_SIN)
return sin (x);
#elif defined(HAVE_SINF)
return sinf (x);
#else
#error ### no sin function available ###
#endif
}
static qse_awk_flt_t math_cos (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_COSQ)
return cosq (x);
#elif defined(HAVE_COSL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return cosl (x);
#elif defined(HAVE_COS)
return cos (x);
#elif defined(HAVE_COSF)
return cosf (x);
#else
#error ### no cos function available ###
#endif
}
static qse_awk_flt_t math_tan (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_TANQ)
return tanq (x);
#elif defined(HAVE_TANL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return tanl (x);
#elif defined(HAVE_TAN)
return tan (x);
#elif defined(HAVE_TANF)
return tanf (x);
#else
#error ### no tan function available ###
#endif
}
static qse_awk_flt_t math_atan (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_ATANQ)
return atanq (x);
#elif defined(HAVE_ATANL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return atanl (x);
#elif defined(HAVE_ATAN)
return atan (x);
#elif defined(HAVE_ATANF)
return atanf (x);
#else
#error ### no atan function available ###
#endif
}
static qse_awk_flt_t math_atan2 (qse_awk_t* awk, qse_awk_flt_t x, qse_awk_flt_t y)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_ATAN2Q)
return atan2q (x, y);
#elif defined(HAVE_ATAN2L) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return atan2l (x, y);
#elif defined(HAVE_ATAN2)
return atan2 (x, y);
#elif defined(HAVE_ATAN2F)
return atan2f (x, y);
#else
#error ### no atan2 function available ###
#endif
}
static QSE_INLINE qse_awk_flt_t math_log (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_LOGQ)
return logq (x);
#elif defined(HAVE_LOGL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return logl (x);
#elif defined(HAVE_LOG)
return log (x);
#elif defined(HAVE_LOGF)
return logf (x);
#else
#error ### no log function available ###
#endif
}
static qse_awk_flt_t math_log2 (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_LOG2Q)
return log2q (x);
#elif defined(HAVE_LOG2L) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return log2l (x);
#elif defined(HAVE_LOG2)
return log2 (x);
#elif defined(HAVE_LOG2F)
return log2f (x);
#else
return math_log(awk, x) / math_log(awk, 2.0);
#endif
}
static qse_awk_flt_t math_log10 (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_LOG10Q)
return log10q (x);
#elif defined(HAVE_LOG10L) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return log10l (x);
#elif defined(HAVE_LOG10)
return log10 (x);
#elif defined(HAVE_LOG10F)
return log10f (x);
#else
#error ### no log10 function available ###
#endif
}
static qse_awk_flt_t math_exp (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_EXPQ)
return expq (x);
#elif defined(HAVE_EXPL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return expl (x);
#elif defined(HAVE_EXP)
return exp (x);
#elif defined(HAVE_EXPF)
return expf (x);
#else
#error ### no exp function available ###
#endif
}
static qse_awk_flt_t math_sqrt (qse_awk_t* awk, qse_awk_flt_t x)
{
#if defined(QSE_USE_AWK_FLTMAX) && defined(HAVE_SQRTQ)
return sqrtq (x);
#elif defined(HAVE_SQRTL) && (QSE_SIZEOF_LONG_DOUBLE > QSE_SIZEOF_DOUBLE)
return sqrtl (x);
#elif defined(HAVE_SQRT)
return sqrt (x);
#elif defined(HAVE_SQRTF)
return sqrtf (x);
#else
#error ### no sqrt function available ###
#endif
}
/* ----------------------------------------------------------------------- */
static int fnc_ceil (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_ceil);
}
static int fnc_floor (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_floor);
}
static int fnc_round (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_round);
}
static int fnc_sinh (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_sinh);
}
static int fnc_cosh (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_cosh);
}
static int fnc_tanh (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_tanh);
}
static int fnc_asin (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_asin);
}
static int fnc_acos (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_acos);
}
/* ----------------------------------------------------------------------- */
static int fnc_sin (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_sin);
}
static int fnc_cos (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_cos);
}
static int fnc_tan (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_tan);
}
static int fnc_atan (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_atan);
}
static int fnc_atan2 (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_2 (rtx, fi, math_atan2);
}
static int fnc_log (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_log);
}
static int fnc_log2 (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_log2);
}
static int fnc_log10 (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_log10);
}
static int fnc_exp (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_exp);
}
static int fnc_sqrt (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return fnc_math_1 (rtx, fi, math_sqrt);
}
/* ----------------------------------------------------------------------- */
static int fnc_rand (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
#define RANDV_MAX QSE_TYPE_MAX(qse_awk_int_t)
qse_awk_val_t* r;
qse_awk_int_t randv;
modctx_t* modctx;
modctx = (modctx_t*)fi->mod->ctx;
#if defined(QSE_USE_AWK_INTMAX)
modctx->prand = qse_randxsuintmax (modctx->prand);
#else
modctx->prand = qse_randxsulong (modctx->prand);
#endif
randv = modctx->prand % RANDV_MAX;
r = qse_awk_rtx_makefltval (rtx, (qse_awk_flt_t)randv / RANDV_MAX);
if (r == QSE_NULL) return -1;
qse_awk_rtx_setretval (rtx, r);
return 0;
#undef RANDV_MAX
}
static int fnc_srand (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
qse_size_t nargs;
qse_awk_val_t* a0;
qse_awk_int_t lv;
qse_awk_val_t* r;
int n;
qse_awk_int_t prev;
qse_ntime_t now;
modctx_t* modctx;
modctx = (modctx_t*)fi->mod->ctx;
nargs = qse_awk_rtx_getnargs (rtx);
QSE_ASSERT (nargs == 0 || nargs == 1);
prev = modctx->seed;
if (nargs <= 0)
{
modctx->seed = (qse_gettime (&now) <= -1)?
(modctx->seed * modctx->seed): ((qse_awk_int_t)now.sec + (qse_awk_int_t)now.nsec);
}
else
{
a0 = qse_awk_rtx_getarg (rtx, 0);
n = qse_awk_rtx_valtoint (rtx, a0, &lv);
if (n <= -1) return -1;
modctx->seed = lv;
}
/* i don't care if the seed becomes negative or overflows.
* i just convert the signed value to the unsigned one. */
modctx->prand = (qse_awk_uint_t)(modctx->seed * modctx->seed * modctx->seed);
/* make sure that the actual seeding is not 0 */
if (modctx->prand == 0) modctx->prand++;
r = qse_awk_rtx_makeintval (rtx, prev);
if (r == QSE_NULL) return -1;
qse_awk_rtx_setretval (rtx, r);
return 0;
}
/* ----------------------------------------------------------------------- */
typedef struct fnctab_t fnctab_t;
struct fnctab_t
{
const qse_char_t* name;
qse_awk_mod_sym_fnc_t info;
};
static fnctab_t fnctab[] =
{
/* keep this table sorted for binary search in query(). */
{ QSE_T("acos"), { { 1, 1, QSE_NULL }, fnc_acos, 0 } },
{ QSE_T("asin"), { { 1, 1, QSE_NULL }, fnc_asin, 0 } },
{ QSE_T("atan"), { { 1, 1, QSE_NULL }, fnc_atan, 0 } },
{ QSE_T("atan2"), { { 2, 2, QSE_NULL }, fnc_atan2, 0 } },
{ QSE_T("ceil"), { { 1, 1, QSE_NULL }, fnc_ceil, 0 } },
{ QSE_T("cos"), { { 1, 1, QSE_NULL }, fnc_cos, 0 } },
{ QSE_T("cosh"), { { 1, 1, QSE_NULL }, fnc_cosh, 0 } },
{ QSE_T("exp"), { { 1, 1, QSE_NULL }, fnc_exp, 0 } },
{ QSE_T("floor"), { { 1, 1, QSE_NULL }, fnc_floor, 0 } },
{ QSE_T("log"), { { 1, 1, QSE_NULL }, fnc_log, 0 } },
{ QSE_T("log10"), { { 1, 1, QSE_NULL }, fnc_log10, 0 } },
{ QSE_T("log2"), { { 1, 1, QSE_NULL }, fnc_log2, 0 } },
{ QSE_T("rand"), { { 0, 0, QSE_NULL }, fnc_rand, 0 } },
{ QSE_T("round"), { { 1, 1, QSE_NULL }, fnc_round, 0 } },
{ QSE_T("sin"), { { 1, 1, QSE_NULL }, fnc_sin, 0 } },
{ QSE_T("sinh"), { { 1, 1, QSE_NULL }, fnc_sinh, 0 } },
{ QSE_T("sqrt"), { { 1, 1, QSE_NULL }, fnc_sqrt, 0 } },
{ QSE_T("srand"), { { 0, 1, QSE_NULL }, fnc_srand, 0 } },
{ QSE_T("tan"), { { 1, 1, QSE_NULL }, fnc_tan, 0 } },
{ QSE_T("tanh"), { { 1, 1, QSE_NULL }, fnc_tanh, 0 } }
};
static int query (qse_awk_mod_t* mod, qse_awk_t* awk, const qse_char_t* name, qse_awk_mod_sym_t* sym)
{
qse_cstr_t ea;
int left, right, mid, n;
left = 0; right = QSE_COUNTOF(fnctab) - 1;
while (left <= right)
{
mid = left + (right - left) / 2;
n = qse_strcmp (fnctab[mid].name, name);
if (n > 0) right = mid - 1;
else if (n < 0) left = mid + 1;
else
{
sym->type = QSE_AWK_MOD_FNC;
sym->u.fnc = fnctab[mid].info;
return 0;
}
}
#if 0
left = 0; right = QSE_COUNTOF(inttab) - 1;
while (left <= right)
{
mid = left + (right - left) / 2;
n = qse_strcmp (inttab[mid].name, name);
if (n > 0) right = mid - 1;
else if (n < 0) left = mid + 1;
else
{
sym->type = QSE_AWK_MOD_INT;
sym->u.in = inttab[mid].info;
return 0;
}
}
#endif
ea.ptr = (qse_char_t*)name;
ea.len = qse_strlen(name);
qse_awk_seterror (awk, QSE_AWK_ENOENT, &ea, QSE_NULL);
return -1;
}
/* TODO: proper resource management */
static int init (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx)
{
return 0;
}
static void fini (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx)
{
/* TODO: anything */
}
static void unload (qse_awk_mod_t* mod, qse_awk_t* awk)
{
modctx_t* modctx;
modctx = (modctx_t*)mod->ctx;
qse_awk_freemem (awk, modctx);
}
int qse_awk_mod_math (qse_awk_mod_t* mod, qse_awk_t* awk)
{
modctx_t* modctx;
qse_ntime_t now;
modctx = qse_awk_allocmem (awk, QSE_SIZEOF(*modctx));
if (modctx == QSE_NULL)
{
qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
QSE_MEMSET (modctx, 0, QSE_SIZEOF(*modctx));
modctx->seed = (qse_gettime (&now) <= -1)? 0u: ((qse_awk_int_t)now.sec + (qse_awk_int_t)now.nsec);
/* i don't care if the seed becomes negative or overflows.
* i just convert the signed value to the unsigned one. */
modctx->prand = (qse_awk_uint_t)(modctx->seed * modctx->seed * modctx->seed);
/* make sure that the actual seeding is not 0 */
if (modctx->prand == 0) modctx->prand++;
mod->query = query;
mod->unload = unload;
mod->init = init;
mod->fini = fini;
mod->ctx = modctx;
return 0;
}

43
lib/awk/mod-math.h Normal file
View File

@ -0,0 +1,43 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_MOD_MATH_H_
#define _QSE_LIB_AWK_MOD_MATH_H_
#include <qse/awk/awk.h>
#if defined(__cplusplus)
extern "C" {
#endif
QSE_EXPORT int qse_awk_mod_math (qse_awk_mod_t* mod, qse_awk_t* awk);
#if defined(__cplusplus)
}
#endif
#endif

674
lib/awk/mod-str.c Normal file
View File

@ -0,0 +1,674 @@
/*
* $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 "mod-str.h"
#include <qse/cmn/str.h>
#include <qse/cmn/chr.h>
#include <qse/cmn/mbwc.h>
#include "../cmn/mem-prv.h"
#include "fnc.h"
#include "val.h"
static int fnc_normspace (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
/* normalize spaces
* - trim leading and trailing spaces
* - replace a series of spaces to a single space
*/
qse_awk_val_t* retv;
qse_awk_val_t* a0;
a0 = qse_awk_rtx_getarg(rtx, 0);
if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) == QSE_AWK_VAL_MBS)
{
qse_mchar_t* str0;
qse_size_t len0;
str0 = qse_awk_rtx_valtombsdup(rtx, a0, &len0);
if (!str0) return -1;
len0 = qse_mbsxpac(str0, len0);
retv = qse_awk_rtx_makembsval(rtx, str0, len0);
qse_awk_rtx_freemem (rtx, str0);
}
else
{
qse_char_t* str0;
qse_size_t len0;
str0 = qse_awk_rtx_valtostrdup(rtx, a0, &len0);
if (!str0) return -1;
len0 = qse_strxpac(str0, len0);
retv = qse_awk_rtx_makestrval(rtx, str0, len0);
qse_awk_rtx_freemem (rtx, str0);
}
if (!retv) return -1;
qse_awk_rtx_setretval (rtx, retv);
return 0;
}
static int trim (qse_awk_rtx_t* rtx, int flags)
{
qse_awk_val_t* retv;
qse_awk_val_t* a0;
a0 = qse_awk_rtx_getarg(rtx, 0);
if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) == QSE_AWK_VAL_MBS)
{
qse_mcstr_t path;
qse_mchar_t* npath;
path.ptr = ((qse_awk_val_mbs_t*)a0)->val.ptr;
path.len = ((qse_awk_val_mbs_t*)a0)->val.len;
npath = qse_mbsxtrmx(path.ptr, &path.len, flags);
retv = qse_awk_rtx_makembsval(rtx, npath, path.len);
}
else
{
qse_cstr_t path;
qse_char_t* npath;
path.ptr = qse_awk_rtx_getvalstr(rtx, a0, &path.len);
if (!path.ptr) return -1;
/* because qse_strxtrmx() returns the pointer and the legnth without
* affecting the string given, it's safe to pass the original value.
* qse_awk_rtx_getvalstr() doesn't duplicate the value if it's of
* the string type. */
npath = qse_strxtrmx(path.ptr, &path.len, flags);
retv = qse_awk_rtx_makestrval(rtx, npath, path.len);
qse_awk_rtx_freevalstr (rtx, a0, path.ptr);
}
if (!retv) return -1;
qse_awk_rtx_setretval (rtx, retv);
return 0;
}
#define TRIM_FLAG_PAC_SPACES (1 << 0)
static int fnc_trim (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
if (qse_awk_rtx_getnargs(rtx) >= 2)
{
qse_awk_int_t iv;
if (qse_awk_rtx_valtoint(rtx, qse_awk_rtx_getarg(rtx, 1), &iv) <= -1) return -1;
if (iv & TRIM_FLAG_PAC_SPACES) return fnc_normspace(rtx, fi);
}
return trim(rtx, QSE_STRTRMX_LEFT | QSE_STRTRMX_RIGHT);
}
static int fnc_ltrim (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return trim(rtx, QSE_STRTRMX_LEFT);
}
static int fnc_rtrim (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return trim(rtx, QSE_STRTRMX_RIGHT);
}
static int is_class (qse_awk_rtx_t* rtx, qse_ctype_t ctype)
{
qse_awk_val_t* a0;
int tmp;
a0 = qse_awk_rtx_getarg (rtx, 0);
if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) == QSE_AWK_VAL_MBS)
{
qse_mchar_t* str0;
qse_size_t len0;
str0 = ((qse_awk_val_mbs_t*)a0)->val.ptr;
len0 = ((qse_awk_val_mbs_t*)a0)->val.len;
if (len0 <= 0) tmp = 0;
else
{
tmp = 1;
do
{
len0--;
if (!qse_ismctype(str0[len0], ctype))
{
tmp = 0;
break;
}
}
while (len0 > 0);
}
}
else
{
qse_char_t* str0;
qse_size_t len0;
str0 = qse_awk_rtx_getvalstr(rtx, a0, &len0);
if (!str0) return -1;
if (len0 <= 0) tmp = 0;
else
{
tmp = 1;
do
{
len0--;
if (!qse_isctype(str0[len0], ctype))
{
tmp = 0;
break;
}
}
while (len0 > 0);
}
qse_awk_rtx_freevalstr (rtx, a0, str0);
}
a0 = qse_awk_rtx_makeintval (rtx, tmp);
if (!a0) return -1;
qse_awk_rtx_setretval (rtx, a0);
return 0;
}
static int fnc_isalnum (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_ALNUM);
}
static int fnc_isalpha (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_ALPHA);
}
static int fnc_isblank (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_BLANK);
}
static int fnc_iscntrl (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_CNTRL);
}
static int fnc_isdigit (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_DIGIT);
}
static int fnc_isgraph (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_GRAPH);
}
static int fnc_islower (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_LOWER);
}
static int fnc_isprint (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_PRINT);
}
static int fnc_ispunct (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_PUNCT);
}
static int fnc_isspace (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_SPACE);
}
static int fnc_isupper (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_UPPER);
}
static int fnc_isxdigit (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
return is_class(rtx, QSE_CTYPE_XDIGIT);
}
static int fnc_fromcharcode (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
/* create a string from a series of charcter codes */
qse_awk_val_t* retv;
qse_size_t nargs, i;
qse_chau_t* ptr0; /* to guarantee the unsigned code conversion */
nargs = qse_awk_rtx_getnargs(rtx);
retv = qse_awk_rtx_makestrval(rtx, QSE_NULL, nargs);
if (!retv) return -1;
ptr0 = (qse_chau_t*)((qse_awk_val_str_t*)retv)->val.ptr;
for (i = 0; i < nargs; i++)
{
qse_awk_val_t* a0;
qse_awk_int_t cc;
a0 = qse_awk_rtx_getarg(rtx, i);
if (qse_awk_rtx_valtoint(rtx, a0, &cc) <= -1)
{
qse_awk_rtx_freeval (rtx, retv, 0);
return -1;
}
ptr0[i] = cc;
}
qse_awk_rtx_setretval (rtx, retv);
return 0;
}
static int fnc_tocharcode (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
/* return the numeric value for the first character or the character of the given position.
* you can use sprintf("%c", num_val) or str::fromcharcode(num_val) for reverse conversion. */
qse_awk_val_t* retv;
qse_awk_val_t* a0;
qse_awk_int_t iv = -1;
qse_awk_int_t pos = 0;
a0 = qse_awk_rtx_getarg(rtx, 0);
if (qse_awk_rtx_getnargs(rtx) >= 2)
{
/* optional index. must be between 1 and the string length inclusive */
qse_awk_val_t* a1;
a1 = qse_awk_rtx_getarg(rtx, 1);
if (qse_awk_rtx_valtoint(rtx, a1, &pos) <= -1) return -1;
pos--; /* 1 based indexing. range check to be done before accessing below */
}
if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) == QSE_AWK_VAL_MBS)
{
qse_mchar_t* str0;
qse_size_t len0;
str0 = ((qse_awk_val_mbs_t*)a0)->val.ptr;
len0 = ((qse_awk_val_mbs_t*)a0)->val.len;
if (pos >= 0 && pos < len0)
{
#if defined(QSE_CHAR_IS_MCHAR)
/* typecasting in case qse_mchar_t is signed */
iv = (unsigned char)str0[pos];
#else
iv = str0[pos];
#endif
}
}
else
{
qse_char_t* str0;
qse_size_t len0;
str0 = qse_awk_rtx_getvalstr(rtx, a0, &len0);
if (!str0) return -1;
if (pos >= 0 && pos < len0)
{
#if defined(QSE_CHAR_IS_MCHAR)
/* typecasting in case qse_mchar_t is signed */
iv = (unsigned char)str0[pos];
#else
iv = str0[pos];
#endif
}
qse_awk_rtx_freevalstr(rtx, a0, str0);
}
if (iv >= 0)
{
retv = qse_awk_rtx_makeintval(rtx, iv);
if (!retv) return -1;
qse_awk_rtx_setretval (rtx, retv);
}
return 0;
}
static int fnc_frommbs (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
/* str::frommbs(B"byte-string" [, "encoding-name"])
*
* if you use a supported encoding name, it may look like this:
* a = str::frommbs(B"\xC7\xD1\xB1\xDB", "cp949");
* printf ("%K\n", a);
*/
qse_awk_val_t* a0, * r;
qse_cmgr_t* cmgr = qse_awk_rtx_getcmgr(rtx);
if (qse_awk_rtx_getnargs(rtx) >= 2)
{
qse_awk_val_t* a1;
qse_cstr_t enc;
a1 = qse_awk_rtx_getarg(rtx, 1);
enc.ptr = qse_awk_rtx_getvalstr(rtx, a1, &enc.len);
if (!enc.ptr) return -1;
/* if encoding name is an empty string, qse_Findcmgr() returns the default cmgr.
* i don't want that behavior. */
cmgr = (enc.len > 0 && enc.len == qse_strlen(enc.ptr))? qse_findcmgr(enc.ptr): QSE_NULL;
qse_awk_rtx_freevalstr (rtx, a1, enc.ptr);
if (!cmgr)
{
/* if the encoding name is not known, return a zero-length string */
r = qse_awk_rtx_makestrval(rtx, QSE_NULL, 0); /* this never fails for length 0 */
goto done;
}
}
a0 = qse_awk_rtx_getarg(rtx, 0);
switch (QSE_AWK_RTX_GETVALTYPE(rtx, a0))
{
case QSE_AWK_VAL_STR:
r = a0;
break;
default:
{
qse_cstr_t str;
str.ptr = qse_awk_rtx_getvalstrwithcmgr(rtx, a0, &str.len, cmgr);
if (!str.ptr) return -1;
r = qse_awk_rtx_makestrvalwithcstr(rtx, &str);
qse_awk_rtx_freevalstr (rtx, a0, str.ptr);
if (!r) return -1;
break;
}
}
done:
qse_awk_rtx_setretval (rtx, r);
return 0;
}
static int fnc_tombs (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
/* str::tombs("string", [, "encoding-name"])
*
* if you use a supported encoding name, it may look like this:
* a = str::tombs("\uD55C\uAE00", "cp949");
* printf (B"%K\n", a);
*/
qse_awk_val_t* a0, * r;
qse_cmgr_t* cmgr = qse_awk_rtx_getcmgr(rtx);
if (qse_awk_rtx_getnargs(rtx) >= 2)
{
qse_awk_val_t* a1;
qse_cstr_t enc;
a1 = qse_awk_rtx_getarg(rtx, 1);
enc.ptr = qse_awk_rtx_getvalstr(rtx, a1, &enc.len);
if (!enc.ptr) return -1;
/* if encoding name is an empty string, qse_Findcmgr() returns the default cmgr.
* i don't want that behavior. */
cmgr = (enc.len > 0 && enc.len == qse_strlen(enc.ptr))? qse_findcmgr(enc.ptr): QSE_NULL;
qse_awk_rtx_freevalstr (rtx, a1, enc.ptr);
if (!cmgr)
{
/* if the encoding name is not known, return a zero-length string */
r = qse_awk_rtx_makembsval(rtx, QSE_NULL, 0); /* this never fails for length 0 */
goto done;
}
}
a0 = qse_awk_rtx_getarg(rtx, 0);
switch (QSE_AWK_RTX_GETVALTYPE(rtx, a0))
{
case QSE_AWK_VAL_MBS:
r = a0;
break;
default:
{
qse_mcstr_t str;
str.ptr = qse_awk_rtx_getvalmbswithcmgr(rtx, a0, &str.len, cmgr);
if (!str.ptr) return -1;
r = qse_awk_rtx_makembsvalwithmcstr(rtx, &str);
qse_awk_rtx_freevalmbs (rtx, a0, str.ptr);
if (!r) return -1;
break;
}
}
done:
qse_awk_rtx_setretval (rtx, r);
return 0;
}
static int fnc_tonum (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi)
{
/* str::tonum(value) */
/* str::tonum(string, base) */
qse_awk_val_t* retv;
qse_awk_val_t* a0;
qse_awk_int_t lv;
qse_awk_flt_t rv;
int rx;
a0 = qse_awk_rtx_getarg(rtx, 0);
if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) == QSE_AWK_VAL_MBS && qse_awk_rtx_getnargs(rtx) >= 2)
{
/* if the value is known to be a byte string, it supports the optional
* base parameter */
qse_awk_val_t* a1 = qse_awk_rtx_getarg(rtx, 1);
qse_awk_int_t base;
if (qse_awk_rtx_valtoint(rtx, a1, &base) <= -1) return -1;
rx = qse_awk_rtx_mbstonum (
rtx,
QSE_AWK_RTX_STRTONUM_MAKE_OPTION(0, base),
((qse_awk_val_mbs_t*)a0)->val.ptr,
((qse_awk_val_mbs_t*)a0)->val.len,
&lv, &rv
);
}
else if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) == QSE_AWK_VAL_STR && qse_awk_rtx_getnargs(rtx) >= 2)
{
/* if the value is known to be a string, it supports the optional
* base parameter */
qse_awk_val_t* a1 = qse_awk_rtx_getarg(rtx, 1);
qse_awk_int_t base;
if (qse_awk_rtx_valtoint(rtx, a1, &base) <= -1) return -1;
rx = qse_awk_rtx_strtonum(
rtx,
QSE_AWK_RTX_STRTONUM_MAKE_OPTION(0, base),
((qse_awk_val_str_t*)a0)->val.ptr,
((qse_awk_val_str_t*)a0)->val.len,
&lv, &rv
);
}
else
{
rx = qse_awk_rtx_valtonum(rtx, a0, &lv, &rv);
}
if (rx == 0)
{
retv = qse_awk_rtx_makeintval(rtx, lv);
}
else if (rx >= 1)
{
retv = qse_awk_rtx_makefltval(rtx, rv);
}
else
{
retv = qse_awk_rtx_makeintval(rtx, 0);
}
if (!retv) return -1;
qse_awk_rtx_setretval (rtx, retv);
return 0;
}
typedef struct fnctab_t fnctab_t;
struct fnctab_t
{
const qse_char_t* name;
qse_awk_mod_sym_fnc_t info;
};
typedef struct inttab_t inttab_t;
struct inttab_t
{
const qse_char_t* name;
qse_awk_mod_sym_int_t info;
};
#define A_MAX QSE_TYPE_MAX(int)
static fnctab_t fnctab[] =
{
/* keep this table sorted for binary search in query(). */
{ QSE_T("fromcharcode"), { { 0, A_MAX, QSE_NULL }, fnc_fromcharcode, 0 } },
{ QSE_T("frommbs"), { { 1, 2, QSE_NULL }, fnc_frommbs, 0 } },
{ QSE_T("gsub"), { { 2, 3, QSE_T("xvr")}, qse_awk_fnc_gsub, 0 } },
{ QSE_T("index"), { { 2, 3, QSE_NULL }, qse_awk_fnc_index, 0 } },
{ QSE_T("isalnum"), { { 1, 1, QSE_NULL }, fnc_isalnum, 0 } },
{ QSE_T("isalpha"), { { 1, 1, QSE_NULL }, fnc_isalpha, 0 } },
{ QSE_T("isblank"), { { 1, 1, QSE_NULL }, fnc_isblank, 0 } },
{ QSE_T("iscntrl"), { { 1, 1, QSE_NULL }, fnc_iscntrl, 0 } },
{ QSE_T("isdigit"), { { 1, 1, QSE_NULL }, fnc_isdigit, 0 } },
{ QSE_T("isgraph"), { { 1, 1, QSE_NULL }, fnc_isgraph, 0 } },
{ QSE_T("islower"), { { 1, 1, QSE_NULL }, fnc_islower, 0 } },
{ QSE_T("isprint"), { { 1, 1, QSE_NULL }, fnc_isprint, 0 } },
{ QSE_T("ispunct"), { { 1, 1, QSE_NULL }, fnc_ispunct, 0 } },
{ QSE_T("isspace"), { { 1, 1, QSE_NULL }, fnc_isspace, 0 } },
{ QSE_T("isupper"), { { 1, 1, QSE_NULL }, fnc_isupper, 0 } },
{ QSE_T("isxdigit"), { { 1, 1, QSE_NULL }, fnc_isxdigit, 0 } },
{ QSE_T("length"), { { 1, 1, QSE_NULL }, qse_awk_fnc_length, 0 } },
{ QSE_T("ltrim"), { { 1, 1, QSE_NULL }, fnc_ltrim, 0 } },
{ QSE_T("match"), { { 2, 4, QSE_T("vxvr") }, qse_awk_fnc_match, 0 } },
{ QSE_T("normspace"), { { 1, 1, QSE_NULL }, fnc_normspace, 0 } }, /* deprecated, use trim("xxx", str::TRIM_PAC_SPACES) */
{ QSE_T("printf"), { { 1, A_MAX, QSE_NULL }, qse_awk_fnc_sprintf, 0 } },
{ QSE_T("rindex"), { { 2, 3, QSE_NULL }, qse_awk_fnc_rindex, 0 } },
{ QSE_T("rtrim"), { { 1, 1, QSE_NULL }, fnc_rtrim, 0 } },
{ QSE_T("split"), { { 2, 3, QSE_T("vrx") }, qse_awk_fnc_split, 0 } },
{ QSE_T("sub"), { { 2, 3, QSE_T("xvr") }, qse_awk_fnc_sub, 0 } },
{ QSE_T("substr"), { { 2, 3, QSE_NULL }, qse_awk_fnc_substr, 0 } },
{ QSE_T("tocharcode"), { { 1, 2, QSE_NULL }, fnc_tocharcode, 0 } },
{ QSE_T("tolower"), { { 1, 1, QSE_NULL }, qse_awk_fnc_tolower, 0 } },
{ QSE_T("tombs"), { { 1, 2, QSE_NULL }, fnc_tombs, 0 } },
{ QSE_T("tonum"), { { 1, 2, QSE_NULL }, fnc_tonum, 0 } },
{ QSE_T("toupper"), { { 1, 1, QSE_NULL }, qse_awk_fnc_toupper, 0 } },
{ QSE_T("trim"), { { 1, 2, QSE_NULL }, fnc_trim, 0 } }
};
static inttab_t inttab[] =
{
/* keep this table sorted for binary search in query(). */
{ QSE_T("TRIM_PAC_SPACES"), { TRIM_FLAG_PAC_SPACES } }
};
static int query (qse_awk_mod_t* mod, qse_awk_t* awk, const qse_char_t* name, qse_awk_mod_sym_t* sym)
{
qse_cstr_t ea;
int left, right, mid, n;
left = 0; right = QSE_COUNTOF(fnctab) - 1;
while (left <= right)
{
mid = left + (right - left) / 2;
n = qse_strcmp(fnctab[mid].name, name);
if (n > 0) right = mid - 1;
else if (n < 0) left = mid + 1;
else
{
sym->type = QSE_AWK_MOD_FNC;
sym->u.fnc = fnctab[mid].info;
return 0;
}
}
left = 0; right = QSE_COUNTOF(inttab) - 1;
while (left <= right)
{
mid = left + (right - left) / 2;
n = qse_strcmp (inttab[mid].name, name);
if (n > 0) right = mid - 1;
else if (n < 0) left = mid + 1;
else
{
sym->type = QSE_AWK_MOD_INT;
sym->u.in = inttab[mid].info;
return 0;
}
}
ea.ptr = (qse_char_t*)name;
ea.len = qse_strlen(name);
qse_awk_seterror (awk, QSE_AWK_ENOENT, &ea, QSE_NULL);
return -1;
}
/* TODO: proper resource management */
static int init (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx)
{
return 0;
}
static void fini (qse_awk_mod_t* mod, qse_awk_rtx_t* rtx)
{
/* TODO: anything */
}
static void unload (qse_awk_mod_t* mod, qse_awk_t* awk)
{
/* TODO: anything */
}
int qse_awk_mod_str (qse_awk_mod_t* mod, qse_awk_t* awk)
{
mod->query = query;
mod->unload = unload;
mod->init = init;
mod->fini = fini;
/*
mod->ctx...
*/
return 0;
}

43
lib/awk/mod-str.h Normal file
View File

@ -0,0 +1,43 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_MOD_STR_H_
#define _QSE_LIB_AWK_MOD_STR_H_
#include <qse/awk/awk.h>
#if defined(__cplusplus)
extern "C" {
#endif
QSE_EXPORT int qse_awk_mod_str (qse_awk_mod_t* mod, qse_awk_t* awk);
#if defined(__cplusplus)
}
#endif
#endif

2876
lib/awk/mod-sys.c Normal file

File diff suppressed because it is too large Load Diff

43
lib/awk/mod-sys.h Normal file
View File

@ -0,0 +1,43 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_MOD_SYS_H_
#define _QSE_LIB_AWK_MOD_SYS_H_
#include <qse/awk/awk.h>
#if defined(__cplusplus)
extern "C" {
#endif
QSE_EXPORT int qse_awk_mod_sys (qse_awk_mod_t* mod, qse_awk_t* awk);
#if defined(__cplusplus)
}
#endif
#endif

7247
lib/awk/parse.c Normal file

File diff suppressed because it is too large Load Diff

103
lib/awk/parse.h Normal file
View File

@ -0,0 +1,103 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_PARSE_H_
#define _QSE_LIB_AWK_PARSE_H_
/* these enums should match kwtab in parse.c */
enum qse_awk_kwid_t
{
QSE_AWK_KWID_XABORT,
QSE_AWK_KWID_XGLOBAL,
QSE_AWK_KWID_XINCLUDE,
QSE_AWK_KWID_XINCLUDE_ONCE,
QSE_AWK_KWID_XLOCAL,
QSE_AWK_KWID_XPRAGMA,
QSE_AWK_KWID_XRESET,
QSE_AWK_KWID_BEGIN,
QSE_AWK_KWID_END,
QSE_AWK_KWID_BREAK,
QSE_AWK_KWID_CONTINUE,
QSE_AWK_KWID_DELETE,
QSE_AWK_KWID_DO,
QSE_AWK_KWID_ELSE,
QSE_AWK_KWID_EXIT,
QSE_AWK_KWID_FOR,
QSE_AWK_KWID_FUNCTION,
QSE_AWK_KWID_GETLINE,
QSE_AWK_KWID_IF,
QSE_AWK_KWID_IN,
QSE_AWK_KWID_NEXT,
QSE_AWK_KWID_NEXTFILE,
QSE_AWK_KWID_NEXTOFILE,
QSE_AWK_KWID_PRINT,
QSE_AWK_KWID_PRINTF,
QSE_AWK_KWID_RETURN,
QSE_AWK_KWID_WHILE
};
typedef enum qse_awk_kwid_t qse_awk_kwid_t;
#if defined(__cplusplus)
extern "C" {
#endif
int qse_awk_putsrcstr (
qse_awk_t* awk,
const qse_char_t* str
);
int qse_awk_putsrcstrn (
qse_awk_t* awk,
const qse_char_t* str,
qse_size_t len
);
const qse_char_t* qse_awk_getgblname (
qse_awk_t* awk,
qse_size_t idx,
qse_size_t* len
);
void qse_awk_getkwname (
qse_awk_t* awk,
qse_awk_kwid_t id,
qse_cstr_t* s
);
int qse_awk_initgbls (
qse_awk_t* awk
);
void qse_awk_clearsionames (
qse_awk_t* awk
);
#if defined(__cplusplus)
}
#endif
#endif

614
lib/awk/rec.c Normal file
View File

@ -0,0 +1,614 @@
/*
* $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 "awk-prv.h"
static int split_record (qse_awk_rtx_t* run);
static int recomp_record_fields (
qse_awk_rtx_t* run, qse_size_t lv, const qse_cstr_t* str);
int qse_awk_rtx_setrec (
qse_awk_rtx_t* run, qse_size_t idx, const qse_cstr_t* str)
{
qse_awk_val_t* v;
if (idx == 0)
{
if (str->ptr == QSE_STR_PTR(&run->inrec.line) &&
str->len == QSE_STR_LEN(&run->inrec.line))
{
if (qse_awk_rtx_clrrec (run, 1) == -1) return -1;
}
else
{
if (qse_awk_rtx_clrrec (run, 0) == -1) return -1;
if (qse_str_ncpy (&run->inrec.line, str->ptr, str->len) == (qse_size_t)-1)
{
qse_awk_rtx_clrrec (run, 0);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
}
v = qse_awk_rtx_makenstrvalwithcstr (run, str);
if (v == QSE_NULL)
{
qse_awk_rtx_clrrec (run, 0);
return -1;
}
QSE_ASSERT (QSE_AWK_RTX_GETVALTYPE (run, run->inrec.d0) == QSE_AWK_VAL_NIL);
/* d0 should be cleared before the next line is reached
* as it doesn't call qse_awk_rtx_refdownval on run->inrec.d0 */
run->inrec.d0 = v;
qse_awk_rtx_refupval (run, v);
if (split_record (run) == -1)
{
qse_awk_rtx_clrrec (run, 0);
return -1;
}
}
else
{
if (recomp_record_fields (run, idx, str) <= -1)
{
qse_awk_rtx_clrrec (run, 0);
return -1;
}
/* recompose $0 */
v = qse_awk_rtx_makestrvalwithcstr (run, QSE_STR_XSTR(&run->inrec.line));
if (v == QSE_NULL)
{
qse_awk_rtx_clrrec (run, 0);
return -1;
}
qse_awk_rtx_refdownval (run, run->inrec.d0);
run->inrec.d0 = v;
qse_awk_rtx_refupval (run, v);
}
return 0;
}
static int split_record (qse_awk_rtx_t* rtx)
{
qse_cstr_t tok;
qse_char_t* p, * px;
qse_size_t len, nflds;
qse_awk_val_t* v, * fs;
qse_awk_val_type_t fsvtype;
qse_char_t* fs_ptr, * fs_free;
qse_size_t fs_len;
qse_awk_errnum_t errnum;
int how;
/* inrec should be cleared before split_record is called */
QSE_ASSERT (rtx->inrec.nflds == 0);
/* get FS */
fs = qse_awk_rtx_getgbl (rtx, QSE_AWK_GBL_FS);
fsvtype = QSE_AWK_RTX_GETVALTYPE (rtx, fs);
if (fsvtype == QSE_AWK_VAL_NIL)
{
fs_ptr = QSE_T(" ");
fs_len = 1;
fs_free = QSE_NULL;
}
else if (fsvtype == QSE_AWK_VAL_STR)
{
fs_ptr = ((qse_awk_val_str_t*)fs)->val.ptr;
fs_len = ((qse_awk_val_str_t*)fs)->val.len;
fs_free = QSE_NULL;
}
else
{
fs_ptr = qse_awk_rtx_valtostrdup(rtx, fs, &fs_len);
if (fs_ptr == QSE_NULL) return -1;
fs_free = fs_ptr;
}
/* scan the input record to count the fields */
if (fs_len == 5 && fs_ptr[0] == QSE_T('?'))
{
if (qse_str_ncpy (
&rtx->inrec.linew,
QSE_STR_PTR(&rtx->inrec.line),
QSE_STR_LEN(&rtx->inrec.line)) == (qse_size_t)-1)
{
if (fs_free != QSE_NULL)
qse_awk_rtx_freemem (rtx, fs_free);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
px = QSE_STR_PTR(&rtx->inrec.linew);
how = 1;
}
else
{
px = QSE_STR_PTR(&rtx->inrec.line);
how = (fs_len <= 1)? 0: 2;
}
p = px;
len = QSE_STR_LEN(&rtx->inrec.line);
#if 0
nflds = 0;
while (p != QSE_NULL)
{
switch (how)
{
case 0:
p = qse_awk_rtx_strxntok (rtx,
p, len, fs_ptr, fs_len, &tok);
break;
case 1:
break;
default:
p = qse_awk_rtx_strxntokbyrex (
rtx,
QSE_STR_PTR(&rtx->inrec.line),
QSE_STR_LEN(&rtx->inrec.line),
p, len,
rtx->gbl.fs[rtx->gbl.ignorecase], &tok, &errnum
);
if (p == QSE_NULL && errnum != QSE_AWK_ENOERR)
{
if (fs_free != QSE_NULL)
qse_awk_rtx_freemem (rtx, fs_free);
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL);
return -1;
}
}
if (nflds == 0 && p == QSE_NULL && tok.len == 0)
{
/* there are no fields. it can just return here
* as qse_awk_rtx_clrrec has been called before this */
if (fs_free) qse_awk_rtx_freemem (rtx, fs_free);
return 0;
}
QSE_ASSERT ((tok.ptr != QSE_NULL && tok.len > 0) || tok.len == 0);
nflds++;
len = QSE_STR_LEN(&rtx->inrec.line) - (p - QSE_STR_PTR(&rtx->inrec.line));
}
/* allocate space */
if (nflds > rtx->inrec.maxflds)
{
void* tmp = qse_awk_rtx_allocmem(rtx, QSE_SIZEOF(*rtx->inrec.flds) * nflds);
if (!tmp)
{
if (fs_free) qse_awk_rtx_freemem (rtx, fs_free);
return -1;
}
if (rtx->inrec.flds) qse_awk_rtx_freemem (rtx, rtx->inrec.flds);
rtx->inrec.flds = tmp;
rtx->inrec.maxflds = nflds;
}
/* scan again and split it */
if (how == 1)
{
if (qse_str_ncpy (
&rtx->inrec.linew,
QSE_STR_PTR(&rtx->inrec.line),
QSE_STR_LEN(&rtx->inrec.line)) == (qse_size_t)-1)
{
if (fs_free) qse_awk_rtx_freemem (rtx, fs_free);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
px = QSE_STR_PTR(&rtx->inrec.linew):
}
else
{
px = QSE_STR_PTR(&rtx->inrec.line);
}
p = px;
len = QSE_STR_LEN(&rtx->inrec.line);
#endif
while (p != QSE_NULL)
{
switch (how)
{
case 0:
/* 1 character FS */
p = qse_awk_rtx_strxntok (
rtx, p, len, fs_ptr, fs_len, &tok);
break;
case 1:
/* 5 character FS beginning with ? */
p = qse_awk_rtx_strxnfld (
rtx, p, len,
fs_ptr[1], fs_ptr[2],
fs_ptr[3], fs_ptr[4], &tok);
break;
default:
/* all other cases */
p = qse_awk_rtx_strxntokbyrex (
rtx,
QSE_STR_PTR(&rtx->inrec.line),
QSE_STR_LEN(&rtx->inrec.line),
p, len,
rtx->gbl.fs[rtx->gbl.ignorecase], &tok, &errnum
);
if (p == QSE_NULL && errnum != QSE_AWK_ENOERR)
{
if (fs_free != QSE_NULL)
qse_awk_rtx_freemem (rtx, fs_free);
qse_awk_rtx_seterrnum (rtx, errnum, QSE_NULL);
return -1;
}
}
#if 1
if (rtx->inrec.nflds == 0 && p == QSE_NULL && tok.len == 0)
{
/* there are no fields. it can just return here
* as qse_awk_rtx_clrrec has been called before this */
if (fs_free) qse_awk_rtx_freemem (rtx, fs_free);
return 0;
}
#endif
QSE_ASSERT ((tok.ptr != QSE_NULL && tok.len > 0) || tok.len == 0);
#if 1
if (rtx->inrec.nflds >= rtx->inrec.maxflds)
{
void* tmp;
if (rtx->inrec.nflds < 16) nflds = 32;
else nflds = rtx->inrec.nflds * 2;
tmp = qse_awk_rtx_allocmem(rtx, QSE_SIZEOF(*rtx->inrec.flds) * nflds);
if (tmp == QSE_NULL)
{
if (fs_free) qse_awk_rtx_freemem (rtx, fs_free);
return -1;
}
if (rtx->inrec.flds != QSE_NULL)
{
QSE_MEMCPY (tmp, rtx->inrec.flds, QSE_SIZEOF(*rtx->inrec.flds) * rtx->inrec.nflds);
qse_awk_rtx_freemem (rtx, rtx->inrec.flds);
}
rtx->inrec.flds = tmp;
rtx->inrec.maxflds = nflds;
}
#endif
rtx->inrec.flds[rtx->inrec.nflds].ptr = tok.ptr;
rtx->inrec.flds[rtx->inrec.nflds].len = tok.len;
rtx->inrec.flds[rtx->inrec.nflds].val = qse_awk_rtx_makenstrvalwithcstr (rtx, &tok);
if (rtx->inrec.flds[rtx->inrec.nflds].val == QSE_NULL)
{
if (fs_free) qse_awk_rtx_freemem (rtx, fs_free);
return -1;
}
qse_awk_rtx_refupval (rtx, rtx->inrec.flds[rtx->inrec.nflds].val);
rtx->inrec.nflds++;
len = QSE_STR_LEN(&rtx->inrec.line) - (p - px);
}
if (fs_free) qse_awk_rtx_freemem (rtx, fs_free);
/* set the number of fields */
v = qse_awk_rtx_makeintval(rtx, (qse_awk_int_t)rtx->inrec.nflds);
if (v == QSE_NULL) return -1;
qse_awk_rtx_refupval (rtx, v);
if (qse_awk_rtx_setgbl(rtx, QSE_AWK_GBL_NF, v) == -1)
{
qse_awk_rtx_refdownval (rtx, v);
return -1;
}
qse_awk_rtx_refdownval (rtx, v);
return 0;
}
int qse_awk_rtx_clrrec (qse_awk_rtx_t* run, int skip_inrec_line)
{
qse_size_t i;
int n = 0;
if (run->inrec.d0 != qse_awk_val_nil)
{
qse_awk_rtx_refdownval (run, run->inrec.d0);
run->inrec.d0 = qse_awk_val_nil;
}
if (run->inrec.nflds > 0)
{
QSE_ASSERT (run->inrec.flds != QSE_NULL);
for (i = 0; i < run->inrec.nflds; i++)
{
QSE_ASSERT (run->inrec.flds[i].val != QSE_NULL);
qse_awk_rtx_refdownval (run, run->inrec.flds[i].val);
}
run->inrec.nflds = 0;
if (qse_awk_rtx_setgbl (
run, QSE_AWK_GBL_NF, QSE_AWK_VAL_ZERO) == -1)
{
/* first of all, this should never happen.
* if it happened, it would return an error
* after all the clearance tasks */
n = -1;
}
}
QSE_ASSERT (run->inrec.nflds == 0);
if (!skip_inrec_line) qse_str_clear (&run->inrec.line);
return n;
}
static int recomp_record_fields (qse_awk_rtx_t* run, qse_size_t lv, const qse_cstr_t* str)
{
qse_awk_val_t* v;
qse_size_t max, i, nflds;
/* recomposes the record and the fields when $N has been assigned
* a new value and recomputes NF accordingly */
QSE_ASSERT (lv > 0);
max = (lv > run->inrec.nflds)? lv: run->inrec.nflds;
nflds = run->inrec.nflds;
if (max > run->inrec.maxflds)
{
void* tmp;
/* if the given field number is greater than the maximum
* number of fields that the current record can hold,
* the field spaces are resized */
tmp = qse_awk_rtx_reallocmem(run, run->inrec.flds, QSE_SIZEOF(*run->inrec.flds) * max);
if (!tmp) return -1;
run->inrec.flds = tmp;
run->inrec.maxflds = max;
}
lv = lv - 1; /* adjust the value to 0-based index */
qse_str_clear (&run->inrec.line);
for (i = 0; i < max; i++)
{
if (i > 0)
{
if (qse_str_ncat (&run->inrec.line, run->gbl.ofs.ptr, run->gbl.ofs.len) == (qse_size_t)-1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
}
if (i == lv)
{
qse_awk_val_t* tmp;
run->inrec.flds[i].ptr =
QSE_STR_PTR(&run->inrec.line) +
QSE_STR_LEN(&run->inrec.line);
run->inrec.flds[i].len = str->len;
if (qse_str_ncat (&run->inrec.line, str->ptr, str->len) == (qse_size_t)-1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
tmp = qse_awk_rtx_makestrvalwithcstr (run, str);
if (tmp == QSE_NULL) return -1;
if (i < nflds)
qse_awk_rtx_refdownval (run, run->inrec.flds[i].val);
else run->inrec.nflds++;
run->inrec.flds[i].val = tmp;
qse_awk_rtx_refupval (run, tmp);
}
else if (i >= nflds)
{
run->inrec.flds[i].ptr =
QSE_STR_PTR(&run->inrec.line) +
QSE_STR_LEN(&run->inrec.line);
run->inrec.flds[i].len = 0;
if (qse_str_cat (&run->inrec.line, QSE_T("")) == (qse_size_t)-1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
/* qse_awk_rtx_refdownval should not be called over
* run->inrec.flds[i].val as it is not initialized
* to any valid values */
/*qse_awk_rtx_refdownval (run, run->inrec.flds[i].val);*/
run->inrec.flds[i].val = qse_awk_val_zls;
qse_awk_rtx_refupval (run, qse_awk_val_zls);
run->inrec.nflds++;
}
else
{
qse_awk_val_str_t* tmp;
tmp = (qse_awk_val_str_t*)run->inrec.flds[i].val;
run->inrec.flds[i].ptr =
QSE_STR_PTR(&run->inrec.line) +
QSE_STR_LEN(&run->inrec.line);
run->inrec.flds[i].len = tmp->val.len;
if (qse_str_ncat (
&run->inrec.line,
tmp->val.ptr, tmp->val.len) == (qse_size_t)-1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
}
}
v = qse_awk_rtx_getgbl (run, QSE_AWK_GBL_NF);
QSE_ASSERT (QSE_AWK_RTX_GETVALTYPE (rtx, v) == QSE_AWK_VAL_INT);
if (QSE_AWK_RTX_GETINTFROMVAL (rtx, v)!= max)
{
v = qse_awk_rtx_makeintval (run, (qse_awk_int_t)max);
if (v == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, v);
if (qse_awk_rtx_setgbl (run, QSE_AWK_GBL_NF, v) == -1)
{
qse_awk_rtx_refdownval (run, v);
return -1;
}
qse_awk_rtx_refdownval (run, v);
}
return 0;
}
int qse_awk_rtx_truncrec (qse_awk_rtx_t* rtx, qse_size_t nflds)
{
qse_awk_val_t* v;
qse_char_t* ofs_free = QSE_NULL, * ofs_ptr;
qse_size_t ofs_len, i;
qse_str_t tmp;
qse_awk_val_type_t vtype;
QSE_ASSERT (nflds <= rtx->inrec.nflds);
if (nflds > 1)
{
v = RTX_STACK_GBL(rtx, QSE_AWK_GBL_OFS);
qse_awk_rtx_refupval (rtx, v);
vtype = QSE_AWK_RTX_GETVALTYPE(rtx, v);
if (vtype == QSE_AWK_VAL_NIL)
{
/* OFS not set */
ofs_ptr = QSE_T(" ");
ofs_len = 1;
}
else if (vtype == QSE_AWK_VAL_STR)
{
ofs_ptr = ((qse_awk_val_str_t*)v)->val.ptr;
ofs_len = ((qse_awk_val_str_t*)v)->val.len;
}
else
{
qse_awk_rtx_valtostr_out_t out;
out.type = QSE_AWK_RTX_VALTOSTR_CPLDUP;
if (qse_awk_rtx_valtostr (rtx, v, &out) <= -1) return -1;
ofs_ptr = out.u.cpldup.ptr;
ofs_len = out.u.cpldup.len;
ofs_free = ofs_ptr;
}
}
if (qse_str_init(&tmp, qse_awk_rtx_getmmgr(rtx), QSE_STR_LEN(&rtx->inrec.line)) <= -1)
{
if (ofs_free) qse_awk_rtx_freemem (rtx, ofs_free);
if (nflds > 1) qse_awk_rtx_refdownval (rtx, v);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
for (i = 0; i < nflds; i++)
{
if (i > 0 && qse_str_ncat(&tmp,ofs_ptr,ofs_len) == (qse_size_t)-1)
{
qse_str_fini (&tmp);
if (ofs_free) qse_awk_rtx_freemem (rtx, ofs_free);
if (nflds > 1) qse_awk_rtx_refdownval (rtx, v);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
if (qse_str_ncat (&tmp, rtx->inrec.flds[i].ptr, rtx->inrec.flds[i].len) == (qse_size_t)-1)
{
qse_str_fini (&tmp);
if (ofs_free) qse_awk_rtx_freemem (rtx, ofs_free);
if (nflds > 1) qse_awk_rtx_refdownval (rtx, v);
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
return -1;
}
}
if (ofs_free) qse_awk_rtx_freemem (rtx, ofs_free);
if (nflds > 1) qse_awk_rtx_refdownval (rtx, v);
v = (qse_awk_val_t*)qse_awk_rtx_makestrvalwithcstr(rtx, QSE_STR_XSTR(&tmp));
if (!v)
{
qse_str_fini (&tmp);
return -1;
}
qse_awk_rtx_refdownval (rtx, rtx->inrec.d0);
rtx->inrec.d0 = v;
qse_awk_rtx_refupval (rtx, rtx->inrec.d0);
qse_str_swap (&tmp, &rtx->inrec.line);
qse_str_fini (&tmp);
for (i = nflds; i < rtx->inrec.nflds; i++)
{
qse_awk_rtx_refdownval (rtx, rtx->inrec.flds[i].val);
}
rtx->inrec.nflds = nflds;
return 0;
}

1253
lib/awk/rio.c Normal file

File diff suppressed because it is too large Load Diff

71
lib/awk/rio.h Normal file
View File

@ -0,0 +1,71 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_RIO_H_
#define _QSE_LIB_AWK_RIO_H_
#if defined(__cplusplus)
extern "C" {
#endif
int qse_awk_rtx_readio (
qse_awk_rtx_t* run, int in_type,
const qse_char_t* name, qse_str_t* buf);
int qse_awk_rtx_writeioval (
qse_awk_rtx_t* run, int out_type,
const qse_char_t* name, qse_awk_val_t* v);
int qse_awk_rtx_writeiostr (
qse_awk_rtx_t* run, int out_type,
const qse_char_t* name, qse_char_t* str, qse_size_t len);
int qse_awk_rtx_writeiobytes (
qse_awk_rtx_t* run, int out_type,
const qse_char_t* name, qse_mchar_t* str, qse_size_t len);
int qse_awk_rtx_flushio (
qse_awk_rtx_t* run, int out_type, const qse_char_t* name);
int qse_awk_rtx_nextio_read (
qse_awk_rtx_t* run, int in_type, const qse_char_t* name);
int qse_awk_rtx_nextio_write (
qse_awk_rtx_t* run, int out_type, const qse_char_t* name);
int qse_awk_rtx_closeio (
qse_awk_rtx_t* run,
const qse_char_t* name,
const qse_char_t* opt
);
void qse_awk_rtx_cleario (qse_awk_rtx_t* run);
#if defined(__cplusplus)
}
#endif
#endif

8673
lib/awk/run.c Normal file

File diff suppressed because it is too large Load Diff

147
lib/awk/run.h Normal file
View File

@ -0,0 +1,147 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_RUN_H_
#define _QSE_LIB_AWK_RUN_H_
enum qse_awk_assop_type_t
{
/* if you change this, you have to change assop_str in tree.c.
* synchronize it wit:
* - binop_func in eval_assignment of run.c
* - assop in assing_to_opcode of parse.c
* - TOK_XXX_ASSN in tok_t in parse.c
* - assop_str in tree.c
*/
QSE_AWK_ASSOP_NONE,
QSE_AWK_ASSOP_PLUS, /* += */
QSE_AWK_ASSOP_MINUS, /* -= */
QSE_AWK_ASSOP_MUL, /* *= */
QSE_AWK_ASSOP_DIV, /* /= */
QSE_AWK_ASSOP_IDIV, /* //= */
QSE_AWK_ASSOP_MOD, /* %= */
QSE_AWK_ASSOP_EXP, /* **= */
QSE_AWK_ASSOP_CONCAT, /* %%= */
QSE_AWK_ASSOP_RS, /* >>= */
QSE_AWK_ASSOP_LS, /* <<= */
QSE_AWK_ASSOP_BAND, /* &= */
QSE_AWK_ASSOP_BXOR, /* ^^= */
QSE_AWK_ASSOP_BOR /* |= */
};
enum qse_awk_binop_type_t
{
/* if you change this, you have to change
* binop_str in tree.c and binop_func in run.c accordingly. */
QSE_AWK_BINOP_LOR,
QSE_AWK_BINOP_LAND,
QSE_AWK_BINOP_IN,
QSE_AWK_BINOP_BOR,
QSE_AWK_BINOP_BXOR,
QSE_AWK_BINOP_BAND,
QSE_AWK_BINOP_TEQ,
QSE_AWK_BINOP_TNE,
QSE_AWK_BINOP_EQ,
QSE_AWK_BINOP_NE,
QSE_AWK_BINOP_GT,
QSE_AWK_BINOP_GE,
QSE_AWK_BINOP_LT,
QSE_AWK_BINOP_LE,
QSE_AWK_BINOP_LS,
QSE_AWK_BINOP_RS,
QSE_AWK_BINOP_PLUS,
QSE_AWK_BINOP_MINUS,
QSE_AWK_BINOP_MUL,
QSE_AWK_BINOP_DIV,
QSE_AWK_BINOP_IDIV,
QSE_AWK_BINOP_MOD,
QSE_AWK_BINOP_EXP,
QSE_AWK_BINOP_CONCAT,
QSE_AWK_BINOP_MA,
QSE_AWK_BINOP_NM
};
enum qse_awk_unrop_type_t
{
/* if you change this, you have to change
* __unrop_str in tree.c accordingly. */
QSE_AWK_UNROP_PLUS,
QSE_AWK_UNROP_MINUS,
QSE_AWK_UNROP_LNOT,
QSE_AWK_UNROP_BNOT
};
enum qse_awk_incop_type_t
{
/* if you change this, you have to change
* __incop_str in tree.c accordingly. */
QSE_AWK_INCOP_PLUS,
QSE_AWK_INCOP_MINUS
};
#if defined(__cplusplus)
extern "C" {
#endif
qse_char_t* qse_awk_rtx_format (
qse_awk_rtx_t* run,
qse_str_t* out,
qse_str_t* fbu,
const qse_char_t* fmt,
qse_size_t fmt_len,
qse_size_t nargs_on_stack,
qse_awk_nde_t* args,
qse_size_t* len
);
qse_mchar_t* qse_awk_rtx_formatmbs (
qse_awk_rtx_t* run,
qse_mbs_t* out,
qse_mbs_t* fbu,
const qse_mchar_t* fmt,
qse_size_t fmt_len,
qse_size_t nargs_on_stack,
qse_awk_nde_t* args,
qse_size_t* len
);
int qse_awk_rtx_cmpval (
qse_awk_rtx_t* rtx,
qse_awk_val_t* left,
qse_awk_val_t* right,
int* ret
);
#if defined(__cplusplus)
}
#endif
#endif

2703
lib/awk/std.c Normal file

File diff suppressed because it is too large Load Diff

51
lib/awk/std.h Normal file
View File

@ -0,0 +1,51 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_STD_H
#define _QSE_LIB_AWK_STD_H_
#include "awk-prv.h"
#if defined(__cplusplus)
extern "C" {
#endif
QSE_EXPORT qse_awk_flt_t qse_awk_stdmathpow (qse_awk_t* awk, qse_awk_flt_t x, qse_awk_flt_t y);
QSE_EXPORT qse_awk_flt_t qse_awk_stdmathmod (qse_awk_t* awk, qse_awk_flt_t x, qse_awk_flt_t y);
QSE_EXPORT int qse_awk_stdmodstartup (qse_awk_t* awk);
QSE_EXPORT void qse_awk_stdmodshutdown (qse_awk_t* awk);
QSE_EXPORT void* qse_awk_stdmodopen (qse_awk_t* awk, const qse_awk_mod_spec_t* spec);
QSE_EXPORT void qse_awk_stdmodclose (qse_awk_t* awk, void* handle);
QSE_EXPORT void* qse_awk_stdmodsym (qse_awk_t* awk, void* handle, const qse_char_t* name);
#if defined(__cplusplus)
}
#endif
#endif

1502
lib/awk/tree.c Normal file

File diff suppressed because it is too large Load Diff

353
lib/awk/tree.h Normal file
View File

@ -0,0 +1,353 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_TREE_H_
#define _QSE_LIB_AWK_TREE_H_
enum qse_awk_in_type_t
{
/* the order of these values match
* __in_type_map and __in_opt_map in rio.c */
QSE_AWK_IN_PIPE,
QSE_AWK_IN_RWPIPE,
QSE_AWK_IN_FILE,
QSE_AWK_IN_CONSOLE
};
enum qse_awk_out_type_t
{
/* the order of these values match
* __out_type_map and __out_opt_map in rio.c */
QSE_AWK_OUT_PIPE,
QSE_AWK_OUT_RWPIPE, /* dual direction pipe */
QSE_AWK_OUT_FILE,
QSE_AWK_OUT_APFILE, /* file for appending */
QSE_AWK_OUT_CONSOLE
};
typedef struct qse_awk_nde_blk_t qse_awk_nde_blk_t;
typedef struct qse_awk_nde_grp_t qse_awk_nde_grp_t;
typedef struct qse_awk_nde_ass_t qse_awk_nde_ass_t;
typedef struct qse_awk_nde_exp_t qse_awk_nde_exp_t;
typedef struct qse_awk_nde_cnd_t qse_awk_nde_cnd_t;
typedef struct qse_awk_nde_pos_t qse_awk_nde_pos_t;
typedef struct qse_awk_nde_int_t qse_awk_nde_int_t;
typedef struct qse_awk_nde_flt_t qse_awk_nde_flt_t;
typedef struct qse_awk_nde_str_t qse_awk_nde_str_t;
typedef struct qse_awk_nde_mbs_t qse_awk_nde_mbs_t;
typedef struct qse_awk_nde_rex_t qse_awk_nde_rex_t;
typedef struct qse_awk_nde_fun_t qse_awk_nde_fun_t;
typedef struct qse_awk_nde_var_t qse_awk_nde_var_t;
typedef struct qse_awk_nde_fncall_t qse_awk_nde_fncall_t;
typedef struct qse_awk_nde_getline_t qse_awk_nde_getline_t;
typedef struct qse_awk_nde_if_t qse_awk_nde_if_t;
typedef struct qse_awk_nde_while_t qse_awk_nde_while_t;
typedef struct qse_awk_nde_for_t qse_awk_nde_for_t;
typedef struct qse_awk_nde_foreach_t qse_awk_nde_foreach_t;
typedef struct qse_awk_nde_break_t qse_awk_nde_break_t;
typedef struct qse_awk_nde_continue_t qse_awk_nde_continue_t;
typedef struct qse_awk_nde_return_t qse_awk_nde_return_t;
typedef struct qse_awk_nde_exit_t qse_awk_nde_exit_t;
typedef struct qse_awk_nde_next_t qse_awk_nde_next_t;
typedef struct qse_awk_nde_nextfile_t qse_awk_nde_nextfile_t;
typedef struct qse_awk_nde_delete_t qse_awk_nde_delete_t;
typedef struct qse_awk_nde_reset_t qse_awk_nde_reset_t;
typedef struct qse_awk_nde_print_t qse_awk_nde_print_t;
/* QSE_AWK_NDE_BLK - block statement including top-level blocks */
struct qse_awk_nde_blk_t
{
QSE_AWK_NDE_HDR;
qse_size_t nlcls; /* number of local variables */
qse_awk_nde_t* body;
};
/* QSE_AWK_NDE_GRP - expression group */
struct qse_awk_nde_grp_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* body;
};
/* QSE_AWK_NDE_ASS - assignment */
struct qse_awk_nde_ass_t
{
QSE_AWK_NDE_HDR;
int opcode;
qse_awk_nde_t* left;
qse_awk_nde_t* right;
};
/* QSE_AWK_NDE_EXP_BIN, QSE_AWK_NDE_EXP_UNR,
* QSE_AWK_NDE_EXP_INCPRE, QSE_AW_NDE_EXP_INCPST */
struct qse_awk_nde_exp_t
{
QSE_AWK_NDE_HDR;
int opcode;
qse_awk_nde_t* left;
qse_awk_nde_t* right; /* QSE_NULL for UNR, INCPRE, INCPST */
};
/* QSE_AWK_NDE_CND */
struct qse_awk_nde_cnd_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* test;
qse_awk_nde_t* left;
qse_awk_nde_t* right;
};
/* QSE_AWK_NDE_POS - positional - $1, $2, $x, etc */
struct qse_awk_nde_pos_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* val;
};
/* QSE_AWK_NDE_INT */
struct qse_awk_nde_int_t
{
QSE_AWK_NDE_HDR;
qse_awk_int_t val;
qse_char_t* str;
qse_size_t len;
};
/* QSE_AWK_NDE_FLT */
struct qse_awk_nde_flt_t
{
QSE_AWK_NDE_HDR;
qse_awk_flt_t val;
qse_char_t* str;
qse_size_t len;
};
/* QSE_AWK_NDE_STR */
struct qse_awk_nde_str_t
{
QSE_AWK_NDE_HDR;
qse_char_t* ptr;
qse_size_t len;
};
/* QSE_AWK_NDE_MBS */
struct qse_awk_nde_mbs_t
{
QSE_AWK_NDE_HDR;
qse_mchar_t* ptr;
qse_size_t len;
};
/* QSE_AWK_NDE_REX */
struct qse_awk_nde_rex_t
{
QSE_AWK_NDE_HDR;
qse_cstr_t str;
void* code[2]; /* [0]: case sensitive, [1]: case insensitive */
};
/* QSE_AWK_NDE_FUN - function as a value */
struct qse_awk_nde_fun_t
{
QSE_AWK_NDE_HDR;
qse_cstr_t name; /* function name */
qse_awk_fun_t* funptr; /* QSE_NULL or actual pointer */
};
/* QSE_AWK_NDE_NAMED, QSE_AWK_NDE_GBL,
* QSE_AWK_NDE_LCL, QSE_AWK_NDE_ARG
* QSE_AWK_NDE_NAMEDIDX, QSE_AWK_NDE_GBLIDX,
* QSE_AWK_NDE_LCLIDX, QSE_AWK_NDE_ARGIDX */
struct qse_awk_nde_var_t
{
QSE_AWK_NDE_HDR;
struct
{
qse_cstr_t name;
qse_size_t idxa;
} id;
qse_awk_nde_t* idx; /* QSE_NULL for non-XXXXIDX */
};
/* QSE_AWK_NDE_FNCALL_FNC, QSE_AWK_NDE_FNCALL_FUN, QSE_AWK_NDE_FNCALL_VAR */
struct qse_awk_nde_fncall_t
{
QSE_AWK_NDE_HDR;
union
{
struct
{
qse_cstr_t name;
qse_awk_fun_t* fun; /* cache it */
} fun;
/* minimum information of a intrinsic function
* needed during run-time. */
struct
{
qse_awk_fnc_info_t info;
qse_awk_fnc_spec_t spec;
} fnc;
struct
{
qse_awk_nde_var_t* var;
} var;
} u;
qse_awk_nde_t* args;
qse_size_t nargs;
};
/* QSE_AWK_NDE_GETLINE */
struct qse_awk_nde_getline_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* var;
int in_type; /* QSE_AWK_GETLINE_XXX */
qse_awk_nde_t* in;
};
/* QSE_AWK_NDE_IF */
struct qse_awk_nde_if_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* test;
qse_awk_nde_t* then_part;
qse_awk_nde_t* else_part; /* optional */
};
/* QSE_AWK_NDE_WHILE, QSE_AWK_NDE_DOWHILE */
struct qse_awk_nde_while_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* test;
qse_awk_nde_t* body;
};
/* QSE_AWK_NDE_FOR */
struct qse_awk_nde_for_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* init; /* optional */
qse_awk_nde_t* test; /* optional */
qse_awk_nde_t* incr; /* optional */
qse_awk_nde_t* body;
};
/* QSE_AWK_NDE_FOREACH */
struct qse_awk_nde_foreach_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* test;
qse_awk_nde_t* body;
};
/* QSE_AWK_NDE_BREAK */
struct qse_awk_nde_break_t
{
QSE_AWK_NDE_HDR;
};
/* QSE_AWK_NDE_CONTINUE */
struct qse_awk_nde_continue_t
{
QSE_AWK_NDE_HDR;
};
/* QSE_AWK_NDE_RETURN */
struct qse_awk_nde_return_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* val; /* optional (no return code if QSE_NULL) */
};
/* QSE_AWK_NDE_EXIT */
struct qse_awk_nde_exit_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* val; /* optional (no exit code if QSE_NULL) */
int abort;
};
/* QSE_AWK_NDE_NEXT */
struct qse_awk_nde_next_t
{
QSE_AWK_NDE_HDR;
};
/* QSE_AWK_NDE_NEXTFILE */
struct qse_awk_nde_nextfile_t
{
QSE_AWK_NDE_HDR;
int out;
};
/* QSE_AWK_NDE_DELETE */
struct qse_awk_nde_delete_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* var;
};
/* QSE_AWK_NDE_RESET */
struct qse_awk_nde_reset_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* var;
};
/* QSE_AWK_NDE_PRINT */
struct qse_awk_nde_print_t
{
QSE_AWK_NDE_HDR;
qse_awk_nde_t* args;
int out_type; /* QSE_AWK_OUT_XXX */
qse_awk_nde_t* out;
};
#if defined(__cplusplus)
extern "C" {
#endif
/* print the entire tree */
int qse_awk_prnpt (qse_awk_t* awk, qse_awk_nde_t* tree);
/* print a single top-level node */
int qse_awk_prnnde (qse_awk_t* awk, qse_awk_nde_t* node);
/* print the pattern part */
int qse_awk_prnptnpt (qse_awk_t* awk, qse_awk_nde_t* tree);
void qse_awk_clrpt (qse_awk_t* awk, qse_awk_nde_t* tree);
#if defined(__cplusplus)
}
#endif
#endif

76
lib/awk/val-imp.h Normal file
View File

@ -0,0 +1,76 @@
/*
* $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.
*/
/* this file is supposed to be included by val.c */
int awk_rtx_strtonum (qse_awk_rtx_t* rtx, int option, const char_t* ptr, qse_size_t len, qse_awk_int_t* l, qse_awk_flt_t* r)
{
const char_t* endptr;
const char_t* end;
int strict = QSE_AWK_RTX_STRTONUM_GET_OPTION_STRICT(option);
int base = QSE_AWK_RTX_STRTONUN_GET_OPTION_BASE(option);
end = ptr + len;
*l = awk_strxtoint(rtx->awk, ptr, len, base, &endptr);
if (endptr < end)
{
if (*endptr == _T('.') || *endptr == _T('E') || *endptr == _T('e'))
{
handle_float:
*r = awk_strxtoflt(rtx->awk, ptr, len, &endptr);
if (strict && endptr < end) return -1;
return 1; /* flt */
}
else if (AWK_ISDIGIT(awk, *endptr))
{
const char_t* p = endptr;
do { p++; } while (p < end && AWK_ISDIGIT(awk, *p));
if (p < end && (*p == _T('.') || *p == _T('E') || *p == _T('e')))
{
/* it's probably an floating-point number.
*
* BEGIN { b=99; printf "%f\n", (0 b 1.112); }
*
* for the above code, this function gets '0991.112'.
* and endptr points to '9' after qse_awk_strxtoint() as
* the numeric string beginning with 0 is treated
* as an octal number.
*
* getting side-tracked,
* BEGIN { b=99; printf "%f\n", (0 b 1.000); }
* the above code cause this function to get 0991, not 0991.000
* because of the default CONVFMT '%.6g' which doesn't produce '.000'.
* so such a number is not treated as a floating-point number.
*/
goto handle_float;
}
}
}
if (strict && endptr < end) return -1;
return 0; /* int */
}

2235
lib/awk/val.c Normal file

File diff suppressed because it is too large Load Diff

157
lib/awk/val.h Normal file
View File

@ -0,0 +1,157 @@
/*
* $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.
*/
#ifndef _QSE_LIB_AWK_VAL_H_
#define _QSE_LIB_AWK_VAL_H_
#define QSE_AWK_VAL_CHUNK_SIZE 100
typedef struct qse_awk_val_chunk_t qse_awk_val_chunk_t;
typedef struct qse_awk_val_ichunk_t qse_awk_val_ichunk_t;
typedef struct qse_awk_val_rchunk_t qse_awk_val_rchunk_t;
struct qse_awk_val_chunk_t
{
qse_awk_val_chunk_t* next;
};
struct qse_awk_val_ichunk_t
{
qse_awk_val_chunk_t* next;
/* make sure that it has the same fields as
qse_awk_val_chunk_t up to this point */
qse_awk_val_int_t slot[QSE_AWK_VAL_CHUNK_SIZE];
};
struct qse_awk_val_rchunk_t
{
qse_awk_val_chunk_t* next;
/* make sure that it has the same fields as
qse_awk_val_chunk_t up to this point */
qse_awk_val_flt_t slot[QSE_AWK_VAL_CHUNK_SIZE];
};
/*
* if shared objects link a static library, statically defined objects
* in the static library will be instatiated in the multiple shared objects.
*
* so equality check with a value pointer doesn't work
* if the code crosses the library boundaries. instead, i decided to
* add a field to indicate if a value is static.
*
#define IS_STATICVAL(val) ((val) == QSE_NULL || (val) == qse_awk_val_nil || (val) == qse_awk_val_zls || (val) == qse_awk_val_zlm)
*/
#define IS_STATICVAL(val) ((val)->stat)
/* qse_awk_val_t pointer encoding assumes the pointer is an even number.
* i shift an integer within a certain range and set bit 0 to 1 to
* encode it in a pointer. (vtr = value pointer).
*
* is this a safe assumption? do i have to use memalign or write my own
* aligned malloc()? */
#define QSE_AWK_VTR_NUM_TYPE_BITS 1
#define QSE_AWK_VTR_MASK_TYPE_BITS 1
#define QSE_AWK_VTR_TYPE_BITS_POINTER 0
#define QSE_AWK_VTR_TYPE_BITS_QUICKINT 1
#define QSE_AWK_VTR_SIGN_BIT ((qse_uintptr_t)1 << (QSE_SIZEOF_UINTPTR_T * 8 - 1))
/* shrink the bit range by 1 more bit to ease signbit handling.
* i want abs(max) == abs(min).
* i don't want abs(max) + 1 == abs(min). e.g min: -32768, max: 32767
*/
#define QSE_AWK_QUICKINT_MAX ((qse_awk_int_t)((~(qse_uintptr_t)0) >> (QSE_AWK_VTR_NUM_TYPE_BITS + 1)))
#define QSE_AWK_QUICKINT_MIN (-QSE_AWK_QUICKINT_MAX)
#define QSE_AWK_IN_QUICKINT_RANGE(i) ((i) >= QSE_AWK_QUICKINT_MIN && (i) <= QSE_AWK_QUICKINT_MAX)
#define QSE_AWK_VTR_TYPE_BITS(p) (((qse_uintptr_t)(p)) & QSE_AWK_VTR_MASK_TYPE_BITS)
#define QSE_AWK_VTR_IS_POINTER(p) (QSE_AWK_VTR_TYPE_BITS(p) == QSE_AWK_VTR_TYPE_BITS_POINTER)
#define QSE_AWK_VTR_IS_QUICKINT(p) (QSE_AWK_VTR_TYPE_BITS(p) == QSE_AWK_VTR_TYPE_BITS_QUICKINT)
#define QSE_AWK_QUICKINT_TO_VTR_POSITIVE(i) \
(((qse_uintptr_t)(i) << QSE_AWK_VTR_NUM_TYPE_BITS) | QSE_AWK_VTR_TYPE_BITS_QUICKINT)
#define QSE_AWK_QUICKINT_TO_VTR_NEGATIVE(i) \
((((qse_uintptr_t)-(i)) << QSE_AWK_VTR_NUM_TYPE_BITS) | QSE_AWK_VTR_TYPE_BITS_QUICKINT | QSE_AWK_VTR_SIGN_BIT)
#define QSE_AWK_QUICKINT_TO_VTR(i) \
((qse_awk_val_t*)(((i) < 0)? QSE_AWK_QUICKINT_TO_VTR_NEGATIVE(i): QSE_AWK_QUICKINT_TO_VTR_POSITIVE(i)))
#define QSE_AWK_VTR_ZERO ((qse_awk_val_t*)QSE_AWK_QUICKINT_TO_VTR_POSITIVE(0))
#define QSE_AWK_VTR_ONE ((qse_awk_val_t*)QSE_AWK_QUICKINT_TO_VTR_POSITIVE(1))
#define QSE_AWK_VTR_NEGONE ((qse_awk_val_t*)QSE_AWK_QUICKINT_TO_VTR_NEGATIVE(-1))
/* sizeof(qse_intptr_t) may not be the same as sizeof(qse_awk_int_t).
* so step-by-step type conversions are needed.
* e.g) pointer to uintptr_t, uintptr_t to intptr_t, intptr_t to awk_int_t */
#define QSE_AWK_VTR_TO_QUICKINT_POSITIVE(p) \
((qse_intptr_t)((qse_uintptr_t)(p) >> QSE_AWK_VTR_NUM_TYPE_BITS))
#define QSE_AWK_VTR_TO_QUICKINT_NEGATIVE(p) \
(-(qse_intptr_t)(((qse_uintptr_t)(p) & ~QSE_AWK_VTR_SIGN_BIT) >> QSE_AWK_VTR_NUM_TYPE_BITS))
#define QSE_AWK_VTR_TO_QUICKINT(p) \
(((qse_uintptr_t)(p) & QSE_AWK_VTR_SIGN_BIT)? QSE_AWK_VTR_TO_QUICKINT_NEGATIVE(p): QSE_AWK_VTR_TO_QUICKINT_POSITIVE(p))
#define QSE_AWK_RTX_GETVALTYPE(rtx,p) (QSE_AWK_VTR_IS_QUICKINT(p)? QSE_AWK_VAL_INT: (p)->v_type)
#define QSE_AWK_RTX_GETINTFROMVAL(rtx,p) ((QSE_AWK_VTR_IS_QUICKINT(p)? (qse_awk_int_t)QSE_AWK_VTR_TO_QUICKINT(p): ((qse_awk_val_int_t*)(p))->i_val))
#define QSE_AWK_VAL_ZERO QSE_AWK_VTR_ZERO
#define QSE_AWK_VAL_ONE QSE_AWK_VTR_ONE
#define QSE_AWK_VAL_NEGONE QSE_AWK_VTR_NEGONE
#if defined(__cplusplus)
extern "C" {
#endif
/* represents a nil value */
extern qse_awk_val_t* qse_awk_val_nil;
/* represents an empty string */
extern qse_awk_val_t* qse_awk_val_zls;
void qse_awk_rtx_freeval (
qse_awk_rtx_t* rtx,
qse_awk_val_t* val,
int cache
);
void qse_awk_rtx_freevalchunk (
qse_awk_rtx_t* rtx,
qse_awk_val_chunk_t* chunk
);
#if defined(__cplusplus)
}
#endif
#endif