aboutsummaryrefslogtreecommitdiff
path: root/mfd/prog.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2010-08-21 11:46:57 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2010-08-21 11:46:57 +0300
commita1718144344d2743713164adc1790ec1ac399d8c (patch)
treecd8b86e6b13f2877151eddcbf7fbb2f69260f0ca /mfd/prog.c
parente2f591b6cd344420023daa910c7435298fe376c9 (diff)
downloadmailfromd-a1718144344d2743713164adc1790ec1ac399d8c.tar.gz
mailfromd-a1718144344d2743713164adc1790ec1ac399d8c.tar.bz2
Rename mfd -> src
Diffstat (limited to 'mfd/prog.c')
-rw-r--r--mfd/prog.c2696
1 files changed, 0 insertions, 2696 deletions
diff --git a/mfd/prog.c b/mfd/prog.c
deleted file mode 100644
index 150f04d8..00000000
--- a/mfd/prog.c
+++ /dev/null
@@ -1,2696 +0,0 @@
-/* This file is part of Mailfromd.
- Copyright (C) 2006, 2007, 2008, 2009, 2010 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/>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <setjmp.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <assert.h>
-#include <fnmatch.h>
-#include <syslog.h>
-#include "mailfromd.h"
-#include "prog.h"
-#include "msg.h"
-#include "optab.h"
-#include "builtin.h"
-
-
-/* Code generation support */
-#define CODE_INITIAL 128
-#define CODE_INCREMENT 128
-
-static prog_counter_t pc, pmax;
-instr_t *prog;
-size_t stack_size = 4096;
-size_t stack_max_size = 0;
-size_t stack_expand_incr = 4096;
-enum stack_expand_policy stack_expand_policy = stack_expand_add;
-
-/* Data segment */
-STKVAL *dataseg;
-size_t datasize;
-size_t dvarsize;
-
-/* Table of relocatable entries in the data segment */
-size_t *dataseg_reloc;
-size_t dataseg_reloc_count;
-
-/* Regular expressions */
-struct rt_regex *regtab;
-size_t regcount;
-struct obstack regstk;
-
-/* Exceptions */
-size_t exception_count = mf_exception_count;
-
-
-void
-code_init()
-{
- pmax = CODE_INITIAL;
- prog = calloc(pmax, sizeof prog[0]);
- if (!prog) {
- mu_error(_("not enough memory"));
- exit(1);
- }
-}
-
-prog_counter_t
-code_get_counter()
-{
- return pc;
-}
-
-prog_counter_t
-code_reserve(size_t count)
-{
- prog_counter_t ret = pc;
- if (pc + count > pmax) {
- size_t incr = (pc + count - pmax + CODE_INCREMENT - 1)
- / CODE_INCREMENT;
- pmax += incr * CODE_INCREMENT;
- prog = realloc(prog, pmax*sizeof prog[0]);
- if (!prog) {
- mu_error(_("not enough memory"));
- exit(1);
- }
- }
- pc += count;
- return ret;
-}
-
-prog_counter_t
-code_instr(const instr_t ptr)
-{
- if (pc >= pmax) {
- pmax += CODE_INCREMENT;
- prog = realloc(prog, pmax*sizeof prog[0]);
- if (!prog) {
- mu_error(_("not enough memory"));
- exit(1);
- }
- }
- prog[pc] = ptr;
- return pc++;
-}
-
-prog_counter_t
-code_op(unsigned code)
-{
- return code_instr((instr_t)code);
-}
-
-prog_counter_t
-code_immediate(const void *ptr)
-{
- return code_instr(ptr);
-}
-
-prog_counter_t
-code_exmask(struct exmask *exmask)
-{
- return code_immediate((void*) exmask->off);
-}
-
-void
-code_put(prog_counter_t pos, void *ptr)
-{
- assert(pos < pmax);
- prog[pos] = (instr_t) ptr;
-}
-
-instr_t
-code_peek(prog_counter_t pos)
-{
- assert(pos < pmax);
- return prog[pos];
-}
-
-
-/* Regexps*/
-
-void
-register_regex(struct sym_regex *rp)
-{
- struct rt_regex r;
- if (regcount == 0)
- obstack_init(&regstk);
- r.compiled = 0; /* Will be compiled later */
- r.expr = rp->lit ? rp->lit->off : 0;
- r.regflags = rp->regflags;
- rp->index = regcount++;
- obstack_grow(&regstk, &r, sizeof r);
-}
-
-void
-finalize_regex()
-{
- if (regcount)
- regtab = obstack_finish(&regstk);
-}
-
-
-#define PROG_TRACE_ENGINE (builtin_module_trace(BUILTIN_IDX_prog))
-
-static void
-set_prog_trace(const char *modlist, int val)
-{
- while (1) {
- size_t len = strcspn(modlist, ",");
- if (len == 3 && memcmp(modlist, "all", 3) == 0)
- builtin_set_all_module_trace(val);
- else if (len == 4 && memcmp(modlist, "none", 4) == 0)
- builtin_set_all_module_trace(!val);
- else {
- if (len > 3 && memcmp (modlist, "no-", 3) == 0)
- builtin_set_module_trace(modlist+3, len-3,
- !val);
- else
- builtin_set_module_trace(modlist, len, val);
- }
- modlist += len;
- if (*modlist)
- modlist++;
- else
- break;
- }
-}
-
-void
-enable_prog_trace(const char *modlist)
-{
- set_prog_trace(modlist, 1);
-}
-
-void
-disable_prog_trace(const char *modlist)
-{
- set_prog_trace(modlist, 0);
-}
-
-/* ========================================================================
- Drzewa w górę, rzeki w dół.
-
- Jacek Kaczmarski.
- "Upadek Ikara"
- ======================================================================== */
-
-/* Run-time evaluation */
-
-/* Max. number of C locals to save in struct eval_environ for eventual fixups.
- See comment to env_fixup_autos, below. */
-#define MAX_AUTO_PTR 128
-
-#define ENVF_MSGMOD 0x01 /* message modofication instruction has been used */
-
-struct exception_context {
- prog_counter_t pc;
- prog_counter_t tos;
- prog_counter_t base;
-};
-
-#define TOS_INVARIANT(env,t) (datasize + (env)->stack_size - (t))
-
-struct eval_environ {
- prog_counter_t pc; /* Program counter */
-
- prog_counter_t tos; /* Top of stack:
- toh <= tos < datasize + stack_size */
- prog_counter_t toh; /* Top of heap:
- datasize <= toh <= tos */
-
- prog_counter_t base; /* Base pointer */
- STKVAL reg; /* General purpose register */
- STKVAL *dataseg; /* Data space */
- size_t stack_size; /* Size of allocated stack + heap */
-
- struct locus locus; /* Program locus corresponding to PC */
-
- /* Temporary heap space */
- size_t temp_start;
- size_t temp_size;
-
- STKVAL *auto_ptr[MAX_AUTO_PTR]; /* Pointers to C automatic variables
- referring to dataseg. */
- size_t numautos; /* Number of entries in auto_ptr. */
-
- /* Sendmail interaction data: */
- SMFICTX *ctx; /* Milter Context */
- void *data; /* MTA symbol table */
- /* methods to access the latter */
- const char *(*getsym)(void *data, const char *str);
- int (*setreply)(void *data, char *code, char *xcode, char *message);
- void (*msgmod)(void *data, struct msgmod_closure *c);
-
- int flags;
-
- /* Regular expression matching */
- regmatch_t *matches; /* Match map */
- size_t matchcount; /* Number of used entries in matches */
- size_t matchsize; /* Total number of entries in matches */
- char *string; /* Last matched string */
-
- mu_stream_t stream; /* Capture stream */
- size_t line_count; /* Number of lines in stream */
- int reposition; /* When !0, stream must be repositioned to
- its end before writing. */
-
- /* Non-local exits */
- struct exception_context *defcatch_ctx;
- struct exception_context *catch_ctx;
-
- /* Built-in private data */
- void **bi_priv_array;
-
- /* Exit information */
- sfsistat status; /* Program exit status */
- jmp_buf x_jmp; /* Return point for runtime errors */
- jmp_buf catch_jmp; /* Return point for throws */
-};
-
-void
-advance_pc(eval_environ_t env, long cnt)
-{
- env->pc += cnt;
-}
-
-void
-adjust_stack(eval_environ_t env, unsigned cnt)
-{
- env->tos += cnt;
-}
-
-void
-unroll_stack(eval_environ_t env, unsigned cnt)
-{
- env->tos -= cnt;
-}
-
-size_t
-env_base(eval_environ_t env, size_t frame)
-{
- size_t base = env->base;
- for (; frame; frame--)
- base = (size_t) env->dataseg[base + 1] + base + 1;
- return base;
-}
-
-char *
-env_vaptr(eval_environ_t env, size_t off)
-{
- return (char*)(env->dataseg + (size_t) env->dataseg[off]);
-}
-
-void
-env_var_inc(eval_environ_t env, size_t off)
-{
- ++*env_data_ref(env, off);
-}
-
-const struct locus *
-env_get_locus(eval_environ_t env)
-{
- return &env->locus;
-}
-
-const char *
-env_get_macro(eval_environ_t env, const char *symbol)
-{
- return env->getsym(env->data, symbol);
-}
-
-mu_stream_t
-env_get_stream(eval_environ_t env)
-{
- return env->stream;
-}
-
-STKVAL
-env_get_reg(eval_environ_t env)
-{
- return env->reg;
-}
-
-void
-env_reposition(eval_environ_t env)
-{
- env->reposition = 1;
-}
-
-
-/* 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 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).
- */
-void
-env_register_auto(eval_environ_t env, void *ptr)
-{
- if (env->numautos == MAX_AUTO_PTR)
- runtime_error(env, "INTERNAL ERROR at %s:%d, please report",
- __FILE__, __LINE__);
- env->auto_ptr[env->numautos++] = ptr;
-}
-
-void
-env_unregister_autos(eval_environ_t env)
-{
- env->numautos = 0;
-}
-
-void
-env_fixup_autos(eval_environ_t env, ptrdiff_t offset)
-{
- int i;
- for (i = 0; i < env->numautos; i++) {
- STKVAL *pptr = env->auto_ptr[i];
- *pptr += offset;
- }
-}
-
-
-static int
-expand_dataseg(eval_environ_t env, size_t count, const char *errtext)
-{
- STKVAL *newds;
- ptrdiff_t offset;
- size_t new_stack_size;
- size_t diff;
-
- switch (stack_expand_policy) {
- case stack_expand_add:
- diff = ((count + stack_expand_incr - 1) / stack_expand_incr)
- * stack_expand_incr;
- new_stack_size = env->stack_size + diff;
- break;
-
- case stack_expand_twice:
- new_stack_size = 2 * env->stack_size;
- if (new_stack_size < env->stack_size) {
- if (errtext)
- runtime_error(env, errtext);
- else
- return 1;
- }
- diff = new_stack_size - env->stack_size;
- if (diff < count) {
- if (errtext)
- runtime_error(env, errtext);
- else
- return 1;
- }
- }
-
- if ((stack_max_size && new_stack_size > stack_max_size)
- || (newds = realloc(env->dataseg,
- (new_stack_size + datasize)
- * sizeof env->dataseg[0])) == NULL) {
- if (errtext)
- runtime_error(env, errtext);
- else
- return 1;
- }
-
- offset = (char*)newds - (char*)env->dataseg;
- env->dataseg = newds;
- env->stack_size = new_stack_size;
- env->tos += diff;
- env->base += diff;
- memmove(newds + env->tos, newds + env->tos - diff,
- (datasize + env->stack_size - env->tos)
- * sizeof newds[0]);
- env_fixup_autos(env, offset);
- mu_diag_output(MU_DIAG_WARNING,
- _("stack segment expanded, new size=%lu"),
- (unsigned long) env->stack_size);
- return 0;
-}
-
-
-void
-prog_trace(eval_environ_t env, const char *fmt, ...)
-{
- char buf[512];
- va_list ap;
-
- va_start(ap, fmt);
- vsnprintf(buf, sizeof buf, fmt, ap);
- va_end(ap);
- logmsg(LOG_DEBUG, "%4lu: %s:%lu: %s",
- (unsigned long) env->pc,
- env->locus.file, (unsigned long) env->locus.line,
- buf);
-}
-
-void instr_funcall(eval_environ_t env);
-void instr_locus(eval_environ_t env);
-
-void
-runtime_stack_trace(eval_environ_t env)
-{
- size_t base;
-
- mu_error(_("stack trace:"));
- for (base = env->base; base < datasize + env->stack_size - 4;
- base = (size_t) env->dataseg[base + 1] + base + 1) {
- int i;
- prog_counter_t pc = (prog_counter_t)env->dataseg[base + 2] - 1;
- char *name;
- struct locus *ploc = NULL, loc;
-
- if (pc < 2)
- break; /*FIXME*/
- if (prog[pc-2] == instr_funcall) {
- name = (char*)(env->dataseg + (size_t) prog[pc-1]);
- pc -= 2;
- } else {
- name = "(in catch)";
- pc -= 3;
- }
-
- for (i = 0; i < 10; i++) {
- if (pc > i + 3
- && prog[pc - i - 3] == instr_locus) {
- loc.file = (char*)(env->dataseg
- + (size_t) prog[pc - i - 2]);
- loc.line = (size_t) prog[pc - i - 1];
- ploc = &loc;
- break;
- }
- }
-
- if (ploc)
- mu_error("%04lu: %s:%lu: %s",
- (unsigned long) pc,
- ploc->file, (unsigned long) ploc->line,
- name);
- else
- mu_error("%04lu: %s",
- (unsigned long) pc,
- name);
- }
- mu_error(_("stack trace finishes"));
-}
-
-void
-runtime_warning(eval_environ_t env, const char *fmt, ...)
-{
- va_list ap;
-
- mu_diag_printf(MU_DIAG_WARNING,
- _("RUNTIME WARNING near %s:%lu: "),
- env->locus.file, (unsigned long) env->locus.line);
- va_start(ap, fmt);
- mu_diag_output(MU_DIAG_WARNING, fmt, ap);
- va_end(ap);
-}
-
-void
-runtime_error(eval_environ_t env, const char *fmt, ...)
-{
- int n;
- va_list ap;
- char buf[512];
-
- n = snprintf(buf, sizeof buf, _("RUNTIME ERROR near %s:%lu: "),
- env->locus.file, (unsigned long) env->locus.line);
- va_start(ap, fmt);
- vsnprintf(buf + n, sizeof buf - n, fmt, ap);
- va_end(ap);
- mu_error(buf);
- if (stack_trace_option)
- runtime_stack_trace(env);
- env->status = SMFIS_TEMPFAIL; /* FIXME */
- longjmp(env->x_jmp, 1);
-}
-
-void *
-get_immediate(eval_environ_t env, unsigned n)
-{
- return prog[env->pc + n + 1];
-}
-
-void
-get_literal(eval_environ_t env, unsigned n, const char **p)
-{
- *p = (char*)(env->dataseg + (size_t) get_immediate(env, n));
- env_register_auto(env, p);
-}
-
-STKVAL
-get_arg(eval_environ_t env, unsigned n)
-{
- return env->dataseg[env->tos + n + 1];
-}
-
-void
-get_string_arg(eval_environ_t env, unsigned n, char **p)
-{
- *p = (char*) (env->dataseg + (size_t) get_arg(env, n));
- env_register_auto(env, p);
-}
-
-void
-get_numeric_arg(eval_environ_t env, unsigned n, long *np)
-{
- *np = (long) get_arg(env, n);
-}
-
-void
-get_pointer_arg(eval_environ_t env, unsigned n, void **p)
-{
- *p = (void*) get_arg(env, n);
-}
-
-void
-push(eval_environ_t env, STKVAL val)
-{
- if (env->tos < env->toh)
- runtime_error(env, "INTERNAL ERROR at %s:%d, please report",
- __FILE__, __LINE__);
- if (env->tos == env->toh) {
- debug(MF_SOURCE_PROG, 100,
- ("tos=%lu, toh=%lu",
- (unsigned long) env->tos,
- (unsigned long) env->toh));
- expand_dataseg(env, 1,
- _("out of stack space; increase #pragma stacksize"));
- }
- env->dataseg[env->tos--] = val;
-}
-
-STKVAL
-pop(eval_environ_t env)
-{
- if (env->tos == datasize + env->stack_size - 1)
- runtime_error(env, _("stack underflow"));
- return env->dataseg[++env->tos];
-}
-
-size_t
-heap_reserve_words(eval_environ_t env, size_t words)
-{
- size_t off = env->toh;
- if (env->toh + words > env->tos)
- expand_dataseg(env, words,
- _("heap overrun; increase #pragma stacksize"));
- env->toh += words;
- return off;
-}
-
-size_t
-heap_reserve(eval_environ_t env, size_t size)
-{
- return heap_reserve_words(env, B2STACK(size));
-}
-
-STKVAL
-heap_tempspace(eval_environ_t env, size_t size)
-{
- size_t words = B2STACK(size);
-
- if (env->toh + words > env->tos)
- expand_dataseg(env, words,
- _("heap overrun; increase #pragma stacksize"));
- return env->dataseg + env->toh;
-}
-
-void
-heap_obstack_begin(eval_environ_t env)
-{
- env->temp_start = env->toh;
- env->temp_size = 0;
-}
-
-void
-heap_obstack_cancel(eval_environ_t env)
-{
- env->toh = env->temp_start;
- env->temp_start = 0;
- env->temp_size = 0;
-}
-
-STKVAL
-heap_obstack_finish(eval_environ_t env)
-{
- size_t ret = env->temp_start;
- env->temp_start = 0;
- env->temp_size = 0;
- return (STKVAL) ret;
-}
-
-void *
-heap_obstack_grow(eval_environ_t env, void *ptr, size_t size)
-{
- size_t words = B2STACK(size);
- char *ret;
-
- if (env->tos - env->toh < words + B2STACK(env->temp_size))
- expand_dataseg(env, words,
- _("memory chunk too big to fit into heap"));
- ret = (char*) env_data_ref(env, env->temp_start) + env->temp_size;
- if (ptr)
- memmove(ret, ptr, size);
- env->temp_size += size;
- env->toh += words;
- return ret;
-}
-
-void *
-heap_obstack_base(eval_environ_t env)
-{
- return (void*) env_data_ref(env, env->temp_start);
-}
-
-STKVAL *
-env_data_ref(eval_environ_t env, size_t off)
-{
- return env->dataseg + off;
-}
-
-void
-pushs(eval_environ_t env, const char *s)
-{
- size_t off = heap_reserve(env, strlen(s) + 1);
- strcpy((char*) env_data_ref(env, off), s);
- push(env, (STKVAL) off);
-}
-
-/* Auxiliary instructions */
-
-void
-instr_locus(eval_environ_t env)
-{
- env->locus.line = (size_t) get_immediate(env, 1);
- get_literal(env, 0, &env->locus.file);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "LOCUS");
- advance_pc(env, 2);
-}
-
-void
-dump_locus(prog_counter_t i)
-{
- printf("\"%s\" %lu", (char*) (dataseg + (size_t)prog[i]),
- (unsigned long) (size_t) prog[i+1]);
-}
-
-/* Stack manipulation instructions */
-void
-instr_xchg(eval_environ_t env)
-{
- prog_counter_t p = env->tos + 1;
- STKVAL tmp = env->dataseg[p];
- env->dataseg[p] = env->dataseg[p + 1];
- env->dataseg[p + 1] = tmp;
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "XCHG");
-}
-
-void
-instr_dup(eval_environ_t env)
-{
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "DUP");
- push(env, get_arg(env, 0));
-}
-
-void
-instr_pop(eval_environ_t env)
-{
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "POP");
- pop(env);
-}
-
-void
-instr_push(eval_environ_t env)
-{
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "PUSH %x", get_immediate(env, 0));
- push(env, get_immediate(env, 0));
- advance_pc(env, 1);
-}
-
-void
-dump_push(prog_counter_t i)
-{
- printf("%lx", (unsigned long) prog[i]);
-}
-
-void
-instr_memstk(eval_environ_t env)
-{
- size_t frame = (size_t) get_immediate(env, 0);
- long off = (long) get_immediate(env, 1);
- size_t val = env_base(env, frame) + off;
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "MEMSTK %lu(%ld)=%lu",
- (unsigned long) frame, off,
- (unsigned long) val);
- advance_pc(env, 2);
- push(env, (STKVAL) val);
-}
-
-void
-dump_memstk(prog_counter_t i)
-{
- printf("%lu(%ld)", (unsigned long) prog[i], (long) prog[i+1]);
-}
-
-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;
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "XMEMSTK %lu(%ld)=%lu",
- (unsigned long) frame, off,
- (unsigned long) val);
- adjust_stack(env, 2);
- push(env, (STKVAL) val);
-}
-
-void
-instr_deref(eval_environ_t env)
-{
- size_t off = (size_t) get_arg(env, 0);
- STKVAL val = env->dataseg[off];
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "DEREF %lu=%lu (%p)",
- (unsigned long) off,
- (unsigned long) val, val);
- adjust_stack(env, 1);
- push(env, val);
-}
-
-void
-instr_stkalloc(eval_environ_t env)
-{
- unsigned n = (unsigned) get_immediate(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "STKALLOC %p", n);
- if (env->tos - n < env->toh) {
- debug(MF_SOURCE_PROG, 100,
- ("tos=%lu, toh=%lu, delta=%u",
- (unsigned long) env->tos,
- (unsigned long) env->toh,
- n));
- expand_dataseg(env, env->toh - (env->tos - n),
- _("Out of stack space; increase #pragma stacksize"));
- }
- env->tos -= n;
- advance_pc(env, 1);
-}
-
-void
-dump_stkalloc(prog_counter_t i)
-{
- printf("%u", (unsigned)prog[i]);
-}
-
-void
-instr_backref(eval_environ_t env)
-{
- unsigned n = (unsigned) get_immediate(env, 0);
- size_t matchlen;
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "BACKREF %u", (unsigned)get_immediate(env, 0));
- advance_pc(env, 1);
-
- if (!env->matches || !env->string) {
- /* FIXME: Try to throw exception first:
- env_throw(env, mf_no_regex);
- */
- runtime_error(env, _("no previous regular expression"));
- }
- if (n > env->matchcount) {
- /* FIXME: See above */
- runtime_error(env, _("invalid back-reference number"));
- }
-
- if (env->matches[n].rm_so == -1) {
- push(env, 0);
- } else {
- char *s;
- size_t off;
-
- matchlen = env->matches[n].rm_eo - env->matches[n].rm_so;
- off = heap_reserve(env, matchlen + 1);
- s = (char*) env_data_ref(env, off);
- memcpy(s, env->string + env->matches[n].rm_so, matchlen);
- s[matchlen] = 0;
- push(env, (STKVAL) off);
- }
-}
-
-void
-dump_backref(prog_counter_t i)
-{
- printf("%u", (unsigned) prog[i]);
-}
-
-/* Type conversion instructions */
-void
-instr_ston(eval_environ_t env)
-{
- char *s;
- char *p;
- long v;
-
- get_string_arg(env, 0, &s);
- v = strtol(s, &p, 0);
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "STON %s", s);
- adjust_stack(env, 1);
- if (*p)
- env_throw(env, mfe_ston_conv,
- "Cannot convert stack value to number (stopped at %-.8s)",
- p);
-
- push(env, (STKVAL) v);
-}
-
-void
-instr_ntos(eval_environ_t env)
-{
- long v = (long) get_arg(env, 0);
- char buf[NUMERIC_BUFSIZE_BOUND];
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "NTOS %ld", v);
- adjust_stack(env, 1);
-
- snprintf(buf, sizeof buf, "%ld", v);
- pushs(env, buf);
-}
-
-/* Evaluation instructions */
-void
-instr_cmp(eval_environ_t env)
-{
- long l = (long) get_arg(env, 1);
- long r = (long) get_arg(env, 0);
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "CMP %ld %ld", l, r);
- adjust_stack(env, 2);
- push(env, (STKVAL) (l == r));
-}
-
-void
-instr_symbol(eval_environ_t env)
-{
- char *symbol;
- const char *s;
-
- get_literal(env, 0, (const char **)&symbol);
- s = env->getsym(env->data, symbol);
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "SYMBOL %s", symbol);
- if (!s)
- env_throw(env, mfe_macroundef, _("macro not defined: %s"),
- symbol);
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "%s dereferenced to %s", symbol, s);
-
- advance_pc(env, 1);
-
- pushs(env, s);
-}
-
-void
-dump_symbol(prog_counter_t i)
-{
- printf("%08lx %s", (unsigned long) prog[i],
- (char *) (dataseg + (size_t) prog[i]));
-}
-
-/* Comparation instructions */
-void
-instr_eqn(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "EQN %ld %ld", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a == b));
-}
-
-void
-instr_eqs(eval_environ_t env)
-{
- char *a, *b;
- get_string_arg(env, 1, &a);
- get_string_arg(env, 0, &b);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "EQS %s %s", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (strcmp(a, b) == 0));
-}
-
-void
-instr_nen(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "NEN %ld %ld", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a != b));
-}
-
-void
-instr_nes(eval_environ_t env)
-{
- char *a, *b;
-
- get_string_arg(env, 1, &a);
- get_string_arg(env, 0, &b);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "NES %s %s", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) strcmp(a, b));
-}
-
-void
-instr_ltn(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "LTN %ld %ld", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a < b));
-}
-
-void
-instr_lts(eval_environ_t env)
-{
- char *a, *b;
-
- get_string_arg(env, 1, &a);
- get_string_arg(env, 0, &b);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "LTS %s %s", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (strcmp(a, b) < 0));
-}
-
-void
-instr_len(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "LEN %ld %ld", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a <= b));
-}
-
-void
-instr_les(eval_environ_t env)
-{
- char *a, *b;
-
- get_string_arg(env, 1, &a);
- get_string_arg(env, 0, &b);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "LES %s %s", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (strcmp(a, b) <= 0));
-}
-
-void
-instr_gtn(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "GTN %ld %ld", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a > b));
-}
-
-void
-instr_gts(eval_environ_t env)
-{
- char *a, *b;
-
- get_string_arg(env, 1, &a);
- get_string_arg(env, 0, &b);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "GTS %s %s", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (strcmp(a, b) > 0));
-}
-
-void
-instr_gen(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "GEN %ld %ld", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a >= b));
-}
-
-void
-instr_ges(eval_environ_t env)
-{
- char *a, *b;
-
- get_string_arg(env, 1, &a);
- get_string_arg(env, 0, &b);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "GES %s %s", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (strcmp(a, b) >= 0));
-}
-
-/* Jump instructions */
-void
-instr_bz(eval_environ_t env)
-{
- long v = (long) get_arg(env, 0);
- long off = (long) get_immediate(env, 0);
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "BZ %ld (%ld)", off, v);
- adjust_stack(env, 1);
- if (v == 0)
- advance_pc(env, off);
- advance_pc(env, 1);
-}
-
-void
-dump_branch (prog_counter_t i)
-{
- printf("%ld (%ld)", (long) prog[i], i + (long) prog[i] + 1);
-}
-
-void
-instr_bnz(eval_environ_t env)
-{
- long v = (long) get_arg(env, 0);
- long off = (long) get_immediate(env, 0);
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "BNZ %ld (%ld)", off, v);
- adjust_stack(env, 1);
- if (v != 0)
- advance_pc(env, off);
- advance_pc(env, 1);
-}
-
-void
-instr_jmp(eval_environ_t env)
-{
- long off = (long) get_immediate(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "JMP %ld", off);
- advance_pc(env, off+1);
-}
-
-/* Boolean instructions */
-void
-instr_not(eval_environ_t env)
-{
- long v = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "NOT %ld", v);
- adjust_stack(env, 1);
- push(env, (STKVAL) !v);
-}
-
-/* Bitwise arithmetics */
-void
-instr_logand(eval_environ_t env)
-{
- unsigned long a = (unsigned long) get_arg(env, 1);
- unsigned long b = (unsigned long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "LOGAND %lu %lu", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a & b));
-}
-
-void
-instr_logor(eval_environ_t env)
-{
- unsigned long a = (unsigned long) get_arg(env, 1);
- unsigned long b = (unsigned long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "LOGOR %lu %lu", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a | b));
-}
-
-void
-instr_logxor(eval_environ_t env)
-{
- unsigned long a = (unsigned long) get_arg(env, 1);
- unsigned long b = (unsigned long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "LOGXOR %lu %lu", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a ^ b));
-}
-
-void
-instr_lognot(eval_environ_t env)
-{
- unsigned long v = (unsigned long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "LOGNOT %ld", v);
- adjust_stack(env, 1);
- push(env, (STKVAL) ~v);
-}
-
-/* Arithmetic instructions */
-void
-instr_add(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "ADD %ld %ld", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a + b));
-}
-
-void
-instr_sub(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "SUB %ld %ld", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a - b));
-}
-
-void
-instr_mul(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "MUL %ld %ld", a, b);
- adjust_stack(env, 2);
- push(env, (STKVAL) (a * b));
-}
-
-void
-instr_div(eval_environ_t env)
-{
- long a = (long) get_arg(env, 1);
- long b = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "DIV %ld %ld", a, b);
- adjust_stack(env, 2);
- if (b == 0)
- env_throw(env, mfe_divzero,
- "Division by zero at %08x", (unsigned int) env->pc);
- push(env, (STKVAL) (a / b));
-}
-
-void
-instr_neg(eval_environ_t env)
-{
- long v = (long) get_arg(env, 0);
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "NEG %ld", v);
- adjust_stack(env, 1);
- push(env, (STKVAL) -v);
-}
-
-/* Matching and Regular expression instructions */
-
-/* REGEX: Basically it is useful only for debugging. Its effect is
- the same as that of instr_push */
-void
-instr_regex(eval_environ_t env)
-{
- char buffer[REGEX_STRING_BUFSIZE];
- size_t index = (size_t) get_immediate(env, 0);
-
- if (PROG_TRACE_ENGINE)
- prog_trace(env, "REGEX (%s) %s",
- regex_flags_to_string(regtab[index].regflags,
- buffer,
- sizeof buffer),
- (char*) env_data_ref(env, regtab[index].expr));
- advance_pc