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, enum getl_prompt_style);
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 enum getl_prompt_style get_prompt_style (void);
108 /* Initialize getl. */
110 getl_initialize (void)
112 ds_init_cstr (&getl_include_path,
113 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
114 ds_init_empty (&getl_buf);
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_put_char (&getl_include_path, ':');
132 ds_put_cstr (&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,
217 enum getl_prompt_style))
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_cstr (&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,
300 enum getl_prompt_style))
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;
381 static int nfile_loc, mfile_loc;
385 getl_uninitialize (void)
387 while (cur_source != NULL)
389 ds_destroy (&getl_buf);
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);
527 /* Reads a single line into getl_buf.
528 Returns true when a line has been read, false at end of input.
529 If INTERACTIVE is non-null, then when true is returned
530 *INTERACTIVE will be set to true if the line was obtained
531 interactively, false otherwise. */
533 getl_read_line (bool *interactive)
535 return do_read_line (&getl_buf, interactive);
538 /* Current prompts in each style. */
539 static char *prompts[GETL_PROMPT_CNT];
541 /* Current prompting style. */
542 static enum getl_prompt_style current_style;
544 /* Initializes prompts. */
548 prompts[GETL_PROMPT_FIRST] = xstrdup ("PSPP> ");
549 prompts[GETL_PROMPT_LATER] = xstrdup (" > ");
550 prompts[GETL_PROMPT_DATA] = xstrdup ("data> ");
551 current_style = GETL_PROMPT_FIRST;
556 uninit_prompts (void)
560 for (i = 0; i < GETL_PROMPT_CNT; i++)
567 /* Gets the command prompt for the given STYLE. */
569 getl_get_prompt (enum getl_prompt_style style)
571 assert (style < GETL_PROMPT_CNT);
572 return prompts[style];
575 /* Sets the given STYLE's prompt to STRING. */
577 getl_set_prompt (enum getl_prompt_style style, const char *string)
579 assert (style < GETL_PROMPT_CNT);
580 free (prompts[style]);
581 prompts[style] = xstrdup (string);
584 /* Sets STYLE as the current prompt style. */
586 getl_set_prompt_style (enum getl_prompt_style style)
588 assert (style < GETL_PROMPT_CNT);
589 current_style = style;
592 /* Returns the current prompt. */
593 static enum getl_prompt_style
594 get_prompt_style (void)
596 return current_style;