diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-09-16 12:10:02 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-09-16 12:10:02 +0000 |
commit | 99c453be5795d76e10b0a9cf1a2558367e538a1c (patch) | |
tree | 7810d5bed75fe0e6e24a647d754c187a714e9819 | |
parent | d6f4adec375f9f50186248462f2774d9dc6ae59e (diff) | |
download | mailfromd-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-- | ChangeLog | 37 | ||||
-rw-r--r-- | NEWS | 44 | ||||
-rw-r--r-- | mfd/Makefile.am | 1 | ||||
-rw-r--r-- | mfd/bi_getopt.m4 | 129 | ||||
-rw-r--r-- | mfd/drivers.c | 99 | ||||
-rw-r--r-- | mfd/gram.y | 175 | ||||
-rw-r--r-- | mfd/lex.l | 8 | ||||
-rw-r--r-- | mfd/mailfromd.h | 12 | ||||
-rw-r--r-- | mfd/main.c | 69 | ||||
-rw-r--r-- | mfd/opcodes | 1 | ||||
-rw-r--r-- | mfd/prog.c | 40 | ||||
-rw-r--r-- | mfd/prog.h | 3 | ||||
-rw-r--r-- | mfd/snarf.m4 | 4 | ||||
-rw-r--r-- | mfd/symtab.c | 6 |
14 files changed, 573 insertions, 55 deletions
@@ -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> @@ -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")); } @@ -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++; } @@ -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); @@ -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 @@ -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) @@ -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) { |