diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index c205de94..f762e597 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h 463 2011-05-19 02:50:51Z hyunghwan.chung $ + * $Id: awk.h 468 2011-05-21 16:08:54Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -118,6 +118,17 @@ typedef struct qse_awk_t qse_awk_t; */ typedef struct qse_awk_rtx_t qse_awk_rtx_t; +/** + * The qse_awk_fun_t type defines an awk function type defined with the + * keyword 'function'. + */ +typedef struct qse_awk_fun_t qse_awk_fun_t; + +/** + * The qse_awk_fnc_t type defines an intrisic function type. + */ +typedef struct qse_awk_fnc_t qse_awk_fnc_t; + /** * The qse_awk_loc_t type defines a structure to hold location. */ @@ -354,6 +365,7 @@ struct qse_awk_nde_t QSE_AWK_NDE_HDR; }; + typedef int (*qse_awk_sprintf_t) ( qse_awk_t* awk, qse_char_t* buf, @@ -1591,8 +1603,30 @@ qse_awk_val_t* qse_awk_rtx_loop ( ); /** - * The qse_awk_rtx_call() function invokes an AWK function. However, it is - * not able to invoke an intrinsic function such as split(). + * The qse_awk_rtx_findfun() function finds the function structure by name + * and returns the pointer to it if one is found. It returns #QSE_NULL if + * it fails to find a function by the @a name. + */ +qse_awk_fun_t* qse_awk_rtx_findfun ( + qse_awk_rtx_t* rtx, /**< runtime context */ + const qse_char_t* name /**< function name */ +); + +/** + * The qse_awk_rtx_callfun() function invokdes an AWK function described by + * the structure pointed to by @a fun. + * @sa qse_awk_rtx_call + */ +qse_awk_val_t* qse_awk_rtx_callfun ( + qse_awk_rtx_t* rtx, /**< runtime context */ + qse_awk_fun_t* fun, /**< function */ + qse_awk_val_t** args, /**< arguments to the function */ + qse_size_t nargs /**< the number of arguments */ +); + +/** + * The qse_awk_rtx_call() function invokes an AWK function named @a name. + * However, it is not able to invoke an intrinsic function such as split(). * The #QSE_AWK_PABLOCK option can be turned off to make illegal the BEGIN * block, the pattern-action blocks, and the END block. * diff --git a/qse/lib/awk/fnc.h b/qse/lib/awk/fnc.h index 3f81cdda..1724269f 100644 --- a/qse/lib/awk/fnc.h +++ b/qse/lib/awk/fnc.h @@ -1,5 +1,5 @@ /* - * $Id: fnc.h 441 2011-04-22 14:28:43Z hyunghwan.chung $ + * $Id: fnc.h 468 2011-05-21 16:08:54Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -21,8 +21,6 @@ #ifndef _QSE_LIB_AWK_FNC_H_ #define _QSE_LIB_AWK_FNC_H_ -typedef struct qse_awk_fnc_t qse_awk_fnc_t; - struct qse_awk_fnc_t { struct diff --git a/qse/lib/awk/run.c b/qse/lib/awk/run.c index 1723df72..9f9568a2 100644 --- a/qse/lib/awk/run.c +++ b/qse/lib/awk/run.c @@ -1,5 +1,5 @@ /* - * $Id: run.c 465 2011-05-19 03:46:53Z hyunghwan.chung $ + * $Id: run.c 468 2011-05-21 16:08:54Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -1515,11 +1515,115 @@ qse_awk_val_t* qse_awk_rtx_loop (qse_awk_rtx_t* rtx) return retv; } -/* call an AWK function */ +/* find an AWK function by name */ +qse_awk_fun_t* qse_awk_rtx_findfun (qse_awk_rtx_t* rtx, const qse_char_t* name) +{ + qse_htb_pair_t* pair; + + pair = qse_htb_search ( + rtx->awk->tree.funs, + name, qse_strlen(name) + ); + + if (pair == QSE_NULL) + { + qse_cstr_t nm; + + nm.ptr = name; + nm.len = qse_strlen(name); + + SETERR_ARGX (rtx, QSE_AWK_EFUNNF, &nm); + return QSE_NULL; + } + + return (qse_awk_fun_t*)QSE_HTB_VPTR(pair); +} + +/* call an AWK function by the function structure */ +qse_awk_val_t* qse_awk_rtx_callfun ( + qse_awk_rtx_t* rtx, qse_awk_fun_t* fun, + qse_awk_val_t** args, qse_size_t nargs) +{ + struct capture_retval_data_t crdata; + qse_awk_val_t* v; + struct pafv pafv/*= { args, nargs }*/; + qse_awk_nde_call_t call; + + QSE_ASSERT (fun != QSE_NULL); + + pafv.args = args; + pafv.nargs = nargs; + + if (rtx->exit_level >= EXIT_GLOBAL) + { + /* cannot call the function again when exit() is called + * in an AWK program or qse_awk_rtx_stop() is invoked */ + SETERR_COD (rtx, QSE_AWK_ENOPER); + return QSE_NULL; + } + /*rtx->exit_level = EXIT_NONE;*/ + + /* forge a fake node containing a function call */ + QSE_MEMSET (&call, 0, QSE_SIZEOF(call)); + call.type = QSE_AWK_NDE_FUN; + call.what.fun.name = fun->name; + call.nargs = nargs; + + /* check if the number of arguments given is more than expected */ + if (nargs > fun->nargs) + { + /* TODO: is this correct? what if i want to + * allow arbitarary numbers of arguments? */ + SETERR_COD (rtx, QSE_AWK_EARGTM); + return QSE_NULL; + } + + /* now that the function is found and ok, let's execute it */ + + crdata.rtx = rtx; + crdata.val = QSE_NULL; + + v = __eval_call ( + rtx, (qse_awk_nde_t*)&call, QSE_NULL, fun, + push_arg_from_vals, (void*)&pafv, + capture_retval_on_exit, + &crdata + ); + + if (v == QSE_NULL) + { + /* an error occurred. let's check if it is caused by exit(). + * if so, the return value should have been captured into + * crdata.val. */ + if (crdata.val != QSE_NULL) v = crdata.val; /* yet it is */ + } + else + { + /* thr return value captured in termination by exit() + * is reference-counted up in capture_retval_on_exit(). + * let's do the same thing for the return value normally + * returned. */ + qse_awk_rtx_refupval (rtx, v); + } + + /* return the return value with its reference count at least 1. + * the caller of this function should count down its reference. */ + return v; +} + +/* call an AWK function by name */ qse_awk_val_t* qse_awk_rtx_call ( qse_awk_rtx_t* rtx, const qse_char_t* name, qse_awk_val_t** args, qse_size_t nargs) { + qse_awk_fun_t* fun; + + fun = qse_awk_rtx_findfun (rtx, name); + if (fun == QSE_NULL) return QSE_NULL; + + return qse_awk_rtx_callfun (rtx, fun, args, nargs); + +#if 0 qse_htb_pair_t* pair; qse_awk_fun_t* fun; struct capture_retval_data_t crdata; @@ -1603,6 +1707,7 @@ qse_awk_val_t* qse_awk_rtx_call ( /* return the return value with its reference count at least 1. * the caller of this function should count down its reference. */ return v; +#endif } static int run_pblocks (qse_awk_rtx_t* run) @@ -4788,8 +4893,8 @@ static qse_awk_val_t* eval_binop_match0 ( n = QSE_AWK_MATCHREX ( rtx->awk, rex_code, ((rtx->gbl.ignorecase)? QSE_REX_IGNORECASE: 0), - &((qse_awk_val_str_t*)left)->val, - &((qse_awk_val_str_t*)left)->val, + xstr_to_cstr(&((qse_awk_val_str_t*)left)->val), + xstr_to_cstr(&((qse_awk_val_str_t*)left)->val), QSE_NULL, &errnum); if (n == -1) { @@ -4825,8 +4930,10 @@ static qse_awk_val_t* eval_binop_match0 ( n = QSE_AWK_MATCHREX ( rtx->awk, rex_code, ((rtx->gbl.ignorecase)? QSE_REX_IGNORECASE: 0), - &out.u.cpldup, &out.u.cpldup, - QSE_NULL, &errnum); + xstr_to_cstr(&out.u.cpldup), + xstr_to_cstr(&out.u.cpldup), + QSE_NULL, &errnum + ); if (n == -1) { QSE_AWK_FREE (rtx->awk, out.u.cpldup.ptr); diff --git a/qse/lib/awk/tree.h b/qse/lib/awk/tree.h index 9d2b2ab2..a1c7afae 100644 --- a/qse/lib/awk/tree.h +++ b/qse/lib/awk/tree.h @@ -1,5 +1,5 @@ /* - * $Id: tree.h 441 2011-04-22 14:28:43Z hyunghwan.chung $ + * $Id: tree.h 468 2011-05-21 16:08:54Z hyunghwan.chung $ * Copyright 2006-2011 Chung, Hyung-Hwan. This file is part of QSE. @@ -44,10 +44,6 @@ enum qse_awk_out_type_t QSE_AWK_OUT_CONSOLE }; -/* AWK function defined with the keyword function. - * note it is different from qse_awk_fnc_t */ -typedef struct qse_awk_fun_t qse_awk_fun_t; - typedef struct qse_awk_nde_blk_t qse_awk_nde_blk_t; typedef struct qse_awk_nde_grp_t qse_awk_nde_grp_t; typedef struct qse_awk_nde_ass_t qse_awk_nde_ass_t;