Clean up file handle code in preparation to add temporary file
[pspp] / src / main.c
index e25991862f7301b2e90e2bf5df0fc84093f648c4..d52741d1bd8605c35c73daf67f09fa541d933d3c 100644 (file)
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
 
 #include <config.h>
-#include <assert.h>
+#include "main.h"
+#include <gsl/gsl_errno.h>
+#include <signal.h>
 #include <stdio.h>
+#include "cmdline.h"
 #include "command.h"
+#include "dictionary.h"
 #include "error.h"
-#include "getline.h"
+#include "file-handle-def.h"
+#include "filename.h"
+#include "getl.h"
+#include "glob.h"
 #include "lexer.h"
 #include "output.h"
+#include "progname.h"
+#include "random.h"
+#include "readln.h"
+#include "settings.h"
+#include "var.h"
+#include "version.h"
+
+#if HAVE_FPU_CONTROL_H
+#include <fpu_control.h>
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#if HAVE_FENV_H
+#include <fenv.h>
+#endif
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 
 #include <stdlib.h>
 
-#undef DEBUGGING
-/*#define DEBUGGING 1*/
 #include "debug-print.h"
 
-static void parse_script (void) __attribute__ ((noreturn));
+static void i18n_init (void);
+static void fpu_init (void);
 static void handle_error (int code);
 static int execute_command (void);
 
-/* argv[0] with stripped leading directories. */
-char *pgmname;
-
 /* Whether FINISH. has been executed. */
 int finished;
 
-/* The current date in the form DD MMM YYYY. */
-char curdate[12];
+/* If a segfault happens, issue a message to that effect and halt */
+void bug_handler(int sig);
+
+/* Handle quit/term/int signals */
+void interrupt_handler(int sig);
 
 /* Whether we're dropping down to interactive mode immediately because
    we hit end-of-file unexpectedly (or whatever). */
@@ -53,41 +80,71 @@ int start_interactive;
 int
 main (int argc, char **argv)
 {
-  void init_glob (int, char **);       /* Exported by glob.c. */
-  void parse_command_line (int, char **);      /* Exported by cmdline.c */
+  signal (SIGSEGV, bug_handler);
+  signal (SIGFPE, bug_handler);
+  signal (SIGINT, interrupt_handler);
+
+  set_program_name ("pspp");
+  i18n_init ();
+  fpu_init ();
+  gsl_set_error_handler_off ();
+
+  outp_init ();
+  fn_init ();
+  fh_init ();
+  getl_initialize ();
+  readln_initialize ();
+  settings_init ();
+  random_init ();
+
+  default_dict = dict_create ();
 
-  /* Initialization. */
-  if (!outp_init ())
-    err_hcf (0);
-  init_glob (argc, argv);
   parse_command_line (argc, argv);
-  if (!outp_read_devices ())
-    msg (FE, _("Error initializing output drivers."));
+  outp_read_devices ();
 
   lex_init ();
-  cmd_init ();
-
-  /* Execution. */
-  parse_script ();
-}
 
-/* Parses the entire script. */
-static void
-parse_script (void)
-{
   while (!finished)
     {
       err_check_count ();
       handle_error (execute_command ());
     }
 
-  err_hcf (1);
+  terminate (err_error_count == 0);
+  abort ();
+}
+
+/* Terminate PSPP.  SUCCESS should be true to exit successfully,
+   false to exit as a failure.  */
+void
+terminate (bool success)
+{
+  static bool terminating = false;
+  if (terminating)
+    return;
+  terminating = true;
+
+  err_done ();
+  outp_done ();
+
+  cancel_transformations ();
+  dict_destroy (default_dict);
+
+  random_done ();
+  settings_done ();
+  fh_done ();
+  lex_done ();
+  getl_uninitialize ();
+
+  exit (success ? EXIT_SUCCESS : EXIT_FAILURE);
 }
 
 /* Parse and execute a command, returning its return code. */
 static int
 execute_command (void)
 {
+  int result;
+  
   /* Read the command's first token.
      We may hit end of file.
      If so, give the line reader a chance to proceed to the next file.
@@ -100,13 +157,30 @@ execute_command (void)
       if (token != T_STOP)
        break;
 
-      if (!getl_perform_delayed_reset ())
-       err_hcf (1);
+      /* Sets the options flag of the current script to 0, thus allowing it
+        to be read in.  Returns nonzero if this action was taken, zero
+        otherwise. */
+      if (getl_head && getl_head->separate)
+       {
+         getl_head->separate = 0;
+         discard_variables ();
+         lex_reset_eof ();
+       }
+      else
+       terminate (err_error_count == 0);
     }
 
   /* Parse the command. */
   getl_prompt = GETL_PRPT_CONTINUATION;
-  return cmd_parse ();
+  result =  cmd_parse ();
+  /* Unset the /ALGORITHM subcommand if it was used */
+  unset_cmd_algorithm ();
+
+  /* Clear any auxiliary data from the dictionary. */
+  dict_clear_aux (default_dict);
+
+  return result;
 }
 
 /* Print an error message corresponding to the command return code
@@ -143,12 +217,64 @@ handle_error (int code)
       assert (0);
     }
 
-  if (getl_reading_script)
+  if (getl_reading_script())
     {
       err_break ();
       while (token != T_STOP && token != '.')
        lex_get ();
     }
-  else
-    lex_discard_line ();
+  else 
+    {
+      msg (SW, _("The rest of this command has been discarded."));
+      lex_discard_line (); 
+    }
+}
+\f
+static void
+i18n_init (void) 
+{
+#if ENABLE_NLS
+#if HAVE_LC_MESSAGES
+  setlocale (LC_MESSAGES, "");
+#endif
+  setlocale (LC_MONETARY, "");
+  bindtextdomain (PACKAGE, locale_dir);
+  textdomain (PACKAGE);
+#endif /* ENABLE_NLS */
+}
+
+static void
+fpu_init (void) 
+{
+#if HAVE_FEHOLDEXCEPT
+  fenv_t foo;
+  feholdexcept (&foo);
+#elif HAVE___SETFPUCW && defined(_FPU_IEEE)
+  __setfpucw (_FPU_IEEE);
+#endif
+}
+
+/* If a segfault happens, issue a message to that effect and halt */
+void 
+bug_handler(int sig)
+{
+  switch (sig) 
+    {
+    case SIGFPE:
+      request_bug_report_and_abort("Floating Point Exception");
+      break;
+    case SIGSEGV:
+      request_bug_report_and_abort("Segmentation Violation");
+      break;
+    default:
+      request_bug_report_and_abort("");
+      break;
+    }
+}
+
+
+void 
+interrupt_handler(int sig UNUSED)
+{
+  terminate (false);
 }