aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2008-09-16 12:10:02 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2008-09-16 12:10:02 +0000
commit99c453be5795d76e10b0a9cf1a2558367e538a1c (patch)
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
-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 db7d7df9..3116aef7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1 +1,38 @@
+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>
diff --git a/NEWS b/NEWS
index 90975a06..d44443ac 100644
--- a/NEWS
+++ b/NEWS
@@ -1,2 +1,2 @@
-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
@@ -21,2 +21,4 @@ It can be converted to a usual string using the `body_string' function
+** Function aliases
+
Functions can have several names. Alternative function names, or
@@ -34,2 +36,26 @@ 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
@@ -95,2 +121,16 @@ the end of the string. Thus:
+* 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:
@@ -174,3 +214,3 @@ Quarantines the message using the given reason.
-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
diff --git a/mfd/Makefile.am b/mfd/Makefile.am
index 136ab520..829454be 100644
--- a/mfd/Makefile.am
+++ b/mfd/Makefile.am
@@ -25,2 +25,3 @@ M4_FILES=\
bi_dns.m4\
+ bi_getopt.m4\
bi_gettext.m4\
diff --git a/mfd/bi_getopt.m4 b/mfd/bi_getopt.m4
new file mode 100644
index 00000000..70a7e555
--- /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 2263a9ed..3e5df6fb 100644
--- a/mfd/drivers.c
+++ b/mfd/drivers.c
@@ -1199,5 +1199,4 @@ 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);
@@ -1205,2 +1204,9 @@ code_type_arg(NODE *node, struct locus **old_locus)
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);
@@ -1209,2 +1215,85 @@ code_type_arg(NODE *node, struct locus **old_locus)
+/* 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);
+}
+
+
@@ -1528,3 +1617,3 @@ code_type_call(NODE *node, struct locus **old_locus)
- if (func->optcount) {
+ if (func->optcount || func->varargs) {
int j;
@@ -2163,2 +2252,3 @@ code_cast(struct locus *locus, data_type_t fromtype, data_type_t totype)
case dtype_number:
+ case dtype_pointer:
code_op(opcode_ntos);
@@ -2166,5 +2256,2 @@ code_cast(struct locus *locus, data_type_t fromtype, data_type_t totype)
- case dtype_pointer:
- parse_error_locus(locus,
- _("Casts from pointer are not supported"));
}
diff --git a/mfd/gram.y b/mfd/gram.y
index 30b904a0..2ec203a3 100644
--- a/mfd/gram.y
+++ b/mfd/gram.y
@@ -174,2 +174,4 @@ parmtype_function(int n)
{
+ if (func->varargs && n > func->parmcount)
+ return dtype_string;
return func->parmtype[n-1];
@@ -189,3 +191,3 @@ struct parminfo {
#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)
@@ -216,2 +218,4 @@ type_to_string(data_type_t t)
return "unspecified";
+ case dtype_pointer:
+ return "pointer";
default:
@@ -296,3 +300,3 @@ _create_alias(void *item, void *data)
%error-verbose
-%expect 27
+%expect 29
@@ -328,2 +332,3 @@ _create_alias(void *item, void *data)
size_t optcount;
+ int varargs;
} parmlist;
@@ -355,3 +360,3 @@ _create_alias(void *item, void *data)
%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
@@ -381,3 +386,3 @@ _create_alias(void *item, void *data)
%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
@@ -397,3 +402,3 @@ _create_alias(void *item, void *data)
%type <type> retdecl
-%type <parmlist> parmlist parmdecl
+%type <parmlist> params parmlist fparmlist parmdecl
%type <parm> parm
@@ -640,2 +645,3 @@ fundecl : IDENTIFIER '(' parmdecl ')' aliasdecl retdecl
$3.count, $3.optcount,
+ $3.varargs,
ptypes, $6,
@@ -653,5 +659,14 @@ parmdecl : /* empty */
$$.count = $$.optcount = 0;
+ $$.varargs = 0;
}
- | parmlist
- | parmlist ';' parmlist
+ | params
+ ;
+
+params : fparmlist
+ | DOTS
+ {
+ $$.count = $$.optcount = 0;
+ $$.varargs = 1;
+ }
+ | parmlist ';' fparmlist
{
@@ -659,2 +674,3 @@ parmdecl : /* empty */
$1.optcount = $3.count;
+ $1.varargs = $3.varargs;
$1.tail->next = $3.head;
@@ -668,2 +684,3 @@ parmlist : parm
$$.count = 1;
+ $$.varargs = 0;
$$.head = $$.tail = $1;
@@ -679,2 +696,10 @@ parmlist : parm
+fparmlist : parmlist
+ | parmlist ',' DOTS
+ {
+ $1.varargs = 1;
+ $$ = $1;
+ }
+ ;
+
parm : TYPE IDENTIFIER
@@ -833,3 +858,3 @@ action : sendmail_action
parse_error(_("Sendmail action is not "
- "allowed in begin block"));
+ "allowed in begin block"));
else if (state_tag == smtp_state_end)
@@ -1491,18 +1516,3 @@ atom : SYMBOL
}
- | 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
@@ -1510,3 +1520,3 @@ atom : SYMBOL
if (outer_context == context_function) {
- if (func->optcount) {
+ if (func->optcount || func->varargs) {
$$ = alloc_node(node_type_arg, &$1);
@@ -1535,3 +1545,59 @@ atom : SYMBOL
}
- ;
+ | 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;
+ }
+ ;
@@ -2972,2 +3038,32 @@ 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)
@@ -3238,3 +3334,3 @@ create_on_node(NODE *sel, struct case_stmt *cases)
- fp = function_install(fname, argc, 0, ptypes,
+ fp = function_install(fname, argc, 0, 0, ptypes,
rettype,
@@ -3271,3 +3367,3 @@ function_call(struct function *function, size_t count, NODE *subtree)
function->name);
- } else if (count > function->parmcount) {
+ } else if (count > function->parmcount && !function->varargs) {
parse_error(_("Too many arguments in call to `%s'"),
@@ -3316,2 +3412,5 @@ node_type(NODE *node)
+ case node_type_argx:
+ return dtype_string;
+
case node_type_call:
@@ -3332,2 +3431,5 @@ node_type(NODE *node)
return dtype_number;
+
+ case node_type_vaptr:
+ return dtype_number;
@@ -3370,3 +3472,4 @@ cast_to(data_type_t type, NODE *node)
return node;
- /* FALL THROUGH */
+ break;
+
case dtype_unspecified:
@@ -3391,5 +3494,14 @@ cast_arg_list(NODE *args, size_t parmc, data_type_t *parmtype)
- 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);
@@ -3401,3 +3513,2 @@ cast_arg_list(NODE *args, size_t parmc, data_type_t *parmtype)
args = next;
- parmtype++;
}
diff --git a/mfd/lex.l b/mfd/lex.l
index 30203ac0..4db65f10 100644
--- a/mfd/lex.l
+++ b/mfd/lex.l
@@ -269,2 +269,3 @@ end return keyword(KW_END);
alias return keyword(ALIAS);
+vaptr return keyword(VAPTR);
@@ -290,4 +291,6 @@ alias return keyword(ALIAS);
}
-<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 */
@@ -575,2 +578,3 @@ alias return keyword(ALIAS);
"~" return keyword(LOGNOT);
+"..." return keyword(DOTS);
. return yytext[0];
diff --git a/mfd/mailfromd.h b/mfd/mailfromd.h
index 5e257ca7..0672cde2 100644
--- a/mfd/mailfromd.h
+++ b/mfd/mailfromd.h
@@ -181,2 +181,3 @@ void disable_prog_trace(const char *modlist);
#define MAILFROMD_SHOW_DEFAULTS 6
+#define MAILFROMD_RUN 7
@@ -444,2 +445,6 @@ struct loop_node {
+struct argx_node {
+ int nargs;
+ NODE *node;
+};
#include "node-type.h"
@@ -477,2 +482,3 @@ struct node {
struct loop_node loop;
+ struct argx_node argx;
} v;
@@ -518,2 +524,4 @@ struct function { /* User-defined function */
size_t optcount; /* Number of optional parameters */
+ int varargs; /* 1 if function takes variable number of
+ arguments */
data_type_t *parmtype; /* Parameter types */
@@ -616,3 +624,3 @@ 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,
@@ -762,2 +770,3 @@ 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);
@@ -792,2 +801,3 @@ 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);
diff --git a/mfd/main.c b/mfd/main.c
index 98015a4d..284723bc 100644
--- a/mfd/main.c
+++ b/mfd/main.c
@@ -130,2 +130,4 @@ mode_t mailfromd_umask = 0017;
+char *main_function_name = "main";
+
@@ -927,2 +929,3 @@ enum mailfromd_option {
OPTION_PREPROCESSOR,
+ OPTION_RUN,
OPTION_SHOW_DEFAULTS,
@@ -954,2 +957,4 @@ static struct argp_option options[] = {
N_("Run in test mode"), GRP+1 },
+ { "run", OPTION_RUN, NULL, OPTION_ARG_OPTIONAL,
+ N_("Run script"), GRP+1 },
{ "lint", OPTION_LINT, NULL, 0,
@@ -1228,2 +1233,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
+ case OPTION_RUN:
+ mode = MAILFROMD_RUN;
+ if (arg)
+ main_function_name = arg;
+ log_to_stderr = 1;
+ need_config = 1;
+ break;
+
case 'O':
@@ -1986,3 +1999,17 @@ version(FILE *stream, struct argp_state *state)
}
-
+
+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
@@ -1992,3 +2019,4 @@ main(int argc, char **argv)
int index;
-
+ prog_counter_t entry_point;
+
mf_init_nls ();
@@ -2017,6 +2045,6 @@ main(int argc, char **argv)
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);
@@ -2034,5 +2062,7 @@ main(int argc, char **argv)
if (strchr(argv[i], '=') == 0) {
- if (n == -1)
+ if (n == -1) {
n = i;
- else {
+ if (mode == MAILFROMD_RUN)
+ break;
+ } else {
mu_error(_("Script file "
@@ -2085,2 +2115,24 @@ main(int argc, char **argv)
+ 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();
@@ -2120,2 +2172,5 @@ main(int argc, char **argv)
break;
+
+ case MAILFROMD_RUN:
+ mailfromd_run(entry_point, argc, argv);
}
diff --git a/mfd/opcodes b/mfd/opcodes
index d6a8f5bb..cee68d46 100644
--- a/mfd/opcodes
+++ b/mfd/opcodes
@@ -76,2 +76,3 @@ CONCAT NULL 0
MEMSTK dump_memstk 2
+XMEMSTK NULL 0
DEREF NULL 0
diff --git a/mfd/prog.c b/mfd/prog.c
index 6624f415..8420a918 100644
--- a/mfd/prog.c
+++ b/mfd/prog.c
@@ -243,3 +243,3 @@ struct eval_environ {
prog_counter_t tos; /* Top of stack:
- toh <= tos <= datasize + stack_size */
+ toh <= tos < datasize + stack_size */
prog_counter_t toh; /* Top of heap:
@@ -318,2 +318,8 @@ env_base(eval_environ_t env, size_t frame)
+char *
+env_vaptr(eval_environ_t env, size_t off)
+{
+ return env->dataseg + (size_t) env->dataseg[off];
+}
+
void
@@ -336,2 +342,8 @@ env_get_stream(eval_environ_t env)
+STKVAL
+env_get_reg(eval_environ_t env)
+{
+ return env->reg;
+}
+
@@ -342,4 +354,4 @@ env_get_stream(eval_environ_t env)
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.
@@ -726,2 +738,16 @@ 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)
@@ -1867,2 +1893,10 @@ 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)
diff --git a/mfd/prog.h b/mfd/prog.h
index 11f2fda9..d3ae879a 100644
--- a/mfd/prog.h
+++ b/mfd/prog.h
@@ -55,2 +55,5 @@ 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);
diff --git a/mfd/snarf.m4 b/mfd/snarf.m4
index b158161a..51dd840a 100644
--- a/mfd/snarf.m4
+++ b/mfd/snarf.m4
@@ -535,2 +535,6 @@ m4_define([<__mf_error_code>],1)
+/* MF_VASTRING(off)
+ */
+m4_define([<MF_VASTRING>],[<env_vaptr(env, $1)>])
+
/* MF_THROW(exception, ...)
diff --git a/mfd/symtab.c b/mfd/symtab.c
index 8fd5b8b4..537dbed4 100644
--- a/mfd/symtab.c
+++ b/mfd/symtab.c
@@ -432,3 +432,3 @@ variable_or_constant_lookup(const char *name, void **dptr)
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,
@@ -469,2 +469,3 @@ function_install(const char *name, size_t parmcnt, size_t optcnt,
fp->optcount = optcnt;
+ fp->varargs = varargs;
fp->parmtype = parmtypes;
@@ -494,3 +495,4 @@ 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)
{

Return to:

Send suggestions and report system problems to the System administrator.