summaryrefslogtreecommitdiff
path: root/mimetypes/lexer.l
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-01-03 12:23:44 +0200
committerSergey Poznyakoff <gray@gnu.org>2018-01-03 12:23:52 +0200
commit80ed5e611de0e31eed65ee207f1fd64ad097e6d1 (patch)
tree40979fe5ecadaa3d1351c645ff7988a87218e142 /mimetypes/lexer.l
parenta4edd153e4cdf703c98008313743b112274e760f (diff)
downloadfileserv-80ed5e611de0e31eed65ee207f1fd64ad097e6d1.tar.gz
fileserv-80ed5e611de0e31eed65ee207f1fd64ad097e6d1.tar.bz2
Add mimetypes library.
Ported from GNU Mailutils.
Diffstat (limited to 'mimetypes/lexer.l')
-rw-r--r--mimetypes/lexer.l371
1 files changed, 371 insertions, 0 deletions
diff --git a/mimetypes/lexer.l b/mimetypes/lexer.l
new file mode 100644
index 0000000..568a5cf
--- /dev/null
+++ b/mimetypes/lexer.l
@@ -0,0 +1,371 @@
+%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 <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+}
+
+%{
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <ctype.h>
+#include "mtint.h"
+#include "grammar.h"
+
+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)
+ abort ();
+ }
+}
+
+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)
+ abort ();
+ 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)
+ abort ();
+ 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]*
+%%
+
+<INITIAL>{
+ /* Comments */
+^#.*\n ;
+\n ;
+^[^ \t\n/]+"/"[^ \t\n]+ {
+ string_append (yytext, yyleng);
+ finish_string ();
+ BEGIN (RULE);
+ return TYPE;
+}
+
+. {
+ yyerror ("type/subtype is missing");
+ return BOGUS;
+}
+}
+
+<RULE>{
+\\\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;
+}
+
+. yyerror("unexpected character '%c'", yytext[0]);
+}
+
+<ARGS>{
+"("|"," 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);
+}
+}
+
+<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 ("MIMETYPE_DEBUG_LEX");
+ yy_flex_debug = p ? (*p - '0') : 0;
+
+ if (stat (name, &st))
+ {
+ yyerror ("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)
+ abort ();
+ strcpy (filename, name);
+ strcat (filename, "/");
+ strcat (filename, fname);
+ }
+ else
+ {
+ filename = strdup (name);
+ if (!filename)
+ abort ();
+ }
+
+ yyin = fopen (filename, "r");
+ if (!yyin)
+ {
+ yyerror ("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);
+}

Return to:

Send suggestions and report system problems to the System administrator.