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]"); ...@@ -25,6 +25,7 @@ static char args_doc[] = N_("[FILE]");
25 static char *format_str; 25 static char *format_str;
26 static mh_format_t format; 26 static mh_format_t format;
27 static int dump_option; 27 static int dump_option;
28 static int disass_option;
28 static int debug_option; 29 static int debug_option;
29 static char *input_file; 30 static char *input_file;
30 static size_t width; 31 static size_t width;
...@@ -41,6 +42,9 @@ static struct mu_option options[] = { ...@@ -41,6 +42,9 @@ static struct mu_option options[] = {
41 { "dump", 0, NULL, MU_OPTION_HIDDEN, 42 { "dump", 0, NULL, MU_OPTION_HIDDEN,
42 N_("dump the listing of compiled format code"), 43 N_("dump the listing of compiled format code"),
43 mu_c_bool, &dump_option }, 44 mu_c_bool, &dump_option },
45 { "disassemble", 0, NULL, MU_OPTION_HIDDEN,
46 N_("dump disassembled format code"),
47 mu_c_bool, &disass_option },
44 { "debug", 0, NULL, MU_OPTION_DEFAULT, 48 { "debug", 0, NULL, MU_OPTION_DEFAULT,
45 N_("enable parser debugging output"), 49 N_("enable parser debugging output"),
46 mu_c_bool, &debug_option }, 50 mu_c_bool, &debug_option },
...@@ -58,11 +62,8 @@ static void ...@@ -58,11 +62,8 @@ static void
58 run (void) 62 run (void)
59 { 63 {
60 mu_message_t msg = mh_file_to_message (NULL, input_file); 64 mu_message_t msg = mh_file_to_message (NULL, input_file);
61 char *output; 65 mh_format (format, msg, msgno, width, mu_strout);
62 66 mu_printf ("\n");
63 mh_format (&format, msg, msgno, width, &output);
64
65 mu_printf ("%s\n", output);
66 } 67 }
67 68
68 int 69 int
...@@ -90,14 +91,16 @@ main (int argc, char **argv) ...@@ -90,14 +91,16 @@ main (int argc, char **argv)
90 mu_error (_("Format string not specified")); 91 mu_error (_("Format string not specified"));
91 return 1; 92 return 1;
92 } 93 }
93 if (mh_format_parse (format_str, &format)) 94 if (mh_format_parse (&format, format_str, MH_FMT_PARSE_TREE))
94 { 95 {
95 mu_error (_("Bad format string")); 96 mu_error (_("Bad format string"));
96 exit (1); 97 exit (1);
97 } 98 }
98 99
99 if (dump_option) 100 if (dump_option)
100 mh_format_dump (&format); 101 mh_format_dump_code (format);
102 if (disass_option)
103 mh_format_dump_disass (format);
101 104
102 if (input_file) 105 if (input_file)
103 run (); 106 run ();
......
...@@ -65,11 +65,6 @@ ...@@ -65,11 +65,6 @@
65 65
66 #include <mu_umaxtostr.h> 66 #include <mu_umaxtostr.h>
67 67
68 #define MH_FMT_RALIGN 0x1000
69 #define MH_FMT_ZEROPAD 0x2000
70 #define MH_FMT_COMPWS 0x4000
71 #define MH_WIDTH_MASK 0x0fff
72
73 #define MH_SEQUENCES_FILE ".mh_sequences" 68 #define MH_SEQUENCES_FILE ".mh_sequences"
74 #define MH_USER_PROFILE ".mh_profile" 69 #define MH_USER_PROFILE ".mh_profile"
75 #define MH_GLOBAL_PROFILE "mh-profile" 70 #define MH_GLOBAL_PROFILE "mh-profile"
...@@ -78,118 +73,6 @@ ...@@ -78,118 +73,6 @@
78 73
79 #define is_true(arg) ((arg) == NULL||mu_true_answer_p (arg) == 1) 74 #define is_true(arg) ((arg) == NULL||mu_true_answer_p (arg) == 1)
80 75
81 enum mh_opcode
82 {
83 /* 0. Stop. Format: mhop_stop */
84 mhop_stop,
85 /* 1. Branch.
86 Format: mhop_branch offset */
87 mhop_branch,
88 /* 2. Assign to numeric register
89 Format: mhop_num_asgn */
90 mhop_num_asgn,
91 /* 3. Assign to string register
92 Format: mhop_str_asgn */
93 mhop_str_asgn,
94 /* 4. Numeric arg follows.
95 Format: mhop_num_arg number */
96 mhop_num_arg,
97 /* 5. String arg follows.
98 Format: mhop_str_arg length string */
99 mhop_str_arg,
100 /* 6. Branch if reg_num is zero.
101 Format: mhop_num_branch dest-off */
102 mhop_num_branch,
103 /* 7. Branch if reg_str is zero.
104 Format: mhop_str_branch dest-off */
105 mhop_str_branch,
106 /* 8. Set str to the value of the header component
107 Format: mhop_header */
108 mhop_header,
109
110 /* 9. Read message body contents into str.
111 Format: mhop_body */
112 mhop_body,
113
114 /* 10. Call a function.
115 Format: mhop_call function-pointer */
116 mhop_call,
117
118 /* 11. assign reg_num to arg_num */
119 mhop_num_to_arg,
120
121 /* 12. assign reg_str to arg_str */
122 mhop_str_to_arg,
123
124 /* 13. Convert arg_str to arg_num */
125 mhop_str_to_num,
126
127 /* 14. Convert arg_num to arg_str */
128 mhop_num_to_str,
129
130 /* 15. Print reg_num */
131 mhop_num_print,
132
133 /* 16. Print reg_str */
134 mhop_str_print,
135
136 /* 17. Set format specification.
137 Format: mhop_fmtspec number */
138 mhop_fmtspec,
139
140 /* 18. Noop */
141 mhop_nop
142 };
143
144 enum mh_type
145 {
146 mhtype_none,
147 mhtype_num,
148 mhtype_str
149 };
150
151 typedef enum mh_opcode mh_opcode_t;
152
153 struct mh_machine;
154 typedef void (*mh_builtin_fp) (struct mh_machine *);
155
156 typedef union {
157 mh_opcode_t opcode;
158 mh_builtin_fp builtin;
159 int num;
160 void *ptr;
161 char str[1]; /* Any number of characters follows */
162 } mh_instr_t;
163
164 #define MHI_OPCODE(m) (m).opcode
165 #define MHI_BUILTIN(m) (m).builtin
166 #define MHI_NUM(m) (m).num
167 #define MHI_PTR(m) (m).ptr
168 #define MHI_STR(m) (m).str
169
170 typedef struct mh_format mh_format_t;
171
172 struct mh_format
173 {
174 size_t progsize; /* Size of allocated program*/
175 mh_instr_t *prog; /* Program itself */
176 };
177
178 #define MHA_REQUIRED 0
179 #define MHA_OPTARG 1
180 #define MHA_OPT_CLEAR 2
181
182 typedef struct mh_builtin mh_builtin_t;
183
184 struct mh_builtin
185 {
186 char *name;
187 mh_builtin_fp fun;
188 int type;
189 int argtype;
190 int optarg;
191 };
192
193 typedef struct 76 typedef struct
194 { 77 {
195 const char *name; 78 const char *name;
...@@ -284,14 +167,22 @@ int mu_getans (const char *variants, const char *fmt, ...) ...@@ -284,14 +167,22 @@ int mu_getans (const char *variants, const char *fmt, ...)
284 int mh_check_folder (const char *pathname, int confirm); 167 int mh_check_folder (const char *pathname, int confirm);
285 int mh_makedir (const char *p); 168 int mh_makedir (const char *p);
286 169
287 int mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno, 170 typedef struct mh_format *mh_format_t;
288 size_t width, char **pret); 171
289 int mh_format_str (mh_format_t *fmt, char *str, size_t width, char **pret); 172 int mh_format (mh_format_t fmt, mu_message_t msg, size_t msgno,
290 void mh_format_dump (mh_format_t *fmt); 173 size_t width, mu_stream_t str);
291 int mh_format_parse (char *format_str, mh_format_t *fmt); 174 int mh_format_str (mh_format_t fmt, char *str, size_t width, char **pret);
175
176 void mh_format_dump_code (mh_format_t fmt);
177 void mh_format_dump_disass (mh_format_t fmt);
178
179 #define MH_FMT_PARSE_DEFAULT 0
180 #define MH_FMT_PARSE_TREE 0x01
181 int mh_format_parse (mh_format_t *fmt, char *format_str, int flags);
182
292 void mh_format_debug (int val); 183 void mh_format_debug (int val);
293 void mh_format_free (mh_format_t *fmt); 184 void mh_format_free (mh_format_t fmt);
294 mh_builtin_t *mh_lookup_builtin (char *name, int *rest); 185 void mh_format_destroy (mh_format_t *fmt);
295 186
296 void mh_error (const char *fmt, ...) MU_PRINTFLIKE(1,2); 187 void mh_error (const char *fmt, ...) MU_PRINTFLIKE(1,2);
297 void mh_err_memory (int fatal); 188 void mh_err_memory (int fatal);
...@@ -350,7 +241,7 @@ int mh_whom_file (const char *filename, int check); ...@@ -350,7 +241,7 @@ int mh_whom_file (const char *filename, int check);
350 int mh_whom_message (mu_message_t msg, int check); 241 int mh_whom_message (mu_message_t msg, int check);
351 242
352 void mh_set_reply_regex (const char *str); 243 void mh_set_reply_regex (const char *str);
353 int mh_decode_2047 (char *text, char **decoded_text); 244 int mh_decode_2047 (char const *text, char **decoded_text);
354 const char *mh_charset (const char *); 245 const char *mh_charset (const char *);
355 246
356 int mh_alias_read (char const *name, int fail); 247 int mh_alias_read (char const *name, int fail);
......
...@@ -17,285 +17,316 @@ ...@@ -17,285 +17,316 @@
17 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ 17 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
18 18
19 #include <mh.h> 19 #include <mh.h>
20 #include <mh_format.h>
20 21
21 int yyerror (const char *s); 22 int yyerror (const char *s);
22 int yylex (); 23 int yylex (void);
23 24
24 static mh_format_t format; /* Format structure being built */
25 static size_t pc; /* Program counter. Poins to current
26 cell in format.prog */
27 static mu_opool_t tokpool; /* Temporary token storage */ 25 static mu_opool_t tokpool; /* Temporary token storage */
28 26
29 #define FORMAT_INC 64 /* Increase format.prog by that many 27
30 cells each time pc reaches 28 /* Lexical context */
31 format.progsize */ 29 enum context
30 {
31 ctx_init, /* Normal text */
32 ctx_if, /* After %< or %? */
33 ctx_expr, /* Expression within cond */
34 ctx_func, /* after (func */
35 };
36
37 static enum context ctx_stack[512];
38 size_t ctx_tos;
39
40 static inline void
41 ctx_push (enum context ctx)
42 {
43 if (ctx_tos == MU_ARRAY_SIZE (ctx_stack))
44 {
45 yyerror ("context nesting level too deep");
46 exit (1);
47 }
48 ctx_stack[ctx_tos++] = ctx;
49 }
32 50
33 static size_t mh_code_op (mh_opcode_t op); 51 static inline void
34 static size_t mh_code_string (char *string); 52 ctx_pop (void)
35 static size_t mh_code_number (int num); 53 {
36 static size_t mh_code_builtin (mh_builtin_t *bp, int argtype); 54 if (ctx_tos == 0)
37 static void branch_fixup (size_t pc, size_t tgt); 55 {
56 yyerror ("out of context");
57 abort ();
58 }
59 ctx_tos--;
60 }
61
62 static inline enum context
63 ctx_get (void)
64 {
65 return ctx_stack[ctx_tos-1];
66 }
67
68 enum node_type
69 {
70 fmtnode_print,
71 fmtnode_literal,
72 fmtnode_number,
73 fmtnode_body,
74 fmtnode_comp,
75 fmtnode_funcall,
76 fmtnode_cntl,
77 fmtnode_typecast
78 };
38 79
39 /* Lexical tie-ins */ 80 struct node
40 static int in_escape; /* Set when inside an escape sequence */ 81 {
41 static int want_function; /* Set when expecting function name */ 82 enum node_type nodetype;
42 static int want_arg; /* Expecting function argument */ 83 enum mh_type datatype;
84 int noprint:1;
85 struct node *prev, *next;
86 union
87 {
88 char *str;
89 long num;
90 struct node *arg;
91 struct
92 {
93 int fmtspec;
94 struct node *arg;
95 } prt;
96 struct
97 {
98 mh_builtin_t *builtin;
99 struct node *arg;
100 } funcall;
101 struct
102 {
103 struct node *cond;
104 struct node *iftrue;
105 struct node *iffalse;
106 } cntl;
107 } v;
108 };
109
110 static struct node *parse_tree;
111 static struct node *new_node (enum node_type nodetype, enum mh_type datatype);
112
113 static struct node *printelim (struct node *root);
114 static void codegen (mh_format_t *fmt, int tree);
115 static struct node *typecast (struct node *node, enum mh_type type);
116
43 %} 117 %}
44 118
45 %union { 119 %union {
46 char *str; 120 char *str;
47 int num; 121 long num;
48 int type;
49 struct { 122 struct {
50 size_t cond; 123 struct node *head, *tail;
51 size_t end; 124 } nodelist;
52 } elif_list; 125 struct node *nodeptr;
53 size_t pc;
54 mh_builtin_t *builtin; 126 mh_builtin_t *builtin;
127 int fmtspec;
128 struct {
129 enum mh_type type;
130 union
131 {
132 char *str;
133 long num;
134 } v;
135 } arg;
55 }; 136 };
137
56 %token <num> NUMBER 138 %token <num> NUMBER
57 %token <str> STRING 139 %token <str> STRING COMPONENT
140 %token <arg> ARGUMENT
58 %token <builtin> FUNCTION 141 %token <builtin> FUNCTION
59 %token IF ELIF ELSE FI 142 %token IF ELIF ELSE FI
60 %token OBRACE CBRACE OCURLY CCURLY 143 %token <fmtspec> FMTSPEC
61 %token <num> FMTSPEC
62 %token BOGUS 144 %token BOGUS
63 %type <type> cond_expr component funcall item argument escape literal 145 %token EOFN
64 %type <elif_list> elif_part elif_list fi 146
65 %type <pc> cond end else elif else_part zlist list pitem 147 %type <nodelist> list zlist elif_list
148 %type <nodeptr> item escape component funcall cntl argument
149 %type <nodeptr> cond cond_expr elif_part else_part printable
66 %type <builtin> function 150 %type <builtin> function
151 %type <fmtspec> fmtspec
67 152
68 %% 153 %%
69 154
70 input : list 155 input : list
71 { 156 {
72 /* nothing: to shut bison up */ 157 parse_tree = $1.head;
73 } 158 }
74 ; 159 ;
75 160
76 list : pitem 161 list : item
77 | list pitem
78 ;
79
80 pitem : item
81 { 162 {
82 switch ($1) 163 $$.head = $$.tail = $1;
83 {
84 case mhtype_none:
85 break;
86
87 case mhtype_num:
88 mh_code_op (mhop_num_asgn);
89 mh_code_op (mhop_num_print);
90 break;
91
92 case mhtype_str:
93 mh_code_op (mhop_str_asgn);
94 mh_code_op (mhop_str_print);
95 break;
96
97 default:
98 yyerror (_("INTERNAL ERROR: unexpected item type (please report)"));
99 abort ();
100 }
101 $$ = pc;
102 } 164 }
103 ; 165 | list item
104 166 {
105 item : literal 167 $2->prev = $1.tail;
106 | escape 168 $1.tail->next = $2;
107 { 169 $1.tail = $2;
108 in_escape = 0; 170 $$ = $1;
109 } 171 }
110 ; 172 ;
111 173
112 literal : STRING 174 item : STRING
113 { 175 {
114 mh_code_string ($1); 176 struct node *n = new_node (fmtnode_literal, mhtype_str);
115 $$ = mhtype_str; 177 n->v.str = $1;
116 } 178 $$ = new_node (fmtnode_print, mhtype_str);
117 | NUMBER 179 $$->v.prt.arg = n;
118 {
119 mh_code_number ($1);
120 $$ = mhtype_num;
121 }
122 ;
123
124 escape : component
125 | funcall
126 | cntl
127 {
128 $$ = mhtype_none;
129 } 180 }
181 | escape
130 ; 182 ;
131 183
132 component : fmtspec OCURLY STRING CCURLY 184 escape : cntl
185 | fmtspec printable
133 { 186 {
134 if (mu_c_strcasecmp ($3, "body") == 0) 187 if ($2->noprint)
135 { 188 $$ = $2;
136 mh_code_op (mhop_body);
137 }
138 else 189 else
139 { 190 {
140 mh_code_string ($3); 191 $$ = new_node (fmtnode_print, $2->datatype);
141 mh_code_op (mhop_header); 192 $$->v.prt.fmtspec = $1;
193 $$->v.prt.arg = $2;
142 } 194 }
143 $$ = mhtype_str;
144 } 195 }
145 ; 196 ;
146 197
147 obrace : OBRACE 198 printable : component
148 { 199 | funcall
149 in_escape++;
150 }
151 ; 200 ;
152 201
153 cbrace : CBRACE 202 component : COMPONENT
154 { 203 {
155 in_escape--; 204 if (mu_c_strcasecmp ($1, "body") == 0)
205 $$ = new_node (fmtnode_body, mhtype_str);
206 else
207 {
208 $$ = new_node (fmtnode_comp, mhtype_str);
209 $$->v.str = $1;
210 }
156 } 211 }
157 ; 212 ;
158 213
159 funcall : fmtspec obrace { want_function = 1;} function { want_function = 0; want_arg = 1;} argument cbrace 214 funcall : function argument EOFN
160 { 215 {
161 if ($4) 216 ctx_pop ();
217 if ($1->optarg == MHA_VOID) /*FIXME*/
162 { 218 {
163 if (!mh_code_builtin ($4, $6)) 219 $2->noprint = 1;
164 YYERROR; 220 $$ = $2;
165 $$ = $4->type;
166 } 221 }
167 else 222 else
168 { 223 {
169 switch ($6) 224 if ($1->argtype == mhtype_none)
170 { 225 {
171 default: 226 if ($2)
172 break; 227 {
173 228 yyerror ("function doesn't take arguments");
174 case mhtype_num: 229 YYABORT;
175 mh_code_op (mhop_num_asgn); 230 }
176 break;
177
178 case mhtype_str:
179 mh_code_op (mhop_str_asgn);
180 break;
181 } 231 }
182 $$ = mhtype_none; 232 else if ($2 == NULL)
233 {
234 if ($1->optarg != MHA_OPTARG)
235 {
236 yyerror ("required argument missing");
237 YYABORT;
238 }
239 }
240 $$ = new_node (fmtnode_funcall, $1->type);
241 $$->v.funcall.builtin = $1;
242 $$->v.funcall.arg = typecast ($2, $1->argtype);
243 $$->noprint = $1->type == mhtype_none;
183 } 244 }
184 } 245 }
185 ; 246 ;
186 247
187 fmtspec : /* empty */ 248 fmtspec : /* empty */
188 | FMTSPEC
189 { 249 {
190 mh_code_op (mhop_fmtspec); 250 $$ = 0;
191 mh_code_op ($1);
192 } 251 }
252 | FMTSPEC
193 ; 253 ;
194 254
195 function : FUNCTION 255 function : FUNCTION
196 | STRING
197 { 256 {
198 if (strcmp ($1, "void") == 0) 257 ctx_push (ctx_func);
199 {
200 $$ = NULL;
201 }
202 else
203 {
204 yyerror (_("undefined function"));
205 mu_error ("%s", $1);
206 YYERROR;
207 }
208 } 258 }
209 ; 259 ;
210 260
211 argument : /* empty */ 261 argument : /* empty */
212 { 262 {
213 $$ = mhtype_none; 263 $$ = NULL;
214 } 264 }
215 | literal 265 | ARGUMENT
216 | escape
217 ;
218
219 /* 1 2 3 4 5 6 7 */
220 cntl : if cond zlist end elif_part else_part fi
221 { 266 {
222 size_t start_pc = 0, end_pc = 0; 267 switch ($1.type)
223
224 /* Fixup first condition */
225 if ($5.cond)
226 MHI_NUM(format.prog[$2]) = $5.cond - $2;
227 else if ($6)
228 MHI_NUM(format.prog[$2]) = $6 - $2;
229 else
230 MHI_NUM(format.prog[$2]) = $7.cond - $2;
231
232 /* Link all "false" lists */
233 if ($5.cond)
234 { 268 {
235 start_pc = $5.end; 269 case mhtype_none:
236 end_pc = $5.end; 270 $$ = NULL;
237 while (MHI_NUM(format.prog[end_pc])) 271 break;
238 end_pc = MHI_NUM(format.prog[end_pc]); 272
239 } 273 case mhtype_str:
274 $$ = new_node (fmtnode_literal, mhtype_str);
275 $$->v.str = $1.v.str;
276 break;
240 277
241 if (start_pc) 278 case mhtype_num:
242 MHI_NUM(format.prog[end_pc]) = $4; 279 $$ = new_node (fmtnode_number, mhtype_num);
243 else 280 $$->v.num = $1.v.num;
244 start_pc = $4; 281 }
282 }
283 | escape
284 {
285 $$ = printelim ($1);
286 }
287 ;
245 288
246 /* Now, fixup the end branches */ 289 /* 1 2 3 4 5 */
247 branch_fixup (start_pc, $7.end); 290 cntl : if cond zlist elif_part fi
248 MHI_NUM(format.prog[start_pc]) = $7.end - start_pc; 291 {
292 $$ = new_node(fmtnode_cntl, mhtype_num);
293 $$->v.cntl.cond = $2;
294 $$->v.cntl.iftrue = $3.head;
295 $$->v.cntl.iffalse = $4;
249 } 296 }
250 ; 297 ;
251 298
252 zlist : /* empty */ 299 zlist : /* empty */
253 { 300 {
254 $$ = pc; 301 $$.head = $$.tail = NULL;
255 } 302 }
256 | list 303 | list
257 ; 304 ;
258 305
259 if : IF 306 if : IF
260 { 307 {
261 in_escape++; 308 ctx_push (ctx_if);
262 } 309 }
263 ; 310 ;
264 311
265 fi : FI 312 fi : FI
266 { 313 {
267 /* False branch of an if-block */ 314 ctx_pop ();
268 $$.cond = mh_code_op (mhop_num_asgn);
269 /* Jump over the true branch */
270 mh_code_op (mhop_branch);
271 mh_code_op (2);
272 /* True branch */
273 $$.end = mh_code_op (mhop_num_asgn);
274 } 315 }
275 ; 316 ;
276 317
277 elif : ELIF 318 elif : ELIF
278 { 319 {
279 in_escape++; 320 ctx_pop ();
280 $$ = pc; 321 ctx_push (ctx_if);
281 }
282 ;
283
284 end : /* empty */
285 {
286 mh_code_op (mhop_branch);
287 $$ = mh_code_op (0);
288 } 322 }
289 ; 323 ;
290 324
291 cond : cond_expr 325 cond : cond_expr
292 { 326 {
293 in_escape--; 327 ctx_pop ();
294 if ($1 == mhtype_str) 328 ctx_push (ctx_expr);
295 mh_code_op (mhop_str_branch); 329 $$ = printelim ($1);
296 else
297 mh_code_op (mhop_num_branch);
298 $$ = mh_code_op (0);
299 } 330 }
300 ; 331 ;
301 332
...@@ -305,45 +336,49 @@ cond_expr : component ...@@ -305,45 +336,49 @@ cond_expr : component
305 336
306 elif_part : /* empty */ 337 elif_part : /* empty */
307 { 338 {
308 $$.cond = 0; 339 $$ = NULL;
309 $$.end = 0;
310 } 340 }
311 | elif_list end 341 | else_part
312 { 342 | elif_list
313 $$.cond = $1.cond; 343 {
314 MHI_NUM(format.prog[$2]) = $1.end; 344 $$ = $1.head;
315 $$.end = $2;
316 } 345 }
317 ; 346 ;
318 347
319 elif_list : elif cond zlist 348 elif_list : elif cond zlist
320 { 349 {
321 $$.cond = $1; 350 struct node *np = new_node (fmtnode_cntl, mhtype_num);
322 MHI_NUM(format.prog[$2]) = pc - $2 + 2; 351 np->v.cntl.cond = $2;
323 $$.end = 0; 352 np->v.cntl.iftrue = $3.head;
353 np->v.cntl.iffalse = NULL;
354 $$.head = $$.tail = np;
324 } 355 }
325 | elif_list end elif cond zlist 356 | elif_list elif cond zlist
326 { 357 {
327 MHI_NUM(format.prog[$4]) = pc - $4 + 2; 358 struct node *np = new_node(fmtnode_cntl, mhtype_num);
328 $$.cond = $1.cond; 359 np->v.cntl.cond = $3;
329 MHI_NUM(format.prog[$2]) = $1.end; 360 np->v.cntl.iftrue = $4.head;
330 $$.end = $2; 361 np->v.cntl.iffalse = NULL;
362
363 $1.tail->v.cntl.iffalse = np;
364 $1.tail = np;
365
366 $$ = $1;
331 } 367 }
368 | elif_list else_part
369 {
370 $1.tail->v.cntl.iffalse = $2;
371 $1.tail = $2;
372 $$ = $1;
373 }
332 ; 374 ;
333 375
334 else_part : /* empty */ 376 else_part : ELSE list
335 { 377 {
336 $$ = 0; 378 $$ = $2.head;
337 } 379 }
338 | else list
339 ; 380 ;
340 381
341 else : ELSE
342 {
343 $$ = pc;
344 }
345 ;
346
347 %% 382 %%
348 383
349 static char *start; 384 static char *start;
...@@ -352,104 +387,154 @@ static char *curp; ...@@ -352,104 +387,154 @@ static char *curp;
352 int 387 int
353 yyerror (const char *s) 388 yyerror (const char *s)
354 { 389 {
355 int len; 390 if (yychar != BOGUS)
356 mu_error ("%s: %s", start, s); 391 {
357 len = curp - start; 392 int len;
358 mu_error ("%*.*s^", len, len, ""); 393 mu_error ("%s: %s", start, s);
394 len = curp - start;
395 mu_error ("%*.*s^", len, len, "");
396 }
359 return 0; 397 return 0;
360 } 398 }
361 399
362 #define isdelim(c) (strchr("%<>?|(){} ",c) != NULL)
363
364 static int percent;
365 static int backslash(int c); 400 static int backslash(int c);
366 401
367 int 402 struct lexer_tab
368 yylex ()
369 { 403 {
370 /* Reset the tie-in */ 404 char *ctx_name;
371 int expect_arg = want_arg; 405 int (*lexer) (void);
372 want_arg = 0; 406 };
407
408 static int yylex_initial (void);
409 static int yylex_cond (void);
410 static int yylex_expr (void);
411 static int yylex_func (void);
412
413 static struct lexer_tab lexer_tab[] = {
414 [ctx_init] = { "initial", yylex_initial },
415 [ctx_if] = { "condition", yylex_cond },
416 [ctx_expr] = { "expression", yylex_expr },
417 [ctx_func] = { "function", yylex_func }
418 };
373 419
420 int
421 yylex (void)
422 {
374 if (yydebug) 423 if (yydebug)
375 fprintf (stderr, "[lex at %10.10s]\n", curp); 424 fprintf (stderr, "lex: [%s] at %-10.10s...]\n",
376 if (*curp == '%') 425 lexer_tab[ctx_get ()].ctx_name, curp);
426 return lexer_tab[ctx_get ()].lexer ();
427 }
428
429 static int
430 token_fmtspec (int flags)
431 {
432 int num = 0;
433
434 if (*curp == '0')
377 { 435 {
436 flags |= MH_FMT_ZEROPAD;
378 curp++; 437 curp++;
379 percent = 1; 438 }
380 if (mu_isdigit (*curp) || *curp == '-') 439 else if (!mu_isdigit (*curp))
381 { 440 {
382 int num = 0; 441 yyerror ("expected digit");
383 int flags = 0; 442 return BOGUS;
443 }
444
445 while (*curp && mu_isdigit (*curp))
446 num = num * 10 + *curp++ - '0';
447 yylval.fmtspec = flags | num;
448 *--curp = '%'; /* FIXME: dirty hack */
449 return FMTSPEC;
450 }
384 451
385 if (*curp == '-') 452 static int
386 { 453 token_function (void)
387 curp++; 454 {
388 flags = MH_FMT_RALIGN; 455 char *start;
389 } 456
390 if (*curp == '0') 457 curp++;
391 flags |= MH_FMT_ZEROPAD; 458 start = curp;
392 while (*curp && mu_isdigit (*curp)) 459 curp = mu_str_skip_class (start, MU_CTYPE_ALPHA);
393 num = num * 10 + *curp++ - '0'; 460 if (start == curp || !strchr (" \t(){%", *curp))
394 yylval.num = num | flags; 461 {
395 return FMTSPEC; 462 yyerror ("expected function name");
396 } 463 return BOGUS;
397 } 464 }
398 465
399 if (percent) 466 yylval.builtin = mh_lookup_builtin (start, curp - start);
467
468 if (!yylval.builtin)
400 { 469 {
401 percent = 0; 470 yyerror ("unknown function");
402 switch (*curp++) 471 return BOGUS;
472 }
473
474 return FUNCTION;
475 }
476
477 static int
478 token_component (void)
479 {
480 char *start;
481
482 curp++;
483 if (!mu_isalpha (*curp))
484 {
485 yyerror ("component name expected");
486 return BOGUS;
487 }
488 start = curp;
489 for (; *curp != '}'; curp++)
490 {
491 if (!(mu_isalnum (*curp) || *curp == '_' || *curp == '-'))
492 {
493 yyerror ("component name expected");
494 return BOGUS;
495 }
496 }
497 mu_opool_append (tokpool, start, curp - start);
498 mu_opool_append_char (tokpool, 0);
499 yylval.str = mu_opool_finish (tokpool, NULL);
500 curp++;
501 return COMPONENT;
502 }
503
504 int
505 yylex_initial (void)
506 {
507 if (*curp == '%')
508 {
509 int c;
510 curp++;
511
512 switch (c = *curp++)
403 { 513 {
404 case '<': 514 case '<':
405 return IF; 515 return IF;
406 case '>':
407 return FI;
408 case '?':
409 return ELIF;
410 case '|':
411 return ELSE;
412 case '%': 516 case '%':
413 return '%'; 517 return '%';
414 case '(': 518 case '(':
415 return OBRACE; 519 curp--;
520 return token_function ();
416 case '{': 521 case '{':
417 return OCURLY; 522 curp--;
523 return token_component ();
524 case '-':
525 return token_fmtspec (MH_FMT_RALIGN);
526 case '0': case '1': case '2': case '3': case '4':
527 case '5': case '6': case '7': case '8': case '9':
528 curp--;
529 return token_fmtspec (MH_FMT_DEFAULT);
418 default: 530 default:
531 yyerror ("component or function name expected");
419 return BOGUS; 532 return BOGUS;
420 } 533 }
421 } 534 }
422 535
423 if (in_escape) 536 if (*curp == 0)
424 { 537 return 0;
425 while (*curp && (*curp == ' ' || *curp == '\n'))
426 curp++;
427 switch (*curp)
428 {
429 case '(':
430 curp++;
431 return OBRACE;
432 case '{':
433 curp++;
434 return OCURLY;
435 case '0':case '1':case '2':case '3':case '4':
436 case '5':case '6':case '7':case '8':case '9':
437 yylval.num = strtol (curp, &curp, 0);
438 return NUMBER;
439 }
440 }
441
442 switch (*curp)
443 {
444 case ')':
445 curp++;
446 return CBRACE;
447 case '}':
448 curp++;
449 return CCURLY;
450 case 0:
451 return 0;
452 }
453 538
454 do 539 do
455 { 540 {
...@@ -462,28 +547,124 @@ yylex () ...@@ -462,28 +547,124 @@ yylex ()
462 mu_opool_append_char (tokpool, *curp); 547 mu_opool_append_char (tokpool, *curp);
463 curp++; 548 curp++;
464 } 549 }
465 while (*curp && (expect_arg ? *curp != ')' : !isdelim(*curp))); 550 while (*curp && *curp != '%');
466 551
467 mu_opool_append_char (tokpool, 0); 552 mu_opool_append_char (tokpool, 0);
468 yylval.str = mu_opool_finish (tokpool, NULL); 553 yylval.str = mu_opool_finish (tokpool, NULL);
554 return STRING;
555 }
469 556
470 if (want_function) 557 int
558 yylex_cond (void)
559 {
560 switch (*curp)
471 { 561 {
472 int rest; 562 case '(':
473 mh_builtin_t *bp = mh_lookup_builtin (yylval.str, &rest); 563 return token_function ();
474 if (bp) 564 case '{':
565 return token_component ();
566 default:
567 yyerror ("'(' or '{' expected");
568 return BOGUS;
569 }
570 }
571
572 int
573 yylex_expr (void)
574 {
575 if (*curp == '%')
576 {
577 curp++;
578 switch (*curp++)
475 { 579 {
476 curp -= rest; 580 case '?':
477 yylval.builtin = bp; 581 return ELIF;
478 while (*curp && mu_isspace (*curp)) 582 case '|':
479 curp++; 583 return ELSE;
480 return FUNCTION; 584 case '>':
585 return FI;
481 } 586 }
587 curp -= 2;
482 } 588 }
483 589 return yylex_initial ();
484 return STRING;
485 } 590 }
486 591
592 int
593 yylex_func (void)
594 {
595 /* Expected argument or closing parenthesis */
596 while (*curp && mu_isspace (*curp))
597 curp++;
598
599 switch (*curp)
600 {
601 case '(':
602 return token_function ();
603
604 case ')':
605 curp++;
606 return EOFN;
607
608 case '{':
609 return token_component ();
610
611 case '%':
612 curp++;
613 switch (*curp)
614 {
615 case '<':
616 curp++;
617 return IF;
618
619 case '%':
620 break;
621
622 default:
623 yyerror ("expected '%' or '<'");
624 return BOGUS;
625 }
626 }
627
628 if (mu_isdigit (*curp))
629 {
630 yylval.arg.type = mhtype_num;
631 yylval.arg.v.num = strtol (curp, &curp, 0);
632 }
633 else
634 {
635 do
636 {
637 if (*curp == 0)
638 {
639 yyerror("expected ')'");
640 return BOGUS;
641 }
642
643 if (*curp == '\\')
644 {
645 int c = backslash (*++curp);
646 mu_opool_append_char (tokpool, c);
647 }
648 else
649 mu_opool_append_char (tokpool, *curp);
650 curp++;
651 }
652 while (*curp != ')');
653 mu_opool_append_char (tokpool, 0);
654
655 yylval.arg.type = mhtype_str;
656 yylval.arg.v.str = mu_opool_finish (tokpool, NULL);
657 }
658
659 if (*curp != ')')
660 {
661 yyerror("expected ')'");
662 return BOGUS;
663 }
664
665 return ARGUMENT;
666 }
667
487 void 668 void
488 mh_format_debug (int val) 669 mh_format_debug (int val)
489 { 670 {
...@@ -491,37 +672,32 @@ mh_format_debug (int val) ...@@ -491,37 +672,32 @@ mh_format_debug (int val)
491 } 672 }
492 673
493 int 674 int
494 mh_format_parse (char *format_str, mh_format_t *fmt) 675 mh_format_parse (mh_format_t *fmtptr, char *format_str, int flags)
495 { 676 {
496 int rc; 677 int rc;
497 char *p = getenv ("MHFORMAT_DEBUG"); 678 char *p = getenv ("MHFORMAT_DEBUG");
498 679
499 if (p) 680 if (p || mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE2))
500 yydebug = 1; 681 yydebug = 1;
501 start = curp = format_str; 682 start = curp = format_str;
502 mu_opool_create (&tokpool, MU_OPOOL_ENOMEMABRT); 683 mu_opool_create (&tokpool, MU_OPOOL_ENOMEMABRT);
503 format.prog = NULL;
504 format.progsize = 0;
505 pc = 0;
506 mh_code_op (mhop_stop);
507
508 in_escape = 0;
509 percent = 0;
510 684
685 ctx_tos = 0;
686 ctx_push (ctx_init);
687
511 rc = yyparse (); 688 rc = yyparse ();
512 mh_code_op (mhop_stop); 689 if (rc == 0)
513 mu_opool_destroy (&tokpool); 690 codegen (fmtptr, flags & MH_FMT_PARSE_TREE);
514 if (rc) 691 else
515 { 692 mu_opool_destroy (&tokpool);
516 mh_format_free (&format); 693
517 return 1; 694 parse_tree = NULL;
518 } 695 tokpool = NULL;
519 *fmt = format; 696 return rc;
520 return 0;
521 } 697 }
522 698
523 int 699 int
524 backslash(int c) 700 backslash (int c)
525 { 701 {
526 static char transtab[] = "b\bf\fn\nr\rt\t"; 702 static char transtab[] = "b\bf\fn\nr\rt\t";
527 char *p; 703 char *p;
...@@ -534,131 +710,500 @@ backslash(int c) ...@@ -534,131 +710,500 @@ backslash(int c)
534 return c; 710 return c;
535 } 711 }
536 712
713 static struct node *
714 new_node (enum node_type nodetype, enum mh_type datatype)
715 {
716 struct node *np = mu_zalloc (sizeof *np);
717 np->nodetype = nodetype;
718 np->datatype = datatype;
719 return np;
720 }
721
722 static void node_list_free (struct node *node);
723
724 static void
725 node_free (struct node *node)
726 {
727 switch (node->nodetype)
728 {
729 case fmtnode_print:
730 node_free (node->v.prt.arg);
731 break;
732
733 case fmtnode_literal:
734 break;
735
736 case fmtnode_number:
737 break;
738
739 case fmtnode_body:
740 break;
741
742 case fmtnode_comp:
743 break;
744
745 case fmtnode_funcall:
746 node_free (node->v.funcall.arg);
747 break;
748
749 case fmtnode_cntl:
750 node_list_free (node->v.cntl.cond);
751 node_list_free (node->v.cntl.iftrue);
752 node_list_free (node->v.cntl.iffalse);
753 break;
754
755 default:
756 abort ();
757 }
758 free (node);
759 }
760
761 static void
762 node_list_free (struct node *node)
763 {
764 while (node)
765 {
766 struct node *next = node->next;
767 node_free (node);
768 node = next;
769 }
770 }
771
772 static struct node *
773 typecast (struct node *node, enum mh_type type)
774 {
775 if (!node)
776 /* FIXME: when passing optional argument, the caller must know the
777 type of value returned by the previous expression */
778 return node;
779 if (node->datatype == type)
780 return node;
781 if (node->nodetype == fmtnode_cntl)
782 {
783 node->v.cntl.iftrue = typecast (node->v.cntl.iftrue, type);
784 node->v.cntl.iffalse = typecast (node->v.cntl.iffalse, type);
785 node->datatype = type;
786 }
787 else
788 {
789 struct node *np = new_node (fmtnode_typecast, type);
790 np->v.arg = node;
791 node = np;
792 }
793 return node;
794 }
795
796 #define INLINE -1
797
798 static inline void
799 indent (int level)
800 {
801 printf ("%*.*s", 2*level, 2*level, "");
802 }
803
804 static inline void
805 delim (int level, char const *dstr)
806 {
807 if (level == INLINE)
808 printf ("%s", dstr);
809 else
810 {
811 printf ("\n");
812 indent (level);
813 }
814 }
815
816 static void dump_statement (struct node *node, int level);
817
537 void 818 void
538 branch_fixup (size_t epc, size_t tgt) 819 mh_print_fmtspec (int fmtspec)
539 { 820 {
540 size_t prev = MHI_NUM(format.prog[epc]); 821 if (!(fmtspec & (MH_FMT_RALIGN|MH_FMT_ZEROPAD|MH_FMT_COMPWS)))
541 if (!prev) 822 printf ("NONE");
542 return; 823 else
543 branch_fixup (prev, tgt); 824 {
544 MHI_NUM(format.prog[prev]) = tgt - prev; 825 if (!(fmtspec & MH_FMT_RALIGN))
826 printf ("NO");
827 printf ("RALIGN|");
828 if (!(fmtspec & MH_FMT_ZEROPAD))
829 printf ("NO");
830 printf ("ZEROPAD|");
831 if (!(fmtspec & MH_FMT_COMPWS))
832 printf ("NO");
833 printf ("COMPWS");
834 }
835 }
836
837 static char *typename[] = { "NONE", "NUM", "STR" };
838
839 static void
840 dump_node_pretty (struct node *node, int level)
841 {
842 switch (node->nodetype)
843 {
844 case fmtnode_print:
845 if (node->v.prt.fmtspec)
846 {
847 printf ("FORMAT(");
848 mh_print_fmtspec (node->v.prt.fmtspec);
849 printf(", %d, ", node->v.prt.fmtspec & MH_WIDTH_MASK);
850 }
851 else
852 printf ("PRINT(%d,", node->v.prt.fmtspec);
853 dump_statement (node->v.prt.arg, INLINE);
854 printf (")");
855 break;
856
857 case fmtnode_literal:
858 {
859 char const *p = node->v.str;
860 putchar ('"');
861 while (*p)
862 {
863 if (*p == '\\' || *p == '"')
864 {
865 putchar ('\\');
866 putchar (*p);
867 }
868 else if (*p == '\n')
869 {
870 putchar ('\\');
871 putchar ('n');
872 }
873 else
874 putchar (*p);
875 p++;
876 }
877 putchar ('"');
878 }
879 break;
880
881 case fmtnode_number:
882 printf ("%ld", node->v.num);
883 break;
884
885 case fmtnode_body:
886 printf ("BODY");
887 break;
888
889 case fmtnode_comp:
890 printf ("COMPONENT.%s", node->v.str);
891 break;
892
893 case fmtnode_funcall:
894 printf ("%s(", node->v.funcall.builtin->name);
895 dump_statement (node->v.funcall.arg, INLINE);
896 printf (")");
897 break;
898
899 case fmtnode_cntl:
900 printf ("IF (");
901 dump_node_pretty (node->v.cntl.cond, INLINE);
902 printf (") THEN");
903
904 if (level != INLINE)
905 level++;
906
907 delim (level, "; ");
908
909 dump_statement (node->v.cntl.iftrue, level);
910
911 if (node->v.cntl.iffalse)
912 {
913 delim (level == INLINE ? level : level - 1, "; ");
914 printf ("ELSE");
915 delim (level, " ");
916 dump_statement (node->v.cntl.iffalse, level);
917 }
918
919 if (level != INLINE)
920 level--;
921 delim (level, "; ");
922 printf ("FI");
923 break;
924
925 case fmtnode_typecast:
926 printf ("%s(", typename[node->datatype]);
927 dump_node_pretty (node->v.arg, INLINE);
928 printf (")");
929 break;
930
931 default:
932 abort ();
933 }
934 }
935
936 static void
937 dump_statement (struct node *node, int level)
938 {
939 while (node)
940 {
941 dump_node_pretty (node, level);
942 node = node->next;
943 if (node)
944 delim (level, "; ");
945 }
946 }
947
948 void
949 mh_format_dump_code (mh_format_t fmt)
950 {
951 dump_statement (fmt->tree, 0);
952 printf ("\n");
953 }
954
955 void
956 mh_format_free_tree (mh_format_t fmt)
957 {
958 if (fmt)
959 {
960 node_list_free (fmt->tree);
961 fmt->tree = NULL;
962 mu_opool_destroy (&fmt->pool);
963 }
545 } 964 }
546 965
966 void
967 mh_format_free (mh_format_t fmt)
968 {
969 if (!fmt)
970 return;
971
972 mh_format_free_tree (fmt);
973
974 if (fmt->prog)
975 free (fmt->prog);
976 fmt->progmax = fmt->progcnt = 0;
977 fmt->prog = NULL;
978 }
547 979
548 /* Make sure there are at least `count' entries available in the prog
549 buffer */
550 void 980 void
551 prog_reserve (size_t count) 981 mh_format_destroy (mh_format_t *fmt)
982 {
983 if (fmt)
984 {
985 mh_format_free (*fmt);
986 *fmt = NULL;
987 }
988 }
989
990 static struct node *
991 printelim (struct node *node)
552 { 992 {
553 if (pc + count >= format.progsize) 993 if (node->nodetype == fmtnode_print)
554 { 994 {
555 size_t inc = (count + 1) / FORMAT_INC + 1; 995 struct node *arg = node->v.prt.arg;
556 format.progsize += inc * FORMAT_INC; 996 arg->next = node->next;
557 format.prog = mu_realloc (format.prog, 997 free (node);
558 format.progsize * sizeof format.prog[0]); 998 node = arg;
559 } 999 }
1000 return node;
560 } 1001 }
1002
1003 #define PROG_MIN_ALLOC 8
561 1004
562 size_t 1005 static inline void
563 mh_code_string (char *string) 1006 ensure_space (struct mh_format *fmt, size_t n)
564 { 1007 {
565 int length = strlen (string) + 1; 1008 while (fmt->progcnt + n >= fmt->progmax)
566 size_t count = (length + sizeof (mh_instr_t)) / sizeof (mh_instr_t); 1009 {
567 size_t start_pc = pc; 1010 if (fmt->progmax == 0)
1011 fmt->progmax = n < PROG_MIN_ALLOC ? PROG_MIN_ALLOC : n;
1012 fmt->prog = mu_2nrealloc (fmt->prog, &fmt->progmax, sizeof fmt->prog[0]);
1013 }
1014 }
568 1015
569 mh_code_op (mhop_str_arg); 1016 static void
570 prog_reserve (count); 1017 emit_instr (struct mh_format *fmt, mh_instr_t instr)
571 MHI_NUM(format.prog[pc++]) = count; 1018 {
572 memcpy (MHI_STR(format.prog[pc]), string, length); 1019 ensure_space (fmt, 1);
573 pc += count; 1020 fmt->prog[fmt->progcnt++] = instr;
574 return start_pc;
575 } 1021 }
576 1022
577 size_t 1023 static inline void
578 mh_code (mh_instr_t *instr) 1024 emit_opcode (struct mh_format *fmt, mh_opcode_t op)
1025 {
1026 emit_instr (fmt, (mh_instr_t) op);
1027 }
1028
1029 static void
1030 emit_string (struct mh_format *fmt, char const *str)
579 { 1031 {
580 prog_reserve (1); 1032 size_t length = strlen (str) + 1;
581 format.prog[pc] = *instr; 1033 size_t count = (length + sizeof (mh_instr_t)) / sizeof (mh_instr_t) + 1;
582 return pc++; 1034
1035 ensure_space (fmt, count);
1036 emit_instr (fmt, (mh_instr_t) count);
1037 memcpy (MHI_STR (fmt->prog[fmt->progcnt]), str, length);
1038 fmt->progcnt += count;
583 } 1039 }
584 1040
585 size_t 1041 static void codegen_node (struct mh_format *fmt, struct node *node);
586 mh_code_op (mh_opcode_t op) 1042 static void codegen_nodelist (struct mh_format *fmt, struct node *node);
1043
1044 static void
1045 emit_opcode_typed (struct mh_format *fmt, enum mh_type type,
1046 enum mh_opcode opnum, enum mh_opcode opstr)
587 { 1047 {
588 mh_instr_t instr; 1048 switch (type)
589 MHI_OPCODE(instr) = op; 1049 {
590 return mh_code(&instr); 1050 case mhtype_num:
1051 emit_opcode (fmt, opnum);
1052 break;
1053
1054 case mhtype_str:
1055 emit_opcode (fmt, opstr);
1056 break;
1057
1058 default:
1059 abort ();
1060 }
591 } 1061 }
592 1062
593 size_t 1063 static void
594 mh_code_number (int num) 1064 emit_funcall (struct mh_format *fmt, mh_builtin_t *builtin, struct node *arg)
595 { 1065 {
596 mh_instr_t instr; 1066 if (arg)
597 size_t ret = mh_code_op (mhop_num_arg); 1067 {
598 MHI_NUM(instr) = num; 1068 codegen_node (fmt, arg);
599 mh_code (&instr); 1069 emit_opcode_typed (fmt, arg->datatype, mhop_movn, mhop_movs);
600 return ret; 1070 }
1071 else if (builtin->argtype != mhtype_none)
1072 emit_opcode_typed (fmt, builtin->type, mhop_movn, mhop_movs);
1073
1074 emit_instr (fmt, (mh_instr_t) (long) R_ARG);
1075 emit_instr (fmt, (mh_instr_t) (long) R_REG);
1076
1077 emit_opcode (fmt, mhop_call);
1078 emit_instr (fmt, (mh_instr_t) builtin->fun);
601 } 1079 }
602 1080
603 size_t 1081 static void
604 mh_code_builtin (mh_builtin_t *bp, int argtype) 1082 codegen_node (struct mh_format *fmt, struct node *node)
605 { 1083 {
606 mh_instr_t instr; 1084 switch (node->nodetype)
607 size_t start_pc = pc;
608 if (bp->argtype != argtype)
609 { 1085 {
610 if (argtype == mhtype_none) 1086 case fmtnode_print:
1087 codegen_node (fmt, node->v.prt.arg);
1088 if (node->v.prt.fmtspec)
611 { 1089 {
612 if (bp->optarg) 1090 emit_opcode (fmt, mhop_fmtspec);
613 { 1091 emit_instr (fmt, (mh_instr_t) (long) node->v.prt.fmtspec);
614 switch (bp->argtype)
615 {
616 case mhtype_num:
617 mh_code_op (mhop_num_to_arg);
618 break;
619
620 case mhtype_str:
621 if (bp->optarg == MHA_OPT_CLEAR)
622 mh_code_string ("");
623 /* mhtype_none means that the argument was an escape,
624 which has left its string value (if any) in the
625 arg_str register. Therefore, there's no need to
626 code mhop_str_to_arg */
627 break;
628
629 default:
630 yyerror (_("INTERNAL ERROR: unknown argtype (please report)"));
631 abort ();
632 }
633 }
634 else
635 {
636 mu_error (_("missing argument for %s"), bp->name);
637 return 0;
638 }
639 } 1092 }
640 else 1093
1094 if (node->v.prt.arg->datatype != mhtype_none)
1095 emit_opcode_typed (fmt, node->v.prt.arg->datatype,
1096 mhop_printn, mhop_prints);
1097 break;
1098
1099 case fmtnode_literal:
1100 emit_opcode (fmt, mhop_sets);
1101 emit_instr (fmt, (mh_instr_t) (long) R_REG);
1102 emit_string (fmt, node->v.str);
1103 break;
1104
1105 case fmtnode_number:
1106 emit_opcode (fmt, mhop_setn);
1107 emit_instr (fmt, (mh_instr_t) (long) R_REG);
1108 break;
1109
1110 case fmtnode_body:
1111 emit_opcode (fmt, mhop_ldbody);
1112 emit_instr (fmt, (mh_instr_t) (long) R_REG);
1113 break;
1114
1115 case fmtnode_comp:
1116 emit_opcode (fmt, mhop_ldcomp);
1117 emit_instr (fmt, (mh_instr_t) (long) R_REG);
1118 emit_string (fmt, node->v.str);
1119 break;
1120
1121 case fmtnode_funcall:
1122 emit_funcall (fmt, node->v.funcall.builtin, node->v.funcall.arg);
1123 break;
1124
1125 case fmtnode_cntl:
1126 {
1127 long pc[2];
1128
1129 codegen_node (fmt, node->v.cntl.cond);
1130 emit_opcode_typed (fmt, node->v.cntl.cond->datatype,
1131 mhop_brzn, mhop_brzs);
1132 pc[0] = fmt->progcnt;
1133 emit_instr (fmt, (mh_instr_t) NULL);
1134 if (node->v.cntl.iftrue)
1135 {
1136 codegen_nodelist (fmt, node->v.cntl.iftrue);
1137 }
1138 emit_opcode (fmt, mhop_branch);
1139 pc[1] = fmt->progcnt;
1140 emit_instr (fmt, (mh_instr_t) NULL);
1141
1142 fmt->prog[pc[0]].num = fmt->progcnt - pc[0];
1143 if (node->v.cntl.iffalse)
1144 {
1145 codegen_nodelist (fmt, node->v.cntl.iffalse);
1146 }
1147 fmt->prog[pc[1]].num = fmt->progcnt - pc[1];
1148 }
1149 break;
1150
1151 case fmtnode_typecast:
1152 codegen_node (fmt, node->v.arg);
1153 switch (node->datatype)
641 { 1154 {
642 switch (bp->argtype) 1155 case mhtype_num:
643 { 1156 emit_opcode (fmt, mhop_itoa);
644 case mhtype_none: 1157 break;
645 mu_error (_("extra arguments to %s"), bp->name); 1158
646 return 0; 1159 case mhtype_str:
647 1160 emit_opcode (fmt, mhop_atoi);
648 case mhtype_num: 1161 break;
649 mh_code_op (mhop_str_to_num); 1162
650 break; 1163 default:
651 1164 abort ();
652 case mhtype_str:
653 mh_code_op (mhop_num_to_str);
654 break;
655 }
656 } 1165 }
1166 break;
1167
1168 default:
1169 abort ();
1170 }
1171 }
1172
1173 static void
1174 codegen_nodelist (struct mh_format *fmt, struct node *node)
1175 {
1176 while (node)
1177 {
1178 codegen_node (fmt, node);
1179 node = node->next;
657 } 1180 }
1181 }
1182
1183 static void
1184 codegen (mh_format_t *fmtptr, int tree)
1185 {
1186 struct mh_format *fmt;
658 1187
659 mh_code_op (mhop_call); 1188 fmt = mu_zalloc (sizeof *fmt);
660 MHI_BUILTIN(instr) = bp->fun; 1189
661 mh_code (&instr); 1190 *fmtptr = fmt;
662 return start_pc; 1191 emit_opcode (fmt, mhop_stop);
1192 codegen_nodelist (fmt, parse_tree);
1193 emit_opcode (fmt, mhop_stop);
1194
1195 if (tree)
1196 {
1197 fmt->tree = parse_tree;
1198 fmt->pool = tokpool;
1199 }
1200 else
1201 {
1202 node_list_free (parse_tree);
1203 mu_opool_destroy (&tokpool);
1204 }
663 } 1205 }
664 1206
1207
1208
1209
......
...@@ -28,92 +28,97 @@ ...@@ -28,92 +28,97 @@
28 #include "mbchar.h" 28 #include "mbchar.h"
29 #include "mbswidth.h" 29 #include "mbswidth.h"
30 30
31 static char *_get_builtin_name (mh_builtin_fp ptr); 31
32 /* String functions */
32 33
33 #define DFLWIDTH(mach) ((mach)->width - (mach)->ind) 34 #define MH_STRING_INITIALIZER { 0, NULL }
34 35
35 /* Functions for handling string objects. */ 36 static inline void
37 mh_string_init (struct mh_string *s)
38 {
39 s->size = 0;
40 s->ptr = NULL;
41 }
36 42
37 void 43 static void
38 strobj_free (strobj_t *obj) 44 mh_string_free (struct mh_string *s)
39 { 45 {
40 if (obj->size) 46 free (s->ptr);
41 free (obj->ptr); 47 s->size = 0;
42 obj->size = 0; 48 s->ptr = NULL;
43 obj->ptr = NULL;
44 } 49 }
45 50
46 void 51 static void
47 strobj_create (strobj_t *lvalue, const char *str) 52 mh_string_realloc (struct mh_string *s, size_t length)
48 { 53 {
49 if (!str) 54 if (length > s->size)
50 {
51 lvalue->size = 0;
52 lvalue->ptr = NULL;
53 }
54 else
55 { 55 {
56 lvalue->size = strlen (str) + 1; 56 s->ptr = mu_realloc (s->ptr, length);
57 lvalue->ptr = mu_alloc (lvalue->size); 57 s->ptr[length-1] = 0;
58 memcpy (lvalue->ptr, str, lvalue->size); 58 s->size = length;
59 } 59 }
60 } 60 }
61 61
62 void 62 static inline int
63 strobj_set (strobj_t *lvalue, char *str) 63 mh_string_is_null (struct mh_string *s)
64 { 64 {
65 lvalue->size = 0; 65 return s->ptr == NULL || s->ptr[0] == 0;
66 lvalue->ptr = str;
67 } 66 }
68 67
69 void 68 static inline size_t
70 strobj_assign (strobj_t *lvalue, strobj_t *rvalue) 69 mh_string_length (struct mh_string *s)
71 { 70 {
72 strobj_free (lvalue); 71 return mh_string_is_null (s) ? 0 : strlen (s->ptr);
73 *lvalue = *rvalue;
74 rvalue->size = 0;
75 rvalue->ptr = NULL;
76 } 72 }
77 73
78 void 74 static inline char const *
79 strobj_copy (strobj_t *lvalue, strobj_t *rvalue) 75 mh_string_value (struct mh_string *s)
80 { 76 {
81 if (strobj_is_null (rvalue)) 77 return mh_string_is_null (s) ? "" : s->ptr;
82 strobj_free (lvalue);
83 else if (lvalue->size >= strobj_len (rvalue) + 1)
84 memcpy (lvalue->ptr, strobj_ptr (rvalue), strobj_len (rvalue) + 1);
85 else
86 {
87 if (lvalue->size)
88 strobj_free (lvalue);
89 strobj_create (lvalue, strobj_ptr (rvalue));
90 }
91 } 78 }
92 79
93 void 80 static inline void
94 strobj_realloc (strobj_t *obj, size_t length) 81 mh_string_clear (struct mh_string *s)
95 { 82 {
96 if (strobj_is_static (obj)) 83 if (s->ptr)
97 { 84 s->ptr[0] = 0;
98 char *value = strobj_ptr (obj); 85 }
99 obj->ptr = mu_alloc (length); 86
100 strncpy (obj->ptr, value, length-1); 87 static void
101 obj->ptr[length-1] = 0; 88 mh_string_load (struct mh_string *s, char const *str)
102 obj->size = length; 89 {
103 } 90 if (!str)
91 mh_string_clear (s);
104 else 92 else
105 { 93 {
106 obj->ptr = mu_realloc (obj->ptr, length); 94 mh_string_realloc (s, strlen (str));
107 obj->ptr[length-1] = 0; 95 strcpy (s->ptr, str);
108 obj->size = length;
109 } 96 }
110 } 97 }
111 98
99 static void
100 mh_string_move (struct mh_machine *mach, enum regid dst, enum regid src)
101 {
102 mh_string_load (&mach->str[dst], mach->str[src].ptr);
103 mh_string_clear (&mach->str[src]);
104 }
105
106
107 static char *_get_builtin_name (mh_builtin_fp ptr);
108
109 static inline size_t
110 output_width (struct mh_machine *mach)
111 {
112 if (mach->width < mach->ind)
113 return 0;
114 return mach->width - mach->ind;
115 }
116
112 /* Return the length (number of octets) of a substring of 117 /* Return the length (number of octets) of a substring of
113 string STR of length LEN, such that it contains NCOL 118 string STR of length LEN, such that it contains NCOL
114 multibyte characters. */ 119 multibyte characters. */
115 int 120 int
116 mbsubstrlen (char *str, size_t len, size_t ncol) 121 mbsubstrlen (char const *str, size_t len, size_t ncol)
117 { 122 {
118 int ret = 0; 123 int ret = 0;
119 mbi_iterator_t iter; 124 mbi_iterator_t iter;
...@@ -131,7 +136,7 @@ mbsubstrlen (char *str, size_t len, size_t ncol) ...@@ -131,7 +136,7 @@ mbsubstrlen (char *str, size_t len, size_t ncol)
131 /* Return the number of multibyte characters in the first LEN bytes 136 /* Return the number of multibyte characters in the first LEN bytes
132 of character string STRING. */ 137 of character string STRING. */
133 size_t 138 size_t
134 mbsnlen (char *str, size_t len) 139 mbsnlen (char const *str, size_t len)
135 { 140 {
136 int ret = 0; 141 int ret = 0;
137 mbi_iterator_t iter; 142 mbi_iterator_t iter;
...@@ -143,10 +148,10 @@ mbsnlen (char *str, size_t len) ...@@ -143,10 +148,10 @@ mbsnlen (char *str, size_t len)
143 148
144 /* Compress whitespace in a string (multi-byte) */ 149 /* Compress whitespace in a string (multi-byte) */
145 static void 150 static void
146 compress_ws (char *str, size_t *psize) 151 str_compress_ws (char *str)
147 { 152 {
148 unsigned char *p, *q; 153 unsigned char *p, *q;
149 size_t size = *psize; 154 size_t size = strlen (str);
150 mbi_iterator_t iter; 155 mbi_iterator_t iter;
151 int space = 0; 156 int space = 0;
152 157
...@@ -173,29 +178,26 @@ compress_ws (char *str, size_t *psize) ...@@ -173,29 +178,26 @@ compress_ws (char *str, size_t *psize)
173 } 178 }
174 } 179 }
175 *p = 0; 180 *p = 0;
176 *psize = p - (unsigned char*) str;
177 } 181 }
178 182
179 #define COMPRESS_WS(mach, str, size) \ 183 static inline void
180 do \ 184 compress_ws (struct mh_machine *mach, char *str)
181 { \ 185 {
182 if ((mach)->fmtflags & MH_FMT_COMPWS) \ 186 if (mach->fmtflags & MH_FMT_COMPWS)
183 compress_ws (str, size); \ 187 str_compress_ws (str);
184 } \ 188 }
185 while (0)
186 189
187 static void 190 static void
188 put_string (struct mh_machine *mach, char *str, int len) 191 put_string (struct mh_machine *mach, char const *str, int len)
189 { 192 {
190 if (len == 0) 193 if (len == 0)
191 return; 194 return;
192 mu_opool_append (mach->pool, str, len); 195 mu_stream_write (mach->output, str, len, NULL);
193 len = mbsnwidth (str, len, 0); 196 mach->ind += mbsnwidth (str, len, 0);
194 mach->ind += len;
195 } 197 }
196 198
197 static void 199 static void
198 print_hdr_segment (struct mh_machine *mach, char *str, size_t len) 200 print_hdr_segment (struct mh_machine *mach, char const *str, size_t len)
199 { 201 {
200 if (!len) 202 if (!len)
201 len = strlen (str); 203 len = strlen (str);
...@@ -207,7 +209,7 @@ print_hdr_segment (struct mh_machine *mach, char *str, size_t len) ...@@ -207,7 +209,7 @@ print_hdr_segment (struct mh_machine *mach, char *str, size_t len)
207 while (1) 209 while (1)
208 { 210 {
209 mbi_iterator_t iter; 211 mbi_iterator_t iter;
210 size_t rest = DFLWIDTH (mach); 212 size_t rest = output_width (mach);
211 size_t width = mbsnlen (str, len); 213 size_t width = mbsnlen (str, len);
212 size_t off, size; 214 size_t off, size;
213 215
...@@ -245,11 +247,10 @@ print_hdr_segment (struct mh_machine *mach, char *str, size_t len) ...@@ -245,11 +247,10 @@ print_hdr_segment (struct mh_machine *mach, char *str, size_t len)
245 } 247 }
246 } 248 }
247 249
248 /* Print len bytes from str into mach->outbuf */
249 static void 250 static void
250 print_hdr_string (struct mh_machine *mach, char *str) 251 print_hdr_string (struct mh_machine *mach, char const *str)
251 { 252 {
252 char *p; 253 char const *p;
253 254
254 if (!str) 255 if (!str)
255 str = ""; 256 str = "";
...@@ -269,7 +270,7 @@ print_hdr_string (struct mh_machine *mach, char *str) ...@@ -269,7 +270,7 @@ print_hdr_string (struct mh_machine *mach, char *str)
269 270
270 static void 271 static void
271 print_simple_segment (struct mh_machine *mach, size_t width, 272 print_simple_segment (struct mh_machine *mach, size_t width,
272 char *str, size_t len) 273 char const *str, size_t len)
273 { 274 {
274 size_t rest; 275 size_t rest;
275 276
...@@ -282,7 +283,7 @@ print_simple_segment (struct mh_machine *mach, size_t width, ...@@ -282,7 +283,7 @@ print_simple_segment (struct mh_machine *mach, size_t width,
282 if (!width) 283 if (!width)
283 width = mach->width; 284 width = mach->width;
284 285
285 rest = DFLWIDTH (mach); 286 rest = output_width (mach);
286 if (rest == 0) 287 if (rest == 0)
287 { 288 {
288 if (len == 1 && str[0] == '\n') 289 if (len == 1 && str[0] == '\n')
...@@ -294,7 +295,7 @@ print_simple_segment (struct mh_machine *mach, size_t width, ...@@ -294,7 +295,7 @@ print_simple_segment (struct mh_machine *mach, size_t width,
294 } 295 }
295 296
296 static void 297 static void
297 print_string (struct mh_machine *mach, size_t width, char *str) 298 print_string (struct mh_machine *mach, size_t width, char const *str)
298 { 299 {
299 char *p; 300 char *p;
300 301
...@@ -318,7 +319,7 @@ print_string (struct mh_machine *mach, size_t width, char *str) ...@@ -318,7 +319,7 @@ print_string (struct mh_machine *mach, size_t width, char *str)
318 } 319 }
319 320
320 static void 321 static void
321 print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char *str, 322 print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char const *str,
322 size_t len) 323 size_t len)
323 { 324 {
324 size_t width = mbsnlen (str, len); 325 size_t width = mbsnlen (str, len);
...@@ -329,7 +330,7 @@ print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char *str, ...@@ -329,7 +330,7 @@ print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char *str,
329 width = fmtwidth; 330 width = fmtwidth;
330 } 331 }
331 else 332 else
332 len = mbsubstrlen (str, len, DFLWIDTH (mach)); 333 len = mbsubstrlen (str, len, output_width (mach));
333 334
334 put_string (mach, str, len); 335 put_string (mach, str, len);
335 336
...@@ -338,12 +339,12 @@ print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char *str, ...@@ -338,12 +339,12 @@ print_fmt_segment (struct mh_machine *mach, size_t fmtwidth, char *str,
338 fmtwidth -= width; 339 fmtwidth -= width;
339 mach->ind += fmtwidth; 340 mach->ind += fmtwidth;
340 while (fmtwidth--) 341 while (fmtwidth--)
341 mu_opool_append_char (mach->pool, ' '); 342 mu_stream_write (mach->output, " ", 1, NULL);
342 } 343 }
343 } 344 }
344 345
345 static void 346 static void
346 print_fmt_string (struct mh_machine *mach, size_t fmtwidth, char *str) 347 print_fmt_string (struct mh_machine *mach, size_t fmtwidth, char const *str)
347 { 348 {
348 char *p = strchr (str, '\n'); 349 char *p = strchr (str, '\n');
349 while (p) 350 while (p)
...@@ -376,7 +377,7 @@ format_num (struct mh_machine *mach, long num) ...@@ -376,7 +377,7 @@ format_num (struct mh_machine *mach, long num)
376 char buf[64]; 377 char buf[64];
377 char *ptr; 378 char *ptr;
378 int fmtwidth = mach->fmtflags & MH_WIDTH_MASK; 379 int fmtwidth = mach->fmtflags & MH_WIDTH_MASK;
379 int padchar = mach->fmtflags & MH_FMT_ZEROPAD ? '0' : ' '; 380 char padchar = mach->fmtflags & MH_FMT_ZEROPAD ? '0' : ' ';
380 381
381 n = snprintf (buf, sizeof buf, "%ld", num); 382 n = snprintf (buf, sizeof buf, "%ld", num);
382 383
...@@ -393,7 +394,7 @@ format_num (struct mh_machine *mach, long num) ...@@ -393,7 +394,7 @@ format_num (struct mh_machine *mach, long num)
393 ptr = buf; 394 ptr = buf;
394 for (i = n; i < fmtwidth && mach->ind < mach->width; 395 for (i = n; i < fmtwidth && mach->ind < mach->width;
395 i++, mach->ind++) 396 i++, mach->ind++)
396 mu_opool_append_char (mach->pool, padchar); 397 mu_stream_write (mach->output, &padchar, 1, NULL);
397 } 398 }
398 } 399 }
399 else 400 else
...@@ -404,7 +405,7 @@ format_num (struct mh_machine *mach, long num) ...@@ -404,7 +405,7 @@ format_num (struct mh_machine *mach, long num)
404 } 405 }
405 406
406 static void 407 static void
407 format_str (struct mh_machine *mach, char *str) 408 format_str (struct mh_machine *mach, char const *str)
408 { 409 {
409 if (!str) 410 if (!str)
410 str = ""; 411 str = "";
...@@ -412,7 +413,7 @@ format_str (struct mh_machine *mach, char *str) ...@@ -412,7 +413,7 @@ format_str (struct mh_machine *mach, char *str)
412 { 413 {
413 int len = strlen (str); 414 int len = strlen (str);
414 int fmtwidth = mach->fmtflags & MH_WIDTH_MASK; 415 int fmtwidth = mach->fmtflags & MH_WIDTH_MASK;
415 int padchar = ' '; 416 char padchar = ' ';
416 417
417 if (mach->fmtflags & MH_FMT_RALIGN) 418 if (mach->fmtflags & MH_FMT_RALIGN)
418 { 419 {
...@@ -421,7 +422,7 @@ format_str (struct mh_machine *mach, char *str) ...@@ -421,7 +422,7 @@ format_str (struct mh_machine *mach, char *str)
421 n = fmtwidth - len; 422 n = fmtwidth - len;
422 for (i = 0; i < n && mach->ind < mach->width; 423 for (i = 0; i < n && mach->ind < mach->width;
423 i++, mach->ind++, fmtwidth--) 424 i++, mach->ind++, fmtwidth--)
424 mu_opool_append_char (mach->pool, padchar); 425 mu_stream_write (mach->output, &padchar, 1, NULL);
425 } 426 }
426 427
427 print_fmt_string (mach, fmtwidth, str); 428 print_fmt_string (mach, fmtwidth, str);
...@@ -472,28 +473,28 @@ addrlist_destroy (mu_list_t *list) ...@@ -472,28 +473,28 @@ addrlist_destroy (mu_list_t *list)
472 } 473 }
473 474
474 /* Execute pre-compiled format on message msg with number msgno. 475 /* Execute pre-compiled format on message msg with number msgno.
475 buffer and bufsize specify output storage */ 476 */
476 int 477 int
477 mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno, 478 mh_format (mh_format_t fmt, mu_message_t msg, size_t msgno,
478 size_t width, char **pret) 479 size_t width, mu_stream_t output)
479 { 480 {
480 struct mh_machine mach; 481 struct mh_machine mach;
481 char buf[64];
482 const char *charset = mh_global_profile_get ("Charset", NULL); 482 const char *charset = mh_global_profile_get ("Charset", NULL);
483 483
484 memset (&mach, 0, sizeof (mach)); 484 memset (&mach, 0, sizeof (mach));
485 mach.progsize = fmt->progsize; 485 mach.progcnt = fmt->progcnt;
486 mach.prog = fmt->prog; 486 mach.prog = fmt->prog;
487 487
488 mach.message = msg; 488 mach.message = msg;
489 mach.msgno = msgno; 489 mach.msgno = msgno;
490 490 mach.output = output;
491
491 if (width == 0) 492 if (width == 0)
492 width = mh_width (); 493 width = mh_width ();
493 mach.width = width - 1; /* Count the newline */ 494 mach.width = width - 1; /* Count the newline */
494 mach.pc = 1; 495 mach.pc = 1;
495 mu_opool_create (&mach.pool, MU_OPOOL_ENOMEMABRT); 496
496 mu_list_create (&mach.addrlist); 497 MU_ASSERT (mu_list_create (&mach.addrlist));
497 498
498 reset_fmt_defaults (&mach); 499 reset_fmt_defaults (&mach);
499 500
...@@ -524,14 +525,12 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno, ...@@ -524,14 +525,12 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno,
524 } 525 }
525 #endif 526 #endif
526 527
527 while (!mach.stop && mach.ind < mach.width) 528 while (!mach.stop)
528 { 529 {
529 mh_opcode_t opcode; 530 mh_opcode_t opcode;
531
530 switch (opcode = MHI_OPCODE (mach.prog[mach.pc++])) 532 switch (opcode = MHI_OPCODE (mach.prog[mach.pc++]))
531 { 533 {
532 case mhop_nop:
533 break;
534
535 case mhop_stop: 534 case mhop_stop:
536 mach.stop = 1; 535 mach.stop = 1;
537 break; 536 break;
...@@ -540,128 +539,138 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno, ...@@ -540,128 +539,138 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno,
540 mach.pc += MHI_NUM (mach.prog[mach.pc]); 539 mach.pc += MHI_NUM (mach.prog[mach.pc]);
541 break; 540 break;
542 541
543 case mhop_num_asgn: 542 case mhop_brzn:
544 mach.reg_num = mach.arg_num; 543 if (!mach.num[R_REG])
544 mach.pc += MHI_NUM (mach.prog[mach.pc]);
545 else
546 mach.pc++;
545 break; 547 break;
546 548
547 case mhop_str_asgn: 549 case mhop_brzs:
548 strobj_assign (&mach.reg_str, &mach.arg_str); 550 if (mh_string_is_null (&mach.str[R_REG]))
551 mach.pc += MHI_NUM (mach.prog[mach.pc]);
552 else
553 mach.pc++;
549 break; 554 break;
550 555
551 case mhop_num_arg: 556 case mhop_setn:
552 mach.arg_num = MHI_NUM (mach.prog[mach.pc++]); 557 {
558 long reg = MHI_NUM (mach.prog[mach.pc++]);
559 mach.num[reg] = MHI_NUM (mach.prog[mach.pc++]);
560 }
553 break; 561 break;
554 562
555 case mhop_str_arg: 563 case mhop_sets:
556 { 564 {
565 long reg = MHI_NUM (mach.prog[mach.pc++]);
557 size_t skip = MHI_NUM (mach.prog[mach.pc++]); 566 size_t skip = MHI_NUM (mach.prog[mach.pc++]);
558 strobj_set (&mach.arg_str, MHI_STR (mach.prog[mach.pc])); 567 char const *str = MHI_STR (mach.prog[mach.pc]);
568
559 mach.pc += skip; 569 mach.pc += skip;
570
571 mh_string_load (&mach.str[reg], str);
560 } 572 }
561 break; 573 break;
562 574
563 case mhop_num_branch: 575 case mhop_movn:
564 if (!mach.arg_num) 576 {
565 mach.pc += MHI_NUM (mach.prog[mach.pc]); 577 long dst = MHI_NUM (mach.prog[mach.pc++]);
566 else 578 long src = MHI_NUM (mach.prog[mach.pc++]);
567 mach.pc++; 579 mach.num[dst] = mach.num[src];
568 break; 580 }
569
570 case mhop_str_branch:
571 if (!*strobj_ptr (&mach.arg_str))
572 mach.pc += MHI_NUM (mach.prog[mach.pc]);
573 else
574 mach.pc++;
575 break; 581 break;
576 582
577 case mhop_call: 583 case mhop_movs:
578 MHI_BUILTIN (mach.prog[mach.pc++]) (&mach); 584 {
585 long dst = MHI_NUM (mach.prog[mach.pc++]);
586 long src = MHI_NUM (mach.prog[mach.pc++]);
587 mh_string_move (&mach, dst, src);
588 /* FIXME: perhaps copy, not move? */
589 }
579 break; 590 break;
580 591
581 case mhop_header: 592 case mhop_ldcomp:
582 { 593 {
594 long reg = MHI_NUM (mach.prog[mach.pc++]);
595 size_t skip = MHI_NUM (mach.prog[mach.pc++]);
596 char const *comp = MHI_STR (mach.prog[mach.pc]);
583 mu_header_t hdr = NULL; 597 mu_header_t hdr = NULL;
584 char *value = NULL; 598 char *value = NULL;
599
600 mach.pc += skip;
601
585 mu_message_get_header (mach.message, &hdr); 602 mu_message_get_header (mach.message, &hdr);
586 mu_header_aget_value_unfold (hdr, strobj_ptr (&mach.arg_str), &value); 603 mu_header_aget_value_unfold (hdr, comp, &value);
587 strobj_free (&mach.arg_str); 604 mh_string_clear (&mach.str[reg]);
588 if (value) 605 if (value)
589 { 606 {
590 size_t len = strlen (value); 607 compress_ws (&mach, value);
591 mach.arg_str.size = len + 1; 608 mh_string_load (&mach.str[reg], value);
592 COMPRESS_WS (&mach, value, &len); 609 free (value);
593 mach.arg_str.ptr = value;
594 mach.arg_num = 1;
595 } 610 }
596 else
597 mach.arg_num = 0;
598 } 611 }
599 break; 612 break;
600 613
601 case mhop_body: 614 case mhop_ldbody:
602 { 615 {
616 long reg = MHI_NUM (mach.prog[mach.pc++]);
603 mu_body_t body = NULL; 617 mu_body_t body = NULL;
604 mu_stream_t stream = NULL; 618 mu_stream_t stream = NULL;
605 size_t size = 0, str_off, nread; 619 size_t size = 0;
606 size_t rest = DFLWIDTH (&mach); 620 size_t rest = output_width (&mach);
621
622 mh_string_clear (&mach.str[reg]);
607 623
608 strobj_free (&mach.arg_str);
609 mu_message_get_body (mach.message, &body); 624 mu_message_get_body (mach.message, &body);
610 mu_body_size (body, &size); 625 mu_body_size (body, &size);
611 if (size == 0) 626 if (size == 0)
612 break; 627 break;
613 mu_body_get_streamref (body, &stream); 628 mu_body_get_streamref (body, &stream);
614 if (!stream) 629 if (stream)
615 break;
616 if (size > rest)
617 size = rest;
618
619 mach.arg_str.ptr = mu_alloc (size+1);
620 mach.arg_str.size = size;
621
622 str_off = 0;
623 while (!mu_stream_read (stream, mach.arg_str.ptr + str_off,
624 mach.arg_str.size - str_off, &nread)
625 && nread != 0
626 && str_off < size)
627 { 630 {
628 COMPRESS_WS (&mach, mach.arg_str.ptr + str_off, &nread); 631 if (size > rest)
629 if (nread) 632 size = rest;
630 str_off += nread; 633
634 mh_string_realloc (&mach.str[reg], size + 1);
635 mu_stream_read (stream, mach.str[reg].ptr, size, NULL);
636 mach.str[reg].ptr[size] = 0;
637 compress_ws (&mach, mach.str[reg].ptr);
638
639 mu_stream_destroy (&stream);
631 } 640 }
632 mu_stream_destroy (&stream);
633 mach.arg_str.ptr[str_off] = 0;
634 } 641 }
635 break; 642 break;
636 643
637 /* assign reg_num to arg_num */ 644 case mhop_call:
638 case mhop_num_to_arg: 645 MHI_BUILTIN (mach.prog[mach.pc++]) (&mach);
639 mach.arg_num = mach.reg_num;
640 break;
641
642 /* assign reg_str to arg_str */
643 case mhop_str_to_arg:
644 strobj_copy (&mach.arg_str, &mach.reg_str);
645 break; 646 break;
646 647
647 /* Convert arg_str to arg_num */ 648 /* Convert string register to number */
648 case mhop_str_to_num: 649 case mhop_atoi:
649 mach.arg_num = strtoul (strobj_ptr (&mach.arg_str), NULL, 0); 650 {
651 long reg = MHI_NUM (mach.prog[mach.pc++]);
652 if (mh_string_is_null (&mach.str[reg]))
653 mach.num[reg] = 0;
654 else
655 mach.num[reg] = strtoul (mach.str[reg].ptr, NULL, 0);
656 }
650 break; 657 break;
651 658
652 /* Convert arg_num to arg_str */ 659 /* Convert numeric register to string */
653 case mhop_num_to_str: 660 case mhop_itoa:
654 snprintf (buf, sizeof buf, "%lu", mach.arg_num); 661 {
655 strobj_free (&mach.arg_str); 662 long reg = MHI_NUM (mach.prog[mach.pc++]);
656 strobj_create (&mach.arg_str, buf); 663 mu_asnprintf (&mach.str[reg].ptr, &mach.str[reg].size,
664 "%lu", mach.num[reg]);
665 }
657 break; 666 break;
658 667
659 case mhop_num_print: 668 case mhop_printn:
660 format_num (&mach, mach.reg_num); 669 format_num (&mach, mach.num[R_REG]);
661 break; 670 break;
662 671
663 case mhop_str_print: 672 case mhop_prints:
664 format_str (&mach, strobj_ptr (&mach.reg_str)); 673 format_str (&mach, mach.str[R_REG].ptr);
665 break; 674 break;
666 675
667 case mhop_fmtspec: 676 case mhop_fmtspec:
...@@ -673,19 +682,14 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno, ...@@ -673,19 +682,14 @@ mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno,
673 abort (); 682 abort ();
674 } 683 }
675 } 684 }
676 strobj_free (&mach.reg_str); 685 mh_string_free (&mach.str[R_REG]);
677 strobj_free (&mach.arg_str); 686 mh_string_free (&mach.str[R_ARG]);
678 addrlist_destroy (&mach.addrlist); 687 addrlist_destroy (&mach.addrlist);
679
680 if (pret)
681 {
682 mu_opool_append_char (mach.pool, 0);
683 *pret = mu_strdup (mu_opool_finish (mach.pool, NULL));
684 }
685 mu_opool_destroy (&mach.pool);
686 return mach.ind; 688 return mach.ind;
687 } 689 }
688 690
691 //FIXME
692 #if 0
689 int 693 int
690 mh_format_str (mh_format_t *fmt, char *str, size_t width, char **pret) 694 mh_format_str (mh_format_t *fmt, char *str, size_t width, char **pret)
691 { 695 {
...@@ -701,197 +705,7 @@ 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)
701 mu_message_destroy (&msg, NULL); 705 mu_message_destroy (&msg, NULL);
702 return rc; 706 return rc;
703 } 707 }
704 708 #endif
705
706 void
707 mh_format_dump (mh_format_t *fmt)
708 {
709 mh_instr_t *prog = fmt->prog;
710 size_t pc = 1;
711 int stop = 0;
712
713 while (!stop)
714 {
715 mh_opcode_t opcode;
716 int num;
717
718 printf ("% 4.4ld: ", (long) pc);
719 switch (opcode = MHI_OPCODE (prog[pc++]))
720 {
721 case mhop_nop:
722 printf ("nop");
723 break;
724
725 case mhop_stop:
726 printf ("stop");
727 stop = 1;
728 break;
729
730 case mhop_branch:
731 num = MHI_NUM (prog[pc++]);
732 printf ("branch %d, %lu",
733 num, (unsigned long) pc + num - 1);
734 break;
735
736 case mhop_num_asgn:
737 printf ("num_asgn");
738 break;
739
740 case mhop_str_asgn:
741 printf ("str_asgn");
742 break;
743
744 case mhop_num_arg:
745 num = MHI_NUM (prog[pc++]);
746 printf ("num_arg %d", num);
747 break;
748
749 case mhop_str_arg:
750 {
751 size_t skip = MHI_NUM (prog[pc++]);
752 char *s = MHI_STR (prog[pc]);
753 printf ("str_arg \"");
754 for (; *s; s++)
755 {
756 switch (*s)
757 {
758 case '\a':
759 printf ("\\a");
760 break;
761
762 case '\b':
763 printf ("\\b");
764 break;
765
766 case '\f':
767 printf ("\\f");
768 break;
769
770 case '\n':
771 printf ("\\n");
772 break;
773
774 case '\r':
775 printf ("\\r");
776 break;
777
778 case '\t':
779 printf ("\\t");
780 break;
781
782 case '"':
783 printf ("\\\"");
784 break;
785
786 default:
787 if (isprint (*s))
788 putchar (*s);
789 else
790 printf ("\\%03o", *s);
791 break;
792 }
793 }
794 printf ("\"");
795 pc += skip;
796 }
797 break;
798
799 case mhop_num_branch:
800 num = MHI_NUM (prog[pc++]);
801 printf ("num_branch %d, %lu",
802 num, (unsigned long) (pc + num - 1));
803 break;
804
805 case mhop_str_branch:
806 num = MHI_NUM (prog[pc++]);
807 printf ("str_branch %d, %lu",
808 num, (unsigned long) (pc + num - 1));
809 break;
810
811 case mhop_call:
812 {
813 char *name = _get_builtin_name (MHI_BUILTIN (prog[pc++]));
814 printf ("call %s", name ? name : "UNKNOWN");
815 }
816 break;
817
818 case mhop_header:
819 printf ("header");
820 break;
821
822 case mhop_body:
823 printf ("body");
824 break;
825
826 case mhop_num_to_arg:
827 printf ("num_to_arg");
828 break;
829
830 /* assign reg_str to arg_str */
831 case mhop_str_to_arg:
832 printf ("str_to_arg");
833 break;
834
835 /* Convert arg_str to arg_num */
836 case mhop_str_to_num:
837 printf ("str_to_num");
838 break;
839
840 /* Convert arg_num to arg_str */
841 case mhop_num_to_str:
842 printf ("num_to_str");
843 break;
844
845 case mhop_num_print:
846 printf ("print");
847 break;
848
849 case mhop_str_print:
850 printf ("str_print");
851 break;
852
853 case mhop_fmtspec:
854 {
855 int space = 0;
856
857 num = MHI_NUM (prog[pc++]);
858 printf ("fmtspec: %#x, ", num);
859 if (num & MH_FMT_RALIGN)
860 {
861 printf ("MH_FMT_RALIGN");
862 space++;
863 }
864 if (num & MH_FMT_ZEROPAD)
865 {
866 if (space)
867 printf ("|");
868 printf ("MH_FMT_ZEROPAD");
869 space++;
870 }
871 if (space)
872 printf ("; ");
873 printf ("%d", num & MH_WIDTH_MASK);
874 }
875 break;
876
877 default:
878 mu_error ("Unknown opcode: %x", opcode);
879 abort ();
880 }
881 printf ("\n");
882 }
883 }
884
885 /* Free any memory associated with a format structure. The structure
886 itself is assumed to be in static storage. */
887 void
888 mh_format_free (mh_format_t *fmt)
889 {
890 if (fmt->prog)
891 free (fmt->prog);
892 fmt->progsize = 0;
893 fmt->prog = NULL;
894 }
895 709
896 /* Built-in functions */ 710 /* Built-in functions */
897 711
...@@ -907,7 +721,7 @@ builtin_msg (struct mh_machine *mach) ...@@ -907,7 +721,7 @@ builtin_msg (struct mh_machine *mach)
907 { 721 {
908 size_t msgno = mach->msgno; 722 size_t msgno = mach->msgno;
909 mh_message_number (mach->message, &msgno); 723 mh_message_number (mach->message, &msgno);
910 mach->arg_num = msgno; 724 mach->num[R_REG] = msgno;
911 } 725 }
912 726
913 static void 727 static void
...@@ -926,7 +740,7 @@ builtin_cur (struct mh_machine *mach) ...@@ -926,7 +740,7 @@ builtin_cur (struct mh_machine *mach)
926 } 740 }
927 mh_message_number (mach->message, &msgno); 741 mh_message_number (mach->message, &msgno);
928 mh_mailbox_get_cur (mbox, &cur); /* FIXME: Cache this */ 742 mh_mailbox_get_cur (mbox, &cur); /* FIXME: Cache this */
929 mach->arg_num = msgno == cur; 743 mach->num[R_REG] = msgno == cur;
930 } 744 }
931 745
932 static void 746 static void
...@@ -934,25 +748,27 @@ builtin_size (struct mh_machine *mach) ...@@ -934,25 +748,27 @@ builtin_size (struct mh_machine *mach)
934 { 748 {
935 size_t size; 749 size_t size;
936 if (mu_message_size (mach->message, &size) == 0) 750 if (mu_message_size (mach->message, &size) == 0)
937 mach->arg_num = size; 751 mach->num[R_REG] = size;
752 else
753 mach->num[R_REG] = 0;
938 } 754 }
939 755
940 static void 756 static void
941 builtin_strlen (struct mh_machine *mach) 757 builtin_strlen (struct mh_machine *mach)
942 { 758 {
943 mach->arg_num = strlen (strobj_ptr (&mach->arg_str)); 759 mach->num[R_REG] = mh_string_length (&mach->str[R_ARG]);
944 } 760 }
945 761
946 static void 762 static void
947 builtin_width (struct mh_machine *mach) 763 builtin_width (struct mh_machine *mach)
948 { 764 {
949 mach->arg_num = mach->width; 765 mach->num[R_REG] = mach->width;
950 } 766 }
951 767
952 static void 768 static void
953 builtin_charleft (struct mh_machine *mach) 769 builtin_charleft (struct mh_machine *mach)
954 { 770 {
955 mach->arg_num = DFLWIDTH (mach); 771 mach->num[R_REG] = output_width (mach);
956 } 772 }
957 773
958 static void 774 static void
...@@ -961,186 +777,175 @@ builtin_timenow (struct mh_machine *mach) ...@@ -961,186 +777,175 @@ builtin_timenow (struct mh_machine *mach)
961 time_t t; 777 time_t t;
962 778
963 time (&t); 779 time (&t);
964 mach->arg_num = t; 780 mach->num[R_REG] = t;
965 } 781 }
966 782
967 static void 783 static void
968 builtin_me (struct mh_machine *mach) 784 builtin_me (struct mh_machine *mach)
969 { 785 {
970 char *s = mh_my_email (); 786 char *s;
971 strobj_realloc (&mach->arg_str, strlen (s) + 3); 787 mu_asprintf (&s, "<%s>", mh_my_email ());
972 sprintf (strobj_ptr (&mach->arg_str), "<%s>", s); 788 mh_string_load (&mach->str[R_REG], s);
789 free (s);
973 } 790 }
974 791
975 static void 792 static void
976 builtin_eq (struct mh_machine *mach) 793 builtin_eq (struct mh_machine *mach)
977 { 794 {
978 mach->arg_num = mach->reg_num == mach->arg_num; 795 mach->num[R_REG] = mach->num[R_REG] == mach->num[R_ARG];
979 } 796 }
980 797
981 static void 798 static void
982 builtin_ne (struct mh_machine *mach) 799 builtin_ne (struct mh_machine *mach)
983 { 800 {
984 mach->arg_num = mach->reg_num != mach->arg_num; 801 mach->num[R_REG] = mach->num[R_REG] != mach->num[R_ARG];
985 } 802 }
986 803
987 static void 804 static void
988 builtin_gt (struct mh_machine *mach) 805 builtin_gt (struct mh_machine *mach)
989 { 806 {
990 mach->arg_num = mach->reg_num > mach->arg_num; 807 mach->num[R_REG] = mach->num[R_REG] > mach->num[R_ARG];
991 } 808 }
992 809
993 static void 810 static void
994 builtin_match (struct mh_machine *mach) 811 builtin_match (struct mh_machine *mach)
995 { 812 {
996 mach->arg_num = strstr (strobj_ptr (&mach->reg_str), 813 mach->num[R_REG] = strstr (mh_string_value (&mach->str[R_REG]),
997 strobj_ptr (&mach->arg_str)) != NULL; 814 mh_string_value (&mach->str[R_ARG])) != NULL;
998 } 815 }
999 816
1000 static void 817 static void
1001 builtin_amatch (struct mh_machine *mach) 818 builtin_amatch (struct mh_machine *mach)
1002 { 819 {
1003 int len = strobj_len (&mach->arg_str); 820 char const *arg = mh_string_value (&mach->str[R_ARG]);
1004 mach->arg_num = strncmp (strobj_ptr (&mach->reg_str), 821 size_t len = strlen (arg);
1005 strobj_ptr (&mach->arg_str), len); 822 mach->num[R_REG] = strncmp (mh_string_value (&mach->str[R_REG]), arg, len);
1006 } 823 }
1007 824
1008 static void 825 static void
1009 builtin_plus (struct mh_machine *mach) 826 builtin_plus (struct mh_machine *mach)
1010 { 827 {
1011 mach->arg_num += mach->reg_num; 828 mach->num[R_REG] += mach->num[R_ARG];
1012 } 829 }
1013 830
1014 static void 831 static void
1015 builtin_minus (struct mh_machine *mach) 832 builtin_minus (struct mh_machine *mach)
1016 { 833 {
1017 mach->arg_num -= mach->reg_num; 834 mach->num[R_REG] -= mach->num[R_ARG];
1018 } 835 }
1019 836
1020 static void 837 static void
1021 builtin_divide (struct mh_machine *mach) 838 builtin_divide (struct mh_machine *mach)
1022 { 839 {
1023 if (!mach->arg_num) 840 if (mach->num[R_ARG] == 0)
1024 { 841 {
1025 /* TRANSLATORS: Do not translate the word 'format'! */ 842 /* TRANSLATORS: Do not translate the word 'format'! */
1026 mu_error (_("format: divide by zero")); 843 mu_error (_("format: divide by zero"));
1027 mach->stop = 1; 844 mach->stop = 1;
1028 } 845 }
1029 else 846 else
1030 mach->arg_num = mach->reg_num / mach->arg_num; 847 mach->num[R_REG] /= mach->num[R_ARG];
1031 } 848 }
1032 849
1033 static void 850 static void
1034 builtin_modulo (struct mh_machine *mach) 851 builtin_modulo (struct mh_machine *mach)
1035 { 852 {
1036 if (!mach->arg_num) 853 if (mach->num[R_ARG] == 0)
1037 { 854 {
1038 mu_error (_("format: divide by zero")); 855 mu_error (_("format: divide by zero"));
1039 mach->stop = 1; 856 mach->stop = 1;
1040 } 857 }
1041 else 858 else
1042 mach->arg_num = mach->reg_num % mach->arg_num; 859 mach->num[R_REG] %= mach->num[R_ARG];
1043 } 860 }
1044 861
1045 static void 862 static void
1046 builtin_num (struct mh_machine *mach) 863 builtin_num (struct mh_machine *mach)
1047 { 864 {
1048 mach->reg_num = mach->arg_num; 865 mach->num[R_REG] = mach->num[R_ARG];
1049 } 866 }
1050 867
1051 static void 868 static void
1052 builtin_lit (struct mh_machine *mach) 869 builtin_lit (struct mh_machine *mach)
1053 { 870 {
1054 /* do nothing */ 871 /* FIXME: do nothing */
1055 } 872 }
1056 873
1057 static void 874 static void
1058 builtin_getenv (struct mh_machine *mach) 875 builtin_getenv (struct mh_machine *mach)
1059 { 876 {
1060 char *val = getenv (strobj_ptr (&mach->arg_str)); 877 char const *val = getenv (mh_string_value (&mach->str[R_ARG]));
1061 strobj_free (&mach->arg_str); 878 mh_string_load (&mach->str[R_REG], val);
1062 strobj_create (&mach->arg_str, val);
1063 } 879 }
1064 880
1065 static void 881 static void
1066 builtin_profile (struct mh_machine *mach) 882 builtin_profile (struct mh_machine *mach)
1067 { 883 {
1068 char *val = strobj_ptr (&mach->arg_str); 884 char const *val = mh_global_profile_get (mh_string_value (&mach->str[R_ARG]),
1069 strobj_free (&mach->arg_str); 885 "");
1070 strobj_create (&mach->arg_str, mh_global_profile_get (val, "")); 886 mh_string_load (&mach->str[R_REG], val);
1071 } 887 }
1072 888
1073 static void 889 static void
1074 builtin_nonzero (struct mh_machine *mach) 890 builtin_nonzero (struct mh_machine *mach)
1075 { 891 {
1076 mach->arg_num = mach->reg_num; 892 mach->num[R_REG] = mach->num[R_ARG] != 0;
1077 } 893 }
1078 894
1079 static void 895 static void
1080 builtin_zero (struct mh_machine *mach) 896 builtin_zero (struct mh_machine *mach)
1081 { 897 {
1082 mach->arg_num = !mach->reg_num; 898 mach->num[R_REG] = mach->num[R_ARG] == 0;
1083 } 899 }
1084 900
1085 static void 901 static void
1086 builtin_null (struct mh_machine *mach) 902 builtin_null (struct mh_machine *mach)
1087 { 903 {
1088 char *s = strobj_ptr (&mach->reg_str); 904 mach->num[R_REG] = mh_string_is_null (&mach->str[R_ARG]);
1089 mach->arg_num = !s && !s[0];
1090 } 905 }
1091 906
1092 static void 907 static void
1093 builtin_nonnull (struct mh_machine *mach) 908 builtin_nonnull (struct mh_machine *mach)
1094 { 909 {
1095 char *s = strobj_ptr (&mach->reg_str); 910 mach->num[R_REG] = !mh_string_is_null (&mach->str[R_ARG]);
1096 mach->arg_num = s && s[0];
1097 } 911 }
1098 912
1099 /* comp comp string Set str to component text*/ 913 /* comp comp string Set str to component text*/
1100 static void 914 static void
1101 builtin_comp (struct mh_machine *mach) 915 builtin_comp (struct mh_machine *mach)
1102 { 916 {
1103 strobj_assign (&mach->reg_str, &mach->arg_str); 917 /* FIXME: Check this */
918 mh_string_move (mach, R_REG, R_ARG);
1104 } 919 }
1105 920
1106 /* compval comp integer num set to "atoi(comp)"*/ 921 /* compval comp integer num set to "atoi(comp)"*/
1107 static void 922 static void
1108 builtin_compval (struct mh_machine *mach) 923 builtin_compval (struct mh_machine *mach)
1109 { 924 {
1110 mach->reg_num = strtoul (strobj_ptr (&mach->arg_str), NULL, 0); 925 /* FIXME: Check this */
926 mach->num[R_REG] = strtol (mh_string_value (&mach->str[R_ARG]), NULL, 0);
1111 } 927 }
1112 928
1113 /* trim expr trim trailing white-space from str*/ 929 /* trim expr trim trailing white-space from str*/
1114 static void 930 static void
1115 builtin_trim (struct mh_machine *mach) 931 builtin_trim (struct mh_machine *mach)
1116 { 932 {
1117 char *p, *start; 933 if (!mh_string_is_null (&mach->str[R_REG]))
1118 int len; 934 mu_rtrim_class (mach->str[R_REG].ptr, MU_CTYPE_SPACE);
1119
1120 if (strobj_is_static (&mach->arg_str))
1121 strobj_copy (&mach->arg_str, &mach->arg_str);
1122
1123 start = strobj_ptr (&mach->arg_str);
1124 len = strlen (start);
1125 if (len == 0)
1126 return;
1127 for (p = start + len - 1; p >= start && isspace (*p); p--)
1128 ;
1129 p[1] = 0;
1130 } 935 }
1131 936
1132 /* putstr expr print str*/ 937 /* putstr expr print str*/
1133 static void 938 static void
1134 builtin_putstr (struct mh_machine *mach) 939 builtin_putstr (struct mh_machine *mach)
1135 { 940 {
1136 print_string (mach, 0, strobj_ptr (&mach->arg_str)); 941 print_string (mach, 0, mh_string_value (&mach->str[R_ARG]));
1137 } 942 }
1138 943
1139 /* putstrf expr print str in a fixed width*/ 944 /* putstrf expr print str in a fixed width*/
1140 static void 945 static void
1141 builtin_putstrf (struct mh_machine *mach) 946 builtin_putstrf (struct mh_machine *mach)
1142 { 947 {
1143 format_str (mach, strobj_ptr (&mach->arg_str)); 948 format_str (mach, mh_string_value (&mach->str[R_ARG]));
1144 } 949 }
1145 950
1146 /* putnum expr print num*/ 951 /* putnum expr print num*/
...@@ -1148,7 +953,7 @@ static void ...@@ -1148,7 +953,7 @@ static void
1148 builtin_putnum (struct mh_machine *mach) 953 builtin_putnum (struct mh_machine *mach)
1149 { 954 {
1150 char *p; 955 char *p;
1151 mu_asprintf (&p, "%ld", mach->arg_num); 956 mu_asprintf (&p, "%ld", mach->num[R_ARG]);
1152 print_string (mach, 0, p); 957 print_string (mach, 0, p);
1153 free (p); 958 free (p);
1154 } 959 }
...@@ -1157,16 +962,16 @@ builtin_putnum (struct mh_machine *mach) ...@@ -1157,16 +962,16 @@ builtin_putnum (struct mh_machine *mach)
1157 static void 962 static void
1158 builtin_putnumf (struct mh_machine *mach) 963 builtin_putnumf (struct mh_machine *mach)
1159 { 964 {
1160 format_num (mach, mach->arg_num); 965 format_num (mach, mach->num[R_ARG]);
1161 } 966 }
1162 967
1163 static int 968 static int
1164 _parse_date (struct mh_machine *mach, struct tm *tm, struct mu_timezone *tz) 969 _parse_date (struct mh_machine *mach, struct tm *tm, struct mu_timezone *tz)
1165 { 970 {
1166 char *date = strobj_ptr (&mach->arg_str); 971 char const *date = mh_string_value (&mach->str[R_ARG]);
1167 const char *p = date; 972 const char *p = date;
1168 973
1169 if (mu_parse822_date_time (&p, date+strlen(date), tm, tz)) 974 if (mu_parse822_date_time (&p, date + strlen(date), tm, tz))
1170 { 975 {
1171 time_t t; 976 time_t t;
1172 977
...@@ -1189,7 +994,7 @@ builtin_sec (struct mh_machine *mach) ...@@ -1189,7 +994,7 @@ builtin_sec (struct mh_machine *mach)
1189 if (_parse_date (mach, &tm, &tz)) 994 if (_parse_date (mach, &tm, &tz))
1190 return; 995 return;
1191 996
1192 mach->arg_num = tm.tm_sec; 997 mach->num[R_REG] = tm.tm_sec;
1193 } 998 }
1194 999
1195 /* min date integer minutes of the hour*/ 1000 /* min date integer minutes of the hour*/
...@@ -1202,7 +1007,7 @@ builtin_min (struct mh_machine *mach) ...@@ -1202,7 +1007,7 @@ builtin_min (struct mh_machine *mach)
1202 if (_parse_date (mach, &tm, &tz)) 1007 if (_parse_date (mach, &tm, &tz))
1203 return; 1008 return;
1204 1009
1205 mach->arg_num = tm.tm_min; 1010 mach->num[R_REG] = tm.tm_min;
1206 } 1011 }
1207 1012
1208 /* hour date integer hours of the day (0-23)*/ 1013 /* hour date integer hours of the day (0-23)*/
...@@ -1215,7 +1020,7 @@ builtin_hour (struct mh_machine *mach) ...@@ -1215,7 +1020,7 @@ builtin_hour (struct mh_machine *mach)
1215 if (_parse_date (mach, &tm, &tz)) 1020 if (_parse_date (mach, &tm, &tz))
1216 return; 1021 return;
1217 1022
1218 mach->arg_num = tm.tm_hour; 1023 mach->num[R_REG] = tm.tm_hour;
1219 } 1024 }
1220 1025
1221 /* wday date integer day of the week (Sun=0)*/ 1026 /* wday date integer day of the week (Sun=0)*/
...@@ -1228,7 +1033,7 @@ builtin_wday (struct mh_machine *mach) ...@@ -1228,7 +1033,7 @@ builtin_wday (struct mh_machine *mach)
1228 if (_parse_date (mach, &tm, &tz)) 1033 if (_parse_date (mach, &tm, &tz))
1229 return; 1034 return;
1230 1035
1231 mach->arg_num = tm.tm_wday; 1036 mach->num[R_REG] = tm.tm_wday;
1232 } 1037 }
1233 1038
1234 /* day date string day of the week (abbrev.)*/ 1039 /* day date string day of the week (abbrev.)*/
...@@ -1243,8 +1048,7 @@ builtin_day (struct mh_machine *mach) ...@@ -1243,8 +1048,7 @@ builtin_day (struct mh_machine *mach)
1243 return; 1048 return;
1244 1049
1245 strftime (buf, sizeof buf, "%a", &tm); 1050 strftime (buf, sizeof buf, "%a", &tm);
1246 strobj_free (&mach->arg_str); 1051 mh_string_load (&mach->str[R_REG], buf);
1247 strobj_create (&mach->arg_str, buf);
1248 } 1052 }
1249 1053
1250 /* weekday date string day of the week */ 1054 /* weekday date string day of the week */
...@@ -1257,10 +1061,8 @@ builtin_weekday (struct mh_machine *mach) ...@@ -1257,10 +1061,8 @@ builtin_weekday (struct mh_machine *mach)
1257 1061
1258 if (_parse_date (mach, &tm, &tz)) 1062 if (_parse_date (mach, &tm, &tz))
1259 return; 1063 return;
1260
1261 strftime (buf, sizeof buf, "%A", &tm); 1064 strftime (buf, sizeof buf, "%A", &tm);
1262 strobj_free (&mach->arg_str); 1065 mh_string_load (&mach->str[R_REG], buf);
1263 strobj_create (&mach->arg_str, buf);
1264 } 1066 }
1265 1067
1266 /* sday date integer day of the week known? 1068 /* sday date integer day of the week known?
...@@ -1273,9 +1075,9 @@ builtin_sday (struct mh_machine *mach) ...@@ -1273,9 +1075,9 @@ builtin_sday (struct mh_machine *mach)
1273 1075
1274 /*FIXME: more elaborate check needed */ 1076 /*FIXME: more elaborate check needed */
1275 if (_parse_date (mach, &tm, &tz)) 1077 if (_parse_date (mach, &tm, &tz))
1276 mach->arg_num = -1; 1078 mach->num[R_REG] = -1;
1277 else 1079 else
1278 mach->arg_num = 1; 1080 mach->num[R_REG] = 1;
1279 } 1081 }
1280 1082
1281 /* mday date integer day of the month*/ 1083 /* mday date integer day of the month*/
...@@ -1288,7 +1090,7 @@ builtin_mday (struct mh_machine *mach) ...@@ -1288,7 +1090,7 @@ builtin_mday (struct mh_machine *mach)
1288 if (_parse_date (mach, &tm, &tz)) 1090 if (_parse_date (mach, &tm, &tz))
1289 return; 1091 return;
1290 1092
1291 mach->arg_num = tm.tm_mday; 1093 mach->num[R_REG] = tm.tm_mday;
1292 } 1094 }
1293 1095
1294 /* yday date integer day of the year */ 1096 /* yday date integer day of the year */
...@@ -1301,7 +1103,7 @@ builtin_yday (struct mh_machine *mach) ...@@ -1301,7 +1103,7 @@ builtin_yday (struct mh_machine *mach)
1301 if (_parse_date (mach, &tm, &tz)) 1103 if (_parse_date (mach, &tm, &tz))
1302 return; 1104 return;
1303 1105
1304 mach->arg_num = tm.tm_yday; 1106 mach->num[R_REG] = tm.tm_yday;
1305 } 1107 }
1306 1108
1307 /* mon date integer month of the year*/ 1109 /* mon date integer month of the year*/
...@@ -1314,7 +1116,7 @@ builtin_mon (struct mh_machine *mach) ...@@ -1314,7 +1116,7 @@ builtin_mon (struct mh_machine *mach)
1314 if (_parse_date (mach, &tm, &tz)) 1116 if (_parse_date (mach, &tm, &tz))
1315 return; 1117 return;
1316 1118
1317 mach->arg_num = tm.tm_mon+1; 1119 mach->num[R_REG] = tm.tm_mon + 1;
1318 } 1120 }
1319 1121
1320 /* month date string month of the year (abbrev.) */ 1122 /* month date string month of the year (abbrev.) */
...@@ -1329,8 +1131,7 @@ builtin_month (struct mh_machine *mach) ...@@ -1329,8 +1131,7 @@ builtin_month (struct mh_machine *mach)
1329 return; 1131 return;
1330 1132
1331 strftime (buf, sizeof buf, "%b", &tm); 1133 strftime (buf, sizeof buf, "%b", &tm);
1332 strobj_free (&mach->arg_str); 1134 mh_string_load (&mach->str[R_REG], buf);
1333 strobj_create (&mach->arg_str, buf);
1334 } 1135 }
1335 1136
1336 /* lmonth date string month of the year*/ 1137 /* lmonth date string month of the year*/
...@@ -1345,8 +1146,7 @@ builtin_lmonth (struct mh_machine *mach) ...@@ -1345,8 +1146,7 @@ builtin_lmonth (struct mh_machine *mach)
1345 return; 1146 return;
1346 1147
1347 strftime (buf, sizeof buf, "%B", &tm); 1148 strftime (buf, sizeof buf, "%B", &tm);
1348 strobj_free (&mach->arg_str); 1149 mh_string_load (&mach->str[R_REG], buf);
1349 strobj_create (&mach->arg_str, buf);
1350 } 1150 }
1351 1151
1352 /* year date integer year (may be > 100)*/ 1152 /* year date integer year (may be > 100)*/
...@@ -1359,7 +1159,7 @@ builtin_year (struct mh_machine *mach) ...@@ -1359,7 +1159,7 @@ builtin_year (struct mh_machine *mach)
1359 if (_parse_date (mach, &tm, &tz)) 1159 if (_parse_date (mach, &tm, &tz))
1360 return; 1160 return;
1361 1161
1362 mach->arg_num = tm.tm_year + 1900; 1162 mach->num[R_REG] = tm.tm_year + 1900;
1363 } 1163 }
1364 1164
1365 /* zone date integer timezone in hours*/ 1165 /* zone date integer timezone in hours*/
...@@ -1372,7 +1172,7 @@ builtin_zone (struct mh_machine *mach) ...@@ -1372,7 +1172,7 @@ builtin_zone (struct mh_machine *mach)
1372 if (_parse_date (mach, &tm, &tz)) 1172 if (_parse_date (mach, &tm, &tz))
1373 return; 1173 return;
1374 1174
1375 mach->arg_num = tz.utc_offset; 1175 mach->num[R_REG] = tz.utc_offset;
1376 } 1176 }
1377 1177
1378 /* tzone date string timezone string */ 1178 /* tzone date string timezone string */
...@@ -1385,9 +1185,8 @@ builtin_tzone (struct mh_machine *mach) ...@@ -1385,9 +1185,8 @@ builtin_tzone (struct mh_machine *mach)
1385 if (_parse_date (mach, &tm, &tz)) 1185 if (_parse_date (mach, &tm, &tz))
1386 return; 1186 return;
1387 1187
1388 strobj_free (&mach->arg_str);
1389 if (tz.tz_name) 1188 if (tz.tz_name)
1390 strobj_create (&mach->arg_str, (char*) tz.tz_name); 1189 mh_string_load (&mach->str[R_REG], tz.tz_name);
1391 else 1190 else
1392 { 1191 {
1393 char buf[6]; 1192 char buf[6];
...@@ -1401,7 +1200,7 @@ builtin_tzone (struct mh_machine *mach) ...@@ -1401,7 +1200,7 @@ builtin_tzone (struct mh_machine *mach)
1401 s = '+'; 1200 s = '+';
1402 snprintf (buf, sizeof buf, "%c%02d%02d", s, 1201 snprintf (buf, sizeof buf, "%c%02d%02d", s,
1403 tz.utc_offset/3600, tz.utc_offset/60); 1202 tz.utc_offset/3600, tz.utc_offset/60);
1404 strobj_create (&mach->arg_str, buf); 1203 mh_string_load (&mach->str[R_REG], buf);
1405 } 1204 }
1406 } 1205 }
1407 1206
...@@ -1415,9 +1214,15 @@ builtin_szone (struct mh_machine *mach) ...@@ -1415,9 +1214,15 @@ builtin_szone (struct mh_machine *mach)
1415 1214
1416 /*FIXME: more elaborate check needed */ 1215 /*FIXME: more elaborate check needed */
1417 if (_parse_date (mach, &tm, &tz)) 1216 if (_parse_date (mach, &tm, &tz))
1418 mach->arg_num = -1; 1217 mach->num[R_REG] = -1;
1419 else 1218 else
1420 mach->arg_num = 1; 1219 mach->num[R_REG] = 1;
1220 }
1221
1222 static void
1223 builtin_str_noop (struct mh_machine *mach)
1224 {
1225 mh_string_move (mach, R_REG, R_ARG);
1421 } 1226 }
1422 1227
1423 /* date2local date coerce date to local timezone*/ 1228 /* date2local date coerce date to local timezone*/
...@@ -1425,6 +1230,7 @@ static void ...@@ -1425,6 +1230,7 @@ static void
1425 builtin_date2local (struct mh_machine *mach) 1230 builtin_date2local (struct mh_machine *mach)
1426 { 1231 {
1427 /*FIXME: Noop*/ 1232 /*FIXME: Noop*/
1233 builtin_str_noop (mach);
1428 } 1234 }
1429 1235
1430 /* date2gmt date coerce date to GMT*/ 1236 /* date2gmt date coerce date to GMT*/
...@@ -1432,6 +1238,7 @@ static void ...@@ -1432,6 +1238,7 @@ static void
1432 builtin_date2gmt (struct mh_machine *mach) 1238 builtin_date2gmt (struct mh_machine *mach)
1433 { 1239 {
1434 /*FIXME: Noop*/ 1240 /*FIXME: Noop*/
1241 builtin_str_noop (mach);
1435 } 1242 }
1436 1243
1437 /* dst date integer daylight savings in effect?*/ 1244 /* dst date integer daylight savings in effect?*/
...@@ -1444,9 +1251,9 @@ builtin_dst (struct mh_machine *mach) ...@@ -1444,9 +1251,9 @@ builtin_dst (struct mh_machine *mach)
1444 if (_parse_date (mach, &tm, &tz)) 1251 if (_parse_date (mach, &tm, &tz))
1445 return; 1252 return;
1446 #ifdef HAVE_STRUCT_TM_TM_ISDST 1253 #ifdef HAVE_STRUCT_TM_TM_ISDST
1447 mach->arg_num = tm.tm_isdst; 1254 mach->num[R_REG] = tm.tm_isdst;
1448 #else 1255 #else
1449 mach->arg_num = 0; 1256 mach->num[R_REG] = 0;
1450 #endif 1257 #endif
1451 } 1258 }
1452 1259
...@@ -1459,7 +1266,7 @@ builtin_clock (struct mh_machine *mach) ...@@ -1459,7 +1266,7 @@ builtin_clock (struct mh_machine *mach)
1459 1266
1460 if (_parse_date (mach, &tm, &tz)) 1267 if (_parse_date (mach, &tm, &tz))
1461 return; 1268 return;
1462 mach->arg_num = mu_datetime_to_utc (&tm, &tz); 1269 mach->num[R_REG] = mu_datetime_to_utc (&tm, &tz);
1463 } 1270 }
1464 1271
1465 /* rclock date integer seconds prior to current time*/ 1272 /* rclock date integer seconds prior to current time*/
...@@ -1472,7 +1279,7 @@ builtin_rclock (struct mh_machine *mach) ...@@ -1472,7 +1279,7 @@ builtin_rclock (struct mh_machine *mach)
1472 1279
1473 if (_parse_date (mach, &tm, &tz)) 1280 if (_parse_date (mach, &tm, &tz))
1474 return; 1281 return;
1475 mach->arg_num = now - mu_datetime_to_utc (&tm, &tz); 1282 mach->num[R_REG] = now - mu_datetime_to_utc (&tm, &tz);
1476 } 1283 }
1477 1284
1478 struct 1285 struct
...@@ -1546,7 +1353,7 @@ date_cvt (struct mh_machine *mach, int pretty) ...@@ -1546,7 +1353,7 @@ date_cvt (struct mh_machine *mach, int pretty)
1546 min %= 60; 1353 min %= 60;
1547 snprintf (buf + len, sizeof(buf) - len, "%c%02d%02d", sign, hrs, min); 1354 snprintf (buf + len, sizeof(buf) - len, "%c%02d%02d", sign, hrs, min);
1548 } 1355 }
1549 strobj_create (&mach->arg_str, buf); 1356 mh_string_load (&mach->str[R_REG], buf);
1550 } 1357 }
1551 1358
1552 /* tws date string official 822 rendering */ 1359 /* tws date string official 822 rendering */
...@@ -1570,7 +1377,7 @@ builtin_nodate (struct mh_machine *mach) ...@@ -1570,7 +1377,7 @@ builtin_nodate (struct mh_machine *mach)
1570 struct tm tm; 1377 struct tm tm;
1571 struct mu_timezone tz; 1378 struct mu_timezone tz;
1572 1379
1573 mach->arg_num = _parse_date (mach, &tm, &tz); 1380 mach->num[R_REG] = _parse_date (mach, &tm, &tz);
1574 } 1381 }
1575 1382
1576 /* proper addr string official 822 rendering */ 1383 /* proper addr string official 822 rendering */
...@@ -1578,6 +1385,7 @@ static void ...@@ -1578,6 +1385,7 @@ static void
1578 builtin_proper (struct mh_machine *mach) 1385 builtin_proper (struct mh_machine *mach)
1579 { 1386 {
1580 /*FIXME: noop*/ 1387 /*FIXME: noop*/
1388 builtin_str_noop (mach);
1581 } 1389 }
1582 1390
1583 /* friendly addr string user-friendly rendering*/ 1391 /* friendly addr string user-friendly rendering*/
...@@ -1588,14 +1396,13 @@ builtin_friendly (struct mh_machine *mach) ...@@ -1588,14 +1396,13 @@ builtin_friendly (struct mh_machine *mach)
1588 const char *str; 1396 const char *str;
1589 int rc; 1397 int rc;
1590 1398
1591 rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str)); 1399 rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
1592 if (rc) 1400 if (rc)
1593 return; 1401 return;
1594 1402
1595 if (mu_address_sget_personal (addr, 1, &str) == 0 && str) 1403 if (mu_address_sget_personal (addr, 1, &str) == 0 && str)
1596 { 1404 {
1597 strobj_free (&mach->arg_str); 1405 mh_string_load (&mach->str[R_ARG], str);
1598 strobj_create (&mach->arg_str, str);
1599 } 1406 }
1600 mu_address_destroy (&addr); 1407 mu_address_destroy (&addr);
1601 } 1408 }
...@@ -1608,13 +1415,13 @@ builtin_addr (struct mh_machine *mach) ...@@ -1608,13 +1415,13 @@ builtin_addr (struct mh_machine *mach)
1608 const char *str; 1415 const char *str;
1609 int rc; 1416 int rc;
1610 1417
1611 rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str)); 1418 rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
1612 strobj_free (&mach->arg_str); 1419 mh_string_clear (&mach->str[R_REG]);
1613 if (rc) 1420 if (rc)
1614 return; 1421 return;
1615 1422
1616 if (mu_address_sget_email (addr, 1, &str) == 0) 1423 if (mu_address_sget_email (addr, 1, &str) == 0)
1617 strobj_create (&mach->arg_str, str); 1424 mh_string_load (&mach->str[R_REG], str);
1618 mu_address_destroy (&addr); 1425 mu_address_destroy (&addr);
1619 } 1426 }
1620 1427
...@@ -1626,13 +1433,13 @@ builtin_pers (struct mh_machine *mach) ...@@ -1626,13 +1433,13 @@ builtin_pers (struct mh_machine *mach)
1626 const char *str; 1433 const char *str;
1627 int rc; 1434 int rc;
1628 1435
1629 rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str)); 1436 rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
1630 strobj_free (&mach->arg_str); 1437 mh_string_clear (&mach->str[R_REG]);
1631 if (rc) 1438 if (rc)
1632 return; 1439 return;
1633 1440
1634 if (mu_address_sget_personal (addr, 1, &str) == 0 && str) 1441 if (mu_address_sget_personal (addr, 1, &str) == 0)
1635 strobj_create (&mach->arg_str, str); 1442 mh_string_load (&mach->str[R_REG], str);
1636 mu_address_destroy (&addr); 1443 mu_address_destroy (&addr);
1637 } 1444 }
1638 1445
...@@ -1645,13 +1452,13 @@ builtin_note (struct mh_machine *mach) ...@@ -1645,13 +1452,13 @@ builtin_note (struct mh_machine *mach)
1645 const char *str; 1452 const char *str;
1646 int rc; 1453 int rc;
1647 1454
1648 rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str)); 1455 rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
1649 strobj_free (&mach->arg_str); 1456 mh_string_clear (&mach->str[R_REG]);
1650 if (rc) 1457 if (rc)
1651 return; 1458 return;
1652 1459
1653 if (mu_address_sget_comments (addr, 1, &str) == 0) 1460 if (mu_address_sget_comments (addr, 1, &str) == 0)
1654 strobj_create (&mach->arg_str, str); 1461 mh_string_load (&mach->str[R_REG], str);
1655 mu_address_destroy (&addr); 1462 mu_address_destroy (&addr);
1656 } 1463 }
1657 1464
...@@ -1663,8 +1470,8 @@ builtin_mbox (struct mh_machine *mach) ...@@ -1663,8 +1470,8 @@ builtin_mbox (struct mh_machine *mach)
1663 char *str; 1470 char *str;
1664 int rc; 1471 int rc;
1665 1472
1666 rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str)); 1473 rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
1667 strobj_free (&mach->arg_str); 1474 mh_string_clear (&mach->str[R_REG]);
1668 if (rc) 1475 if (rc)
1669 return; 1476 return;
1670 1477
...@@ -1673,7 +1480,7 @@ builtin_mbox (struct mh_machine *mach) ...@@ -1673,7 +1480,7 @@ builtin_mbox (struct mh_machine *mach)
1673 char *p = strchr (str, '@'); 1480 char *p = strchr (str, '@');
1674 if (p) 1481 if (p)
1675 *p = 0; 1482 *p = 0;
1676 strobj_create (&mach->arg_str, p); 1483 mh_string_load (&mach->str[R_REG], str);
1677 free (str); 1484 free (str);
1678 } 1485 }
1679 mu_address_destroy (&addr); 1486 mu_address_destroy (&addr);
...@@ -1686,12 +1493,13 @@ builtin_mymbox (struct mh_machine *mach) ...@@ -1686,12 +1493,13 @@ builtin_mymbox (struct mh_machine *mach)
1686 mu_address_t addr; 1493 mu_address_t addr;
1687 const char *str; 1494 const char *str;
1688 1495
1689 mach->arg_num = 0; 1496 if (mu_address_create (&addr, mh_string_value (&mach->str[R_ARG])))
1690 if (mu_address_create (&addr, strobj_ptr (&mach->arg_str)))
1691 return; 1497 return;
1692 1498
1693 if (mu_address_sget_email (addr, 1, &str) == 0 && str) 1499 if (mu_address_sget_email (addr, 1, &str) == 0 && str)
1694 mach->arg_num = mh_is_my_name (str); 1500 mach->num[R_REG] = mh_is_my_name (str);
1501 else
1502 mach->num[R_REG] = 0;
1695 mu_address_destroy (&addr); 1503 mu_address_destroy (&addr);
1696 } 1504 }
1697 1505
...@@ -1703,8 +1511,8 @@ builtin_host (struct mh_machine *mach) ...@@ -1703,8 +1511,8 @@ builtin_host (struct mh_machine *mach)
1703 char *str; 1511 char *str;
1704 int rc; 1512 int rc;
1705 1513
1706 rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str)); 1514 rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
1707 strobj_free (&mach->arg_str); 1515 mh_string_clear (&mach->str[R_REG]);
1708 if (rc) 1516 if (rc)
1709 return; 1517 return;
1710 1518
...@@ -1712,7 +1520,7 @@ builtin_host (struct mh_machine *mach) ...@@ -1712,7 +1520,7 @@ builtin_host (struct mh_machine *mach)
1712 { 1520 {
1713 char *p = strchr (str, '@'); 1521 char *p = strchr (str, '@');
1714 if (p) 1522 if (p)
1715 strobj_create (&mach->arg_str, p+1); 1523 mh_string_load (&mach->str[R_REG], p + 1);
1716 free (str); 1524 free (str);
1717 } 1525 }
1718 mu_address_destroy (&addr); 1526 mu_address_destroy (&addr);
...@@ -1725,15 +1533,15 @@ builtin_nohost (struct mh_machine *mach) ...@@ -1725,15 +1533,15 @@ builtin_nohost (struct mh_machine *mach)
1725 mu_address_t addr; 1533 mu_address_t addr;
1726 const char *str; 1534 const char *str;
1727 1535
1728 int rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str)); 1536 int rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
1729 strobj_free (&mach->arg_str); 1537 mh_string_clear (&mach->str[R_REG]);
1730 if (rc) 1538 if (rc)
1731 return; 1539 return;
1732 1540
1733 if (mu_address_sget_email (addr, 1, &str) == 0 && str) 1541 if (mu_address_sget_email (addr, 1, &str) == 0 && str)
1734 mach->arg_num = strchr (str, '@') != NULL; 1542 mach->num[R_REG] = strchr (str, '@') != NULL;
1735 else 1543 else
1736 mach->arg_num = 0; 1544 mach->num[R_REG] = 0;
1737 mu_address_destroy (&addr); 1545 mu_address_destroy (&addr);
1738 } 1546 }
1739 1547
...@@ -1746,22 +1554,22 @@ builtin_type (struct mh_machine *mach) ...@@ -1746,22 +1554,22 @@ builtin_type (struct mh_machine *mach)
1746 int rc; 1554 int rc;
1747 const char *str; 1555 const char *str;
1748 1556
1749 rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str)); 1557 rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
1750 strobj_free (&mach->arg_str); 1558 mh_string_clear (&mach->str[R_REG]);
1751 if (rc) 1559 if (rc)
1752 return; 1560 return;
1753 1561
1754 if (mu_address_sget_email (addr, 1, &str) == 0 && str) 1562 if (mu_address_sget_email (addr, 1, &str) == 0 && str)
1755 { 1563 {
1756 if (strchr (str, '@')) 1564 if (strchr (str, '@'))
1757 mach->arg_num = 1; 1565 mach->num[R_REG] = 1;
1758 else if (strchr (str, '!')) 1566 else if (strchr (str, '!'))
1759 mach->arg_num = -1; 1567 mach->num[R_REG] = -1;
1760 else 1568 else
1761 mach->arg_num = 0; /* assume local */ 1569 mach->num[R_REG] = 0; /* assume local */
1762 } 1570 }
1763 else 1571 else
1764 mach->arg_num = 2; 1572 mach->num[R_REG] = 2;
1765 mu_address_destroy (&addr); 1573 mu_address_destroy (&addr);
1766 } 1574 }
1767 1575
...@@ -1771,12 +1579,12 @@ builtin_path (struct mh_machine *mach) ...@@ -1771,12 +1579,12 @@ builtin_path (struct mh_machine *mach)
1771 { 1579 {
1772 mu_address_t addr; 1580 mu_address_t addr;
1773 const char *str; 1581 const char *str;
1774 int rc = mu_address_create (&addr, strobj_ptr (&mach->arg_str)); 1582 int rc = mu_address_create (&addr, mh_string_value (&mach->str[R_ARG]));
1775 strobj_free (&mach->arg_str); 1583 mh_string_clear (&mach->str[R_REG]);
1776 if (rc) 1584 if (rc)
1777 return; 1585 return;
1778 if (mu_address_sget_route (addr, 1, &str)) 1586 if (mu_address_sget_route (addr, 1, &str))
1779 strobj_create (&mach->arg_str, str); 1587 mh_string_load (&mach->str[R_REG], str);
1780 mu_address_destroy (&addr); 1588 mu_address_destroy (&addr);
1781 } 1589 }
1782 1590
...@@ -1786,6 +1594,7 @@ builtin_ingrp (struct mh_machine *mach) ...@@ -1786,6 +1594,7 @@ builtin_ingrp (struct mh_machine *mach)
1786 { 1594 {
1787 /*FIXME:*/ 1595 /*FIXME:*/
1788 builtin_not_implemented ("ingrp"); 1596 builtin_not_implemented ("ingrp");
1597 mach->num[R_REG] = 0;
1789 } 1598 }
1790 1599
1791 /* gname addr string name of group**/ 1600 /* gname addr string name of group**/
...@@ -1794,6 +1603,7 @@ builtin_gname (struct mh_machine *mach) ...@@ -1794,6 +1603,7 @@ builtin_gname (struct mh_machine *mach)
1794 { 1603 {
1795 /*FIXME:*/ 1604 /*FIXME:*/
1796 builtin_not_implemented ("gname"); 1605 builtin_not_implemented ("gname");
1606 builtin_str_noop (mach);
1797 } 1607 }
1798 1608
1799 /* formataddr expr append arg to str as a 1609 /* formataddr expr append arg to str as a
...@@ -1806,12 +1616,12 @@ builtin_formataddr (struct mh_machine *mach) ...@@ -1806,12 +1616,12 @@ builtin_formataddr (struct mh_machine *mach)
1806 size_t num; 1616 size_t num;
1807 const char *buf; 1617 const char *buf;
1808 1618
1809 if (strobj_len (&mach->reg_str) == 0) 1619 if (mh_string_is_null (&mach->str[R_REG]))
1810 dest = NULL; 1620 dest = NULL;
1811 else if (mu_address_create (&dest, strobj_ptr (&mach->reg_str))) 1621 else if (mu_address_create (&dest, mh_string_value (&mach->str[R_REG])))
1812 return; 1622 return;
1813 1623
1814 if (mu_address_create (&addr, strobj_ptr (&mach->arg_str))) 1624 if (mu_address_create (&addr, mh_string_value (&mach->str[R_ARG])))
1815 { 1625 {
1816 mu_address_destroy (&dest); 1626 mu_address_destroy (&dest);
1817 return; 1627 return;
...@@ -1838,10 +1648,9 @@ builtin_formataddr (struct mh_machine *mach) ...@@ -1838,10 +1648,9 @@ builtin_formataddr (struct mh_machine *mach)
1838 } 1648 }
1839 1649
1840 if (mu_address_sget_printable (dest, &buf) == 0) 1650 if (mu_address_sget_printable (dest, &buf) == 0)
1841 { 1651 mh_string_load (&mach->str[R_REG], buf);
1842 strobj_realloc (&mach->reg_str, strlen (buf) + 1); 1652 else
1843 strcpy (strobj_ptr (&mach->reg_str), buf); 1653 mh_string_clear (&mach->str[R_REG]);
1844 }
1845 mu_address_destroy (&dest); 1654 mu_address_destroy (&dest);
1846 } 1655 }
1847 1656
...@@ -1854,10 +1663,10 @@ builtin_formataddr (struct mh_machine *mach) ...@@ -1854,10 +1663,10 @@ builtin_formataddr (struct mh_machine *mach)
1854 static void 1663 static void
1855 builtin_putaddr (struct mh_machine *mach) 1664 builtin_putaddr (struct mh_machine *mach)
1856 { 1665 {
1857 if (!strobj_is_null (&mach->arg_str)) 1666 if (!mh_string_is_null (&mach->str[R_ARG]))
1858 print_hdr_string (mach, strobj_ptr (&mach->arg_str)); 1667 print_hdr_string (mach, mh_string_value (&mach->str[R_ARG]));
1859 if (!strobj_is_null (&mach->reg_str)) 1668 if (!mh_string_is_null (&mach->str[R_REG]))
1860 print_hdr_string (mach, strobj_ptr (&mach->reg_str)); 1669 print_hdr_string (mach, mh_string_value (&mach->str[R_REG]));
1861 } 1670 }
1862 1671
1863 /* GNU extension: Strip leading whitespace and eventual Re: (or Re\[[0-9]+\]:) 1672 /* GNU extension: Strip leading whitespace and eventual Re: (or Re\[[0-9]+\]:)
...@@ -1865,14 +1674,15 @@ builtin_putaddr (struct mh_machine *mach) ...@@ -1865,14 +1674,15 @@ builtin_putaddr (struct mh_machine *mach)
1865 static void 1674 static void
1866 builtin_unre (struct mh_machine *mach) 1675 builtin_unre (struct mh_machine *mach)
1867 { 1676 {
1868 const char *p; 1677 char const *arg = mh_string_value (&mach->str[R_ARG]);
1869 int rc = mu_unre_subject (strobj_ptr (&mach->arg_str), &p); 1678 char const *p;
1870 if (rc == 0 && p != strobj_ptr (&mach->arg_str)) 1679 int rc = mu_unre_subject (arg, &p);
1680 mh_string_clear (&mach->str[R_REG]);
1681 if (rc == 0 && p != arg)
1871 { 1682 {
1872 char *q = mu_strdup (p); /* Create a copy, since strobj_create will 1683 char *q = mu_strdup (p); /* Create a copy, since mh_string_load can
1873 destroy p */ 1684 destroy p */
1874 strobj_free (&mach->arg_str); 1685 mh_string_load (&mach->str[R_REG], q);
1875 strobj_create (&mach->arg_str, q);
1876 free (q); 1686 free (q);
1877 } 1687 }
1878 } 1688 }
...@@ -1882,7 +1692,7 @@ builtin_isreply (struct mh_machine *mach) ...@@ -1882,7 +1692,7 @@ builtin_isreply (struct mh_machine *mach)
1882 { 1692 {
1883 int rc; 1693 int rc;
1884 1694
1885 if (strobj_is_null (&mach->arg_str)) 1695 if (mh_string_is_null (&mach->str[R_ARG]))
1886 { 1696 {
1887 mu_header_t hdr = NULL; 1697 mu_header_t hdr = NULL;
1888 char *value = NULL; 1698 char *value = NULL;
...@@ -1893,37 +1703,31 @@ builtin_isreply (struct mh_machine *mach) ...@@ -1893,37 +1703,31 @@ builtin_isreply (struct mh_machine *mach)
1893 free (value); 1703 free (value);
1894 } 1704 }
1895 else 1705 else
1896 rc = mu_unre_subject (strobj_ptr (&mach->arg_str), NULL); 1706 rc = mu_unre_subject (mh_string_value (&mach->str[R_ARG]), NULL);
1897 1707
1898 mach->arg_num = !rc; 1708 mach->num[R_REG] = !rc;
1899 } 1709 }
1900 1710
1901 static void 1711 static void
1902 decode_string (strobj_t *obj) 1712 builtin_decode (struct mh_machine *mach)
1903 { 1713 {
1904 char *tmp; 1714 char *tmp;
1905 1715
1906 if (strobj_is_null (obj)) 1716 if (mh_string_is_null (&mach->str[R_ARG]))
1907 return; 1717 return;
1908 1718
1909 if (mh_decode_2047 (strobj_ptr (obj), &tmp) == 0) 1719 mh_string_clear (&mach->str[R_REG]);
1720 if (mh_decode_2047 (mh_string_value (&mach->str[R_ARG]), &tmp) == 0)
1910 { 1721 {
1911 strobj_free (obj); 1722 mh_string_load (&mach->str[R_REG], tmp);
1912 strobj_create (obj, tmp);
1913 free (tmp); 1723 free (tmp);
1914 } 1724 }
1915 } 1725 }
1916 1726
1917 static void 1727 static void
1918 builtin_decode (struct mh_machine *mach)
1919 {
1920 decode_string (&mach->arg_str);
1921 }
1922
1923 static void
1924 builtin_reply_regex (struct mh_machine *mach) 1728 builtin_reply_regex (struct mh_machine *mach)
1925 { 1729 {
1926 mh_set_reply_regex (strobj_ptr (&mach->arg_str)); 1730 mh_set_reply_regex (mh_string_value (&mach->str[R_ARG]));
1927 } 1731 }
1928 1732
1929 int 1733 int
...@@ -1944,34 +1748,34 @@ mh_decode_rcpt_flag (const char *arg) ...@@ -1944,34 +1748,34 @@ mh_decode_rcpt_flag (const char *arg)
1944 static void 1748 static void
1945 builtin_rcpt (struct mh_machine *mach) 1749 builtin_rcpt (struct mh_machine *mach)
1946 { 1750 {
1947 int rc = mh_decode_rcpt_flag (strobj_ptr (&mach->arg_str)); 1751 int rc = mh_decode_rcpt_flag (mh_string_value (&mach->str[R_ARG]));
1948 if (rc == RCPT_NONE) 1752 if (rc == RCPT_NONE)
1949 { 1753 {
1950 mu_error (_("invalid recipient mask")); 1754 mu_error (_("invalid recipient mask"));
1951 /* try to continue anyway */ 1755 /* try to continue anyway */
1952 } 1756 }
1953 mach->arg_num = rc & rcpt_mask; 1757 mach->num[R_REG] = !!(rc & rcpt_mask);
1954 } 1758 }
1955 1759
1956 static void 1760 static void
1957 builtin_concat (struct mh_machine *mach) 1761 builtin_concat (struct mh_machine *mach)
1958 { 1762 {
1959 size_t size = strobj_len (&mach->arg_str); 1763 if (mh_string_is_null (&mach->str[R_ARG]))
1960
1961 if (size == 0)
1962 return; 1764 return;
1963 COMPRESS_WS (mach, strobj_ptr (&mach->arg_str), &size); 1765
1964 if (strobj_len (&mach->reg_str) == 0) 1766 compress_ws (mach, mach->str[R_ARG].ptr);
1965 strobj_copy (&mach->reg_str, &mach->arg_str); 1767 if (mh_string_is_null (&mach->str[R_REG]))
1768 mh_string_move (mach, R_REG, R_ARG);
1966 else 1769 else
1967 { 1770 {
1968 int length = 1; 1771 size_t length = 1;
1969 1772
1970 length += 1 + strobj_len (&mach->reg_str); /* reserve en extra space */ 1773 length += 1 + mh_string_length (&mach->str[R_REG]);
1971 length += strobj_len (&mach->arg_str); 1774 /* reserve en extra space */
1972 strobj_realloc (&mach->reg_str, length); 1775 length += mh_string_length (&mach->str[R_ARG]);
1973 strcat (strcat (strobj_ptr (&mach->reg_str), " "), 1776 mh_string_realloc (&mach->str[R_REG], length);
1974 strobj_ptr (&mach->arg_str)); 1777 strcat (strcat (mach->str[R_REG].ptr, " "),
1778 mh_string_value (&mach->str[R_ARG]));
1975 } 1779 }
1976 } 1780 }
1977 1781
...@@ -1981,17 +1785,17 @@ builtin_printhdr (struct mh_machine *mach) ...@@ -1981,17 +1785,17 @@ builtin_printhdr (struct mh_machine *mach)
1981 char *tmp = NULL; 1785 char *tmp = NULL;
1982 size_t s = 0; 1786 size_t s = 0;
1983 1787
1984 if (!strobj_is_null (&mach->arg_str)) 1788 if (!mh_string_is_null (&mach->str[R_ARG]))
1985 { 1789 {
1986 s = strobj_len (&mach->arg_str); 1790 s = mh_string_length (&mach->str[R_ARG]);
1987 tmp = mu_strdup (strobj_ptr (&mach->arg_str)); 1791 tmp = mu_strdup (mh_string_value (&mach->str[R_ARG]));
1988 } 1792 }
1989 1793
1990 if (!strobj_is_null (&mach->reg_str)) 1794 if (!mh_string_is_null (&mach->str[R_REG]))
1991 { 1795 {
1992 s += strobj_len (&mach->reg_str) + 1; 1796 s += mh_string_length (&mach->str[R_REG]) + 1;
1993 tmp = realloc (tmp, s); 1797 tmp = mu_realloc (tmp, s);
1994 strcat (tmp, strobj_ptr (&mach->reg_str)); 1798 strcat (tmp, mh_string_value (&mach->str[R_REG]));
1995 } 1799 }
1996 1800
1997 if (tmp) 1801 if (tmp)
...@@ -2006,10 +1810,10 @@ builtin_in_reply_to (struct mh_machine *mach) ...@@ -2006,10 +1810,10 @@ builtin_in_reply_to (struct mh_machine *mach)
2006 { 1810 {
2007 char *value; 1811 char *value;
2008 1812
2009 strobj_free (&mach->arg_str); 1813 mh_string_clear (&mach->str[R_REG]);
2010 if (mu_rfc2822_in_reply_to (mach->message, &value) == 0) 1814 if (mu_rfc2822_in_reply_to (mach->message, &value) == 0)
2011 { 1815 {
2012 strobj_create (&mach->arg_str, value); 1816 mh_string_load (&mach->str[R_REG], value);
2013 free (value); 1817 free (value);
2014 } 1818 }
2015 } 1819 }
...@@ -2019,10 +1823,10 @@ builtin_references (struct mh_machine *mach) ...@@ -2019,10 +1823,10 @@ builtin_references (struct mh_machine *mach)
2019 { 1823 {
2020 char *value; 1824 char *value;
2021 1825
2022 strobj_free (&mach->arg_str); 1826 mh_string_clear (&mach->str[R_REG]);
2023 if (mu_rfc2822_references (mach->message, &value) == 0) 1827 if (mu_rfc2822_references (mach->message, &value) == 0)
2024 { 1828 {
2025 strobj_create (&mach->arg_str, value); 1829 mh_string_load (&mach->str[R_REG], value);
2026 free (value); 1830 free (value);
2027 } 1831 }
2028 } 1832 }
...@@ -2030,22 +1834,19 @@ builtin_references (struct mh_machine *mach) ...@@ -2030,22 +1834,19 @@ builtin_references (struct mh_machine *mach)
2030 static void 1834 static void
2031 builtin_package (struct mh_machine *mach) 1835 builtin_package (struct mh_machine *mach)
2032 { 1836 {
2033 strobj_free (&mach->arg_str); 1837 mh_string_load (&mach->str[R_REG], PACKAGE);
2034 strobj_set (&mach->arg_str, PACKAGE);
2035 } 1838 }
2036 1839
2037 static void 1840 static void
2038 builtin_package_string (struct mh_machine *mach) 1841 builtin_package_string (struct mh_machine *mach)
2039 { 1842 {
2040 strobj_free (&mach->arg_str); 1843 mh_string_load (&mach->str[R_REG], PACKAGE_STRING);
2041 strobj_set (&mach->arg_str, PACKAGE_STRING);
2042 } 1844 }
2043 1845
2044 static void 1846 static void
2045 builtin_version (struct mh_machine *mach) 1847 builtin_version (struct mh_machine *mach)
2046 { 1848 {
2047 strobj_free (&mach->arg_str); 1849 mh_string_load (&mach->str[R_REG], VERSION);
2048 strobj_set (&mach->arg_str, VERSION);
2049 } 1850 }
2050 1851
2051 /* Builtin function table */ 1852 /* Builtin function table */
...@@ -2135,24 +1936,19 @@ mh_builtin_t builtin_tab[] = { ...@@ -2135,24 +1936,19 @@ mh_builtin_t builtin_tab[] = {
2135 { "reply_regex", builtin_reply_regex, mhtype_none, mhtype_str }, 1936 { "reply_regex", builtin_reply_regex, mhtype_none, mhtype_str },
2136 { "isreply", builtin_isreply, mhtype_num, mhtype_str, MHA_OPTARG }, 1937 { "isreply", builtin_isreply, mhtype_num, mhtype_str, MHA_OPTARG },
2137 { "decode", builtin_decode, mhtype_str, mhtype_str }, 1938 { "decode", builtin_decode, mhtype_str, mhtype_str },
1939 { "void", NULL, mhtype_none, mhtype_none, MHA_VOID },
2138 { 0 } 1940 { 0 }
2139 }; 1941 };
2140 1942
2141 mh_builtin_t * 1943 mh_builtin_t *
2142 mh_lookup_builtin (char *name, int *rest) 1944 mh_lookup_builtin (char *name, size_t len)
2143 { 1945 {
2144 mh_builtin_t *bp; 1946 mh_builtin_t *bp;
2145 int namelen = strlen (name);
2146 1947
2147 for (bp = builtin_tab; bp->name; bp++) 1948 for (bp = builtin_tab; bp->name; bp++)
2148 { 1949 {
2149 int len = strlen (bp->name); 1950 if (strlen (bp->name) == len && memcmp (name, bp->name, len) == 0)
2150 if (len >= namelen 1951 return bp;
2151 && memcmp (name, bp->name, len) == 0)
2152 {
2153 *rest = namelen - len;
2154 return bp;
2155 }
2156 } 1952 }
2157 return NULL; 1953 return NULL;
2158 } 1954 }
...@@ -2167,3 +1963,151 @@ _get_builtin_name (mh_builtin_fp ptr) ...@@ -2167,3 +1963,151 @@ _get_builtin_name (mh_builtin_fp ptr)
2167 return bp->name; 1963 return bp->name;
2168 return NULL; 1964 return NULL;
2169 } 1965 }
1966
1967 void
1968 mh_format_dump_disass (mh_format_t fmt)
1969 {
1970 mh_instr_t *prog = fmt->prog;
1971 size_t pc = 1;
1972 int stop = 0;
1973 static char *regname[] = {
1974 [R_REG] = "reg",
1975 [R_ARG] = "arg"
1976 };
1977
1978 if (!prog)
1979 return;
1980 while (!stop)
1981 {
1982 mh_opcode_t opcode;
1983
1984 printf ("% 4.4ld: ", (long) pc);
1985 switch (opcode = MHI_OPCODE (prog[pc++]))
1986 {
1987 case mhop_stop:
1988 printf ("stop");
1989 stop = 1;
1990 break;
1991
1992 case mhop_branch:
1993 {
1994 long n = MHI_NUM (prog[pc++]);
1995 printf ("branch %ld", pc + n - 1);
1996 }
1997 break;
1998
1999 case mhop_brzn:
2000 {
2001 long n = MHI_NUM (prog[pc++]);
2002 printf ("brzn %ld", pc + n - 1);
2003 }
2004 break;
2005
2006 case mhop_brzs:
2007 {
2008 long n = MHI_NUM (prog[pc++]);
2009 printf ("brzs %ld", pc + n - 1);
2010 }
2011 break;
2012
2013 case mhop_setn:
2014 {
2015 long reg = MHI_NUM (prog[pc++]);
2016 long n = MHI_NUM (prog[pc++]);
2017 printf ("setn %s, %ld", regname[reg], n);
2018 }
2019 break;
2020
2021 case mhop_sets:
2022 {
2023 long reg = MHI_NUM (prog[pc++]);
2024 size_t skip = MHI_NUM (prog[pc++]);
2025 char const *str = MHI_STR (prog[pc]);
2026 char *prt;
2027
2028 MU_ASSERT (mu_c_str_escape_trans (str,
2029 "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v",
2030 &prt));
2031
2032 pc += skip;
2033 printf ("setn %s, \"%s\"", regname[reg], prt);
2034 free (prt);
2035 }
2036 break;
2037
2038 case mhop_movn:
2039 {
2040 long dst = MHI_NUM (prog[pc++]);
2041 long src = MHI_NUM (prog[pc++]);
2042 printf ("movn %s, %s", regname[dst], regname[src]);
2043 }
2044 break;
2045
2046 case mhop_movs:
2047 {
2048 long dst = MHI_NUM (prog[pc++]);
2049 long src = MHI_NUM (prog[pc++]);
2050 printf ("movs %s, %s", regname[dst], regname[src]);
2051 }
2052 break;
2053
2054 case mhop_ldcomp:
2055 {
2056 long reg = MHI_NUM (prog[pc++]);
2057 size_t skip = MHI_NUM (prog[pc++]);
2058 char const *comp = MHI_STR (prog[pc]);
2059 pc += skip;
2060 printf ("ldcomp %s, \"%s\"", regname[reg], comp);
2061 }
2062 break;
2063
2064 case mhop_ldbody:
2065 {
2066 long reg = MHI_NUM (prog[pc++]);
2067 printf ("ldbody %s", regname[reg]);
2068 }
2069 break;
2070
2071 case mhop_call:
2072 {
2073 char *name = _get_builtin_name (MHI_BUILTIN (prog[pc++]));
2074 printf ("call %s", name ? name : "UNKNOWN");
2075 }
2076 break;
2077
2078 case mhop_atoi:
2079 {
2080 long reg = MHI_NUM (prog[pc++]);
2081 printf ("atoi %s", regname[reg]);
2082 }
2083 break;
2084
2085 case mhop_itoa:
2086 {
2087 long reg = MHI_NUM (prog[pc++]);
2088 printf ("itoa %s", regname[reg]);
2089 }
2090 break;
2091
2092 case mhop_printn:
2093 printf ("printn");
2094 break;
2095
2096 case mhop_prints:
2097 printf ("prints");
2098 break;
2099
2100 case mhop_fmtspec:
2101 {
2102 int fmtspec = MHI_NUM (prog[pc++]);
2103 printf ("fmtspec ");
2104 mh_print_fmtspec (fmtspec);
2105 }
2106 break;
2107
2108 default:
2109 abort ();
2110 }
2111 printf ("\n");
2112 }
2113 }
......
...@@ -15,34 +15,146 @@ ...@@ -15,34 +15,146 @@
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ 16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17 17
18 typedef struct /* A string object type */ 18 #define MH_FMT_DEFAULT 0
19 #define MH_FMT_RALIGN 0x1000
20 #define MH_FMT_ZEROPAD 0x2000
21 #define MH_FMT_COMPWS 0x4000
22 #define MH_WIDTH_MASK 0x0fff
23
24 enum mh_opcode
19 { 25 {
20 int size; /* Allocated size or 0 for static storage */ 26 /* Stop. Format: mhop_stop */
21 char *ptr; /* Actual data */ 27 mhop_stop,
22 } 28 /* Unconditional branch
23 strobj_t; 29 Format: mhop_branch offset */
30 mhop_branch,
31 /* Branch if num reg is zero.
32 Format: mhop_brz_num dest-off */
33 mhop_brzn,
34 /* Branch if str reg is zero.
35 Format: mhop_brz_str dest-off */
36 mhop_brzs,
37
38 /* Set numeric register
39 Format: mhop_setn val */
40 mhop_setn,
41
42 /* Set string register
43 Format: mhop_sets reg length string */
44 mhop_sets,
24 45
25 #define strobj_ptr(p) ((p)->ptr ? (p)->ptr : "") 46 /* Move value bewtween two numeric registers
26 #define strobj_len(p) (strobj_is_null(p) ? 0 : strlen((p)->ptr)) 47 Format: mhop_movn dest src */
27 #define strobj_is_null(p) ((p)->ptr == NULL) 48 mhop_movn,
28 #define strobj_is_static(p) ((p)->size == 0)
29 49
30 struct mh_machine 50 /* Move value bewtween two string registers
51 Format: mhop_movs dest src */
52 mhop_movs,
53
54 /* Load component value into a string register
55 Format: mhop_load reg string */
56 mhop_ldcomp,
57
58 /* Load first width bytes of message body contents into a string register.
59 Format: mhop_body reg */
60 mhop_ldbody,
61
62 /* Call a function.
63 Format: mhop_call function-pointer */
64 mhop_call,
65
66 /* Convert string register to number reg
67 Format: mhop_atoi reg
68 */
69 mhop_atoi,
70
71 /* Convert numeric register to string
72 Format: mhop_itoa reg */
73 mhop_itoa,
74
75 /* Print num reg */
76 mhop_printn,
77
78 /* Print str reg */
79 mhop_prints,
80
81 /* Set format specification.
82 Format: mhop_fmtspec number */
83 mhop_fmtspec,
84 };
85
86 enum regid { R_REG, R_ARG };
87
88 enum mh_type
89 {
90 mhtype_none,
91 mhtype_num,
92 mhtype_str
93 };
94
95 typedef enum mh_opcode mh_opcode_t;
96
97 struct mh_machine;
98 typedef void (*mh_builtin_fp) (struct mh_machine *);
99
100 typedef union {
101 mh_opcode_t opcode;
102 mh_builtin_fp builtin;
103 long num;
104 void *ptr;
105 char str[1]; /* Any number of characters follows */
106 } mh_instr_t;
107
108 #define MHI_OPCODE(m) (m).opcode
109 #define MHI_BUILTIN(m) (m).builtin
110 #define MHI_NUM(m) (m).num
111 #define MHI_PTR(m) (m).ptr
112 #define MHI_STR(m) (m).str
113
114 struct mh_format
115 {
116 size_t progmax; /* Size of allocated program*/
117 size_t progcnt; /* Actual number of elements used */
118 mh_instr_t *prog; /* Program itself */
119 struct node *tree;
120 mu_opool_t pool;
121 };
122
123 #define MHA_REQUIRED 0
124 #define MHA_OPTARG 1
125 #define MHA_OPT_CLEAR 2
126 #define MHA_VOID 3
127
128 typedef struct mh_builtin mh_builtin_t;
129
130 struct mh_builtin
31 { 131 {
32 strobj_t reg_str; /* String register */ 132 char *name;
33 int reg_num; /* Numeric register */ 133 mh_builtin_fp fun;
134 enum mh_type type;
135 enum mh_type argtype;
136 int optarg;
137 };
34 138
35 strobj_t arg_str; /* String argument */ 139 struct mh_string
36 long arg_num; /* Numeric argument */ 140 {
141 size_t size;
142 char *ptr;
143 };
144
145 struct mh_machine
146 {
147 long num[2]; /* numeric registers */
148 struct mh_string str[2]; /* string registers */
37 149
38 size_t pc; /* Program counter */ 150 size_t pc; /* Program counter */
39 size_t progsize; /* Size of allocated program*/ 151 size_t progcnt; /* Size of allocated program*/
40 mh_instr_t *prog; /* Program itself */ 152 mh_instr_t *prog; /* Program itself */
41 int stop; /* Stop execution immediately */ 153 int stop; /* Stop execution immediately */
42 154
43 mu_opool_t pool; /* Output buffer */ 155 size_t width; /* Output line width */
44 size_t width; /* Output buffer width */ 156 size_t ind; /* Output line index */
45 size_t ind; /* Output buffer index */ 157 mu_stream_t output; /* Output stream */
46 158
47 mu_list_t addrlist; /* The list of email addresses output this far */ 159 mu_list_t addrlist; /* The list of email addresses output this far */
48 int fmtflags; /* Current formatting flags */ 160 int fmtflags; /* Current formatting flags */
...@@ -51,9 +163,5 @@ struct mh_machine ...@@ -51,9 +163,5 @@ struct mh_machine
51 size_t msgno; /* Its number */ 163 size_t msgno; /* Its number */
52 }; 164 };
53 165
54 void strobj_free (strobj_t *obj); 166 mh_builtin_t *mh_lookup_builtin (char *name, size_t len);
55 void strobj_create (strobj_t *lvalue, const char *str); 167 void mh_print_fmtspec (int fmtspec);
56 void strobj_set (strobj_t *lvalue, char *str);
57 void strobj_assign (strobj_t *lvalue, strobj_t *rvalue);
58 void strobj_copy (strobj_t *lvalue, strobj_t *rvalue);
59 void strobj_realloc (strobj_t *obj, size_t length);
......
...@@ -913,7 +913,7 @@ mh_charset (const char *dfl) ...@@ -913,7 +913,7 @@ mh_charset (const char *dfl)
913 } 913 }
914 914
915 int 915 int
916 mh_decode_2047 (char *text, char **decoded_text) 916 mh_decode_2047 (char const *text, char **decoded_text)
917 { 917 {
918 const char *charset = mh_charset (NULL); 918 const char *charset = mh_charset (NULL);
919 if (!charset) 919 if (!charset)
......
...@@ -46,7 +46,7 @@ enum mhl_datatype ...@@ -46,7 +46,7 @@ enum mhl_datatype
46 typedef union mhl_value { 46 typedef union mhl_value {
47 char *str; 47 char *str;
48 int num; 48 int num;
49 mh_format_t *fmt; 49 mh_format_t fmt;
50 } mhl_value_t; 50 } mhl_value_t;
51 51
52 typedef struct mhl_variable 52 typedef struct mhl_variable
...@@ -151,7 +151,6 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str) ...@@ -151,7 +151,6 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str)
151 { 151 {
152 size_t i; 152 size_t i;
153 struct mu_wordsplit ws; 153 struct mu_wordsplit ws;
154 mh_format_t fmt;
155 int wsflags; 154 int wsflags;
156 155
157 if (strncmp (str, "ignores=", 8) == 0 && str[8] != '"') 156 if (strncmp (str, "ignores=", 8) == 0 && str[8] != '"')
...@@ -219,15 +218,14 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str) ...@@ -219,15 +218,14 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str)
219 break; 218 break;
220 219
221 case dt_format: 220 case dt_format:
222 if (mh_format_parse (value, &fmt)) 221 if (mh_format_parse (&stmt->v.variable.value.fmt, value,
222 MH_FMT_PARSE_DEFAULT))
223 { 223 {
224 mu_error (_("%s:%d: bad format string"), 224 mu_error (_("%s:%d: bad format string"),
225 loc->filename, 225 loc->filename,
226 loc->line); 226 loc->line);
227 exit (1); 227 exit (1);
228 } 228 }
229 stmt->v.variable.value.fmt = mu_alloc (sizeof (mh_format_t));
230 *stmt->v.variable.value.fmt = fmt;
231 break; 229 break;
232 230
233 case dt_flag: 231 case dt_flag:
...@@ -456,7 +454,7 @@ struct eval_env ...@@ -456,7 +454,7 @@ struct eval_env
456 int ivar[I_MAX]; 454 int ivar[I_MAX];
457 int bvar[B_MAX]; 455 int bvar[B_MAX];
458 char *svar[S_MAX]; 456 char *svar[S_MAX];
459 mh_format_t *fvar[F_MAX]; 457 mh_format_t fvar[F_MAX];
460 char *prefix; 458 char *prefix;
461 }; 459 };
462 460
......