1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "data/case.h"
23 #include "data/dataset.h"
24 #include "data/data-out.h"
25 #include "data/format.h"
26 #include "data/transformations.h"
27 #include "data/variable.h"
28 #include "language/command.h"
29 #include "language/data-io/data-writer.h"
30 #include "language/data-io/file-handle.h"
31 #include "language/data-io/placement-parser.h"
32 #include "language/lexer/format-parser.h"
33 #include "language/lexer/lexer.h"
34 #include "language/lexer/variable-parser.h"
35 #include "libpspp/assertion.h"
36 #include "libpspp/compiler.h"
37 #include "libpspp/i18n.h"
38 #include "libpspp/ll.h"
39 #include "libpspp/message.h"
40 #include "libpspp/misc.h"
41 #include "libpspp/pool.h"
42 #include "libpspp/u8-line.h"
43 #include "output/pivot-table.h"
44 #include "output/table.h"
45 #include "output/page-eject-item.h"
46 #include "output/text-item.h"
48 #include "gl/xalloc.h"
51 #define N_(msgid) msgid
52 #define _(msgid) gettext (msgid)
54 /* Describes what to do when an output field is encountered. */
57 PRT_LITERAL, /* Literal string. */
58 PRT_VAR /* Variable. */
61 /* Describes how to output one field. */
65 struct ll ll; /* In struct print_trns `specs' list. */
66 enum field_type type; /* What type of field this is. */
67 int record; /* 1-based record number. */
68 int first_column; /* 0-based first column. */
71 const struct variable *var; /* Associated variable. */
72 struct fmt_spec format; /* Output spec. */
73 bool add_space; /* Add trailing space? */
74 bool sysmis_as_spaces; /* Output SYSMIS as spaces? */
76 /* PRT_LITERAL only. */
77 struct string string; /* String to output. */
78 int width; /* Width of 'string', in display columns. */
81 /* PRINT, PRINT EJECT, WRITE private data structure. */
84 struct pool *pool; /* Stores related data. */
85 bool eject; /* Eject page before printing? */
86 bool include_prefix; /* Prefix lines with space? */
87 const char *encoding; /* Encoding to use for output. */
88 struct dfm_writer *writer; /* Output file, NULL=listing file. */
89 struct ll_list specs; /* List of struct prt_out_specs. */
90 size_t record_cnt; /* Number of records to write. */
99 static int internal_cmd_print (struct lexer *, struct dataset *ds,
100 enum which_formats, bool eject);
101 static trns_proc_func print_text_trns_proc, print_binary_trns_proc;
102 static trns_free_func print_trns_free;
103 static bool parse_specs (struct lexer *, struct pool *tmp_pool, struct print_trns *,
104 struct dictionary *dict, enum which_formats);
105 static void dump_table (struct print_trns *);
109 /* Parses PRINT command. */
111 cmd_print (struct lexer *lexer, struct dataset *ds)
113 return internal_cmd_print (lexer, ds, PRINT, false);
116 /* Parses PRINT EJECT command. */
118 cmd_print_eject (struct lexer *lexer, struct dataset *ds)
120 return internal_cmd_print (lexer, ds, PRINT, true);
123 /* Parses WRITE command. */
125 cmd_write (struct lexer *lexer, struct dataset *ds)
127 return internal_cmd_print (lexer, ds, WRITE, false);
130 /* Parses the output commands. */
132 internal_cmd_print (struct lexer *lexer, struct dataset *ds,
133 enum which_formats which_formats, bool eject)
135 bool print_table = false;
136 const struct prt_out_spec *spec;
137 struct print_trns *trns;
138 struct file_handle *fh = NULL;
139 char *encoding = NULL;
140 struct pool *tmp_pool;
143 /* Fill in prt to facilitate error-handling. */
144 trns = pool_create_container (struct print_trns, pool);
147 trns->record_cnt = 0;
148 ll_init (&trns->specs);
150 tmp_pool = pool_create_subpool (trns->pool);
152 /* Parse the command options. */
153 while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
155 if (lex_match_id (lexer, "OUTFILE"))
157 lex_match (lexer, T_EQUALS);
159 fh = fh_parse (lexer, FH_REF_FILE, NULL);
163 else if (lex_match_id (lexer, "ENCODING"))
165 lex_match (lexer, T_EQUALS);
166 if (!lex_force_string (lexer))
170 encoding = ss_xstrdup (lex_tokss (lexer));
174 else if (lex_match_id (lexer, "RECORDS"))
176 lex_match (lexer, T_EQUALS);
177 lex_match (lexer, T_LPAREN);
178 if (!lex_force_int (lexer))
180 trns->record_cnt = lex_integer (lexer);
182 lex_match (lexer, T_RPAREN);
184 else if (lex_match_id (lexer, "TABLE"))
186 else if (lex_match_id (lexer, "NOTABLE"))
190 lex_error (lexer, _("expecting a valid subcommand"));
195 /* When PRINT or PRINT EJECT writes to an external file, we
196 prefix each line with a space for compatibility. */
197 trns->include_prefix = which_formats == PRINT && fh != NULL;
199 /* Parse variables and strings. */
200 if (!parse_specs (lexer, tmp_pool, trns, dataset_dict (ds), which_formats))
203 /* Are there any binary formats?
205 There are real difficulties figuring out what to do when both binary
206 formats and nontrivial encodings enter the picture. So when binary
207 formats are present we fall back to much simpler handling. */
209 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
211 if (spec->type == PRT_VAR
212 && fmt_get_category (spec->format.type) == FMT_CAT_BINARY)
218 if (binary && fh == NULL)
220 msg (SE, _("%s is required when binary formats are specified."), "OUTFILE");
224 if (lex_end_of_command (lexer) != CMD_SUCCESS)
229 trns->writer = dfm_open_writer (fh, encoding);
230 if (trns->writer == NULL)
232 trns->encoding = dfm_writer_get_encoding (trns->writer);
235 trns->encoding = UTF8;
237 /* Output the variable table if requested. */
241 /* Put the transformation in the queue. */
242 add_transformation (ds,
244 ? print_binary_trns_proc
245 : print_text_trns_proc),
246 print_trns_free, trns);
248 pool_destroy (tmp_pool);
254 print_trns_free (trns);
259 static bool parse_string_argument (struct lexer *, struct print_trns *,
260 int record, int *column);
261 static bool parse_variable_argument (struct lexer *, const struct dictionary *,
263 struct pool *tmp_pool,
264 int *record, int *column,
267 /* Parses all the variable and string specifications on a single
268 PRINT, PRINT EJECT, or WRITE command into the prt structure.
271 parse_specs (struct lexer *lexer, struct pool *tmp_pool, struct print_trns *trns,
272 struct dictionary *dict,
273 enum which_formats which_formats)
278 if (lex_token (lexer) == T_ENDCMD)
280 trns->record_cnt = 1;
284 while (lex_token (lexer) != T_ENDCMD)
288 if (!parse_record_placement (lexer, &record, &column))
291 if (lex_is_string (lexer))
292 ok = parse_string_argument (lexer, trns, record, &column);
294 ok = parse_variable_argument (lexer, dict, trns, tmp_pool, &record,
295 &column, which_formats);
299 lex_match (lexer, T_COMMA);
302 if (trns->record_cnt != 0 && trns->record_cnt != record)
303 msg (SW, _("Output calls for %d records but %zu specified on RECORDS "
305 record, trns->record_cnt);
306 trns->record_cnt = record;
311 /* Parses a string argument to the PRINT commands. Returns success. */
313 parse_string_argument (struct lexer *lexer, struct print_trns *trns, int record, int *column)
315 struct prt_out_spec *spec = pool_alloc (trns->pool, sizeof *spec);
316 spec->type = PRT_LITERAL;
317 spec->record = record;
318 spec->first_column = *column;
319 ds_init_substring (&spec->string, lex_tokss (lexer));
320 ds_register_pool (&spec->string, trns->pool);
323 /* Parse the included column range. */
324 if (lex_is_number (lexer))
326 int first_column, last_column;
327 bool range_specified;
329 if (!parse_column_range (lexer, 1,
330 &first_column, &last_column, &range_specified))
333 spec->first_column = first_column;
335 ds_set_length (&spec->string, last_column - first_column + 1, ' ');
338 spec->width = u8_strwidth (CHAR_CAST (const uint8_t *,
339 ds_cstr (&spec->string)),
341 *column = spec->first_column + spec->width;
343 ll_push_tail (&trns->specs, &spec->ll);
347 /* Parses a variable argument to the PRINT commands by passing it off
348 to fixed_parse_compatible() or fixed_parse_fortran() as appropriate.
351 parse_variable_argument (struct lexer *lexer, const struct dictionary *dict,
352 struct print_trns *trns, struct pool *tmp_pool,
353 int *record, int *column,
354 enum which_formats which_formats)
356 const struct variable **vars;
357 size_t var_cnt, var_idx;
358 struct fmt_spec *formats, *f;
362 if (!parse_variables_const_pool (lexer, tmp_pool, dict,
363 &vars, &var_cnt, PV_DUPLICATE))
366 if (lex_is_number (lexer) || lex_token (lexer) == T_LPAREN)
368 if (!parse_var_placements (lexer, tmp_pool, var_cnt, FMT_FOR_OUTPUT,
369 &formats, &format_cnt))
377 lex_match (lexer, T_ASTERISK);
379 formats = pool_nmalloc (tmp_pool, var_cnt, sizeof *formats);
380 format_cnt = var_cnt;
381 for (i = 0; i < var_cnt; i++)
383 const struct variable *v = vars[i];
384 formats[i] = (which_formats == PRINT
385 ? *var_get_print_format (v)
386 : *var_get_write_format (v));
388 add_space = which_formats == PRINT;
392 for (f = formats; f < &formats[format_cnt]; f++)
393 if (!execute_placement_format (f, record, column))
395 const struct variable *var;
396 struct prt_out_spec *spec;
398 var = vars[var_idx++];
399 if (!fmt_check_width_compat (f, var_get_width (var)))
402 spec = pool_alloc (trns->pool, sizeof *spec);
403 spec->type = PRT_VAR;
404 spec->record = *record;
405 spec->first_column = *column;
408 spec->add_space = add_space;
410 /* This is a completely bizarre twist for compatibility:
411 WRITE outputs the system-missing value as a field
412 filled with spaces, instead of using the normal format
413 that usually contains a period. */
414 spec->sysmis_as_spaces = (which_formats == WRITE
415 && var_is_numeric (var)
416 && (fmt_get_category (spec->format.type)
419 ll_push_tail (&trns->specs, &spec->ll);
421 *column += f->w + add_space;
423 assert (var_idx == var_cnt);
428 /* Prints the table produced by the TABLE subcommand to the listing
431 dump_table (struct print_trns *trns)
433 struct pivot_table *table = pivot_table_create (N_("Print Summary"));
435 pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Attributes"),
436 N_("Record"), N_("Columns"), N_("Format"));
438 struct pivot_dimension *variables = pivot_dimension_create (
439 table, PIVOT_AXIS_ROW, N_("Variable"));
441 struct prt_out_spec *spec;
442 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
444 if (spec->type != PRT_VAR)
447 int row = pivot_category_create_leaf (
448 variables->root, pivot_value_new_variable (spec->var));
450 pivot_table_put2 (table, 0, row,
451 pivot_value_new_integer (spec->record));
452 int last_column = spec->first_column + spec->format.w - 1;
453 pivot_table_put2 (table, 1, row, pivot_value_new_user_text_nocopy (
455 spec->first_column, last_column)));
457 char fmt_string[FMT_STRING_LEN_MAX + 1];
458 pivot_table_put2 (table, 2, row, pivot_value_new_user_text (
459 fmt_to_string (&spec->format, fmt_string), -1));
462 int row = pivot_category_create_leaf (
463 variables->root, pivot_value_new_text (N_("N of Records")));
464 pivot_table_put2 (table, 0, row,
465 pivot_value_new_integer (trns->record_cnt));
467 pivot_table_submit (table);
470 /* Transformation, for all-text output. */
472 static void print_text_flush_records (struct print_trns *, struct u8_line *,
474 bool *eject, int *record);
476 /* Performs the transformation inside print_trns T on case C. */
478 print_text_trns_proc (void *trns_, struct ccase **c,
479 casenumber case_num UNUSED)
481 struct print_trns *trns = trns_;
482 struct prt_out_spec *spec;
485 bool eject = trns->eject;
488 u8_line_init (&line);
489 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
491 int x0 = spec->first_column;
493 print_text_flush_records (trns, &line, spec->record, &eject, &record);
495 u8_line_set_length (&line, spec->first_column);
496 if (spec->type == PRT_VAR)
498 const union value *input = case_data (*c, spec->var);
501 if (!spec->sysmis_as_spaces || input->f != SYSMIS)
507 s = data_out (input, var_get_encoding (spec->var),
510 width = u8_width (CHAR_CAST (const uint8_t *, s), len, UTF8);
512 u8_line_put (&line, x0, x1, s, len);
517 int n = spec->format.w;
520 memset (u8_line_reserve (&line, x0, x1, n), ' ', n);
524 *u8_line_reserve (&line, x1, x1 + 1, 1) = ' ';
528 const struct string *s = &spec->string;
530 u8_line_put (&line, x0, x0 + spec->width,
531 ds_data (s), ds_length (s));
534 print_text_flush_records (trns, &line, trns->record_cnt + 1,
536 u8_line_destroy (&line);
538 if (trns->writer != NULL && dfm_write_error (trns->writer))
540 return TRNS_CONTINUE;
543 /* Advance from *RECORD to TARGET_RECORD, outputting records
544 along the way. If *EJECT is true, then the first record
545 output is preceded by ejecting the page (and *EJECT is set
548 print_text_flush_records (struct print_trns *trns, struct u8_line *line,
549 int target_record, bool *eject, int *record)
551 for (; target_record > *record; (*record)++)
558 if (trns->writer == NULL)
559 page_eject_item_submit (page_eject_item_create ());
563 *u8_line_reserve (line, 0, 1, 1) = leader;
565 if (trns->writer == NULL)
566 table_output_text (TAB_FIX, ds_cstr (&line->s) + 1);
569 size_t len = ds_length (&line->s);
570 char *s = ds_cstr (&line->s);
572 if (!trns->include_prefix)
578 if (is_encoding_utf8 (trns->encoding))
579 dfm_put_record (trns->writer, s, len);
582 char *recoded = recode_string (trns->encoding, UTF8, s, len);
583 dfm_put_record (trns->writer, recoded, strlen (recoded));
590 /* Transformation, for output involving binary. */
592 static void print_binary_flush_records (struct print_trns *,
593 struct string *line, int target_record,
594 bool *eject, int *record);
596 /* Performs the transformation inside print_trns T on case C. */
598 print_binary_trns_proc (void *trns_, struct ccase **c,
599 casenumber case_num UNUSED)
601 struct print_trns *trns = trns_;
602 bool eject = trns->eject;
603 char encoded_space = recode_byte (trns->encoding, C_ENCODING, ' ');
605 struct prt_out_spec *spec;
608 ds_init_empty (&line);
609 ds_put_byte (&line, ' ');
610 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
612 print_binary_flush_records (trns, &line, spec->record, &eject, &record);
614 ds_set_length (&line, spec->first_column, encoded_space);
615 if (spec->type == PRT_VAR)
617 const union value *input = case_data (*c, spec->var);
618 if (!spec->sysmis_as_spaces || input->f != SYSMIS)
619 data_out_recode (input, var_get_encoding (spec->var),
620 &spec->format, &line, trns->encoding);
622 ds_put_byte_multiple (&line, encoded_space, spec->format.w);
624 ds_put_byte (&line, encoded_space);
628 ds_put_substring (&line, ds_ss (&spec->string));
629 if (0 != strcmp (trns->encoding, UTF8))
631 size_t length = ds_length (&spec->string);
632 char *data = ss_data (ds_tail (&line, length));
633 char *s = recode_string (trns->encoding, UTF8, data, length);
634 memcpy (data, s, length);
639 print_binary_flush_records (trns, &line, trns->record_cnt + 1,
643 if (trns->writer != NULL && dfm_write_error (trns->writer))
645 return TRNS_CONTINUE;
648 /* Advance from *RECORD to TARGET_RECORD, outputting records
649 along the way. If *EJECT is true, then the first record
650 output is preceded by ejecting the page (and *EJECT is set
653 print_binary_flush_records (struct print_trns *trns, struct string *line,
654 int target_record, bool *eject, int *record)
656 for (; target_record > *record; (*record)++)
658 char *s = ds_cstr (line);
659 size_t length = ds_length (line);
667 s[0] = recode_byte (trns->encoding, C_ENCODING, leader);
669 if (!trns->include_prefix)
674 dfm_put_record (trns->writer, s, length);
676 ds_truncate (line, 1);
682 print_trns_free (void *trns_)
684 struct print_trns *trns = trns_;
687 if (trns->writer != NULL)
688 ok = dfm_close_writer (trns->writer);
689 pool_destroy (trns->pool);