1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
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.
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.
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
22 #include <language/line-buffer.h>
28 #include <data/file-name.h>
29 #include <data/settings.h>
30 #include <data/variable.h>
31 #include <language/command.h>
32 #include <language/lexer/lexer.h>
33 #include <libpspp/alloc.h>
34 #include <libpspp/message.h>
35 #include <libpspp/message.h>
36 #include <libpspp/str.h>
37 #include <libpspp/verbose-msg.h>
38 #include <libpspp/version.h>
39 #include <output/table.h>
42 #define _(msgid) gettext (msgid)
47 struct getl_source *included_from; /* File that this is nested inside. */
48 struct getl_source *includes; /* File nested inside this file. */
49 struct getl_source *next; /* Next file in list. */
51 /* Current location. */
52 char *fn; /* File name. */
53 int ln; /* Line number. */
72 void (*filter) (struct string *line, void *aux);
73 void (*close) (void *aux);
81 bool (*read) (struct string *line, char **fn, int *ln, void *aux);
82 void (*close) (void *aux);
88 bool (*interactive) (struct string *line, const char *prompt);
94 /* List of source files. */
95 static struct getl_source *cur_source;
96 static struct getl_source *last_source;
98 static struct string getl_include_path;
100 struct string getl_buf;
102 static void close_source (void);
104 static void init_prompts (void);
105 static void uninit_prompts (void);
106 static const char *get_prompt (void);
108 /* Initialize getl. */
110 getl_initialize (void)
112 ds_create (&getl_include_path,
113 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
114 ds_init (&getl_buf, 256);
118 /* Delete everything from the include path. */
120 getl_clear_include_path (void)
122 ds_clear (&getl_include_path);
125 /* Add to the include path. */
127 getl_add_include_dir (const char *path)
129 if (ds_length (&getl_include_path))
130 ds_putc (&getl_include_path, ':');
132 ds_puts (&getl_include_path, path);
135 /* Appends source S to the list of source files. */
137 append_source (struct getl_source *s)
139 s->included_from = s->includes = s->next = NULL;
140 if (last_source == NULL)
143 last_source->next = s;
147 /* Nests source S within the current source file. */
149 include_source (struct getl_source *s)
151 if (last_source == NULL)
155 s->included_from = cur_source;
156 s->includes = s->next = NULL;
158 cur_source->includes = s;
163 /* Creates a source of the given TYPE.
164 Type-specific data must be initialized by the caller. */
165 static struct getl_source *
166 create_source (enum getl_source_type type)
168 struct getl_source *s = xmalloc (sizeof *s);
175 /* Creates a syntax file source with file name FN. */
176 static struct getl_source *
177 create_syntax_file_source (const char *fn)
179 struct getl_source *s = create_source (SYNTAX_FILE);
180 s->fn = xstrdup (fn);
181 s->u.syntax_file = NULL;
185 /* Creates a filter source with the given FILTER and CLOSE
186 functions that receive auxiliary data AUX. */
187 static struct getl_source *
188 create_filter_source (void (*filter) (struct string *, void *aux),
189 void (*close) (void *aux),
192 struct getl_source *s = create_source (FILTER);
193 s->u.filter.filter = filter;
194 s->u.filter.close = close;
195 s->u.filter.aux = aux;
199 /* Creates a function source with the given READ and CLOSE
200 functions that receive auxiliary data AUX. */
201 static struct getl_source *
202 create_function_source (bool (*read) (struct string *line,
203 char **fn, int *ln, void *aux),
204 void (*close) (void *aux),
207 struct getl_source *s = create_source (FUNCTION);
208 s->u.function.read = read;
209 s->u.function.close = close;
210 s->u.function.aux = aux;
214 /* Creates an interactive source with the given FUNCTION. */
215 static struct getl_source *
216 create_interactive_source (bool (*function) (struct string *line,
219 struct getl_source *s = xmalloc (sizeof *s);
222 s->type = INTERACTIVE;
223 s->u.interactive = function;
227 /* Adds FN to the tail end of the list of source files to
230 getl_append_syntax_file (const char *fn)
232 append_source (create_syntax_file_source (fn));
235 /* Inserts the given file with name FN into the current file
236 after the current line. */
238 getl_include_syntax_file (const char *fn)
240 if (cur_source != NULL)
242 char *found_fn = fn_search_path (fn, ds_c_str (&getl_include_path),
243 fn_dir_name (cur_source->fn));
244 if (found_fn != NULL)
246 include_source (create_syntax_file_source (found_fn));
250 msg (SE, _("Can't find `%s' in include file search path."), fn);
253 getl_append_syntax_file (fn);
256 /* Inserts the given filter into the current file after the
257 current line. Each line read while the filter is in place
258 will be passed through FILTER, which may modify it as
259 necessary. When the filter is closed, CLOSE will be called.
260 AUX will be passed to both functions.
262 The filter cannot itself output any new lines, and it will be
263 closed as soon as any line would be read from it. This means
264 that, for a filter to be useful, another source must be nested
265 inside it with, e.g., getl_include_syntax_file(). */
267 getl_include_filter (void (*filter) (struct string *, void *aux),
268 void (*close) (void *aux),
271 include_source (create_filter_source (filter, close, aux));
274 /* Inserts the given functional source into the current file
275 after the current line. Lines are read by calling READ, which
276 should write the next line in LINE, store the file name and
277 line number of the line in *FN and *LN, and return true. The
278 string stored in *FN will not be freed by getl. When no lines
279 are left, READ should return false.
281 When the source is closed, CLOSE will be called.
283 AUX will be passed to both READ and CLOSE. */
285 getl_include_function (bool (*read) (struct string *line,
286 char **fn, int *ln, void *aux),
287 void (*close) (void *aux),
290 include_source (create_function_source (read, close, aux));
293 /* Adds an interactive source to the end of the list of sources.
294 FUNCTION will be called to obtain a line. It should store the
295 line in LINE. PROMPT is the prompt to be displayed to the
296 user. FUNCTION should return true when a line has been
297 obtained or false at end of file. */
299 getl_append_interactive (bool (*function) (struct string *line,
302 append_source (create_interactive_source (function));
305 /* Closes all sources until an interactive source is
308 getl_abort_noninteractive (void)
310 while (cur_source != NULL && cur_source->type != INTERACTIVE)
314 /* Returns true if the current source is interactive,
317 getl_is_interactive (void)
319 return cur_source != NULL && cur_source->type == INTERACTIVE;
322 /* Closes the current file, whether it be a main file or included
323 file, then moves cur_source to the next file in the chain. */
327 struct getl_source *s;
333 if (s->u.syntax_file && EOF == fn_close (s->fn, s->u.syntax_file))
334 msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
339 if (s->u.filter.close != NULL)
340 s->u.filter.close (s->u.filter.aux);
344 if (s->u.function.close != NULL)
345 s->u.function.close (s->u.function.aux);
352 if (s->included_from != NULL)
354 cur_source = s->included_from;
355 cur_source->includes = NULL;
359 cur_source = s->next;
360 if (cur_source == NULL)
367 /* Puts the current file and line number in *FN and *LN, respectively,
368 or NULL and -1 if none. */
370 getl_location (const char **fn, int *ln)
373 *fn = cur_source ? cur_source->fn : "";
375 *ln = cur_source ? cur_source->ln : -1;
378 /* File locator stack. */
379 static const struct msg_locator **file_loc;
380 static int nfile_loc, mfile_loc;
384 getl_uninitialize (void)
386 while (cur_source != NULL)
388 ds_destroy (&getl_buf);
389 ds_destroy (&getl_include_path);
392 nfile_loc = mfile_loc = 0;
397 /* File locator stack functions. */
399 /* Pushes F onto the stack of file locations. */
401 msg_push_msg_locator (const struct msg_locator *loc)
403 if (nfile_loc >= mfile_loc)
410 file_loc = xnrealloc (file_loc, mfile_loc, sizeof *file_loc);
413 file_loc[nfile_loc++] = loc;
416 /* Pops F off the stack of file locations.
417 Argument F is only used for verification that that is actually the
418 item on top of the stack. */
420 msg_pop_msg_locator (const struct msg_locator *loc)
422 assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == loc);
426 /* Puts the current file and line number in F, or NULL and -1 if
429 msg_location (struct msg_locator *loc)
432 *loc = *file_loc[nfile_loc - 1];
434 getl_location (&loc->file_name, &loc->line_number);
437 /* Reads a line from syntax file source S into LINE.
438 Returns true if successful, false at end of file. */
440 read_syntax_file (struct string *line, struct getl_source *s)
442 /* Open file, if not yet opened. */
443 if (s->u.syntax_file == NULL)
445 verbose_msg (1, _("opening \"%s\" as syntax file"), s->fn);
446 s->u.syntax_file = fn_open (s->fn, "r");
448 if (s->u.syntax_file == NULL)
450 msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
455 /* Read line from file and remove new-line.
456 Skip initial "#! /usr/bin/pspp" line. */
460 if (!ds_gets (line, s->u.syntax_file))
462 if (ferror (s->u.syntax_file))
463 msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
466 ds_chomp (line, '\n');
468 while (s->ln == 1 && !memcmp (ds_c_str (line), "#!", 2));
470 /* Echo to listing file, if configured to do so. */
472 tab_output_text (TAB_LEFT | TAB_FIX, ds_c_str (line));
477 /* Reads a line from source S into LINE.
478 Returns true if successful, false at end of file. */
480 read_line_from_source (struct string *line, struct getl_source *s)
486 return read_syntax_file (line, s);
490 return s->u.function.read (line, &s->fn, &s->ln, s->u.function.aux);
492 return s->u.interactive (line, get_prompt ());
498 /* Reads a single line into LINE.
499 Returns true when a line has been read, false at end of input.
500 If INTERACTIVE is non-null, then when true is returned
501 *INTERACTIVE will be set to true if the line was obtained
502 interactively, false otherwise. */
504 do_read_line (struct string *line, bool *interactive)
506 while (cur_source != NULL)
508 struct getl_source *s = cur_source;
509 if (read_line_from_source (line, s))
511 if (interactive != NULL)
512 *interactive = s->type == INTERACTIVE;
514 while ((s = s->included_from) != NULL)
515 if (s->type == FILTER)
516 s->u.filter.filter (line, s->u.filter.aux);
526 /* Reads a single line into getl_buf.
527 Returns true when a line has been read, false at end of input.
528 If INTERACTIVE is non-null, then when true is returned
529 *INTERACTIVE will be set to true if the line was obtained
530 interactively, false otherwise. */
532 getl_read_line (bool *interactive)
534 return do_read_line (&getl_buf, interactive);
537 /* Current prompts in each style. */
538 static char *prompts[GETL_PROMPT_CNT];
540 /* Current prompting style. */
541 static enum getl_prompt_style current_style;
543 /* Initializes prompts. */
547 prompts[GETL_PROMPT_FIRST] = xstrdup ("PSPP> ");
548 prompts[GETL_PROMPT_LATER] = xstrdup (" > ");
549 prompts[GETL_PROMPT_DATA] = xstrdup ("data> ");
550 current_style = GETL_PROMPT_FIRST;
555 uninit_prompts (void)
559 for (i = 0; i < GETL_PROMPT_CNT; i++)
566 /* Gets the command prompt for the given STYLE. */
568 getl_get_prompt (enum getl_prompt_style style)
570 assert (style < GETL_PROMPT_CNT);
571 return prompts[style];
574 /* Sets the given STYLE's prompt to STRING. */
576 getl_set_prompt (enum getl_prompt_style style, const char *string)
578 assert (style < GETL_PROMPT_CNT);
579 free (prompts[style]);
580 prompts[style] = xstrdup (string);
583 /* Sets STYLE as the current prompt style. */
585 getl_set_prompt_style (enum getl_prompt_style style)
587 assert (style < GETL_PROMPT_CNT);
588 current_style = style;
591 /* Returns the current prompt. */
595 return prompts[current_style];