diff --git a/ase/awk/awk.c b/ase/awk/awk.c index d3ea7f10..1c887b0d 100644 --- a/ase/awk/awk.c +++ b/ase/awk/awk.c @@ -1,5 +1,5 @@ /* - * $Id: awk.c,v 1.69 2006-08-13 05:55:02 bacon Exp $ + * $Id: awk.c,v 1.70 2006-08-13 16:04:32 bacon Exp $ */ #include @@ -177,6 +177,11 @@ int xp_awk_clear (xp_awk_t* awk) return 0; } +int xp_awk_getopt (xp_awk_t* awk) +{ + return awk->option; +} + void xp_awk_setopt (xp_awk_t* awk, int opt) { awk->option = opt; diff --git a/ase/awk/awk.h b/ase/awk/awk.h index c3e08180..6e91a6f8 100644 --- a/ase/awk/awk.h +++ b/ase/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h,v 1.95 2006-08-13 05:55:02 bacon Exp $ + * $Id: awk.h,v 1.96 2006-08-13 16:04:32 bacon Exp $ */ #ifndef _XP_AWK_AWK_H_ @@ -96,41 +96,44 @@ enum enum { /* allow undeclared variables */ - XP_AWK_IMPLICIT = (1 << 0), + XP_AWK_IMPLICIT = (1 << 0), /* variable requires explicit declaration */ - XP_AWK_EXPLICIT = (1 << 1), + XP_AWK_EXPLICIT = (1 << 1), /* a function name should not coincide to be a variable name */ - XP_AWK_UNIQUE = (1 << 2), + XP_AWK_UNIQUE = (1 << 2), /* allow variable shading */ - XP_AWK_SHADING = (1 << 3), + XP_AWK_SHADING = (1 << 3), /* support shift operators */ - XP_AWK_SHIFT = (1 << 4), + XP_AWK_SHIFT = (1 << 4), /* support comments by a hash sign */ - XP_AWK_HASHSIGN = (1 << 5), + XP_AWK_HASHSIGN = (1 << 5), /* support comments by double slashes */ - XP_AWK_DBLSLASHES = (1 << 6), + XP_AWK_DBLSLASHES = (1 << 6), /* support string concatenation in tokenization. * this option can change the behavior of a certain construct. * getline < "abc" ".def" is treated as if it is getline < "abc.def" * when this option is on. If this option is off, the same expression * is treated as if it is (getline < "abc") ".def". */ - XP_AWK_STRCONCAT = (1 << 7), + XP_AWK_STRCONCAT = (1 << 7), /* support getline and print */ - XP_AWK_EXTIO = (1 << 8), + XP_AWK_EXTIO = (1 << 8), /* support blockless patterns */ - XP_AWK_BLOCKLESS = (1 << 9), + XP_AWK_BLOCKLESS = (1 << 9), /* execution starts from main */ - XP_AWK_RUNMAIN = (1 << 10) + XP_AWK_RUNMAIN = (1 << 10), + + /* use 1 as the start index for string operations */ + XP_AWK_STRINDEXONE = (1 << 11) }; /* error code */ @@ -253,6 +256,8 @@ int xp_awk_clear (xp_awk_t* awk); int xp_awk_geterrnum (xp_awk_t* awk); xp_size_t xp_awk_getsrcline (xp_awk_t* awk); + +int xp_awk_getopt (xp_awk_t* awk); void xp_awk_setopt (xp_awk_t* awk, int opt); int xp_awk_parse (xp_awk_t* awk, xp_awk_srcios_t* srcios); diff --git a/ase/awk/func.c b/ase/awk/func.c index 9b28d318..b89902e9 100644 --- a/ase/awk/func.c +++ b/ase/awk/func.c @@ -1,5 +1,5 @@ /* - * $Id: func.c,v 1.17 2006-08-04 17:36:40 bacon Exp $ + * $Id: func.c,v 1.18 2006-08-13 16:04:32 bacon Exp $ */ #include @@ -16,28 +16,38 @@ #include #else #include + #include #endif -static int __bfn_close (void* run); -static int __bfn_system (void* run); -static int __bfn_sin (void* run); +static int __bfn_close (xp_awk_t* awk, void* run); +static int __bfn_index (xp_awk_t* awk, void* run); +static int __bfn_length (xp_awk_t* awk, void* run); +static int __bfn_substr (xp_awk_t* awk, void* run); +static int __bfn_split (xp_awk_t* awk, void* run); +static int __bfn_system (xp_awk_t* awk, void* run); +static int __bfn_sin (xp_awk_t* awk, void* run); /* TODO: move it under the awk structure... */ static xp_awk_bfn_t __sys_bfn[] = { /* ensure that this matches XP_AWK_BNF_XXX in func.h */ + { XP_T("close"), 5, XP_AWK_EXTIO, 1, 1, XP_NULL, __bfn_close }, - { XP_T("close"), 5, XP_AWK_EXTIO, 1, 1, __bfn_close }, - { XP_T("system"), 6, 0, 1, 1, __bfn_system }, + { XP_T("index"), 5, 0, 2, 2, XP_NULL, __bfn_index }, + { XP_T("length"), 6, 0, 1, 1, XP_NULL, __bfn_length }, + { XP_T("substr"), 6, 0, 2, 3, XP_NULL, __bfn_substr }, + { XP_T("split"), 5, 0, 2, 3, XP_NULL, __bfn_split }, - { XP_T("sin"), 3, 0, 1, 1, __bfn_sin }, + { XP_T("system"), 6, 0, 1, 1, XP_NULL, __bfn_system }, + { XP_T("sin"), 3, 0, 1, 1, XP_NULL, __bfn_sin }, - { XP_NULL, 0, 0, 0, 0, XP_NULL } + { XP_NULL, 0, 0, 0, 0, XP_NULL, XP_NULL } }; xp_awk_bfn_t* xp_awk_addbfn ( - xp_awk_t* awk, const xp_char_t* name, int when_valid, - xp_size_t min_args, xp_size_t max_args, int (*handler)(void*)) + xp_awk_t* awk, const xp_char_t* name, int when_valid, + xp_size_t min_args, xp_size_t max_args, const xp_char_t* arg_spec, + int (*handler)(xp_awk_t*,void*)) { xp_awk_bfn_t* p; @@ -51,6 +61,7 @@ xp_awk_bfn_t* xp_awk_addbfn ( p->valid = when_valid; p->min_args = min_args; p->max_args = max_args; + p->arg_spec = arg_spec; p->handler = handler; p->next = awk->bfn.user; @@ -120,7 +131,7 @@ xp_awk_bfn_t* xp_awk_getbfn (xp_awk_t* awk, const xp_char_t* name) return XP_NULL; } -static int __bfn_close (void* run) +static int __bfn_close (xp_awk_t* awk, void* run) { xp_size_t nargs; xp_str_t buf; @@ -213,7 +224,208 @@ skip_close: return 0; } -static int __bfn_system (void* run) +static int __bfn_index (xp_awk_t* awk, void* run) +{ + xp_size_t nargs; + xp_awk_val_t* a0, * a1; + xp_char_t* str0, * str1, * ptr; + xp_size_t len0, len1; + xp_long_t idx; + int errnum; + + nargs = xp_awk_getnargs (run); + xp_assert (nargs == 2); + + a0 = xp_awk_getarg (run, 0); + a1 = xp_awk_getarg (run, 1); + + if (a0->type == XP_AWK_VAL_STR) + { + str0 = ((xp_awk_val_str_t*)a0)->buf; + len0 = ((xp_awk_val_str_t*)a0)->len; + } + else + { + str0 = xp_awk_valtostr (a0, &errnum, xp_true, XP_NULL, &len0); + if (str0 == XP_NULL) + { + xp_awk_seterrnum (run, errnum); + return -1; + } + } + + if (a1->type == XP_AWK_VAL_STR) + { + str1 = ((xp_awk_val_str_t*)a1)->buf; + len1 = ((xp_awk_val_str_t*)a1)->len; + } + else + { + str1 = xp_awk_valtostr (a1, &errnum, xp_true, XP_NULL, &len1); + if (str1 == XP_NULL) + { + xp_awk_seterrnum (run, errnum); + if (a0->type != XP_AWK_VAL_STR) xp_free (str0); + return -1; + } + } + + + ptr = xp_strxnstr (str0, len0, str1, len1); + idx = (ptr == XP_NULL)? -1: (xp_long_t)(ptr - str0); + + if (xp_awk_getopt(awk) & XP_AWK_STRINDEXONE) idx = idx + 1; + + if (a0->type != XP_AWK_VAL_STR) xp_free (str0); + if (a1->type != XP_AWK_VAL_STR) xp_free (str1); + + a0 = xp_awk_makeintval (run, idx); + if (a0 == XP_NULL) + { + xp_awk_seterrnum (run, XP_AWK_ENOMEM); + return -1; + } + + xp_awk_setretval (run, a0); + return 0; +} + +static int __bfn_length (xp_awk_t* awk, void* run) +{ + xp_size_t nargs; + xp_awk_val_t* v; + xp_char_t* str; + xp_size_t len; + int errnum; + + nargs = xp_awk_getnargs (run); + xp_assert (nargs == 1); + + v = xp_awk_getarg (run, 0); + if (v->type == XP_AWK_VAL_STR) + { + len = ((xp_awk_val_str_t*)v)->len; + } + else + { + str = xp_awk_valtostr (v, &errnum, xp_true, XP_NULL, &len); + if (str == XP_NULL) + { + xp_awk_seterrnum (run, errnum); + return -1; + } + + xp_free (str); + } + + v = xp_awk_makeintval (run, len); + if (v == XP_NULL) + { + xp_awk_seterrnum (run, XP_AWK_ENOMEM); + return -1; + } + + xp_awk_setretval (run, v); + return 0; +} + +static int __bfn_substr (xp_awk_t* awk, void* run) +{ + xp_size_t nargs; + xp_awk_val_t* a0, * a1, * a2; + xp_char_t* str; + xp_size_t len; + xp_long_t lindex, lcount; + xp_real_t rindex, rcount; + int errnum, n; + + nargs = xp_awk_getnargs (run); + xp_assert (nargs >= 2 && nargs <= 3); + + a0 = xp_awk_getarg (run, 0); + a1 = xp_awk_getarg (run, 1); + a2 = (nargs >= 3)? xp_awk_getarg (run, 2): XP_NULL; + + if (a0->type == XP_AWK_VAL_STR) + { + str = ((xp_awk_val_str_t*)a0)->buf; + len = ((xp_awk_val_str_t*)a0)->len; + } + else + { + str = xp_awk_valtostr (a0, &errnum, xp_true, XP_NULL, &len); + if (str == XP_NULL) + { + xp_awk_seterrnum (run, errnum); + return -1; + } + } + + n = xp_awk_valtonum (a1, &lindex, &rindex); + if (n == -1) + { + if (a0->type != XP_AWK_VAL_STR) xp_free (str); + xp_awk_seterrnum (run, XP_AWK_EVALTYPE); + return -1; + } + if (n == 1) lindex = (xp_long_t)rindex; + + if (a2 == XP_NULL) lcount = (xp_long_t)len; + else + { + n = xp_awk_valtonum (a2, &lcount, &rcount); + if (n == -1) + { + if (a0->type != XP_AWK_VAL_STR) xp_free (str); + xp_awk_seterrnum (run, XP_AWK_EVALTYPE); + return -1; + } + if (n == 1) lcount = (xp_long_t)rcount; + } + + if (xp_awk_getopt(awk) & XP_AWK_STRINDEXONE) lindex = lindex - 1; + if (lindex >= len) lindex = len; + else if (lindex < 0) lindex = 0; + + if (lcount < 0) lcount = 0; + else if (lcount > len - lindex) lcount = len - lindex; + + a0 = xp_awk_makestrval (&str[lindex], (xp_size_t)lcount); + if (a0 == XP_NULL) + { + if (a0->type != XP_AWK_VAL_STR) xp_free (str); + xp_awk_seterrnum (run, XP_AWK_ENOMEM); + return -1; + } + + if (a0->type != XP_AWK_VAL_STR) xp_free (str); + xp_awk_setretval (run, a0); + return 0; +} + +static int __bfn_split (xp_awk_t* awk, void* run) +{ + xp_size_t nargs; + xp_awk_val_t* a0, * a1, * a2; + + nargs = xp_awk_getnargs (run); + xp_assert (nargs >= 2 && nargs <= 3); + + a0 = xp_awk_getarg (run, 0); + a1 = xp_awk_getarg (run, 1); + a2 = (nargs >= 3)? xp_awk_getarg (run, 2): XP_NULL; + +/* TODO: what should i do when it is nil??? */ + if (a1->type != XP_AWK_VAL_MAP) + { + } +/* TODO: */ + + xp_awk_setretval (run, a0); + return 0; +} + +static int __bfn_system (xp_awk_t* awk, void* run) { xp_size_t nargs; xp_char_t* cmd; @@ -227,7 +439,7 @@ static int __bfn_system (void* run) xp_awk_getarg(run, 0), &errnum, xp_true, XP_NULL, XP_NULL); if (cmd == XP_NULL) { - xp_awk_seterrnum (run, XP_AWK_ENOMEM); + xp_awk_seterrnum (run, errnum); return -1; } @@ -251,7 +463,7 @@ static int __bfn_system (void* run) } /* math functions */ -static int __bfn_sin (void* run) +static int __bfn_sin (xp_awk_t* awk, void* run) { xp_size_t nargs; xp_awk_val_t* v; diff --git a/ase/awk/func.h b/ase/awk/func.h index 65c08521..0136202f 100644 --- a/ase/awk/func.h +++ b/ase/awk/func.h @@ -1,5 +1,5 @@ /* - * $Id: func.h,v 1.8 2006-08-03 05:05:47 bacon Exp $ + * $Id: func.h,v 1.9 2006-08-13 16:04:32 bacon Exp $ */ #ifndef _XP_AWK_FUNC_H_ @@ -19,7 +19,8 @@ struct xp_awk_bfn_t xp_size_t min_args; xp_size_t max_args; - int (*handler) (void* run); + const xp_char_t* arg_spec; + int (*handler) (xp_awk_t* awk, void* run); xp_awk_bfn_t* next; }; @@ -29,8 +30,9 @@ enum /* ensure that this matches __sys_bfn in func.c */ XP_AWK_BFN_CLOSE, + XP_AWK_BFN_INDEX, + XP_AWK_BFN_LENGTH, XP_AWK_BFN_SYSTEM, - XP_AWK_BFN_SIN }; @@ -40,10 +42,14 @@ extern "C" { #endif xp_awk_bfn_t* xp_awk_addbfn ( - xp_awk_t* awk, const xp_char_t* name, int when_valid, - xp_size_t min_args, xp_size_t max_args, int (*handler)(void*)); + xp_awk_t* awk, const xp_char_t* name, int when_valid, + xp_size_t min_args, xp_size_t max_args, const xp_char_t* arg_spec, + int (*handler)(xp_awk_t*,void*)); + int xp_awk_delbfn (xp_awk_t* awk, const xp_char_t* name); + void xp_awk_clrbfn (xp_awk_t* awk); + xp_awk_bfn_t* xp_awk_getbfn (xp_awk_t* awk, const xp_char_t* name); #ifdef __cplusplus diff --git a/ase/awk/parse.c b/ase/awk/parse.c index 9f25befc..6c98da56 100644 --- a/ase/awk/parse.c +++ b/ase/awk/parse.c @@ -1,5 +1,5 @@ /* - * $Id: parse.c,v 1.164 2006-08-13 05:55:02 bacon Exp $ + * $Id: parse.c,v 1.165 2006-08-13 16:04:32 bacon Exp $ */ #include @@ -2501,6 +2501,8 @@ static xp_awk_nde_t* __parse_fncall ( } else { + /* parse function parameters */ + while (1) { nde = __parse_expression (awk); @@ -2559,6 +2561,7 @@ static xp_awk_nde_t* __parse_fncall ( call->what.bfn.name_len = bfn->name_len; call->what.bfn.min_args = bfn->min_args; call->what.bfn.max_args = bfn->max_args; + call->what.bfn.arg_spec = bfn->arg_spec; call->what.bfn.handler = bfn->handler; call->args = head; diff --git a/ase/awk/run.c b/ase/awk/run.c index 8750fb5a..f73fb4c8 100644 --- a/ase/awk/run.c +++ b/ase/awk/run.c @@ -1,5 +1,5 @@ /* - * $Id: run.c,v 1.165 2006-08-13 05:55:02 bacon Exp $ + * $Id: run.c,v 1.166 2006-08-13 16:04:32 bacon Exp $ */ #include @@ -2102,7 +2102,7 @@ static xp_awk_val_t* __do_assignment_pos ( n = xp_awk_valtonum (v, &lv, &rv); xp_awk_refdownval (run, v); - if (n == -1) PANIC (run, XP_AWK_EPOSIDX); + if (n == -1) PANIC (run, XP_AWK_EPOSIDX); if (n == 1) lv = (xp_long_t)rv; if (lv < 0) PANIC (run, XP_AWK_EPOSIDX); @@ -2824,7 +2824,7 @@ static xp_awk_val_t* __eval_binop_lshift ( n1 = xp_awk_valtonum (left, &l1, &r1); n2 = xp_awk_valtonum (right, &l2, &r2); - if (n1 == -1 || n2 == -1) PANIC (run, XP_AWK_EOPERAND); + if (n1 == -1 || n2 == -1) PANIC (run, XP_AWK_EOPERAND); n3 = n1 + (n2 << 1); if (n3 == 0) @@ -2849,7 +2849,7 @@ static xp_awk_val_t* __eval_binop_rshift ( n1 = xp_awk_valtonum (left, &l1, &r1); n2 = xp_awk_valtonum (right, &l2, &r2); - if (n1 == -1 || n2 == -1) PANIC (run, XP_AWK_EOPERAND); + if (n1 == -1 || n2 == -1) PANIC (run, XP_AWK_EOPERAND); n3 = n1 + (n2 << 1); if (n3 == 0) @@ -2874,7 +2874,7 @@ static xp_awk_val_t* __eval_binop_plus ( n1 = xp_awk_valtonum (left, &l1, &r1); n2 = xp_awk_valtonum (right, &l2, &r2); - if (n1 == -1 || n2 == -1) PANIC (run, XP_AWK_EOPERAND); + if (n1 == -1 || n2 == -1) PANIC (run, XP_AWK_EOPERAND); /* n1 n2 n3 0 0 = 0 @@ -3926,7 +3926,7 @@ static xp_awk_val_t* __eval_call ( if (call->what.bfn.handler != XP_NULL) { - n = call->what.bfn.handler (run); + n = call->what.bfn.handler (run->awk, run); } } diff --git a/ase/awk/sa.c b/ase/awk/sa.c index 4401131b..b4a1d2a4 100644 --- a/ase/awk/sa.c +++ b/ase/awk/sa.c @@ -1,5 +1,5 @@ /* - * $Id: sa.c,v 1.28 2006-07-17 04:17:40 bacon Exp $ + * $Id: sa.c,v 1.29 2006-08-13 16:04:32 bacon Exp $ */ #include @@ -92,6 +92,34 @@ int xp_strxncmp ( return (*s1 > *s2)? 1: -1; } +xp_char_t* xp_strxnstr ( + const xp_char_t* str, xp_size_t strsz, + const xp_char_t* sub, xp_size_t subsz) +{ + const xp_char_t* end, * subp; + + if (subsz == 0) return (xp_char_t*)str; + if (strsz < subsz) return XP_NULL; + + end = str + strsz - subsz; + subp = sub + subsz; + + while (str <= end) { + const xp_char_t* x = str; + const xp_char_t* y = sub; + + while (xp_true) { + if (y >= subp) return (xp_char_t*)str; + if (*x != *y) break; + x++; y++; + } + + str++; + } + + return XP_NULL; +} + xp_char_t* xp_strtok (const xp_char_t* s, const xp_char_t* delim, xp_char_t** tok, xp_size_t* tok_len) { diff --git a/ase/awk/sa.h b/ase/awk/sa.h index 91efd80d..fe61158d 100644 --- a/ase/awk/sa.h +++ b/ase/awk/sa.h @@ -1,5 +1,5 @@ /* - * $Id: sa.h,v 1.28 2006-08-13 05:55:02 bacon Exp $ + * $Id: sa.h,v 1.29 2006-08-13 16:04:32 bacon Exp $ */ #ifndef _XP_AWK_SA_H_ @@ -124,6 +124,11 @@ int xp_strxncmp ( const xp_char_t* s1, xp_size_t len1, const xp_char_t* s2, xp_size_t len2); +#define xp_strxnstr xp_awk_strxnstr +xp_char_t* xp_strxnstr ( + const xp_char_t* str, xp_size_t strsz, + const xp_char_t* sub, xp_size_t subsz); + #define xp_strtok xp_awk_strtok xp_char_t* xp_strtok (const xp_char_t* s, const xp_char_t* delim, xp_char_t** tok, xp_size_t* tok_len); diff --git a/ase/awk/tree.h b/ase/awk/tree.h index 8d8d1094..83748fd0 100644 --- a/ase/awk/tree.h +++ b/ase/awk/tree.h @@ -1,5 +1,5 @@ /* - * $Id: tree.h,v 1.67 2006-08-06 15:02:55 bacon Exp $ + * $Id: tree.h,v 1.68 2006-08-13 16:04:32 bacon Exp $ */ #ifndef _XP_AWK_TREE_H_ @@ -252,7 +252,8 @@ struct xp_awk_nde_call_t xp_size_t name_len; xp_size_t min_args; xp_size_t max_args; - int (*handler) (void* run); + const xp_char_t* arg_spec; + int (*handler) (xp_awk_t* awk, void* run); } bfn; /* xp_awk_bfn_t* bfn; */ } what; diff --git a/ase/test/awk/awk.c b/ase/test/awk/awk.c index 708783ee..edd41464 100644 --- a/ase/test/awk/awk.c +++ b/ase/test/awk/awk.c @@ -1,5 +1,5 @@ /* - * $Id: awk.c,v 1.71 2006-08-13 06:33:30 bacon Exp $ + * $Id: awk.c,v 1.72 2006-08-13 16:05:04 bacon Exp $ */ #include @@ -558,7 +558,7 @@ static int __main (int argc, xp_char_t* argv[]) opt = XP_AWK_EXPLICIT | XP_AWK_UNIQUE | XP_AWK_DBLSLASHES | XP_AWK_SHADING | XP_AWK_IMPLICIT | XP_AWK_SHIFT | - XP_AWK_EXTIO | XP_AWK_BLOCKLESS; + XP_AWK_EXTIO | XP_AWK_BLOCKLESS | XP_AWK_STRINDEXONE; if (argc == 2) { diff --git a/ase/test/awk/t28.awk b/ase/test/awk/t28.awk index 1d5e353f..5ccfeaa9 100644 --- a/ase/test/awk/t28.awk +++ b/ase/test/awk/t28.awk @@ -1,5 +1,17 @@ END { print index ("abc", "abc"); print index ("abc", "b"); - print index ("abc", "k"); + print index ("abc", "kabc"); + + print "----------------------------"; + print substr ("abc", "abcdefg", 5); + print substr ("abc", -1, 5); + print substr ("abc", 0, 5); + print substr ("abc", 1, 5); + print substr ("abc", 2.829, 5); + print substr ("abc", "3", 5); + print substr ("abc", 4, 5); + + a[1] = 20; + substr (a, 3, 4); } diff --git a/ase/test/awk/t29.awk b/ase/test/awk/t29.awk new file mode 100644 index 00000000..0ced598b --- /dev/null +++ b/ase/test/awk/t29.awk @@ -0,0 +1,2 @@ +{ gsub ("abc", "&&&&"); print $0; } +