diff --git a/ase/awk/awk.h b/ase/awk/awk.h index aeb00da9..bf48b875 100644 --- a/ase/awk/awk.h +++ b/ase/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h,v 1.137 2006-10-30 14:31:36 bacon Exp $ + * $Id: awk.h,v 1.138 2006-10-31 10:13:14 bacon Exp $ */ #ifndef _ASE_AWK_AWK_H_ @@ -268,6 +268,7 @@ enum ASE_AWK_ENEXT, /* next illegal in BEGIN or END block */ ASE_AWK_ENEXTFILE, /* nextfile illegal in BEGIN or END block */ ASE_AWK_EGETLINE, /* getline expected */ + ASE_AWK_EPRINTFARG, /* printf must have one or more arguments */ /* run time error */ ASE_AWK_EDIVBYZERO, /* divide by zero */ diff --git a/ase/awk/err.c b/ase/awk/err.c index f1158fb1..9945c1be 100644 --- a/ase/awk/err.c +++ b/ase/awk/err.c @@ -1,5 +1,5 @@ /* - * $Id: err.c,v 1.45 2006-10-24 04:10:12 bacon Exp $ + * $Id: err.c,v 1.46 2006-10-31 10:13:14 bacon Exp $ */ #include @@ -80,6 +80,7 @@ const ase_char_t* ase_awk_geterrstr (int errnum) ASE_T("next illegal in BEGIN or END block"), ASE_T("nextfile illegal in BEGIN or END block"), ASE_T("getline expected"), + ASE_T("printf requires one or more arguments"), ASE_T("divide by zero"), ASE_T("invalid operand"), diff --git a/ase/awk/misc.c b/ase/awk/misc.c index 3ded86e9..10d752ea 100644 --- a/ase/awk/misc.c +++ b/ase/awk/misc.c @@ -1,5 +1,5 @@ /* - * $Id: misc.c,v 1.35 2006-10-30 14:31:37 bacon Exp $ + * $Id: misc.c,v 1.36 2006-10-31 10:13:14 bacon Exp $ */ #include @@ -1060,6 +1060,13 @@ exit_loop: } } +int ase_awk_sprintf (ase_awk_t* awk, + ase_char_t* buf, ase_size_t len, const ase_char_t* fmt, ...) +{ + /* TODO: */ + return -1; +} + int ase_awk_assertfail (ase_awk_t* awk, const ase_char_t* expr, const ase_char_t* desc, const ase_char_t* file, int line) diff --git a/ase/awk/misc.h b/ase/awk/misc.h index 28c6bb7f..40159460 100644 --- a/ase/awk/misc.h +++ b/ase/awk/misc.h @@ -1,5 +1,5 @@ /* - * $Id: misc.h,v 1.8 2006-10-24 04:48:52 bacon Exp $ + * $Id: misc.h,v 1.9 2006-10-31 10:13:14 bacon Exp $ */ #ifndef _ASE_AWK_MISC_H_ @@ -38,6 +38,9 @@ ase_char_t* ase_awk_strxntokbyrex ( ase_awk_run_t* run, const ase_char_t* s, ase_size_t len, void* rex, ase_char_t** tok, ase_size_t* tok_len, int* errnum); +int ase_awk_sprintf (ase_awk_t* awk, + ase_char_t* buf, ase_size_t len, const ase_char_t* fmt, ...); + #ifdef __cplusplus } #endif diff --git a/ase/awk/parse.c b/ase/awk/parse.c index f6c25764..6a432784 100644 --- a/ase/awk/parse.c +++ b/ase/awk/parse.c @@ -1,5 +1,5 @@ /* - * $Id: parse.c,v 1.198 2006-10-28 12:17:24 bacon Exp $ + * $Id: parse.c,v 1.199 2006-10-31 10:13:15 bacon Exp $ */ #include @@ -182,8 +182,7 @@ static ase_awk_nde_t* __parse_exit (ase_awk_t* awk); static ase_awk_nde_t* __parse_next (ase_awk_t* awk); static ase_awk_nde_t* __parse_nextfile (ase_awk_t* awk); static ase_awk_nde_t* __parse_delete (ase_awk_t* awk); -static ase_awk_nde_t* __parse_print (ase_awk_t* awk); -static ase_awk_nde_t* __parse_printf (ase_awk_t* awk); +static ase_awk_nde_t* __parse_print (ase_awk_t* awk, int type); static int __get_token (ase_awk_t* awk); static int __get_number (ase_awk_t* awk); @@ -1265,12 +1264,12 @@ awk->parse.nl_semicolon = 1; else if (MATCH(awk,TOKEN_PRINT)) { if (__get_token(awk) == -1) return ASE_NULL; - nde = __parse_print (awk); + nde = __parse_print (awk, ASE_AWK_NDE_PRINT); } else if (MATCH(awk,TOKEN_PRINTF)) { if (__get_token(awk) == -1) return ASE_NULL; - nde = __parse_printf (awk); + nde = __parse_print (awk, ASE_AWK_NDE_PRINTF); } else { @@ -3135,7 +3134,7 @@ static ase_awk_nde_t* __parse_delete (ase_awk_t* awk) return (ase_awk_nde_t*)nde; } -static ase_awk_nde_t* __parse_print (ase_awk_t* awk) +static ase_awk_nde_t* __parse_print (ase_awk_t* awk, int type) { ase_awk_nde_print_t* nde; ase_awk_nde_t* args = ASE_NULL; @@ -3261,10 +3260,24 @@ static ase_awk_nde_t* __parse_print (ase_awk_t* awk) { if (args != ASE_NULL) ase_awk_clrpt (awk, args); if (out != ASE_NULL) ase_awk_clrpt (awk, out); - PANIC (awk, ASE_AWK_ENOMEM); + + awk->errnum = ASE_AWK_ENOMEM; + return ASE_NULL; } - nde->type = ASE_AWK_NDE_PRINT; + ASE_AWK_ASSERTX (awk, + type == ASE_AWK_NDE_PRINT || type == ASE_AWK_NDE_PRINTF, + "the node type should be either ASE_AWK_NDE_PRINT or " + "ASE_AWK_NDE_PRINTF"); + + if (type == ASE_AWK_NDE_PRINTF && args == ASE_NULL) + { + if (out != ASE_NULL) ase_awk_clrpt (awk, out); + awk->errnum = ASE_AWK_EPRINTFARG; + return ASE_NULL; + } + + nde->type = type; nde->next = ASE_NULL; nde->args = args; nde->out_type = out_type; @@ -3273,14 +3286,6 @@ static ase_awk_nde_t* __parse_print (ase_awk_t* awk) return (ase_awk_nde_t*)nde; } -static ase_awk_nde_t* __parse_printf (ase_awk_t* awk) -{ - /* TODO: implement this... */ -ASE_AWK_ASSERT (awk, !"printf not implemented yet"); -awk->errnum = ASE_AWK_EINTERNAL; - return ASE_NULL; -} - static ase_awk_nde_t* __parse_next (ase_awk_t* awk) { ase_awk_nde_next_t* nde; diff --git a/ase/awk/run.c b/ase/awk/run.c index 2ecabb54..ac05e689 100644 --- a/ase/awk/run.c +++ b/ase/awk/run.c @@ -1,5 +1,5 @@ /* - * $Id: run.c,v 1.249 2006-10-28 12:17:25 bacon Exp $ + * $Id: run.c,v 1.250 2006-10-31 10:13:15 bacon Exp $ */ #include @@ -83,6 +83,7 @@ static int __run_next (ase_awk_run_t* run, ase_awk_nde_next_t* nde); static int __run_nextfile (ase_awk_run_t* run, ase_awk_nde_nextfile_t* nde); static int __run_delete (ase_awk_run_t* run, ase_awk_nde_delete_t* nde); static int __run_print (ase_awk_run_t* run, ase_awk_nde_print_t* nde); +static int __run_printf (ase_awk_run_t* run, ase_awk_nde_print_t* nde); static ase_awk_val_t* __eval_expression (ase_awk_run_t* run, ase_awk_nde_t* nde); static ase_awk_val_t* __eval_expression0 (ase_awk_run_t* run, ase_awk_nde_t* nde); @@ -1557,6 +1558,13 @@ static int __run_statement (ase_awk_run_t* run, ase_awk_nde_t* nde) break; } + case ASE_AWK_NDE_PRINTF: + { + if (__run_printf (run, + (ase_awk_nde_print_t*)nde) == -1) return -1; + break; + } + /* case ASE_AWK_NDE_PRINT: { @@ -1741,10 +1749,7 @@ static int __run_for (ase_awk_run_t* run, ase_awk_nde_for_t* nde) } else { - if (__run_statement(run,nde->body) == -1) - { - return -1; - } + if (__run_statement(run,nde->body) == -1) return -1; } if (run->exit_level == EXIT_BREAK) @@ -1978,16 +1983,23 @@ static int __run_delete (ase_awk_run_t* run, ase_awk_nde_delete_t* nde) * create a map and assign it to the variable */ tmp = ase_awk_makemapval (run); - if (tmp == ASE_NULL) PANIC_I (run, ASE_AWK_ENOMEM); + if (tmp == ASE_NULL) + { + run->errnum = ASE_AWK_ENOMEM; + return -1; + } if (ase_awk_map_put (&run->named, var->id.name, var->id.name_len, tmp) == ASE_NULL) { ase_awk_refupval (tmp); ase_awk_refdownval (run, tmp); - PANIC_I (run, ASE_AWK_ENOMEM); + run->errnum = ASE_AWK_ENOMEM; + return -1; } + /* as this is the assignment, it needs to update + * the reference count of the target value */ ase_awk_refupval (tmp); } else @@ -1999,7 +2011,10 @@ static int __run_delete (ase_awk_run_t* run, ase_awk_nde_delete_t* nde) ASE_AWK_ASSERT (run->awk, val != ASE_NULL); if (val->type != ASE_AWK_VAL_MAP) - PANIC_I (run, ASE_AWK_ENOTDELETABLE); + { + run->errnum = ASE_AWK_ENOTDELETABLE; + return -1; + } map = ((ase_awk_val_map_t*)val)->map; if (var->type == ASE_AWK_NDE_NAMEDIDX) @@ -2015,7 +2030,8 @@ static int __run_delete (ase_awk_run_t* run, ase_awk_nde_delete_t* nde) ase_awk_refupval (idx); key = ase_awk_valtostr ( - run, idx, ASE_AWK_VALTOSTR_CLEAR, ASE_NULL, &key_len); + run, idx, ASE_AWK_VALTOSTR_CLEAR, + ASE_NULL, &key_len); ase_awk_refdownval (run, idx); if (key == ASE_NULL) return -1; @@ -2056,7 +2072,11 @@ static int __run_delete (ase_awk_run_t* run, ase_awk_nde_delete_t* nde) * create a map and assign it to the variable */ tmp = ase_awk_makemapval (run); - if (tmp == ASE_NULL) PANIC_I (run, ASE_AWK_ENOMEM); + if (tmp == ASE_NULL) + { + run->errnum = ASE_AWK_ENOMEM; + return -1; + } /* no need to reduce the reference count of * the previous value because it was nil. */ @@ -2088,7 +2108,10 @@ static int __run_delete (ase_awk_run_t* run, ase_awk_nde_delete_t* nde) ase_awk_map_t* map; if (val->type != ASE_AWK_VAL_MAP) - PANIC_I (run, ASE_AWK_ENOTDELETABLE); + { + run->errnum = ASE_AWK_ENOTDELETABLE; + return -1; + } map = ((ase_awk_val_map_t*)val)->map; if (var->type == ASE_AWK_NDE_GLOBALIDX || @@ -2106,7 +2129,8 @@ static int __run_delete (ase_awk_run_t* run, ase_awk_nde_delete_t* nde) ase_awk_refupval (idx); key = ase_awk_valtostr ( - run, idx, ASE_AWK_VALTOSTR_CLEAR, ASE_NULL, &key_len); + run, idx, ASE_AWK_VALTOSTR_CLEAR, + ASE_NULL, &key_len); ase_awk_refdownval (run, idx); if (key == ASE_NULL) return -1; @@ -2122,8 +2146,13 @@ static int __run_delete (ase_awk_run_t* run, ase_awk_nde_delete_t* nde) } else { - ASE_AWK_ASSERT (run->awk, !"should never happen - wrong variable type for delete"); - PANIC_I (run, ASE_AWK_EINTERNAL); + ASE_AWK_ASSERTX (run->awk, + !"should never happen - wrong variable type for delete", + "the delete statement cannot be called with other " + "nodes than the variables such as a named variable, " + "a named indexed variable, etc"); + run->errnum = ASE_AWK_EINTERNAL; + return -1; } return 0; @@ -2193,18 +2222,6 @@ static int __run_print (ase_awk_run_t* run, ase_awk_nde_print_t* nde) if (p->args == ASE_NULL) { - /* - v = run->inrec.d0; - ase_awk_refupval (v); - n = ase_awk_writeextio_val (run, p->out_type, dst, v); - if (n < 0 && run->errnum != ASE_AWK_EIOHANDLER) - { - if (out != ASE_NULL) ASE_AWK_FREE (run->awk, out); - ase_awk_refdownval (run, v); - return -1; - } - ase_awk_refdownval (run, v); - */ n = ase_awk_writeextio_str ( run, p->out_type, dst, ASE_AWK_STR_BUF(&run->inrec.line), @@ -2286,6 +2303,137 @@ skip_write: return 0; } +static int xxx__run_printf (ase_awk_run_t* run, ase_awk_nde_print_t* nde) +{ +ASE_AWK_ASSERTX (run->awk, !"should never happen - not implemented", + "the runtime function for the printf statement has not been " + "implemented yet. please do not use printf until it is fully " + "implemented"); + + run->errnum = ASE_AWK_EINTERNAL; + return -1; +} + +static int __run_printf (ase_awk_run_t* run, ase_awk_nde_print_t* nde) +{ + ase_awk_nde_print_t* p = (ase_awk_nde_print_t*)nde; + ase_char_t* out = ASE_NULL; + const ase_char_t* dst; + ase_awk_val_t* v; + ase_awk_nde_t* head, * np; + int n; + + ASE_AWK_ASSERT (run->awk, + (p->out_type == ASE_AWK_OUT_PIPE && p->out != ASE_NULL) || + (p->out_type == ASE_AWK_OUT_COPROC && p->out != ASE_NULL) || + (p->out_type == ASE_AWK_OUT_FILE && p->out != ASE_NULL) || + (p->out_type == ASE_AWK_OUT_FILE_APPEND && p->out != ASE_NULL) || + (p->out_type == ASE_AWK_OUT_CONSOLE && p->out == ASE_NULL)); + + if (p->out != ASE_NULL) + { + ase_size_t len; + + v = __eval_expression (run, p->out); + if (v == ASE_NULL) return -1; + + ase_awk_refupval (v); + out = ase_awk_valtostr ( + run, v, ASE_AWK_VALTOSTR_CLEAR, ASE_NULL, &len); + if (out == ASE_NULL) + { + ase_awk_refdownval (run, v); + return -1; + } + ase_awk_refdownval (run, v); + + if (len <= 0) + { + /* the output destination name is empty. */ + ASE_AWK_FREE (run->awk, out); + n = -1; + goto skip_write; + } + + while (len > 0) + { + if (out[--len] == ASE_T('\0')) + { + /* the output destination name contains a null + * character. */ + ASE_AWK_FREE (run->awk, out); + n = -1; + goto skip_write; + /* TODO: how to handle error??? + * make print return -1??? not possible. + * throw an exception?? + * set ERRNO or what??? this seems most + * reasonable. or can it have a global + * flag variable for print/printf such + * as PRINT_ERRNO? */ + } + } + } + + dst = (out == ASE_NULL)? ASE_T(""): out; + + ASE_AWK_ASSERTX (run->awk, p->args != ASE_NULL, + "a valid printf statement should have at least one argument. " + "the parser must ensure this."); + + + if (p->args->type == ASE_AWK_NDE_GRP) + { + /* parenthesized print */ + ASE_AWK_ASSERT (run->awk, p->args->next == ASE_NULL); + head = ((ase_awk_nde_grp_t*)p->args)->body; + } + else head = p->args; + + for (np = head; np != ASE_NULL; np = np->next) + { + if (np != head) + { + n = ase_awk_writeextio_str ( + run, p->out_type, dst, + run->global.ofs.ptr, + run->global.ofs.len); + if (n < 0 && run->errnum != ASE_AWK_EIOHANDLER) + { + if (out != ASE_NULL) ASE_AWK_FREE (run->awk, out); + return -1; + } + } + + v = __eval_expression (run, np); + if (v == ASE_NULL) + { + if (out != ASE_NULL) ASE_AWK_FREE (run->awk, out); + return -1; + } + ase_awk_refupval (v); + + n = ase_awk_writeextio_val (run, p->out_type, dst, v); + if (n < 0 && run->errnum != ASE_AWK_EIOHANDLER) + { + if (out != ASE_NULL) ASE_AWK_FREE (run->awk, out); + ase_awk_refdownval (run, v); + return -1; + } + + ase_awk_refdownval (run, v); + + + /* TODO: how to handle n == -1 && run->errnum == ASE_AWK_EIOHANDLER. + * that is the user handler returned an error... */ + } + + if (out != ASE_NULL) ASE_AWK_FREE (run->awk, out); + +skip_write: + return 0; +} + static ase_awk_val_t* __eval_expression (ase_awk_run_t* run, ase_awk_nde_t* nde) { ase_awk_val_t* v; @@ -2307,7 +2455,11 @@ static ase_awk_val_t* __eval_expression (ase_awk_run_t* run, ase_awk_nde_t* nde) } else { - ASE_AWK_ASSERT (run->awk, run->inrec.d0->type == ASE_AWK_VAL_STR); + ASE_AWK_ASSERTX (run->awk, + run->inrec.d0->type == ASE_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."); n = ase_awk_matchrex ( ((ase_awk_run_t*)run)->awk, diff --git a/ase/awk/tree.c b/ase/awk/tree.c index bb30d2ef..733e220d 100644 --- a/ase/awk/tree.c +++ b/ase/awk/tree.c @@ -1,5 +1,5 @@ /* - * $Id: tree.c,v 1.84 2006-10-26 09:27:15 bacon Exp $ + * $Id: tree.c,v 1.85 2006-10-31 10:13:15 bacon Exp $ */ #include @@ -777,12 +777,16 @@ static int __print_statements (ase_awk_t* awk, ase_awk_nde_t* tree, int depth) } case ASE_AWK_NDE_PRINT: + case ASE_AWK_NDE_PRINTF: { ase_awk_nde_print_t* px = (ase_awk_nde_print_t*)p; PRINT_TABS (awk, depth); - PUT_SRCSTR (awk, ASE_T("print")); + if (p->type == ASE_AWK_NDE_PRINT) + PUT_SRCSTR (awk, ASE_T("print")); + else PUT_SRCSTR (awk, ASE_T("printf")); + if (px->args != ASE_NULL) { PUT_SRCSTR (awk, ASE_T(" ")); @@ -949,6 +953,7 @@ void ase_awk_clrpt (ase_awk_t* awk, ase_awk_nde_t* tree) } case ASE_AWK_NDE_PRINT: + case ASE_AWK_NDE_PRINTF: { ase_awk_nde_print_t* px = (ase_awk_nde_print_t*)p; diff --git a/ase/awk/tree.h b/ase/awk/tree.h index 5ec6b7db..dfcbe1e8 100644 --- a/ase/awk/tree.h +++ b/ase/awk/tree.h @@ -1,5 +1,5 @@ /* - * $Id: tree.h,v 1.77 2006-10-24 04:10:12 bacon Exp $ + * $Id: tree.h,v 1.78 2006-10-31 10:13:15 bacon Exp $ */ #ifndef _ASE_AWK_TREE_H_ @@ -28,6 +28,7 @@ enum ASE_AWK_NDE_NEXTFILE, ASE_AWK_NDE_DELETE, ASE_AWK_NDE_PRINT, + ASE_AWK_NDE_PRINTF, /* expression */ /* if you change the following values including their order, diff --git a/ase/test/awk/arg.awk b/ase/test/awk/arg.awk index 3d40feb6..b943c54e 100644 --- a/ase/test/awk/arg.awk +++ b/ase/test/awk/arg.awk @@ -19,5 +19,5 @@ BEGIN { # i;;) print i; - if (ARGC >= 0) print "ARGC is positive"; + if (ARGC >= 0) printf "ARGC is positive"; } diff --git a/ase/test/awk/awk.c b/ase/test/awk/awk.c index 0dd75a71..2b412b9f 100644 --- a/ase/test/awk/awk.c +++ b/ase/test/awk/awk.c @@ -1,5 +1,5 @@ /* - * $Id: awk.c,v 1.107 2006-10-28 05:24:08 bacon Exp $ + * $Id: awk.c,v 1.108 2006-10-31 10:12:44 bacon Exp $ */ #include @@ -99,7 +99,7 @@ static int __aprintf (const ase_char_t* fmt, ...) #if defined(_MSC_VER) && (_MSC_VER<1400) MessageBox (NULL, buf, ASE_T("Assertion Failure"), MB_OK | MB_ICONERROR); #else - MessageBox (NULL, buf, ASE_T("\uD655\uC778\uC2E4\uD328 Assertion Failure"), MB_OK | MB_ICONERROR); + MessageBox (NULL, buf, ASE_T("\uB2DD\uAE30\uB9AC \uC870\uB610"), MB_OK | MB_ICONERROR); #endif #else