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/assertion.h>
35 #include <libpspp/message.h>
36 #include <libpspp/message.h>
37 #include <libpspp/str.h>
38 #include <libpspp/verbose-msg.h>
39 #include <libpspp/version.h>
40 #include <output/table.h>
43 #define _(msgid) gettext (msgid)
48 struct getl_source *included_from; /* File that this is nested inside. */
49 struct getl_source *includes; /* File nested inside this file. */
50 struct getl_source *next; /* Next file in list. */
52 /* Current location. */
53 char *fn; /* File name. */
54 int ln; /* Line number. */
73 void (*filter) (struct string *line, void *aux);
74 void (*close) (void *aux);
82 bool (*read) (struct string *line, char **fn, int *ln, void *aux);
83 void (*close) (void *aux);
89 bool (*interactive) (struct string *line, enum getl_prompt_style);
95 /* List of source files. */
96 static struct getl_source *cur_source;
97 static struct getl_source *last_source;
99 static struct string getl_include_path;
102 static void close_source (void);
104 static void init_prompts (void);
105 static void uninit_prompts (void);
106 static enum getl_prompt_style get_prompt_style (void);
109 /* Initialize getl. */
111 getl_initialize (void)
113 ds_init_cstr (&getl_include_path,
114 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
119 /* Delete everything from the include path. */
121 getl_clear_include_path (void)
123 ds_clear (&getl_include_path);
126 /* Add to the include path. */
128 getl_add_include_dir (const char *path)
130 if (ds_length (&getl_include_path))
131 ds_put_char (&getl_include_path, ':');
133 ds_put_cstr (&getl_include_path, path);
136 /* Appends source S to the list of source files. */
138 append_source (struct getl_source *s)
140 s->included_from = s->includes = s->next = NULL;
141 if (last_source == NULL)
144 last_source->next = s;
148 /* Nests source S within the current source file. */
150 include_source (struct getl_source *s)
152 if (last_source == NULL)
156 s->included_from = cur_source;
157 s->includes = s->next = NULL;
159 cur_source->includes = s;
164 /* Creates a source of the given TYPE.
165 Type-specific data must be initialized by the caller. */
166 static struct getl_source *
167 create_source (enum getl_source_type type)
169 struct getl_source *s = xmalloc (sizeof *s);
176 /* Creates a syntax file source with file name FN. */
177 static struct getl_source *
178 create_syntax_file_source (const char *fn)
180 struct getl_source *s = create_source (SYNTAX_FILE);
181 s->fn = xstrdup (fn);
182 s->u.syntax_file = NULL;
186 /* Creates a filter source with the given FILTER and CLOSE
187 functions that receive auxiliary data AUX. */
188 static struct getl_source *
189 create_filter_source (void (*filter) (struct string *, void *aux),
190 void (*close) (void *aux),
193 struct getl_source *s = create_source (FILTER);
194 s->u.filter.filter = filter;
195 s->u.filter.close = close;
196 s->u.filter.aux = aux;
200 /* Creates a function source with the given READ and CLOSE
201 functions that receive auxiliary data AUX. */
202 static struct getl_source *
203 create_function_source (bool (*read) (struct string *line,
204 char **fn, int *ln, void *aux),
205 void (*close) (void *aux),
208 struct getl_source *s = create_source (FUNCTION);
209 s->u.function.read = read;
210 s->u.function.close = close;
211 s->u.function.aux = aux;
215 /* Creates an interactive source with the given FUNCTION. */
216 static struct getl_source *
217 create_interactive_source (bool (*function) (struct string *line,
218 enum getl_prompt_style))
220 struct getl_source *s = xmalloc (sizeof *s);
223 s->type = INTERACTIVE;
224 s->u.interactive = function;
228 /* Adds FN to the tail end of the list of source files to
231 getl_append_syntax_file (const char *fn)
233 append_source (create_syntax_file_source (fn));
236 /* Inserts the given file with name FN into the current file
237 after the current line. */
239 getl_include_syntax_file (const char *fn)
241 if (cur_source != NULL)
243 char *found_fn = fn_search_path (fn, ds_cstr (&getl_include_path),
244 fn_dir_name (cur_source->fn));
245 if (found_fn != NULL)
247 include_source (create_syntax_file_source (found_fn));
251 msg (SE, _("Can't find `%s' in include file search path."), fn);
254 getl_append_syntax_file (fn);
257 /* Inserts the given filter into the current file after the
258 current line. Each line read while the filter is in place
259 will be passed through FILTER, which may modify it as
260 necessary. When the filter is closed, CLOSE will be called.
261 AUX will be passed to both functions.
263 The filter cannot itself output any new lines, and it will be
264 closed as soon as any line would be read from it. This means
265 that, for a filter to be useful, another source must be nested
266 inside it with, e.g., getl_include_syntax_file(). */
268 getl_include_filter (void (*filter) (struct string *, void *aux),
269 void (*close) (void *aux),
272 include_source (create_filter_source (filter, close, aux));
275 /* Inserts the given functional source into the current file
276 after the current line. Lines are read by calling READ, which
277 should write the next line in LINE, store the file name and
278 line number of the line in *FN and *LN, and return true. The
279 string stored in *FN will not be freed by getl. When no lines
280 are left, READ should return false.
282 When the source is closed, CLOSE will be called.
284 AUX will be passed to both READ and CLOSE. */
286 getl_include_function (bool (*read) (struct string *line,
287 char **fn, int *ln, void *aux),
288 void (*close) (void *aux),
291 include_source (create_function_source (read, close, aux));
294 /* Adds an interactive source to the end of the list of sources.
295 FUNCTION will be called to obtain a line. It should store the
296 line in LINE. PROMPT is the prompt to be displayed to the
297 user. FUNCTION should return true when a line has been
298 obtained or false at end of file. */
300 getl_append_interactive (bool (*function) (struct string *line,
301 enum getl_prompt_style))
303 append_source (create_interactive_source (function));
306 /* Closes all sources until an interactive source is
309 getl_abort_noninteractive (void)
311 while (cur_source != NULL && cur_source->type != INTERACTIVE)
315 /* Returns true if the current source is interactive,
318 getl_is_interactive (void)
320 return cur_source != NULL && cur_source->type == INTERACTIVE;
323 /* Closes the current file, whether it be a main file or included
324 file, then moves cur_source to the next file in the chain. */
328 struct getl_source *s;
334 if (s->u.syntax_file && EOF == fn_close (s->fn, s->u.syntax_file))
335 msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
340 if (s->u.filter.close != NULL)
341 s->u.filter.close (s->u.filter.aux);
345 if (s->u.function.close != NULL)
346 s->u.function.close (s->u.function.aux);
353 if (s->included_from != NULL)
355 cur_source = s->included_from;
356 cur_source->includes = NULL;
360 cur_source = s->next;
361 if (cur_source == NULL)
368 /* Puts the current file and line number in *FN and *LN, respectively,
369 or NULL and -1 if none. */
371 getl_location (const char **fn, int *ln)
374 *fn = cur_source ? cur_source->fn : "";
376 *ln = cur_source ? cur_source->ln : -1;
379 /* File locator stack. */
380 static const struct msg_locator **file_loc;
382 static int nfile_loc, mfile_loc;
386 getl_uninitialize (void)
388 while (cur_source != NULL)
390 ds_destroy (&getl_include_path);
393 nfile_loc = mfile_loc = 0;
398 /* File locator stack functions. */
400 /* Pushes F onto the stack of file locations. */
402 msg_push_msg_locator (const struct msg_locator *loc)
404 if (nfile_loc >= mfile_loc)
411 file_loc = xnrealloc (file_loc, mfile_loc, sizeof *file_loc);
414 file_loc[nfile_loc++] = loc;
417 /* Pops F off the stack of file locations.
418 Argument F is only used for verification that that is actually the
419 item on top of the stack. */
421 msg_pop_msg_locator (const struct msg_locator *loc)
423 assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == loc);
427 /* Puts the current file and line number into LOC, or NULL and -1 if
430 get_msg_location (struct msg_locator *loc)
433 *loc = *file_loc[nfile_loc - 1];
435 getl_location (&loc->file_name, &loc->line_number);
438 /* Reads a line from syntax file source S into LINE.
439 Returns true if successful, false at end of file. */
441 read_syntax_file (struct string *line, struct getl_source *s)
443 /* Open file, if not yet opened. */
444 if (s->u.syntax_file == NULL)
446 verbose_msg (1, _("opening \"%s\" as syntax file"), s->fn);
447 s->u.syntax_file = fn_open (s->fn, "r");
449 if (s->u.syntax_file == NULL)
451 msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
456 /* Read line from file and remove new-line.
457 Skip initial "#! /usr/bin/pspp" line. */
461 if (!ds_read_line (line, s->u.syntax_file))
463 if (ferror (s->u.syntax_file))
464 msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
467 ds_chomp (line, '\n');
469 while (s->ln == 1 && !memcmp (ds_cstr (line), "#!", 2));
471 /* Echo to listing file, if configured to do so. */
473 tab_output_text (TAB_LEFT | TAB_FIX, ds_cstr (line));
478 /* Reads a line from source S into LINE.
479 Returns true if successful, false at end of file. */
481 read_line_from_source (struct string *line, struct getl_source *s)
487 return read_syntax_file (line, s);
491 return s->u.function.read (line, &s->fn, &s->ln, s->u.function.aux);
493 return s->u.interactive (line, get_prompt_style ());
499 /* Reads a single line into LINE.
500 Returns true when a line has been read, false at end of input.
501 If INTERACTIVE is non-null, then when true is returned
502 *INTERACTIVE will be set to true if the line was obtained
503 interactively, false otherwise. */
505 do_read_line (struct string *line, bool *interactive)
507 while (cur_source != NULL)
509 struct getl_source *s = cur_source;
510 if (read_line_from_source (line, s))
512 if (interactive != NULL)
513 *interactive = s->type == INTERACTIVE;
515 while ((s = s->included_from) != NULL)
516 if (s->type == FILTER)
517 s->u.filter.filter (line, s->u.filter.aux);
528 /* Current prompts in each style. */
529 static char *prompts[GETL_PROMPT_CNT];
531 /* Current prompting style. */
532 static enum getl_prompt_style current_style;
534 /* Initializes prompts. */
538 prompts[GETL_PROMPT_FIRST] = xstrdup ("PSPP> ");
539 prompts[GETL_PROMPT_LATER] = xstrdup (" > ");
540 prompts[GETL_PROMPT_DATA] = xstrdup ("data> ");
541 current_style = GETL_PROMPT_FIRST;
546 uninit_prompts (void)
550 for (i = 0; i < GETL_PROMPT_CNT; i++)
557 /* Gets the command prompt for the given STYLE. */
559 getl_get_prompt (enum getl_prompt_style style)
561 assert (style < GETL_PROMPT_CNT);
562 return prompts[style];
565 /* Sets the given STYLE's prompt to STRING. */
567 getl_set_prompt (enum getl_prompt_style style, const char *string)
569 assert (style < GETL_PROMPT_CNT);
570 free (prompts[style]);
571 prompts[style] = xstrdup (string);
574 /* Sets STYLE as the current prompt style. */
576 getl_set_prompt_style (enum getl_prompt_style style)
578 assert (style < GETL_PROMPT_CNT);
579 current_style = style;
582 /* Returns the current prompt. */
583 static enum getl_prompt_style
584 get_prompt_style (void)
586 return current_style;