This will allow the argument to be processed through the macro processor.
S_DOCUMENT_1,
S_DOCUMENT_2,
S_DOCUMENT_3,
- S_FILE_LABEL,
+ S_FILE_LABEL_1,
+ S_FILE_LABEL_2,
+ S_FILE_LABEL_3,
S_DO_REPEAT_1,
S_DO_REPEAT_2,
S_DO_REPEAT_3,
S_BEGIN_DATA_2,
S_BEGIN_DATA_3,
S_BEGIN_DATA_4,
- S_TITLE_1,
- S_TITLE_2
};
#define SS_START_OF_LINE (1u << 0)
*type = SEG_START_DOCUMENT;
return 0;
}
- else if (lex_id_match (ss_cstr ("TITLE"), word)
- || lex_id_match (ss_cstr ("SUBTITLE"), word))
- {
- int result = segmenter_unquoted (input, n, eof, ofs);
- if (result < 0)
- return -1;
- else if (result)
- {
- s->state = S_TITLE_1;
- return ofs;
- }
- }
else if (lex_id_match_n (ss_cstr ("DEFINE"), word, 6))
{
s->state = S_DEFINE_1;
return -1;
else if (lex_id_match (ss_cstr ("LABEL"), ss_cstr (id)))
{
- s->state = S_FILE_LABEL;
+ s->state = S_FILE_LABEL_1;
s->substate = 0;
return ofs;
}
}
static int
-segmenter_parse_file_label__ (struct segmenter *s,
- const char *input, size_t n, bool eof,
- enum segment_type *type)
+segmenter_parse_file_label_1__ (struct segmenter *s,
+ const char *input, size_t n, bool eof,
+ enum segment_type *type)
{
struct segmenter sub;
int ofs;
else
{
if (result)
- s->state = S_TITLE_1;
+ s->state = S_FILE_LABEL_2;
else
*s = sub;
return ofs;
}
}
+static int
+segmenter_parse_file_label_2__ (struct segmenter *s,
+ const char *input, size_t n, bool eof,
+ enum segment_type *type)
+{
+ int ofs;
+
+ ofs = skip_spaces (input, n, eof, 0);
+ if (ofs < 0)
+ return -1;
+ s->state = S_FILE_LABEL_3;
+ *type = SEG_SPACES;
+ return ofs;
+}
+
+static int
+segmenter_parse_file_label_3__ (struct segmenter *s,
+ const char *input, size_t n, bool eof,
+ enum segment_type *type)
+{
+ int endcmd;
+ int ofs;
+
+ endcmd = -1;
+ ofs = 0;
+ while (ofs < n)
+ {
+ ucs4_t uc;
+ int mblen;
+
+ mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
+ if (mblen < 0)
+ return -1;
+
+ switch (uc)
+ {
+ case '\n':
+ goto end_of_line;
+
+ case '.':
+ endcmd = ofs;
+ break;
+
+ default:
+ if (!lex_uc_is_space (uc))
+ endcmd = -1;
+ break;
+ }
+
+ ofs += mblen;
+ }
+
+ if (eof)
+ {
+ end_of_line:
+ s->state = S_GENERAL;
+ s->substate = 0;
+ *type = SEG_UNQUOTED_STRING;
+ return endcmd >= 0 ? endcmd : ofs;
+ }
+
+ return -1;
+}
+
static int
segmenter_subparse (struct segmenter *s,
const char *input, size_t n, bool eof,
return ofs;
}
-static int
-segmenter_parse_title_1__ (struct segmenter *s,
- const char *input, size_t n, bool eof,
- enum segment_type *type)
-{
- int ofs;
-
- ofs = skip_spaces (input, n, eof, 0);
- if (ofs < 0)
- return -1;
- s->state = S_TITLE_2;
- *type = SEG_SPACES;
- return ofs;
-}
-
-static int
-segmenter_parse_title_2__ (struct segmenter *s,
- const char *input, size_t n, bool eof,
- enum segment_type *type)
-{
- int endcmd;
- int ofs;
-
- endcmd = -1;
- ofs = 0;
- while (ofs < n)
- {
- ucs4_t uc;
- int mblen;
-
- mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
- if (mblen < 0)
- return -1;
-
- switch (uc)
- {
- case '\n':
- goto end_of_line;
-
- case '.':
- endcmd = ofs;
- break;
-
- default:
- if (!lex_uc_is_space (uc))
- endcmd = -1;
- break;
- }
-
- ofs += mblen;
- }
-
- if (eof)
- {
- end_of_line:
- s->state = S_GENERAL;
- s->substate = 0;
- *type = SEG_UNQUOTED_STRING;
- return endcmd >= 0 ? endcmd : ofs;
- }
-
- return -1;
-}
-
/* Returns the name of segment TYPE as a string. The caller must not modify
or free the returned string.
case S_DOCUMENT_3:
return segmenter_parse_document_3__ (s, type);
- case S_FILE_LABEL:
- return segmenter_parse_file_label__ (s, input, n, eof, type);
+ case S_FILE_LABEL_1:
+ return segmenter_parse_file_label_1__ (s, input, n, eof, type);
+ case S_FILE_LABEL_2:
+ return segmenter_parse_file_label_2__ (s, input, n, eof, type);
+ case S_FILE_LABEL_3:
+ return segmenter_parse_file_label_3__ (s, input, n, eof, type);
case S_DO_REPEAT_1:
return segmenter_parse_do_repeat_1__ (s, input, n, eof, type);
return segmenter_parse_begin_data_3__ (s, input, n, eof, type);
case S_BEGIN_DATA_4:
return segmenter_parse_begin_data_4__ (s, input, n, eof, type);
-
- case S_TITLE_1:
- return segmenter_parse_title_1__ (s, input, n, eof, type);
- case S_TITLE_2:
- return segmenter_parse_title_2__ (s, input, n, eof, type);
}
NOT_REACHED ();
case S_DOCUMENT_3:
return PROMPT_FIRST;
- case S_FILE_LABEL:
+ case S_FILE_LABEL_1:
return PROMPT_LATER;
+ case S_FILE_LABEL_2:
+ case S_FILE_LABEL_3:
+ return PROMPT_FIRST;
case S_DO_REPEAT_1:
case S_DO_REPEAT_2:
case S_BEGIN_DATA_4:
return PROMPT_DATA;
- case S_TITLE_1:
- case S_TITLE_2:
- return PROMPT_FIRST;
}
NOT_REACHED ();
return xstrdup (buf);
}
+static char *
+show_SUBTITLE (const struct dataset *ds UNUSED)
+{
+ return xstrdup (output_get_subtitle ());
+}
+
static char *
show_SYSTEM (const struct dataset *ds UNUSED)
{
- return strdup (host_system);
+ return xstrdup (host_system);
}
static char *
show_TEMPDIR (const struct dataset *ds UNUSED)
{
- return strdup (temp_dir_name ());
+ return xstrdup (temp_dir_name ());
+}
+
+static char *
+show_TITLE (const struct dataset *ds UNUSED)
+{
+ return xstrdup (output_get_title ());
}
static bool
do_show (const struct dataset *ds, const struct setting *s)
{
char *value = s->show (ds);
- msg (SN, _("%s is %s."), s->name, value);
+ msg (SN, _("%s is %s."), s->name, value ? value : _("empty"));
free (value);
}
show_warranty (ds);
else if (lex_match_id (lexer, "COPYING") || lex_match_id (lexer, "LICENSE"))
show_copying (ds);
+ else if (lex_match_id (lexer, "TITLE"))
+ {
+ struct setting s = { .name = "TITLE", .show = show_TITLE };
+ do_show (ds, &s);
+ }
+ else if (lex_match_id (lexer, "SUBTITLE"))
+ {
+ struct setting s = { .name = "SUBTITLE", .show = show_SUBTITLE };
+ do_show (ds, &s);
+ }
else if (lex_token (lexer) == T_ID)
{
int i;
#include "data/variable.h"
#include "language/command.h"
#include "language/lexer/lexer.h"
+#include "language/lexer/token.h"
#include "libpspp/message.h"
#include "libpspp/start-date.h"
#include "libpspp/version.h"
#include "output/driver.h"
+#include "gl/c-ctype.h"
#include "gl/xalloc.h"
#include "gettext.h"
static int
parse_title (struct lexer *lexer, void (*set_title) (const char *))
{
- if (!lex_force_string (lexer))
- return CMD_FAILURE;
- set_title (lex_tokcstr (lexer));
- lex_get (lexer);
+ if (lex_token (lexer) == T_STRING)
+ {
+ set_title (lex_tokcstr (lexer));
+ lex_get (lexer);
+ }
+ else if (lex_token (lexer) == T_ENDCMD)
+ {
+ /* This would be a bad special case below because n-1 would be
+ SIZE_MAX. */
+ set_title ("");
+ }
+ else
+ {
+ /* Count the tokens in the title. */
+ size_t n = 0;
+ while (lex_next (lexer, n)->type != T_ENDCMD)
+ n++;
+
+ /* Get the raw representation of all the tokens, including any space
+ between them, and use it as the title. */
+ char *title = ss_xstrdup (lex_next_representation (lexer, 0, n - 1));
+ set_title (title);
+ free (title);
+
+ /* Skip past the tokens. */
+ for (size_t i = 0; i < n; i++)
+ lex_get (lexer);
+ }
return CMD_SUCCESS;
}
output_submit (text_item_create_nocopy (TEXT_ITEM_LOG, s, NULL));
}
+const char *
+output_get_title (void)
+{
+ return engine_stack_top ()->title;
+}
+
void
output_set_title (const char *title)
{
output_set_title__ (e, &e->title, title);
}
+const char *
+output_get_subtitle (void)
+{
+ return engine_stack_top ()->subtitle;
+}
+
void
output_set_subtitle (const char *subtitle)
{
void output_log (const char *, ...) PRINTF_FORMAT (1, 2);
+const char *output_get_title (void);
void output_set_title (const char *);
+const char *output_get_subtitle (void);
void output_set_subtitle (const char *);
void output_set_filename (const char *);
PSPP_CHECK_SCAN([-i])
AT_CLEANUP
\f
-AT_SETUP([TITLE, SUBTITLE, FILE LABEL commands])
+AT_SETUP([FILE LABEL commands])
AT_KEYWORDS([scan])
AT_DATA([input], [dnl
-title/**/'Quoted string title'.
-tit /*
-"Quoted string on second line".
-sub "Quoted string subtitle"
- .
-
-TITL /* Not a */ quoted string title.
-SUBT Not a quoted string /* subtitle
-
FIL label isn't quoted.
FILE
lab 'is quoted'.
])
AT_DATA([expout-base], [dnl
-ID "title"
-SKIP
-STRING "Quoted string title"
-ENDCMD
-SKIP
-ID "tit"
-SKIP
-SKIP
-SKIP
-STRING "Quoted string on second line"
-ENDCMD
-SKIP
-ID "sub"
-SKIP
-STRING "Quoted string subtitle"
-SKIP
-SKIP
-ENDCMD
-SKIP
-ENDCMD
-SKIP
-ID "TITL"
-SKIP
-STRING "/* Not a */ quoted string title"
-ENDCMD
-SKIP
-ID "SUBT"
-SKIP
-STRING "Not a quoted string /* subtitle"
-SKIP
-ENDCMD
-SKIP
ID "FIL"
SKIP
ID "label"
newline \n (first)
identifier title space
-unquoted_string my_title
+identifier my space
+identifier title
end_command .
newline \n (first)
PSPP_CHECK_SEGMENT([-i])
AT_CLEANUP
\f
-AT_SETUP([TITLE, SUBTITLE, FILE LABEL commands])
+AT_SETUP([FILE LABEL command])
AT_KEYWORDS([segment])
AT_DATA([input], [dnl
-title/**/'Quoted string title'.
-tit /*
-"Quoted string on second line".
-sub "Quoted string subtitle"
- .
-
-TITL /* Not a */ quoted string title.
-SUBT Not a quoted string /* subtitle
-
FIL label isn't quoted.
FILE
lab 'is quoted'.
])
AT_DATA([expout-base], [dnl
-identifier title
-comment /**/
-quoted_string 'Quoted_string_title'
-end_command .
-newline \n (first)
-
-identifier tit space
-comment /*
-newline \n (later)
-
-quoted_string "Quoted_string_on_second_line"
-end_command .
-newline \n (first)
-
-identifier sub space
-quoted_string "Quoted_string_subtitle"
-newline \n (later)
- space
-end_command .
-newline \n (first)
-
-separate_commands
-newline \n (first)
-
-identifier TITL space
-unquoted_string /*_Not_a_*/_quoted_string_title
-end_command .
-newline \n (first)
-
-identifier SUBT space
-unquoted_string Not_a_quoted_string_/*_subtitle
-newline \n (later)
-
-separate_commands
-newline \n (first)
-
identifier FIL space
identifier label space
unquoted_string isn't_quoted
Label,This is a test file label
])
AT_CLEANUP
+
+AT_SETUP([TITLE and SUBTITLE])
+for command in TITLE SUBTITLE; do
+ cat >title.sps <<EOF
+$command foo bar.
+SHOW $command.
+
+$command 'foo bar baz quux'.
+SHOW $command.
+EOF
+ cat >expout <<EOF
+title.sps:2: note: SHOW: $command is foo bar.
+
+title.sps:5: note: SHOW: $command is foo bar baz quux.
+EOF
+ AT_CHECK([pspp -O format=csv title.sps], [0], [expout])
+done
+AT_CLEANUP