%top { /* This file is part of fileserv. Copyright (C) 2017, 2018 Sergey Poznyakoff Fileserv is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Fileserv is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with fileserv. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif } %{ #include #include #include #include #include #include "mtint.h" #include "grammar.h" #define yylval yymtlval #define yylloc yymtlloc #define yyerror yymterror int yyerror (char *s); static linetrack_t trk; struct locus_point string_beg; char *string_buffer; size_t string_level; size_t string_size; static void string_moremem (size_t size) { if (string_size - string_level < size) { while (string_size - string_level < size) { if ((size_t) -1 / 3 * 2 <= string_size) abort (); string_size += (string_size + 1) / 2 + 1; } string_buffer = realloc (string_buffer, string_size); if (!string_buffer) mimetypes_nomem (); } } static void string_append (char const *b, size_t n) { string_moremem (n); memcpy (string_buffer + string_level, b, n); string_level += n; } static void string_append_char (int c) { string_moremem (1); string_buffer[string_level++] = c; } static unsigned digit_to_number (char c) { return (unsigned) (c >= '0' && c <= '9' ? c-'0' : c >= 'A' && c <= 'Z' ? c-'A'+10 : c-'a'+10); } static void drop_string (void) { string_level = 0; } static void finish_string (void) { yylval.string.ptr = malloc (string_level + 1); if (!yylval.string.ptr) mimetypes_nomem (); memcpy (yylval.string.ptr, string_buffer, string_level); yylval.string.ptr[string_level] = 0; yylval.string.len = string_level; string_level = 0; } static void finish_astring (void) { yylval.string.ptr = malloc (string_level + 1); if (!yylval.string.ptr) mimetypes_nomem (); memcpy (yylval.string.ptr, string_buffer, string_level); yylval.string.ptr[string_level] = 0; yylval.string.len = string_level; locus_point_copy (&yylloc.end, &yylloc.beg); yylloc.end.col--; locus_point_copy (&yylloc.beg, &string_beg); locus_point_deinit (&string_beg); string_level = 0; if (yy_flex_debug) { size_t i; printf ("string %zu: ", yylval.string.len); for (i = 0; i < yylval.string.len; i++) if (isprint (yylval.string.ptr[i])) printf ("%c", yylval.string.ptr[i]); else printf ("\\%03o", yylval.string.ptr[i]); putchar ('\n'); } #if 0 YY_LOCATION_PRINT (stderr, yylloc); fprintf (stderr, ": %s\n", yylval.string.ptr); #endif } #define YY_USER_ACTION \ linetrack_advance (trk, &yylloc, yytext, yyleng); %} %x RULE ARGS ASTRING X [0-9a-fA-F] IDENT [a-zA-Z_\.][a-zA-Z0-9_\.-]* WS [ \t][ \t]* %% { /* Comments */ ^#.*\n ; \n ; ^[^ \t\n/]+"/"[^ \t\n]+ { string_append (yytext, yyleng); finish_string (); BEGIN (RULE); return TYPE; } . { yyerror ("type/subtype is missing"); return BOGUS; } } { \\\n ; \n { BEGIN (INITIAL); return EOL; } {WS} ; /* Operators */ "!"|"+"|","|"("|")"|"/" return yytext[0]; /* Special cases: && and ||. Docs don't say anything about them, but I've found them in my mime.types file... --Sergey */ "&&" return '+'; "||" return ','; "priority"/"(" { return PRIORITY; } {IDENT}/"(" { string_append (yytext, yyleng); finish_string (); BEGIN (ARGS); return IDENT; } [a-zA-Z0-9_.-]+/[^(] { string_append (yytext, yyleng); finish_string (); return STRING; } . { struct locus_range lr = LOCUS_RANGE_INITIALIZER; linetrack_locus (trk, &lr.beg); mimetypes_error_at (&lr, "unexpected character '%c'", yytext[0]); locus_range_deinit (&lr); } } { "("|"," return yytext[0]; ")" { BEGIN (RULE); return yytext[0]; } {WS} yyerror ("unexpected whitespace in argument list"); \n { yyerror ("unexpected newline in argument list"); return BOGUS; } . { locus_point_copy (&string_beg, &yylloc.beg); linetrack_retreat (trk, 1); yyless (0); BEGIN (ASTRING); } } { /* Quoted string */ \"[^"\n]*\" { string_append (yytext+1, yyleng-2); } "'"[^'\n]*"'" { string_append (yytext+1, yyleng-2); } /* Hex string */ "<"({X}{X})+">" { int i; for (i = 1; i < yyleng - 2; i += 2) { string_append_char (digit_to_number (yytext[i])*16 + digit_to_number (yytext[i+1])); } } /* Unquoted character sequence */ [^ \t\n,)<"']+/[^"'<] { string_append (yytext, yyleng); } [^ \t\n,)<"]+/< { string_append (yytext, yyleng); } [^ \t\n,)<"]+/["'] { string_append (yytext, yyleng); } \n { yyerror ("unexpected newline in argument"); drop_string (); return BOGUS; } . { linetrack_retreat (trk, 1); yyless (0); BEGIN (ARGS); finish_astring (); return STRING; } } %% int mimetypes_open (const char *name) { struct stat st; char *filename; char *p; p = getenv ("MIMETYPES_DEBUG_LEX"); yy_flex_debug = p ? (*p - '0') : 0; if (stat (name, &st)) { mimetypes_error ("cannot stat `%s': %s", name, strerror (errno)); return -1; } if (S_ISDIR (st.st_mode)) { size_t blen = strlen (name); static char *fname = "mime.types"; while (blen && name[blen-1] == '/') blen--; if (!blen) abort (); filename = malloc (blen + 1 + strlen (fname) + 1); if (!filename) mimetypes_nomem (); strcpy (filename, name); strcat (filename, "/"); strcat (filename, fname); } else { filename = strdup (name); if (!filename) abort (); } yyin = fopen (filename, "r"); if (!yyin) { mimetypes_error ("cannot open `%s': %s", filename, strerror (errno)); free (filename); return -1; } assert (linetrack_create (&trk, filename, 3) == 0); free (filename); drop_string (); return 0; } void mimetypes_close (void) { fclose (yyin); locus_range_deinit (&yylloc); linetrack_destroy (&trk); } int yyerror (char *s) { struct locus_range lr = LOCUS_RANGE_INITIALIZER; linetrack_locus (trk, &lr.beg); mimetypes_error_at (&lr, "%s", s); locus_range_deinit (&lr); return 0; } int yywrap (void) { return 1; } /* Position input at the beginning of the next rule as a final part of error recovery */ void lex_next_rule (void) { int c; if (yy_flex_debug) { YY_LOCATION_PRINT (stderr, yylloc); fprintf (stderr, ": started error recovery\n"); } while ((c = input ()) != EOF) { char ch = c; if (!isspace (c) && linetrack_at_bol (trk)) { unput (c); break; } linetrack_advance (trk, &yylloc, &ch, 1); } if (yy_flex_debug) { struct locus_range lr = LOCUS_RANGE_INITIALIZER; linetrack_locus (trk, &lr.beg); YY_LOCATION_PRINT (stderr, lr); fprintf (stderr, ": finished error recovery\n"); locus_point_deinit (&lr.beg); } BEGIN (RULE); unput ('\n'); linetrack_retreat (trk, 1); }