%{
/* ckaliases - verify syntax of sendmail-style alias files
Copyright (C) 2005, 2007 Sergey Poznyakoff
This program 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 of the License, or (at your
option) any later version.
This program 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 this program. If not, see . */
#include "ckaliases.h"
#include "gram.h"
static void line_begin (void);
static void line_add (char *text, size_t len);
static void line_add_unescape (char *text, size_t len);
static void line_finish (void);
struct obstack string_stk;
char *file_name;
int line_num;
%}
%x STR
IDENT [a-zA-Z0-9_\-+\./]+
WS [ \t]
SPEC [:@\\]
%%
/* Comments */
#.*\n { line_num++; return EOL; }
/* White space */
^{WS}+\n { line_num++; return EOL; }
{WS}+ ;
/* Names and emails */
:include: return INCLUDE;
^{IDENT} {
line_begin();
line_add(yytext, yyleng);
line_finish ();
return LHS; }
{IDENT}@{IDENT} {
line_begin();
line_add(yytext, yyleng);
line_finish();
return EMAIL; }
{IDENT} { line_begin();
line_add(yytext, yyleng);
line_finish();
return IDENT; }
/* Quoted strings */
\"[^\\"\n]*\" { line_begin();
line_add(yytext, yyleng);
line_finish();
return STRING; }
\"[^\\"\n]*\\. { BEGIN(STR);
line_begin();
line_add_unescape(yytext + 1, yyleng - 1); }
[^\\"\n]*\\. { line_add_unescape(yytext, yyleng); }
[^\\"\n]*\" { BEGIN(INITIAL);
if (yyleng > 1)
line_add(yytext, yyleng - 1);
line_finish();
return STRING; }
/* Other characters */
{SPEC} return yytext[0];
\\\n { line_num++; }
\n{WS}+/[^ \t\n] { line_num++; return CONT; }
\n { line_num++; return EOL; }
, return yytext[0];
. { error_at_line(0, 0, file_name, line_num,
"Stray character %03o in alias file", yytext[0]);
error_count++; }
%%
int
yywrap()
{
fclose(yyin);
return 1;
}
static char escape_transtab[] = "\\\\a\ab\bf\fn\nr\rt\t";
int
unescape_char(int c)
{
char *p;
for (p = escape_transtab; *p; p += 2) {
if (*p == c)
return p[1];
}
return c;
}
void
line_add(char *text, size_t len)
{
obstack_grow(&string_stk, text, len);
}
void
line_add_unescape(char *text, size_t len)
{
char c;
obstack_grow(&string_stk, text, len - 2);
c = unescape_char(text[len - 1]);
obstack_1grow(&string_stk, c);
}
void
line_begin()
{
}
void
line_finish ()
{
obstack_1grow(&string_stk, 0);
yylval.string = obstack_finish(&string_stk);
}
void
openaliases(char *name)
{
yyin = fopen (name, "r");
if (!yyin)
error(1, errno, "cannot open file `%s'", name);
file_name = name;
line_num = 0;
}
void
openaliases_prefix(char *prefix, char *name)
{
char *fullname = NULL;
struct stat st;
if (stat(prefix, &st))
error(1, errno, "cannot stat `%s'", prefix);
if (!S_ISDIR(st.st_mode)) {
char *p = strrchr(prefix, '/');
if (p)
*p = 0;
else
prefix = ".";
}
asprintf(&fullname, "%s/%s", prefix, name);
openaliases(fullname);
free(fullname);
}
void
init_lex()
{
obstack_init(&string_stk);
yy_flex_debug = 0;
}
void
lex_debug(int debug)
{
yy_flex_debug = debug;
}
void
read_include(SLIST **plist, char *name)
{
char *p;
char buffer[256];
FILE *fp = fopen(name, "r");
if (!fp) {
error_at_line(0, 0, file_name, line_num,
"cannot open include file `%s': %s",
name, strerror(errno));
error_count++;
return;
}
while (p = fgets(buffer, sizeof buffer, fp)) {
char *q;
while (*p && isspace(*p))
p++;
if (*p == '#')
continue;
for (q = p + strlen(p) - 1; q > p && isspace(*q); q--)
;
q[1] = 0;
if (*p)
slist_add(plist, strdup(p));
}
fclose(fp);
}