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
36 /* Global variables. */
37 struct string getl_buf;
38 struct getl_script *getl_head;
39 struct getl_script *getl_tail;
46 static char *history_file;
48 #if HAVE_READLINE_HISTORY_H
49 #include <readline/history.h>
50 #else /* no readline/history.h */
51 extern void add_history (char *);
52 extern void using_history (void);
53 extern int read_history (char *);
54 extern void stifle_history (int);
55 extern int write_history (char *);
56 #endif /* no readline/history.h */
57 #endif /* -lhistory */
59 static struct string getl_include_path;
61 /* Number of levels of DO REPEAT structures we're nested inside. If
62 this is greater than zero then DO REPEAT macro substitutions are
64 static int DO_REPEAT_level;
66 static int read_console (void);
68 /* Initialize getline. */
70 getl_initialize (void)
72 ds_create (NULL, &getl_include_path,
73 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
74 ds_init (NULL, &getl_buf, 256);
79 getl_uninitialize (void)
81 #if HAVE_LIBHISTORY && unix
83 write_history (history_file);
87 /* Returns a string that represents the directory that the syntax file
88 currently being read resides in. If there is no syntax file then
89 returns the OS current working directory. Return value must be
92 getl_get_current_directory (void)
94 return getl_head ? fn_dirname (getl_head->fn) : fn_get_cwd ();
97 /* Delete everything from the include path. */
99 getl_clear_include_path (void)
101 ds_clear (&getl_include_path);
104 /* Add to the include path. */
106 getl_add_include_dir (const char *path)
108 if (ds_length (&getl_include_path))
109 ds_putchar (&getl_include_path, PATH_DELIMITER);
111 ds_concat (&getl_include_path, path);
114 /* Adds FN to the tail end of the list of script files to execute.
115 OPTIONS is the value to stick in the options field of the
116 getl_script struct. If WHERE is zero then the file is added after
117 all other files; otherwise it is added before all other files (this
118 can be done only if parsing has not yet begun). */
120 getl_add_file (const char *fn, int separate, int where)
122 struct getl_script *n = xmalloc (sizeof *n);
126 if (getl_tail == NULL)
127 getl_head = getl_tail = n;
129 getl_tail = getl_tail->next = n;
132 assert (getl_head->f == NULL);
136 n->included_from = n->includes = NULL;
137 n->fn = xstrdup (fn);
140 n->separate = separate;
141 n->first_line = NULL;
144 /* Inserts the given file with filename FN into the current file after
147 getl_include (const char *fn)
149 struct getl_script *n;
153 char *cur_dir = getl_get_current_directory ();
154 real_fn = fn_search_path (fn, ds_value (&getl_include_path), cur_dir);
160 msg (SE, _("Can't find `%s' in include file search path."), fn);
166 getl_add_file (real_fn, 0, 0);
171 n = xmalloc (sizeof *n);
172 n->included_from = getl_head;
173 getl_head = getl_head->includes = n;
180 n->first_line = NULL;
184 /* Add the virtual file FILE to the list of files to be processed.
185 The first_line field in FILE must already have been initialized. */
187 getl_add_virtual_file (struct getl_script *file)
189 if (getl_tail == NULL)
190 getl_head = getl_tail = file;
192 getl_tail = getl_tail->next = file;
193 file->included_from = file->includes = NULL;
195 file->fn = file->first_line->line;
196 file->ln = -file->first_line->len - 1;
199 file->cur_line = NULL;
200 file->remaining_loops = 1;
201 file->loop_index = -1;
205 /* Causes the DO REPEAT virtual file passed in FILE to be included in
206 the current file. The first_line, cur_line, remaining_loops,
207 loop_index, and macros fields in FILE must already have been
210 getl_add_DO_REPEAT_file (struct getl_script *file)
212 /* getl_head == NULL can't happen. */
216 file->included_from = getl_head;
217 getl_head = getl_head->includes = file;
218 file->includes = NULL;
220 assert (file->first_line->len < 0);
221 file->fn = file->first_line->line;
222 file->ln = -file->first_line->len - 1;
227 /* Display a welcoming message. */
232 fputs ("PSPP is free software and you are welcome to distribute copies of"
233 "it\nunder certain conditions; type \"show copying.\" to see the "
234 "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
235 "warranty.\" for details.\n", stdout);
239 /* Reads a single line from the user's terminal. */
242 extern void perform_DO_REPEAT_substitutions (void);
244 /* Reads a single line from the line buffer associated with getl_head.
245 Returns 1 if a line was successfully read or 0 if no more lines are
248 handle_line_buffer (void)
250 struct getl_script *s = getl_head;
252 /* Check that we're not all done. */
255 if (s->cur_line == NULL)
258 if (s->remaining_loops-- == 0)
260 s->cur_line = s->first_line;
263 if (s->cur_line->len < 0)
265 s->ln = -s->cur_line->len - 1;
266 s->fn = s->cur_line->line;
267 s->cur_line = s->cur_line->next;
271 while (s->cur_line == NULL);
273 ds_concat_buffer (&getl_buf, s->cur_line->line, s->cur_line->len);
275 /* Advance pointers. */
276 s->cur_line = s->cur_line->next;
282 /* Reads a single line into getl_buf from the list of files. Will not
283 read from the eof of one file to the beginning of another unless
284 the options field on the new file's getl_script is nonzero. Return
287 getl_read_line (void)
289 getl_mode = GETL_MODE_BATCH;
293 struct getl_script *s = getl_head;
295 ds_clear (&getl_buf);
301 if (!handle_line_buffer ())
306 perform_DO_REPEAT_substitutions ();
307 if (getl_head->print)
308 tab_output_text (TAB_LEFT | TAT_FIX | TAT_PRINTF, "+%s",
309 ds_value (&getl_buf));
315 msg (VM (1), _("%s: Opening as syntax file."), s->fn);
316 s->f = fn_open (s->fn, "r");
320 msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
326 if (!ds_getline (&getl_buf, s->f))
329 msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
333 if (ds_length (&getl_buf) > 0 && ds_end (&getl_buf)[-1] == '\n')
334 ds_truncate (&getl_buf, ds_length (&getl_buf) - 1);
337 tab_output_text (TAB_LEFT | TAT_FIX, ds_value (&getl_buf));
341 /* Allows shebang invocation: `#! /usr/local/bin/pspp'. */
342 if (ds_value (&getl_buf)[0] == '#'
343 && ds_value (&getl_buf)[1] == '!')
349 if (getl_interactive == 0)
352 getl_mode = GETL_MODE_INTERACTIVE;
354 if (getl_welcomed == 0)
357 return read_console ();
360 /* Closes the current file, whether it be a main file or included
361 file, then moves getl_head to the next file in the chain. */
363 getl_close_file (void)
365 struct getl_script *s = getl_head;
369 assert (getl_tail != NULL);
373 struct getl_line_list *cur, *next;
375 s->fn = NULL; /* It will be freed below. */
376 for (cur = s->first_line; cur; cur = next)
386 if (s->f && EOF == fn_close (s->fn, s->f))
387 msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
390 if (s->included_from)
392 getl_head = s->included_from;
393 getl_head->includes = NULL;
398 if (NULL == getl_head)
405 /* PORTME: Adapt to your local system's idea of the terminal. */
408 #if HAVE_READLINE_READLINE_H
409 #include <readline/readline.h>
410 #else /* no readline/readline.h */
411 extern char *readline (char *);
412 #endif /* no readline/readline.h */
420 err_error_count = err_warning_count = 0;
421 err_already_flagged = 0;
427 history_file = tilde_expand (HISTORY_FILE);
430 read_history (history_file);
431 stifle_history (MAX_HISTORY);
433 #endif /* -lhistory */
437 case GETL_PRPT_STANDARD:
441 case GETL_PRPT_CONTINUATION:
442 prompt = set_cprompt;
446 prompt = set_dprompt;
453 line = readline (prompt);
462 ds_clear (&getl_buf);
463 ds_concat (&getl_buf, line);
467 #else /* no -lreadline */
471 err_error_count = err_warning_count = 0;
472 err_already_flagged = 0;
474 fputs (getl_prompt ? set_cprompt : set_prompt, stdout);
475 ds_clear (&getl_buf);
476 if (ds_getline (&getl_buf, stdin))
480 msg (FE, "stdin: fgets(): %s.", strerror (errno));
484 #endif /* no -lreadline */
486 /* Closes all files. */
488 getl_close_all (void)
494 /* Sets the options flag of the current script to 0, thus allowing it
495 to be read in. Returns nonzero if this action was taken, zero
498 getl_perform_delayed_reset (void)
500 if (getl_head && getl_head->separate)
502 getl_head->separate = 0;
503 discard_variables ();
510 /* Puts the current file and line number in *FN and *LN, respectively,
511 or NULL and -1 if none. */
513 getl_location (const char **fn, int *ln)
516 *fn = getl_head ? getl_head->fn : NULL;
518 *ln = getl_head ? getl_head->ln : -1;