+++ /dev/null
-/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
- Written by Ben Pfaff <blp@gnu.org>.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
-
-#include <config.h>
-
-#include <language/line-buffer.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include <data/file-name.h>
-#include <data/settings.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/alloc.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <libpspp/verbose-msg.h>
-#include <libpspp/version.h>
-#include <output/table.h>
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-/* Source file. */
-struct getl_source
- {
- struct getl_source *included_from; /* File that this is nested inside. */
- struct getl_source *includes; /* File nested inside this file. */
- struct getl_source *next; /* Next file in list. */
-
- /* Current location. */
- char *fn; /* File name. */
- int ln; /* Line number. */
-
- enum getl_source_type
- {
- SYNTAX_FILE,
- FILTER,
- FUNCTION,
- INTERACTIVE
- }
- type;
-
- union
- {
- /* SYNTAX_FILE. */
- FILE *syntax_file;
-
- /* FILTER. */
- struct
- {
- void (*filter) (struct string *line, void *aux);
- void (*close) (void *aux);
- void *aux;
- }
- filter;
-
- /* FUNCTION. */
- struct
- {
- bool (*read) (struct string *line, char **fn, int *ln, void *aux);
- void (*close) (void *aux);
- void *aux;
- }
- function;
-
- /* INTERACTIVE. */
- bool (*interactive) (struct string *line, enum getl_prompt_style);
- }
- u;
-
- };
-
-/* List of source files. */
-static struct getl_source *cur_source;
-static struct getl_source *last_source;
-
-static struct string getl_include_path;
-
-
-static void close_source (void);
-
-static void init_prompts (void);
-static void uninit_prompts (void);
-static enum getl_prompt_style get_prompt_style (void);
-
-
-/* Initialize getl. */
-void
-getl_initialize (void)
-{
- ds_init_cstr (&getl_include_path,
- fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
- init_prompts ();
-}
-
-
-/* Delete everything from the include path. */
-void
-getl_clear_include_path (void)
-{
- ds_clear (&getl_include_path);
-}
-
-/* Add to the include path. */
-void
-getl_add_include_dir (const char *path)
-{
- if (ds_length (&getl_include_path))
- ds_put_char (&getl_include_path, ':');
-
- ds_put_cstr (&getl_include_path, path);
-}
-
-/* Appends source S to the list of source files. */
-static void
-append_source (struct getl_source *s)
-{
- s->included_from = s->includes = s->next = NULL;
- if (last_source == NULL)
- cur_source = s;
- else
- last_source->next = s;
- last_source = s;
-}
-
-/* Nests source S within the current source file. */
-static void
-include_source (struct getl_source *s)
-{
- if (last_source == NULL)
- append_source (s);
- else
- {
- s->included_from = cur_source;
- s->includes = s->next = NULL;
- s->next = NULL;
- cur_source->includes = s;
- cur_source = s;
- }
-}
-
-/* Creates a source of the given TYPE.
- Type-specific data must be initialized by the caller. */
-static struct getl_source *
-create_source (enum getl_source_type type)
-{
- struct getl_source *s = xmalloc (sizeof *s);
- s->fn = NULL;
- s->ln = 0;
- s->type = type;
- return s;
-}
-
-/* Creates a syntax file source with file name FN. */
-static struct getl_source *
-create_syntax_file_source (const char *fn)
-{
- struct getl_source *s = create_source (SYNTAX_FILE);
- s->fn = xstrdup (fn);
- s->u.syntax_file = NULL;
- return s;
-}
-
-/* Creates a filter source with the given FILTER and CLOSE
- functions that receive auxiliary data AUX. */
-static struct getl_source *
-create_filter_source (void (*filter) (struct string *, void *aux),
- void (*close) (void *aux),
- void *aux)
-{
- struct getl_source *s = create_source (FILTER);
- s->u.filter.filter = filter;
- s->u.filter.close = close;
- s->u.filter.aux = aux;
- return s;
-}
-
-/* Creates a function source with the given READ and CLOSE
- functions that receive auxiliary data AUX. */
-static struct getl_source *
-create_function_source (bool (*read) (struct string *line,
- char **fn, int *ln, void *aux),
- void (*close) (void *aux),
- void *aux)
-{
- struct getl_source *s = create_source (FUNCTION);
- s->u.function.read = read;
- s->u.function.close = close;
- s->u.function.aux = aux;
- return s;
-}
-
-/* Creates an interactive source with the given FUNCTION. */
-static struct getl_source *
-create_interactive_source (bool (*function) (struct string *line,
- enum getl_prompt_style))
-{
- struct getl_source *s = xmalloc (sizeof *s);
- s->fn = NULL;
- s->ln = 0;
- s->type = INTERACTIVE;
- s->u.interactive = function;
- return s;
-}
-
-/* Adds FN to the tail end of the list of source files to
- execute. */
-void
-getl_append_syntax_file (const char *fn)
-{
- append_source (create_syntax_file_source (fn));
-}
-
-/* Inserts the given file with name FN into the current file
- after the current line. */
-void
-getl_include_syntax_file (const char *fn)
-{
- if (cur_source != NULL)
- {
- char *found_fn = fn_search_path (fn, ds_cstr (&getl_include_path),
- fn_dir_name (cur_source->fn));
- if (found_fn != NULL)
- {
- include_source (create_syntax_file_source (found_fn));
- free (found_fn);
- }
- else
- msg (SE, _("Can't find `%s' in include file search path."), fn);
- }
- else
- getl_append_syntax_file (fn);
-}
-
-/* Inserts the given filter into the current file after the
- current line. Each line read while the filter is in place
- will be passed through FILTER, which may modify it as
- necessary. When the filter is closed, CLOSE will be called.
- AUX will be passed to both functions.
-
- The filter cannot itself output any new lines, and it will be
- closed as soon as any line would be read from it. This means
- that, for a filter to be useful, another source must be nested
- inside it with, e.g., getl_include_syntax_file(). */
-void
-getl_include_filter (void (*filter) (struct string *, void *aux),
- void (*close) (void *aux),
- void *aux)
-{
- include_source (create_filter_source (filter, close, aux));
-}
-
-/* Inserts the given functional source into the current file
- after the current line. Lines are read by calling READ, which
- should write the next line in LINE, store the file name and
- line number of the line in *FN and *LN, and return true. The
- string stored in *FN will not be freed by getl. When no lines
- are left, READ should return false.
-
- When the source is closed, CLOSE will be called.
-
- AUX will be passed to both READ and CLOSE. */
-void
-getl_include_function (bool (*read) (struct string *line,
- char **fn, int *ln, void *aux),
- void (*close) (void *aux),
- void *aux)
-{
- include_source (create_function_source (read, close, aux));
-}
-
-/* Adds an interactive source to the end of the list of sources.
- FUNCTION will be called to obtain a line. It should store the
- line in LINE. PROMPT is the prompt to be displayed to the
- user. FUNCTION should return true when a line has been
- obtained or false at end of file. */
-void
-getl_append_interactive (bool (*function) (struct string *line,
- enum getl_prompt_style))
-{
- append_source (create_interactive_source (function));
-}
-
-/* Closes all sources until an interactive source is
- encountered. */
-void
-getl_abort_noninteractive (void)
-{
- while (cur_source != NULL && cur_source->type != INTERACTIVE)
- close_source ();
-}
-
-/* Returns true if the current source is interactive,
- false otherwise. */
-bool
-getl_is_interactive (void)
-{
- return cur_source != NULL && cur_source->type == INTERACTIVE;
-}
-
-/* Closes the current file, whether it be a main file or included
- file, then moves cur_source to the next file in the chain. */
-static void
-close_source (void)
-{
- struct getl_source *s;
-
- s = cur_source;
- switch (s->type)
- {
- case SYNTAX_FILE:
- if (s->u.syntax_file && EOF == fn_close (s->fn, s->u.syntax_file))
- msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
- free (s->fn);
- break;
-
- case FILTER:
- if (s->u.filter.close != NULL)
- s->u.filter.close (s->u.filter.aux);
- break;
-
- case FUNCTION:
- if (s->u.function.close != NULL)
- s->u.function.close (s->u.function.aux);
- break;
-
- case INTERACTIVE:
- break;
- }
-
- if (s->included_from != NULL)
- {
- cur_source = s->included_from;
- cur_source->includes = NULL;
- }
- else
- {
- cur_source = s->next;
- if (cur_source == NULL)
- last_source = NULL;
- }
-
- free (s);
-}
-
-/* Puts the current file and line number in *FN and *LN, respectively,
- or NULL and -1 if none. */
-void
-getl_location (const char **fn, int *ln)
-{
- if (fn != NULL)
- *fn = cur_source ? cur_source->fn : "";
- if (ln != NULL)
- *ln = cur_source ? cur_source->ln : -1;
-}
-
-/* File locator stack. */
-static const struct msg_locator **file_loc;
-
-static int nfile_loc, mfile_loc;
-\f
-/* Close getl. */
-void
-getl_uninitialize (void)
-{
- while (cur_source != NULL)
- close_source ();
- ds_destroy (&getl_include_path);
- free(file_loc);
- file_loc = NULL;
- nfile_loc = mfile_loc = 0;
- uninit_prompts ();
-}
-
-
-/* File locator stack functions. */
-
-/* Pushes F onto the stack of file locations. */
-void
-msg_push_msg_locator (const struct msg_locator *loc)
-{
- if (nfile_loc >= mfile_loc)
- {
- if (mfile_loc == 0)
- mfile_loc = 8;
- else
- mfile_loc *= 2;
-
- file_loc = xnrealloc (file_loc, mfile_loc, sizeof *file_loc);
- }
-
- file_loc[nfile_loc++] = loc;
-}
-
-/* Pops F off the stack of file locations.
- Argument F is only used for verification that that is actually the
- item on top of the stack. */
-void
-msg_pop_msg_locator (const struct msg_locator *loc)
-{
- assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == loc);
- nfile_loc--;
-}
-
-/* Puts the current file and line number into LOC, or NULL and -1 if
- none. */
-void
-get_msg_location (struct msg_locator *loc)
-{
- if (nfile_loc)
- *loc = *file_loc[nfile_loc - 1];
- else
- getl_location (&loc->file_name, &loc->line_number);
-}
-
-/* Reads a line from syntax file source S into LINE.
- Returns true if successful, false at end of file. */
-static bool
-read_syntax_file (struct string *line, struct getl_source *s)
-{
- /* Open file, if not yet opened. */
- if (s->u.syntax_file == NULL)
- {
- verbose_msg (1, _("opening \"%s\" as syntax file"), s->fn);
- s->u.syntax_file = fn_open (s->fn, "r");
-
- if (s->u.syntax_file == NULL)
- {
- msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
- return false;
- }
- }
-
- /* Read line from file and remove new-line.
- Skip initial "#! /usr/bin/pspp" line. */
- do
- {
- s->ln++;
- if (!ds_read_line (line, s->u.syntax_file))
- {
- if (ferror (s->u.syntax_file))
- msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
- return false;
- }
- ds_chomp (line, '\n');
- }
- while (s->ln == 1 && !memcmp (ds_cstr (line), "#!", 2));
-
- /* Echo to listing file, if configured to do so. */
- if (get_echo ())
- tab_output_text (TAB_LEFT | TAB_FIX, ds_cstr (line));
-
- return true;
-}
-
-/* Reads a line from source S into LINE.
- Returns true if successful, false at end of file. */
-static bool
-read_line_from_source (struct string *line, struct getl_source *s)
-{
- ds_clear (line);
- switch (s->type)
- {
- case SYNTAX_FILE:
- return read_syntax_file (line, s);
- case FILTER:
- return false;
- case FUNCTION:
- return s->u.function.read (line, &s->fn, &s->ln, s->u.function.aux);
- case INTERACTIVE:
- return s->u.interactive (line, get_prompt_style ());
- }
-
- NOT_REACHED ();
-}
-
-/* Reads a single line into LINE.
- Returns true when a line has been read, false at end of input.
- If INTERACTIVE is non-null, then when true is returned
- *INTERACTIVE will be set to true if the line was obtained
- interactively, false otherwise. */
-bool
-do_read_line (struct string *line, bool *interactive)
-{
- while (cur_source != NULL)
- {
- struct getl_source *s = cur_source;
- if (read_line_from_source (line, s))
- {
- if (interactive != NULL)
- *interactive = s->type == INTERACTIVE;
-
- while ((s = s->included_from) != NULL)
- if (s->type == FILTER)
- s->u.filter.filter (line, s->u.filter.aux);
-
- return true;
- }
- close_source ();
- }
-
- return false;
-}
-
-\f
-/* Current prompts in each style. */
-static char *prompts[GETL_PROMPT_CNT];
-
-/* Current prompting style. */
-static enum getl_prompt_style current_style;
-
-/* Initializes prompts. */
-static void
-init_prompts (void)
-{
- prompts[GETL_PROMPT_FIRST] = xstrdup ("PSPP> ");
- prompts[GETL_PROMPT_LATER] = xstrdup (" > ");
- prompts[GETL_PROMPT_DATA] = xstrdup ("data> ");
- current_style = GETL_PROMPT_FIRST;
-}
-
-/* Frees prompts. */
-static void
-uninit_prompts (void)
-{
- int i;
-
- for (i = 0; i < GETL_PROMPT_CNT; i++)
- {
- free (prompts[i]);
- prompts[i] = NULL;
- }
-}
-
-/* Gets the command prompt for the given STYLE. */
-const char *
-getl_get_prompt (enum getl_prompt_style style)
-{
- assert (style < GETL_PROMPT_CNT);
- return prompts[style];
-}
-
-/* Sets the given STYLE's prompt to STRING. */
-void
-getl_set_prompt (enum getl_prompt_style style, const char *string)
-{
- assert (style < GETL_PROMPT_CNT);
- free (prompts[style]);
- prompts[style] = xstrdup (string);
-}
-
-/* Sets STYLE as the current prompt style. */
-void
-getl_set_prompt_style (enum getl_prompt_style style)
-{
- assert (style < GETL_PROMPT_CNT);
- current_style = style;
-}
-
-/* Returns the current prompt. */
-static enum getl_prompt_style
-get_prompt_style (void)
-{
- return current_style;
-}
+++ /dev/null
-/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
- Written by Ben Pfaff <blp@gnu.org>.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
-
-#ifndef GETL_H
-#define GETL_H 1
-
-#include <stdbool.h>
-#include <libpspp/str.h>
-
-enum getl_prompt_style
- {
- GETL_PROMPT_FIRST, /* First line of command. */
- GETL_PROMPT_LATER, /* Second or later line of command. */
- GETL_PROMPT_DATA, /* Between BEGIN DATA and END DATA. */
- GETL_PROMPT_CNT
- };
-
-
-void getl_initialize (void);
-void getl_uninitialize (void);
-
-void getl_clear_include_path (void);
-void getl_add_include_dir (const char *);
-
-void getl_append_syntax_file (const char *);
-void getl_include_syntax_file (const char *);
-void getl_include_filter (void (*filter) (struct string *, void *aux),
- void (*close) (void *aux),
- void *aux);
-void getl_include_function (bool (*read) (struct string *line,
- char **fn, int *ln, void *aux),
- void (*close) (void *aux),
- void *aux);
-void getl_append_interactive (bool (*function) (struct string *line,
- enum getl_prompt_style));
-void getl_abort_noninteractive (void);
-bool getl_is_interactive (void);
-
-bool getl_read_line (bool *interactive);
-
-const char *getl_get_prompt (enum getl_prompt_style);
-void getl_set_prompt (enum getl_prompt_style, const char *);
-void getl_set_prompt_style (enum getl_prompt_style);
-
-struct msg_locator;
-void get_msg_location (struct msg_locator *loc);
-
-void getl_location (const char **fn, int *ln);
-
-bool do_read_line (struct string *line, bool *interactive);
-
-
-#endif /* line-buffer.h */
--- /dev/null
+/* PSPP - computes sample statistics.
+ Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "prompt.h"
+
+#include <data/file-name.h>
+#include <data/settings.h>
+#include <data/variable.h>
+#include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/assertion.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
+#include <libpspp/str.h>
+#include <libpspp/verbose-msg.h>
+#include <libpspp/version.h>
+#include <output/table.h>
+
+/* Current prompts in each style. */
+static char *prompts[PROMPT_CNT];
+
+/* Current prompting style. */
+static enum prompt_style current_style;
+
+/* Initializes prompts. */
+void
+prompt_init (void)
+{
+ prompts[PROMPT_FIRST] = xstrdup ("PSPP> ");
+ prompts[PROMPT_LATER] = xstrdup (" > ");
+ prompts[PROMPT_DATA] = xstrdup ("data> ");
+ current_style = PROMPT_FIRST;
+}
+
+/* Frees prompts. */
+void
+prompt_done (void)
+{
+ int i;
+
+ for (i = 0; i < PROMPT_CNT; i++)
+ {
+ free (prompts[i]);
+ prompts[i] = NULL;
+ }
+}
+
+/* Gets the command prompt for the given STYLE. */
+const char *
+prompt_get (enum prompt_style style)
+{
+ assert (style < PROMPT_CNT);
+ return prompts[style];
+}
+
+/* Sets the given STYLE's prompt to STRING. */
+void
+prompt_set (enum prompt_style style, const char *string)
+{
+ assert (style < PROMPT_CNT);
+ free (prompts[style]);
+ prompts[style] = xstrdup (string);
+}
+
+/* Sets STYLE as the current prompt style. */
+void
+prompt_set_style (enum prompt_style style)
+{
+ assert (style < PROMPT_CNT);
+ current_style = style;
+}
+
+/* Returns the current prompt. */
+enum prompt_style
+prompt_get_style (void)
+{
+ return current_style;
+}
--- /dev/null
+/* PSPP - computes sample statistics.
+ Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef PROMPT_H
+#define PROMPT_H 1
+
+#include <stdbool.h>
+
+enum prompt_style
+ {
+ PROMPT_FIRST, /* First line of command. */
+ PROMPT_LATER, /* Second or later line of command. */
+ PROMPT_DATA, /* Between BEGIN DATA and END DATA. */
+ PROMPT_CNT
+ };
+
+
+void prompt_init (void);
+void prompt_done (void);
+
+enum prompt_style prompt_get_style (void);
+
+const char *prompt_get (enum prompt_style);
+void prompt_set (enum prompt_style, const char *);
+void prompt_set_style (enum prompt_style);
+
+
+#endif /* PROMPT_H */
--- /dev/null
+/* PSPP - computes sample statistics.
+ Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include "syntax-file.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <data/file-name.h>
+#include <data/settings.h>
+#include <data/variable.h>
+#include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <libpspp/alloc.h>
+#include <libpspp/assertion.h>
+#include <libpspp/message.h>
+#include <libpspp/message.h>
+#include <libpspp/str.h>
+#include <libpspp/verbose-msg.h>
+#include <libpspp/version.h>
+#include <output/table.h>
+
+#include <libpspp/ll.h>
+
+#include "prompt.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+#include <libpspp/getl.h>
+
+
+struct syntax_file_source
+ {
+ struct getl_interface parent ;
+
+ FILE *syntax_file;
+
+ /* Current location. */
+ char *fn; /* File name. */
+ int ln; /* Line number. */
+ };
+
+static const char *
+name (const struct getl_interface *s)
+{
+ const struct syntax_file_source *sfs = (const struct syntax_file_source *) s;
+ return sfs->fn;
+}
+
+static int
+line_number (const struct getl_interface *s)
+{
+ const struct syntax_file_source *sfs = (const struct syntax_file_source *) s;
+ return sfs->ln;
+}
+
+
+/* Reads a line from syntax file source S into LINE.
+ Returns true if successful, false at end of file. */
+bool
+read_syntax_file (struct getl_interface *s, struct string *line)
+{
+ struct syntax_file_source *sfs = (struct syntax_file_source *) s;
+
+ /* Open file, if not yet opened. */
+ if (sfs->syntax_file == NULL)
+ {
+ verbose_msg (1, _("opening \"%s\" as syntax file"), sfs->fn);
+ sfs->syntax_file = fn_open (sfs->fn, "r");
+
+ if (sfs->syntax_file == NULL)
+ {
+ msg (ME, _("Opening `%s': %s."), sfs->fn, strerror (errno));
+ return false;
+ }
+ }
+
+ /* Read line from file and remove new-line.
+ Skip initial "#! /usr/bin/pspp" line. */
+ do
+ {
+ sfs->ln++;
+ if (!ds_read_line (line, sfs->syntax_file))
+ {
+ if (ferror (sfs->syntax_file))
+ msg (ME, _("Reading `%s': %s."), sfs->fn, strerror (errno));
+ return false;
+ }
+ ds_chomp (line, '\n');
+ }
+ while (sfs->ln == 1 && !memcmp (ds_cstr (line), "#!", 2));
+
+ /* Echo to listing file, if configured to do so. */
+ if (get_echo ())
+ tab_output_text (TAB_LEFT | TAB_FIX, ds_cstr (line));
+
+ return true;
+}
+
+static void
+syntax_close (struct getl_interface *s)
+{
+ struct syntax_file_source *sfs = (struct syntax_file_source *) s;
+
+ if (sfs->syntax_file && EOF == fn_close (sfs->fn, sfs->syntax_file))
+ msg (MW, _("Closing `%s': %s."), sfs->fn, strerror (errno));
+ free (sfs->fn);
+ free (sfs);
+}
+
+static bool
+always_false (const struct getl_interface *s UNUSED)
+{
+ return false;
+}
+
+
+/* Creates a syntax file source with file name FN. */
+struct getl_interface *
+create_syntax_file_source (const char *fn)
+{
+ struct syntax_file_source *ss = xzalloc (sizeof (*ss));
+
+ ss->fn = xstrdup (fn);
+
+ ss->parent.interactive = always_false;
+ ss->parent.read = read_syntax_file ;
+ ss->parent.filter = NULL;
+ ss->parent.close = syntax_close ;
+ ss->parent.name = name ;
+ ss->parent.location = line_number;
+
+ return (struct getl_interface *) ss;
+}
+
--- /dev/null
+/* PSPP - computes sample statistics.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#if !SYNTAX_FILE
+#define SYNTAX_FILE 1
+
+#include <stdbool.h>
+
+struct string;
+struct getl_interface;
+struct getl_source;
+
+bool read_syntax_file (struct getl_interface *s, struct string *line);
+
+/* Creates a syntax file source with file name FN. */
+struct getl_interface * create_syntax_file_source (const char *fn) ;
+
+#endif
--- /dev/null
+/* PSPP - computes sample statistics.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <stdlib.h>
+
+#include <config.h>
+
+#include "getl.h"
+
+#include <libpspp/str.h>
+#include <libpspp/ll.h>
+#include <libpspp/version.h>
+#include <libpspp/alloc.h>
+
+#include <data/file-name.h>
+
+struct getl_source
+ {
+ struct getl_source *included_from; /* File that this is nested inside. */
+ struct getl_source *includes; /* File nested inside this file. */
+
+ struct ll ll; /* Element in the sources list */
+
+ struct getl_interface *interface;
+ };
+
+/* List of source files. */
+static struct ll_list sources ;
+
+static struct string the_include_path;
+
+const char *
+getl_include_path (void)
+{
+ return ds_cstr (&the_include_path);
+}
+
+static struct getl_source *
+current_source (struct ll_list *list)
+{
+ const struct ll *ll = ll_head (list);
+ return ll_data (ll, struct getl_source, ll );
+}
+
+/* Initialize getl. */
+void
+getl_initialize (void)
+{
+ ll_init (&sources);
+ ds_init_cstr (&the_include_path,
+ fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
+}
+
+/* Delete everything from the include path. */
+void
+getl_clear_include_path (void)
+{
+ ds_clear (&the_include_path);
+}
+
+/* Add to the include path. */
+void
+getl_add_include_dir (const char *path)
+{
+ if (ds_length (&the_include_path))
+ ds_put_char (&the_include_path, ':');
+
+ ds_put_cstr (&the_include_path, path);
+}
+
+/* Appends source S to the list of source files. */
+void
+getl_append_source (struct getl_interface *i)
+{
+ struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
+
+ s->interface = i ;
+
+ ll_push_head (&sources, &s->ll);
+}
+
+/* Nests source S within the current source file. */
+void
+getl_include_source (struct getl_interface *i)
+{
+ struct getl_source *current = current_source (&sources);
+ struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
+
+ s->interface = i;
+
+ s->included_from = current ;
+ s->includes = NULL;
+ current->includes = s;
+
+ ll_push_head (&sources, &s->ll);
+}
+
+/* Closes the current source, and move the current source to the
+ next file in the chain. */
+static void
+close_source (void)
+{
+ struct getl_source *s = current_source (&sources);
+
+ if ( s->interface->close )
+ s->interface->close (s->interface);
+
+ ll_pop_head (&sources);
+
+ if (s->included_from != NULL)
+ current_source (&sources)->includes = NULL;
+
+ free (s);
+}
+
+/* Closes all sources until an interactive source is
+ encountered. */
+void
+getl_abort_noninteractive (void)
+{
+ while ( ! ll_is_empty (&sources))
+ {
+ const struct getl_source *s = current_source (&sources);
+
+ if ( !s->interface->interactive (s->interface) )
+ close_source ();
+ }
+}
+
+/* Returns true if the current source is interactive,
+ false otherwise. */
+bool
+getl_is_interactive (void)
+{
+ const struct getl_source *s = current_source (&sources);
+
+ if (ll_is_empty (&sources) )
+ return false;
+
+ return s->interface->interactive (s->interface);
+}
+
+/* Returns the name of the current source, or NULL if there is no
+ current source */
+const char *
+getl_source_name (void)
+{
+ const struct getl_source *s = current_source (&sources);
+
+ if ( ll_is_empty (&sources) )
+ return NULL;
+
+ if ( ! s->interface->name )
+ return NULL;
+
+ return s->interface->name (s->interface);
+}
+
+/* Returns the location within the current source, or -1 if there is
+ no current source */
+int
+getl_source_location (void)
+{
+ const struct getl_source *s = current_source (&sources);
+
+ if ( ll_is_empty (&sources) )
+ return -1;
+
+ if ( !s->interface->location )
+ return -1;
+
+ return s->interface->location (s->interface);
+}
+
+
+/* Close getl. */
+void
+getl_uninitialize (void)
+{
+ while ( !ll_is_empty (&sources))
+ close_source ();
+ ds_destroy (&the_include_path);
+}
+
+
+/* Reads a single line into LINE.
+ Returns true when a line has been read, false at end of input.
+ If INTERACTIVE is non-null, then when true is returned
+ *INTERACTIVE will be set to true if the line was obtained
+ interactively, false otherwise. */
+bool
+do_read_line (struct string *line, bool *interactive)
+{
+ while (!ll_is_empty (&sources))
+ {
+ struct getl_source *s = current_source (&sources);
+
+ ds_clear (line);
+ if (s->interface->read (s->interface, line))
+ {
+ if (interactive != NULL)
+ *interactive = s->interface->interactive (s->interface);
+
+ while ((s))
+ {
+ if (s->interface->filter)
+ s->interface->filter (s->interface, line);
+ s = s->included_from;
+ }
+
+ return true;
+ }
+ close_source ();
+ }
+
+ return false;
+}
--- /dev/null
+/* PSPP - computes sample statistics.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef GETL_H
+#define GETL_H 1
+
+#include <stdbool.h>
+#include <libpspp/ll.h>
+
+struct string;
+
+struct getl_source;
+
+
+/* An abstract base class for objects which act as line buffers for the
+ PSPP. Ie anything which might contain content for the lexer */
+struct getl_interface
+ {
+ /* Returns true, if the interface is interactive */
+ bool (*interactive) (const struct getl_interface *);
+
+ /* Read a line from the interface */
+ bool (*read) (struct getl_interface *, struct string *);
+
+ /* Close and destroy the interface */
+ void (*close) (struct getl_interface *);
+
+ /* Filter for current and all included sources. May be NULL */
+ void (*filter) (struct getl_interface *, struct string *line);
+
+ /* Returns the name of the source */
+ const char * (*name) (const struct getl_interface *);
+
+ /* Returns the current location within the source */
+ int (*location) (const struct getl_interface *);
+ };
+
+void getl_initialize (void);
+void getl_uninitialize (void);
+
+void getl_clear_include_path (void);
+void getl_add_include_dir (const char *);
+const char * getl_include_path (void);
+
+void getl_abort_noninteractive (void);
+bool getl_is_interactive (void);
+
+bool getl_read_line (bool *interactive);
+
+bool do_read_line (struct string *line, bool *interactive);
+
+void getl_append_source (struct getl_interface *s) ;
+void getl_include_source (struct getl_interface *s) ;
+
+const char * getl_source_name (void);
+int getl_source_location (void);
+
+#endif /* line-buffer.h */
--- /dev/null
+/* PSPP - computes sample statistics.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+#include <stdlib.h>
+#include <libpspp/alloc.h>
+#include "msg-locator.h"
+#include <libpspp/message.h>
+#include <libpspp/assertion.h>
+#include "getl.h"
+
+/* File locator stack. */
+static const struct msg_locator **file_loc;
+
+static int nfile_loc, mfile_loc;
+
+void
+msg_locator_done (void)
+{
+ free(file_loc);
+ file_loc = NULL;
+ nfile_loc = mfile_loc = 0;
+}
+
+
+/* File locator stack functions. */
+
+/* Pushes F onto the stack of file locations. */
+void
+msg_push_msg_locator (const struct msg_locator *loc)
+{
+ if (nfile_loc >= mfile_loc)
+ {
+ if (mfile_loc == 0)
+ mfile_loc = 8;
+ else
+ mfile_loc *= 2;
+
+ file_loc = xnrealloc (file_loc, mfile_loc, sizeof *file_loc);
+ }
+
+ file_loc[nfile_loc++] = loc;
+}
+
+/* Pops F off the stack of file locations.
+ Argument F is only used for verification that that is actually the
+ item on top of the stack. */
+void
+msg_pop_msg_locator (const struct msg_locator *loc)
+{
+ assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == loc);
+ nfile_loc--;
+}
+
+/* Puts the current file and line number into LOC, or NULL and -1 if
+ none. */
+void
+get_msg_location (struct msg_locator *loc)
+{
+ if (nfile_loc)
+ {
+ *loc = *file_loc[nfile_loc - 1];
+ }
+ else
+ {
+ loc->file_name = getl_source_name ();
+ loc->line_number = getl_source_location ();
+ }
+}
--- /dev/null
+/* PSPP - computes sample statistics.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+struct msg_locator ;
+
+void msg_locator_done (void);
+
+/* File locator stack functions. */
+
+/* Pushes F onto the stack of file locations. */
+void msg_push_msg_locator (const struct msg_locator *loc);
+
+/* Pops F off the stack of file locations.
+ Argument F is only used for verification that that is actually the
+ item on top of the stack. */
+void msg_pop_msg_locator (const struct msg_locator *loc);
+
+/* Puts the current file and line number into LOC, or NULL and -1 if
+ none. */
+void get_msg_location (struct msg_locator *loc);