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 (&getl_include_path,
76 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
77 ds_init (&getl_buf, 256);
82 getl_uninitialize (void)
85 #if HAVE_LIBHISTORY && defined (unix)
87 write_history (history_file);
89 ds_destroy (&getl_buf);
90 ds_destroy (&getl_include_path);
93 /* Returns a string that represents the directory that the syntax file
94 currently being read resides in. If there is no syntax file then
95 returns the OS current working directory. Return value must be
98 getl_get_current_directory (void)
100 return getl_head ? fn_dirname (getl_head->fn) : fn_get_cwd ();
103 /* Delete everything from the include path. */
105 getl_clear_include_path (void)
107 ds_clear (&getl_include_path);
110 /* Add to the include path. */
112 getl_add_include_dir (const char *path)
114 if (ds_length (&getl_include_path))
115 ds_putc (&getl_include_path, PATH_DELIMITER);
117 ds_puts (&getl_include_path, path);
120 /* Adds FN to the tail end of the list of script files to execute.
121 OPTIONS is the value to stick in the options field of the
122 getl_script struct. If WHERE is zero then the file is added after
123 all other files; otherwise it is added before all other files (this
124 can be done only if parsing has not yet begun). */
126 getl_add_file (const char *fn, int separate, int where)
128 struct getl_script *n = xmalloc (sizeof *n);
132 if (getl_tail == NULL)
133 getl_head = getl_tail = n;
135 getl_tail = getl_tail->next = n;
138 assert (getl_head->f == NULL);
142 n->included_from = n->includes = NULL;
143 n->fn = xstrdup (fn);
146 n->separate = separate;
147 n->first_line = NULL;
150 /* Inserts the given file with filename FN into the current file after
153 getl_include (const char *fn)
155 struct getl_script *n;
159 char *cur_dir = getl_get_current_directory ();
160 real_fn = fn_search_path (fn, ds_c_str (&getl_include_path), cur_dir);
166 msg (SE, _("Can't find `%s' in include file search path."), fn);
172 getl_add_file (real_fn, 0, 0);
177 n = xmalloc (sizeof *n);
178 n->included_from = getl_head;
179 getl_head = getl_head->includes = n;
186 n->first_line = NULL;
190 /* Add the virtual file FILE to the list of files to be processed.
191 The first_line field in FILE must already have been initialized. */
193 getl_add_virtual_file (struct getl_script *file)
195 if (getl_tail == NULL)
196 getl_head = getl_tail = file;
198 getl_tail = getl_tail->next = file;
199 file->included_from = file->includes = NULL;
201 file->fn = file->first_line->line;
202 file->ln = -file->first_line->len - 1;
205 file->cur_line = NULL;
206 file->remaining_loops = 1;
207 file->loop_index = -1;
211 /* Causes the DO REPEAT virtual file passed in FILE to be included in
212 the current file. The first_line, cur_line, remaining_loops,
213 loop_index, and macros fields in FILE must already have been
216 getl_add_DO_REPEAT_file (struct getl_script *file)
218 /* getl_head == NULL can't happen. */
222 file->included_from = getl_head;
223 getl_head = getl_head->includes = file;
224 file->includes = NULL;
226 assert (file->first_line->len < 0);
227 file->fn = file->first_line->line;
228 file->ln = -file->first_line->len - 1;
233 /* Display a welcoming message. */
238 fputs ("PSPP is free software and you are welcome to distribute copies of "
239 "it\nunder certain conditions; type \"show copying.\" to see the "
240 "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
241 "warranty.\" for details.\n", stdout);
245 /* Reads a single line from the user's terminal. */
248 extern void perform_DO_REPEAT_substitutions (void);
250 /* Reads a single line from the line buffer associated with getl_head.
251 Returns 1 if a line was successfully read or 0 if no more lines are
254 handle_line_buffer (void)
256 struct getl_script *s = getl_head;
258 /* Check that we're not all done. */
261 if (s->cur_line == NULL)
264 if (s->remaining_loops-- == 0)
266 s->cur_line = s->first_line;
269 if (s->cur_line->len < 0)
271 s->ln = -s->cur_line->len - 1;
272 s->fn = s->cur_line->line;
273 s->cur_line = s->cur_line->next;
277 while (s->cur_line == NULL);
279 ds_concat (&getl_buf, s->cur_line->line, s->cur_line->len);
281 /* Advance pointers. */
282 s->cur_line = s->cur_line->next;
288 /* Reads a single line into getl_buf from the list of files. Will not
289 read from the eof of one file to the beginning of another unless
290 the options field on the new file's getl_script is nonzero. Return
293 getl_read_line (void)
295 getl_mode = GETL_MODE_BATCH;
299 struct getl_script *s = getl_head;
301 ds_clear (&getl_buf);
307 if (!handle_line_buffer ())
312 perform_DO_REPEAT_substitutions ();
313 if (getl_head->print)
314 tab_output_text (TAB_LEFT | TAT_FIX | TAT_PRINTF, "+%s",
315 ds_c_str (&getl_buf));
321 msg (VM (1), _("%s: Opening as syntax file."), s->fn);
322 s->f = fn_open (s->fn, "r");
326 msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
332 if (!ds_gets (&getl_buf, s->f))
335 msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
339 if (ds_length (&getl_buf) > 0 && ds_end (&getl_buf)[-1] == '\n')
340 ds_truncate (&getl_buf, ds_length (&getl_buf) - 1);
343 tab_output_text (TAB_LEFT | TAT_FIX, ds_c_str (&getl_buf));
347 /* Allows shebang invocation: `#! /usr/local/bin/pspp'. */
348 if (ds_c_str (&getl_buf)[0] == '#'
349 && ds_c_str (&getl_buf)[1] == '!')
355 if (getl_interactive == 0)
358 getl_mode = GETL_MODE_INTERACTIVE;
360 if (getl_welcomed == 0)
363 return read_console ();
366 /* Closes the current file, whether it be a main file or included
367 file, then moves getl_head to the next file in the chain. */
369 getl_close_file (void)
371 struct getl_script *s = getl_head;
375 assert (getl_tail != NULL);
379 struct getl_line_list *cur, *next;
381 s->fn = NULL; /* It will be freed below. */
382 for (cur = s->first_line; cur; cur = next)
392 if (s->f && EOF == fn_close (s->fn, s->f))
393 msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
396 if (s->included_from)
398 getl_head = s->included_from;
399 getl_head->includes = NULL;
404 if (NULL == getl_head)
411 /* PORTME: Adapt to your local system's idea of the terminal. */
414 #if HAVE_READLINE_READLINE_H
415 #include <readline/readline.h>
416 #else /* no readline/readline.h */
417 extern char *readline (char *);
418 #endif /* no readline/readline.h */
426 err_error_count = err_warning_count = 0;
427 err_already_flagged = 0;
433 history_file = tilde_expand (HISTORY_FILE);
436 read_history (history_file);
437 stifle_history (MAX_HISTORY);
439 #endif /* -lhistory */
443 case GETL_PRPT_STANDARD:
444 prompt = get_prompt();
447 case GETL_PRPT_CONTINUATION:
448 prompt = get_cprompt();
452 prompt = get_dprompt();
460 line = readline (prompt);
469 ds_clear (&getl_buf);
470 ds_puts (&getl_buf, line);
474 #else /* no -lreadline */
478 err_error_count = err_warning_count = 0;
479 err_already_flagged = 0;
481 fputs (getl_prompt ? get_cprompt() : get_prompt(), stdout);
482 ds_clear (&getl_buf);
483 if (ds_gets (&getl_buf, stdin))
487 msg (FE, "stdin: fgets(): %s.", strerror (errno));
491 #endif /* no -lreadline */
493 /* Closes all files. */
495 getl_close_all (void)
501 /* Sets the options flag of the current script to 0, thus allowing it
502 to be read in. Returns nonzero if this action was taken, zero
505 getl_perform_delayed_reset (void)
507 if (getl_head && getl_head->separate)
509 getl_head->separate = 0;
510 discard_variables ();
517 /* Puts the current file and line number in *FN and *LN, respectively,
518 or NULL and -1 if none. */
520 getl_location (const char **fn, int *ln)
523 *fn = getl_head ? getl_head->fn : NULL;
525 *ln = getl_head ? getl_head->ln : -1;