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
21 #include "line-buffer.h"
38 #define _(msgid) gettext (msgid)
43 struct getl_source *included_from; /* File that this is nested inside. */
44 struct getl_source *includes; /* File nested inside this file. */
45 struct getl_source *next; /* Next file in list. */
47 /* Current location. */
48 char *fn; /* Filename. */
49 int ln; /* Line number. */
68 void (*filter) (struct string *line, void *aux);
69 void (*close) (void *aux);
77 bool (*read) (struct string *line, char **fn, int *ln, void *aux);
78 void (*close) (void *aux);
84 bool (*interactive) (struct string *line, const char *prompt);
90 /* List of source files. */
91 static struct getl_source *cur_source;
92 static struct getl_source *last_source;
94 static struct string getl_include_path;
96 struct string getl_buf;
98 static void close_source (void);
100 static void init_prompts (void);
101 static void uninit_prompts (void);
102 static const char *get_prompt (void);
104 /* Initialize getl. */
106 getl_initialize (void)
108 ds_create (&getl_include_path,
109 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
110 ds_init (&getl_buf, 256);
114 /* Delete everything from the include path. */
116 getl_clear_include_path (void)
118 ds_clear (&getl_include_path);
121 /* Add to the include path. */
123 getl_add_include_dir (const char *path)
125 if (ds_length (&getl_include_path))
126 ds_putc (&getl_include_path, PATH_DELIMITER);
128 ds_puts (&getl_include_path, path);
131 /* Appends source S to the list of source files. */
133 append_source (struct getl_source *s)
135 s->included_from = s->includes = s->next = NULL;
136 if (last_source == NULL)
139 last_source->next = s;
143 /* Nests source S within the current source file. */
145 include_source (struct getl_source *s)
147 if (last_source == NULL)
151 s->included_from = cur_source;
152 s->includes = s->next = NULL;
154 cur_source->includes = s;
159 /* Creates a source of the given TYPE.
160 Type-specific data must be initialized by the caller. */
161 static struct getl_source *
162 create_source (enum getl_source_type type)
164 struct getl_source *s = xmalloc (sizeof *s);
171 /* Creates a syntax file source with file name FN. */
172 static struct getl_source *
173 create_syntax_file_source (const char *fn)
175 struct getl_source *s = create_source (SYNTAX_FILE);
176 s->fn = xstrdup (fn);
177 s->u.syntax_file = NULL;
181 /* Creates a filter source with the given FILTER and CLOSE
182 functions that receive auxiliary data AUX. */
183 static struct getl_source *
184 create_filter_source (void (*filter) (struct string *, void *aux),
185 void (*close) (void *aux),
188 struct getl_source *s = create_source (FILTER);
189 s->u.filter.filter = filter;
190 s->u.filter.close = close;
191 s->u.filter.aux = aux;
195 /* Creates a function source with the given READ and CLOSE
196 functions that receive auxiliary data AUX. */
197 static struct getl_source *
198 create_function_source (bool (*read) (struct string *line,
199 char **fn, int *ln, void *aux),
200 void (*close) (void *aux),
203 struct getl_source *s = create_source (FUNCTION);
204 s->u.function.read = read;
205 s->u.function.close = close;
206 s->u.function.aux = aux;
210 /* Creates an interactive source with the given FUNCTION. */
211 static struct getl_source *
212 create_interactive_source (bool (*function) (struct string *line,
215 struct getl_source *s = xmalloc (sizeof *s);
218 s->type = INTERACTIVE;
219 s->u.interactive = function;
223 /* Adds FN to the tail end of the list of source files to
226 getl_append_syntax_file (const char *fn)
228 append_source (create_syntax_file_source (fn));
231 /* Inserts the given file with filename FN into the current file after
234 getl_include_syntax_file (const char *fn)
236 if (cur_source != NULL)
238 char *found_fn = fn_search_path (fn, ds_c_str (&getl_include_path),
239 fn_dirname (cur_source->fn));
240 if (found_fn != NULL)
242 include_source (create_syntax_file_source (found_fn));
246 msg (SE, _("Can't find `%s' in include file search path."), fn);
249 getl_append_syntax_file (fn);
252 /* Inserts the given filter into the current file after the
253 current line. Each line read while the filter is in place
254 will be passed through FILTER, which may modify it as
255 necessary. When the filter is closed, CLOSE will be called.
256 AUX will be passed to both functions.
258 The filter cannot itself output any new lines, and it will be
259 closed as soon as any line would be read from it. This means
260 that, for a filter to be useful, another source must be nested
261 inside it with, e.g., getl_include_syntax_file(). */
263 getl_include_filter (void (*filter) (struct string *, void *aux),
264 void (*close) (void *aux),
267 include_source (create_filter_source (filter, close, aux));
270 /* Inserts the given functional source into the current file
271 after the current line. Lines are read by calling READ, which
272 should write the next line in LINE, store the file name and
273 line number of the line in *FN and *LN, and return true. The
274 string stored in *FN will not be freed by getl. When no lines
275 are left, READ should return false.
277 When the source is closed, CLOSE will be called.
279 AUX will be passed to both READ and CLOSE. */
281 getl_include_function (bool (*read) (struct string *line,
282 char **fn, int *ln, void *aux),
283 void (*close) (void *aux),
286 include_source (create_function_source (read, close, aux));
289 /* Adds an interactive source to the end of the list of sources.
290 FUNCTION will be called to obtain a line. It should store the
291 line in LINE. PROMPT is the prompt to be displayed to the
292 user. FUNCTION should return true when a line has been
293 obtained or false at end of file. */
295 getl_append_interactive (bool (*function) (struct string *line,
298 append_source (create_interactive_source (function));
301 /* Closes all sources until an interactive source is
304 getl_abort_noninteractive (void)
306 while (cur_source != NULL && cur_source->type != INTERACTIVE)
310 /* Returns true if the current source is interactive,
313 getl_is_interactive (void)
315 return cur_source != NULL && cur_source->type == INTERACTIVE;
318 /* Closes the current file, whether it be a main file or included
319 file, then moves cur_source to the next file in the chain. */
323 struct getl_source *s;
329 if (s->u.syntax_file && EOF == fn_close (s->fn, s->u.syntax_file))
330 msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
335 if (s->u.filter.close != NULL)
336 s->u.filter.close (s->u.filter.aux);
340 if (s->u.function.close != NULL)
341 s->u.function.close (s->u.function.aux);
348 if (s->included_from != NULL)
350 cur_source = s->included_from;
351 cur_source->includes = NULL;
355 cur_source = s->next;
356 if (cur_source == NULL)
363 /* Puts the current file and line number in *FN and *LN, respectively,
364 or NULL and -1 if none. */
366 getl_location (const char **fn, int *ln)
369 *fn = cur_source ? cur_source->fn : "";
371 *ln = cur_source ? cur_source->ln : -1;
374 /* File locator stack. */
375 static const struct file_locator **file_loc;
376 static int nfile_loc, mfile_loc;
380 getl_uninitialize (void)
382 while (cur_source != NULL)
384 ds_destroy (&getl_buf);
385 ds_destroy (&getl_include_path);
388 nfile_loc = mfile_loc = 0;
393 /* File locator stack functions. */
395 /* Pushes F onto the stack of file locations. */
397 err_push_file_locator (const struct file_locator *f)
399 if (nfile_loc >= mfile_loc)
406 file_loc = xnrealloc (file_loc, mfile_loc, sizeof *file_loc);
409 file_loc[nfile_loc++] = f;
412 /* Pops F off the stack of file locations.
413 Argument F is only used for verification that that is actually the
414 item on top of the stack. */
416 err_pop_file_locator (const struct file_locator *f)
418 assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == f);
422 /* Puts the current file and line number in F, or NULL and -1 if
425 err_location (struct file_locator *f)
428 *f = *file_loc[nfile_loc - 1];
430 getl_location (&f->filename, &f->line_number);
433 /* Reads a line from syntax file source S into LINE.
434 Returns true if successful, false at end of file. */
436 read_syntax_file (struct string *line, struct getl_source *s)
438 /* Open file, if not yet opened. */
439 if (s->u.syntax_file == NULL)
441 msg (VM (1), _("%s: Opening as syntax file."), s->fn);
442 s->u.syntax_file = fn_open (s->fn, "r");
444 if (s->u.syntax_file == NULL)
446 msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
451 /* Read line from file and remove new-line.
452 Skip initial "#! /usr/bin/pspp" line. */
456 if (!ds_gets (line, s->u.syntax_file))
458 if (ferror (s->u.syntax_file))
459 msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
462 ds_chomp (line, '\n');
464 while (s->ln == 1 && !memcmp (ds_c_str (line), "#!", 2));
466 /* Echo to listing file, if configured to do so. */
468 tab_output_text (TAB_LEFT | TAT_FIX, ds_c_str (line));
473 /* Reads a line from source S into LINE.
474 Returns true if successful, false at end of file. */
476 read_line_from_source (struct string *line, struct getl_source *s)
482 return read_syntax_file (line, s);
486 return s->u.function.read (line, &s->fn, &s->ln, s->u.function.aux);
488 return s->u.interactive (line, get_prompt ());
494 /* Reads a single line into LINE.
495 Returns true when a line has been read, false at end of input.
496 If INTERACTIVE is non-null, then when true is returned
497 *INTERACTIVE will be set to true if the line was obtained
498 interactively, false otherwise. */
500 do_read_line (struct string *line, bool *interactive)
502 while (cur_source != NULL)
504 struct getl_source *s = cur_source;
505 if (read_line_from_source (line, s))
507 if (interactive != NULL)
508 *interactive = s->type == INTERACTIVE;
510 while ((s = s->included_from) != NULL)
511 if (s->type == FILTER)
512 s->u.filter.filter (line, s->u.filter.aux);
522 /* Reads a single line into getl_buf.
523 Returns true when a line has been read, false at end of input.
524 If INTERACTIVE is non-null, then when true is returned
525 *INTERACTIVE will be set to true if the line was obtained
526 interactively, false otherwise. */
528 getl_read_line (bool *interactive)
530 return do_read_line (&getl_buf, interactive);
533 /* Current prompts in each style. */
534 static char *prompts[GETL_PROMPT_CNT];
536 /* Current prompting style. */
537 static enum getl_prompt_style current_style;
539 /* Initializes prompts. */
543 prompts[GETL_PROMPT_FIRST] = xstrdup ("PSPP> ");
544 prompts[GETL_PROMPT_LATER] = xstrdup (" > ");
545 prompts[GETL_PROMPT_DATA] = xstrdup ("data> ");
546 current_style = GETL_PROMPT_FIRST;
551 uninit_prompts (void)
555 for (i = 0; i < GETL_PROMPT_CNT; i++)
562 /* Gets the command prompt for the given STYLE. */
564 getl_get_prompt (enum getl_prompt_style style)
566 assert (style < GETL_PROMPT_CNT);
567 return prompts[style];
570 /* Sets the given STYLE's prompt to STRING. */
572 getl_set_prompt (enum getl_prompt_style style, const char *string)
574 assert (style < GETL_PROMPT_CNT);
575 free (prompts[style]);
576 prompts[style] = xstrdup (string);
579 /* Sets STYLE as the current prompt style. */
581 getl_set_prompt_style (enum getl_prompt_style style)
583 assert (style < GETL_PROMPT_CNT);
584 current_style = style;
587 /* Returns the current prompt. */
591 return prompts[current_style];