output: Introduce group_item in place of TEXT_ITEM_COMMAND_OPEN and CLOSE.
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 25 Dec 2018 04:54:44 +0000 (20:54 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 25 Dec 2018 21:21:16 +0000 (13:21 -0800)
This allows groups to be nested.

22 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/driver.h
src/output/group-item.c [new file with mode: 0644]
src/output/group-item.h [new file with mode: 0644]
src/output/html.c
src/output/journal.c
src/output/message-item.c
src/output/message-item.h
src/output/msglog.c
src/output/odt.c
src/output/text-item.h
src/ui/gui/psppire-output-view.c
src/ui/gui/psppire.c
src/ui/terminal/main.c
tests/language/data-io/inpt-pgm.at

index 8f955b3e4987022ab1bd66950bf0a956668cd206..0a198bc94c4f6015c128477cd9641abc42136030 100644 (file)
@@ -36,7 +36,7 @@
 #include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
-#include "output/text-item.h"
+#include "output/group-item.h"
 
 #include "xalloc.h"
 #include "xmalloca.h"
@@ -199,7 +199,7 @@ do_parse_command (struct lexer *lexer,
       result = CMD_FAILURE;
       goto finish;
     }
-  text_item_submit (text_item_create (TEXT_ITEM_COMMAND_OPEN, command->name));
+  group_open_item_submit (group_open_item_create (command->name));
   opened = true;
 
   if (command->function == NULL)
@@ -247,8 +247,7 @@ finish:
       lex_get (lexer);
 
   if (opened)
-    text_item_submit (text_item_create (TEXT_ITEM_COMMAND_CLOSE,
-                                        command->name));
+    group_close_item_submit (group_close_item_create ());
 
   return result;
 }
index 356fcf9b1fc39bb7b3e59b67977a042383da7403..de3dab8df754efb40cd357ee1311cbc3223cb7a3 100644 (file)
@@ -128,6 +128,8 @@ msg_dup (const struct msg *m)
   new_msg = xmemdup (m, sizeof *m);
   if (m->file_name != NULL)
     new_msg->file_name = xstrdup (m->file_name);
+  if (m->command_name != NULL)
+    new_msg->command_name = xstrdup (m->command_name);
   new_msg->text = xstrdup (m->text);
 
   return new_msg;
@@ -143,11 +145,12 @@ msg_destroy (struct msg *m)
 {
   free (m->file_name);
   free (m->text);
+  free (m->command_name);
   free (m);
 }
 
 char *
-msg_to_string (const struct msg *m, const char *command_name)
+msg_to_string (const struct msg *m)
 {
   struct string s;
 
@@ -210,8 +213,8 @@ msg_to_string (const struct msg *m, const char *command_name)
 
   ds_put_format (&s, "%s: ", msg_severity_to_string (m->severity));
 
-  if (m->category == MSG_C_SYNTAX && command_name != NULL)
-    ds_put_format (&s, "%s: ", command_name);
+  if (m->category == MSG_C_SYNTAX && m->command_name != NULL)
+    ds_put_format (&s, "%s: ", m->command_name);
 
   ds_put_cstr (&s, m->text);
 
@@ -349,6 +352,7 @@ msg_emit (struct msg *m)
      process_msg (m);
 
   free (m->text);
+  free (m->command_name);
 }
 
 /* Disables message output until the next call to msg_enable.  If
index f2ec23c2c331c8b4007cbecf5cb545179a2191dd..720b9f23d78b8c4903e01aafccd50cbcb3d5e8d4 100644 (file)
@@ -75,6 +75,7 @@ struct msg
     enum msg_category category; /* Message category. */
     enum msg_severity severity; /* Message severity. */
     char *file_name;            /* Name of file containing error, or NULL. */
+    char *command_name;         /* Name of erroneous command, or NULL.  */
     int first_line;             /* 1-based line number, or 0 if none. */
     int last_line;             /* 1-based exclusive last line (0=none). */
     int first_column;           /* 1-based first column, or 0 if none. */
