diff --git a/qse/doc/page/awk.doc b/qse/doc/page/awk.doc index b2e7c1f9..aec4261e 100644 --- a/qse/doc/page/awk.doc +++ b/qse/doc/page/awk.doc @@ -1,4 +1,68 @@ /** @page awk AWK AWK Interpreter + +VARIABLE DECLARATION + +QSE_AWK_EXPLICIT enables variable declaration. Variables declared are accessed +directly bypassing the global named map that stores undeclared variables. +The keyword global introduces a global variable and the keyword local introduces +a local variable. Local variable declaraion in a block should be located before +an expression or a statement appears. + +@code +global g1, g2; #declares two global variables g1 and g2 + +BEGIN { + local a1, a2, a3; # declares three local variables + + g1 = 300; a1 = 200; + + { + local a1; # this a1 hides the a1 at the outer scope + local g1; # this g1 hides the global g1 + a1 = 10; g1 = 5; + print a1, g1; # it prints 10 and 5 + } + + print a1, g1; # it prints 200 and 300 +} + +@endcode + +However, turning on QSE_AWK_EXPLICIT does not disable named variables. +To disable named variables, you must turn off QSE_AWK_IMPLICIT. + +INCLUDE + +The \@include directive inserts the contents of the object specified in the +following string, typically a file name, as if they appeared in the source +stream being processed. The directive can only be used at the outmost scope +where global variable declarations, BEGIN, END, and/or pattern-action blocks +appear. To use @include, you must turn on QSE_AWK_INCLUDE. + +@code +@include "abc.awk" +BEGIN { func_in_abc (); } +@endcode + +TWO-WAY PIPE + +The two-way pipe indicated by '||' is supproted, in addition to the one-way +pipe indicated by '|'. Turn on QSE_AWK_RWPIPE to enable the two-way pipe. + +@code +BEGIN { + print "15" || "sort"; + print "14" || "sort"; + print "13" || "sort"; + print "12" || "sort"; + print "11" || "sort"; + #close the input as sort emits when the input is closed + close ("sort", "r"); + while (("sort" || getline x) > 0) print x; +} +@endcode + */ + diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index 5795839c..6020154c 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h 267 2009-08-25 09:50:07Z hyunghwan.chung $ + * $Id: awk.h 270 2009-08-26 12:59:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -351,6 +351,12 @@ enum qse_awk_rio_mode_t }; typedef enum qse_awk_rio_mode_t qse_awk_rio_mode_t; +enum qse_awk_rio_close_opt_t +{ + QSE_AWK_RIO_CLOSE_R = (1 << 0), + QSE_AWK_RIO_CLOSE_W = (1 << 1) +}; + /** * The qse_awk_rio_arg_t defines the data structure passed to a runtime * I/O handler. An I/O handler should inspect the @a mode field and the @@ -361,9 +367,10 @@ typedef enum qse_awk_rio_mode_t qse_awk_rio_mode_t; typedef struct qse_awk_rio_arg_t qse_awk_rio_arg_t; struct qse_awk_rio_arg_t { - qse_awk_rio_mode_t mode; /**< [IN] I/O mode */ - qse_char_t* name; /**< [IN] name of I/O object */ - void* handle; /**< [OUT] I/O handle set by a handler */ + qse_awk_rio_mode_t mode; /**< [IN] I/O mode */ + qse_char_t* name; /**< [IN] name of I/O object */ + int copt; /**< [IN] closing option */ + void* handle; /**< [OUT] I/O handle set by a handler */ /*-- from here down, internal use only --*/ int type; diff --git a/qse/lib/awk/fnc.c b/qse/lib/awk/fnc.c index 55067c21..441aafe7 100644 --- a/qse/lib/awk/fnc.c +++ b/qse/lib/awk/fnc.c @@ -1,5 +1,5 @@ /* - * $Id: fnc.c 259 2009-08-20 11:28:03Z hyunghwan.chung $ + * $Id: fnc.c 270 2009-08-26 12:59:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -37,7 +37,7 @@ static int fnc_sprintf (qse_awk_rtx_t*, const qse_cstr_t*); static qse_awk_fnc_t sys_fnc[] = { /* io functions */ - { {QSE_T("close"), 5}, 0, QSE_AWK_RIO, {1, 1, QSE_NULL}, fnc_close}, + { {QSE_T("close"), 5}, 0, QSE_AWK_RIO, {1, 2, QSE_NULL}, fnc_close}, { {QSE_T("fflush"), 6}, 0, QSE_AWK_RIO, {0, 1, QSE_NULL}, fnc_fflush}, /* string functions */ @@ -227,20 +227,20 @@ qse_awk_fnc_t* qse_awk_getfnc ( return fnc; } -static int fnc_close (qse_awk_rtx_t* run, const qse_cstr_t* fnm) +static int fnc_close (qse_awk_rtx_t* rtx, const qse_cstr_t* fnm) { qse_size_t nargs; - qse_awk_val_t* v, * a0; + qse_awk_val_t* v, * a0, * a1 = QSE_NULL; int n; - qse_char_t* name; - qse_size_t len; + qse_char_t* name, * opt = QSE_NULL; + qse_size_t len, optlen = 0; - nargs = qse_awk_rtx_getnargs (run); - QSE_ASSERT (nargs == 1); -/* TODO: support close (xxx, "to"/"from"/"rw"/"r"/"w"/????) */ + nargs = qse_awk_rtx_getnargs (rtx); + QSE_ASSERT (nargs == 1 || nargs == 2); - a0 = qse_awk_rtx_getarg (run, 0); + a0 = qse_awk_rtx_getarg (rtx, 0); + a1 = qse_awk_rtx_getarg (rtx, 1); QSE_ASSERT (a0 != QSE_NULL); if (a0->type == QSE_AWK_VAL_STR) @@ -250,10 +250,29 @@ static int fnc_close (qse_awk_rtx_t* run, const qse_cstr_t* fnm) } else { - name = qse_awk_rtx_valtocpldup (run, a0, &len); + name = qse_awk_rtx_valtocpldup (rtx, a0, &len); if (name == QSE_NULL) return -1; } + if (a1 != QSE_NULL) + { + if (a1->type == QSE_AWK_VAL_STR) + { + opt = ((qse_awk_val_str_t*)a1)->ptr; + optlen = ((qse_awk_val_str_t*)a1)->len; + } + else + { + opt = qse_awk_rtx_valtocpldup (rtx, a1, &optlen); + if (opt == QSE_NULL) + { + if (a1->type != QSE_AWK_VAL_STR) + QSE_AWK_FREE (rtx->awk, name); + return -1; + } + } + } + if (len == 0) { /* getline or print doesn't allow an emptry for the @@ -272,30 +291,44 @@ static int fnc_close (qse_awk_rtx_t* run, const qse_cstr_t* fnm) { if (name[--len] == QSE_T('\0')) { - /* the name contains a null string. + /* the name contains a null charater. * make close return -1 */ n = -1; goto skip_close; } } - n = qse_awk_rtx_closeio (run, name); - /* - if (n == -1 && run->errinf.num != QSE_AWK_EIONMNF) + if (opt != QSE_NULL) + { + if (optlen != 1 || + (opt[0] != QSE_T('r') && opt[0] != QSE_T('w'))) + { + n = -1; + goto skip_close; + } + } + + n = qse_awk_rtx_closeio (rtx, name, opt); + /* failure to close is not a critical error. instead, that is + * flagged by the return value of close(). + if (n == -1 && rtx->errinf.num != QSE_AWK_EIONMNF) { if (a0->type != QSE_AWK_VAL_STR) - QSE_AWK_FREE (run->awk, name); + QSE_AWK_FREE (rtx->awk, name); return -1; } */ skip_close: - if (a0->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (run->awk, name); + if (a1 != QSE_NULL && a1->type != QSE_AWK_VAL_STR) + QSE_AWK_FREE (rtx->awk, opt); - v = qse_awk_rtx_makeintval (run, (qse_long_t)n); + if (a0->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (rtx->awk, name); + + v = qse_awk_rtx_makeintval (rtx, (qse_long_t)n); if (v == QSE_NULL) return -1; - qse_awk_rtx_setretval (run, v); + qse_awk_rtx_setretval (rtx, v); return 0; } diff --git a/qse/lib/awk/rio.c b/qse/lib/awk/rio.c index c89826d5..58099c0d 100644 --- a/qse/lib/awk/rio.c +++ b/qse/lib/awk/rio.c @@ -1,5 +1,5 @@ /* - * $Id: rio.c 256 2009-08-16 13:44:20Z hyunghwan.chung $ + * $Id: rio.c 270 2009-08-26 12:59:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -904,9 +904,10 @@ int qse_awk_rtx_closio_write ( return -1; } -int qse_awk_rtx_closeio (qse_awk_rtx_t* run, const qse_char_t* name) +int qse_awk_rtx_closeio ( + qse_awk_rtx_t* rtx, const qse_char_t* name, const qse_char_t* opt) { - qse_awk_rio_arg_t* p = run->rio.chain, * px = QSE_NULL; + qse_awk_rio_arg_t* p = rtx->rio.chain, * px = QSE_NULL; while (p != QSE_NULL) { @@ -915,34 +916,58 @@ int qse_awk_rtx_closeio (qse_awk_rtx_t* run, const qse_char_t* name) if (qse_strcmp (p->name, name) == 0) { qse_awk_rio_fun_t handler; - - handler = run->rio.handler[p->type & MASK_CLEAR]; - if (handler != QSE_NULL) + int copt = QSE_AWK_RIO_CLOSE_R | QSE_AWK_RIO_CLOSE_W; + + if (opt != QSE_NULL) { - qse_awk_rtx_seterrnum (run, QSE_AWK_ENOERR, QSE_NULL); - if (handler (run, QSE_AWK_RIO_CLOSE, p, QSE_NULL, 0) <= -1) + if (opt[0] == QSE_T('r')) { - /* this is not a run-time error.*/ - if (run->errinf.num == QSE_AWK_ENOERR) - qse_awk_rtx_seterrnum (run, QSE_AWK_EIOIMPL, QSE_NULL); - return -1; + if (p->type & MASK_RDWR) copt = QSE_AWK_RIO_CLOSE_R; + else if (!(p->type & MASK_READ)) goto skip; + } + else + { + QSE_ASSERT (opt[0] == QSE_T('w')); + if (p->type & MASK_RDWR) copt = QSE_AWK_RIO_CLOSE_W; + else if (!(p->type & MASK_WRITE)) goto skip; } } - if (px != QSE_NULL) px->next = p->next; - else run->rio.chain = p->next; + handler = rtx->rio.handler[p->type & MASK_CLEAR]; + if (handler != QSE_NULL) + { + qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOERR, QSE_NULL); + p->copt = copt; + if (handler (rtx, QSE_AWK_RIO_CLOSE, p, QSE_NULL, 0) <= -1) + { + /* this is not a run-time error.*/ + if (rtx->errinf.num == QSE_AWK_ENOERR) + qse_awk_rtx_seterrnum (rtx, QSE_AWK_EIOIMPL, QSE_NULL); + return -1; + } + } +/* TODO: +if (p->type & MASK_RDWR) +{ + if partially closed don't destroy it yet... +} +*/ - QSE_AWK_FREE (run->awk, p->name); - QSE_AWK_FREE (run->awk, p); + if (px != QSE_NULL) px->next = p->next; + else rtx->rio.chain = p->next; + + QSE_AWK_FREE (rtx->awk, p->name); + QSE_AWK_FREE (rtx->awk, p); return 0; } + skip: px = p; p = p->next; } - qse_awk_rtx_seterrnum (run, QSE_AWK_EIONMNF, QSE_NULL); + qse_awk_rtx_seterrnum (rtx, QSE_AWK_EIONMNF, QSE_NULL); return -1; } diff --git a/qse/lib/awk/rio.h b/qse/lib/awk/rio.h index 6fd85aeb..177d8026 100644 --- a/qse/lib/awk/rio.h +++ b/qse/lib/awk/rio.h @@ -1,5 +1,5 @@ /* - * $Id: rio.h 196 2009-06-11 07:44:44Z hyunghwan.chung $ + * $Id: rio.h 270 2009-08-26 12:59:08Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -44,7 +44,12 @@ int qse_awk_rtx_nextio_read ( int qse_awk_rtx_nextio_write ( qse_awk_rtx_t* run, int out_type, const qse_char_t* name); -int qse_awk_rtx_closeio (qse_awk_rtx_t* run, const qse_char_t* name); +int qse_awk_rtx_closeio ( + qse_awk_rtx_t* run, + const qse_char_t* name, + const qse_char_t* opt +); + void qse_awk_rtx_cleario (qse_awk_rtx_t* run); #ifdef __cplusplus