Added new files resulting from directory restructuring.
[pspp-builds.git] / src / getl.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 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 <config.h>
21 #include "getl.h"
22 #include "error.h"
23 #include <stdio.h>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include "alloc.h"
27 #include "command.h"
28 #include "error.h"
29 #include "filename.h"
30 #include "lexer.h"
31 #include "repeat.h"
32 #include "settings.h"
33 #include "str.h"
34 #include "tab.h"
35 #include "var.h"
36 #include "version.h"
37
38 #include "gettext.h"
39 #define _(msgid) gettext (msgid)
40
41 static struct string getl_include_path;
42
43 /* Number of levels of DO REPEAT structures we're nested inside.  If
44    this is greater than zero then DO REPEAT macro substitutions are
45    performed. */
46 static int DO_REPEAT_level;
47
48 struct string getl_buf;
49
50
51 /* Initialize getl. */
52 void
53 getl_initialize (void)
54 {
55   ds_create (&getl_include_path,
56              fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
57   ds_init (&getl_buf, 256);
58 }
59
60
61
62 struct getl_script *getl_head;
63 struct getl_script *getl_tail;
64
65
66 /* Returns a string that represents the directory that the syntax file
67    currently being read resides in.  If there is no syntax file then
68    returns the OS current working directory.  Return value must be
69    free()'d. */
70 char *
71 getl_get_current_directory (void)
72 {
73   return getl_head ? fn_dirname (getl_head->fn) : fn_get_cwd ();
74 }
75
76 /* Delete everything from the include path. */
77 void
78 getl_clear_include_path (void)
79 {
80   ds_clear (&getl_include_path);
81 }
82
83 /* Add to the include path. */
84 void
85 getl_add_include_dir (const char *path)
86 {
87   if (ds_length (&getl_include_path))
88     ds_putc (&getl_include_path, PATH_DELIMITER);
89
90   ds_puts (&getl_include_path, path);
91 }
92
93 /* Adds FN to the tail end of the list of script files to execute.
94    OPTIONS is the value to stick in the options field of the
95    getl_script struct.  If WHERE is zero then the file is added after
96    all other files; otherwise it is added before all other files (this
97    can be done only if parsing has not yet begun). */
98 void
99 getl_add_file (const char *fn, int separate, int where)
100 {
101   struct getl_script *n = xmalloc (sizeof *n);
102
103   assert (fn != NULL);
104   n->next = NULL;
105   if (getl_tail == NULL)
106     getl_head = getl_tail = n;
107   else if (!where)
108     getl_tail = getl_tail->next = n;
109   else
110     {
111       assert (getl_head->f == NULL);
112       n->next = getl_head;
113       getl_head = n;
114     }
115   n->included_from = n->includes = NULL;
116   n->fn = xstrdup (fn);
117   n->ln = 0;
118   n->f = NULL;
119   n->separate = separate;
120   n->first_line = NULL;
121 }
122
123 /* Inserts the given file with filename FN into the current file after
124    the current line. */
125 void
126 getl_include (const char *fn)
127 {
128   struct getl_script *n;
129   char *real_fn;
130
131   {
132     char *cur_dir = getl_get_current_directory ();
133     real_fn = fn_search_path (fn, ds_c_str (&getl_include_path), cur_dir);
134     free (cur_dir);
135   }
136
137   if (!real_fn)
138     {
139       msg (SE, _("Can't find `%s' in include file search path."), fn);
140       return;
141     }
142
143   if (!getl_head)
144     {
145       getl_add_file (real_fn, 0, 0);
146       free (real_fn);
147     }
148   else
149     {
150       n = xmalloc (sizeof *n);
151       n->included_from = getl_head;
152       getl_head = getl_head->includes = n;
153       n->includes = NULL;
154       n->next = NULL;
155       n->fn = real_fn;
156       n->ln = 0;
157       n->f = NULL;
158       n->separate = 0;
159       n->first_line = NULL;
160     }
161 }
162
163 /* Add the virtual file FILE to the list of files to be processed.
164    The first_line field in FILE must already have been initialized. */
165 void 
166 getl_add_virtual_file (struct getl_script *file)
167 {
168   if (getl_tail == NULL)
169     getl_head = getl_tail = file;
170   else
171     getl_tail = getl_tail->next = file;
172   file->included_from = file->includes = NULL;
173   file->next = NULL;
174   file->fn = file->first_line->line;
175   file->ln = -file->first_line->len - 1;
176   file->separate = 0;
177   file->f = NULL;
178   file->cur_line = NULL;
179   file->remaining_loops = 1;
180   file->loop_index = -1;
181   file->macros = NULL;
182 }
183
184 /* Causes the DO REPEAT virtual file passed in FILE to be included in
185    the current file.  The first_line, cur_line, remaining_loops,
186    loop_index, and macros fields in FILE must already have been
187    initialized. */
188 void
189 getl_add_DO_REPEAT_file (struct getl_script *file)
190 {
191   assert (getl_head);
192
193   DO_REPEAT_level++;
194   file->included_from = getl_head;
195   getl_head = getl_head->includes = file;
196   file->includes = NULL;
197   file->next = NULL;
198   assert (file->first_line->len < 0);
199   file->fn = file->first_line->line;
200   file->ln = -file->first_line->len - 1;
201   file->separate = 0;
202   file->f = NULL;
203 }
204
205 /* Reads a single line from the line buffer associated with getl_head.
206    Returns 1 if a line was successfully read or 0 if no more lines are
207    available. */
208 int
209 getl_handle_line_buffer (void)
210 {
211   struct getl_script *s = getl_head;
212
213   /* Check that we're not all done. */
214   do
215     {
216       if (s->cur_line == NULL)
217         {
218           s->loop_index++;
219           if (s->remaining_loops-- == 0)
220             return 0;
221           s->cur_line = s->first_line;
222         }
223
224       if (s->cur_line->len < 0)
225         {
226           s->ln = -s->cur_line->len - 1;
227           s->fn = s->cur_line->line;
228           s->cur_line = s->cur_line->next;
229           continue;
230         }
231     }
232   while (s->cur_line == NULL);
233
234   ds_concat (&getl_buf, s->cur_line->line, s->cur_line->len);
235
236   /* Advance pointers. */
237   s->cur_line = s->cur_line->next;
238   s->ln++;
239
240   return 1;
241 }
242
243 /* Closes the current file, whether it be a main file or included
244    file, then moves getl_head to the next file in the chain. */
245 void
246 getl_close_file (void)
247 {
248   struct getl_script *s = getl_head;
249
250   if (!s)
251     return;
252   assert (getl_tail != NULL);
253
254   if (s->first_line)
255     {
256       struct getl_line_list *cur, *next;
257
258       s->fn = NULL; /* It will be freed below. */
259       for (cur = s->first_line; cur; cur = next)
260         {
261           next = cur->next;
262           free (cur->line);
263           free (cur);
264         }
265
266       DO_REPEAT_level--;
267     }
268   
269   if (s->f && EOF == fn_close (s->fn, s->f))
270     msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
271   free (s->fn);
272
273   if (s->included_from)
274     {
275       getl_head = s->included_from;
276       getl_head->includes = NULL;
277     }
278   else
279     {
280       getl_head = s->next;
281       if (NULL == getl_head)
282         getl_tail = NULL;
283     }
284   
285   free (s);
286 }
287
288 /* Closes all files. */
289 void
290 getl_close_all (void)
291 {
292   while (getl_head)
293     getl_close_file ();
294 }
295
296 bool
297 getl_is_separate(void)
298 {
299   return (getl_head && getl_head->separate);
300 }
301
302 void
303 getl_set_separate(bool sep)
304 {
305   assert (getl_head);
306
307   getl_head->separate = sep ;
308 }
309
310
311 /* Puts the current file and line number in *FN and *LN, respectively,
312    or NULL and -1 if none. */
313 void
314 getl_location (const char **fn, int *ln)
315 {
316   if (fn != NULL)
317     *fn = getl_head ? getl_head->fn : NULL;
318   if (ln != NULL)
319     *ln = getl_head ? getl_head->ln : -1;
320 }
321
322 bool 
323 getl_reading_script (void)
324 {
325   return (getl_head != NULL);
326 }
327
328 /* File locator stack. */
329 static const struct file_locator **file_loc;
330 static int nfile_loc, mfile_loc;
331 \f
332 /* Close getl. */
333 void
334 getl_uninitialize (void)
335 {
336   getl_close_all();
337   ds_destroy (&getl_buf);
338   ds_destroy (&getl_include_path);
339   free(file_loc);
340   file_loc = NULL;
341   nfile_loc = mfile_loc = 0;
342 }
343
344
345 /* File locator stack functions. */
346
347 /* Pushes F onto the stack of file locations. */
348 void
349 err_push_file_locator (const struct file_locator *f)
350 {
351   if (nfile_loc >= mfile_loc)
352     {
353       if (mfile_loc == 0)
354         mfile_loc = 8;
355       else
356         mfile_loc *= 2;
357
358       file_loc = xnrealloc (file_loc, mfile_loc, sizeof *file_loc);
359     }
360
361   file_loc[nfile_loc++] = f;
362 }
363
364 /* Pops F off the stack of file locations.
365    Argument F is only used for verification that that is actually the
366    item on top of the stack. */
367 void
368 err_pop_file_locator (const struct file_locator *f)
369 {
370   assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == f);
371   nfile_loc--;
372 }
373
374 /* Puts the current file and line number in F, or NULL and -1 if
375    none. */
376 void
377 err_location (struct file_locator *f)
378 {
379   if (nfile_loc)
380     *f = *file_loc[nfile_loc - 1];
381   else
382     getl_location (&f->filename, &f->line_number);
383 }
384
385