output: Make errors, warnings, and notes into a new "message_item".
authorBen Pfaff <blp@gnu.org>
Sun, 7 Feb 2010 17:42:53 +0000 (09:42 -0800)
committerBen Pfaff <blp@gnu.org>
Sun, 7 Feb 2010 20:46:12 +0000 (12:46 -0800)
This lets us move the terminal UI's support for writing errors to a file
or to stdout into a new "msglog" output driver, and to convert journaling
from a special case to an output driver of its own.

28 files changed:
src/language/command.c
src/libpspp/message.c
src/libpspp/message.h
src/output/ascii.c
src/output/automake.mk
src/output/cairo.c
src/output/csv.c
src/output/driver.c
src/output/html.c
src/output/journal.c
src/output/journal.h
src/output/message-item.c [new file with mode: 0644]
src/output/message-item.h [new file with mode: 0644]
src/output/msglog.c [new file with mode: 0644]
src/output/msglog.h [new file with mode: 0644]
src/output/odt.c
src/output/output-item.h
src/ui/gui/automake.mk
src/ui/gui/message-dialog.c [deleted file]
src/ui/gui/message-dialog.h [deleted file]
src/ui/gui/message-dialog.ui [deleted file]
src/ui/gui/psppire-dict.c
src/ui/gui/psppire.c
src/ui/terminal/main.c
src/ui/terminal/msg-ui.c
src/ui/terminal/msg-ui.h
src/ui/terminal/read-line.c
src/ui/terminal/terminal-opts.c

index 803b5398888dec3c739c748afa8c13059d272ec3..448fae7ea803463f11a54edbec50a23c816875a4 100644 (file)
@@ -224,9 +224,7 @@ do_parse_command (struct lexer *lexer,
   else
     {
       /* Execute command. */
-      msg_set_command_name (command->name);
       result = command->function (lexer, ds);
-      msg_set_command_name (NULL);
     }
 
   assert (cmd_result_is_valid (result));
index b3025156ef0dd33703068e03b1847316a903eecb..c227a60368a0ff725dacc9baba4e00bf916cf37d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include <string.h>
 #include <unistd.h>
 
+#include <libpspp/str.h>
 #include <libpspp/version.h>
 
-#include "progname.h"
-#include "xalloc.h"
-#include "xvasprintf.h"
+#include "gl/progname.h"
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
 
-/* Current command name as set by msg_set_command_name(). */
-static char *command_name;
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 
 /* Message handler as set by msg_init(). */
 static void (*msg_handler)  (const struct msg *);
@@ -73,11 +74,12 @@ void
 msg_done (void)
 {
 }
-
+\f
+/* Working with messages. */
 
 /* Duplicate a message */
 struct msg *
-msg_dup(const struct msg *m)
+msg_dup (const struct msg *m)
 {
   struct msg *new_msg;
 
@@ -102,6 +104,47 @@ msg_destroy (struct msg *m)
   free (m);
 }
 
+char *
+msg_to_string (const struct msg *m, const char *command_name)
+{
+  const char *label;
+  struct string s;
+
+  ds_init_empty (&s);
+
+  if (m->category != MSG_C_GENERAL
+      && (m->where.file_name || m->where.line_number != -1))
+    {
+      if (m->where.file_name)
+        ds_put_format (&s, "%s:", m->where.file_name);
+      if (m->where.line_number != -1)
+        ds_put_format (&s, "%d:", m->where.line_number);
+      ds_put_char (&s, ' ');
+    }
+
+  switch (m->severity)
+    {
+    case MSG_S_ERROR:
+      label = _("error");
+      break;
+    case MSG_S_WARNING:
+      label = _("warning");
+      break;
+    case MSG_S_NOTE:
+    default:
+      label = _("note");
+      break;
+    }
+  ds_put_format (&s, "%s: ", label);
+
+  if (m->category == MSG_C_SYNTAX && command_name != NULL)
+    ds_put_format (&s, "%s: ", command_name);
+
+  ds_put_cstr (&s, m->text);
+
+  return ds_cstr (&s);
+}
+\f
 /* Emits M as an error message.
    Frees allocated data in M. */
 void
@@ -140,22 +183,6 @@ msg_enable (void)
 \f
 /* Private functions. */
 
-/* Sets COMMAND_NAME as the command name included in some kinds
-   of error messages. */
-void
-msg_set_command_name (const char *command_name_)
-{
-  free (command_name);
-  command_name = command_name_ ? xstrdup (command_name_) : NULL;
-}
-
-/* Returns the current command name, or NULL if none. */
-const char *
-msg_get_command_name (void)
-{
-  return command_name;
-}
-
 void
 request_bug_report_and_abort (const char *msg)
 {
index b1e09253353e1c9740ef4a5406b3f47963f6b37d..e1fc4f5aab1235459b075ddf92e2c704c4561d62 100644 (file)
@@ -90,8 +90,10 @@ void msg_init (struct source_stream *, void (*handler) (const struct msg *) );
 
 void msg_done (void);
 
-struct msg * msg_dup(const struct msg *m);
-void msg_destroy(struct msg *m);
+/* Working with messages. */
+struct msg *msg_dup (const struct msg *);
+void msg_destroy(struct msg *);
+char *msg_to_string (const struct msg *, const char *command_name);
 
 /* Emitting messages. */
 void msg (enum msg_class, const char *format, ...)
@@ -103,8 +105,6 @@ void msg_enable (void);
 void msg_disable (void);
 
 /* Error context. */
-void msg_set_command_name (const char *);
-const char *msg_get_command_name (void);
 void msg_push_msg_locator (const struct msg_locator *);
 void msg_pop_msg_locator (const struct msg_locator *);
 
index b427df5318007df1cb42a04d75ecebfcafa33d65..c5f30816fb12efefae8865ea43de35158b59d13c 100644 (file)
 #include <data/settings.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
+#include <libpspp/message.h>
 #include <libpspp/start-date.h>
 #include <libpspp/string-map.h>
 #include <libpspp/version.h>
 #include <output/cairo.h>
 #include <output/chart-item-provider.h>
-#include "output/options.h"
+#include <output/message-item.h>
+#include <output/options.h>
 #include <output/tab.h>
 #include <output/text-item.h>
 #include <output/driver-provider.h>
@@ -112,6 +114,7 @@ struct ascii_driver
     char *init;                 /* Device initialization string. */
 
     /* Internal state. */
+    char *command_name;
     char *title;
     char *subtitle;
     char *file_name;            /* Output file name. */
@@ -209,6 +212,7 @@ ascii_create (const char *file_name, enum settings_output_devices device_type,
           }
   a->init = parse_string (opt (d, o, "init", ""));
 
+  a->command_name = NULL;
   a->title = xstrdup ("");
   a->subtitle = xstrdup ("");
   a->file_name = xstrdup (file_name);
@@ -330,6 +334,7 @@ ascii_destroy (struct output_driver *driver)
 
   if (a->file != NULL)
     fn_close (a->file_name, a->file);
+  free (a->command_name);
   free (a->title);
   free (a->subtitle);
   free (a->file_name);
@@ -367,103 +372,121 @@ ascii_init_caption_cell (const char *caption, struct table_cell *cell)
 }
 
 static void
-ascii_submit (struct output_driver *driver,
-              const struct output_item *output_item)
+ascii_output_table_item (struct ascii_driver *a,
+                         const struct table_item *table_item)
 {
-  struct ascii_driver *a = ascii_driver_cast (driver);
-  if (a->error)
-    return;
-  if (is_table_item (output_item))
+  const char *caption = table_item_get_caption (table_item);
+  struct render_params params;
+  struct render_page *page;
+  struct render_break x_break;
+  int caption_height;
+  int i;
+
+  update_page_size (a, false);
+
+  if (caption != NULL)
+    {
+      /* XXX doesn't do well with very large captions */
+      struct table_cell cell;
+      ascii_init_caption_cell (caption, &cell);
+      caption_height = ascii_measure_cell_height (a, &cell, a->width);
+    }
+  else
+    caption_height = 0;
+
+  params.draw_line = ascii_draw_line;
+  params.measure_cell_width = ascii_measure_cell_width;
+  params.measure_cell_height = ascii_measure_cell_height;
+  params.draw_cell = ascii_draw_cell,
+    params.aux = a;
+  params.size[H] = a->width;
+  params.size[V] = a->length - caption_height;
+  params.font_size[H] = 1;
+  params.font_size[V] = 1;
+  for (i = 0; i < RENDER_N_LINES; i++)
     {
-      struct table_item *table_item = to_table_item (output_item);
-      const char *caption = table_item_get_caption (table_item);
-      struct render_params params;
-      struct render_page *page;
-      struct render_break x_break;
-      int caption_height;
-      int i;
+      int width = i == RENDER_LINE_NONE ? 0 : 1;
+      params.line_widths[H][i] = width;
+      params.line_widths[V][i] = width;
+    }
 
-      update_page_size (a, false);
+  if (a->file == NULL && !ascii_open_page (a))
+    return;
 
-      if (caption != NULL)
-        {
-          /* XXX doesn't do well with very large captions */
-          struct table_cell cell;
-          ascii_init_caption_cell (caption, &cell);
-          caption_height = ascii_measure_cell_height (a, &cell, a->width);
-        }
-      else
-        caption_height = 0;
-
-      params.draw_line = ascii_draw_line;
-      params.measure_cell_width = ascii_measure_cell_width;
-      params.measure_cell_height = ascii_measure_cell_height;
-      params.draw_cell = ascii_draw_cell,
-      params.aux = a;
-      params.size[H] = a->width;
-      params.size[V] = a->length - caption_height;
-      params.font_size[H] = 1;
-      params.font_size[V] = 1;
-      for (i = 0; i < RENDER_N_LINES; i++)
+  page = render_page_create (&params, table_item_get_table (table_item));
+  for (render_break_init (&x_break, page, H);
+       render_break_has_next (&x_break); )
+    {
+      struct render_page *x_slice;
+      struct render_break y_break;
+
+      x_slice = render_break_next (&x_break, a->width);
+      for (render_break_init (&y_break, x_slice, V);
+           render_break_has_next (&y_break); )
         {
-          int width = i == RENDER_LINE_NONE ? 0 : 1;
-          params.line_widths[H][i] = width;
-          params.line_widths[V][i] = width;
-        }
+          struct render_page *y_slice;
+          int space;
 
-      if (a->file == NULL && !ascii_open_page (a))
-        return;
+          if (a->y > 0)
+            a->y++;
 
-      page = render_page_create (&params, table_item_get_table (table_item));
-      for (render_break_init (&x_break, page, H);
-           render_break_has_next (&x_break); )
-        {
-          struct render_page *x_slice;
-          struct render_break y_break;
+          space = a->length - a->y - caption_height;
+          if (render_break_next_size (&y_break) > space)
+            {
+              assert (a->y > 0);
+              ascii_close_page (a);
+              if (!ascii_open_page (a))
+                return;
+              continue;
+            }
 
-          x_slice = render_break_next (&x_break, a->width);
-          for (render_break_init (&y_break, x_slice, V);
-               render_break_has_next (&y_break); )
+          y_slice = render_break_next (&y_break, space);
+          if (caption_height)
             {
-              struct render_page *y_slice;
-              int space;
-
-              if (a->y > 0)
-                a->y++;
-
-              space = a->length - a->y - caption_height;
-              if (render_break_next_size (&y_break) > space)
-                {
-                  assert (a->y > 0);
-                  ascii_close_page (a);
-                  if (!ascii_open_page (a))
-                    return;
-                  continue;
-                }
-
-              y_slice = render_break_next (&y_break, space);
-              if (caption_height)
-                {
-                  struct table_cell cell;
-                  int bb[TABLE_N_AXES][2];
-
-                  ascii_init_caption_cell (caption, &cell);
-                  bb[H][0] = 0;
-                  bb[H][1] = a->width;
-                  bb[V][0] = 0;
-                  bb[V][1] = caption_height;
-                  ascii_draw_cell (a, &cell, bb, bb);
-                  a->y += caption_height;
-                  caption_height = 0;
-                }
-              render_page_draw (y_slice);
-              a->y += render_page_get_size (y_slice, V);
-              render_page_unref (y_slice);
+              struct table_cell cell;
+              int bb[TABLE_N_AXES][2];
+
+              ascii_init_caption_cell (caption, &cell);
+              bb[H][0] = 0;
+              bb[H][1] = a->width;
+              bb[V][0] = 0;
+              bb[V][1] = caption_height;
+              ascii_draw_cell (a, &cell, bb, bb);
+              a->y += caption_height;
+              caption_height = 0;
             }
-          render_break_destroy (&y_break);
+          render_page_draw (y_slice);
+          a->y += render_page_get_size (y_slice, V);
+          render_page_unref (y_slice);
         }
-      render_break_destroy (&x_break);
+      render_break_destroy (&y_break);
     }
+  render_break_destroy (&x_break);
+}
+
+static void
+ascii_output_text (struct ascii_driver *a, const char *text)
+{
+  struct table_item *table_item;
+
+  table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
+  ascii_output_table_item (a, table_item);
+  table_item_unref (table_item);
+}
+
+static void
+ascii_submit (struct output_driver *driver,
+              const struct output_item *output_item)
+{
+  struct ascii_driver *a = ascii_driver_cast (driver);
+
+  output_driver_track_current_command (output_item, &a->command_name);
+
+  if (a->error)
+    return;
+
+  if (is_table_item (output_item))
+    ascii_output_table_item (a, to_table_item (output_item));
   else if (is_chart_item (output_item) && a->chart_file_name != NULL)
     {
       struct chart_item *chart_item = to_chart_item (output_item);
@@ -515,17 +538,18 @@ ascii_submit (struct output_driver *driver,
           break;
 
         default:
-          {
-            struct table_item *item;
-
-            item = table_item_create (table_from_string (TAB_LEFT, text),
-                                      NULL);
-            ascii_submit (&a->driver, &item->output_item);
-            table_item_unref (item);
-          }
+          ascii_output_text (a, text);
           break;
         }
     }
+  else if (is_message_item (output_item))
+    {
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, a->command_name);
+      ascii_output_text (a, s);
+      free (s);
+    }
 }
 
 const struct output_driver_factory txt_driver_factory =
