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., 59 Temple Place - Suite 330, Boston, MA
37 /* Global variables. */
38 struct string getl_buf;
39 struct getl_script *getl_head;
40 struct getl_script *getl_tail;
47 static char *history_file;
49 #if HAVE_READLINE_HISTORY_H
50 #include <readline/history.h>
51 #else /* no readline/history.h */
52 extern void add_history (char *);
53 extern void using_history (void);
54 extern int read_history (char *);
55 extern void stifle_history (int);
56 extern int write_history (char *);
57 #endif /* no readline/history.h */
58 #endif /* -lhistory */
60 extern struct cmd_set cmd;
62 static struct string getl_include_path;
64 /* Number of levels of DO REPEAT structures we're nested inside. If
65 this is greater than zero then DO REPEAT macro substitutions are
67 static int DO_REPEAT_level;
69 static int read_console (void);
71 /* Initialize getline. */
73 getl_initialize (void)
75 ds_create (NULL, &getl_include_path,
76 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
77 ds_init (NULL, &getl_buf, 256);
82 getl_uninitialize (void)
84 #if HAVE_LIBHISTORY && defined (unix)
86 write_history (history_file);
90 /* Returns a string that represents the directory that the syntax file
91 currently being read resides in. If there is no syntax file then
92 returns the OS current working directory. Return value must be
95 getl_get_current_directory (void)
97 return getl_head ? fn_dirname (getl_head->fn) : fn_get_cwd ();
100 /* Delete everything from the include path. */
102 getl_clear_include_path (void)
104 ds_clear (&getl_include_path);
107 /* Add to the include path. */
109 getl_add_include_dir (const char *path)
111 if (ds_length (&getl_include_path))
112 ds_putchar (&getl_include_path, PATH_DELIMITER);
114 ds_concat (&getl_include_path, path);
117 /* Adds FN to the tail end of the list of script files to execute.
118 OPTIONS is the value to stick in the options field of the
119 getl_script struct. If WHERE is zero then the file is added after
120 all other files; otherwise it is added before all other files (this
121 can be done only if parsing has not yet begun). */
123 getl_add_file (const char *fn, int separate, int where)
125 struct getl_script *n = xmalloc (sizeof *n);
129 if (getl_tail == NULL)
130 getl_head = getl_tail = n;
132 getl_tail = getl_tail->next = n;
135 assert (getl_head->f == NULL);
139 n->included_from = n->includes = NULL;
140 n->fn = xstrdup (fn);
143 n->separate = separate;
144 n->first_line = NULL;
147 /* Inserts the given file with filename FN into the current file after
150 getl_include (const char *fn)
152 struct getl_script *n;
156 char *cur_dir = getl_get_current_directory ();
157 real_fn = fn_search_path (fn, ds_value (&getl_include_path), cur_dir);
163 msg (SE, _("Can't find `%s' in include file search path."), fn);
169 getl_add_file (real_fn, 0, 0);
174 n = xmalloc (sizeof *n);
175 n->included_from = getl_head;
176 getl_head = getl_head->includes = n;
183 n->first_line = NULL;
187 /* Add the virtual file FILE to the list of files to be processed.
188 The first_line field in FILE must already have been initialized. */
190 getl_add_virtual_file (struct getl_script *file)
192 if (getl_tail == NULL)
193 getl_head = getl_tail = file;
195 getl_tail = getl_tail->next = file;
196 file->included_from = file->includes = NULL;
198 file->fn = file->first_line->line;
199 file->ln = -file->first_line->len - 1;
202 file->cur_line = NULL;
203 file->remaining_loops = 1;
204 file->loop_index = -1;
208 /* Causes the DO REPEAT virtual file passed in FILE to be included in
209 the current file. The first_line, cur_line, remaining_loops,
210 loop_index, and macros fields in FILE must already have been
213 getl_add_DO_REPEAT_file (struct getl_script *file)
215 /* getl_head == NULL can't happen. */
219 file->included_from = getl_head;
220 getl_head = getl_head->includes = file;
221 file->includes = NULL;
223 assert (file->first_line->len < 0);
224 file->fn = file->first_line->line;
225 file->ln = -file->first_line->len - 1;
230 /* Display a welcoming message. */
235 fputs ("PSPP is free software and you are welcome to distribute copies of "
236 "it\nunder certain conditions; type \"show copying.\" to see the "
237 "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
238 "warranty.\" for details.\n", stdout);
242 /* Reads a single line from the user's terminal. */
245 extern void perform_DO_REPEAT_substitutions (void);
247 /* Reads a single line from the line buffer associated with getl_head.
248 Returns 1 if a line was successfully read or 0 if no more lines are
251 handle_line_buffer (void)
253 struct getl_script *s = getl_head;
255 /* Check that we're not all done. */
258 if (s->cur_line == NULL)
261 if (s->remaining_loops-- == 0)
263 s->cur_line = s->first_line;
266 if (s->cur_line->len < 0)
268 s->ln = -s->cur_line->len - 1;
269 s->fn = s->cur_line->line;
270 s->cur_line = s->cur_line->next;
274 while (s->cur_line == NULL);
276 ds_concat_buffer (&getl_buf, s->cur_line->line, s->cur_line->len);
278 /* Advance pointers. */
279 s->cur_line = s->cur_line->next;
285 /* Reads a single line into getl_buf from the list of files. Will not
286 read from the eof of one file to the beginning of another unless
287 the options field on the new file's getl_script is nonzero. Return
290 getl_read_line (void)
292 getl_mode = GETL_MODE_BATCH;
296 struct getl_script *s = getl_head;
298 ds_clear (&getl_buf);
304 if (!handle_line_buffer ())
309 perform_DO_REPEAT_substitutions ();
310 if (getl_head->print)
311 tab_output_text (TAB_LEFT | TAT_FIX | TAT_PRINTF, "+%s",
312 ds_value (&getl_buf));
318 msg (VM (1), _("%s: Opening as syntax file."), s->fn);
319 s->f = fn_open (s->fn, "r");
323 msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
329 if (!ds_getline (&getl_buf, s->f))
332 msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
336 if (ds_length (&getl_buf) > 0 && ds_end (&getl_buf)[-1] == '\n')
337 ds_truncate (&getl_buf, ds_length (&getl_buf) - 1);
340 tab_output_text (TAB_LEFT | TAT_FIX, ds_value (&getl_buf));
344 /* Allows shebang invocation: `#! /usr/local/bin/pspp'. */
345 if (ds_value (&getl_buf)[0] == '#'
346 && ds_value (&getl_buf)[1] == '!')
352 if (getl_interactive == 0)
355 getl_mode = GETL_MODE_INTERACTIVE;
357 if (getl_welcomed == 0)
360 return read_console ();
363 /* Closes the current file, whether it be a main file or included
364 file, then moves getl_head to the next file in the chain. */
366 getl_close_file (void)
368 struct getl_script *s = getl_head;
372 assert (getl_tail != NULL);
376 struct getl_line_list *cur, *next;
378 s->fn = NULL; /* It will be freed below. */
379 for (cur = s->first_line; cur; cur = next)
389 if (s->f && EOF == fn_close (s->fn, s->f))
390 msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
393 if (s->included_from)
395 getl_head = s->included_from;
396 getl_head->includes = NULL;
401 if (NULL == getl_head)
408 /* PORTME: Adapt to your local system's idea of the terminal. */
411 #if HAVE_READLINE_READLINE_H
412 #include <readline/readline.h>
413 #else /* no readline/readline.h */
414 extern char *readline (char *);
415 #endif /* no readline/readline.h */
423 err_error_count = err_warning_count = 0;
424 err_already_flagged = 0;
430 history_file = tilde_expand (HISTORY_FILE);
433 read_history (history_file);
434 stifle_history (MAX_HISTORY);
436 #endif /* -lhistory */
440 case GETL_PRPT_STANDARD:
441 prompt = get_prompt();
444 case GETL_PRPT_CONTINUATION:
445 prompt = get_cprompt();
449 prompt = get_dprompt();
456 line = readline (prompt);
465 ds_clear (&getl_buf);
466 ds_concat (&getl_buf, line);
470 #else /* no -lreadline */
474 err_error_count = err_warning_count = 0;
475 err_already_flagged = 0;
477 fputs (getl_prompt ? get_cprompt() : get_prompt(), stdout);
478 ds_clear (&getl_buf);
479 if (ds_getline (&getl_buf, stdin))
483 msg (FE, "stdin: fgets(): %s.", strerror (errno));
487 #endif /* no -lreadline */
489 /* Closes all files. */
491 getl_close_all (void)
497 /* Sets the options flag of the current script to 0, thus allowing it
498 to be read in. Returns nonzero if this action was taken, zero
501 getl_perform_delayed_reset (void)
503 if (getl_head && getl_head->separate)
505 getl_head->separate = 0;
506 discard_variables ();
513 /* Puts the current file and line number in *FN and *LN, respectively,
514 or NULL and -1 if none. */
516 getl_location (const char **fn, int *ln)
519 *fn = getl_head ? getl_head->fn : NULL;
521 *ln = getl_head ? getl_head->ln : -1;