@@ -90,7 +91,7 @@ void msg_set_handler (void (*handler) (const struct msg *, void *lexer),
 /* 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);
+char *msg_to_string (const struct msg *);
 
 /* Emitting messages. */
 void vmsg (enum msg_class class, const char *format, va_list args)
index 46ab98a95c41a7dab77b0ccd1145bd59ec8be794..fd580107e3be30a8df60ed7533fe69c966d25e9b 100644 (file)
@@ -485,10 +485,6 @@ ascii_submit (struct output_driver *driver,
       switch (type)
         {
         case TEXT_ITEM_PAGE_TITLE:
-        case TEXT_ITEM_COMMAND_OPEN:
-        case TEXT_ITEM_COMMAND_CLOSE:
-          break;
-
         case TEXT_ITEM_BLANK_LINE:
           break;
 
@@ -503,8 +499,7 @@ ascii_submit (struct output_driver *driver,
   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, message_item->command_name);
+      char *s = msg_to_string (message_item_get_msg (message_item));
       ascii_output_text (a, s);
       free (s);
     }
index 9412c07f4933b4873e8fda8c00a4ccfda5ef3956..576168dae2e758f808ed2479e6a4a5bcb89275dc 100644 (file)
@@ -48,6 +48,8 @@ src_output_liboutput_la_SOURCES = \
        src/output/driver-provider.h \
        src/output/driver.c \
        src/output/driver.h \
+       src/output/group-item.c \
+       src/output/group-item.h \
        src/output/html.c \
        src/output/journal.c \
        src/output/journal.h \
index 4debc93d8e29c02e88afb2e587c248bd49952132..4922590448c53326d9dccbb5b1065e3092dd6106 100644 (file)
@@ -1356,8 +1356,7 @@ xr_rendering_create (struct xr_driver *xr, const struct output_item *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, NULL);
+      char *s = msg_to_string (message_item_get_msg (message_item));
       r = xr_rendering_create_text (xr, s, cr);
       free (s);
     }
@@ -1668,9 +1667,6 @@ xr_render_text (struct xr_driver *xr, const struct text_item *text_item)
     case TEXT_ITEM_PAGE_TITLE:
       break;
 
-    case TEXT_ITEM_COMMAND_CLOSE:
-      break;
-
     case TEXT_ITEM_BLANK_LINE:
       if (xr->y > 0)
         xr->y += xr->char_height;
@@ -1692,8 +1688,7 @@ static struct xr_render_fsm *
 xr_render_message (struct xr_driver *xr,
                    const struct message_item *message_item)
 {
-  const struct msg *msg = message_item_get_msg (message_item);
-  char *s = msg_to_string (msg, message_item->command_name);
+  char *s = msg_to_string (message_item_get_msg (message_item));
   struct text_item *item = text_item_create (TEXT_ITEM_PARAGRAPH, s);
   free (s);
   struct xr_render_fsm *fsm = xr_create_text_renderer (xr, item);
index c5d418293efcaa00a340efa8900701172037cae8..8493df34c613e02b35c519126f73364ce55e0473 100644 (file)
@@ -268,8 +268,7 @@ csv_submit (struct output_driver *driver,
       enum text_item_type type = text_item_get_type (text_item);
       const char *text = text_item_get_text (text_item);
 
-      if (type == TEXT_ITEM_COMMAND_OPEN || type == TEXT_ITEM_COMMAND_CLOSE
-          || type == TEXT_ITEM_SYNTAX || type == TEXT_ITEM_PAGE_TITLE)
+      if (type == TEXT_ITEM_SYNTAX || type == TEXT_ITEM_PAGE_TITLE)
         return;
 
       csv_put_separator (csv);
@@ -279,8 +278,7 @@ csv_submit (struct output_driver *driver,
   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, message_item->command_name);
+      char *s = msg_to_string (message_item_get_msg (message_item));
       csv_put_separator (csv);
       csv_output_field (csv, s);
       free (s);
index b07330633386aff1d5854a318a602d14839bfa7e..6e60258329469ed6303c62b63809703e988e62ce 100644 (file)
@@ -34,6 +34,7 @@
 #include "libpspp/string-map.h"
 #include "libpspp/string-set.h"
 #include "libpspp/str.h"
+#include "output/group-item.h"
 #include "output/message-item.h"
 #include "output/output-item.h"
 #include "output/text-item.h"
@@ -51,6 +52,14 @@ struct output_engine
     struct string deferred_syntax; /* TEXT_ITEM_SYNTAX being accumulated. */
     char *command_name;            /* Name of command being processed. */
     char *title, *subtitle;        /* Components of page title. */
+
+    /* Output grouping stack.
+
+       TEXT_ITEM_GROUP_OPEN pushes a group on the stack and
+       TEXT_ITEM_GROUP_CLOSE pops one off. */
+    char **groups;               /* Command names of nested sections. */
+    size_t n_groups;
+    size_t allocated_groups;
   };
 
 static const struct output_driver_factory *factories[];
@@ -76,9 +85,9 @@ output_engine_push (void)
                                sizeof *engine_stack);
 
   e = &engine_stack[n_stack++];
+  memset (e, 0, sizeof *e);
   llx_init (&e->drivers);
   ds_init_empty (&e->deferred_syntax);
-  e->command_name = NULL;
   e->title = NULL;
   e->subtitle = NULL;
 }
