summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2017-07-01 20:12:26 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2017-07-01 20:12:26 (GMT)
commit9671c7d62638d1ab02261717863a7e9864b67cbd (patch) (side-by-side diff)
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
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--mh/mh_fmtgram.y248
-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, 234 insertions, 103 deletions
diff --git a/mh/mh_fmtgram.y b/mh/mh_fmtgram.y
index 4a51d48..67560d3 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,67 +217,99 @@ component : COMPONENT
funcall : function argument EOFN
{
+ struct node *arg;
+
ctx_pop ();
- if ($1->flags & MHA_VOID) /*FIXME*/
+
+ arg = $2;
+ if ($1->argtype == mhtype_none)
{
- $2->noprint = 1;
- $$ = $2;
+ if (arg)
+ {
+ yyerror ("function doesn't take arguments");
+ YYABORT;
+ }
}
- else
+ else if (arg == NULL)
{
- struct node *arg = $2;
- if ($1->argtype == mhtype_none)
+ if ($1->flags & MHA_OPTARG_NIL)
{
- if (arg)
+ switch ($1->argtype)
{
- yyerror ("function doesn't take arguments");
- YYABORT;
+ case mhtype_str:
+ arg = new_node (fmtnode_literal, mhtype_str);
+ arg->v.str = "";
+ break;
+
+ case mhtype_num:
+ arg = new_node (fmtnode_number, mhtype_num);
+ arg->v.num = 0;
+ break;
+
+ default:
+ abort ();
}
}
- else if (arg == NULL)
+ else if ($1->flags & MHA_OPTARG)
{
- if ($1->flags & MHA_OPTARG_NIL)
+ /* ok - ignore */;
+ }
+ else
+ {
+ yyerror ("required argument missing");
+ YYABORT;
+ }
+ }
+ else if ($1->flags & MHA_LITERAL)
+ {
+ switch ($1->argtype)
+ {
+ case mhtype_num:
+ if (arg->nodetype == fmtnode_number)
+ /* ok */;
+ else
{
- switch ($1->argtype)
- {
- case mhtype_str:
- arg = new_node (fmtnode_literal, mhtype_str);
- arg->v.str = "";
- break;
-
- case mhtype_num:
- arg = new_node (fmtnode_number, mhtype_num);
- arg->v.num = 0;
- break;
-
- default:
- abort ();
- }
+ yyerror ("argument must be a number");
+ YYABORT;
}
- else if ($1->flags & MHA_OPTARG)
+ break;
+
+ case mhtype_str:
+ if (arg->nodetype == fmtnode_literal)
+ /* ok */;
+ else if (arg->nodetype == fmtnode_number)
{
- /* ok - ignore */;
+ char *s;
+ mu_asprintf (&s, "%ld", arg->v.num);
+ arg->nodetype = fmtnode_literal;
+ arg->datatype = mhtype_str;
+ arg->v.str = s;
}
else
{
- yyerror ("required argument missing");
- YYABORT;
- }
- }
- else if ($1->flags & MHA_LITERAL)
- {
- if (!(arg->nodetype == fmtnode_literal
- || arg->nodetype == fmtnode_number))
- {
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,42 +846,58 @@ 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;
- while ((c = input ()) != ')')
+ mark ();
+
+ while ((c = input ()) != ')')
+ {
+ if (c == 0)
{
- if (c == 0)
- {
- return bogus ("expected ')'");
- }
+ return bogus ("expected ')'");
+ }
- if (c == '\\')
+ if (c == '\\')
+ {
+ if ((c = input ()) == 0)
{
- if ((c = input ()) == 0)
- {
- return bogus ("unexpected end of file");
- }
- mu_opool_append_char (tokpool, backslash (c));
+ return bogus ("unexpected end of file");
}
- else
- mu_opool_append_char (tokpool, c);
+ mu_opool_append_char (tokpool, backslash (c));
}
- mu_opool_append_char (tokpool, 0);
-
- yylval.arg.type = mhtype_str;
- yylval.arg.v.str = mu_opool_finish (tokpool, NULL);
- unput (c);
+ else
+ mu_opool_append_char (tokpool, c);
}
+ mu_opool_append_char (tokpool, 0);
+
+ 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 () != ')')
{
return bogus ("expected ')'");
@@ -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
- {
- struct node *np = new_node (fmtnode_typecast, type);
- np->v.arg = node;
- node = np;
+ break;
+
+ default:
+ {
+ 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)
@@ -1379,7 +1467,7 @@ emit_funcall (struct mh_format *fmt, mh_builtin_t *builtin, struct node *arg)
emit_instr (fmt, (mh_instr_t) (long) R_ARG);
emit_instr (fmt, (mh_instr_t) (long) R_REG);
}
-
+
emit_opcode (fmt, mhop_call);
emit_instr (fmt, (mh_instr_t) builtin->fun);
}
@@ -1539,7 +1627,5 @@ codegen (mh_format_t *fmtptr, int tree)
mu_opool_destroy (&tokpool);
}
}
-
-
-
+
diff --git a/mh/mh_format.c b/mh/mh_format.c
index 914a85b..1690630 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 3c90217..ce53715 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 253ecd9..ca93786 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 a7d72bc..5191e9e 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.