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/tab.h"
44 #include "output/text-item.h"
46 #include "gl/xalloc.h"
49 #define _(msgid) gettext (msgid)
51 /* Describes what to do when an output field is encountered. */
54 PRT_LITERAL, /* Literal string. */
55 PRT_VAR /* Variable. */
58 /* Describes how to output one field. */
62 struct ll ll; /* In struct print_trns `specs' list. */
63 enum field_type type; /* What type of field this is. */
64 int record; /* 1-based record number. */
65 int first_column; /* 0-based first column. */
68 const struct variable *var; /* Associated variable. */
69 struct fmt_spec format; /* Output spec. */
70 bool add_space; /* Add trailing space? */
71 bool sysmis_as_spaces; /* Output SYSMIS as spaces? */
73 /* PRT_LITERAL only. */
74 struct string string; /* String to output. */
75 int width; /* Width of 'string', in display columns. */
78 /* PRINT, PRINT EJECT, WRITE private data structure. */
81 struct pool *pool; /* Stores related data. */
82 bool eject; /* Eject page before printing? */
83 bool include_prefix; /* Prefix lines with space? */
84 const char *encoding; /* Encoding to use for output. */
85 struct dfm_writer *writer; /* Output file, NULL=listing file. */
86 struct ll_list specs; /* List of struct prt_out_specs. */
87 size_t record_cnt; /* Number of records to write. */
96 static int internal_cmd_print (struct lexer *, struct dataset *ds,
97 enum which_formats, bool eject);
98 static trns_proc_func print_text_trns_proc, print_binary_trns_proc;
99 static trns_free_func print_trns_free;
100 static bool parse_specs (struct lexer *, struct pool *tmp_pool, struct print_trns *,
101 struct dictionary *dict, enum which_formats);
102 static void dump_table (struct print_trns *, const struct file_handle *);
106 /* Parses PRINT command. */
108 cmd_print (struct lexer *lexer, struct dataset *ds)
110 return internal_cmd_print (lexer, ds, PRINT, false);
113 /* Parses PRINT EJECT command. */
115 cmd_print_eject (struct lexer *lexer, struct dataset *ds)
117 return internal_cmd_print (lexer, ds, PRINT, true);
120 /* Parses WRITE command. */
122 cmd_write (struct lexer *lexer, struct dataset *ds)
124 return internal_cmd_print (lexer, ds, WRITE, false);
127 /* Parses the output commands. */
129 internal_cmd_print (struct lexer *lexer, struct dataset *ds,
130 enum which_formats which_formats, bool eject)
132 bool print_table = false;
133 const struct prt_out_spec *spec;
134 struct print_trns *trns;
135 struct file_handle *fh = NULL;
136 char *encoding = NULL;
137 struct pool *tmp_pool;
140 /* Fill in prt to facilitate error-handling. */
141 trns = pool_create_container (struct print_trns, pool);
144 trns->record_cnt = 0;
145 ll_init (&trns->specs);
147 tmp_pool = pool_create_subpool (trns->pool);
149 /* Parse the command options. */
150 while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
152 if (lex_match_id (lexer, "OUTFILE"))
154 lex_match (lexer, T_EQUALS);
156 fh = fh_parse (lexer, FH_REF_FILE, NULL);
160 else if (lex_match_id (lexer, "ENCODING"))
162 lex_match (lexer, T_EQUALS);
163 if (!lex_force_string (lexer))
167 encoding = ss_xstrdup (lex_tokss (lexer));
171 else if (lex_match_id (lexer, "RECORDS"))
173 lex_match (lexer, T_EQUALS);
174 lex_match (lexer, T_LPAREN);
175 if (!lex_force_int (lexer))
177 trns->record_cnt = lex_integer (lexer);
179 lex_match (lexer, T_RPAREN);
181 else if (lex_match_id (lexer, "TABLE"))
183 else if (lex_match_id (lexer, "NOTABLE"))
187 lex_error (lexer, _("expecting a valid subcommand"));
192 /* When PRINT or PRINT EJECT writes to an external file, we
193 prefix each line with a space for compatibility. */
194 trns->include_prefix = which_formats == PRINT && fh != NULL;
196 /* Parse variables and strings. */
197 if (!parse_specs (lexer, tmp_pool, trns, dataset_dict (ds), which_formats))
200 /* Are there any binary formats?
202 There are real difficulties figuring out what to do when both binary
203 formats and nontrivial encodings enter the picture. So when binary
204 formats are present we fall back to much simpler handling. */
206 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
208 if (spec->type == PRT_VAR
209 && fmt_get_category (spec->format.type) == FMT_CAT_BINARY)
215 if (binary && fh == NULL)
217 msg (SE, _("%s is required when binary formats are specified."), "OUTFILE");
221 if (lex_end_of_command (lexer) != CMD_SUCCESS)
226 trns->writer = dfm_open_writer (fh, encoding);
227 if (trns->writer == NULL)
229 trns->encoding = dfm_writer_get_encoding (trns->writer);
232 trns->encoding = UTF8;
234 /* Output the variable table if requested. */
236 dump_table (trns, fh);
238 /* Put the transformation in the queue. */
239 add_transformation (ds,
241 ? print_binary_trns_proc
242 : print_text_trns_proc),
243 print_trns_free, trns);
245 pool_destroy (tmp_pool);
251 print_trns_free (trns);
256 static bool parse_string_argument (struct lexer *, struct print_trns *,
257 int record, int *column);
258 static bool parse_variable_argument (struct lexer *, const struct dictionary *,
260 struct pool *tmp_pool,
261 int *record, int *column,
264 /* Parses all the variable and string specifications on a single
265 PRINT, PRINT EJECT, or WRITE command into the prt structure.
268 parse_specs (struct lexer *lexer, struct pool *tmp_pool, struct print_trns *trns,
269 struct dictionary *dict,
270 enum which_formats which_formats)
275 if (lex_token (lexer) == T_ENDCMD)
277 trns->record_cnt = 1;
281 while (lex_token (lexer) != T_ENDCMD)
285 if (!parse_record_placement (lexer, &record, &column))
288 if (lex_is_string (lexer))
289 ok = parse_string_argument (lexer, trns, record, &column);
291 ok = parse_variable_argument (lexer, dict, trns, tmp_pool, &record,
292 &column, which_formats);
296 lex_match (lexer, T_COMMA);
299 if (trns->record_cnt != 0 && trns->record_cnt != record)
300 msg (SW, _("Output calls for %d records but %zu specified on RECORDS "
302 record, trns->record_cnt);
303 trns->record_cnt = record;
308 /* Parses a string argument to the PRINT commands. Returns success. */
310 parse_string_argument (struct lexer *lexer, struct print_trns *trns, int record, int *column)
312 struct prt_out_spec *spec = pool_alloc (trns->pool, sizeof *spec);
313 spec->type = PRT_LITERAL;
314 spec->record = record;
315 spec->first_column = *column;
316 ds_init_substring (&spec->string, lex_tokss (lexer));
317 ds_register_pool (&spec->string, trns->pool);
320 /* Parse the included column range. */
321 if (lex_is_number (lexer))
323 int first_column, last_column;
324 bool range_specified;
326 if (!parse_column_range (lexer, 1,
327 &first_column, &last_column, &range_specified))
330 spec->first_column = first_column;
332 ds_set_length (&spec->string, last_column - first_column + 1, ' ');
335 spec->width = u8_strwidth (CHAR_CAST (const uint8_t *,
336 ds_cstr (&spec->string)),
338 *column = spec->first_column + spec->width;
340 ll_push_tail (&trns->specs, &spec->ll);
344 /* Parses a variable argument to the PRINT commands by passing it off
345 to fixed_parse_compatible() or fixed_parse_fortran() as appropriate.
348 parse_variable_argument (struct lexer *lexer, const struct dictionary *dict,
349 struct print_trns *trns, struct pool *tmp_pool,
350 int *record, int *column,
351 enum which_formats which_formats)
353 const struct variable **vars;
354 size_t var_cnt, var_idx;
355 struct fmt_spec *formats, *f;
359 if (!parse_variables_const_pool (lexer, tmp_pool, dict,
360 &vars, &var_cnt, PV_DUPLICATE))
363 if (lex_is_number (lexer) || lex_token (lexer) == T_LPAREN)
365 if (!parse_var_placements (lexer, tmp_pool, var_cnt, FMT_FOR_OUTPUT,
366 &formats, &format_cnt))
374 lex_match (lexer, T_ASTERISK);
376 formats = pool_nmalloc (tmp_pool, var_cnt, sizeof *formats);
377 format_cnt = var_cnt;
378 for (i = 0; i < var_cnt; i++)
380 const struct variable *v = vars[i];
381 formats[i] = (which_formats == PRINT
382 ? *var_get_print_format (v)
383 : *var_get_write_format (v));
385 add_space = which_formats == PRINT;
389 for (f = formats; f < &formats[format_cnt]; f++)
390 if (!execute_placement_format (f, record, column))
392 const struct variable *var;
393 struct prt_out_spec *spec;
395 var = vars[var_idx++];
396 if (!fmt_check_width_compat (f, var_get_width (var)))
399 spec = pool_alloc (trns->pool, sizeof *spec);
400 spec->type = PRT_VAR;
401 spec->record = *record;
402 spec->first_column = *column;
405 spec->add_space = add_space;
407 /* This is a completely bizarre twist for compatibility:
408 WRITE outputs the system-missing value as a field
409 filled with spaces, instead of using the normal format
410 that usually contains a period. */
411 spec->sysmis_as_spaces = (which_formats == WRITE
412 && var_is_numeric (var)
413 && (fmt_get_category (spec->format.type)
416 ll_push_tail (&trns->specs, &spec->ll);
418 *column += f->w + add_space;
420 assert (var_idx == var_cnt);
425 /* Prints the table produced by the TABLE subcommand to the listing
428 dump_table (struct print_trns *trns, const struct file_handle *fh)
430 struct prt_out_spec *spec;
435 spec_cnt = ll_count (&trns->specs);
436 t = tab_create (4, spec_cnt + 1);
437 tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, spec_cnt);
438 tab_hline (t, TAL_2, 0, 3, 1);
439 tab_headers (t, 0, 0, 1, 0);
440 tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable"));
441 tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record"));
442 tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns"));
443 tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format"));
445 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
447 char fmt_string[FMT_STRING_LEN_MAX + 1];
452 tab_text_format (t, 0, row, TAB_LEFT | TAB_FIX, "`%.*s'",
453 (int) ds_length (&spec->string),
454 ds_data (&spec->string));
455 width = ds_length (&spec->string);
458 tab_text (t, 0, row, TAB_LEFT, var_get_name (spec->var));
459 tab_text (t, 3, row, TAB_LEFT | TAB_FIX,
460 fmt_to_string (&spec->format, fmt_string));
461 width = spec->format.w;
466 tab_text_format (t, 1, row, 0, "%d", spec->record);
467 tab_text_format (t, 2, row, 0, "%3d-%3d",
468 spec->first_column, spec->first_column + width - 1);
473 tab_title (t, ngettext ("Writing %zu record to %s.",
474 "Writing %zu records to %s.", trns->record_cnt),
475 trns->record_cnt, fh_get_name (fh));
477 tab_title (t, ngettext ("Writing %zu record.",
478 "Writing %zu records.", trns->record_cnt),
483 /* Transformation, for all-text output. */
485 static void print_text_flush_records (struct print_trns *, struct u8_line *,
487 bool *eject, int *record);
489 /* Performs the transformation inside print_trns T on case C. */
491 print_text_trns_proc (void *trns_, struct ccase **c,
492 casenumber case_num UNUSED)
494 struct print_trns *trns = trns_;
495 struct prt_out_spec *spec;
498 bool eject = trns->eject;
501 u8_line_init (&line);
502 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
504 int x0 = spec->first_column;
506 print_text_flush_records (trns, &line, spec->record, &eject, &record);
508 u8_line_set_length (&line, spec->first_column);
509 if (spec->type == PRT_VAR)
511 const union value *input = case_data (*c, spec->var);
514 if (!spec->sysmis_as_spaces || input->f != SYSMIS)
520 s = data_out (input, var_get_encoding (spec->var),
523 width = u8_width (CHAR_CAST (const uint8_t *, s), len, UTF8);
525 u8_line_put (&line, x0, x1, s, len);
530 int n = spec->format.w;
533 memset (u8_line_reserve (&line, x0, x1, n), ' ', n);
537 *u8_line_reserve (&line, x1, x1 + 1, 1) = ' ';
541 const struct string *s = &spec->string;
543 u8_line_put (&line, x0, x0 + spec->width,
544 ds_data (s), ds_length (s));
547 print_text_flush_records (trns, &line, trns->record_cnt + 1,
549 u8_line_destroy (&line);
551 if (trns->writer != NULL && dfm_write_error (trns->writer))
553 return TRNS_CONTINUE;
556 /* Advance from *RECORD to TARGET_RECORD, outputting records
557 along the way. If *EJECT is true, then the first record
558 output is preceded by ejecting the page (and *EJECT is set
561 print_text_flush_records (struct print_trns *trns, struct u8_line *line,
562 int target_record, bool *eject, int *record)
564 for (; target_record > *record; (*record)++)
571 if (trns->writer == NULL)
572 text_item_submit (text_item_create (TEXT_ITEM_EJECT_PAGE, ""));
576 *u8_line_reserve (line, 0, 1, 1) = leader;
578 if (trns->writer == NULL)
579 tab_output_text (TAB_FIX, ds_cstr (&line->s) + 1);
582 size_t len = ds_length (&line->s);
583 char *s = ds_cstr (&line->s);
585 if (!trns->include_prefix)
591 if (is_encoding_utf8 (trns->encoding))
592 dfm_put_record (trns->writer, s, len);
595 char *recoded = recode_string (trns->encoding, UTF8, s, len);
596 dfm_put_record (trns->writer, recoded, strlen (recoded));
603 /* Transformation, for output involving binary. */
605 static void print_binary_flush_records (struct print_trns *,
606 struct string *line, int target_record,
607 bool *eject, int *record);
609 /* Performs the transformation inside print_trns T on case C. */
611 print_binary_trns_proc (void *trns_, struct ccase **c,
612 casenumber case_num UNUSED)
614 struct print_trns *trns = trns_;
615 bool eject = trns->eject;
616 char encoded_space = recode_byte (trns->encoding, C_ENCODING, ' ');
618 struct prt_out_spec *spec;
621 ds_init_empty (&line);
622 ds_put_byte (&line, ' ');
623 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
625 print_binary_flush_records (trns, &line, spec->record, &eject, &record);
627 ds_set_length (&line, spec->first_column, encoded_space);
628 if (spec->type == PRT_VAR)
630 const union value *input = case_data (*c, spec->var);
631 if (!spec->sysmis_as_spaces || input->f != SYSMIS)
632 data_out_recode (input, var_get_encoding (spec->var),
633 &spec->format, &line, trns->encoding);
635 ds_put_byte_multiple (&line, encoded_space, spec->format.w);
637 ds_put_byte (&line, encoded_space);
641 ds_put_substring (&line, ds_ss (&spec->string));
642 if (0 != strcmp (trns->encoding, UTF8))
644 size_t length = ds_length (&spec->string);
645 char *data = ss_data (ds_tail (&line, length));
646 char *s = recode_string (trns->encoding, UTF8, data, length);
647 memcpy (data, s, length);
652 print_binary_flush_records (trns, &line, trns->record_cnt + 1,
656 if (trns->writer != NULL && dfm_write_error (trns->writer))
658 return TRNS_CONTINUE;
661 /* Advance from *RECORD to TARGET_RECORD, outputting records
662 along the way. If *EJECT is true, then the first record
663 output is preceded by ejecting the page (and *EJECT is set
666 print_binary_flush_records (struct print_trns *trns, struct string *line,
667 int target_record, bool *eject, int *record)
669 for (; target_record > *record; (*record)++)
671 char *s = ds_cstr (line);
672 size_t length = ds_length (line);
680 s[0] = recode_byte (trns->encoding, C_ENCODING, leader);
682 if (!trns->include_prefix)
687 dfm_put_record (trns->writer, s, length);
689 ds_truncate (line, 1);
695 print_trns_free (void *trns_)
697 struct print_trns *trns = trns_;
700 if (trns->writer != NULL)
701 ok = dfm_close_writer (trns->writer);
702 pool_destroy (trns->pool);