diff options
author | Ted Lemon <source@isc.org> | 2000-01-08 01:30:29 +0000 |
---|---|---|
committer | Ted Lemon <source@isc.org> | 2000-01-08 01:30:29 +0000 |
commit | 91c82d9fb6925cb462c86129a942c23391342d29 (patch) | |
tree | 9203474ac71dd8541e62851489ee926f3915f269 /common/execute.c | |
parent | 376be35ce7e11f3601863258e6d07d7f7d9c8fa7 (diff) | |
download | isc-dhcp-91c82d9fb6925cb462c86129a942c23391342d29.tar.gz |
- Add switch, case, default and set statements.
- Allow more than one type in a single on statement.
Diffstat (limited to 'common/execute.c')
-rw-r--r-- | common/execute.c | 308 |
1 files changed, 266 insertions, 42 deletions
diff --git a/common/execute.c b/common/execute.c index 60c9de2d..9afe1a7c 100644 --- a/common/execute.c +++ b/common/execute.c @@ -22,7 +22,7 @@ #ifndef lint static char copyright[] = -"$Id: execute.c,v 1.21 1999/10/07 06:35:42 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: execute.c,v 1.22 2000/01/08 01:30:29 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -34,9 +34,11 @@ int execute_statements (packet, lease, in_options, out_options, statements) struct option_state *out_options; struct executable_statement *statements; { - struct executable_statement *r; + struct executable_statement *r, *e; int result; int status; + struct binding *binding; + struct data_string ds; if (!statements) return 1; @@ -59,32 +61,54 @@ int execute_statements (packet, lease, in_options, out_options, statements) case on_statement: if (lease) { - struct executable_statement **d; - switch (r -> data.on.evtype) { - case expiry: - d = &lease -> on_expiry; - break; - case commit: - d = &lease -> on_commit; - break; - case release: - d = &lease -> on_release; - break; - default: - log_fatal ("unknown event type %d %s", - r -> data.on.evtype, - "in on statement."); - break; - } - if (*d) + if (r -> data.on.evtypes & ON_EXPIRY) { + if (lease -> on_expiry) executable_statement_dereference - (d, "execute_statements"); + (&lease -> on_expiry, + "execute_statements"); executable_statement_reference - (d, r -> data.on.statements, + (&lease -> on_expiry, + r -> data.on.statements, "execute_statements"); + } + if (r -> data.on.evtypes & ON_RELEASE) { + if (lease -> on_release) + executable_statement_dereference + (&lease -> on_release, + "execute_statements"); + executable_statement_reference + (&lease -> on_release, + r -> data.on.statements, + "execute_statements"); + } + if (r -> data.on.evtypes & ON_COMMIT) { + if (lease -> on_commit) + executable_statement_dereference + (&lease -> on_commit, + "execute_statements"); + executable_statement_reference + (&lease -> on_commit, + r -> data.on.statements, + "execute_statements"); + } } break; + case switch_statement: + e = find_matching_case (packet, lease, + in_options, out_options, + r -> data.s_switch.expr, + r -> data.s_switch.statements); + if (e && !execute_statements (packet, lease, + in_options, out_options, + e)) + return 0; + + /* These have no effect when executed. */ + case case_statement: + case default_statement: + break; + case if_statement: status = evaluate_boolean_expression (&result, packet, lease, @@ -166,6 +190,65 @@ int execute_statements (packet, lease, in_options, out_options, statements) r -> data.option, r -> op)); break; + case set_statement: + if (!lease) { +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: set %s = NULL", + r -> data.set.name); +#endif + break; + } + + memset (&ds, 0, sizeof ds); + status = (evaluate_data_expression + (&ds, packet, lease, in_options, out_options, + r -> data.set.expr)); + + for (binding = lease -> bindings; + binding; binding = binding -> next) { + if (!(strcasecmp + (lease -> bindings -> name, + r -> data.set.name))) + break; + } + if (!binding && status) { + binding = dmalloc (sizeof *binding, + "execute_statements"); + if (binding) { + binding -> name = + dmalloc (strlen + (r -> data.set.name + 1), + "execute_statements"); + if (binding -> name) + strcpy (binding -> name, + r -> data.set.name); + else + dfree (binding, + "execute_statements"); + binding -> next = lease -> bindings; + lease -> bindings = binding; + } else + status = 0; + } + if (binding) { + data_string_forget (&binding -> value, + "execute_statements"); + if (status) + data_string_copy + (&binding -> value, &ds, + "execute_statements"); + } + if (status) + data_string_forget (&ds, "execute_statements"); +#if defined (DEBUG_EXPRESSIONS) + log_debug ("exec: set %s = %s", r -> data.set.name, + (status + ? print_hex_1 (binding -> value.len, + binding -> value.data, 50) + : "NULL")); +#endif + break; + default: log_fatal ("bogus statement type %d\n", r -> op); } @@ -274,6 +357,21 @@ int executable_statement_dereference (ptr, name) (&(*ptr) -> data.on.statements, name); break; + case switch_statement: + if ((*ptr) -> data.s_switch.statements) + executable_statement_dereference + (&(*ptr) -> data.on.statements, name); + if ((*ptr) -> data.s_switch.expr) + expression_dereference (&(*ptr) -> data.s_switch.expr, + name); + break; + + case case_statement: + if ((*ptr) -> data.s_switch.expr) + expression_dereference (&(*ptr) -> data.c_case, + name); + break; + case if_statement: if ((*ptr) -> data.ie.expr) expression_dereference (&(*ptr) -> data.ie.expr, name); @@ -290,6 +388,14 @@ int executable_statement_dereference (ptr, name) expression_dereference (&(*ptr) -> data.eval, name); break; + case set_statement: + if ((*ptr)->data.set.name) + dfree ((*ptr)->data.set.name, name); + if ((*ptr)->data.set.expr) + expression_dereference (&(*ptr) -> data.set.expr, + name); + break; + case supersede_option_statement: case default_option_statement: case append_option_statement: @@ -330,36 +436,65 @@ void write_statements (file, statements, indent) break; case on_statement: - switch (r -> data.on.evtype) { - case expiry: - s = "expiry"; - break; - case commit: - s = "commit"; - break; - case release: - s = "release"; - break; - default: - log_fatal ("unknown event type %d %s", - r -> data.on.evtype, - "in on statement."); - } indent_spaces (file, indent); - fprintf (file, "on %s {", s); + fprintf (file, "on "); + s = ""; + if (r -> data.on.evtypes & ON_EXPIRY) { + fprintf (file, "expiry"); + s = "or"; + } + if (r -> data.on.evtypes & ON_COMMIT) { + fprintf (file, "commit"); + s = "or"; + } + if (r -> data.on.evtypes & ON_RELEASE) { + fprintf (file, "release"); + s = "or"; + } write_statements (file, r -> data.on.statements, indent + 2); indent_spaces (file, indent); fprintf (file, "}"); break; + case switch_statement: + indent_spaces (file, indent); + fprintf (file, "switch ("); + col = write_expression (file, + r -> data.s_switch.expr, + indent + 7, indent + 7, 1); + col = token_print_indent (file, col, indent + 7, + "", "", ")"); + token_print_indent (file, + col, indent, " ", "", "{"); + write_statements (file, r -> data.s_switch.statements, + indent + 2); + indent_spaces (file, indent); + fprintf (file, "}"); + break; + + case case_statement: + indent_spaces (file, indent - 1); + fprintf (file, "case "); + col = write_expression (file, + r -> data.s_switch.expr, + indent + 5, indent + 5, 1); + token_print_indent (file, col, indent + 5, + "", "", ":"); + break; + + case default_statement: + indent_spaces (file, indent - 1); + fprintf (file, "default: "); + break; + case if_statement: indent_spaces (file, indent); fprintf (file, "if "); x = r; col = write_expression (file, x -> data.ie.expr, - indent + 3, indent + 3); + indent + 3, indent + 3, 1); else_if: token_print_indent (file, col, indent, " ", "", "{"); write_statements (file, x -> data.ie.true, indent + 2); @@ -372,7 +507,7 @@ void write_statements (file, statements, indent) col = write_expression (file, x -> data.ie.expr, indent + 6, - indent + 6); + indent + 6, 1); goto else_if; } if (x -> data.ie.false) { @@ -389,7 +524,7 @@ void write_statements (file, statements, indent) indent_spaces (file, indent); fprintf (file, "eval "); col = write_expression (file, r -> data.eval, - indent + 5, indent + 5); + indent + 5, indent + 5, 1); fprintf (file, ";"); break; @@ -442,7 +577,7 @@ void write_statements (file, statements, indent) write_expression (file, r -> data.option -> expression, - col, indent + 8); + col, indent + 8, 1); else token_indent_data_string (file, col, indent + 8, "", "", @@ -451,8 +586,97 @@ void write_statements (file, statements, indent) fprintf (file, ";"); /* XXX */ break; + case set_statement: + indent_spaces (file, indent); + fprintf (file, "set "); + col = token_print_indent (file, indent + 4, indent + 4, + "", "", r -> data.set.name); + col = token_print_indent (file, col, indent + 4, + " ", " ", "="); + col = write_expression (file, r -> data.set.expr, + indent + 3, indent + 3, 0); + col = token_print_indent (file, col, indent + 4, + " ", "", ";"); + break; + default: log_fatal ("bogus statement type %d\n", r -> op); } } } + +/* Find a case statement in the sequence of executable statements that + matches the expression, and if found, return the following statement. + If no case statement matches, try to find a default statement and + return that (the default statement can precede all the case statements). + Otherwise, return the null statement. */ + +struct executable_statement *find_matching_case (packet, lease, + in_options, out_options, + expr, stmt) + struct packet *packet; + struct lease *lease; + struct option_state *in_options; + struct option_state *out_options; + struct expression *expr; + struct executable_statement *stmt; +{ + int status, sub; + struct executable_statement *s; + unsigned long foo; + + if (is_data_expression (expr)) { + struct executable_statement *e; + struct data_string cd, ds; + memset (&ds, 0, sizeof ds); + memset (&cd, 0, sizeof cd); + + status = (evaluate_data_expression + (&ds, packet, lease, in_options, out_options, expr)); + if (status) { + for (s = stmt; s; s = s -> next) { + if (s -> op == case_statement) { + sub = (evaluate_data_expression + (&cd, packet, lease, in_options, + out_options, s -> data.c_case)); + if (sub && cd.len == ds.len && + !memcmp (cd.data, ds.data, cd.len)) + { + data_string_forget + (&cd, "execute_statements"); + data_string_forget + (&ds, "execute_statements"); + return s -> next; + } + data_string_forget (&cd, "execute_statements"); + } + } + data_string_forget (&ds, "execute_statements"); + } + } else { + unsigned long n, c; + status = (evaluate_numeric_expression + (&n, packet, lease, in_options, out_options, expr)); + + if (status) { + for (s = stmt; s; s = s -> next) { + if (s -> op == case_statement) { + sub = (evaluate_numeric_expression + (&c, packet, lease, in_options, + out_options, s -> data.c_case)); + if (sub && n == c) + return s -> next; + } + } + } + } + + /* If we didn't find a matching case statement, look for a default + statement and return the statement following it. */ + for (s = stmt; s; s = s -> next) + if (s -> op == default_statement) + break; + if (s) + return s -> next; + return (struct executable_statement *)0; +} |