Add regression test infrastructure.
[dragonfly.git] / contrib / dhcp-3.0 / common / execute.c
1 /* execute.c
2
3    Support for executable statements. */
4
5 /*
6  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1998-2003 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  *   Internet Systems Consortium, Inc.
22  *   950 Charter Street
23  *   Redwood City, CA 94063
24  *   <info@isc.org>
25  *   http://www.isc.org/
26  *
27  * This software has been written for Internet Systems Consortium
28  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29  * To learn more about Internet Systems Consortium, see
30  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
31  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32  * ``http://www.nominum.com''.
33  */
34
35 #ifndef lint
36 static char copyright[] =
37 "$Id: execute.c,v 1.44.2.12 2004/11/24 17:39:15 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #include "dhcpd.h"
41 #include <omapip/omapip_p.h>
42
43 int execute_statements (result, packet, lease, client_state,
44                         in_options, out_options, scope, statements)
45         struct binding_value **result;
46         struct packet *packet;
47         struct lease *lease;
48         struct client_state *client_state;
49         struct option_state *in_options;
50         struct option_state *out_options;
51         struct binding_scope **scope;
52         struct executable_statement *statements;
53 {
54         struct executable_statement *r, *e, *next;
55         int rc;
56         int status;
57         unsigned long num;
58         struct binding_scope *outer;
59         struct binding *binding;
60         struct data_string ds;
61         struct binding_scope *ns;
62
63         if (!statements)
64                 return 1;
65
66         r = (struct executable_statement *)0;
67         next = (struct executable_statement *)0;
68         e = (struct executable_statement *)0;
69         executable_statement_reference (&r, statements, MDL);
70         while (r && !(result && *result)) {
71                 if (r -> next)
72                         executable_statement_reference (&next, r -> next, MDL);
73                 switch (r -> op) {
74                       case statements_statement:
75 #if defined (DEBUG_EXPRESSIONS)
76                         log_debug ("exec: statements");
77 #endif
78                         status = execute_statements (result, packet, lease,
79                                                      client_state, in_options,
80                                                      out_options, scope,
81                                                      r -> data.statements);
82 #if defined (DEBUG_EXPRESSIONS)
83                         log_debug ("exec: statements returns %d", status);
84 #endif
85                         if (!status)
86                                 return 0;
87                         break;
88
89                       case on_statement:
90                         if (lease) {
91                             if (r -> data.on.evtypes & ON_EXPIRY) {
92 #if defined (DEBUG_EXPRESSIONS)
93                                     log_debug ("exec: on expiry");
94 #endif
95                                 if (lease -> on_expiry)
96                                         executable_statement_dereference
97                                                 (&lease -> on_expiry, MDL);
98                                 if (r -> data.on.statements)
99                                         executable_statement_reference
100                                                 (&lease -> on_expiry,
101                                                  r -> data.on.statements, MDL);
102                             }
103                             if (r -> data.on.evtypes & ON_RELEASE) {
104 #if defined (DEBUG_EXPRESSIONS)
105                                     log_debug ("exec: on release");
106 #endif
107                                 if (lease -> on_release)
108                                         executable_statement_dereference
109                                                 (&lease -> on_release, MDL);
110                                 if (r -> data.on.statements)
111                                         executable_statement_reference
112                                                 (&lease -> on_release,
113                                                  r -> data.on.statements, MDL);
114                             }
115                             if (r -> data.on.evtypes & ON_COMMIT) {
116 #if defined (DEBUG_EXPRESSIONS)
117                                     log_debug ("exec: on commit");
118 #endif
119                                 if (lease -> on_commit)
120                                         executable_statement_dereference
121                                                 (&lease -> on_commit, MDL);
122                                 if (r -> data.on.statements)
123                                         executable_statement_reference
124                                                 (&lease -> on_commit,
125                                                  r -> data.on.statements, MDL);
126                             }
127                         }
128                         break;
129
130                       case switch_statement:
131 #if defined (DEBUG_EXPRESSIONS)
132                         log_debug ("exec: switch");
133 #endif
134                         status = (find_matching_case
135                                   (&e, packet, lease, client_state,
136                                    in_options, out_options, scope,
137                                    r -> data.s_switch.expr,
138                                    r -> data.s_switch.statements));
139 #if defined (DEBUG_EXPRESSIONS)
140                         log_debug ("exec: switch: case %lx", (unsigned long)e);
141 #endif
142                         if (status) {
143                                 if (!(execute_statements
144                                       (result, packet, lease, client_state,
145                                        in_options, out_options, scope, e))) {
146                                         executable_statement_dereference
147                                                 (&e, MDL);
148                                         return 0;
149                                 }
150                                 executable_statement_dereference (&e, MDL);
151                         }
152                         break;
153
154                         /* These have no effect when executed. */
155                       case case_statement:
156                       case default_statement:
157                         break;
158
159                       case if_statement:
160                         status = (evaluate_boolean_expression
161                                   (&rc, packet,
162                                    lease, client_state, in_options,
163                                    out_options, scope, r -> data.ie.expr));
164                         
165 #if defined (DEBUG_EXPRESSIONS)
166                         log_debug ("exec: if %s", (status
167                                               ? (rc ? "true" : "false")
168                                               : "NULL"));
169 #endif
170                         /* XXX Treat NULL as false */
171                         if (!status)
172                                 rc = 0;
173                         if (!execute_statements
174                             (result, packet, lease, client_state,
175                              in_options, out_options, scope,
176                              rc ? r -> data.ie.tc : r -> data.ie.fc))
177                                 return 0;
178                         break;
179
180                       case eval_statement:
181                         status = evaluate_expression
182                                 ((struct binding_value **)0,
183                                  packet, lease, client_state, in_options,
184                                  out_options, scope, r -> data.eval, MDL);
185 #if defined (DEBUG_EXPRESSIONS)
186                         log_debug ("exec: evaluate: %s",
187                                    (status ? "succeeded" : "failed"));
188 #endif
189                         break;
190
191                       case return_statement:
192                         status = evaluate_expression
193                                 (result, packet,
194                                  lease, client_state, in_options,
195                                  out_options, scope, r -> data.retval, MDL);
196 #if defined (DEBUG_EXPRESSIONS)
197                         log_debug ("exec: return: %s",
198                                    (status ? "succeeded" : "failed"));
199 #endif
200                         break;
201
202                       case add_statement:
203 #if defined (DEBUG_EXPRESSIONS)
204                         log_debug ("exec: add %s", (r -> data.add -> name
205                                                ? r -> data.add -> name
206                                                : "<unnamed class>"));
207 #endif
208                         classify (packet, r -> data.add);
209                         break;
210
211                       case break_statement:
212 #if defined (DEBUG_EXPRESSIONS)
213                         log_debug ("exec: break");
214 #endif
215                         return 1;
216
217                       case supersede_option_statement:
218                       case send_option_statement:
219 #if defined (DEBUG_EXPRESSIONS)
220                         log_debug ("exec: %s option %s.%s",
221                               (r -> op == supersede_option_statement
222                                ? "supersede" : "send"),
223                               r -> data.option -> option -> universe -> name,
224                               r -> data.option -> option -> name);
225                         goto option_statement;
226 #endif
227                       case default_option_statement:
228 #if defined (DEBUG_EXPRESSIONS)
229                         log_debug ("exec: default option %s.%s",
230                               r -> data.option -> option -> universe -> name,
231                               r -> data.option -> option -> name);
232                         goto option_statement;
233 #endif
234                       case append_option_statement:
235 #if defined (DEBUG_EXPRESSIONS)
236                         log_debug ("exec: append option %s.%s",
237                               r -> data.option -> option -> universe -> name,
238                               r -> data.option -> option -> name);
239                         goto option_statement;
240 #endif
241                       case prepend_option_statement:
242 #if defined (DEBUG_EXPRESSIONS)
243                         log_debug ("exec: prepend option %s.%s",
244                               r -> data.option -> option -> universe -> name,
245                               r -> data.option -> option -> name);
246                       option_statement:
247 #endif
248                         set_option (r -> data.option -> option -> universe,
249                                     out_options, r -> data.option, r -> op);
250                         break;
251
252                       case set_statement:
253                       case define_statement:
254                         if (!scope) {
255                                 log_error ("set %s: no scope",
256                                            r -> data.set.name);
257                                 status = 0;
258                                 break;
259                         }
260                         if (!*scope) {
261                             if (!binding_scope_allocate (scope, MDL)) {
262                                 log_error ("set %s: can't allocate scope",
263                                            r -> data.set.name);
264                                 status = 0;
265                                 break;
266                             }
267                         }
268                         binding = find_binding (*scope, r -> data.set.name);
269 #if defined (DEBUG_EXPRESSIONS)
270                         log_debug ("exec: set %s", r -> data.set.name);
271 #endif
272                         if (!binding) {
273                                 binding = dmalloc (sizeof *binding, MDL);
274                                 if (binding) {
275                                     memset (binding, 0, sizeof *binding);
276                                     binding -> name =
277                                             dmalloc (strlen
278                                                      (r -> data.set.name) + 1,
279                                                      MDL);
280                                     if (binding -> name) {
281                                         strcpy (binding -> name,
282                                                 r -> data.set.name);
283                                         binding -> next = (*scope) -> bindings;
284                                         (*scope) -> bindings = binding;
285                                     } else {
286                                        badalloc:
287                                         dfree (binding, MDL);
288                                         binding = (struct binding *)0;
289                                     }
290                                 }
291                         }
292                         if (binding) {
293                                 if (binding -> value)
294                                         binding_value_dereference
295                                                 (&binding -> value, MDL);
296                                 if (r -> op == set_statement) {
297                                         status = (evaluate_expression
298                                                   (&binding -> value, packet,
299                                                    lease, client_state,
300                                                    in_options, out_options,
301                                                    scope, r -> data.set.expr,
302                                                    MDL));
303                                 } else {
304                                     if (!(binding_value_allocate
305                                           (&binding -> value, MDL))) {
306                                             dfree (binding, MDL);
307                                             binding = (struct binding *)0;
308                                     }
309                                     if (binding -> value) {
310                                         binding -> value -> type =
311                                                 binding_function;
312                                         (fundef_reference
313                                          (&binding -> value -> value.fundef,
314                                           r -> data.set.expr -> data.func,
315                                           MDL));
316                                     }
317                                 }
318                         }
319 #if defined (DEBUG_EXPRESSIONS)
320                         log_debug ("exec: set %s%s", r -> data.set.name,
321                                    (binding && status ? "" : " (failed)"));
322 #endif
323                         break;
324
325                       case unset_statement:
326                         if (!scope || !*scope) {
327                                 status = 0;
328                                 break;
329                         }
330                         binding = find_binding (*scope, r -> data.unset);
331                         if (binding) {
332                                 if (binding -> value)
333                                         binding_value_dereference
334                                                 (&binding -> value, MDL);
335                                 status = 1;
336                         } else
337                                 status = 0;
338 #if defined (DEBUG_EXPRESSIONS)
339                         log_debug ("exec: unset %s: %s", r -> data.unset,
340                                    (status ? "found" : "not found"));
341 #endif
342                         break;
343
344                       case let_statement:
345 #if defined (DEBUG_EXPRESSIONS)
346                         log_debug ("exec: let %s", r -> data.let.name);
347 #endif
348                         ns = (struct binding_scope *)0;
349                         binding_scope_allocate (&ns, MDL);
350                         e = r;
351
352                       next_let:
353                         if (ns) {
354                                 binding = dmalloc (sizeof *binding, MDL);
355                                 memset (binding, 0, sizeof *binding);
356                                 if (!binding) {
357                                    blb:
358                                     binding_scope_dereference (&ns, MDL);
359                                 } else {
360                                     binding -> name =
361                                             dmalloc (strlen
362                                                      (e -> data.let.name + 1),
363                                                      MDL);
364                                     if (binding -> name)
365                                         strcpy (binding -> name,
366                                                 e -> data.let.name);
367                                     else {
368                                         dfree (binding, MDL);
369                                         binding = (struct binding *)0;
370                                         goto blb;
371                                     }
372                                 }
373                         } else
374                                 binding = NULL;
375
376                         if (ns && binding) {
377                                 status = (evaluate_expression
378                                           (&binding -> value, packet, lease,
379                                            client_state,
380                                            in_options, out_options,
381                                            scope, e -> data.set.expr, MDL));
382                                 binding -> next = ns -> bindings;
383                                 ns -> bindings = binding;
384                         }
385
386 #if defined (DEBUG_EXPRESSIONS)
387                         log_debug ("exec: let %s%s", e -> data.let.name,
388                                    (binding && status ? "" : "failed"));
389 #endif
390                         if (!e -> data.let.statements) {
391                         } else if (e -> data.let.statements -> op ==
392                                    let_statement) {
393                                 e = e -> data.let.statements;
394                                 goto next_let;
395                         } else if (ns) {
396                                 if (scope && *scope)
397                                         binding_scope_reference (&ns -> outer,
398                                                                  *scope, MDL);
399                                 execute_statements
400                                       (result, packet, lease,
401                                        client_state,
402                                        in_options, out_options,
403                                        &ns, e -> data.let.statements);
404                         }
405                         if (ns)
406                                 binding_scope_dereference (&ns, MDL);
407                         break;
408
409                       case log_statement:
410                         memset (&ds, 0, sizeof ds);
411                         status = (evaluate_data_expression
412                                   (&ds, packet,
413                                    lease, client_state, in_options,
414                                    out_options, scope, r -> data.log.expr,
415                                    MDL));
416                         
417 #if defined (DEBUG_EXPRESSIONS)
418                         log_debug ("exec: log");
419 #endif
420
421                         if (status) {
422                                 switch (r -> data.log.priority) {
423                                 case log_priority_fatal:
424                                         log_fatal ("%.*s", (int)ds.len,
425                                                 ds.data);
426                                         break;
427                                 case log_priority_error:
428                                         log_error ("%.*s", (int)ds.len,
429                                                 ds.data);
430                                         break;
431                                 case log_priority_debug:
432                                         log_debug ("%.*s", (int)ds.len,
433                                                 ds.data);
434                                         break;
435                                 case log_priority_info:
436                                         log_info ("%.*s", (int)ds.len,
437                                                 ds.data);
438                                         break;
439                                 }
440                                 data_string_forget (&ds, MDL);
441                         }
442
443                         break;
444
445                       default:
446                         log_error ("bogus statement type %d", r -> op);
447                         break;
448                 }
449                 executable_statement_dereference (&r, MDL);
450                 if (next) {
451                         executable_statement_reference (&r, next, MDL);
452                         executable_statement_dereference (&next, MDL);
453                 }
454         }
455
456         return 1;
457 }
458
459 /* Execute all the statements in a particular scope, and all statements in
460    scopes outer from that scope, but if a particular limiting scope is
461    reached, do not execute statements in that scope or in scopes outer
462    from it.   More specific scopes need to take precedence over less
463    specific scopes, so we recursively traverse the scope list, executing
464    the most outer scope first. */
465
466 void execute_statements_in_scope (result, packet,
467                                   lease, client_state, in_options, out_options,
468                                   scope, group, limiting_group)
469         struct binding_value **result;
470         struct packet *packet;
471         struct lease *lease;
472         struct client_state *client_state;
473         struct option_state *in_options;
474         struct option_state *out_options;
475         struct binding_scope **scope;
476         struct group *group;
477         struct group *limiting_group;
478 {
479         struct group *limit;
480
481         /* If we've recursed as far as we can, return. */
482         if (!group)
483                 return;
484
485         /* As soon as we get to a scope that is outer than the limiting
486            scope, we are done.   This is so that if somebody does something
487            like this, it does the expected thing:
488
489                 domain-name "fugue.com";
490                 shared-network FOO {
491                         host bar {
492                                 domain-name "othello.fugue.com";
493                                 fixed-address 10.20.30.40;
494                         }
495                         subnet 10.20.30.0 netmask 255.255.255.0 {
496                                 domain-name "manhattan.fugue.com";
497                         }
498                 }
499
500            The problem with the above arrangement is that the host's
501            group nesting will be host -> shared-network -> top-level,
502            and the limiting scope when we evaluate the host's scope
503            will be the subnet -> shared-network -> top-level, so we need
504            to know when we evaluate the host's scope to stop before we
505            evaluate the shared-networks scope, because it's outer than
506            the limiting scope, which means we've already evaluated it. */
507
508         for (limit = limiting_group; limit; limit = limit -> next) {
509                 if (group == limit)
510                         return;
511         }
512
513         if (group -> next)
514                 execute_statements_in_scope (result, packet,
515                                              lease, client_state,
516                                              in_options, out_options, scope,
517                                              group -> next, limiting_group);
518         execute_statements (result, packet, lease, client_state, in_options,
519                             out_options, scope, group -> statements);
520 }
521
522 /* Dereference or free any subexpressions of a statement being freed. */
523
524 int executable_statement_dereference (ptr, file, line)
525         struct executable_statement **ptr;
526         const char *file;
527         int line;
528 {
529         struct executable_statement *bp;
530
531         if (!ptr || !*ptr) {
532                 log_error ("%s(%d): null pointer", file, line);
533 #if defined (POINTER_DEBUG)
534                 abort ();
535 #else
536                 return 0;
537 #endif
538         }
539
540         (*ptr) -> refcnt--;
541         rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
542         if ((*ptr) -> refcnt > 0) {
543                 *ptr = (struct executable_statement *)0;
544                 return 1;
545         }
546
547         if ((*ptr) -> refcnt < 0) {
548                 log_error ("%s(%d): negative refcnt!", file, line);
549 #if defined (DEBUG_RC_HISTORY)
550                 dump_rc_history (*ptr);
551 #endif
552 #if defined (POINTER_DEBUG)
553                 abort ();
554 #else
555                 return 0;
556 #endif
557         }
558
559         if ((*ptr) -> next)
560                 executable_statement_dereference (&(*ptr) -> next, file, line);
561
562         switch ((*ptr) -> op) {
563               case statements_statement:
564                 if ((*ptr) -> data.statements)
565                         executable_statement_dereference
566                                 (&(*ptr) -> data.statements, file, line);
567                 break;
568
569               case on_statement:
570                 if ((*ptr) -> data.on.statements)
571                         executable_statement_dereference
572                                 (&(*ptr) -> data.on.statements, file, line);
573                 break;
574
575               case switch_statement:
576                 if ((*ptr) -> data.s_switch.statements)
577                         executable_statement_dereference
578                                 (&(*ptr) -> data.on.statements, file, line);
579                 if ((*ptr) -> data.s_switch.expr)
580                         expression_dereference (&(*ptr) -> data.s_switch.expr,
581                                                 file, line);
582                 break;
583
584               case case_statement:
585                 if ((*ptr) -> data.s_switch.expr)
586                         expression_dereference (&(*ptr) -> data.c_case,
587                                                 file, line);
588                 break;
589
590               case if_statement:
591                 if ((*ptr) -> data.ie.expr)
592                         expression_dereference (&(*ptr) -> data.ie.expr,
593                                                 file, line);
594                 if ((*ptr) -> data.ie.tc)
595                         executable_statement_dereference
596                                 (&(*ptr) -> data.ie.tc, file, line);
597                 if ((*ptr) -> data.ie.fc)
598                         executable_statement_dereference
599                                 (&(*ptr) -> data.ie.fc, file, line);
600                 break;
601
602               case eval_statement:
603                 if ((*ptr) -> data.eval)
604                         expression_dereference (&(*ptr) -> data.eval,
605                                                 file, line);
606                 break;
607
608               case return_statement:
609                 if ((*ptr) -> data.eval)
610                         expression_dereference (&(*ptr) -> data.eval,
611                                                 file, line);
612                 break;
613
614               case set_statement:
615                 if ((*ptr)->data.set.name)
616                         dfree ((*ptr)->data.set.name, file, line);
617                 if ((*ptr)->data.set.expr)
618                         expression_dereference (&(*ptr) -> data.set.expr,
619                                                 file, line);
620                 break;
621
622               case unset_statement:
623                 if ((*ptr)->data.unset)
624                         dfree ((*ptr)->data.unset, file, line);
625                 break;
626
627               case supersede_option_statement:
628               case send_option_statement:
629               case default_option_statement:
630               case append_option_statement:
631               case prepend_option_statement:
632                 if ((*ptr) -> data.option)
633                         option_cache_dereference (&(*ptr) -> data.option,
634                                                   file, line);
635                 break;
636
637               default:
638                 /* Nothing to do. */
639                 break;
640         }
641
642         dfree ((*ptr), file, line);
643         *ptr = (struct executable_statement *)0;
644         return 1;
645 }
646
647 void write_statements (file, statements, indent)
648         FILE *file;
649         struct executable_statement *statements;
650         int indent;
651 {
652         struct executable_statement *r, *x;
653         int result;
654         int status;
655         const char *s, *t, *dot;
656         int col;
657
658         if (!statements)
659                 return;
660
661         for (r = statements; r; r = r -> next) {
662                 switch (r -> op) {
663                       case statements_statement:
664                         write_statements (file, r -> data.statements, indent);
665                         break;
666
667                       case on_statement:
668                         indent_spaces (file, indent);
669                         fprintf (file, "on ");
670                         s = "";
671                         if (r -> data.on.evtypes & ON_EXPIRY) {
672                                 fprintf (file, "%sexpiry", s);
673                                 s = " or ";
674                         }
675                         if (r -> data.on.evtypes & ON_COMMIT) {
676                                 fprintf (file, "%scommit", s);
677                                 s = "or";
678                         }
679                         if (r -> data.on.evtypes & ON_RELEASE) {
680                                 fprintf (file, "%srelease", s);
681                                 s = "or";
682                         }
683                         if (r -> data.on.statements) {
684                                 fprintf (file, " {");
685                                 write_statements (file,
686                                                   r -> data.on.statements,
687                                                   indent + 2);
688                                 indent_spaces (file, indent);
689                                 fprintf (file, "}");
690                         } else {
691                                 fprintf (file, ";");
692                         }
693                         break;
694
695                       case switch_statement:
696                         indent_spaces (file, indent);
697                         fprintf (file, "switch (");
698                         col = write_expression (file,
699                                                 r -> data.s_switch.expr,
700                                                 indent + 7, indent + 7, 1);
701                         col = token_print_indent (file, col, indent + 7,
702                                                   "", "", ")");
703                         token_print_indent (file,
704                                             col, indent, " ", "", "{");
705                         write_statements (file, r -> data.s_switch.statements,
706                                           indent + 2);
707                         indent_spaces (file, indent);
708                         fprintf (file, "}");
709                         break;
710                         
711                       case case_statement:
712                         indent_spaces (file, indent - 1);
713                         fprintf (file, "case ");
714                         col = write_expression (file,
715                                                 r -> data.s_switch.expr,
716                                                 indent + 5, indent + 5, 1);
717                         token_print_indent (file, col, indent + 5,
718                                             "", "", ":");
719                         break;
720                         
721                       case default_statement:
722                         indent_spaces (file, indent - 1);
723                         fprintf (file, "default: ");
724                         break;
725
726                       case if_statement:
727                         indent_spaces (file, indent);
728                         fprintf (file, "if ");
729                         x = r;
730                         col = write_expression (file,
731                                                 x -> data.ie.expr,
732                                                 indent + 3, indent + 3, 1);
733                       else_if:
734                         token_print_indent (file, col, indent, " ", "", "{");
735                         write_statements (file, x -> data.ie.tc, indent + 2);
736                         if (x -> data.ie.fc &&
737                             x -> data.ie.fc -> op == if_statement &&
738                             !x -> data.ie.fc -> next) {
739                                 indent_spaces (file, indent);
740                                 fprintf (file, "} elsif ");
741                                 x = x -> data.ie.fc;
742                                 col = write_expression (file,
743                                                         x -> data.ie.expr,
744                                                         indent + 6,
745                                                         indent + 6, 1);
746                                 goto else_if;
747                         }
748                         if (x -> data.ie.fc) {
749                                 indent_spaces (file, indent);
750                                 fprintf (file, "} else {");
751                                 write_statements (file, x -> data.ie.fc,
752                                                   indent + 2);
753                         }
754                         indent_spaces (file, indent);
755                         fprintf (file, "}");
756                         break;
757
758                       case eval_statement:
759                         indent_spaces (file, indent);
760                         fprintf (file, "eval ");
761                         col = write_expression (file, r -> data.eval,
762                                                 indent + 5, indent + 5, 1);
763                         fprintf (file, ";");
764                         break;
765
766                       case return_statement:
767                         indent_spaces (file, indent);
768                         fprintf (file, "return;");
769                         break;
770
771                       case add_statement:
772                         indent_spaces (file, indent);
773                         fprintf (file, "add \"%s\"", r -> data.add -> name);
774                         break;
775
776                       case break_statement:
777                         indent_spaces (file, indent);
778                         fprintf (file, "break;");
779                         break;
780
781                       case supersede_option_statement:
782                       case send_option_statement:
783                         s = "supersede";
784                         goto option_statement;
785
786                       case default_option_statement:
787                         s = "default";
788                         goto option_statement;
789
790                       case append_option_statement:
791                         s = "append";
792                         goto option_statement;
793
794                       case prepend_option_statement:
795                         s = "prepend";
796                       option_statement:
797                         /* Note: the reason we don't try to pretty print
798                            the option here is that the format of the option
799                            may change in dhcpd.conf, and then when this
800                            statement was read back, it would cause a syntax
801                            error. */
802                         if (r -> data.option -> option -> universe ==
803                             &dhcp_universe) {
804                                 t = "";
805                                 dot = "";
806                         } else {
807                                 t = (r -> data.option -> option ->
808                                      universe -> name);
809                                 dot = ".";
810                         }
811                         indent_spaces (file, indent);
812                         fprintf (file, "%s %s%s%s = ", s, t, dot,
813                                  r -> data.option -> option -> name);
814                         col = (indent + strlen (s) + strlen (t) +
815                                strlen (dot) + strlen (r -> data.option ->
816                                                       option -> name) + 4);
817                         if (r -> data.option -> expression)
818                                 write_expression
819                                         (file,
820                                          r -> data.option -> expression,
821                                          col, indent + 8, 1);
822                         else
823                                 token_indent_data_string
824                                         (file, col, indent + 8, "", "",
825                                          &r -> data.option -> data);
826                                          
827                         fprintf (file, ";"); /* XXX */
828                         break;
829
830                       case set_statement:
831                         indent_spaces (file, indent);
832                         fprintf (file, "set ");
833                         col = token_print_indent (file, indent + 4, indent + 4,
834                                                   "", "", r -> data.set.name);
835                         col = token_print_indent (file, col, indent + 4,
836                                                   " ", " ", "=");
837                         col = write_expression (file, r -> data.set.expr,
838                                                 indent + 3, indent + 3, 0);
839                         col = token_print_indent (file, col, indent + 4,
840                                                   " ", "", ";");
841                         break;
842                         
843                       case unset_statement:
844                         indent_spaces (file, indent);
845                         fprintf (file, "unset ");
846                         col = token_print_indent (file, indent + 6, indent + 6,
847                                                   "", "", r -> data.set.name);
848                         col = token_print_indent (file, col, indent + 6,
849                                                   " ", "", ";");
850                         break;
851
852                       case log_statement:
853                         indent_spaces (file, indent);
854                         fprintf (file, "log ");
855                         col = token_print_indent (file, indent + 4, indent + 4,
856                                                   "", "", "(");
857                         switch (r -> data.log.priority) {
858                         case log_priority_fatal:
859                                 col = token_print_indent
860                                         (file, col, indent + 4, "",
861                                          " ", "fatal,");
862                                 break;
863                         case log_priority_error:
864                                 col = token_print_indent
865                                         (file, col, indent + 4, "",
866                                          " ", "error,");
867                                 break;
868                         case log_priority_debug:
869                                 col = token_print_indent
870                                         (file, col, indent + 4, "",
871                                          " ", "debug,");
872                                 break;
873                         case log_priority_info:
874                                 col = token_print_indent
875                                         (file, col, indent + 4, "",
876                                          " ", "info,");
877                                 break;
878                         }
879                         col = write_expression (file, r -> data.log.expr,
880                                                 indent + 4, indent + 4, 0);
881                         col = token_print_indent (file, col, indent + 4,
882                                                   "", "", ");");
883
884                         break;
885                         
886                       default:
887                         log_fatal ("bogus statement type %d\n", r -> op);
888                 }
889         }
890 }
891
892 /* Find a case statement in the sequence of executable statements that
893    matches the expression, and if found, return the following statement.
894    If no case statement matches, try to find a default statement and
895    return that (the default statement can precede all the case statements).
896    Otherwise, return the null statement. */
897
898 int find_matching_case (struct executable_statement **ep,
899                         struct packet *packet, struct lease *lease,
900                         struct client_state *client_state,
901                         struct option_state *in_options,
902                         struct option_state *out_options,
903                         struct binding_scope **scope,
904                         struct expression *expr,
905                         struct executable_statement *stmt)
906 {
907         int status, sub;
908         struct executable_statement *s;
909         unsigned long foo;
910
911         if (is_data_expression (expr)) {
912                 struct executable_statement *e;
913                 struct data_string cd, ds;
914                 memset (&ds, 0, sizeof ds);
915                 memset (&cd, 0, sizeof cd);
916
917                 status = (evaluate_data_expression (&ds, packet, lease,
918                                                     client_state, in_options,
919                                                     out_options, scope, expr,
920                                                     MDL));
921                 if (status) {
922                     for (s = stmt; s; s = s -> next) {
923                         if (s -> op == case_statement) {
924                                 sub = (evaluate_data_expression
925                                        (&cd, packet, lease, client_state,
926                                         in_options, out_options,
927                                         scope, s -> data.c_case, MDL));
928                                 if (sub && cd.len == ds.len &&
929                                     !memcmp (cd.data, ds.data, cd.len))
930                                 {
931                                         data_string_forget (&cd, MDL);
932                                         data_string_forget (&ds, MDL);
933                                         executable_statement_reference
934                                                 (ep, s -> next, MDL);
935                                         return 1;
936                                 }
937                                 data_string_forget (&cd, MDL);
938                         }
939                     }
940                     data_string_forget (&ds, MDL);
941                 }
942         } else {
943                 unsigned long n, c;
944                 status = evaluate_numeric_expression (&n, packet, lease,
945                                                       client_state,
946                                                       in_options, out_options,
947                                                       scope, expr);
948
949                 if (status) {
950                     for (s = stmt; s; s = s -> next) {
951                         if (s -> op == case_statement) {
952                                 sub = (evaluate_numeric_expression
953                                        (&c, packet, lease, client_state,
954                                         in_options, out_options,
955                                         scope, s -> data.c_case));
956                                 if (sub && n == c) {
957                                         executable_statement_reference
958                                                 (ep, s -> next, MDL);
959                                         return 1;
960                                 }
961                         }
962                     }
963                 }
964         }
965
966         /* If we didn't find a matching case statement, look for a default
967            statement and return the statement following it. */
968         for (s = stmt; s; s = s -> next)
969                 if (s -> op == default_statement)
970                         break;
971         if (s) {
972                 executable_statement_reference (ep, s -> next, MDL);
973                 return 1;
974         }
975         return 0;
976 }
977
978 int executable_statement_foreach (struct executable_statement *stmt,
979                                   int (*callback) (struct
980                                                    executable_statement *,
981                                                    void *, int),
982                                   void *vp, int condp)
983 {
984         struct executable_statement *foo;
985         int ok = 0;
986         int result;
987
988         for (foo = stmt; foo; foo = foo -> next) {
989             if ((*callback) (foo, vp, condp) != 0)
990                 ok = 1;
991             switch (foo -> op) {
992               case null_statement:
993                 break;
994               case if_statement:
995                 if (executable_statement_foreach (foo -> data.ie.tc,
996                                                   callback, vp, 1))
997                         ok = 1;
998                 if (executable_statement_foreach (foo -> data.ie.fc,
999                                                   callback, vp, 1))
1000                         ok = 1;
1001                 break;
1002               case add_statement:
1003                 break;
1004               case eval_statement:
1005                 break;
1006               case break_statement:
1007                 break;
1008               case default_option_statement:
1009                 break;
1010               case supersede_option_statement:
1011                 break;
1012               case append_option_statement:
1013                 break;
1014               case prepend_option_statement:
1015                 break;
1016               case send_option_statement:
1017                 break;
1018               case statements_statement:
1019                 if ((executable_statement_foreach
1020                      (foo -> data.statements, callback, vp, condp)))
1021                         ok = 1;
1022                 break;
1023               case on_statement:
1024                 if ((executable_statement_foreach
1025                      (foo -> data.on.statements, callback, vp, 1)))
1026                         ok = 1;
1027                 break;
1028               case switch_statement:
1029                 if ((executable_statement_foreach
1030                      (foo -> data.s_switch.statements, callback, vp, 1)))
1031                         ok = 1;
1032                 break;
1033               case case_statement:
1034                 break;
1035               case default_statement:
1036                 break;
1037               case set_statement:
1038                 break;
1039               case unset_statement:
1040                 break;
1041               case let_statement:
1042                 if ((executable_statement_foreach
1043                      (foo -> data.let.statements, callback, vp, 0)))
1044                         ok = 1;
1045                 break;
1046               case define_statement:
1047                 break;
1048               case log_statement:
1049               case return_statement:
1050                 break;
1051             }
1052         }
1053         return ok;
1054 }