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