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 static struct string getl_include_path;
62 /* Number of levels of DO REPEAT structures we're nested inside. If
63 this is greater than zero then DO REPEAT macro substitutions are
65 static int DO_REPEAT_level;
67 static int read_console (void);
69 /* Initialize getline. */
71 getl_initialize (void)
73 ds_create (NULL, &getl_include_path,
74 fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
75 ds_init (NULL, &getl_buf, 256);
80 getl_uninitialize (void)
82 #if HAVE_LIBHISTORY && defined (unix)
84 write_history (history_file);
88 /* Returns a string that represents the directory that the syntax file
89 currently being read resides in. If there is no syntax file then
90 returns the OS current working directory. Return value must be
93 getl_get_current_directory (void)
95 return getl_head ? fn_dirname (getl_head->fn) : fn_get_cwd ();
98 /* Delete everything from the include path. */
100 getl_clear_include_path (void)
102 ds_clear (&getl_include_path);
105 /* Add to the include path. */
107 getl_add_include_dir (const char *path)
109 if (ds_length (&getl_include_path))
110 ds_putchar (&getl_include_path, PATH_DELIMITER);
112 ds_concat (&getl_include_path, path);
115 /* Adds FN to the tail end of the list of script files to execute.
116 OPTIONS is the value to stick in the options field of the
117 getl_script struct. If WHERE is zero then the file is added after
118 all other files; otherwise it is added before all other files (this
119 can be done only if parsing has not yet begun). */
121 getl_add_file (const char *fn, int separate, int where)
123 struct getl_script *n = xmalloc (sizeof *n);
127 if (getl_tail == NULL)
128 getl_head = getl_tail = n;
130 getl_tail = getl_tail->next = n;
133 assert (getl_head->f == NULL);
137 n->included_from = n->includes = NULL;
138 n->fn = xstrdup (fn);
141 n->separate = separate;
142 n->first_line = NULL;
145 /* Inserts the given file with filename FN into the current file after
148 getl_include (const char *fn)
150 struct getl_script *n;
154 char *cur_dir = getl_get_current_directory ();
155 real_fn = fn_search_path (fn, ds_value (&getl_include_path), cur_dir);
161 msg (SE, _("Can't find `%s' in include file search path."), fn);
167 getl_add_file (real_fn, 0, 0);
172 n = xmalloc (sizeof *n);
173 n->included_from = getl_head;
174 getl_head = getl_head->includes = n;
181 n->first_line = NULL;
185 /* Add the virtual file FILE to the list of files to be processed.
186 The first_line field in FILE must already have been initialized. */
188 getl_add_virtual_file (struct getl_script *file)
190 if (getl_tail == NULL)
191 getl_head = getl_tail = file;
193 getl_tail = getl_tail->next = file;
194 file->included_from = file->includes = NULL;
196 file->fn = file->first_line->line;
197 file->ln = -file->first_line->len - 1;
200 file->cur_line = NULL;
201 file->remaining_loops = 1;
202 file->loop_index = -1;
206 /* Causes the DO REPEAT virtual file passed in FILE to be included in
207 the current file. The first_line, cur_line, remaining_loops,
208 loop_index, and macros fields in FILE must already have been
211 getl_add_DO_REPEAT_file (struct getl_script *file)
213 /* getl_head == NULL can't happen. */
217 file->included_from = getl_head;
218 getl_head = getl_head->includes = file;
219 file->includes = NULL;
221 assert (file->first_line->len < 0);
222 file->fn = file->first_line->line;
223 file->ln = -file->first_line->len - 1;
228 /* Display a welcoming message. */
233 fputs ("PSPP is free software and you are welcome to distribute copies of "
234 "it\nunder certain conditions; type \"show copying.\" to see the "
235 "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
236 "warranty.\" for details.\n", stdout);
240 /* Reads a single line from the user's terminal. */
243 extern void perform_DO_REPEAT_substitutions (void);
245 /* Reads a single line from the line buffer associated with getl_head.
246 Returns 1 if a line was successfully read or 0 if no more lines are
249 handle_line_buffer (void)
251 struct getl_script *s = getl_head;
253 /* Check that we're not all done. */
256 if (s->cur_line == NULL)
259 if (s->remaining_loops-- == 0)
261 s->cur_line = s->first_line;
264 if (s->cur_line->len < 0)
266 s->ln = -s->cur_line->len - 1;
267 s->fn = s->cur_line->line;
268 s->cur_line = s->cur_line->next;
272 while (s->cur_line == NULL);
274 ds_concat_buffer (&getl_buf, s->cur_line->line, s->cur_line->len);
276 /* Advance pointers. */
277 s->cur_line = s->cur_line->next;
283 /* Reads a single line into getl_buf from the list of files. Will not
284 read from the eof of one file to the beginning of another unless
285 the options field on the new file's getl_script is nonzero. Return
288 getl_read_line (void)
290 getl_mode = GETL_MODE_BATCH;
294 struct getl_script *s = getl_head;
296 ds_clear (&getl_buf);
302 if (!handle_line_buffer ())
307 perform_DO_REPEAT_substitutions ();
308 if (getl_head->print)
309 tab_output_text (TAB_LEFT | TAT_FIX | TAT_PRINTF, "+%s",
310 ds_value (&getl_buf));
316 msg (VM (1), _("%s: Opening as syntax file."), s->fn);
317 s->f = fn_open (s->fn, "r");
321 msg (ME, _("Opening `%s': %s."), s->fn, strerror (errno));
327 if (!ds_getline (&getl_buf, s->f))
330 msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
334 if (ds_length (&getl_buf) > 0 && ds_end (&getl_buf)[-1] == '\n')
335 ds_truncate (&getl_buf, ds_length (&getl_buf) - 1);
338 tab_output_text (TAB_LEFT | TAT_FIX, ds_value (&getl_buf));
342 /* Allows shebang invocation: `#! /usr/local/bin/pspp'. */
343 if (ds_value (&getl_buf)[0] == '#'
344 && ds_value (&getl_buf)[1] == '!')
350 if (getl_interactive == 0)
353 getl_mode = GETL_MODE_INTERACTIVE;
355 if (getl_welcomed == 0)
358 return read_console ();
361 /* Closes the current file, whether it be a main file or included
362 file, then moves getl_head to the next file in the chain. */
364 getl_close_file (void)
366 struct getl_script *s = getl_head;
370 assert (getl_tail != NULL);
374 struct getl_line_list *cur, *next;
376 s->fn = NULL; /* It will be freed below. */
377 for (cur = s->first_line; cur; cur = next)
387 if (s->f && EOF == fn_close (s->fn, s->f))
388 msg (MW, _("Closing `%s': %s."), s->fn, strerror (errno));
391 if (s->included_from)
393 getl_head = s->included_from;
394 getl_head->includes = NULL;
399 if (NULL == getl_head)
406 /* PORTME: Adapt to your local system's idea of the terminal. */
409 #if HAVE_READLINE_READLINE_H
410 #include <readline/readline.h>
411 #else /* no readline/readline.h */
412 extern char *readline (char *);
413 #endif /* no readline/readline.h */
421 err_error_count = err_warning_count = 0;
422 err_already_flagged = 0;
428 history_file = tilde_expand (HISTORY_FILE);
431 read_history (history_file);
432 stifle_history (MAX_HISTORY);
434 #endif /* -lhistory */
438 case GETL_PRPT_STANDARD:
442 case GETL_PRPT_CONTINUATION:
443 prompt = set_cprompt;
447 prompt = set_dprompt;
454 line = readline (prompt);
463 ds_clear (&getl_buf);
464 ds_concat (&getl_buf, line);
468 #else /* no -lreadline */
472 err_error_count = err_warning_count = 0;
473 err_already_flagged = 0;
475 fputs (getl_prompt ? set_cprompt : set_prompt, stdout);
476 ds_clear (&getl_buf);
477 if (ds_getline (&getl_buf, stdin))
481 msg (FE, "stdin: fgets(): %s.", strerror (errno));
485 #endif /* no -lreadline */
487 /* Closes all files. */
489 getl_close_all (void)
495 /* Sets the options flag of the current script to 0, thus allowing it
496 to be read in. Returns nonzero if this action was taken, zero
499 getl_perform_delayed_reset (void)
501 if (getl_head && getl_head->separate)
503 getl_head->separate = 0;
504 discard_variables ();
511 /* Puts the current file and line number in *FN and *LN, respectively,
512 or NULL and -1 if none. */
514 getl_location (const char **fn, int *ln)
517 *fn = getl_head ? getl_head->fn : NULL;
519 *ln = getl_head ? getl_head->ln : -1;