Remove "Written by Ben Pfaff <blp@gnu.org>" lines everywhere.
[pspp-builds.git] / src / libpspp / getl.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    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, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19 #include <stdlib.h>
20 #include <config.h>
21
22 #include "getl.h"
23
24 #include <libpspp/str.h>
25 #include <libpspp/ll.h>
26 #include <libpspp/version.h>
27 #include <libpspp/alloc.h>
28
29 struct getl_source
30   {
31     struct getl_source *included_from;  /* File that this is nested inside. */
32     struct getl_source *includes;       /* File nested inside this file. */
33     
34     struct ll  ll;   /* Element in the sources list */
35
36     struct getl_interface *interface;
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 /* Initialize getl. */
60 struct source_stream *
61 create_source_stream (const char *initial_include_path)
62 {
63   struct source_stream *ss = xzalloc (sizeof (*ss));
64   ll_init (&ss->sources);
65 #if 0
66   ds_init_cstr (&ss->the_include_path,
67                 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
68 #endif
69   ds_init_cstr (&ss->the_include_path, initial_include_path);
70
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 }