@@ -99,6 +108,9 @@ output_engine_pop (void)
   free (e->command_name);
   free (e->title);
   free (e->subtitle);
+  for (size_t i = 0; i < e->n_groups; i++)
+    free (e->groups[i]);
+  free (e->groups);
 }
 
 void
@@ -184,33 +196,40 @@ output_submit (struct output_item *item)
 
   flush_deferred_syntax (e);
 
-  if (is_text_item (item))
+  if (is_group_open_item (item))
     {
-      const struct text_item *text_item = to_text_item (item);
-      const char *text = text_item_get_text (text_item);
-      enum text_item_type type = text_item_get_type (text_item);
+      const struct group_open_item *group_open_item
+        = to_group_open_item (item);
+      if (e->n_groups >= e->allocated_groups)
+        e->groups = x2nrealloc (e->groups, &e->allocated_groups,
+                                sizeof *e->groups);
+      e->groups[e->n_groups] = (group_open_item->command_name
+                                ? xstrdup (group_open_item->command_name)
+                                : NULL);
+      e->n_groups++;
+    }
+  else if (is_group_close_item (item))
+    {
+      assert (e->n_groups > 0);
 
-      if (type == TEXT_ITEM_COMMAND_OPEN)
-        {
-          free (e->command_name);
-          e->command_name = xstrdup (text);
-        }
-      else if (type == TEXT_ITEM_COMMAND_CLOSE)
-        {
-          free (e->command_name);
-          e->command_name = NULL;
-        }
+      size_t idx = --e->n_groups;
+      free (e->groups[idx]);
     }
