Reorganized the directory structure
This commit is contained in:
2455
lib/awk/Awk.cpp
Normal file
2455
lib/awk/Awk.cpp
Normal file
File diff suppressed because it is too large
Load Diff
123
lib/awk/Makefile.am
Normal file
123
lib/awk/Makefile.am
Normal 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
1162
lib/awk/Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
1401
lib/awk/StdAwk.cpp
Normal file
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
489
lib/awk/awk-prv.h
Normal 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
546
lib/awk/awk.c
Normal 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
71
lib/awk/awk.txt
Normal 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
422
lib/awk/err.c
Normal 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
41
lib/awk/err.h
Normal 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
1888
lib/awk/fnc.c
Normal file
File diff suppressed because it is too large
Load Diff
77
lib/awk/fnc.h
Normal file
77
lib/awk/fnc.h
Normal 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
33
lib/awk/generrcode.awk
Normal 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
33
lib/awk/genoptcode.awk
Normal 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
156
lib/awk/imap-imp.h
Normal 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
530
lib/awk/misc-imp.h
Normal 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
1121
lib/awk/misc.c
Normal file
File diff suppressed because it is too large
Load Diff
100
lib/awk/misc.h
Normal file
100
lib/awk/misc.h
Normal 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
569
lib/awk/mod-dir.c
Normal 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
43
lib/awk/mod-dir.h
Normal 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
730
lib/awk/mod-math.c
Normal 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
43
lib/awk/mod-math.h
Normal 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
674
lib/awk/mod-str.c
Normal 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
43
lib/awk/mod-str.h
Normal 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
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
43
lib/awk/mod-sys.h
Normal 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
7247
lib/awk/parse.c
Normal file
File diff suppressed because it is too large
Load Diff
103
lib/awk/parse.h
Normal file
103
lib/awk/parse.h
Normal 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
614
lib/awk/rec.c
Normal 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
1253
lib/awk/rio.c
Normal file
File diff suppressed because it is too large
Load Diff
71
lib/awk/rio.h
Normal file
71
lib/awk/rio.h
Normal 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
8673
lib/awk/run.c
Normal file
File diff suppressed because it is too large
Load Diff
147
lib/awk/run.h
Normal file
147
lib/awk/run.h
Normal 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
2703
lib/awk/std.c
Normal file
File diff suppressed because it is too large
Load Diff
51
lib/awk/std.h
Normal file
51
lib/awk/std.h
Normal 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
1502
lib/awk/tree.c
Normal file
File diff suppressed because it is too large
Load Diff
353
lib/awk/tree.h
Normal file
353
lib/awk/tree.h
Normal 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
76
lib/awk/val-imp.h
Normal 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
2235
lib/awk/val.c
Normal file
File diff suppressed because it is too large
Load Diff
157
lib/awk/val.h
Normal file
157
lib/awk/val.h
Normal 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
|
||||
Reference in New Issue
Block a user