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]");
static char *format_str;
static mh_format_t format;
static int dump_option;
static int disass_option;
static int debug_option;
static char *input_file;
static size_t width;
......@@ -41,6 +42,9 @@ static struct mu_option options[] = {
{ "dump", 0, NULL, MU_OPTION_HIDDEN,
N_("dump the listing of compiled format code"),
mu_c_bool, &dump_option },
{ "disassemble", 0, NULL, MU_OPTION_HIDDEN,
N_("dump disassembled format code"),
mu_c_bool, &disass_option },
{ "debug", 0, NULL, MU_OPTION_DEFAULT,
N_("enable parser debugging output"),
mu_c_bool, &debug_option },
......@@ -58,11 +62,8 @@ static void
run (void)
{
mu_message_t msg = mh_file_to_message (NULL, input_file);
char *output;
mh_format (&format, msg, msgno, width, &output);
mu_printf ("%s\n", output);
mh_format (format, msg, msgno, width, mu_strout);
mu_printf ("\n");
}
int
......@@ -90,14 +91,16 @@ main (int argc, char **argv)
mu_error (_("Format string not specified"));
return 1;
}
if (mh_format_parse (format_str, &format))
if (mh_format_parse (&format, format_str, MH_FMT_PARSE_TREE))
{
mu_error (_("Bad format string"));
exit (1);
}
if (dump_option)
mh_format_dump (&format);
mh_format_dump_code (format);
if (disass_option)
mh_format_dump_disass (format);
if (input_file)
run ();
......
......@@ -65,11 +65,6 @@
#include <mu_umaxtostr.h>
#define MH_FMT_RALIGN 0x1000
#define MH_FMT_ZEROPAD 0x2000
#define MH_FMT_COMPWS 0x4000
#define MH_WIDTH_MASK 0x0fff
#define MH_SEQUENCES_FILE ".mh_sequences"
#define MH_USER_PROFILE ".mh_profile"
#define MH_GLOBAL_PROFILE "mh-profile"
......@@ -78,118 +73,6 @@
#define is_true(arg) ((arg) == NULL||mu_true_answer_p (arg) == 1)
enum mh_opcode
{
/* 0. Stop. Format: mhop_stop */
mhop_stop,
/* 1. Branch.
Format: mhop_branch offset */
mhop_branch,
/* 2. Assign to numeric register
Format: mhop_num_asgn */
mhop_num_asgn,
/* 3. Assign to string register
Format: mhop_str_asgn */
mhop_str_asgn,
/* 4. Numeric arg follows.
Format: mhop_num_arg number */
mhop_num_arg,
/* 5. String arg follows.
Format: mhop_str_arg length string */
mhop_str_arg,
/* 6. Branch if reg_num is zero.
Format: mhop_num_branch dest-off */
mhop_num_branch,
/* 7. Branch if reg_str is zero.
Format: mhop_str_branch dest-off */
mhop_str_branch,
/* 8. Set str to the value of the header component
Format: mhop_header */
mhop_header,
/* 9. Read message body contents into str.
Format: mhop_body */
mhop_body,
/* 10. Call a function.
Format: mhop_call function-pointer */
mhop_call,
/* 11. assign reg_num to arg_num */
mhop_num_to_arg,
/* 12. assign reg_str to arg_str */
mhop_str_to_arg,
/* 13. Convert arg_str to arg_num */
mhop_str_to_num,
/* 14. Convert arg_num to arg_str */
mhop_num_to_str,
/* 15. Print reg_num */
mhop_num_print,
/* 16. Print reg_str */
mhop_str_print,
/* 17. Set format specification.
Format: mhop_fmtspec number */
mhop_fmtspec,
/* 18. Noop */
mhop_nop
};
enum mh_type
{
mhtype_none,
mhtype_num,
mhtype_str
};
typedef enum mh_opcode mh_opcode_t;
struct mh_machine;
typedef void (*mh_builtin_fp) (struct mh_machine *);
typedef union {
mh_opcode_t opcode;
mh_builtin_fp builtin;
int num;
void *ptr;
char str[1]; /* Any number of characters follows */
} mh_instr_t;
#define MHI_OPCODE(m) (m).opcode
#define MHI_BUILTIN(m) (m).builtin
#define MHI_NUM(m) (m).num
#define MHI_PTR(m) (m).ptr
#define MHI_STR(m) (m).str
typedef struct mh_format mh_format_t;
struct mh_format
{
size_t progsize; /* Size of allocated program*/
mh_instr_t *prog; /* Program itself */
};
#define MHA_REQUIRED 0
#define MHA_OPTARG 1
#define MHA_OPT_CLEAR 2
typedef struct mh_builtin mh_builtin_t;
struct mh_builtin
{
char *name;
mh_builtin_fp fun;
int type;
int argtype;
int optarg;
};
typedef struct
{
const char *name;
......@@ -284,14 +167,22 @@ int mu_getans (const char *variants, const char *fmt, ...)
int mh_check_folder (const char *pathname, int confirm);
int mh_makedir (const char *p);
int mh_format (mh_format_t *fmt, mu_message_t msg, size_t msgno,
size_t width, char **pret);
int mh_format_str (mh_format_t *fmt, char *str, size_t width, char **pret);
void mh_format_dump (mh_format_t *fmt);
int mh_format_parse (char *format_str, mh_format_t *fmt);
typedef struct mh_format *mh_format_t;
int mh_format (mh_format_t fmt, mu_message_t msg, size_t msgno,
size_t width, mu_stream_t str);
int mh_format_str (mh_format_t fmt, char *str, size_t width, char **pret);
void mh_format_dump_code (mh_format_t fmt);
void mh_format_dump_disass (mh_format_t fmt);
#define MH_FMT_PARSE_DEFAULT 0
#define MH_FMT_PARSE_TREE 0x01
int mh_format_parse (mh_format_t *fmt, char *format_str, int flags);
void mh_format_debug (int val);
void mh_format_free (mh_format_t *fmt);
mh_builtin_t *mh_lookup_builtin (char *name, int *rest);
void mh_format_free (mh_format_t fmt);
void mh_format_destroy (mh_format_t *fmt);
void mh_error (const char *fmt, ...) MU_PRINTFLIKE(1,2);
void mh_err_memory (int fatal);
......@@ -350,7 +241,7 @@ int mh_whom_file (const char *filename, int check);
int mh_whom_message (mu_message_t msg, int check);
void mh_set_reply_regex (const char *str);
int mh_decode_2047 (char *text, char **decoded_text);
int mh_decode_2047 (char const *text, char **decoded_text);
const char *mh_charset (const char *);
int mh_alias_read (char const *name, int fail);
......
......@@ -15,34 +15,146 @@
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
typedef struct /* A string object type */
#define MH_FMT_DEFAULT 0
#define MH_FMT_RALIGN 0x1000
#define MH_FMT_ZEROPAD 0x2000
#define MH_FMT_COMPWS 0x4000
#define MH_WIDTH_MASK 0x0fff
enum mh_opcode
{
int size; /* Allocated size or 0 for static storage */
char *ptr; /* Actual data */
}
strobj_t;
/* Stop. Format: mhop_stop */
mhop_stop,
/* Unconditional branch
Format: mhop_branch offset */
mhop_branch,
/* Branch if num reg is zero.
Format: mhop_brz_num dest-off */
mhop_brzn,
/* Branch if str reg is zero.
Format: mhop_brz_str dest-off */
mhop_brzs,
/* Set numeric register
Format: mhop_setn val */
mhop_setn,
/* Set string register
Format: mhop_sets reg length string */
mhop_sets,
#define strobj_ptr(p) ((p)->ptr ? (p)->ptr : "")
#define strobj_len(p) (strobj_is_null(p) ? 0 : strlen((p)->ptr))
#define strobj_is_null(p) ((p)->ptr == NULL)
#define strobj_is_static(p) ((p)->size == 0)
/* Move value bewtween two numeric registers
Format: mhop_movn dest src */
mhop_movn,
struct mh_machine
/* Move value bewtween two string registers
Format: mhop_movs dest src */
mhop_movs,
/* Load component value into a string register
Format: mhop_load reg string */
mhop_ldcomp,
/* Load first width bytes of message body contents into a string register.
Format: mhop_body reg */
mhop_ldbody,
/* Call a function.
Format: mhop_call function-pointer */
mhop_call,
/* Convert string register to number reg
Format: mhop_atoi reg
*/
mhop_atoi,
/* Convert numeric register to string
Format: mhop_itoa reg */
mhop_itoa,
/* Print num reg */
mhop_printn,
/* Print str reg */
mhop_prints,
/* Set format specification.
Format: mhop_fmtspec number */
mhop_fmtspec,
};
enum regid { R_REG, R_ARG };
enum mh_type
{
mhtype_none,
mhtype_num,
mhtype_str
};
typedef enum mh_opcode mh_opcode_t;
struct mh_machine;
typedef void (*mh_builtin_fp) (struct mh_machine *);
typedef union {
mh_opcode_t opcode;
mh_builtin_fp builtin;
long num;
void *ptr;
char str[1]; /* Any number of characters follows */
} mh_instr_t;
#define MHI_OPCODE(m) (m).opcode
#define MHI_BUILTIN(m) (m).builtin
#define MHI_NUM(m) (m).num
#define MHI_PTR(m) (m).ptr
#define MHI_STR(m) (m).str
struct mh_format
{
size_t progmax; /* Size of allocated program*/
size_t progcnt; /* Actual number of elements used */
mh_instr_t *prog; /* Program itself */
struct node *tree;
mu_opool_t pool;
};
#define MHA_REQUIRED 0
#define MHA_OPTARG 1
#define MHA_OPT_CLEAR 2
#define MHA_VOID 3
typedef struct mh_builtin mh_builtin_t;
struct mh_builtin
{
strobj_t reg_str; /* String register */
int reg_num; /* Numeric register */
char *name;
mh_builtin_fp fun;
enum mh_type type;
enum mh_type argtype;
int optarg;
};
strobj_t arg_str; /* String argument */
long arg_num; /* Numeric argument */
struct mh_string
{
size_t size;
char *ptr;
};
struct mh_machine
{
long num[2]; /* numeric registers */
struct mh_string str[2]; /* string registers */
size_t pc; /* Program counter */
size_t progsize; /* Size of allocated program*/
size_t progcnt; /* Size of allocated program*/
mh_instr_t *prog; /* Program itself */
int stop; /* Stop execution immediately */
mu_opool_t pool; /* Output buffer */
size_t width; /* Output buffer width */
size_t ind; /* Output buffer index */
size_t width; /* Output line width */
size_t ind; /* Output line index */
mu_stream_t output; /* Output stream */
mu_list_t addrlist; /* The list of email addresses output this far */
int fmtflags; /* Current formatting flags */
......@@ -51,9 +163,5 @@ struct mh_machine
size_t msgno; /* Its number */
};
void strobj_free (strobj_t *obj);
void strobj_create (strobj_t *lvalue, const char *str);
void strobj_set (strobj_t *lvalue, char *str);
void strobj_assign (strobj_t *lvalue, strobj_t *rvalue);
void strobj_copy (strobj_t *lvalue, strobj_t *rvalue);
void strobj_realloc (strobj_t *obj, size_t length);
mh_builtin_t *mh_lookup_builtin (char *name, size_t len);
void mh_print_fmtspec (int fmtspec);
......
......@@ -913,7 +913,7 @@ mh_charset (const char *dfl)
}
int
mh_decode_2047 (char *text, char **decoded_text)
mh_decode_2047 (char const *text, char **decoded_text)
{
const char *charset = mh_charset (NULL);
if (!charset)
......
......@@ -46,7 +46,7 @@ enum mhl_datatype
typedef union mhl_value {
char *str;
int num;
mh_format_t *fmt;
mh_format_t fmt;
} mhl_value_t;
typedef struct mhl_variable
......@@ -151,7 +151,6 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str)
{
size_t i;
struct mu_wordsplit ws;
mh_format_t fmt;
int wsflags;
if (strncmp (str, "ignores=", 8) == 0 && str[8] != '"')
......@@ -219,15 +218,14 @@ parse_variable (locus_t *loc, mu_list_t formlist, char *str)
break;
case dt_format:
if (mh_format_parse (value, &fmt))
if (mh_format_parse (&stmt->v.variable.value.fmt, value,
MH_FMT_PARSE_DEFAULT))
{
mu_error (_("%s:%d: bad format string"),
loc->filename,
loc->line);
exit (1);
}
stmt->v.variable.value.fmt = mu_alloc (sizeof (mh_format_t));
*stmt->v.variable.value.fmt = fmt;
break;
case dt_flag:
......@@ -456,7 +454,7 @@ struct eval_env
int ivar[I_MAX];
int bvar[B_MAX];
char *svar[S_MAX];
mh_format_t *fvar[F_MAX];
mh_format_t fvar[F_MAX];
char *prefix;
};
......