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