index 1d9f65868bfdb651ffb68d35096926a325449dcf..259f3b0e6a95afd8e8d04f3e9e6801b1ff1a477d 100644 (file)
@@ -30,6 +30,10 @@ src_output_liboutput_la_SOURCES = \
        src/output/journal.h \
        src/output/measure.c \
        src/output/measure.h \
+       src/output/message-item.c \
+       src/output/message-item.h \
+       src/output/msglog.c \
+       src/output/msglog.h \
        src/output/odt.c \
        src/output/options.c \
        src/output/options.h \
index c6892793d17962124f637983b9b0ebe7a4d2fe38..4e8b1d38bcdc71b896233454076042cee3d553ba 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <libpspp/assertion.h>
 #include <libpspp/cast.h>
+#include <libpspp/message.h>
 #include <libpspp/start-date.h>
 #include <libpspp/str.h>
 #include <libpspp/string-map.h>
@@ -33,6 +34,7 @@
 #include <output/charts/roc-chart.h>
 #include <output/charts/scree.h>
 #include <output/driver-provider.h>
+#include <output/message-item.h>
 #include <output/options.h>
 #include <output/render.h>
 #include <output/tab.h>
@@ -126,6 +128,7 @@ struct xr_driver
 
     /* Internal state. */
     struct render_params *params;
+    char *command_name;
     char *title;
     char *subtitle;
     cairo_t *cairo;
@@ -364,6 +367,7 @@ xr_destroy (struct output_driver *driver)
       cairo_destroy (xr->cairo);
     }
 
+  free (xr->command_name);
   for (i = 0; i < XR_N_FONTS; i++)
     free_font (&xr->fonts[i]);
   free (xr->params);
@@ -406,67 +410,81 @@ xr_render_table_item (struct xr_driver *xr, const struct table_item *item,
 }
 
 static void
