Commit 35056a6e 35056a6e5f5417bf14f161ed2065210560376220 by Sergey Poznyakoff

Start rewriting MH format functions.

* mh/fmtcheck.c: New option -disassemble
* mh/mh.h: Move format-related declarations to mh_format.h
(mh_format_parse): Change signature.
(mh_format): Change signature.
(mh_format_dump_code)
(mh_format_dump_disass): New protos.
(mh_decode_2047): Change signature.
* mh/mh_fmtgram.y: Rewrite from scratch.  First, build a parse tree,
then use it to generate code.
* mh/mh_format.c: Rewrite from scratch.
* mh/mh_format.h: Move format-related declarations from mh.h
* mh/mh_init.c (mh_decode_2047): Text is const.
* mh/mh_list.c: Fix calls to mh_format_parse and related objects.
1 parent 6878eb80
......@@ -25,6 +25,7 @@ static char args_doc[] = N_("[FILE]");
static char *format_str;
static mh_format_t format;
static int dump_option;
static int disass_option;
static int debug_option;
static char *input_file;
static size_t width;
......@@ -41,6 +42,9 @@ static struct mu_option options[] = {
{ "dump", 0, NULL, MU_OPTION_HIDDEN,
N_("dump the listing of compiled format code"),
mu_c_bool, &dump_option },
{ "disassemble", 0, NULL, MU_OPTION_HIDDEN,
N_("dump disassembled format code"),
mu_c_bool, &disass_option },
{ "debug", 0, NULL, MU_OPTION_DEFAULT,
N_("enable parser debugging output"),
mu_c_bool, &debug_option },
......@@ -58,11 +62,8 @@ static void
run (void)
{
mu_message_t msg = mh_file_to_message (NULL, input_file);
char *output;
mh_format (&format, msg, msgno, width, &output);
mu_printf ("%s\n", output);
mh_format (format, msg, msgno, width, mu_strout);
mu_printf ("\n");
}
int
......@@ -90,14 +91,16 @@ main (int argc, char **argv)
mu_error (_("Format string not specified"));
return 1;
}
if (mh_format_parse (format_str, &format))
if (mh_format_parse (&format, format_str, MH_FMT_PARSE_TREE))
{
mu_error (_("Bad format string"));
exit (1);
}
if (dump_option)
mh_format_dump (&format);
mh_format_dump_code (format);
if (disass_option)
mh_format_dump_disass (format);
if (input_file)
run ();
......
......@@ -65,11 +65,6 @@
#include <mu_umaxtostr.h>
#define MH_FMT_RALIGN 0x1000
#define MH_FMT_ZEROPAD 0x2000
#define MH_FMT_COMPWS 0x4000
#define MH_WIDTH_MASK 0x0fff
#define MH_SEQUENCES_FILE ".mh_sequences"
#define MH_USER_PROFILE ".mh_profile"
#define MH_GLOBAL_PROFILE "mh-profile"
......@@ -78,118 +73,6 @@
#define is_true(arg) ((arg) == NULL||mu_true_answer_p (arg) == 1)
enum mh_opcode
{
/* 0. Stop. Format: mhop_stop */
mhop_stop,
/* 1. Branch.
Format: mhop_branch offset */
mhop_branch,
/* 2. Assign to numeric register
Format: mhop_num_asgn */
mhop_num_asgn,
/* 3. Assign to string register
Format: mhop_str_asgn */
mhop_str_asgn,
/* 4. Numeric arg follows.
Format: mhop_num_arg number */
mhop_num_arg,
/* 5. String arg follows.
Format: mhop_str_arg length string */
mhop_str_arg,
/* 6. Branch if reg_num is zero.
Format: mhop_num_branch dest-off */
mhop_num_branch,
/* 7. Branch if reg_str is zero.
Format: mhop_str_branch dest-off */
mhop_str_branch,
/* 8. Set str to the value of the header component
Format: mhop_header */
mhop_header,
/* 9. Read message body contents into str.
Format: mhop_body */
mhop_body,
/* 10. Call a function.
Format: mhop_call function-pointer */
mhop_call,
/* 11. assign reg_num to arg_num */
mhop_num_to_arg,
/* 12. assign reg_str to arg_str */
mhop_str_to_arg,
/* 13. Convert arg_str to arg_num */
mhop_str_to_num,
/* 14. Convert arg_num to arg_str */
mhop_num_to_str,
/* 15. Print reg_num */
mhop_num_print,
/* 16. Print reg_str */
mhop_str_print,
/* 17. Set format specification.
Format: mhop_fmtspec number */
mhop_fmtspec,
/* 18. Noop */
mhop_nop
};
enum mh_type
{
mhtype_none,
mhtype_num,
mhtype_str
};
typedef enum mh_opcode mh_opcode_t;
struct mh_machine;
typedef void (*mh_builtin_fp) (struct mh_machine *);
typedef union {
mh_opcode_t opcode;
mh_builtin_fp builtin;
int num;
void *ptr;
char str[1]; /* Any number of characters follows */
} mh_instr_t;
#define MHI_OPCODE(m) (m).opcode
#define MHI_BUILTIN(m) (m).builtin
#define MHI_NUM(m) (m).num
#define MHI_PTR(m) (m).ptr
#define MHI_STR(m) (m).str
typedef struct mh_format mh_format_t;
struct mh_format
{
size_t progsize; /* Size of allocated program*/
mh_instr_t *prog; /* Program itself */
};
#define MHA_REQUIRED 0
#define MHA_OPTARG 1
#define MHA_OPT_CLEAR 2
typedef struct mh_builtin mh_builtin_t;
struct mh_builtin
{
char *name;
mh_builtin_fp fun;
int type;
int argtype;
int optarg;
};
typedef struct
{
const char *name;
......@@ -284,14 +167,22 @@ int mu_getans (const char *variants, const char *fmt, ...)
int mh_check_folder (const char *pathname, int confirm);
int mh_makedir (const char *p);
int mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno,
size_t width, char **pret);
int mh_format_str (mh_format_t *fmt, char *str, size_t width, char **pret);
void mh_format_dump (mh_format_t *fmt);
int mh_format_parse (char *format_str, mh_format_t *fmt);
typedef struct mh_format *mh_format_t;
int mh_format (mh_format_t fmt, mu_message_t msg, size_t msgno,
size_t width, mu_stream_t str);
int mh_format_str (mh_format_t fmt, char *str, size_t width, char **pret);
void mh_format_dump_code (mh_format_t fmt);
void mh_format_dump_disass (mh_format_t fmt);
#define MH_FMT_PARSE_DEFAULT 0
#define MH_FMT_PARSE_TREE 0x01
int mh_format_parse (mh_format_t *fmt, char *format_str, int flags);
void mh_format_debug (int val);
void mh_format_free (mh_format_t *fmt);
mh_builtin_t *mh_lookup_builtin (char *name, int *rest);
void mh_format_free (mh_format_t fmt);
void mh_format_destroy (mh_format_t *fmt);
void mh_error (const char *fmt, ...) MU_PRINTFLIKE(1,2);
void mh_err_memory (int fatal);
......@@ -350,7 +241,7 @@ int mh_whom_file (const char *filename, int check);
int mh_whom_message (mu_message_t msg, int check);
void mh_set_reply_regex (const char *str);
int mh_decode_2047 (char *text, char **decoded_text);
int mh_decode_2047 (char const *text, char **decoded_text);
const char *mh_charset (const char *);
int mh_alias_read (char const *name, int fail);
......
......@@ -17,285 +17,316 @@
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#include <mh.h>
#include <mh_format.h>
int yyerror (const char *s);
int yylex ();
int yylex (void);
static mh_format_t format; /* Format structure being built */
static size_t pc; /* Program counter. Poins to current
cell in format.prog */
static mu_opool_t tokpool; /* Temporary token storage */
#define FORMAT_INC 64 /* Increase format.prog by that many
cells each time pc reaches
format.progsize */
static size_t mh_code_op (mh_opcode_t op);
static size_t mh_code_string (char *string);
static size_t mh_code_number (int num);
static size_t mh_code_builtin (mh_builtin_t *bp, int argtype);
static void branch_fixup (size_t pc, size_t tgt);
/* Lexical context */
enum context
{
ctx_init, /* Normal text */
ctx_if, /* After %< or %? */
ctx_expr, /* Expression within cond */
ctx_func, /* after (func */
};
static enum context ctx_stack[512];
size_t ctx_tos;
static inline void
ctx_push (enum context ctx)
{
if (ctx_tos == MU_ARRAY_SIZE (ctx_stack))
{
yyerror ("context nesting level too deep");
exit (1);
}
ctx_stack[ctx_tos++] = ctx;
}
static inline void
ctx_pop (void)
{
if (ctx_tos == 0)
{
yyerror ("out of context");
abort ();
}
ctx_tos--;
}
static inline enum context
ctx_get (void)
{
return ctx_stack[ctx_tos-1];
}
enum node_type
{
fmtnode_print,
fmtnode_literal,
fmtnode_number,
fmtnode_body,
fmtnode_comp,
fmtnode_funcall,
fmtnode_cntl,
fmtnode_typecast
};
struct node
{
enum node_type nodetype;
enum mh_type datatype;
int noprint:1;
struct node *prev, *next;
union
{
char *str;
long num;
struct node *arg;
struct
{
int fmtspec;
struct node *arg;
} prt;
struct
{
mh_builtin_t *builtin;
struct node *arg;
} funcall;
struct
{
struct node *cond;
struct node *iftrue;
struct node *iffalse;
} cntl;
} v;
};
static struct node *parse_tree;
static struct node *new_node (enum node_type nodetype, enum mh_type datatype);
static struct node *printelim (struct node *root);
static void codegen (mh_format_t *fmt, int tree);
static struct node *typecast (struct node *node, enum mh_type type);
/* Lexical tie-ins */
static int in_escape; /* Set when inside an escape sequence */
static int want_function; /* Set when expecting function name */
static int want_arg; /* Expecting function argument */
%}
%union {
char *str;
int num;
int type;
long num;
struct {
size_t cond;
size_t end;
} elif_list;
size_t pc;
struct node *head, *tail;
} nodelist;
struct node *nodeptr;
mh_builtin_t *builtin;
int fmtspec;
struct {
enum mh_type type;
union
{
char *str;
long num;
} v;
} arg;
};
%token <num> NUMBER
%token <str> STRING
%token <str> STRING COMPONENT
%token <arg> ARGUMENT
%token <builtin> FUNCTION
%token IF ELIF ELSE FI
%token OBRACE CBRACE OCURLY CCURLY
%token <num> FMTSPEC
%token <fmtspec> FMTSPEC
%token BOGUS
%type <type> cond_expr component funcall item argument escape literal
%type <elif_list> elif_part elif_list fi
%type <pc> cond end else elif else_part zlist list pitem
%token EOFN
%type <nodelist> list zlist elif_list
%type <nodeptr> item escape component funcall cntl argument
%type <nodeptr> cond cond_expr elif_part else_part printable
%type <builtin> function
%type <fmtspec> fmtspec
%%
input : list
{
/* nothing: to shut bison up */
parse_tree = $1.head;
}
;
list : pitem
| list pitem
;
pitem : item
{
switch ($1)
list : item
{
case mhtype_none:
break;
case mhtype_num:
mh_code_op (mhop_num_asgn);
mh_code_op (mhop_num_print);
break;
case mhtype_str:
mh_code_op (mhop_str_asgn);
mh_code_op (mhop_str_print);
break;
default:
yyerror (_("INTERNAL ERROR: unexpected item type (please report)"));
abort ();
$$.head = $$.tail = $1;
}
$$ = pc;
| list item
{
$2->prev = $1.tail;
$1.tail->next = $2;
$1.tail = $2;
$$ = $1;
}
;
item : literal
| escape
item : STRING
{
in_escape = 0;
struct node *n = new_node (fmtnode_literal, mhtype_str);
n->v.str = $1;
$$ = new_node (fmtnode_print, mhtype_str);
$$->v.prt.arg = n;
}
| escape
;
literal : STRING
escape : cntl
| fmtspec printable
{
mh_code_string ($1);
$$ = mhtype_str;
}
| NUMBER
if ($2->noprint)
$$ = $2;
else
{
mh_code_number ($1);
$$ = mhtype_num;
$$ = new_node (fmtnode_print, $2->datatype);
$$->v.prt.fmtspec = $1;
$$->v.prt.arg = $2;
}
}
;
escape : component
printable : component
| funcall
| cntl
{
$$ = mhtype_none;
}
;
component : fmtspec OCURLY STRING CCURLY
component : COMPONENT
{
if (mu_c_strcasecmp ($3, "body") == 0)
{
mh_code_op (mhop_body);
}
if (mu_c_strcasecmp ($1, "body") == 0)
$$ = new_node (fmtnode_body, mhtype_str);
else
{
mh_code_string ($3);
mh_code_op (mhop_header);
$$ = new_node (fmtnode_comp, mhtype_str);
$$->v.str = $1;
}
$$ = mhtype_str;
}
;
obrace : OBRACE
funcall : function argument EOFN
{
in_escape++;
}
;
cbrace : CBRACE
ctx_pop ();
if ($1->optarg == MHA_VOID) /*FIXME*/
{
in_escape--;
$2->noprint = 1;
$$ = $2;
}
;
funcall : fmtspec obrace { want_function = 1;} function { want_function = 0; want_arg = 1;} argument cbrace
else
{
if ($4)
if ($1->argtype == mhtype_none)
{
if (!mh_code_builtin ($4, $6))
YYERROR;
$$ = $4->type;
if ($2)
{
yyerror ("function doesn't take arguments");
YYABORT;
}
else
}
else if ($2 == NULL)
{
switch ($6)
if ($1->optarg != MHA_OPTARG)
{
default:
break;
case mhtype_num:
mh_code_op (mhop_num_asgn);
break;
case mhtype_str:
mh_code_op (mhop_str_asgn);
break;
yyerror ("required argument missing");
YYABORT;
}
$$ = mhtype_none;
}
$$ = new_node (fmtnode_funcall, $1->type);
$$->v.funcall.builtin = $1;
$$->v.funcall.arg = typecast ($2, $1->argtype);
$$->noprint = $1->type == mhtype_none;
}
}
;
fmtspec : /* empty */
| FMTSPEC
{
mh_code_op (mhop_fmtspec);
mh_code_op ($1);
$$ = 0;
}
| FMTSPEC
;
function : FUNCTION
| STRING
{
if (strcmp ($1, "void") == 0)
{
$$ = NULL;
}
else
{
yyerror (_("undefined function"));
mu_error ("%s", $1);
YYERROR;
}
ctx_push (ctx_func);
}
;
argument : /* empty */
{
$$ = mhtype_none;
$$ = NULL;
}
| literal
| escape
;
/* 1 2 3 4 5 6 7 */
cntl : if cond zlist end elif_part else_part fi
| ARGUMENT
{
size_t start_pc = 0, end_pc = 0;
switch ($1.type)
{
case mhtype_none:
$$ = NULL;
break;
/* Fixup first condition */
if ($5.cond)
MHI_NUM(format.prog[$2]) = $5.cond - $2;
else if ($6)
MHI_NUM(format.prog[$2]) = $6 - $2;
else
MHI_NUM(format.prog[$2]) = $7.cond - $2;
case mhtype_str:
$$ = new_node (fmtnode_literal, mhtype_str);
$$->v.str = $1.v.str;
break;
/* Link all "false" lists */
if ($5.cond)
case mhtype_num:
$$ = new_node (fmtnode_number, mhtype_num);
$$->v.num = $1.v.num;
}
}
| escape
{
start_pc = $5.end;
end_pc = $5.end;
while (MHI_NUM(format.prog[end_pc]))
end_pc = MHI_NUM(format.prog[end_pc]);
$$ = printelim ($1);
}
;
if (start_pc)
MHI_NUM(format.prog[end_pc]) = $4;
else
start_pc = $4;
/* Now, fixup the end branches */
branch_fixup (start_pc, $7.end);
MHI_NUM(format.prog[start_pc]) = $7.end - start_pc;
/* 1 2 3 4 5 */
cntl : if cond zlist elif_part fi
{
$$ = new_node(fmtnode_cntl, mhtype_num);
$$->v.cntl.cond = $2;
$$->v.cntl.iftrue = $3.head;
$$->v.cntl.iffalse = $4;
}
;
zlist : /* empty */
{
$$ = pc;
$$.head = $$.tail = NULL;
}
| list
;
if : IF
{
in_escape++;
ctx_push (ctx_if);
}
;
fi : FI
{
/* False branch of an if-block */
$$.cond = mh_code_op (mhop_num_asgn);
/* Jump over the true branch */
mh_code_op (mhop_branch);
mh_code_op (2);
/* True branch */
$$.end = mh_code_op (mhop_num_asgn);
ctx_pop ();
}
;
elif : ELIF
{
in_escape++;
$$ = pc;
}
;
end : /* empty */
{
mh_code_op (mhop_branch);
$$ = mh_code_op (0);
ctx_pop ();
ctx_push (ctx_if);
}
;
cond : cond_expr
{
in_escape--;
if ($1 == mhtype_str)
mh_code_op (mhop_str_branch);
else
mh_code_op (mhop_num_branch);
$$ = mh_code_op (0);
ctx_pop ();
ctx_push (ctx_expr);
$$ = printelim ($1);
}
;
......@@ -305,42 +336,46 @@ cond_expr : component
elif_part : /* empty */
{
$$.cond = 0;
$$.end = 0;
$$ = NULL;
}
| elif_list end
| else_part
| elif_list
{
$$.cond = $1.cond;
MHI_NUM(format.prog[$2]) = $1.end;
$$.end = $2;
$$ = $1.head;
}
;
elif_list : elif cond zlist
{
$$.cond = $1;
MHI_NUM(format.prog[$2]) = pc - $2 + 2;
$$.end = 0;
struct node *np = new_node (fmtnode_cntl, mhtype_num);
np->v.cntl.cond = $2;
np->v.cntl.iftrue = $3.head;
np->v.cntl.iffalse = NULL;
$$.head = $$.tail = np;
}
| elif_list end elif cond zlist
| elif_list elif cond zlist
{
MHI_NUM(format.prog[$4]) = pc - $4 + 2;
$$.cond = $1.cond;
MHI_NUM(format.prog[$2]) = $1.end;
$$.end = $2;
}
;
struct node *np = new_node(fmtnode_cntl, mhtype_num);
np->v.cntl.cond = $3;
np->v.cntl.iftrue = $4.head;
np->v.cntl.iffalse = NULL;
$1.tail->v.cntl.iffalse = np;
$1.tail = np;
else_part : /* empty */
$$ = $1;
}
| elif_list else_part
{
$$ = 0;
$1.tail->v.cntl.iffalse = $2;
$1.tail = $2;
$$ = $1;
}
| else list
;
else : ELSE
else_part : ELSE list
{
$$ = pc;
$$ = $2.head;
}
;
......@@ -352,107 +387,259 @@ static char *curp;
int
yyerror (const char *s)
{
if (yychar != BOGUS)
{
int len;
mu_error ("%s: %s", start, s);
len = curp - start;
mu_error ("%*.*s^", len, len, "");
}
return 0;
}
#define isdelim(c) (strchr("%<>?|(){} ",c) != NULL)
static int percent;
static int backslash(int c);
int
yylex ()
struct lexer_tab
{
/* Reset the tie-in */
int expect_arg = want_arg;
want_arg = 0;
char *ctx_name;
int (*lexer) (void);
};
static int yylex_initial (void);
static int yylex_cond (void);
static int yylex_expr (void);
static int yylex_func (void);
static struct lexer_tab lexer_tab[] = {
[ctx_init] = { "initial", yylex_initial },
[ctx_if] = { "condition", yylex_cond },
[ctx_expr] = { "expression", yylex_expr },
[ctx_func] = { "function", yylex_func }
};
int
yylex (void)
{
if (yydebug)
fprintf (stderr, "[lex at %10.10s]\n", curp);
if (*curp == '%')
{
curp++;
percent = 1;
if (mu_isdigit (*curp) || *curp == '-')
{
fprintf (stderr, "lex: [%s] at %-10.10s...]\n",
lexer_tab[ctx_get ()].ctx_name, curp);
return lexer_tab[ctx_get ()].lexer ();
}
static int
token_fmtspec (int flags)
{
int num = 0;
int flags = 0;
if (*curp == '-')
if (*curp == '0')
{
flags |= MH_FMT_ZEROPAD;
curp++;
flags = MH_FMT_RALIGN;
}
if (*curp == '0')
flags |= MH_FMT_ZEROPAD;
else if (!mu_isdigit (*curp))
{
yyerror ("expected digit");
return BOGUS;
}
while (*curp && mu_isdigit (*curp))
num = num * 10 + *curp++ - '0';
yylval.num = num | flags;
yylval.fmtspec = flags | num;
*--curp = '%'; /* FIXME: dirty hack */
return FMTSPEC;
}
static int
token_function (void)
{
char *start;
curp++;
start = curp;
curp = mu_str_skip_class (start, MU_CTYPE_ALPHA);
if (start == curp || !strchr (" \t(){%", *curp))
{
yyerror ("expected function name");
return BOGUS;
}
yylval.builtin = mh_lookup_builtin (start, curp - start);
if (!yylval.builtin)
{
yyerror ("unknown function");
return BOGUS;
}
if (percent)
return FUNCTION;
}
static int
token_component (void)
{
char *start;
curp++;
if (!mu_isalpha (*curp))
{
percent = 0;
switch (*curp++)
yyerror ("component name expected");
return BOGUS;
}
start = curp;
for (; *curp != '}'; curp++)
{
if (!(mu_isalnum (*curp) || *curp == '_' || *curp == '-'))
{
yyerror ("component name expected");
return BOGUS;
}
}
mu_opool_append (tokpool, start, curp - start);
mu_opool_append_char (tokpool, 0);
yylval.str = mu_opool_finish (tokpool, NULL);
curp++;
return COMPONENT;
}
int
yylex_initial (void)
{
if (*curp == '%')
{
int c;
curp++;
switch (c = *curp++)
{
case '<':
return IF;
case '>':
return FI;
case '?':
return ELIF;
case '|':
return ELSE;
case '%':
return '%';
case '(':
return OBRACE;
curp--;
return token_function ();
case '{':
return OCURLY;
curp--;
return token_component ();
case '-':
return token_fmtspec (MH_FMT_RALIGN);
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
curp--;
return token_fmtspec (MH_FMT_DEFAULT);
default:
yyerror ("component or function name expected");
return BOGUS;
}
}
if (in_escape)
if (*curp == 0)
return 0;
do
{
while (*curp && (*curp == ' ' || *curp == '\n'))
if (*curp == '\\')
{
int c = backslash (*++curp);
mu_opool_append_char (tokpool, c);
}
else
mu_opool_append_char (tokpool, *curp);
curp++;
}
while (*curp && *curp != '%');
mu_opool_append_char (tokpool, 0);
yylval.str = mu_opool_finish (tokpool, NULL);
return STRING;
}
int
yylex_cond (void)
{
switch (*curp)
{
case '(':
curp++;
return OBRACE;
return token_function ();
case '{':
return token_component ();
default:
yyerror ("'(' or '{' expected");
return BOGUS;
}
}
int
yylex_expr (void)
{
if (*curp == '%')
{
curp++;
return OCURLY;
case '0':case '1':case '2':case '3':case '4':
case '5':case '6':case '7':case '8':case '9':
yylval.num = strtol (curp, &curp, 0);
return NUMBER;
switch (*curp++)
{
case '?':
return ELIF;
case '|':
return ELSE;
case '>':
return FI;
}
curp -= 2;
}
return yylex_initial ();
}
int
yylex_func (void)
{
/* Expected argument or closing parenthesis */
while (*curp && mu_isspace (*curp))
curp++;
switch (*curp)
{
case '(':
return token_function ();
case ')':
curp++;
return CBRACE;
case '}':
return EOFN;
case '{':
return token_component ();
case '%':
curp++;
return CCURLY;
case 0:
return 0;
switch (*curp)
{
case '<':
curp++;
return IF;
case '%':
break;
default:
yyerror ("expected '%' or '<'");
return BOGUS;
}
}
if (mu_isdigit (*curp))
{
yylval.arg.type = mhtype_num;
yylval.arg.v.num = strtol (curp, &curp, 0);
}
else
{
do
{
if (*curp == 0)
{
yyerror("expected ')'");
return BOGUS;
}
if (*curp == '\\')
{
int c = backslash (*++curp);
......@@ -462,26 +649,20 @@ yylex ()
mu_opool_append_char (tokpool, *curp);
curp++;
}
while (*curp && (expect_arg ? *curp != ')' : !isdelim(*curp)));
while (*curp != ')');
mu_opool_append_char (tokpool, 0);
yylval.str = mu_opool_finish (tokpool, NULL);
if (want_function)
{
int rest;
mh_builtin_t *bp = mh_lookup_builtin (yylval.str, &rest);
if (bp)
{
curp -= rest;
yylval.builtin = bp;
while (*curp && mu_isspace (*curp))
curp++;
return FUNCTION;
yylval.arg.type = mhtype_str;
yylval.arg.v.str = mu_opool_finish (tokpool, NULL);
}
if (*curp != ')')
{
yyerror("expected ')'");
return BOGUS;
}
return STRING;
return ARGUMENT;
}
void
......@@ -491,37 +672,32 @@ mh_format_debug (int val)
}
int
mh_format_parse (char *format_str, mh_format_t *fmt)
mh_format_parse (mh_format_t *fmtptr, char *format_str, int flags)
{
int rc;
char *p = getenv ("MHFORMAT_DEBUG");
if (p)
if (p || mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE2))
yydebug = 1;
start = curp = format_str;
mu_opool_create (&tokpool, MU_OPOOL_ENOMEMABRT);
format.prog = NULL;
format.progsize = 0;
pc = 0;
mh_code_op (mhop_stop);
in_escape = 0;
percent = 0;
ctx_tos = 0;
ctx_push (ctx_init);
rc = yyparse ();
mh_code_op (mhop_stop);
if (rc == 0)
codegen (fmtptr, flags & MH_FMT_PARSE_TREE);
else
mu_opool_destroy (&tokpool);
if (rc)
{
mh_format_free (&format);
return 1;
}
*fmt = format;
return 0;
parse_tree = NULL;
tokpool = NULL;
return rc;
}
int
backslash(int c)
backslash (int c)
{
static char transtab[] = "b\bf\fn\nr\rt\t";
char *p;
......@@ -534,131 +710,500 @@ backslash(int c)
return c;
}
void
branch_fixup (size_t epc, size_t tgt)
static struct node *
new_node (enum node_type nodetype, enum mh_type datatype)
{
size_t prev = MHI_NUM(format.prog[epc]);
if (!prev)
return;
branch_fixup (prev, tgt);
MHI_NUM(format.prog[prev]) = tgt - prev;
struct node *np = mu_zalloc (sizeof *np);
np->nodetype = nodetype;
np->datatype = datatype;
return np;
}
static void node_list_free (struct node *node);
static void
node_free (struct node *node)
{
switch (node->nodetype)
{
case fmtnode_print:
node_free (node->v.prt.arg);
break;
case fmtnode_literal:
break;
case fmtnode_number:
break;
case fmtnode_body:
break;
case fmtnode_comp:
break;
case fmtnode_funcall:
node_free (node->v.funcall.arg);
break;
case fmtnode_cntl:
node_list_free (node->v.cntl.cond);
node_list_free (node->v.cntl.iftrue);
node_list_free (node->v.cntl.iffalse);
break;
default:
abort ();
}
free (node);
}
static void
node_list_free (struct node *node)
{
while (node)
{
struct node *next = node->next;
node_free (node);
node = next;
}
}
static struct node *
typecast (struct node *node, enum mh_type type)
{
if (!node)
/* FIXME: when passing optional argument, the caller must know the
type of value returned by the previous expression */
return node;
if (node->datatype == type)
return node;
if (node->nodetype == fmtnode_cntl)
{
node->v.cntl.iftrue = typecast (node->v.cntl.iftrue, type);
node->v.cntl.iffalse = typecast (node->v.cntl.iffalse, type);
node->datatype = type;
}
else
{
struct node *np = new_node (fmtnode_typecast, type);
np->v.arg = node;
node = np;
}
return node;
}
#define INLINE -1
static inline void
indent (int level)
{
printf ("%*.*s", 2*level, 2*level, "");
}
static inline void
delim (int level, char const *dstr)
{
if (level == INLINE)
printf ("%s", dstr);
else
{
printf ("\n");
indent (level);
}
}
static void dump_statement (struct node *node, int level);
/* Make sure there are at least `count' entries available in the prog
buffer */
void
prog_reserve (size_t count)
mh_print_fmtspec (int fmtspec)
{
if (pc + count >= format.progsize)
if (!(fmtspec & (MH_FMT_RALIGN|MH_FMT_ZEROPAD|MH_FMT_COMPWS)))
printf ("NONE");
else
{
size_t inc = (count + 1) / FORMAT_INC + 1;
format.progsize += inc * FORMAT_INC;
format.prog = mu_realloc (format.prog,
format.progsize * sizeof format.prog[0]);
if (!(fmtspec & MH_FMT_RALIGN))
printf ("NO");
printf ("RALIGN|");
if (!(fmtspec & MH_FMT_ZEROPAD))
printf ("NO");
printf ("ZEROPAD|");
if (!(fmtspec & MH_FMT_COMPWS))
printf ("NO");
printf ("COMPWS");
}
}
size_t
mh_code_string (char *string)
static char *typename[] = { "NONE", "NUM", "STR" };
static void
dump_node_pretty (struct node *node, int level)
{
int length = strlen (string) + 1;
size_t count = (length + sizeof (mh_instr_t)) / sizeof (mh_instr_t);
size_t start_pc = pc;
switch (node->nodetype)
{
case fmtnode_print:
if (node->v.prt.fmtspec)
{
printf ("FORMAT(");
mh_print_fmtspec (node->v.prt.fmtspec);
printf(", %d, ", node->v.prt.fmtspec & MH_WIDTH_MASK);
}
else
printf ("PRINT(%d,", node->v.prt.fmtspec);
dump_statement (node->v.prt.arg, INLINE);
printf (")");
break;
case fmtnode_literal:
{
char const *p = node->v.str;
putchar ('"');
while (*p)
{
if (*p == '\\' || *p == '"')
{
putchar ('\\');
putchar (*p);
}
else if (*p == '\n')
{
putchar ('\\');
putchar ('n');
}
else
putchar (*p);
p++;
}
putchar ('"');
}
break;
case fmtnode_number:
printf ("%ld", node->v.num);
break;
case fmtnode_body:
printf ("BODY");
break;
case fmtnode_comp:
printf ("COMPONENT.%s", node->v.str);
break;
case fmtnode_funcall:
printf ("%s(", node->v.funcall.builtin->name);
dump_statement (node->v.funcall.arg, INLINE);
printf (")");
break;
mh_code_op (mhop_str_arg);
prog_reserve (count);
MHI_NUM(format.prog[pc++]) = count;
memcpy (MHI_STR(format.prog[pc]), string, length);
pc += count;
return start_pc;
case fmtnode_cntl:
printf ("IF (");
dump_node_pretty (node->v.cntl.cond, INLINE);
printf (") THEN");
if (level != INLINE)
level++;
delim (level, "; ");
dump_statement (node->v.cntl.iftrue, level);
if (node->v.cntl.iffalse)
{
delim (level == INLINE ? level : level - 1, "; ");
printf ("ELSE");
delim (level, " ");
dump_statement (node->v.cntl.iffalse, level);
}
if (level != INLINE)
level--;
delim (level, "; ");
printf ("FI");
break;
case fmtnode_typecast:
printf ("%s(", typename[node->datatype]);
dump_node_pretty (node->v.arg, INLINE);
printf (")");
break;
default:
abort ();
}
}
size_t
mh_code (mh_instr_t *instr)
static void
dump_statement (struct node *node, int level)
{
prog_reserve (1);
format.prog[pc] = *instr;
return pc++;
while (node)
{
dump_node_pretty (node, level);
node = node->next;
if (node)
delim (level, "; ");
}
}
size_t
mh_code_op (mh_opcode_t op)
void
mh_format_dump_code (mh_format_t fmt)
{
mh_instr_t instr;
MHI_OPCODE(instr) = op;
return mh_code(&instr);
dump_statement (fmt->tree, 0);
printf ("\n");
}
void
mh_format_free_tree (mh_format_t fmt)
{
if (fmt)
{
node_list_free (fmt->tree);
fmt->tree = NULL;
mu_opool_destroy (&fmt->pool);
}
}
size_t
mh_code_number (int num)
void
mh_format_free (mh_format_t fmt)
{
mh_instr_t instr;
size_t ret = mh_code_op (mhop_num_arg);
MHI_NUM(instr) = num;
mh_code (&instr);
return ret;
if (!fmt)
return;
mh_format_free_tree (fmt);
if (fmt->prog)
free (fmt->prog);
fmt->progmax = fmt->progcnt = 0;
fmt->prog = NULL;
}
size_t
mh_code_builtin (mh_builtin_t *bp, int argtype)
void
mh_format_destroy (mh_format_t *fmt)
{
mh_instr_t instr;
size_t start_pc = pc;
if (bp->argtype != argtype)
if (fmt)
{
if (argtype == mhtype_none)
mh_format_free (*fmt);
*fmt = NULL;
}
}
static struct node *
printelim (struct node *node)
{
if (node->nodetype == fmtnode_print)
{
if (bp->optarg)
struct node *arg = node->v.prt.arg;
arg->next = node->next;
free (node);
node = arg;
}
return node;
}
#define PROG_MIN_ALLOC 8
static inline void
ensure_space (struct mh_format *fmt, size_t n)
{
while (fmt->progcnt + n >= fmt->progmax)
{
switch (bp->argtype)
if (fmt->progmax == 0)
fmt->progmax = n < PROG_MIN_ALLOC ? PROG_MIN_ALLOC : n;
fmt->prog = mu_2nrealloc (fmt->prog, &fmt->progmax, sizeof fmt->prog[0]);
}
}
static void
emit_instr (struct mh_format *fmt, mh_instr_t instr)
{
ensure_space (fmt, 1);
fmt->prog[fmt->progcnt++] = instr;
}
static inline void
emit_opcode (struct mh_format *fmt, mh_opcode_t op)
{
emit_instr (fmt, (mh_instr_t) op);
}
static void
emit_string (struct mh_format *fmt, char const *str)
{
size_t length = strlen (str) + 1;
size_t count = (length + sizeof (mh_instr_t)) / sizeof (mh_instr_t) + 1;
ensure_space (fmt, count);
emit_instr (fmt, (mh_instr_t) count);
memcpy (MHI_STR (fmt->prog[fmt->progcnt]), str, length);
fmt->progcnt += count;
}
static void codegen_node (struct mh_format *fmt, struct node *node);
static void codegen_nodelist (struct mh_format *fmt, struct node *node);
static void
emit_opcode_typed (struct mh_format *fmt, enum mh_type type,
enum mh_opcode opnum, enum mh_opcode opstr)
{
switch (type)
{
case mhtype_num:
mh_code_op (mhop_num_to_arg);
emit_opcode (fmt, opnum);
break;
case mhtype_str:
if (bp->optarg == MHA_OPT_CLEAR)
mh_code_string ("");
/* mhtype_none means that the argument was an escape,
which has left its string value (if any) in the
arg_str register. Therefore, there's no need to
code mhop_str_to_arg */
emit_opcode (fmt, opstr);
break;
default:
yyerror (_("INTERNAL ERROR: unknown argtype (please report)"));
abort ();
}
}
else
}
static void
emit_funcall (struct mh_format *fmt, mh_builtin_t *builtin, struct node *arg)
{
if (arg)
{
mu_error (_("missing argument for %s"), bp->name);
return 0;
codegen_node (fmt, arg);
emit_opcode_typed (fmt, arg->datatype, mhop_movn, mhop_movs);
}
else if (builtin->argtype != mhtype_none)
emit_opcode_typed (fmt, builtin->type, mhop_movn, mhop_movs);
emit_instr (fmt, (mh_instr_t) (long) R_ARG);
emit_instr (fmt, (mh_instr_t) (long) R_REG);
emit_opcode (fmt, mhop_call);
emit_instr (fmt, (mh_instr_t) builtin->fun);
}
static void
codegen_node (struct mh_format *fmt, struct node *node)
{
switch (node->nodetype)
{
case fmtnode_print:
codegen_node (fmt, node->v.prt.arg);
if (node->v.prt.fmtspec)
{
emit_opcode (fmt, mhop_fmtspec);
emit_instr (fmt, (mh_instr_t) (long) node->v.prt.fmtspec);
}
else
if (node->v.prt.arg->datatype != mhtype_none)
emit_opcode_typed (fmt, node->v.prt.arg->datatype,
mhop_printn, mhop_prints);
break;
case fmtnode_literal:
emit_opcode (fmt, mhop_sets);
emit_instr (fmt, (mh_instr_t) (long) R_REG);
emit_string (fmt, node->v.str);
break;
case fmtnode_number:
emit_opcode (fmt, mhop_setn);
emit_instr (fmt, (mh_instr_t) (long) R_REG);
break;
case fmtnode_body:
emit_opcode (fmt, mhop_ldbody);
emit_instr (fmt, (mh_instr_t) (long) R_REG);
break;
case fmtnode_comp:
emit_opcode (fmt, mhop_ldcomp);
emit_instr (fmt, (mh_instr_t) (long) R_REG);
emit_string (fmt, node->v.str);
break;
case fmtnode_funcall:
emit_funcall (fmt, node->v.funcall.builtin, node->v.funcall.arg);
break;
case fmtnode_cntl:
{
switch (bp->argtype)
long pc[2];
codegen_node (fmt, node->v.cntl.cond);
emit_opcode_typed (fmt, node->v.cntl.cond->datatype,
mhop_brzn, mhop_brzs);
pc[0] = fmt->progcnt;
emit_instr (fmt, (mh_instr_t) NULL);
if (node->v.cntl.iftrue)
{
case mhtype_none:
mu_error (_("extra arguments to %s"), bp->name);
return 0;
codegen_nodelist (fmt, node->v.cntl.iftrue);
}
emit_opcode (fmt, mhop_branch);
pc[1] = fmt->progcnt;
emit_instr (fmt, (mh_instr_t) NULL);
fmt->prog[pc[0]].num = fmt->progcnt - pc[0];
if (node->v.cntl.iffalse)
{
codegen_nodelist (fmt, node->v.cntl.iffalse);
}
fmt->prog[pc[1]].num = fmt->progcnt - pc[1];
}
break;
case fmtnode_typecast:
codegen_node (fmt, node->v.arg);
switch (node->datatype)
{
case mhtype_num:
mh_code_op (mhop_str_to_num);
emit_opcode (fmt, mhop_itoa);
break;
case mhtype_str:
mh_code_op (mhop_num_to_str);
emit_opcode (fmt, mhop_atoi);
break;
default:
abort ();
}
break;
default:
abort ();
}
}
static void
codegen_nodelist (struct mh_format *fmt, struct node *node)
{
while (node)
{
codegen_node (fmt, node);
node = node->next;
}
}
static void
codegen (mh_format_t *fmtptr, int tree)
{
struct mh_format *fmt;
fmt = mu_zalloc (sizeof *fmt);
mh_code_op (mhop_call);
MHI_BUILTIN(instr) = bp->fun;
mh_code (&instr);
return start_pc;
*fmtptr = fmt;
emit_opcode (fmt, mhop_stop);
codegen_nodelist (fmt, parse_tree);
emit_opcode (fmt, mhop_stop);
if (tree)
{
fmt->tree = parse_tree;
fmt->pool = tokpool;
}
else
{
node_list_free (parse_tree);
mu_opool_destroy (&tokpool);
}
}
......
......@@ -28,92 +28,97 @@
#include "mbchar.h"
#include "mbswidth.h"
static char *_get_builtin_name (mh_builtin_fp ptr);
#define DFLWIDTH(mach) ((mach)->width - (mach)->ind)
/* String functions */
/* Functions for handling string objects. */
#define MH_STRING_INITIALIZER { 0, NULL }
void
strobj_free (strobj_t *obj)
static inline void
mh_string_init (struct mh_string *s)
{
if (obj->size)
free (obj->ptr);
obj->size = 0;
obj->ptr = NULL;
s->size = 0;
s->ptr = NULL;
}
void
strobj_create (strobj_t *lvalue, const char *str)
static void
mh_string_free (struct mh_string *s)
{
if (!str)
{
lvalue->size = 0;
lvalue->ptr = NULL;
}
else
free (s->ptr);
s->size = 0;
s->ptr = NULL;
}
static void
mh_string_realloc (struct mh_string *s, size_t length)
{
if (length > s->size)
{
lvalue->size = strlen (str) + 1;
lvalue->ptr = mu_alloc (lvalue->size);
memcpy (lvalue->ptr, str, lvalue->size);
s->ptr = mu_realloc (s->ptr, length);
s->ptr[length-1] = 0;
s->size = length;
}
}
void
strobj_set (strobj_t *lvalue, char *str)
static inline int
mh_string_is_null (struct mh_string *s)
{
lvalue->size = 0;
lvalue->ptr = str;
return s->ptr == NULL || s->ptr[0] == 0;
}
void
strobj_assign (strobj_t *lvalue, strobj_t *rvalue)
static inline size_t
mh_string_length (struct mh_string *s)
{
strobj_free (lvalue);
*lvalue = *rvalue;
rvalue->size = 0;
rvalue->ptr = NULL;
return mh_string_is_null (s) ? 0 : strlen (s->ptr);
}
void
strobj_copy (strobj_t *lvalue, strobj_t *rvalue)
static inline char const *
mh_string_value (struct mh_string *s)
{
if (strobj_is_null (rvalue))
strobj_free (lvalue);
else if (lvalue->size >= strobj_len (rvalue) + 1)
memcpy (lvalue->ptr, strobj_ptr (rvalue), strobj_len (rvalue) + 1);
else
{
if (lvalue->size)
strobj_free (lvalue);
strobj_create (lvalue, strobj_ptr (rvalue));
}
return mh_string_is_null (s) ? "" : s->ptr;
}
void
strobj_realloc (strobj_t *obj, size_t length)
static inline void
mh_string_clear (struct mh_string *s)
{
if (strobj_is_static (obj))
{
char *value = strobj_ptr (obj);
obj->ptr = mu_alloc (length);
strncpy (obj->ptr, value, length-1);
obj->ptr[length-1] = 0;
obj->size = length;
}
if (s->ptr)
s->ptr[0] = 0;
}
static void
mh_string_load (struct mh_string *s, char const *str)
{
if (!str)
mh_string_clear (s);
else
{
obj->ptr = mu_realloc (obj->ptr, length);
obj->ptr[length-1] = 0;
obj->size = length;
mh_string_realloc (s, strlen (str));
strcpy (s->ptr, str);
}
}
static void
mh_string_move (struct mh_machine *mach, enum regid dst, enum regid src)
{
mh_string_load (&mach->str[dst], mach->str[src].ptr);
mh_string_clear (&mach->str[src]);
}
static char *_get_builtin_name (mh_builtin_fp ptr);
static inline size_t
output_width (struct mh_machine *mach)
{
if (mach->width < mach->ind)
return 0;
return mach->width - mach->ind;
}
/* Return the length (number of octets) of a substring of
string STR of length LEN, such that it contains NCOL
multibyte characters. */
int
mbsubstrlen (char *str, size_t len, size_t ncol)
mbsubstrlen (char const *str, size_t len, size_t ncol)
{
int ret = 0;
mbi_iterator_t iter;
......@@ -131,7 +136,7 @@ mbsubstrlen (char *str, size_t len, size_t ncol)
/* Return the number of multibyte characters in the first LEN bytes
of character string STRING. */
size_t
mbsnlen (char *str, size_t len)
mbsnlen (char const *str, size_t len)
{
int ret = 0;
mbi_iterator_t iter;
......@@ -143,10 +148,10 @@ mbsnlen (char *str, size_t len)
/* Compress whitespace in a string (multi-byte) */
static void
compress_ws (char *str, size_t *psize)
str_compress_ws (char *str)
{
unsigned char *p, *q;
size_t size = *psize;
size_t size = strlen (str);
mbi_iterator_t iter;
int space = 0;
......@@ -173,29 +178,26 @@ compress_ws (char *str, size_t *psize)
}
}
*p = 0;
*psize = p - (unsigned char*) str;
}
#define COMPRESS_WS(mach, str, size) \
do \
{ \
if ((mach)->fmtflags & MH_FMT_COMPWS) \
compress_ws (str, size); \
} \
while (0)
static inline void
compress_ws (struct mh_machine *mach, char *str)
{
if (mach->fmtflags & MH_FMT_COMPWS)
str_compress_ws (str);
}
static void
put_string (struct mh_machine *mach, char *str, int len)
put_string (struct mh_machine *mach, char const *str, int len)
{
if (len == 0)
return;
mu_opool_append (mach->pool, str, len);
len = mbsnwidth (str, len, 0);
mach->ind += len;
mu_stream_write (mach->output, str, len, NULL);
mach->ind += mbsnwidth (str, len, 0);
}
static void
print_hdr_segment (struct mh_machine *mach, char *str, size_t len)
print_hdr_segment (struct mh_machine *mach, char const *str, size_t len)
{
if (!len)
len = strlen (str);
......@@ -207,7 +209,7 @@ print_hdr_segment (struct mh_machine *mach, char *str, size_t len)
while (1)
{
mbi_iterator_t iter;
size_t rest = DFLWIDTH (mach);
size_t rest = output_width (mach);
size_t width = mbsnlen (str, len);
size_t off, size;
......@@ -245,11 +247,10 @@ print_hdr_segment (struct mh_machine *mach, char *str, size_t len)
}
}
/* Print len bytes from str into mach->outbuf */
static void
print_hdr_string (struct mh_machine *mach, char *str)
print_hdr_string (struct mh_machine *mach, char const *str)
{
char *p;
char const *p;
if (!str)
str = "";
......@@ -269,7 +270,7 @@ print_hdr_string (struct mh_machine *mach, char *str)
static void
print_simple_segment (struct mh_machine *mach, size_t width,
char *str, size_t len)
char const *str, size_t len)
{
size_t rest;
......@@ -282,7 +283,7 @@ print_simple_segment (struct mh_machine *mach, size_t width,
if (!width)
width = mach->width;
rest = DFLWIDTH (mach);
rest = output_width (mach);
if (rest == 0)
{
if (len == 1 && str[0] == '\n')
......@@ -294,7 +295,7 @@ print_simple_segment (struct mh_machine *mach, size_t width,
}
static void
print_string (struct mh_machine *mach, size_t width, char *str)
print_string (struct mh_machine *mach, size_t width, char const *str)
{
char *p;
......@@ -318,7 +319,7 @@ print_string (struct mh_machine *mach, size_t width, char *str)
}
static void
print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char *str,
print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char const *str,
size_t len)
{
size_t width = mbsnlen (str, len);
......@@ -329,7 +330,7 @@ print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char *str,
width = fmtwidth;
}
else
len = mbsubstrlen (str, len, DFLWIDTH (mach));
len = mbsubstrlen (str, len, output_width (mach));
put_string (mach, str, len);
......@@ -338,12 +339,12 @@ print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char *str,
fmtwidth -= width;
mach->ind += fmtwidth;
while (fmtwidth--)
mu_opool_append_char (mach->pool, ' ');
mu_stream_write (mach->output, " ", 1, NULL);
}
}
static void
print_fmt_string (struct mh_machine *mach, size_t fmtwidth, char *str)
print_fmt_string (struct mh_machine *mach, size_t fmtwidth, char const *str)
{
char *p = strchr (str, '\n');
while (p)
......@@ -376,7 +377,7 @@ format_num (struct mh_machine *mach, long num)
char buf[64];
char *ptr;
int fmtwidth = mach->fmtflags & MH_WIDTH_MASK;
int padchar = mach->fmtflags & MH_FMT_ZEROPAD ? '0' : ' ';
char padchar = mach->fmtflags & MH_FMT_ZEROPAD ? '0' : ' ';
n = snprintf (buf, sizeof buf, "%ld", num);
......@@ -393,7 +394,7 @@ format_num (struct mh_machine *mach, long num)
ptr = buf;
for (i = n; i < fmtwidth && mach->ind < mach->width;
i++, mach->ind++)
mu_opool_append_char (mach->pool, padchar);
mu_stream_write (mach->output, &padchar, 1, NULL);
}
}
else
......@@ -404,7 +405,7 @@ format_num (struct mh_machine *mach, long num)
}
static void
format_str (struct mh_machine *mach, char *str)
format_str (struct mh_machine *mach, char const *str)
{
if (!str)
str = "";
......@@ -412,7 +413,7 @@ format_str (struct mh_machine *mach, char *str)
{
int len = strlen (str);
int fmtwidth = mach->fmtflags & MH_WIDTH_MASK;
int padchar = ' ';
char padchar = ' ';
if (mach->fmtflags & MH_FMT_RALIGN)
{
......@@ -421,7 +422,7 @@ format_str (struct mh_machine *mach, char *str)
n = fmtwidth - len;
for (i = 0; i < n && mach->ind < mach->width;
i++, mach->ind++, fmtwidth--)
mu_opool_append_char (mach->pool, padchar);
mu_stream_write (mach->output, &padchar, 1, NULL);
}
print_fmt_string (mach, fmtwidth, str);
......@@ -472,28 +473,28 @@ addrlist_destroy (mu_list_t *list)
}
/* Execute pre-compiled format on message msg with number msgno.
buffer and bufsize specify output storage */
*/
int
mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno,
size_t width, char **pret)
mh_format (mh_format_t fmt, mu_message_t msg, size_t msgno,
size_t width, mu_stream_t output)
{
struct mh_machine mach;
char buf[64];
const char *charset = mh_global_profile_get ("Charset", NULL);
memset (&mach, 0, sizeof (mach));
mach.progsize = fmt->progsize;
mach.progcnt = fmt->progcnt;
mach.prog = fmt->prog;
mach.message = msg;
mach.msgno = msgno;
mach.output = output;
if (width == 0)
width = mh_width ();
mach.width = width - 1; /* Count the newline */
mach.pc = 1;
mu_opool_create (&mach.pool, MU_OPOOL_ENOMEMABRT);
mu_list_create (&mach.addrlist);
MU_ASSERT (mu_list_create (&mach.addrlist));
reset_fmt_defaults (&mach);
......@@ -524,14 +525,12 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno,
}
#endif
while (!mach.stop && mach.ind < mach.width)
while (!mach.stop)
{
mh_opcode_t opcode;
switch (opcode = MHI_OPCODE (mach.prog[mach.pc++]))
{
case mhop_nop:
break;
case mhop_stop:
mach.stop = 1;
break;
......@@ -540,128 +539,138 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno,
mach.pc += MHI_NUM (mach.prog[mach.pc]);
break;
case mhop_num_asgn:
mach.reg_num = mach.arg_num;
case mhop_brzn:
if (!mach.num[R_REG])
mach.pc += MHI_NUM (mach.prog[mach.pc]);
else
mach.pc++;
break;
case mhop_str_asgn:
strobj_assign (&mach.reg_str, &mach.arg_str);
case mhop_brzs:
if (mh_string_is_null (&mach.str[R_REG]))
mach.pc += MHI_NUM (mach.prog[mach.pc]);
else
mach.pc++;
break;
case mhop_num_arg:
mach.arg_num = MHI_NUM (mach.prog[mach.pc++]);
case mhop_setn:
{
long reg = MHI_NUM (mach.prog[mach.pc++]);
mach.num[reg] = MHI_NUM (mach.prog[mach.pc++]);
}
break;
case mhop_str_arg:
case mhop_sets:
{
long reg = MHI_NUM (mach.prog[mach.pc++]);
size_t skip = MHI_NUM (mach.prog[mach.pc++]);
strobj_set (&mach.arg_str, MHI_STR (mach.prog[mach.pc]));
char const *str = MHI_STR (mach.prog[mach.pc]);
mach.pc += skip;
}
break;
case mhop_num_branch:
if (!mach.arg_num)
mach.pc += MHI_NUM (mach.prog[mach.pc]);
else
mach.pc++;
mh_string_load (&mach.str[reg], str);
}
break;
case mhop_str_branch:
if (!*strobj_ptr (&mach.arg_str))
mach.pc += MHI_NUM (mach.prog[mach.pc]);
else
mach.pc++;
case mhop_movn:
{
long dst = MHI_NUM (mach.prog[mach.pc++]);
long src = MHI_NUM (mach.prog[mach.pc++]);
mach.num[dst] = mach.num[src];
}
break;
case mhop_call:
MHI_BUILTIN (mach.prog[mach.pc++]) (&mach);
case mhop_movs:
{
long dst = MHI_NUM (mach.prog[mach.pc++]);
long src = MHI_NUM (mach.prog[mach.pc++]);
mh_string_move (&mach, dst, src);
/* FIXME: perhaps copy, not move? */
}
break;
case mhop_header:
case mhop_ldcomp:
{
long reg = MHI_NUM (mach.prog[mach.pc++]);
size_t skip = MHI_NUM (mach.prog[mach.pc++]);
char const *comp = MHI_STR (mach.prog[mach.pc]);
mu_header_t hdr = NULL;
char *value = NULL;
mach.pc += skip;
mu_message_get_header (mach.message, &hdr);
mu_header_aget_value_unfold (hdr, strobj_ptr (&mach.arg_str), &value);
strobj_free (&mach.arg_str);
mu_header_aget_value_unfold (hdr, comp, &value);
mh_string_clear (&mach.str[reg]);
if (value)
{
size_t len = strlen (value);
mach.arg_str.size = len + 1;
COMPRESS_WS (&mach, value, &len);
mach.arg_str.ptr = value;
mach.arg_num = 1;
compress_ws (&mach, value);
mh_string_load (&mach.str[reg], value);
free (value);
}
else
mach.arg_num = 0;
}
break;
case mhop_body:
case mhop_ldbody:
{
long reg = MHI_NUM (mach.prog[mach.pc++]);
mu_body_t body = NULL;
mu_stream_t stream = NULL;
size_t size = 0, str_off, nread;
size_t rest = DFLWIDTH (&mach);
size_t size = 0;
size_t rest = output_width (&mach);
mh_string_clear (&mach.str[reg]);
strobj_free (&mach.arg_str);
mu_message_get_body (mach.message, &body);
mu_body_size (body, &size);
if (size == 0)
break;
mu_body_get_streamref (body, &stream);
if (!stream)
break;
if (stream)
{
if (size > rest)
size = rest;
mach.arg_str.ptr = mu_alloc (size+1);
mach.arg_str.size = size;
mh_string_realloc (&mach.str[reg], size + 1);
mu_stream_read (stream, mach.str[reg].ptr, size, NULL);
mach.str[reg].ptr[size] = 0;
compress_ws (&mach, mach.str[reg].ptr);
str_off = 0;
while (!mu_stream_read (stream, mach.arg_str.ptr + str_off,
mach.arg_str.size - str_off, &nread)
&& nread != 0
&& str_off < size)
{
COMPRESS_WS (&mach, mach.arg_str.ptr + str_off, &nread);
if (nread)
str_off += nread;
}
mu_stream_destroy (&stream);
mach.arg_str.ptr[str_off] = 0;
}
}
break;
/* assign reg_num to arg_num */
case mhop_num_to_arg:
mach.arg_num = mach.reg_num;
break;
/* assign reg_str to arg_str */
case mhop_str_to_arg:
strobj_copy (&mach.arg_str, &mach.reg_str);
case mhop_call:
MHI_BUILTIN (mach.prog[mach.pc++]) (&mach);
break;
/* Convert arg_str to arg_num */
case mhop_str_to_num:
mach.arg_num = strtoul (strobj_ptr (&mach.arg_str), NULL, 0);
/* Convert string register to number */
case mhop_atoi:
{
long reg = MHI_NUM (mach.prog[mach.pc++]);
if (mh_string_is_null (&mach.str[reg]))
mach.num[reg] = 0;
else
mach.num[reg] = strtoul (mach.str[reg].ptr, NULL, 0);
}
break;
/* Convert arg_num to arg_str */
case mhop_num_to_str:
snprintf (buf, sizeof buf, "%lu", mach.arg_num);
strobj_free (&mach.arg_str);
strobj_create (&mach.arg_str, buf);
/* Convert numeric register to string */
case mhop_itoa:
{
long reg = MHI_NUM (mach.prog[mach.pc++]);
mu_asnprintf (&mach.str[reg].ptr, &mach.str[reg].size,
"%lu", mach.num[reg]);
}
break;
case mhop_num_print:
format_num (&mach, mach.reg_num);
case mhop_printn:
format_num (&mach, mach.num[R_REG]);
break;
case mhop_str_print:
format_str (&mach, strobj_ptr (&mach.reg_str));
case mhop_prints:
format_str (&mach, mach.str[R_REG].ptr);
break;
case mhop_fmtspec:
......@@ -673,19 +682,14 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno,
abort ();
}
}
strobj_free (&mach.reg_str);
strobj_free (&mach.arg_str);
mh_string_free (&mach.str[R_REG]);
mh_string_free (&mach.str[R_ARG]);
addrlist_destroy (&mach.addrlist);
if (pret)
{
mu_opool_append_char (mach.pool, 0);
*pret = mu_strdup (mu_opool_finish (mach.pool, NULL));
}
mu_opool_destroy (&mach.pool);
return mach.ind;
}
//FIXME
#if 0
int
mh_format_str (mh_format_t *fmt, char *str, size_t width, char **pret)
{
......@@ -701,197 +705,7 @@ mh_format_str (mh_format_t *fmt, char *str, size_t width, char **pret)
mu_message_destroy (&msg, NULL);
return rc;
}
void
mh_format_dump (mh_format_t *fmt)
{
mh_instr_t *prog = fmt->prog;
size_t pc = 1;
int stop = 0;
while (!stop)
{
mh_opcode_t opcode;
int num;
printf ("% 4.4ld: ", (long) pc);
switch (opcode = MHI_OPCODE (prog[pc++]))
{
case mhop_nop:
printf ("nop");
break;
case mhop_stop:
printf ("stop");
stop = 1;
break;
case mhop_branch:
num = MHI_NUM (prog[pc++]);
printf ("branch %d, %lu",
num, (unsigned long) pc + num - 1);
break;
case mhop_num_asgn:
printf ("num_asgn");
break;
case mhop_str_asgn:
printf ("str_asgn");
break;
case mhop_num_arg:
num = MHI_NUM (prog[pc++]);
printf ("num_arg %d", num);
break;
case mhop_str_arg:
{
size_t skip = MHI_NUM (prog[pc++]);
char *s = MHI_STR (prog[pc]);
printf ("str_arg \"");
for (; *s; s++)
{
switch (*s)
{
case '\a':
printf ("\\a");
break;
case '\b':
printf ("\\b");
break;
case '\f':
printf ("\\f");
break;
case '\n':
printf ("\\n");
break;
case '\r':
printf ("\\r");
break;
case '\t':
printf ("\\t");
break;
case '"':
printf ("\\\"");
break;
default:
if (isprint (*s))
putchar (*s);
else
printf ("\\%03o", *s);
break;
}
}
printf ("\"");
pc += skip;
}
break;
case mhop_num_branch:
num = MHI_NUM (prog[pc++]);
printf ("num_branch %d, %lu",
num, (unsigned long) (pc + num - 1));
break;
case mhop_str_branch:
num = MHI_NUM (prog[pc++]);
printf ("str_branch %d, %lu",
num, (unsigned long) (pc + num - 1));
break;
case mhop_call:
{
char *name = _get_builtin_name (MHI_BUILTIN (prog[pc++]));
printf ("call %s", name ? name : "UNKNOWN");
}
break;
case mhop_header:
printf ("header");
break;
case mhop_body:
printf ("body");
break;
case mhop_num_to_arg:
printf ("num_to_arg");
break;
/* assign reg_str to arg_str */
case mhop_str_to_arg:
printf ("str_to_arg");
break;
/* Convert arg_str to arg_num */
case mhop_str_to_num:
printf ("str_to_num");
break;
/* Convert arg_num to arg_str */
case mhop_num_to_str:
printf ("num_to_str");
break;
case mhop_num_print:
printf ("print");
break;
case mhop_str_print:
printf ("str_print");
break;
case mhop_fmtspec:
{
int space = 0;
num = MHI_NUM (prog[pc++]);
printf ("fmtspec: %#x, ", num);
if (num & MH_FMT_RALIGN)
{
printf ("MH_FMT_RALIGN");
space++;
}
if (num & MH_FMT_ZEROPAD)
{
if (space)
printf ("|");
printf ("MH_FMT_ZEROPAD");
space++;
}
if (space)
printf ("; ");
printf ("%d", num & MH_WIDTH_MASK);
}
break;
default:
mu_error ("Unknown opcode: %x", opcode);
abort ();
}
printf ("\n");
}
}
/* Free any memory associated with a format structure. The structure
itself is assumed to be in static storage. */
void
mh_format_free (mh_format_t *fmt)
{
if (fmt->prog)
free (fmt->prog);
fmt->progsize = 0;
fmt->prog = NULL;
}
#endif
/* Built-in functions */
......@@ -907,7 +721,7 @@ builtin_msg (struct mh_machine *mach)
{
size_t msgno = mach->msgno;
mh_message_number (mach->message, &msgno);
mach->arg_num = msgno;
mach->num[R_REG] = msgno;
}
static void
......@@ -926,7 +740,7 @@ builtin_cur (struct mh_machine *mach)
}
mh_message_number (mach->message, &msgno);
mh_mailbox_get_cur (mbox, &cur); /* FIXME: Cache this */
mach->arg_num = msgno == cur;
mach->num[R_REG] = msgno == cur;
}
static void
......@@ -934,25 +748,27 @@ builtin_size (struct mh_machine *mach)
{
size_t size;
if (mu_message_size (mach->message, &size) == 0)
mach->arg_num = size;
mach->num[R_REG] = size;
else
mach->num[R_REG] = 0;
}
static void
builtin_strlen (struct mh_machine *mach)
{
mach->arg_num = strlen (strobj_ptr (&mach->arg_str));
mach->num[R_REG] = mh_string_length (&mach->str[R_ARG]);
}
static void
builtin_width (struct mh_machine *mach)
{
mach->arg_num = mach->width;
mach->num[R_REG] = mach->width;
}
static void
builtin_charleft (struct mh_machine *mach)
{
mach->arg_num = DFLWIDTH (mach);
mach->num[R_REG] = output_width (mach);
}
static void
......@@ -961,186 +777,175 @@ builtin_timenow (struct mh_machine *mach)
time_t t;
time (&t);
mach->arg_num = t;
mach->num[R_REG] = t;
}
static void
builtin_me (struct mh_machine *mach)
{
char *s = mh_my_email ();
strobj_realloc (&mach->arg_str, strlen (s) + 3);
sprintf (strobj_ptr (&mach->arg_str), "<%s>", s);
char *s;
mu_asprintf (&s, "<%s>", mh_my_email ());
mh_string_load (&mach->str[R_REG], s);
free (s);
}
static void
builtin_eq (struct mh_machine *mach)
{
mach->arg_num = mach->reg_num == mach->arg_num;
mach->num[R_REG] = mach->num[R_REG] == mach->num[R_ARG];
}
static void
builtin_ne (struct mh_machine *mach)
{
mach->arg_num = mach->reg_num != mach->arg_num;
mach->num[R_REG] = mach->num[R_REG] != mach->num[R_ARG];
}
static void
builtin_gt (struct mh_machine *mach)
{
mach->arg_num = mach->reg_num > mach->arg_num;
mach->num[R_REG] = mach->num[R_REG] > mach->num[R_ARG];
}
static void
builtin_match (struct mh_machine *mach)
{
mach->arg_num = strstr (strobj_ptr (&mach->reg_str),
strobj_ptr (&mach->arg_str)) != NULL;
mach->num[R_REG] = strstr (mh_string_value (&mach->str[R_REG]),
mh_string_value (&mach->str[R_ARG])) != NULL;
}
static void
builtin_amatch (struct mh_machine *mach)
{
int len = strobj_len (&mach->arg_str);
mach->arg_num = strncmp (strobj_ptr (&mach->reg_str),
strobj_ptr (&mach->arg_str), len);
char const *arg = mh_string_value (&mach->str[R_ARG]);
size_t len = strlen (arg);
mach->num[R_REG] = strncmp (mh_string_value (&mach->str[R_REG]), arg, len);
}
static void
builtin_plus (struct mh_machine *mach)
{
mach->arg_num += mach->reg_num;
mach->num[R_REG] += mach->num[R_ARG];
}
static void
builtin_minus (struct mh_machine *mach)
{
mach->arg_num -= mach->reg_num;
mach->num[R_REG] -= mach->num[R_ARG];
}
static void
builtin_divide (struct mh_machine *mach)
{
if (!mach->arg_num)
if (mach->num[R_ARG] == 0)
{
/* TRANSLATORS: Do not translate the word 'format'! */
mu_error (_("format: divide by zero"));
mach->stop = 1;
}
else
mach->arg_num = mach->reg_num / mach->arg_num;
mach->num[R_REG] /= mach->num[R_ARG];
}
static void
builtin_modulo (struct mh_machine *mach)
{
if (!mach->arg_num)
if (mach->num[R_ARG] == 0)
{
mu_error (_("format: divide by zero"));
mach->stop = 1;
}
else
mach->arg_num = mach->reg_num % mach->arg_num;
mach->num[R_REG] %= mach->num[R_ARG];
}
static void
builtin_num (struct mh_machine *mach)
{
mach->reg_num = mach->arg_num;
mach->num[R_REG] = mach->num[R_ARG];
}
static void
builtin_lit (struct mh_machine *mach)
{
/* do nothing */
/* FIXME: do nothing */
}
static void
builtin_getenv (struct mh_machine *mach)
{
char *val = getenv (strobj_ptr (&mach->arg_str));
strobj_free (&mach->arg_str);
strobj_create (&mach->arg_str, val);
char const *val = getenv (mh_string_value (&mach->str[R_ARG]));
mh_string_load (&mach->str[R_REG], val);
}
static void
builtin_profile (struct mh_machine *mach)
{
char *val = strobj_ptr (&mach->arg_str);
strobj_free (&mach->arg_str);
strobj_create (&mach->arg_str, mh_global_profile_get (val, ""));
char const *val = mh_global_profile_get (mh_string_value (&mach->str[R_ARG]),
"");
mh_string_load (&mach->str[R_REG], val);
}
static void
builtin_nonzero (struct mh_machine *mach)
{
mach->arg_num = mach->reg_num;
mach->num[R_REG] = mach->num[R_ARG] != 0;
}
static void
builtin_zero (struct mh_machine *mach)
{
mach->arg_num = !mach->reg_num;
mach->num[R_REG] = mach->num[R_ARG] == 0;
}
static void
builtin_null (struct mh_machine *mach)
{
char *s = strobj_ptr (&mach->reg_str);
mach->arg_num = !s && !s[0];
mach->num[R_REG] = mh_string_is_null (&mach->str[R_ARG]);
}
static void
builtin_nonnull (struct mh_machine *mach)
{
char *s = strobj_ptr (&mach->reg_str);
mach->arg_num = s && s[0];
mach->num[R_REG] = !mh_string_is_null (&mach->str[R_ARG]);
}
/* comp comp string Set str to component text*/
static void
builtin_comp (struct mh_machine *mach)
{
strobj_assign (&mach->reg_str, &mach->arg_str);
/* FIXME: Check this */
mh_string_move (mach, R_REG, R_ARG);
}
/* compval comp integer num set to "atoi(comp)"*/
static void
builtin_compval (struct mh_machine *mach)
{
mach->reg_num = strtoul (strobj_ptr (&mach->arg_str), NULL, 0);
/* FIXME: Check this */
mach->num[R_REG] = strtol (mh_string_value (&mach->str[R_ARG]), NULL, 0);
}
/* trim expr trim trailing white-space from str*/
static void
builtin_trim (struct mh_machine *mach)
{
char *p, *start;
int len;
if (strobj_is_static (&mach->arg_str))
strobj_copy (&mach->arg_str, &mach->arg_str);
start = strobj_ptr (&mach->arg_str);
len = strlen (start);
if (len == 0)
return;
for (p = start + len - 1; p >= start && isspace (*p); p--)
;
p[1] = 0;
if (!mh_string_is_null (&mach->str[R_REG]))
mu_rtrim_class (mach->str[R_REG].ptr, MU_CTYPE_SPACE);
}
/* putstr expr print str*/
static void
builtin_putstr (struct mh_machine *mach)
{
print_string (mach, 0, strobj_ptr (&mach->arg_str));
print_string (mach, 0, mh_string_value (&mach->str[R_ARG]));
}
/* putstrf expr print str in a fixed width*/
static void
builtin_putstrf (struct mh_machine *mach)
{
format_str (mach, strobj_ptr (&mach->arg_str));
format_str (mach, mh_string_value (&mach->str[R_ARG]));
}
/* putnum expr print num*/
......@@ -1148,7 +953,7 @@ static void
builtin_putnum (struct mh_machine *mach)
{
char *p;
mu_asprintf (&p, "%ld", mach->arg_num);
mu_asprintf (&p, "%ld", mach->num[R_ARG]);
print_string (mach, 0, p);
free (p);
}
......@@ -1157,16 +962,16 @@ builtin_putnum (struct mh_machine *mach)
static void
builtin_putnumf (struct mh_machine *mach)
{
format_num (mach, mach->arg_num);
format_num (mach, mach->num[R_ARG]);
}
static int
_parse_date (struct mh_machine *mach, struct tm *tm, struct mu_timezone *tz)
{
char *date = strobj_ptr (&mach->arg_str);
char const *date = mh_string_value (&mach->str[R_ARG]);
const char *p = date;
if (mu_parse822_date_time (&p, date+strlen(date), tm, tz))
if (mu_parse822_date_time (&p, date + strlen(date), tm, tz))
{
time_t t;
......@@ -1189,7 +994,7 @@ builtin_sec (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = tm.tm_sec;
mach->num[R_REG] = tm.tm_sec;
}
/* min date integer minutes of the hour*/
......@@ -1202,7 +1007,7 @@ builtin_min (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = tm.tm_min;
mach->num[R_REG] = tm.tm_min;
}
/* hour date integer hours of the day (0-23)*/
......@@ -1215,7 +1020,7 @@ builtin_hour (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = tm.tm_hour;
mach->num[R_REG] = tm.tm_hour;
}
/* wday date integer day of the week (Sun=0)*/
......@@ -1228,7 +1033,7 @@ builtin_wday (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = tm.tm_wday;
mach->num[R_REG] = tm.tm_wday;
}
/* day date string day of the week (abbrev.)*/
......@@ -1243,8 +1048,7 @@ builtin_day (struct mh_machine *mach)
return;
strftime (buf, sizeof buf, "%a", &tm);
strobj_free (&mach->arg_str);
strobj_create (&mach->arg_str, buf);
mh_string_load (&mach->str[R_REG], buf);
}
/* weekday date string day of the week */
......@@ -1257,10 +1061,8 @@ builtin_weekday (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
strftime (buf, sizeof buf, "%A", &tm);
strobj_free (&mach->arg_str);
strobj_create (&mach->arg_str, buf);
mh_string_load (&mach->str[R_REG], buf);
}
/* sday date integer day of the week known?
......@@ -1273,9 +1075,9 @@ builtin_sday (struct mh_machine *mach)
/*FIXME: more elaborate check needed */
if (_parse_date (mach, &tm, &tz))
mach->arg_num = -1;
mach->num[R_REG] = -1;
else
mach->arg_num = 1;
mach->num[R_REG] = 1;
}
/* mday date integer day of the month*/
......@@ -1288,7 +1090,7 @@ builtin_mday (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = tm.tm_mday;
mach->num[R_REG] = tm.tm_mday;
}
/* yday date integer day of the year */
......@@ -1301,7 +1103,7 @@ builtin_yday (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = tm.tm_yday;
mach->num[R_REG] = tm.tm_yday;
}
/* mon date integer month of the year*/
......@@ -1314,7 +1116,7 @@ builtin_mon (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = tm.tm_mon+1;
mach->num[R_REG] = tm.tm_mon + 1;
}
/* month date string month of the year (abbrev.) */
......@@ -1329,8 +1131,7 @@ builtin_month (struct mh_machine *mach)
return;
strftime (buf, sizeof buf, "%b", &tm);
strobj_free (&mach->arg_str);
strobj_create (&mach->arg_str, buf);
mh_string_load (&mach->str[R_REG], buf);
}
/* lmonth date string month of the year*/
......@@ -1345,8 +1146,7 @@ builtin_lmonth (struct mh_machine *mach)
return;
strftime (buf, sizeof buf, "%B", &tm);
strobj_free (&mach->arg_str);
strobj_create (&mach->arg_str, buf);
mh_string_load (&mach->str[R_REG], buf);
}
/* year date integer year (may be > 100)*/
......@@ -1359,7 +1159,7 @@ builtin_year (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = tm.tm_year + 1900;
mach->num[R_REG] = tm.tm_year + 1900;
}
/* zone date integer timezone in hours*/
......@@ -1372,7 +1172,7 @@ builtin_zone (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = tz.utc_offset;
mach->num[R_REG] = tz.utc_offset;
}
/* tzone date string timezone string */
......@@ -1385,9 +1185,8 @@ builtin_tzone (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
strobj_free (&mach->arg_str);
if (tz.tz_name)
strobj_create (&mach->arg_str, (char*) tz.tz_name);
mh_string_load (&mach->str[R_REG], tz.tz_name);
else
{
char buf[6];
......@@ -1401,7 +1200,7 @@ builtin_tzone (struct mh_machine *mach)
s = '+';
snprintf (buf, sizeof buf, "%c%02d%02d", s,
tz.utc_offset/3600, tz.utc_offset/60);
strobj_create (&mach->arg_str, buf);
mh_string_load (&mach->str[R_REG], buf);
}
}
......@@ -1415,9 +1214,15 @@ builtin_szone (struct mh_machine *mach)
/*FIXME: more elaborate check needed */
if (_parse_date (mach, &tm, &tz))
mach->arg_num = -1;
mach->num[R_REG] = -1;
else
mach->arg_num = 1;
mach->num[R_REG] = 1;
}
static void
builtin_str_noop (struct mh_machine *mach)
{
mh_string_move (mach, R_REG, R_ARG);
}
/* date2local date coerce date to local timezone*/
......@@ -1425,6 +1230,7 @@ static void
builtin_date2local (struct mh_machine *mach)
{
/*FIXME: Noop*/
builtin_str_noop (mach);
}
/* date2gmt date coerce date to GMT*/
......@@ -1432,6 +1238,7 @@ static void
builtin_date2gmt (struct mh_machine *mach)
{
/*FIXME: Noop*/
builtin_str_noop (mach);
}
/* dst date integer daylight savings in effect?*/
......@@ -1444,9 +1251,9 @@ builtin_dst (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
#ifdef HAVE_STRUCT_TM_TM_ISDST
mach->arg_num = tm.tm_isdst;
mach->num[R_REG] = tm.tm_isdst;
#else
mach->arg_num = 0;
mach->num[R_REG] = 0;
#endif
}
......@@ -1459,7 +1266,7 @@ builtin_clock (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = mu_datetime_to_utc (&tm, &tz);
mach->num[R_REG] = mu_datetime_to_utc (&tm, &tz);
}
/* rclock date integer seconds prior to current time*/
......@@ -1472,7 +1279,7 @@ builtin_rclock (struct mh_machine *mach)
if (_parse_date (mach, &tm, &tz))
return;
mach->arg_num = now - mu_datetime_to_utc (&tm, &tz);
mach->num[R_REG] = now - mu_datetime_to_utc (&tm, &tz);
}
struct
......@@ -1546,7 +1353,7 @@ date_cvt (struct mh_machine *mach, int pretty)
min %= 60;
snprintf (buf + len, sizeof(buf) - len, "%c%02d%02d", sign, hrs, min);
}
strobj_create (&mach->arg_str, buf);
mh_string_load (&mach->str[R_REG], buf);
}
/* tws date string official 822 rendering */
......@@ -1570,7 +1377,7 @@ builtin_nodate (struct mh_machine *mach)
struct tm tm;
struct mu_timezone tz;
mach->arg_num = _parse_date (mach, &tm, &tz);
mach->num[R_REG] = _parse_date (mach, &tm, &tz);
}
/* proper addr string official 822 rendering */
......@@ -1578,6 +1385,7 @@ static void
builtin_proper (struct mh_machine *mach)
{
/*FIXME: noop*/
builtin_str_noop (mach);
}
/* friendly addr string user-friendly rendering*/
......@@ -1588,14 +1396,13 @@ builtin_friendly (struct mh_machine *mach)
const char *str;
int rc;
rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str));
rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
if (rc)
return;
if (mu_address_sget_personal (addr, 1, &str) == 0 && str)
{
strobj_free (&mach->arg_str);
strobj_create (&mach->arg_str, str);
mh_string_load (&mach->str[R_ARG], str);
}
mu_address_destroy (&addr);
}
......@@ -1608,13 +1415,13 @@ builtin_addr (struct mh_machine *mach)
const char *str;
int rc;
rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str));
strobj_free (&mach->arg_str);
rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
mh_string_clear (&mach->str[R_REG]);
if (rc)
return;
if (mu_address_sget_email (addr, 1, &str) == 0)
strobj_create (&mach->arg_str, str);
mh_string_load (&mach->str[R_REG], str);
mu_address_destroy (&addr);
}
......@@ -1626,13 +1433,13 @@ builtin_pers (struct mh_machine *mach)
const char *str;
int rc;
rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str));
strobj_free (&mach->arg_str);
rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
mh_string_clear (&mach->str[R_REG]);
if (rc)
return;
if (mu_address_sget_personal (addr, 1, &str) == 0 && str)
strobj_create (&mach->arg_str, str);
if (mu_address_sget_personal (addr, 1, &str) == 0)
mh_string_load (&mach->str[R_REG], str);
mu_address_destroy (&addr);
}
......@@ -1645,13 +1452,13 @@ builtin_note (struct mh_machine *mach)
const char *str;
int rc;
rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str));
strobj_free (&mach->arg_str);
rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
mh_string_clear (&mach->str[R_REG]);
if (rc)
return;
if (mu_address_sget_comments (addr, 1, &str) == 0)
strobj_create (&mach->arg_str, str);
mh_string_load (&mach->str[R_REG], str);
mu_address_destroy (&addr);
}
......@@ -1663,8 +1470,8 @@ builtin_mbox (struct mh_machine *mach)
char *str;
int rc;
rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str));
strobj_free (&mach->arg_str);
rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
mh_string_clear (&mach->str[R_REG]);
if (rc)
return;
......@@ -1673,7 +1480,7 @@ builtin_mbox (struct mh_machine *mach)
char *p = strchr (str, '@');
if (p)
*p = 0;
strobj_create (&mach->arg_str, p);
mh_string_load (&mach->str[R_REG], str);
free (str);
}
mu_address_destroy (&addr);
......@@ -1686,12 +1493,13 @@ builtin_mymbox (struct mh_machine *mach)
mu_address_t addr;
const char *str;
mach->arg_num = 0;
if (mu_address_create (&addr, strobj_ptr (&mach->arg_str)))
if (mu_address_create (&addr, mh_string_value (&mach->str[R_ARG])))
return;
if (mu_address_sget_email (addr, 1, &str) == 0 && str)
mach->arg_num = mh_is_my_name (str);
mach->num[R_REG] = mh_is_my_name (str);
else
mach->num[R_REG] = 0;
mu_address_destroy (&addr);
}
......@@ -1703,8 +1511,8 @@ builtin_host (struct mh_machine *mach)
char *str;
int rc;
rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str));
strobj_free (&mach->arg_str);
rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
mh_string_clear (&mach->str[R_REG]);
if (rc)
return;
......@@ -1712,7 +1520,7 @@ builtin_host (struct mh_machine *mach)
{
char *p = strchr (str, '@');
if (p)
strobj_create (&mach->arg_str, p+1);
mh_string_load (&mach->str[R_REG], p + 1);
free (str);
}
mu_address_destroy (&addr);
......@@ -1725,15 +1533,15 @@ builtin_nohost (struct mh_machine *mach)
mu_address_t addr;
const char *str;
int rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str));
strobj_free (&mach->arg_str);
int rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
mh_string_clear (&mach->str[R_REG]);
if (rc)
return;
if (mu_address_sget_email (addr, 1, &str) == 0 && str)
mach->arg_num = strchr (str, '@') != NULL;
mach->num[R_REG] = strchr (str, '@') != NULL;
else
mach->arg_num = 0;
mach->num[R_REG] = 0;
mu_address_destroy (&addr);
}
......@@ -1746,22 +1554,22 @@ builtin_type (struct mh_machine *mach)
int rc;
const char *str;
rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str));
strobj_free (&mach->arg_str);
rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
mh_string_clear (&mach->str[R_REG]);
if (rc)
return;
if (mu_address_sget_email (addr, 1, &str) == 0 && str)
{
if (strchr (str, '@'))
mach->arg_num = 1;
mach->num[R_REG] = 1;
else if (strchr (str, '!'))
mach->arg_num = -1;
mach->num[R_REG] = -1;
else
mach->arg_num = 0; /* assume local */
mach->num[R_REG] = 0; /* assume local */
}
else
mach->arg_num = 2;
mach->num[R_REG] = 2;
mu_address_destroy (&addr);
}
......@@ -1771,12 +1579,12 @@ builtin_path (struct mh_machine *mach)
{
mu_address_t addr;
const char *str;
int rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str));
strobj_free (&mach->arg_str);
int rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
mh_string_clear (&mach->str[R_REG]);
if (rc)
return;
if (mu_address_sget_route (addr, 1, &str))
strobj_create (&mach->arg_str, str);
mh_string_load (&mach->str[R_REG], str);
mu_address_destroy (&addr);
}
......@@ -1786,6 +1594,7 @@ builtin_ingrp (struct mh_machine *mach)
{
/*FIXME:*/
builtin_not_implemented ("ingrp");
mach->num[R_REG] = 0;
}
/* gname addr string name of group**/
......@@ -1794,6 +1603,7 @@ builtin_gname (struct mh_machine *mach)
{
/*FIXME:*/
builtin_not_implemented ("gname");
builtin_str_noop (mach);
}
/* formataddr expr append arg to str as a
......@@ -1806,12 +1616,12 @@ builtin_formataddr (struct mh_machine *mach)
size_t num;
const char *buf;
if (strobj_len (&mach->reg_str) == 0)
if (mh_string_is_null (&mach->str[R_REG]))
dest = NULL;
else if (mu_address_create (&dest, strobj_ptr (&mach->reg_str)))
else if (mu_address_create (&dest, mh_string_value (&mach->str[R_REG])))
return;
if (mu_address_create (&addr, strobj_ptr (&mach->arg_str)))
if (mu_address_create (&addr, mh_string_value (&mach->str[R_ARG])))
{
mu_address_destroy (&dest);
return;
......@@ -1838,10 +1648,9 @@ builtin_formataddr (struct mh_machine *mach)
}
if (mu_address_sget_printable (dest, &buf) == 0)
{
strobj_realloc (&mach->reg_str, strlen (buf) + 1);
strcpy (strobj_ptr (&mach->reg_str), buf);
}
mh_string_load (&mach->str[R_REG], buf);
else
mh_string_clear (&mach->str[R_REG]);
mu_address_destroy (&dest);
}
......@@ -1854,10 +1663,10 @@ builtin_formataddr (struct mh_machine *mach)
static void
builtin_putaddr (struct mh_machine *mach)
{
if (!strobj_is_null (&mach->arg_str))
print_hdr_string (mach, strobj_ptr (&mach->arg_str));
if (!strobj_is_null (&mach->reg_str))
print_hdr_string (mach, strobj_ptr (&mach->reg_str));
if (!mh_string_is_null (&mach->str[R_ARG]))
print_hdr_string (mach, mh_string_value (&mach->str[R_ARG]));
if (!mh_string_is_null (&mach->str[R_REG]))
print_hdr_string (mach, mh_string_value (&mach->str[R_REG]));
}
/* GNU extension: Strip leading whitespace and eventual Re: (or Re\[[0-9]+\]:)
......@@ -1865,14 +1674,15 @@ builtin_putaddr (struct mh_machine *mach)
static void
builtin_unre (struct mh_machine *mach)
{
const char *p;
int rc = mu_unre_subject (strobj_ptr (&mach->arg_str), &p);
if (rc == 0 && p != strobj_ptr (&mach->arg_str))
char const *arg = mh_string_value (&mach->str[R_ARG]);
char const *p;
int rc = mu_unre_subject (arg, &p);
mh_string_clear (&mach->str[R_REG]);
if (rc == 0 && p != arg)
{
char *q = mu_strdup (p); /* Create a copy, since strobj_create will
char *q = mu_strdup (p); /* Create a copy, since mh_string_load can
destroy p */
strobj_free (&mach->arg_str);
strobj_create (&mach->arg_str, q);
mh_string_load (&mach->str[R_REG], q);
free (q);
}
}
......@@ -1882,7 +1692,7 @@ builtin_isreply (struct mh_machine *mach)
{
int rc;
if (strobj_is_null (&mach->arg_str))
if (mh_string_is_null (&mach->str[R_ARG]))
{
mu_header_t hdr = NULL;
char *value = NULL;
......@@ -1893,37 +1703,31 @@ builtin_isreply (struct mh_machine *mach)
free (value);
}
else
rc = mu_unre_subject (strobj_ptr (&mach->arg_str), NULL);
rc = mu_unre_subject (mh_string_value (&mach->str[R_ARG]), NULL);
mach->arg_num = !rc;
mach->num[R_REG] = !rc;
}
static void
decode_string (strobj_t *obj)
builtin_decode (struct mh_machine *mach)
{
char *tmp;
if (strobj_is_null (obj))
if (mh_string_is_null (&mach->str[R_ARG]))
return;
if (mh_decode_2047 (strobj_ptr (obj), &tmp) == 0)
mh_string_clear (&mach->str[R_REG]);
if (mh_decode_2047 (mh_string_value (&mach->str[R_ARG]), &tmp) == 0)
{
strobj_free (obj);
strobj_create (obj, tmp);
mh_string_load (&mach->str[R_REG], tmp);
free (tmp);
}
}
static void
builtin_decode (struct mh_machine *mach)
{
decode_string (&mach->arg_str);
}
static void
builtin_reply_regex (struct mh_machine *mach)
{
mh_set_reply_regex (strobj_ptr (&mach->arg_str));
mh_set_reply_regex (mh_string_value (&mach->str[R_ARG]));
}
int
......@@ -1944,34 +1748,34 @@ mh_decode_rcpt_flag (const char *arg)
static void
builtin_rcpt (struct mh_machine *mach)
{
int rc = mh_decode_rcpt_flag (strobj_ptr (&mach->arg_str));
int rc = mh_decode_rcpt_flag (mh_string_value (&mach->str[R_ARG]));
if (rc == RCPT_NONE)
{
mu_error (_("invalid recipient mask"));
/* try to continue anyway */
}
mach->arg_num = rc & rcpt_mask;
mach->num[R_REG] = !!(rc & rcpt_mask);
}
static void
builtin_concat (struct mh_machine *mach)
{
size_t size = strobj_len (&mach->arg_str);
if (size == 0)
if (mh_string_is_null (&mach->str[R_ARG]))
return;
COMPRESS_WS (mach, strobj_ptr (&mach->arg_str), &size);
if (strobj_len (&mach->reg_str) == 0)
strobj_copy (&mach->reg_str, &mach->arg_str);
compress_ws (mach, mach->str[R_ARG].ptr);
if (mh_string_is_null (&mach->str[R_REG]))
mh_string_move (mach, R_REG, R_ARG);
else
{
int length = 1;
size_t length = 1;
length += 1 + strobj_len (&mach->reg_str); /* reserve en extra space */
length += strobj_len (&mach->arg_str);
strobj_realloc (&mach->reg_str, length);
strcat (strcat (strobj_ptr (&mach->reg_str), " "),
strobj_ptr (&mach->arg_str));
length += 1 + mh_string_length (&mach->str[R_REG]);
/* reserve en extra space */
length += mh_string_length (&mach->str[R_ARG]);
mh_string_realloc (&mach->str[R_REG], length);
strcat (strcat (mach->str[R_REG].ptr, " "),
mh_string_value (&mach->str[R_ARG]));
}
}
......@@ -1981,17 +1785,17 @@ builtin_printhdr (struct mh_machine *mach)
char *tmp = NULL;
size_t s = 0;
if (!strobj_is_null (&mach->arg_str))
if (!mh_string_is_null (&mach->str[R_ARG]))
{
s = strobj_len (&mach->arg_str);
tmp = mu_strdup (strobj_ptr (&mach->arg_str));
s = mh_string_length (&mach->str[R_ARG]);
tmp = mu_strdup (mh_string_value (&mach->str[R_ARG]));
}
if (!strobj_is_null (&mach->reg_str))
if (!mh_string_is_null (&mach->str[R_REG]))
{
s += strobj_len (&mach->reg_str) + 1;
tmp = realloc (tmp, s);
strcat (tmp, strobj_ptr (&mach->reg_str));
s += mh_string_length (&mach->str[R_REG]) + 1;
tmp = mu_realloc (tmp, s);
strcat (tmp, mh_string_value (&mach->str[R_REG]));
}
if (tmp)
......@@ -2006,10 +1810,10 @@ builtin_in_reply_to (struct mh_machine *mach)
{
char *value;
strobj_free (&mach->arg_str);
mh_string_clear (&mach->str[R_REG]);
if (mu_rfc2822_in_reply_to (mach->message, &value) == 0)
{
strobj_create (&mach->arg_str, value);
mh_string_load (&mach->str[R_REG], value);
free (value);
}
}
......@@ -2019,10 +1823,10 @@ builtin_references (struct mh_machine *mach)
{
char *value;
strobj_free (&mach->arg_str);
mh_string_clear (&mach->str[R_REG]);
if (mu_rfc2822_references (mach->message, &value) == 0)
{
strobj_create (&mach->arg_str, value);
mh_string_load (&mach->str[R_REG], value);
free (value);
}
}
......@@ -2030,22 +1834,19 @@ builtin_references (struct mh_machine *mach)
static void
builtin_package (struct mh_machine *mach)
{
strobj_free (&mach->arg_str);
strobj_set (&mach->arg_str, PACKAGE);
mh_string_load (&mach->str[R_REG], PACKAGE);
}
static void
builtin_package_string (struct mh_machine *mach)
{
strobj_free (&mach->arg_str);
strobj_set (&mach->arg_str, PACKAGE_STRING);
mh_string_load (&mach->str[R_REG], PACKAGE_STRING);
}
static void
builtin_version (struct mh_machine *mach)
{
strobj_free (&mach->arg_str);
strobj_set (&mach->arg_str, VERSION);
mh_string_load (&mach->str[R_REG], VERSION);
}
/* Builtin function table */
......@@ -2135,25 +1936,20 @@ mh_builtin_t builtin_tab[] = {
{ "reply_regex", builtin_reply_regex, mhtype_none, mhtype_str },
{ "isreply", builtin_isreply, mhtype_num, mhtype_str, MHA_OPTARG },
{ "decode", builtin_decode, mhtype_str, mhtype_str },
{ "void", NULL, mhtype_none, mhtype_none, MHA_VOID },
{ 0 }
};
mh_builtin_t *
mh_lookup_builtin (char *name, int *rest)
mh_lookup_builtin (char *name, size_t len)
{
mh_builtin_t *bp;
int namelen = strlen (name);
for (bp = builtin_tab; bp->name; bp++)
{
int len = strlen (bp->name);
if (len >= namelen
&& memcmp (name, bp->name, len) == 0)
{
*rest = namelen - len;
if (strlen (bp->name) == len && memcmp (name, bp->name, len) == 0)
return bp;
}
}
return NULL;
}
......@@ -2167,3 +1963,151 @@ _get_builtin_name (mh_builtin_fp ptr)
return bp->name;
return NULL;
}
void
mh_format_dump_disass (mh_format_t fmt)
{
mh_instr_t *prog = fmt->prog;
size_t pc = 1;
int stop = 0;
static char *regname[] = {
[R_REG] = "reg",
[R_ARG] = "arg"
};
if (!prog)
return;
while (!stop)
{
mh_opcode_t opcode;
printf ("% 4.4ld: ", (long) pc);
switch (opcode = MHI_OPCODE (prog[pc++]))
{
case mhop_stop:
printf ("stop");
stop = 1;
break;
case mhop_branch:
{
long n = MHI_NUM (prog[pc++]);
printf ("branch %ld", pc + n - 1);
}
break;
case mhop_brzn:
{
long n = MHI_NUM (prog[pc++]);
printf ("brzn %ld", pc + n - 1);
}
break;
case mhop_brzs:
{
long n = MHI_NUM (prog[pc++]);
printf ("brzs %ld", pc + n - 1);
}
break;
case mhop_setn:
{
long reg = MHI_NUM (prog[pc++]);
long n = MHI_NUM (prog[pc++]);
printf ("setn %s, %ld", regname[reg], n);
}
break;
case mhop_sets:
{
long reg = MHI_NUM (prog[pc++]);
size_t skip = MHI_NUM (prog[pc++]);
char const *str = MHI_STR (prog[pc]);
char *prt;
MU_ASSERT (mu_c_str_escape_trans (str,
"\\\\\"\"a\ab\bf\fn\nr\rt\tv\v",
&prt));
pc += skip;
printf ("setn %s, \"%s\"", regname[reg], prt);
free (prt);
}
break;
case mhop_movn:
{
long dst = MHI_NUM (prog[pc++]);
long src = MHI_NUM (prog[pc++]);
printf ("movn %s, %s", regname[dst], regname[src]);
}
break;
case mhop_movs:
{
long dst = MHI_NUM (prog[pc++]);
long src = MHI_NUM (prog[pc++]);
printf ("movs %s, %s", regname[dst], regname[src]);
}
break;
case mhop_ldcomp:
{
long reg = MHI_NUM (prog[pc++]);
size_t skip = MHI_NUM (prog[pc++]);
char const *comp = MHI_STR (prog[pc]);
pc += skip;
printf ("ldcomp %s, \"%s\"", regname[reg], comp);
}
break;
case mhop_ldbody:
{
long reg = MHI_NUM (prog[pc++]);
printf ("ldbody %s", regname[reg]);
}
break;
case mhop_call:
{
char *name = _get_builtin_name (MHI_BUILTIN (prog[pc++]));
printf ("call %s", name ? name : "UNKNOWN");
}
break;
case mhop_atoi:
{
long reg = MHI_NUM (prog[pc++]);
printf ("atoi %s", regname[reg]);
}
break;
case mhop_itoa:
{
long reg = MHI_NUM (prog[pc++]);
printf ("itoa %s", regname[reg]);
}
break;
case mhop_printn:
printf ("printn");
break;
case mhop_prints:
printf ("prints");
break;
case mhop_fmtspec:
{
int fmtspec = MHI_NUM (prog[pc++]);
printf ("fmtspec ");
mh_print_fmtspec (fmtspec);
}
break;
default:
abort ();
}
printf ("\n");
}
}
......
......@@ -15,34 +15,146 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
typedef struct /* A string object type */
#define MH_FMT_DEFAULT 0
#define MH_FMT_RALIGN 0x1000
#define MH_FMT_ZEROPAD 0x2000
#define MH_FMT_COMPWS 0x4000
#define MH_WIDTH_MASK 0x0fff
enum mh_opcode
{
int size; /* Allocated size or 0 for static storage */
char *ptr; /* Actual data */
}
strobj_t;
/* Stop. Format: mhop_stop */
mhop_stop,
/* Unconditional branch
Format: mhop_branch offset */
mhop_branch,
/* Branch if num reg is zero.
Format: mhop_brz_num dest-off */
mhop_brzn,
/* Branch if str reg is zero.
Format: mhop_brz_str dest-off */
mhop_brzs,
#define strobj_ptr(p) ((p)->ptr ? (p)->ptr : "")
#define strobj_len(p) (strobj_is_null(p) ? 0 : strlen((p)->ptr))
#define strobj_is_null(p) ((p)->ptr == NULL)
#define strobj_is_static(p) ((p)->size == 0)
/* Set numeric register
Format: mhop_setn val */
mhop_setn,
struct mh_machine
/* Set string register
Format: mhop_sets reg length string */
mhop_sets,
/* Move value bewtween two numeric registers
Format: mhop_movn dest src */
mhop_movn,
/* Move value bewtween two string registers
Format: mhop_movs dest src */
mhop_movs,
/* Load component value into a string register
Format: mhop_load reg string */
mhop_ldcomp,
/* Load first width bytes of message body contents into a string register.
Format: mhop_body reg */
mhop_ldbody,
/* Call a function.
Format: mhop_call function-pointer */
mhop_call,
/* Convert string register to number reg
Format: mhop_atoi reg
*/
mhop_atoi,
/* Convert numeric register to string
Format: mhop_itoa reg */
mhop_itoa,
/* Print num reg */
mhop_printn,
/* Print str reg */
mhop_prints,
/* Set format specification.
Format: mhop_fmtspec number */
mhop_fmtspec,
};
enum regid { R_REG, R_ARG };
enum mh_type
{
mhtype_none,
mhtype_num,
mhtype_str
};
typedef enum mh_opcode mh_opcode_t;
struct mh_machine;
typedef void (*mh_builtin_fp) (struct mh_machine *);
typedef union {
mh_opcode_t opcode;
mh_builtin_fp builtin;
long num;
void *ptr;
char str[1]; /* Any number of characters follows */
} mh_instr_t;
#define MHI_OPCODE(m) (m).opcode
#define MHI_BUILTIN(m) (m).builtin
#define MHI_NUM(m) (m).num
#define MHI_PTR(m) (m).ptr
#define MHI_STR(m) (m).str
struct mh_format
{
strobj_t reg_str; /* String register */
int reg_num; /* Numeric register */
size_t progmax; /* Size of allocated program*/
size_t progcnt; /* Actual number of elements used */
mh_instr_t *prog; /* Program itself */
struct node *tree;
mu_opool_t pool;
};
#define MHA_REQUIRED 0
#define MHA_OPTARG 1
#define MHA_OPT_CLEAR 2
#define MHA_VOID 3
typedef struct mh_builtin mh_builtin_t;
strobj_t arg_str; /* String argument */
long arg_num; /* Numeric argument */
struct mh_builtin
{
char *name;
mh_builtin_fp fun;
enum mh_type type;
enum mh_type argtype;
int optarg;
};
struct mh_string
{
size_t size;
char *ptr;
};
struct mh_machine
{
long num[2]; /* numeric registers */
struct mh_string str[2]; /* string registers */
size_t pc; /* Program counter */
size_t progsize; /* Size of allocated program*/
size_t progcnt; /* Size of allocated program*/
mh_instr_t *prog; /* Program itself */
int stop; /* Stop execution immediately */
mu_opool_t pool; /* Output buffer */
size_t width; /* Output buffer width */
size_t ind; /* Output buffer index */
size_t width; /* Output line width */
size_t ind; /* Output line index */
mu_stream_t output; /* Output stream */
mu_list_t addrlist; /* The list of email addresses output this far */
int fmtflags; /* Current formatting flags */
......@@ -51,9 +163,5 @@ struct mh_machine
size_t msgno; /* Its number */
};
void strobj_free (strobj_t *obj);
void strobj_create (strobj_t *lvalue, const char *str);
void strobj_set (strobj_t *lvalue, char *str);
void strobj_assign (strobj_t *lvalue, strobj_t *rvalue);
void strobj_copy (strobj_t *lvalue, strobj_t *rvalue);
void strobj_realloc (strobj_t *obj, size_t length);
mh_builtin_t *mh_lookup_builtin (char *name, size_t len);
void mh_print_fmtspec (int fmtspec);
......
......@@ -913,7 +913,7 @@ mh_charset (const char *dfl)
}
int
mh_decode_2047 (char *text, char **decoded_text)
mh_decode_2047 (char const *text, char **decoded_text)
{
const char *charset = mh_charset (NULL);
if (!charset)
......
......@@ -46,7 +46,7 @@ enum mhl_datatype
typedef union mhl_value {
char *str;
int num;
mh_format_t *fmt;
mh_format_t fmt;
} mhl_value_t;
typedef struct mhl_variable
......@@ -151,7 +151,6 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str)
{
size_t i;
struct mu_wordsplit ws;
mh_format_t fmt;
int wsflags;
if (strncmp (str, "ignores=", 8) == 0 && str[8] != '"')
......@@ -219,15 +218,14 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str)
break;
case dt_format:
if (mh_format_parse (value, &fmt))
if (mh_format_parse (&stmt->v.variable.value.fmt, value,
MH_FMT_PARSE_DEFAULT))
{
mu_error (_("%s:%d: bad format string"),
loc->filename,
loc->line);
exit (1);
}
stmt->v.variable.value.fmt = mu_alloc (sizeof (mh_format_t));
*stmt->v.variable.value.fmt = fmt;
break;
case dt_flag:
......@@ -456,7 +454,7 @@ struct eval_env
int ivar[I_MAX];
int bvar[B_MAX];
char *svar[S_MAX];
mh_format_t *fvar[F_MAX];
mh_format_t fvar[F_MAX];
char *prefix;
};
......