diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-01 23:12:26 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-01 23:12:26 +0300 |
commit | 9671c7d62638d1ab02261717863a7e9864b67cbd (patch) | |
tree | 628ced411bfabf32cb3467c0571e8bf169ea140c | |
parent | 0f5bd212a2cbb8a35c9d9b45a1ab66bb4d585948 (diff) | |
download | mailutils-9671c7d62638d1ab02261717863a7e9864b67cbd.tar.gz mailutils-9671c7d62638d1ab02261717863a7e9864b67cbd.tar.bz2 |
MH format: fix processing of special functions: putstrf, putnumf, lit, and num
* mh/mh_fmtgram.y (node): Replace noprint with printflag.
(escape production): Consult printflag to decide whether to
amd how to print
(funcall production): Rewrite logic
(yylex_func): Make a clear distinction between literals and
inlined ctls, which require leading whitespace, and funcalls
and components, that don't tolerate it.
(emit_funcall): Process special functions separately
* mh/mh_format.c (builtin_tab): Mark lit, num, putstrf, and putnumf
as specials.
* mh/mh_format.h: Revamp MHA_ flags
* mh/tests/fmtcomp.at: Update.
* mh/tests/fmtfunc.at: Add tests for putstrf and putnumf
-rw-r--r-- | mh/mh_fmtgram.y | 152 | ||||
-rw-r--r-- | mh/mh_format.c | 12 | ||||
-rw-r--r-- | mh/mh_format.h | 14 | ||||
-rw-r--r-- | mh/tests/fmtcomp.at | 52 | ||||
-rw-r--r-- | mh/tests/fmtfunc.at | 11 |
5 files changed, 186 insertions, 55 deletions
diff --git a/mh/mh_fmtgram.y b/mh/mh_fmtgram.y index 4a51d481a..67560d3e8 100644 --- a/mh/mh_fmtgram.y +++ b/mh/mh_fmtgram.y @@ -82,7 +82,7 @@ struct node { enum node_type nodetype; enum mh_type datatype; - int noprint:1; + int printflag; struct node *prev, *next; union { @@ -188,12 +188,12 @@ item : STRING escape : cntl | fmtspec printable { - if ($2->noprint) + if ($2->printflag & MHA_NOPRINT) $$ = $2; else { $$ = new_node (fmtnode_print, $2->datatype); - $$->v.prt.fmtspec = $1; + $$->v.prt.fmtspec = ($2->printflag & MHA_IGNOREFMT) ? 0 : $1; $$->v.prt.arg = $2; } } @@ -217,15 +217,11 @@ component : COMPONENT funcall : function argument EOFN { + struct node *arg; + ctx_pop (); - if ($1->flags & MHA_VOID) /*FIXME*/ - { - $2->noprint = 1; - $$ = $2; - } - else - { - struct node *arg = $2; + + arg = $2; if ($1->argtype == mhtype_none) { if (arg) @@ -266,18 +262,54 @@ funcall : function argument EOFN } else if ($1->flags & MHA_LITERAL) { - if (!(arg->nodetype == fmtnode_literal - || arg->nodetype == fmtnode_number)) + switch ($1->argtype) + { + case mhtype_num: + if (arg->nodetype == fmtnode_number) + /* ok */; + else + { + yyerror ("argument must be a number"); + YYABORT; + } + break; + + case mhtype_str: + if (arg->nodetype == fmtnode_literal) + /* ok */; + else if (arg->nodetype == fmtnode_number) + { + char *s; + mu_asprintf (&s, "%ld", arg->v.num); + arg->nodetype = fmtnode_literal; + arg->datatype = mhtype_str; + arg->v.str = s; + } + else { yyerror ("argument must be literal"); YYABORT; } + break; + + default: + break; + } } + if ($1->flags & MHA_VOID) + { + $2->printflag = MHA_NOPRINT; + $$ = $2; + } + else + { $$ = new_node (fmtnode_funcall, $1->type); $$->v.funcall.builtin = $1; $$->v.funcall.arg = typecast (arg, $1->argtype); - $$->noprint = $1->type == mhtype_none; + $$->printflag = $1->flags & MHA_PRINT_MASK; + if ($1->type == mhtype_none) + $$->printflag = MHA_NOPRINT; } } ; @@ -783,9 +815,10 @@ yylex_expr (void) int yylex_func (void) { + int c; + /* Expected argument or closing parenthesis */ - mark (); - skip (MU_CTYPE_SPACE); + again: mark (); switch (peek ()) { @@ -813,16 +846,20 @@ yylex_func (void) default: return bogus ("expected '%' or '<'"); } - } + break; - if (mu_isdigit (peek ())) - { - yylval.arg.type = mhtype_num; - yylval.arg.v.num = strtol (curp, &curp, 0); + case ' ': + case '\t': + skip (MU_CTYPE_SPACE); + if (peek () == '%') + goto again; + break; + + default: + return input (); } - else - { - int c; + + mark (); while ((c = input ()) != ')') { @@ -844,9 +881,21 @@ yylex_func (void) } mu_opool_append_char (tokpool, 0); - yylval.arg.type = mhtype_str; yylval.arg.v.str = mu_opool_finish (tokpool, NULL); + yylval.arg.type = mhtype_str; unput (c); + + if (mu_isdigit (yylval.arg.v.str[0])) + { + long n; + char *p; + errno = 0; + n = strtol (yylval.arg.v.str, &p, 0); + if (errno == 0 && *p == 0) + { + yylval.arg.type = mhtype_num; + yylval.arg.v.num = n; + } } if (peek () != ')') @@ -1056,17 +1105,20 @@ typecast (struct node *node, enum mh_type type) if (node->datatype == type) return node; - if (node->nodetype == fmtnode_cntl) + switch (node->nodetype) { + case fmtnode_cntl: node->v.cntl.iftrue = typecast (node->v.cntl.iftrue, type); node->v.cntl.iffalse = typecast (node->v.cntl.iffalse, type); node->datatype = type; - } - else + break; + + default: { - struct node *np = new_node (fmtnode_typecast, type); - np->v.arg = node; - node = np; + struct node *arg = new_node (fmtnode_typecast, type); + arg->v.arg = node; + node = arg; + } } return node; } @@ -1341,8 +1393,44 @@ emit_opcode_typed (struct mh_format *fmt, enum mh_type type, } static void +emit_special (struct mh_format *fmt, mh_builtin_t *builtin, struct node *arg) +{ + if (arg) + { + if (builtin->flags & MHA_LITERAL) + { + switch (arg->nodetype) + { + case fmtnode_literal: + emit_opcode (fmt, mhop_sets); + emit_instr (fmt, (mh_instr_t) (long) R_REG); + emit_string (fmt, arg->v.str); + break; + + case fmtnode_number: + emit_opcode (fmt, mhop_setn); + emit_instr (fmt, (mh_instr_t) (long) R_REG); + emit_instr (fmt, (mh_instr_t) (long) arg->v.num); + break; + + default: + abort (); + } + } + else + codegen_node (fmt, arg); + } +} + +static void emit_funcall (struct mh_format *fmt, mh_builtin_t *builtin, struct node *arg) { + if (builtin->flags & MHA_SPECIAL) + { + emit_special (fmt, builtin, arg); + return; + } + if (arg) { if (builtin->flags & MHA_LITERAL) @@ -1541,5 +1629,3 @@ codegen (mh_format_t *fmtptr, int tree) } - - diff --git a/mh/mh_format.c b/mh/mh_format.c index 914a85b1e..16906308b 100644 --- a/mh/mh_format.c +++ b/mh/mh_format.c @@ -933,7 +933,7 @@ builtin_putstr (struct mh_fvm *mach) static void builtin_putstrf (struct mh_fvm *mach) { - format_str (mach, mh_string_value (&mach->str[R_ARG])); + mh_string_copy (mach, R_REG, R_ARG); } /* putnum expr print num*/ @@ -1842,8 +1842,8 @@ mh_builtin_t builtin_tab[] = { { "minus", builtin_minus, mhtype_num, mhtype_num, MHA_LITERAL }, { "divide", builtin_divide, mhtype_num, mhtype_num, MHA_LITERAL }, { "modulo", builtin_modulo, mhtype_num, mhtype_num, MHA_LITERAL }, - { "num", builtin_num, mhtype_num, mhtype_num, MHA_LITERAL|MHA_OPTARG|MHA_OPTARG_NIL }, - { "lit", builtin_lit, mhtype_str, mhtype_str, MHA_LITERAL|MHA_OPTARG|MHA_OPTARG_NIL }, + { "num", NULL, mhtype_num, mhtype_num, MHA_LITERAL|MHA_OPTARG|MHA_OPTARG_NIL|MHA_SPECIAL }, + { "lit", NULL, mhtype_str, mhtype_str, MHA_LITERAL|MHA_OPTARG|MHA_OPTARG_NIL|MHA_SPECIAL }, { "getenv", builtin_getenv, mhtype_str, mhtype_str, MHA_LITERAL }, { "profile", builtin_profile, mhtype_str, mhtype_str, MHA_LITERAL }, { "nonzero", builtin_nonzero, mhtype_num, mhtype_num, MHA_OPTARG }, @@ -1854,9 +1854,9 @@ mh_builtin_t builtin_tab[] = { { "compval", builtin_compval, mhtype_num, mhtype_str }, { "trim", builtin_trim, mhtype_none, mhtype_str, MHA_OPTARG }, { "putstr", builtin_putstr, mhtype_none, mhtype_str, MHA_OPTARG }, - { "putstrf", builtin_putstrf, mhtype_none, mhtype_str, MHA_OPTARG }, + { "putstrf", NULL, mhtype_str, mhtype_str, MHA_SPECIAL|MHA_OPTARG }, { "putnum", builtin_putnum, mhtype_none, mhtype_num, MHA_OPTARG }, - { "putnumf", builtin_putnumf, mhtype_none, mhtype_num, MHA_OPTARG }, + { "putnumf", NULL, mhtype_num, mhtype_num, MHA_SPECIAL|MHA_OPTARG }, { "sec", builtin_sec, mhtype_num, mhtype_str }, { "min", builtin_min, mhtype_num, mhtype_str }, { "hour", builtin_hour, mhtype_num, mhtype_str }, @@ -1907,7 +1907,7 @@ mh_builtin_t builtin_tab[] = { { "reply_regex", builtin_reply_regex, mhtype_none, mhtype_str }, { "isreply", builtin_isreply, mhtype_num, mhtype_str, MHA_OPTARG }, { "decode", builtin_decode, mhtype_str, mhtype_str }, - { "void", NULL, mhtype_none, mhtype_none, MHA_VOID }, + { "void", NULL, mhtype_none, mhtype_str, MHA_VOID }, { 0 } }; diff --git a/mh/mh_format.h b/mh/mh_format.h index 3c9021785..ce537153c 100644 --- a/mh/mh_format.h +++ b/mh/mh_format.h @@ -127,10 +127,15 @@ struct mh_format }; #define MHA_DEFAULT 0 -#define MHA_OPTARG 0x1 -#define MHA_LITERAL 0x2 -#define MHA_VOID 0x4 -#define MHA_OPTARG_NIL 0x8 +#define MHA_IGNOREFMT 0x001 +#define MHA_NOPRINT 0x002 +#define MHA_PRINT_MASK 0x003 + +#define MHA_OPTARG 0x004 +#define MHA_OPTARG_NIL 0x008 +#define MHA_LITERAL 0x010 +#define MHA_VOID 0x020 +#define MHA_SPECIAL 0x040 typedef struct mh_builtin mh_builtin_t; @@ -173,3 +178,4 @@ struct mh_fvm mh_builtin_t *mh_lookup_builtin (char *name, size_t len); void mh_print_fmtspec (int fmtspec); + diff --git a/mh/tests/fmtcomp.at b/mh/tests/fmtcomp.at index 253ecd9a5..ca937866a 100644 --- a/mh/tests/fmtcomp.at +++ b/mh/tests/fmtcomp.at @@ -69,29 +69,29 @@ FMTCOMP([function call formatted], 0006: stop ]) -FMTCOMP([function call with argument], -[%(lit text: )], -[PRINT(lit("text: ")) - 0001: sets arg, "text: " - 0007: call lit +FMTCOMP([function call with literal argument], +[%(getenv PATH)], +[PRINT(getenv("PATH")) + 0001: sets arg, "PATH" + 0007: call getenv 0009: prints 0010: stop ]) FMTCOMP([function call with numeric argument], -[%(num 10)], -[PRINT(num(10)) +[%(plus 10)], +[PRINT(plus(10)) 0001: setn arg, 10 - 0004: call num + 0004: call plus 0006: printn 0007: stop ]) FMTCOMP([function call with numeric argument and format spec], -[%08(num 10)], -[FORMAT(NORALIGN|ZEROPAD|NOCOMPWS, 8, num(10)) +[%08(plus 10)], +[FORMAT(NORALIGN|ZEROPAD|NOCOMPWS, 8, plus(10)) 0001: setn arg, 10 - 0004: call num + 0004: call plus 0006: fmtspec NORALIGN|ZEROPAD|NOCOMPWS, 8 0008: printn 0009: stop @@ -132,6 +132,36 @@ FMTCOMP([nested function calls with typecast], 0020: stop ]) +FMTCOMP([lit], +[%(lit string)%(lit 10)dnl +[%(lit (comp)]dnl +%(lit)], +[PRINT(lit("string")) +PRINT(lit("10")) +PRINT(lit(["(comp"])) +PRINT(lit("")) + 0001: sets reg, "string" + 0007: prints + 0008: sets reg, "10" + 0013: prints + 0014: sets reg, ["(comp"] + 0020: prints + 0021: sets reg, "" + 0026: prints + 0027: stop +]) + +FMTCOMP([num], +[%(num 10)%(num)], +[PRINT(num(10)) +PRINT(num(0)) + 0001: setn reg, 10 + 0004: printn + 0005: setn reg, 0 + 0008: printn + 0009: stop +]) + FMTCOMP([simple conditional], [%<{replied}-%>], [IF (COMPONENT.replied) THEN diff --git a/mh/tests/fmtfunc.at b/mh/tests/fmtfunc.at index a7d72bce5..5191e9e1f 100644 --- a/mh/tests/fmtfunc.at +++ b/mh/tests/fmtfunc.at @@ -345,7 +345,16 @@ foo@example.org 1 ]) -# FIXME: putstrf +FMTFUNC([putstrf], +[%(void(comp{Subject}))%-20(putstrf) +], +[From: foo@example.org +Subject: test message + +body +], +[ test message +]) FMTFUNC([putnum], [%(void(num 10))%(putnum) |