-  else if (is_message_item (item))
+  output_submit__ (e, item);
+}
+
+const char *
+output_get_command_name (void)
+{
+  if (n_stack)
     {
-      struct message_item *message_item = to_message_item (item);
-      free (message_item->command_name);
-      message_item->command_name = (e->command_name
-                                    ? xstrdup (e->command_name)
-                                    : NULL);
+      struct output_engine *e = engine_stack_top ();
+      for (size_t i = e->n_groups; i-- > 0; )
+        if (e->groups[i])
+          return e->groups[i];
     }
 
-  output_submit__ (e, item);
+  return NULL;
 }
 
 /* Flushes output to screen devices, so that the user can see
@@ -261,6 +280,14 @@ output_set_subtitle (const char *subtitle)
 
   output_set_title__ (e, &e->subtitle, subtitle);
 }
+
+size_t
+output_get_group_level (void)
+{
+  struct output_engine *e = engine_stack_top ();
+
+  return e->n_groups;
+}
 \f
 void
 output_driver_init (struct output_driver *driver,
index 5849a06ac14f450505c66bd22090808730d1d761..09281449df90cb26b530648ff48fcaaff9da56a5 100644 (file)
@@ -18,6 +18,7 @@
 #define OUTPUT_DRIVER_H 1
 
 #include <stdbool.h>
+#include <stddef.h>
 
 struct output_item;
 struct string_set;
@@ -33,6 +34,9 @@ void output_flush (void);
 
 void output_set_title (const char *);
 void output_set_subtitle (const char *);
+const char *output_get_command_name (void);
+
+size_t output_get_group_level (void);
 
 void output_driver_parse_option (const char *option,
                                  struct string_map *options);
diff --git a/src/output/group-item.c b/src/output/group-item.c
new file mode 100644 (file)
index 0000000..b5cb84e
--- /dev/null
@@ -0,0 +1,92 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2018 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/group-item.h"
+
+#include <stdlib.h>
+
+#include "output/driver.h"
+#include "output/output-item-provider.h"
+
+#include "gl/xalloc.h"
+
+struct group_open_item *
+group_open_item_create (const char *command_name)
+{
+  struct group_open_item *item;
+
+  item = xmalloc (sizeof *item);
+  output_item_init (&item->output_item, &group_open_item_class);
+  item->command_name = command_name ? xstrdup (command_name) : NULL;
+
+  return item;
+}
+
+/* Submits ITEM to the configured output drivers, and transfers ownership to
+   the output subsystem. */
+void
+group_open_item_submit (struct group_open_item *item)
+{
+  output_submit (&item->output_item);
+}
+
+static void
+group_open_item_destroy (struct output_item *output_item)
+{
+  struct group_open_item *item = to_group_open_item (output_item);
+
+  free (item->command_name);
+  free (item);
+}
+
+const struct output_item_class group_open_item_class =
+  {
+    group_open_item_destroy,
+  };
+\f
+struct group_close_item *
+group_close_item_create (void)
+{
+  struct group_close_item *item;
+
+  item = xmalloc (sizeof *item);
+  output_item_init (&item->output_item, &group_close_item_class);
+
+  return item;
+}
+
+/* Submits ITEM to the configured output drivers, and transfers ownership to
+   the output subsystem. */
+void
+group_close_item_submit (struct group_close_item *item)
+{
+  output_submit (&item->output_item);
+}
+
+static void
+group_close_item_destroy (struct output_item *output_item)
+{
+  struct group_close_item *item = to_group_close_item (output_item);
+
+  free (item);
+}
+
+const struct output_item_class group_close_item_class =
+  {
+    group_close_item_destroy,
+  };
diff --git a/src/output/group-item.h b/src/output/group-item.h
new file mode 100644 (file)
index 0000000..09bde59
--- /dev/null
@@ -0,0 +1,156 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2018 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_GROUP_ITEM_H
+#define OUTPUT_GROUP_ITEM_H 1
+
+/* Grouping items.
+
+   A group-open item marks the beginning of a group of related output items.  A
+   later group-close item ends the group.  Groups can nest. */
+
+#include <stdbool.h>
+#include "output/output-item.h"
+
+/* A group_open item. */
+struct group_open_item
+  {
+    struct output_item output_item;
+    char *command_name;
+  };
+
+struct group_open_item *group_open_item_create (const char *command_name);
+
+/* A group_close item. */
+struct group_close_item
+  {
+    struct output_item output_item;
+  };
+struct group_close_item *group_close_item_create (void);
+\f
+/* This boilerplate for group_open_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 group_open_item_class;
+
+/* Returns true if SUPER is a group_open_item, otherwise false. */
+static inline bool
+is_group_open_item (const struct output_item *super)
+{
+  return super->class == &group_open_item_class;
+}
+
+/* Returns SUPER converted to group_open_item.  SUPER must be a
+   group_open_item, as reported by is_group_open_item. */
+static inline struct group_open_item *
+to_group_open_item (const struct output_item *super)
+{
+  assert (is_group_open_item (super));
+  return UP_CAST (super, struct group_open_item, output_item);
+}
+
+/* Returns INSTANCE converted to output_item. */
+static inline struct output_item *
+group_open_item_super (const struct group_open_item *instance)
+{
+  return CONST_CAST (struct output_item *, &instance->output_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct group_open_item *
+group_open_item_ref (const struct group_open_item *instance)
+{
+  return to_group_open_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
+group_open_item_unref (struct group_open_item *instance)
+{
+  output_item_unref (&instance->output_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+group_open_item_is_shared (const struct group_open_item *instance)
+{
+  return output_item_is_shared (&instance->output_item);
+}
+
+void group_open_item_submit (struct group_open_item *);
+\f
+/* This boilerplate for group_close_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 group_close_item_class;
+
+/* Returns true if SUPER is a group_close_item, otherwise false. */
+static inline bool
+is_group_close_item (const struct output_item *super)
+{
+  return super->class == &group_close_item_class;
+}
+
+/* Returns SUPER converted to group_close_item.  SUPER must be a
+   group_close_item, as reported by is_group_close_item. */
+static inline struct group_close_item *
+to_group_close_item (const struct output_item *super)
+{
+  assert (is_group_close_item (super));
+  return UP_CAST (super, struct group_close_item, output_item);
+}
+
+/* Returns INSTANCE converted to output_item. */
+static inline struct output_item *
+group_close_item_super (const struct group_close_item *instance)
+{
+  return CONST_CAST (struct output_item *, &instance->output_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct group_close_item *
+group_close_item_ref (const struct group_close_item *instance)
+{
+  return to_group_close_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
+group_close_item_unref (struct group_close_item *instance)
+{
+  output_item_unref (&instance->output_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+group_close_item_is_shared (const struct group_close_item *instance)
+{
+  return output_item_is_shared (&instance->output_item);
+}
+
+void group_close_item_submit (struct group_close_item *);
+\f
+#endif /* output/group-item.h */
index d75b13190948ee1896ede47bd0851f6e4490df4f..84843cbd64eebb17d37aab86f21bce0d0eb55cfa 100644 (file)
@@ -264,17 +264,6 @@ html_submit (struct output_driver *driver,
         case TEXT_ITEM_PAGE_TITLE:
           break;
 
-        case TEXT_ITEM_COMMAND_OPEN:
-          fprintf (html->file, "<DIV class=\"");
-          escape_string (html->file, s, strlen (s), "_", "<BR>");
-          fprintf (html->file, "\">");
-          print_title_tag (html->file, "H3", s);
-          break;
-
-        case TEXT_ITEM_COMMAND_CLOSE:
-          fprintf (html->file, "</DIV>\n");
-          break;
-
         case TEXT_ITEM_SUBHEAD:
           print_title_tag (html->file, "H4", s);
           break;
@@ -310,8 +299,7 @@ html_submit (struct output_driver *driver,
   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, message_item->command_name);
+      char *s = msg_to_string (message_item_get_msg (message_item));
       print_title_tag (html->file, "P", s);
       free (s);
     }
index 5ace0db2164f08206dd9daf6df96da83263e44b9..92fa793be1db62ebaae4575732b6e5e8b5e60401 100644 (file)
@@ -114,8 +114,7 @@ journal_submit (struct output_driver *driver, const struct output_item *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, message_item->command_name);
+      char *s = msg_to_string (message_item_get_msg (message_item));
       journal_output (j, s);
       free (s);
     }
index a44784fe2eac99b7b8291290366682fdcc83367e..feb1d32c02eed54e13cb66eba6c869c429447f2b 100644 (file)
@@ -34,7 +34,6 @@ message_item_create (const struct msg *msg)
   item = xmalloc (sizeof *msg);
   output_item_init (&item->output_item, &message_item_class);
   item->msg = msg_dup (msg);
-  item->command_name = NULL;
 
   return item;
 }
@@ -50,7 +49,6 @@ message_item_destroy (struct output_item *output_item)
 {
   struct message_item *item = to_message_item (output_item);
   msg_destroy (item->msg);
-  free (item->command_name);
   free (item);
 }
 
index 8f0befe350b91a3f8bb17d10b626cc13678e8646..88450f1adee4cc91276e649853794eaab767fe95 100644 (file)
@@ -36,7 +36,6 @@ struct message_item
   {
     struct output_item output_item;
     struct msg *msg;
-    char *command_name;
   };
 
 struct message_item *message_item_create (const struct msg *);
index 9b606b4f18f1bde7cfdb478eac1bb3985334c7cb..ef2cf6b007deef169f6481b32ef7d5c80352479c 100644 (file)
@@ -101,8 +101,7 @@ msglog_submit (struct output_driver *driver, const struct output_item *item)
   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, message_item->command_name);
+      char *s = msg_to_string (message_item_get_msg (message_item));
       fprintf (ml->file, "%s\n", s);
       free (s);
     }
index 1d430eac5a355b234bef250e95cc7464ee6e1b44..18827a600e6f0135e8d5d3c0c3469b1a20b869c7 100644 (file)
@@ -578,17 +578,11 @@ odt_submit (struct output_driver *driver,
   if (is_table_item (output_item))
     write_table (odt, to_table_item (output_item));
   else if (is_text_item (output_item))
-    {
-      struct text_item *text_item = to_text_item (output_item);
-
-      if (text_item_get_type (text_item) != TEXT_ITEM_COMMAND_CLOSE)
-        odt_output_text (odt, text_item_get_text (text_item));
-    }
+    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, message_item->command_name);
+      char *s = msg_to_string (message_item_get_msg (message_item));
       odt_output_text (odt, s);
       free (s);
     }
index e09d06badc4da4f3ff11d8b626f72a393c9f4eee..1bfb63689b28cd94f6cce1c14b7c8fa570456e03 100644 (file)
 
 enum text_item_type
   {
-    /* Each PSPP command is bracketed between a pair of these text items.  The
-       text item's string is the full name of the command.  The syntax text
-       items associated with the command, as well as all output produced
-       directly by the command, are contained within the pair.  There is no
-       nesting. */
-    TEXT_ITEM_COMMAND_OPEN,     /* Command starting. */
-    TEXT_ITEM_COMMAND_CLOSE,    /* Command completed. */
-
     /* Headings. */
     TEXT_ITEM_PAGE_TITLE,       /* TITLE and SUBTITLE commands. */
     TEXT_ITEM_SUBHEAD,          /* Heading within a command's output.*/
index dd8618f7337d37560f8570e010440446babea4df..80e394faf528978c8d204f9d74a1d364a457588e 100644 (file)
@@ -27,6 +27,7 @@
 #include "output/driver-provider.h"
 #include "output/driver.h"
 #include "output/chart-item.h"
+#include "output/group-item.h"
 #include "output/message-item.h"
 #include "output/output-item.h"
 #include "output/table-item.h"
@@ -292,18 +293,19 @@ psppire_output_view_put (struct psppire_output_view *view,
   GtkTreeIter iter;
   int tw, th;
 
-  if (is_text_item (item))
+  if (is_group_close_item (item))
     {
-      const struct text_item *text_item = to_text_item (item);
-      enum text_item_type type = text_item_get_type (text_item);
-      const char *text = text_item_get_text (text_item);
-
-      if (type == TEXT_ITEM_COMMAND_CLOSE)
+      if (output_get_group_level () == 0)
         {
           view->in_command = false;
           return;
         }
-      else if (text[0] == '\0')
+    }
+  else if (is_text_item (item))
+    {
+      const struct text_item *text_item = to_text_item (item);
+      const char *text = text_item_get_text (text_item);
+      if (text[0] == '\0')
         return;
     }
 
@@ -344,8 +346,7 @@ psppire_output_view_put (struct psppire_output_view *view,
       store = GTK_TREE_STORE (gtk_tree_view_get_model (view->overview));
 
       ds_init_empty (&name);
-      if (is_text_item (item)
-          && text_item_get_type (to_text_item (item)) == TEXT_ITEM_COMMAND_OPEN)
+      if (is_group_open_item (item) && output_get_group_level () == 1)
         {
           gtk_tree_store_append (store, &iter, NULL);
           view->cur_command = iter; /* XXX shouldn't save a GtkTreeIter */
index af61eeefc188f70cb79507a55e3972fd9cbdb371..1f903beda993c75616491e08f11f7100408ac2aa 100644 (file)
@@ -160,6 +160,7 @@ handle_msg (const struct msg *m_, void *lexer_)
       m.first_column = lex_get_first_column (lexer, 0);
       m.last_column = lex_get_last_column (lexer, 0);
     }
+  m.command_name = CONST_CAST (char *, output_get_command_name ());
 
   message_item_submit (message_item_create (&m));
 }
index f7ec11520a95a573bf07a59088d545b373185dc0..4609e4eded20f39fc93e74e4d432b4de25ee4772 100644 (file)
@@ -226,6 +226,8 @@ output_msg (const struct msg *m_, void *lexer_)
       m.last_line = lex_get_last_line_number (lexer, 0);
     }
 
+  m.command_name = CONST_CAST (char *, output_get_command_name ());
+
   message_item_submit (message_item_create (&m));
 }
 
index a6ce23eefb3303c000a4312366e541f769c486ce..4cb53210802af516d850688929d35223fe1e4594 100644 (file)
@@ -57,7 +57,7 @@ END INPUT PROGRAM.
 EXECUTE.
 ])
 AT_CHECK([pspp -O format=csv input-program.sps], [1], [dnl
-input-program.sps:3: error: Input program must contain DATA LIST or END FILE.
+input-program.sps:3: error: INPUT PROGRAM: Input program must contain DATA LIST or END FILE.
 
 input-program.sps:4: error: EXECUTE: EXECUTE is allowed only after the active dataset has been defined.
 ])