diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-05-31 11:37:22 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-05-31 12:15:30 +0300 |
commit | a79ec559859084cfe8a357bf9076d472fefbeeee (patch) | |
tree | 22e2a8b8b9002c7570651e2048bdf1ec118410db | |
parent | d2952d1c8f6ca4edc65e3c61a47c7a7154f5353b (diff) | |
download | mailutils-a79ec559859084cfe8a357bf9076d472fefbeeee.tar.gz mailutils-a79ec559859084cfe8a357bf9076d472fefbeeee.tar.bz2 |
Improve mimeview
Old short option '-t' renamed to '-f' for consistency (-f stands for
--file in most other utilities). Thus, 'mimevief -f my.types' reads
the file 'my.types'.
The '-t' option is reused as a short equivalent of the new
'--lint' option, which instructs the tool to check the syntax of the
mime.types file and exit, ignoring any surplus command line arguments.
Added support for priority and regex functions.
Improved debugging output.
* mimeview/mimetypes.l: Rewrite lexer in a cleaner way.
* mimeview/mimetypes.y: Rewrite parser. Track locations. Add line
information to nodes and rules. Improve debugging
* mimeview/mimeview.c: Remove the debug configuration statement. Using
debug { level } provides the same functionality. Use mu_debug for debugging.
New option -t (--lint). Rename the -t short option to -f.
* mimeview/mimeview.h: Define lexer and parser macros for location tracking.
* NEWS: Document changes to mimeview utility.
* doc/texinfo/programs.texi: Document changes to mimeview utility.
* lib/mailcap.c: Use standart mu_debug calls for debugging.
* lib/mailcap.h (display_stream_mailcap): Change last argument: take a
mu_debug_handle_t
* libmailutils/diag/debcat (app): New category. Application-specific
debug
* mail/decode.c (display_submessage): Change invocation of
display_stream_mailcap.
* mail/mailvar.c: Setting "verbose" enables app.trace7, unsetting it
clears app.*
-rw-r--r-- | NEWS | 15 | ||||
-rw-r--r-- | doc/texinfo/programs.texi | 30 | ||||
-rw-r--r-- | lib/mailcap.c | 28 | ||||
-rw-r--r-- | lib/mailcap.h | 2 | ||||
-rw-r--r-- | libmailutils/diag/debcat | 1 | ||||
-rw-r--r-- | mail/decode.c | 7 | ||||
-rw-r--r-- | mail/mailvar.c | 20 | ||||
-rw-r--r-- | mimeview/mimetypes.l | 203 | ||||
-rw-r--r-- | mimeview/mimetypes.y | 325 | ||||
-rw-r--r-- | mimeview/mimeview.c | 92 | ||||
-rw-r--r-- | mimeview/mimeview.h | 43 | ||||
-rw-r--r-- | po/.gitignore | 1 |
12 files changed, 532 insertions, 235 deletions
@@ -1,4 +1,4 @@ -GNU mailutils NEWS -- history of user-visible changes. 2017-04-19 +GNU mailutils NEWS -- history of user-visible changes. 2017-05-31 Copyright (C) 2002-2017 Free Software Foundation, Inc. See the end of file for copying conditions. @@ -136,6 +136,19 @@ the implementation in Scheme. The decision has therefore been taken to discontinue the latter and to concentrate all efforts on the further development of the former. +* mimeview + +Old short option '-t' renamed to '-f' for consistency. +Thus, 'mimevief -f my.types' reads the file 'my.types'. + +New option '--lint' (short '-t') instructs the tool to check the +syntax of the mime.types file and exit, ignoring any surplus command +line arguments. + +Added support for priority and regex functions. + +Debugging considerably improved. + Version 3.2 - 2017-03-11 diff --git a/doc/texinfo/programs.texi b/doc/texinfo/programs.texi index 542945a92..954f782a3 100644 --- a/doc/texinfo/programs.texi +++ b/doc/texinfo/programs.texi @@ -7309,22 +7309,28 @@ Enables debugging of @file{mime.types} parser Enables debugging of @file{mime.types} lexical analyzer (warning: produces @emph{very} copious output) -@item 1 +@item 0 Prints basic information about actions to be executed and reports about exit status of executed commands. -@item 2 +@item 1 Additionally displays each file name along with its MIME type -@item 3 +@item 2 Additionally traces the process of looking up the matching entry in @code{mailcap} files. -@item digits from 4 to 9 -The same as 3, currently. +@item 3 +Additionally, enables debugging of @file{mime.types} parser (@samp{g}). + +@item 4 +Additionally, enables debugging of @file{mime.types} lexer (@samp{l}). + +@item digits from 5 to 9 +The same as 4, currently. @end table -If @var{flags} are not given, the default @samp{9} is assumed. +If @var{flags} are not given, the default @samp{2} is assumed. @item --metamail[=@var{file}] Run @command{metamail} to display files, instead of using the internal @@ -7358,10 +7364,15 @@ a @asis{tty} device. Do not do anything, just print what would be done. Implies @option{--debug=1}, unless the debugging level is set up explicitly. -@item -t @var{file} +@item -f @var{file} @itemx --mimetypes @var{file} Use @var{file} as @file{mime.types} file. If @var{file} is a directory, use @file{@var{file}/mime.types} + +@item -t +@itemx --lint +Check syntax of the @file{mime.types} file and exit. Command line +arguments are ignored. @end table @node Mimeview Config @@ -7375,11 +7386,6 @@ The following configuration statements affect the behavior of @item debug @tab @xref{Debug Statement}. @end multitable -@deffn {Mimeview Config} debug @var{number} -Set @command{mimeview} debug level. @xref{Mimeview Invocation, ---debug}, for a description of debug levels. -@end deffn - @deffn {Mimeview Config} mimetypes @var{file} Read @var{file} instead of the default @file{mime.types}. @end deffn diff --git a/lib/mailcap.c b/lib/mailcap.c index 00e8bf0b2..073cdfd80 100644 --- a/lib/mailcap.c +++ b/lib/mailcap.c @@ -51,16 +51,14 @@ struct mime_context int unlink_temp_file; mu_list_t no_ask_types; - int debug_level; + int dh; int flags; }; -#define DEBUG(c,l,f) if ((c)->debug_level > (l)) printf f - static int mime_context_fill (struct mime_context *ctx, const char *file, mu_stream_t input, mu_header_t hdr, const char *no_ask, - int interactive, int dry_run, int debug_level) + int interactive, int dry_run, mu_debug_handle_t dh) { struct mu_wordsplit ws; size_t i; @@ -91,7 +89,7 @@ mime_context_fill (struct mime_context *ctx, const char *file, ctx->flags |= FLAGS_INTERACTIVE; if (dry_run) ctx->flags |= FLAGS_DRY_RUN; - ctx->debug_level = debug_level; + ctx->dh = dh; mu_list_create (&ctx->values); @@ -339,7 +337,7 @@ confirm_action (struct mime_context *ctx, const char *str) char *type; mime_context_get_content_type (ctx, &type); - if (dry_run_p (ctx) || !interactive_p (ctx) || mime_context_do_not_ask (ctx)) + if (!interactive_p (ctx) || mime_context_do_not_ask (ctx)) return 1; printf (_("Run `%s'?"), str); @@ -540,7 +538,7 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx) int outfd = -1; pid_t pid; - if (ctx->debug_level > 1) + if (mu_debug_level_p (ctx->dh, MU_DEBUG_TRACE3)) dump_mailcap_entry (entry); if (run_test (entry, ctx)) @@ -571,11 +569,13 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx) pfd = NULL; else pfd = &fd; - DEBUG (ctx, 0, (_("Executing %s...\n"), view_command)); + mu_debug (ctx->dh, MU_DEBUG_TRACE0, (_("executing %s...\n"), view_command)); if (!confirm_action (ctx, view_command)) return 1; - + if (dry_run_p (ctx)) + return 0; + flag = 0; if (interactive_p (ctx) && mu_mailcap_entry_copiousoutput (entry, &flag) == 0 && flag) @@ -596,7 +596,7 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx) mu_error ("waitpid: %s", mu_strerror (errno)); break; } - if (ctx->debug_level) + if (mu_debug_level_p (ctx->dh, MU_DEBUG_TRACE0)) print_exit_status (status); } return 0; @@ -610,7 +610,7 @@ find_entry (const char *file, struct mime_context *ctx) mu_stream_t stream; int rc = 1; - DEBUG (ctx, 2, (_("Trying %s...\n"), file)); + mu_debug (ctx->dh, MU_DEBUG_TRACE1, (_("trying %s...\n"), file)); status = mu_file_stream_create (&stream, file, MU_STREAM_READ); if (status) { @@ -643,7 +643,7 @@ find_entry (const char *file, struct mime_context *ctx) if (fnmatch (buffer, type, FNM_CASEFOLD) == 0) { - DEBUG (ctx, 2, (_("Found in %s\n"), file)); + mu_debug (ctx->dh, MU_DEBUG_TRACE1, (_("found in %s\n"), file)); if (run_mailcap (entry, ctx) == 0) { rc = 0; @@ -664,7 +664,7 @@ find_entry (const char *file, struct mime_context *ctx) int display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, const char *no_ask, int interactive, int dry_run, - int debug_level) + mu_debug_handle_t dh) { char *mailcap_path, *mailcap_path_tmp = NULL; struct mu_wordsplit ws; @@ -672,7 +672,7 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, int rc = 1; if (mime_context_fill (&ctx, ident, stream, hdr, - no_ask, interactive, dry_run, debug_level)) + no_ask, interactive, dry_run, dh)) return 1; mailcap_path = getenv ("MAILCAP"); if (!mailcap_path) diff --git a/lib/mailcap.h b/lib/mailcap.h index 3b5c57b46..da7f1f9d5 100644 --- a/lib/mailcap.h +++ b/lib/mailcap.h @@ -1,5 +1,5 @@ extern int display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, const char *no_ask, int interactive, int dry_run, - int debug_level); + mu_debug_handle_t dh); diff --git a/libmailutils/diag/debcat b/libmailutils/diag/debcat index 4b401bc7e..11c03d0d3 100644 --- a/libmailutils/diag/debcat +++ b/libmailutils/diag/debcat @@ -42,3 +42,4 @@ assoc acl server tls +app diff --git a/mail/decode.c b/mail/decode.c index 9e09f235e..f73661467 100644 --- a/mail/decode.c +++ b/mail/decode.c @@ -284,14 +284,11 @@ display_submessage (struct mime_descend_closure *closure, void *data) if (mailvar_is_true ("metamail")) { char *no_ask = NULL; - int debug = 0; mailvar_get (&no_ask, "mimenoask", mailvar_type_string, 0); - if (mailvar_is_true ("verbose")) - debug = 9; - builtin_display = display_stream_mailcap (NULL, stream, hdr, no_ask, - interactive, 0, debug); + interactive, 0, + MU_DEBCAT_APP); } if (builtin_display) diff --git a/mail/mailvar.c b/mail/mailvar.c index 78438567a..4ebc41d5f 100644 --- a/mail/mailvar.c +++ b/mail/mailvar.c @@ -44,6 +44,8 @@ static int set_replyregex (enum mailvar_cmd cmd, struct mailvar_variable *); static int set_screen (enum mailvar_cmd cmd, struct mailvar_variable *); +static int set_verbose (enum mailvar_cmd cmd, + struct mailvar_variable *); static int set_debug (enum mailvar_cmd cmd, struct mailvar_variable *); static int set_folder (enum mailvar_cmd cmd, @@ -272,7 +274,8 @@ struct mailvar_symbol mailvar_tab[] = { { "varstrict", }, MAILVAR_ALIAS }, { { "verbose", }, MAILVAR_TYPEMASK (mailvar_type_boolean), - N_("verbosely trace the process of message delivery") }, + N_("verbosely trace the process of message delivery"), + set_verbose }, { { "xmailer", }, MAILVAR_TYPEMASK (mailvar_type_boolean), N_("add the `X-Mailer' header to the outgoing messages") }, @@ -666,6 +669,21 @@ set_screen (enum mailvar_cmd cmd, struct mailvar_variable *var) #define DEFAULT_DEBUG_LEVEL MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE7) static int +set_verbose (enum mailvar_cmd cmd, struct mailvar_variable *var) +{ + switch (cmd) + { + case mailvar_cmd_set: + mu_debug_set_category_level (MU_DEBCAT_APP, DEFAULT_DEBUG_LEVEL); + break; + + case mailvar_cmd_unset: + mu_debug_set_category_level (MU_DEBCAT_APP, 0); + } + return 0; +} + +static int set_debug (enum mailvar_cmd cmd, struct mailvar_variable *var) { mu_debug_clear_all (); diff --git a/mimeview/mimetypes.l b/mimeview/mimetypes.l index 996768c2a..6e74163b7 100644 --- a/mimeview/mimetypes.l +++ b/mimeview/mimetypes.l @@ -28,13 +28,11 @@ #include <mimeview.h> #include <mimetypes-decl.h> #include <mailutils/io.h> - -static int line_num; -static char *file_name; -static int file_name_alloc; +static struct mu_locus loc; +static int newline; + static mu_opool_t pool; -static int prev_state; static unsigned digit_to_number (char c) @@ -43,106 +41,121 @@ digit_to_number (char c) c >= 'A' && c <= 'Z' ? c-'A'+10 : c-'a'+10); } + +static void +advance_locus (void) +{ + if (newline) + { + loc.mu_line++; + loc.mu_col = 1; + } + yylloc.beg = loc; + loc.mu_col += yyleng; + yylloc.end = loc; + yylloc.end.mu_col--; + + newline = yytext[yyleng-1] == '\n'; + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS, &loc); +} + +#define YY_USER_ACTION advance_locus (); + %} %option nounput %option noinput -%x ARGS HEX +%s RULE ARGS X [0-9a-fA-F] IDENT [a-zA-Z_\.][a-zA-Z0-9_\.-]* WS [ \t]* %% /* Comments */ -<INITIAL>#.*\n { line_num++; } -<INITIAL>#.* /* end-of-file comment */; +^#.*\n ; /* Tokens */ -\\\n { line_num++; } -\n { line_num++; return EOL; } +\\\n ; +\n+ { loc.mu_line += yyleng - 1; return EOL; } {WS} ; -{IDENT} { +<INITIAL,RULE>^[^ \t\n/]+"/"[^ \t\n]+ { mu_opool_append (pool, yytext, yyleng); mu_opool_append_char (pool, 0); yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); - return IDENT; + BEGIN (RULE); + return TYPE; +} + +<RULE>"priority"/"(" { + return PRIORITY; } -<INITIAL>{IDENT}"(" { - mu_opool_append (pool, yytext, yyleng-1); +<RULE>{IDENT}/"(" { + mu_opool_append (pool, yytext, yyleng); mu_opool_append_char (pool, 0); yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); - BEGIN(ARGS); - return IDENT_L; + return IDENT; } -<INITIAL,ARGS>\"[^\\"\n]*\" { - mu_opool_append (pool, yytext+1, yyleng-2); +<RULE>{IDENT} { + mu_opool_append (pool, yytext, yyleng); mu_opool_append_char (pool, 0); yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); return STRING; } -<INITIAL,ARGS>"<" { - prev_state = YYSTATE; - BEGIN(HEX); -} -<ARGS>[^ \t<\\\n),]+/[),] { - mu_opool_append (pool, yytext, yyleng); +<RULE,ARGS>\"[^"\n]*\" { + mu_opool_append (pool, yytext+1, yyleng-2); mu_opool_append_char (pool, 0); yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); return STRING; } -<ARGS>[^ \t<\\\n),]+< { - mu_opool_append (pool, yytext, yyleng); - prev_state = YYSTATE; - BEGIN(HEX); +<RULE,ARGS>"<"({X}{X})+">" { + int i; + for (i = 0; i < yyleng; i += 2) + { + mu_opool_append_char (pool, digit_to_number (yytext[i])*16 + + digit_to_number (yytext[i+1])); + } + yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); + return STRING; } -<INITIAL>[^ \t<\\\n)+,&]/[ \t\\\n)+,&] { +<ARGS>[^ \t<\n),<"]+/[),<"] { mu_opool_append (pool, yytext, yyleng); mu_opool_append_char (pool, 0); yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); return STRING; } -<ARGS>[^ \t<\\\n),]/[ \t\\\n] { +<RULE>[^ \t<\\\n)+,&]/[ \t\\\n)+,&] { mu_opool_append (pool, yytext, yyleng); mu_opool_append_char (pool, 0); yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); return STRING; } -<HEX>{X}{X} { - int c = digit_to_number (yytext[0])*16 + digit_to_number (yytext[1]); - mu_opool_append_char (pool, c); -} -<HEX>">"/[ \t\\\n,)] { - BEGIN(prev_state); +<ARGS>[^ \t<\\\n),]/[ \t\\\n] { + mu_opool_append (pool, yytext, yyleng); mu_opool_append_char (pool, 0); yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); return STRING; } -<HEX>">" { - BEGIN(prev_state); -} /* Special cases: && and ||. Docs don't say anything about them, but I've found them in my mime.types file... --Sergey */ "&&" return '+'; "||" return ','; /* Operators */ -"!"|"+"|","|"("|")"|"/" return yytext[0]; +<RULE>"!"|"+"|","|"("|")"|"/" return yytext[0]; <ARGS>"," return yytext[0]; -<ARGS>")" { BEGIN(INITIAL); return yytext[0]; } -<INITIAL,ARGS,HEX>. { - fprintf (stderr, "Invalid character '%c', state %d\n", yytext[0], YYSTATE); - abort(); +<ARGS>")" { BEGIN (RULE); return yytext[0]; } +<*>. { + mu_error ("invalid character '%c', state %d", yytext[0], YYSTATE); + return BOGUS; } %% - -void -mimetypes_lex_debug (int level) -{ - yy_flex_debug = level; -} - int mimetypes_open (const char *name) { struct stat st; + int mode; + + yy_flex_debug = mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE4); + if (stat (name, &st)) { mu_error (_("cannot stat `%s': %s"), name, mu_strerror (errno)); @@ -150,28 +163,29 @@ mimetypes_open (const char *name) } if (S_ISDIR (st.st_mode)) - { - file_name = mu_make_file_name (name, "mime.types"); - file_name_alloc = 1; - } + loc.mu_file = mu_make_file_name (name, "mime.types"); else - { - file_name = (char*) name; - file_name_alloc = 0; - } - - yyin = fopen (file_name, "r"); + loc.mu_file = mu_strdup (name); + loc.mu_line = 1; + loc.mu_col = 1; + newline = 0; + + yyin = fopen (loc.mu_file, "r"); if (!yyin) { - mu_error (_("Cannot open `%s': %s"), file_name, mu_strerror (errno)); - if (file_name_alloc) - { - free (file_name); - file_name_alloc = 0; - } + mu_error (_("cannot open `%s': %s"), loc.mu_file, mu_strerror (errno)); + free (loc.mu_file); return -1; } - line_num = 1; + + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_GET_MODE, &mode); + mode |= MU_LOGMODE_LOCUS; + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS, &loc); + mu_opool_create (&pool, MU_OPOOL_ENOMEMABRT); return 0; } @@ -179,18 +193,25 @@ mimetypes_open (const char *name) void mimetypes_close () { + int mode; + fclose (yyin); - if (file_name_alloc) - { - free (file_name); - file_name_alloc = 0; - } + /* FIXME: Don't free (loc.mu_file), because it is referenced by + mu_locus structures in the parse tree */ + + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_GET_MODE, &mode); + mode &= ~MU_LOGMODE_LOCUS; + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_MODE, &mode); + mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, + MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL); } int yyerror (char *s) { - mu_error ("%s:%d: %s", file_name, line_num, s); + mu_error (s); return 0; } @@ -200,22 +221,6 @@ yywrap () return 1; } -struct mimetypes_string -mimetypes_append_string2 (struct mimetypes_string *s1, - char c, - struct mimetypes_string *s2) -{ - struct mimetypes_string r; - - r.len = s1->len + s2->len + 1; - mu_opool_append (pool, s1->ptr, s1->len); - mu_opool_append_char (pool, c); - mu_opool_append (pool, s2->ptr, s2->len); - mu_opool_append_char (pool, 0); - r.ptr = mu_opool_finish (pool, NULL); - return r; -} - struct mimetypes_string * mimetypes_string_dup (struct mimetypes_string *s) { @@ -231,9 +236,21 @@ mimetypes_malloc (size_t size) } void -reset_lex () +lex_arglist (int enable) { - BEGIN(INITIAL); + if (enable) + BEGIN (ARGS); + else + BEGIN (RULE); } - +void +lex_concat (struct concat_segm *p, struct mimetypes_string *ret) +{ + for (; p; p = p->next) + { + mu_opool_appendz (pool, p->val); + } + mu_opool_append_char (pool, 0); + ret->ptr = mu_opool_finish (pool, &ret->len); +} diff --git a/mimeview/mimetypes.y b/mimeview/mimetypes.y index 9e33716f6..dffb827b2 100644 --- a/mimeview/mimetypes.y +++ b/mimeview/mimetypes.y @@ -23,6 +23,7 @@ #include <mailutils/cctype.h> #include <mimeview.h> #include <mimetypes-decl.h> +#include <regex.h> static void yyprint (FILE *output, unsigned short toknum, YYSTYPE val) @@ -30,14 +31,20 @@ yyprint (FILE *output, unsigned short toknum, YYSTYPE val) switch (toknum) { case IDENT: - case IDENT_L: case STRING: fprintf (output, "[%lu] %s", (unsigned long) val.string.len, val.string.ptr); break; case EOL: + fprintf (output, "\\n"); + break; + default: + if (mu_isprint (toknum)) + fprintf (output, "'%c'", toknum); + else + fprintf (output, "tok(%d)", toknum); break; } } @@ -51,6 +58,7 @@ static mu_list_t arg_list; /* For error recovery */ enum node_type { + true_node, functional_node, binary_node, negation_node, @@ -62,6 +70,7 @@ union argument struct mimetypes_string *string; unsigned number; int c; + regex_t rx; }; typedef int (*builtin_t) (union argument *args); @@ -69,6 +78,7 @@ typedef int (*builtin_t) (union argument *args); struct node { enum node_type type; + struct mu_locus_range loc; union { struct @@ -87,41 +97,56 @@ struct node } v; }; +static struct node *make_node (enum node_type type, + struct mu_locus_range const *loc); static struct node *make_binary_node (int op, - struct node *left, struct node *rigth); -static struct node *make_negation_node (struct node *p); + struct node *left, struct node *rigth, + struct mu_locus_range const *loc); +static struct node *make_negation_node (struct node *p, + struct mu_locus_range const *loc); -static struct node *make_suffix_node (struct mimetypes_string *suffix); -static struct node *make_functional_node (char *ident, mu_list_t list); +static struct node *make_suffix_node (struct mimetypes_string *suffix, + struct mu_locus_range const *loc); +static struct node *make_functional_node (char *ident, mu_list_t list, + struct mu_locus_range const *loc); static int eval_rule (struct node *root); struct rule_tab { char *type; + int priority; + struct mu_locus_range loc; struct node *node; }; static mu_list_t rule_list; - %} -%token <string> IDENT IDENT_L +%locations + +%token <string> TYPE IDENT %token <string> STRING -%token EOL BOGUS +%token EOL BOGUS PRIORITY %left ',' %left '+' -%type <string> string arg type +%type <string> string arg %type <list> arglist -%type <node> function stmt rule +%type <node> function stmt rule maybe_rule +%type <result> priority maybe_priority +%type <concat> concat; +%type <segment> simple_string %union { struct mimetypes_string string; + char *s; mu_list_t list; int result; struct node *node; + struct { struct concat_segm *head, *tail; } concat; + struct concat_segm *segment; } %% @@ -130,56 +155,65 @@ input : list ; list : rule_line - | list eol rule_line + | list EOL rule_line ; rule_line: /* empty */ - | type rule + | TYPE maybe_rule maybe_priority { struct rule_tab *p = mimetypes_malloc (sizeof (*p)); if (!rule_list) mu_list_create (&rule_list); p->type = $1.ptr; p->node = $2; + p->priority = $3; + p->loc.beg = @1.beg; + p->loc.end = @3.end; mu_list_append (rule_list, p); } - | error eol + | error EOL { if (arg_list) mu_list_destroy (&arg_list); arg_list = NULL; - reset_lex (); + lex_arglist (0); } ; -eol : EOL - | eol EOL - ; - -type : IDENT '/' IDENT +maybe_rule: /* empty */ { - $$ = mimetypes_append_string2 (&$1, '/', &$3); + $$ = make_node (true_node, &yylloc); } - ; + | rule + ; rule : stmt | rule rule %prec ',' { - $$ = make_binary_node (L_OR, $1, $2); + struct mu_locus_range lr; + lr.beg = @1.beg; + lr.end = @2.end; + $$ = make_binary_node (L_OR, $1, $2, &lr); } | rule ',' rule { - $$ = make_binary_node (L_OR, $1, $3); + struct mu_locus_range lr; + lr.beg = @1.beg; + lr.end = @3.end; + $$ = make_binary_node (L_OR, $1, $3, &lr); } | rule '+' rule { - $$ = make_binary_node (L_AND, $1, $3); + struct mu_locus_range lr; + lr.beg = @1.beg; + lr.end = @3.end; + $$ = make_binary_node (L_AND, $1, $3, &lr); } ; stmt : '!' stmt { - $$ = make_negation_node ($2); + $$ = make_negation_node ($2, &@2); } | '(' rule ')' { @@ -187,19 +221,79 @@ stmt : '!' stmt } | string { - $$ = make_suffix_node (&$1); + $$ = make_suffix_node (&$1, &@1); } | function ; -string : STRING - | IDENT +string : concat + { + lex_concat ($1.head, &$$); + } + ; + +concat : simple_string + { + $$.head = $$.tail = $1; + } + | concat simple_string + { + $$.tail->next = $2; + $$.tail = $2; + } + ; + +simple_string : STRING + { + $$ = mu_alloc (sizeof $$); + $$->next = NULL; + $$->val = $1.ptr; + } + ; + +priority : PRIORITY oparen arglist cparen + { + size_t count = 0; + struct mimetypes_string *arg; + + mu_list_count ($3, &count); + if (count != 1) + { + yyerror (_("priority takes single numberic argument")); + YYERROR; + } + mu_list_head ($3, (void**) &arg); + $$ = atoi (arg->ptr); + mu_list_destroy (&$3); + } + ; + +maybe_priority: /* empty */ + { + $$ = 100; + } + | priority + ; + +oparen : '(' + { + lex_arglist (1); + } + ; + +cparen : ')' + { + lex_arglist (0); + } ; -function : IDENT_L arglist ')' +function : IDENT oparen arglist cparen { - reset_lex (); - $$ = make_functional_node ($1.ptr, $2); + struct mu_locus_range lr; + lr.beg = @1.beg; + lr.end = @4.end; + + $$ = make_functional_node ($1.ptr, $3, &lr); if (!$$) YYERROR; } @@ -229,30 +323,26 @@ mimetypes_parse (const char *name) int rc; if (mimetypes_open (name)) return 1; + yydebug = mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE3); rc = yyparse (); mimetypes_close (); return rc || rule_list == NULL; } - -void -mimetypes_gram_debug (int level) -{ - yydebug = level; -} - static struct node * -make_node (enum node_type type) +make_node (enum node_type type, struct mu_locus_range const *loc) { struct node *p = mimetypes_malloc (sizeof *p); p->type = type; + p->loc = *loc; return p; } static struct node * -make_binary_node (int op, struct node *left, struct node *right) +make_binary_node (int op, struct node *left, struct node *right, + struct mu_locus_range const *loc) { - struct node *node = make_node (binary_node); + struct node *node = make_node (binary_node, loc); node->v.bin.op = op; node->v.bin.arg1 = left; @@ -261,17 +351,18 @@ make_binary_node (int op, struct node *left, struct node *right) } struct node * -make_negation_node (struct node *p) +make_negation_node (struct node *p, struct mu_locus_range const *loc) { - struct node *node = make_node (negation_node); + struct node *node = make_node (negation_node, loc); node->v.arg = p; return node; } struct node * -make_suffix_node (struct mimetypes_string *suffix) +make_suffix_node (struct mimetypes_string *suffix, + struct mu_locus_range const *loc) { - struct node *node = make_node (suffix_node); + struct node *node = make_node (suffix_node, loc); node->v.suffix = *suffix; return node; } @@ -508,7 +599,7 @@ b_contains (union argument *args) buf = mu_alloc (args[1].number); rc = mu_stream_read (mimeview_stream, buf, args[1].number, &count); - if (count != args[1].number) + if (rc) { mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc); } @@ -523,10 +614,41 @@ b_contains (union argument *args) return 0; } +#define MIME_MAX_BUFFER 4096 + +/* regex(offset,"regex") True if bytes match regular expression + */ +static int +b_regex (union argument *args) +{ + size_t count; + int rc; + char buf[MIME_MAX_BUFFER]; + + rc = mu_stream_seek (mimeview_stream, args[0].number, MU_SEEK_SET, NULL); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc); + return 0; + } + + rc = mu_stream_read (mimeview_stream, buf, sizeof buf - 1, &count); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc); + return 0; + } + buf[count] = 0; + + return regexec (&args[1].rx, buf, 0, NULL, 0) == 0; +} + + static struct builtin_tab builtin_tab[] = { { "match", "s", b_match }, { "ascii", "dd", b_ascii }, { "printable", "dd", b_printable }, + { "regex", "dx", b_regex }, { "string", "ds", b_string }, { "istring", "ds", b_istring }, { "char", "dc", b_char }, @@ -538,13 +660,15 @@ static struct builtin_tab builtin_tab[] = { }; struct node * -make_functional_node (char *ident, mu_list_t list) +make_functional_node (char *ident, mu_list_t list, + struct mu_locus_range const *loc) { size_t count, i; struct builtin_tab *p; struct node *node; union argument *args; mu_iterator_t itr; + int rc; for (p = builtin_tab; ; p++) { @@ -602,6 +726,30 @@ make_functional_node (char *ident, mu_list_t list) case 's': args[i].string = data; break; + + case 'x': + { + char *s; + + rc = mu_c_str_unescape_trans (data->ptr, + "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v", &s); + if (rc) + { + mu_diag_func |