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
ctl_stack_clear(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
ctl_stack_push(const struct ctl_class * class,void * private)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 *
ctl_stack_top(const struct ctl_class * class)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 *
ctl_stack_search(const struct ctl_class * class)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
ctl_stack_pop(void * private)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
ctl_stack_is_empty(void)113 ctl_stack_is_empty (void)
114 {
115 return ctl_stack == NULL;
116 }
117