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