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)
84 #if HAVE_LIBHISTORY && defined (unix)
86 write_history (history_file);
88 ds_destroy (&getl_buf);
89 ds_destroy (&getl_include_path);
92 /* Returns a string that represents the directory that the syntax file
93 currently being read resides in. If there is no syntax file then
94 returns the OS current working directory. Return value must be
97 getl_get_current_directory (void)
99 return getl_head ? fn_dirname (getl_head->fn) : fn_get_cwd ();
102 /* Delete everything from the include path. */
104 getl_clear_include_path (void)
106 ds_clear (&getl_include_path);
109 /* Add to the include path. */
111 getl_add_include_dir (const char *path)
113 if (ds_length (&getl_include_path))
114 ds_putc (&getl_include_path, PATH_DELIMITER);
116 ds_puts (&getl_include_path, path);
119 /* Adds FN to the tail end of the list of script files to execute.
120 OPTIONS is the value to stick in the options field of the
121 getl_script struct. If WHERE is zero then the file is added after
122 all other files; otherwise it is added before all other files (this
123 can be done only if parsing has not yet begun). */
125 getl_add_file (const char *fn, int separate, int where)
127 struct getl_script *n = xmalloc (sizeof *n);
131 if (getl_tail == NULL)
132 getl_head = getl_tail = n;
134 getl_tail = getl_tail->next = n;
137 assert (getl_head->f == NULL);
141 n->included_from = n->includes = NULL;
142 n->fn = xstrdup (fn);
145 n->separate = separate;
146 n->first_line = NULL;
149 /* Inserts the given file with filename FN into the current file after
152 getl_include (const char *fn)
154 struct getl_script *n;
158 char *cur_dir = getl_get_current_directory ();
159 real_fn = fn_search_path (fn, ds_c_str (&getl_include_path), cur_dir);
165 msg (SE, _("Can't find `%s' in include file search path."), fn);
171 getl_add_file (real_fn, 0, 0);
176 n = xmalloc (sizeof *n);
177 n->included_from = getl_head;
178 getl_head = getl_head->includes = n;
185 n->first_line = NULL;
189 /* Add the virtual file FILE to the list of files to be processed.
190 The first_line field in FILE must already have been initialized. */
192 getl_add_virtual_file (struct getl_script *file)
194 if (getl_tail == NULL)
195 getl_head = getl_tail = file;
197 getl_tail = getl_tail->next = file;
198 file->included_from = file->includes = NULL;
200 file->fn = file->first_line->line;
201 file->ln = -file->first_line->len - 1;
204 file->cur_line = NULL;
205 file->remaining_loops = 1;
206 file->loop_index = -1;
210 /* Causes the DO REPEAT virtual file passed in FILE to be included in
211 the current file. The first_line, cur_line, remaining_loops,
212 loop_index, and macros fields in FILE must already have been
215 getl_add_DO_REPEAT_file (struct getl_script *file)
217 /* getl_head == NULL can't happen. */
221 file->included_from = getl_head;
222 getl_head = getl_head->includes = file;
223 file->includes = NULL;
225 assert (file->first_line->len < 0);
226 file->fn = file->first_line->line;
227 file->ln = -file->first_line->len - 1;
232 /* Display a welcoming message. */
237 fputs ("PSPP is free software and you are welcome to distribute copies of "
238 "it\nunder certain conditions; type \"show copying.\" to see the "
239 "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
240 "warranty.\" for details.\n", stdout);
244 /* Reads a single line from the user's terminal. */
247 extern void perform_DO_REPEAT_substitutions (void);
249 /* Reads a single line from the line buffer associated with getl_head.
250 Returns 1 if a line was successfully read or 0 if no more lines are
253 handle_line_buffer (void)
255 struct getl_script *s = getl_head;
257 /* Check that we're not all done. */
260 if (s->cur_line == NULL)
263 if (s->remaining_loops-- == 0)
265 s->cur_line = s->first_line;
268 if (s->cur_line->len < 0)
270 s->ln = -s->cur_line->len - 1;
271 s->fn = s->cur_line->line;
272 s->cur_line = s->cur_line->next;
276 while (s->cur_line == NULL);
278 ds_concat (&getl_buf, s->cur_line->line, s->cur_line->len);
280 /* Advance pointers. */
281 s->cur_line = s->cur_line->next;
287 /* Reads a single line into getl_buf from the list of files. Will not
288 read from the eof of one file to the beginning of another unless
289 the options field on the new file's getl_script is nonzero. Return
292 getl_read_line (void)
294 getl_mode = GETL_MODE_BATCH;
298 struct getl_script *s = getl_head;
300 ds_clear (&getl_buf);
306 if (!handle_line_buffer ())
311 perform_DO_REPEAT_substitutions ();
312 if (getl_head->print)
313 tab_output_text (TAB_LEFT | TAT_FIX | TAT_PRINTF, "+%s",
314 ds_c_str (&getl_buf));
320 msg (VM (1), _("%s: Opening as syntax file."), s->fn);
321 s->f = fn_open (s->fn, "r");
325 msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
331 if (!ds_gets (&getl_buf, s->f))
334 msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
338 if (ds_length (&getl_buf) > 0 && ds_end (&getl_buf)[-1] == '\n')
339 ds_truncate (&getl_buf, ds_length (&getl_buf) - 1);
342 tab_output_text (TAB_LEFT | TAT_FIX, ds_c_str (&getl_buf));
346 /* Allows shebang invocation: `#! /usr/local/bin/pspp'. */
347 if (ds_c_str (&getl_buf)[0] == '#'
348 && ds_c_str (&getl_buf)[1] == '!')
354 if (getl_interactive == 0)
357 getl_mode = GETL_MODE_INTERACTIVE;
359 if (getl_welcomed == 0)
362 return read_console ();
365 /* Closes the current file, whether it be a main file or included
366 file, then moves getl_head to the next file in the chain. */
368 getl_close_file (void)
370 struct getl_script *s = getl_head;
374 assert (getl_tail != NULL);
378 struct getl_line_list *cur, *next;
380 s->fn = NULL; /* It will be freed below. */
381 for (cur = s->first_line; cur; cur = next)
391 if (s->f && EOF == fn_close (s->fn, s->f))
392 msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
395 if (s->included_from)
397 getl_head = s->included_from;
398 getl_head->includes = NULL;
403 if (NULL == getl_head)
410 /* PORTME: Adapt to your local system's idea of the terminal. */
413 #if HAVE_READLINE_READLINE_H
414 #include <readline/readline.h>
415 #else /* no readline/readline.h */
416 extern char *readline (char *);
417 #endif /* no readline/readline.h */
425 err_error_count = err_warning_count = 0;
426 err_already_flagged = 0;
432 history_file = tilde_expand (HISTORY_FILE);
435 read_history (history_file);
436 stifle_history (MAX_HISTORY);
438 #endif /* -lhistory */
442 case GETL_PRPT_STANDARD:
443 prompt = get_prompt();
446 case GETL_PRPT_CONTINUATION:
447 prompt = get_cprompt();
451 prompt = get_dprompt();
459 line = readline (prompt);
468 ds_clear (&getl_buf);
469 ds_puts (&getl_buf, line);
473 #else /* no -lreadline */
477 err_error_count = err_warning_count = 0;
478 err_already_flagged = 0;
480 fputs (getl_prompt ? get_cprompt() : get_prompt(), stdout);
481 ds_clear (&getl_buf);
482 if (ds_gets (&getl_buf, stdin))
486 msg (FE, "stdin: fgets(): %s.", strerror (errno));
490 #endif /* no -lreadline */
492 /* Closes all files. */
494 getl_close_all (void)
500 /* Sets the options flag of the current script to 0, thus allowing it
501 to be read in. Returns nonzero if this action was taken, zero
504 getl_perform_delayed_reset (void)
506 if (getl_head && getl_head->separate)
508 getl_head->separate = 0;
509 discard_variables ();
516 /* Puts the current file and line number in *FN and *LN, respectively,
517 or NULL and -1 if none. */
519 getl_location (const char **fn, int *ln)
522 *fn = getl_head ? getl_head->fn : NULL;
524 *ln = getl_head ? getl_head->ln : -1;