Commit 58cc7c8f 58cc7c8f6bd1956a47f56c3aba1be8a417916064 by Sergey Poznyakoff

Revise the mime.types lexer; provide the testsuite

* am/testsuite.m4: New file.
* configure.ac: Use the MU_CONFIG_TESTSUITE macro.
* mimeview/Makefile.am (SUBDIRS): Add tests
* mimeview/mimetypes.l: Rewrite in three exclusive states.
* mimeview/mimetypes.y: Simplify grammar.
* mimeview/mimeview.c: New option --identify (-i).
* mimeview/mimeview.h: Update.

* mimeview/tests/Makefile.am: New file.
* mimeview/tests/atlocal.in: New file.
* mimeview/tests/bf.c: New file.
* mimeview/tests/testsuite.at: New file.

* README: Update.
* doc/texinfo/programs.texi
1 parent be0acbf5
1 GNU mailutils NEWS -- history of user-visible changes. 2017-05-31 1 GNU mailutils NEWS -- history of user-visible changes. 2017-06-01
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
...@@ -145,6 +145,9 @@ New option '--lint' (short '-t') instructs the tool to check the ...@@ -145,6 +145,9 @@ New option '--lint' (short '-t') instructs the tool to check the
145 syntax of the mime.types file and exit, ignoring any surplus command 145 syntax of the mime.types file and exit, ignoring any surplus command
146 line arguments. 146 line arguments.
147 147
148 New option '-i' ('--identify') identifies and prints the MIME type for
149 each input file, but not starts viewer.
150
148 Added support for priority and regex functions. 151 Added support for priority and regex functions.
149 152
150 Debugging considerably improved. 153 Debugging considerably improved.
......
1 # Initialize the (autotest) test suite.
2 AC_DEFUN([MU_CONFIG_TESTSUITE],
3 [AC_CONFIG_TESTDIR([$1/tests])
4 AC_CONFIG_FILES([$1/tests/Makefile $1/tests/atlocal])
5 ])
...@@ -1324,40 +1324,22 @@ test -z "$server_list" && server_list=" [NONE]" ...@@ -1324,40 +1324,22 @@ test -z "$server_list" && server_list=" [NONE]"
1324 test -z "$client_list" && client_list=" [NONE]" 1324 test -z "$client_list" && client_list=" [NONE]"
1325 1325
1326 # Initialize the (autotest) test suite. 1326 # Initialize the (autotest) test suite.
1327 AC_CONFIG_TESTDIR(libmailutils/tests) 1327
1328 AC_CONFIG_TESTDIR(testsuite) 1328 AC_CONFIG_TESTDIR(testsuite)
1329 AC_CONFIG_TESTDIR(frm/tests) 1329 AC_CONFIG_FILES([testsuite/Makefile testsuite/atlocal])
1330 AC_CONFIG_TESTDIR(maidag/tests) 1330
1331 AC_CONFIG_TESTDIR(mail/tests) 1331 MU_CONFIG_TESTSUITE(libmailutils)
1332 AC_CONFIG_TESTDIR(messages/tests) 1332 MU_CONFIG_TESTSUITE(frm)
1333 AC_CONFIG_TESTDIR(readmsg/tests) 1333 MU_CONFIG_TESTSUITE(maidag)
1334 AC_CONFIG_TESTDIR(sieve/tests) 1334 MU_CONFIG_TESTSUITE(mail)
1335 AC_CONFIG_TESTDIR(mh/tests) 1335 MU_CONFIG_TESTSUITE(messages)
1336 AC_CONFIG_TESTDIR(comsat/tests) 1336 MU_CONFIG_TESTSUITE(readmsg)
1337 AC_CONFIG_TESTDIR(imap4d/tests) 1337 MU_CONFIG_TESTSUITE(sieve)
1338 1338 MU_CONFIG_TESTSUITE(mh)
1339 AC_CONFIG_FILES([libmailutils/tests/Makefile 1339 MU_CONFIG_TESTSUITE(comsat)
1340 libmailutils/tests/atlocal 1340 MU_CONFIG_TESTSUITE(imap4d)
1341 testsuite/Makefile 1341 MU_CONFIG_TESTSUITE(mimeview)
1342 testsuite/atlocal 1342
1343 comsat/tests/Makefile
1344 comsat/tests/atlocal
1345 frm/tests/Makefile
1346 frm/tests/atlocal
1347 imap4d/tests/Makefile
1348 imap4d/tests/atlocal
1349 maidag/tests/Makefile
1350 maidag/tests/atlocal
1351 mail/tests/Makefile
1352 mail/tests/atlocal
1353 messages/tests/Makefile
1354 messages/tests/atlocal
1355 readmsg/tests/Makefile
1356 readmsg/tests/atlocal
1357 sieve/tests/Makefile
1358 sieve/tests/atlocal
1359 mh/tests/Makefile
1360 mh/tests/atlocal])
1361 AM_MISSING_PROG([AUTOM4TE], [autom4te]) 1343 AM_MISSING_PROG([AUTOM4TE], [autom4te])
1362 1344
1363 dnl Make sysconfdir available to the application 1345 dnl Make sysconfdir available to the application
......
...@@ -7359,6 +7359,10 @@ By default @command{mimeview} behaves as if given ...@@ -7359,6 +7359,10 @@ By default @command{mimeview} behaves as if given
7359 @option{--no-interactive} option whenever its standard input is not 7359 @option{--no-interactive} option whenever its standard input is not
7360 a @asis{tty} device. 7360 a @asis{tty} device.
7361 7361
7362 @item -i
7363 @itemx --identify
7364 Identifies and prints the MIME type for each input file.
7365
7362 @item -n 7366 @item -n
7363 @itemx --dry-run 7367 @itemx --dry-run
7364 Do not do anything, just print what would be done. Implies 7368 Do not do anything, just print what would be done. Implies
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
15 ## You should have received a copy of the GNU General Public License 15 ## You should have received a copy of the GNU General Public License
16 ## along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. 16 ## along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
17 17
18 SUBDIRS = tests
19
18 AM_CPPFLAGS = \ 20 AM_CPPFLAGS = \
19 @MU_APP_COMMON_INCLUDES@\ 21 @MU_APP_COMMON_INCLUDES@\
20 -D_GNU_SOURCE=1\ 22 -D_GNU_SOURCE=1\
......
...@@ -42,9 +42,16 @@ digit_to_number (char c) ...@@ -42,9 +42,16 @@ digit_to_number (char c)
42 c-'a'+10); 42 c-'a'+10);
43 } 43 }
44 44
45 static struct mu_locus prev_loc;
46 static struct mu_locus string_beg;
47 static int prev_newline;
48
45 static void 49 static void
46 advance_locus (void) 50 advance_locus (void)
47 { 51 {
52 prev_loc = loc;
53 prev_newline = newline;
54
48 if (newline) 55 if (newline)
49 { 56 {
50 loc.mu_line++; 57 loc.mu_line++;
...@@ -55,98 +62,173 @@ advance_locus (void) ...@@ -55,98 +62,173 @@ advance_locus (void)
55 yylloc.end = loc; 62 yylloc.end = loc;
56 yylloc.end.mu_col--; 63 yylloc.end.mu_col--;
57 64
65 #if 0
66 printf ("+%2d> %u:%u-%u:%u: %s\n",
67 yyleng,
68 yylloc.beg.mu_line, yylloc.beg.mu_col,
69 yylloc.end.mu_line, yylloc.end.mu_col, yytext);
70 #endif
58 newline = yytext[yyleng-1] == '\n'; 71 newline = yytext[yyleng-1] == '\n';
59 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, 72 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
60 MU_IOCTL_LOGSTREAM_SET_LOCUS, &loc); 73 MU_IOCTL_LOGSTREAM_SET_LOCUS, &loc);
61 } 74 }
62 75
63 #define YY_USER_ACTION advance_locus (); 76 static void
77 retreat_locus (void)
78 {
79 loc = prev_loc;
80 newline = prev_newline;
81 }
82
83 static void
84 finish_string (void)
85 {
86 mu_opool_append_char (pool, 0);
87 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
88 yylval.string.len--;
89 yylloc.end = yylloc.beg;
90 yylloc.end.mu_col--;
91 yylloc.beg = string_beg;
92 if (mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE5))
93 {
94 size_t i;
95 mu_debug_log_begin ("string %d: ", yylval.string.len);
96 for (i = 0; i < yylval.string.len; i++)
97 if (mu_isprint (yylval.string.ptr[i]))
98 mu_debug_log_cont ("%c", yylval.string.ptr[i]);
99 else
100 mu_debug_log_cont ("\\%03o", yylval.string.ptr[i]);
101 mu_debug_log_nl ();
102 }
103 #if 0
104 YY_LOCATION_PRINT (stderr, yylloc);
105 fprintf (stderr, ": %s\n", yylval.string.ptr);
106 #endif
107 }
64 108
109 #define YY_USER_ACTION advance_locus ();
65 %} 110 %}
66 111
67 %option nounput 112 %option nounput
68 %option noinput 113 %option noinput
69 114
70 %s RULE ARGS 115 %x RULE ARGS ASTRING
71 X [0-9a-fA-F] 116 X [0-9a-fA-F]
72 IDENT [a-zA-Z_\.][a-zA-Z0-9_\.-]* 117 IDENT [a-zA-Z_\.][a-zA-Z0-9_\.-]*
73 WS [ \t]* 118 WS [ \t][ \t]*
74 %% 119 %%
120
121 <INITIAL>{
75 /* Comments */ 122 /* Comments */
76 ^#.*\n ; 123 ^#.*\n ;
77 /* Tokens */ 124 \n ;
78 \\\n ; 125 ^[^ \t\n/]+"/"[^ \t\n]+ {
79 \n+ { loc.mu_line += yyleng - 1; return EOL; }
80 {WS} ;
81 <INITIAL,RULE>^[^ \t\n/]+"/"[^ \t\n]+ {
82 mu_opool_append (pool, yytext, yyleng); 126 mu_opool_append (pool, yytext, yyleng);
83 mu_opool_append_char (pool, 0); 127 mu_opool_append_char (pool, 0);
84 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 128 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
129 yylval.string.len--;
85 BEGIN (RULE); 130 BEGIN (RULE);
86 return TYPE; 131 return TYPE;
87 } 132 }
133 }
134
135 <RULE>{
136 \\\n ;
137 \n {
138 BEGIN (INITIAL);
139 return EOL;
140 }
141 {WS} ;
142
143 /* Operators */
144 "!"|"+"|","|"("|")"|"/" return yytext[0];
145 /* Special cases: && and ||. Docs don't say anything about them, but
146 I've found them in my mime.types file... --Sergey */
147 "&&" return '+';
148 "||" return ',';
88 149
89 <RULE>"priority"/"(" { 150 "priority"/"(" {
90 return PRIORITY; 151 return PRIORITY;
91 } 152 }
92 <RULE>{IDENT}/"(" { 153
154 {IDENT}/"(" {
93 mu_opool_append (pool, yytext, yyleng); 155 mu_opool_append (pool, yytext, yyleng);
94 mu_opool_append_char (pool, 0); 156 mu_opool_append_char (pool, 0);
95 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 157 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
158 BEGIN (ARGS);
96 return IDENT; 159 return IDENT;
97 } 160 }
98 <RULE>{IDENT} { 161
162 [a-zA-Z0-9_.-]+/[^(] {
99 mu_opool_append (pool, yytext, yyleng); 163 mu_opool_append (pool, yytext, yyleng);
100 mu_opool_append_char (pool, 0);
101 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 164 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
102 return STRING; 165 return STRING;
103 } 166 }
104 <RULE,ARGS>\"[^"\n]*\" { 167
168 . mu_error("unexpected character '%c'", yytext[0]);
169 }
170
171 <ARGS>{
172 "("|"," return yytext[0];
173 ")" {
174 BEGIN (RULE);
175 return yytext[0];
176 }
177 {WS} mu_error ("unexpected whitespace in argument list");
178 \n {
179 mu_error ("unexpected newline in argument list");
180 BEGIN (RULE);
181 return EOL;
182 }
183 . {
184 string_beg = yylloc.beg;
185 retreat_locus ();
186 yyless (0);
187 BEGIN (ASTRING);
188 }
189 }
190
191 <ASTRING>{
192 /* Quoted string */
193 \"[^"\n]*\" {
194 mu_opool_append (pool, yytext+1, yyleng-2);
195 }
196 "'"[^'\n]*"'" {
105 mu_opool_append (pool, yytext+1, yyleng-2); 197 mu_opool_append (pool, yytext+1, yyleng-2);
106 mu_opool_append_char (pool, 0);
107 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
108 return STRING;
109 } 198 }
110 <RULE,ARGS>"<"({X}{X})+">" { 199
200 /* Hex string */
201 "<"({X}{X})+">" {
111 int i; 202 int i;
112 for (i = 0; i < yyleng; i += 2) 203 for (i = 1; i < yyleng - 2; i += 2)
113 { 204 {
114 mu_opool_append_char (pool, digit_to_number (yytext[i])*16 205 mu_opool_append_char (pool, digit_to_number (yytext[i])*16
115 + digit_to_number (yytext[i+1])); 206 + digit_to_number (yytext[i+1]));
116 } 207 }
117 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
118 return STRING;
119 } 208 }
120 <ARGS>[^ \t<\n),<"]+/[),<"] { 209
210 /* Unquoted character sequence */
211 [^ \t\n,)<"']+/[^"'<] {
121 mu_opool_append (pool, yytext, yyleng); 212 mu_opool_append (pool, yytext, yyleng);
122 mu_opool_append_char (pool, 0);
123 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
124 return STRING;
125 } 213 }
126 <RULE>[^ \t<\\\n)+,&]/[ \t\\\n)+,&] { 214
215 [^ \t\n,)<"]+/< {
127 mu_opool_append (pool, yytext, yyleng); 216 mu_opool_append (pool, yytext, yyleng);
128 mu_opool_append_char (pool, 0);
129 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
130 return STRING;
131 } 217 }
132 <ARGS>[^ \t<\\\n),]/[ \t\\\n] { 218
219 [^ \t\n,)<"]+/["'] {
133 mu_opool_append (pool, yytext, yyleng); 220 mu_opool_append (pool, yytext, yyleng);
134 mu_opool_append_char (pool, 0); 221 }
135 yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len); 222
223 . {
224 retreat_locus ();
225 yyless (0);
226 BEGIN (ARGS);
227 finish_string ();
136 return STRING; 228 return STRING;
137 } 229 }
138 /* Special cases: && and ||. Docs don't say anything about them, but
139 I've found them in my mime.types file... --Sergey */
140 "&&" return '+';
141 "||" return ',';
142 /* Operators */
143 <RULE>"!"|"+"|","|"("|")"|"/" return yytext[0];
144 <ARGS>"," return yytext[0];
145 <ARGS>")" { BEGIN (RULE); return yytext[0]; }
146 <*>. {
147 mu_error ("invalid character '%c', state %d", yytext[0], YYSTATE);
148 return BOGUS;
149 } 230 }
231
150 %% 232 %%
151 int 233 int
152 mimetypes_open (const char *name) 234 mimetypes_open (const char *name)
...@@ -236,21 +318,7 @@ mimetypes_malloc (size_t size) ...@@ -236,21 +318,7 @@ mimetypes_malloc (size_t size)
236 } 318 }
237 319
238 void 320 void
239 lex_arglist (int enable) 321 lex_reset (void)
240 { 322 {
241 if (enable) 323 BEGIN (INITIAL);
242 BEGIN (ARGS);
243 else
244 BEGIN (RULE);
245 }
246
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 } 324 }
......
...@@ -132,12 +132,10 @@ static mu_list_t rule_list; ...@@ -132,12 +132,10 @@ static mu_list_t rule_list;
132 %left ',' 132 %left ','
133 %left '+' 133 %left '+'
134 134
135 %type <string> string arg 135 %type <string> arg
136 %type <list> arglist 136 %type <list> arglist
137 %type <node> function stmt rule maybe_rule 137 %type <node> function stmt rule maybe_rule
138 %type <result> priority maybe_priority 138 %type <result> priority maybe_priority
139 %type <concat> concat;
140 %type <segment> simple_string
141 139
142 %union { 140 %union {
143 struct mimetypes_string string; 141 struct mimetypes_string string;
...@@ -145,8 +143,6 @@ static mu_list_t rule_list; ...@@ -145,8 +143,6 @@ static mu_list_t rule_list;
145 mu_list_t list; 143 mu_list_t list;
146 int result; 144 int result;
147 struct node *node; 145 struct node *node;
148 struct { struct concat_segm *head, *tail; } concat;
149 struct concat_segm *segment;
150 } 146 }
151 147
152 %% 148 %%
...@@ -176,7 +172,7 @@ rule_line: /* empty */ ...@@ -176,7 +172,7 @@ rule_line: /* empty */
176 if (arg_list) 172 if (arg_list)
177 mu_list_destroy (&arg_list); 173 mu_list_destroy (&arg_list);
178 arg_list = NULL; 174 arg_list = NULL;
179 lex_arglist (0); 175 lex_reset ();
180 } 176 }
181 ; 177 ;
182 178
...@@ -219,39 +215,14 @@ stmt : '!' stmt ...@@ -219,39 +215,14 @@ stmt : '!' stmt
219 { 215 {
220 $$ = $2; 216 $$ = $2;
221 } 217 }
222 | string 218 | STRING
223 { 219 {
224 $$ = make_suffix_node (&$1, &@1); 220 $$ = make_suffix_node (&$1, &@1);
225 } 221 }
226 | function 222 | function
227 ; 223 ;
228 224
229 string : concat 225 priority : PRIORITY '(' arglist ')'
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 { 226 {
256 size_t count = 0; 227 size_t count = 0;
257 struct mimetypes_string *arg; 228 struct mimetypes_string *arg;
...@@ -275,19 +246,7 @@ maybe_priority: /* empty */ ...@@ -275,19 +246,7 @@ maybe_priority: /* empty */
275 | priority 246 | priority
276 ; 247 ;
277 248
278 oparen : '(' 249 function : IDENT '(' arglist ')'
279 {
280 lex_arglist (1);
281 }
282 ;
283
284 cparen : ')'
285 {
286 lex_arglist (0);
287 }
288 ;
289
290 function : IDENT oparen arglist cparen
291 { 250 {
292 struct mu_locus_range lr; 251 struct mu_locus_range lr;
293 lr.beg = @1.beg; 252 lr.beg = @1.beg;
...@@ -312,7 +271,7 @@ arglist : arg ...@@ -312,7 +271,7 @@ arglist : arg
312 } 271 }
313 ; 272 ;
314 273
315 arg : string 274 arg : STRING
316 ; 275 ;
317 276
318 %% 277 %%
...@@ -387,6 +346,9 @@ b_match (union argument *args) ...@@ -387,6 +346,9 @@ b_match (union argument *args)
387 True if bytes are valid printable ASCII (CR, NL, TAB, 346 True if bytes are valid printable ASCII (CR, NL, TAB,
388 BS, 32-126) 347 BS, 32-126)
389 */ 348 */
349 #define ISASCII(c) ((c) &&\
350 (strchr ("\n\r\t\b",c) \
351 || (32<=((unsigned) c) && ((unsigned) c)<=126)))
390 static int 352 static int
391 b_ascii (union argument *args) 353 b_ascii (union argument *args)
392 { 354 {
...@@ -402,13 +364,13 @@ b_ascii (union argument *args) ...@@ -402,13 +364,13 @@ b_ascii (union argument *args)
402 364
403 for (i = 0; i < args[1].number; i++) 365 for (i = 0; i < args[1].number; i++)
404 { 366 {
405 char c; 367 unsigned char c;
406 size_t n; 368 size_t n;
407 369
408 rc = mu_stream_read (mimeview_stream, &c, 1, &n); 370 rc = mu_stream_read (mimeview_stream, &c, 1, &n);
409 if (rc || n == 0) 371 if (rc || n == 0)
410 break; 372 break;
411 if (!mu_isascii (c)) 373 if (!ISASCII (c))
412 return 0; 374 return 0;
413 } 375 }
414 376
...@@ -419,10 +381,8 @@ b_ascii (union argument *args) ...@@ -419,10 +381,8 @@ b_ascii (union argument *args)
419 True if bytes are printable 8-bit chars (CR, NL, TAB, 381 True if bytes are printable 8-bit chars (CR, NL, TAB,
420 BS, 32-126, 128-254) 382 BS, 32-126, 128-254)
421 */ 383 */
422 #define ISPRINT(c) ((c) &&\ 384 #define ISPRINT(c) (ISASCII (c) \
423 (strchr ("\n\r\t\b",c) \ 385 || (128<=((unsigned) c) && ((unsigned) c)<=254))
424 || (32<=(c) && (c)<=126) \
425 || (128<=(c) && (c)<=254)))
426 static int 386 static int
427 b_printable (union argument *args) 387 b_printable (union argument *args)
428 { 388 {
...@@ -438,13 +398,13 @@ b_printable (union argument *args) ...@@ -438,13 +398,13 @@ b_printable (union argument *args)
438 398
439 for (i = 0; i < args[1].number; i++) 399 for (i = 0; i < args[1].number; i++)
440 { 400 {
441 char c; 401 unsigned char c;
442 size_t n; 402 size_t n;
443 403
444 rc = mu_stream_read (mimeview_stream, &c, 1, &n); 404 rc = mu_stream_read (mimeview_stream, &c, 1, &n);
445 if (rc || n == 0) 405 if (rc || n == 0)
446 break; 406 break;
447 if (!ISPRINT ((unsigned)c)) 407 if (!ISPRINT (c))
448 return 0; 408 return 0;
449 } 409 }
450 return 1; 410 return 1;
...@@ -552,8 +512,8 @@ b_char (union argument *args) ...@@ -552,8 +512,8 @@ b_char (union argument *args)
552 static int 512 static int
553 b_short (union argument *args) 513 b_short (union argument *args)
554 { 514 {
555 unsigned short val = args[1].number; 515 uint16_t val = args[1].number;
556 unsigned short buf; 516 uint16_t buf;
557 return compare_bytes (args, &val, &buf, sizeof (buf)); 517 return compare_bytes (args, &val, &buf, sizeof (buf));
558 } 518 }
559 519
...@@ -564,8 +524,8 @@ b_short (union argument *args) ...@@ -564,8 +524,8 @@ b_short (union argument *args)
564 static int 524 static int
565 b_int (union argument *args) 525 b_int (union argument *args)
566 { 526 {
567 unsigned int val = args[1].number; 527 uint32_t val = args[1].number;
568 unsigned int buf; 528 uint32_t buf;
569 return compare_bytes (args, &val, &buf, sizeof (buf)); 529 return compare_bytes (args, &val, &buf, sizeof (buf));
570 } 530 }
571 531
...@@ -604,7 +564,7 @@ b_contains (union argument *args) ...@@ -604,7 +564,7 @@ b_contains (union argument *args)
604 mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc); 564 mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc);
605 } 565 }
606 else if (count > str->len) 566 else if (count > str->len)
607 for (i = 0; i < count - str->len; i++) 567 for (i = 0; i <= count - str->len; i++)
608 if (buf[i] == str->ptr[0] && memcmp (buf + i, str->ptr, str->len) == 0) 568 if (buf[i] == str->ptr[0] && memcmp (buf + i, str->ptr, str->len) == 0)
609 { 569 {
610 free (buf); 570 free (buf);
...@@ -896,7 +856,16 @@ rule_cmp (const void *a, const void *b) ...@@ -896,7 +856,16 @@ rule_cmp (const void *a, const void *b)
896 struct rule_tab const *brule = b; 856 struct rule_tab const *brule = b;
897 857
898 if (arule->priority == brule->priority) 858 if (arule->priority == brule->priority)
859 {
860 if (arule->node->type == true_node
861 && brule->node->type != true_node)
862 return 1;
863 else if (brule->node->type == true_node
864 && arule->node->type != true_node)
865 return -1;
866 else
899 return mu_c_strcasecmp (arule->type, brule->type); 867 return mu_c_strcasecmp (arule->type, brule->type);
868 }
900 return arule->priority - brule->priority; 869 return arule->priority - brule->priority;
901 } 870 }
902 871
......
...@@ -33,12 +33,13 @@ ...@@ -33,12 +33,13 @@
33 33
34 static int dry_run; /* Dry run mode */ 34 static int dry_run; /* Dry run mode */
35 static int lint; /* Syntax check mode */ 35 static int lint; /* Syntax check mode */
36 static int identify; /* Print only the file's type */
36 static char *metamail; /* Name of metamail program, if requested */ 37 static char *metamail; /* Name of metamail program, if requested */
37 static char *mimetypes_config = DEFAULT_CUPS_CONFDIR; 38 static char *mimetypes_config = DEFAULT_CUPS_CONFDIR;
38 static char *no_ask_types; /* List of MIME types for which no questions 39 static char *no_ask_types; /* List of MIME types for which no questions
39 should be asked */ 40 should be asked */
40 static int interactive = -1; 41 static int interactive = -1;
41 char *mimeview_file; /* Name of the file to view */ 42 char const *mimeview_file; /* Name of the file to view */
42 mu_stream_t mimeview_stream; /* The corresponding stream */ 43 mu_stream_t mimeview_stream; /* The corresponding stream */
43 44
44 45
...@@ -122,6 +123,10 @@ static struct mu_option mimeview_options[] = { ...@@ -122,6 +123,10 @@ static struct mu_option mimeview_options[] = {
122 N_("test mime.types syntax and exit"), 123 N_("test mime.types syntax and exit"),
123 mu_c_bool, &lint }, 124 mu_c_bool, &lint },
124 125
126 { "identify", 'i', NULL, MU_OPTION_DEFAULT,
127 N_("identify MIME type of each file"),
128 mu_c_bool, &identify },
129
125 { "metamail", 0, N_("FILE"), MU_OPTION_ARG_OPTIONAL, 130 { "metamail", 0, N_("FILE"), MU_OPTION_ARG_OPTIONAL,
126 N_("use metamail to display files"), 131 N_("use metamail to display files"),
127 mu_c_string, NULL, cli_metamail }, 132 mu_c_string, NULL, cli_metamail },
...@@ -157,7 +162,7 @@ static char *capa[] = { ...@@ -157,7 +162,7 @@ static char *capa[] = {
157 }; 162 };
158 163
159 static int 164 static int
160 open_file (char *name) 165 open_file (char const *name)
161 { 166 {
162 int rc; 167 int rc;
163 struct stat st; 168 struct stat st;
...@@ -190,10 +195,19 @@ close_file () ...@@ -190,10 +195,19 @@ close_file ()
190 } 195 }
191 196
192 void 197 void
193 display_file (const char *type) 198 display_file (const char *file, const char *type)
194 { 199 {
195 int status; 200 int status;
196 201
202 if (identify)
203 {
204 printf ("%s: %s\n", file, type ? type : "unknown");
205 return;
206 }
207
208 if (!type)
209 return;
210
197 if (metamail) 211 if (metamail)
198 { 212 {
199 char *argv[7]; 213 char *argv[7];
...@@ -205,7 +219,7 @@ display_file (const char *type) ...@@ -205,7 +219,7 @@ display_file (const char *type)
205 219
206 argv[3] = "-c"; 220 argv[3] = "-c";
207 argv[4] = (char*) type; 221 argv[4] = (char*) type;
208 argv[5] = mimeview_file; 222 argv[5] = (char*) mimeview_file;
209 argv[6] = NULL; 223 argv[6] = NULL;
210 224
211 if (mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE0)) 225 if (mu_debug_level_p (MU_DEBCAT_MIME, MU_DEBUG_TRACE0))
...@@ -269,12 +283,11 @@ main (int argc, char **argv) ...@@ -269,12 +283,11 @@ main (int argc, char **argv)
269 while (argc--) 283 while (argc--)
270 { 284 {
271 const char *type; 285 const char *type;
272 286 char const *file = *argv++;
273 if (open_file (*argv++)) 287 if (open_file (file))
274 continue; 288 continue;
275 type = get_file_type (); 289 type = get_file_type ();
276 if (type) 290 display_file (file, type);
277 display_file (type);
278 close_file (); 291 close_file ();
279 } 292 }
280 293
......
...@@ -37,24 +37,17 @@ int mimetypes_open (const char *name); ...@@ -37,24 +37,17 @@ 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_lex_init (void); 39 void mimetypes_lex_init (void);
40 void lex_arglist (int); 40
41 void lex_reset (void);
41 void *mimetypes_malloc (size_t size); 42 void *mimetypes_malloc (size_t size);
42 43
43 struct mimetypes_string *mimetypes_string_dup (struct mimetypes_string *s); 44 struct mimetypes_string *mimetypes_string_dup (struct mimetypes_string *s);
44 45
45 const char *get_file_type (void); 46 const char *get_file_type (void);
46 47
47 extern char *mimeview_file; 48 extern char const *mimeview_file;
48 extern mu_stream_t mimeview_stream; 49 extern mu_stream_t mimeview_stream;
49 50
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 51 struct mu_locus_range
59 { 52 {
60 struct mu_locus beg; 53 struct mu_locus beg;
......
1 atconfig
2 atlocal
3 bf
4 package.m4
5 testsuite
6 testsuite.dir
7 testsuite.log
1 # This file is part of GNU Mailutils.
2 # Copyright (C) 2017 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # GNU Mailutils is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16
17 EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4
18 DISTCLEANFILES = atconfig $(check_SCRIPTS)
19 MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE)
20
21 ## ------------ ##
22 ## package.m4. ##
23 ## ------------ ##
24
25 $(srcdir)/package.m4: $(top_srcdir)/configure.ac
26 $(AM_V_GEN){ \
27 echo '# Signature of the current package.'; \
28 echo 'm4_define([AT_PACKAGE_NAME], [@PACKAGE_NAME@])'; \
29 echo 'm4_define([AT_PACKAGE_TARNAME], [@PACKAGE_TARNAME@])'; \
30 echo 'm4_define([AT_PACKAGE_VERSION], [@PACKAGE_VERSION@])'; \
31 echo 'm4_define([AT_PACKAGE_STRING], [@PACKAGE_STRING@])'; \
32 echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \
33 } >$(srcdir)/package.m4
34
35 ## -------------------------- ##
36 ## Non-installable programs ##
37 ## -------------------------- ##
38
39 noinst_PROGRAMS = bf
40
41 ## ------------ ##
42 ## Test suite. ##
43 ## ------------ ##
44
45 TESTSUITE_AT = testsuite.at
46
47 TESTSUITE = $(srcdir)/testsuite
48 M4=m4
49
50 AUTOTEST = $(AUTOM4TE) --language=autotest
51 $(TESTSUITE): package.m4 $(TESTSUITE_AT) $(top_srcdir)/testsuite/testsuite.inc
52 $(AM_V_GEN)$(AUTOTEST) -I $(srcdir) -I $(top_srcdir)/testsuite testsuite.at -o $@.tmp
53 $(AM_V_at)mv $@.tmp $@
54
55 atconfig: $(top_builddir)/config.status
56 cd $(top_builddir) && ./config.status tests/$@
57
58 clean-local:
59 @test ! -f $(TESTSUITE) || $(SHELL) $(TESTSUITE) --clean
60
61 check-local: atconfig atlocal $(TESTSUITE)
62 @$(SHELL) $(TESTSUITE)
63
64 # Run the test suite on the *installed* tree.
65 #installcheck-local:
66 # $(SHELL) $(TESTSUITE) AUTOTEST_PATH=$(exec_prefix)/bin
67
68
1 # @configure_input@ -*- shell-script -*-
2 # Configurable variable values for Mailutils test suite.
3
4 PATH=@abs_builddir@:@abs_top_builddir@/mimeview:$top_srcdir:$srcdir:$PATH
5
1 /* This file is part of the GNU Mailutils testsuite.
2 Copyright (C) 2017 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <limits.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include <inttypes.h>
24
25 typedef int (*ACTION) (FILE *, char *);
26
27 int
28 seek_file (FILE *fp, char *arg)
29 {
30 long off;
31 int whence;
32
33 switch (arg[0])
34 {
35 case '+':
36 whence = SEEK_CUR;
37 arg++;
38 break;
39
40 case '-':
41 whence = SEEK_CUR;
42 break;
43
44 case '$':
45 whence = SEEK_END;
46 arg++;
47 break;
48
49 default:
50 whence = SEEK_SET;
51 }
52
53 if (sscanf (arg, "%ld", &off) != 1)
54 {
55 fprintf (stderr, "bad offset: %s\n", arg);
56 abort ();
57 }
58 return fseek (fp, off, whence);
59 }
60
61 int
62 write_string (FILE *fp, char *arg)
63 {
64 size_t n = strlen (arg);
65 return fwrite (arg, n, 1, fp) != 1;
66 }
67
68 int
69 write_byte (FILE *fp, char *arg)
70 {
71 int c;
72 if (strlen (arg) == 3
73 && (arg[0] == '\'' || arg[0] == '"'))
74 c = arg[1];
75 else
76 {
77 char *p;
78 unsigned long n = strtoul (arg, &p, 0);
79 if (*p || n > UCHAR_MAX)
80 {
81 errno = EINVAL;
82 return -1;
83 }
84 c = n;
85 }
86 return fwrite (&c, 1, 1, fp) != 1;
87 }
88
89 int
90 write_short (FILE *fp, char *arg)
91 {
92 uint16_t val;
93 char *p;
94 unsigned long n = strtoul (arg, &p, 0);
95 if (*p || n > UINT16_MAX)
96 {
97 errno = EINVAL;
98 return -1;
99 }
100 val = n;
101 return fwrite (&val, sizeof(val), 1, fp) != 1;
102 }
103
104 int
105 write_int (FILE *fp, char *arg)
106 {
107 uint32_t val;
108 char *p;
109 unsigned long n = strtoul (arg, &p, 0);
110 if (*p || n > UINT32_MAX)
111 {
112 errno = EINVAL;
113 return -1;
114 }
115 val = n;
116 return fwrite (&val, sizeof(val), 1, fp) != 1;
117 }
118
119 static struct dispatch {
120 char *opt;
121 int (*act) (FILE *, char *);
122 } dispatch[] = {
123 { "-seek", seek_file },
124 { "-string", write_string },
125 { "-byte", write_byte },
126 { "-short", write_short },
127 { "-int", write_int },
128 { NULL }
129 };
130
131 static ACTION
132 find_action (char const *opt)
133 {
134 struct dispatch *p;
135
136 for (p = dispatch; p->opt; p++)
137 if (strcmp (p->opt, opt) == 0)
138 return p->act;
139 return NULL;
140 }
141
142 /*
143 -seek OFF
144 -string STRING
145 -byte BYTE
146 -short SHORT
147 -int INT
148 -repeat N
149 */
150 int
151 main (int argc, char **argv)
152 {
153 char *name;
154 FILE *fp;
155 ACTION action;
156 char **pp;
157
158 assert (argc > 1);
159
160 name = argv[1];
161 fp = fopen (name, "w");
162 if (!fp)
163 {
164 perror (name);
165 abort ();
166 }
167
168 pp = argv + 2;
169 while (*pp)
170 {
171 char *opt = *pp++, *arg;
172
173 if (opt[0] != '-')
174 {
175 fprintf (stderr, "not an option: %s\n", opt);
176 abort ();
177 }
178
179 action = find_action (opt);
180 if (!action)
181 {
182 fprintf (stderr, "unknown action: %s\n", opt);
183 abort ();
184 }
185
186 if (!*pp)
187 {
188 fprintf (stderr, "argument to %s missing\n", opt);
189 abort ();
190 }
191 arg = *pp++;
192 if (action (fp, arg))
193 {
194 fprintf (stderr, "%s %s: %s\n", opt, arg, strerror (errno));
195 abort ();
196 }
197 }
198 fclose (fp);
199 return 0;
200 }
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2017 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # GNU Mailutils is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16
17 m4_include([testsuite.inc])
18
19 dnl ------------------------------------------------------------
20 dnl MIMEVIEW_OPTIONS -- default options for mimeview
21 m4_pushdef([MIMEVIEW_OPTIONS],[--no-site --no-user])
22
23 m4_pushdef([__prepare_input],[
24 m4_if([$1],[],[],[bf $1 $2
25 __prepare_input(m4_shift(m4_shift(m4_shift($@))))])])
26
27 m4_pushdef([prepare_input],[__prepare_input(m4_shift(m4_shift($@)))])
28
29 m4_pushdef([__select_args],[dnl
30 m4_if([$2],[],[$1],[dnl
31 __select_args([$1 $2], m4_shift(m4_shift(m4_shift(m4_shift($@)))))])])
32
33 m4_pushdef([select_args],[__select_args([],m4_shift(m4_shift($@)))])
34
35 m4_pushdef([__build_expect],[dnl
36 m4_if([$2],[],[$1],[__build_expect([dnl
37 $1[]dnl
38 $2: $4
39 ],m4_shift(m4_shift(m4_shift(m4_shift($@)))))])])
40
41 m4_pushdef([build_expect],[__build_expect([],m4_shift(m4_shift($@)))])
42
43 # MIMETEST(NAME,TYPES,FILE,CONTENT,RES)
44 m4_pushdef([MIMETEST],[
45 AT_SETUP([$1])
46 AT_KEYWORDS([mimeview])
47 AT_CHECK([
48 AT_DATA([mime.types],[$2
49 ])
50 prepare_input($@)
51 mimeview MIMEVIEW_OPTIONS --identify -f mime.types select_args($@)
52 ],
53 [0],
54 [build_expect($@)])
55 AT_CLEANUP
56 ])
57
58 dnl ------------------------------------------------------------
59
60 AT_INIT
61 AT_TESTED([mimeview])
62 MUT_VERSION([mimeview])
63
64 MIMETEST([default],
65 [application/octet-stream],
66 [input], [], [application/octet-stream])
67
68 MIMETEST([suffixes],
69 [foo/x-bar bar baz
70 foo/x-qux qux quux
71 ],
72 [a.bar], [], [foo/x-bar],
73 [a.baz], [], [foo/x-bar],
74 [a.quux], [], [foo/x-qux],
75 [a.qx], [], [unknown])
76
77 MIMETEST([default ordering],
78 [text/foo bar
79 text/bar bar
80 ],
81 [a.bar], [], [text/bar])
82
83 MIMETEST([priority],
84 [text/bar bar
85 text/foo bar priority(20)
86 ],
87 [a.bar], [], [text/foo])
88
89 AT_BANNER([Functions])
90
91 # match("pattern") Pattern match on filename
92 MIMETEST([match],
93 [application/x-csource match(*.c)
94 ],
95 [a.c],[],[application/x-csource],
96 [a.c1],[],[unknown])
97
98 # ascii(offset,length) True if bytes are valid printable ASCII
99 # (CR, NL, TAB, BS, 32-126)
100 MIMETEST([ascii],
101 [application/x-bar ascii(16,6)
102 ],
103 [one],[-seek 16 -string foobar -int 100],[application/x-bar],
104 [two],[-seek 16 -string fooba -byte 129],[unknown])
105
106 # printable(offset,length) True if bytes are printable 8-bit chars
107 # (CR, NL, TAB, BS, 32-126, 128-254)
108 MIMETEST([printable],
109 [application/x-bar printable(16,6)
110 ],
111 [one],[-seek 16 -string foobar -int 100],[application/x-bar],
112 [two],[-seek 16 -string fooba -byte 129],[application/x-bar],
113 [three],[-seek 16 -string fooba -byte 127],[unknown])
114
115 # regex(offset,"regex") True if bytes match regular expression
116 MIMETEST([regex],
117 [application/pdf regex(0,^[[\n\r]]*%PDF)
118 ],
119 [one],[-byte 10 -byte 10 -byte 13 -byte 10 -string %PDF],[application/pdf],
120 [two],[-byte 10 -byte 10 -byte 13 -byte 7 -string %PDF],[unknown])
121
122 # string(offset,"string") True if bytes are identical to string
123 MIMETEST([string],
124 [application/x-foo string(5,FOO)
125 ],
126 [one],[-seek 5 -string FOO],[application/x-foo],
127 [two],[-seek 4 -string FOO],[unknown])
128
129 # istring(offset,"string") True if bytes are identical to
130 # case-insensitive string
131 MIMETEST([istring],
132 [application/x-foo istring(5,FOO)
133 ],
134 [one],[-seek 5 -string foO],[application/x-foo],
135 [two],[-seek 4 -string FOO],[unknown])
136
137 # char(offset,value) True if byte is identical
138 MIMETEST([char],
139 [application/x-foo char(5,15)
140 ],
141 [one],[-seek 5 -byte 15],[application/x-foo],
142 [two],[-seek 5 -byte 1],[unknown])
143
144 # short(offset,value) True if 16-bit integer is identical
145 MIMETEST([short],
146 [application/x-foo short(5,1600)
147 ],
148 [one],[-seek 5 -short 1600],[application/x-foo],
149 [two],[-seek 5 -short 1601],[unknown])
150
151 # int(offset,value) True if 32-bit integer is identical
152 MIMETEST([int],
153 [application/x-foo int(5,16578)
154 ],
155 [one],[-seek 5 -int 16578],[application/x-foo],
156 [two],[-seek 5 -int 16579],[unknown])
157
158 # locale("string") True if current locale matches string
159 # FIXME
160
161 # contains(offset,range,"string") True if the range contains the string
162 MIMETEST([contains],
163 [application/x-foo contains(10,1024,"TESTSTRING")
164 ],
165 [one],[-seek 512 -string TESTSTRING],[application/x-foo],
166 [two],[-seek 512 -string TEST],[unknown])
167
168 MIMETEST([argument strings],
169 [application/x-foo string(0,"FOO")
170 application/x-bar string(0,'B A R')
171 application/x-baz string(0,"B A"Z<1B0103>BAZ)
172 application/x-qux string(0,<1B>45" Q "<01>)
173 ],
174 [one],[-string FOO],[application/x-foo],
175 [two],[-string 'B A R'],[application/x-bar],
176 [three],[-string "B AZ" -byte 0x1b -byte 0x01 -byte 0x03 -string BAZ],[application/x-baz],
177 [four],[-byte 0x1b -string '45 Q ' -byte 0x01],[application/x-qux])
178
179 MIMETEST([logical or],
180 [text/x-bar bar baz string(0,bar) printable(3,10)
181 ],
182 [one.bar],[],[text/x-bar],
183 [one.baz],[],[text/x-bar],
184 [foo],[-string bar],[text/x-bar],
185 [bar],[-seek 3 -string teststring],[text/x-bar],
186 [baz],[-seek 3 -string test -byte 0 -string tring],[unknown])
187
188 MIMETEST([logical and],
189 [text/x-foo bar + string(0,bar<10>) + printable(4,10)
190 ],
191 [one.bar],[-string bar -byte 0x10 -string TESTSTRING],[text/x-foo],
192 [one],[-string bar -byte 0x10 -string TESTSTRING],[unknown],
193 [two.bar],[-string bar -byte 0x13 -byte 0x10 -string TEST],[unknown])
194
195 MIMETEST([grouping],
196 [text/x-foo bar (string(0,bar) + printable(4,10))
197 ],
198 [one.bar],[-string foo],[text/x-foo],
199 [two.baz],[-string bar -byte 0x10 -string TESTSTRING],[text/x-foo],
200 [three],[-string bar -byte 0x13 -byte 0x10 -string TESTSTRING],[unknown])