/* -*- c -*-
elmo - ELectronic Mail Operator
Copyright (C) 2003, 2004 rzyjontko
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; version 2.
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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------
*/
%{
#define _GNU_SOURCE 1
/****************************************************************************
* IMPLEMENTATION HEADERS
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#ifdef HAVE_WORDEXP_H
# include <wordexp.h>
#endif
#include "error.h"
#include "xmalloc.h"
#include "confhold.h"
#include "misc.h"
#include "ecurses.h"
#include "keymap.h"
#include "cmd.h"
#include "gettext.h"
#include "abook.h"
#include "procmail.h"
#include "mime.h"
#include "property.h"
/****************************************************************************
* IMPLEMENTATION PRIVATE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS
****************************************************************************/
#define FIRST_ALLOC 128
#define MAX_DEPTH 10
#define YY_DECL static token_t next_token YY_PROTO ((void))
typedef enum token {KW_SET = 300,
KW_HOOK = 301,
KW_KEY = 302,
KW_ADDR = 303,
KW_INCLUDE = 304,
KW_RULE = 305,
KW_TRANSLATE = 306,
KW_MIME = 307,
KW_HANDLER = 308,
KW_PROPERTY = 309,
KW_MACRO = 310,
IDENTIFIER = 401,
EOL = 402,
SQUOTED = 403,
DQUOTED = 404,
TEXT = 405,
ARROW = 406,
KEY_SPECIAL = 501,
KEY_CONTROL = 502,
KEY_SIMPLE = 503,
KEY_VALUE = 504,
} token_t;
/****************************************************************************
* IMPLEMENTATION PRIVATE CLASS PROTOTYPES / EXTERNAL CLASS REFERENCES
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE STRUCTURES / UTILITY CLASSES
****************************************************************************/
typedef struct finfo {
YY_BUFFER_STATE state;
char *fname;
int lineno;
} finfo_t;
/****************************************************************************
* IMPLEMENTATION REQUIRED EXTERNAL REFERENCES (AVOID)
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE DATA
****************************************************************************/
static token_t current_token = 0;
/**
* this is used for recursive file inclusion
*
* fstack and ftop are to be used only by frame_pop, and frame_push
* others should use these functions and get data from fframe
*
* ftop points to the top used frame, so that fstack[ftop + 1] is the
* first available
*/
static finfo_t fstack[MAX_DEPTH];
static int ftop = -1;
static finfo_t *fframe;
/**
* these are copies of yytext and yyleng
*/
static char *token_txt = NULL;
static int token_len = 0;
/**
* key-value, and a flag if a key is a meta-key
*/
static int token_key = 0;
static int key_meta = 0;
/**
* this is set to 0 if confhold does not have appropriate structures
* to hold new variable, it may happen if someone defines not registered
* variable
*/
static int prepared_to_insert = 1;
/**
* this holds field's name that is passed to confhold_insert_value
*/
static char *field_name = NULL;
/****************************************************************************
* INTERFACE DATA
****************************************************************************/
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTION PROTOTYPES
****************************************************************************/
static int parse (void);
static int frame_push (char *file, int silent);
static int frame_pop (void);
/****************************************************************************
* INTERFACE FUNCTIONS
****************************************************************************/
%}
%option noyywrap
ID [a-zA-Z_][a-zA-Z0-9_\-]+
SQT \'[^\']*\'
DQT \"[^\"]*\"
SKEY1 (<tab>)|(<esc>)|(<up>)|(<down>)|(<left>)|(<right>)|(<pageup>)
SKEY2 (<pagedown>)|(<backspace>)|(<delete>)|(<insert>)|(<enter>)|(<home>)
SKEY3 (<end>)|(<space>)|(<f[0-9]{1,2}>)
KEY ([^<>\n \t:\\\{\}\'\"\(\)])|(\\[^CM0-9\n])
VKEY \\[0-9]{3}
%%
^[ \t]*#.* /* ignore */
[ \t] /* ignore */
^set return KW_SET;
^key return KW_KEY;
^hook return KW_HOOK;
^addr return KW_ADDR;
^include return KW_INCLUDE;
^rule return KW_RULE;
^translate return KW_TRANSLATE;
^mime return KW_MIME;
^handler return KW_HANDLER;
^property return KW_PROPERTY;
^macro return KW_MACRO;
{ID} return IDENTIFIER;
{SQT} return SQUOTED;
{DQT} return DQUOTED;
"=>" return ARROW;
(\\M)?({KEY}) {
char *seek;
if (strstr (yytext, "\\M") == yytext){
key_meta = 1;
seek = yytext + 2;
}
else {
key_meta = 0;
seek = yytext;
}
if (*seek == '\\')
token_key = seek[1];
else
token_key = seek[0];
return KEY_SIMPLE;
}
(\\M)?({SKEY1}|{SKEY2}|{SKEY3}) {
int f;
char *seek;
if (strstr (yytext, "\\M") == yytext){
key_meta = 1;
seek = yytext + 2;
}
else {
key_meta = 0;
seek = yytext;
}
if (! strcmp (seek, "<tab>"))
token_key = 9;
else if (! strcmp (seek, "<esc>"))
token_key = 27;
else if (! strcmp (seek, "<up>"))
token_key = KEY_UP;
else if (! strcmp (seek, "<down>"))
token_key = KEY_DOWN;
else if (! strcmp (seek, "<left>"))
token_key = KEY_LEFT;
else if (! strcmp (seek, "<right>"))
token_key = KEY_RIGHT;
else if (! strcmp (seek, "<pageup>"))
token_key = KEY_PPAGE;
else if (! strcmp (seek, "<pagedown>"))
token_key = KEY_NPAGE;
else if (! strcmp (seek, "<backspace>"))
token_key = KEY_BACKSPACE;
else if (! strcmp (seek, "<delete>"))
token_key = KEY_DC;
else if (! strcmp (seek, "<insert>"))
token_key = KEY_IC;
else if (! strcmp (seek, "<enter>"))
token_key = '\r';
else if (! strcmp (seek, "<home>"))
token_key = KEY_HOME;
else if (! strcmp (seek, "<end>"))
token_key = KEY_END;
else if (! strcmp (seek, "<space>"))
token_key = ' ';
else {
f = atoi (seek + 2);
token_key = KEY_F (f);
}
return KEY_SPECIAL;
}
(\\M)?({VKEY}) {
char *seek;
if (strstr (yytext, "\\M") == yytext){
key_meta = 1;
seek = yytext + 2;
}
else {
key_meta = 0;
seek = yytext;
}
token_key = strtol (seek + 1, NULL, 8);
return KEY_VALUE;
}
(\\M)?(\\C[a-z]) {
char *seek;
if (strstr (yytext, "\\M") == yytext){
key_meta = 1;
seek = yytext + 2;
}
else {
key_meta = 0;
seek = yytext;
}
token_key = seek[2] - 'a' + 1;
return KEY_CONTROL;
}
\\\n fframe->lineno++;
\n fframe->lineno++; return EOL;
[^ \t\n:\\<>\{\}\(\),]+ return TEXT;
. return *yytext;
<<EOF>> {
if (ftop > 0)
frame_pop ();
else {
return EOF;
yyunput (0, NULL);
}
}
%%
int
confread_read_file (const char *file, int silent)
{
int ret;
ftop = -1;
if (frame_push (xstrdup (file), silent))
return -1;
current_token = next_token ();
ret = parse ();
frame_pop ();
if (token_txt)
xfree (token_txt);
token_txt = NULL;
return ret;
}
/****************************************************************************
* IMPLEMENTATION PRIVATE FUNCTIONS
****************************************************************************/
static char *
expand (char *str)
{
#ifdef HAVE_WORDEXP_H
wordexp_t word_vector;
int len = 0;
int i;
char *result;
char *end;
if (wordexp (str, &word_vector, 0)){
return NULL;
}
for (i = 0; i < word_vector.we_wordc; i++){
len += strlen (word_vector.we_wordv[i]);
}
result = xmalloc (len + 1);
end = result;
for (i = 0; i < word_vector.we_wordc; i++){
end = stpcpy (end, word_vector.we_wordv[i]);
}
*end = '\0';
wordfree (&word_vector);
return result;
#else
int len = strlen (str);
char *result;
if ((*str == '"' && str[len - 1] == '"')
|| (*str == '\'' && str[len - 1] == '\'')){
result = xmalloc (len - 2 + 1);
memcpy (result, str + 1, len - 2);
result[len - 2] = '\0';
}
return xstrdup (str);
#endif
}
static cmd_state_t
name_to_state (char *name)
{
if (! strcmp (name, "folder"))
return CMD_LIST;
if (! strcmp (name, "mail"))
return CMD_READ_MAIL;
if (! strcmp (name, "select"))
return CMD_SELECT_BOX;
if (! strcmp (name, "fetch"))
return CMD_FETCH;
if (! strcmp (name, "send"))
return CMD_SENDER;
if (! strcmp (name, "attach"))
return CMD_ATTACH;
if (! strcmp (name, "abook"))
return CMD_ABOOK;
if (! strcmp (name, "abook_add"))
return CMD_ABOOK_ADD;
if (! strcmp (name, "ask"))
return CMD_ASK;
if (! strcmp (name, "help"))
return CMD_HELP;
if (! strcmp (name, "read"))
return CMD_READ;
if (! strcmp (name, "debug"))
return CMD_DEBUG;
if (! strcmp (name, "search"))
return CMD_SEARCH;
return CMD_INVALID;
}
static int
frame_push (char *fname, int silent)
{
FILE *fp;
struct stat st;
if (ftop >= MAX_DEPTH){
error_ (0, _("includes nested to deep"));
xfree (fname);
return 1;
}
if (stat (fname, & st)){
if (! silent)
error_ (errno, "%s", fname);
xfree (fname);
return 1;
}
if (! S_ISREG (st.st_mode)){
error_ (0, _("%s is not a file"), fname);
xfree (fname);
return 1;
}
fp = fopen (fname, "r");
if (fp == NULL){
error_ (errno, "%s", fname);
xfree (fname);
return 1;
}
ftop++;
yyin = fp;
fframe = fstack + ftop;
fframe->fname = fname;
fframe->lineno = 1;
fframe->state = yy_create_buffer (yyin, YY_BUF_SIZE);
yy_switch_to_buffer (fframe->state);
return 0;
}
static int
frame_pop (void)
{
xfree (fframe->fname);
yy_delete_buffer (fframe->state);
fclose (yyin);
if (ftop > 0){
ftop--;
fframe = fstack + ftop;
yy_switch_to_buffer (fframe->state);
}
else {
fframe = NULL;
}
return 0;
}
/****************************************************************************
* PARSER FUNCTIONS
****************************************************************************/
/**
* Please note, that there is no error-recovery. First error generates
* parse error message and stops file analysis.
*/
/*
GRAMMAR
<command-list> ::= <command-list> <command> | <command>
<command> ::= <hook-command> | <key-command> | <set-command>
| <addr-command> | <include> | <rule-command>
| <translate-cmd> | <mime-command> | <handler-cmd>
| <property-cmd>
<hook-command> ::= "hook" ID ID EOL
<key-command> ::= "key" ID <key-specifier> ID EOL
<set-command> ::= "set" ID <simple-value> EOL
| "set" ID "{" EOL <struct-value> "}"
<addr-command> ::= "addr" "{" EOL <struct-value> "}"
<rule-command> ::= "rule" ID "{" <rule-content> "}"
<translate-cmd> ::= "translate" <simple-value> <simple-value>
<mime-command> ::= "mime" <simple-value> <simple-value> EOL
<handler-cmd> ::= "handler" <simple-value> <simple-value> EOL
<property-cmd> ::= "property" <simple-value> "(" <property-args> ")" "{"
EOL <property-body> "}"
<include> ::= "include" <simple-value> EOL
<key-specifier> ::= KEY | CONTROL-KEY | SPECIAL | VALUE
<struct-value> ::= <struct-value> <field> | <field>
<rule-content> ::= <constraints> <rule-action>
<constraints> ::= <constraints> <rule-header> <rule-constraint> | ""
<rule-header> ::= <crap> <rule-header> | <real-header>
<rule-constraint>::= <crap> <rule-constraint> | <real-constraint>
<rule-action> ::= <crap> <rule-action> | <real-action>
<crap> ::= ID | EOL | TEXT | ...
<real-header> ::= "TO" | "SUBJECT" | "FROM" | "CC" | "TOCC"
<real-constraint>::= SQUOTED | DQUOTED
<real-action> ::= TEXT"."
<property-args> ::= <property-args> <property-arg> | <property-arg>
<property-arg> ::= TEXT | IDENTIFIER | EOL
<property-body> ::= <property-body> <property-rule> | <property-rule>
<property-rule> ::= <property-conds> "=>" <simple-value>
<property-conds>::= <property-conds> <property-cond> | <property-cond>
<property-cond> ::= SQUOTED | DQUOTED | EOL
<field> ::= ID ":" <simple-value> EOL | EOL
<simple-value> ::= ID | SQUOTED | DQUOTED | TEXT
*/
static char *
token_2_string (int token)
{
static char token_txt[2] = {'\0', '\0'};
if (token > 0 && token < 255){
*token_txt = token;
return token_txt;
}
switch (token){
case KW_SET:
return "set";
case KW_KEY:
return "key";
case KW_HOOK:
return "hook";
case KW_ADDR:
return "addr";
case KW_INCLUDE:
return "include";
case KW_RULE:
return "rule";
case KW_TRANSLATE:
return "translate";
case KW_MIME:
return "mime";
case KW_HANDLER:
return "handler";
case KW_PROPERTY:
return "property";
case KW_MACRO:
return "macro";
case IDENTIFIER:
return _("identifier");
case EOL:
/* it's tricky but this is about end of
PREVIOUS line */
fframe->lineno--;
return _("end of line");
case TEXT:
return _("text");
case SQUOTED:
case DQUOTED:
return _("quoted text");
case ARROW:
return "=>";
case KEY_SPECIAL:
case KEY_CONTROL:
case KEY_SIMPLE:
case KEY_VALUE:
return _("key specifier");
case EOF:
return _("end of file");
}
return "";
}
static void
parse_error (void)
{
error_ (0, _("%s:%d: parse error near %s"), fframe->fname,
fframe->lineno, token_2_string (current_token));
}
static int
match (token_t token)
{
token_t old_token = current_token;
if (token_txt == NULL){
token_len = FIRST_ALLOC + yyleng;
token_txt = xmalloc (token_len + 1);
}
else if (token_len < yyleng + 2){
token_len += yyleng + 2;
xfree (token_txt);
token_txt = xmalloc (token_len);
}
memcpy (token_txt, yytext, yyleng + 1);
current_token = next_token ();
return old_token != token;
}
static int
set_field_value (void)
{
char *txt;
switch (current_token){
case IDENTIFIER:
case KEY_SIMPLE:
case TEXT:
case SQUOTED:
case DQUOTED:
match (current_token);
if (! prepared_to_insert)
return 0;
txt = expand (token_txt);
if (txt){
if (confhold_insert_value (field_name, txt))
error_ (0, _("%s:%d: invalid field: %s"),
fframe->fname, fframe->lineno,
field_name);
xfree (txt);
}
return 0;
default:
return 1;
}
}
static int
set_field (void)
{
if (current_token == EOL)
return match (EOL);
if (match (IDENTIFIER))
return 1;
field_name = xstrdup (token_txt);
if (match (':')){
if (field_name)
xfree (field_name);
field_name = NULL;
return 1;
}
if (set_field_value ()){
if (field_name)
xfree (field_name);
field_name = NULL;
return 1;
}
xfree (field_name);
field_name = NULL;
return match (EOL);
}
static int
set_struct_value (void)
{
do {
if (set_field ())
return 1;
}
while (current_token == IDENTIFIER || current_token == EOL);
return 0;
}
static int
set_value (void)
{
char *txt;
switch (current_token){
case '{':
match ('{');
if (match (EOL))
return 1;
if (set_struct_value ())
return 1;
return match ('}');
case IDENTIFIER:
case SQUOTED:
case DQUOTED:
case TEXT:
case KEY_SIMPLE:
match (current_token);
if (! prepared_to_insert)
return match (EOL);
txt = expand (token_txt);
if (txt){
confhold_insert_value (NULL, txt);
xfree (txt);
}
return match (EOL);
default:
return 1;
}
}
static int
set_command (void)
{
prepared_to_insert = 1;
if (match (KW_SET))
return 1;
if (match (IDENTIFIER))
return 1;
if (confhold_prepare_to_insert (token_txt)){
prepared_to_insert = 0;
error_ (0, _("%s:%d: no such variable: %s"), fframe->fname,
fframe->lineno, token_txt);
}
return set_value ();
}
static int
hook_command (void)
{
exec_t *trigger;
exec_t *action;
if (match (KW_HOOK))
return 1;
if (match (IDENTIFIER))
return 1;
trigger = exec_lookup (token_txt);
if (trigger == NULL){
error_ (0, _("%s:%d: no such function: %s"), fframe->fname,
fframe->lineno, token_txt);
}
if (match (IDENTIFIER))
return 1;
action = exec_lookup (token_txt);
if (action == NULL){
error_ (0, _("%s:%d: no such function: %s"), fframe->fname,
fframe->lineno - 1, token_txt);
}
if (action->fun){
if (trigger && action){
if (trigger->hook == NULL)
trigger->hook = hook_create (action->fun);
else
hook_add (trigger->hook, action->fun);
}
}
else {
error_ (0, _("%s:%d: macros (%s) may not be used as actions "
"in hook command"), fframe->fname,
fframe->lineno - 1, token_txt);
}
return match (EOL);
}
static int
key_specifier (void)
{
switch (current_token){
case KEY_SIMPLE:
case KEY_VALUE:
case KEY_SPECIAL:
case KEY_CONTROL:
match (current_token);
return 0;
default:
return 1;
}
}
static int
key_command (void)
{
cmd_state_t state;
exec_t *exec;
if (match (KW_KEY))
return 1;
if (match (IDENTIFIER))
return 1;
state = name_to_state (token_txt);
if (state == CMD_INVALID)
error_ (0, _("%s:%d: no such state: %s"), fframe->fname,
fframe->lineno, token_txt);
if (key_specifier ())
return 1;
if (match (IDENTIFIER))
return 1;
exec = exec_lookup (token_txt);
if (exec == NULL)
error_ (0, _("%s:%d: no such function: %s"), fframe->fname,
fframe->lineno - 1, token_txt);
if (state != CMD_INVALID && exec){
keymap_add (keymaps + state, token_key, key_meta, exec->fun);
}
return match (EOL);
}
static int
addr_field_value (void)
{
char *txt;
switch (current_token){
case IDENTIFIER:
case TEXT:
case SQUOTED:
case DQUOTED:
case KEY_SIMPLE:
match (current_token);
txt = expand (token_txt);
if (txt){
abook_new_value (txt);
xfree (txt);
}
return 0;
default:
return 1;
}
}
static int
addr_field (void)
{
switch (current_token){
case EOL:
match (EOL);
return 0;
case IDENTIFIER:
match (IDENTIFIER);
if (abook_new_field (token_txt))
error_ (0, _("%s:%d: invalid field: %s"),
fframe->fname, fframe->lineno,
token_txt);
if (match (':'))
return 1;
return addr_field_value ();
default:
return 1;
}
}
static int
addr_value (void)
{
do {
if (addr_field ())
return 1;
}
while (current_token == IDENTIFIER || current_token == EOL);
return 0;
}
static int
addr_command (void)
{
if (match (KW_ADDR))
return 1;
if (match ('{'))
return 1;
if (match (EOL))
return 1;
abook_new_prepare ();
if (addr_value ()){
abook_new_drop ();
return 1;
}
abook_new_store ();
return match ('}');
}
static int
include_command (void)
{
char *fname;
if (match (KW_INCLUDE))
return 1;
switch (current_token){
case DQUOTED:
case SQUOTED:
case IDENTIFIER:
case TEXT:
match (current_token);
fname = expand (token_txt);
frame_push (fname, 0);
return match (EOL);
default:
return 1;
}
}
static int
rule_header (void)
{
while (1){
switch (current_token){
case IDENTIFIER:
match (IDENTIFIER);
if (strcmp (token_txt, "SUBJECT") == 0
|| strcmp (token_txt, "TO") == 0
|| strcmp (token_txt, "FROM") == 0
|| strcmp (token_txt, "CC") == 0
|| strcmp (token_txt, "TOCC") == 0){
procmail_setup_header (token_txt);
return 0;
}
break;
case EOL:
case TEXT:
case KEY_SPECIAL:
case KEY_CONTROL:
case KEY_SIMPLE:
case KEY_VALUE:
match (current_token);
break;
default:
return 1;
}
}
}
static int
rule_constraint (void)
{
char *txt;
while (1){
switch (current_token){
case SQUOTED:
match (SQUOTED);
txt = expand (token_txt);
procmail_setup_str (txt);
xfree (txt);
return 0;
case DQUOTED:
match (DQUOTED);
txt = expand (token_txt);
procmail_setup_re (txt);
xfree (txt);
return 0;
case IDENTIFIER:
case EOL:
case TEXT:
case KEY_SPECIAL:
case KEY_CONTROL:
case KEY_SIMPLE:
case KEY_VALUE:
match (current_token);
break;
default:
return 1;
}
}
}
static int
rule_action (void)
{
int len;
while (1){
switch (current_token){
case SQUOTED:
case DQUOTED:
return 0;
case IDENTIFIER:
if (strcmp (yytext, "SUBJECT") == 0
|| strcmp (yytext, "TO") == 0
|| strcmp (yytext, "FROM") == 0
|| strcmp (yytext, "CC") == 0
|| strcmp (yytext, "TOCC") == 0)
return 0;
match (IDENTIFIER);
break;
case KEY_CONTROL:
case KEY_SIMPLE:
case KEY_VALUE:
case EOL:
match (current_token);
break;
case TEXT:
match (TEXT);
len = strlen (token_txt);
if (len < 2)
break;
if (token_txt[len - 1] == '.'){
token_txt[len - 1] = '\0';
procmail_setup_action (token_txt, 1);
goto eat_empty_tokens;
}
else if (token_txt[len - 1] == ';'){
token_txt[len - 1] = '\0';
procmail_setup_action (token_txt, 0);
goto eat_empty_tokens;
}
break;
default:
return 1;
}
}
eat_empty_tokens:
while (current_token == EOL)
match (EOL);
return 0;
}
static int
rule_content (void)
{
do {
if (rule_header ())
return 1;
if (rule_constraint ())
return 1;
if (rule_action ())
return 1;
}
while (current_token != EOF && current_token != '}');
return 0;
}
static int
rule_command (void)
{
if (match (KW_RULE))
return 1;
if (match (IDENTIFIER))
return 1;
procmail_setup_name (token_txt);
if (match ('{')){
return 1;
}
if (rule_content ()){
return 1;
}
return match ('}');
}
static int
translate_charset (void)
{
char *txt;
switch (current_token){
case IDENTIFIER:
case SQUOTED:
case DQUOTED:
case TEXT:
case KEY_SIMPLE:
match (current_token);
txt = expand (token_txt);
mime_add_charset (txt);
return 0;
default:
return 1;
}
}
static int
translate_command (void)
{
if (match (KW_TRANSLATE))
return 1;
if (translate_charset ())
return 1;
if (translate_charset ())
return 1;
return match (EOL);
}
static char *
mime_value (void)
{
char *txt;
switch (current_token){
case IDENTIFIER:
case SQUOTED:
case DQUOTED:
case TEXT:
case KEY_SIMPLE:
match (current_token);
txt = expand (token_txt);
return txt;
default:
return NULL;
}
}
static int
mime_command (void)
{
char *type;
char *re;
if (match (KW_MIME))
return 1;
type = mime_value ();
if (type == NULL)
return 1;
re = mime_value ();
if (re == NULL)
return 1;
mime_register_type (type, re);
return match (EOL);
}
static int
handler_command (void)
{
char *type;
char *handler;
if (match (KW_HANDLER))
return 1;
type = mime_value ();
if (type == NULL)
return 1;
handler = mime_value ();
if (handler == NULL)
return 1;
mime_register_handler (type, handler);
return match (EOL);
}
static int
property_arg (void)
{
switch (current_token){
case TEXT:
case IDENTIFIER:
match (current_token);
property_add_arg (token_txt);
return 0;
case EOL:
match (EOL);
return 0;
default:
return 1;
}
}
static int
property_args (void)
{
do {
if (property_arg ())
return 1;
}
while (current_token == TEXT || current_token == IDENTIFIER
|| current_token == EOL);
return 0;
}
static int
property_rule_cond (void)
{
char *txt;
switch (current_token){
case SQUOTED:
match (SQUOTED);
txt = expand (token_txt);
property_add_cond_str (txt);
xfree (txt);
return 0;
case DQUOTED:
match (DQUOTED);
txt = expand (token_txt);
property_add_cond_re (txt);
xfree (txt);
return 0;
case EOL:
match (EOL);
return 0;
default:
return 1;
}
}
static int
property_rule_conds (void)
{
do {
if (property_rule_cond ())
return 1;
}
while (current_token == SQUOTED || current_token == DQUOTED
|| current_token == EOL);
return 0;
}
static int
property_rule_val (void)
{
char *txt;
switch (current_token){
case IDENTIFIER:
case TEXT:
case SQUOTED:
case DQUOTED:
case KEY_SIMPLE:
match (current_token);
txt = expand (token_txt);
property_add_value (txt);
return 0;
default:
return 1;
}
}
static int
property_rule (void)
{
if (property_rule_conds ())
return 1;
if (match (ARROW))
return 1;
if (property_rule_val ())
return 1;
return match (EOL);
}
static int
property_body (void)
{
do {
if (property_rule ())
return 1;
}
while (current_token == SQUOTED || current_token == DQUOTED
|| current_token == EOL);
return 0;
}
static int
property_name (void)
{
switch (current_token){
case IDENTIFIER:
case TEXT:
match (current_token);
property_new (token_txt);
return 0;
default:
return 1;
}
}
static int
property_command (void)
{
if (match (KW_PROPERTY))
return 1;
if (property_name ())
return 1;
if (match ('('))
return 1;
if (property_args ())
return 1;
if (match (')'))
return 1;
if (match ('{'))
return 1;
if (match (EOL))
return 1;
if (property_body ())
return 1;
if (match ('}'))
return 1;
return 0;
}
static int
macro_comment (void)
{
char *txt;
switch (current_token){
case SQUOTED:
case DQUOTED:
match (current_token);
txt = expand (token_txt);
exec_macro_comment (txt);
return match (EOL);
default:
return 0;
}
}
static int
macro_instruction (void)
{
switch (current_token){
case IDENTIFIER:
match (IDENTIFIER);
exec_macro_add_hook (token_txt);
return match (EOL);
case EOL:
match (EOL);
return 0;
default:
return 1;
}
}
static int
macro_body (void)
{
do {
if (macro_instruction ())
return 1;
}
while (current_token == IDENTIFIER || current_token == EOL);
return 0;
}
static int
macro_command (void)
{
if (match (KW_MACRO))
return 1;
if (match (IDENTIFIER))
return 1;
exec_new_macro (token_txt);
if (match ('{'))
return 1;
if (match (EOL))
return 1;
if (macro_comment ())
return 1;
if (macro_body ())
return 1;
exec_macro_commit ();
if (match ('}'))
return 1;
return 0;
}
static int
command (void)
{
switch (current_token){
case KW_SET:
return set_command ();
case KW_HOOK:
return hook_command ();
case KW_KEY:
return key_command ();
case KW_ADDR:
return addr_command ();
case KW_INCLUDE:
return include_command ();
case KW_RULE:
return rule_command ();
case KW_TRANSLATE:
return translate_command ();
case KW_MIME:
return mime_command ();
case KW_HANDLER:
return handler_command ();
case KW_PROPERTY:
return property_command ();
case KW_MACRO:
return macro_command ();
case EOL:
return match (EOL);
default:
return 1;
}
}
static int
command_list (void)
{
while (current_token != EOF){
if (command ()){
return 1;
}
}
return 0;
}
static int
parse (void)
{
if (command_list ()){
parse_error ();
return 1;
}
return match (EOF);
}
/****************************************************************************
* INTERFACE CLASS BODIES
****************************************************************************/
/****************************************************************************
*
* END MODULE confread.l
*
****************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1