message: Consistently initialize locator; use 0 for "no line number".
[pspp] / 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/configmake.h"
28 #include "gl/relocatable.h"
29 #include "gl/xalloc.h"
30
31 struct getl_source
32   {
33     struct getl_source *included_from;  /* File that this is nested inside. */
34     struct getl_source *includes;       /* File nested inside this file. */
35
36     struct ll  ll;   /* Element in the sources list */
37
38     struct getl_interface *interface;
39     enum syntax_mode syntax_mode;
40     enum error_mode error_mode;
41   };
42
43 struct source_stream
44   {
45     struct ll_list sources ;  /* List of source files. */
46     struct string_array include_path;
47   };
48
49 char **
50 getl_include_path (const struct source_stream *ss_)
51 {
52   struct source_stream *ss = CONST_CAST (struct source_stream *, ss_);
53   string_array_terminate_null (&ss->include_path);
54   return ss->include_path.strings;
55 }
56
57 static struct getl_source *
58 current_source (const struct source_stream *ss)
59 {
60   const struct ll *ll = ll_head (&ss->sources);
61   return ll_data (ll, struct getl_source, ll );
62 }
63
64 enum syntax_mode
65 source_stream_current_syntax_mode (const struct source_stream *ss)
66 {
67   struct getl_source *cs = current_source (ss);
68
69   return cs->syntax_mode;
70 }
71
72
73
74 enum error_mode
75 source_stream_current_error_mode (const struct source_stream *ss)
76 {
77   struct getl_source *cs = current_source (ss);
78
79   return cs->error_mode;
80 }
81
82
83
84 /* Initialize getl. */
85 struct source_stream *
86 create_source_stream (void)
87 {
88   struct source_stream *ss;
89
90   ss = xzalloc (sizeof (*ss));
91   ll_init (&ss->sources);
92
93   string_array_init (&ss->include_path);
94   string_array_append (&ss->include_path, ".");
95   if (getenv ("HOME") != NULL)
96     string_array_append_nocopy (&ss->include_path,
97                                 xasprintf ("%s/.pspp", getenv ("HOME")));
98   string_array_append (&ss->include_path, relocate (PKGDATADIR));
99
100   return ss;
101 }
102
103 /* Delete everything from the include path. */
104 void
105 getl_clear_include_path (struct source_stream *ss)
106 {
107   string_array_clear (&ss->include_path);
108 }
109
110 /* Add to the include path. */
111 void
112 getl_add_include_dir (struct source_stream *ss, const char *path)
113 {
114   string_array_append (&ss->include_path, path);
115 }
116
117 /* Appends source S to the list of source files. */
118 void
119 getl_append_source (struct source_stream *ss,
120                     struct getl_interface *i,
121                     enum syntax_mode syntax_mode,
122                     enum error_mode err_mode)
123 {
124   struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
125
126   s->interface = i ;
127   s->syntax_mode = syntax_mode;
128   s->error_mode = err_mode;
129
130   ll_push_tail (&ss->sources, &s->ll);
131 }
132
133 /* Nests source S within the current source file. */
134 void
135 getl_include_source (struct source_stream *ss,
136                      struct getl_interface *i,
137                      enum syntax_mode syntax_mode,
138                      enum error_mode err_mode)
139 {
140   struct getl_source *current = current_source (ss);
141   struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
142
143   s->interface = i;
144
145   s->included_from = current ;
146   s->includes  = NULL;
147   s->syntax_mode  = syntax_mode;
148   s->error_mode = err_mode;
149   current->includes = s;
150
151   ll_push_head (&ss->sources, &s->ll);
152 }
153
154 /* Closes the current source, and move  the current source to the
155    next file in the chain. */
156 static void
157 close_source (struct source_stream *ss)
158 {
159   struct getl_source *s = current_source (ss);
160
161   if ( s->interface->close )
162     s->interface->close (s->interface);
163
164   ll_pop_head (&ss->sources);
165
166   if (s->included_from != NULL)
167     current_source (ss)->includes = NULL;
168
169   free (s);
170 }
171
172 /* Closes all sources until an interactive source is
173    encountered. */
174 void
175 getl_abort_noninteractive (struct source_stream *ss)
176 {
177   while ( ! ll_is_empty (&ss->sources))
178     {
179       const struct getl_source *s = current_source (ss);
180
181       if ( !s->interface->interactive (s->interface) )
182         close_source (ss);
183     }
184 }
185
186 /* Returns true if the current source is interactive,
187    false otherwise. */
188 bool
189 getl_is_interactive (const struct source_stream *ss)
190 {
191   const struct getl_source *s = current_source (ss);
192
193   if (ll_is_empty (&ss->sources) )
194     return false;
195
196   return s->interface->interactive (s->interface);
197 }
198
199 /* Returns the name of the current source, or NULL if there is no
200    current source */
201 const char *
202 getl_source_name (const struct source_stream *ss)
203 {
204   const struct getl_source *s = current_source (ss);
205
206   if ( ll_is_empty (&ss->sources) )
207     return NULL;
208
209   if ( ! s->interface->name )
210     return NULL;
211
212   return s->interface->name (s->interface);
213 }
214
215 /* Returns the line number within the current source, or 0 if there is no
216    current source. */
217 int
218 getl_source_location (const struct source_stream *ss)
219 {
220   const struct getl_source *s = current_source (ss);
221
222   if ( ll_is_empty (&ss->sources) )
223     return 0;
224
225   if ( !s->interface->location )
226     return 0;
227
228   return s->interface->location (s->interface);
229 }
230
231
232 /* Close getl. */
233 void
234 destroy_source_stream (struct source_stream *ss)
235 {
236   while ( !ll_is_empty (&ss->sources))
237     close_source (ss);
238   string_array_destroy (&ss->include_path);
239
240   free (ss);
241 }
242
243
244 /* Reads a single line into LINE.
245    Returns true when a line has been read, false at end of input.
246 */
247 bool
248 getl_read_line (struct source_stream *ss, struct string *line)
249 {
250   assert (ss != NULL);
251   while (!ll_is_empty (&ss->sources))
252     {
253       struct getl_source *s = current_source (ss);
254
255       ds_clear (line);
256       if (s->interface->read (s->interface, line))
257         {
258           while (s)
259             {
260               if (s->interface->filter)
261                 s->interface->filter (s->interface, line);
262               s = s->included_from;
263             }
264
265           return true;
266         }
267       close_source (ss);
268     }
269
270   return false;
271 }