-xr_submit (struct output_driver *driver, const struct output_item *output_item)
+xr_output_table_item (struct xr_driver *xr,
+                      const struct table_item *table_item)
 {
-  struct xr_driver *xr = xr_driver_cast (driver);
-  if (is_table_item (output_item))
-    {
-      struct table_item *table_item = to_table_item (output_item);
-      struct render_break x_break;
-      struct render_page *page;
-      int caption_height;
+  struct render_break x_break;
+  struct render_page *page;
+  int caption_height;
 
-      if (xr->y > 0)
-        xr->y += xr->font_height;
+  if (xr->y > 0)
+    xr->y += xr->font_height;
 
-      page = xr_render_table_item (xr, table_item, &caption_height);
-      xr->params->size[V] = xr->length - caption_height;
-      for (render_break_init (&x_break, page, H);
-           render_break_has_next (&x_break); )
+  page = xr_render_table_item (xr, table_item, &caption_height);
+  xr->params->size[V] = xr->length - caption_height;
+  for (render_break_init (&x_break, page, H);
+       render_break_has_next (&x_break); )
+    {
+      struct render_page *x_slice;
+      struct render_break y_break;
+
+      x_slice = render_break_next (&x_break, xr->width);
+      for (render_break_init (&y_break, x_slice, V);
+           render_break_has_next (&y_break); )
         {
-          struct render_page *x_slice;
-          struct render_break y_break;
+          int space = xr->length - xr->y;
+          struct render_page *y_slice;
 
-          x_slice = render_break_next (&x_break, xr->width);
-          for (render_break_init (&y_break, x_slice, V);
-               render_break_has_next (&y_break); )
+          /* XXX doesn't allow for caption or space between segments */
+          if (render_break_next_size (&y_break) > space)
             {
-              int space = xr->length - xr->y;
-              struct render_page *y_slice;
-
-              /* XXX doesn't allow for caption or space between segments */
-              if (render_break_next_size (&y_break) > space)
-                {
-                  assert (xr->y > 0);
-                  xr_show_page (xr);
-                  continue;
-                }
-
-              y_slice = render_break_next (&y_break, space);
-              if (caption_height)
-                {
-                  struct table_cell cell;
-                  int bb[TABLE_N_AXES][2];
-
-                  xr_init_caption_cell (table_item_get_caption (table_item),
-                                        &cell);
-                  bb[H][0] = 0;
-                  bb[H][1] = xr->width;
-                  bb[V][0] = 0;
-                  bb[V][1] = caption_height;
-                  xr_draw_cell (xr, &cell, bb, bb);
-                  xr->y += caption_height;
-                  caption_height = 0;
-                }
-
-              render_page_draw (y_slice);
-              xr->y += render_page_get_size (y_slice, V);
-              render_page_unref (y_slice);
+              assert (xr->y > 0);
+              xr_show_page (xr);
+              continue;
             }
-          render_break_destroy (&y_break);
+
+          y_slice = render_break_next (&y_break, space);
+          if (caption_height)
+            {
+              struct table_cell cell;
+              int bb[TABLE_N_AXES][2];
+
+              xr_init_caption_cell (table_item_get_caption (table_item),
+                                    &cell);
+              bb[H][0] = 0;
+              bb[H][1] = xr->width;
+              bb[V][0] = 0;
+              bb[V][1] = caption_height;
+              xr_draw_cell (xr, &cell, bb, bb);
+              xr->y += caption_height;
+              caption_height = 0;
+            }
+
+          render_page_draw (y_slice);
+          xr->y += render_page_get_size (y_slice, V);
+          render_page_unref (y_slice);
         }
-      render_break_destroy (&x_break);
+      render_break_destroy (&y_break);
     }
+  render_break_destroy (&x_break);
+}
+
+static void
+xr_output_text (struct xr_driver *xr, const char *text)
+{
+  struct table_item *table_item;
+
+  table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
+  xr_output_table_item (xr, table_item);
+  table_item_unref (table_item);
+}
+
+static void
+xr_submit (struct output_driver *driver, const struct output_item *output_item)
+{
+  struct xr_driver *xr = xr_driver_cast (driver);
+  if (is_table_item (output_item))
+    xr_output_table_item (xr, to_table_item (output_item));
   else if (is_chart_item (output_item))
     {
       if (xr->y > 0)
@@ -507,17 +525,17 @@ xr_submit (struct output_driver *driver, const struct output_item *output_item)
           break;
 
         default:
-          {
-            struct table_item *item;
-
-            item = table_item_create (table_from_string (TAB_LEFT, text),
-                                      NULL);
-            xr_submit (&xr->driver, &item->output_item);
-            table_item_unref (item);
-          }
+          xr_output_text (xr, text);
           break;
         }
-
+    }
+  else if (is_message_item (output_item))
+    {
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, xr->command_name);
+      xr_output_text (xr, s);
+      free (s);
     }
 }
 
@@ -960,6 +978,19 @@ xr_create_driver (cairo_t *cairo)
   return xr;
 }
 
+static struct xr_rendering *
+xr_rendering_create_text (struct xr_driver *xr, const char *text, cairo_t *cr)
+{
+  struct table_item *table_item;
+  struct xr_rendering *r;
+
+  table_item = table_item_create (table_from_string (0, text), NULL);
+  r = xr_rendering_create (xr, &table_item->output_item, cr);
+  table_item_unref (table_item);
+
+  return r;
+}
+
 struct xr_rendering *
 xr_rendering_create (struct xr_driver *xr, const struct output_item *item,
                      cairo_t *cr)
@@ -967,15 +998,15 @@ xr_rendering_create (struct xr_driver *xr, const struct output_item *item,
   struct xr_rendering *r = NULL;
 
   if (is_text_item (item))
+    r = xr_rendering_create_text (xr, text_item_get_text (to_text_item (item)),
+                                  cr);
+  else if (is_message_item (item))
     {
-      const struct text_item *text_item = to_text_item (item);
-      const char *text = text_item_get_text (text_item);
-      struct table_item *table_item;
-
-      table_item = table_item_create (table_from_string (TAB_LEFT, text),
-                                      NULL);
-      r = xr_rendering_create (xr, &table_item->output_item, cr);
-      table_item_unref (table_item);
+      const struct message_item *message_item = to_message_item (item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, NULL);
+      r = xr_rendering_create_text (xr, s, cr);
+      free (s);
     }
   else if (is_table_item (item))
     {
index 6be9c43acfaf4ded795b3a1a9ac6aa8e881276bd..004558f1b1dee53974680f26e60a3817d93ebd05 100644 (file)
 #include <errno.h>
 #include <stdlib.h>
 
-#include <data/file-name.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/string-map.h>
-#include <output/text-item.h>
-#include <output/driver-provider.h>
-#include <output/options.h>
-#include <output/table-item.h>
-#include <output/table-provider.h>
+#include "data/file-name.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/string-map.h"
+#include "output/text-item.h"
+#include "output/driver-provider.h"
+#include "output/options.h"
+#include "output/message-item.h"
+#include "output/table-item.h"
+#include "output/table-provider.h"
 
 #include "gl/error.h"
 #include "gl/xalloc.h"
@@ -43,6 +45,7 @@ struct csv_driver
 
     char *separator;            /* Comma or tab. */
     char *file_name;            /* Output file name. */
+    char *command_name;         /* Current command. */
     FILE *file;                 /* Output file. */
     int n_items;                /* Number of items output so far. */
   };
@@ -164,6 +167,8 @@ csv_submit (struct output_driver *driver,
 {
   struct csv_driver *csv = csv_driver_cast (driver);
 
+  output_driver_track_current_command (output_item, &csv->command_name);
+
   if (is_table_item (output_item))
     {
       struct table_item *table_item = to_table_item (output_item);
@@ -227,6 +232,16 @@ csv_submit (struct output_driver *driver,
         }
       putc ('\n', csv->file);
     }
+  else if (is_message_item (output_item))
+    {
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, csv->command_name);
+      csv_put_separator (csv);
+      csv_output_field (csv->file, s);
+      free (s);
+      putc ('\n', csv->file);
+    }
 }
 
 struct output_driver_factory csv_driver_factory = { "csv", csv_create };
index 61852c4a5e89e8b49cf02afc336660a23db02263..203644584f162eade6f30663c26ffaa81625d58d 100644 (file)
@@ -34,6 +34,7 @@
 #include "libpspp/string-map.h"
 #include "libpspp/string-set.h"
 #include "libpspp/str.h"
+#include "output/message-item.h"
 #include "output/output-item.h"
 #include "output/text-item.h"
 
@@ -83,8 +84,16 @@ output_submit__ (struct output_item *item)
 
       next = llx_next (llx);
 
-      if (is_text_item (item)
-          && text_item_get_type (to_text_item (item)) == TEXT_ITEM_SYNTAX)
+      if (is_message_item (item))
+        {
+          const struct msg *m = message_item_get_msg (to_message_item (item));
+          if (m->severity == MSG_S_NOTE)
+            type = SETTINGS_OUTPUT_NOTE;
+          else
+            type = SETTINGS_OUTPUT_ERROR;
+        }
+      else if (is_text_item (item)
+               && text_item_get_type (to_text_item (item)) == TEXT_ITEM_SYNTAX)
         type = SETTINGS_OUTPUT_SYNTAX;
       else
         type = SETTINGS_OUTPUT_RESULT;
index a3e14ba1f1ef27240b514cbe3c9985a6d00b350f..636450a9a353c1d43ccac0f7c4a54b665e946401 100644 (file)
 #include <time.h>
 #include <unistd.h>
 
-#include <data/file-name.h>
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
-#include <libpspp/compiler.h>
-#include <libpspp/version.h>
-#include <output/cairo.h>
-#include <output/chart-item.h>
-#include <output/driver-provider.h>
-#include <output/options.h>
-#include <output/output-item-provider.h>
-#include <output/table-provider.h>
-#include <output/table-item.h>
-#include <output/text-item.h>
+#include "data/file-name.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/version.h"
+#include "output/cairo.h"
+#include "output/chart-item.h"
+#include "output/driver-provider.h"
+#include "output/message-item.h"
+#include "output/options.h"
+#include "output/output-item-provider.h"
+#include "output/table-provider.h"
+#include "output/table-item.h"
+#include "output/text-item.h"
 
 #include "error.h"
 #include "xalloc.h"
@@ -50,6 +52,7 @@ struct html_driver
     char *file_name;
     char *chart_file_name;
 
+    char *command_name;
     FILE *file;
     size_t chart_cnt;
 
@@ -210,6 +213,7 @@ html_destroy (struct output_driver *driver)
     }
   free (html->chart_file_name);
   free (html->file_name);
