session: Fix two memory leaks.
[pspp] / src / language / control / control-stack.c
1 #include <config.h>
2
3 #include "language/control/control-stack.h"
4
5 #include <assert.h>
6 #include <stdlib.h>
7
8 #include "libpspp/compiler.h"
9 #include "libpspp/message.h"
10
11 #include "gl/xalloc.h"
12
13 #include "gettext.h"
14 #define _(msgid) gettext (msgid)
15
16 struct ctl_struct
17   {
18     const struct ctl_class *class;    /* Class of control structure. */
19     struct ctl_struct *down;    /* Points toward the bottom of ctl_stack. */
20     void *private;              /* Private data. */
21   };
22
23 static struct ctl_struct *ctl_stack;
24
25 void
26 ctl_stack_clear (void)
27 {
28   while (ctl_stack != NULL)
29     {
30       struct ctl_struct *top = ctl_stack;
31       msg (SE, _("%s without %s."),
32            top->class->start_name, top->class->end_name);
33       ctl_stack_pop (top->private);
34     }
35 }
36
37 void
38 ctl_stack_push (const struct ctl_class *class, void *private)
39 {
40   struct ctl_struct *ctl;
41
42   assert (private != NULL);
43   ctl = xmalloc (sizeof *ctl);
44   ctl->class = class;
45   ctl->down = ctl_stack;
46   ctl->private = private;
47   ctl_stack = ctl;
48 }
49
50 void *
51 ctl_stack_top (const struct ctl_class *class)
52 {
53   struct ctl_struct *top = ctl_stack;
54   if (top != NULL && top->class == class)
55     return top->private;
56   else
57     {
58       if (ctl_stack_search (class) != NULL)
59         msg (SE, _("This command must appear inside %s...%s, "
60                    "without intermediate %s...%s."),
61              class->start_name, class->end_name,
62              top->class->start_name, top->class->end_name);
63       return NULL;
64     }
65 }
66
67 void *
68 ctl_stack_search (const struct ctl_class *class)
69 {
70   struct ctl_struct *ctl;
71
72   for (ctl = ctl_stack; ctl != NULL; ctl = ctl->down)
73     if (ctl->class == class)
74       return ctl->private;
75
76   msg (SE, _("This command cannot appear outside %s...%s."),
77        class->start_name, class->end_name);
78   return NULL;
79 }
80
81 void
82 ctl_stack_pop (void *private)
83 {
84   struct ctl_struct *top = ctl_stack;
85
86   assert (top != NULL);
87   assert (top->private == private);
88
89   top->class->close (top->private);
90   ctl_stack = top->down;
91   free (top);
92 }
93
94 bool
95 ctl_stack_is_empty (void)
96 {
97   return ctl_stack == NULL;
98 }