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