Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
John McEleney
/
mailutils
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit
9da939eb
...
9da939ebc7cde925ee45f405786a6b0d451b7180
authored
2017-06-26 18:06:58 +0300
by
Sergey Poznyakoff
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Fix premature push.
1 parent
35056a6e
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1141 additions
and
1630 deletions
mh/fmtcheck.c
mh/mh.h
mh/mh_fmtgram.y
mh/mh_format.c
mh/mh_format.h
mh/mh_init.c
mh/mh_list.c
mh/fmtcheck.c
View file @
9da939e
...
...
@@ -25,7 +25,6 @@ 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
;
...
...
@@ -42,9 +41,6 @@ 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
},
...
...
@@ -62,8 +58,11 @@ static void
run
(
void
)
{
mu_message_t
msg
=
mh_file_to_message
(
NULL
,
input_file
);
mh_format
(
format
,
msg
,
msgno
,
width
,
mu_strout
);
mu_printf
(
"
\n
"
);
char
*
output
;
mh_format
(
&
format
,
msg
,
msgno
,
width
,
&
output
);
mu_printf
(
"%s
\n
"
,
output
);
}
int
...
...
@@ -91,16 +90,14 @@ main (int argc, char **argv)
mu_error
(
_
(
"Format string not specified"
));
return
1
;
}
if
(
mh_format_parse
(
&
format
,
format_str
,
MH_FMT_PARSE_TREE
))
if
(
mh_format_parse
(
format_str
,
&
format
))
{
mu_error
(
_
(
"Bad format string"
));
exit
(
1
);
}
if
(
dump_option
)
mh_format_dump_code
(
format
);
if
(
disass_option
)
mh_format_dump_disass
(
format
);
mh_format_dump
(
&
format
);
if
(
input_file
)
run
();
...
...
mh/mh.h
View file @
9da939e
...
...
@@ -65,6 +65,11 @@
#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"
...
...
@@ -73,6 +78,118 @@
#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
;
...
...
@@ -167,22 +284,14 @@ int mu_getans (const char *variants, const char *fmt, ...)
int
mh_check_folder
(
const
char
*
pathname
,
int
confirm
);
int
mh_makedir
(
const
char
*
p
);
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
);
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
);
void
mh_format_debug
(
int
val
);
void
mh_format_free
(
mh_format_t
fmt
);
void
mh_format_destroy
(
mh_format_t
*
fm
t
);
void
mh_format_free
(
mh_format_t
*
fmt
);
mh_builtin_t
*
mh_lookup_builtin
(
char
*
name
,
int
*
res
t
);
void
mh_error
(
const
char
*
fmt
,
...)
MU_PRINTFLIKE
(
1
,
2
);
void
mh_err_memory
(
int
fatal
);
...
...
@@ -241,7 +350,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
const
*
text
,
char
**
decoded_text
);
int
mh_decode_2047
(
char
*
text
,
char
**
decoded_text
);
const
char
*
mh_charset
(
const
char
*
);
int
mh_alias_read
(
char
const
*
name
,
int
fail
);
...
...
mh/mh_fmtgram.y
View file @
9da939e
...
...
@@ -17,316 +17,285 @@
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 (
void
);
int yylex ();
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 */
/* 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;
}
#define FORMAT_INC 64 /* Increase format.prog by that many
cells each time pc reaches
format.progsize */
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
};
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);
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;
long num;
int num;
int type;
struct {
struct node *head, *tail;
} nodelist;
struct node *nodeptr;
size_t cond;
size_t end;
} elif_list;
size_t pc;
mh_builtin_t *builtin;
int fmtspec;
struct {
enum mh_type type;
union
{
char *str;
long num;
} v;
} arg;
};
%token <num> NUMBER
%token <str> STRING COMPONENT
%token <arg> ARGUMENT
%token <str> STRING
%token <builtin> FUNCTION
%token IF ELIF ELSE FI
%token <fmtspec> FMTSPEC
%token OBRACE CBRACE OCURLY CCURLY
%token <num> FMTSPEC
%token BOGUS
%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 <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
%type <builtin> function
%type <fmtspec> fmtspec
%%
input : list
{
parse_tree = $1.head;
/* nothing: to shut bison up */
}
;
list : item
list : pitem
| list pitem
;
pitem : item
{
$$.head = $$.tail = $1;
}
| list item
{
$2->prev = $1.tail;
$1.tail->next = $2;
$1.tail = $2;
$$ = $1;
switch ($1)
{
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 ();
}
$$ = pc;
}
;
item : STRING
item : literal
| escape
{
struct node *n = new_node (fmtnode_literal, mhtype_str);
n->v.str = $1;
$$ = new_node (fmtnode_print, mhtype_str);
$$->v.prt.arg = n;
in_escape = 0;
}
| escape
;
escape : cntl
| fmtspec printable
literal : STRING
{
if ($2->noprint)
$$ = $2;
else
{
$$ = new_node (fmtnode_print, $2->datatype);
$$->v.prt.fmtspec = $1;
$$->v.prt.arg = $2;
}
mh_code_string ($1);
$$ = mhtype_str;
}
| NUMBER
{
mh_code_number ($1);
$$ = mhtype_num;
}
;
printable
: component
escape
: component
| funcall
| cntl
{
$$ = mhtype_none;
}
;
component :
COMPONENT
component :
fmtspec OCURLY STRING CCURLY
{
if (mu_c_strcasecmp ($1, "body") == 0)
$$ = new_node (fmtnode_body, mhtype_str);
if (mu_c_strcasecmp ($3, "body") == 0)
{
mh_code_op (mhop_body);
}
else
{
$$ = new_node (fmtnode_comp, mhtype_str
);
$$->v.str = $1
;
mh_code_string ($3
);
mh_code_op (mhop_header)
;
}
$$ = mhtype_str;
}
;
obrace : OBRACE
{
in_escape++;
}
;
funcall : function argument EOFN
cbrace : CBRACE
{
ctx_pop ();
if ($1->optarg == MHA_VOID) /*FIXME*/
in_escape--;
}
;
funcall : fmtspec obrace { want_function = 1;} function { want_function = 0; want_arg = 1;} argument cbrace
{
if ($4)
{
$2->noprint = 1;
$$ = $2;
if (!mh_code_builtin ($4, $6))
YYERROR;
$$ = $4->type;
}
else
{
if ($1->argtype == mhtype_none)
{
if ($2)
{
yyerror ("function doesn't take arguments");
YYABORT;
}
}
else if ($2 == NULL)
switch ($6)
{
if ($1->optarg != MHA_OPTARG)
{
yyerror ("required argument missing");
YYABORT;
}
default:
break;
case mhtype_num:
mh_code_op (mhop_num_asgn);
break;
case mhtype_str:
mh_code_op (mhop_str_asgn);
break;
}
$$ = new_node (fmtnode_funcall, $1->type);
$$->v.funcall.builtin = $1;
$$->v.funcall.arg = typecast ($2, $1->argtype);
$$->noprint = $1->type == mhtype_none;
$$ = mhtype_none;
}
}
;
fmtspec : /* empty */
| FMTSPEC
{
$$ = 0;
mh_code_op (mhop_fmtspec);
mh_code_op ($1);
}
| FMTSPEC
;
function : FUNCTION
| STRING
{
ctx_push (ctx_func);
if (strcmp ($1, "void") == 0)
{
$$ = NULL;
}
else
{
yyerror (_("undefined function"));
mu_error ("%s", $1);
YYERROR;
}
}
;
argument : /* empty */
{
$$ = NULL;
}
| ARGUMENT
{
switch ($1.type)
{
case mhtype_none:
$$ = NULL;
break;
case mhtype_str:
$$ = new_node (fmtnode_literal, mhtype_str);
$$->v.str = $1.v.str;
break;
case mhtype_num:
$$ = new_node (fmtnode_number, mhtype_num);
$$->v.num = $1.v.num;
}
$$ = mhtype_none;
}
| literal
| escape
{
$$ = printelim ($1);
}
;
/* 1 2 3
4 5
*/
cntl : if cond zlist e
lif
_part fi
/* 1 2 3
4 5 6 7
*/
cntl : if cond zlist e
nd elif_part else
_part fi
{
$$ = new_node(fmtnode_cntl, mhtype_num);
$$->v.cntl.cond = $2;
$$->v.cntl.iftrue = $3.head;
$$->v.cntl.iffalse = $4;
size_t start_pc = 0, end_pc = 0;
/* 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;
/* Link all "false" lists */
if ($5.cond)
{
start_pc = $5.end;
end_pc = $5.end;
while (MHI_NUM(format.prog[end_pc]))
end_pc = MHI_NUM(format.prog[end_pc]);
}
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;
}
;
zlist : /* empty */
{
$$
.head = $$.tail = NULL
;
$$
= pc
;
}
| list
;
if : IF
{
ctx_push (ctx_if)
;
in_escape++
;
}
;
fi : FI
{
ctx_pop ();
/* 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);
}
;
elif : ELIF
{
ctx_pop ();
ctx_push (ctx_if);
in_escape++;
$$ = pc;
}
;
end : /* empty */
{
mh_code_op (mhop_branch);
$$ = mh_code_op (0);
}
;
cond : cond_expr
{
ctx_pop ();
ctx_push (ctx_expr);
$$ = printelim ($1);
in_escape--;
if ($1 == mhtype_str)
mh_code_op (mhop_str_branch);
else
mh_code_op (mhop_num_branch);
$$ = mh_code_op (0);
}
;
...
...
@@ -336,49 +305,45 @@ cond_expr : component
elif_part : /* empty */
{
$$ = NULL;
$$.cond = 0;
$$.end = 0;
}
| else_part
| elif_list
{
$$ = $1.head;
| elif_list end
{
$$.cond = $1.cond;
MHI_NUM(format.prog[$2]) = $1.end;
$$.end = $2;
}
;
elif_list : elif cond zlist
{
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;
$$.cond = $1;
MHI_NUM(format.prog[$2]) = pc - $2 + 2;
$$.end = 0;
}
| elif_list elif cond zlist
{
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;
$$ = $1;
| elif_list end elif cond zlist
{
MHI_NUM(format.prog[$4]) = pc - $4 + 2;
$$.cond = $1.cond;
MHI_NUM(format.prog[$2]) = $1.end;
$$.end = $2;
}
| elif_list else_part
{
$1.tail->v.cntl.iffalse = $2;
$1.tail = $2;
$$ = $1;
}
;
else_part :
ELSE list
{
$$ =
$2.head
;
else_part :
/* empty */
{
$$ =
0
;
}
| else list
;
else : ELSE
{
$$ = pc;
}
;
%%
static char *start;
...
...
@@ -387,154 +352,104 @@ 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, "");
}
int len;
mu_error ("%s: %s", start, s);
len = curp - start;
mu_error ("%*.*s^", len, len, "");
return 0;
}
static int backslash(int c);
struct lexer_tab
{
char *ctx_name;
int (*lexer) (void);
};
#define isdelim(c) (strchr("%<>?|(){} ",c) != NULL)
static int yylex_initial (void);
static int yylex_cond (void);
static int yylex_expr (void);
static int yylex_func (void);
static int percent;
static int backslash(int c);
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: [%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;
if (*curp == '0')
{
flags |= MH_FMT_ZEROPAD;
curp++;
}
else if (!mu_isdigit (*curp))
{
yyerror ("expected digit");
return BOGUS;
}
while (*curp && mu_isdigit (*curp))
num = num * 10 + *curp++ - '0';
yylval.fmtspec = flags | num;
*--curp = '%'; /* FIXME: dirty hack */
return FMTSPEC;
}
static int
token_function (void)
yylex ()
{
char *start;
/* Reset the tie-in */
int expect_arg = want_arg;
want_arg = 0;
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;
}
return FUNCTION;
}
static int
token_component (void)
{
char *start;
curp++;
if (!mu_isalpha (*curp))
{
yyerror ("component name expected");
return BOGUS;
}
start = curp;
for (; *curp != '}'; curp++)
if (yydebug)
fprintf (stderr, "[lex at %10.10s]\n", curp);
if (*curp == '%')
{
if (!(mu_isalnum (*curp) || *curp == '_' || *curp == '-'))
curp++;
percent = 1;
if (mu_isdigit (*curp) || *curp == '-')
{
yyerror ("component name expected");
return BOGUS;
int num = 0;
int flags = 0;
if (*curp == '-')
{
curp++;
flags = MH_FMT_RALIGN;
}
if (*curp == '0')
flags |= MH_FMT_ZEROPAD;
while (*curp && mu_isdigit (*curp))
num = num * 10 + *curp++ - '0';
yylval.num = num | flags;
return FMTSPEC;
}
}
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++)
if (percent)
{
percent = 0;
switch (*curp++)
{
case '<':
return IF;
case '>':
return FI;
case '?':
return ELIF;
case '|':
return ELSE;
case '%':
return '%';
case '(':
curp--;
return token_function ();
return OBRACE;
case '{':
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);
return OCURLY;
default:
yyerror ("component or function name expected");
return BOGUS;
}
}
if (*curp == 0)
return 0;
if (in_escape)
{
while (*curp && (*curp == ' ' || *curp == '\n'))
curp++;
switch (*curp)
{
case '(':
curp++;
return OBRACE;
case '{':
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 ')':
curp++;
return CBRACE;
case '}':
curp++;
return CCURLY;
case 0:
return 0;
}
do
{
...
...
@@ -547,124 +462,28 @@ yylex_initial (void)
mu_opool_append_char (tokpool, *curp);
curp++;
}
while (*curp &&
*curp != '%'
);
while (*curp &&
(expect_arg ? *curp != ')' : !isdelim(*curp))
);
mu_opool_append_char (tokpool, 0);
yylval.str = mu_opool_finish (tokpool, NULL);
return STRING;
}
int
yylex_cond (void)
{
switch (*curp)
if (want_function)
{
case '(':
return token_function ();
case '{':
return token_component ();
default:
yyerror ("'(' or '{' expected");
return BOGUS;
}
}
int
yylex_expr (void)
{
if (*curp == '%')
{
curp++;
switch (*curp++)
int rest;
mh_builtin_t *bp = mh_lookup_builtin (yylval.str, &rest);
if (bp)
{
case '?':
return ELIF;
case '|':
return ELSE;
case '>':
return FI;
curp -= rest;
yylval.builtin = bp;
while (*curp && mu_isspace (*curp))
curp++;
return FUNCTION;
}
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 EOFN;
case '{':
return token_component ();
case '%':
curp++;
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);
mu_opool_append_char (tokpool, c);
}
else
mu_opool_append_char (tokpool, *curp);
curp++;
}
while (*curp != ')');
mu_opool_append_char (tokpool, 0);
yylval.arg.type = mhtype_str;
yylval.arg.v.str = mu_opool_finish (tokpool, NULL);
}
if (*curp != ')')
{
yyerror("expected ')'");
return BOGUS;
}
return
ARGUMENT
;
return
STRING
;
}
void
mh_format_debug (int val)
{
...
...
@@ -672,32 +491,37 @@ mh_format_debug (int val)
}
int
mh_format_parse (
mh_format_t *fmtptr, char *format_str, int flags
)
mh_format_parse (
char *format_str, mh_format_t *fmt
)
{
int rc;
char *p = getenv ("MHFORMAT_DEBUG");
if (p
|| mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE2)
)
if (p)
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 ();
if (rc == 0)
codegen (fmtptr, flags & MH_FMT_PARSE_TREE);
else
mu_opool_destroy (&tokpool);
parse_tree = NULL;
tokpool = NULL;
return rc;
mh_code_op (mhop_stop);
mu_opool_destroy (&tokpool);
if (rc)
{
mh_format_free (&format);
return 1;
}
*fmt = format;
return 0;
}
int
backslash
(int c)
backslash(int c)
{
static char transtab[] = "b\bf\fn\nr\rt\t";
char *p;
...
...
@@ -710,500 +534,131 @@ backslash (int c)
return c;
}
static struct node *
new_node (enum node_type nodetype, enum mh_type datatype)
{
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);
void
mh_print_fmtspec (int fmtspec
)
branch_fixup (size_t epc, size_t tgt
)
{
if (!(fmtspec & (MH_FMT_RALIGN|MH_FMT_ZEROPAD|MH_FMT_COMPWS)))
printf ("NONE");
else
{
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");
}
}
static char *typename[] = { "NONE", "NUM", "STR" };
static void
dump_node_pretty (struct node *node, int level)
{
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;
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 ();
}
}
static void
dump_statement (struct node *node, int level)
{
while (node)
{
dump_node_pretty (node, level);
node = node->next;
if (node)
delim (level, "; ");
}
}
void
mh_format_dump_code (mh_format_t fmt)
{
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);
}
}
void
mh_format_free (mh_format_t fmt)
{
if (!fmt)
size_t prev = MHI_NUM(format.prog[epc]);
if (!prev)
return;
mh_format_free_tree (fmt);
if (fmt->prog)
free (fmt->prog);
fmt->progmax = fmt->progcnt = 0;
fmt->prog = NULL;
branch_fixup (prev, tgt);
MHI_NUM(format.prog[prev]) = tgt - prev;
}
void
mh_format_destroy (mh_format_t *fmt)
{
if (fmt)
{
mh_format_free (*fmt);
*fmt = NULL;
}
}
static struct node *
printelim (struct node *node)
/* Make sure there are at least `count' entries available in the prog
buffer */
void
prog_reserve (size_t count)
{
if (
node->nodetype == fmtnode_print
)
if (
pc + count >= format.progsize
)
{
s
truct node *arg = node->v.prt.arg
;
arg->next = node->next
;
f
ree (node);
node = arg
;
s
ize_t inc = (count + 1) / FORMAT_INC + 1
;
format.progsize += inc * FORMAT_INC
;
f
ormat.prog = mu_realloc (format.prog,
format.progsize * sizeof format.prog[0])
;
}
return node;
}
#define PROG_MIN_ALLOC 8
s
tatic inline void
ensure_space (struct mh_format *fmt, size_t n
)
s
ize_t
mh_code_string (char *string
)
{
while (fmt->progcnt + n >= fmt->progmax)
{
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]);
}
}
int length = strlen (string) + 1;
size_t count = (length + sizeof (mh_instr_t)) / sizeof (mh_instr_t);
size_t start_pc = pc;
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);
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;
}
s
tatic void
emit_string (struct mh_format *fmt, char const *
str)
s
ize_t
mh_code (mh_instr_t *in
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;
prog_reserve (1);
format.prog[pc] = *instr;
return pc++;
}
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)
size_t
mh_code_op (mh_opcode_t op)
{
switch (type)
{
case mhtype_num:
emit_opcode (fmt, opnum);
break;
case mhtype_str:
emit_opcode (fmt, opstr);
break;
default:
abort ();
}
mh_instr_t instr;
MHI_OPCODE(instr) = op;
return mh_code(&instr);
}
s
tatic void
emit_funcall (struct mh_format *fmt, mh_builtin_t *builtin, struct node *arg
)
s
ize_t
mh_code_number (int num
)
{
if (arg)
{
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);
mh_instr_t instr;
size_t ret = mh_code_op (mhop_num_arg);
MHI_NUM(instr) = num;
mh_code (&instr);
return ret;
}
s
tatic void
codegen_node (struct mh_format *fmt, struct node *nod
e)
s
ize_t
mh_code_builtin (mh_builtin_t *bp, int argtyp
e)
{
switch (node->nodetype)
mh_instr_t instr;
size_t start_pc = pc;
if (bp->argtype != argtype)
{
case fmtnode_print:
codegen_node (fmt, node->v.prt.arg);
if (node->v.prt.fmtspec)
if (argtype == mhtype_none)
{
emit_opcode (fmt, mhop_fmtspec);
emit_instr (fmt, (mh_instr_t) (long) node->v.prt.fmtspec);
if (bp->optarg)
{
switch (bp->argtype)
{
case mhtype_num:
mh_code_op (mhop_num_to_arg);
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 */
break;
default:
yyerror (_("INTERNAL ERROR: unknown argtype (please report)"));
abort ();
}
}
else
{
mu_error (_("missing argument for %s"), bp->name);
return 0;
}
}
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:
{
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)
{
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)
else
{
case mhtype_num:
emit_opcode (fmt, mhop_itoa);
break;
case mhtype_str:
emit_opcode (fmt, mhop_atoi);
break;
default:
abort ();
switch (bp->argtype)
{
case mhtype_none:
mu_error (_("extra arguments to %s"), bp->name);
return 0;
case mhtype_num:
mh_code_op (mhop_str_to_num);
break;
case mhtype_str:
mh_code_op (mhop_num_to_str);
break;
}
}
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);
*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);
}
mh_code_op (mhop_call);
MHI_BUILTIN(instr) = bp->fun;
mh_code (&instr);
return start_pc;
}
...
...
mh/mh_format.c
View file @
9da939e
...
...
@@ -28,97 +28,92 @@
#include "mbchar.h"
#include "mbswidth.h"
/* String functions */
static
char
*
_get_builtin_name
(
mh_builtin_fp
ptr
);
#define
MH_STRING_INITIALIZER { 0, NULL }
#define
DFLWIDTH(mach) ((mach)->width - (mach)->ind)
static
inline
void
mh_string_init
(
struct
mh_string
*
s
)
{
s
->
size
=
0
;
s
->
ptr
=
NULL
;
}
/* Functions for handling string objects. */
static
void
mh_string_free
(
struct
mh_string
*
s
)
void
strobj_free
(
strobj_t
*
obj
)
{
free
(
s
->
ptr
);
s
->
size
=
0
;
s
->
ptr
=
NULL
;
if
(
obj
->
size
)
free
(
obj
->
ptr
);
obj
->
size
=
0
;
obj
->
ptr
=
NULL
;
}
static
void
mh_string_realloc
(
struct
mh_string
*
s
,
size_t
length
)
void
strobj_create
(
strobj_t
*
lvalue
,
const
char
*
str
)
{
if
(
length
>
s
->
size
)
if
(
!
str
)
{
s
->
ptr
=
mu_realloc
(
s
->
ptr
,
length
);
s
->
ptr
[
length
-
1
]
=
0
;
s
->
size
=
length
;
lvalue
->
size
=
0
;
lvalue
->
ptr
=
NULL
;
}
else
{
lvalue
->
size
=
strlen
(
str
)
+
1
;
lvalue
->
ptr
=
mu_alloc
(
lvalue
->
size
);
memcpy
(
lvalue
->
ptr
,
str
,
lvalue
->
size
);
}
}
static
inline
int
mh_string_is_null
(
struct
mh_string
*
s
)
{
return
s
->
ptr
==
NULL
||
s
->
ptr
[
0
]
==
0
;
}
static
inline
size_t
mh_string_length
(
struct
mh_string
*
s
)
{
return
mh_string_is_null
(
s
)
?
0
:
strlen
(
s
->
ptr
);
}
static
inline
char
const
*
mh_string_value
(
struct
mh_string
*
s
)
void
strobj_set
(
strobj_t
*
lvalue
,
char
*
str
)
{
return
mh_string_is_null
(
s
)
?
""
:
s
->
ptr
;
lvalue
->
size
=
0
;
lvalue
->
ptr
=
str
;
}
static
inline
void
mh_string_clear
(
struct
mh_string
*
s
)
void
strobj_assign
(
strobj_t
*
lvalue
,
strobj_t
*
rvalue
)
{
if
(
s
->
ptr
)
s
->
ptr
[
0
]
=
0
;
strobj_free
(
lvalue
);
*
lvalue
=
*
rvalue
;
rvalue
->
size
=
0
;
rvalue
->
ptr
=
NULL
;
}
static
void
mh_string_load
(
struct
mh_string
*
s
,
char
const
*
str
)
void
strobj_copy
(
strobj_t
*
lvalue
,
strobj_t
*
rvalue
)
{
if
(
!
str
)
mh_string_clear
(
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
{
mh_string_realloc
(
s
,
strlen
(
str
));
strcpy
(
s
->
ptr
,
str
);
if
(
lvalue
->
size
)
strobj_free
(
lvalue
);
strobj_create
(
lvalue
,
strobj_ptr
(
rvalue
));
}
}
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
)
void
strobj_realloc
(
strobj_t
*
obj
,
size_t
length
)
{
if
(
mach
->
width
<
mach
->
ind
)
return
0
;
return
mach
->
width
-
mach
->
ind
;
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
;
}
else
{
obj
->
ptr
=
mu_realloc
(
obj
->
ptr
,
length
);
obj
->
ptr
[
length
-
1
]
=
0
;
obj
->
size
=
length
;
}
}
/* 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
const
*
str
,
size_t
len
,
size_t
ncol
)
mbsubstrlen
(
char
*
str
,
size_t
len
,
size_t
ncol
)
{
int
ret
=
0
;
mbi_iterator_t
iter
;
...
...
@@ -136,7 +131,7 @@ mbsubstrlen (char const *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
const
*
str
,
size_t
len
)
mbsnlen
(
char
*
str
,
size_t
len
)
{
int
ret
=
0
;
mbi_iterator_t
iter
;
...
...
@@ -148,10 +143,10 @@ mbsnlen (char const *str, size_t len)
/* Compress whitespace in a string (multi-byte) */
static
void
str_compress_ws
(
char
*
str
)
compress_ws
(
char
*
str
,
size_t
*
psize
)
{
unsigned
char
*
p
,
*
q
;
size_t
size
=
strlen
(
str
)
;
size_t
size
=
*
psize
;
mbi_iterator_t
iter
;
int
space
=
0
;
...
...
@@ -178,26 +173,29 @@ str_compress_ws (char *str)
}
}
*
p
=
0
;
*
psize
=
p
-
(
unsigned
char
*
)
str
;
}
static
inline
void
compress_ws
(
struct
mh_machine
*
mach
,
char
*
str
)
{
if
(
mach
->
fmtflags
&
MH_FMT_COMPWS
)
str_compress_ws
(
str
);
}
#define COMPRESS_WS(mach, str, size) \
do \
{ \
if ((mach)->fmtflags & MH_FMT_COMPWS) \
compress_ws (str, size); \
} \
while (0)
static
void
put_string
(
struct
mh_machine
*
mach
,
char
const
*
str
,
int
len
)
put_string
(
struct
mh_machine
*
mach
,
char
*
str
,
int
len
)
{
if
(
len
==
0
)
return
;
mu_stream_write
(
mach
->
output
,
str
,
len
,
NULL
);
mach
->
ind
+=
mbsnwidth
(
str
,
len
,
0
);
mu_opool_append
(
mach
->
pool
,
str
,
len
);
len
=
mbsnwidth
(
str
,
len
,
0
);
mach
->
ind
+=
len
;
}
static
void
print_hdr_segment
(
struct
mh_machine
*
mach
,
char
const
*
str
,
size_t
len
)
print_hdr_segment
(
struct
mh_machine
*
mach
,
char
*
str
,
size_t
len
)
{
if
(
!
len
)
len
=
strlen
(
str
);
...
...
@@ -209,7 +207,7 @@ print_hdr_segment (struct mh_machine *mach, char const *str, size_t len)
while
(
1
)
{
mbi_iterator_t
iter
;
size_t
rest
=
output_width
(
mach
);
size_t
rest
=
DFLWIDTH
(
mach
);
size_t
width
=
mbsnlen
(
str
,
len
);
size_t
off
,
size
;
...
...
@@ -247,10 +245,11 @@ print_hdr_segment (struct mh_machine *mach, char const *str, size_t len)
}
}
/* Print len bytes from str into mach->outbuf */
static
void
print_hdr_string
(
struct
mh_machine
*
mach
,
char
const
*
str
)
print_hdr_string
(
struct
mh_machine
*
mach
,
char
*
str
)
{
char
const
*
p
;
char
*
p
;
if
(
!
str
)
str
=
""
;
...
...
@@ -270,7 +269,7 @@ print_hdr_string (struct mh_machine *mach, char const *str)
static
void
print_simple_segment
(
struct
mh_machine
*
mach
,
size_t
width
,
char
const
*
str
,
size_t
len
)
char
*
str
,
size_t
len
)
{
size_t
rest
;
...
...
@@ -283,7 +282,7 @@ print_simple_segment (struct mh_machine *mach, size_t width,
if
(
!
width
)
width
=
mach
->
width
;
rest
=
output_width
(
mach
);
rest
=
DFLWIDTH
(
mach
);
if
(
rest
==
0
)
{
if
(
len
==
1
&&
str
[
0
]
==
'\n'
)
...
...
@@ -295,7 +294,7 @@ print_simple_segment (struct mh_machine *mach, size_t width,
}
static
void
print_string
(
struct
mh_machine
*
mach
,
size_t
width
,
char
const
*
str
)
print_string
(
struct
mh_machine
*
mach
,
size_t
width
,
char
*
str
)
{
char
*
p
;
...
...
@@ -319,7 +318,7 @@ print_string (struct mh_machine *mach, size_t width, char const *str)
}
static
void
print_fmt_segment
(
struct
mh_machine
*
mach
,
size_t
fmtwidth
,
char
const
*
str
,
print_fmt_segment
(
struct
mh_machine
*
mach
,
size_t
fmtwidth
,
char
*
str
,
size_t
len
)
{
size_t
width
=
mbsnlen
(
str
,
len
);
...
...
@@ -330,7 +329,7 @@ print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char const *str,
width
=
fmtwidth
;
}
else
len
=
mbsubstrlen
(
str
,
len
,
output_width
(
mach
));
len
=
mbsubstrlen
(
str
,
len
,
DFLWIDTH
(
mach
));
put_string
(
mach
,
str
,
len
);
...
...
@@ -339,12 +338,12 @@ print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char const *str,
fmtwidth
-=
width
;
mach
->
ind
+=
fmtwidth
;
while
(
fmtwidth
--
)
mu_
stream_write
(
mach
->
output
,
" "
,
1
,
NULL
);
mu_
opool_append_char
(
mach
->
pool
,
' '
);
}
}
static
void
print_fmt_string
(
struct
mh_machine
*
mach
,
size_t
fmtwidth
,
char
const
*
str
)
print_fmt_string
(
struct
mh_machine
*
mach
,
size_t
fmtwidth
,
char
*
str
)
{
char
*
p
=
strchr
(
str
,
'\n'
);
while
(
p
)
...
...
@@ -377,7 +376,7 @@ format_num (struct mh_machine *mach, long num)
char
buf
[
64
];
char
*
ptr
;
int
fmtwidth
=
mach
->
fmtflags
&
MH_WIDTH_MASK
;
char
padchar
=
mach
->
fmtflags
&
MH_FMT_ZEROPAD
?
'0'
:
' '
;
int
padchar
=
mach
->
fmtflags
&
MH_FMT_ZEROPAD
?
'0'
:
' '
;
n
=
snprintf
(
buf
,
sizeof
buf
,
"%ld"
,
num
);
...
...
@@ -394,7 +393,7 @@ format_num (struct mh_machine *mach, long num)
ptr
=
buf
;
for
(
i
=
n
;
i
<
fmtwidth
&&
mach
->
ind
<
mach
->
width
;
i
++
,
mach
->
ind
++
)
mu_
stream_write
(
mach
->
output
,
&
padchar
,
1
,
NULL
);
mu_
opool_append_char
(
mach
->
pool
,
padchar
);
}
}
else
...
...
@@ -405,7 +404,7 @@ format_num (struct mh_machine *mach, long num)
}
static
void
format_str
(
struct
mh_machine
*
mach
,
char
const
*
str
)
format_str
(
struct
mh_machine
*
mach
,
char
*
str
)
{
if
(
!
str
)
str
=
""
;
...
...
@@ -413,7 +412,7 @@ format_str (struct mh_machine *mach, char const *str)
{
int
len
=
strlen
(
str
);
int
fmtwidth
=
mach
->
fmtflags
&
MH_WIDTH_MASK
;
char
padchar
=
' '
;
int
padchar
=
' '
;
if
(
mach
->
fmtflags
&
MH_FMT_RALIGN
)
{
...
...
@@ -422,7 +421,7 @@ format_str (struct mh_machine *mach, char const *str)
n
=
fmtwidth
-
len
;
for
(
i
=
0
;
i
<
n
&&
mach
->
ind
<
mach
->
width
;
i
++
,
mach
->
ind
++
,
fmtwidth
--
)
mu_
stream_write
(
mach
->
output
,
&
padchar
,
1
,
NULL
);
mu_
opool_append_char
(
mach
->
pool
,
padchar
);
}
print_fmt_string
(
mach
,
fmtwidth
,
str
);
...
...
@@ -473,28 +472,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
,
mu_stream_t
outpu
t
)
mh_format
(
mh_format_t
*
fmt
,
mu_message_t
msg
,
size_t
msgno
,
size_t
width
,
char
**
pre
t
)
{
struct
mh_machine
mach
;
char
buf
[
64
];
const
char
*
charset
=
mh_global_profile_get
(
"Charset"
,
NULL
);
memset
(
&
mach
,
0
,
sizeof
(
mach
));
mach
.
prog
cnt
=
fmt
->
progcnt
;
mach
.
prog
size
=
fmt
->
progsize
;
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_ASSERT
(
mu_list_create
(
&
mach
.
addrlist
)
);
mu_opool_create
(
&
mach
.
pool
,
MU_OPOOL_ENOMEMABRT
);
mu_list_create
(
&
mach
.
addrlist
);
reset_fmt_defaults
(
&
mach
);
...
...
@@ -525,12 +524,14 @@ mh_format (mh_format_t fmt, mu_message_t msg, size_t msgno,
}
#endif
while
(
!
mach
.
stop
)
while
(
!
mach
.
stop
&&
mach
.
ind
<
mach
.
width
)
{
mh_opcode_t
opcode
;
switch
(
opcode
=
MHI_OPCODE
(
mach
.
prog
[
mach
.
pc
++
]))
{
case
mhop_nop
:
break
;
case
mhop_stop
:
mach
.
stop
=
1
;
break
;
...
...
@@ -539,138 +540,128 @@ mh_format (mh_format_t fmt, mu_message_t msg, size_t msgno,
mach
.
pc
+=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
]);
break
;
case
mhop_brzn
:
if
(
!
mach
.
num
[
R_REG
])
mach
.
pc
+=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
]);
else
mach
.
pc
++
;
case
mhop_num_asgn
:
mach
.
reg_num
=
mach
.
arg_num
;
break
;
case
mhop_brzs
:
if
(
mh_string_is_null
(
&
mach
.
str
[
R_REG
]))
mach
.
pc
+=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
]);
else
mach
.
pc
++
;
case
mhop_str_asgn
:
strobj_assign
(
&
mach
.
reg_str
,
&
mach
.
arg_str
);
break
;
case
mhop_setn
:
{
long
reg
=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
++
]);
mach
.
num
[
reg
]
=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
++
]);
}
case
mhop_num_arg
:
mach
.
arg_num
=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
++
]);
break
;
case
mhop_s
ets
:
case
mhop_s
tr_arg
:
{
long
reg
=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
++
]);
size_t
skip
=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
++
]);
char
const
*
str
=
MHI_STR
(
mach
.
prog
[
mach
.
pc
]);
strobj_set
(
&
mach
.
arg_str
,
MHI_STR
(
mach
.
prog
[
mach
.
pc
]));
mach
.
pc
+=
skip
;
mh_string_load
(
&
mach
.
str
[
reg
],
str
);
}
break
;
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
];
}
case
mhop_num_branch
:
if
(
!
mach
.
arg_num
)
mach
.
pc
+=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
]);
else
mach
.
pc
++
;
break
;
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? */
}
case
mhop_str_branch
:
if
(
!*
strobj_ptr
(
&
mach
.
arg_str
))
mach
.
pc
+=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
]);
else
mach
.
pc
++
;
break
;
case
mhop_ldcomp
:
case
mhop_call
:
MHI_BUILTIN
(
mach
.
prog
[
mach
.
pc
++
])
(
&
mach
);
break
;
case
mhop_header
:
{
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
,
comp
,
&
value
);
mh_string_clear
(
&
mach
.
str
[
reg
]
);
mu_header_aget_value_unfold
(
hdr
,
strobj_ptr
(
&
mach
.
arg_str
)
,
&
value
);
strobj_free
(
&
mach
.
arg_str
);
if
(
value
)
{
compress_ws
(
&
mach
,
value
);
mh_string_load
(
&
mach
.
str
[
reg
],
value
);
free
(
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
;
}
else
mach
.
arg_num
=
0
;
}
break
;
case
mhop_
ld
body
:
case
mhop_body
:
{
long
reg
=
MHI_NUM
(
mach
.
prog
[
mach
.
pc
++
]);
mu_body_t
body
=
NULL
;
mu_stream_t
stream
=
NULL
;
size_t
size
=
0
;
size_t
rest
=
output_width
(
&
mach
);
mh_string_clear
(
&
mach
.
str
[
reg
]);
size_t
size
=
0
,
str_off
,
nread
;
size_t
rest
=
DFLWIDTH
(
&
mach
);
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
)
{
if
(
size
>
rest
)
size
=
rest
;
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
);
if
(
!
stream
)
break
;
if
(
size
>
rest
)
size
=
rest
;
mu_stream_destroy
(
&
stream
);
mach
.
arg_str
.
ptr
=
mu_alloc
(
size
+
1
);
mach
.
arg_str
.
size
=
size
;
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
;
case
mhop_call
:
MHI_BUILTIN
(
mach
.
prog
[
mach
.
pc
++
])
(
&
mach
);
/* 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
);
break
;
/* 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
);
}
/* Convert arg_str to arg_num */
case
mhop_str_to_num
:
mach
.
arg_num
=
strtoul
(
strobj_ptr
(
&
mach
.
arg_str
),
NULL
,
0
);
break
;
/* 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
]);
}
/* 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
);
break
;
case
mhop_
printn
:
format_num
(
&
mach
,
mach
.
num
[
R_REG
]
);
case
mhop_
num_print
:
format_num
(
&
mach
,
mach
.
reg_num
);
break
;
case
mhop_
prints
:
format_str
(
&
mach
,
mach
.
str
[
R_REG
].
ptr
);
case
mhop_
str_print
:
format_str
(
&
mach
,
strobj_ptr
(
&
mach
.
reg_str
)
);
break
;
case
mhop_fmtspec
:
...
...
@@ -682,14 +673,19 @@ mh_format (mh_format_t fmt, mu_message_t msg, size_t msgno,
abort
();
}
}
mh_string_free
(
&
mach
.
str
[
R_REG
]
);
mh_string_free
(
&
mach
.
str
[
R_ARG
]
);
strobj_free
(
&
mach
.
reg_str
);
strobj_free
(
&
mach
.
arg_str
);
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
)
{
...
...
@@ -705,7 +701,197 @@ mh_format_str (mh_format_t *fmt, char *str, size_t width, char **pret)
mu_message_destroy
(
&
msg
,
NULL
);
return
rc
;
}
#endif
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
;
}
/* Built-in functions */
...
...
@@ -721,7 +907,7 @@ builtin_msg (struct mh_machine *mach)
{
size_t
msgno
=
mach
->
msgno
;
mh_message_number
(
mach
->
message
,
&
msgno
);
mach
->
num
[
R_REG
]
=
msgno
;
mach
->
arg_num
=
msgno
;
}
static
void
...
...
@@ -740,7 +926,7 @@ builtin_cur (struct mh_machine *mach)
}
mh_message_number
(
mach
->
message
,
&
msgno
);
mh_mailbox_get_cur
(
mbox
,
&
cur
);
/* FIXME: Cache this */
mach
->
num
[
R_REG
]
=
msgno
==
cur
;
mach
->
arg_num
=
msgno
==
cur
;
}
static
void
...
...
@@ -748,27 +934,25 @@ builtin_size (struct mh_machine *mach)
{
size_t
size
;
if
(
mu_message_size
(
mach
->
message
,
&
size
)
==
0
)
mach
->
num
[
R_REG
]
=
size
;
else
mach
->
num
[
R_REG
]
=
0
;
mach
->
arg_num
=
size
;
}
static
void
builtin_strlen
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
mh_string_length
(
&
mach
->
str
[
R_ARG
]
);
mach
->
arg_num
=
strlen
(
strobj_ptr
(
&
mach
->
arg_str
)
);
}
static
void
builtin_width
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
mach
->
width
;
mach
->
arg_num
=
mach
->
width
;
}
static
void
builtin_charleft
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
output_width
(
mach
);
mach
->
arg_num
=
DFLWIDTH
(
mach
);
}
static
void
...
...
@@ -777,175 +961,186 @@ builtin_timenow (struct mh_machine *mach)
time_t
t
;
time
(
&
t
);
mach
->
num
[
R_REG
]
=
t
;
mach
->
arg_num
=
t
;
}
static
void
builtin_me
(
struct
mh_machine
*
mach
)
{
char
*
s
;
mu_asprintf
(
&
s
,
"<%s>"
,
mh_my_email
());
mh_string_load
(
&
mach
->
str
[
R_REG
],
s
);
free
(
s
);
char
*
s
=
mh_my_email
();
strobj_realloc
(
&
mach
->
arg_str
,
strlen
(
s
)
+
3
);
sprintf
(
strobj_ptr
(
&
mach
->
arg_str
),
"<%s>"
,
s
);
}
static
void
builtin_eq
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
mach
->
num
[
R_REG
]
==
mach
->
num
[
R_ARG
]
;
mach
->
arg_num
=
mach
->
reg_num
==
mach
->
arg_num
;
}
static
void
builtin_ne
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
mach
->
num
[
R_REG
]
!=
mach
->
num
[
R_ARG
]
;
mach
->
arg_num
=
mach
->
reg_num
!=
mach
->
arg_num
;
}
static
void
builtin_gt
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
mach
->
num
[
R_REG
]
>
mach
->
num
[
R_ARG
]
;
mach
->
arg_num
=
mach
->
reg_num
>
mach
->
arg_num
;
}
static
void
builtin_match
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
strstr
(
mh_string_value
(
&
mach
->
str
[
R_REG
]
),
mh_string_value
(
&
mach
->
str
[
R_ARG
]
))
!=
NULL
;
mach
->
arg_num
=
strstr
(
strobj_ptr
(
&
mach
->
reg_str
),
strobj_ptr
(
&
mach
->
arg_str
))
!=
NULL
;
}
static
void
builtin_amatch
(
struct
mh_machine
*
mach
)
{
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
);
int
len
=
strobj_len
(
&
mach
->
arg_str
);
mach
->
arg_num
=
strncmp
(
strobj_ptr
(
&
mach
->
reg_str
),
strobj_ptr
(
&
mach
->
arg_str
)
,
len
);
}
static
void
builtin_plus
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
+=
mach
->
num
[
R_ARG
]
;
mach
->
arg_num
+=
mach
->
reg_num
;
}
static
void
builtin_minus
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
-=
mach
->
num
[
R_ARG
]
;
mach
->
arg_num
-=
mach
->
reg_num
;
}
static
void
builtin_divide
(
struct
mh_machine
*
mach
)
{
if
(
mach
->
num
[
R_ARG
]
==
0
)
if
(
!
mach
->
arg_num
)
{
/* TRANSLATORS: Do not translate the word 'format'! */
mu_error
(
_
(
"format: divide by zero"
));
mach
->
stop
=
1
;
}
else
mach
->
num
[
R_REG
]
/=
mach
->
num
[
R_ARG
]
;
mach
->
arg_num
=
mach
->
reg_num
/
mach
->
arg_num
;
}
static
void
builtin_modulo
(
struct
mh_machine
*
mach
)
{
if
(
mach
->
num
[
R_ARG
]
==
0
)
if
(
!
mach
->
arg_num
)
{
mu_error
(
_
(
"format: divide by zero"
));
mach
->
stop
=
1
;
}
else
mach
->
num
[
R_REG
]
%=
mach
->
num
[
R_ARG
]
;
mach
->
arg_num
=
mach
->
reg_num
%
mach
->
arg_num
;
}
static
void
builtin_num
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
mach
->
num
[
R_ARG
]
;
mach
->
reg_num
=
mach
->
arg_num
;
}
static
void
builtin_lit
(
struct
mh_machine
*
mach
)
{
/*
FIXME:
do nothing */
/* do nothing */
}
static
void
builtin_getenv
(
struct
mh_machine
*
mach
)
{
char
const
*
val
=
getenv
(
mh_string_value
(
&
mach
->
str
[
R_ARG
]));
mh_string_load
(
&
mach
->
str
[
R_REG
],
val
);
char
*
val
=
getenv
(
strobj_ptr
(
&
mach
->
arg_str
));
strobj_free
(
&
mach
->
arg_str
);
strobj_create
(
&
mach
->
arg_str
,
val
);
}
static
void
builtin_profile
(
struct
mh_machine
*
mach
)
{
char
const
*
val
=
mh_global_profile_get
(
mh_string_value
(
&
mach
->
str
[
R_ARG
]),
""
);
mh_string_load
(
&
mach
->
str
[
R_REG
],
val
);
char
*
val
=
strobj_ptr
(
&
mach
->
arg_str
);
strobj_free
(
&
mach
->
arg_str
);
strobj_create
(
&
mach
->
arg_str
,
mh_global_profile_get
(
val
,
""
)
);
}
static
void
builtin_nonzero
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
mach
->
num
[
R_ARG
]
!=
0
;
mach
->
arg_num
=
mach
->
reg_num
;
}
static
void
builtin_zero
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
mach
->
num
[
R_ARG
]
==
0
;
mach
->
arg_num
=
!
mach
->
reg_num
;
}
static
void
builtin_null
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
mh_string_is_null
(
&
mach
->
str
[
R_ARG
]);
char
*
s
=
strobj_ptr
(
&
mach
->
reg_str
);
mach
->
arg_num
=
!
s
&&
!
s
[
0
];
}
static
void
builtin_nonnull
(
struct
mh_machine
*
mach
)
{
mach
->
num
[
R_REG
]
=
!
mh_string_is_null
(
&
mach
->
str
[
R_ARG
]);
char
*
s
=
strobj_ptr
(
&
mach
->
reg_str
);
mach
->
arg_num
=
s
&&
s
[
0
];
}
/* comp comp string Set str to component text*/
static
void
builtin_comp
(
struct
mh_machine
*
mach
)
{
/* FIXME: Check this */
mh_string_move
(
mach
,
R_REG
,
R_ARG
);
strobj_assign
(
&
mach
->
reg_str
,
&
mach
->
arg_str
);
}
/* compval comp integer num set to "atoi(comp)"*/
static
void
builtin_compval
(
struct
mh_machine
*
mach
)
{
/* FIXME: Check this */
mach
->
num
[
R_REG
]
=
strtol
(
mh_string_value
(
&
mach
->
str
[
R_ARG
]),
NULL
,
0
);
mach
->
reg_num
=
strtoul
(
strobj_ptr
(
&
mach
->
arg_str
),
NULL
,
0
);
}
/* trim expr trim trailing white-space from str*/
static
void
builtin_trim
(
struct
mh_machine
*
mach
)
{
if
(
!
mh_string_is_null
(
&
mach
->
str
[
R_REG
]))
mu_rtrim_class
(
mach
->
str
[
R_REG
].
ptr
,
MU_CTYPE_SPACE
);
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
;
}
/* putstr expr print str*/
static
void
builtin_putstr
(
struct
mh_machine
*
mach
)
{
print_string
(
mach
,
0
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
print_string
(
mach
,
0
,
strobj_ptr
(
&
mach
->
arg_str
));
}
/* putstrf expr print str in a fixed width*/
static
void
builtin_putstrf
(
struct
mh_machine
*
mach
)
{
format_str
(
mach
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
format_str
(
mach
,
strobj_ptr
(
&
mach
->
arg_str
));
}
/* putnum expr print num*/
...
...
@@ -953,7 +1148,7 @@ static void
builtin_putnum
(
struct
mh_machine
*
mach
)
{
char
*
p
;
mu_asprintf
(
&
p
,
"%ld"
,
mach
->
num
[
R_ARG
]
);
mu_asprintf
(
&
p
,
"%ld"
,
mach
->
arg_num
);
print_string
(
mach
,
0
,
p
);
free
(
p
);
}
...
...
@@ -962,16 +1157,16 @@ builtin_putnum (struct mh_machine *mach)
static
void
builtin_putnumf
(
struct
mh_machine
*
mach
)
{
format_num
(
mach
,
mach
->
num
[
R_ARG
]
);
format_num
(
mach
,
mach
->
arg_num
);
}
static
int
_parse_date
(
struct
mh_machine
*
mach
,
struct
tm
*
tm
,
struct
mu_timezone
*
tz
)
{
char
const
*
date
=
mh_string_value
(
&
mach
->
str
[
R_ARG
]
);
char
*
date
=
strobj_ptr
(
&
mach
->
arg_str
);
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
;
...
...
@@ -994,7 +1189,7 @@ builtin_sec (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
tm
.
tm_sec
;
mach
->
arg_num
=
tm
.
tm_sec
;
}
/* min date integer minutes of the hour*/
...
...
@@ -1007,7 +1202,7 @@ builtin_min (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
tm
.
tm_min
;
mach
->
arg_num
=
tm
.
tm_min
;
}
/* hour date integer hours of the day (0-23)*/
...
...
@@ -1020,7 +1215,7 @@ builtin_hour (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
tm
.
tm_hour
;
mach
->
arg_num
=
tm
.
tm_hour
;
}
/* wday date integer day of the week (Sun=0)*/
...
...
@@ -1033,7 +1228,7 @@ builtin_wday (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
tm
.
tm_wday
;
mach
->
arg_num
=
tm
.
tm_wday
;
}
/* day date string day of the week (abbrev.)*/
...
...
@@ -1048,7 +1243,8 @@ builtin_day (struct mh_machine *mach)
return
;
strftime
(
buf
,
sizeof
buf
,
"%a"
,
&
tm
);
mh_string_load
(
&
mach
->
str
[
R_REG
],
buf
);
strobj_free
(
&
mach
->
arg_str
);
strobj_create
(
&
mach
->
arg_str
,
buf
);
}
/* weekday date string day of the week */
...
...
@@ -1061,8 +1257,10 @@ builtin_weekday (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
strftime
(
buf
,
sizeof
buf
,
"%A"
,
&
tm
);
mh_string_load
(
&
mach
->
str
[
R_REG
],
buf
);
strobj_free
(
&
mach
->
arg_str
);
strobj_create
(
&
mach
->
arg_str
,
buf
);
}
/* sday date integer day of the week known?
...
...
@@ -1075,9 +1273,9 @@ builtin_sday (struct mh_machine *mach)
/*FIXME: more elaborate check needed */
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
mach
->
num
[
R_REG
]
=
-
1
;
mach
->
arg_num
=
-
1
;
else
mach
->
num
[
R_REG
]
=
1
;
mach
->
arg_num
=
1
;
}
/* mday date integer day of the month*/
...
...
@@ -1090,7 +1288,7 @@ builtin_mday (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
tm
.
tm_mday
;
mach
->
arg_num
=
tm
.
tm_mday
;
}
/* yday date integer day of the year */
...
...
@@ -1103,7 +1301,7 @@ builtin_yday (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
tm
.
tm_yday
;
mach
->
arg_num
=
tm
.
tm_yday
;
}
/* mon date integer month of the year*/
...
...
@@ -1116,7 +1314,7 @@ builtin_mon (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
tm
.
tm_mon
+
1
;
mach
->
arg_num
=
tm
.
tm_mon
+
1
;
}
/* month date string month of the year (abbrev.) */
...
...
@@ -1131,7 +1329,8 @@ builtin_month (struct mh_machine *mach)
return
;
strftime
(
buf
,
sizeof
buf
,
"%b"
,
&
tm
);
mh_string_load
(
&
mach
->
str
[
R_REG
],
buf
);
strobj_free
(
&
mach
->
arg_str
);
strobj_create
(
&
mach
->
arg_str
,
buf
);
}
/* lmonth date string month of the year*/
...
...
@@ -1146,7 +1345,8 @@ builtin_lmonth (struct mh_machine *mach)
return
;
strftime
(
buf
,
sizeof
buf
,
"%B"
,
&
tm
);
mh_string_load
(
&
mach
->
str
[
R_REG
],
buf
);
strobj_free
(
&
mach
->
arg_str
);
strobj_create
(
&
mach
->
arg_str
,
buf
);
}
/* year date integer year (may be > 100)*/
...
...
@@ -1159,7 +1359,7 @@ builtin_year (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
tm
.
tm_year
+
1900
;
mach
->
arg_num
=
tm
.
tm_year
+
1900
;
}
/* zone date integer timezone in hours*/
...
...
@@ -1172,7 +1372,7 @@ builtin_zone (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
tz
.
utc_offset
;
mach
->
arg_num
=
tz
.
utc_offset
;
}
/* tzone date string timezone string */
...
...
@@ -1185,8 +1385,9 @@ builtin_tzone (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
strobj_free
(
&
mach
->
arg_str
);
if
(
tz
.
tz_name
)
mh_string_load
(
&
mach
->
str
[
R_REG
],
tz
.
tz_name
);
strobj_create
(
&
mach
->
arg_str
,
(
char
*
)
tz
.
tz_name
);
else
{
char
buf
[
6
];
...
...
@@ -1200,7 +1401,7 @@ builtin_tzone (struct mh_machine *mach)
s
=
'+'
;
snprintf
(
buf
,
sizeof
buf
,
"%c%02d%02d"
,
s
,
tz
.
utc_offset
/
3600
,
tz
.
utc_offset
/
60
);
mh_string_load
(
&
mach
->
str
[
R_REG
]
,
buf
);
strobj_create
(
&
mach
->
arg_str
,
buf
);
}
}
...
...
@@ -1214,15 +1415,9 @@ builtin_szone (struct mh_machine *mach)
/*FIXME: more elaborate check needed */
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
mach
->
num
[
R_REG
]
=
-
1
;
mach
->
arg_num
=
-
1
;
else
mach
->
num
[
R_REG
]
=
1
;
}
static
void
builtin_str_noop
(
struct
mh_machine
*
mach
)
{
mh_string_move
(
mach
,
R_REG
,
R_ARG
);
mach
->
arg_num
=
1
;
}
/* date2local date coerce date to local timezone*/
...
...
@@ -1230,7 +1425,6 @@ static void
builtin_date2local
(
struct
mh_machine
*
mach
)
{
/*FIXME: Noop*/
builtin_str_noop
(
mach
);
}
/* date2gmt date coerce date to GMT*/
...
...
@@ -1238,7 +1432,6 @@ static void
builtin_date2gmt
(
struct
mh_machine
*
mach
)
{
/*FIXME: Noop*/
builtin_str_noop
(
mach
);
}
/* dst date integer daylight savings in effect?*/
...
...
@@ -1251,9 +1444,9 @@ builtin_dst (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
#ifdef HAVE_STRUCT_TM_TM_ISDST
mach
->
num
[
R_REG
]
=
tm
.
tm_isdst
;
mach
->
arg_num
=
tm
.
tm_isdst
;
#else
mach
->
num
[
R_REG
]
=
0
;
mach
->
arg_num
=
0
;
#endif
}
...
...
@@ -1266,7 +1459,7 @@ builtin_clock (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
mu_datetime_to_utc
(
&
tm
,
&
tz
);
mach
->
arg_num
=
mu_datetime_to_utc
(
&
tm
,
&
tz
);
}
/* rclock date integer seconds prior to current time*/
...
...
@@ -1279,7 +1472,7 @@ builtin_rclock (struct mh_machine *mach)
if
(
_parse_date
(
mach
,
&
tm
,
&
tz
))
return
;
mach
->
num
[
R_REG
]
=
now
-
mu_datetime_to_utc
(
&
tm
,
&
tz
);
mach
->
arg_num
=
now
-
mu_datetime_to_utc
(
&
tm
,
&
tz
);
}
struct
...
...
@@ -1353,7 +1546,7 @@ date_cvt (struct mh_machine *mach, int pretty)
min
%=
60
;
snprintf
(
buf
+
len
,
sizeof
(
buf
)
-
len
,
"%c%02d%02d"
,
sign
,
hrs
,
min
);
}
mh_string_load
(
&
mach
->
str
[
R_REG
]
,
buf
);
strobj_create
(
&
mach
->
arg_str
,
buf
);
}
/* tws date string official 822 rendering */
...
...
@@ -1377,7 +1570,7 @@ builtin_nodate (struct mh_machine *mach)
struct
tm
tm
;
struct
mu_timezone
tz
;
mach
->
num
[
R_REG
]
=
_parse_date
(
mach
,
&
tm
,
&
tz
);
mach
->
arg_num
=
_parse_date
(
mach
,
&
tm
,
&
tz
);
}
/* proper addr string official 822 rendering */
...
...
@@ -1385,7 +1578,6 @@ static void
builtin_proper
(
struct
mh_machine
*
mach
)
{
/*FIXME: noop*/
builtin_str_noop
(
mach
);
}
/* friendly addr string user-friendly rendering*/
...
...
@@ -1396,13 +1588,14 @@ builtin_friendly (struct mh_machine *mach)
const
char
*
str
;
int
rc
;
rc
=
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
rc
=
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
));
if
(
rc
)
return
;
if
(
mu_address_sget_personal
(
addr
,
1
,
&
str
)
==
0
&&
str
)
{
mh_string_load
(
&
mach
->
str
[
R_ARG
],
str
);
strobj_free
(
&
mach
->
arg_str
);
strobj_create
(
&
mach
->
arg_str
,
str
);
}
mu_address_destroy
(
&
addr
);
}
...
...
@@ -1415,13 +1608,13 @@ builtin_addr (struct mh_machine *mach)
const
char
*
str
;
int
rc
;
rc
=
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
rc
=
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
));
strobj_free
(
&
mach
->
arg_str
);
if
(
rc
)
return
;
if
(
mu_address_sget_email
(
addr
,
1
,
&
str
)
==
0
)
mh_string_load
(
&
mach
->
str
[
R_REG
]
,
str
);
strobj_create
(
&
mach
->
arg_str
,
str
);
mu_address_destroy
(
&
addr
);
}
...
...
@@ -1433,13 +1626,13 @@ builtin_pers (struct mh_machine *mach)
const
char
*
str
;
int
rc
;
rc
=
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
rc
=
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
));
strobj_free
(
&
mach
->
arg_str
);
if
(
rc
)
return
;
if
(
mu_address_sget_personal
(
addr
,
1
,
&
str
)
==
0
)
mh_string_load
(
&
mach
->
str
[
R_REG
]
,
str
);
if
(
mu_address_sget_personal
(
addr
,
1
,
&
str
)
==
0
&&
str
)
strobj_create
(
&
mach
->
arg_str
,
str
);
mu_address_destroy
(
&
addr
);
}
...
...
@@ -1452,13 +1645,13 @@ builtin_note (struct mh_machine *mach)
const
char
*
str
;
int
rc
;
rc
=
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
rc
=
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
));
strobj_free
(
&
mach
->
arg_str
);
if
(
rc
)
return
;
if
(
mu_address_sget_comments
(
addr
,
1
,
&
str
)
==
0
)
mh_string_load
(
&
mach
->
str
[
R_REG
]
,
str
);
strobj_create
(
&
mach
->
arg_str
,
str
);
mu_address_destroy
(
&
addr
);
}
...
...
@@ -1470,8 +1663,8 @@ builtin_mbox (struct mh_machine *mach)
char
*
str
;
int
rc
;
rc
=
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
rc
=
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
));
strobj_free
(
&
mach
->
arg_str
);
if
(
rc
)
return
;
...
...
@@ -1480,7 +1673,7 @@ builtin_mbox (struct mh_machine *mach)
char
*
p
=
strchr
(
str
,
'@'
);
if
(
p
)
*
p
=
0
;
mh_string_load
(
&
mach
->
str
[
R_REG
],
str
);
strobj_create
(
&
mach
->
arg_str
,
p
);
free
(
str
);
}
mu_address_destroy
(
&
addr
);
...
...
@@ -1493,13 +1686,12 @@ builtin_mymbox (struct mh_machine *mach)
mu_address_t
addr
;
const
char
*
str
;
if
(
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
])))
mach
->
arg_num
=
0
;
if
(
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
)))
return
;
if
(
mu_address_sget_email
(
addr
,
1
,
&
str
)
==
0
&&
str
)
mach
->
num
[
R_REG
]
=
mh_is_my_name
(
str
);
else
mach
->
num
[
R_REG
]
=
0
;
mach
->
arg_num
=
mh_is_my_name
(
str
);
mu_address_destroy
(
&
addr
);
}
...
...
@@ -1511,8 +1703,8 @@ builtin_host (struct mh_machine *mach)
char
*
str
;
int
rc
;
rc
=
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
rc
=
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
));
strobj_free
(
&
mach
->
arg_str
);
if
(
rc
)
return
;
...
...
@@ -1520,7 +1712,7 @@ builtin_host (struct mh_machine *mach)
{
char
*
p
=
strchr
(
str
,
'@'
);
if
(
p
)
mh_string_load
(
&
mach
->
str
[
R_REG
],
p
+
1
);
strobj_create
(
&
mach
->
arg_str
,
p
+
1
);
free
(
str
);
}
mu_address_destroy
(
&
addr
);
...
...
@@ -1533,15 +1725,15 @@ builtin_nohost (struct mh_machine *mach)
mu_address_t
addr
;
const
char
*
str
;
int
rc
=
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
int
rc
=
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
));
strobj_free
(
&
mach
->
arg_str
);
if
(
rc
)
return
;
if
(
mu_address_sget_email
(
addr
,
1
,
&
str
)
==
0
&&
str
)
mach
->
num
[
R_REG
]
=
strchr
(
str
,
'@'
)
!=
NULL
;
mach
->
arg_num
=
strchr
(
str
,
'@'
)
!=
NULL
;
else
mach
->
num
[
R_REG
]
=
0
;
mach
->
arg_num
=
0
;
mu_address_destroy
(
&
addr
);
}
...
...
@@ -1554,22 +1746,22 @@ builtin_type (struct mh_machine *mach)
int
rc
;
const
char
*
str
;
rc
=
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
rc
=
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
));
strobj_free
(
&
mach
->
arg_str
);
if
(
rc
)
return
;
if
(
mu_address_sget_email
(
addr
,
1
,
&
str
)
==
0
&&
str
)
{
if
(
strchr
(
str
,
'@'
))
mach
->
num
[
R_REG
]
=
1
;
mach
->
arg_num
=
1
;
else
if
(
strchr
(
str
,
'!'
))
mach
->
num
[
R_REG
]
=
-
1
;
mach
->
arg_num
=
-
1
;
else
mach
->
num
[
R_REG
]
=
0
;
/* assume local */
mach
->
arg_num
=
0
;
/* assume local */
}
else
mach
->
num
[
R_REG
]
=
2
;
mach
->
arg_num
=
2
;
mu_address_destroy
(
&
addr
);
}
...
...
@@ -1579,12 +1771,12 @@ builtin_path (struct mh_machine *mach)
{
mu_address_t
addr
;
const
char
*
str
;
int
rc
=
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
int
rc
=
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
));
strobj_free
(
&
mach
->
arg_str
);
if
(
rc
)
return
;
if
(
mu_address_sget_route
(
addr
,
1
,
&
str
))
mh_string_load
(
&
mach
->
str
[
R_REG
]
,
str
);
strobj_create
(
&
mach
->
arg_str
,
str
);
mu_address_destroy
(
&
addr
);
}
...
...
@@ -1594,7 +1786,6 @@ builtin_ingrp (struct mh_machine *mach)
{
/*FIXME:*/
builtin_not_implemented
(
"ingrp"
);
mach
->
num
[
R_REG
]
=
0
;
}
/* gname addr string name of group**/
...
...
@@ -1603,7 +1794,6 @@ builtin_gname (struct mh_machine *mach)
{
/*FIXME:*/
builtin_not_implemented
(
"gname"
);
builtin_str_noop
(
mach
);
}
/* formataddr expr append arg to str as a
...
...
@@ -1616,12 +1806,12 @@ builtin_formataddr (struct mh_machine *mach)
size_t
num
;
const
char
*
buf
;
if
(
mh_string_is_null
(
&
mach
->
str
[
R_REG
])
)
if
(
strobj_len
(
&
mach
->
reg_str
)
==
0
)
dest
=
NULL
;
else
if
(
mu_address_create
(
&
dest
,
mh_string_value
(
&
mach
->
str
[
R_REG
]
)))
else
if
(
mu_address_create
(
&
dest
,
strobj_ptr
(
&
mach
->
reg_str
)))
return
;
if
(
mu_address_create
(
&
addr
,
mh_string_value
(
&
mach
->
str
[
R_ARG
]
)))
if
(
mu_address_create
(
&
addr
,
strobj_ptr
(
&
mach
->
arg_str
)))
{
mu_address_destroy
(
&
dest
);
return
;
...
...
@@ -1648,9 +1838,10 @@ builtin_formataddr (struct mh_machine *mach)
}
if
(
mu_address_sget_printable
(
dest
,
&
buf
)
==
0
)
mh_string_load
(
&
mach
->
str
[
R_REG
],
buf
);
else
mh_string_clear
(
&
mach
->
str
[
R_REG
]);
{
strobj_realloc
(
&
mach
->
reg_str
,
strlen
(
buf
)
+
1
);
strcpy
(
strobj_ptr
(
&
mach
->
reg_str
),
buf
);
}
mu_address_destroy
(
&
dest
);
}
...
...
@@ -1663,10 +1854,10 @@ builtin_formataddr (struct mh_machine *mach)
static
void
builtin_putaddr
(
struct
mh_machine
*
mach
)
{
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
]
));
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
));
}
/* GNU extension: Strip leading whitespace and eventual Re: (or Re\[[0-9]+\]:)
...
...
@@ -1674,15 +1865,14 @@ builtin_putaddr (struct mh_machine *mach)
static
void
builtin_unre
(
struct
mh_machine
*
mach
)
{
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
)
const
char
*
p
;
int
rc
=
mu_unre_subject
(
strobj_ptr
(
&
mach
->
arg_str
),
&
p
);
if
(
rc
==
0
&&
p
!=
strobj_ptr
(
&
mach
->
arg_str
))
{
char
*
q
=
mu_strdup
(
p
);
/* Create a copy, since
mh_string_load can
char
*
q
=
mu_strdup
(
p
);
/* Create a copy, since
strobj_create will
destroy p */
mh_string_load
(
&
mach
->
str
[
R_REG
],
q
);
strobj_free
(
&
mach
->
arg_str
);
strobj_create
(
&
mach
->
arg_str
,
q
);
free
(
q
);
}
}
...
...
@@ -1692,7 +1882,7 @@ builtin_isreply (struct mh_machine *mach)
{
int
rc
;
if
(
mh_string_is_null
(
&
mach
->
str
[
R_ARG
]
))
if
(
strobj_is_null
(
&
mach
->
arg_str
))
{
mu_header_t
hdr
=
NULL
;
char
*
value
=
NULL
;
...
...
@@ -1703,31 +1893,37 @@ builtin_isreply (struct mh_machine *mach)
free
(
value
);
}
else
rc
=
mu_unre_subject
(
mh_string_value
(
&
mach
->
str
[
R_ARG
]
),
NULL
);
rc
=
mu_unre_subject
(
strobj_ptr
(
&
mach
->
arg_str
),
NULL
);
mach
->
num
[
R_REG
]
=
!
rc
;
mach
->
arg_num
=
!
rc
;
}
static
void
builtin_decode
(
struct
mh_machine
*
mach
)
decode_string
(
strobj_t
*
obj
)
{
char
*
tmp
;
if
(
mh_string_is_null
(
&
mach
->
str
[
R_ARG
]
))
if
(
strobj_is_null
(
obj
))
return
;
mh_string_clear
(
&
mach
->
str
[
R_REG
]);
if
(
mh_decode_2047
(
mh_string_value
(
&
mach
->
str
[
R_ARG
]),
&
tmp
)
==
0
)
if
(
mh_decode_2047
(
strobj_ptr
(
obj
),
&
tmp
)
==
0
)
{
mh_string_load
(
&
mach
->
str
[
R_REG
],
tmp
);
strobj_free
(
obj
);
strobj_create
(
obj
,
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
(
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
mh_set_reply_regex
(
strobj_ptr
(
&
mach
->
arg_str
));
}
int
...
...
@@ -1748,34 +1944,34 @@ mh_decode_rcpt_flag (const char *arg)
static
void
builtin_rcpt
(
struct
mh_machine
*
mach
)
{
int
rc
=
mh_decode_rcpt_flag
(
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
int
rc
=
mh_decode_rcpt_flag
(
strobj_ptr
(
&
mach
->
arg_str
));
if
(
rc
==
RCPT_NONE
)
{
mu_error
(
_
(
"invalid recipient mask"
));
/* try to continue anyway */
}
mach
->
num
[
R_REG
]
=
!!
(
rc
&
rcpt_mask
)
;
mach
->
arg_num
=
rc
&
rcpt_mask
;
}
static
void
builtin_concat
(
struct
mh_machine
*
mach
)
{
if
(
mh_string_is_null
(
&
mach
->
str
[
R_ARG
]))
return
;
size_t
size
=
strobj_len
(
&
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
);
if
(
size
==
0
)
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
);
else
{
size_
t
length
=
1
;
in
t
length
=
1
;
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
]));
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
));
}
}
...
...
@@ -1785,17 +1981,17 @@ builtin_printhdr (struct mh_machine *mach)
char
*
tmp
=
NULL
;
size_t
s
=
0
;
if
(
!
mh_string_is_null
(
&
mach
->
str
[
R_ARG
]
))
if
(
!
strobj_is_null
(
&
mach
->
arg_str
))
{
s
=
mh_string_length
(
&
mach
->
str
[
R_ARG
]
);
tmp
=
mu_strdup
(
mh_string_value
(
&
mach
->
str
[
R_ARG
]
));
s
=
strobj_len
(
&
mach
->
arg_str
);
tmp
=
mu_strdup
(
strobj_ptr
(
&
mach
->
arg_str
));
}
if
(
!
mh_string_is_null
(
&
mach
->
str
[
R_REG
]
))
if
(
!
strobj_is_null
(
&
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
]
));
s
+=
strobj_len
(
&
mach
->
reg_str
)
+
1
;
tmp
=
realloc
(
tmp
,
s
);
strcat
(
tmp
,
strobj_ptr
(
&
mach
->
reg_str
));
}
if
(
tmp
)
...
...
@@ -1810,10 +2006,10 @@ builtin_in_reply_to (struct mh_machine *mach)
{
char
*
value
;
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
strobj_free
(
&
mach
->
arg_str
);
if
(
mu_rfc2822_in_reply_to
(
mach
->
message
,
&
value
)
==
0
)
{
mh_string_load
(
&
mach
->
str
[
R_REG
]
,
value
);
strobj_create
(
&
mach
->
arg_str
,
value
);
free
(
value
);
}
}
...
...
@@ -1823,10 +2019,10 @@ builtin_references (struct mh_machine *mach)
{
char
*
value
;
mh_string_clear
(
&
mach
->
str
[
R_REG
]
);
strobj_free
(
&
mach
->
arg_str
);
if
(
mu_rfc2822_references
(
mach
->
message
,
&
value
)
==
0
)
{
mh_string_load
(
&
mach
->
str
[
R_REG
]
,
value
);
strobj_create
(
&
mach
->
arg_str
,
value
);
free
(
value
);
}
}
...
...
@@ -1834,19 +2030,22 @@ builtin_references (struct mh_machine *mach)
static
void
builtin_package
(
struct
mh_machine
*
mach
)
{
mh_string_load
(
&
mach
->
str
[
R_REG
],
PACKAGE
);
strobj_free
(
&
mach
->
arg_str
);
strobj_set
(
&
mach
->
arg_str
,
PACKAGE
);
}
static
void
builtin_package_string
(
struct
mh_machine
*
mach
)
{
mh_string_load
(
&
mach
->
str
[
R_REG
],
PACKAGE_STRING
);
strobj_free
(
&
mach
->
arg_str
);
strobj_set
(
&
mach
->
arg_str
,
PACKAGE_STRING
);
}
static
void
builtin_version
(
struct
mh_machine
*
mach
)
{
mh_string_load
(
&
mach
->
str
[
R_REG
],
VERSION
);
strobj_free
(
&
mach
->
arg_str
);
strobj_set
(
&
mach
->
arg_str
,
VERSION
);
}
/* Builtin function table */
...
...
@@ -1936,19 +2135,24 @@ 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
,
size_t
len
)
mh_lookup_builtin
(
char
*
name
,
int
*
rest
)
{
mh_builtin_t
*
bp
;
int
namelen
=
strlen
(
name
);
for
(
bp
=
builtin_tab
;
bp
->
name
;
bp
++
)
{
if
(
strlen
(
bp
->
name
)
==
len
&&
memcmp
(
name
,
bp
->
name
,
len
)
==
0
)
return
bp
;
int
len
=
strlen
(
bp
->
name
);
if
(
len
>=
namelen
&&
memcmp
(
name
,
bp
->
name
,
len
)
==
0
)
{
*
rest
=
namelen
-
len
;
return
bp
;
}
}
return
NULL
;
}
...
...
@@ -1963,151 +2167,3 @@ _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
\a
b
\b
f
\f
n
\n
r
\r
t
\t
v
\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
"
);
}
}
...
...
mh/mh_format.h
View file @
9da939e
...
...
@@ -15,146 +15,34 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#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
{
/* 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
,
/* Set numeric register
Format: mhop_setn val */
mhop_setn
,
/* 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
typedef
struct
/* A string object 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
{
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
;
};
int
size
;
/* Allocated size or 0 for static storage */
char
*
ptr
;
/* Actual data */
}
strobj_t
;
#define
MHA_REQUIRED 0
#define
MHA_OPTARG 1
#define
MHA_OPT_CLEAR 2
#define
MHA_VOID 3
#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)
typedef
struct
mh_builtin
mh_builtin_t
;
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 */
strobj_t
reg_str
;
/* String register */
int
reg_num
;
/* Numeric register */
strobj_t
arg_str
;
/* String argument */
long
arg_num
;
/* Numeric argument */
size_t
pc
;
/* Program counter */
size_t
prog
cnt
;
/* Size of allocated program*/
size_t
prog
size
;
/* Size of allocated program*/
mh_instr_t
*
prog
;
/* Program itself */
int
stop
;
/* Stop execution immediately */
size_t
width
;
/* Output line width
*/
size_t
ind
;
/* Output line index
*/
mu_stream_t
output
;
/* Output stream
*/
mu_opool_t
pool
;
/* Output buffer
*/
size_t
width
;
/* Output buffer width
*/
size_t
ind
;
/* Output buffer index
*/
mu_list_t
addrlist
;
/* The list of email addresses output this far */
int
fmtflags
;
/* Current formatting flags */
...
...
@@ -163,5 +51,9 @@ struct mh_machine
size_t
msgno
;
/* Its number */
};
mh_builtin_t
*
mh_lookup_builtin
(
char
*
name
,
size_t
len
);
void
mh_print_fmtspec
(
int
fmtspec
);
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/mh_init.c
View file @
9da939e
...
...
@@ -913,7 +913,7 @@ mh_charset (const char *dfl)
}
int
mh_decode_2047
(
char
const
*
text
,
char
**
decoded_text
)
mh_decode_2047
(
char
*
text
,
char
**
decoded_text
)
{
const
char
*
charset
=
mh_charset
(
NULL
);
if
(
!
charset
)
...
...
mh/mh_list.c
View file @
9da939e
...
...
@@ -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,6 +151,7 @@ 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
]
!=
'"'
)
...
...
@@ -218,14 +219,15 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str)
break
;
case
dt_format
:
if
(
mh_format_parse
(
&
stmt
->
v
.
variable
.
value
.
fmt
,
value
,
MH_FMT_PARSE_DEFAULT
))
if
(
mh_format_parse
(
value
,
&
fmt
))
{
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
:
...
...
@@ -454,7 +456,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
;
};
...
...
Please
register
or
sign in
to post a comment