1 %top {
2 /* GNU Mailutils -- a suite of utilities for electronic mail
3    Copyright (C) 2005-2021 Free Software Foundation, Inc.
4 
5    GNU Mailutils is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3, or (at your option)
8    any later version.
9 
10    GNU Mailutils is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
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/>. */
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 }
22 
23 %{
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <sys/stat.h>
27 #include <mimeview.h>
28 #include <grammar.h>
29 #include <mailutils/io.h>
30 
31 static mu_linetrack_t trk;
32 struct mu_locus_point string_beg;
33 
34 static mu_opool_t pool;
35 
36 static unsigned
digit_to_number(char c)37 digit_to_number (char c)
38 {
39   return (unsigned) (c >= '0' && c <= '9' ? c-'0' :
40                      c >= 'A' && c <= 'Z' ? c-'A'+10 :
41                      c-'a'+10);
42 }
43 
44 static void
drop_string(void)45 drop_string (void)
46 {
47   mu_opool_clear (pool);
48 }
49 
50 static void
finish_string(void)51 finish_string (void)
52 {
53   mu_opool_append_char (pool, 0);
54   yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
55   yylval.string.len--;
56 
57   mu_locus_point_copy (&yylloc.end, &yylloc.beg);
58   yylloc.end.mu_col--;
59   mu_locus_point_copy (&yylloc.beg, &string_beg);
60   mu_locus_point_deinit (&string_beg);
61 
62   if (mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE5))
63     {
64       size_t i;
65       mu_debug_log_begin ("string %zu: ", yylval.string.len);
66       for (i = 0; i < yylval.string.len; i++)
67 	if (mu_isprint (yylval.string.ptr[i]))
68 	  mu_debug_log_cont ("%c", yylval.string.ptr[i]);
69         else
70 	  mu_debug_log_cont ("\\%03o", yylval.string.ptr[i]);
71       mu_debug_log_nl ();
72     }
73 #if 0
74   YY_LOCATION_PRINT (stderr, yylloc);
75   fprintf (stderr, ": %s\n", yylval.string.ptr);
76 #endif
77 }
78 
79 #define YY_USER_ACTION							\
80   do									\
81     {									\
82       mu_linetrack_advance (trk, &yylloc, yytext, yyleng);		\
83       mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,			\
84 		       MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &yylloc);	\
85     }									\
86   while (0);
87 
88 %}
89 
90 %x RULE ARGS ASTRING
91 X [0-9a-fA-F]
92 IDENT [a-zA-Z_\.][a-zA-Z0-9_\.-]*
93 WS [ \t][ \t]*
94 %%
95 
96 <INITIAL>{
97      /* Comments */
98 ^#.*\n               ;
99 \n                   ;
100 ^[^ \t\n/]+"/"[^ \t\n]+ {
101   mu_opool_append (pool, yytext, yyleng);
102   mu_opool_append_char (pool, 0);
103   yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
104   yylval.string.len--;
105   BEGIN (RULE);
106   return TYPE;
107 }
108 
109 . {
110   mu_error (_("type/subtype is missing"));
111   return BOGUS;
112 }
113 }
114 
115 <RULE>{
116 \\\n                 ;
117 \n                   {
118   BEGIN (INITIAL);
119   return EOL;
120 }
121 {WS}                 ;
122 
123    /* Operators */
124 "!"|"+"|","|"("|")"|"/"  return yytext[0];
125   /* Special cases: && and ||. Docs don't say anything about them, but
126      I've found them in my mime.types file...         --Sergey */
127 "&&"  return '+';
128 "||"  return ',';
129 
130 "priority"/"(" {
131   return PRIORITY;
132 }
133 
134 {IDENT}/"(" {
135   mu_opool_append (pool, yytext, yyleng);
136   mu_opool_append_char (pool, 0);
137   yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
138   BEGIN (ARGS);
139   return IDENT;
140 }
141 
142 [a-zA-Z0-9_.-]+/[^(] {
143   mu_opool_append (pool, yytext, yyleng);
144   yylval.string.ptr = mu_opool_finish (pool, &yylval.string.len);
145   return STRING;
146 }
147 
148 . mu_error("unexpected character '%c'", yytext[0]);
149 }
150 
151 <ARGS>{
152 "("|","    return yytext[0];
153 ")"  {
154   BEGIN (RULE);
155   return yytext[0];
156 }
157 {WS} mu_error ("unexpected whitespace in argument list");
158 \n   {
159   mu_error ("unexpected newline in argument list");
160   return BOGUS;
161 }
162 . {
163   mu_locus_point_copy (&string_beg, &yylloc.beg);
164   mu_linetrack_retreat (trk, 1);
165   yyless (0);
166   BEGIN (ASTRING);
167 }
168 }
169 
170 <ASTRING>{
171   /* Quoted string */
172 \"[^"\n]*\"        {
173   mu_opool_append (pool, yytext+1, yyleng-2);
174 }
175 "'"[^'\n]*"'" {
176   mu_opool_append (pool, yytext+1, yyleng-2);
177 }
178 
179   /* Hex string */
180 "<"({X}{X})+">" {
181   int i;
182   for (i = 1; i < yyleng - 2; i += 2)
183     {
184       mu_opool_append_char (pool, digit_to_number (yytext[i])*16
185                                   + digit_to_number (yytext[i+1]));
186     }
187 }
188 
189   /* Unquoted character sequence */
190 [^ \t\n,)<"']+/[^"'<] {
191   mu_opool_append (pool, yytext, yyleng);
192 }
193 
194 [^ \t\n,)<"]+/< {
195   mu_opool_append (pool, yytext, yyleng);
196 }
197 
198 [^ \t\n,)<"]+/["'] {
199   mu_opool_append (pool, yytext, yyleng);
200 }
201 
202 \n   {
203   mu_error ("unexpected newline in argument");
204   drop_string ();
205   return BOGUS;
206 }
207 
208 . {
209   mu_linetrack_retreat (trk, 1);
210   yyless (0);
211   BEGIN (ARGS);
212   finish_string ();
213   return STRING;
214 }
215 }
216 
217 %%
218 int
219 mimetypes_open (const char *name)
220 {
221   struct stat st;
222   int mode;
223   char *filename;
224 
225   yy_flex_debug = mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE4);
226 
227   if (stat (name, &st))
228     {
229       mu_error (_("cannot stat `%s': %s"), name, mu_strerror (errno));
230       return -1;
231     }
232 
233   if (S_ISDIR (st.st_mode))
234     filename = mu_make_file_name (name, "mime.types");
235   else
236     filename = mu_strdup (name);
237 
238   yyin = fopen (filename, "r");
239   if (!yyin)
240     {
241       mu_error (_("cannot open `%s': %s"), filename, mu_strerror (errno));
242       free (filename);
243       return -1;
244     }
245 
246   MU_ASSERT (mu_linetrack_create (&trk, filename, 3));
247   free (filename);
248 
249   mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
250                    MU_IOCTL_LOGSTREAM_GET_MODE, &mode);
251   mode |= MU_LOGMODE_LOCUS;
252   mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
253                    MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
254 
255   mu_opool_create (&pool, MU_OPOOL_ENOMEMABRT);
256   return 0;
257 }
258 
259 void
260 mimetypes_close ()
261 {
262   int mode;
263 
264   fclose (yyin);
265   mu_locus_range_deinit (&yylloc);
266   mu_linetrack_destroy (&trk);
267   mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
268                    MU_IOCTL_LOGSTREAM_GET_MODE, &mode);
269   mode &= ~MU_LOGMODE_LOCUS;
270   mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
271                    MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
272   mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
273                    MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, NULL);
274 }
275 
276 int
277 yyerror (char *s)
278 {
279   mu_error ("%s", s);
280   return 0;
281 }
282 
283 int
284 yywrap ()
285 {
286   return 1;
287 }
288 
289 struct mimetypes_string *
290 mimetypes_string_dup (struct mimetypes_string *s)
291 {
292   mu_opool_append (pool, s, sizeof *s);
293   return mu_opool_finish (pool, NULL);
294 }
295 
296 void *
297 mimetypes_malloc (size_t size)
298 {
299   mu_opool_alloc (pool, size);
300   return mu_opool_finish (pool, NULL);
301 }
302 
303 /* Position input at the beginning of the next rule as a final part of error
304    recovery */
305 void
306 lex_next_rule (void)
307 {
308   int c;
309   int dbg = yy_flex_debug
310                || mu_debug_level_p (MU_DEBCAT_APP, MU_DEBUG_TRACE6);
311 
312   if (dbg)
313     {
314       YY_LOCATION_PRINT (stderr, yylloc);
315       fprintf (stderr, ": started error recovery\n");
316     }
317   while ((c = input ()) != EOF)
318     {
319       char ch = c;
320       if (!mu_isspace (c) && mu_linetrack_at_bol (trk))
321 	{
322 	  unput (c);
323 	  break;
324  	}
325       mu_linetrack_advance (trk, &yylloc, &ch, 1);
326     }
327   if (dbg)
328     {
329       struct mu_locus_range lr = MU_LOCUS_RANGE_INITIALIZER;
330       mu_linetrack_locus (trk, &lr.beg);
331       YY_LOCATION_PRINT (stderr, lr);
332       fprintf (stderr, ": finished error recovery\n");
333       mu_locus_point_deinit (&lr.beg);
334     }
335   BEGIN (RULE);
336   unput ('\n');
337   mu_linetrack_retreat (trk, 1);
338  }
339