summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2017-07-01 23:12:26 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2017-07-01 23:12:26 +0300
commit9671c7d62638d1ab02261717863a7e9864b67cbd (patch)
tree628ced411bfabf32cb3467c0571e8bf169ea140c
parent0f5bd212a2cbb8a35c9d9b45a1ab66bb4d585948 (diff)
downloadmailutils-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.y152
-rw-r--r--mh/mh_format.c12
-rw-r--r--mh/mh_format.h14
-rw-r--r--mh/tests/fmtcomp.at52
-rw-r--r--mh/tests/fmtfunc.at11
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)

Return to:

Send suggestions and report system problems to the System administrator.