treewide: Replace <name>_cnt by n_<name>s and <name>_cap by allocated_<name>.
[pspp] / src / language / control / control-stack.c
1 /*
2 PSPP - a program for statistical analysis.
3 Copyright (C) 2017 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include "language/control/control-stack.h"
22
23 #include <assert.h>
24 #include <stdlib.h>
25
26 #include "libpspp/compiler.h"
27 #include "libpspp/message.h"
28
29 #include "gl/xalloc.h"
30
31 #include "gettext.h"
32 #define _(msgid) gettext (msgid)
33
34 struct ctl_struct
35   {
36     const struct ctl_class *class;    /* Class of control structure. */
37     struct ctl_struct *down;    /* Points toward the bottom of ctl_stack. */
38     void *private;              /* Private data. */
39   };
40
41 static struct ctl_struct *ctl_stack;
42
43 void
44 ctl_stack_clear (void)
45 {
46   while (ctl_stack != NULL)
47     {
48       struct ctl_struct *top = ctl_stack;
49       msg (SE, _("%s without %s."),
50            top->class->start_name, top->class->end_name);
51       ctl_stack_pop (top->private);
52     }
53 }
54
55 void
56 ctl_stack_push (const struct ctl_class *class, void *private)
57 {
58   struct ctl_struct *ctl;
59
60   assert (private != NULL);
61   ctl = xmalloc (sizeof *ctl);
62   ctl->class = class;
63   ctl->down = ctl_stack;
64   ctl->private = private;
65   ctl_stack = ctl;
66 }
67
68 void *
69 ctl_stack_top (const struct ctl_class *class)
70 {
71   struct ctl_struct *top = ctl_stack;
72   if (top != NULL && top->class == class)
73     return top->private;
74   else
75     {
76       if (ctl_stack_search (class) != NULL)
77         msg (SE, _("This command must appear inside %s...%s, "
78                    "without intermediate %s...%s."),
79              class->start_name, class->end_name,
80              top->class->start_name, top->class->end_name);
81       return NULL;
82     }
83 }
84
85 void *
86 ctl_stack_search (const struct ctl_class *class)
87 {
88   struct ctl_struct *ctl;
89
90   for (ctl = ctl_stack; ctl != NULL; ctl = ctl->down)
91     if (ctl->class == class)
92       return ctl->private;
93
94   msg (SE, _("This command cannot appear outside %s...%s."),
95        class->start_name, class->end_name);
96   return NULL;
97 }
98
99 void
100 ctl_stack_pop (void *private)
101 {
102   struct ctl_struct *top = ctl_stack;
103
104   assert (top != NULL);
105   assert (top->private == private);
106
107   top->class->close (top->private);
108   ctl_stack = top->down;
109   free (top);
110 }
111
112 bool
113 ctl_stack_is_empty (void)
114 {
115   return ctl_stack == NULL;
116 }