Commit a79ec559 a79ec559859084cfe8a357bf9076d472fefbeeee by Sergey Poznyakoff

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.*
1 parent d2952d1c
1 GNU mailutils NEWS -- history of user-visible changes. 2017-04-19 1 GNU mailutils NEWS -- history of user-visible changes. 2017-05-31
2 Copyright (C) 2002-2017 Free Software Foundation, Inc. 2 Copyright (C) 2002-2017 Free Software Foundation, Inc.
3 See the end of file for copying conditions. 3 See the end of file for copying conditions.
4 4
...@@ -136,6 +136,19 @@ the implementation in Scheme. The decision has therefore been taken to ...@@ -136,6 +136,19 @@ the implementation in Scheme. The decision has therefore been taken to
136 discontinue the latter and to concentrate all efforts on the further 136 discontinue the latter and to concentrate all efforts on the further
137 development of the former. 137 development of the former.
138 138
139 * mimeview
140
141 Old short option '-t' renamed to '-f' for consistency.
142 Thus, 'mimevief -f my.types' reads the file 'my.types'.
143
144 New option '--lint' (short '-t') instructs the tool to check the
145 syntax of the mime.types file and exit, ignoring any surplus command
146 line arguments.
147
148 Added support for priority and regex functions.
149
150 Debugging considerably improved.
151
139 152
140 Version 3.2 - 2017-03-11 153 Version 3.2 - 2017-03-11
141 154
......
...@@ -7309,22 +7309,28 @@ Enables debugging of @file{mime.types} parser ...@@ -7309,22 +7309,28 @@ Enables debugging of @file{mime.types} parser
7309 Enables debugging of @file{mime.types} lexical analyzer (warning: 7309 Enables debugging of @file{mime.types} lexical analyzer (warning:
7310 produces @emph{very} copious output) 7310 produces @emph{very} copious output)
7311 7311
7312 @item 1 7312 @item 0
7313 Prints basic information about actions to be executed and reports 7313 Prints basic information about actions to be executed and reports
7314 about exit status of executed commands. 7314 about exit status of executed commands.
7315 7315
7316 @item 2 7316 @item 1
7317 Additionally displays each file name along with its MIME type 7317 Additionally displays each file name along with its MIME type
7318 7318
7319 @item 3 7319 @item 2
7320 Additionally traces the process of looking up the matching entry 7320 Additionally traces the process of looking up the matching entry
7321 in @code{mailcap} files. 7321 in @code{mailcap} files.
7322 7322
7323 @item digits from 4 to 9 7323 @item 3
7324 The same as 3, currently. 7324 Additionally, enables debugging of @file{mime.types} parser (@samp{g}).
7325
7326 @item 4
7327 Additionally, enables debugging of @file{mime.types} lexer (@samp{l}).
7328
7329 @item digits from 5 to 9
7330 The same as 4, currently.
7325 @end table 7331 @end table
7326 7332
7327 If @var{flags} are not given, the default @samp{9} is assumed. 7333 If @var{flags} are not given, the default @samp{2} is assumed.
7328 7334
7329 @item --metamail[=@var{file}] 7335 @item --metamail[=@var{file}]
7330 Run @command{metamail} to display files, instead of using the internal 7336 Run @command{metamail} to display files, instead of using the internal
...@@ -7358,10 +7364,15 @@ a @asis{tty} device. ...@@ -7358,10 +7364,15 @@ a @asis{tty} device.
7358 Do not do anything, just print what would be done. Implies 7364 Do not do anything, just print what would be done. Implies
7359 @option{--debug=1}, unless the debugging level is set up explicitly. 7365 @option{--debug=1}, unless the debugging level is set up explicitly.
7360 7366
7361 @item -t @var{file} 7367 @item -f @var{file}
7362 @itemx --mimetypes @var{file} 7368 @itemx --mimetypes @var{file}
7363 Use @var{file} as @file{mime.types} file. If @var{file} is a 7369 Use @var{file} as @file{mime.types} file. If @var{file} is a
7364 directory, use @file{@var{file}/mime.types} 7370 directory, use @file{@var{file}/mime.types}
7371
7372 @item -t
7373 @itemx --lint
7374 Check syntax of the @file{mime.types} file and exit. Command line
7375 arguments are ignored.
7365 @end table 7376 @end table
7366 7377
7367 @node Mimeview Config 7378 @node Mimeview Config
...@@ -7375,11 +7386,6 @@ The following configuration statements affect the behavior of ...@@ -7375,11 +7386,6 @@ The following configuration statements affect the behavior of
7375 @item debug @tab @xref{Debug Statement}. 7386 @item debug @tab @xref{Debug Statement}.
7376 @end multitable 7387 @end multitable
7377 7388
7378 @deffn {Mimeview Config} debug @var{number}
7379 Set @command{mimeview} debug level. @xref{Mimeview Invocation,
7380 --debug}, for a description of debug levels.
7381 @end deffn
7382
7383 @deffn {Mimeview Config} mimetypes @var{file} 7389 @deffn {Mimeview Config} mimetypes @var{file}
7384 Read @var{file} instead of the default @file{mime.types}. 7390 Read @var{file} instead of the default @file{mime.types}.
7385 @end deffn 7391 @end deffn
......
...@@ -51,16 +51,14 @@ struct mime_context ...@@ -51,16 +51,14 @@ struct mime_context
51 int unlink_temp_file; 51 int unlink_temp_file;
52 52
53 mu_list_t no_ask_types; 53 mu_list_t no_ask_types;
54 int debug_level; 54 int dh;
55 int flags; 55 int flags;
56 }; 56 };
57 57
58 #define DEBUG(c,l,f) if ((c)->debug_level > (l)) printf f
59
60 static int 58 static int
61 mime_context_fill (struct mime_context *ctx, const char *file, 59 mime_context_fill (struct mime_context *ctx, const char *file,
62 mu_stream_t input, mu_header_t hdr, const char *no_ask, 60 mu_stream_t input, mu_header_t hdr, const char *no_ask,
63 int interactive, int dry_run, int debug_level) 61 int interactive, int dry_run, mu_debug_handle_t dh)
64 { 62 {
65 struct mu_wordsplit ws; 63 struct mu_wordsplit ws;
66 size_t i; 64 size_t i;
...@@ -91,7 +89,7 @@ mime_context_fill (struct mime_context *ctx, const char *file, ...@@ -91,7 +89,7 @@ mime_context_fill (struct mime_context *ctx, const char *file,
91 ctx->flags |= FLAGS_INTERACTIVE; 89 ctx->flags |= FLAGS_INTERACTIVE;
92 if (dry_run) 90 if (dry_run)
93 ctx->flags |= FLAGS_DRY_RUN; 91 ctx->flags |= FLAGS_DRY_RUN;
94 ctx->debug_level = debug_level; 92 ctx->dh = dh;
95 93
96 mu_list_create (&ctx->values); 94 mu_list_create (&ctx->values);
97 95
...@@ -339,7 +337,7 @@ confirm_action (struct mime_context *ctx, const char *str) ...@@ -339,7 +337,7 @@ confirm_action (struct mime_context *ctx, const char *str)
339 char *type; 337 char *type;
340 338
341 mime_context_get_content_type (ctx, &type); 339 mime_context_get_content_type (ctx, &type);
342 if (dry_run_p (ctx) || !interactive_p (ctx) || mime_context_do_not_ask (ctx)) 340 if (!interactive_p (ctx) || mime_context_do_not_ask (ctx))
343 return 1; 341 return 1;
344 342
345 printf (_("Run `%s'?"), str); 343 printf (_("Run `%s'?"), str);
...@@ -540,7 +538,7 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx) ...@@ -540,7 +538,7 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx)
540 int outfd = -1; 538 int outfd = -1;
541 pid_t pid; 539 pid_t pid;
542 540
543 if (ctx->debug_level > 1) 541 if (mu_debug_level_p (ctx->dh, MU_DEBUG_TRACE3))
544 dump_mailcap_entry (entry); 542 dump_mailcap_entry (entry);
545 543
546 if (run_test (entry, ctx)) 544 if (run_test (entry, ctx))
...@@ -571,11 +569,13 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx) ...@@ -571,11 +569,13 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx)
571 pfd = NULL; 569 pfd = NULL;
572 else 570 else
573 pfd = &fd; 571 pfd = &fd;
574 DEBUG (ctx, 0, (_("Executing %s...\n"), view_command)); 572 mu_debug (ctx->dh, MU_DEBUG_TRACE0, (_("executing %s...\n"), view_command));
575 573
576 if (!confirm_action (ctx, view_command)) 574 if (!confirm_action (ctx, view_command))
577 return 1; 575 return 1;
578 576 if (dry_run_p (ctx))
577 return 0;
578
579 flag = 0; 579 flag = 0;
580 if (interactive_p (ctx) 580 if (interactive_p (ctx)
581 && mu_mailcap_entry_copiousoutput (entry, &flag) == 0 && flag) 581 && mu_mailcap_entry_copiousoutput (entry, &flag) == 0 && flag)
...@@ -596,7 +596,7 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx) ...@@ -596,7 +596,7 @@ run_mailcap (mu_mailcap_entry_t entry, struct mime_context *ctx)
596 mu_error ("waitpid: %s", mu_strerror (errno)); 596 mu_error ("waitpid: %s", mu_strerror (errno));
597 break; 597 break;
598 } 598 }
599 if (ctx->debug_level) 599 if (mu_debug_level_p (ctx->dh, MU_DEBUG_TRACE0))
600 print_exit_status (status); 600 print_exit_status (status);
601 } 601 }
602 return 0; 602 return 0;
...@@ -610,7 +610,7 @@ find_entry (const char *file, struct mime_context *ctx) ...@@ -610,7 +610,7 @@ find_entry (const char *file, struct mime_context *ctx)
610 mu_stream_t stream; 610 mu_stream_t stream;
611 int rc = 1; 611 int rc = 1;
612 612
613 DEBUG (ctx, 2, (_("Trying %s...\n"), file)); 613 mu_debug (ctx->dh, MU_DEBUG_TRACE1, (_("trying %s...\n"), file));
614 status = mu_file_stream_create (&stream, file, MU_STREAM_READ); 614 status = mu_file_stream_create (&stream, file, MU_STREAM_READ);
615 if (status) 615 if (status)
616 { 616 {
...@@ -643,7 +643,7 @@ find_entry (const char *file, struct mime_context *ctx) ...@@ -643,7 +643,7 @@ find_entry (const char *file, struct mime_context *ctx)
643 643
644 if (fnmatch (buffer, type, FNM_CASEFOLD) == 0) 644 if (fnmatch (buffer, type, FNM_CASEFOLD) == 0)
645 { 645 {
646 DEBUG (ctx, 2, (_("Found in %s\n"), file)); 646 mu_debug (ctx->dh, MU_DEBUG_TRACE1, (_("found in %s\n"), file));
647 if (run_mailcap (entry, ctx) == 0) 647 if (run_mailcap (entry, ctx) == 0)
648 { 648 {
649 rc = 0; 649 rc = 0;
...@@ -664,7 +664,7 @@ find_entry (const char *file, struct mime_context *ctx) ...@@ -664,7 +664,7 @@ find_entry (const char *file, struct mime_context *ctx)
664 int 664 int
665 display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, 665 display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr,
666 const char *no_ask, int interactive, int dry_run, 666 const char *no_ask, int interactive, int dry_run,
667 int debug_level) 667 mu_debug_handle_t dh)
668 { 668 {
669 char *mailcap_path, *mailcap_path_tmp = NULL; 669 char *mailcap_path, *mailcap_path_tmp = NULL;
670 struct mu_wordsplit ws; 670 struct mu_wordsplit ws;
...@@ -672,7 +672,7 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr, ...@@ -672,7 +672,7 @@ display_stream_mailcap (const char *ident, mu_stream_t stream, mu_header_t hdr,
672 int rc = 1; 672 int rc = 1;
673 673
674 if (mime_context_fill (&ctx, ident, stream, hdr, 674 if (mime_context_fill (&ctx, ident, stream, hdr,
675 no_ask, interactive, dry_run, debug_level)) 675 no_ask, interactive, dry_run, dh))
676 return 1; 676 return 1;
677 mailcap_path = getenv ("MAILCAP"); 677 mailcap_path = getenv ("MAILCAP");
678 if (!mailcap_path) 678 if (!mailcap_path)
......
1 extern int display_stream_mailcap (const char *ident, mu_stream_t stream, 1 extern int display_stream_mailcap (const char *ident, mu_stream_t stream,
2 mu_header_t hdr, const char *no_ask, 2 mu_header_t hdr, const char *no_ask,
3 int interactive, int dry_run, 3 int interactive, int dry_run,
4 int debug_level); 4 mu_debug_handle_t dh);
5 5
......
...@@ -42,3 +42,4 @@ assoc ...@@ -42,3 +42,4 @@ assoc
42 acl 42 acl
43 server 43 server
44 tls 44 tls
45 app
......
...@@ -284,14 +284,11 @@ display_submessage (struct mime_descend_closure *closure, void *data) ...@@ -284,14 +284,11 @@ display_submessage (struct mime_descend_closure *closure, void *data)
284 if (mailvar_is_true ("metamail")) 284 if (mailvar_is_true ("metamail"))
285 { 285 {
286 char *no_ask = NULL; 286 char *no_ask = NULL;
287 int debug = 0;
288 287
289 mailvar_get (&no_ask, "mimenoask", mailvar_type_string, 0); 288 mailvar_get (&no_ask, "mimenoask", mailvar_type_string, 0);
290 if (mailvar_is_true ("verbose"))
291 debug = 9;
292
293 builtin_display = display_stream_mailcap (NULL, stream, hdr, no_ask, 289 builtin_display = display_stream_mailcap (NULL, stream, hdr, no_ask,
294 interactive, 0, debug); 290 interactive, 0,
291 MU_DEBCAT_APP);
295 } 292 }
296 293
297 if (builtin_display) 294 if (builtin_display)
......
...@@ -44,6 +44,8 @@ static int set_replyregex (enum mailvar_cmd cmd, ...@@ -44,6 +44,8 @@ static int set_replyregex (enum mailvar_cmd cmd,
44 struct mailvar_variable *); 44 struct mailvar_variable *);
45 static int set_screen (enum mailvar_cmd cmd, 45 static int set_screen (enum mailvar_cmd cmd,
46 struct mailvar_variable *); 46 struct mailvar_variable *);
47 static int set_verbose (enum mailvar_cmd cmd,
48 struct mailvar_variable *);
47 static int set_debug (enum mailvar_cmd cmd, 49 static int set_debug (enum mailvar_cmd cmd,
48 struct mailvar_variable *); 50 struct mailvar_variable *);
49 static int set_folder (enum mailvar_cmd cmd, 51 static int set_folder (enum mailvar_cmd cmd,
...@@ -272,7 +274,8 @@ struct mailvar_symbol mailvar_tab[] = ...@@ -272,7 +274,8 @@ struct mailvar_symbol mailvar_tab[] =
272 { { "varstrict", }, MAILVAR_ALIAS }, 274 { { "varstrict", }, MAILVAR_ALIAS },
273 { { "verbose", }, 275 { { "verbose", },
274 MAILVAR_TYPEMASK (mailvar_type_boolean), 276 MAILVAR_TYPEMASK (mailvar_type_boolean),
275 N_("verbosely trace the process of message delivery") }, 277 N_("verbosely trace the process of message delivery"),
278 set_verbose },
276 { { "xmailer", }, 279 { { "xmailer", },
277 MAILVAR_TYPEMASK (mailvar_type_boolean), 280 MAILVAR_TYPEMASK (mailvar_type_boolean),
278 N_("add the `X-Mailer' header to the outgoing messages") }, 281 N_("add the `X-Mailer' header to the outgoing messages") },
...@@ -666,6 +669,21 @@ set_screen (enum mailvar_cmd cmd, struct mailvar_variable *var) ...@@ -666,6 +669,21 @@ set_screen (enum mailvar_cmd cmd, struct mailvar_variable *var)
666 #define DEFAULT_DEBUG_LEVEL MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE7) 669 #define DEFAULT_DEBUG_LEVEL MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE7)
667 670
668 static int 671 static int
672 set_verbose (enum mailvar_cmd cmd, struct mailvar_variable *var)
673 {
674 switch (cmd)
675 {
676 case mailvar_cmd_set:
677 mu_debug_set_category_level (MU_DEBCAT_APP, DEFAULT_DEBUG_LEVEL);
678 break;
679
680 case mailvar_cmd_unset:
681 mu_debug_set_category_level (MU_DEBCAT_APP, 0);
682 }
683 return 0;
684 }
685
686 static int
669 set_debug (enum mailvar_cmd cmd, struct mailvar_variable *var) 687 set_debug (enum mailvar_cmd cmd, struct mailvar_variable *var)
670 { 688 {
671 mu_debug_clear_all (); 689 mu_debug_clear_all ();
......
...@@ -28,13 +28,11 @@ ...@@ -28,13 +28,11 @@
28 #include <mimeview.h> 28 #include <mimeview.h>
29 #include <mimetypes-decl.h> 29 #include <mimetypes-decl.h>
30 #include <mailutils/io.h> 30 #include <mailutils/io.h>
31
32 static int line_num;
33 static char *file_name;
34 static int file_name_alloc;
35 31
32 static struct mu_locus loc;
33 static int newline;
34
36 static mu_opool_t pool; 35 static mu_opool_t pool;
37 static int prev_state;
38 36
39 static unsigned 37 static unsigned
40 digit_to_number (char c) 38 digit_to_number (char c)
...@@ -43,106 +41,121 @@ digit_to_number (char c) ...@@ -43,106 +41,121 @@ digit_to_number (char c)
43 c >= 'A' && c <= 'Z' ? c-'A'+10 : 41 c >= 'A' && c <= 'Z' ? c-'A'+10 :
44 c-'a'+10); 42 c-'a'+10);
45 } 43 }
44
45 static void
46 advance_locus (void)
47 {
48 if (newline)
49 {
50 loc.mu_line++;
51 loc.mu_col = 1;
52 }
53 yylloc.beg = loc;
54 loc.mu_col += yyleng;
55 yylloc.end = loc;
56 yylloc.end.mu_col--;
57
58 newline = yytext[yyleng-1] == '\n';
59 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
60 MU_IOCTL_LOGSTREAM_SET_LOCUS, &loc);
61 }
62
63 #define YY_USER_ACTION advance_locus ();
64
46 %} 65 %}
47 66
48 %option nounput 67 %option nounput
49 %option noinput 68 %option noinput
50 69
51 %x ARGS HEX 70 %s RULE ARGS
52 X [0-9a-fA-F] 71 X [0-9a-fA-F]
53 IDENT [a-zA-Z_\.][a-zA-Z0-9_\.-]* 72 IDENT [a-zA-Z_\.][a-zA-Z0-9_\.-]*
54 WS [ \t]* 73 WS [ \t]*
55 %% 74 %%
56 /* Comments */ 75 /* Comments */
57 <INITIAL>#.*\n { line_num++; } 76 ^#.*\n ;
58 <INITIAL>#.* /* end-of-file comment */;
59 /* Tokens */ 77 /* Tokens */
60 \\\n { line_num++; } 78 \\\n ;
61 \n { line_num++; return EOL; } 79 \n+ { loc.mu_line += yyleng - 1; return EOL; }
62 {WS} ; 80 {WS} ;
63 {IDENT} { 81 <INITIAL,RULE>^[^ \t\n/]+"/"[^ \t\n]+ {
64 mu_opool_append (pool, yytext, yyleng); 82 mu_opool_append (pool, yytext, yyleng);
65 mu_opool_append_char (pool, 0); 83 mu_opool_append_char (pool, 0);
66 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 84 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
67 return IDENT; 85 BEGIN (RULE);
86 return TYPE;
87 }
88
89 <RULE>"priority"/"(" {
90 return PRIORITY;
68 } 91 }
69 <INITIAL>{IDENT}"(" { 92 <RULE>{IDENT}/"(" {
70 mu_opool_append (pool, yytext, yyleng-1); 93 mu_opool_append (pool, yytext, yyleng);
71 mu_opool_append_char (pool, 0); 94 mu_opool_append_char (pool, 0);
72 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 95 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
73 BEGIN(ARGS); 96 return IDENT;
74 return IDENT_L;
75 } 97 }
76 <INITIAL,ARGS>\"[^\\"\n]*\" { 98 <RULE>{IDENT} {
77 mu_opool_append (pool, yytext+1, yyleng-2); 99 mu_opool_append (pool, yytext, yyleng);
78 mu_opool_append_char (pool, 0); 100 mu_opool_append_char (pool, 0);
79 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 101 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
80 return STRING; 102 return STRING;
81 } 103 }
82 <INITIAL,ARGS>"<" { 104 <RULE,ARGS>\"[^"\n]*\" {
83 prev_state = YYSTATE; 105 mu_opool_append (pool, yytext+1, yyleng-2);
84 BEGIN(HEX);
85 }
86 <ARGS>[^ \t<\\\n),]+/[),] {
87 mu_opool_append (pool, yytext, yyleng);
88 mu_opool_append_char (pool, 0); 106 mu_opool_append_char (pool, 0);
89 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 107 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
90 return STRING; 108 return STRING;
91 } 109 }
92 <ARGS>[^ \t<\\\n),]+< { 110 <RULE,ARGS>"<"({X}{X})+">" {
93 mu_opool_append (pool, yytext, yyleng); 111 int i;
94 prev_state = YYSTATE; 112 for (i = 0; i < yyleng; i += 2)
95 BEGIN(HEX); 113 {
114 mu_opool_append_char (pool, digit_to_number (yytext[i])*16
115 + digit_to_number (yytext[i+1]));
116 }
117 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
118 return STRING;
96 } 119 }
97 <INITIAL>[^ \t<\\\n)+,&]/[ \t\\\n)+,&] { 120 <ARGS>[^ \t<\n),<"]+/[),<"] {
98 mu_opool_append (pool, yytext, yyleng); 121 mu_opool_append (pool, yytext, yyleng);
99 mu_opool_append_char (pool, 0); 122 mu_opool_append_char (pool, 0);
100 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 123 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
101 return STRING; 124 return STRING;
102 } 125 }
103 <ARGS>[^ \t<\\\n),]/[ \t\\\n] { 126 <RULE>[^ \t<\\\n)+,&]/[ \t\\\n)+,&] {
104 mu_opool_append (pool, yytext, yyleng); 127 mu_opool_append (pool, yytext, yyleng);
105 mu_opool_append_char (pool, 0); 128 mu_opool_append_char (pool, 0);
106 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 129 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
107 return STRING; 130 return STRING;
108 } 131 }
109 <HEX>{X}{X} { 132 <ARGS>[^ \t<\\\n),]/[ \t\\\n] {
110 int c = digit_to_number (yytext[0])*16 + digit_to_number (yytext[1]); 133 mu_opool_append (pool, yytext, yyleng);
111 mu_opool_append_char (pool, c);
112 }
113 <HEX>">"/[ \t\\\n,)] {
114 BEGIN(prev_state);
115 mu_opool_append_char (pool, 0); 134 mu_opool_append_char (pool, 0);
116 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 135 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
117 return STRING; 136 return STRING;
118 } 137 }
119 <HEX>">" {
120 BEGIN(prev_state);
121 }
122 /* Special cases: && and ||. Docs don't say anything about them, but 138 /* Special cases: && and ||. Docs don't say anything about them, but
123 I've found them in my mime.types file... --Sergey */ 139 I've found them in my mime.types file... --Sergey */
124 "&&" return '+'; 140 "&&" return '+';
125 "||" return ','; 141 "||" return ',';
126 /* Operators */ 142 /* Operators */
127 "!"|"+"|","|"("|")"|"/" return yytext[0]; 143 <RULE>"!"|"+"|","|"("|")"|"/" return yytext[0];
128 <ARGS>"," return yytext[0]; 144 <ARGS>"," return yytext[0];
129 <ARGS>")" { BEGIN(INITIAL); return yytext[0]; } 145 <ARGS>")" { BEGIN (RULE); return yytext[0]; }
130 <INITIAL,ARGS,HEX>. { 146 <*>. {
131 fprintf (stderr, "Invalid character '%c', state %d\n", yytext[0], YYSTATE); 147 mu_error ("invalid character '%c', state %d", yytext[0], YYSTATE);
132 abort(); 148 return BOGUS;
133 } 149 }
134 %% 150 %%
135
136 void
137 mimetypes_lex_debug (int level)
138 {
139 yy_flex_debug = level;
140 }
141
142 int 151 int
143 mimetypes_open (const char *name) 152 mimetypes_open (const char *name)
144 { 153 {
145 struct stat st; 154 struct stat st;
155 int mode;
156
157 yy_flex_debug = mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE4);
158
146 if (stat (name, &st)) 159 if (stat (name, &st))
147 { 160 {
148 mu_error (_("cannot stat `%s': %s"), name, mu_strerror (errno)); 161 mu_error (_("cannot stat `%s': %s"), name, mu_strerror (errno));
...@@ -150,28 +163,29 @@ mimetypes_open (const char *name) ...@@ -150,28 +163,29 @@ mimetypes_open (const char *name)
150 } 163 }
151 164
152 if (S_ISDIR (st.st_mode)) 165 if (S_ISDIR (st.st_mode))
153 { 166 loc.mu_file = mu_make_file_name (name, "mime.types");
154 file_name = mu_make_file_name (name, "mime.types");
155 file_name_alloc = 1;
156 }
157 else 167 else
158 { 168 loc.mu_file = mu_strdup (name);
159 file_name = (char*) name; 169 loc.mu_line = 1;
160 file_name_alloc = 0; 170 loc.mu_col = 1;
161 } 171 newline = 0;
162 172
163 yyin = fopen (file_name, "r"); 173 yyin = fopen (loc.mu_file, "r");
164 if (!yyin) 174 if (!yyin)
165 { 175 {
166 mu_error (_("Cannot open `%s': %s"), file_name, mu_strerror (errno)); 176 mu_error (_("cannot open `%s': %s"), loc.mu_file, mu_strerror (errno));
167 if (file_name_alloc) 177 free (loc.mu_file);
168 {
169 free (file_name);
170 file_name_alloc = 0;
171 }
172 return -1; 178 return -1;
173 } 179 }
174 line_num = 1; 180
181 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
182 MU_IOCTL_LOGSTREAM_GET_MODE, &mode);
183 mode |= MU_LOGMODE_LOCUS;
184 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
185 MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
186 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
187 MU_IOCTL_LOGSTREAM_SET_LOCUS, &loc);
188
175 mu_opool_create (&pool, MU_OPOOL_ENOMEMABRT); 189 mu_opool_create (&pool, MU_OPOOL_ENOMEMABRT);
176 return 0; 190 return 0;
177 } 191 }
...@@ -179,18 +193,25 @@ mimetypes_open (const char *name) ...@@ -179,18 +193,25 @@ mimetypes_open (const char *name)
179 void 193 void
180 mimetypes_close () 194 mimetypes_close ()
181 { 195 {
196 int mode;
197
182 fclose (yyin); 198 fclose (yyin);
183 if (file_name_alloc) 199 /* FIXME: Don't free (loc.mu_file), because it is referenced by
184 { 200 mu_locus structures in the parse tree */
185 free (file_name); 201
186 file_name_alloc = 0; 202 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
187 } 203 MU_IOCTL_LOGSTREAM_GET_MODE, &mode);
204 mode &= ~MU_LOGMODE_LOCUS;
205 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
206 MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
207 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
208 MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL);
188 } 209 }
189 210
190 int 211 int
191 yyerror (char *s) 212 yyerror (char *s)
192 { 213 {
193 mu_error ("%s:%d: %s", file_name, line_num, s); 214 mu_error (s);
194 return 0; 215 return 0;
195 } 216 }
196 217
...@@ -200,22 +221,6 @@ yywrap () ...@@ -200,22 +221,6 @@ yywrap ()
200 return 1; 221 return 1;
201 } 222 }
202 223
203 struct mimetypes_string
204 mimetypes_append_string2 (struct mimetypes_string *s1,
205 char c,
206 struct mimetypes_string *s2)
207 {
208 struct mimetypes_string r;
209
210 r.len = s1->len + s2->len + 1;
211 mu_opool_append (pool, s1->ptr, s1->len);
212 mu_opool_append_char (pool, c);
213 mu_opool_append (pool, s2->ptr, s2->len);
214 mu_opool_append_char (pool, 0);
215 r.ptr = mu_opool_finish (pool, NULL);
216 return r;
217 }
218
219 struct mimetypes_string * 224 struct mimetypes_string *
220 mimetypes_string_dup (struct mimetypes_string *s) 225 mimetypes_string_dup (struct mimetypes_string *s)
221 { 226 {
...@@ -231,9 +236,21 @@ mimetypes_malloc (size_t size) ...@@ -231,9 +236,21 @@ mimetypes_malloc (size_t size)
231 } 236 }
232 237
233 void 238 void
234 reset_lex () 239 lex_arglist (int enable)
235 { 240 {
236 BEGIN(INITIAL); 241 if (enable)
242 BEGIN (ARGS);
243 else
244 BEGIN (RULE);
237 } 245 }
238 246
239 247 void
248 lex_concat (struct concat_segm *p, struct mimetypes_string *ret)
249 {
250 for (; p; p = p->next)
251 {
252 mu_opool_appendz (pool, p->val);
253 }
254 mu_opool_append_char (pool, 0);
255 ret->ptr = mu_opool_finish (pool, &ret->len);
256 }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
23 #include <mailutils/cctype.h> 23 #include <mailutils/cctype.h>
24 #include <mimeview.h> 24 #include <mimeview.h>
25 #include <mimetypes-decl.h> 25 #include <mimetypes-decl.h>
26 #include <regex.h>
26 27
27 static void 28 static void
28 yyprint (FILE *output, unsigned short toknum, YYSTYPE val) 29 yyprint (FILE *output, unsigned short toknum, YYSTYPE val)
...@@ -30,14 +31,20 @@ yyprint (FILE *output, unsigned short toknum, YYSTYPE val) ...@@ -30,14 +31,20 @@ yyprint (FILE *output, unsigned short toknum, YYSTYPE val)
30 switch (toknum) 31 switch (toknum)
31 { 32 {
32 case IDENT: 33 case IDENT:
33 case IDENT_L:
34 case STRING: 34 case STRING:
35 fprintf (output, "[%lu] %s", (unsigned long) val.string.len, 35 fprintf (output, "[%lu] %s", (unsigned long) val.string.len,
36 val.string.ptr); 36 val.string.ptr);
37 break; 37 break;
38 38
39 case EOL: 39 case EOL:
40 fprintf (output, "\\n");
41 break;
42
40 default: 43 default:
44 if (mu_isprint (toknum))
45 fprintf (output, "'%c'", toknum);
46 else
47 fprintf (output, "tok(%d)", toknum);
41 break; 48 break;
42 } 49 }
43 } 50 }
...@@ -51,6 +58,7 @@ static mu_list_t arg_list; /* For error recovery */ ...@@ -51,6 +58,7 @@ static mu_list_t arg_list; /* For error recovery */
51 58
52 enum node_type 59 enum node_type
53 { 60 {
61 true_node,
54 functional_node, 62 functional_node,
55 binary_node, 63 binary_node,
56 negation_node, 64 negation_node,
...@@ -62,6 +70,7 @@ union argument ...@@ -62,6 +70,7 @@ union argument
62 struct mimetypes_string *string; 70 struct mimetypes_string *string;
63 unsigned number; 71 unsigned number;
64 int c; 72 int c;
73 regex_t rx;
65 }; 74 };
66 75
67 typedef int (*builtin_t) (union argument *args); 76 typedef int (*builtin_t) (union argument *args);
...@@ -69,6 +78,7 @@ typedef int (*builtin_t) (union argument *args); ...@@ -69,6 +78,7 @@ typedef int (*builtin_t) (union argument *args);
69 struct node 78 struct node
70 { 79 {
71 enum node_type type; 80 enum node_type type;
81 struct mu_locus_range loc;
72 union 82 union
73 { 83 {
74 struct 84 struct
...@@ -87,41 +97,56 @@ struct node ...@@ -87,41 +97,56 @@ struct node
87 } v; 97 } v;
88 }; 98 };
89 99
100 static struct node *make_node (enum node_type type,
101 struct mu_locus_range const *loc);
90 static struct node *make_binary_node (int op, 102 static struct node *make_binary_node (int op,
91 struct node *left, struct node *rigth); 103 struct node *left, struct node *rigth,
92 static struct node *make_negation_node (struct node *p); 104 struct mu_locus_range const *loc);
105 static struct node *make_negation_node (struct node *p,
106 struct mu_locus_range const *loc);
93 107
94 static struct node *make_suffix_node (struct mimetypes_string *suffix); 108 static struct node *make_suffix_node (struct mimetypes_string *suffix,
95 static struct node *make_functional_node (char *ident, mu_list_t list); 109 struct mu_locus_range const *loc);
110 static struct node *make_functional_node (char *ident, mu_list_t list,
111 struct mu_locus_range const *loc);
96 112
97 static int eval_rule (struct node *root); 113 static int eval_rule (struct node *root);
98 114
99 struct rule_tab 115 struct rule_tab
100 { 116 {
101 char *type; 117 char *type;
118 int priority;
119 struct mu_locus_range loc;
102 struct node *node; 120 struct node *node;
103 }; 121 };
104 122
105 static mu_list_t rule_list; 123 static mu_list_t rule_list;
106
107 %} 124 %}
108 125
109 %token <string> IDENT IDENT_L 126 %locations
127
128 %token <string> TYPE IDENT
110 %token <string> STRING 129 %token <string> STRING
111 %token EOL BOGUS 130 %token EOL BOGUS PRIORITY
112 131
113 %left ',' 132 %left ','
114 %left '+' 133 %left '+'
115 134
116 %type <string> string arg type 135 %type <string> string arg
117 %type <list> arglist 136 %type <list> arglist
118 %type <node> function stmt rule 137 %type <node> function stmt rule maybe_rule
138 %type <result> priority maybe_priority
139 %type <concat> concat;
140 %type <segment> simple_string
119 141
120 %union { 142 %union {
121 struct mimetypes_string string; 143 struct mimetypes_string string;
144 char *s;
122 mu_list_t list; 145 mu_list_t list;
123 int result; 146 int result;
124 struct node *node; 147 struct node *node;
148 struct { struct concat_segm *head, *tail; } concat;
149 struct concat_segm *segment;
125 } 150 }
126 151
127 %% 152 %%
...@@ -130,56 +155,65 @@ input : list ...@@ -130,56 +155,65 @@ input : list
130 ; 155 ;
131 156
132 list : rule_line 157 list : rule_line
133 | list eol rule_line 158 | list EOL rule_line
134 ; 159 ;
135 160
136 rule_line: /* empty */ 161 rule_line: /* empty */
137 | type rule 162 | TYPE maybe_rule maybe_priority
138 { 163 {
139 struct rule_tab *p = mimetypes_malloc (sizeof (*p)); 164 struct rule_tab *p = mimetypes_malloc (sizeof (*p));
140 if (!rule_list) 165 if (!rule_list)
141 mu_list_create (&rule_list); 166 mu_list_create (&rule_list);
142 p->type = $1.ptr; 167 p->type = $1.ptr;
143 p->node = $2; 168 p->node = $2;
169 p->priority = $3;
170 p->loc.beg = @1.beg;
171 p->loc.end = @3.end;
144 mu_list_append (rule_list, p); 172 mu_list_append (rule_list, p);
145 } 173 }
146 | error eol 174 | error EOL
147 { 175 {
148 if (arg_list) 176 if (arg_list)
149 mu_list_destroy (&arg_list); 177 mu_list_destroy (&arg_list);
150 arg_list = NULL; 178 arg_list = NULL;
151 reset_lex (); 179 lex_arglist (0);
152 } 180 }
153 ; 181 ;
154 182
155 eol : EOL 183 maybe_rule: /* empty */
156 | eol EOL
157 ;
158
159 type : IDENT '/' IDENT
160 { 184 {
161 $$ = mimetypes_append_string2 (&$1, '/', &$3); 185 $$ = make_node (true_node, &yylloc);
162 } 186 }
163 ; 187 | rule
188 ;
164 189
165 rule : stmt 190 rule : stmt
166 | rule rule %prec ',' 191 | rule rule %prec ','
167 { 192 {
168 $$ = make_binary_node (L_OR, $1, $2); 193 struct mu_locus_range lr;
194 lr.beg = @1.beg;
195 lr.end = @2.end;
196 $$ = make_binary_node (L_OR, $1, $2, &lr);
169 } 197 }
170 | rule ',' rule 198 | rule ',' rule
171 { 199 {
172 $$ = make_binary_node (L_OR, $1, $3); 200 struct mu_locus_range lr;
201 lr.beg = @1.beg;
202 lr.end = @3.end;
203 $$ = make_binary_node (L_OR, $1, $3, &lr);
173 } 204 }
174 | rule '+' rule 205 | rule '+' rule
175 { 206 {
176 $$ = make_binary_node (L_AND, $1, $3); 207 struct mu_locus_range lr;
208 lr.beg = @1.beg;
209 lr.end = @3.end;
210 $$ = make_binary_node (L_AND, $1, $3, &lr);
177 } 211 }
178 ; 212 ;
179 213
180 stmt : '!' stmt 214 stmt : '!' stmt
181 { 215 {
182 $$ = make_negation_node ($2); 216 $$ = make_negation_node ($2, &@2);
183 } 217 }
184 | '(' rule ')' 218 | '(' rule ')'
185 { 219 {
...@@ -187,19 +221,79 @@ stmt : '!' stmt ...@@ -187,19 +221,79 @@ stmt : '!' stmt
187 } 221 }
188 | string 222 | string
189 { 223 {
190 $$ = make_suffix_node (&$1); 224 $$ = make_suffix_node (&$1, &@1);
191 } 225 }
192 | function 226 | function
193 ; 227 ;
194 228
195 string : STRING 229 string : concat
196 | IDENT 230 {
231 lex_concat ($1.head, &$$);
232 }
233 ;
234
235 concat : simple_string
236 {
237 $$.head = $$.tail = $1;
238 }
239 | concat simple_string
240 {
241 $$.tail->next = $2;
242 $$.tail = $2;
243 }
244 ;
245
246 simple_string : STRING
247 {
248 $$ = mu_alloc (sizeof $$);
249 $$->next = NULL;
250 $$->val = $1.ptr;
251 }
252 ;
253
254 priority : PRIORITY oparen arglist cparen
255 {
256 size_t count = 0;
257 struct mimetypes_string *arg;
258
259 mu_list_count ($3, &count);
260 if (count != 1)
261 {
262 yyerror (_("priority takes single numberic argument"));
263 YYERROR;
264 }
265 mu_list_head ($3, (void**) &arg);
266 $$ = atoi (arg->ptr);
267 mu_list_destroy (&$3);
268 }
269 ;
270
271 maybe_priority: /* empty */
272 {
273 $$ = 100;
274 }
275 | priority
276 ;
277
278 oparen : '('
279 {
280 lex_arglist (1);
281 }
282 ;
283
284 cparen : ')'
285 {
286 lex_arglist (0);
287 }
197 ; 288 ;
198 289
199 function : IDENT_L arglist ')' 290 function : IDENT oparen arglist cparen
200 { 291 {
201 reset_lex (); 292 struct mu_locus_range lr;
202 $$ = make_functional_node ($1.ptr, $2); 293 lr.beg = @1.beg;
294 lr.end = @4.end;
295
296 $$ = make_functional_node ($1.ptr, $3, &lr);
203 if (!$$) 297 if (!$$)
204 YYERROR; 298 YYERROR;
205 } 299 }
...@@ -229,30 +323,26 @@ mimetypes_parse (const char *name) ...@@ -229,30 +323,26 @@ mimetypes_parse (const char *name)
229 int rc; 323 int rc;
230 if (mimetypes_open (name)) 324 if (mimetypes_open (name))
231 return 1; 325 return 1;
326 yydebug = mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE3);
232 rc = yyparse (); 327 rc = yyparse ();
233 mimetypes_close (); 328 mimetypes_close ();
234 return rc || rule_list == NULL; 329 return rc || rule_list == NULL;
235 } 330 }
236
237 void
238 mimetypes_gram_debug (int level)
239 {
240 yydebug = level;
241 }
242
243 331
244 static struct node * 332 static struct node *
245 make_node (enum node_type type) 333 make_node (enum node_type type, struct mu_locus_range const *loc)
246 { 334 {
247 struct node *p = mimetypes_malloc (sizeof *p); 335 struct node *p = mimetypes_malloc (sizeof *p);
248 p->type = type; 336 p->type = type;
337 p->loc = *loc;
249 return p; 338 return p;
250 } 339 }
251 340
252 static struct node * 341 static struct node *
253 make_binary_node (int op, struct node *left, struct node *right) 342 make_binary_node (int op, struct node *left, struct node *right,
343 struct mu_locus_range const *loc)
254 { 344 {
255 struct node *node = make_node (binary_node); 345 struct node *node = make_node (binary_node, loc);
256 346
257 node->v.bin.op = op; 347 node->v.bin.op = op;
258 node->v.bin.arg1 = left; 348 node->v.bin.arg1 = left;
...@@ -261,17 +351,18 @@ make_binary_node (int op, struct node *left, struct node *right) ...@@ -261,17 +351,18 @@ make_binary_node (int op, struct node *left, struct node *right)
261 } 351 }
262 352
263 struct node * 353 struct node *
264 make_negation_node (struct node *p) 354 make_negation_node (struct node *p, struct mu_locus_range const *loc)
265 { 355 {
266 struct node *node = make_node (negation_node); 356 struct node *node = make_node (negation_node, loc);
267 node->v.arg = p; 357 node->v.arg = p;
268 return node; 358 return node;
269 } 359 }
270 360
271 struct node * 361 struct node *
272 make_suffix_node (struct mimetypes_string *suffix) 362 make_suffix_node (struct mimetypes_string *suffix,
363 struct mu_locus_range const *loc)
273 { 364 {
274 struct node *node = make_node (suffix_node); 365 struct node *node = make_node (suffix_node, loc);
275 node->v.suffix = *suffix; 366 node->v.suffix = *suffix;
276 return node; 367 return node;
277 } 368 }
...@@ -508,7 +599,7 @@ b_contains (union argument *args) ...@@ -508,7 +599,7 @@ b_contains (union argument *args)
508 599
509 buf = mu_alloc (args[1].number); 600 buf = mu_alloc (args[1].number);
510 rc = mu_stream_read (mimeview_stream, buf, args[1].number, &count); 601 rc = mu_stream_read (mimeview_stream, buf, args[1].number, &count);
511 if (count != args[1].number) 602 if (rc)
512 { 603 {
513 mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc); 604 mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc);
514 } 605 }
...@@ -523,10 +614,41 @@ b_contains (union argument *args) ...@@ -523,10 +614,41 @@ b_contains (union argument *args)
523 return 0; 614 return 0;
524 } 615 }
525 616
617 #define MIME_MAX_BUFFER 4096
618
619 /* regex(offset,"regex") True if bytes match regular expression
620 */
621 static int
622 b_regex (union argument *args)
623 {
624 size_t count;
625 int rc;
626 char buf[MIME_MAX_BUFFER];
627
628 rc = mu_stream_seek (mimeview_stream, args[0].number, MU_SEEK_SET, NULL);
629 if (rc)
630 {
631 mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc);
632 return 0;
633 }
634
635 rc = mu_stream_read (mimeview_stream, buf, sizeof buf - 1, &count);
636 if (rc)
637 {
638 mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc);
639 return 0;
640 }
641 buf[count] = 0;
642
643 return regexec (&args[1].rx, buf, 0, NULL, 0) == 0;
644 }
645
646
526 static struct builtin_tab builtin_tab[] = { 647 static struct builtin_tab builtin_tab[] = {
527 { "match", "s", b_match }, 648 { "match", "s", b_match },
528 { "ascii", "dd", b_ascii }, 649 { "ascii", "dd", b_ascii },
529 { "printable", "dd", b_printable }, 650 { "printable", "dd", b_printable },
651 { "regex", "dx", b_regex },
530 { "string", "ds", b_string }, 652 { "string", "ds", b_string },
531 { "istring", "ds", b_istring }, 653 { "istring", "ds", b_istring },
532 { "char", "dc", b_char }, 654 { "char", "dc", b_char },
...@@ -538,13 +660,15 @@ static struct builtin_tab builtin_tab[] = { ...@@ -538,13 +660,15 @@ static struct builtin_tab builtin_tab[] = {
538 }; 660 };
539 661
540 struct node * 662 struct node *
541 make_functional_node (char *ident, mu_list_t list) 663 make_functional_node (char *ident, mu_list_t list,
664 struct mu_locus_range const *loc)
542 { 665 {
543 size_t count, i; 666 size_t count, i;
544 struct builtin_tab *p; 667 struct builtin_tab *p;
545 struct node *node; 668 struct node *node;
546 union argument *args; 669 union argument *args;
547 mu_iterator_t itr; 670 mu_iterator_t itr;
671 int rc;
548 672
549 for (p = builtin_tab; ; p++) 673 for (p = builtin_tab; ; p++)
550 { 674 {
...@@ -602,6 +726,30 @@ make_functional_node (char *ident, mu_list_t list) ...@@ -602,6 +726,30 @@ make_functional_node (char *ident, mu_list_t list)
602 case 's': 726 case 's':
603 args[i].string = data; 727 args[i].string = data;
604 break; 728 break;
729
730 case 'x':
731 {
732 char *s;
733
734 rc = mu_c_str_unescape_trans (data->ptr,
735 "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v", &s);
736 if (rc)
737 {
738 mu_diag_funcall (MU_DIAG_ERROR, "mu_c_str_unescape_trans",
739 data->ptr, rc);
740 return NULL;
741 }
742 rc = regcomp (&args[i].rx, s, REG_EXTENDED|REG_NOSUB);
743 free (s);
744 if (rc)
745 {
746 char errbuf[512];
747 regerror (rc, &args[i].rx, errbuf, sizeof errbuf);
748 yyerror (errbuf);
749 return NULL;
750 }
751 }
752 break;
605 753
606 case 'c': 754 case 'c':
607 args[i].c = strtoul (data->ptr, &tmp, 0); 755 args[i].c = strtoul (data->ptr, &tmp, 0);
...@@ -614,7 +762,7 @@ make_functional_node (char *ident, mu_list_t list) ...@@ -614,7 +762,7 @@ make_functional_node (char *ident, mu_list_t list)
614 } 762 }
615 } 763 }
616 764
617 node = make_node (functional_node); 765 node = make_node (functional_node, loc);
618 node->v.function.fun = p->handler; 766 node->v.function.fun = p->handler;
619 node->v.function.args = args; 767 node->v.function.args = args;
620 return node; 768 return node;
...@@ -640,6 +788,45 @@ check_suffix (char *suf) ...@@ -640,6 +788,45 @@ check_suffix (char *suf)
640 return strcmp (p+1, suf) == 0; 788 return strcmp (p+1, suf) == 0;
641 } 789 }
642 790
791 void
792 mime_debug (int lev, struct mu_locus_range const *loc, char const *fmt, ...)
793 {
794 if (mu_debug_level_p (MU_DEBCAT_MIME, lev))
795 {
796 va_list ap;
797
798 if (loc->beg.mu_col == 0)
799 mu_debug_log_begin ("%s:%u", loc->beg.mu_file, loc->beg.mu_line);
800 else if (strcmp(loc->beg.mu_file, loc->end.mu_file))
801 mu_debug_log_begin ("%s:%u.%u-%s:%u.%u",
802 loc->beg.mu_file,
803 loc->beg.mu_line, loc->beg.mu_col,
804 loc->end.mu_file,
805 loc->end.mu_line, loc->end.mu_col);
806 else if (loc->beg.mu_line != loc->end.mu_line)
807 mu_debug_log_begin ("%s:%u.%u-%u.%u",
808 loc->beg.mu_file,
809 loc->beg.mu_line, loc->beg.mu_col,
810 loc->end.mu_line, loc->end.mu_col);
811 else if (loc->beg.mu_col != loc->end.mu_col)
812 mu_debug_log_begin ("%s:%u.%u-%u",
813 loc->beg.mu_file,
814 loc->beg.mu_line, loc->beg.mu_col,
815 loc->end.mu_col);
816 else
817 mu_debug_log_begin ("%s:%u.%u",
818 loc->beg.mu_file,
819 loc->beg.mu_line, loc->beg.mu_col);
820
821 mu_stream_write (mu_strerr, ": ", 2, NULL);
822
823 va_start (ap, fmt);
824 mu_stream_vprintf (mu_strerr, fmt, ap);
825 va_end (ap);
826 mu_debug_log_nl ();
827 }
828 }
829
643 static int 830 static int
644 eval_rule (struct node *root) 831 eval_rule (struct node *root)
645 { 832 {
...@@ -647,6 +834,10 @@ eval_rule (struct node *root) ...@@ -647,6 +834,10 @@ eval_rule (struct node *root)
647 834
648 switch (root->type) 835 switch (root->type)
649 { 836 {
837 case true_node:
838 result = 1;
839 break;
840
650 case functional_node: 841 case functional_node:
651 result = root->v.function.fun (root->v.function.args); 842 result = root->v.function.fun (root->v.function.args);
652 break; 843 break;
...@@ -681,28 +872,50 @@ eval_rule (struct node *root) ...@@ -681,28 +872,50 @@ eval_rule (struct node *root)
681 default: 872 default:
682 abort (); 873 abort ();
683 } 874 }
875 mime_debug (MU_DEBUG_TRACE2, &root->loc, "result %s", result ? "true" : "false");
684 return result; 876 return result;
685 } 877 }
686 878
687 static int 879 static int
688 evaluate (void *item, void *data) 880 evaluate (void **itmv, size_t itmc, void *call_data)
689 { 881 {
690 struct rule_tab *p = item; 882 struct rule_tab *p = itmv[0];
691 char **ptype = data;
692
693 if (eval_rule (p->node)) 883 if (eval_rule (p->node))
694 { 884 {
695 *ptype = p->type; 885 itmv[0] = p;
696 return MU_ERR_USER0; 886 mime_debug (MU_DEBUG_TRACE1, &p->loc, "rule %s matches", p->type);
887 return MU_LIST_MAP_OK;
697 } 888 }
698 return 0; 889 return MU_LIST_MAP_SKIP;
890 }
891
892 static int
893 rule_cmp (const void *a, const void *b)
894 {
895 struct rule_tab const *arule = a;
896 struct rule_tab const *brule = b;
897
898 if (arule->priority == brule->priority)
899 return mu_c_strcasecmp (arule->type, brule->type);
900 return arule->priority - brule->priority;
699 } 901 }
700 902
701 const char * 903 const char *
702 get_file_type () 904 get_file_type ()
703 { 905 {
906 mu_list_t res = NULL;
704 const char *type = NULL; 907 const char *type = NULL;
705 mu_list_foreach (rule_list, evaluate, &type); 908
909 mu_list_map (rule_list, evaluate, NULL, 1, &res);
910 if (!mu_list_is_empty (res))
911 {
912 struct rule_tab *rule;
913 mu_list_sort (res, rule_cmp);
914 mu_list_head (res, (void**) &rule);
915 mime_debug (MU_DEBUG_TRACE0, &rule->loc, "selected rule %s", rule->type);
916 type = rule->type;
917 }
918 mu_list_destroy (&res);
706 return type; 919 return type;
707 } 920 }
708 921
......
...@@ -31,8 +31,8 @@ ...@@ -31,8 +31,8 @@
31 31
32 #include "mailcap.h" 32 #include "mailcap.h"
33 33
34 int debug_level; /* Debugging level set by --debug option */
35 static int dry_run; /* Dry run mode */ 34 static int dry_run; /* Dry run mode */
35 static int lint; /* Syntax check mode */
36 static char *metamail; /* Name of metamail program, if requested */ 36 static char *metamail; /* Name of metamail program, if requested */
37 static char *mimetypes_config = DEFAULT_CUPS_CONFDIR; 37 static char *mimetypes_config = DEFAULT_CUPS_CONFDIR;
38 static char *no_ask_types; /* List of MIME types for which no questions 38 static char *no_ask_types; /* List of MIME types for which no questions
...@@ -41,26 +41,6 @@ static int interactive = -1; ...@@ -41,26 +41,6 @@ static int interactive = -1;
41 char *mimeview_file; /* Name of the file to view */ 41 char *mimeview_file; /* Name of the file to view */
42 mu_stream_t mimeview_stream; /* The corresponding stream */ 42 mu_stream_t mimeview_stream; /* The corresponding stream */
43 43
44 static void
45 set_debug_flags (const char *arg)
46 {
47 for (; *arg; arg++)
48 {
49 switch (*arg)
50 {
51 case 'l':
52 mimetypes_lex_debug (1);
53 break;
54
55 case 'g':
56 mimetypes_gram_debug (1);
57 break;
58
59 default:
60 debug_level = *arg - '0';
61 }
62 }
63 }
64 44
65 static void 45 static void
66 cli_no_ask (struct mu_parseopt *po, struct mu_option *opt, char const *arg) 46 cli_no_ask (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
...@@ -80,7 +60,34 @@ static void ...@@ -80,7 +60,34 @@ static void
80 cli_debug (struct mu_parseopt *po, struct mu_option *opt, 60 cli_debug (struct mu_parseopt *po, struct mu_option *opt,
81 char const *arg) 61 char const *arg)
82 { 62 {
83 set_debug_flags (arg); 63 mu_debug_level_t lev;
64 if (!arg)
65 lev = MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE2);
66 else
67 {
68 mu_debug_get_category_level (MU_DEBCAT_MIME, &lev);
69 for (; *arg; arg++)
70 {
71 switch (*arg)
72 {
73 case 'l':
74 lev |= MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE4);
75 break;
76
77 case 'g':
78 lev |= MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE3);
79 break;
80
81 default:
82 if (mu_isdigit (*arg))
83 lev |= MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE0 + *arg - '0');
84 else
85 mu_parseopt_error (po, _("ignoring invalid debug flag: %c"),
86 *arg);
87 }
88 }
89 }
90 mu_debug_set_category_level (MU_DEBCAT_MIME, lev);
84 } 91 }
85 92
86 static void 93 static void
...@@ -103,13 +110,17 @@ static struct mu_option mimeview_options[] = { ...@@ -103,13 +110,17 @@ static struct mu_option mimeview_options[] = {
103 { "debug", 'd', N_("FLAGS"), MU_OPTION_ARG_OPTIONAL, 110 { "debug", 'd', N_("FLAGS"), MU_OPTION_ARG_OPTIONAL,
104 N_("enable debugging output"), 111 N_("enable debugging output"),
105 mu_c_string, NULL, cli_debug }, 112 mu_c_string, NULL, cli_debug },
106 { "mimetypes", 't', N_("FILE"), MU_OPTION_DEFAULT, 113 { "mimetypes", 'f', N_("FILE"), MU_OPTION_DEFAULT,
107 N_("use this mime.types file"), 114 N_("use this mime.types file"),
108 mu_c_string, &mimetypes_config }, 115 mu_c_string, &mimetypes_config },
109 116
110 { "dry-run", 'n', NULL, MU_OPTION_DEFAULT, 117 { "dry-run", 'n', NULL, MU_OPTION_DEFAULT,
111 N_("do nothing, just print what would have been done"), 118 N_("do nothing, just print what would have been done"),
112 mu_c_bool, &dry_run }, 119 mu_c_bool, &dry_run },
120
121 { "lint", 't', NULL, MU_OPTION_DEFAULT,
122 N_("test mime.types syntax and exit"),
123 mu_c_bool, &lint },
113 124
114 { "metamail", 0, N_("FILE"), MU_OPTION_ARG_OPTIONAL, 125 { "metamail", 0, N_("FILE"), MU_OPTION_ARG_OPTIONAL,
115 N_("use metamail to display files"), 126 N_("use metamail to display files"),
...@@ -118,19 +129,7 @@ static struct mu_option mimeview_options[] = { ...@@ -118,19 +129,7 @@ static struct mu_option mimeview_options[] = {
118 MU_OPTION_END 129 MU_OPTION_END
119 }, *options[] = { mimeview_options, NULL }; 130 }, *options[] = { mimeview_options, NULL };
120 131
121 static int
122 cb_debug (void *data, mu_config_value_t *val)
123 {
124 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
125 return 1;
126 set_debug_flags (val->v.string);
127 return 0;
128 }
129
130 struct mu_cfg_param mimeview_cfg_param[] = { 132 struct mu_cfg_param mimeview_cfg_param[] = {
131 { "debug", mu_cfg_callback, NULL, 0, cb_debug,
132 N_("Set debug verbosity level."),
133 N_("flags: string") },
134 { "mimetypes", mu_c_string, &mimetypes_config, 0, NULL, 133 { "mimetypes", mu_c_string, &mimetypes_config, 0, NULL,
135 N_("Use this mime.types file."), 134 N_("Use this mime.types file."),
136 N_("file") }, 135 N_("file") },
...@@ -209,11 +208,12 @@ display_file (const char *type) ...@@ -209,11 +208,12 @@ display_file (const char *type)
209 argv[5] = mimeview_file; 208 argv[5] = mimeview_file;
210 argv[6] = NULL; 209 argv[6] = NULL;
211 210
212 if (debug_level) 211 if (mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE0))
213 { 212 {
214 char *string; 213 char *string;
215 mu_argcv_string (6, argv, &string); 214 mu_argcv_string (6, argv, &string);
216 printf (_("Executing %s...\n"), string); 215 mu_debug (MU_DEBCAT_MIME, MU_DEBUG_TRACE0,
216 (_("executing %s...\n"), string));
217 free (string); 217 free (string);
218 } 218 }
219 219
...@@ -233,7 +233,7 @@ display_file (const char *type) ...@@ -233,7 +233,7 @@ display_file (const char *type)
233 { 233 {
234 display_stream_mailcap (mimeview_file, mimeview_stream, hdr, 234 display_stream_mailcap (mimeview_file, mimeview_stream, hdr,
235 no_ask_types, interactive, dry_run, 235 no_ask_types, interactive, dry_run,
236 debug_level); 236 MU_DEBCAT_MIME);
237 mu_header_destroy (&hdr); 237 mu_header_destroy (&hdr);
238 } 238 }
239 } 239 }
...@@ -244,15 +244,18 @@ main (int argc, char **argv) ...@@ -244,15 +244,18 @@ main (int argc, char **argv)
244 { 244 {
245 MU_APP_INIT_NLS (); 245 MU_APP_INIT_NLS ();
246 246
247 mimetypes_lex_debug (0);
248 mimetypes_gram_debug (0);
249 interactive = isatty (fileno (stdin)); 247 interactive = isatty (fileno (stdin));
250 248
251 mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv); 249 mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv);
252 if (dry_run && !debug_level) 250 if (dry_run)
253 debug_level = 1; 251 {
252 mu_debug_level_t lev;
253 mu_debug_get_category_level (MU_DEBCAT_MIME, &lev);
254 lev |= MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE2);
255 mu_debug_set_category_level (MU_DEBCAT_MIME, lev);
256 }
254 257
255 if (argc == 0) 258 if (argc == 0 && !lint)
256 { 259 {
257 mu_error (_("no files given")); 260 mu_error (_("no files given"));
258 return 1; 261 return 1;
...@@ -260,6 +263,8 @@ main (int argc, char **argv) ...@@ -260,6 +263,8 @@ main (int argc, char **argv)
260 263
261 if (mimetypes_parse (mimetypes_config)) 264 if (mimetypes_parse (mimetypes_config))
262 return 1; 265 return 1;
266 if (lint)
267 return 0;
263 268
264 while (argc--) 269 while (argc--)
265 { 270 {
...@@ -268,7 +273,6 @@ main (int argc, char **argv) ...@@ -268,7 +273,6 @@ main (int argc, char **argv)
268 if (open_file (*argv++)) 273 if (open_file (*argv++))
269 continue; 274 continue;
270 type = get_file_type (); 275 type = get_file_type ();
271 DEBUG (1, ("%s: %s\n", mimeview_file, type ? type : "?"));
272 if (type) 276 if (type)
273 display_file (type); 277 display_file (type);
274 close_file (); 278 close_file ();
......
...@@ -36,21 +36,48 @@ int mimetypes_yyerror (char *s); ...@@ -36,21 +36,48 @@ int mimetypes_yyerror (char *s);
36 int mimetypes_open (const char *name); 36 int mimetypes_open (const char *name);
37 void mimetypes_close (void); 37 void mimetypes_close (void);
38 int mimetypes_parse (const char *name); 38 int mimetypes_parse (const char *name);
39 void mimetypes_gram_debug (int level);
40 void mimetypes_lex_debug (int level);
41 void mimetypes_lex_init (void); 39 void mimetypes_lex_init (void);
42 void reset_lex (void); 40 void lex_arglist (int);
43 void *mimetypes_malloc (size_t size); 41 void *mimetypes_malloc (size_t size);
44 42
45 struct mimetypes_string mimetypes_append_string2 (struct mimetypes_string *s1,
46 char c,
47 struct mimetypes_string *s2);
48 struct mimetypes_string *mimetypes_string_dup (struct mimetypes_string *s); 43 struct mimetypes_string *mimetypes_string_dup (struct mimetypes_string *s);
49 44
50 const char *get_file_type (void); 45 const char *get_file_type (void);
51 46
52 extern char *mimeview_file; 47 extern char *mimeview_file;
53 extern mu_stream_t mimeview_stream; 48 extern mu_stream_t mimeview_stream;
54 extern int debug_level;
55 49
56 #define DEBUG(l,f) if (debug_level > (l)) printf f 50 struct concat_segm
51 {
52 struct concat_segm *next;
53 char const *val;
54 };
55
56 void lex_concat (struct concat_segm *p, struct mimetypes_string *ret);
57
58 struct mu_locus_range
59 {
60 struct mu_locus beg;
61 struct mu_locus end;
62 };
63
64 #define YYLTYPE struct mu_locus_range
65 #define YYLLOC_DEFAULT(Current, Rhs, N) \
66 do \
67 { \
68 if (N) \
69 { \
70 (Current).beg = YYRHSLOC(Rhs, 1).beg; \
71 (Current).end = YYRHSLOC(Rhs, N).end; \
72 } \
73 else \
74 { \
75 (Current).beg = YYRHSLOC(Rhs, 0).end; \
76 (Current).end = (Current).beg; \
77 } \
78 } while (0)
79 #define YY_LOCATION_PRINT(File, Loc) \
80 fprintf(File, "%s:%u.%u-%u.%u", \
81 (Loc).beg.mu_file, \
82 (Loc).beg.mu_line, (Loc).beg.mu_col, \
83 (Loc).end.mu_line, (Loc).end.mu_col)
......
1 /Makefile.in.in
1 /Makevars.template~ 2 /Makevars.template~
2 /Makefile.in.in~ 3 /Makefile.in.in~
3 *.gmo 4 *.gmo
......