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 static inline struct prt_out_spec *
79 ll_to_prt_out_spec (struct ll *ll)
81 return ll_data (ll, struct prt_out_spec, ll);
84 /* PRINT, PRINT EJECT, WRITE private data structure. */
87 struct pool *pool; /* Stores related data. */
88 bool eject; /* Eject page before printing? */
89 bool include_prefix; /* Prefix lines with space? */
90 const char *encoding; /* Encoding to use for output. */
91 struct dfm_writer *writer; /* Output file, NULL=listing file. */
92 struct ll_list specs; /* List of struct prt_out_specs. */
93 size_t record_cnt; /* Number of records to write. */
102 static int internal_cmd_print (struct lexer *, struct dataset *ds,
103 enum which_formats, bool eject);
104 static trns_proc_func print_text_trns_proc, print_binary_trns_proc;
105 static trns_free_func print_trns_free;
106 static bool parse_specs (struct lexer *, struct pool *tmp_pool, struct print_trns *,
107 struct dictionary *dict, enum which_formats);
108 static void dump_table (struct print_trns *, const struct file_handle *);
112 /* Parses PRINT command. */
114 cmd_print (struct lexer *lexer, struct dataset *ds)
116 return internal_cmd_print (lexer, ds, PRINT, false);
119 /* Parses PRINT EJECT command. */
121 cmd_print_eject (struct lexer *lexer, struct dataset *ds)
123 return internal_cmd_print (lexer, ds, PRINT, true);
126 /* Parses WRITE command. */
128 cmd_write (struct lexer *lexer, struct dataset *ds)
130 return internal_cmd_print (lexer, ds, WRITE, false);
133 /* Parses the output commands. */
135 internal_cmd_print (struct lexer *lexer, struct dataset *ds,
136 enum which_formats which_formats, bool eject)
138 bool print_table = false;
139 const struct prt_out_spec *spec;
140 struct print_trns *trns;
141 struct file_handle *fh = NULL;
142 char *encoding = NULL;
143 struct pool *tmp_pool;
146 /* Fill in prt to facilitate error-handling. */
147 trns = pool_create_container (struct print_trns, pool);
150 trns->record_cnt = 0;
151 ll_init (&trns->specs);
153 tmp_pool = pool_create_subpool (trns->pool);
155 /* Parse the command options. */
156 while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
158 if (lex_match_id (lexer, "OUTFILE"))
160 lex_match (lexer, T_EQUALS);
162 fh = fh_parse (lexer, FH_REF_FILE, NULL);
166 else if (lex_match_id (lexer, "ENCODING"))
168 lex_match (lexer, T_EQUALS);
169 if (!lex_force_string (lexer))
173 encoding = ss_xstrdup (lex_tokss (lexer));
177 else if (lex_match_id (lexer, "RECORDS"))
179 lex_match (lexer, T_EQUALS);
180 lex_match (lexer, T_LPAREN);
181 if (!lex_force_int (lexer))
183 trns->record_cnt = lex_integer (lexer);
185 lex_match (lexer, T_RPAREN);
187 else if (lex_match_id (lexer, "TABLE"))
189 else if (lex_match_id (lexer, "NOTABLE"))
193 lex_error (lexer, _("expecting a valid subcommand"));
198 /* When PRINT or PRINT EJECT writes to an external file, we
199 prefix each line with a space for compatibility. */
200 trns->include_prefix = which_formats == PRINT && fh != NULL;
202 /* Parse variables and strings. */
203 if (!parse_specs (lexer, tmp_pool, trns, dataset_dict (ds), which_formats))
206 /* Are there any binary formats?
208 There are real difficulties figuring out what to do when both binary
209 formats and nontrivial encodings enter the picture. So when binary
210 formats are present we fall back to much simpler handling. */
212 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
214 if (spec->type == PRT_VAR
215 && fmt_get_category (spec->format.type) == FMT_CAT_BINARY)
221 if (binary && fh == NULL)
223 msg (SE, _("%s is required when binary formats are specified."), "OUTFILE");
227 if (lex_end_of_command (lexer) != CMD_SUCCESS)
232 trns->writer = dfm_open_writer (fh, encoding);
233 if (trns->writer == NULL)
235 trns->encoding = dfm_writer_get_encoding (trns->writer);
238 trns->encoding = UTF8;
240 /* Output the variable table if requested. */
242 dump_table (trns, fh);
244 /* Put the transformation in the queue. */
245 add_transformation (ds,
247 ? print_binary_trns_proc
248 : print_text_trns_proc),
249 print_trns_free, trns);
251 pool_destroy (tmp_pool);
257 print_trns_free (trns);
262 static bool parse_string_argument (struct lexer *, struct print_trns *,
263 int record, int *column);
264 static bool parse_variable_argument (struct lexer *, const struct dictionary *,
266 struct pool *tmp_pool,
267 int *record, int *column,
270 /* Parses all the variable and string specifications on a single
271 PRINT, PRINT EJECT, or WRITE command into the prt structure.
274 parse_specs (struct lexer *lexer, struct pool *tmp_pool, struct print_trns *trns,
275 struct dictionary *dict,
276 enum which_formats which_formats)
281 if (lex_token (lexer) == T_ENDCMD)
283 trns->record_cnt = 1;
287 while (lex_token (lexer) != T_ENDCMD)
291 if (!parse_record_placement (lexer, &record, &column))
294 if (lex_is_string (lexer))
295 ok = parse_string_argument (lexer, trns, record, &column);
297 ok = parse_variable_argument (lexer, dict, trns, tmp_pool, &record,
298 &column, which_formats);
302 lex_match (lexer, T_COMMA);
305 if (trns->record_cnt != 0 && trns->record_cnt != record)
306 msg (SW, _("Output calls for %d records but %zu specified on RECORDS "
308 record, trns->record_cnt);
309 trns->record_cnt = record;
314 /* Parses a string argument to the PRINT commands. Returns success. */
316 parse_string_argument (struct lexer *lexer, struct print_trns *trns, int record, int *column)
318 struct prt_out_spec *spec = pool_alloc (trns->pool, sizeof *spec);
319 spec->type = PRT_LITERAL;
320 spec->record = record;
321 spec->first_column = *column;
322 ds_init_substring (&spec->string, lex_tokss (lexer));
323 ds_register_pool (&spec->string, trns->pool);
326 /* Parse the included column range. */
327 if (lex_is_number (lexer))
329 int first_column, last_column;
330 bool range_specified;
332 if (!parse_column_range (lexer, 1,
333 &first_column, &last_column, &range_specified))
336 spec->first_column = first_column;
338 ds_set_length (&spec->string, last_column - first_column + 1, ' ');
341 spec->width = u8_strwidth (CHAR_CAST (const uint8_t *,
342 ds_cstr (&spec->string)),
344 *column = spec->first_column + spec->width;
346 ll_push_tail (&trns->specs, &spec->ll);
350 /* Parses a variable argument to the PRINT commands by passing it off
351 to fixed_parse_compatible() or fixed_parse_fortran() as appropriate.
354 parse_variable_argument (struct lexer *lexer, const struct dictionary *dict,
355 struct print_trns *trns, struct pool *tmp_pool,
356 int *record, int *column,
357 enum which_formats which_formats)
359 const struct variable **vars;
360 size_t var_cnt, var_idx;
361 struct fmt_spec *formats, *f;
365 if (!parse_variables_const_pool (lexer, tmp_pool, dict,
366 &vars, &var_cnt, PV_DUPLICATE))
369 if (lex_is_number (lexer) || lex_token (lexer) == T_LPAREN)
371 if (!parse_var_placements (lexer, tmp_pool, var_cnt, FMT_FOR_OUTPUT,
372 &formats, &format_cnt))
380 lex_match (lexer, T_ASTERISK);
382 formats = pool_nmalloc (tmp_pool, var_cnt, sizeof *formats);
383 format_cnt = var_cnt;
384 for (i = 0; i < var_cnt; i++)
386 const struct variable *v = vars[i];
387 formats[i] = (which_formats == PRINT
388 ? *var_get_print_format (v)
389 : *var_get_write_format (v));
391 add_space = which_formats == PRINT;
395 for (f = formats; f < &formats[format_cnt]; f++)
396 if (!execute_placement_format (f, record, column))
398 const struct variable *var;
399 struct prt_out_spec *spec;
401 var = vars[var_idx++];
402 if (!fmt_check_width_compat (f, var_get_width (var)))
405 spec = pool_alloc (trns->pool, sizeof *spec);
406 spec->type = PRT_VAR;
407 spec->record = *record;
408 spec->first_column = *column;
411 spec->add_space = add_space;
413 /* This is a completely bizarre twist for compatibility:
414 WRITE outputs the system-missing value as a field
415 filled with spaces, instead of using the normal format
416 that usually contains a period. */
417 spec->sysmis_as_spaces = (which_formats == WRITE
418 && var_is_numeric (var)
419 && (fmt_get_category (spec->format.type)
422 ll_push_tail (&trns->specs, &spec->ll);
424 *column += f->w + add_space;
426 assert (var_idx == var_cnt);
431 /* Prints the table produced by the TABLE subcommand to the listing
434 dump_table (struct print_trns *trns, const struct file_handle *fh)
436 struct prt_out_spec *spec;
441 spec_cnt = ll_count (&trns->specs);
442 t = tab_create (4, spec_cnt + 1);
443 tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, spec_cnt);
444 tab_hline (t, TAL_2, 0, 3, 1);
445 tab_headers (t, 0, 0, 1, 0);
446 tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable"));
447 tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record"));
448 tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns"));
449 tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format"));
451 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
453 char fmt_string[FMT_STRING_LEN_MAX + 1];
458 tab_text_format (t, 0, row, TAB_LEFT | TAB_FIX, "`%.*s'",
459 (int) ds_length (&spec->string),
460 ds_data (&spec->string));
461 width = ds_length (&spec->string);
464 tab_text (t, 0, row, TAB_LEFT, var_get_name (spec->var));
465 tab_text (t, 3, row, TAB_LEFT | TAB_FIX,
466 fmt_to_string (&spec->format, fmt_string));
467 width = spec->format.w;
472 tab_text_format (t, 1, row, 0, "%d", spec->record);
473 tab_text_format (t, 2, row, 0, "%3d-%3d",
474 spec->first_column, spec->first_column + width - 1);
479 tab_title (t, ngettext ("Writing %zu record to %s.",
480 "Writing %zu records to %s.", trns->record_cnt),
481 trns->record_cnt, fh_get_name (fh));
483 tab_title (t, ngettext ("Writing %zu record.",
484 "Writing %zu records.", trns->record_cnt),
489 /* Transformation, for all-text output. */
491 static void print_text_flush_records (struct print_trns *, struct u8_line *,
493 bool *eject, int *record);
495 /* Performs the transformation inside print_trns T on case C. */
497 print_text_trns_proc (void *trns_, struct ccase **c,
498 casenumber case_num UNUSED)
500 struct print_trns *trns = trns_;
501 struct prt_out_spec *spec;
504 bool eject = trns->eject;
507 u8_line_init (&line);
508 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
510 int x0 = spec->first_column;
512 print_text_flush_records (trns, &line, spec->record, &eject, &record);
514 u8_line_set_length (&line, spec->first_column);
515 if (spec->type == PRT_VAR)
517 const union value *input = case_data (*c, spec->var);
520 if (!spec->sysmis_as_spaces || input->f != SYSMIS)
526 s = data_out (input, var_get_encoding (spec->var),
529 width = u8_width (CHAR_CAST (const uint8_t *, s), len, UTF8);
531 u8_line_put (&line, x0, x1, s, len);
536 int n = spec->format.w;
539 memset (u8_line_reserve (&line, x0, x1, n), ' ', n);
543 *u8_line_reserve (&line, x1, x1 + 1, 1) = ' ';
547 const struct string *s = &spec->string;
549 u8_line_put (&line, x0, x0 + spec->width,
550 ds_data (s), ds_length (s));
553 print_text_flush_records (trns, &line, trns->record_cnt + 1,
555 u8_line_destroy (&line);
557 if (trns->writer != NULL && dfm_write_error (trns->writer))
559 return TRNS_CONTINUE;
562 /* Advance from *RECORD to TARGET_RECORD, outputting records
563 along the way. If *EJECT is true, then the first record
564 output is preceded by ejecting the page (and *EJECT is set
567 print_text_flush_records (struct print_trns *trns, struct u8_line *line,
568 int target_record, bool *eject, int *record)
570 for (; target_record > *record; (*record)++)
577 if (trns->writer == NULL)
578 text_item_submit (text_item_create (TEXT_ITEM_EJECT_PAGE, ""));
582 *u8_line_reserve (line, 0, 1, 1) = leader;
584 if (trns->writer == NULL)
585 tab_output_text (TAB_FIX, ds_cstr (&line->s) + 1);
588 size_t len = ds_length (&line->s);
589 char *s = ds_cstr (&line->s);
591 if (!trns->include_prefix)
597 if (is_encoding_utf8 (trns->encoding))
598 dfm_put_record (trns->writer, s, len);
601 char *recoded = recode_string (trns->encoding, UTF8, s, len);
602 dfm_put_record (trns->writer, recoded, strlen (recoded));
609 /* Transformation, for output involving binary. */
611 static void print_binary_flush_records (struct print_trns *,
612 struct string *line, int target_record,
613 bool *eject, int *record);
615 /* Performs the transformation inside print_trns T on case C. */
617 print_binary_trns_proc (void *trns_, struct ccase **c,
618 casenumber case_num UNUSED)
620 struct print_trns *trns = trns_;
621 bool eject = trns->eject;
622 char encoded_space = recode_byte (trns->encoding, C_ENCODING, ' ');
624 struct prt_out_spec *spec;
627 ds_init_empty (&line);
628 ds_put_byte (&line, ' ');
629 ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
631 print_binary_flush_records (trns, &line, spec->record, &eject, &record);
633 ds_set_length (&line, spec->first_column, encoded_space);
634 if (spec->type == PRT_VAR)
636 const union value *input = case_data (*c, spec->var);
637 if (!spec->sysmis_as_spaces || input->f != SYSMIS)
638 data_out_recode (input, var_get_encoding (spec->var),
639 &spec->format, &line, trns->encoding);
641 ds_put_byte_multiple (&line, encoded_space, spec->format.w);
643 ds_put_byte (&line, encoded_space);
647 ds_put_substring (&line, ds_ss (&spec->string));
648 if (0 != strcmp (trns->encoding, UTF8))
650 size_t length = ds_length (&spec->string);
651 char *data = ss_data (ds_tail (&line, length));
652 char *s = recode_string (trns->encoding, UTF8, data, length);
653 memcpy (data, s, length);
658 print_binary_flush_records (trns, &line, trns->record_cnt + 1,
662 if (trns->writer != NULL && dfm_write_error (trns->writer))
664 return TRNS_CONTINUE;
667 /* Advance from *RECORD to TARGET_RECORD, outputting records
668 along the way. If *EJECT is true, then the first record
669 output is preceded by ejecting the page (and *EJECT is set
672 print_binary_flush_records (struct print_trns *trns, struct string *line,
673 int target_record, bool *eject, int *record)
675 for (; target_record > *record; (*record)++)
677 char *s = ds_cstr (line);
678 size_t length = ds_length (line);
686 s[0] = recode_byte (trns->encoding, C_ENCODING, leader);
688 if (!trns->include_prefix)
693 dfm_put_record (trns->writer, s, length);
695 ds_truncate (line, 1);
701 print_trns_free (void *trns_)
703 struct print_trns *trns = trns_;
706 if (trns->writer != NULL)
707 ok = dfm_close_writer (trns->writer);
708 pool_destroy (trns->pool);