Fix premature push.
Showing
7 changed files
with
1141 additions
and
1630 deletions
... | @@ -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 | ... | ... |
-
Please register or sign in to post a comment