+  free (html->command_name);
   free (html);
 }
 
@@ -226,6 +230,8 @@ html_submit (struct output_driver *driver,
 {
   struct html_driver *html = html_driver_cast (driver);
 
+  output_driver_track_current_command (output_item, &html->command_name);
+
   if (html->in_syntax && !is_syntax_item (output_item))
     {
       fprintf (html->file, "</PRE>\n");
@@ -313,6 +319,14 @@ html_submit (struct output_driver *driver,
           break;
         }
     }
+  else if (is_message_item (output_item))
+    {
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, html->command_name);
+      print_title_tag (html->file, "P", s);
+      free (s);
+    }
 }
 
 /* Write LENGTH characters in TEXT to file F, escaping characters
index 67657f6247cc8ec731cf8154c4f45aa48d369003..6b7332771c0f5e7727ffe631c04d11e1ab63a5ac 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2010 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include <config.h>
 
-#include <output/journal.h>
+#include "output/journal.h"
 
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <data/file-name.h>
-#include <libpspp/str.h>
+#include "data/file-name.h"
+#include "libpspp/cast.h"
+#include "libpspp/str.h"
+#include "output/driver-provider.h"
+#include "output/message-item.h"
+#include "output/text-item.h"
 
-#include "fwriteerror.h"
-#include "error.h"
-#include "xalloc.h"
+#include "gl/error.h"
+#include "gl/fwriteerror.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* Journaling enabled? */
-static bool journal_enabled = false;
+struct journal_driver
+  {
+    struct output_driver driver;
+    FILE *file;
+    char *command_name;
+  };
 
-/* Name of the journal file. */
-static char *journal_file_name = NULL;
+static const struct output_driver_class journal_class;
 
-/* Journal file. */
-static FILE *journal_file = NULL;
+/* Journal driver, if journaling is enabled. */
+static struct journal_driver *journal;
 
-/* Enables journaling. */
-void
-journal_enable (void)
+/* Name of journal file. */
+static char *journal_file_name;
+
+static struct journal_driver *
+journal_driver_cast (struct output_driver *driver)
 {
-  journal_enabled = true;
+  assert (driver->class == &journal_class);
+  return UP_CAST (driver, struct journal_driver, driver);
 }
 
-/* Disables journaling. */
-void
-journal_disable (void)
+static void
+journal_close (void)
 {
-  journal_enabled = false;
-  if (journal_file != NULL)
-    fflush (journal_file);
+  if (journal != NULL && journal->file != NULL)
+    {
+      if (fwriteerror (journal->file))
+        error (0, errno, _("error writing \"%s\""), journal_file_name);
+      journal->file = NULL;
+    }
 }
 
-/* Sets the name of the journal file to FILE_NAME. */
-void
-journal_set_file_name (const char *file_name)
+static void
+journal_destroy (struct output_driver *driver)
 {
-  assert (file_name != NULL);
+  struct journal_driver *j = journal_driver_cast (driver);
+
+  journal_close ();
+  free (j->command_name);
+  free (j);
 
-  if (journal_file != NULL)
+  journal = NULL;
+}
+
+static void
+journal_output (struct journal_driver *j, const char *s)
+{
+  if (j->file == NULL)
     {
-      if (fwriteerror (journal_file))
-        error (0, errno, _("error writing \"%s\""), journal_file_name);
+      j->file = fopen (journal_file_name, "a");
+      if (j->file == NULL)
+        {
+          error (0, errno, _("%s: open failed"), journal_file_name);
+          output_driver_destroy (&j->driver);
+          return;
+        }
     }
 
-  free (journal_file_name);
-  journal_file_name = xstrdup (file_name);
+  fprintf (j->file, "%s\n", s);
 }
 
-/* Writes LINE to the journal file (if journaling is enabled).
-   If PREFIX is non-null, the line will be prefixed by "> ". */
-void
-journal_write (bool prefix, const char *line)
+static void
+journal_submit (struct output_driver *driver, const struct output_item *item)
 {
-  if (!journal_enabled)
-    return;
+  struct journal_driver *j = journal_driver_cast (driver);
+
+  output_driver_track_current_command (item, &j->command_name);
+
+  if (is_text_item (item))
+    {
+      const struct text_item *text_item = to_text_item (item);
+      enum text_item_type type = text_item_get_type (text_item);
 
-  if (journal_file == NULL)
+      if (type == TEXT_ITEM_SYNTAX)
+        journal_output (j, text_item_get_text (text_item));
+    }
+  else if (is_message_item (item))
+    {
+      const struct message_item *message_item = to_message_item (item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, j->command_name);
+      journal_output (j, s);
+      free (s);
+    }
+}
+
+static const struct output_driver_class journal_class =
+  {
+    "journal",
+    journal_destroy,
+    journal_submit,
+    NULL                        /* flush */
+  };
+\f
+/* Enables journaling. */
+void
+journal_enable (void)
+{
+  if (journal == NULL)
     {
+      /* If no journal file name is configured, use the default. */
       if (journal_file_name == NULL)
        {
          const char *output_path = default_output_path ();
          journal_file_name = xasprintf ("%s%s", output_path, "pspp.jnl");
        }
-      journal_file = fopen (journal_file_name, "w");
-      if (journal_file == NULL)
-        {
-          error (0, errno, _("error creating \"%s\""), journal_file_name);
-          journal_enabled = false;
-          return;
-        }
+
+      /* Create journal driver. */
+      journal = xzalloc (sizeof *journal);
+      output_driver_init (&journal->driver, &journal_class, "journal",
+                          SETTINGS_DEVICE_UNFILTERED);
+      journal->file = NULL;
+      journal->command_name = NULL;
+
+      /* Register journal driver. */
+      output_driver_register (&journal->driver);
     }
+}
+
+/* Disables journaling. */
+void
+journal_disable (void)
+{
+  if (journal != NULL)
+    output_driver_destroy (&journal->driver);
+}
 
-  if (prefix)
-    fputs ("> ", journal_file);
-  fputs (line, journal_file);
-  if (strchr (line, '\n') == NULL)
-    putc ('\n', journal_file);
-  fflush (journal_file);
+/* Sets the name of the journal file to FILE_NAME. */
+void
+journal_set_file_name (const char *file_name)
+{
+  journal_close ();
+  free (journal_file_name);
+  journal_file_name = xstrdup (file_name);
 }
index 3509ff09890b4329a7b62bba36771a34ef516b92..5051193a67ea3c7d03ed61be1fddfe0167273173 100644 (file)
@@ -29,6 +29,5 @@
 void journal_enable (void);
 void journal_disable (void);
 void journal_set_file_name (const char *);
-void journal_write (bool prefix, const char *);
 
 #endif /* output/journal.h */
