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;
101 struct string getl_buf;
103 static void close_source (void);
105 static void init_prompts (void);
106 static void uninit_prompts (void);
107 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));
115 ds_init_empty (&getl_buf);
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_buf);
391 ds_destroy (&getl_include_path);
394 nfile_loc = mfile_loc = 0;
399 /* File locator stack functions. */
401 /* Pushes F onto the stack of file locations. */
403 msg_push_msg_locator (const struct msg_locator *loc)
405 if (nfile_loc >= mfile_loc)
412 file_loc = xnrealloc (file_loc, mfile_loc, sizeof *file_loc);
415 file_loc[nfile_loc++] = loc;
418 /* Pops F off the stack of file locations.
419 Argument F is only used for verification that that is actually the
420 item on top of the stack. */
422 msg_pop_msg_locator (const struct msg_locator *loc)
424 assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == loc);
428 /* Puts the current file and line number into LOC, or NULL and -1 if
431 get_msg_location (struct msg_locator *loc)
434 *loc = *file_loc[nfile_loc - 1];
436 getl_location (&loc->file_name, &loc->line_number);
439 /* Reads a line from syntax file source S into LINE.
440 Returns true if successful, false at end of file. */
442 read_syntax_file (struct string *line, struct getl_source *s)
444 /* Open file, if not yet opened. */
445 if (s->u.syntax_file == NULL)
447 verbose_msg (1, _("opening \"%s\" as syntax file"), s->fn);
448 s->u.syntax_file = fn_open (s->fn, "r");
450 if (s->u.syntax_file == NULL)
452 msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
457 /* Read line from file and remove new-line.
458 Skip initial "#! /usr/bin/pspp" line. */
462 if (!ds_read_line (line, s->u.syntax_file))
464 if (ferror (s->u.syntax_file))
465 msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
468 ds_chomp (line, '\n');
470 while (s->ln == 1 && !memcmp (ds_cstr (line), "#!", 2));
472 /* Echo to listing file, if configured to do so. */
474 tab_output_text (TAB_LEFT | TAB_FIX, ds_cstr (line));
479 /* Reads a line from source S into LINE.
480 Returns true if successful, false at end of file. */
482 read_line_from_source (struct string *line, struct getl_source *s)
488 return read_syntax_file (line, s);
492 return s->u.function.read (line, &s->fn, &s->ln, s->u.function.aux);
494 return s->u.interactive (line, get_prompt_style ());
500 /* Reads a single line into LINE.
501 Returns true when a line has been read, false at end of input.
502 If INTERACTIVE is non-null, then when true is returned
503 *INTERACTIVE will be set to true if the line was obtained
504 interactively, false otherwise. */
506 do_read_line (struct string *line, bool *interactive)
508 while (cur_source != NULL)
510 struct getl_source *s = cur_source;
511 if (read_line_from_source (line, s))
513 if (interactive != NULL)
514 *interactive = s->type == INTERACTIVE;
516 while ((s = s->included_from) != NULL)
517 if (s->type == FILTER)
518 s->u.filter.filter (line, s->u.filter.aux);
528 /* Reads a single line into getl_buf.
529 Returns true when a line has been read, false at end of input.
530 If INTERACTIVE is non-null, then when true is returned
531 *INTERACTIVE will be set to true if the line was obtained
532 interactively, false otherwise. */
534 getl_read_line (bool *interactive)
536 return do_read_line (&getl_buf, interactive);
539 /* Current prompts in each style. */
540 static char *prompts[GETL_PROMPT_CNT];
542 /* Current prompting style. */
543 static enum getl_prompt_style current_style;
545 /* Initializes prompts. */
549 prompts[GETL_PROMPT_FIRST] = xstrdup ("PSPP> ");
550 prompts[GETL_PROMPT_LATER] = xstrdup (" > ");
551 prompts[GETL_PROMPT_DATA] = xstrdup ("data> ");
552 current_style = GETL_PROMPT_FIRST;
557 uninit_prompts (void)
561 for (i = 0; i < GETL_PROMPT_CNT; i++)
568 /* Gets the command prompt for the given STYLE. */
570 getl_get_prompt (enum getl_prompt_style style)
572 assert (style < GETL_PROMPT_CNT);
573 return prompts[style];
576 /* Sets the given STYLE's prompt to STRING. */
578 getl_set_prompt (enum getl_prompt_style style, const char *string)
580 assert (style < GETL_PROMPT_CNT);
581 free (prompts[style]);
582 prompts[style] = xstrdup (string);
585 /* Sets STYLE as the current prompt style. */
587 getl_set_prompt_style (enum getl_prompt_style style)
589 assert (style < GETL_PROMPT_CNT);
590 current_style = style;
593 /* Returns the current prompt. */
594 static enum getl_prompt_style
595 get_prompt_style (void)
597 return current_style;