4a3f9debf95a9eb56e2e898a7b42ec80e7f9beb3
[pspp-builds.git] / src / libpspp / getl.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <stdlib.h>
21 #include <config.h>
22
23 #include "getl.h"
24
25 #include <libpspp/str.h>
26 #include <libpspp/ll.h>
27 #include <libpspp/version.h>
28 #include <libpspp/alloc.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   };
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 /* Initialize getl. */
61 struct source_stream *
62 create_source_stream (const char *initial_include_path)
63 {
64   struct source_stream *ss = xzalloc (sizeof (*ss));
65   ll_init (&ss->sources);
66 #if 0
67   ds_init_cstr (&ss->the_include_path,
68                 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
69 #endif
70   ds_init_cstr (&ss->the_include_path, initial_include_path);
71
72   return ss;
73 }
74
75 /* Delete everything from the include path. */
76 void
77 getl_clear_include_path (struct source_stream *ss)
78 {
79   ds_clear (&ss->the_include_path);
80 }
81
82 /* Add to the include path. */
83 void
84 getl_add_include_dir (struct source_stream *ss, const char *path)
85 {
86   if (ds_length (&ss->the_include_path))
87     ds_put_char (&ss->the_include_path, ':');
88
89   ds_put_cstr (&ss->the_include_path, path);
90 }
91
92 /* Appends source S to the list of source files. */
93 void
94 getl_append_source (struct source_stream *ss, struct getl_interface *i) 
95 {
96   struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
97
98   s->interface = i ;
99
100   ll_push_head (&ss->sources, &s->ll);
101 }
102
103 /* Nests source S within the current source file. */
104 void
105 getl_include_source (struct source_stream *ss, struct getl_interface *i) 
106 {
107   struct getl_source *current = current_source (ss);
108   struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
109
110   s->interface = i;
111
112   s->included_from = current ;
113   s->includes  = NULL;
114   current->includes = s;
115
116   ll_push_head (&ss->sources, &s->ll);
117 }
118
119 /* Closes the current source, and move  the current source to the 
120    next file in the chain. */
121 static void
122 close_source (struct source_stream *ss)
123 {
124   struct getl_source *s = current_source (ss);
125
126   if ( s->interface->close ) 
127     s->interface->close (s->interface);
128
129   ll_pop_head (&ss->sources);
130
131   if (s->included_from != NULL)
132     current_source (ss)->includes = NULL;
133
134   free (s);
135 }
136
137 /* Closes all sources until an interactive source is
138    encountered. */
139 void
140 getl_abort_noninteractive (struct source_stream *ss) 
141 {
142   while ( ! ll_is_empty (&ss->sources))
143     {
144       const struct getl_source *s = current_source (ss);
145       
146       if ( !s->interface->interactive (s->interface) ) 
147         close_source (ss);
148     }
149 }
150
151 /* Returns true if the current source is interactive,
152    false otherwise. */
153 bool
154 getl_is_interactive (const struct source_stream *ss) 
155 {
156   const struct getl_source *s = current_source (ss);
157
158   if (ll_is_empty (&ss->sources) ) 
159     return false;
160
161   return s->interface->interactive (s->interface);
162 }
163
164 /* Returns the name of the current source, or NULL if there is no 
165    current source */
166 const char *
167 getl_source_name (const struct source_stream *ss)
168 {
169   const struct getl_source *s = current_source (ss);
170
171   if ( ll_is_empty (&ss->sources) )
172     return NULL;
173
174   if ( ! s->interface->name ) 
175     return NULL;
176
177   return s->interface->name (s->interface);
178 }
179
180 /* Returns the location within the current source, or -1 if there is
181    no current source */
182 int
183 getl_source_location (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 -1;
189
190   if ( !s->interface->location )
191     return -1;
192
193   return s->interface->location (s->interface);
194 }
195
196
197 /* Close getl. */
198 void
199 destroy_source_stream (struct source_stream *ss)
200 {
201   while ( !ll_is_empty (&ss->sources))
202     close_source (ss);
203   ds_destroy (&ss->the_include_path);
204
205   free (ss);
206 }
207
208
209 /* Reads a single line into LINE.
210    Returns true when a line has been read, false at end of input.
211    On success, sets *SYNTAX to the style of the syntax read. */
212 bool
213 getl_read_line (struct source_stream *ss, struct string *line,
214                 enum getl_syntax *syntax)
215 {
216   while (!ll_is_empty (&ss->sources))
217     {
218       struct getl_source *s = current_source (ss);
219
220       ds_clear (line);
221       if (s->interface->read (s->interface, line, syntax))
222         {
223           while (s)
224             {
225               if (s->interface->filter)
226                 s->interface->filter (s->interface, line, *syntax);
227               s = s->included_from;
228             }
229
230           return true;
231         }
232       close_source (ss);
233     }
234
235   return false;
236 }