diff --git a/src/output/message-item.c b/src/output/message-item.c
new file mode 100644 (file)
index 0000000..feb1d32
--- /dev/null
@@ -0,0 +1,66 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 Free Sonftware Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "output/message-item.h"
+
+#include <stdlib.h>
+
+#include "libpspp/message.h"
+#include "output/driver.h"
+#include "output/output-item-provider.h"
+
+#include "gl/xalloc.h"
+
+struct message_item *
+message_item_create (const struct msg *msg)
+{
+  struct message_item *item;
+
+  item = xmalloc (sizeof *msg);
+  output_item_init (&item->output_item, &message_item_class);
+  item->msg = msg_dup (msg);
+
+  return item;
+}
+
+const struct msg *
+message_item_get_msg (const struct message_item *item)
+{
+  return item->msg;
+}
+
+static void
+message_item_destroy (struct output_item *output_item)
+{
+  struct message_item *item = to_message_item (output_item);
+  msg_destroy (item->msg);
+  free (item);
+}
+
+/* Submits ITEM to the configured output drivers, and transfers ownership to
+   the output subsystem. */
+void
+message_item_submit (struct message_item *item)
+{
+  output_submit (&item->output_item);
+}
+
+const struct output_item_class message_item_class =
+  {
+    message_item_destroy,
+  };
diff --git a/src/output/message-item.h b/src/output/message-item.h
new file mode 100644 (file)
index 0000000..a97b227
--- /dev/null
@@ -0,0 +1,101 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 Free Sonftware Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef OUTPUT_MESSAGE_ITEM_H
+#define OUTPUT_MESSAGE_ITEM_H 1
+
+/* Message items.
+
+   A message item is a subclass of an output item (see
+   output/output-item.h).
+
+   A message item is an error, warning, or note to the user.
+
+   Message items should not be submitted directly to the output subsystem.
+   Instead, use the msg() function in libpspp/message.h, which will ensure that
+   the message gets routed properly for the PSPP user interface in use. */
+
+#include <stdbool.h>
+#include <output/output-item.h>
+
+/* A message item. */
+struct message_item
+  {
+    struct output_item output_item;
+    struct msg *msg;
+  };
+
+struct message_item *message_item_create (const struct msg *);
+
+const struct msg *message_item_get_msg (const struct message_item *);
+\f
+/* This boilerplate for message_item, a subclass of output_item, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct output_item_class message_item_class;
+
+/* Returns true if SUPER is a message_item, otherwise false. */
+static inline bool
+is_message_item (const struct output_item *super)
+{
+  return super->class == &message_item_class;
+}
+
+/* Returns SUPER converted to message_item.  SUPER must be a message_item, as
+   reported by is_message_item. */
+static inline struct message_item *
+to_message_item (const struct output_item *super)
+{
+  assert (is_message_item (super));
+  return UP_CAST (super, struct message_item, output_item);
+}
+
+/* Returns INSTANCE converted to output_item. */
+static inline struct output_item *
+message_item_super (const struct message_item *instance)
+{
+  return CONST_CAST (struct output_item *, &instance->output_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct message_item *
+message_item_ref (const struct message_item *instance)
+{
+  return to_message_item (output_item_ref (&instance->output_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+message_item_unref (struct message_item *instance)
+{
+  output_item_unref (&instance->output_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+message_item_is_shared (const struct message_item *instance)
+{
+  return output_item_is_shared (&instance->output_item);
+}
+
+void message_item_submit (struct message_item *);
+\f
+#endif /* output/message-item.h */
diff --git a/src/output/msglog.c b/src/output/msglog.c
new file mode 100644 (file)
index 0000000..d5c6806
--- /dev/null
@@ -0,0 +1,119 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "output/msglog.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "data/file-name.h"
+#include "data/settings.h"
+#include "libpspp/cast.h"
+#include "output/driver-provider.h"
+#include "output/message-item.h"
+
+#include "gl/error.h"
+#include "gl/fwriteerror.h"
+#include "gl/xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct msglog_driver
+  {
+    struct output_driver driver;
+    FILE *file;
+    char *file_name;
+    char *command_name;
+  };
+
+static const struct output_driver_class msglog_class;
+
+static struct msglog_driver *
+msglog_driver_cast (struct output_driver *driver)
+{
+  assert (driver->class == &msglog_class);
+  return UP_CAST (driver, struct msglog_driver, driver);
+}
+
+struct output_driver *
+msglog_create (const char *file_name)
+{
+  enum settings_output_devices type;
+  struct msglog_driver *ml;
+  FILE *file;
+
+  file = fn_open (file_name, "w");
+  if (file == NULL)
+    {
+      error (0, errno, _("%s: open failed"), file_name);
+      return NULL;
+    }
+
+  type = (!strcmp (file_name, "-") || isatty (fileno (file))
+          ? SETTINGS_DEVICE_TERMINAL
+          : SETTINGS_DEVICE_UNFILTERED);
+
+  ml = xzalloc (sizeof *ml);
+  output_driver_init (&ml->driver, &msglog_class, file_name, type);
+  ml->file = file;
+  ml->file_name = xstrdup (file_name);
+  ml->command_name = NULL;
+
+  output_driver_register (&ml->driver);
+
+  return &ml->driver;
+}
+
+static void
+msglog_destroy (struct output_driver *driver)
+{
+  struct msglog_driver *ml = msglog_driver_cast (driver);
+
+  fn_close (ml->file_name, ml->file);
+  free (ml->file_name);
+  free (ml->command_name);
+  free (ml);
+}
+
+static void
+msglog_submit (struct output_driver *driver, const struct output_item *item)
+{
+  struct msglog_driver *ml = msglog_driver_cast (driver);
+
+  output_driver_track_current_command (item, &ml->command_name);
+
+  if (is_message_item (item))
+    {
+      const struct message_item *message_item = to_message_item (item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, ml->command_name);
+      fprintf (ml->file, "%s\n", s);
+      free (s);
+    }
+}
+
+static const struct output_driver_class msglog_class =
+  {
+    "msglog",
+    msglog_destroy,
+    msglog_submit,
+    NULL
+  };
diff --git a/src/output/msglog.h b/src/output/msglog.h
new file mode 100644 (file)
index 0000000..e5d5498
--- /dev/null
@@ -0,0 +1,24 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef OUTPUT_MSGLOG_H
+#define OUTPUT_MSGLOG_H 1
+
+/* Output driver to log errors, warnings, and notes to files. */
+
+struct output_driver *msglog_create (const char *file_name);
+
+#endif /* output/msglog.h */
index ab38cd0411c91d779a860f86c7380896d6e425de..0b55ac9ae9222efb7b60aede6e4a1c4fdc0351c4 100644 (file)
@@ -32,6 +32,7 @@
 #include "libpspp/str.h"
 #include "libpspp/version.h"
 #include "output/driver-provider.h"
+#include "output/message-item.h"
 #include "output/options.h"
 #include "output/tab.h"
 #include "output/table-item.h"
@@ -64,6 +65,9 @@ struct odt_driver
 
   /* Number of tables so far. */
   int table_num;
+
+  /* Name of current command. */
+  char *command_name;
 };
 
 static const struct output_driver_class odt_driver_class;
@@ -403,6 +407,7 @@ odt_destroy (struct output_driver *driver)
   else
     fprintf (stderr, "Not removing directory %s\n", odt->dirname);
 
+  free (odt->command_name);
   free (odt->dirname);
   free (odt);
 }
@@ -503,23 +508,37 @@ odt_submit_table (struct odt_driver *odt, struct table_item *item)
   xmlTextWriterEndElement (odt->content_wtr); /* table */
 }
 
+static void
+odt_output_text (struct odt_driver *odt, const char *text)
+{
+  xmlTextWriterStartElement (odt->content_wtr, _xml("text:p"));
+  xmlTextWriterWriteString (odt->content_wtr, _xml(text));
+  xmlTextWriterEndElement (odt->content_wtr);
+}
+
 /* Submit a table to the ODT driver */
 static void
 odt_submit (struct output_driver *driver,
             const struct output_item *output_item)
 {
   struct odt_driver *odt = odt_driver_cast (driver);
+
+  output_driver_track_current_command (output_item, &odt->command_name);
+
   if (is_table_item (output_item))
     odt_submit_table (odt, to_table_item (output_item));
   else if (is_text_item (output_item))
     {
-      const struct text_item *text_item = to_text_item (output_item);
-      const char *text = text_item_get_text (text_item);
-
       /* XXX apply different styles based on text_item's type.  */
-      xmlTextWriterStartElement (odt->content_wtr, _xml("text:p"));
-      xmlTextWriterWriteString (odt->content_wtr, _xml(text));
-      xmlTextWriterEndElement (odt->content_wtr);
+      odt_output_text (odt, text_item_get_text (to_text_item (output_item)));
+    }
+  else if (is_message_item (output_item))
+    {
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, odt->command_name);
+      odt_output_text (odt, s);
+      free (s);
     }
 }
 
index 57ced30323ff57fa488be7f9a9055b9b839bc204..b45e008720dee14132c1d03ee25ad49df982915a 100644 (file)
@@ -27,6 +27,8 @@
         - Charts (see output/chart-item.h).
 
         - Text strings (see output/text-item.h).
+
+        - Messages (see output/message-item.h).
 */
 
 #include <libpspp/cast.h>
index 3fbf46520d2137e18d934c86f16e0ce4b1f553c4..cb730ec2def0bee1c0cde000f67294a4db7df2e4 100644 (file)
@@ -61,7 +61,6 @@ UI_FILES = \
        src/ui/gui/examine.ui \
        src/ui/gui/find.ui \
        src/ui/gui/frequencies.ui \
-       src/ui/gui/message-dialog.ui \
        src/ui/gui/oneway.ui \
        src/ui/gui/psppire.ui \
        src/ui/gui/rank.ui \
@@ -141,8 +140,6 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/helper.c \
        src/ui/gui/helper.h \
        src/ui/gui/main.c \
-       src/ui/gui/message-dialog.c \
-       src/ui/gui/message-dialog.h \
        src/ui/gui/missing-val-dialog.c \
        src/ui/gui/missing-val-dialog.h \
         src/ui/gui/oneway-anova-dialog.c \
diff --git a/src/ui/gui/message-dialog.c b/src/ui/gui/message-dialog.c
deleted file mode 100644 (file)
index ccb4364..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2005, 2010 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-
-#include <stdio.h>
-#include <stdarg.h>
-
-#include <config.h>
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <libpspp/msg-locator.h>
-#include "message-dialog.h"
-#include "progname.h"
-
-
-#include <gtk/gtk.h>
-#include <glib.h>
-
-#include "helper.h"
-
-static void enqueue_msg (const struct msg *m);
-static gboolean popup_messages (gpointer);
-
-#define MAX_EARLY_MESSAGES 100
-static GQueue *early_queue;
-
-static unsigned long dropped_messages;
-
-#define MAX_LATE_MESSAGES 10
-static GQueue *late_queue;
-
-static int error_cnt, warning_cnt, note_cnt;
-
-static GtkBuilder *message_xml;
-static GtkWidget *message_dialog;
-
-void
-message_dialog_init (struct source_stream *ss)
-{
-  early_queue = g_queue_new ();
-  dropped_messages = 0;
-  late_queue = g_queue_new ();
-  error_cnt = warning_cnt = note_cnt = 0;
-  msg_init (ss, enqueue_msg);
-  message_xml = builder_new ("message-dialog.ui");
-  message_dialog = get_widget_assert (message_xml, "message-dialog");
-
-  GTK_WIDGET_SET_FLAGS (get_widget_assert (message_xml, "close-button"),
-                       GTK_CAN_DEFAULT);
-
-}
-
-void
-message_dialog_done (void)
-{
-  msg_done ();
-  g_queue_free (early_queue);
-  dropped_messages = 0;
-  g_queue_free (late_queue);
-  gtk_widget_destroy (message_dialog);
-  g_object_unref (message_xml);
-}
-
-static void
-format_message (struct msg *m, struct string *msg)
-{
-  const char *label;
-
-  if (m->where.file_name)
-    ds_put_format (msg, "%s:", m->where.file_name);
-  if (m->where.line_number != -1)
-    ds_put_format (msg, "%d:", m->where.line_number);
-  if (m->where.file_name || m->where.line_number != -1)
-    ds_put_char (msg, ' ');
-
-  switch (m->severity)
-    {
-    case MSG_S_ERROR:
-      switch (m->category)
-       {
-       case MSG_C_SYNTAX:
-         label = _("syntax error");
-         break;
-
-       case MSG_C_DATA:
-         label = _("data file error");
-         break;
-
-       case MSG_C_GENERAL:
-       default:
-         label = _("PSPP error");
-         break;
-       }
-      break;
-    case MSG_S_WARNING:
-      switch (m->category)
-       {
-       case MSG_C_SYNTAX:
-         label = _("syntax warning");
-          break;
-
-       case MSG_C_DATA:
-         label = _("data file warning");
-         break;
-
-       case MSG_C_GENERAL:
-        default:
-         label = _("PSPP warning");
-          break;
-        }
-      break;
-    case MSG_S_NOTE:
-    default:
-      switch (m->category)
-        {
-        case MSG_C_SYNTAX:
-         label = _("syntax information");
-          break;
-
-        case MSG_C_DATA:
-         label = _("data file information");
-          break;
-
-        case MSG_C_GENERAL:
-        default:
-         label = _("PSPP information");
-         break;
-       }
-      break;
-    }
-  ds_put_format (msg, "%s: %s\n", label, m->text);
-  msg_destroy (m);
-}
-
-static void
-enqueue_msg (const struct msg *msg)
-{
-  struct msg *m = msg_dup (msg);
-
-  switch (m->severity)
-    {
-    case MSG_S_ERROR:
-      error_cnt++;
-      break;
-    case MSG_S_WARNING:
-      warning_cnt++;
-      break;
-    case MSG_S_NOTE:
-      note_cnt++;
-      break;
-    case MSG_N_SEVERITIES:
-      NOT_REACHED ();
-    }
-
-  if (g_queue_get_length (early_queue) < MAX_EARLY_MESSAGES)
-    {
-      if (g_queue_is_empty (early_queue))
-        g_idle_add (popup_messages, NULL);
-      g_queue_push_tail (early_queue, m);
-    }
-  else
-    {
-      if (g_queue_get_length (late_queue) >= MAX_LATE_MESSAGES)
-        {
-          struct msg *m = g_queue_pop_head (late_queue);
-          msg_destroy (m);
-          dropped_messages++;
-        }
-      g_queue_push_tail (late_queue, m);
-    }
-}
-
-static gboolean
-popup_messages (gpointer unused UNUSED)
-{
-  GtkTextBuffer *text_buffer;
-  GtkTextIter end;
-  GtkTextView *text_view;
-  GtkLabel *label;
-  struct string lead = DS_EMPTY_INITIALIZER;
-  struct string msg = DS_EMPTY_INITIALIZER;
-  int message_cnt;
-
-  gdk_threads_enter ();
-
-  /* Set up the dialog. */
-  if (message_xml == NULL || message_dialog == NULL)
-    goto use_fallback;
-
-  /* If a pointer grab is in effect, then the combination of that, and
-     a modal dialog box, will cause an impossible situation.
-     So don't pop it up just yet.
-  */
-  if ( gdk_display_pointer_is_grabbed (gtk_widget_get_display (message_dialog)))
-    {
-      ds_destroy (&lead);
-      ds_destroy (&msg);
-      gdk_threads_leave ();
-      return TRUE;
-    }
-
-  /* Compose the lead-in. */
-  message_cnt = error_cnt + warning_cnt + note_cnt;
-  if (dropped_messages == 0)
-    ds_put_format (
-      &lead,
-      ngettext ("The PSPP processing engine reported the following message:",
-                "The PSPP processing engine reported the following messages:",
-                message_cnt));
-  else
-    {
-      ds_put_format (
-        &lead,
-        ngettext ("The PSPP processing engine reported %d message.",
-                  "The PSPP processing engine reported %d messages.",
-                  message_cnt),
-        message_cnt);
-      ds_put_cstr (&lead, "  ");
-      ds_put_format (
-        &lead,
-        ngettext ("%d of these messages are displayed below.",
-                  "%d of these messages are displayed below.",
-                  MAX_EARLY_MESSAGES + MAX_LATE_MESSAGES),
-        MAX_EARLY_MESSAGES + MAX_LATE_MESSAGES);
-    }
-
-
-  /* Compose the messages. */
-  while (!g_queue_is_empty (early_queue))
-    format_message (g_queue_pop_head (early_queue), &msg);
-  if (dropped_messages)
-    {
-      ds_put_format (&msg, "...\nOmitting %lu messages\n...\n",
-                     dropped_messages);
-      dropped_messages = 0;
-    }
-  while (!g_queue_is_empty (late_queue))
-    format_message (g_queue_pop_head (late_queue), &msg);
-
-  text_buffer = gtk_text_buffer_new (NULL);
-  gtk_text_buffer_get_end_iter (text_buffer, &end);
-  gtk_text_buffer_insert (text_buffer, &end, ds_data (&msg), ds_length (&msg));
-
-  label = GTK_LABEL (get_widget_assert (message_xml, "lead-in"));
-  if (label == NULL)
-    goto use_fallback;
-  gtk_label_set_text (label, ds_cstr (&lead));
-
-  text_view = GTK_TEXT_VIEW (get_widget_assert (message_xml, "message"));
-  if (text_view == NULL)
-    goto use_fallback;
-  gtk_text_view_set_buffer (text_view, text_buffer);
-
-  gtk_widget_grab_default (get_widget_assert (message_xml, "close-button"));
-  gtk_widget_grab_focus (get_widget_assert (message_xml, "close-button"));
-  gtk_dialog_run ( GTK_DIALOG (message_dialog));
-  gtk_widget_hide (message_dialog);
-
-  ds_destroy (&lead);
-  ds_destroy (&msg);
-
-  gdk_threads_leave ();
-  return FALSE;
-
-use_fallback:
-  g_warning ("Could not create message dialog.  "
-             "Is PSPPIRE properly installed?");
-  fputs (ds_cstr (&msg), stderr);
-  ds_destroy (&lead);
-  ds_destroy (&msg);
-  gdk_threads_leave ();
-  return FALSE;
-}
-
diff --git a/src/ui/gui/message-dialog.h b/src/ui/gui/message-dialog.h
deleted file mode 100644 (file)
index 45eeca6..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004,2005  Free Software Foundation
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef ERROR_DIALOG_H
-#define ERROR_DIALOG_H
-
-#include <libpspp/message.h>
-
-struct source_stream ;
-
-void message_dialog_init (struct source_stream *);
-void message_dialog_done (void);
-
-#endif
diff --git a/src/ui/gui/message-dialog.ui b/src/ui/gui/message-dialog.ui
deleted file mode 100644 (file)
index 540a390..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0"?>
-<interface>
-  <!-- interface-requires gtk+ 2.12 -->
-  <!-- interface-naming-policy project-wide -->
-  <object class="GtkDialog" id="message-dialog">
-    <property name="width_request">600</property>
-    <property name="height_request">350</property>
-    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-    <property name="border_width">12</property>
-    <property name="title" translatable="yes">Messages Reported</property>
-    <property name="modal">True</property>
-    <property name="window_position">center-on-parent</property>
-    <property name="type_hint">dialog</property>
-    <property name="has_separator">False</property>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox1">
-        <property name="visible">True</property>
-        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-        <property name="orientation">vertical</property>
-        <property name="spacing">24</property>
-        <child>
-          <object class="GtkHBox" id="hbox1">
-            <property name="visible">True</property>
-            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <property name="spacing">12</property>
-            <child>
-              <object class="GtkImage" id="image1">
-                <property name="visible">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="yalign">0</property>
-                <property name="stock">gtk-dialog-info</property>
-                <property name="icon-size">6</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkVBox" id="vbox1">
-                <property name="visible">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="orientation">vertical</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkLabel" id="lead-in">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">The PSPP processor reported # errors.  The first # and last # are shown below:</property>
-                    <property name="wrap">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow1">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="hscrollbar_policy">automatic</property>
-                    <property name="vscrollbar_policy">automatic</property>
-                    <property name="shadow_type">etched-in</property>
-                    <child>
-                      <object class="GtkTextView" id="message">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="editable">False</property>
-                        <property name="wrap_mode">word</property>
-                        <property name="left_margin">6</property>
-                        <property name="right_margin">6</property>
-                        <property name="cursor_visible">False</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area1">
-            <property name="visible">True</property>
-            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="close-button">
-                <property name="label">gtk-close</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <action-widgets>
-      <action-widget response="0">close-button</action-widget>
-    </action-widgets>
-  </object>
-</interface>
index 9e2190b2909e181475309ed1c58e10b3ce304872..bc31022a5d7056876007cb9b95a6f1fa1e2fa48a 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
+
+#include "ui/gui/psppire-dict.h"
+
 #include <string.h>
 #include <stdlib.h>
-
 #include <gtk/gtk.h>
-#include <ui/gui/psppire-marshal.h>
-
-#include "psppire-var-ptr.h"
-#include "psppire-dict.h"
-#include <data/dictionary.h>
-#include <data/missing-values.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <libpspp/i18n.h>
-
-#include "helper.h"
-#include "message-dialog.h"
 
+#include "data/dictionary.h"
+#include "data/missing-values.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/psppire-marshal.h"
+#include "ui/gui/psppire-var-ptr.h"
 
 enum  {
   BACKEND_CHANGED,
index 1c04e93b72244a8e5001c921d57dc1acf9cda60f..e61269164046cfaa6792f2ece2b390d2d23bc3b9 100644 (file)
@@ -40,9 +40,9 @@
 #include "libpspp/version.h"
 #include "output/driver.h"
 #include "output/journal.h"
+#include "output/message-item.h"
 #include "ui/gui/dict-display.h"
 #include "ui/gui/executor.h"
-#include "ui/gui/message-dialog.h"
 #include "ui/gui/psppire-data-store.h"
 #include "ui/gui/psppire-data-window.h"
 #include "ui/gui/psppire-dict.h"
@@ -70,6 +70,7 @@ struct dataset * the_dataset = NULL;
 
 static GtkWidget *the_data_window;
 
+static void handle_msg (const struct msg *);
 static void load_data_file (const char *);
 
 static void
@@ -99,8 +100,8 @@ initialize (struct source_stream *ss, const char *data_file)
 
   the_dataset = create_dataset ();
 
-  message_dialog_init (the_source_stream);
   the_source_stream = ss;
+  msg_init (ss, handle_msg);
 
   dictionary = psppire_dict_new_from_dict (dataset_dict (the_dataset));
 
@@ -140,7 +141,6 @@ void
 de_initialize (void)
 {
   destroy_source_stream (the_source_stream);
-  message_dialog_done ();
   settings_done ();
   output_close ();
   i18n_done ();
@@ -295,3 +295,9 @@ load_data_file (const char *arg)
 
   g_free (filename);
 }
+
+static void
+handle_msg (const struct msg *m)
+{
+  message_item_submit (message_item_create (m));
+}
index 10b3b7e9abc9e92027ccfb8504b4acd6dbac5ed7..02be4f78c0e777f1e93df1719fc7fc0ed48f13f2 100644 (file)
@@ -129,13 +129,13 @@ main (int argc, char **argv)
                     "a cascade of dependent command failures."));
          getl_abort_noninteractive (the_source_stream);
        }
-      else
-       check_msg_count (the_source_stream);
+      else if (msg_ui_too_many_errors ())
+        getl_abort_noninteractive (the_source_stream);
     }
 
 
   clean_up ();
