3 Support for executable statements. */
6 * Copyright (c) 1998-2002 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
45 static char copyright[] =
46 "$Id: execute.c,v 1.44.2.9 2002/11/17 02:26:58 dhankins Exp $ Copyright (c) 1998-2002 The Internet Software Consortium. All rights reserved.\n";
50 #include <omapip/omapip_p.h>
52 int execute_statements (result, packet, lease, client_state,
53 in_options, out_options, scope, statements)
54 struct binding_value **result;
55 struct packet *packet;
57 struct client_state *client_state;
58 struct option_state *in_options;
59 struct option_state *out_options;
60 struct binding_scope **scope;
61 struct executable_statement *statements;
63 struct executable_statement *r, *e, *next;
67 struct binding_scope *outer;
68 struct binding *binding;
69 struct data_string ds;
70 struct binding_scope *ns;
75 r = (struct executable_statement *)0;
76 next = (struct executable_statement *)0;
77 e = (struct executable_statement *)0;
78 executable_statement_reference (&r, statements, MDL);
79 while (r && !(result && *result)) {
81 executable_statement_reference (&next, r -> next, MDL);
83 case statements_statement:
84 #if defined (DEBUG_EXPRESSIONS)
85 log_debug ("exec: statements");
87 status = execute_statements (result, packet, lease,
88 client_state, in_options,
90 r -> data.statements);
91 #if defined (DEBUG_EXPRESSIONS)
92 log_debug ("exec: statements returns %d", status);
100 if (r -> data.on.evtypes & ON_EXPIRY) {
101 #if defined (DEBUG_EXPRESSIONS)
102 log_debug ("exec: on expiry");
104 if (lease -> on_expiry)
105 executable_statement_dereference
106 (&lease -> on_expiry, MDL);
107 if (r -> data.on.statements)
108 executable_statement_reference
109 (&lease -> on_expiry,
110 r -> data.on.statements, MDL);
112 if (r -> data.on.evtypes & ON_RELEASE) {
113 #if defined (DEBUG_EXPRESSIONS)
114 log_debug ("exec: on release");
116 if (lease -> on_release)
117 executable_statement_dereference
118 (&lease -> on_release, MDL);
119 if (r -> data.on.statements)
120 executable_statement_reference
121 (&lease -> on_release,
122 r -> data.on.statements, MDL);
124 if (r -> data.on.evtypes & ON_COMMIT) {
125 #if defined (DEBUG_EXPRESSIONS)
126 log_debug ("exec: on commit");
128 if (lease -> on_commit)
129 executable_statement_dereference
130 (&lease -> on_commit, MDL);
131 if (r -> data.on.statements)
132 executable_statement_reference
133 (&lease -> on_commit,
134 r -> data.on.statements, MDL);
139 case switch_statement:
140 #if defined (DEBUG_EXPRESSIONS)
141 log_debug ("exec: switch");
143 status = (find_matching_case
144 (&e, packet, lease, client_state,
145 in_options, out_options, scope,
146 r -> data.s_switch.expr,
147 r -> data.s_switch.statements));
148 #if defined (DEBUG_EXPRESSIONS)
149 log_debug ("exec: switch: case %lx", (unsigned long)e);
152 if (!(execute_statements
153 (result, packet, lease, client_state,
154 in_options, out_options, scope, e))) {
155 executable_statement_dereference
159 executable_statement_dereference (&e, MDL);
163 /* These have no effect when executed. */
165 case default_statement:
169 status = (evaluate_boolean_expression
171 lease, client_state, in_options,
172 out_options, scope, r -> data.ie.expr));
174 #if defined (DEBUG_EXPRESSIONS)
175 log_debug ("exec: if %s", (status
176 ? (rc ? "true" : "false")
179 /* XXX Treat NULL as false */
182 if (!execute_statements
183 (result, packet, lease, client_state,
184 in_options, out_options, scope,
185 rc ? r -> data.ie.tc : r -> data.ie.fc))
190 status = evaluate_expression
191 ((struct binding_value **)0,
192 packet, lease, client_state, in_options,
193 out_options, scope, r -> data.eval, MDL);
194 #if defined (DEBUG_EXPRESSIONS)
195 log_debug ("exec: evaluate: %s",
196 (status ? "succeeded" : "failed"));
200 case return_statement:
201 status = evaluate_expression
203 lease, client_state, in_options,
204 out_options, scope, r -> data.retval, MDL);
205 #if defined (DEBUG_EXPRESSIONS)
206 log_debug ("exec: return: %s",
207 (status ? "succeeded" : "failed"));
212 #if defined (DEBUG_EXPRESSIONS)
213 log_debug ("exec: add %s", (r -> data.add -> name
214 ? r -> data.add -> name
215 : "<unnamed class>"));
217 classify (packet, r -> data.add);
220 case break_statement:
221 #if defined (DEBUG_EXPRESSIONS)
222 log_debug ("exec: break");
226 case supersede_option_statement:
227 case send_option_statement:
228 #if defined (DEBUG_EXPRESSIONS)
229 log_debug ("exec: %s option %s.%s",
230 (r -> op == supersede_option_statement
231 ? "supersede" : "send"),
232 r -> data.option -> option -> universe -> name,
233 r -> data.option -> option -> name);
234 goto option_statement;
236 case default_option_statement:
237 #if defined (DEBUG_EXPRESSIONS)
238 log_debug ("exec: default option %s.%s",
239 r -> data.option -> option -> universe -> name,
240 r -> data.option -> option -> name);
241 goto option_statement;
243 case append_option_statement:
244 #if defined (DEBUG_EXPRESSIONS)
245 log_debug ("exec: append option %s.%s",
246 r -> data.option -> option -> universe -> name,
247 r -> data.option -> option -> name);
248 goto option_statement;
250 case prepend_option_statement:
251 #if defined (DEBUG_EXPRESSIONS)
252 log_debug ("exec: prepend option %s.%s",
253 r -> data.option -> option -> universe -> name,
254 r -> data.option -> option -> name);
257 set_option (r -> data.option -> option -> universe,
258 out_options, r -> data.option, r -> op);
262 case define_statement:
264 log_error ("set %s: no scope",
270 if (!binding_scope_allocate (scope, MDL)) {
271 log_error ("set %s: can't allocate scope",
277 binding = find_binding (*scope, r -> data.set.name);
278 #if defined (DEBUG_EXPRESSIONS)
279 log_debug ("exec: set %s", r -> data.set.name);
282 binding = dmalloc (sizeof *binding, MDL);
284 memset (binding, 0, sizeof *binding);
287 (r -> data.set.name) + 1,
289 if (binding -> name) {
290 strcpy (binding -> name,
292 binding -> next = (*scope) -> bindings;
293 (*scope) -> bindings = binding;
296 dfree (binding, MDL);
297 binding = (struct binding *)0;
302 if (binding -> value)
303 binding_value_dereference
304 (&binding -> value, MDL);
305 if (r -> op == set_statement) {
306 status = (evaluate_expression
307 (&binding -> value, packet,
309 in_options, out_options,
310 scope, r -> data.set.expr,
313 if (!(binding_value_allocate
314 (&binding -> value, MDL))) {
315 dfree (binding, MDL);
316 binding = (struct binding *)0;
318 if (binding -> value) {
319 binding -> value -> type =
322 (&binding -> value -> value.fundef,
323 r -> data.set.expr -> data.func,
328 #if defined (DEBUG_EXPRESSIONS)
329 log_debug ("exec: set %s%s", r -> data.set.name,
330 (binding && status ? "" : " (failed)"));
334 case unset_statement:
335 if (!scope || !*scope) {
339 binding = find_binding (*scope, r -> data.unset);
341 if (binding -> value)
342 binding_value_dereference
343 (&binding -> value, MDL);
347 #if defined (DEBUG_EXPRESSIONS)
348 log_debug ("exec: unset %s: %s", r -> data.unset,
349 (status ? "found" : "not found"));
354 #if defined (DEBUG_EXPRESSIONS)
355 log_debug ("exec: let %s", r -> data.let.name);
357 ns = (struct binding_scope *)0;
358 binding_scope_allocate (&ns, MDL);
363 binding = dmalloc (sizeof *binding, MDL);
364 memset (binding, 0, sizeof *binding);
367 binding_scope_dereference (&ns, MDL);
371 (e -> data.let.name + 1),
374 strcpy (binding -> name,
377 dfree (binding, MDL);
378 binding = (struct binding *)0;
384 status = (evaluate_expression
385 (&binding -> value, packet, lease,
387 in_options, out_options,
388 scope, e -> data.set.expr, MDL));
389 binding -> next = ns -> bindings;
390 ns -> bindings = binding;
393 #if defined (DEBUG_EXPRESSIONS)
394 log_debug ("exec: let %s%s", e -> data.let.name,
395 (binding && status ? "" : "failed"));
397 if (!e -> data.let.statements) {
398 } else if (e -> data.let.statements -> op ==
400 e = e -> data.let.statements;
404 binding_scope_reference (&ns -> outer,
407 (result, packet, lease,
409 in_options, out_options,
410 &ns, e -> data.let.statements);
413 binding_scope_dereference (&ns, MDL);
417 memset (&ds, 0, sizeof ds);
418 status = (evaluate_data_expression
420 lease, client_state, in_options,
421 out_options, scope, r -> data.log.expr,
424 #if defined (DEBUG_EXPRESSIONS)
425 log_debug ("exec: log");
429 switch (r -> data.log.priority) {
430 case log_priority_fatal:
431 log_fatal ("%.*s", (int)ds.len,
434 case log_priority_error:
435 log_error ("%.*s", (int)ds.len,
438 case log_priority_debug:
439 log_debug ("%.*s", (int)ds.len,
442 case log_priority_info:
443 log_info ("%.*s", (int)ds.len,
447 data_string_forget (&ds, MDL);
453 log_error ("bogus statement type %d", r -> op);
456 executable_statement_dereference (&r, MDL);
458 executable_statement_reference (&r, next, MDL);
459 executable_statement_dereference (&next, MDL);
466 /* Execute all the statements in a particular scope, and all statements in
467 scopes outer from that scope, but if a particular limiting scope is
468 reached, do not execute statements in that scope or in scopes outer
469 from it. More specific scopes need to take precedence over less
470 specific scopes, so we recursively traverse the scope list, executing
471 the most outer scope first. */
473 void execute_statements_in_scope (result, packet,
474 lease, client_state, in_options, out_options,
475 scope, group, limiting_group)
476 struct binding_value **result;
477 struct packet *packet;
479 struct client_state *client_state;
480 struct option_state *in_options;
481 struct option_state *out_options;
482 struct binding_scope **scope;
484 struct group *limiting_group;
488 /* If we've recursed as far as we can, return. */
492 /* As soon as we get to a scope that is outer than the limiting
493 scope, we are done. This is so that if somebody does something
494 like this, it does the expected thing:
496 domain-name "fugue.com";
499 domain-name "othello.fugue.com";
500 fixed-address 10.20.30.40;
502 subnet 10.20.30.0 netmask 255.255.255.0 {
503 domain-name "manhattan.fugue.com";
507 The problem with the above arrangement is that the host's
508 group nesting will be host -> shared-network -> top-level,
509 and the limiting scope when we evaluate the host's scope
510 will be the subnet -> shared-network -> top-level, so we need
511 to know when we evaluate the host's scope to stop before we
512 evaluate the shared-networks scope, because it's outer than
513 the limiting scope, which means we've already evaluated it. */
515 for (limit = limiting_group; limit; limit = limit -> next) {
521 execute_statements_in_scope (result, packet,
523 in_options, out_options, scope,
524 group -> next, limiting_group);
525 execute_statements (result, packet, lease, client_state, in_options,
526 out_options, scope, group -> statements);
529 /* Dereference or free any subexpressions of a statement being freed. */
531 int executable_statement_dereference (ptr, file, line)
532 struct executable_statement **ptr;
536 struct executable_statement *bp;
539 log_error ("%s(%d): null pointer", file, line);
540 #if defined (POINTER_DEBUG)
548 rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
549 if ((*ptr) -> refcnt > 0) {
550 *ptr = (struct executable_statement *)0;
554 if ((*ptr) -> refcnt < 0) {
555 log_error ("%s(%d): negative refcnt!", file, line);
556 #if defined (DEBUG_RC_HISTORY)
557 dump_rc_history (*ptr);
559 #if defined (POINTER_DEBUG)
567 executable_statement_dereference (&(*ptr) -> next, file, line);
569 switch ((*ptr) -> op) {
570 case statements_statement:
571 if ((*ptr) -> data.statements)
572 executable_statement_dereference
573 (&(*ptr) -> data.statements, file, line);
577 if ((*ptr) -> data.on.statements)
578 executable_statement_dereference
579 (&(*ptr) -> data.on.statements, file, line);
582 case switch_statement:
583 if ((*ptr) -> data.s_switch.statements)
584 executable_statement_dereference
585 (&(*ptr) -> data.on.statements, file, line);
586 if ((*ptr) -> data.s_switch.expr)
587 expression_dereference (&(*ptr) -> data.s_switch.expr,
592 if ((*ptr) -> data.s_switch.expr)
593 expression_dereference (&(*ptr) -> data.c_case,
598 if ((*ptr) -> data.ie.expr)
599 expression_dereference (&(*ptr) -> data.ie.expr,
601 if ((*ptr) -> data.ie.tc)
602 executable_statement_dereference
603 (&(*ptr) -> data.ie.tc, file, line);
604 if ((*ptr) -> data.ie.fc)
605 executable_statement_dereference
606 (&(*ptr) -> data.ie.fc, file, line);
610 if ((*ptr) -> data.eval)
611 expression_dereference (&(*ptr) -> data.eval,
615 case return_statement:
616 if ((*ptr) -> data.eval)
617 expression_dereference (&(*ptr) -> data.eval,
622 if ((*ptr)->data.set.name)
623 dfree ((*ptr)->data.set.name, file, line);
624 if ((*ptr)->data.set.expr)
625 expression_dereference (&(*ptr) -> data.set.expr,
629 case unset_statement:
630 if ((*ptr)->data.unset)
631 dfree ((*ptr)->data.unset, file, line);
634 case supersede_option_statement:
635 case send_option_statement:
636 case default_option_statement:
637 case append_option_statement:
638 case prepend_option_statement:
639 if ((*ptr) -> data.option)
640 option_cache_dereference (&(*ptr) -> data.option,
649 dfree ((*ptr), file, line);
650 *ptr = (struct executable_statement *)0;
654 void write_statements (file, statements, indent)
656 struct executable_statement *statements;
659 struct executable_statement *r, *x;
662 const char *s, *t, *dot;
668 for (r = statements; r; r = r -> next) {
670 case statements_statement:
671 write_statements (file, r -> data.statements, indent);
675 indent_spaces (file, indent);
676 fprintf (file, "on ");
678 if (r -> data.on.evtypes & ON_EXPIRY) {
679 fprintf (file, "%sexpiry", s);
682 if (r -> data.on.evtypes & ON_COMMIT) {
683 fprintf (file, "%scommit", s);
686 if (r -> data.on.evtypes & ON_RELEASE) {
687 fprintf (file, "%srelease", s);
690 if (r -> data.on.statements) {
691 fprintf (file, " {");
692 write_statements (file,
693 r -> data.on.statements,
695 indent_spaces (file, indent);
702 case switch_statement:
703 indent_spaces (file, indent);
704 fprintf (file, "switch (");
705 col = write_expression (file,
706 r -> data.s_switch.expr,
707 indent + 7, indent + 7, 1);
708 col = token_print_indent (file, col, indent + 7,
710 token_print_indent (file,
711 col, indent, " ", "", "{");
712 write_statements (file, r -> data.s_switch.statements,
714 indent_spaces (file, indent);
719 indent_spaces (file, indent - 1);
720 fprintf (file, "case ");
721 col = write_expression (file,
722 r -> data.s_switch.expr,
723 indent + 5, indent + 5, 1);
724 token_print_indent (file, col, indent + 5,
728 case default_statement:
729 indent_spaces (file, indent - 1);
730 fprintf (file, "default: ");
734 indent_spaces (file, indent);
735 fprintf (file, "if ");
737 col = write_expression (file,
739 indent + 3, indent + 3, 1);
741 token_print_indent (file, col, indent, " ", "", "{");
742 write_statements (file, x -> data.ie.tc, indent + 2);
743 if (x -> data.ie.fc &&
744 x -> data.ie.fc -> op == if_statement &&
745 !x -> data.ie.fc -> next) {
746 indent_spaces (file, indent);
747 fprintf (file, "} elsif ");
749 col = write_expression (file,
755 if (x -> data.ie.fc) {
756 indent_spaces (file, indent);
757 fprintf (file, "} else {");
758 write_statements (file, x -> data.ie.fc,
761 indent_spaces (file, indent);
766 indent_spaces (file, indent);
767 fprintf (file, "eval ");
768 col = write_expression (file, r -> data.eval,
769 indent + 5, indent + 5, 1);
773 case return_statement:
774 indent_spaces (file, indent);
775 fprintf (file, "return;");
779 indent_spaces (file, indent);
780 fprintf (file, "add \"%s\"", r -> data.add -> name);
783 case break_statement:
784 indent_spaces (file, indent);
785 fprintf (file, "break;");
788 case supersede_option_statement:
789 case send_option_statement:
791 goto option_statement;
793 case default_option_statement:
795 goto option_statement;
797 case append_option_statement:
799 goto option_statement;
801 case prepend_option_statement:
804 /* Note: the reason we don't try to pretty print
805 the option here is that the format of the option
806 may change in dhcpd.conf, and then when this
807 statement was read back, it would cause a syntax
809 if (r -> data.option -> option -> universe ==
814 t = (r -> data.option -> option ->
818 indent_spaces (file, indent);
819 fprintf (file, "%s %s%s%s = ", s, t, dot,
820 r -> data.option -> option -> name);
821 col = (indent + strlen (s) + strlen (t) +
822 strlen (dot) + strlen (r -> data.option ->
823 option -> name) + 4);
824 if (r -> data.option -> expression)
827 r -> data.option -> expression,
830 token_indent_data_string
831 (file, col, indent + 8, "", "",
832 &r -> data.option -> data);
834 fprintf (file, ";"); /* XXX */
838 indent_spaces (file, indent);
839 fprintf (file, "set ");
840 col = token_print_indent (file, indent + 4, indent + 4,
841 "", "", r -> data.set.name);
842 col = token_print_indent (file, col, indent + 4,
844 col = write_expression (file, r -> data.set.expr,
845 indent + 3, indent + 3, 0);
846 col = token_print_indent (file, col, indent + 4,
850 case unset_statement:
851 indent_spaces (file, indent);
852 fprintf (file, "unset ");
853 col = token_print_indent (file, indent + 6, indent + 6,
854 "", "", r -> data.set.name);
855 col = token_print_indent (file, col, indent + 6,
860 indent_spaces (file, indent);
861 fprintf (file, "log ");
862 col = token_print_indent (file, col, indent + 4,
864 switch (r -> data.log.priority) {
865 case log_priority_fatal:
866 col = token_print_indent
867 (file, col, indent + 4, "",
870 case log_priority_error:
871 col = token_print_indent
872 (file, col, indent + 4, "",
875 case log_priority_debug:
876 col = token_print_indent
877 (file, col, indent + 4, "",
880 case log_priority_info:
881 col = token_print_indent
882 (file, col, indent + 4, "",
886 col = write_expression (file, r -> data.log.expr,
887 indent + 4, indent + 4, 0);
888 col = token_print_indent (file, col, indent + 4,
894 log_fatal ("bogus statement type %d\n", r -> op);
899 /* Find a case statement in the sequence of executable statements that
900 matches the expression, and if found, return the following statement.
901 If no case statement matches, try to find a default statement and
902 return that (the default statement can precede all the case statements).
903 Otherwise, return the null statement. */
905 int find_matching_case (struct executable_statement **ep,
906 struct packet *packet, struct lease *lease,
907 struct client_state *client_state,
908 struct option_state *in_options,
909 struct option_state *out_options,
910 struct binding_scope **scope,
911 struct expression *expr,
912 struct executable_statement *stmt)
915 struct executable_statement *s;
918 if (is_data_expression (expr)) {
919 struct executable_statement *e;
920 struct data_string cd, ds;
921 memset (&ds, 0, sizeof ds);
922 memset (&cd, 0, sizeof cd);
924 status = (evaluate_data_expression (&ds, packet, lease,
925 client_state, in_options,
926 out_options, scope, expr,
929 for (s = stmt; s; s = s -> next) {
930 if (s -> op == case_statement) {
931 sub = (evaluate_data_expression
932 (&cd, packet, lease, client_state,
933 in_options, out_options,
934 scope, s -> data.c_case, MDL));
935 if (sub && cd.len == ds.len &&
936 !memcmp (cd.data, ds.data, cd.len))
938 data_string_forget (&cd, MDL);
939 data_string_forget (&ds, MDL);
940 executable_statement_reference
941 (ep, s -> next, MDL);
944 data_string_forget (&cd, MDL);
947 data_string_forget (&ds, MDL);
951 status = evaluate_numeric_expression (&n, packet, lease,
953 in_options, out_options,
957 for (s = stmt; s; s = s -> next) {
958 if (s -> op == case_statement) {
959 sub = (evaluate_numeric_expression
960 (&c, packet, lease, client_state,
961 in_options, out_options,
962 scope, s -> data.c_case));
964 executable_statement_reference
965 (ep, s -> next, MDL);
973 /* If we didn't find a matching case statement, look for a default
974 statement and return the statement following it. */
975 for (s = stmt; s; s = s -> next)
976 if (s -> op == default_statement)
979 executable_statement_reference (ep, s -> next, MDL);
985 int executable_statement_foreach (struct executable_statement *stmt,
986 int (*callback) (struct
987 executable_statement *,
991 struct executable_statement *foo;
995 for (foo = stmt; foo; foo = foo -> next) {
996 if ((*callback) (foo, vp, condp) != 0)
1002 if (executable_statement_foreach (foo -> data.ie.tc,
1005 if (executable_statement_foreach (foo -> data.ie.fc,
1011 case eval_statement:
1013 case break_statement:
1015 case default_option_statement:
1017 case supersede_option_statement:
1019 case append_option_statement:
1021 case prepend_option_statement:
1023 case send_option_statement:
1025 case statements_statement:
1026 if ((executable_statement_foreach
1027 (foo -> data.statements, callback, vp, condp)))
1031 if ((executable_statement_foreach
1032 (foo -> data.on.statements, callback, vp, 1)))
1035 case switch_statement:
1036 if ((executable_statement_foreach
1037 (foo -> data.s_switch.statements, callback, vp, 1)))
1040 case case_statement:
1042 case default_statement:
1046 case unset_statement:
1049 if ((executable_statement_foreach
1050 (foo -> data.let.statements, callback, vp, 0)))
1053 case define_statement:
1056 case return_statement: