Commit 35056a6e 35056a6e5f5417bf14f161ed2065210560376220 by Sergey Poznyakoff

Start rewriting MH format functions.

* mh/fmtcheck.c: New option -disassemble
* mh/mh.h: Move format-related declarations to mh_format.h
(mh_format_parse): Change signature.
(mh_format): Change signature.
(mh_format_dump_code)
(mh_format_dump_disass): New protos.
(mh_decode_2047): Change signature.
* mh/mh_fmtgram.y: Rewrite from scratch.  First, build a parse tree,
then use it to generate code.
* mh/mh_format.c: Rewrite from scratch.
* mh/mh_format.h: Move format-related declarations from mh.h
* mh/mh_init.c (mh_decode_2047): Text is const.
* mh/mh_list.c: Fix calls to mh_format_parse and related objects.
1 parent 6878eb80
...@@ -25,6 +25,7 @@ static char args_doc[] = N_("[FILE]"); ...@@ -25,6 +25,7 @@ static char args_doc[] = N_("[FILE]");
25 static char *format_str; 25 static char *format_str;
26 static mh_format_t format; 26 static mh_format_t format;
27 static int dump_option; 27 static int dump_option;
28 static int disass_option;
28 static int debug_option; 29 static int debug_option;
29 static char *input_file; 30 static char *input_file;
30 static size_t width; 31 static size_t width;
...@@ -41,6 +42,9 @@ static struct mu_option options[] = { ...@@ -41,6 +42,9 @@ static struct mu_option options[] = {
41 { "dump", 0, NULL, MU_OPTION_HIDDEN, 42 { "dump", 0, NULL, MU_OPTION_HIDDEN,
42 N_("dump the listing of compiled format code"), 43 N_("dump the listing of compiled format code"),
43 mu_c_bool, &dump_option }, 44 mu_c_bool, &dump_option },
45 { "disassemble", 0, NULL, MU_OPTION_HIDDEN,
46 N_("dump disassembled format code"),
47 mu_c_bool, &disass_option },
44 { "debug", 0, NULL, MU_OPTION_DEFAULT, 48 { "debug", 0, NULL, MU_OPTION_DEFAULT,
45 N_("enable parser debugging output"), 49 N_("enable parser debugging output"),
46 mu_c_bool, &debug_option }, 50 mu_c_bool, &debug_option },
...@@ -58,11 +62,8 @@ static void ...@@ -58,11 +62,8 @@ static void
58 run (void) 62 run (void)
59 { 63 {
60 mu_message_t msg = mh_file_to_message (NULL, input_file); 64 mu_message_t msg = mh_file_to_message (NULL, input_file);
61 char *output; 65 mh_format (format, msg, msgno, width, mu_strout);
62 66 mu_printf ("\n");
63 mh_format (&format, msg, msgno, width, &output);
64
65 mu_printf ("%s\n", output);
66 } 67 }
67 68
68 int 69 int
...@@ -90,14 +91,16 @@ main (int argc, char **argv) ...@@ -90,14 +91,16 @@ main (int argc, char **argv)
90 mu_error (_("Format string not specified")); 91 mu_error (_("Format string not specified"));
91 return 1; 92 return 1;
92 } 93 }
93 if (mh_format_parse (format_str, &format)) 94 if (mh_format_parse (&format, format_str, MH_FMT_PARSE_TREE))
94 { 95 {
95 mu_error (_("Bad format string")); 96 mu_error (_("Bad format string"));
96 exit (1); 97 exit (1);
97 } 98 }
98 99
99 if (dump_option) 100 if (dump_option)
100 mh_format_dump (&format); 101 mh_format_dump_code (format);
102 if (disass_option)
103 mh_format_dump_disass (format);
101 104
102 if (input_file) 105 if (input_file)
103 run (); 106 run ();
......
...@@ -65,11 +65,6 @@ ...@@ -65,11 +65,6 @@
65 65
66 #include <mu_umaxtostr.h> 66 #include <mu_umaxtostr.h>
67 67
68 #define MH_FMT_RALIGN 0x1000
69 #define MH_FMT_ZEROPAD 0x2000
70 #define MH_FMT_COMPWS 0x4000
71 #define MH_WIDTH_MASK 0x0fff
72
73 #define MH_SEQUENCES_FILE ".mh_sequences" 68 #define MH_SEQUENCES_FILE ".mh_sequences"
74 #define MH_USER_PROFILE ".mh_profile" 69 #define MH_USER_PROFILE ".mh_profile"
75 #define MH_GLOBAL_PROFILE "mh-profile" 70 #define MH_GLOBAL_PROFILE "mh-profile"
...@@ -78,118 +73,6 @@ ...@@ -78,118 +73,6 @@
78 73
79 #define is_true(arg) ((arg) == NULL||mu_true_answer_p (arg) == 1) 74 #define is_true(arg) ((arg) == NULL||mu_true_answer_p (arg) == 1)
80 75
81 enum mh_opcode
82 {
83 /* 0. Stop. Format: mhop_stop */
84 mhop_stop,
85 /* 1. Branch.
86 Format: mhop_branch offset */
87 mhop_branch,
88 /* 2. Assign to numeric register
89 Format: mhop_num_asgn */
90 mhop_num_asgn,
91 /* 3. Assign to string register
92 Format: mhop_str_asgn */
93 mhop_str_asgn,
94 /* 4. Numeric arg follows.
95 Format: mhop_num_arg number */
96 mhop_num_arg,
97 /* 5. String arg follows.
98 Format: mhop_str_arg length string */
99 mhop_str_arg,
100 /* 6. Branch if reg_num is zero.
101 Format: mhop_num_branch dest-off */
102 mhop_num_branch,
103 /* 7. Branch if reg_str is zero.
104 Format: mhop_str_branch dest-off */
105 mhop_str_branch,
106 /* 8. Set str to the value of the header component
107 Format: mhop_header */
108 mhop_header,
109
110 /* 9. Read message body contents into str.
111 Format: mhop_body */
112 mhop_body,
113
114 /* 10. Call a function.
115 Format: mhop_call function-pointer */
116 mhop_call,
117
118 /* 11. assign reg_num to arg_num */
119 mhop_num_to_arg,
120
121 /* 12. assign reg_str to arg_str */
122 mhop_str_to_arg,
123
124 /* 13. Convert arg_str to arg_num */
125 mhop_str_to_num,
126
127 /* 14. Convert arg_num to arg_str */
128 mhop_num_to_str,
129
130 /* 15. Print reg_num */
131 mhop_num_print,
132
133 /* 16. Print reg_str */
134 mhop_str_print,
135
136 /* 17. Set format specification.
137 Format: mhop_fmtspec number */
138 mhop_fmtspec,
139
140 /* 18. Noop */
141 mhop_nop
142 };
143
144 enum mh_type
145 {
146 mhtype_none,
147 mhtype_num,
148 mhtype_str
149 };
150
151 typedef enum mh_opcode mh_opcode_t;
152
153 struct mh_machine;
154 typedef void (*mh_builtin_fp) (struct mh_machine *);
155
156 typedef union {
157 mh_opcode_t opcode;
158 mh_builtin_fp builtin;
159 int num;
160 void *ptr;
161 char str[1]; /* Any number of characters follows */
162 } mh_instr_t;
163
164 #define MHI_OPCODE(m) (m).opcode
165 #define MHI_BUILTIN(m) (m).builtin
166 #define MHI_NUM(m) (m).num
167 #define MHI_PTR(m) (m).ptr
168 #define MHI_STR(m) (m).str
169
170 typedef struct mh_format mh_format_t;
171
172 struct mh_format
173 {
174 size_t progsize; /* Size of allocated program*/
175 mh_instr_t *prog; /* Program itself */
176 };
177
178 #define MHA_REQUIRED 0
179 #define MHA_OPTARG 1
180 #define MHA_OPT_CLEAR 2
181
182 typedef struct mh_builtin mh_builtin_t;
183
184 struct mh_builtin
185 {
186 char *name;
187 mh_builtin_fp fun;
188 int type;
189 int argtype;
190 int optarg;
191 };
192
193 typedef struct 76 typedef struct
194 { 77 {
195 const char *name; 78 const char *name;
...@@ -284,14 +167,22 @@ int mu_getans (const char *variants, const char *fmt, ...) ...@@ -284,14 +167,22 @@ int mu_getans (const char *variants, const char *fmt, ...)
284 int mh_check_folder (const char *pathname, int confirm); 167 int mh_check_folder (const char *pathname, int confirm);
285 int mh_makedir (const char *p); 168 int mh_makedir (const char *p);
286 169
287 int mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno, 170 typedef struct mh_format *mh_format_t;
288 size_t width, char **pret); 171
289 int mh_format_str (mh_format_t *fmt, char *str, size_t width, char **pret); 172 int mh_format (mh_format_t fmt, mu_message_t msg, size_t msgno,
290 void mh_format_dump (mh_format_t *fmt); 173 size_t width, mu_stream_t str);
291 int mh_format_parse (char *format_str, mh_format_t *fmt); 174 int mh_format_str (mh_format_t fmt, char *str, size_t width, char **pret);
175
176 void mh_format_dump_code (mh_format_t fmt);
177 void mh_format_dump_disass (mh_format_t fmt);
178
179 #define MH_FMT_PARSE_DEFAULT 0
180 #define MH_FMT_PARSE_TREE 0x01
181 int mh_format_parse (mh_format_t *fmt, char *format_str, int flags);
182
292 void mh_format_debug (int val); 183 void mh_format_debug (int val);
293 void mh_format_free (mh_format_t *fmt); 184 void mh_format_free (mh_format_t fmt);
294 mh_builtin_t *mh_lookup_builtin (char *name, int *rest); 185 void mh_format_destroy (mh_format_t *fmt);
295 186
296 void mh_error (const char *fmt, ...) MU_PRINTFLIKE(1,2); 187 void mh_error (const char *fmt, ...) MU_PRINTFLIKE(1,2);
297 void mh_err_memory (int fatal); 188 void mh_err_memory (int fatal);
...@@ -350,7 +241,7 @@ int mh_whom_file (const char *filename, int check); ...@@ -350,7 +241,7 @@ int mh_whom_file (const char *filename, int check);
350 int mh_whom_message (mu_message_t msg, int check); 241 int mh_whom_message (mu_message_t msg, int check);
351 242
352 void mh_set_reply_regex (const char *str); 243 void mh_set_reply_regex (const char *str);
353 int mh_decode_2047 (char *text, char **decoded_text); 244 int mh_decode_2047 (char const *text, char **decoded_text);
354 const char *mh_charset (const char *); 245 const char *mh_charset (const char *);
355 246
356 int mh_alias_read (char const *name, int fail); 247 int mh_alias_read (char const *name, int fail);
......
...@@ -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,
24 37
25 #define strobj_ptr(p) ((p)->ptr ? (p)->ptr : "") 38 /* Set numeric register
26 #define strobj_len(p) (strobj_is_null(p) ? 0 : strlen((p)->ptr)) 39 Format: mhop_setn val */
27 #define strobj_is_null(p) ((p)->ptr == NULL) 40 mhop_setn,
28 #define strobj_is_static(p) ((p)->size == 0)
29 41
30 struct mh_machine 42 /* Set string register
43 Format: mhop_sets reg length string */
44 mhop_sets,
45
46 /* Move value bewtween two numeric registers
47 Format: mhop_movn dest src */
48 mhop_movn,
49
50 /* Move value bewtween two string registers
51 Format: mhop_movs dest src */
52 mhop_movs,
53
54 /* Load component value into a string register
55 Format: mhop_load reg string */
56 mhop_ldcomp,
57
58 /* Load first width bytes of message body contents into a string register.
59 Format: mhop_body reg */
60 mhop_ldbody,
61
62 /* Call a function.
63 Format: mhop_call function-pointer */
64 mhop_call,
65
66 /* Convert string register to number reg
67 Format: mhop_atoi reg
68 */
69 mhop_atoi,
70
71 /* Convert numeric register to string
72 Format: mhop_itoa reg */
73 mhop_itoa,
74
75 /* Print num reg */
76 mhop_printn,
77
78 /* Print str reg */
79 mhop_prints,
80
81 /* Set format specification.
82 Format: mhop_fmtspec number */
83 mhop_fmtspec,
84 };
85
86 enum regid { R_REG, R_ARG };
87
88 enum mh_type
89 {
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
31 { 115 {
32 strobj_t reg_str; /* String register */ 116 size_t progmax; /* Size of allocated program*/
33 int reg_num; /* Numeric register */ 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;
34 129
35 strobj_t arg_str; /* String argument */ 130 struct mh_builtin
36 long arg_num; /* Numeric argument */ 131 {
132 char *name;
133 mh_builtin_fp fun;
134 enum mh_type type;
135 enum mh_type argtype;
136 int optarg;
137 };
138
139 struct mh_string
140 {
141 size_t size;
142 char *ptr;
143 };
144
145 struct mh_machine
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
......