summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2008-09-16 12:10:02 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2008-09-16 12:10:02 (GMT)
commit99c453be5795d76e10b0a9cf1a2558367e538a1c (patch) (side-by-side diff)
tree7810d5bed75fe0e6e24a647d754c187a714e9819
parentd6f4adec375f9f50186248462f2774d9dc6ae59e (diff)
downloadmailfromd-99c453be5795d76e10b0a9cf1a2558367e538a1c.tar.gz
mailfromd-99c453be5795d76e10b0a9cf1a2558367e538a1c.tar.bz2
Implement functions with variable number of arguments and 'run' mode.
* mfd/symtab.c (function_install): Take additional argument. * mfd/lex.l: New tokens `vaptr', `...' and ARGX. * mfd/snarf.m4 (MF_VASTRING): New define. * mfd/gram.y: Handle functions with variable number of arguments, $(expr), and vaptr() expressions. This raises shift/reduce expectation to 29 conflicts. (parmtype_function): Return dtype_string for arguments from vararg list. (FUNC_HIDDEN_ARGS): Return 1 if f->varargs is set. (type_to_string): Handle pointer argument. (function_call): Handle function->varargs. (node_type): Handle node_type_argx, and node_type_vaptr. (cast_arg_list): Handle variable number of arguments. (cast_to): Handle dtype_pointer as dtype_number. * mfd/drivers.c (argx, vaptr): New node types. (code_type_call): Handle variable number of arguments. (code_cast): Handle dtype_pointer as dtype_number. * mfd/mailfromd.h (MAILFROMD_RUN): New define. (struct argx_node): New type. (struct node): Add argx_node. (struct function): New member `varargs'. (function_install): Add varargs. (mailfromd_run): New prototype. * mfd/prog.c (env_vaptr, env_get_reg): New functions. (env_make_frame0): New function. (instr_xmemstk): New instruction handler. * mfd/opcodes (XMEMSTK): New opcode. * mfd/prog.h (env_get_reg, env_vaptr): New protos. * mfd/main.c (options): New option `--run'. (main): Handle `run' mode. * mfd/Makefile.am (M4_FILES): Add bi_getopt.m4. * NEWS: Update. git-svn-id: file:///svnroot/mailfromd/trunk@1669 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--ChangeLog37
-rw-r--r--NEWS44
-rw-r--r--mfd/Makefile.am1
-rw-r--r--mfd/bi_getopt.m4129
-rw-r--r--mfd/drivers.c99
-rw-r--r--mfd/gram.y175
-rw-r--r--mfd/lex.l8
-rw-r--r--mfd/mailfromd.h12
-rw-r--r--mfd/main.c69
-rw-r--r--mfd/opcodes1
-rw-r--r--mfd/prog.c40
-rw-r--r--mfd/prog.h3
-rw-r--r--mfd/snarf.m44
-rw-r--r--mfd/symtab.c6
14 files changed, 573 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index db7d7df..3116aef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2008-09-16 Sergey Poznyakoff <gray@gnu.org.ua>
+
+ Implement functions with variable number of arguments and 'run' mode.
+
+ * mfd/symtab.c (function_install): Take additional argument.
+ * mfd/lex.l: New tokens `vaptr', `...' and ARGX.
+ * mfd/snarf.m4 (MF_VASTRING): New define.
+ * mfd/gram.y: Handle functions with variable number of arguments,
+ $(expr), and vaptr() expressions. This raises shift/reduce
+ expectation to 29 conflicts.
+ (parmtype_function): Return dtype_string for
+ arguments from vararg list.
+ (FUNC_HIDDEN_ARGS): Return 1 if f->varargs is set.
+ (type_to_string): Handle pointer argument.
+ (function_call): Handle function->varargs.
+ (node_type): Handle node_type_argx, and node_type_vaptr.
+ (cast_arg_list): Handle variable number of arguments.
+ (cast_to): Handle dtype_pointer as dtype_number.
+ * mfd/drivers.c (argx, vaptr): New node types.
+ (code_type_call): Handle variable number of arguments.
+ (code_cast): Handle dtype_pointer as dtype_number.
+ * mfd/mailfromd.h (MAILFROMD_RUN): New define.
+ (struct argx_node): New type.
+ (struct node): Add argx_node.
+ (struct function): New member `varargs'.
+ (function_install): Add varargs.
+ (mailfromd_run): New prototype.
+ * mfd/prog.c (env_vaptr, env_get_reg): New functions.
+ (env_make_frame0): New function.
+ (instr_xmemstk): New instruction handler.
+ * mfd/opcodes (XMEMSTK): New opcode.
+ * mfd/prog.h (env_get_reg, env_vaptr): New protos.
+ * mfd/main.c (options): New option `--run'.
+ (main): Handle `run' mode.
+ * mfd/Makefile.am (M4_FILES): Add bi_getopt.m4.
+ * NEWS: Update.
+
2008-09-15 Sergey Poznyakoff <gray@gnu.org.ua>
* tests/alias.at: New file.
diff --git a/NEWS b/NEWS
index 90975a0..d44443a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-Mailfromd NEWS -- history of user-visible changes. 2008-09-15
+Mailfromd NEWS -- history of user-visible changes. 2008-09-16
Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff
See the end of file for copying conditions.
@@ -19,6 +19,8 @@ It can be converted to a usual string using the `body_string' function
* Changes to MFL
+** Function aliases
+
Functions can have several names. Alternative function names, or
aliases, are introduced by `alias' statement, placed between the
function declaration and return type declaration, e.g.:
@@ -32,6 +34,30 @@ done
Any number of aliases is allowed.
+** Functions with variable number of arguments
+
+Ellipsis as the last argument in a list of formal arguments to a
+function indicates that this function takes a variable number of
+arguments. For example:
+
+ func foo (string a ; string b, ...)
+
+Actual arguments passed in a list of variable arguments have string
+data type. A special construct is provided to access these arguments:
+
+ $(expr)
+
+where expr is any valid MFL expression, evaluating to a number. This
+construct returns exprth argument from the variable argument list.
+
+FIXME: Document it.
+
+** getopt and varptr
+
+New function `getopt' is provided.
+
+FIXME: Document it.
+
* New MFL functions
** body_string
@@ -93,6 +119,20 @@ the end of the string. Thus:
substring("mailfrom",4,-1) => "from"
substring("mailfrom",4,-2) => "fro"
+* New operation mode.
+
+When given `--run' command line option, mailfromd looks for a function
+named `main' and invokes it, passing the rest of command line as its
+arguments. The function `main' must be declared as:
+
+ func main(...) returns number
+
+The return value from this function is used as the exit code.
+
+Command line arguments may be processed using `getopt' builtin function.
+
+FIXME: Document it.
+
* New programs:
** smap.
@@ -172,7 +212,7 @@ Quarantines the message using the given reason.
* mtasim
-New command line options `--usage' and `--group' allow to specify user
+New command line options `--user' and `--group' allow to specify user
name and a list of additional groups when the program is run with
`root' privileges.
diff --git a/mfd/Makefile.am b/mfd/Makefile.am
index 136ab52..829454b 100644
--- a/mfd/Makefile.am
+++ b/mfd/Makefile.am
@@ -23,6 +23,7 @@ M4_FILES=\
bi_body.m4\
bi_db.m4\
bi_dns.m4\
+ bi_getopt.m4\
bi_gettext.m4\
bi_header.m4\
bi_io.m4\
diff --git a/mfd/bi_getopt.m4 b/mfd/bi_getopt.m4
new file mode 100644
index 0000000..70a7e55
--- a/dev/null
+++ b/mfd/bi_getopt.m4
@@ -0,0 +1,129 @@
+/* This file is part of Mailfromd. -*- c -*-
+ Copyright (C) 2008 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+MF_VAR(optarg, STRING);
+MF_VAR(optind, NUMBER);
+
+MF_DEFUN_VARARGS(getopt, STRING, NUMBER argc, NUMBER argoff)
+{
+ int rc;
+ int long_idx;
+ static char xargc;
+ static char **xargv;
+ static struct option *option;
+ static char *optstr;
+ static char *loptstr;
+
+ if (argc) {
+ size_t i, n;
+ size_t serial = 256;
+
+ xargc = argc + 1;
+ xargv = xcalloc(xargc+1, sizeof(xargv[0]));
+ xargv[0] = script_file;
+ for (i = 0; i < argc; i++)
+ xargv[i+1] = MF_VASTRING(argoff + i);
+ xargv[i+1] = NULL;
+
+ n = MF_VA_COUNT();
+ if (n) {
+ size_t i, j;
+ size_t len;
+ char *str;
+ size_t size, lsize, lcnt;
+
+ MF_VA_START();
+
+ size = lsize = lcnt = 0;
+ for (i = 0; i < n; i++) {
+ MF_VA_ARG(i, STRING, str);
+ len = strcspn(str, ",");
+ size += len;
+ if (str[len]) {
+ lcnt++;
+ lsize += strlen(str + len);
+ }
+ }
+
+ optstr = xrealloc(optstr, size + 1);
+ loptstr = xrealloc(loptstr, lsize + 1);
+ option = xrealloc(option,
+ (lcnt + 1) * sizeof(option[0]));
+
+ size = 0;
+ lsize = 0;
+ for (i = j = 0; i < n; i++) {
+ size_t len;
+ int val;
+
+ MF_VA_ARG(i, STRING, str);
+ len = strcspn(str, ",");
+
+ if (len > 0) {
+ memcpy(optstr + size, str, len);
+ size += len;
+ val = str[0];
+ } else
+ val = serial++;
+
+ if (str[len]) {
+ option[j].name = loptstr + lsize;
+ strcpy(loptstr + lsize,
+ str + len + 1);
+ lsize += strlen(str + len) + 1;
+ if (str[1] == ':')
+ option[j].has_arg =
+ (str[2] == ':') ?
+ optional_argument :
+ required_argument;
+ else
+ option[j].has_arg =
+ no_argument;
+ option[j].flag = NULL;
+ option[j].val = val;
+ j++;
+ }
+ }
+ MF_VA_END();
+ optstr[size] = 0;
+ loptstr[lsize] = 0;
+ memset(&option[j], 0, sizeof option[0]);
+ } else
+ option = NULL;
+ }
+
+ optind = (int) MF_VAR_REF(optind);
+
+ rc = getopt_long(xargc, xargv, optstr, option, &long_idx);
+ if (rc == EOF)
+ MF_RETURN_STRING("");
+ MF_VAR_REF(optind, optind);
+ MF_VAR_SET_STRING(optarg, optarg);
+ if (rc < 256) {
+ char s[2];
+ s[0] = rc;
+ s[1] = 0;
+ MF_RETURN_STRING(s);
+ }
+ MF_RETURN_STRING(option[long_idx].name);
+}
+END
+
+MF_INIT
diff --git a/mfd/drivers.c b/mfd/drivers.c
index 2263a9e..3e5df6f 100644
--- a/mfd/drivers.c
+++ b/mfd/drivers.c
@@ -1197,16 +1197,105 @@ print_type_arg(NODE *node, int level)
}
void
-code_type_arg(NODE *node, struct locus **old_locus)
+code_argref(NODE *node)
{
- MARK_LOCUS();
code_op(opcode_memstk);
code_immediate((void*)0);
code_immediate((void*)(node->v.arg.number + 2));
+}
+
+void
+code_type_arg(NODE *node, struct locus **old_locus)
+{
+ MARK_LOCUS();
+ code_argref(node);
code_op(opcode_deref);
}
+/* type argx */
+
+void
+print_type_argx(NODE *node, int level)
+{
+ print_level(level);
+ printf("ARGX\n");
+ print_node(node->v.argx.node, level + 1);
+}
+
+void
+code_argxref(NODE *node)
+{
+ code_op(opcode_push);
+ code_immediate((void*)0);
+ code_node(node->v.argx.node);
+
+ code_op(opcode_push);
+ code_immediate((void*)(node->v.argx.nargs + 2));
+ code_op(opcode_add);
+
+ code_op(opcode_xmemstk);
+}
+
+void
+code_type_argx(NODE *node, struct locus **old_locus)
+{
+ MARK_LOCUS();
+ code_argxref(node);
+ code_op(opcode_deref);
+}
+
+void
+optimize_type_argx(NODE *node)
+{
+ NODE *argx = node->v.argx.node;
+ optimize(argx);
+ if (argx->type == node_type_number) {
+ node->type = node_type_arg;
+ node->v.arg.number = node->v.argx.nargs + 2;
+ }
+}
+
+
+/* type vaptr */
+void
+print_type_vaptr(NODE *node, int level)
+{
+ print_level(level);
+ printf("VAPTR\n");
+ print_node(node->v.node, level + 1);
+}
+
+void
+code_type_vaptr(NODE *node, struct locus **old_locus)
+{
+ NODE *arg = node->v.node;
+ MARK_LOCUS();
+ switch (arg->type) {
+ case node_type_variable:
+ code_memref(arg);
+ break;
+
+ case node_type_arg:
+ code_argref(arg);
+ break;
+
+ case node_type_argx:
+ code_argxref(arg);
+ break;
+
+ default:
+ abort();
+ }
+}
+
+void
+optimize_type_vaptr(NODE *node)
+{
+ optimize(node->v.node);
+}
+
+
char *
regex_flags_to_string(int flags, char *buf, size_t size)
@@ -1526,7 +1615,7 @@ code_type_call(NODE *node, struct locus **old_locus)
struct function *func = node->v.call.func;
int i;
- if (func->optcount) {
+ if (func->optcount || func->varargs) {
int j;
/* Count actual arguments */
@@ -2161,12 +2250,10 @@ code_cast(struct locus *locus, data_type_t fromtype, data_type_t totype)
break;
case dtype_number:
+ case dtype_pointer:
code_op(opcode_ntos);
break;
- case dtype_pointer:
- parse_error_locus(locus,
- _("Casts from pointer are not supported"));
}
return 0;
}
diff --git a/mfd/gram.y b/mfd/gram.y
index 30b904a..2ec203a 100644
--- a/mfd/gram.y
+++ b/mfd/gram.y
@@ -172,6 +172,8 @@ parmcount_function()
static data_type_t
parmtype_function(int n)
{
+ if (func->varargs && n > func->parmcount)
+ return dtype_string;
return func->parmtype[n-1];
}
@@ -187,7 +189,7 @@ struct parminfo {
#define PARMCOUNT() parminfo[inner_context].parmcount()
#define PARMTYPE(n) parminfo[inner_context].parmtype(n)
-#define FUNC_HIDDEN_ARGS(f) ((f)->optcount ? 1 : 0)
+#define FUNC_HIDDEN_ARGS(f) (((f)->optcount || (f)->varargs) ? 1 : 0)
/* Loop stack */
@@ -214,6 +216,8 @@ type_to_string(data_type_t t)
return "string";
case dtype_unspecified:
return "unspecified";
+ case dtype_pointer:
+ return "pointer";
default:
abort();
}
@@ -294,7 +298,7 @@ _create_alias(void *item, void *data)
%}
%error-verbose
-%expect 27
+%expect 29
%union {
struct literal *literal;
@@ -326,6 +330,7 @@ _create_alias(void *item, void *data)
struct parmtype *head, *tail;
size_t count;
size_t optcount;
+ int varargs;
} parmlist;
enum lexical_context tie_in;
struct function *function;
@@ -353,7 +358,7 @@ _create_alias(void *item, void *data)
%token <locus> MXMATCHES MXFNMATCHES
%token <locus> WHEN PASS SET CATCH THROW KW_ECHO RETURNS RETURN FUNC
%token <locus> SWITCH CASE DEFAULT CONST
-%token <locus> FOR LOOP WHILE BREAK NEXT ARGCOUNT ALIAS
+%token <locus> FOR LOOP WHILE BREAK NEXT ARGCOUNT ALIAS DOTS ARGX VAPTR
%token <literal> STRING CODE XCODE
%token <literal> SYMBOL IDENTIFIER
%token <number> ARG NUMBER BACKREF
@@ -379,7 +384,7 @@ _create_alias(void *item, void *data)
%left BUILTIN FUNCTION FUNCTION_P BUILTIN_P
%type <node> decl stmt condition action sendmail_action header_action
- if_cond else_cond on_cond atom
+ if_cond else_cond on_cond atom argref paren_argref
funcall proccall expr common_expr simp_expr atom_expr
asgn catch throw return case_cond autodcl constdecl
loopstmt opt_while jumpstmt
@@ -395,7 +400,7 @@ _create_alias(void *item, void *data)
%type <state> state_ident
%type <matchtype> matches fnmatches
%type <type> retdecl
-%type <parmlist> parmlist parmdecl
+%type <parmlist> params parmlist fparmlist parmdecl
%type <parm> parm
%type <function> fundecl
%type <value> value
@@ -638,6 +643,7 @@ fundecl : IDENTIFIER '(' parmdecl ')' aliasdecl retdecl
$$ = func = function_install($1->text,
$3.count, $3.optcount,
+ $3.varargs,
ptypes, $6,
get_locus());
if ($5) {
@@ -651,12 +657,22 @@ fundecl : IDENTIFIER '(' parmdecl ')' aliasdecl retdecl
parmdecl : /* empty */
{
$$.count = $$.optcount = 0;
+ $$.varargs = 0;
}
- | parmlist
- | parmlist ';' parmlist
+ | params
+ ;
+
+params : fparmlist
+ | DOTS
+ {
+ $$.count = $$.optcount = 0;
+ $$.varargs = 1;
+ }
+ | parmlist ';' fparmlist
{
$1.count += $3.count;
$1.optcount = $3.count;
+ $1.varargs = $3.varargs;
$1.tail->next = $3.head;
$1.tail = $3.tail;
$$ = $1;
@@ -666,6 +682,7 @@ parmdecl : /* empty */
parmlist : parm
{
$$.count = 1;
+ $$.varargs = 0;
$$.head = $$.tail = $1;
}
| parmlist ',' parm
@@ -677,6 +694,14 @@ parmlist : parm
}
;
+fparmlist : parmlist
+ | parmlist ',' DOTS
+ {
+ $1.varargs = 1;
+ $$ = $1;
+ }
+ ;
+
parm : TYPE IDENTIFIER
{
if (!vardecl($2->text, $1, storage_param, NULL))
@@ -831,7 +856,7 @@ action : sendmail_action
if (inner_context == context_handler) {
if (state_tag == smtp_state_begin)
parse_error(_("Sendmail action is not "
- "allowed in begin block"));
+ "allowed in begin block"));
else if (state_tag == smtp_state_end)
parse_error(_("Sendmail action is not "
"allowed in end block"));
@@ -1489,26 +1514,11 @@ atom : SYMBOL
$$ = alloc_node(node_type_backref, get_locus());
$$->v.number = $1;
}
- | variable
- {
- $$ = alloc_node(node_type_variable, get_locus());
- $$->v.var_ref.variable = $1;
- $$->v.var_ref.nframes = catch_nesting;
- }
- | ARG
- {
- if ($1 > PARMCOUNT())
- parse_error(_("Argument number too high"));
- $$ = alloc_node(node_type_arg, get_locus());
- $$->v.arg.data_type = PARMTYPE($1);
- $$->v.arg.number = $1;
- if (inner_context == context_function)
- $$->v.arg.number += FUNC_HIDDEN_ARGS(func);
- }
+ | argref
| ARGCOUNT
{
if (outer_context == context_function) {
- if (func->optcount) {
+ if (func->optcount || func->varargs) {
$$ = alloc_node(node_type_arg, &$1);
$$->v.arg.data_type = dtype_number;
$$->v.arg.number = 1;
@@ -1533,7 +1543,63 @@ atom : SYMBOL
$$->v.var_ref.variable = var;
$$->v.var_ref.nframes = catch_nesting;
}
- ;
+ | VAPTR paren_argref
+ {
+ $$ = alloc_node(node_type_vaptr, get_locus());
+ $$->v.node = $2;
+ }
+ ;
+
+argref : variable
+ {
+ $$ = alloc_node(node_type_variable, get_locus());
+ $$->v.var_ref.variable = $1;
+ $$->v.var_ref.nframes = catch_nesting;
+ }
+ | ARG
+ {
+ if (inner_context == context_function
+ && func->varargs)
+ ;
+ else if ($1 > PARMCOUNT())
+ parse_error(_("Argument number too high"));
+ $$ = alloc_node(node_type_arg, get_locus());
+ $$->v.arg.data_type = PARMTYPE($1);
+ $$->v.arg.number = $1;
+ if (inner_context == context_function)
+ $$->v.arg.number += FUNC_HIDDEN_ARGS(func);
+ }
+ | ARGX '(' expr ')'
+ {
+ if (outer_context == context_function) {
+ if (func->varargs) {
+ $$ = alloc_node(node_type_argx, &$1);
+ $$->v.argx.nargs = PARMCOUNT() +
+ FUNC_HIDDEN_ARGS(func);
+ $$->v.argx.node = $3;
+ } else {
+ $$ = alloc_node(node_type_noop, &$1);
+ parse_error(_("$(expr) is allowed only "
+ "in a function with "
+ "variable number of "
+ "arguments"));
+ }
+ } else {
+ $$ = alloc_node(node_type_noop, &$1);
+ parse_error(_("$(expr) is allowed only "
+ "in a function with "
+ "variable number of "
+ "arguments"));
+ }
+ }
+ ;
+
+paren_argref: argref
+ | '(' argref ')'
+ {
+ $$ = $2;
+ }
+ ;
funcall : BUILTIN '(' arglist ')'
{
@@ -2970,6 +3036,36 @@ mailfromd_test(int argc, char **argv)
}
void
+mailfromd_run(prog_counter_t entry_point, int argc, char **argv)
+{
+ int rc, i;
+ mu_assoc_t dict = NULL;
+ eval_environ_t env;
+ sfsistat status;
+
+ dict_init(&dict);
+ env = create_environment(NULL,
+ dbg_dict_getsym, dbg_setreply, dbg_msgmod,
+ dict);
+
+ env_init(env);
+
+ env_push_number(env, 0);
+
+ for (i = argc - 1; i >= 0; i--)
+ env_push_string(env, argv[i]);
+ env_push_number(env, argc);
+
+ env_make_frame0(env);
+ rc = eval_environment(env, entry_point);
+ env_leave_frame(env, 0);
+ env_final_gc(env);
+ rc = (int) env_get_reg(env);
+ destroy_environment(env);
+ exit(rc);
+}
+
+void
set_poll_arg(struct poll_data *poll, int kw, NODE *expr)
{
switch (kw) {
@@ -3236,7 +3332,7 @@ create_on_node(NODE *sel, struct case_stmt *cases)
catch_node->next = np;
- fp = function_install(fname, argc, 0, ptypes,
+ fp = function_install(fname, argc, 0, 0, ptypes,
rettype,
get_locus());
fp->exmask = mask;
@@ -3269,7 +3365,7 @@ function_call(struct function *function, size_t count, NODE *subtree)
if (count < function->parmcount - function->optcount) {
parse_error(_("Too few arguments in call to `%s'"),
function->name);
- } else if (count > function->parmcount) {
+ } else if (count > function->parmcount && !function->varargs) {
parse_error(_("Too many arguments in call to `%s'"),
function->name);
} else {
@@ -3314,6 +3410,9 @@ node_type(NODE *node)
case node_type_arg:
return node->v.arg.data_type;
+ case node_type_argx:
+ return dtype_string;
+
case node_type_call:
return node->v.call.func->rettype;
@@ -3330,6 +3429,9 @@ node_type(NODE *node)
case node_type_offset:
return dtype_number;
+
+ case node_type_vaptr:
+ return dtype_number;
case node_type_result:
case node_type_header:
@@ -3368,7 +3470,8 @@ cast_to(data_type_t type, NODE *node)
case dtype_pointer:
if (type == ntype)
return node;
- /* FALL THROUGH */
+ break;
+
case dtype_unspecified:
parse_error(_("Cannot convert %s to %s"), type_to_string(ntype),
type_to_string(type));
@@ -3389,9 +3492,18 @@ cast_arg_list(NODE *args, size_t parmc, data_type_t *parmtype)
{
NODE *head = NULL, *tail = NULL;
- while (args && parmc--) {
+ while (args) {
NODE *next = args->next;
- NODE *p = cast_to(*parmtype, args);
+ NODE *p;
+ data_type_t type;
+
+ if (parmc) {
+ type = *parmtype++;
+ parmc--;
+ } else
+ type = dtype_string;
+
+ p = cast_to(type, args);
if (head)
tail->next = p;
@@ -3399,7 +3511,6 @@ cast_arg_list(NODE *args, size_t parmc, data_type_t *parmtype)
head = p;
tail = p;
args = next;
- parmtype++;
}
return head;
}
diff --git a/mfd/lex.l b/mfd/lex.l
index 30203ac..4db65f1 100644
--- a/mfd/lex.l
+++ b/mfd/lex.l
@@ -267,6 +267,7 @@ pass return keyword(PASS);
begin return keyword(KW_BEGIN);
end return keyword(KW_END);
alias return keyword(ALIAS);
+vaptr return keyword(VAPTR);
{ICONST} { return builtin_const(yytext); }
<ONBLOCK>poll return keyword(POLL);
@@ -288,8 +289,10 @@ alias return keyword(ALIAS);
<INITIAL,ONBLOCK,ML,CML,STR>\$# {
return ARGCOUNT;
}
-<INITIAL,ONBLOCK,ML,CML,STR>\${P} {
- yylval.number = strtol(yytext + 1, NULL, 0); return ARG; }
+<INITIAL,ONBLOCK,ML,CML,STR>\${P} {
+ yylval.number = strtol(yytext + 1, NULL, 0);
+ return ARG; }
+<INITIAL,ONBLOCK>\$/"(" { return keyword(ARGX); }
/* Sendmail variables */
<INITIAL,ONBLOCK,ML,CML,STR>\${IDENT} {
if (yyleng == 2)
@@ -573,6 +576,7 @@ alias return keyword(ALIAS);
"|" return keyword(LOGOR);
"^" return keyword(LOGXOR);
"~" return keyword(LOGNOT);
+"..." return keyword(DOTS);
. return yytext[0];
%%
diff --git a/mfd/mailfromd.h b/mfd/mailfromd.h
index 5e257ca..0672cde 100644
--- a/mfd/mailfromd.h
+++ b/mfd/mailfromd.h
@@ -179,6 +179,7 @@ void disable_prog_trace(const char *modlist);
#define MAILFROMD_EXPIRE 4
#define MAILFROMD_COMPACT 5
#define MAILFROMD_SHOW_DEFAULTS 6
+#define MAILFROMD_RUN 7
extern char *script_file;
extern char *ext_pp;
@@ -442,6 +443,10 @@ struct loop_node {
NODE *body;
};
+struct argx_node {
+ int nargs;
+ NODE *node;
+};
#include "node-type.h"
/* Parse tree node */
@@ -475,6 +480,7 @@ struct node {
struct regcomp_data regcomp_data;
struct sym_regex *regex;
struct loop_node loop;
+ struct argx_node argx;
} v;
};
@@ -516,6 +522,8 @@ struct function { /* User-defined function */
be used */
size_t parmcount; /* Number of parameters */
size_t optcount; /* Number of optional parameters */
+ int varargs; /* 1 if function takes variable number of
+ arguments */
data_type_t *parmtype; /* Parameter types */
data_type_t rettype; /* Return type */
};
@@ -614,7 +622,7 @@ void defer_initialize_variable(char *arg, char *val);
int variable_or_constant_lookup(const char *name, void **dptr);
struct function *function_install(const char *name,
- size_t parmcnt, size_t optcnt,
+ size_t parmcnt, size_t optcnt, int varargs,
data_type_t *parmtypes,
data_type_t rettype,
const struct locus *locus);
@@ -760,6 +768,7 @@ void env_push_string(eval_environ_t env, char *arg);
void env_push_number(eval_environ_t env, long arg);
void env_push_pointer(eval_environ_t env, void *arg);
void env_make_frame(eval_environ_t env);
+void env_make_frame0(eval_environ_t env);
void env_leave_frame(eval_environ_t env, int nargs);
int env_set_variable(eval_environ_t env, char *ident, char *value);
int eval_environment(eval_environ_t env, prog_counter_t pc);
@@ -790,6 +799,7 @@ void mailfromd_daemon(void);
void save_cmdline(int argc, char **argv);
void mailfromd_test(int argc, char **argv);
+void mailfromd_run(prog_counter_t entry, int argc, char **argv);
int set_option(char *name, char *value, int override);
int sendmail_mlreply(SMFICTX * ctx, const char *rcode, const char *xcode,
diff --git a/mfd/main.c b/mfd/main.c
index 98015a4..284723b 100644
--- a/mfd/main.c
+++ b/mfd/main.c
@@ -128,6 +128,8 @@ mu_acl_t mailfromd_acl;
/* Umask for creating new files */
mode_t mailfromd_umask = 0017;
+char *main_function_name = "main";
+
/* Preprocessor helper function */
static void
@@ -925,6 +927,7 @@ enum mailfromd_option {
OPTION_POSTMASTER_EMAIL,
OPTION_PREDICT_NEXT,
OPTION_PREPROCESSOR,
+ OPTION_RUN,
OPTION_SHOW_DEFAULTS,
OPTION_SINGLE_PROCESS,
OPTION_STACK_TRACE,
@@ -952,6 +955,8 @@ static struct argp_option options[] = {
N_("Compact the database"), GRP+1 },
{ "test", 't', N_("HANDLER"), OPTION_ARG_OPTIONAL,
N_("Run in test mode"), GRP+1 },
+ { "run", OPTION_RUN, NULL, OPTION_ARG_OPTIONAL,
+ N_("Run script"), GRP+1 },
{ "lint", OPTION_LINT, NULL, 0,
N_("Check syntax and exit"), GRP+1 },
{ "syntax-check", 0, NULL, OPTION_ALIAS, NULL, GRP+1 },
@@ -1226,6 +1231,14 @@ parse_opt (int key, char *arg, struct argp_state *state)
force_remove = 1;
break;
+ case OPTION_RUN:
+ mode = MAILFROMD_RUN;
+ if (arg)
+ main_function_name = arg;
+ log_to_stderr = 1;
+ need_config = 1;
+ break;
+
case 'O':
if (!arg)
optimization_level = 1;
@@ -1984,13 +1997,28 @@ version(FILE *stream, struct argp_state *state)
{
mailfromd_version("mailfromd", stream);
}
-
+
+static int
+argpflag(int argc, char **argv)
+{
+ int i;
+ int flag = 0;
+ for (i = 0; i < argc; i++)
+ if (strncmp(argv[i], "--run", 5) == 0
+ && (argv[i][5] == 0 || argv[i][5] == '=')) {
+ flag = ARGP_IN_ORDER;
+ break;
+ }
+ return flag;
+}
+
int
main(int argc, char **argv)
{
int rc;
int index;
-
+ prog_counter_t entry_point;
+
mf_init_nls ();
MU_AUTH_REGISTER_ALL_MODULES();
@@ -2015,10 +2043,10 @@ main(int argc, char **argv)
mu_acl_cfg_init ();
mu_argp_init(program_version, "<" PACKAGE_BUGREPORT ">");
- rc = mu_app_init(&argp, capa, mf_cfg_param, argc, argv, 0, &index,
- NULL);
+ rc = mu_app_init(&argp, capa, mf_cfg_param, argc, argv,
+ argpflag(argc, argv), &index, NULL);
if (rc)
- exit (EX_CONFIG);
+ exit(EX_CONFIG);
alloc_ext_pp();
@@ -2032,9 +2060,11 @@ main(int argc, char **argv)
int i, n = -1;
for (i = 0; i < argc; i++) {
if (strchr(argv[i], '=') == 0) {
- if (n == -1)
+ if (n == -1) {
n = i;
- else {
+ if (mode == MAILFROMD_RUN)
+ break;
+ } else {
mu_error(_("Script file "
"specified twice "
"(%s and %s)"),
@@ -2083,6 +2113,28 @@ main(int argc, char **argv)
|| yy_flex_debug || script_ydebug)
exit(EX_OK);
+ if (mode == MAILFROMD_RUN) {
+ struct function *fun = function_lookup(main_function_name);
+ if (!fun) {
+ mu_error(_("Function %s is not defined"),
+ main_function_name);
+ exit(EX_CONFIG);
+ }
+
+ if (fun->parmcount || !fun->varargs) {
+ mu_error(_("Function %s must take variable number of "
+ "arguments"),
+ main_function_name);
+ exit(EX_CONFIG);
+ }
+ if (fun->rettype != dtype_number) {
+ mu_error(_("Function %s must return number"),
+ main_function_name);
+ exit(EX_CONFIG);
+ }
+ entry_point = fun->entry;
+ }
+
free_symbols();
free_string_space();
@@ -2118,6 +2170,9 @@ main(int argc, char **argv)
case MAILFROMD_SHOW_DEFAULTS:
mailfromd_show_defaults();
break;
+
+ case MAILFROMD_RUN:
+ mailfromd_run(entry_point, argc, argv);
}
exit(EX_OK);
diff --git a/mfd/opcodes b/mfd/opcodes
index d6a8f5b..cee68d4 100644
--- a/mfd/opcodes
+++ b/mfd/opcodes
@@ -74,6 +74,7 @@ LOGNOT NULL 0
CONCAT NULL 0
MEMSTK dump_memstk 2
+XMEMSTK NULL 0
DEREF NULL 0
ASGN NULL 0
BUILTIN dump_builtin 2
diff --git a/mfd/prog.c b/mfd/prog.c
index 6624f41..8420a91 100644
--- a/mfd/prog.c
+++ b/mfd/prog.c
@@ -241,7 +241,7 @@ struct eval_environ {
prog_counter_t pc; /* Program counter */
prog_counter_t tos; /* Top of stack:
- toh <= tos <= datasize + stack_size */
+ toh <= tos < datasize + stack_size */
prog_counter_t toh; /* Top of heap:
datasize <= toh <= tos */
@@ -316,6 +316,12 @@ env_base(eval_environ_t env, size_t frame)
return base;
}
+char *
+env_vaptr(eval_environ_t env, size_t off)
+{
+ return env->dataseg + (size_t) env->dataseg[off];
+}
+
void
env_var_inc(eval_environ_t env, size_t off)
{
@@ -334,14 +340,20 @@ env_get_stream(eval_environ_t env)
return env->stream;
}
+STKVAL
+env_get_reg(eval_environ_t env)
+{
+ return env->reg;
+}
+
/* A call to expand_dataseg (see below) invalidates any C variables that
pointed to the dataseg before the call. To avoid dereferencing invalid
memory pointers, addresses of such C variables are stored in env->auto_ptr
using env_register_auto (it is done by get_string_arg). When
expand_dataseg is called, it calls env_fixup_autos and passes it the
- offset of new dataseg from old one. env_fixup_autos adds this value to
- every address in auto_ptr, thereby fixing them.
+ offset of the new dataseg from the old one. Env_fixup_autos adds this
+ value to every address in auto_ptr, thereby fixing them.
The auto_ptr array is cleared (by calling env_unregister_autos) after
executing each instruction (see eval_environment).
@@ -724,6 +736,20 @@ dump_memstk(prog_counter_t i)
}
void
+instr_xmemstk(eval_environ_t env)
+{
+ size_t frame = (size_t) get_arg(env, 1);
+ long off = (long) get_arg(env, 0);
+ size_t val = env_base(env, frame) + off;
+ adjust_stack(env, 2);
+ if (PROG_TRACE_ENGINE)
+ prog_trace(env, "XMEMSTK %lu(%ld)=%lu",
+ (unsigned long) frame, off,
+ (unsigned long) val);
+ push(env, (STKVAL) val);
+}
+
+void
instr_deref(eval_environ_t env)
{
size_t off = (size_t) get_arg(env, 0);
@@ -1865,6 +1891,14 @@ env_init(eval_environ_t env)
}
void
+env_make_frame0(eval_environ_t env)
+{
+ push(env, (STKVAL) 0);
+ push(env, (STKVAL) (env->base - env->tos));
+ env->base = env->tos;
+}
+
+void
env_make_frame(eval_environ_t env)
{
push(env, (STKVAL) (env->pc + 1));
diff --git a/mfd/prog.h b/mfd/prog.h
index 11f2fda..d3ae879 100644
--- a/mfd/prog.h
+++ b/mfd/prog.h
@@ -53,6 +53,9 @@ void env_var_inc(eval_environ_t env, size_t off);
char *env_dict_getsym(eval_environ_t env, char *string);
char *env_dict_install(eval_environ_t env, char *key, char *value);
const struct locus *env_get_locus(eval_environ_t env);
+STKVAL env_get_reg(eval_environ_t env);
+char *env_vaptr(eval_environ_t env, size_t off);
+
void *env_get_builtin_priv(eval_environ_t env, int id);
int builtin_priv_register(void *(*init)(void), void (*destroy)(void*));
diff --git a/mfd/snarf.m4 b/mfd/snarf.m4
index b158161..51dd840 100644
--- a/mfd/snarf.m4
+++ b/mfd/snarf.m4
@@ -533,6 +533,10 @@ env_get_builtin_priv(m4_ifelse($1,,env,$1),__MF_PRIV_ID__)>],m4_dnl
m4_define([<__mf_error_code>],1)
>])>])
+/* MF_VASTRING(off)
+ */
+m4_define([<MF_VASTRING>],[<env_vaptr(env, $1)>])
+
/* MF_THROW(exception, ...)
*/
m4_define([<MF_THROW>],[<m4_dnl
diff --git a/mfd/symtab.c b/mfd/symtab.c
index 8fd5b8b..537dbed 100644
--- a/mfd/symtab.c
+++ b/mfd/symtab.c
@@ -430,7 +430,7 @@ variable_or_constant_lookup(const char *name, void **dptr)
#define SYM_FUNCTION_MAP (SYM_BITS|SYM_MASK(SYM_FUNC)|SYM_MASK(SYM_ALIAS))
struct function *
-function_install(const char *name, size_t parmcnt, size_t optcnt,
+function_install(const char *name, size_t parmcnt, size_t optcnt, int varargs,
data_type_t *parmtypes, data_type_t rettype,
const struct locus *locus)
{
@@ -467,6 +467,7 @@ function_install(const char *name, size_t parmcnt, size_t optcnt,
fp->entry = 0;
fp->parmcount = parmcnt;
fp->optcount = optcnt;
+ fp->varargs = varargs;
fp->parmtype = parmtypes;
fp->rettype = rettype;
fp->exmask = 0;
@@ -492,7 +493,8 @@ function_lookup(const char *name)
void
-install_alias(const char *name, struct function *fun, const struct locus *locus)
+install_alias(const char *name, struct function *fun,
+ const struct locus *locus)
{
struct symtab *sp = lookup_or_install(SYM_FUNCTION_MAP, name, 1);

Return to:

Send suggestions and report system problems to the System administrator.