Remove SOL body flags
[neverball] / share / solid_cmd.c
1 #include <stdlib.h>
2
3 #include "solid_cmd.h"
4 #include "cmd.h"
5 #include "list.h"
6
7 /*---------------------------------------------------------------------------*/
8
9 /*
10  * sol_step generates a few commands that supersede previous commands
11  * of the same type generated by the same sol_step invocation.  The
12  * code below provides the means to accumulate commands for later
13  * addition to the command queue, while making sure that commands that
14  * have been superseded during the accumulation are discarded.
15  */
16
17 int sol_cmd_defer;
18
19 static void (*cmd_enq_fn)(const union cmd *);
20 static List deferred_cmds;
21
22 void sol_cmd_enq_deferred(void)
23 {
24     List l, r;
25
26     /* Reverse the list to preserve original command order. */
27
28     for (r = NULL, l = deferred_cmds;
29          l;
30          r = list_cons(l->data, r), l = list_rest(l));
31
32     /* Enqueue commands. */
33
34     for (; r; r = list_rest(r))
35     {
36         if (cmd_enq_fn)
37             cmd_enq_fn(r->data);
38
39         free(r->data);
40     }
41
42     deferred_cmds = NULL;
43 }
44
45 void sol_cmd_enq(const union cmd *new)
46 {
47     if (sol_cmd_defer)
48     {
49         union cmd *copy;
50         List l, p;
51
52         for (p = NULL, l = deferred_cmds; l; p = l, l = l->next)
53         {
54             union cmd *cur = l->data;
55
56             /* Remove element made obsolete by the new command. */
57
58             if (new->type == cur->type &&
59                 ((new->type == CMD_BODY_TIME &&
60                   new->bodytime.bi == cur->bodytime.bi) ||
61                  (new->type == CMD_BODY_PATH &&
62                   new->bodypath.bi == cur->bodypath.bi)))
63             {
64                 free(cur);
65
66                 if (p)
67                     p->next       = list_rest(l);
68                 else
69                     deferred_cmds = list_rest(l);
70
71                 /*
72                  * The operation above made the list pointer useless
73                  * for the variable update part of the loop, and it
74                  * seems a bit involved to recover from that in a
75                  * proper fashion.  Fortunately, this very block
76                  * ensures that there's only one element to remove, so
77                  * no more iterations are needed.
78                  */
79
80                 l = NULL;
81                 break;
82             }
83         }
84
85         if ((copy = malloc(sizeof (*copy))))
86         {
87             *copy = *new;
88             deferred_cmds = list_cons(copy, deferred_cmds);
89         }
90     }
91     else if (cmd_enq_fn)
92         cmd_enq_fn(new);
93 }
94
95 void sol_cmd_enq_func(void (*enq_fn) (const union cmd *))
96 {
97     cmd_enq_fn = enq_fn;
98 }
99
100 /*---------------------------------------------------------------------------*/