-  return any_errors ();
+  return msg_ui_any_errors ();
 }
 \f
 
index b5280fe6bba980949083151ddefc99c82b544dab..c657f096f3c16d9679f3bfafff44fa57017d2994 100644 (file)
 
 #include <config.h>
 
-#include "msg-ui.h"
-
-#include <data/settings.h>
-#include <libpspp/getl.h>
-#include <libpspp/message.h>
-#include <libpspp/msg-locator.h>
-#include <libpspp/str.h>
-#include <output/journal.h>
-#include <output/driver.h>
-#include <output/tab.h>
+#include "ui/terminal/msg-ui.h"
 
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "unilbrk.h"
-#include "localcharset.h"
+#include "data/settings.h"
+#include "libpspp/getl.h"
+#include "libpspp/message.h"
+#include "libpspp/msg-locator.h"
+#include "libpspp/str.h"
+#include "output/journal.h"
+#include "output/driver.h"
+#include "output/tab.h"
+#include "output/message-item.h"
+
+#include "gl/unilbrk.h"
+#include "gl/localcharset.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-/* Number of errors, warnings reported. */
-static int error_count;
-static int warning_count;
-static const char *error_file;
+/* Number of messages reported, by severity level. */
+static int counts[MSG_N_SEVERITIES];
 
