qse/qse/lib/awk/run.c

7686 lines
176 KiB
C
Raw Normal View History

/*
2008-12-16 03:56:48 +00:00
* $Id: run.c 496 2008-12-15 09:56:48Z baconevi $
*
2008-12-27 04:35:14 +00:00
Copyright 2006-2008 Chung, Hyung-Hwan.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
2008-08-21 03:17:25 +00:00
#include "awk.h"
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
#include <qse/utl/stdio.h>
#endif
#define CMP_ERROR -99
#define DEF_BUF_CAPA 256
#define STACK_INCREMENT 512
2008-01-16 21:46:08 +00:00
#define IDXBUFSIZE 64
2008-07-20 23:53:29 +00:00
#define MMGR(run) ((run)->awk->mmgr)
2008-07-21 06:42:39 +00:00
#define CCLS(run) ((run)->awk->ccls)
2008-07-20 23:53:29 +00:00
#define STACK_AT(run,n) ((run)->stack[(run)->stack_base+(n)])
#define STACK_NARGS(run) (STACK_AT(run,3))
#define STACK_ARG(run,n) STACK_AT(run,3+1+(n))
2008-12-21 21:35:07 +00:00
#define STACK_LOCAL(run,n) STACK_AT(run,3+(qse_size_t)STACK_NARGS(run)+1+(n))
#define STACK_RETVAL(run) STACK_AT(run,2)
#define STACK_GLOBAL(run,n) ((run)->stack[(n)])
#define STACK_RETVAL_GLOBAL(run) ((run)->stack[(run)->awk->tree.nglobals+2])
enum exit_level_t
{
EXIT_NONE,
EXIT_BREAK,
EXIT_CONTINUE,
EXIT_FUNCTION,
EXIT_NEXT,
EXIT_GLOBAL,
EXIT_ABORT
};
2008-12-21 21:35:07 +00:00
#define DEFAULT_CONVFMT QSE_T("%.6g")
#define DEFAULT_OFMT QSE_T("%.6g")
#define DEFAULT_OFS QSE_T(" ")
#define DEFAULT_ORS QSE_T("\n")
#define DEFAULT_ORS_CRLF QSE_T("\r\n")
#define DEFAULT_SUBSEP QSE_T("\034")
/* the index of a positional variable should be a positive interger
* equal to or less than the maximum value of the type by which
* the index is represented. but it has an extra check against the
2008-12-21 21:35:07 +00:00
* maximum value of qse_size_t as the reference is represented
* in a pointer variable of qse_awk_val_ref_t and sizeof(void*) is
* equal to sizeof(qse_size_t). */
#define IS_VALID_POSIDX(idx) \
((idx) >= 0 && \
2008-12-21 21:35:07 +00:00
(idx) < QSE_TYPE_MAX(qse_long_t) && \
(idx) < QSE_TYPE_MAX(qse_size_t))
static int set_global (
qse_awk_rtx_t* run, qse_size_t idx,
2008-12-21 21:35:07 +00:00
qse_awk_nde_var_t* var, qse_awk_val_t* val);
static int init_run (
qse_awk_rtx_t* run, qse_awk_t* awk,
2008-12-21 21:35:07 +00:00
qse_awk_runios_t* runios, void* data);
static void deinit_run (qse_awk_rtx_t* run);
static int run_main (
qse_awk_rtx_t* run, const qse_char_t* main,
const qse_cstr_t* runarg);
static int run_pattern_blocks (qse_awk_rtx_t* run);
static int run_pattern_block_chain (
qse_awk_rtx_t* run, qse_awk_chain_t* chain);
static int run_pattern_block (
qse_awk_rtx_t* run, qse_awk_chain_t* chain, qse_size_t block_no);
static int run_block (qse_awk_rtx_t* run, qse_awk_nde_blk_t* nde);
static int run_block0 (qse_awk_rtx_t* run, qse_awk_nde_blk_t* nde);
static int run_statement (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static int run_if (qse_awk_rtx_t* run, qse_awk_nde_if_t* nde);
static int run_while (qse_awk_rtx_t* run, qse_awk_nde_while_t* nde);
static int run_for (qse_awk_rtx_t* run, qse_awk_nde_for_t* nde);
static int run_foreach (qse_awk_rtx_t* run, qse_awk_nde_foreach_t* nde);
static int run_break (qse_awk_rtx_t* run, qse_awk_nde_break_t* nde);
static int run_continue (qse_awk_rtx_t* run, qse_awk_nde_continue_t* nde);
static int run_return (qse_awk_rtx_t* run, qse_awk_nde_return_t* nde);
static int run_exit (qse_awk_rtx_t* run, qse_awk_nde_exit_t* nde);
static int run_next (qse_awk_rtx_t* run, qse_awk_nde_next_t* nde);
static int run_nextfile (qse_awk_rtx_t* run, qse_awk_nde_nextfile_t* nde);
static int run_delete (qse_awk_rtx_t* run, qse_awk_nde_delete_t* nde);
static int run_reset (qse_awk_rtx_t* run, qse_awk_nde_reset_t* nde);
static int run_print (qse_awk_rtx_t* run, qse_awk_nde_print_t* nde);
static int run_printf (qse_awk_rtx_t* run, qse_awk_nde_print_t* nde);
static int output_formatted (
qse_awk_rtx_t* run, int out_type, const qse_char_t* dst,
2008-12-21 21:35:07 +00:00
const qse_char_t* fmt, qse_size_t fmt_len, qse_awk_nde_t* args);
static qse_awk_val_t* eval_expression (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_expression0 (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_group (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_assignment (
qse_awk_rtx_t* run, qse_awk_nde_t* nde);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* do_assignment (
qse_awk_rtx_t* run, qse_awk_nde_t* var, qse_awk_val_t* val);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* do_assignment_scalar (
qse_awk_rtx_t* run, qse_awk_nde_var_t* var, qse_awk_val_t* val);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* do_assignment_map (
qse_awk_rtx_t* run, qse_awk_nde_var_t* var, qse_awk_val_t* val);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* do_assignment_pos (
qse_awk_rtx_t* run, qse_awk_nde_pos_t* pos, qse_awk_val_t* val);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binary (
qse_awk_rtx_t* run, qse_awk_nde_t* nde);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_lor (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_land (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_in (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_bor (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_bxor (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_band (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_eq (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_ne (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_gt (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_ge (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_lt (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_le (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_lshift (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_rshift (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_plus (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_minus (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_mul (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_div (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_idiv (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_mod (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_exp (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_concat (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_ma (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_nm (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_match0 (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right,
2008-12-21 21:35:07 +00:00
qse_size_t lline, qse_size_t rline, int ret);
static qse_awk_val_t* eval_unary (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_incpre (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_incpst (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_cnd (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_fun_intrinsic (
qse_awk_rtx_t* run, qse_awk_nde_t* nde,
2007-12-07 23:58:44 +00:00
void(*errhandler)(void*), void* eharg);
static qse_awk_val_t* eval_fnc (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_fun (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_call (
qse_awk_rtx_t* run, qse_awk_nde_t* nde,
const qse_char_t* fnc_arg_spec, qse_awk_fun_t* fun,
2007-12-07 23:58:44 +00:00
void(*errhandler)(void*), void* eharg);
static int get_reference (
qse_awk_rtx_t* run, qse_awk_nde_t* nde, qse_awk_val_t*** ref);
2008-12-21 21:35:07 +00:00
static qse_awk_val_t** get_reference_indexed (
qse_awk_rtx_t* run, qse_awk_nde_var_t* nde, qse_awk_val_t** val);
static qse_awk_val_t* eval_int (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_real (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_str (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_rex (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_named (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_global (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_local (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_arg (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_namedidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_globalidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_localidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_argidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_pos (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_getline (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static int __raw_push (qse_awk_rtx_t* run, void* val);
#define __raw_pop(run) \
do { \
2008-12-21 21:35:07 +00:00
QSE_ASSERT ((run)->stack_top > (run)->stack_base); \
(run)->stack_top--; \
} while (0)
static int read_record (qse_awk_rtx_t* run);
static int shorten_record (qse_awk_rtx_t* run, qse_size_t nflds);
2008-12-21 21:35:07 +00:00
static qse_char_t* idxnde_to_str (
qse_awk_rtx_t* run, qse_awk_nde_t* nde, qse_char_t* buf, qse_size_t* len);
2008-12-21 21:35:07 +00:00
typedef qse_awk_val_t* (*binop_func_t) (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
typedef qse_awk_val_t* (*eval_expr_t) (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
qse_size_t qse_awk_rtx_getnargs (qse_awk_rtx_t* run)
{
2008-12-21 21:35:07 +00:00
return (qse_size_t) STACK_NARGS (run);
}
qse_awk_val_t* qse_awk_rtx_getarg (qse_awk_rtx_t* run, qse_size_t idx)
{
return STACK_ARG (run, idx);
}
qse_awk_val_t* qse_awk_rtx_getglobal (qse_awk_rtx_t* run, int id)
{
QSE_ASSERT (id >= 0 && id < (int)QSE_LDA_SIZE(run->awk->parse.globals));
return STACK_GLOBAL (run, id);
}
int qse_awk_rtx_setglobal (qse_awk_rtx_t* run, int id, qse_awk_val_t* val)
{
QSE_ASSERT (id >= 0 && id < (int)QSE_LDA_SIZE(run->awk->parse.globals));
2008-12-21 21:35:07 +00:00
return set_global (run, (qse_size_t)id, QSE_NULL, val);
}
static int set_global (
qse_awk_rtx_t* run, qse_size_t idx,
2008-12-21 21:35:07 +00:00
qse_awk_nde_var_t* var, qse_awk_val_t* val)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* old;
old = STACK_GLOBAL (run, idx);
2008-12-21 21:35:07 +00:00
if (old->type == QSE_AWK_VAL_MAP)
{
/* once a variable becomes a map,
* it cannot be changed to a scalar variable */
2008-12-21 21:35:07 +00:00
if (var != QSE_NULL)
{
/* global variable */
2008-12-21 21:35:07 +00:00
qse_cstr_t errarg;
errarg.ptr = var->id.name.ptr;
errarg.len = var->id.name.len;
qse_awk_rtx_seterror (run,
2008-12-21 21:35:07 +00:00
QSE_AWK_EMAPTOSCALAR, var->line, &errarg, 1);
}
else
{
/* qse_awk_rtx_setglobal has been called */
2008-12-21 21:35:07 +00:00
qse_cstr_t errarg;
errarg.ptr = qse_awk_rtx_getglobalname (
run->awk, idx, &errarg.len);
qse_awk_rtx_seterror (run,
2008-12-21 21:35:07 +00:00
QSE_AWK_EMAPTOSCALAR, 0, &errarg, 1);
}
return -1;
}
/* builtin variables except ARGV cannot be assigned a map */
2008-12-21 21:35:07 +00:00
if (val->type == QSE_AWK_VAL_MAP &&
(idx >= QSE_AWK_GLOBAL_ARGC && idx <= QSE_AWK_GLOBAL_SUBSEP) &&
idx != QSE_AWK_GLOBAL_ARGV)
{
/* TODO: better error code */
qse_awk_rtx_seterrnum (run, QSE_AWK_ESCALARTOMAP);
return -1;
}
2008-12-21 21:35:07 +00:00
if (idx == QSE_AWK_GLOBAL_CONVFMT)
{
2008-12-21 21:35:07 +00:00
qse_char_t* convfmt_ptr;
qse_size_t convfmt_len, i;
convfmt_ptr = qse_awk_rtx_valtostr (run,
2008-12-21 21:35:07 +00:00
val, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &convfmt_len);
if (convfmt_ptr == QSE_NULL) return -1;
for (i = 0; i < convfmt_len; i++)
{
2008-12-21 21:35:07 +00:00
if (convfmt_ptr[i] == QSE_T('\0'))
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, convfmt_ptr);
qse_awk_rtx_seterrnum (run, QSE_AWK_ECONVFMTCHR);
return -1;
}
}
2008-12-21 21:35:07 +00:00
if (run->global.convfmt.ptr != QSE_NULL)
QSE_AWK_FREE (run->awk, run->global.convfmt.ptr);
run->global.convfmt.ptr = convfmt_ptr;
run->global.convfmt.len = convfmt_len;
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_FNR)
{
int n;
2008-12-21 21:35:07 +00:00
qse_long_t lv;
qse_real_t rv;
n = qse_awk_rtx_valtonum (run, val, &lv, &rv);
if (n == -1) return -1;
2008-12-21 21:35:07 +00:00
if (n == 1) lv = (qse_long_t)rv;
run->global.fnr = lv;
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_FS)
{
2008-12-21 21:35:07 +00:00
qse_char_t* fs_ptr;
qse_size_t fs_len;
2008-12-21 21:35:07 +00:00
if (val->type == QSE_AWK_VAL_STR)
{
fs_ptr = ((qse_awk_val_str_t*)val)->ptr;
2008-12-21 21:35:07 +00:00
fs_len = ((qse_awk_val_str_t*)val)->len;
}
else
{
/* due to the expression evaluation rule, the
* regular expression can not be an assigned value */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (val->type != QSE_AWK_VAL_REX);
fs_ptr = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, val, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &fs_len);
if (fs_ptr == QSE_NULL) return -1;
}
if (fs_len > 1)
{
void* rex;
/* TODO: use safebuild */
2008-12-21 21:35:07 +00:00
rex = QSE_AWK_BUILDREX (
run->awk, fs_ptr, fs_len, &run->errnum);
2008-12-21 21:35:07 +00:00
if (rex == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (val->type != QSE_AWK_VAL_STR)
QSE_AWK_FREE (run->awk, fs_ptr);
return -1;
}
2008-12-21 21:35:07 +00:00
if (run->global.fs != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREEREX (run->awk, run->global.fs);
}
run->global.fs = rex;
}
2008-12-21 21:35:07 +00:00
if (val->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, fs_ptr);
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_IGNORECASE)
{
2008-12-21 21:35:07 +00:00
if ((val->type == QSE_AWK_VAL_INT &&
((qse_awk_val_int_t*)val)->val != 0) ||
(val->type == QSE_AWK_VAL_REAL &&
((qse_awk_val_real_t*)val)->val != 0.0) ||
(val->type == QSE_AWK_VAL_STR &&
((qse_awk_val_str_t*)val)->len != 0))
{
run->global.ignorecase = 1;
}
else
{
run->global.ignorecase = 0;
}
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_NF)
{
int n;
2008-12-21 21:35:07 +00:00
qse_long_t lv;
qse_real_t rv;
n = qse_awk_rtx_valtonum (run, val, &lv, &rv);
if (n == -1) return -1;
2008-12-21 21:35:07 +00:00
if (n == 1) lv = (qse_long_t)rv;
2008-12-21 21:35:07 +00:00
if (lv < (qse_long_t)run->inrec.nflds)
{
2008-12-21 21:35:07 +00:00
if (shorten_record (run, (qse_size_t)lv) == -1)
{
/* adjust the error line */
2008-12-21 21:35:07 +00:00
if (var != QSE_NULL) run->errlin = var->line;
return -1;
}
}
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_NR)
{
int n;
2008-12-21 21:35:07 +00:00
qse_long_t lv;
qse_real_t rv;
n = qse_awk_rtx_valtonum (run, val, &lv, &rv);
if (n == -1) return -1;
2008-12-21 21:35:07 +00:00
if (n == 1) lv = (qse_long_t)rv;
run->global.nr = lv;
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_OFMT)
{
2008-12-21 21:35:07 +00:00
qse_char_t* ofmt_ptr;
qse_size_t ofmt_len, i;
ofmt_ptr = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, val, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &ofmt_len);
if (ofmt_ptr == QSE_NULL) return -1;
for (i = 0; i < ofmt_len; i++)
{
2008-12-21 21:35:07 +00:00
if (ofmt_ptr[i] == QSE_T('\0'))
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, ofmt_ptr);
qse_awk_rtx_seterrnum (run, QSE_AWK_EOFMTCHR);
return -1;
}
}
2008-12-21 21:35:07 +00:00
if (run->global.ofmt.ptr != QSE_NULL)
QSE_AWK_FREE (run->awk, run->global.ofmt.ptr);
run->global.ofmt.ptr = ofmt_ptr;
run->global.ofmt.len = ofmt_len;
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_OFS)
{
2008-12-21 21:35:07 +00:00
qse_char_t* ofs_ptr;
qse_size_t ofs_len;
ofs_ptr = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, val, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &ofs_len);
if (ofs_ptr == QSE_NULL) return -1;
2008-12-21 21:35:07 +00:00
if (run->global.ofs.ptr != QSE_NULL)
QSE_AWK_FREE (run->awk, run->global.ofs.ptr);
run->global.ofs.ptr = ofs_ptr;
run->global.ofs.len = ofs_len;
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_ORS)
{
2008-12-21 21:35:07 +00:00
qse_char_t* ors_ptr;
qse_size_t ors_len;
ors_ptr = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, val, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &ors_len);
if (ors_ptr == QSE_NULL) return -1;
2008-12-21 21:35:07 +00:00
if (run->global.ors.ptr != QSE_NULL)
QSE_AWK_FREE (run->awk, run->global.ors.ptr);
run->global.ors.ptr = ors_ptr;
run->global.ors.len = ors_len;
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_RS)
{
2008-12-21 21:35:07 +00:00
qse_char_t* rs_ptr;
qse_size_t rs_len;
2008-12-21 21:35:07 +00:00
if (val->type == QSE_AWK_VAL_STR)
{
rs_ptr = ((qse_awk_val_str_t*)val)->ptr;
2008-12-21 21:35:07 +00:00
rs_len = ((qse_awk_val_str_t*)val)->len;
}
else
{
/* due to the expression evaluation rule, the
* regular expression can not be an assigned value */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (val->type != QSE_AWK_VAL_REX);
rs_ptr = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, val, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &rs_len);
if (rs_ptr == QSE_NULL) return -1;
}
if (rs_len > 1)
{
void* rex;
/* compile the regular expression */
/* TODO: use safebuild */
2008-12-21 21:35:07 +00:00
rex = QSE_AWK_BUILDREX (
run->awk, rs_ptr, rs_len, &run->errnum);
2008-12-21 21:35:07 +00:00
if (rex == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (val->type != QSE_AWK_VAL_STR)
QSE_AWK_FREE (run->awk, rs_ptr);
return -1;
}
2008-12-21 21:35:07 +00:00
if (run->global.rs != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREEREX (run->awk, run->global.rs);
}
run->global.rs = rex;
}
2008-12-21 21:35:07 +00:00
if (val->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, rs_ptr);
}
2008-12-21 21:35:07 +00:00
else if (idx == QSE_AWK_GLOBAL_SUBSEP)
{
2008-12-21 21:35:07 +00:00
qse_char_t* subsep_ptr;
qse_size_t subsep_len;
subsep_ptr = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, val, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &subsep_len);
if (subsep_ptr == QSE_NULL) return -1;
2008-12-21 21:35:07 +00:00
if (run->global.subsep.ptr != QSE_NULL)
QSE_AWK_FREE (run->awk, run->global.subsep.ptr);
run->global.subsep.ptr = subsep_ptr;
run->global.subsep.len = subsep_len;
}
qse_awk_rtx_refdownval (run, old);
STACK_GLOBAL(run,idx) = val;
qse_awk_rtx_refupval (run, val);
return 0;
}
void qse_awk_rtx_setretval (qse_awk_rtx_t* run, qse_awk_val_t* val)
{
qse_awk_rtx_refdownval (run, STACK_RETVAL(run));
STACK_RETVAL(run) = val;
/* should use the same trick as run_return */
qse_awk_rtx_refupval (run, val);
}
int qse_awk_rtx_setfilename (
qse_awk_rtx_t* run, const qse_char_t* name, qse_size_t len)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp;
int n;
2008-12-21 21:35:07 +00:00
if (len == 0) tmp = qse_awk_val_zls;
else
{
tmp = qse_awk_rtx_makestrval (run, name, len);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL) return -1;
}
qse_awk_rtx_refupval (run, tmp);
n = qse_awk_rtx_setglobal (run, QSE_AWK_GLOBAL_FILENAME, tmp);
qse_awk_rtx_refdownval (run, tmp);
return n;
}
int qse_awk_rtx_setofilename (
qse_awk_rtx_t* run, const qse_char_t* name, qse_size_t len)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp;
int n;
2008-12-21 21:35:07 +00:00
if (run->awk->option & QSE_AWK_NEXTOFILE)
{
2008-12-21 21:35:07 +00:00
if (len == 0) tmp = qse_awk_val_zls;
else
{
tmp = qse_awk_rtx_makestrval (run, name, len);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL) return -1;
}
qse_awk_rtx_refupval (run, tmp);
n = qse_awk_rtx_setglobal (run, QSE_AWK_GLOBAL_OFILENAME, tmp);
qse_awk_rtx_refdownval (run, tmp);
}
else n = 0;
return n;
}
qse_awk_t* qse_awk_rtx_getawk (qse_awk_rtx_t* run)
{
return run->awk;
}
qse_mmgr_t* qse_awk_rtx_getmmgr (qse_awk_rtx_t* run)
2008-12-12 04:05:28 +00:00
{
return run->awk->mmgr;
}
void* qse_awk_rtx_getdata (qse_awk_rtx_t* run)
{
2008-08-19 05:21:48 +00:00
return run->data;
}
qse_map_t* qse_awk_rtx_getnvmap (qse_awk_rtx_t* run)
{
2008-03-22 05:57:29 +00:00
return run->named;
}
2008-12-21 21:35:07 +00:00
int qse_awk_run (qse_awk_t* awk,
const qse_char_t* main,
qse_awk_runios_t* runios,
qse_awk_runcbs_t* runcbs,
const qse_cstr_t* runarg,
2008-08-19 05:21:48 +00:00
void* data)
{
qse_awk_rtx_t* run;
int n;
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (awk->ccls != QSE_NULL, "Call qse_setccls() first");
QSE_ASSERTX (awk->prmfns != QSE_NULL, "Call qse_setprmfns() first");
2008-07-21 06:42:39 +00:00
/* clear the awk error code */
2008-12-21 21:35:07 +00:00
qse_awk_seterror (awk, QSE_AWK_ENOERR, 0, QSE_NULL, 0);
/* check if the code has ever been parsed */
if (awk->tree.nglobals == 0 &&
2008-12-21 21:35:07 +00:00
awk->tree.begin == QSE_NULL &&
awk->tree.end == QSE_NULL &&
awk->tree.chain_size == 0 &&
qse_map_getsize(awk->tree.funs) == 0)
{
/* if not, deny the run */
2008-12-21 21:35:07 +00:00
qse_awk_seterror (awk, QSE_AWK_ENOPER, 0, QSE_NULL, 0);
return -1;
}
/* allocate the storage for the run object */
run = (qse_awk_rtx_t*) QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_rtx_t));
2008-12-21 21:35:07 +00:00
if (run == QSE_NULL)
{
/* if it fails, the failure is reported thru
* the awk object */
2008-12-21 21:35:07 +00:00
qse_awk_seterror (awk, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
return -1;
}
/* clear the run object space */
QSE_MEMSET (run, 0, QSE_SIZEOF(qse_awk_rtx_t));
/* initialize the run object */
2008-08-19 05:21:48 +00:00
if (init_run (run, awk, runios, data) == -1)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (awk, run);
return -1;
}
/* clear the run error */
2008-12-21 21:35:07 +00:00
run->errnum = QSE_AWK_ENOERR;
run->errlin = 0;
2008-12-21 21:35:07 +00:00
run->errmsg[0] = QSE_T('\0');
run->cbs = runcbs;
/* execute the start callback if it exists */
2008-12-21 21:35:07 +00:00
if (runcbs != QSE_NULL && runcbs->on_start != QSE_NULL)
{
n = runcbs->on_start (run, runcbs->data);
if (n <= -1) n = -1;
}
/* enter the main run loop */
n = run_main (run, main, runarg);
if (n == -1)
{
2007-12-07 23:58:44 +00:00
/* if no callback is specified, awk's error number
* is updated with the run's error number */
2008-12-21 21:35:07 +00:00
if (runcbs == QSE_NULL)
{
2007-12-07 23:58:44 +00:00
awk->errnum = run->errnum;
awk->errlin = run->errlin;
2008-12-21 21:35:07 +00:00
qse_strxcpy (
awk->errmsg, QSE_COUNTOF(awk->errmsg),
2007-12-07 23:58:44 +00:00
run->errmsg);
}
else
{
2008-12-21 21:35:07 +00:00
qse_awk_seterrnum (awk, QSE_AWK_ERUNTIME);
}
}
/* the run loop ended. execute the end callback if it exists */
2008-12-21 21:35:07 +00:00
if (runcbs != QSE_NULL && runcbs->on_end != QSE_NULL)
{
if (n == 0)
{
/* clear error if run is successful just in case */
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR);
}
runcbs->on_end (run,
2008-12-21 21:35:07 +00:00
((n == -1)? run->errnum: QSE_AWK_ENOERR),
2008-08-19 05:21:48 +00:00
runcbs->data);
/* when using callbacks, this function always returns 0
* after the start callbacks has been triggered */
n = 0;
}
/* uninitialize the run object */
deinit_run (run);
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (awk, run);
return n;
}
void qse_awk_rtx_stop (qse_awk_rtx_t* run)
{
run->exit_level = EXIT_ABORT;
}
qse_bool_t qse_awk_rtx_shouldstop (qse_awk_rtx_t* run)
{
return (run->exit_level == EXIT_ABORT || run->awk->stopall);
}
2008-12-21 21:35:07 +00:00
static void free_namedval (qse_map_t* map, void* dptr, qse_size_t dlen)
{
qse_awk_rtx_refdownval (
*(qse_awk_rtx_t**)QSE_MAP_XTN(map), dptr);
}
2008-12-21 21:35:07 +00:00
static void same_namedval (qse_map_t* map, void* dptr, qse_size_t dlen)
2007-12-07 19:57:10 +00:00
{
qse_awk_rtx_refdownval_nofree (
*(qse_awk_rtx_t**)QSE_MAP_XTN(map), dptr);
2007-12-07 19:57:10 +00:00
}
static int init_run (
qse_awk_rtx_t* run, qse_awk_t* awk,
2008-12-21 21:35:07 +00:00
qse_awk_runios_t* runios, void* data)
{
run->awk = awk;
2008-08-19 05:21:48 +00:00
run->data = data;
2008-12-21 21:35:07 +00:00
run->stack = QSE_NULL;
run->stack_top = 0;
run->stack_base = 0;
run->stack_limit = 0;
run->exit_level = EXIT_NONE;
run->fcache_count = 0;
2008-01-16 03:03:40 +00:00
/*run->scache32_count = 0;
run->scache64_count = 0;*/
2008-12-21 21:35:07 +00:00
run->vmgr.ichunk = QSE_NULL;
run->vmgr.ifree = QSE_NULL;
run->vmgr.rchunk = QSE_NULL;
run->vmgr.rfree = QSE_NULL;
2008-12-21 21:35:07 +00:00
run->errnum = QSE_AWK_ENOERR;
run->errlin = 0;
2008-12-21 21:35:07 +00:00
run->errmsg[0] = QSE_T('\0');
run->inrec.buf_pos = 0;
run->inrec.buf_len = 0;
2008-12-21 21:35:07 +00:00
run->inrec.flds = QSE_NULL;
run->inrec.nflds = 0;
run->inrec.maxflds = 0;
2008-12-21 21:35:07 +00:00
run->inrec.d0 = qse_awk_val_nil;
if (qse_str_init (
&run->inrec.line, MMGR(run), DEF_BUF_CAPA) == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_awk_seterror (awk, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
if (qse_str_init (&run->format.out, MMGR(run), 256) == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_str_fini (&run->inrec.line);
qse_awk_seterror (awk, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
if (qse_str_init (&run->format.fmt, MMGR(run), 256) == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_str_fini (&run->format.out);
qse_str_fini (&run->inrec.line);
qse_awk_seterror (awk, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
run->named = qse_map_open (
MMGR(run), QSE_SIZEOF(run), 1024, 70);
if (run->named == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_str_fini (&run->format.fmt);
qse_str_fini (&run->format.out);
qse_str_fini (&run->inrec.line);
qse_awk_seterror (awk, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
return -1;
}
*(qse_awk_rtx_t**)QSE_MAP_XTN(run->named) = run;
2008-12-21 21:35:07 +00:00
qse_map_setcopier (run->named, QSE_MAP_KEY, QSE_MAP_COPIER_INLINE);
qse_map_setfreeer (run->named, QSE_MAP_VAL, free_namedval);
qse_map_setkeeper (run->named, same_namedval);
qse_map_setscale (run->named, QSE_MAP_KEY, QSE_SIZEOF(qse_char_t));
run->format.tmp.ptr = (qse_char_t*)
QSE_AWK_ALLOC (run->awk, 4096*QSE_SIZEOF(qse_char_t*));
if (run->format.tmp.ptr == QSE_NULL)
{
qse_map_close (run->named);
qse_str_fini (&run->format.fmt);
qse_str_fini (&run->format.out);
qse_str_fini (&run->inrec.line);
qse_awk_seterror (awk, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
return -1;
}
run->format.tmp.len = 4096;
run->format.tmp.inc = 4096*2;
if (run->awk->tree.chain_size > 0)
{
2008-12-21 21:35:07 +00:00
run->pattern_range_state = (qse_byte_t*) QSE_AWK_ALLOC (
run->awk, run->awk->tree.chain_size*QSE_SIZEOF(qse_byte_t));
if (run->pattern_range_state == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->format.tmp.ptr);
qse_map_close (run->named);
qse_str_fini (&run->format.fmt);
qse_str_fini (&run->format.out);
qse_str_fini (&run->inrec.line);
qse_awk_seterror (awk, QSE_AWK_ENOMEM, 0, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
QSE_MEMSET (
run->pattern_range_state, 0,
2008-12-21 21:35:07 +00:00
run->awk->tree.chain_size * QSE_SIZEOF(qse_byte_t));
}
2008-12-21 21:35:07 +00:00
else run->pattern_range_state = QSE_NULL;
2008-12-21 21:35:07 +00:00
if (runios != QSE_NULL)
{
run->eio.handler[QSE_AWK_EIO_PIPE] = runios->pipe;
run->eio.handler[QSE_AWK_EIO_FILE] = runios->file;
run->eio.handler[QSE_AWK_EIO_CONSOLE] = runios->console;
run->eio.data = runios->data;
run->eio.chain = QSE_NULL;
}
2008-12-21 21:35:07 +00:00
run->global.rs = QSE_NULL;
run->global.fs = QSE_NULL;
run->global.ignorecase = 0;
run->depth.max.block = awk->run.depth.max.block;
run->depth.max.expr = awk->run.depth.max.expr;
run->depth.cur.block = 0;
run->depth.cur.expr = 0;
return 0;
}
static void deinit_run (qse_awk_rtx_t* run)
{
2008-12-21 21:35:07 +00:00
if (run->pattern_range_state != QSE_NULL)
QSE_AWK_FREE (run->awk, run->pattern_range_state);
/* close all pending eio's */
/* TODO: what if this operation fails? */
qse_awk_cleareio (run);
QSE_ASSERT (run->eio.chain == QSE_NULL);
2008-12-21 21:35:07 +00:00
if (run->global.rs != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->global.rs);
run->global.rs = QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (run->global.fs != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->global.fs);
run->global.fs = QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (run->global.convfmt.ptr != QSE_NULL &&
run->global.convfmt.ptr != DEFAULT_CONVFMT)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->global.convfmt.ptr);
run->global.convfmt.ptr = QSE_NULL;
run->global.convfmt.len = 0;
}
2008-12-21 21:35:07 +00:00
if (run->global.ofmt.ptr != QSE_NULL &&
run->global.ofmt.ptr != DEFAULT_OFMT)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->global.ofmt.ptr);
run->global.ofmt.ptr = QSE_NULL;
run->global.ofmt.len = 0;
}
2008-12-21 21:35:07 +00:00
if (run->global.ofs.ptr != QSE_NULL &&
run->global.ofs.ptr != DEFAULT_OFS)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->global.ofs.ptr);
run->global.ofs.ptr = QSE_NULL;
run->global.ofs.len = 0;
}
2008-12-21 21:35:07 +00:00
if (run->global.ors.ptr != QSE_NULL &&
run->global.ors.ptr != DEFAULT_ORS &&
run->global.ors.ptr != DEFAULT_ORS_CRLF)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->global.ors.ptr);
run->global.ors.ptr = QSE_NULL;
run->global.ors.len = 0;
}
2008-12-21 21:35:07 +00:00
if (run->global.subsep.ptr != QSE_NULL &&
run->global.subsep.ptr != DEFAULT_SUBSEP)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->global.subsep.ptr);
run->global.subsep.ptr = QSE_NULL;
run->global.subsep.len = 0;
}
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->format.tmp.ptr);
run->format.tmp.ptr = QSE_NULL;
run->format.tmp.len = 0;
2008-12-21 21:35:07 +00:00
qse_str_fini (&run->format.fmt);
qse_str_fini (&run->format.out);
/* destroy input record. qse_awk_rtx_clrrec should be called
* before the run stack has been destroyed because it may try
2008-12-21 21:35:07 +00:00
* to change the value to QSE_AWK_GLOBAL_NF. */
qse_awk_rtx_clrrec (run, QSE_FALSE);
2008-12-21 21:35:07 +00:00
if (run->inrec.flds != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->inrec.flds);
run->inrec.flds = QSE_NULL;
run->inrec.maxflds = 0;
}
2008-12-21 21:35:07 +00:00
qse_str_fini (&run->inrec.line);
/* destroy run stack */
2008-12-21 21:35:07 +00:00
if (run->stack != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (run->stack_top == 0);
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, run->stack);
run->stack = QSE_NULL;
run->stack_top = 0;
run->stack_base = 0;
run->stack_limit = 0;
}
/* destroy named variables */
2008-12-21 21:35:07 +00:00
qse_map_close (run->named);
/* destroy values in free list */
while (run->fcache_count > 0)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_ref_t* tmp = run->fcache[--run->fcache_count];
qse_awk_rtx_freeval (run, (qse_awk_val_t*)tmp, QSE_FALSE);
}
2008-01-16 03:01:47 +00:00
2008-01-16 03:03:40 +00:00
/*while (run->scache32_count > 0)
2008-01-16 03:01:47 +00:00
{
2008-12-21 21:35:07 +00:00
qse_awk_val_str_t* tmp = run->scache32[--run->scache32_count];
qse_awk_rtx_freeval (run, (qse_awk_val_t*)tmp, QSE_FALSE);
2008-01-16 03:01:47 +00:00
}
while (run->scache64_count > 0)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_str_t* tmp = run->scache64[--run->scache64_count];
qse_awk_rtx_freeval (run, (qse_awk_val_t*)tmp, QSE_FALSE);
2008-01-16 03:03:40 +00:00
}*/
2008-01-16 08:03:41 +00:00
qse_awk_rtx_freevalchunk (run, run->vmgr.ichunk);
qse_awk_rtx_freevalchunk (run, run->vmgr.rchunk);
2008-12-21 21:35:07 +00:00
run->vmgr.ichunk = QSE_NULL;
run->vmgr.rchunk = QSE_NULL;
}
static int build_runarg (
qse_awk_rtx_t* run, const qse_cstr_t* runarg, qse_size_t* nargs)
{
const qse_cstr_t* p;
2008-12-21 21:35:07 +00:00
qse_size_t argc;
qse_awk_val_t* v_argc;
qse_awk_val_t* v_argv;
qse_awk_val_t* v_tmp;
qse_char_t key[QSE_SIZEOF(qse_long_t)*8+2];
qse_size_t key_len;
v_argv = qse_awk_rtx_makemapval (run);
2008-12-21 21:35:07 +00:00
if (v_argv == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, v_argv);
2008-12-21 21:35:07 +00:00
if (runarg == QSE_NULL) argc = 0;
else
{
2008-12-21 21:35:07 +00:00
for (argc = 0, p = runarg; p->ptr != QSE_NULL; argc++, p++)
{
v_tmp = qse_awk_rtx_makestrval (run, p->ptr, p->len);
2008-12-21 21:35:07 +00:00
if (v_tmp == QSE_NULL)
{
qse_awk_rtx_refdownval (run, v_argv);
return -1;
}
2008-12-21 21:35:07 +00:00
if (qse_awk_getoption(run->awk) & QSE_AWK_BASEONE)
{
2008-12-21 21:35:07 +00:00
key_len = qse_awk_longtostr (argc+1,
10, QSE_NULL, key, QSE_COUNTOF(key));
}
else
{
2008-12-21 21:35:07 +00:00
key_len = qse_awk_longtostr (argc,
10, QSE_NULL, key, QSE_COUNTOF(key));
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (key_len != (qse_size_t)-1);
/* increment reference count of v_tmp in advance as if
* it has successfully been assigned into ARGV. */
qse_awk_rtx_refupval (run, v_tmp);
2008-12-21 21:35:07 +00:00
if (qse_map_upsert (
((qse_awk_val_map_t*)v_argv)->map,
key, key_len, v_tmp, 0) == QSE_NULL)
{
/* if the assignment operation fails, decrements
* the reference of v_tmp to free it */
qse_awk_rtx_refdownval (run, v_tmp);
/* the values previously assigned into the
* map will be freeed when v_argv is freed */
qse_awk_rtx_refdownval (run, v_argv);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
}
}
v_argc = qse_awk_rtx_makeintval (run, (qse_long_t)argc);
2008-12-21 21:35:07 +00:00
if (v_argc == QSE_NULL)
{
qse_awk_rtx_refdownval (run, v_argv);
return -1;
}
qse_awk_rtx_refupval (run, v_argc);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
STACK_GLOBAL(run,QSE_AWK_GLOBAL_ARGC) == qse_awk_val_nil);
if (qse_awk_rtx_setglobal (run, QSE_AWK_GLOBAL_ARGC, v_argc) == -1)
{
qse_awk_rtx_refdownval (run, v_argc);
qse_awk_rtx_refdownval (run, v_argv);
return -1;
}
if (qse_awk_rtx_setglobal (run, QSE_AWK_GLOBAL_ARGV, v_argv) == -1)
{
/* ARGC is assigned nil when ARGV assignment has failed.
* However, this requires preconditions, as follows:
* 1. build_runarg should be called in a proper place
* as it is not a generic-purpose routine.
* 2. ARGC should be nil before build_runarg is called
* If the restoration fails, nothing can salvage it. */
qse_awk_rtx_setglobal (run, QSE_AWK_GLOBAL_ARGC, qse_awk_val_nil);
qse_awk_rtx_refdownval (run, v_argc);
qse_awk_rtx_refdownval (run, v_argv);
return -1;
}
qse_awk_rtx_refdownval (run, v_argc);
qse_awk_rtx_refdownval (run, v_argv);
*nargs = argc;
return 0;
}
static int update_fnr (qse_awk_rtx_t* run, qse_long_t fnr, qse_long_t nr)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp1, * tmp2;
tmp1 = qse_awk_rtx_makeintval (run, fnr);
2008-12-21 21:35:07 +00:00
if (tmp1 == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, tmp1);
if (nr == fnr) tmp2 = tmp1;
else
{
tmp2 = qse_awk_rtx_makeintval (run, nr);
2008-12-21 21:35:07 +00:00
if (tmp2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, tmp1);
return -1;
}
qse_awk_rtx_refupval (run, tmp2);
}
if (qse_awk_rtx_setglobal (run, QSE_AWK_GLOBAL_FNR, tmp1) == -1)
{
if (nr != fnr) qse_awk_rtx_refdownval (run, tmp2);
qse_awk_rtx_refdownval (run, tmp1);
return -1;
}
if (qse_awk_rtx_setglobal (run, QSE_AWK_GLOBAL_NR, tmp2) == -1)
{
if (nr != fnr) qse_awk_rtx_refdownval (run, tmp2);
qse_awk_rtx_refdownval (run, tmp1);
return -1;
}
if (nr != fnr) qse_awk_rtx_refdownval (run, tmp2);
qse_awk_rtx_refdownval (run, tmp1);
return 0;
}
static int set_globals_to_default (qse_awk_rtx_t* run)
{
struct gtab_t
{
int idx;
2008-12-21 21:35:07 +00:00
const qse_char_t* str;
} gtab[] =
{
2008-12-21 21:35:07 +00:00
{ QSE_AWK_GLOBAL_CONVFMT, DEFAULT_CONVFMT },
{ QSE_AWK_GLOBAL_FILENAME, QSE_NULL },
{ QSE_AWK_GLOBAL_OFILENAME, QSE_NULL },
{ QSE_AWK_GLOBAL_OFMT, DEFAULT_OFMT },
{ QSE_AWK_GLOBAL_OFS, DEFAULT_OFS },
{ QSE_AWK_GLOBAL_ORS, DEFAULT_ORS },
{ QSE_AWK_GLOBAL_SUBSEP, DEFAULT_SUBSEP },
};
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp;
qse_size_t i, j;
2008-12-21 21:35:07 +00:00
if (run->awk->option & QSE_AWK_CRLF)
{
/* ugly */
gtab[5].str = DEFAULT_ORS_CRLF;
}
2008-12-21 21:35:07 +00:00
for (i = 0; i < QSE_COUNTOF(gtab); i++)
{
2008-12-21 21:35:07 +00:00
if (gtab[i].str == QSE_NULL || gtab[i].str[0] == QSE_T('\0'))
{
2008-12-21 21:35:07 +00:00
tmp = qse_awk_val_zls;
}
else
{
tmp = qse_awk_rtx_makestrval0 (run, gtab[i].str);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL) return -1;
}
qse_awk_rtx_refupval (run, tmp);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
STACK_GLOBAL(run,gtab[i].idx) == qse_awk_val_nil);
if (qse_awk_rtx_setglobal (run, gtab[i].idx, tmp) == -1)
{
for (j = 0; j < i; j++)
{
qse_awk_rtx_setglobal (
2008-12-21 21:35:07 +00:00
run, gtab[i].idx, qse_awk_val_nil);
}
qse_awk_rtx_refdownval (run, tmp);
return -1;
}
qse_awk_rtx_refdownval (run, tmp);
}
return 0;
}
2007-12-07 23:58:44 +00:00
struct capture_retval_data_t
{
qse_awk_rtx_t* run;
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
2007-12-07 23:58:44 +00:00
};
static void capture_retval_on_exit (void* arg)
{
struct capture_retval_data_t* data;
data = (struct capture_retval_data_t*)arg;
data->val = STACK_RETVAL(data->run);
qse_awk_rtx_refupval (data->run, data->val);
2007-12-07 23:58:44 +00:00
}
static int prepare_globals (qse_awk_rtx_t* run, const qse_cstr_t* runarg)
{
qse_size_t saved_stack_top;
qse_size_t nglobals;
qse_size_t nrunargs;
saved_stack_top = run->stack_top;
nglobals = run->awk->tree.nglobals;
/* initialize all global variables to nil by push nils to the stack */
while (nglobals > 0)
{
--nglobals;
if (__raw_push(run,qse_awk_val_nil) == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
goto oops;
}
}
/* override NF to zero */
if (qse_awk_rtx_setglobal (
run, QSE_AWK_GLOBAL_NF, qse_awk_val_zero) == -1) goto oops;
/* override ARGC and ARGV */
if (build_runarg (run, runarg, &nrunargs) == -1) goto oops;
/* return success */
return 0;
oops:
/* restore the stack_top this way instead of calling __raw_pop()
* as many times as successful __raw_push(). it is ok because
* the values pushed so far are qse_awk_val_nils and qse_awk_val_zeros.
*/
run->stack_top = saved_stack_top;
return -1;
}
static void refdown_globals (qse_awk_rtx_t* run, int pop)
{
qse_size_t nglobals;
nglobals = run->awk->tree.nglobals;
while (nglobals > 0)
{
--nglobals;
qse_awk_rtx_refdownval (run, STACK_GLOBAL(run,nglobals));
if (pop) __raw_pop (run);
else STACK_GLOBAL(run,nglobals) = qse_awk_val_nil;
}
}
static int enter_stack_frame (qse_awk_rtx_t* run)
{
qse_size_t saved_stack_top;
/* remember the current stack top */
saved_stack_top = run->stack_top;
/* push the current stack base */
if (__raw_push(run,(void*)run->stack_base) == -1) goto oops;
/* push the current stack top before push the current stack base */
if (__raw_push(run,(void*)saved_stack_top) == -1) goto oops;
/* secure space for a return value */
if (__raw_push(run,qse_awk_val_nil) == -1) goto oops;
/* secure space for STACK_NARGS */
if (__raw_push(run,qse_awk_val_nil) == -1) goto oops;
/* let the stack top remembered be the base of a new stack frame */
run->stack_base = saved_stack_top;
return 0;
oops:
/* restore the stack top in a cheesy(?) way.
* it is ok to do so as the values pushed are
* nils and binary numbers. */
run->stack_top = saved_stack_top;
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
static void exit_stack_frame (qse_awk_rtx_t* run)
{
/* At this point, the current stack frame should have
* the 4 entries pushed in enter_stack_frame(). */
QSE_ASSERT ((run->stack_top-run->stack_base) == 4);
run->stack_top = (qse_size_t)run->stack[run->stack_base+1];
run->stack_base = (qse_size_t)run->stack[run->stack_base+0];
}
static int run_bpae_loop (qse_awk_rtx_t* run)
{
qse_awk_nde_t* nde;
qse_size_t nargs, i;
qse_awk_val_t* v;
int ret = 0;
/* set nargs to zero */
nargs = 0;
STACK_NARGS(run) = (void*)nargs;
/* call the callback */
if (run->cbs != QSE_NULL && run->cbs->on_enter != QSE_NULL)
{
ret = run->cbs->on_enter (run, run->cbs->data);
if (ret <= -1) ret = -1;
}
/* execute the BEGIN block */
for (nde = run->awk->tree.begin;
ret == 0 && nde != QSE_NULL && run->exit_level < EXIT_GLOBAL;
nde = nde->next)
{
qse_awk_nde_blk_t* blk;
blk = (qse_awk_nde_blk_t*)nde;
QSE_ASSERT (blk->type == QSE_AWK_NDE_BLK);
run->active_block = blk;
run->exit_level = EXIT_NONE;
if (run_block (run, blk) == -1) ret = -1;
}
if (ret == -1 && run->errnum == QSE_AWK_ENOERR)
{
/* an error is returned with no error number set.
* this feature is used by eval_expression to
* abort the evaluation when exit() is executed
* during function evaluation */
ret = 0;
run->errlin = 0;
run->errmsg[0] = QSE_T('\0');
}
/* run pattern block loops */
if (ret == 0 &&
(run->awk->tree.chain != QSE_NULL ||
run->awk->tree.end != QSE_NULL) &&
run->exit_level < EXIT_GLOBAL)
{
if (run_pattern_blocks(run) == -1) ret = -1;
}
if (ret == -1 && run->errnum == QSE_AWK_ENOERR)
{
/* an error is returned with no error number set.
* this feature is used by eval_expression to
* abort the evaluation when exit() is executed
* during function evaluation */
ret = 0;
run->errlin = 0;
run->errmsg[0] = QSE_T('\0');
}
/* execute END blocks. the first END block is executed if the
* program is not explicitly aborted with qse_awk_rtx_stop().*/
for (nde = run->awk->tree.end;
ret == 0 && nde != QSE_NULL && run->exit_level < EXIT_ABORT;
nde = nde->next)
{
qse_awk_nde_blk_t* blk;
blk = (qse_awk_nde_blk_t*)nde;
QSE_ASSERT (blk->type == QSE_AWK_NDE_BLK);
run->active_block = blk;
run->exit_level = EXIT_NONE;
if (run_block (run, blk) == -1) ret = -1;
else if (run->exit_level >= EXIT_GLOBAL)
{
/* once exit is called inside one of END blocks,
* subsequent END blocks must not be executed */
break;
}
}
if (ret == -1 && run->errnum == QSE_AWK_ENOERR)
{
/* an error is returned with no error number set.
* this feature is used by eval_expression to
* abort the evaluation when exit() is executed
* during function evaluation */
ret = 0;
run->errlin = 0;
run->errmsg[0] = QSE_T('\0');
}
/* derefrence all arguments. however, there should be no arguments
* pushed to the stack as asserted below. we didn't push any arguments
* for BEGIN/pattern action/END block execution.*/
nargs = (qse_size_t)STACK_NARGS(run);
QSE_ASSERT (nargs == 0);
for (i = 0; i < nargs; i++) qse_awk_rtx_refdownval (run, STACK_ARG(run,i));
/* get the return value in the current stack frame */
v = STACK_RETVAL(run);
if (ret == 0)
{
if (run->cbs != QSE_NULL && run->cbs->on_exit != QSE_NULL)
{
run->cbs->on_exit (run, v, run->cbs->data);
}
}
/* end the life of the global return value */
qse_awk_rtx_refdownval (run, v);
return ret;
}
static int run_bpae (qse_awk_rtx_t* run, const qse_cstr_t* runarg)
{
int ret;
/* the stack must be clean when this function
* is invoked */
QSE_ASSERT (run->stack_base == 0);
QSE_ASSERT (run->stack_top == 0);
run->exit_level = EXIT_NONE;
/* prepare global variables with initial primitive values */
ret = prepare_globals (run, runarg);
if (ret == 0)
{
/* adjust global variables a little more */
ret = update_fnr (run, 0, 0);
if (ret == 0) ret = set_globals_to_default(run);
/* run the BEGIN/pattern action/END blocks */
if (ret == 0)
{
ret = enter_stack_frame (run);
if (ret == 0)
{
ret = run_bpae_loop (run);
exit_stack_frame (run);
}
}
/* destroy global variables */
refdown_globals (run, 1);
}
/* reset the exit level */
run->exit_level = EXIT_NONE;
return ret;
}
static int qse_awk_pushfuncarg (qse_awk_rtx_t* run, qse_awk_val_t* val)
{
}
static int qse_awk_runfunc (qse_awk_rtx_t* run, const qse_char_t* name)
{
int ret = 0;
struct capture_retval_data_t crdata;
qse_awk_nde_call_t nde;
qse_awk_val_t* v;
/* forge a fake node containing a function call */
nde.type = QSE_AWK_NDE_AFN;
nde.line = 0;
nde.next = QSE_NULL;
nde.what.fun.name.ptr = (qse_char_t*)name;
nde.what.fun.name.len = qse_strlen(name);
nde.args = QSE_NULL;
nde.nargs = 0;
#if 0
if (runarg != QSE_NULL)
{
/* prepare to pass the arguments to the main function */
for (i = nrunargs; i > 0; )
{
qse_awk_nde_str_t* tmp, * tmp2;
i--;
tmp = (qse_awk_nde_str_t*) QSE_AWK_ALLOC (
run->awk, QSE_SIZEOF(*tmp));
if (tmp == QSE_NULL)
{
tmp = (qse_awk_nde_str_t*)nde.args;
while (tmp != QSE_NULL)
{
tmp2 = (qse_awk_nde_str_t*)tmp->next;
QSE_AWK_FREE (run->awk, tmp->ptr);
QSE_AWK_FREE (run->awk, tmp);
tmp = tmp2;
}
refdown_globals (run, 0);
run->stack_top = saved_stack_top;
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
tmp->type = QSE_AWK_NDE_STR;
tmp->ptr = QSE_AWK_STRXDUP (run->awk,
runarg[i].ptr, runarg[i].len);
if (tmp->ptr == QSE_NULL)
{
QSE_AWK_FREE (run->awk, tmp);
tmp = (qse_awk_nde_str_t*)nde.args;
while (tmp != QSE_NULL)
{
tmp2 = (qse_awk_nde_str_t*)tmp->next;
QSE_AWK_FREE (run->awk, tmp->ptr);
QSE_AWK_FREE (run->awk, tmp);
tmp = tmp2;
}
refdown_globals (run, 0);
run->stack_top = saved_stack_top;
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
tmp->len = runarg[i].len;
tmp->next = nde.args;
nde.args = (qse_awk_nde_t*)tmp;
nde.nargs++;
}
QSE_ASSERT (nrunargs == nde.nargs);
}
#endif
crdata.run = run;
crdata.val = QSE_NULL;
v = eval_fun_intrinsic (run, (qse_awk_nde_t*)&nde,
capture_retval_on_exit, &crdata);
if (v == QSE_NULL)
{
if (crdata.val == QSE_NULL)
{
QSE_ASSERT (run->errnum != QSE_AWK_ENOERR);
ret = -1;
}
else
{
if (run->errnum == QSE_AWK_ENOERR)
{
if (run->cbs != QSE_NULL && run->cbs->on_exit != QSE_NULL)
{
run->cbs->on_exit (run, crdata.val, run->cbs->data);
}
}
else ret = -1;
qse_awk_rtx_refdownval(run, crdata.val);
}
}
else
{
qse_awk_rtx_refupval (run, v);
if (run->cbs != QSE_NULL && run->cbs->on_exit != QSE_NULL)
{
run->cbs->on_exit (run, v, run->cbs->data);
}
qse_awk_rtx_refdownval (run, v);
}
if (nde.args != QSE_NULL) qse_awk_clrpt (run->awk, nde.args);
return ret;
}
static int run_function (
qse_awk_rtx_t* run, const qse_char_t* main, const qse_cstr_t* runarg)
{
int ret;
run->exit_level = EXIT_NONE;
ret = prepare_globals (run, runarg);
if (ret == 0)
{
/* adjust global variables a little more */
ret = update_fnr (run, 0, 0);
if (ret == 0) ret = set_globals_to_default(run);
if (ret == 0)
{
/* TODO: */
}
refdown_globals (run, 1);
}
return ret;
}
static int run_main (
qse_awk_rtx_t* run, const qse_char_t* name,
const qse_cstr_t* runarg)
{
return (name == QSE_NULL)?
run_bpae (run, runarg):
run_function (run, name, runarg);
}
static int ____run_main_to_be_removed____ (
qse_awk_rtx_t* run, const qse_char_t* main,
const qse_cstr_t* runarg)
{
2008-12-21 21:35:07 +00:00
qse_size_t nglobals, nargs, nrunargs, i;
qse_size_t saved_stack_top;
qse_awk_val_t* v;
int n;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (run->stack_base == 0 && run->stack_top == 0);
/* secure space for global variables */
saved_stack_top = run->stack_top;
nglobals = run->awk->tree.nglobals;
while (nglobals > 0)
{
--nglobals;
2008-12-21 21:35:07 +00:00
if (__raw_push(run,qse_awk_val_nil) == -1)
{
/* restore the stack_top with the saved value
* instead of calling __raw_pop as many times as
* the successful __raw_push. it is ok because
2008-12-21 21:35:07 +00:00
* the values pushed so far are all qse_awk_val_nil */
run->stack_top = saved_stack_top;
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
}
if (qse_awk_rtx_setglobal (run, QSE_AWK_GLOBAL_NF, qse_awk_val_zero) == -1)
{
/* it can simply restore the top of the stack this way
* because the values pused onto the stack so far are
2008-12-21 21:35:07 +00:00
* all qse_awk_val_nils and qse_awk_val_zeros */
run->stack_top = saved_stack_top;
return -1;
}
if (build_runarg (run, runarg, &nrunargs) == -1)
{
/* it can simply restore the top of the stack this way
* because the values pused onto the stack so far are
2008-12-21 21:35:07 +00:00
* all qse_awk_val_nils and qse_awk_val_zeros and
* build_runarg doesn't push other values than them
* when it has failed */
run->stack_top = saved_stack_top;
return -1;
}
run->exit_level = EXIT_NONE;
n = update_fnr (run, 0, 0);
if (n == 0) n = set_globals_to_default (run);
2008-12-21 21:35:07 +00:00
if (n == 0 && main != QSE_NULL)
{
/* run the given function */
2007-12-07 23:58:44 +00:00
struct capture_retval_data_t crdata;
2008-12-21 21:35:07 +00:00
qse_awk_nde_call_t nde;
2008-12-21 21:35:07 +00:00
nde.type = QSE_AWK_NDE_AFN;
nde.line = 0;
2008-12-21 21:35:07 +00:00
nde.next = QSE_NULL;
nde.what.fun.name.ptr = (qse_char_t*)main;
nde.what.fun.name.len = qse_strlen(main);
2008-12-21 21:35:07 +00:00
nde.args = QSE_NULL;
nde.nargs = 0;
2008-12-21 21:35:07 +00:00
if (runarg != QSE_NULL)
{
2007-12-07 23:58:44 +00:00
2008-12-21 21:35:07 +00:00
if (!(run->awk->option & QSE_AWK_ARGSTOMAIN))
{
/* if the option is not set, the arguments
* are not passed to the main function as
* parameters */
nrunargs = 0;
}
/* prepare to pass the arguments to the main function */
for (i = nrunargs; i > 0; )
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_str_t* tmp, * tmp2;
i--;
2008-12-21 21:35:07 +00:00
tmp = (qse_awk_nde_str_t*) QSE_AWK_ALLOC (
run->awk, QSE_SIZEOF(*tmp));
if (tmp == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
tmp = (qse_awk_nde_str_t*)nde.args;
while (tmp != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
tmp2 = (qse_awk_nde_str_t*)tmp->next;
QSE_AWK_FREE (run->awk, tmp->ptr);
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, tmp);
tmp = tmp2;
}
refdown_globals (run, 0);
run->stack_top = saved_stack_top;
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
2008-12-21 21:35:07 +00:00
tmp->type = QSE_AWK_NDE_STR;
tmp->ptr = QSE_AWK_STRXDUP (run->awk,
runarg[i].ptr, runarg[i].len);
if (tmp->ptr == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, tmp);
tmp = (qse_awk_nde_str_t*)nde.args;
while (tmp != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
tmp2 = (qse_awk_nde_str_t*)tmp->next;
QSE_AWK_FREE (run->awk, tmp->ptr);
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, tmp);
tmp = tmp2;
}
refdown_globals (run, 0);
run->stack_top = saved_stack_top;
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
tmp->len = runarg[i].len;
tmp->next = nde.args;
2008-12-21 21:35:07 +00:00
nde.args = (qse_awk_nde_t*)tmp;
nde.nargs++;
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nrunargs == nde.nargs);
}
2007-12-07 23:58:44 +00:00
crdata.run = run;
2008-12-21 21:35:07 +00:00
crdata.val = QSE_NULL;
v = eval_fun_intrinsic (run, (qse_awk_nde_t*)&nde,
2007-12-07 23:58:44 +00:00
capture_retval_on_exit, &crdata);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL)
2007-12-07 23:58:44 +00:00
{
2008-12-21 21:35:07 +00:00
if (crdata.val == QSE_NULL)
2007-12-07 23:58:44 +00:00
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (run->errnum != QSE_AWK_ENOERR);
2007-12-07 23:58:44 +00:00
n = -1;
}
else
{
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
2007-12-07 23:58:44 +00:00
{
if (run->cbs != QSE_NULL && run->cbs->on_exit != QSE_NULL)
2007-12-07 23:58:44 +00:00
{
run->cbs->on_exit (run, crdata.val, run->cbs->data);
2007-12-07 23:58:44 +00:00
}
}
else n = -1;
qse_awk_rtx_refdownval(run, crdata.val);
2007-12-07 23:58:44 +00:00
}
}
else
{
qse_awk_rtx_refupval (run, v);
if (run->cbs != QSE_NULL && run->cbs->on_exit != QSE_NULL)
{
run->cbs->on_exit (run, v, run->cbs->data);
}
qse_awk_rtx_refdownval (run, v);
}
2008-12-21 21:35:07 +00:00
if (nde.args != QSE_NULL) qse_awk_clrpt (run->awk, nde.args);
}
else if (n == 0)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_t* nde;
2007-12-05 08:13:38 +00:00
/* no main function is specified.
* run the normal pattern blocks including BEGIN and END */
saved_stack_top = run->stack_top;
if (__raw_push(run,(void*)run->stack_base) == -1)
{
/* restore the stack top in a cheesy(?) way */
run->stack_top = saved_stack_top;
/* pops off global variables in a decent way */
/*refdown_globals (run);
__raw_pop_times (run, run->awk->tree.nglobals);*/
refdown_globals (run, 1);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
if (__raw_push(run,(void*)saved_stack_top) == -1)
{
run->stack_top = saved_stack_top;
/*refdown_globals (run);
__raw_pop_times (run, run->awk->tree.nglobals); */
refdown_globals (run, 1);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
/* secure space for a return value */
2008-12-21 21:35:07 +00:00
if (__raw_push(run,qse_awk_val_nil) == -1)
{
run->stack_top = saved_stack_top;
/*refdown_globals (run);
__raw_pop_times (run, run->awk->tree.nglobals);*/
refdown_globals (run, 1);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
/* secure space for nargs */
2008-12-21 21:35:07 +00:00
if (__raw_push(run,qse_awk_val_nil) == -1)
{
run->stack_top = saved_stack_top;
/*refdown_globals (run);
__raw_pop_times (run, run->awk->tree.nglobals);*/
refdown_globals (run, 1);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
run->stack_base = saved_stack_top;
/* set nargs to zero */
nargs = 0;
STACK_NARGS(run) = (void*)nargs;
/* stack set up properly. ready to exeucte statement blocks */
2007-12-05 08:13:38 +00:00
for (nde = run->awk->tree.begin;
2008-12-21 21:35:07 +00:00
n == 0 && nde != QSE_NULL && run->exit_level < EXIT_GLOBAL;
2007-12-05 08:13:38 +00:00
nde = nde->next)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_blk_t* blk;
2008-12-21 21:35:07 +00:00
blk = (qse_awk_nde_blk_t*)nde;
QSE_ASSERT (blk->type == QSE_AWK_NDE_BLK);
run->active_block = blk;
run->exit_level = EXIT_NONE;
if (run_block (run, blk) == -1) n = -1;
}
2008-12-21 21:35:07 +00:00
if (n == -1 && run->errnum == QSE_AWK_ENOERR)
2007-12-07 23:58:44 +00:00
{
/* an error is returned with no error number set.
* this feature is used by eval_expression to
* abort the evaluation when exit() is executed
* during function evaluation */
n = 0;
run->errlin = 0;
2008-12-21 21:35:07 +00:00
run->errmsg[0] = QSE_T('\0');
2007-12-07 23:58:44 +00:00
}
if (n == 0 &&
2008-12-21 21:35:07 +00:00
(run->awk->tree.chain != QSE_NULL ||
run->awk->tree.end != QSE_NULL) &&
2007-12-06 08:10:34 +00:00
run->exit_level < EXIT_GLOBAL)
{
if (run_pattern_blocks (run) == -1) n = -1;
}
2008-12-21 21:35:07 +00:00
if (n == -1 && run->errnum == QSE_AWK_ENOERR)
2007-12-07 23:58:44 +00:00
{
/* an error is returned with no error number set.
* this feature is used by eval_expression to
* abort the evaluation when exit() is executed
* during function evaluation */
n = 0;
run->errlin = 0;
2008-12-21 21:35:07 +00:00
run->errmsg[0] = QSE_T('\0');
2007-12-07 23:58:44 +00:00
}
2007-12-06 08:10:34 +00:00
/* the first END block is executed if the program is not
* explicitly aborted with qse_awk_rtx_stop */
2007-12-05 08:13:38 +00:00
for (nde = run->awk->tree.end;
2008-12-21 21:35:07 +00:00
n == 0 && nde != QSE_NULL && run->exit_level < EXIT_ABORT;
2007-12-05 08:13:38 +00:00
nde = nde->next)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_blk_t* blk;
2008-12-21 21:35:07 +00:00
blk = (qse_awk_nde_blk_t*)nde;
QSE_ASSERT (blk->type == QSE_AWK_NDE_BLK);
run->active_block = blk;
run->exit_level = EXIT_NONE;
if (run_block (run, blk) == -1) n = -1;
2007-12-06 08:10:34 +00:00
else if (run->exit_level >= EXIT_GLOBAL)
{
/* once exit is called inside one of END blocks,
* subsequent END blocks must not be executed */
break;
}
}
2008-12-21 21:35:07 +00:00
if (n == -1 && run->errnum == QSE_AWK_ENOERR)
2007-12-07 23:58:44 +00:00
{
/* an error is returned with no error number set.
* this feature is used by eval_expression to
* abort the evaluation when exit() is executed
* during function evaluation */
n = 0;
run->errlin = 0;
2008-12-21 21:35:07 +00:00
run->errmsg[0] = QSE_T('\0');
2007-12-07 23:58:44 +00:00
}
/* restore stack */
2008-12-21 21:35:07 +00:00
nargs = (qse_size_t)STACK_NARGS(run);
QSE_ASSERT (nargs == 0);
for (i = 0; i < nargs; i++)
{
qse_awk_rtx_refdownval (run, STACK_ARG(run,i));
}
v = STACK_RETVAL(run);
if (n == 0)
{
if (run->cbs != QSE_NULL && run->cbs->on_exit != QSE_NULL)
{
run->cbs->on_exit (run, v, run->cbs->data);
}
}
/* end the life of the global return value */
qse_awk_rtx_refdownval (run, v);
run->stack_top =
2008-12-21 21:35:07 +00:00
(qse_size_t)run->stack[run->stack_base+1];
run->stack_base =
2008-12-21 21:35:07 +00:00
(qse_size_t)run->stack[run->stack_base+0];
}
/* pops off the global variables */
nglobals = run->awk->tree.nglobals;
while (nglobals > 0)
{
--nglobals;
qse_awk_rtx_refdownval (run, STACK_GLOBAL(run,nglobals));
__raw_pop (run);
}
/* reset the exit level */
run->exit_level = EXIT_NONE;
return n;
}
static int run_pattern_blocks (qse_awk_rtx_t* run)
{
int n;
#define ADJUST_ERROR_LINE(run) \
2008-12-21 21:35:07 +00:00
if (run->awk->tree.chain != QSE_NULL) \
{ \
2008-12-21 21:35:07 +00:00
if (run->awk->tree.chain->pattern != QSE_NULL) \
run->errlin = run->awk->tree.chain->pattern->line; \
2008-12-21 21:35:07 +00:00
else if (run->awk->tree.chain->action != QSE_NULL) \
run->errlin = run->awk->tree.chain->action->line; \
} \
2008-12-21 21:35:07 +00:00
else if (run->awk->tree.end != QSE_NULL) \
{ \
run->errlin = run->awk->tree.end->line; \
}
run->inrec.buf_pos = 0;
run->inrec.buf_len = 0;
2008-12-21 21:35:07 +00:00
run->inrec.eof = QSE_FALSE;
/* run each pattern block */
2007-12-06 08:10:34 +00:00
while (run->exit_level < EXIT_GLOBAL)
{
run->exit_level = EXIT_NONE;
n = read_record (run);
if (n == -1)
{
ADJUST_ERROR_LINE (run);
return -1; /* error */
}
if (n == 0) break; /* end of input */
if (update_fnr (run, run->global.fnr+1, run->global.nr+1) == -1)
{
ADJUST_ERROR_LINE (run);
return -1;
}
2008-12-21 21:35:07 +00:00
if (run->awk->tree.chain != QSE_NULL)
{
if (run_pattern_block_chain (
run, run->awk->tree.chain) == -1) return -1;
}
}
#undef ADJUST_ERROR_LINE
return 0;
}
static int run_pattern_block_chain (qse_awk_rtx_t* run, qse_awk_chain_t* chain)
{
2008-12-21 21:35:07 +00:00
qse_size_t block_no = 0;
2008-12-21 21:35:07 +00:00
while (run->exit_level < EXIT_GLOBAL && chain != QSE_NULL)
{
if (run->exit_level == EXIT_NEXT)
{
run->exit_level = EXIT_NONE;
break;
}
if (run_pattern_block (run, chain, block_no) == -1) return -1;
chain = chain->next;
block_no++;
}
return 0;
}
static int run_pattern_block (
qse_awk_rtx_t* run, qse_awk_chain_t* chain, qse_size_t block_no)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_t* ptn;
qse_awk_nde_blk_t* blk;
ptn = chain->pattern;
2008-12-21 21:35:07 +00:00
blk = (qse_awk_nde_blk_t*)chain->action;
2008-12-21 21:35:07 +00:00
if (ptn == QSE_NULL)
{
/* just execute the block */
run->active_block = blk;
if (run_block (run, blk) == -1) return -1;
}
else
{
2008-12-21 21:35:07 +00:00
if (ptn->next == QSE_NULL)
{
/* pattern { ... } */
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v1;
v1 = eval_expression (run, ptn);
2008-12-21 21:35:07 +00:00
if (v1 == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, v1);
if (qse_awk_rtx_valtobool (run, v1))
{
run->active_block = blk;
if (run_block (run, blk) == -1)
{
qse_awk_rtx_refdownval (run, v1);
return -1;
}
}
qse_awk_rtx_refdownval (run, v1);
}
else
{
/* pattern, pattern { ... } */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (ptn->next->next == QSE_NULL);
QSE_ASSERT (run->pattern_range_state != QSE_NULL);
if (run->pattern_range_state[block_no] == 0)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v1;
v1 = eval_expression (run, ptn);
2008-12-21 21:35:07 +00:00
if (v1 == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, v1);
if (qse_awk_rtx_valtobool (run, v1))
{
run->active_block = blk;
if (run_block (run, blk) == -1)
{
qse_awk_rtx_refdownval (run, v1);
return -1;
}
run->pattern_range_state[block_no] = 1;
}
qse_awk_rtx_refdownval (run, v1);
}
else if (run->pattern_range_state[block_no] == 1)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v2;
v2 = eval_expression (run, ptn->next);
2008-12-21 21:35:07 +00:00
if (v2 == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, v2);
run->active_block = blk;
if (run_block (run, blk) == -1)
{
qse_awk_rtx_refdownval (run, v2);
return -1;
}
if (qse_awk_rtx_valtobool (run, v2))
run->pattern_range_state[block_no] = 0;
qse_awk_rtx_refdownval (run, v2);
}
}
}
return 0;
}
static int run_block (qse_awk_rtx_t* run, qse_awk_nde_blk_t* nde)
{
int n;
if (run->depth.max.block > 0 &&
run->depth.cur.block >= run->depth.max.block)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EBLKNST, nde->line, QSE_NULL, 0);
return -1;;
}
run->depth.cur.block++;
n = run_block0 (run, nde);
run->depth.cur.block--;
return n;
}
static int run_block0 (qse_awk_rtx_t* run, qse_awk_nde_blk_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_t* p;
qse_size_t nlocals;
qse_size_t saved_stack_top;
int n = 0;
2008-12-21 21:35:07 +00:00
if (nde == QSE_NULL)
{
/* blockless pattern - execute print $0*/
qse_awk_rtx_refupval (run, run->inrec.d0);
n = qse_awk_writeeio_str (run,
2008-12-21 21:35:07 +00:00
QSE_AWK_OUT_CONSOLE, QSE_T(""),
QSE_STR_PTR(&run->inrec.line),
QSE_STR_LEN(&run->inrec.line));
if (n == -1)
{
qse_awk_rtx_refdownval (run, run->inrec.d0);
/* adjust the error line */
run->errlin = nde->line;
return -1;
}
n = qse_awk_writeeio_str (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_OUT_CONSOLE, QSE_T(""),
run->global.ors.ptr, run->global.ors.len);
if (n == -1)
{
qse_awk_rtx_refdownval (run, run->inrec.d0);
/* adjust the error line */
run->errlin = nde->line;
return -1;
}
qse_awk_rtx_refdownval (run, run->inrec.d0);
return 0;
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->type == QSE_AWK_NDE_BLK);
p = nde->body;
nlocals = nde->nlocals;
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (
QSE_T("securing space for local variables nlocals = %d\n"),
(int)nlocals);
#endif
saved_stack_top = run->stack_top;
/* secure space for local variables */
while (nlocals > 0)
{
--nlocals;
2008-12-21 21:35:07 +00:00
if (__raw_push(run,qse_awk_val_nil) == -1)
{
/* restore stack top */
run->stack_top = saved_stack_top;
return -1;
}
2008-12-21 21:35:07 +00:00
/* refupval is not required for qse_awk_val_nil */
}
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (QSE_T("executing block statements\n"));
#endif
2008-12-21 21:35:07 +00:00
while (p != QSE_NULL && run->exit_level == EXIT_NONE)
{
if (run_statement (run, p) == -1)
{
n = -1;
break;
}
p = p->next;
}
/* pop off local variables */
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (QSE_T("popping off local variables\n"));
#endif
nlocals = nde->nlocals;
while (nlocals > 0)
{
--nlocals;
qse_awk_rtx_refdownval (run, STACK_LOCAL(run,nlocals));
__raw_pop (run);
}
return n;
}
#define ON_STATEMENT(run,nde) \
if ((run)->awk->stopall) (run)->exit_level = EXIT_ABORT; \
2008-12-21 21:35:07 +00:00
if ((run)->cbs != QSE_NULL && \
(run)->cbs->on_statement != QSE_NULL) \
{ \
(run)->cbs->on_statement ( \
2008-08-19 05:21:48 +00:00
run, (nde)->line, (run)->cbs->data); \
}
static int run_statement (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
ON_STATEMENT (run, nde);
switch (nde->type)
{
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_NULL:
{
/* do nothing */
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_BLK:
{
if (run_block (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_blk_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_IF:
{
if (run_if (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_if_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_WHILE:
case QSE_AWK_NDE_DOWHILE:
{
if (run_while (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_while_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_FOR:
{
if (run_for (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_for_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_FOREACH:
{
if (run_foreach (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_foreach_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_BREAK:
{
if (run_break (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_break_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_CONTINUE:
{
if (run_continue (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_continue_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_RETURN:
{
if (run_return (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_return_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_EXIT:
{
if (run_exit (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_exit_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_NEXT:
{
if (run_next (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_next_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_NEXTFILE:
{
if (run_nextfile (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_nextfile_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_DELETE:
{
if (run_delete (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_delete_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_RESET:
{
if (run_reset (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_reset_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_PRINT:
{
if (run_print (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_print_t*)nde) == -1) return -1;
break;
}
2008-12-21 21:35:07 +00:00
case QSE_AWK_NDE_PRINTF:
{
if (run_printf (run,
2008-12-21 21:35:07 +00:00
(qse_awk_nde_print_t*)nde) == -1) return -1;
break;
}
default:
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
v = eval_expression (run, nde);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return -1;
/* destroy the value if not referenced */
qse_awk_rtx_refupval (run, v);
qse_awk_rtx_refdownval (run, v);
break;
}
}
return 0;
}
static int run_if (qse_awk_rtx_t* run, qse_awk_nde_if_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* test;
int n = 0;
/* the test expression for the if statement cannot have
* chained expressions. this should not be allowed by the
* parser first of all */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->test->next == QSE_NULL);
test = eval_expression (run, nde->test);
2008-12-21 21:35:07 +00:00
if (test == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, test);
if (qse_awk_rtx_valtobool (run, test))
{
n = run_statement (run, nde->then_part);
}
2008-12-21 21:35:07 +00:00
else if (nde->else_part != QSE_NULL)
{
n = run_statement (run, nde->else_part);
}
qse_awk_rtx_refdownval (run, test); /* TODO: is this correct?*/
return n;
}
static int run_while (qse_awk_rtx_t* run, qse_awk_nde_while_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* test;
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_WHILE)
{
/* no chained expressions are allowed for the test
* expression of the while statement */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->test->next == QSE_NULL);
while (1)
{
ON_STATEMENT (run, nde->test);
test = eval_expression (run, nde->test);
2008-12-21 21:35:07 +00:00
if (test == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, test);
if (qse_awk_rtx_valtobool (run, test))
{
if (run_statement(run,nde->body) == -1)
{
qse_awk_rtx_refdownval (run, test);
return -1;
}
}
else
{
qse_awk_rtx_refdownval (run, test);
break;
}
qse_awk_rtx_refdownval (run, test);
if (run->exit_level == EXIT_BREAK)
{
run->exit_level = EXIT_NONE;
break;
}
else if (run->exit_level == EXIT_CONTINUE)
{
run->exit_level = EXIT_NONE;
}
else if (run->exit_level != EXIT_NONE) break;
}
}
2008-12-21 21:35:07 +00:00
else if (nde->type == QSE_AWK_NDE_DOWHILE)
{
/* no chained expressions are allowed for the test
* expression of the while statement */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->test->next == QSE_NULL);
do
{
if (run_statement(run,nde->body) == -1) return -1;
if (run->exit_level == EXIT_BREAK)
{
run->exit_level = EXIT_NONE;
break;
}
else if (run->exit_level == EXIT_CONTINUE)
{
run->exit_level = EXIT_NONE;
}
else if (run->exit_level != EXIT_NONE) break;
ON_STATEMENT (run, nde->test);
test = eval_expression (run, nde->test);
2008-12-21 21:35:07 +00:00
if (test == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, test);
if (!qse_awk_rtx_valtobool (run, test))
{
qse_awk_rtx_refdownval (run, test);
break;
}
qse_awk_rtx_refdownval (run, test);
}
while (1);
}
return 0;
}
static int run_for (qse_awk_rtx_t* run, qse_awk_nde_for_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
2008-12-21 21:35:07 +00:00
if (nde->init != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->init->next == QSE_NULL);
ON_STATEMENT (run, nde->init);
val = eval_expression(run,nde->init);
2008-12-21 21:35:07 +00:00
if (val == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, val);
qse_awk_rtx_refdownval (run, val);
}
while (1)
{
2008-12-21 21:35:07 +00:00
if (nde->test != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* test;
/* no chained expressions for the test expression of
* the for statement are allowed */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->test->next == QSE_NULL);
ON_STATEMENT (run, nde->test);
test = eval_expression (run, nde->test);
2008-12-21 21:35:07 +00:00
if (test == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, test);
if (qse_awk_rtx_valtobool (run, test))
{
if (run_statement(run,nde->body) == -1)
{
qse_awk_rtx_refdownval (run, test);
return -1;
}
}
else
{
qse_awk_rtx_refdownval (run, test);
break;
}
qse_awk_rtx_refdownval (run, test);
}
else
{
if (run_statement(run,nde->body) == -1) return -1;
}
if (run->exit_level == EXIT_BREAK)
{
run->exit_level = EXIT_NONE;
break;
}
else if (run->exit_level == EXIT_CONTINUE)
{
run->exit_level = EXIT_NONE;
}
else if (run->exit_level != EXIT_NONE) break;
2008-12-21 21:35:07 +00:00
if (nde->incr != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->incr->next == QSE_NULL);
ON_STATEMENT (run, nde->incr);
val = eval_expression (run, nde->incr);
2008-12-21 21:35:07 +00:00
if (val == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, val);
qse_awk_rtx_refdownval (run, val);
}
}
return 0;
}
struct foreach_walker_t
{
qse_awk_rtx_t* run;
2008-12-21 21:35:07 +00:00
qse_awk_nde_t* var;
qse_awk_nde_t* body;
int ret;
};
2008-12-21 21:35:07 +00:00
static qse_map_walk_t walk_foreach (
qse_map_t* map, qse_map_pair_t* pair, void* arg)
{
struct foreach_walker_t* w = (struct foreach_walker_t*)arg;
2008-12-21 21:35:07 +00:00
qse_awk_val_t* str;
str = (qse_awk_val_t*) qse_awk_rtx_makestrval (
2008-12-21 21:35:07 +00:00
w->run, QSE_MAP_KPTR(pair), QSE_MAP_KLEN(pair));
if (str == QSE_NULL)
{
/* adjust the error line */
w->run->errlin = w->var->line;
w->ret = -1;
2008-12-21 21:35:07 +00:00
return QSE_MAP_WALK_STOP;
}
qse_awk_rtx_refupval (w->run, str);
2008-12-21 21:35:07 +00:00
if (do_assignment (w->run, w->var, str) == QSE_NULL)
{
qse_awk_rtx_refdownval (w->run, str);
w->ret = -1;
2008-12-21 21:35:07 +00:00
return QSE_MAP_WALK_STOP;
}
if (run_statement (w->run, w->body) == -1)
{
qse_awk_rtx_refdownval (w->run, str);
w->ret = -1;
2008-12-21 21:35:07 +00:00
return QSE_MAP_WALK_STOP;
}
qse_awk_rtx_refdownval (w->run, str);
2008-12-21 21:35:07 +00:00
return QSE_MAP_WALK_FORWARD;
}
static int run_foreach (qse_awk_rtx_t* run, qse_awk_nde_foreach_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_exp_t* test;
qse_awk_val_t* rv;
qse_map_t* map;
struct foreach_walker_t walker;
2008-12-21 21:35:07 +00:00
test = (qse_awk_nde_exp_t*)nde->test;
QSE_ASSERT (
test->type == QSE_AWK_NDE_EXP_BIN &&
test->opcode == QSE_AWK_BINOP_IN);
/* chained expressions should not be allowed
* by the parser first of all */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (test->right->next == QSE_NULL);
rv = eval_expression (run, test->right);
2008-12-21 21:35:07 +00:00
if (rv == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, rv);
2008-12-21 21:35:07 +00:00
if (rv->type != QSE_AWK_VAL_MAP)
{
qse_awk_rtx_refdownval (run, rv);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOTMAPIN, test->right->line, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
map = ((qse_awk_val_map_t*)rv)->map;
walker.run = run;
walker.var = test->left;
walker.body = nde->body;
walker.ret = 0;
2008-12-21 21:35:07 +00:00
qse_map_walk (map, walk_foreach, &walker);
qse_awk_rtx_refdownval (run, rv);
return walker.ret;
}
static int run_break (qse_awk_rtx_t* run, qse_awk_nde_break_t* nde)
{
run->exit_level = EXIT_BREAK;
return 0;
}
static int run_continue (qse_awk_rtx_t* run, qse_awk_nde_continue_t* nde)
{
run->exit_level = EXIT_CONTINUE;
return 0;
}
static int run_return (qse_awk_rtx_t* run, qse_awk_nde_return_t* nde)
{
2008-12-21 21:35:07 +00:00
if (nde->val != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
/* chained expressions should not be allowed
* by the parser first of all */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->val->next == QSE_NULL);
val = eval_expression (run, nde->val);
2008-12-21 21:35:07 +00:00
if (val == QSE_NULL) return -1;
2008-12-21 21:35:07 +00:00
if ((run->awk->option & QSE_AWK_MAPTOVAR) == 0)
{
2008-12-21 21:35:07 +00:00
if (val->type == QSE_AWK_VAL_MAP)
{
/* cannot return a map */
qse_awk_rtx_refupval (run, val);
qse_awk_rtx_refdownval (run, val);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EMAPNOTALLOWED,
nde->line, QSE_NULL, 0);
return -1;
}
}
qse_awk_rtx_refdownval (run, STACK_RETVAL(run));
STACK_RETVAL(run) = val;
qse_awk_rtx_refupval (run, val); /* see eval_call for the trick */
}
run->exit_level = EXIT_FUNCTION;
return 0;
}
static int run_exit (qse_awk_rtx_t* run, qse_awk_nde_exit_t* nde)
{
2008-12-21 21:35:07 +00:00
if (nde->val != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
/* chained expressions should not be allowed
* by the parser first of all */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->val->next == QSE_NULL);
val = eval_expression (run, nde->val);
2008-12-21 21:35:07 +00:00
if (val == QSE_NULL) return -1;
qse_awk_rtx_refdownval (run, STACK_RETVAL_GLOBAL(run));
STACK_RETVAL_GLOBAL(run) = val; /* global return value */
qse_awk_rtx_refupval (run, val);
}
run->exit_level = EXIT_GLOBAL;
return 0;
}
static int run_next (qse_awk_rtx_t* run, qse_awk_nde_next_t* nde)
{
/* the parser checks if next has been called in the begin/end
* block or whereever inappropriate. so the runtime doesn't
* check that explicitly */
2008-12-21 21:35:07 +00:00
if (run->active_block == (qse_awk_nde_blk_t*)run->awk->tree.begin)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ERNEXTBEG, nde->line, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
else if (run->active_block == (qse_awk_nde_blk_t*)run->awk->tree.end)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ERNEXTEND, nde->line, QSE_NULL, 0);
return -1;
}
run->exit_level = EXIT_NEXT;
return 0;
}
static int run_nextinfile (qse_awk_rtx_t* run, qse_awk_nde_nextfile_t* nde)
{
int n;
/* normal nextfile statement */
2008-12-21 21:35:07 +00:00
if (run->active_block == (qse_awk_nde_blk_t*)run->awk->tree.begin)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ERNEXTFBEG, nde->line, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
else if (run->active_block == (qse_awk_nde_blk_t*)run->awk->tree.end)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ERNEXTFEND, nde->line, QSE_NULL, 0);
return -1;
}
n = qse_awk_nexteio_read (run, QSE_AWK_IN_CONSOLE, QSE_T(""));
if (n == -1)
{
/* adjust the error line */
run->errlin = nde->line;
return -1;
}
if (n == 0)
{
/* no more input console */
run->exit_level = EXIT_GLOBAL;
return 0;
}
/* FNR resets to 0, NR remains the same */
if (update_fnr (run, 0, run->global.nr) == -1)
{
run->errlin = nde->line;
return -1;
}
run->exit_level = EXIT_NEXT;
return 0;
}
static int run_nextoutfile (qse_awk_rtx_t* run, qse_awk_nde_nextfile_t* nde)
{
int n;
/* nextofile can be called from BEGIN and END block unlike nextfile */
n = qse_awk_nexteio_write (run, QSE_AWK_OUT_CONSOLE, QSE_T(""));
if (n == -1)
{
/* adjust the error line */
run->errlin = nde->line;
return -1;
}
if (n == 0)
{
/* should it terminate the program there is no more
* output console? no. there will just be no more console
* output */
/*run->exit_level = EXIT_GLOBAL;*/
return 0;
}
return 0;
}
static int run_nextfile (qse_awk_rtx_t* run, qse_awk_nde_nextfile_t* nde)
{
return (nde->out)?
run_nextoutfile (run, nde):
run_nextinfile (run, nde);
}
static int run_delete (qse_awk_rtx_t* run, qse_awk_nde_delete_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_var_t* var;
2008-12-21 21:35:07 +00:00
var = (qse_awk_nde_var_t*) nde->var;
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_NAMED ||
var->type == QSE_AWK_NDE_NAMEDIDX)
{
2008-12-21 21:35:07 +00:00
qse_map_pair_t* pair;
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (
(var->type == QSE_AWK_NDE_NAMED && var->idx == QSE_NULL) ||
(var->type == QSE_AWK_NDE_NAMEDIDX && var->idx != QSE_NULL),
"if a named variable has an index part and a named indexed variable doesn't have an index part, the program is definitely wrong");
2008-12-21 21:35:07 +00:00
pair = qse_map_search (
run->named, var->id.name.ptr, var->id.name.len);
2008-12-21 21:35:07 +00:00
if (pair == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp;
/* value not set for the named variable.
* create a map and assign it to the variable */
tmp = qse_awk_rtx_makemapval (run);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL)
{
/* adjust error line */
run->errlin = nde->line;
return -1;
}
2008-12-21 21:35:07 +00:00
pair = qse_map_upsert (run->named,
var->id.name.ptr, var->id.name.len, tmp, 0);
2008-12-21 21:35:07 +00:00
if (pair == QSE_NULL)
{
qse_awk_rtx_refupval (run, tmp);
qse_awk_rtx_refdownval (run, tmp);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, var->line,
QSE_NULL, 0);
return -1;
}
/* as this is the assignment, it needs to update
2007-12-07 19:57:10 +00:00
* the reference count of the target value. */
qse_awk_rtx_refupval (run, tmp);
}
else
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
qse_map_t* map;
2008-12-21 21:35:07 +00:00
val = (qse_awk_val_t*)QSE_MAP_VPTR(pair);
QSE_ASSERT (val != QSE_NULL);
2008-12-21 21:35:07 +00:00
if (val->type != QSE_AWK_VAL_MAP)
{
2008-12-21 21:35:07 +00:00
qse_cstr_t errarg;
errarg.ptr = var->id.name.ptr;
errarg.len = var->id.name.len;
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOTDEL, var->line,
&errarg, 1);
return -1;
}
2008-12-21 21:35:07 +00:00
map = ((qse_awk_val_map_t*)val)->map;
if (var->type == QSE_AWK_NDE_NAMEDIDX)
{
2008-12-21 21:35:07 +00:00
qse_char_t* key;
qse_size_t keylen;
qse_awk_val_t* idx;
qse_char_t buf[IDXBUFSIZE];
2008-12-21 21:35:07 +00:00
QSE_ASSERT (var->idx != QSE_NULL);
idx = eval_expression (run, var->idx);
2008-12-21 21:35:07 +00:00
if (idx == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, idx);
2008-01-16 21:46:08 +00:00
/* try with a fixed-size buffer */
2008-12-21 21:35:07 +00:00
keylen = QSE_COUNTOF(buf);
key = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, idx, QSE_AWK_VALTOSTR_FIXED,
(qse_str_t*)buf, &keylen);
if (key == QSE_NULL)
2008-01-16 21:46:08 +00:00
{
/* if it doesn't work, switch to dynamic mode */
key = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, idx, QSE_AWK_VALTOSTR_CLEAR,
QSE_NULL, &keylen);
2008-01-16 21:46:08 +00:00
}
qse_awk_rtx_refdownval (run, idx);
2008-12-21 21:35:07 +00:00
if (key == QSE_NULL)
{
/* change the error line */
run->errlin = var->line;
return -1;
}
2008-12-21 21:35:07 +00:00
qse_map_delete (map, key, keylen);
if (key != buf) QSE_AWK_FREE (run->awk, key);
}
else
{
2008-12-21 21:35:07 +00:00
qse_map_clear (map);
}
}
}
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_GLOBAL ||
var->type == QSE_AWK_NDE_LOCAL ||
var->type == QSE_AWK_NDE_ARG ||
var->type == QSE_AWK_NDE_GLOBALIDX ||
var->type == QSE_AWK_NDE_LOCALIDX ||
var->type == QSE_AWK_NDE_ARGIDX)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_GLOBAL ||
var->type == QSE_AWK_NDE_GLOBALIDX)
val = STACK_GLOBAL (run,var->id.idxa);
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_LOCAL ||
var->type == QSE_AWK_NDE_LOCALIDX)
val = STACK_LOCAL (run,var->id.idxa);
else val = STACK_ARG (run,var->id.idxa);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (val != QSE_NULL);
2008-12-21 21:35:07 +00:00
if (val->type == QSE_AWK_VAL_NIL)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp;
/* value not set.
* create a map and assign it to the variable */
tmp = qse_awk_rtx_makemapval (run);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL)
{
/* adjust error line */
run->errlin = nde->line;
return -1;
}
/* no need to reduce the reference count of
* the previous value because it was nil. */
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_GLOBAL ||
var->type == QSE_AWK_NDE_GLOBALIDX)
{
if (qse_awk_rtx_setglobal (
run, (int)var->id.idxa, tmp) == -1)
{
qse_awk_rtx_refupval (run, tmp);
qse_awk_rtx_refdownval (run, tmp);
run->errlin = var->line;
return -1;
}
}
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_LOCAL ||
var->type == QSE_AWK_NDE_LOCALIDX)
{
STACK_LOCAL(run,var->id.idxa) = tmp;
qse_awk_rtx_refupval (run, tmp);
}
else
{
STACK_ARG(run,var->id.idxa) = tmp;
qse_awk_rtx_refupval (run, tmp);
}
}
else
{
2008-12-21 21:35:07 +00:00
qse_map_t* map;
2008-12-21 21:35:07 +00:00
if (val->type != QSE_AWK_VAL_MAP)
{
2008-12-21 21:35:07 +00:00
qse_cstr_t errarg;
errarg.ptr = var->id.name.ptr;
errarg.len = var->id.name.len;
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOTDEL, var->line,
&errarg, 1);
return -1;
}
2008-12-21 21:35:07 +00:00
map = ((qse_awk_val_map_t*)val)->map;
if (var->type == QSE_AWK_NDE_GLOBALIDX ||
var->type == QSE_AWK_NDE_LOCALIDX ||
var->type == QSE_AWK_NDE_ARGIDX)
{
2008-12-21 21:35:07 +00:00
qse_char_t* key;
qse_size_t keylen;
qse_awk_val_t* idx;
qse_char_t buf[IDXBUFSIZE];
2008-12-21 21:35:07 +00:00
QSE_ASSERT (var->idx != QSE_NULL);
idx = eval_expression (run, var->idx);
2008-12-21 21:35:07 +00:00
if (idx == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, idx);
2008-01-16 21:46:08 +00:00
/* try with a fixed-size buffer */
2008-12-21 21:35:07 +00:00
keylen = QSE_COUNTOF(buf);
key = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, idx, QSE_AWK_VALTOSTR_FIXED,
(qse_str_t*)buf, &keylen);
if (key == QSE_NULL)
2008-01-16 21:46:08 +00:00
{
/* if it doesn't work, switch to dynamic mode */
key = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, idx, QSE_AWK_VALTOSTR_CLEAR,
QSE_NULL, &keylen);
2008-01-16 21:46:08 +00:00
}
qse_awk_rtx_refdownval (run, idx);
2008-12-21 21:35:07 +00:00
if (key == QSE_NULL)
{
run->errlin = var->line;
return -1;
}
2008-12-21 21:35:07 +00:00
qse_map_delete (map, key, keylen);
if (key != buf) QSE_AWK_FREE (run->awk, key);
}
else
{
2008-12-21 21:35:07 +00:00
qse_map_clear (map);
}
}
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (
!"should never happen - wrong target for delete",
"the delete statement cannot be called with other nodes than the variables such as a named variable, a named indexed variable, etc");
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ERDELETE, var->line, QSE_NULL, 0);
return -1;
}
return 0;
}
static int run_reset (qse_awk_rtx_t* run, qse_awk_nde_reset_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_var_t* var;
2008-12-21 21:35:07 +00:00
var = (qse_awk_nde_var_t*) nde->var;
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_NAMED)
{
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (
var->type == QSE_AWK_NDE_NAMED && var->idx == QSE_NULL,
"if a named variable has an index part, something is definitely wrong");
/* a named variable can be reset if removed from a internal map
to manage it */
2008-12-21 21:35:07 +00:00
qse_map_delete (run->named, var->id.name.ptr, var->id.name.len);
}
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_GLOBAL ||
var->type == QSE_AWK_NDE_LOCAL ||
var->type == QSE_AWK_NDE_ARG)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_GLOBAL)
val = STACK_GLOBAL(run,var->id.idxa);
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_LOCAL)
val = STACK_LOCAL(run,var->id.idxa);
else val = STACK_ARG(run,var->id.idxa);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (val != QSE_NULL);
2008-12-21 21:35:07 +00:00
if (val->type != QSE_AWK_VAL_NIL)
{
qse_awk_rtx_refdownval (run, val);
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_GLOBAL)
STACK_GLOBAL(run,var->id.idxa) = qse_awk_val_nil;
else if (var->type == QSE_AWK_NDE_LOCAL)
STACK_LOCAL(run,var->id.idxa) = qse_awk_val_nil;
else
2008-12-21 21:35:07 +00:00
STACK_ARG(run,var->id.idxa) = qse_awk_val_nil;
}
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (
!"should never happen - wrong target for reset",
"the reset statement can only be called with plain variables");
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ERRESET, var->line, QSE_NULL, 0);
return -1;
}
return 0;
}
static int run_print (qse_awk_rtx_t* run, qse_awk_nde_print_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_char_t* out = QSE_NULL;
const qse_char_t* dst;
qse_awk_val_t* v;
int n;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
(nde->out_type == QSE_AWK_OUT_PIPE && nde->out != QSE_NULL) ||
(nde->out_type == QSE_AWK_OUT_RWPIPE && nde->out != QSE_NULL) ||
2008-12-21 21:35:07 +00:00
(nde->out_type == QSE_AWK_OUT_FILE && nde->out != QSE_NULL) ||
(nde->out_type == QSE_AWK_OUT_APFILE && nde->out != QSE_NULL) ||
2008-12-21 21:35:07 +00:00
(nde->out_type == QSE_AWK_OUT_CONSOLE && nde->out == QSE_NULL));
/* check if destination has been specified. */
2008-12-21 21:35:07 +00:00
if (nde->out != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_size_t len;
/* if so, resolve the destination name */
v = eval_expression (run, nde->out);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, v);
out = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, v, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &len);
if (out == QSE_NULL)
{
qse_awk_rtx_refdownval (run, v);
/* change the error line */
run->errlin = nde->line;
return -1;
}
qse_awk_rtx_refdownval (run, v);
if (len <= 0)
{
/* the destination name is empty */
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, out);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EIONMEM, nde->line, QSE_NULL, 0);
return -1;
}
/* it needs to check if the destination name contains
* any invalid characters to the underlying system */
while (len > 0)
{
2008-12-21 21:35:07 +00:00
if (out[--len] == QSE_T('\0'))
{
/* if so, it skips writing */
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, out);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EIONMNL, nde->line,
QSE_NULL, 0);
return -1;
}
}
}
/* transforms the destination to suit the usage with eio */
2008-12-21 21:35:07 +00:00
dst = (out == QSE_NULL)? QSE_T(""): out;
/* check if print is followed by any arguments */
2008-12-21 21:35:07 +00:00
if (nde->args == QSE_NULL)
{
/* if it doesn't have any arguments, print the entire
* input record */
n = qse_awk_writeeio_str (
run, nde->out_type, dst,
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(&run->inrec.line),
QSE_STR_LEN(&run->inrec.line));
if (n <= -1 /*&& run->errnum != QSE_AWK_EIOIMPL*/)
{
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL)
QSE_AWK_FREE (run->awk, out);
/* adjust the error line */
run->errlin = nde->line;
return -1;
}
}
else
{
/* if it has any arguments, print the arguments separated by
* the value OFS */
2008-12-21 21:35:07 +00:00
qse_awk_nde_t* head, * np;
2008-12-21 21:35:07 +00:00
if (nde->args->type == QSE_AWK_NDE_GRP)
{
/* parenthesized print */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->args->next == QSE_NULL);
head = ((qse_awk_nde_grp_t*)nde->args)->body;
}
else head = nde->args;
2008-12-21 21:35:07 +00:00
for (np = head; np != QSE_NULL; np = np->next)
{
if (np != head)
{
n = qse_awk_writeeio_str (
run, nde->out_type, dst,
run->global.ofs.ptr,
run->global.ofs.len);
2008-12-21 21:35:07 +00:00
if (n <= -1 /*&& run->errnum != QSE_AWK_EIOIMPL*/)
{
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL)
QSE_AWK_FREE (run->awk, out);
/* adjust the error line */
run->errlin = nde->line;
return -1;
}
}
v = eval_expression (run, np);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL)
QSE_AWK_FREE (run->awk, out);
return -1;
}
qse_awk_rtx_refupval (run, v);
n = qse_awk_writeeio_val (run, nde->out_type, dst, v);
2008-12-21 21:35:07 +00:00
if (n <= -1 /*&& run->errnum != QSE_AWK_EIOIMPL*/)
{
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL)
QSE_AWK_FREE (run->awk, out);
qse_awk_rtx_refdownval (run, v);
/* adjust the error line */
run->errlin = nde->line;
return -1;
}
qse_awk_rtx_refdownval (run, v);
}
}
/* print the value ORS to terminate the operation */
n = qse_awk_writeeio_str (
run, nde->out_type, dst,
run->global.ors.ptr, run->global.ors.len);
2008-12-21 21:35:07 +00:00
if (n <= -1 /*&& run->errnum != QSE_AWK_EIOIMPL*/)
{
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL) QSE_AWK_FREE (run->awk, out);
/* change the error line */
run->errlin = nde->line;
return -1;
}
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL) QSE_AWK_FREE (run->awk, out);
/*skip_write:*/
return 0;
}
static int run_printf (qse_awk_rtx_t* run, qse_awk_nde_print_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_char_t* out = QSE_NULL;
const qse_char_t* dst;
qse_awk_val_t* v;
qse_awk_nde_t* head;
int n;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
(nde->out_type == QSE_AWK_OUT_PIPE && nde->out != QSE_NULL) ||
(nde->out_type == QSE_AWK_OUT_RWPIPE && nde->out != QSE_NULL) ||
2008-12-21 21:35:07 +00:00
(nde->out_type == QSE_AWK_OUT_FILE && nde->out != QSE_NULL) ||
(nde->out_type == QSE_AWK_OUT_APFILE && nde->out != QSE_NULL) ||
2008-12-21 21:35:07 +00:00
(nde->out_type == QSE_AWK_OUT_CONSOLE && nde->out == QSE_NULL));
2008-12-21 21:35:07 +00:00
if (nde->out != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_size_t len;
v = eval_expression (run, nde->out);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, v);
out = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, v, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &len);
if (out == QSE_NULL)
{
qse_awk_rtx_refdownval (run, v);
/* change the error line */
run->errlin = nde->line;
return -1;
}
qse_awk_rtx_refdownval (run, v);
if (len <= 0)
{
/* the output destination name is empty. */
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, out);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EIONMEM, nde->line, QSE_NULL, 0);
return -1;
}
while (len > 0)
{
2008-12-21 21:35:07 +00:00
if (out[--len] == QSE_T('\0'))
{
/* the output destination name contains a null
* character. */
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, out);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EIONMNL, nde->line,
QSE_NULL, 0);
return -1;
}
}
}
2008-12-21 21:35:07 +00:00
dst = (out == QSE_NULL)? QSE_T(""): out;
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (nde->args != QSE_NULL,
"a valid printf statement should have at least one argument. the parser must ensure this.");
2008-12-21 21:35:07 +00:00
if (nde->args->type == QSE_AWK_NDE_GRP)
{
/* parenthesized print */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->args->next == QSE_NULL);
head = ((qse_awk_nde_grp_t*)nde->args)->body;
}
else head = nde->args;
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (head != QSE_NULL,
"a valid printf statement should have at least one argument. the parser must ensure this.");
v = eval_expression (run, head);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL) QSE_AWK_FREE (run->awk, out);
return -1;
}
qse_awk_rtx_refupval (run, v);
2008-12-21 21:35:07 +00:00
if (v->type != QSE_AWK_VAL_STR)
{
/* the remaining arguments are ignored as the format cannot
* contain any % characters */
n = qse_awk_writeeio_val (run, nde->out_type, dst, v);
2008-12-21 21:35:07 +00:00
if (n <= -1 /*&& run->errnum != QSE_AWK_EIOIMPL*/)
{
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL) QSE_AWK_FREE (run->awk, out);
qse_awk_rtx_refdownval (run, v);
/* change the error line */
run->errlin = nde->line;
return -1;
}
}
else
{
/* perform the formatted output */
if (output_formatted (
run, nde->out_type, dst,
((qse_awk_val_str_t*)v)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)v)->len,
head->next) == -1)
{
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL) QSE_AWK_FREE (run->awk, out);
qse_awk_rtx_refdownval (run, v);
/* adjust the error line */
run->errlin = nde->line;
return -1;
}
}
qse_awk_rtx_refdownval (run, v);
2008-12-21 21:35:07 +00:00
if (out != QSE_NULL) QSE_AWK_FREE (run->awk, out);
/*skip_write:*/
return 0;
}
static int output_formatted (
qse_awk_rtx_t* run, int out_type, const qse_char_t* dst,
2008-12-21 21:35:07 +00:00
const qse_char_t* fmt, qse_size_t fmt_len, qse_awk_nde_t* args)
{
2008-12-21 21:35:07 +00:00
qse_char_t* ptr;
qse_size_t len;
int n;
2008-12-21 21:35:07 +00:00
ptr = qse_awk_format (run,
QSE_NULL, QSE_NULL, fmt, fmt_len, 0, args, &len);
if (ptr == QSE_NULL) return -1;
n = qse_awk_writeeio_str (run, out_type, dst, ptr, len);
2008-12-21 21:35:07 +00:00
if (n <= -1 /*&& run->errnum != QSE_AWK_EIOIMPL*/) return -1;
return 0;
}
static qse_awk_val_t* eval_expression (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
int n, errnum;
2008-01-01 07:30:18 +00:00
#if 0
2007-12-07 20:48:09 +00:00
if (run->exit_level >= EXIT_GLOBAL)
{
2008-12-21 21:35:07 +00:00
/* returns QSE_NULL as if an error occurred but
2007-12-07 23:58:44 +00:00
* clears the error number. run_main will
2007-12-07 20:48:09 +00:00
* detect this condition and treat it as a
* non-error condition.*/
2008-12-21 21:35:07 +00:00
run->errnum = QSE_AWK_ENOERR;
return QSE_NULL;
2007-12-07 20:48:09 +00:00
}
2008-01-01 07:30:18 +00:00
#endif
2007-12-07 20:48:09 +00:00
v = eval_expression0 (run, nde);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
2008-12-21 21:35:07 +00:00
if (v->type == QSE_AWK_VAL_REX)
{
qse_awk_rtx_refupval (run, v);
2008-12-21 21:35:07 +00:00
if (run->inrec.d0->type == QSE_AWK_VAL_NIL)
{
/* the record has never been read.
* probably, this functions has been triggered
* by the statements in the BEGIN block */
2008-12-21 21:35:07 +00:00
n = QSE_AWK_ISEMPTYREX(run->awk,((qse_awk_val_rex_t*)v)->code)? 1: 0;
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (
run->inrec.d0->type == QSE_AWK_VAL_STR,
"the internal value representing $0 should always be of the string type once it has been set/updated. it is nil initially.");
2008-12-21 21:35:07 +00:00
n = QSE_AWK_MATCHREX (
((qse_awk_rtx_t*)run)->awk,
2008-12-21 21:35:07 +00:00
((qse_awk_val_rex_t*)v)->code,
((((qse_awk_rtx_t*)run)->global.ignorecase)? QSE_REX_IGNORECASE: 0),
((qse_awk_val_str_t*)run->inrec.d0)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)run->inrec.d0)->len,
QSE_NULL, QSE_NULL, &errnum);
if (n == -1)
{
qse_awk_rtx_refdownval (run, v);
/* matchrex should never set the error number
* whose message contains a formatting
* character. otherwise, the following way of
* setting the error information may not work */
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, errnum, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
}
qse_awk_rtx_refdownval (run, v);
v = qse_awk_rtx_makeintval (run, (n != 0));
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL)
{
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
return v;
}
static qse_awk_val_t* eval_expression0 (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
static eval_expr_t eval_func[] =
{
/* the order of functions here should match the order
* of node types declared in tree.h */
eval_group,
eval_assignment,
eval_binary,
eval_unary,
eval_incpre,
eval_incpst,
eval_cnd,
eval_fnc,
eval_fun,
eval_int,
eval_real,
eval_str,
eval_rex,
eval_named,
eval_global,
eval_local,
eval_arg,
eval_namedidx,
eval_globalidx,
eval_localidx,
eval_argidx,
eval_pos,
eval_getline
};
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
2008-01-01 07:30:18 +00:00
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->type >= QSE_AWK_NDE_GRP &&
(nde->type - QSE_AWK_NDE_GRP) < QSE_COUNTOF(eval_func));
2008-12-21 21:35:07 +00:00
v = eval_func[nde->type-QSE_AWK_NDE_GRP] (run, nde);
2008-01-01 07:30:18 +00:00
2008-12-21 21:35:07 +00:00
if (v != QSE_NULL && run->exit_level >= EXIT_GLOBAL)
2008-01-01 07:30:18 +00:00
{
qse_awk_rtx_refupval (run, v);
qse_awk_rtx_refdownval (run, v);
2008-01-01 07:30:18 +00:00
2008-12-21 21:35:07 +00:00
/* returns QSE_NULL as if an error occurred but
2008-01-01 07:30:18 +00:00
* clears the error number. run_main will
* detect this condition and treat it as a
* non-error condition.*/
2008-12-21 21:35:07 +00:00
run->errnum = QSE_AWK_ENOERR;
return QSE_NULL;
2008-01-01 07:30:18 +00:00
}
return v;
}
static qse_awk_val_t* eval_group (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
/* eval_binop_in evaluates the QSE_AWK_NDE_GRP specially.
* so this function should never be reached. */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (!"should never happen - NDE_GRP only for in");
qse_awk_rtx_seterror (run, QSE_AWK_EINTERN, nde->line, QSE_NULL, 0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
static qse_awk_val_t* eval_assignment (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val, * ret;
qse_awk_nde_ass_t* ass = (qse_awk_nde_ass_t*)nde;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (ass->left != QSE_NULL);
QSE_ASSERT (ass->right != QSE_NULL);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (ass->right->next == QSE_NULL);
val = eval_expression (run, ass->right);
2008-12-21 21:35:07 +00:00
if (val == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, val);
2008-12-21 21:35:07 +00:00
if (ass->opcode != QSE_AWK_ASSOP_NONE)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val2, * tmp;
2008-02-09 03:04:38 +00:00
static binop_func_t binop_func[] =
{
2008-12-21 21:35:07 +00:00
QSE_NULL, /* QSE_AWK_ASSOP_NONE */
eval_binop_plus,
eval_binop_minus,
eval_binop_mul,
eval_binop_div,
eval_binop_idiv,
eval_binop_mod,
2008-02-09 03:04:38 +00:00
eval_binop_exp,
eval_binop_rshift,
eval_binop_lshift,
eval_binop_band,
eval_binop_bxor,
eval_binop_bor
};
2008-12-21 21:35:07 +00:00
QSE_ASSERT (ass->left->next == QSE_NULL);
val2 = eval_expression (run, ass->left);
2008-12-21 21:35:07 +00:00
if (val2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, val);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refupval (run, val2);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (ass->opcode >= 0);
QSE_ASSERT (ass->opcode < QSE_COUNTOF(binop_func));
QSE_ASSERT (binop_func[ass->opcode] != QSE_NULL);
2008-02-09 03:04:38 +00:00
tmp = binop_func[ass->opcode] (run, val2, val);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL)
{
qse_awk_rtx_refdownval (run, val2);
qse_awk_rtx_refdownval (run, val);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, val2);
qse_awk_rtx_refdownval (run, val);
val = tmp;
qse_awk_rtx_refupval (run, val);
}
ret = do_assignment (run, ass->left, val);
qse_awk_rtx_refdownval (run, val);
return ret;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* do_assignment (
qse_awk_rtx_t* run, qse_awk_nde_t* var, qse_awk_val_t* val)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* ret;
int errnum;
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_NAMED ||
var->type == QSE_AWK_NDE_GLOBAL ||
var->type == QSE_AWK_NDE_LOCAL ||
var->type == QSE_AWK_NDE_ARG)
{
2008-12-21 21:35:07 +00:00
if ((run->awk->option & QSE_AWK_MAPTOVAR) == 0)
{
2008-12-21 21:35:07 +00:00
if (val->type == QSE_AWK_VAL_MAP)
{
2008-12-21 21:35:07 +00:00
errnum = QSE_AWK_ENOTASS;
goto exit_on_error;
}
}
2008-12-21 21:35:07 +00:00
ret = do_assignment_scalar (run, (qse_awk_nde_var_t*)var, val);
}
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_NAMEDIDX ||
var->type == QSE_AWK_NDE_GLOBALIDX ||
var->type == QSE_AWK_NDE_LOCALIDX ||
var->type == QSE_AWK_NDE_ARGIDX)
{
2008-12-21 21:35:07 +00:00
if (val->type == QSE_AWK_VAL_MAP)
{
2008-12-21 21:35:07 +00:00
errnum = QSE_AWK_ENOTASS;
goto exit_on_error;
}
2008-12-21 21:35:07 +00:00
ret = do_assignment_map (run, (qse_awk_nde_var_t*)var, val);
}
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_POS)
{
2008-12-21 21:35:07 +00:00
if (val->type == QSE_AWK_VAL_MAP)
{
2008-12-21 21:35:07 +00:00
errnum = QSE_AWK_ENOTASS;
goto exit_on_error;
}
2008-12-21 21:35:07 +00:00
ret = do_assignment_pos (run, (qse_awk_nde_pos_t*)var, val);
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (!"should never happen - invalid variable type");
errnum = QSE_AWK_EINTERN;
goto exit_on_error;
}
return ret;
exit_on_error:
qse_awk_rtx_seterror (run, errnum, var->line, QSE_NULL, 0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* do_assignment_scalar (
qse_awk_rtx_t* run, qse_awk_nde_var_t* var, qse_awk_val_t* val)
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
(var->type == QSE_AWK_NDE_NAMED ||
var->type == QSE_AWK_NDE_GLOBAL ||
var->type == QSE_AWK_NDE_LOCAL ||
var->type == QSE_AWK_NDE_ARG) && var->idx == QSE_NULL);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
(run->awk->option & QSE_AWK_MAPTOVAR) ||
val->type != QSE_AWK_VAL_MAP);
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_NAMED)
{
2008-12-21 21:35:07 +00:00
qse_map_pair_t* pair;
2008-12-21 21:35:07 +00:00
pair = qse_map_search (
run->named, var->id.name.ptr, var->id.name.len);
2008-12-21 21:35:07 +00:00
if (pair != QSE_NULL &&
((qse_awk_val_t*)QSE_MAP_VPTR(pair))->type == QSE_AWK_VAL_MAP)
{
/* once a variable becomes a map,
* it cannot be changed to a scalar variable */
2008-12-21 21:35:07 +00:00
qse_cstr_t errarg;
errarg.ptr = var->id.name.ptr;
errarg.len = var->id.name.len;
qse_awk_rtx_seterror (run,
2008-12-21 21:35:07 +00:00
QSE_AWK_EMAPTOSCALAR, var->line, &errarg, 1);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (qse_map_upsert (run->named,
var->id.name.ptr, var->id.name.len, val, 0) == QSE_NULL)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, var->line, QSE_NULL, 0);
return QSE_NULL;
}
qse_awk_rtx_refupval (run, val);
}
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_GLOBAL)
{
if (set_global (run, var->id.idxa, var, val) == -1)
{
/* adjust error line */
run->errlin = var->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_LOCAL)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* old = STACK_LOCAL(run,var->id.idxa);
if (old->type == QSE_AWK_VAL_MAP)
{
/* once the variable becomes a map,
* it cannot be changed to a scalar variable */
2008-12-21 21:35:07 +00:00
qse_cstr_t errarg;
errarg.ptr = var->id.name.ptr;
errarg.len = var->id.name.len;
qse_awk_rtx_seterror (run,
2008-12-21 21:35:07 +00:00
QSE_AWK_EMAPTOSCALAR, var->line, &errarg, 1);
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, old);
STACK_LOCAL(run,var->id.idxa) = val;
qse_awk_rtx_refupval (run, val);
}
2008-12-21 21:35:07 +00:00
else /* if (var->type == QSE_AWK_NDE_ARG) */
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* old = STACK_ARG(run,var->id.idxa);
if (old->type == QSE_AWK_VAL_MAP)
{
/* once the variable becomes a map,
* it cannot be changed to a scalar variable */
2008-12-21 21:35:07 +00:00
qse_cstr_t errarg;
errarg.ptr = var->id.name.ptr;
errarg.len = var->id.name.len;
qse_awk_rtx_seterror (run,
2008-12-21 21:35:07 +00:00
QSE_AWK_EMAPTOSCALAR, var->line, &errarg, 1);
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, old);
STACK_ARG(run,var->id.idxa) = val;
qse_awk_rtx_refupval (run, val);
}
return val;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* do_assignment_map (
qse_awk_rtx_t* run, qse_awk_nde_var_t* var, qse_awk_val_t* val)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_map_t* map;
qse_char_t* str;
qse_size_t len;
qse_char_t idxbuf[IDXBUFSIZE];
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
(var->type == QSE_AWK_NDE_NAMEDIDX ||
var->type == QSE_AWK_NDE_GLOBALIDX ||
var->type == QSE_AWK_NDE_LOCALIDX ||
var->type == QSE_AWK_NDE_ARGIDX) && var->idx != QSE_NULL);
QSE_ASSERT (val->type != QSE_AWK_VAL_MAP);
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_NAMEDIDX)
{
2008-12-21 21:35:07 +00:00
qse_map_pair_t* pair;
pair = qse_map_search (
run->named, var->id.name.ptr, var->id.name.len);
2008-12-21 21:35:07 +00:00
map = (pair == QSE_NULL)?
(qse_awk_val_map_t*)qse_awk_val_nil:
(qse_awk_val_map_t*)QSE_MAP_VPTR(pair);
}
else
{
2008-12-21 21:35:07 +00:00
map = (var->type == QSE_AWK_NDE_GLOBALIDX)?
(qse_awk_val_map_t*)STACK_GLOBAL(run,var->id.idxa):
(var->type == QSE_AWK_NDE_LOCALIDX)?
(qse_awk_val_map_t*)STACK_LOCAL(run,var->id.idxa):
(qse_awk_val_map_t*)STACK_ARG(run,var->id.idxa);
}
2008-12-21 21:35:07 +00:00
if (map->type == QSE_AWK_VAL_NIL)
{
/* the map is not initialized yet */
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp;
tmp = qse_awk_rtx_makemapval (run);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL)
{
/* adjust error line */
run->errlin = var->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (var->type == QSE_AWK_NDE_NAMEDIDX)
{
/* doesn't have to decrease the reference count
* of the previous value here as it is done by
2008-12-21 21:35:07 +00:00
* qse_map_upsert */
if (qse_map_upsert (
run->named,
var->id.name.ptr,
var->id.name.len,
tmp,
2008-12-21 21:35:07 +00:00
0) == QSE_NULL)
{
qse_awk_rtx_refupval (run, tmp);
qse_awk_rtx_refdownval (run, tmp);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, var->line, QSE_NULL, 0);
return QSE_NULL;
}
qse_awk_rtx_refupval (run, tmp);
}
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_GLOBALIDX)
{
qse_awk_rtx_refupval (run, tmp);
if (qse_awk_rtx_setglobal (run, (int)var->id.idxa, tmp) == -1)
{
qse_awk_rtx_refdownval (run, tmp);
/* change error line */
run->errlin = var->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, tmp);
}
2008-12-21 21:35:07 +00:00
else if (var->type == QSE_AWK_NDE_LOCALIDX)
{
qse_awk_rtx_refdownval (run, (qse_awk_val_t*)map);
STACK_LOCAL(run,var->id.idxa) = tmp;
qse_awk_rtx_refupval (run, tmp);
}
2008-12-21 21:35:07 +00:00
else /* if (var->type == QSE_AWK_NDE_ARGIDX) */
{
qse_awk_rtx_refdownval (run, (qse_awk_val_t*)map);
STACK_ARG(run,var->id.idxa) = tmp;
qse_awk_rtx_refupval (run, tmp);
}
2008-12-21 21:35:07 +00:00
map = (qse_awk_val_map_t*) tmp;
}
2008-12-21 21:35:07 +00:00
else if (map->type != QSE_AWK_VAL_MAP)
{
/* variable assigned is not a map */
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOTIDX, var->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
len = QSE_COUNTOF(idxbuf);
2008-01-16 21:46:08 +00:00
str = idxnde_to_str (run, var->idx, idxbuf, &len);
2008-12-21 21:35:07 +00:00
if (str == QSE_NULL)
2008-01-16 21:46:08 +00:00
{
2008-12-21 21:35:07 +00:00
str = idxnde_to_str (run, var->idx, QSE_NULL, &len);
if (str == QSE_NULL) return QSE_NULL;
2008-01-16 21:46:08 +00:00
}
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (QSE_T("**** index str=>%s, map->ref=%d, map->type=%d\n"),
str, (int)map->ref, (int)map->type);
#endif
2008-12-21 21:35:07 +00:00
if (qse_map_upsert (map->map, str, len, val, 0) == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (str != idxbuf) QSE_AWK_FREE (run->awk, str);
qse_awk_rtx_seterror (run, QSE_AWK_ENOMEM, var->line, QSE_NULL, 0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (str != idxbuf) QSE_AWK_FREE (run->awk, str);
qse_awk_rtx_refupval (run, val);
return val;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* do_assignment_pos (
qse_awk_rtx_t* run, qse_awk_nde_pos_t* pos, qse_awk_val_t* val)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
qse_long_t lv;
qse_real_t rv;
qse_char_t* str;
qse_size_t len;
int n;
v = eval_expression (run, pos->val);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, v);
n = qse_awk_rtx_valtonum (run, v, &lv, &rv);
qse_awk_rtx_refdownval (run, v);
if (n == -1)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EPOSIDX, pos->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (n == 1) lv = (qse_long_t)rv;
if (!IS_VALID_POSIDX(lv))
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EPOSIDX, pos->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (val->type == QSE_AWK_VAL_STR)
{
str = ((qse_awk_val_str_t*)val)->ptr;
2008-12-21 21:35:07 +00:00
len = ((qse_awk_val_str_t*)val)->len;
}
else
{
str = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, val, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &len);
if (str == QSE_NULL)
{
/* change error line */
run->errlin = pos->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
n = qse_awk_rtx_setrec (run, (qse_size_t)lv, str, len);
2008-12-21 21:35:07 +00:00
if (val->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, str);
2008-12-21 21:35:07 +00:00
if (n == -1) return QSE_NULL;
return (lv == 0)? run->inrec.d0: run->inrec.flds[lv-1].val;
}
static qse_awk_val_t* eval_binary (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-02-09 03:04:38 +00:00
static binop_func_t binop_func[] =
{
/* the order of the functions should be inline with
* the operator declaration in run.h */
2008-12-21 21:35:07 +00:00
QSE_NULL, /* eval_binop_lor */
QSE_NULL, /* eval_binop_land */
QSE_NULL, /* eval_binop_in */
eval_binop_bor,
eval_binop_bxor,
eval_binop_band,
eval_binop_eq,
eval_binop_ne,
eval_binop_gt,
eval_binop_ge,
eval_binop_lt,
eval_binop_le,
eval_binop_lshift,
eval_binop_rshift,
eval_binop_plus,
eval_binop_minus,
eval_binop_mul,
eval_binop_div,
eval_binop_idiv,
eval_binop_mod,
eval_binop_exp,
eval_binop_concat,
2008-12-21 21:35:07 +00:00
QSE_NULL, /* eval_binop_ma */
QSE_NULL /* eval_binop_nm */
};
2008-12-21 21:35:07 +00:00
qse_awk_nde_exp_t* exp = (qse_awk_nde_exp_t*)nde;
qse_awk_val_t* left, * right, * res;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (exp->type == QSE_AWK_NDE_EXP_BIN);
2008-12-21 21:35:07 +00:00
if (exp->opcode == QSE_AWK_BINOP_LAND)
{
res = eval_binop_land (run, exp->left, exp->right);
}
2008-12-21 21:35:07 +00:00
else if (exp->opcode == QSE_AWK_BINOP_LOR)
{
res = eval_binop_lor (run, exp->left, exp->right);
}
2008-12-21 21:35:07 +00:00
else if (exp->opcode == QSE_AWK_BINOP_IN)
{
/* treat the in operator specially */
res = eval_binop_in (run, exp->left, exp->right);
}
2008-12-21 21:35:07 +00:00
else if (exp->opcode == QSE_AWK_BINOP_NM)
{
res = eval_binop_nm (run, exp->left, exp->right);
}
2008-12-21 21:35:07 +00:00
else if (exp->opcode == QSE_AWK_BINOP_MA)
{
res = eval_binop_ma (run, exp->left, exp->right);
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (exp->left->next == QSE_NULL);
left = eval_expression (run, exp->left);
2008-12-21 21:35:07 +00:00
if (left == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, left);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (exp->right->next == QSE_NULL);
right = eval_expression (run, exp->right);
2008-12-21 21:35:07 +00:00
if (right == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refupval (run, right);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (exp->opcode >= 0 &&
exp->opcode < QSE_COUNTOF(binop_func));
QSE_ASSERT (binop_func[exp->opcode] != QSE_NULL);
2008-02-09 03:04:38 +00:00
res = binop_func[exp->opcode] (run, left, right);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
/* change the error line */
run->errlin = nde->line;
}
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_refdownval (run, right);
}
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_lor (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right)
{
/*
2008-12-21 21:35:07 +00:00
qse_awk_val_t* res = QSE_NULL;
res = qse_awk_rtx_makeintval (run,
qse_awk_rtx_valtobool(run left) || qse_awk_rtx_valtobool(run,right));
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
run->errlin = left->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
return res;
*/
/* short-circuit evaluation required special treatment */
2008-12-21 21:35:07 +00:00
qse_awk_val_t* lv, * rv, * res;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (left->next == QSE_NULL);
lv = eval_expression (run, left);
2008-12-21 21:35:07 +00:00
if (lv == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, lv);
if (qse_awk_rtx_valtobool (run, lv))
{
2008-12-21 21:35:07 +00:00
res = qse_awk_val_one;
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (right->next == QSE_NULL);
rv = eval_expression (run, right);
2008-12-21 21:35:07 +00:00
if (rv == QSE_NULL)
{
qse_awk_rtx_refdownval (run, lv);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refupval (run, rv);
res = qse_awk_rtx_valtobool(run,rv)? qse_awk_val_one: qse_awk_val_zero;
qse_awk_rtx_refdownval (run, rv);
}
qse_awk_rtx_refdownval (run, lv);
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_land (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right)
{
/*
2008-12-21 21:35:07 +00:00
qse_awk_val_t* res = QSE_NULL;
res = qse_awk_rtx_makeintval (run,
qse_awk_rtx_valtobool(run,left) && qse_awk_rtx_valtobool(run,right));
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
run->errlin = left->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
return res;
*/
/* short-circuit evaluation required special treatment */
2008-12-21 21:35:07 +00:00
qse_awk_val_t* lv, * rv, * res;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (left->next == QSE_NULL);
lv = eval_expression (run, left);
2008-12-21 21:35:07 +00:00
if (lv == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, lv);
if (!qse_awk_rtx_valtobool (run, lv))
{
2008-12-21 21:35:07 +00:00
res = qse_awk_val_zero;
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (right->next == QSE_NULL);
rv = eval_expression (run, right);
2008-12-21 21:35:07 +00:00
if (rv == QSE_NULL)
{
qse_awk_rtx_refdownval (run, lv);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refupval (run, rv);
res = qse_awk_rtx_valtobool(run,rv)? qse_awk_val_one: qse_awk_val_zero;
qse_awk_rtx_refdownval (run, rv);
}
qse_awk_rtx_refdownval (run, lv);
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_in (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* rv;
qse_char_t* str;
qse_size_t len;
qse_char_t idxbuf[IDXBUFSIZE];
2008-12-21 21:35:07 +00:00
if (right->type != QSE_AWK_NDE_GLOBAL &&
right->type != QSE_AWK_NDE_LOCAL &&
right->type != QSE_AWK_NDE_ARG &&
right->type != QSE_AWK_NDE_NAMED)
{
/* the compiler should have handled this case */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
!"should never happen - in needs a plain variable");
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EINTERN, right->line, QSE_NULL, 0);
return QSE_NULL;
}
/* evaluate the left-hand side of the operator */
2008-12-21 21:35:07 +00:00
len = QSE_COUNTOF(idxbuf);
str = (left->type == QSE_AWK_NDE_GRP)?
idxnde_to_str (run, ((qse_awk_nde_grp_t*)left)->body, idxbuf, &len):
2008-01-16 21:46:08 +00:00
idxnde_to_str (run, left, idxbuf, &len);
2008-12-21 21:35:07 +00:00
if (str == QSE_NULL)
2008-01-16 21:46:08 +00:00
{
2008-12-21 21:35:07 +00:00
str = (left->type == QSE_AWK_NDE_GRP)?
idxnde_to_str (run, ((qse_awk_nde_grp_t*)left)->body, QSE_NULL, &len):
idxnde_to_str (run, left, QSE_NULL, &len);
if (str == QSE_NULL) return QSE_NULL;
2008-01-16 21:46:08 +00:00
}
/* evaluate the right-hand side of the operator */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (right->next == QSE_NULL);
rv = eval_expression (run, right);
2008-12-21 21:35:07 +00:00
if (rv == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (str != idxbuf) QSE_AWK_FREE (run->awk, str);
return QSE_NULL;
}
qse_awk_rtx_refupval (run, rv);
2008-12-21 21:35:07 +00:00
if (rv->type == QSE_AWK_VAL_NIL)
{
2008-12-21 21:35:07 +00:00
if (str != idxbuf) QSE_AWK_FREE (run->awk, str);
qse_awk_rtx_refdownval (run, rv);
2008-12-21 21:35:07 +00:00
return qse_awk_val_zero;
}
2008-12-21 21:35:07 +00:00
else if (rv->type == QSE_AWK_VAL_MAP)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* res;
qse_map_t* map;
2008-12-21 21:35:07 +00:00
map = ((qse_awk_val_map_t*)rv)->map;
res = (qse_map_search (map, str, len) == QSE_NULL)?
qse_awk_val_zero: qse_awk_val_one;
2008-12-21 21:35:07 +00:00
if (str != idxbuf) QSE_AWK_FREE (run->awk, str);
qse_awk_rtx_refdownval (run, rv);
return res;
}
/* need a map */
2008-12-21 21:35:07 +00:00
if (str != idxbuf) QSE_AWK_FREE (run->awk, str);
qse_awk_rtx_refdownval (run, rv);
qse_awk_rtx_seterror (run, QSE_AWK_ENOTMAPNILIN, right->line, QSE_NULL, 0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_bor (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n3 >= 0 && n3 <= 3);
return (n3 == 0)? qse_awk_rtx_makeintval(run,(qse_long_t)l1|(qse_long_t)l2):
(n3 == 1)? qse_awk_rtx_makeintval(run,(qse_long_t)r1|(qse_long_t)l2):
(n3 == 2)? qse_awk_rtx_makeintval(run,(qse_long_t)l1|(qse_long_t)r2):
qse_awk_rtx_makeintval(run,(qse_long_t)r1|(qse_long_t)r2);
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_bxor (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n3 >= 0 && n3 <= 3);
return (n3 == 0)? qse_awk_rtx_makeintval(run,(qse_long_t)l1^(qse_long_t)l2):
(n3 == 1)? qse_awk_rtx_makeintval(run,(qse_long_t)r1^(qse_long_t)l2):
(n3 == 2)? qse_awk_rtx_makeintval(run,(qse_long_t)l1^(qse_long_t)r2):
qse_awk_rtx_makeintval(run,(qse_long_t)r1^(qse_long_t)r2);
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_band (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n3 >= 0 && n3 <= 3);
return (n3 == 0)? qse_awk_rtx_makeintval(run,(qse_long_t)l1&(qse_long_t)l2):
(n3 == 1)? qse_awk_rtx_makeintval(run,(qse_long_t)r1&(qse_long_t)l2):
(n3 == 2)? qse_awk_rtx_makeintval(run,(qse_long_t)l1&(qse_long_t)r2):
qse_awk_rtx_makeintval(run,(qse_long_t)r1&(qse_long_t)r2);
}
static int __cmp_nil_nil (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
return 0;
}
static int __cmp_nil_int (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_int_t*)right)->val < 0) return 1;
if (((qse_awk_val_int_t*)right)->val > 0) return -1;
return 0;
}
static int __cmp_nil_real (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_real_t*)right)->val < 0) return 1;
if (((qse_awk_val_real_t*)right)->val > 0) return -1;
return 0;
}
static int __cmp_nil_str (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
return (((qse_awk_val_str_t*)right)->len == 0)? 0: -1;
}
static int __cmp_int_nil (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_int_t*)left)->val > 0) return 1;
if (((qse_awk_val_int_t*)left)->val < 0) return -1;
return 0;
}
static int __cmp_int_int (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_int_t*)left)->val >
((qse_awk_val_int_t*)right)->val) return 1;
if (((qse_awk_val_int_t*)left)->val <
((qse_awk_val_int_t*)right)->val) return -1;
return 0;
}
static int __cmp_int_real (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_int_t*)left)->val >
((qse_awk_val_real_t*)right)->val) return 1;
if (((qse_awk_val_int_t*)left)->val <
((qse_awk_val_real_t*)right)->val) return -1;
return 0;
}
static int __cmp_int_str (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
qse_char_t* str;
qse_size_t len;
qse_long_t r;
qse_real_t rr;
int n;
2008-12-21 21:35:07 +00:00
r = qse_awk_strxtolong (run->awk,
((qse_awk_val_str_t*)right)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len, 0, (const qse_char_t**)&str);
if (str == ((qse_awk_val_str_t*)right)->ptr +
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_int_t*)left)->val > r) return 1;
if (((qse_awk_val_int_t*)left)->val < r) return -1;
return 0;
}
/* TODO: should i do this??? conversion to real and comparision... */
2008-12-21 21:35:07 +00:00
else if (*str == QSE_T('.') || *str == QSE_T('E') || *str == QSE_T('e'))
{
2008-12-21 21:35:07 +00:00
rr = qse_awk_strxtoreal (run->awk,
((qse_awk_val_str_t*)right)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len,
(const qse_char_t**)&str);
if (str == ((qse_awk_val_str_t*)right)->ptr +
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_int_t*)left)->val > rr) return 1;
if (((qse_awk_val_int_t*)left)->val < rr) return -1;
return 0;
}
}
str = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, left, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &len);
if (str == QSE_NULL) return CMP_ERROR;
if (run->global.ignorecase)
{
2008-12-21 21:35:07 +00:00
n = qse_strxncasecmp (
str, len,
((qse_awk_val_str_t*)right)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len,
2008-07-21 06:42:39 +00:00
CCLS(run));
}
else
{
2008-12-21 21:35:07 +00:00
n = qse_strxncmp (
str, len,
((qse_awk_val_str_t*)right)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len);
}
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, str);
return n;
}
static int __cmp_real_nil (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_real_t*)left)->val > 0) return 1;
if (((qse_awk_val_real_t*)left)->val < 0) return -1;
return 0;
}
static int __cmp_real_int (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_real_t*)left)->val >
((qse_awk_val_int_t*)right)->val) return 1;
if (((qse_awk_val_real_t*)left)->val <
((qse_awk_val_int_t*)right)->val) return -1;
return 0;
}
static int __cmp_real_real (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_real_t*)left)->val >
((qse_awk_val_real_t*)right)->val) return 1;
if (((qse_awk_val_real_t*)left)->val <
((qse_awk_val_real_t*)right)->val) return -1;
return 0;
}
static int __cmp_real_str (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
qse_char_t* str;
qse_size_t len;
qse_real_t rr;
int n;
2008-12-21 21:35:07 +00:00
rr = qse_awk_strxtoreal (run->awk,
((qse_awk_val_str_t*)right)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len,
(const qse_char_t**)&str);
if (str == ((qse_awk_val_str_t*)right)->ptr +
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len)
{
2008-12-21 21:35:07 +00:00
if (((qse_awk_val_real_t*)left)->val > rr) return 1;
if (((qse_awk_val_real_t*)left)->val < rr) return -1;
return 0;
}
str = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, left, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &len);
if (str == QSE_NULL) return CMP_ERROR;
if (run->global.ignorecase)
{
2008-12-21 21:35:07 +00:00
n = qse_strxncasecmp (
str, len,
((qse_awk_val_str_t*)right)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len,
2008-07-21 06:42:39 +00:00
CCLS(run));
}
else
{
2008-12-21 21:35:07 +00:00
n = qse_strxncmp (
str, len,
((qse_awk_val_str_t*)right)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len);
}
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, str);
return n;
}
static int __cmp_str_nil (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
return (((qse_awk_val_str_t*)left)->len == 0)? 0: 1;
}
static int __cmp_str_int (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
return -__cmp_int_str (run, right, left);
}
static int __cmp_str_real (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
return -__cmp_real_str (run, right, left);
}
static int __cmp_str_str (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n;
2008-12-21 21:35:07 +00:00
qse_awk_val_str_t* ls, * rs;
2008-12-21 21:35:07 +00:00
ls = (qse_awk_val_str_t*)left;
rs = (qse_awk_val_str_t*)right;
if (run->global.ignorecase)
{
2008-12-21 21:35:07 +00:00
n = qse_strxncasecmp (
ls->ptr, ls->len, rs->ptr, rs->len, CCLS(run));
}
else
{
2008-12-21 21:35:07 +00:00
n = qse_strxncmp (
ls->ptr, ls->len, rs->ptr, rs->len);
}
return n;
}
static int __cmp_val (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
typedef int (*cmp_val_t) (qse_awk_rtx_t*, qse_awk_val_t*, qse_awk_val_t*);
static cmp_val_t func[] =
{
/* this table must be synchronized with
2008-12-21 21:35:07 +00:00
* the QSE_AWK_VAL_XXX values in awk.h */
__cmp_nil_nil, __cmp_nil_int, __cmp_nil_real, __cmp_nil_str,
__cmp_int_nil, __cmp_int_int, __cmp_int_real, __cmp_int_str,
__cmp_real_nil, __cmp_real_int, __cmp_real_real, __cmp_real_str,
__cmp_str_nil, __cmp_str_int, __cmp_str_real, __cmp_str_str,
};
2008-12-21 21:35:07 +00:00
if (left->type == QSE_AWK_VAL_MAP || right->type == QSE_AWK_VAL_MAP)
{
/* a map can't be compared againt other values */
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
return CMP_ERROR;
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
left->type >= QSE_AWK_VAL_NIL &&
left->type <= QSE_AWK_VAL_STR);
QSE_ASSERT (
right->type >= QSE_AWK_VAL_NIL &&
right->type <= QSE_AWK_VAL_STR);
return func[left->type*4+right->type] (run, left, right);
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_eq (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n = __cmp_val (run, left, right);
2008-12-21 21:35:07 +00:00
if (n == CMP_ERROR) return QSE_NULL;
return (n == 0)? qse_awk_val_one: qse_awk_val_zero;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_ne (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n = __cmp_val (run, left, right);
2008-12-21 21:35:07 +00:00
if (n == CMP_ERROR) return QSE_NULL;
return (n != 0)? qse_awk_val_one: qse_awk_val_zero;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_gt (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n = __cmp_val (run, left, right);
2008-12-21 21:35:07 +00:00
if (n == CMP_ERROR) return QSE_NULL;
return (n > 0)? qse_awk_val_one: qse_awk_val_zero;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_ge (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n = __cmp_val (run, left, right);
2008-12-21 21:35:07 +00:00
if (n == CMP_ERROR) return QSE_NULL;
return (n >= 0)? qse_awk_val_one: qse_awk_val_zero;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_lt (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n = __cmp_val (run, left, right);
2008-12-21 21:35:07 +00:00
if (n == CMP_ERROR) return QSE_NULL;
return (n < 0)? qse_awk_val_one: qse_awk_val_zero;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_le (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n = __cmp_val (run, left, right);
2008-12-21 21:35:07 +00:00
if (n == CMP_ERROR) return QSE_NULL;
return (n <= 0)? qse_awk_val_one: qse_awk_val_zero;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_lshift (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
if (n3 == 0)
{
return qse_awk_rtx_makeintval (run, (qse_long_t)l1<<(qse_long_t)l2);
}
else
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_rshift (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
if (n3 == 0)
{
return qse_awk_rtx_makeintval (
2008-12-21 21:35:07 +00:00
run, (qse_long_t)l1>>(qse_long_t)l2);
}
else
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_plus (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
/*
n1 n2 n3
0 0 = 0
1 0 = 1
0 1 = 2
1 1 = 3
*/
n3 = n1 + (n2 << 1);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n3 >= 0 && n3 <= 3);
return (n3 == 0)? qse_awk_rtx_makeintval(run,(qse_long_t)l1+(qse_long_t)l2):
(n3 == 1)? qse_awk_rtx_makerealval(run,(qse_real_t)r1+(qse_real_t)l2):
(n3 == 2)? qse_awk_rtx_makerealval(run,(qse_real_t)l1+(qse_real_t)r2):
qse_awk_rtx_makerealval(run,(qse_real_t)r1+(qse_real_t)r2);
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_minus (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n3 >= 0 && n3 <= 3);
return (n3 == 0)? qse_awk_rtx_makeintval(run,(qse_long_t)l1-(qse_long_t)l2):
(n3 == 1)? qse_awk_rtx_makerealval(run,(qse_real_t)r1-(qse_real_t)l2):
(n3 == 2)? qse_awk_rtx_makerealval(run,(qse_real_t)l1-(qse_real_t)r2):
qse_awk_rtx_makerealval(run,(qse_real_t)r1-(qse_real_t)r2);
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_mul (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n3 >= 0 && n3 <= 3);
return (n3 == 0)? qse_awk_rtx_makeintval(run,(qse_long_t)l1*(qse_long_t)l2):
(n3 == 1)? qse_awk_rtx_makerealval(run,(qse_real_t)r1*(qse_real_t)l2):
(n3 == 2)? qse_awk_rtx_makerealval(run,(qse_real_t)l1*(qse_real_t)r2):
qse_awk_rtx_makerealval(run,(qse_real_t)r1*(qse_real_t)r2);
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_div (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
qse_awk_val_t* res;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
if (n3 == 0)
{
if (l2 == 0)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EDIVBY0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (((qse_long_t)l1 % (qse_long_t)l2) == 0)
{
res = qse_awk_rtx_makeintval (
2008-12-21 21:35:07 +00:00
run, (qse_long_t)l1 / (qse_long_t)l2);
}
else
{
res = qse_awk_rtx_makerealval (
2008-12-21 21:35:07 +00:00
run, (qse_real_t)l1 / (qse_real_t)l2);
}
}
else if (n3 == 1)
{
res = qse_awk_rtx_makerealval (
2008-12-21 21:35:07 +00:00
run, (qse_real_t)r1 / (qse_real_t)l2);
}
else if (n3 == 2)
{
res = qse_awk_rtx_makerealval (
2008-12-21 21:35:07 +00:00
run, (qse_real_t)l1 / (qse_real_t)r2);
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n3 == 3);
res = qse_awk_rtx_makerealval (
2008-12-21 21:35:07 +00:00
run, (qse_real_t)r1 / (qse_real_t)r2);
}
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_idiv (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2, quo;
qse_awk_val_t* res;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
if (n3 == 0)
{
if (l2 == 0)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EDIVBY0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res = qse_awk_rtx_makeintval (
2008-12-21 21:35:07 +00:00
run, (qse_long_t)l1 / (qse_long_t)l2);
}
else if (n3 == 1)
{
2008-12-21 21:35:07 +00:00
quo = (qse_real_t)r1 / (qse_real_t)l2;
res = qse_awk_rtx_makeintval (run, (qse_long_t)quo);
}
else if (n3 == 2)
{
2008-12-21 21:35:07 +00:00
quo = (qse_real_t)l1 / (qse_real_t)r2;
res = qse_awk_rtx_makeintval (run, (qse_long_t)quo);
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n3 == 3);
2008-12-21 21:35:07 +00:00
quo = (qse_real_t)r1 / (qse_real_t)r2;
res = qse_awk_rtx_makeintval (run, (qse_long_t)quo);
}
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_mod (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
qse_awk_val_t* res;
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
if (n3 == 0)
{
if (l2 == 0)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EDIVBY0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res = qse_awk_rtx_makeintval (
2008-12-21 21:35:07 +00:00
run, (qse_long_t)l1 % (qse_long_t)l2);
}
else
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_exp (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n1, n2, n3;
2008-12-21 21:35:07 +00:00
qse_long_t l1, l2;
qse_real_t r1, r2;
qse_awk_val_t* res;
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (run->awk->prmfns->pow != QSE_NULL,
"the pow function should be provided when the awk object is created to make the exponentiation work properly.");
n1 = qse_awk_rtx_valtonum (run, left, &l1, &r1);
n2 = qse_awk_rtx_valtonum (run, right, &l2, &r2);
if (n1 == -1 || n2 == -1)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EOPERAND);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
n3 = n1 + (n2 << 1);
if (n3 == 0)
{
/* left - int, right - int */
if (l2 >= 0)
{
2008-12-21 21:35:07 +00:00
qse_long_t v = 1;
while (l2-- > 0) v *= l1;
res = qse_awk_rtx_makeintval (run, v);
}
else if (l1 == 0)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EDIVBY0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
else
{
2008-12-21 21:35:07 +00:00
qse_real_t v = 1.0;
l2 *= -1;
while (l2-- > 0) v /= l1;
res = qse_awk_rtx_makerealval (run, v);
}
}
else if (n3 == 1)
{
/* left - real, right - int */
if (l2 >= 0)
{
2008-12-21 21:35:07 +00:00
qse_real_t v = 1.0;
while (l2-- > 0) v *= r1;
res = qse_awk_rtx_makerealval (run, v);
}
else if (r1 == 0.0)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EDIVBY0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
else
{
2008-12-21 21:35:07 +00:00
qse_real_t v = 1.0;
l2 *= -1;
while (l2-- > 0) v /= r1;
res = qse_awk_rtx_makerealval (run, v);
}
}
else if (n3 == 2)
{
/* left - int, right - real */
res = qse_awk_rtx_makerealval (run,
2008-07-21 06:42:39 +00:00
run->awk->prmfns->pow (
2008-08-19 05:21:48 +00:00
run->awk->prmfns->data,
2008-12-21 21:35:07 +00:00
(qse_real_t)l1,(qse_real_t)r2));
}
else
{
/* left - real, right - real */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n3 == 3);
res = qse_awk_rtx_makerealval (run,
2008-07-21 06:42:39 +00:00
run->awk->prmfns->pow(
2008-08-19 05:21:48 +00:00
run->awk->prmfns->data,
2008-12-21 21:35:07 +00:00
(qse_real_t)r1,(qse_real_t)r2));
}
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_concat (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right)
{
2008-12-21 21:35:07 +00:00
qse_char_t* strl, * strr;
qse_size_t strl_len, strr_len;
qse_awk_val_t* res;
strl = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, left, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &strl_len);
if (strl == QSE_NULL) return QSE_NULL;
strr = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, right, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &strr_len);
if (strr == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, strl);
return QSE_NULL;
}
res = qse_awk_rtx_makestrval2 (run, strl, strl_len, strr, strr_len);
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, strl);
QSE_AWK_FREE (run->awk, strr);
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_ma (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* lv, * rv, * res;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (left->next == QSE_NULL);
QSE_ASSERT (right->next == QSE_NULL);
lv = eval_expression (run, left);
2008-12-21 21:35:07 +00:00
if (lv == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, lv);
rv = eval_expression0 (run, right);
2008-12-21 21:35:07 +00:00
if (rv == QSE_NULL)
{
qse_awk_rtx_refdownval (run, lv);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refupval (run, rv);
2007-12-07 19:57:10 +00:00
res = eval_binop_match0 (run, lv, rv, left->line, right->line, 1);
qse_awk_rtx_refdownval (run, rv);
qse_awk_rtx_refdownval (run, lv);
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_nm (
qse_awk_rtx_t* run, qse_awk_nde_t* left, qse_awk_nde_t* right)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* lv, * rv, * res;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (left->next == QSE_NULL);
QSE_ASSERT (right->next == QSE_NULL);
lv = eval_expression (run, left);
2008-12-21 21:35:07 +00:00
if (lv == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, lv);
rv = eval_expression0 (run, right);
2008-12-21 21:35:07 +00:00
if (rv == QSE_NULL)
{
qse_awk_rtx_refdownval (run, lv);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refupval (run, rv);
res = eval_binop_match0 (
run, lv, rv, left->line, right->line, 0);
qse_awk_rtx_refdownval (run, rv);
qse_awk_rtx_refdownval (run, lv);
return res;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_binop_match0 (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right,
2008-12-21 21:35:07 +00:00
qse_size_t lline, qse_size_t rline, int ret)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* res;
int n, errnum;
2008-12-21 21:35:07 +00:00
qse_char_t* str;
qse_size_t len;
void* rex_code;
2008-12-21 21:35:07 +00:00
if (right->type == QSE_AWK_VAL_REX)
{
2008-12-21 21:35:07 +00:00
rex_code = ((qse_awk_val_rex_t*)right)->code;
}
2008-12-21 21:35:07 +00:00
else if (right->type == QSE_AWK_VAL_STR)
{
2008-12-21 21:35:07 +00:00
rex_code = QSE_AWK_BUILDREX (
run->awk,
((qse_awk_val_str_t*)right)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)right)->len, &errnum);
if (rex_code == QSE_NULL)
{
qse_awk_rtx_seterror (run, errnum, rline, QSE_NULL, 0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
else
{
str = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, right, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &len);
if (str == QSE_NULL) return QSE_NULL;
2008-12-21 21:35:07 +00:00
rex_code = QSE_AWK_BUILDREX (run->awk, str, len, &errnum);
if (rex_code == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, str);
qse_awk_rtx_seterror (run, errnum, rline, QSE_NULL, 0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, str);
}
2008-12-21 21:35:07 +00:00
if (left->type == QSE_AWK_VAL_STR)
{
2008-12-21 21:35:07 +00:00
n = QSE_AWK_MATCHREX (
run->awk, rex_code,
2008-12-21 21:35:07 +00:00
((run->global.ignorecase)? QSE_REX_IGNORECASE: 0),
((qse_awk_val_str_t*)left)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_val_str_t*)left)->len,
QSE_NULL, QSE_NULL, &errnum);
if (n == -1)
{
2008-12-21 21:35:07 +00:00
if (right->type != QSE_AWK_VAL_REX)
QSE_AWK_FREE (run->awk, rex_code);
qse_awk_rtx_seterror (run, errnum, lline, QSE_NULL, 0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res = qse_awk_rtx_makeintval (run, (n == ret));
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (right->type != QSE_AWK_VAL_REX)
QSE_AWK_FREE (run->awk, rex_code);
/* adjust error line */
run->errlin = lline;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
else
{
str = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, left, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &len);
if (str == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (right->type != QSE_AWK_VAL_REX)
QSE_AWK_FREE (run->awk, rex_code);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
n = QSE_AWK_MATCHREX (
run->awk, rex_code,
2008-12-21 21:35:07 +00:00
((run->global.ignorecase)? QSE_REX_IGNORECASE: 0),
str, len, QSE_NULL, QSE_NULL, &errnum);
if (n == -1)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, str);
if (right->type != QSE_AWK_VAL_REX)
QSE_AWK_FREE (run->awk, rex_code);
qse_awk_rtx_seterror (run, errnum, lline, QSE_NULL, 0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res = qse_awk_rtx_makeintval (run, (n == ret));
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, str);
if (right->type != QSE_AWK_VAL_REX)
QSE_AWK_FREE (run->awk, rex_code);
/* adjust error line */
run->errlin = lline;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, str);
}
2008-12-21 21:35:07 +00:00
if (right->type != QSE_AWK_VAL_REX) QSE_AWK_FREE (run->awk, rex_code);
return res;
}
static qse_awk_val_t* eval_unary (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* left, * res = QSE_NULL;
qse_awk_nde_exp_t* exp = (qse_awk_nde_exp_t*)nde;
int n;
2008-12-21 21:35:07 +00:00
qse_long_t l;
qse_real_t r;
QSE_ASSERT (
exp->type == QSE_AWK_NDE_EXP_UNR);
QSE_ASSERT (
exp->left != QSE_NULL && exp->right == QSE_NULL);
QSE_ASSERT (
exp->opcode == QSE_AWK_UNROP_PLUS ||
exp->opcode == QSE_AWK_UNROP_MINUS ||
exp->opcode == QSE_AWK_UNROP_LNOT ||
exp->opcode == QSE_AWK_UNROP_BNOT);
QSE_ASSERT (exp->left->next == QSE_NULL);
left = eval_expression (run, exp->left);
2008-12-21 21:35:07 +00:00
if (left == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, left);
2008-12-21 21:35:07 +00:00
if (exp->opcode == QSE_AWK_UNROP_MINUS)
{
n = qse_awk_rtx_valtonum (run, left, &l, &r);
if (n == -1) goto exit_func;
res = (n == 0)? qse_awk_rtx_makeintval (run, -l):
qse_awk_rtx_makerealval (run, -r);
}
2008-12-21 21:35:07 +00:00
else if (exp->opcode == QSE_AWK_UNROP_LNOT)
{
2008-12-21 21:35:07 +00:00
if (left->type == QSE_AWK_VAL_STR)
{
res = qse_awk_rtx_makeintval (
2008-12-21 21:35:07 +00:00
run, !(((qse_awk_val_str_t*)left)->len > 0));
}
else
{
n = qse_awk_rtx_valtonum (run, left, &l, &r);
if (n == -1) goto exit_func;
res = (n == 0)? qse_awk_rtx_makeintval (run, !l):
qse_awk_rtx_makerealval (run, !r);
}
}
2008-12-21 21:35:07 +00:00
else if (exp->opcode == QSE_AWK_UNROP_BNOT)
{
n = qse_awk_rtx_valtonum (run, left, &l, &r);
if (n == -1) goto exit_func;
2008-12-21 21:35:07 +00:00
if (n == 1) l = (qse_long_t)r;
res = qse_awk_rtx_makeintval (run, ~l);
}
2008-12-21 21:35:07 +00:00
else if (exp->opcode == QSE_AWK_UNROP_PLUS)
{
n = qse_awk_rtx_valtonum (run, left, &l, &r);
if (n == -1) goto exit_func;
res = (n == 0)? qse_awk_rtx_makeintval (run, l):
qse_awk_rtx_makerealval (run, r);
}
exit_func:
qse_awk_rtx_refdownval (run, left);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL) run->errlin = nde->line;
return res;
}
static qse_awk_val_t* eval_incpre (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* left, * res;
qse_awk_nde_exp_t* exp = (qse_awk_nde_exp_t*)nde;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (exp->type == QSE_AWK_NDE_EXP_INCPRE);
QSE_ASSERT (exp->left != QSE_NULL && exp->right == QSE_NULL);
/* this way of checking if the l-value is assignable is
* ugly as it is dependent of the values defined in tree.h.
* but let's keep going this way for the time being. */
2008-12-21 21:35:07 +00:00
if (exp->left->type < QSE_AWK_NDE_NAMED ||
/*exp->left->type > QSE_AWK_NDE_ARGIDX) XXX */
exp->left->type > QSE_AWK_NDE_POS)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EOPERAND, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (exp->left->next == QSE_NULL);
left = eval_expression (run, exp->left);
2008-12-21 21:35:07 +00:00
if (left == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, left);
2008-12-21 21:35:07 +00:00
if (exp->opcode == QSE_AWK_INCOP_PLUS)
{
2008-12-21 21:35:07 +00:00
if (left->type == QSE_AWK_VAL_INT)
{
2008-12-21 21:35:07 +00:00
qse_long_t r = ((qse_awk_val_int_t*)left)->val;
res = qse_awk_rtx_makeintval (run, r + 1);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
2008-12-21 21:35:07 +00:00
else if (left->type == QSE_AWK_VAL_REAL)
{
2008-12-21 21:35:07 +00:00
qse_real_t r = ((qse_awk_val_real_t*)left)->val;
res = qse_awk_rtx_makerealval (run, r + 1.0);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
else
{
2008-12-21 21:35:07 +00:00
qse_long_t v1;
qse_real_t v2;
int n;
n = qse_awk_rtx_valtonum (run, left, &v1, &v2);
if (n == -1)
{
qse_awk_rtx_refdownval (run, left);
/*
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EOPERAND, nde->line,
QSE_NULL, 0);
*/
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
if (n == 0)
{
res = qse_awk_rtx_makeintval (run, v1 + 1);
}
else /* if (n == 1) */
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n == 1);
res = qse_awk_rtx_makerealval (run, v2 + 1.0);
}
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
}
2008-12-21 21:35:07 +00:00
else if (exp->opcode == QSE_AWK_INCOP_MINUS)
{
2008-12-21 21:35:07 +00:00
if (left->type == QSE_AWK_VAL_INT)
{
2008-12-21 21:35:07 +00:00
qse_long_t r = ((qse_awk_val_int_t*)left)->val;
res = qse_awk_rtx_makeintval (run, r - 1);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
2008-12-21 21:35:07 +00:00
else if (left->type == QSE_AWK_VAL_REAL)
{
2008-12-21 21:35:07 +00:00
qse_real_t r = ((qse_awk_val_real_t*)left)->val;
res = qse_awk_rtx_makerealval (run, r - 1.0);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
else
{
2008-12-21 21:35:07 +00:00
qse_long_t v1;
qse_real_t v2;
int n;
n = qse_awk_rtx_valtonum (run, left, &v1, &v2);
if (n == -1)
{
qse_awk_rtx_refdownval (run, left);
/*
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EOPERAND, nde->line,
QSE_NULL, 0);
*/
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
if (n == 0)
{
res = qse_awk_rtx_makeintval (run, v1 - 1);
}
else /* if (n == 1) */
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n == 1);
res = qse_awk_rtx_makerealval (run, v2 - 1.0);
}
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
!"should never happen - invalid opcode");
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EINTERN, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (do_assignment (run, exp->left, res) == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, left);
return res;
}
static qse_awk_val_t* eval_incpst (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* left, * res, * res2;
qse_awk_nde_exp_t* exp = (qse_awk_nde_exp_t*)nde;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (exp->type == QSE_AWK_NDE_EXP_INCPST);
QSE_ASSERT (exp->left != QSE_NULL && exp->right == QSE_NULL);
/* this way of checking if the l-value is assignable is
* ugly as it is dependent of the values defined in tree.h.
* but let's keep going this way for the time being. */
2008-12-21 21:35:07 +00:00
if (exp->left->type < QSE_AWK_NDE_NAMED ||
/*exp->left->type > QSE_AWK_NDE_ARGIDX) XXX */
exp->left->type > QSE_AWK_NDE_POS)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EOPERAND, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (exp->left->next == QSE_NULL);
left = eval_expression (run, exp->left);
2008-12-21 21:35:07 +00:00
if (left == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, left);
2008-12-21 21:35:07 +00:00
if (exp->opcode == QSE_AWK_INCOP_PLUS)
{
2008-12-21 21:35:07 +00:00
if (left->type == QSE_AWK_VAL_INT)
{
2008-12-21 21:35:07 +00:00
qse_long_t r = ((qse_awk_val_int_t*)left)->val;
res = qse_awk_rtx_makeintval (run, r);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res2 = qse_awk_rtx_makeintval (run, r + 1);
2008-12-21 21:35:07 +00:00
if (res2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_freeval (run, res, QSE_TRUE);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
2008-12-21 21:35:07 +00:00
else if (left->type == QSE_AWK_VAL_REAL)
{
2008-12-21 21:35:07 +00:00
qse_real_t r = ((qse_awk_val_real_t*)left)->val;
res = qse_awk_rtx_makerealval (run, r);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res2 = qse_awk_rtx_makerealval (run, r + 1.0);
2008-12-21 21:35:07 +00:00
if (res2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_freeval (run, res, QSE_TRUE);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
else
{
2008-12-21 21:35:07 +00:00
qse_long_t v1;
qse_real_t v2;
int n;
n = qse_awk_rtx_valtonum (run, left, &v1, &v2);
if (n == -1)
{
qse_awk_rtx_refdownval (run, left);
/*
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EOPERAND, nde->line,
QSE_NULL, 0);
*/
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
if (n == 0)
{
res = qse_awk_rtx_makeintval (run, v1);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res2 = qse_awk_rtx_makeintval (run, v1 + 1);
2008-12-21 21:35:07 +00:00
if (res2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_freeval (run, res, QSE_TRUE);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
else /* if (n == 1) */
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n == 1);
res = qse_awk_rtx_makerealval (run, v2);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res2 = qse_awk_rtx_makerealval (run, v2 + 1.0);
2008-12-21 21:35:07 +00:00
if (res2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_freeval (run, res, QSE_TRUE);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
}
}
2008-12-21 21:35:07 +00:00
else if (exp->opcode == QSE_AWK_INCOP_MINUS)
{
2008-12-21 21:35:07 +00:00
if (left->type == QSE_AWK_VAL_INT)
{
2008-12-21 21:35:07 +00:00
qse_long_t r = ((qse_awk_val_int_t*)left)->val;
res = qse_awk_rtx_makeintval (run, r);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res2 = qse_awk_rtx_makeintval (run, r - 1);
2008-12-21 21:35:07 +00:00
if (res2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_freeval (run, res, QSE_TRUE);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
2008-12-21 21:35:07 +00:00
else if (left->type == QSE_AWK_VAL_REAL)
{
2008-12-21 21:35:07 +00:00
qse_real_t r = ((qse_awk_val_real_t*)left)->val;
res = qse_awk_rtx_makerealval (run, r);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res2 = qse_awk_rtx_makerealval (run, r - 1.0);
2008-12-21 21:35:07 +00:00
if (res2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_freeval (run, res, QSE_TRUE);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
else
{
2008-12-21 21:35:07 +00:00
qse_long_t v1;
qse_real_t v2;
int n;
n = qse_awk_rtx_valtonum (run, left, &v1, &v2);
if (n == -1)
{
qse_awk_rtx_refdownval (run, left);
/*
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EOPERAND, nde->line,
QSE_NULL, 0);
*/
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
if (n == 0)
{
res = qse_awk_rtx_makeintval (run, v1);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res2 = qse_awk_rtx_makeintval (run, v1 - 1);
2008-12-21 21:35:07 +00:00
if (res2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_freeval (run, res, QSE_TRUE);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
else /* if (n == 1) */
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (n == 1);
res = qse_awk_rtx_makerealval (run, v2);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
res2 = qse_awk_rtx_makerealval (run, v2 - 1.0);
2008-12-21 21:35:07 +00:00
if (res2 == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_freeval (run, res, QSE_TRUE);
/* adjust error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
}
}
else
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
!"should never happen - invalid opcode");
qse_awk_rtx_refdownval (run, left);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EINTERN, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (do_assignment (run, exp->left, res2) == QSE_NULL)
{
qse_awk_rtx_refdownval (run, left);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, left);
return res;
}
static qse_awk_val_t* eval_cnd (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tv, * v;
qse_awk_nde_cnd_t* cnd = (qse_awk_nde_cnd_t*)nde;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (cnd->test->next == QSE_NULL);
tv = eval_expression (run, cnd->test);
2008-12-21 21:35:07 +00:00
if (tv == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, tv);
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
cnd->left->next == QSE_NULL &&
cnd->right->next == QSE_NULL);
v = (qse_awk_rtx_valtobool (run, tv))?
eval_expression (run, cnd->left):
eval_expression (run, cnd->right);
qse_awk_rtx_refdownval (run, tv);
return v;
}
static qse_awk_val_t* eval_fnc (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_call_t* call = (qse_awk_nde_call_t*)nde;
/* intrinsic function */
if (call->nargs < call->what.fnc.arg.min)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EARGTF, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
if (call->nargs > call->what.fnc.arg.max)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EARGTM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2007-12-07 23:58:44 +00:00
return eval_call (
run, nde, call->what.fnc.arg.spec,
2008-12-21 21:35:07 +00:00
QSE_NULL, QSE_NULL, QSE_NULL);
}
static qse_awk_val_t* eval_fun_intrinsic (
qse_awk_rtx_t* run, qse_awk_nde_t* nde, void(*errhandler)(void*), void* eharg)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_call_t* call = (qse_awk_nde_call_t*)nde;
qse_awk_fun_t* fun;
2008-12-21 21:35:07 +00:00
qse_map_pair_t* pair;
pair = qse_map_search (run->awk->tree.funs,
call->what.fun.name.ptr, call->what.fun.name.len);
2008-12-21 21:35:07 +00:00
if (pair == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_cstr_t errarg;
errarg.ptr = call->what.fun.name.ptr;
errarg.len = call->what.fun.name.len,
qse_awk_rtx_seterror (run,
2008-12-21 21:35:07 +00:00
QSE_AWK_EFNNONE, nde->line, &errarg, 1);
return QSE_NULL;
}
fun = (qse_awk_fun_t*)QSE_MAP_VPTR(pair);
QSE_ASSERT (fun != QSE_NULL);
if (call->nargs > fun->nargs)
{
/* TODO: is this correct? what if i want to
* allow arbitarary numbers of arguments? */
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EARGTM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
return eval_call (run, nde, QSE_NULL, fun, errhandler, eharg);
}
static qse_awk_val_t* eval_fun (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
2007-12-07 23:58:44 +00:00
{
return eval_fun_intrinsic (run, nde, QSE_NULL, QSE_NULL);
2007-12-07 23:58:44 +00:00
}
/* run->stack_base has not been set for this
* stack frame. so the STACK_ARG macro cannot be used as in
* qse_awk_rtx_refdownval (run, STACK_ARG(run,nargs));*/
#define UNWIND_RUN_STACK(run,nargs) \
do { \
while ((nargs) > 0) \
{ \
--(nargs); \
qse_awk_rtx_refdownval ((run), \
(run)->stack[(run)->stack_top-1]); \
__raw_pop (run); \
} \
__raw_pop (run); /* nargs */ \
__raw_pop (run); /* return */ \
__raw_pop (run); /* prev stack top */ \
__raw_pop (run); /* prev stack back */ \
} while (0)
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_call (
qse_awk_rtx_t* run, qse_awk_nde_t* nde,
const qse_char_t* fnc_arg_spec, qse_awk_fun_t* fun,
2007-12-07 23:58:44 +00:00
void(*errhandler)(void*), void* eharg)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_call_t* call = (qse_awk_nde_call_t*)nde;
qse_size_t saved_stack_top;
qse_size_t nargs, i;
qse_awk_nde_t* p;
qse_awk_val_t* v;
int n;
/*
* ---------------------
* localn <- stack top
* ---------------------
* ....
* ---------------------
* local0 local variables are pushed by run_block
* =====================
* argn
* ---------------------
* ....
* ---------------------
* arg1
* ---------------------
* arg0
* ---------------------
* nargs
* ---------------------
* return value
* ---------------------
* previous stack top
* ---------------------
* previous stack base <- stack base
* =====================
* 0 (nargs) <- stack top
* ---------------------
* return value
* ---------------------
* previous stack top
* ---------------------
* previous stack base <- stack base
* =====================
* globaln
* ---------------------
* ....
* ---------------------
* global0
* ---------------------
*/
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
QSE_SIZEOF(void*) >= QSE_SIZEOF(run->stack_top));
QSE_ASSERT (
QSE_SIZEOF(void*) >= QSE_SIZEOF(run->stack_base));
saved_stack_top = run->stack_top;
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (QSE_T("setting up function stack frame top=%ld base=%ld\n"),
(long)run->stack_top, (long)run->stack_base);
#endif
if (__raw_push(run,(void*)run->stack_base) == -1)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
if (__raw_push(run,(void*)saved_stack_top) == -1)
{
__raw_pop (run);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
/* secure space for a return value. */
2008-12-21 21:35:07 +00:00
if (__raw_push(run,qse_awk_val_nil) == -1)
{
__raw_pop (run);
__raw_pop (run);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
/* secure space for nargs */
2008-12-21 21:35:07 +00:00
if (__raw_push(run,qse_awk_val_nil) == -1)
{
__raw_pop (run);
__raw_pop (run);
__raw_pop (run);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
for (p = call->args, nargs = 0; p != QSE_NULL; p = p->next, nargs++)
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
fnc_arg_spec == QSE_NULL ||
(fnc_arg_spec != QSE_NULL &&
qse_strlen(fnc_arg_spec) > nargs));
if (fnc_arg_spec != QSE_NULL &&
fnc_arg_spec[nargs] == QSE_T('r'))
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t** ref;
if (get_reference (run, p, &ref) == -1)
{
UNWIND_RUN_STACK (run, nargs);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
/* p->type-QSE_AWK_NDE_NAMED assumes that the
* derived value matches QSE_AWK_VAL_REF_XXX */
v = qse_awk_rtx_makerefval (
2008-12-21 21:35:07 +00:00
run, p->type-QSE_AWK_NDE_NAMED, ref);
}
else if (fnc_arg_spec != QSE_NULL &&
fnc_arg_spec[nargs] == QSE_T('x'))
{
/* a regular expression is passed to
* the function as it is */
v = eval_expression0 (run, p);
}
else
{
v = eval_expression (run, p);
}
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL)
{
UNWIND_RUN_STACK (run, nargs);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
if (__raw_push(run,v) == -1)
{
/* ugly - v needs to be freed if it doesn't have
* any reference. but its reference has not been
* updated yet as it is carried out after the
* successful stack push. so it adds up a reference
* and dereferences it */
qse_awk_rtx_refupval (run, v);
qse_awk_rtx_refdownval (run, v);
UNWIND_RUN_STACK (run, nargs);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
qse_awk_rtx_refupval (run, v);
/*nargs++; p = p->next;*/
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nargs == call->nargs);
if (fun != QSE_NULL)
{
/* extra step for normal awk functions */
while (nargs < fun->nargs)
{
/* push as many nils as the number of missing actual arguments */
2008-12-21 21:35:07 +00:00
if (__raw_push(run,qse_awk_val_nil) == -1)
{
UNWIND_RUN_STACK (run, nargs);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line,
QSE_NULL, 0);
return QSE_NULL;
}
nargs++;
}
}
run->stack_base = saved_stack_top;
STACK_NARGS(run) = (void*)nargs;
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (QSE_T("running function body\n"));
#endif
if (fun != QSE_NULL)
{
/* normal awk function */
QSE_ASSERT (fun->body->type == QSE_AWK_NDE_BLK);
n = run_block(run,(qse_awk_nde_blk_t*)fun->body);
}
else
{
n = 0;
/* intrinsic function */
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
call->nargs >= call->what.fnc.arg.min &&
call->nargs <= call->what.fnc.arg.max);
if (call->what.fnc.handler != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
run->errnum = QSE_AWK_ENOERR;
/* NOTE: oname is used when the handler is invoked.
* name might be differnt from oname if
2008-12-21 21:35:07 +00:00
* qse_awk_setword has been used */
n = call->what.fnc.handler (
run,
call->what.fnc.oname.ptr,
call->what.fnc.oname.len);
if (n <= -1)
{
2008-12-21 21:35:07 +00:00
if (run->errnum == QSE_AWK_ENOERR)
{
/* the handler has not set the error.
* fix it */
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EBFNIMPL,
nde->line, QSE_NULL, 0);
}
else
{
/* adjust the error line */
run->errlin = nde->line;
}
/* correct the return code just in case */
if (n < -1) n = -1;
}
}
}
/* refdown args in the run.stack */
2008-12-21 21:35:07 +00:00
nargs = (qse_size_t)STACK_NARGS(run);
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (QSE_T("block run complete nargs = %d\n"), (int)nargs);
#endif
for (i = 0; i < nargs; i++)
{
qse_awk_rtx_refdownval (run, STACK_ARG(run,i));
}
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (QSE_T("got return value\n"));
#endif
v = STACK_RETVAL(run);
if (n == -1)
{
2008-12-21 21:35:07 +00:00
if (errhandler != QSE_NULL)
2007-12-07 23:58:44 +00:00
{
/* capture_retval_on_exit takes advantage of
* this handler to retrieve the return value
* when exit() is used to terminate the program. */
errhandler (eharg);
}
/* if the earlier operations failed and this function
* has to return a error, the return value is just
* destroyed and replaced by nil */
qse_awk_rtx_refdownval (run, v);
2008-12-21 21:35:07 +00:00
STACK_RETVAL(run) = qse_awk_val_nil;
}
else
{
/* this trick has been mentioned in run_return.
* adjust the reference count of the return value.
* the value must not be freed even if the reference count
* reached zero because its reference has been incremented
* in run_return or directly by qse_awk_rtx_setretval
* regardless of its reference count. */
qse_awk_rtx_refdownval_nofree (run, v);
}
2008-12-21 21:35:07 +00:00
run->stack_top = (qse_size_t)run->stack[run->stack_base+1];
run->stack_base = (qse_size_t)run->stack[run->stack_base+0];
if (run->exit_level == EXIT_FUNCTION) run->exit_level = EXIT_NONE;
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (QSE_T("returning from function top=%ld, base=%ld\n"),
(long)run->stack_top, (long)run->stack_base);
#endif
2008-12-21 21:35:07 +00:00
return (n == -1)? QSE_NULL: v;
}
static int get_reference (
qse_awk_rtx_t* run, qse_awk_nde_t* nde, qse_awk_val_t*** ref)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_var_t* tgt = (qse_awk_nde_var_t*)nde;
qse_awk_val_t** tmp;
/* refer to eval_indexed for application of a similar concept */
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_NAMED)
{
2008-12-21 21:35:07 +00:00
qse_map_pair_t* pair;
2008-12-21 21:35:07 +00:00
pair = qse_map_search (
run->named, tgt->id.name.ptr, tgt->id.name.len);
2008-12-21 21:35:07 +00:00
if (pair == QSE_NULL)
{
/* it is bad that the named variable has to be
* created in the function named "__get_refernce".
* would there be any better ways to avoid this? */
2008-12-21 21:35:07 +00:00
pair = qse_map_upsert (
run->named, tgt->id.name.ptr,
2008-12-21 21:35:07 +00:00
tgt->id.name.len, qse_awk_val_nil, 0);
if (pair == QSE_NULL)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line,
QSE_NULL, 0);
return -1;
}
}
2008-12-21 21:35:07 +00:00
*ref = (qse_awk_val_t**)&QSE_MAP_VPTR(pair);
return 0;
}
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_GLOBAL)
{
2008-12-21 21:35:07 +00:00
*ref = (qse_awk_val_t**)&STACK_GLOBAL(run,tgt->id.idxa);
return 0;
}
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_LOCAL)
{
2008-12-21 21:35:07 +00:00
*ref = (qse_awk_val_t**)&STACK_LOCAL(run,tgt->id.idxa);
return 0;
}
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_ARG)
{
2008-12-21 21:35:07 +00:00
*ref = (qse_awk_val_t**)&STACK_ARG(run,tgt->id.idxa);
return 0;
}
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_NAMEDIDX)
{
2008-12-21 21:35:07 +00:00
qse_map_pair_t* pair;
2008-12-21 21:35:07 +00:00
pair = qse_map_search (
run->named, tgt->id.name.ptr, tgt->id.name.len);
2008-12-21 21:35:07 +00:00
if (pair == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
pair = qse_map_upsert (
run->named, tgt->id.name.ptr,
2008-12-21 21:35:07 +00:00
tgt->id.name.len, qse_awk_val_nil, 0);
if (pair == QSE_NULL)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line,
QSE_NULL, 0);
return -1;
}
}
tmp = get_reference_indexed (
2008-12-21 21:35:07 +00:00
run, tgt, (qse_awk_val_t**)&QSE_MAP_VPTR(pair));
if (tmp == QSE_NULL) return -1;
*ref = tmp;
}
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_GLOBALIDX)
{
tmp = get_reference_indexed (run, tgt,
2008-12-21 21:35:07 +00:00
(qse_awk_val_t**)&STACK_GLOBAL(run,tgt->id.idxa));
if (tmp == QSE_NULL) return -1;
*ref = tmp;
}
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_LOCALIDX)
{
tmp = get_reference_indexed (run, tgt,
2008-12-21 21:35:07 +00:00
(qse_awk_val_t**)&STACK_LOCAL(run,tgt->id.idxa));
if (tmp == QSE_NULL) return -1;
*ref = tmp;
}
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_ARGIDX)
{
tmp = get_reference_indexed (run, tgt,
2008-12-21 21:35:07 +00:00
(qse_awk_val_t**)&STACK_ARG(run,tgt->id.idxa));
if (tmp == QSE_NULL) return -1;
*ref = tmp;
}
2008-12-21 21:35:07 +00:00
if (nde->type == QSE_AWK_NDE_POS)
{
int n;
2008-12-21 21:35:07 +00:00
qse_long_t lv;
qse_real_t rv;
qse_awk_val_t* v;
/* the position number is returned for the positional
* variable unlike other reference types. */
2008-12-21 21:35:07 +00:00
v = eval_expression (run, ((qse_awk_nde_pos_t*)nde)->val);
if (v == QSE_NULL) return -1;
qse_awk_rtx_refupval (run, v);
n = qse_awk_rtx_valtonum (run, v, &lv, &rv);
qse_awk_rtx_refdownval (run, v);
if (n == -1)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EPOSIDX, nde->line, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
if (n == 1) lv = (qse_long_t)rv;
if (!IS_VALID_POSIDX(lv))
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EPOSIDX, nde->line, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
*ref = (qse_awk_val_t**)((qse_size_t)lv);
return 0;
}
qse_awk_rtx_seterror (run, QSE_AWK_ENOTREF, nde->line, QSE_NULL, 0);
return -1;
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t** get_reference_indexed (
qse_awk_rtx_t* run, qse_awk_nde_var_t* nde, qse_awk_val_t** val)
{
2008-12-21 21:35:07 +00:00
qse_map_pair_t* pair;
qse_char_t* str;
qse_size_t len;
qse_char_t idxbuf[IDXBUFSIZE];
2008-12-21 21:35:07 +00:00
QSE_ASSERT (val != QSE_NULL);
2008-12-21 21:35:07 +00:00
if ((*val)->type == QSE_AWK_VAL_NIL)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp;
tmp = qse_awk_rtx_makemapval (run);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL)
{
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, *val);
*val = tmp;
qse_awk_rtx_refupval (run, (qse_awk_val_t*)*val);
}
2008-12-21 21:35:07 +00:00
else if ((*val)->type != QSE_AWK_VAL_MAP)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOTMAP, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->idx != QSE_NULL);
2008-12-21 21:35:07 +00:00
len = QSE_COUNTOF(idxbuf);
2008-01-16 21:46:08 +00:00
str = idxnde_to_str (run, nde->idx, idxbuf, &len);
2008-12-21 21:35:07 +00:00
if (str == QSE_NULL)
2008-01-16 21:46:08 +00:00
{
2008-12-21 21:35:07 +00:00
str = idxnde_to_str (run, nde->idx, QSE_NULL, &len);
if (str == QSE_NULL) return QSE_NULL;
2008-01-16 21:46:08 +00:00
}
2008-12-21 21:35:07 +00:00
pair = qse_map_search ((*(qse_awk_val_map_t**)val)->map, str, len);
if (pair == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
pair = qse_map_upsert (
(*(qse_awk_val_map_t**)val)->map,
str, len, qse_awk_val_nil, 0);
if (pair == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (str != idxbuf) QSE_AWK_FREE (run->awk, str);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
qse_awk_rtx_refupval (run, QSE_MAP_VPTR(pair));
}
2008-12-21 21:35:07 +00:00
if (str != idxbuf) QSE_AWK_FREE (run->awk, str);
return (qse_awk_val_t**)&QSE_MAP_VPTR(pair);
}
static qse_awk_val_t* eval_int (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
val = qse_awk_rtx_makeintval (run, ((qse_awk_nde_int_t*)nde)->val);
2008-12-21 21:35:07 +00:00
if (val == QSE_NULL)
{
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
((qse_awk_val_int_t*)val)->nde = nde;
return val;
}
static qse_awk_val_t* eval_real (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
val = qse_awk_rtx_makerealval (run, ((qse_awk_nde_real_t*)nde)->val);
2008-12-21 21:35:07 +00:00
if (val == QSE_NULL)
{
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
((qse_awk_val_real_t*)val)->nde = nde;
return val;
}
static qse_awk_val_t* eval_str (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
val = qse_awk_rtx_makestrval (run,
((qse_awk_nde_str_t*)nde)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_nde_str_t*)nde)->len);
if (val == QSE_NULL)
{
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
return val;
}
static qse_awk_val_t* eval_rex (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* val;
val = qse_awk_rtx_makerexval (run,
((qse_awk_nde_rex_t*)nde)->ptr,
2008-12-21 21:35:07 +00:00
((qse_awk_nde_rex_t*)nde)->len,
((qse_awk_nde_rex_t*)nde)->code);
if (val == QSE_NULL)
{
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
return val;
}
static qse_awk_val_t* eval_named (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_map_pair_t* pair;
2008-12-21 21:35:07 +00:00
pair = qse_map_search (run->named,
((qse_awk_nde_var_t*)nde)->id.name.ptr,
((qse_awk_nde_var_t*)nde)->id.name.len);
2008-12-21 21:35:07 +00:00
return (pair == QSE_NULL)? qse_awk_val_nil: QSE_MAP_VPTR(pair);
}
static qse_awk_val_t* eval_global (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
return STACK_GLOBAL(run,((qse_awk_nde_var_t*)nde)->id.idxa);
}
static qse_awk_val_t* eval_local (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
return STACK_LOCAL(run,((qse_awk_nde_var_t*)nde)->id.idxa);
}
static qse_awk_val_t* eval_arg (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
return STACK_ARG(run,((qse_awk_nde_var_t*)nde)->id.idxa);
}
2008-12-21 21:35:07 +00:00
static qse_awk_val_t* eval_indexed (
qse_awk_rtx_t* run, qse_awk_nde_var_t* nde, qse_awk_val_t** val)
{
2008-12-21 21:35:07 +00:00
qse_map_pair_t* pair;
qse_char_t* str;
qse_size_t len;
qse_char_t idxbuf[IDXBUFSIZE];
2008-12-21 21:35:07 +00:00
QSE_ASSERT (val != QSE_NULL);
2008-12-21 21:35:07 +00:00
if ((*val)->type == QSE_AWK_VAL_NIL)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* tmp;
tmp = qse_awk_rtx_makemapval (run);
2008-12-21 21:35:07 +00:00
if (tmp == QSE_NULL)
{
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, *val);
*val = tmp;
qse_awk_rtx_refupval (run, (qse_awk_val_t*)*val);
}
2008-12-21 21:35:07 +00:00
else if ((*val)->type != QSE_AWK_VAL_MAP)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOTMAP, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde->idx != QSE_NULL);
2008-12-21 21:35:07 +00:00
len = QSE_COUNTOF(idxbuf);
2008-01-16 21:46:08 +00:00
str = idxnde_to_str (run, nde->idx, idxbuf, &len);
2008-12-21 21:35:07 +00:00
if (str == QSE_NULL)
2008-01-16 21:46:08 +00:00
{
2008-12-21 21:35:07 +00:00
str = idxnde_to_str (run, nde->idx, QSE_NULL, &len);
if (str == QSE_NULL) return QSE_NULL;
2008-01-16 21:46:08 +00:00
}
2008-12-21 21:35:07 +00:00
pair = qse_map_search ((*(qse_awk_val_map_t**)val)->map, str, len);
if (str != idxbuf) QSE_AWK_FREE (run->awk, str);
2008-12-21 21:35:07 +00:00
return (pair == QSE_NULL)? qse_awk_val_nil:
(qse_awk_val_t*)QSE_MAP_VPTR(pair);
}
static qse_awk_val_t* eval_namedidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_var_t* tgt = (qse_awk_nde_var_t*)nde;
qse_map_pair_t* pair;
2008-12-21 21:35:07 +00:00
pair = qse_map_search (run->named, tgt->id.name.ptr, tgt->id.name.len);
if (pair == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
pair = qse_map_upsert (run->named,
tgt->id.name.ptr, tgt->id.name.len, qse_awk_val_nil, 0);
if (pair == QSE_NULL)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
qse_awk_rtx_refupval (run, QSE_MAP_VPTR(pair));
}
2008-12-21 21:35:07 +00:00
return eval_indexed (run, tgt, (qse_awk_val_t**)&QSE_MAP_VPTR(pair));
}
static qse_awk_val_t* eval_globalidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
return eval_indexed (run, (qse_awk_nde_var_t*)nde,
(qse_awk_val_t**)&STACK_GLOBAL(run,((qse_awk_nde_var_t*)nde)->id.idxa));
}
static qse_awk_val_t* eval_localidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
return eval_indexed (run, (qse_awk_nde_var_t*)nde,
(qse_awk_val_t**)&STACK_LOCAL(run,((qse_awk_nde_var_t*)nde)->id.idxa));
}
static qse_awk_val_t* eval_argidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
return eval_indexed (run, (qse_awk_nde_var_t*)nde,
(qse_awk_val_t**)&STACK_ARG(run,((qse_awk_nde_var_t*)nde)->id.idxa));
}
static qse_awk_val_t* eval_pos (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_pos_t* pos = (qse_awk_nde_pos_t*)nde;
qse_awk_val_t* v;
qse_long_t lv;
qse_real_t rv;
int n;
v = eval_expression (run, pos->val);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, v);
n = qse_awk_rtx_valtonum (run, v, &lv, &rv);
qse_awk_rtx_refdownval (run, v);
if (n == -1)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EPOSIDX, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (n == 1) lv = (qse_long_t)rv;
if (lv < 0)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_EPOSIDX, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
if (lv == 0) v = run->inrec.d0;
2008-12-21 21:35:07 +00:00
else if (lv > 0 && lv <= (qse_long_t)run->inrec.nflds)
v = run->inrec.flds[lv-1].val;
2008-12-21 21:35:07 +00:00
else v = qse_awk_val_zls; /*qse_awk_val_nil;*/
return v;
}
static qse_awk_val_t* eval_getline (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
2008-12-21 21:35:07 +00:00
qse_awk_nde_getline_t* p;
qse_awk_val_t* v, * res;
qse_char_t* in = QSE_NULL;
const qse_char_t* dst;
qse_str_t buf;
int n;
2008-12-21 21:35:07 +00:00
p = (qse_awk_nde_getline_t*)nde;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (
(p->in_type == QSE_AWK_IN_PIPE && p->in != QSE_NULL) ||
(p->in_type == QSE_AWK_IN_RWPIPE && p->in != QSE_NULL) ||
2008-12-21 21:35:07 +00:00
(p->in_type == QSE_AWK_IN_FILE && p->in != QSE_NULL) ||
(p->in_type == QSE_AWK_IN_CONSOLE && p->in == QSE_NULL));
2008-12-21 21:35:07 +00:00
if (p->in != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_size_t len;
v = eval_expression (run, p->in);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
2008-12-21 21:35:07 +00:00
/* TODO: distinction between v->type == QSE_AWK_VAL_STR
* and v->type != QSE_AWK_VAL_STR
* if you use the buffer the v directly when
* v->type == QSE_AWK_VAL_STR, qse_awk_rtx_refdownval(v)
* should not be called immediately below */
qse_awk_rtx_refupval (run, v);
in = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, v, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &len);
if (in == QSE_NULL)
{
qse_awk_rtx_refdownval (run, v);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, v);
if (len <= 0)
{
/* the input source name is empty.
* make getline return -1 */
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, in);
n = -1;
goto skip_read;
}
while (len > 0)
{
2008-12-21 21:35:07 +00:00
if (in[--len] == QSE_T('\0'))
{
/* the input source name contains a null
* character. make getline return -1 */
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, in);
n = -1;
goto skip_read;
}
}
}
2008-12-21 21:35:07 +00:00
dst = (in == QSE_NULL)? QSE_T(""): in;
/* TODO: optimize the line buffer management */
2008-12-21 21:35:07 +00:00
if (qse_str_init (&buf, MMGR(run), DEF_BUF_CAPA) == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
if (in != QSE_NULL) QSE_AWK_FREE (run->awk, in);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
n = qse_awk_readeio (run, p->in_type, dst, &buf);
2008-12-21 21:35:07 +00:00
if (in != QSE_NULL) QSE_AWK_FREE (run->awk, in);
if (n <= -1)
{
/* make getline return -1 */
n = -1;
}
if (n > 0)
{
2008-12-21 21:35:07 +00:00
if (p->var == QSE_NULL)
{
/* set $0 with the input value */
if (qse_awk_rtx_setrec (run, 0,
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(&buf),
QSE_STR_LEN(&buf)) == -1)
{
2008-12-21 21:35:07 +00:00
qse_str_fini (&buf);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
qse_str_fini (&buf);
}
else
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
v = qse_awk_rtx_makestrval (run,
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(&buf), QSE_STR_LEN(&buf));
qse_str_fini (&buf);
if (v == QSE_NULL)
{
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refupval (run, v);
2008-12-21 21:35:07 +00:00
if (do_assignment(run, p->var, v) == QSE_NULL)
{
qse_awk_rtx_refdownval (run, v);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, v);
}
}
else
{
2008-12-21 21:35:07 +00:00
qse_str_fini (&buf);
}
skip_read:
res = qse_awk_rtx_makeintval (run, n);
2008-12-21 21:35:07 +00:00
if (res == QSE_NULL) run->errlin = nde->line;
return res;
}
static int __raw_push (qse_awk_rtx_t* run, void* val)
{
if (run->stack_top >= run->stack_limit)
{
void** tmp;
2008-12-21 21:35:07 +00:00
qse_size_t n;
n = run->stack_limit + STACK_INCREMENT;
2008-12-21 21:35:07 +00:00
if (MMGR(run)->realloc != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
tmp = (void**) QSE_AWK_REALLOC (
run->awk, run->stack, n * QSE_SIZEOF(void*));
if (tmp == QSE_NULL) return -1;
}
else
{
2008-12-21 21:35:07 +00:00
tmp = (void**) QSE_AWK_ALLOC (
run->awk, n * QSE_SIZEOF(void*));
if (tmp == QSE_NULL) return -1;
if (run->stack != QSE_NULL)
{
2008-12-21 21:35:07 +00:00
QSE_MEMCPY (
tmp, run->stack,
2008-12-21 21:35:07 +00:00
run->stack_limit * QSE_SIZEOF(void*));
QSE_AWK_FREE (run->awk, run->stack);
}
}
run->stack = tmp;
run->stack_limit = n;
}
run->stack[run->stack_top++] = val;
return 0;
}
static int read_record (qse_awk_rtx_t* run)
{
2008-12-21 21:35:07 +00:00
qse_ssize_t n;
if (qse_awk_rtx_clrrec (run, QSE_FALSE) == -1) return -1;
n = qse_awk_readeio (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_IN_CONSOLE, QSE_T(""), &run->inrec.line);
if (n <= -1)
{
qse_awk_rtx_clrrec (run, QSE_FALSE);
return -1;
}
#ifdef DEBUG_RUN
2008-12-21 21:35:07 +00:00
qse_dprintf (QSE_T("record len = %d str=[%.*s]\n"),
(int)QSE_STR_LEN(&run->inrec.line),
(int)QSE_STR_LEN(&run->inrec.line),
QSE_STR_PTR(&run->inrec.line));
#endif
if (n == 0)
{
2008-12-21 21:35:07 +00:00
QSE_ASSERT (QSE_STR_LEN(&run->inrec.line) == 0);
return 0;
}
if (qse_awk_rtx_setrec (run, 0,
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(&run->inrec.line),
QSE_STR_LEN(&run->inrec.line)) == -1) return -1;
return 1;
}
static int shorten_record (qse_awk_rtx_t* run, qse_size_t nflds)
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
qse_char_t* ofs_free = QSE_NULL, * ofs;
qse_size_t ofs_len, i;
qse_str_t tmp;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nflds <= run->inrec.nflds);
if (nflds > 1)
{
2008-12-21 21:35:07 +00:00
v = STACK_GLOBAL(run, QSE_AWK_GLOBAL_OFS);
qse_awk_rtx_refupval (run, v);
2008-12-21 21:35:07 +00:00
if (v->type == QSE_AWK_VAL_NIL)
{
/* OFS not set */
2008-12-21 21:35:07 +00:00
ofs = QSE_T(" ");
ofs_len = 1;
}
2008-12-21 21:35:07 +00:00
else if (v->type == QSE_AWK_VAL_STR)
{
ofs = ((qse_awk_val_str_t*)v)->ptr;
2008-12-21 21:35:07 +00:00
ofs_len = ((qse_awk_val_str_t*)v)->len;
}
else
{
ofs = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, v, QSE_AWK_VALTOSTR_CLEAR,
QSE_NULL, &ofs_len);
if (ofs == QSE_NULL) return -1;
ofs_free = ofs;
}
}
2008-12-21 21:35:07 +00:00
if (qse_str_init (
&tmp, MMGR(run), QSE_STR_LEN(&run->inrec.line)) == QSE_NULL)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
for (i = 0; i < nflds; i++)
{
2008-12-21 21:35:07 +00:00
if (i > 0 && qse_str_ncat(&tmp,ofs,ofs_len) == (qse_size_t)-1)
{
2008-12-21 21:35:07 +00:00
if (ofs_free != QSE_NULL)
QSE_AWK_FREE (run->awk, ofs_free);
if (nflds > 1) qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
2008-12-21 21:35:07 +00:00
if (qse_str_ncat (&tmp,
run->inrec.flds[i].ptr,
2008-12-21 21:35:07 +00:00
run->inrec.flds[i].len) == (qse_size_t)-1)
{
2008-12-21 21:35:07 +00:00
if (ofs_free != QSE_NULL)
QSE_AWK_FREE (run->awk, ofs_free);
if (nflds > 1) qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
return -1;
}
}
2008-12-21 21:35:07 +00:00
if (ofs_free != QSE_NULL) QSE_AWK_FREE (run->awk, ofs_free);
if (nflds > 1) qse_awk_rtx_refdownval (run, v);
v = (qse_awk_val_t*) qse_awk_rtx_makestrval (
2008-12-21 21:35:07 +00:00
run, QSE_STR_PTR(&tmp), QSE_STR_LEN(&tmp));
if (v == QSE_NULL) return -1;
qse_awk_rtx_refdownval (run, run->inrec.d0);
run->inrec.d0 = v;
qse_awk_rtx_refupval (run, run->inrec.d0);
2008-12-21 21:35:07 +00:00
qse_str_swap (&tmp, &run->inrec.line);
qse_str_fini (&tmp);
for (i = nflds; i < run->inrec.nflds; i++)
{
qse_awk_rtx_refdownval (run, run->inrec.flds[i].val);
}
run->inrec.nflds = nflds;
return 0;
}
2008-12-21 21:35:07 +00:00
static qse_char_t* idxnde_to_str (
qse_awk_rtx_t* run, qse_awk_nde_t* nde, qse_char_t* buf, qse_size_t* len)
{
2008-12-21 21:35:07 +00:00
qse_char_t* str;
qse_awk_val_t* idx;
2008-12-21 21:35:07 +00:00
QSE_ASSERT (nde != QSE_NULL);
2008-12-21 21:35:07 +00:00
if (nde->next == QSE_NULL)
{
/* single node index */
idx = eval_expression (run, nde);
2008-12-21 21:35:07 +00:00
if (idx == QSE_NULL) return QSE_NULL;
qse_awk_rtx_refupval (run, idx);
2008-12-21 21:35:07 +00:00
str = QSE_NULL;
2008-01-16 21:46:08 +00:00
2008-12-21 21:35:07 +00:00
if (buf != QSE_NULL)
{
2008-01-16 21:46:08 +00:00
/* try with a fixed-size buffer */
str = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, idx, QSE_AWK_VALTOSTR_FIXED, (qse_str_t*)buf, len);
2008-01-16 21:46:08 +00:00
}
2008-12-21 21:35:07 +00:00
if (str == QSE_NULL)
2008-01-16 21:46:08 +00:00
{
/* if it doen't work, switch to the dynamic mode */
str = qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, idx, QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, len);
2008-01-16 21:46:08 +00:00
2008-12-21 21:35:07 +00:00
if (str == QSE_NULL)
2008-01-16 21:46:08 +00:00
{
qse_awk_rtx_refdownval (run, idx);
2008-01-16 21:46:08 +00:00
/* change error line */
run->errlin = nde->line;
2008-12-21 21:35:07 +00:00
return QSE_NULL;
2008-01-16 21:46:08 +00:00
}
}
qse_awk_rtx_refdownval (run, idx);
}
else
{
/* multidimensional index */
2008-12-21 21:35:07 +00:00
qse_str_t idxstr;
qse_xstr_t tmp;
2008-12-21 21:35:07 +00:00
if (qse_str_init (&idxstr, MMGR(run), DEF_BUF_CAPA) == QSE_NULL)
{
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line, QSE_NULL, 0);
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
while (nde != QSE_NULL)
{
idx = eval_expression (run, nde);
2008-12-21 21:35:07 +00:00
if (idx == QSE_NULL)
{
2008-12-21 21:35:07 +00:00
qse_str_fini (&idxstr);
return QSE_NULL;
}
qse_awk_rtx_refupval (run, idx);
2008-12-21 21:35:07 +00:00
if (QSE_STR_LEN(&idxstr) > 0 &&
qse_str_ncat (&idxstr,
run->global.subsep.ptr,
2008-12-21 21:35:07 +00:00
run->global.subsep.len) == (qse_size_t)-1)
{
qse_awk_rtx_refdownval (run, idx);
2008-12-21 21:35:07 +00:00
qse_str_fini (&idxstr);
qse_awk_rtx_seterror (
2008-12-21 21:35:07 +00:00
run, QSE_AWK_ENOMEM, nde->line,
QSE_NULL, 0);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
if (qse_awk_rtx_valtostr (
2008-12-21 21:35:07 +00:00
run, idx, 0, &idxstr, QSE_NULL) == QSE_NULL)
{
qse_awk_rtx_refdownval (run, idx);
2008-12-21 21:35:07 +00:00
qse_str_fini (&idxstr);
return QSE_NULL;
}
qse_awk_rtx_refdownval (run, idx);
nde = nde->next;
}
2008-12-21 21:35:07 +00:00
qse_str_yield (&idxstr, &tmp, 0);
2008-09-05 04:58:08 +00:00
str = tmp.ptr;
*len = tmp.len;
2008-12-21 21:35:07 +00:00
qse_str_fini (&idxstr);
}
return str;
}
2008-12-21 21:35:07 +00:00
qse_char_t* qse_awk_format (
qse_awk_rtx_t* run, qse_str_t* out, qse_str_t* fbu,
2008-12-21 21:35:07 +00:00
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)
{
2008-12-21 21:35:07 +00:00
qse_size_t i, j;
qse_size_t stack_arg_idx = 1;
qse_awk_val_t* val;
#define OUT_CHAR(c) \
do { \
2008-12-21 21:35:07 +00:00
if (qse_str_ccat (out, (c)) == -1) \
{ \
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM); \
2008-12-21 21:35:07 +00:00
return QSE_NULL; \
} \
} while (0)
#define FMT_CHAR(c) \
do { \
2008-12-21 21:35:07 +00:00
if (qse_str_ccat (fbu, (c)) == -1) \
{ \
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM); \
2008-12-21 21:35:07 +00:00
return QSE_NULL; \
} \
} while (0)
#define GROW(buf) \
do { \
2008-12-21 21:35:07 +00:00
if ((buf)->ptr != QSE_NULL) \
{ \
2008-12-21 21:35:07 +00:00
QSE_AWK_FREE (run->awk, (buf)->ptr); \
(buf)->ptr = QSE_NULL; \
} \
(buf)->len += (buf)->inc; \
2008-12-21 21:35:07 +00:00
(buf)->ptr = (qse_char_t*)QSE_AWK_ALLOC ( \
run->awk, (buf)->len * QSE_SIZEOF(qse_char_t)); \
if ((buf)->ptr == QSE_NULL) (buf)->len = 0; \
} while (0)
2008-12-21 21:35:07 +00:00
QSE_ASSERTX (run->format.tmp.ptr != QSE_NULL,
"run->format.tmp.ptr should have been assigned a pointer to a block of memory before this function has been called");
2008-12-21 21:35:07 +00:00
if (nargs_on_stack == (qse_size_t)-1)
{
2008-12-21 21:35:07 +00:00
val = (qse_awk_val_t*)args;
nargs_on_stack = 2;
}
else
{
2008-12-21 21:35:07 +00:00
val = QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (out == QSE_NULL) out = &run->format.out;
if (fbu == QSE_NULL) fbu = &run->format.fmt;
2008-12-21 21:35:07 +00:00
qse_str_clear (out);
qse_str_clear (fbu);
for (i = 0; i < fmt_len; i++)
{
2008-12-21 21:35:07 +00:00
qse_long_t width = -1, prec = -1;
qse_bool_t minus = QSE_FALSE;
2008-12-21 21:35:07 +00:00
if (QSE_STR_LEN(fbu) == 0)
{
2008-12-21 21:35:07 +00:00
if (fmt[i] == QSE_T('%')) FMT_CHAR (fmt[i]);
else OUT_CHAR (fmt[i]);
continue;
}
while (i < fmt_len &&
2008-12-21 21:35:07 +00:00
(fmt[i] == QSE_T(' ') || fmt[i] == QSE_T('#') ||
fmt[i] == QSE_T('0') || fmt[i] == QSE_T('+') ||
fmt[i] == QSE_T('-')))
{
2008-12-21 21:35:07 +00:00
if (fmt[i] == QSE_T('-')) minus = QSE_TRUE;
FMT_CHAR (fmt[i]); i++;
}
2008-12-21 21:35:07 +00:00
if (i < fmt_len && fmt[i] == QSE_T('*'))
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
qse_real_t r;
qse_char_t* p;
int n;
2008-12-21 21:35:07 +00:00
if (args == QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = qse_awk_rtx_getarg (run, stack_arg_idx);
}
else
{
2008-12-21 21:35:07 +00:00
if (val != QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = val;
}
else
{
v = eval_expression (run, args);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
}
}
qse_awk_rtx_refupval (run, v);
n = qse_awk_rtx_valtonum (run, v, &width, &r);
qse_awk_rtx_refdownval (run, v);
2008-12-21 21:35:07 +00:00
if (n == -1) return QSE_NULL;
if (n == 1) width = (qse_long_t)r;
do
{
2008-07-21 06:42:39 +00:00
n = run->awk->prmfns->sprintf (
2008-08-19 05:21:48 +00:00
run->awk->prmfns->data,
run->format.tmp.ptr,
run->format.tmp.len,
2008-12-21 21:35:07 +00:00
#if QSE_SIZEOF_LONG_LONG > 0
QSE_T("%lld"), (long long)width
#elif QSE_SIZEOF___INT64 > 0
QSE_T("%I64d"), (__int64)width
#elif QSE_SIZEOF_LONG > 0
QSE_T("%ld"), (long)width
#elif QSE_SIZEOF_INT > 0
QSE_T("%d"), (int)width
#else
#error unsupported size
#endif
);
if (n == -1)
{
GROW (&run->format.tmp);
2008-12-21 21:35:07 +00:00
if (run->format.tmp.ptr == QSE_NULL)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
continue;
}
break;
}
while (1);
p = run->format.tmp.ptr;
2008-12-21 21:35:07 +00:00
while (*p != QSE_T('\0'))
{
FMT_CHAR (*p);
p++;
}
2008-12-21 21:35:07 +00:00
if (args == QSE_NULL || val != QSE_NULL) stack_arg_idx++;
else args = args->next;
i++;
}
else
{
2008-12-21 21:35:07 +00:00
if (i < fmt_len && QSE_AWK_ISDIGIT(run->awk, fmt[i]))
{
width = 0;
do
{
2008-12-21 21:35:07 +00:00
width = width * 10 + fmt[i] - QSE_T('0');
FMT_CHAR (fmt[i]); i++;
}
2008-12-21 21:35:07 +00:00
while (i < fmt_len && QSE_AWK_ISDIGIT(run->awk, fmt[i]));
}
}
2008-12-21 21:35:07 +00:00
if (i < fmt_len && fmt[i] == QSE_T('.'))
{
prec = 0;
FMT_CHAR (fmt[i]); i++;
}
2008-12-21 21:35:07 +00:00
if (i < fmt_len && fmt[i] == QSE_T('*'))
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
qse_real_t r;
qse_char_t* p;
int n;
2008-12-21 21:35:07 +00:00
if (args == QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = qse_awk_rtx_getarg (run, stack_arg_idx);
}
else
{
2008-12-21 21:35:07 +00:00
if (val != QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = val;
}
else
{
v = eval_expression (run, args);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
}
}
qse_awk_rtx_refupval (run, v);
n = qse_awk_rtx_valtonum (run, v, &prec, &r);
qse_awk_rtx_refdownval (run, v);
2008-12-21 21:35:07 +00:00
if (n == -1) return QSE_NULL;
if (n == 1) prec = (qse_long_t)r;
do
{
2008-07-21 06:42:39 +00:00
n = run->awk->prmfns->sprintf (
2008-08-19 05:21:48 +00:00
run->awk->prmfns->data,
run->format.tmp.ptr,
run->format.tmp.len,
2008-12-21 21:35:07 +00:00
#if QSE_SIZEOF_LONG_LONG > 0
QSE_T("%lld"), (long long)prec
#elif QSE_SIZEOF___INT64 > 0
QSE_T("%I64d"), (__int64)prec
#elif QSE_SIZEOF_LONG > 0
QSE_T("%ld"), (long)prec
#elif QSE_SIZEOF_INT > 0
QSE_T("%d"), (int)prec
#endif
);
if (n == -1)
{
GROW (&run->format.tmp);
2008-12-21 21:35:07 +00:00
if (run->format.tmp.ptr == QSE_NULL)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
continue;
}
break;
}
while (1);
p = run->format.tmp.ptr;
2008-12-21 21:35:07 +00:00
while (*p != QSE_T('\0'))
{
FMT_CHAR (*p);
p++;
}
2008-12-21 21:35:07 +00:00
if (args == QSE_NULL || val != QSE_NULL) stack_arg_idx++;
else args = args->next;
i++;
}
else
{
2008-12-21 21:35:07 +00:00
if (i < fmt_len && QSE_AWK_ISDIGIT(run->awk, fmt[i]))
{
prec = 0;
do
{
2008-12-21 21:35:07 +00:00
prec = prec * 10 + fmt[i] - QSE_T('0');
FMT_CHAR (fmt[i]); i++;
}
2008-12-21 21:35:07 +00:00
while (i < fmt_len && QSE_AWK_ISDIGIT(run->awk, fmt[i]));
}
}
if (i >= fmt_len) break;
2008-12-21 21:35:07 +00:00
if (fmt[i] == QSE_T('d') || fmt[i] == QSE_T('i') ||
fmt[i] == QSE_T('x') || fmt[i] == QSE_T('X') ||
fmt[i] == QSE_T('o'))
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
qse_long_t l;
qse_real_t r;
qse_char_t* p;
int n;
2008-12-21 21:35:07 +00:00
#if QSE_SIZEOF_LONG_LONG > 0
FMT_CHAR (QSE_T('l'));
FMT_CHAR (QSE_T('l'));
FMT_CHAR (fmt[i]);
2008-12-21 21:35:07 +00:00
#elif QSE_SIZEOF___INT64 > 0
FMT_CHAR (QSE_T('I'));
FMT_CHAR (QSE_T('6'));
FMT_CHAR (QSE_T('4'));
FMT_CHAR (fmt[i]);
2008-12-21 21:35:07 +00:00
#elif QSE_SIZEOF_LONG > 0
FMT_CHAR (QSE_T('l'));
FMT_CHAR (fmt[i]);
2008-12-21 21:35:07 +00:00
#elif QSE_SIZEOF_INT > 0
FMT_CHAR (fmt[i]);
#else
#error unsupported integer size
#endif
2008-12-21 21:35:07 +00:00
if (args == QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = qse_awk_rtx_getarg (run, stack_arg_idx);
}
else
{
2008-12-21 21:35:07 +00:00
if (val != QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = val;
}
else
{
v = eval_expression (run, args);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
}
}
qse_awk_rtx_refupval (run, v);
n = qse_awk_rtx_valtonum (run, v, &l, &r);
qse_awk_rtx_refdownval (run, v);
2008-12-21 21:35:07 +00:00
if (n == -1) return QSE_NULL;
if (n == 1) l = (qse_long_t)r;
do
{
2008-07-21 06:42:39 +00:00
n = run->awk->prmfns->sprintf (
2008-08-19 05:21:48 +00:00
run->awk->prmfns->data,
run->format.tmp.ptr,
run->format.tmp.len,
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(fbu),
#if QSE_SIZEOF_LONG_LONG > 0
(long long)l
2008-12-21 21:35:07 +00:00
#elif QSE_SIZEOF___INT64 > 0
(__int64)l
2008-12-21 21:35:07 +00:00
#elif QSE_SIZEOF_LONG > 0
(long)l
2008-12-21 21:35:07 +00:00
#elif QSE_SIZEOF_INT > 0
(int)l
#endif
);
if (n == -1)
{
GROW (&run->format.tmp);
2008-12-21 21:35:07 +00:00
if (run->format.tmp.ptr == QSE_NULL)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
continue;
}
break;
}
while (1);
p = run->format.tmp.ptr;
2008-12-21 21:35:07 +00:00
while (*p != QSE_T('\0'))
{
OUT_CHAR (*p);
p++;
}
}
2008-12-21 21:35:07 +00:00
else if (fmt[i] == QSE_T('e') || fmt[i] == QSE_T('E') ||
fmt[i] == QSE_T('g') || fmt[i] == QSE_T('G') ||
fmt[i] == QSE_T('f'))
{
2008-12-21 21:35:07 +00:00
qse_awk_val_t* v;
qse_long_t l;
qse_real_t r;
qse_char_t* p;
int n;
2008-12-21 21:35:07 +00:00
FMT_CHAR (QSE_T('L'));
FMT_CHAR (fmt[i]);
2008-12-21 21:35:07 +00:00
if (args == QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = qse_awk_rtx_getarg (run, stack_arg_idx);
}
else
{
2008-12-21 21:35:07 +00:00
if (val != QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = val;
}
else
{
v = eval_expression (run, args);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
}
}
qse_awk_rtx_refupval (run, v);
n = qse_awk_rtx_valtonum (run, v, &l, &r);
qse_awk_rtx_refdownval (run, v);
2008-12-21 21:35:07 +00:00
if (n == -1) return QSE_NULL;
if (n == 0) r = (qse_real_t)l;
do
{
2008-07-21 06:42:39 +00:00
n = run->awk->prmfns->sprintf (
2008-08-19 05:21:48 +00:00
run->awk->prmfns->data,
run->format.tmp.ptr,
run->format.tmp.len,
2008-12-21 21:35:07 +00:00
QSE_STR_PTR(fbu),
#if defined(__MINGW32__)
(double)r
#else
(long double)r
#endif
);
if (n == -1)
{
GROW (&run->format.tmp);
2008-12-21 21:35:07 +00:00
if (run->format.tmp.ptr == QSE_NULL)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
continue;
}
break;
}
while (1);
p = run->format.tmp.ptr;
2008-12-21 21:35:07 +00:00
while (*p != QSE_T('\0'))
{
OUT_CHAR (*p);
p++;
}
}
2008-12-21 21:35:07 +00:00
else if (fmt[i] == QSE_T('c'))
{
2008-12-21 21:35:07 +00:00
qse_char_t ch;
qse_size_t ch_len;
qse_awk_val_t* v;
2008-12-21 21:35:07 +00:00
if (args == QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = qse_awk_rtx_getarg (run, stack_arg_idx);
}
else
{
2008-12-21 21:35:07 +00:00
if (val != QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = val;
}
else
{
v = eval_expression (run, args);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
}
}
qse_awk_rtx_refupval (run, v);
2008-12-21 21:35:07 +00:00
if (v->type == QSE_AWK_VAL_NIL)
{
2008-12-21 21:35:07 +00:00
ch = QSE_T('\0');
ch_len = 0;
}
2008-12-21 21:35:07 +00:00
else if (v->type == QSE_AWK_VAL_INT)
{
2008-12-21 21:35:07 +00:00
ch = (qse_char_t)((qse_awk_val_int_t*)v)->val;
ch_len = 1;
}
2008-12-21 21:35:07 +00:00
else if (v->type == QSE_AWK_VAL_REAL)
{
2008-12-21 21:35:07 +00:00
ch = (qse_char_t)((qse_awk_val_real_t*)v)->val;
ch_len = 1;
}
2008-12-21 21:35:07 +00:00
else if (v->type == QSE_AWK_VAL_STR)
{
2008-12-21 21:35:07 +00:00
ch_len = ((qse_awk_val_str_t*)v)->len;
if (ch_len > 0)
{
ch = ((qse_awk_val_str_t*)v)->ptr[0];
ch_len = 1;
}
2008-12-21 21:35:07 +00:00
else ch = QSE_T('\0');
}
else
{
qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_EVALTYPE);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
2008-12-21 21:35:07 +00:00
if (prec == -1 || prec == 0 || prec > (qse_long_t)ch_len) prec = (qse_long_t)ch_len;
if (prec > width) width = prec;
if (!minus)
{
while (width > prec)
{
2008-12-21 21:35:07 +00:00
if (qse_str_ccat (out, QSE_T(' ')) == -1)
{
qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
width--;
}
}
if (prec > 0)
{
2008-12-21 21:35:07 +00:00
if (qse_str_ccat (out, ch) == -1)
{
qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
if (minus)
{
while (width > prec)
{
2008-12-21 21:35:07 +00:00
if (qse_str_ccat (out, QSE_T(' ')) == -1)
{
qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
width--;
}
}
qse_awk_rtx_refdownval (run, v);
}
2008-12-21 21:35:07 +00:00
else if (fmt[i] == QSE_T('s'))
{
2008-12-21 21:35:07 +00:00
qse_char_t* str, * str_free = QSE_NULL;
qse_size_t str_len;
qse_long_t k;
qse_awk_val_t* v;
2008-12-21 21:35:07 +00:00
if (args == QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = qse_awk_rtx_getarg (run, stack_arg_idx);
}
else
{
2008-12-21 21:35:07 +00:00
if (val != QSE_NULL)
{
if (stack_arg_idx >= nargs_on_stack)
{
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTARG);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
v = val;
}
else
{
v = eval_expression (run, args);
2008-12-21 21:35:07 +00:00
if (v == QSE_NULL) return QSE_NULL;
}
}
qse_awk_rtx_refupval (run, v);
2008-12-21 21:35:07 +00:00
if (v->type == QSE_AWK_VAL_NIL)
{
2008-12-21 21:35:07 +00:00
str = QSE_T("");
str_len = 0;
}
2008-12-21 21:35:07 +00:00
else if (v->type == QSE_AWK_VAL_STR)
{
str = ((qse_awk_val_str_t*)v)->ptr;
2008-12-21 21:35:07 +00:00
str_len = ((qse_awk_val_str_t*)v)->len;
}
else
{
if (v == val)
{
qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_EFMTCNV);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
str = qse_awk_rtx_valtostr (run, v,
2008-12-21 21:35:07 +00:00
QSE_AWK_VALTOSTR_CLEAR, QSE_NULL, &str_len);
if (str == QSE_NULL)
{
qse_awk_rtx_refdownval (run, v);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
str_free = str;
}
2008-12-21 21:35:07 +00:00
if (prec == -1 || prec > (qse_long_t)str_len ) prec = (qse_long_t)str_len;
if (prec > width) width = prec;
if (!minus)
{
while (width > prec)
{
2008-12-21 21:35:07 +00:00
if (qse_str_ccat (out, QSE_T(' ')) == -1)
{
2008-12-21 21:35:07 +00:00
if (str_free != QSE_NULL)
QSE_AWK_FREE (run->awk, str_free);
qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
width--;
}
}
for (k = 0; k < prec; k++)
{
2008-12-21 21:35:07 +00:00
if (qse_str_ccat (out, str[k]) == -1)
{
2008-12-21 21:35:07 +00:00
if (str_free != QSE_NULL)
QSE_AWK_FREE (run->awk, str_free);
qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
}
2008-12-21 21:35:07 +00:00
if (str_free != QSE_NULL) QSE_AWK_FREE (run->awk, str_free);
if (minus)
{
while (width > prec)
{
2008-12-21 21:35:07 +00:00
if (qse_str_ccat (out, QSE_T(' ')) == -1)
{
qse_awk_rtx_refdownval (run, v);
qse_awk_rtx_seterrnum (run, QSE_AWK_ENOMEM);
2008-12-21 21:35:07 +00:00
return QSE_NULL;
}
width--;
}
}
qse_awk_rtx_refdownval (run, v);
}
2008-12-21 21:35:07 +00:00
else /*if (fmt[i] == QSE_T('%'))*/
{
2008-12-21 21:35:07 +00:00
for (j = 0; j < QSE_STR_LEN(fbu); j++)
OUT_CHAR (QSE_STR_CHAR(fbu,j));
OUT_CHAR (fmt[i]);
}
2008-12-21 21:35:07 +00:00
if (args == QSE_NULL || val != QSE_NULL) stack_arg_idx++;
else args = args->next;
2008-12-21 21:35:07 +00:00
qse_str_clear (fbu);
}
/* flush uncompleted formatting sequence */
2008-12-21 21:35:07 +00:00
for (j = 0; j < QSE_STR_LEN(fbu); j++)
OUT_CHAR (QSE_STR_CHAR(fbu,j));
2008-12-21 21:35:07 +00:00
*len = QSE_STR_LEN(out);
return QSE_STR_PTR(out);
}