Commit 9da939eb 9da939ebc7cde925ee45f405786a6b0d451b7180 by Sergey Poznyakoff

Fix premature push.

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