%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);
}