dc69f11a12a2b45e9ecf77c5dd89a00e5c69e18e
[pspp-builds.git] / src / libpspp / getl.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "libpspp/getl.h"
20
21 #include <stdlib.h>
22
23 #include "libpspp/ll.h"
24 #include "libpspp/str.h"
25 #include "libpspp/string-array.h"
26
27 #include "gl/relocatable.h"
28 #include "gl/xalloc.h"
29
30 struct getl_source
31   {
32     struct getl_source *included_from;  /* File that this is nested inside. */
33     struct getl_source *includes;       /* File nested inside this file. */
34
35     struct ll  ll;   /* Element in the sources list */
36
37     struct getl_interface *interface;
38     enum syntax_mode syntax_mode;
39     enum error_mode error_mode;
40   };
41
42 struct source_stream
43   {
44     struct ll_list sources ;  /* List of source files. */
45     struct string_array include_path;
46   };
47
48 char **
49 getl_include_path (const struct source_stream *ss_)
50 {
51   struct source_stream *ss = CONST_CAST (struct source_stream *, ss_);
52   string_array_terminate_null (&ss->include_path);
53   return ss->include_path.strings;
54 }
55
56 static struct getl_source *
57 current_source (const struct source_stream *ss)
58 {
59   const struct ll *ll = ll_head (&ss->sources);
60   return ll_data (ll, struct getl_source, ll );
61 }
62
63 enum syntax_mode
64 source_stream_current_syntax_mode (const struct source_stream *ss)
65 {
66   struct getl_source *cs = current_source (ss);
67
68   return cs->syntax_mode;
69 }
70
71
72
73 enum error_mode
74 source_stream_current_error_mode (const struct source_stream *ss)
75 {
76   struct getl_source *cs = current_source (ss);
77
78   return cs->error_mode;
79 }
80
81
82
83 /* Initialize getl. */
84 struct source_stream *
85 create_source_stream (void)
86 {
87   struct source_stream *ss;
88
89   ss = xzalloc (sizeof (*ss));
90   ll_init (&ss->sources);
91
92   string_array_init (&ss->include_path);
93   string_array_append (&ss->include_path, ".");
94   if (getenv ("HOME") != NULL)
95     string_array_append_nocopy (&ss->include_path,
96                                 xasprintf ("%s/.pspp", getenv ("HOME")));
97   string_array_append (&ss->include_path, relocate (PKGDATADIR));
98
99   return ss;
100 }
101
102 /* Delete everything from the include path. */
103 void
104 getl_clear_include_path (struct source_stream *ss)
105 {
106   string_array_clear (&ss->include_path);
107 }
108
109 /* Add to the include path. */
110 void
111 getl_add_include_dir (struct source_stream *ss, const char *path)
112 {
113   string_array_append (&ss->include_path, path);
114 }
115
116 /* Appends source S to the list of source files. */
117 void
118 getl_append_source (struct source_stream *ss,
119                     struct getl_interface *i,
120                     enum syntax_mode syntax_mode,
121                     enum error_mode err_mode)
122 {
123   struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
124
125   s->interface = i ;
126   s->syntax_mode = syntax_mode;
127   s->error_mode = err_mode;
128
129   ll_push_tail (&ss->sources, &s->ll);
130 }
131
132 /* Nests source S within the current source file. */
133 void
134 getl_include_source (struct source_stream *ss,
135                      struct getl_interface *i,
136                      enum syntax_mode syntax_mode,
137                      enum error_mode err_mode)
138 {
139   struct getl_source *current = current_source (ss);
140   struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
141
142   s->interface = i;
143
144   s->included_from = current ;
145   s->includes  = NULL;
146   s->syntax_mode  = syntax_mode;
147   s->error_mode = err_mode;
148   current->includes = s;
149
150   ll_push_head (&ss->sources, &s->ll);
151 }
152
153 /* Closes the current source, and move  the current source to the
154    next file in the chain. */
155 static void
156 close_source (struct source_stream *ss)
157 {
158   struct getl_source *s = current_source (ss);
159
160   if ( s->interface->close )
161     s->interface->close (s->interface);
162
163   ll_pop_head (&ss->sources);
164
165   if (s->included_from != NULL)
166     current_source (ss)->includes = NULL;
167
168   free (s);
169 }
170
171 /* Closes all sources until an interactive source is
172    encountered. */
173 void
174 getl_abort_noninteractive (struct source_stream *ss)
175 {
176   while ( ! ll_is_empty (&ss->sources))
177     {
178       const struct getl_source *s = current_source (ss);
179
180       if ( !s->interface->interactive (s->interface) )
181         close_source (ss);
182     }
183 }
184
185 /* Returns true if the current source is interactive,
186    false otherwise. */
187 bool
188 getl_is_interactive (const struct source_stream *ss)
189 {
190   const struct getl_source *s = current_source (ss);
191
192   if (ll_is_empty (&ss->sources) )
193     return false;
194
195   return s->interface->interactive (s->interface);
196 }
197
198 /* Returns the name of the current source, or NULL if there is no
199    current source */
200 const char *
201 getl_source_name (const struct source_stream *ss)
202 {
203   const struct getl_source *s = current_source (ss);
204
205   if ( ll_is_empty (&ss->sources) )
206     return NULL;
207
208   if ( ! s->interface->name )
209     return NULL;
210
211   return s->interface->name (s->interface);
212 }
213
214 /* Returns the location within the current source, or -1 if there is
215    no current source */
216 int
217 getl_source_location (const struct source_stream *ss)
218 {
219   const struct getl_source *s = current_source (ss);
220
221   if ( ll_is_empty (&ss->sources) )
222     return -1;
223
224   if ( !s->interface->location )
225     return -1;
226
227   return s->interface->location (s->interface);
228 }
229
230
231 /* Close getl. */
232 void
233 destroy_source_stream (struct source_stream *ss)
234 {
235   while ( !ll_is_empty (&ss->sources))
236     close_source (ss);
237   string_array_destroy (&ss->include_path);
238
239   free (ss);
240 }
241
242
243 /* Reads a single line into LINE.
244    Returns true when a line has been read, false at end of input.
245 */
246 bool
247 getl_read_line (struct source_stream *ss, struct string *line)
248 {
249   assert (ss != NULL);
250   while (!ll_is_empty (&ss->sources))
251     {
252       struct getl_source *s = current_source (ss);
253
254       ds_clear (line);
255       if (s->interface->read (s->interface, line))
256         {
257           while (s)
258             {
259               if (s->interface->filter)
260                 s->interface->filter (s->interface, line);
261               s = s->included_from;
262             }
263
264           return true;
265         }
266       close_source (ss);
267     }
268
269   return false;
270 }