Remove unneeded #includes.
[pspp] / src / language / data-io / print.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include <stdlib.h>
20 #include <uniwidth.h>
21
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/message.h"
39 #include "libpspp/misc.h"
40 #include "libpspp/pool.h"
41 #include "libpspp/u8-line.h"
42 #include "output/driver.h"
43 #include "output/pivot-table.h"
44 #include "output/output-item.h"
45
46 #include "gl/xalloc.h"
47
48 #include "gettext.h"
49 #define N_(msgid) msgid
50 #define _(msgid) gettext (msgid)
51
52 /* Describes what to do when an output field is encountered. */
53 enum field_type
54   {
55     PRT_LITERAL,                /* Literal string. */
56     PRT_VAR                     /* Variable. */
57   };
58
59 /* Describes how to output one field. */
60 struct prt_out_spec
61   {
62     /* All fields. */
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. */
66     int start_ofs, end_ofs;
67
68     /* PRT_VAR only. */
69     const struct variable *var; /* Associated variable. */
70     struct fmt_spec format;     /* Output spec. */
71     bool add_space;             /* Add trailing space? */
72     bool sysmis_as_spaces;      /* Output SYSMIS as spaces? */
73
74     /* PRT_LITERAL only. */
75     struct substring string;    /* String to output. */
76     int width;                  /* Width of 'string', in display columns. */
77   };
78
79 /* PRINT, PRINT EJECT, WRITE private data structure. */
80 struct print_trns
81   {
82     struct pool *pool;          /* Stores related data. */
83     bool eject;                 /* Eject page before printing? */
84     bool include_prefix;        /* Prefix lines with space? */
85     const char *encoding;       /* Encoding to use for output. */
86     struct dfm_writer *writer;  /* Output file, NULL=listing file. */
87     struct prt_out_spec *specs;
88     size_t n_specs;
89     size_t n_records;           /* Number of records to write. */
90   };
91
92 enum which_formats
93   {
94     PRINT,
95     WRITE
96   };
97
98 static const struct trns_class print_binary_trns_class;
99 static const struct trns_class print_text_trns_class;
100
101 static int cmd_print__ (struct lexer *, struct dataset *,
102                         enum which_formats, bool eject);
103 static bool parse_specs (struct lexer *, struct pool *tmp_pool,
104                          struct print_trns *, int records_ofs,
105                          struct dictionary *, enum which_formats);
106 static void dump_table (struct print_trns *);
107
108 static bool print_trns_free (void *trns_);
109
110 static const struct prt_out_spec *find_binary_spec (const struct print_trns *);
111 \f
112 /* Basic parsing. */
113
114 /* Parses PRINT command. */
115 int
116 cmd_print (struct lexer *lexer, struct dataset *ds)
117 {
118   return cmd_print__ (lexer, ds, PRINT, false);
119 }
120
121 /* Parses PRINT EJECT command. */
122 int
123 cmd_print_eject (struct lexer *lexer, struct dataset *ds)
124 {
125   return cmd_print__ (lexer, ds, PRINT, true);
126 }
127
128 /* Parses WRITE command. */
129 int
130 cmd_write (struct lexer *lexer, struct dataset *ds)
131 {
132   return cmd_print__ (lexer, ds, WRITE, false);
133 }
134
135 /* Parses the output commands. */
136 static int
137 cmd_print__ (struct lexer *lexer, struct dataset *ds,
138              enum which_formats which_formats, bool eject)
139 {
140   bool print_table = false;
141   struct file_handle *fh = NULL;
142   char *encoding = NULL;
143
144   /* Fill in prt to facilitate error-handling. */
145   struct pool *pool = pool_create ();
146   struct print_trns *trns = pool_alloc (pool, sizeof *trns);
147   *trns = (struct print_trns) { .pool = pool, .eject = eject };
148   struct pool *tmp_pool = pool_create_subpool (trns->pool);
149
150   /* Parse the command options. */
151   int records_ofs = 0;
152   while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
153     {
154       if (lex_match_id (lexer, "OUTFILE"))
155         {
156           lex_match (lexer, T_EQUALS);
157
158           fh = fh_parse (lexer, FH_REF_FILE, NULL);
159           if (fh == NULL)
160             goto error;
161         }
162       else if (lex_match_id (lexer, "ENCODING"))
163         {
164           lex_match (lexer, T_EQUALS);
165           if (!lex_force_string (lexer))
166             goto error;
167
168           free (encoding);
169           encoding = ss_xstrdup (lex_tokss (lexer));
170
171           lex_get (lexer);
172         }
173       else if (lex_match_id (lexer, "RECORDS"))
174         {
175           lex_match (lexer, T_EQUALS);
176           lex_match (lexer, T_LPAREN);
177           if (!lex_force_int_range (lexer, "RECORDS", 0, INT_MAX))
178             goto error;
179           trns->n_records = lex_integer (lexer);
180           records_ofs = lex_ofs (lexer);
181           lex_get (lexer);
182           lex_match (lexer, T_RPAREN);
183         }
184       else if (lex_match_id (lexer, "TABLE"))
185         print_table = true;
186       else if (lex_match_id (lexer, "NOTABLE"))
187         print_table = false;
188       else
189         {
190           lex_error_expecting (lexer, "OUTFILE", "ENCODING", "RECORDS",
191                                "TABLE", "NOTABLE");
192           goto error;
193         }
194     }
195
196   /* When PRINT or PRINT EJECT writes to an external file, we
197      prefix each line with a space for compatibility. */
198   trns->include_prefix = which_formats == PRINT && fh != NULL;
199
200   /* Parse variables and strings. */
201   if (!parse_specs (lexer, tmp_pool, trns, records_ofs,
202                     dataset_dict (ds), which_formats))
203     goto error;
204
205   /* Are there any binary formats?
206
207      There are real difficulties figuring out what to do when both binary
208      formats and nontrivial encodings enter the picture.  So when binary
209      formats are present we fall back to much simpler handling. */
210   const struct prt_out_spec *binary_spec = find_binary_spec (trns);
211   if (binary_spec && !fh)
212     {
213       lex_ofs_error (lexer, binary_spec->start_ofs, binary_spec->end_ofs,
214                      _("%s is required when binary formats are specified."),
215                      "OUTFILE");
216       goto error;
217     }
218
219   if (lex_end_of_command (lexer) != CMD_SUCCESS)
220     goto error;
221
222   if (fh != NULL)
223     {
224       trns->writer = dfm_open_writer (fh, encoding);
225       if (trns->writer == NULL)
226         goto error;
227       trns->encoding = dfm_writer_get_encoding (trns->writer);
228     }
229   else
230     trns->encoding = UTF8;
231
232   /* Output the variable table if requested. */
233   if (print_table)
234     dump_table (trns);
235
236   /* Put the transformation in the queue. */
237   add_transformation (ds, (binary_spec
238                            ? &print_binary_trns_class
239                            : &print_text_trns_class), trns);
240
241   pool_destroy (tmp_pool);
242   fh_unref (fh);
243
244   return CMD_SUCCESS;
245
246  error:
247   print_trns_free (trns);
248   fh_unref (fh);
249   return CMD_FAILURE;
250 }
251 \f
252 static bool parse_string_argument (struct lexer *, struct print_trns *,
253                                    size_t *allocated_specs,
254                                    int record, int *column);
255 static bool parse_variable_argument (struct lexer *, const struct dictionary *,
256                                      struct print_trns *,
257                                      size_t *allocated_specs,
258                                      struct pool *tmp_pool,
259                                      int *record, int *column,
260                                      enum which_formats);
261
262 /* Parses all the variable and string specifications on a single
263    PRINT, PRINT EJECT, or WRITE command into the prt structure.
264    Returns success. */
265 static bool
266 parse_specs (struct lexer *lexer, struct pool *tmp_pool,
267              struct print_trns *trns, int records_ofs, struct dictionary *dict,
268              enum which_formats which_formats)
269 {
270   int record = 0;
271   int column = 1;
272
273   if (lex_token (lexer) == T_ENDCMD)
274     {
275       trns->n_records = 1;
276       return true;
277     }
278
279   size_t allocated_specs = 0;
280   while (lex_token (lexer) != T_ENDCMD)
281     {
282       if (!parse_record_placement (lexer, &record, &column))
283         return false;
284
285       bool ok = (lex_is_string (lexer)
286                  ? parse_string_argument (lexer, trns, &allocated_specs,
287                                           record, &column)
288                  : parse_variable_argument (lexer, dict, trns, &allocated_specs,
289                                             tmp_pool, &record, &column,
290                                             which_formats));
291       if (!ok)
292         return 0;
293
294       lex_match (lexer, T_COMMA);
295     }
296
297   if (trns->n_records != 0 && trns->n_records != record)
298     lex_ofs_error (lexer, records_ofs, records_ofs,
299                    _("Output calls for %d records but %zu specified on RECORDS "
300                      "subcommand."),
301                    record, trns->n_records);
302   trns->n_records = record;
303
304   return true;
305 }
306
307 static struct prt_out_spec *
308 add_spec (struct print_trns *trns, size_t *allocated_specs)
309 {
310   if (trns->n_specs >= *allocated_specs)
311     trns->specs = pool_2nrealloc (trns->pool, trns->specs, allocated_specs,
312                                   sizeof *trns->specs);
313   return &trns->specs[trns->n_specs++];
314 }
315
316 /* Parses a string argument to the PRINT commands.  Returns success. */
317 static bool
318 parse_string_argument (struct lexer *lexer, struct print_trns *trns,
319                        size_t *allocated_specs, int record, int *column)
320 {
321   struct prt_out_spec *spec = add_spec (trns, allocated_specs);
322   *spec = (struct prt_out_spec) {
323     .type = PRT_LITERAL,
324     .record = record,
325     .first_column = *column,
326     .string = ss_clone_pool (lex_tokss (lexer), trns->pool),
327     .start_ofs = lex_ofs (lexer),
328   };
329   lex_get (lexer);
330
331   /* Parse the included column range. */
332   if (lex_is_number (lexer))
333     {
334       int first_column, last_column;
335       bool range_specified;
336
337       if (!parse_column_range (lexer, 1,
338                                &first_column, &last_column, &range_specified))
339         return false;
340
341       spec->first_column = first_column;
342       if (range_specified)
343         {
344           struct string s;
345           ds_init_substring (&s, spec->string);
346           ds_set_length (&s, last_column - first_column + 1, ' ');
347           spec->string = ss_clone_pool (s.ss, trns->pool);
348           ds_destroy (&s);
349         }
350     }
351   spec->end_ofs = lex_ofs (lexer) - 1;
352
353   spec->width = u8_width (CHAR_CAST (const uint8_t *, spec->string.string),
354                           spec->string.length, UTF8);
355   *column = spec->first_column + spec->width;
356
357   return true;
358 }
359
360 /* Parses a variable argument to the PRINT commands by passing it off
361    to fixed_parse_compatible() or fixed_parse_fortran() as appropriate.
362    Returns success. */
363 static bool
364 parse_variable_argument (struct lexer *lexer, const struct dictionary *dict,
365                          struct print_trns *trns, size_t *allocated_specs,
366                          struct pool *tmp_pool, int *record, int *column,
367                          enum which_formats which_formats)
368 {
369   const struct variable **vars;
370   size_t n_vars;
371   if (!parse_variables_const_pool (lexer, tmp_pool, dict,
372                                    &vars, &n_vars, PV_DUPLICATE))
373     return false;
374
375   struct fmt_spec *formats, *f;
376   size_t n_formats;
377   bool add_space;
378   int formats_start = lex_ofs (lexer);
379   if (lex_is_number (lexer) || lex_token (lexer) == T_LPAREN)
380     {
381       if (!parse_var_placements (lexer, tmp_pool, n_vars, FMT_FOR_OUTPUT,
382                                  &formats, &n_formats))
383         return false;
384       add_space = false;
385     }
386   else
387     {
388       lex_match (lexer, T_ASTERISK);
389
390       formats = pool_nmalloc (tmp_pool, n_vars, sizeof *formats);
391       n_formats = n_vars;
392       for (size_t i = 0; i < n_vars; i++)
393         {
394           const struct variable *v = vars[i];
395           formats[i] = (which_formats == PRINT
396                         ? *var_get_print_format (v)
397                         : *var_get_write_format (v));
398         }
399       add_space = which_formats == PRINT;
400     }
401   int formats_end = lex_ofs (lexer) - 1;
402
403   size_t var_idx = 0;
404   for (f = formats; f < &formats[n_formats]; f++)
405     if (!execute_placement_format (f, record, column))
406       {
407         const struct variable *var = vars[var_idx++];
408         char *error = fmt_check_width_compat__ (f, var_get_name (var),
409                                                 var_get_width (var));
410         if (error)
411           {
412             lex_ofs_error (lexer, formats_start, formats_end, "%s", error);
413             free (error);
414             return false;
415           }
416
417         struct prt_out_spec *spec = add_spec (trns, allocated_specs);
418         *spec = (struct prt_out_spec) {
419           .type = PRT_VAR,
420           .record = *record,
421           .first_column = *column,
422           .var = var,
423           .format = *f,
424           .add_space = add_space,
425
426           /* This is a completely bizarre twist for compatibility: WRITE
427              outputs the system-missing value as a field filled with spaces,
428              instead of using the normal format that usually contains a
429              period. */
430           .sysmis_as_spaces = (which_formats == WRITE
431                                && var_is_numeric (var)
432                                && (fmt_get_category (f->type)
433                                    != FMT_CAT_BINARY)),
434         };
435
436         *column += f->w + add_space;
437       }
438   assert (var_idx == n_vars);
439
440   return true;
441 }
442
443 /* Prints the table produced by the TABLE subcommand to the listing
444    file. */
445 static void
446 dump_table (struct print_trns *trns)
447 {
448   struct pivot_table *table = pivot_table_create (N_("Print Summary"));
449
450   pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Attributes"),
451                           N_("Record"), N_("Columns"), N_("Format"));
452
453   struct pivot_dimension *variables = pivot_dimension_create (
454     table, PIVOT_AXIS_ROW, N_("Variable"));
455
456   for (size_t i = 0; i < trns->n_specs; i++)
457     {
458       const struct prt_out_spec *spec = &trns->specs[i];
459       if (spec->type != PRT_VAR)
460         continue;
461
462       int row = pivot_category_create_leaf (
463         variables->root, pivot_value_new_variable (spec->var));
464
465       pivot_table_put2 (table, 0, row,
466                         pivot_value_new_integer (spec->record));
467       int last_column = spec->first_column + spec->format.w - 1;
468       pivot_table_put2 (table, 1, row, pivot_value_new_user_text_nocopy (
469                           xasprintf ("%d-%d",
470                                      spec->first_column, last_column)));
471
472       char fmt_string[FMT_STRING_LEN_MAX + 1];
473       pivot_table_put2 (table, 2, row, pivot_value_new_user_text (
474                           fmt_to_string (&spec->format, fmt_string), -1));
475     }
476
477   int row = pivot_category_create_leaf (
478     variables->root, pivot_value_new_text (N_("N of Records")));
479   pivot_table_put2 (table, 0, row,
480                     pivot_value_new_integer (trns->n_records));
481
482   pivot_table_submit (table);
483 }
484
485 static const struct prt_out_spec *
486 find_binary_spec (const struct print_trns *trns)
487 {
488   for (size_t i = 0; i < trns->n_specs; i++)
489     {
490       const struct prt_out_spec *spec = &trns->specs[i];
491       if (spec->type == PRT_VAR
492           && fmt_get_category (spec->format.type) == FMT_CAT_BINARY)
493         return spec;
494     }
495   return NULL;
496 }
497 \f
498 /* Transformation, for all-text output. */
499
500 static void print_text_flush_records (struct print_trns *, struct u8_line *,
501                                       int target_record,
502                                       bool *eject, int *record);
503
504 /* Performs the transformation inside print_trns T on case C. */
505 static enum trns_result
506 print_text_trns_proc (void *trns_, struct ccase **c,
507                       casenumber case_num UNUSED)
508 {
509   struct print_trns *trns = trns_;
510   struct u8_line line;
511
512   bool eject = trns->eject;
513   int record = 1;
514
515   u8_line_init (&line);
516   for (size_t i = 0; i < trns->n_specs; i++)
517     {
518       const struct prt_out_spec *spec = &trns->specs[i];
519       int x0 = spec->first_column;
520
521       print_text_flush_records (trns, &line, spec->record, &eject, &record);
522
523       u8_line_set_length (&line, spec->first_column);
524       if (spec->type == PRT_VAR)
525         {
526           const union value *input = case_data (*c, spec->var);
527           int x1;
528
529           if (!spec->sysmis_as_spaces || input->f != SYSMIS)
530             {
531               size_t len;
532               int width;
533               char *s;
534
535               s = data_out (input, var_get_encoding (spec->var),
536                             &spec->format, settings_get_fmt_settings ());
537               len = strlen (s);
538               width = u8_width (CHAR_CAST (const uint8_t *, s), len, UTF8);
539               x1 = x0 + width;
540               u8_line_put (&line, x0, x1, s, len);
541               free (s);
542             }
543           else
544             {
545               int n = spec->format.w;
546
547               x1 = x0 + n;
548               memset (u8_line_reserve (&line, x0, x1, n), ' ', n);
549             }
550
551           if (spec->add_space)
552             *u8_line_reserve (&line, x1, x1 + 1, 1) = ' ';
553         }
554       else
555         {
556           const struct substring *s = &spec->string;
557
558           u8_line_put (&line, x0, x0 + spec->width, s->string, s->length);
559         }
560     }
561   print_text_flush_records (trns, &line, trns->n_records + 1,
562                             &eject, &record);
563   u8_line_destroy (&line);
564
565   if (trns->writer != NULL && dfm_write_error (trns->writer))
566     return TRNS_ERROR;
567   return TRNS_CONTINUE;
568 }
569
570 /* Advance from *RECORD to TARGET_RECORD, outputting records
571    along the way.  If *EJECT is true, then the first record
572    output is preceded by ejecting the page (and *EJECT is set
573    false). */
574 static void
575 print_text_flush_records (struct print_trns *trns, struct u8_line *line,
576                           int target_record, bool *eject, int *record)
577 {
578   for (; target_record > *record; (*record)++)
579     {
580       char leader = ' ';
581
582       if (*eject)
583         {
584           *eject = false;
585           if (trns->writer == NULL)
586             output_item_submit (page_break_item_create ());
587           else
588             leader = '1';
589         }
590       *u8_line_reserve (line, 0, 1, 1) = leader;
591
592       if (trns->writer == NULL)
593         output_log ("%s", ds_cstr (&line->s) + 1);
594       else
595         {
596           size_t len = ds_length (&line->s);
597           char *s = ds_cstr (&line->s);
598
599           if (!trns->include_prefix)
600             {
601               s++;
602               len--;
603             }
604
605           dfm_put_record_utf8 (trns->writer, s, len);
606         }
607     }
608 }
609 \f
610 /* Transformation, for output involving binary. */
611
612 static void print_binary_flush_records (struct print_trns *,
613                                         struct string *line, int target_record,
614                                         bool *eject, int *record);
615
616 /* Performs the transformation inside print_trns T on case C. */
617 static enum trns_result
618 print_binary_trns_proc (void *trns_, struct ccase **c,
619                         casenumber case_num UNUSED)
620 {
621   struct print_trns *trns = trns_;
622   bool eject = trns->eject;
623   char encoded_space = recode_byte (trns->encoding, C_ENCODING, ' ');
624   int record = 1;
625   struct string line = DS_EMPTY_INITIALIZER;
626
627   ds_put_byte (&line, ' ');
628   for (size_t i = 0; i < trns->n_specs; i++)
629     {
630       const struct prt_out_spec *spec = &trns->specs[i];
631       print_binary_flush_records (trns, &line, spec->record, &eject, &record);
632
633       ds_set_length (&line, spec->first_column, encoded_space);
634       if (spec->type == PRT_VAR)
635         {
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, settings_get_fmt_settings (),
640                              &line, trns->encoding);
641           else
642             ds_put_byte_multiple (&line, encoded_space, spec->format.w);
643           if (spec->add_space)
644             ds_put_byte (&line, encoded_space);
645         }
646       else
647         {
648           ds_put_substring (&line, spec->string);
649           if (0 != strcmp (trns->encoding, UTF8))
650             {
651               size_t length = spec->string.length;
652               char *data = ss_data (ds_tail (&line, length));
653               char *s = recode_string (trns->encoding, UTF8, data, length);
654               memcpy (data, s, length);
655               free (s);
656             }
657         }
658     }
659   print_binary_flush_records (trns, &line, trns->n_records + 1,
660                               &eject, &record);
661   ds_destroy (&line);
662
663   if (trns->writer != NULL && dfm_write_error (trns->writer))
664     return TRNS_ERROR;
665   return TRNS_CONTINUE;
666 }
667
668 /* Advance from *RECORD to TARGET_RECORD, outputting records
669    along the way.  If *EJECT is true, then the first record
670    output is preceded by ejecting the page (and *EJECT is set
671    false). */
672 static void
673 print_binary_flush_records (struct print_trns *trns, struct string *line,
674                             int target_record, bool *eject, int *record)
675 {
676   for (; target_record > *record; (*record)++)
677     {
678       char *s = ds_cstr (line);
679       size_t length = ds_length (line);
680       char leader = ' ';
681
682       if (*eject)
683         {
684           *eject = false;
685           leader = '1';
686         }
687       s[0] = recode_byte (trns->encoding, C_ENCODING, leader);
688
689       if (!trns->include_prefix)
690         {
691           s++;
692           length--;
693         }
694       dfm_put_record (trns->writer, s, length);
695
696       ds_truncate (line, 1);
697     }
698 }
699 \f
700 /* Frees TRNS. */
701 static bool
702 print_trns_free (void *trns_)
703 {
704   struct print_trns *trns = trns_;
705   bool ok = true;
706
707   if (trns->writer != NULL)
708     ok = dfm_close_writer (trns->writer);
709   pool_destroy (trns->pool);
710
711   return ok;
712 }
713
714 static const struct trns_class print_binary_trns_class = {
715   .name = "PRINT",
716   .execute = print_binary_trns_proc,
717   .destroy = print_trns_free,
718 };
719
720 static const struct trns_class print_text_trns_class = {
721   .name = "PRINT",
722   .execute = print_text_trns_proc,
723   .destroy = print_trns_free,
724 };
725