37 |
extern int yylex(void); |
extern int yylex(void); |
38 |
int yyerror(char *s); |
int yyerror(char *s); |
39 |
|
|
40 |
static RC_SECTION *rc_section_create(char *, RC_STMT *); |
static RC_SECTION *rc_section_create(char *, size_t, RC_STMT *); |
41 |
static void rc_section_destroy(RC_SECTION **); |
static void rc_section_destroy(RC_SECTION **); |
42 |
static void rc_section_print(RC_SECTION *); |
static void rc_section_print(RC_SECTION *); |
43 |
static void rc_asgn_destroy(RC_ASGN *); |
static void rc_asgn_destroy(RC_ASGN *); |
78 |
RC_REGEX *key; |
RC_REGEX *key; |
79 |
char *string; |
char *string; |
80 |
} msgpart; |
} msgpart; |
81 |
|
RC_LOC loc; |
82 |
|
struct { |
83 |
|
size_t line; |
84 |
|
char *name; |
85 |
|
} begin_sec; |
86 |
LIST *list; |
LIST *list; |
87 |
}; |
}; |
88 |
|
|
96 |
%left AND |
%left AND |
97 |
%left NOT |
%left NOT |
98 |
|
|
99 |
%type <string> begin keyword string modifier arg string_key |
%type <string> keyword string modifier arg string_key |
100 |
%type <section> section seclist |
%type <section> section seclist |
101 |
%type <stmtlist> stmtlist |
%type <stmtlist> stmtlist |
102 |
%type <stmt> stmt asgn_stmt cond_stmt rule_stmt inst_stmt modf_stmt |
%type <stmt> stmt asgn_stmt cond_stmt rule_stmt inst_stmt modf_stmt |
104 |
%type <node> rule_start cond expr |
%type <node> rule_start cond expr |
105 |
%type <msgpart> msgpart s_msgpart r_msgpart key opt_key |
%type <msgpart> msgpart s_msgpart r_msgpart key opt_key |
106 |
%type <list> arglist |
%type <list> arglist |
107 |
%type <regex> regex |
%type <regex> regex |
108 |
|
%type <begin_sec> begin |
109 |
|
|
110 |
%% |
%% |
111 |
|
|
144 |
} |
} |
145 |
| begin stmtlist end |
| begin stmtlist end |
146 |
{ |
{ |
147 |
$$ = rc_section_create($1, $2.head); |
$$ = rc_section_create($1.name, $1.line, $2.head); |
148 |
} |
} |
149 |
| begin end |
| begin end |
150 |
{ |
{ |
154 |
|
|
155 |
begin : T_BEGIN { verbatim(); } string EOL |
begin : T_BEGIN { verbatim(); } string EOL |
156 |
{ |
{ |
157 |
$$ = $3; |
$$.line = cfg_line_num - 1; |
158 |
|
$$.name = $3; |
159 |
if (rc_section_lookup(rc_section, $3)) |
if (rc_section_lookup(rc_section, $3)) |
160 |
parse_error(_("Section %s already defined"), $3); |
parse_error(_("Section %s already defined"), $3); |
161 |
rc_secdef = anubis_find_section($3); |
rc_secdef = anubis_find_section($3); |
162 |
} |
} |
163 |
| D_BEGIN EOL |
| D_BEGIN EOL |
164 |
{ |
{ |
165 |
|
$$.line = cfg_line_num - 1; |
166 |
|
$$.name = $1; |
167 |
if (rc_section_lookup(rc_section, $1)) |
if (rc_section_lookup(rc_section, $1)) |
168 |
parse_error(_("Section %s already defined"), $1); |
parse_error(_("Section %s already defined"), $1); |
169 |
rc_secdef = anubis_find_section($1); |
rc_secdef = anubis_find_section($1); |
575 |
yydebug = debug_level; |
yydebug = debug_level; |
576 |
} |
} |
577 |
|
|
578 |
|
|
579 |
|
/* Locations */ |
580 |
|
|
581 |
|
/* To save space, each filename is allocated only once. Each filename |
582 |
|
has a reference count associated with it. It is incremented |
583 |
|
with each new allocation of the same string. It is decremented |
584 |
|
with each attempt to free the string. Only when the reference count |
585 |
|
drops to zero is the storage actually reclaimed */ |
586 |
|
|
587 |
|
struct strobj { |
588 |
|
char *value; /* String value */ |
589 |
|
size_t refcnt; /* Reference count */ |
590 |
|
}; |
591 |
|
|
592 |
|
/* A list of string objects */ |
593 |
|
static LIST /* of struct strobj */ *string_list; |
594 |
|
|
595 |
|
static int |
596 |
|
string_comparator(void *item, void *data) |
597 |
|
{ |
598 |
|
struct strobj *s = item; |
599 |
|
return strcmp (s->value, (char*) data); |
600 |
|
} |
601 |
|
|
602 |
|
static int |
603 |
|
value_comparator(void *item, void *data) |
604 |
|
{ |
605 |
|
struct strobj *s = item; |
606 |
|
return s->value != data; |
607 |
|
} |
608 |
|
|
609 |
|
/* Looks up a string object with the given value. If not found, a |
610 |
|
new object is created and added to the list. In any case the |
611 |
|
reference count of the objet is incremented. |
612 |
|
The return value is the string value associated with the object. */ |
613 |
|
char * |
614 |
|
string_create(char *str) |
615 |
|
{ |
616 |
|
struct strobj *s = list_locate(string_list, str, string_comparator); |
617 |
|
if (!s) { |
618 |
|
s = xmalloc(sizeof(*s)); |
619 |
|
s->value = strdup(str); |
620 |
|
s->refcnt = 0; |
621 |
|
list_prepend(string_list, s); |
622 |
|
} |
623 |
|
s->refcnt++; |
624 |
|
return s->value; |
625 |
|
} |
626 |
|
|
627 |
|
/* Destroys the object with the given string value */ |
628 |
|
void |
629 |
|
string_destroy(char *str) |
630 |
|
{ |
631 |
|
struct strobj *s = list_locate(string_list, str, value_comparator); |
632 |
|
if (s) { |
633 |
|
if (--s->refcnt == 0) { |
634 |
|
free(s->value); |
635 |
|
list_remove(string_list, str, value_comparator); |
636 |
|
} |
637 |
|
} |
638 |
|
} |
639 |
|
|
640 |
|
/* Initializes LOC with the current location. If the second argument |
641 |
|
is not zero, it overrides the current line number. */ |
642 |
|
void |
643 |
|
rc_mark_loc(RC_LOC *loc, size_t line) |
644 |
|
{ |
645 |
|
loc->file = string_create(cfg_file); |
646 |
|
loc->line = line ? line : cfg_line_num; |
647 |
|
} |
648 |
|
|
649 |
|
/* Reclaims the memory associated with the LOC */ |
650 |
|
void |
651 |
|
rc_destroy_loc(RC_LOC *loc) |
652 |
|
{ |
653 |
|
string_destroy(loc->file); |
654 |
|
} |
655 |
|
|
656 |
|
|
657 |
/* Section manipulation */ |
/* Section manipulation */ |
658 |
|
|
659 |
RC_SECTION * |
RC_SECTION * |
660 |
rc_section_create(char *name, RC_STMT *stmt) |
rc_section_create(char *name, size_t line, RC_STMT *stmt) |
661 |
{ |
{ |
662 |
RC_SECTION *p = xmalloc(sizeof(*p)); |
RC_SECTION *p = xmalloc(sizeof(*p)); |
663 |
|
rc_mark_loc(&p->loc, line); |
664 |
p->next = NULL; |
p->next = NULL; |
665 |
p->name = name; |
p->name = name; |
666 |
p->stmt = stmt; |
p->stmt = stmt; |
671 |
rc_section_destroy(RC_SECTION **s) |
rc_section_destroy(RC_SECTION **s) |
672 |
{ |
{ |
673 |
rc_stmt_list_destroy((*s)->stmt); |
rc_stmt_list_destroy((*s)->stmt); |
674 |
|
rc_destroy_loc(&(*s)->loc); |
675 |
xfree((*s)->name); |
xfree((*s)->name); |
676 |
xfree(*s); |
xfree(*s); |
677 |
} |
} |
709 |
rc_section_link(RC_SECTION **ap, RC_SECTION *b) |
rc_section_link(RC_SECTION **ap, RC_SECTION *b) |
710 |
{ |
{ |
711 |
RC_SECTION *a, *prev; |
RC_SECTION *a, *prev; |
712 |
|
|
713 |
/* Remove all sections with prio == override (the default) */ |
/* Remove all sections with prio == override (the default) */ |
714 |
a = *ap; |
a = *ap; |
715 |
prev = NULL; |
prev = NULL; |
797 |
{ |
{ |
798 |
RC_NODE *p = xmalloc(sizeof(*p)); |
RC_NODE *p = xmalloc(sizeof(*p)); |
799 |
memset(p, 0, sizeof(*p)); |
memset(p, 0, sizeof(*p)); |
800 |
|
rc_mark_loc(&p->loc, 0); |
801 |
p->type = t; |
p->type = t; |
802 |
return p; |
return p; |
803 |
} |
} |
816 |
free(node->v.expr.key); |
free(node->v.expr.key); |
817 |
anubis_regex_free(&node->v.expr.re); |
anubis_regex_free(&node->v.expr.re); |
818 |
} |
} |
819 |
|
rc_destroy_loc(&node->loc); |
820 |
xfree(node); |
xfree(node); |
821 |
} |
} |
822 |
|
|
958 |
{ |
{ |
959 |
RC_STMT *p = xmalloc(sizeof(*p)); |
RC_STMT *p = xmalloc(sizeof(*p)); |
960 |
memset(p, 0, sizeof(*p)); |
memset(p, 0, sizeof(*p)); |
961 |
|
rc_mark_loc(&p->loc, 0); |
962 |
p->type = type; |
p->type = type; |
963 |
return p; |
return p; |
964 |
} |
} |
982 |
case rc_stmt_inst: |
case rc_stmt_inst: |
983 |
rc_inst_destroy(&stmt->v.inst); |
rc_inst_destroy(&stmt->v.inst); |
984 |
} |
} |
985 |
|
rc_destroy_loc(&stmt->loc); |
986 |
xfree(stmt); |
xfree(stmt); |
987 |
} |
} |
988 |
|
|
1142 |
int refcnt; |
int refcnt; |
1143 |
char **refstr; |
char **refstr; |
1144 |
jmp_buf jmp; |
jmp_buf jmp; |
1145 |
|
RC_LOC loc; |
1146 |
}; |
}; |
1147 |
|
|
1148 |
static void asgn_eval(struct eval_env *env, RC_ASGN *asgn); |
static void asgn_eval(struct eval_env *env, RC_ASGN *asgn); |
1153 |
static void stmt_list_eval(struct eval_env *env, RC_STMT *stmt); |
static void stmt_list_eval(struct eval_env *env, RC_STMT *stmt); |
1154 |
static void inst_eval(struct eval_env *env, RC_INST *inst); |
static void inst_eval(struct eval_env *env, RC_INST *inst); |
1155 |
|
|
1156 |
|
#define VALID_STR(s) ((s)?(s):"NULL") |
1157 |
|
|
1158 |
void |
void |
1159 |
inst_eval(struct eval_env *env, RC_INST *inst) |
inst_eval(struct eval_env *env, RC_INST *inst) |
1160 |
{ |
{ |
1172 |
|
|
1173 |
switch (inst->opcode) { |
switch (inst->opcode) { |
1174 |
case inst_stop: |
case inst_stop: |
1175 |
|
trace(&env->loc, _("STOP")); |
1176 |
longjmp(env->jmp, 1); |
longjmp(env->jmp, 1); |
1177 |
break; |
break; |
1178 |
|
|
1179 |
case inst_call: |
case inst_call: |
1180 |
|
trace(&env->loc, _("Calling %s"), inst->arg); |
1181 |
rcfile_call_section(env->method, inst->arg, |
rcfile_call_section(env->method, inst->arg, |
1182 |
env->data, env->msg); |
env->data, env->msg); |
1183 |
break; |
break; |
1184 |
|
|
1185 |
case inst_add: |
case inst_add: |
1186 |
if (inst->part == BODY) |
trace(&env->loc, _("ADD %s [%s] %s"), |
1187 |
|
(inst->part == BODY) ? "BODY" : "HEADER", |
1188 |
|
VALID_STR(inst->key2), arg); |
1189 |
|
if (inst->part == BODY) |
1190 |
message_add_body(env->msg, inst->key2, arg); |
message_add_body(env->msg, inst->key2, arg); |
1191 |
else |
else |
1192 |
message_add_header(env->msg, inst->key2, arg); |
message_add_header(env->msg, inst->key2, arg); |
1193 |
break; |
break; |
1194 |
|
|
1195 |
case inst_modify: |
case inst_modify: |
1196 |
|
trace(&env->loc, _("MODIFY %s [%s] [%s] %s"), |
1197 |
|
(inst->part == BODY) ? "BODY" : "HEADER", |
1198 |
|
anubis_regex_source(inst->key), |
1199 |
|
VALID_STR(inst->key2), arg); |
1200 |
|
|
1201 |
if (inst->part == BODY) |
if (inst->part == BODY) |
1202 |
message_modify_body(env->msg, inst->key, arg); |
message_modify_body(env->msg, inst->key, arg); |
1203 |
else |
else |
1206 |
break; |
break; |
1207 |
|
|
1208 |
case inst_remove: |
case inst_remove: |
1209 |
|
trace(&env->loc, _("REMOVE HEADER [%s]"), |
1210 |
|
anubis_regex_source(inst->key)); |
1211 |
message_remove_headers(env->msg, inst->key); |
message_remove_headers(env->msg, inst->key); |
1212 |
break; |
break; |
1213 |
|
|
1228 |
if (!p) |
if (!p) |
1229 |
return; |
return; |
1230 |
|
|
1231 |
|
trace(&env->loc, _("executing %s"), asgn->lhs); |
1232 |
if (env->refstr) { |
if (env->refstr) { |
1233 |
char *s; |
char *s; |
1234 |
LIST *arg = list_create(); |
LIST *arg = list_create(); |
1297 |
default: |
default: |
1298 |
abort(); |
abort(); |
1299 |
} |
} |
1300 |
|
if (rc) |
1301 |
|
trace(&env->loc, _("Matched condition %s[%s] \"%s\""), |
1302 |
|
part_string(expr->part), |
1303 |
|
VALID_STR(expr->key), |
1304 |
|
anubis_regex_source(expr->re)); |
1305 |
return rc; |
return rc; |
1306 |
} |
} |
1307 |
|
|
1310 |
{ |
{ |
1311 |
int rc; /* It won't be used uninitialized despite what cc says. |
int rc; /* It won't be used uninitialized despite what cc says. |
1312 |
Note default: branch below */ |
Note default: branch below */ |
1313 |
|
|
1314 |
|
env->loc = node->loc; |
1315 |
switch (node->type) { |
switch (node->type) { |
1316 |
case rc_node_bool: |
case rc_node_bool: |
1317 |
rc = bool_eval(env, &node->v.bool); |
rc = bool_eval(env, &node->v.bool); |
1318 |
break; |
break; |
1319 |
|
|
1320 |
case rc_node_expr: |
case rc_node_expr: |
1321 |
rc = expr_eval(env, &node->v.expr); |
rc = expr_eval(env, &node->v.expr); |
1322 |
break; |
break; |
1324 |
default: |
default: |
1325 |
abort(); |
abort(); |
1326 |
} |
} |
1327 |
|
|
1328 |
return rc; |
return rc; |
1329 |
} |
} |
1330 |
|
|
1369 |
void |
void |
1370 |
stmt_list_eval(struct eval_env *env, RC_STMT *stmt) |
stmt_list_eval(struct eval_env *env, RC_STMT *stmt) |
1371 |
{ |
{ |
1372 |
for (; stmt; stmt = stmt->next) |
for (; stmt; stmt = stmt->next) { |
1373 |
|
env->loc = stmt->loc; |
1374 |
|
|
1375 |
switch (stmt->type) { |
switch (stmt->type) { |
1376 |
case rc_stmt_asgn: |
case rc_stmt_asgn: |
1377 |
asgn_eval(env, &stmt->v.asgn); |
asgn_eval(env, &stmt->v.asgn); |
1388 |
case rc_stmt_inst: |
case rc_stmt_inst: |
1389 |
inst_eval(env, &stmt->v.inst); |
inst_eval(env, &stmt->v.inst); |
1390 |
} |
} |
1391 |
|
} |
1392 |
} |
} |
1393 |
|
|
1394 |
void |
void |
1402 |
env.refstr = NULL; |
env.refstr = NULL; |
1403 |
env.msg = msg; |
env.msg = msg; |
1404 |
env.data = data; |
env.data = data; |
1405 |
|
env.loc = sec->loc; |
1406 |
|
|
1407 |
|
trace(&sec->loc, "section %s", sec->name); |
1408 |
|
|
1409 |
if (setjmp(env.jmp) == 0) |
if (setjmp(env.jmp) == 0) |
1410 |
stmt_list_eval(&env, sec->stmt); |
stmt_list_eval(&env, sec->stmt); |
1470 |
parse_error(_("program is not allowed in this section")); |
parse_error(_("program is not allowed in this section")); |
1471 |
return p->allow_prog; |
return p->allow_prog; |
1472 |
} |
} |
1473 |
|
|