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