-static void handle_msg (const struct msg *);
+/* True after the maximum number of errors or warnings has been exceeded. */
+static bool too_many_errors;
 
-static FILE *msg_file ;
+/* True after the maximum number of notes has been exceeded. */
+static bool too_many_notes;
 
-void
-msg_ui_set_error_file (const char *filename)
-{
-  error_file = filename;
-}
+static void handle_msg (const struct msg *);
 
 void
 msg_ui_init (struct source_stream *ss)
 {
-  msg_file = stdout;
-
-  if ( error_file )
-    {
-      msg_file = fopen (error_file, "a");
-      if ( NULL == msg_file )
-       {
-         int err = errno;
-         printf ( _("Cannot open %s (%s). "
-                    "Writing errors to stdout instead.\n"),
-                  error_file, strerror(err) );
-         msg_file = stdout;
-       }
-    }
   msg_init (ss, handle_msg);
 }
 
@@ -80,202 +63,80 @@ msg_ui_done (void)
 {
   msg_done ();
   msg_locator_done ();
-
-  if ( msg_file ) /* FIXME: do we really want to close stdout ?? */
-    fclose (msg_file);
 }
 
 /* Checks whether we've had so many errors that it's time to quit
    processing this syntax file. */
-void
-check_msg_count (struct source_stream *ss)
+bool
+msg_ui_too_many_errors (void)
 {
-  if (!getl_is_interactive (ss))
-    {
-      int max_errors = settings_get_max_messages (MSG_S_ERROR);
-      int max_warnings = settings_get_max_messages (MSG_S_WARNING);
-
-      if (error_count > max_errors)
-        msg (MN, _("Errors (%d) exceed limit (%d)."),
-             error_count, max_errors);
-      else if (error_count + warning_count > max_warnings)
-        msg (MN, _("Warnings (%d) exceed limit (%d)."),
-             error_count + warning_count, max_warnings);
-      else
-        return;
-
-      getl_abort_noninteractive (ss);
-    }
+  return too_many_errors;
 }
 
 void
-reset_msg_count (void)
+msg_ui_reset_counts (void)
 {
-  error_count = warning_count = 0;
+  int i;
+
+  for (i = 0; i < MSG_N_SEVERITIES; i++)
+    counts[i] = 0;
+  too_many_errors = false;
+  too_many_notes = false;
 }
 
 bool
-any_errors (void)
+msg_ui_any_errors (void)
 {
-  return error_count > 0;
+  return counts[MSG_S_ERROR] > 0;
 }
-\f
-typedef void write_line_func (int indent, struct substring line, void *aux);
-static void dump_message (char *msg, unsigned width, unsigned indent,
-                          write_line_func *, void *aux);
-static write_line_func write_stream;
-static write_line_func write_journal;
 
 static void
