From a353919df75c25331144602421353a856f4236d6 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 24 Dec 2018 20:54:44 -0800 Subject: [PATCH] output: Introduce group_item in place of TEXT_ITEM_COMMAND_OPEN and CLOSE. This allows groups to be nested. --- src/language/command.c | 7 +- src/libpspp/message.c | 10 +- src/libpspp/message.h | 3 +- src/output/ascii.c | 7 +- src/output/automake.mk | 2 + src/output/cairo.c | 9 +- src/output/csv.c | 6 +- src/output/driver.c | 71 +++++++++---- src/output/driver.h | 4 + src/output/group-item.c | 92 +++++++++++++++++ src/output/group-item.h | 156 +++++++++++++++++++++++++++++ src/output/html.c | 14 +-- src/output/journal.c | 3 +- src/output/message-item.c | 2 - src/output/message-item.h | 1 - src/output/msglog.c | 3 +- src/output/odt.c | 10 +- src/output/text-item.h | 8 -- src/ui/gui/psppire-output-view.c | 19 ++-- src/ui/gui/psppire.c | 1 + src/ui/terminal/main.c | 2 + tests/language/data-io/inpt-pgm.at | 2 +- 22 files changed, 339 insertions(+), 93 deletions(-) create mode 100644 src/output/group-item.c create mode 100644 src/output/group-item.h diff --git a/src/language/command.c b/src/language/command.c index 8f955b3e49..0a198bc94c 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -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; } diff --git a/src/libpspp/message.c b/src/libpspp/message.c index 356fcf9b1f..de3dab8df7 100644 --- a/src/libpspp/message.c +++ b/src/libpspp/message.c @@ -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 diff --git a/src/libpspp/message.h b/src/libpspp/message.h index f2ec23c2c3..720b9f23d7 100644 --- a/src/libpspp/message.h +++ b/src/libpspp/message.h @@ -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) diff --git a/src/output/ascii.c b/src/output/ascii.c index 46ab98a95c..fd580107e3 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -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); } diff --git a/src/output/automake.mk b/src/output/automake.mk index 9412c07f49..576168dae2 100644 --- a/src/output/automake.mk +++ b/src/output/automake.mk @@ -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 \ diff --git a/src/output/cairo.c b/src/output/cairo.c index 4debc93d8e..4922590448 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -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); diff --git a/src/output/csv.c b/src/output/csv.c index c5d418293e..8493df34c6 100644 --- a/src/output/csv.c +++ b/src/output/csv.c @@ -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); diff --git a/src/output/driver.c b/src/output/driver.c index b073306333..6e60258329 100644 --- a/src/output/driver.c +++ b/src/output/driver.c @@ -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; +} void output_driver_init (struct output_driver *driver, diff --git a/src/output/driver.h b/src/output/driver.h index 5849a06ac1..09281449df 100644 --- a/src/output/driver.h +++ b/src/output/driver.h @@ -18,6 +18,7 @@ #define OUTPUT_DRIVER_H 1 #include +#include 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 index 0000000000..b5cb84ea59 --- /dev/null +++ b/src/output/group-item.c @@ -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 . */ + +#include + +#include "output/group-item.h" + +#include + +#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, + }; + +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 index 0000000000..09bde59023 --- /dev/null +++ b/src/output/group-item.h @@ -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 . */ + +#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 +#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); + +/* This boilerplate for group_open_item, a subclass of output_item, was + autogenerated by mk-class-boilerplate. */ + +#include +#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 *); + +/* This boilerplate for group_close_item, a subclass of output_item, was + autogenerated by mk-class-boilerplate. */ + +#include +#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 *); + +#endif /* output/group-item.h */ diff --git a/src/output/html.c b/src/output/html.c index d75b131909..84843cbd64 100644 --- a/src/output/html.c +++ b/src/output/html.c @@ -264,17 +264,6 @@ html_submit (struct output_driver *driver, case TEXT_ITEM_PAGE_TITLE: break; - case TEXT_ITEM_COMMAND_OPEN: - fprintf (html->file, "
file, s, strlen (s), "_", "
"); - fprintf (html->file, "\">"); - print_title_tag (html->file, "H3", s); - break; - - case TEXT_ITEM_COMMAND_CLOSE: - fprintf (html->file, "
\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); } diff --git a/src/output/journal.c b/src/output/journal.c index 5ace0db216..92fa793be1 100644 --- a/src/output/journal.c +++ b/src/output/journal.c @@ -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); } diff --git a/src/output/message-item.c b/src/output/message-item.c index a44784fe2e..feb1d32c02 100644 --- a/src/output/message-item.c +++ b/src/output/message-item.c @@ -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); } diff --git a/src/output/message-item.h b/src/output/message-item.h index 8f0befe350..88450f1ade 100644 --- a/src/output/message-item.h +++ b/src/output/message-item.h @@ -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 *); diff --git a/src/output/msglog.c b/src/output/msglog.c index 9b606b4f18..ef2cf6b007 100644 --- a/src/output/msglog.c +++ b/src/output/msglog.c @@ -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); } diff --git a/src/output/odt.c b/src/output/odt.c index 1d430eac5a..18827a600e 100644 --- a/src/output/odt.c +++ b/src/output/odt.c @@ -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); } diff --git a/src/output/text-item.h b/src/output/text-item.h index e09d06badc..1bfb63689b 100644 --- a/src/output/text-item.h +++ b/src/output/text-item.h @@ -30,14 +30,6 @@ 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.*/ diff --git a/src/ui/gui/psppire-output-view.c b/src/ui/gui/psppire-output-view.c index dd8618f733..80e394faf5 100644 --- a/src/ui/gui/psppire-output-view.c +++ b/src/ui/gui/psppire-output-view.c @@ -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 */ diff --git a/src/ui/gui/psppire.c b/src/ui/gui/psppire.c index af61eeefc1..1f903beda9 100644 --- a/src/ui/gui/psppire.c +++ b/src/ui/gui/psppire.c @@ -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)); } diff --git a/src/ui/terminal/main.c b/src/ui/terminal/main.c index f7ec11520a..4609e4eded 100644 --- a/src/ui/terminal/main.c +++ b/src/ui/terminal/main.c @@ -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)); } diff --git a/tests/language/data-io/inpt-pgm.at b/tests/language/data-io/inpt-pgm.at index a6ce23eefb..4cb5321080 100644 --- a/tests/language/data-io/inpt-pgm.at +++ b/tests/language/data-io/inpt-pgm.at @@ -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. ]) -- 2.30.2