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