-handle_msg (const struct msg *m)
+submit_note (char *s)
 {
-  struct category
-    {
-      bool show_command_name;   /* Show command name with error? */
-      bool show_file_location;  /* Show syntax file location? */
-    };
-
-  static const struct category categories[] =
-    {
-      {false, false},           /* MSG_GENERAL. */
-      {true, true},             /* MSG_SYNTAX. */
-      {false, true},            /* MSG_DATA. */
-    };
-
-  struct severity
-    {
-      enum settings_output_type type;
-      const char *name;         /* How to identify this severity. */
-      int *count;               /* Number of msgs with this severity so far. */
-    };
-
-  static struct severity severities[] =
-    {
-      { SETTINGS_OUTPUT_ERROR, N_("error"), &error_count },
-      { SETTINGS_OUTPUT_ERROR, N_("warning"), &warning_count },
-      { SETTINGS_OUTPUT_NOTE, NULL, NULL},
-    };
-
-  const struct category *category = &categories[m->category];
-  const struct severity *severity = &severities[m->severity];
-  struct string string = DS_EMPTY_INITIALIZER;
-  enum settings_output_devices routing;
-
-  if (category->show_file_location && m->where.file_name)
-    {
-      ds_put_format (&string, "%s:", m->where.file_name);
-      if (m->where.line_number != -1)
-       ds_put_format (&string, "%d:", m->where.line_number);
-      ds_put_char (&string, ' ');
-    }
-
-  if (severity->name != NULL)
-    ds_put_format (&string, "%s: ", gettext (severity->name));
-
-  if (severity->count != NULL)
-    ++*severity->count;
-
-  if (category->show_command_name && msg_get_command_name () != NULL)
-    ds_put_format (&string, "%s: ", msg_get_command_name ());
-
-  ds_put_cstr (&string, m->text);
-
-  routing = settings_get_output_routing (severity->type);
-  if (msg_file != stdout || routing & SETTINGS_DEVICE_TERMINAL)
-    dump_message (ds_cstr (&string),
-                  isatty (fileno (msg_file)) ? settings_get_viewwidth () : INT_MAX, 8,
-                  write_stream, msg_file);
-
-  dump_message (ds_cstr (&string), 78, 0, write_journal, NULL);
-
-  if (routing & SETTINGS_DEVICE_LISTING)
-    {
-      /* Disable terminal output devices, because the error should already have
-         been reported to the terminal with the dump_message call above. */
-      settings_set_output_routing (severity->type,
-                                   routing & ~SETTINGS_DEVICE_TERMINAL);
-      tab_output_text (TAB_LEFT, ds_cstr (&string));
-      settings_set_output_routing (severity->type, routing);
-    }
-
-  ds_destroy (&string);
+  struct msg m;
+
+  m.category = MSG_C_GENERAL;
+  m.severity = MSG_S_NOTE;
+  m.where.file_name = NULL;
+  m.where.line_number = -1;
+  m.text = s;
+  message_item_submit (message_item_create (&m));
+  free (s);
 }
 
-/* Divides MSG into lines of WIDTH width for the first line and
-   WIDTH - INDENT width for each succeeding line, and writes the
-   lines by calling DUMP_LINE for each line, passing AUX as
-   auxiliary data. */
 static void
-dump_message (char *msg, unsigned width, unsigned indent,
-              write_line_func *dump_line, void *aux)
+handle_msg (const struct msg *m)
 {
-  size_t length = strlen (msg);
-  char *string, *breaks;
-  int line_indent;
-  size_t line_start, i;
-
-  /* Allocate temporary buffers.
-     If we can't get memory for them, then just dump the whole
-     message. */
-  string = strdup (msg);
-  breaks = malloc (length);
-  if (string == NULL || breaks == NULL)
-    {
-      free (string);
-      free (breaks);
-      dump_line (0, ss_cstr (msg), aux);
-      return;
-    }
-
-  /* Break into lines. */
-  if (indent > width / 3)
-    indent = width / 3;
-  ulc_width_linebreaks (string, length,
-                        width - indent, -indent, 0,
-                        NULL, locale_charset (), breaks);
+  int n_msgs, max_msgs;
 
-  /* Write out lines. */
-  line_start = 0;
-  line_indent = 0;
-  for (i = 0; i < length; i++)
-    if (breaks[i] == UC_BREAK_POSSIBLE || breaks[i] == UC_BREAK_MANDATORY)
-      {
-        dump_line (line_indent,
-                   ss_buffer (string + line_start, i - line_start), aux);
-        line_indent = indent;
+  if (too_many_errors || (too_many_notes && m->severity == MSG_S_NOTE))
+    return;
 
-        /* UC_BREAK_POSSIBLE means that a line break can be
-           inserted, and that the character should be included
-           in the next line.
-           UC_BREAK_MANDATORY means that this character is a line
-           break, so it should not be included in the next line. */
-        line_start = i + (breaks[i] == UC_BREAK_MANDATORY);
-      }
-  if (line_start < length)
-    dump_line (line_indent,
-               ss_buffer (string + line_start, length - line_start), aux);
-
-  free (string);
-  free (breaks);
-}
+  message_item_submit (message_item_create (m));
 
-/* Write LINE_INDENT spaces, LINE, then a new-line to STREAM. */
-static void
-write_stream (int line_indent, struct substring line, void *stream_)
-{
-  FILE *stream = stream_;
-  int i;
-  for (i = 0; i < line_indent; i++)
-    putc (' ', stream);
-  fwrite (ss_data (line), 1, ss_length (line), stream);
-  putc ('\n', stream);
-}
-
-/* Writes LINE to the journal. */
-static void
-write_journal (int line_indent UNUSED, struct substring line, void *unused UNUSED)
-{
-  char *s = xstrndup (ss_data (line), ss_length (line));
-  journal_write (true, s);
-  free (s);
+  counts[m->severity]++;
+  max_msgs = settings_get_max_messages (m->severity);
+  n_msgs = counts[m->severity];
+  if (m->severity == MSG_S_WARNING)
+    n_msgs += counts[MSG_S_ERROR];
+  if (n_msgs > max_msgs)
+    {
+      if (m->severity == MSG_S_NOTE)
+        {
+          too_many_notes = true;
+          submit_note (xasprintf (_("Notes (%d) exceed limit (%d).  "
+                                    "Suppressing further notes."),
+                                  n_msgs, max_msgs));
+        }
+      else
+        {
+          too_many_errors = true;
+          if (m->severity == MSG_S_WARNING)
+            submit_note (xasprintf (_("Warnings (%d) exceed limit (%d)."),
+                                    n_msgs, max_msgs));
+          else
+            submit_note (xasprintf (_("Errors (%d) exceed limit (%d)."),
+                                    n_msgs, max_msgs));
+        }
+    }
 }
index aa49e730e012d681db53f25dfdf35e2deeb39795..2c08a8822aa4f9948da02f8b13f466882dca76d1 100644 (file)
 #define MSG_UI_H 1
 
 #include <stdbool.h>
+#include <stdio.h>
 
-struct source_stream ;
+struct source_stream;
 
-void msg_ui_set_error_file (const char *filename);
+void msg_ui_set_error_file (FILE *);
 void msg_ui_init (struct source_stream *);
 void msg_ui_done (void);
-void check_msg_count (struct source_stream *);
-void reset_msg_count (void);
-bool any_errors (void);
+bool msg_ui_too_many_errors (void);
+void msg_ui_reset_counts (void);
+bool msg_ui_any_errors (void);
 
 #endif /* msg-ui.h */
index 54f90858a5d90542aa70d0d7bade755d5ecd9621..0fa145c98ac502edb7f29f25e471a2ca6ee885b7 100644 (file)
@@ -151,7 +151,7 @@ readln_read (struct string *line, enum prompt_style style)
 
   assert (initialised);
 
-  reset_msg_count ();
+  msg_ui_reset_counts ();
 
   welcome ();
 
index 886bcdc2fe86bafcb7b602d0fcef3e0bdbdd4ffc..a0f6072b521b65698ee4d0c6bb33fee8da2f4b4e 100644 (file)
@@ -38,6 +38,7 @@
 #include "libpspp/version.h"
 #include "output/driver.h"
 #include "output/driver-provider.h"
+#include "output/msglog.h"
 #include "ui/terminal/msg-ui.h"
 #include "ui/terminal/read-line.h"
 
@@ -57,6 +58,7 @@ struct terminal_opts
     struct string_map options;  /* Output driver options. */
     bool has_output_driver;
     bool has_terminal_driver;
+    bool has_error_file;
     bool process_statrc;
   };
 
@@ -234,7 +236,8 @@ terminal_option_callback (int id, void *to_)
       break;
 
     case OPT_ERROR_FILE:
-      msg_ui_set_error_file (optarg);
+      if (!strcmp (optarg, "none") || msglog_create (optarg))
+        to->has_error_file = true;
       break;
 
     case OPT_OUTPUT:
@@ -279,6 +282,7 @@ terminal_opts_init (struct argv_parser *ap, struct source_stream *ss)
   to->syntax_mode = GETL_BATCH;
   string_map_init (&to->options);
   to->has_output_driver = false;
+  to->has_error_file = false;
   to->process_statrc = true;
 
   argv_parser_add_options (ap, terminal_argv_options, N_TERMINAL_OPTIONS,
@@ -331,6 +335,9 @@ terminal_opts_done (struct terminal_opts *to, int argc, char *argv[])
       register_output_driver (to);
     }
 
+  if (to->has_terminal_driver && !to->has_error_file)
+    msglog_create ("-");
+
   string_map_destroy (&to->options);
   free (to);
 }