summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2017-05-31 11:37:22 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2017-05-31 12:15:30 +0300
commita79ec559859084cfe8a357bf9076d472fefbeeee (patch)
tree22e2a8b8b9002c7570651e2048bdf1ec118410db
parentd2952d1c8f6ca4edc65e3c61a47c7a7154f5353b (diff)
downloadmailutils-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--NEWS15
-rw-r--r--doc/texinfo/programs.texi30
-rw-r--r--lib/mailcap.c28
-rw-r--r--lib/mailcap.h2
-rw-r--r--libmailutils/diag/debcat1
-rw-r--r--mail/decode.c7
-rw-r--r--mail/mailvar.c20
-rw-r--r--mimeview/mimetypes.l203
-rw-r--r--mimeview/mimetypes.y325
-rw-r--r--mimeview/mimeview.c92
-rw-r--r--mimeview/mimeview.h43
-rw-r--r--po/.gitignore1
12 files changed, 532 insertions, 235 deletions
diff --git a/NEWS b/NEWS
index ca1f74315..a108d094f 100644
--- a/NEWS
+++ b/NEWS
@@ -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