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
163 additions
and
163 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); | ... | ... |
This diff is collapsed.
Click to expand it.
This diff is collapsed.
Click to expand it.
... | @@ -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