1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 /* FIXME: seems like a lot of code duplication with data-list.c. */
28 #include "dfm-write.h"
30 #include "expressions/public.h"
31 #include "file-handle.h"
39 #define _(msgid) gettext (msgid)
41 /* Describes what to do when an output field is encountered. */
44 PRT_ERROR, /* Invalid value. */
45 PRT_NEWLINE, /* Newline. */
46 PRT_CONST, /* Constant string. */
47 PRT_VAR, /* Variable. */
48 PRT_SPACE /* A single space. */
51 /* Describes how to output one field. */
54 struct prt_out_spec *next;
55 int type; /* PRT_* constant. */
56 int fc; /* 0-based first column. */
59 char *c; /* PRT_CONST: Associated string. */
62 struct variable *v; /* PRT_VAR: Associated variable. */
63 struct fmt_spec f; /* PRT_VAR: Output spec. */
70 /* Enums for use with print_trns's `options' field. */
73 PRT_CMD_MASK = 1, /* Command type mask. */
74 PRT_PRINT = 0, /* PRINT transformation identifier. */
75 PRT_WRITE = 1, /* WRITE transformation identifier. */
76 PRT_EJECT = 002, /* Can be combined with CMD_PRINT only. */
77 PRT_BINARY = 004 /* File is binary, omit newlines. */
80 /* PRINT, PRINT EJECT, WRITE private data structure. */
84 struct dfm_writer *writer; /* Output file, NULL=listing file. */
85 int options; /* PRT_* bitmapped field. */
86 struct prt_out_spec *spec; /* Output specifications. */
87 int max_width; /* Maximum line width including null. */
88 char *line; /* Buffer for sticking lines in. */
91 /* PRT_PRINT or PRT_WRITE. */
94 /* Holds information on parsing the data file. */
95 static struct print_trns prt;
97 /* Last prt_out_spec in the chain. Used for building the linked-list. */
98 static struct prt_out_spec *next;
100 /* Number of records. */
103 static int internal_cmd_print (int flags);
104 static trns_proc_func print_trns_proc;
105 static trns_free_func print_trns_free;
106 static int parse_specs (void);
107 static void dump_table (const struct file_handle *);
108 static void append_var_spec (struct prt_out_spec *);
109 static void alloc_line (void);
113 /* Parses PRINT command. */
117 return internal_cmd_print (PRT_PRINT);
120 /* Parses PRINT EJECT command. */
122 cmd_print_eject (void)
124 return internal_cmd_print (PRT_PRINT | PRT_EJECT);
127 /* Parses WRITE command. */
131 return internal_cmd_print (PRT_WRITE);
134 /* Parses the output commands. F is PRT_PRINT, PRT_WRITE, or
135 PRT_PRINT|PRT_EJECT. */
137 internal_cmd_print (int f)
139 int table = 0; /* Print table? */
140 struct print_trns *trns; /* malloc()'d transformation. */
141 struct file_handle *fh = NULL;
143 /* Fill in prt to facilitate error-handling. */
144 prt.h.proc = print_trns_proc;
145 prt.h.free = print_trns_free;
153 which_cmd = f & PRT_CMD_MASK;
155 /* Parse the command options. */
156 while (!lex_match ('/'))
158 if (lex_match_id ("OUTFILE"))
166 else if (lex_match_id ("RECORDS"))
170 if (!lex_force_int ())
172 nrec = lex_integer ();
176 else if (lex_match_id ("TABLE"))
178 else if (lex_match_id ("NOTABLE"))
182 lex_error (_("expecting a valid subcommand"));
187 /* Parse variables and strings. */
193 prt.writer = dfm_open_writer (fh);
194 if (prt.writer == NULL)
197 if (handle_get_mode (fh) == MODE_BINARY)
198 prt.options |= PRT_BINARY;
201 /* Output the variable table if requested. */
205 /* Count the maximum line width. Allocate linebuffer if
209 /* Put the transformation in the queue. */
210 trns = xmalloc (sizeof *trns);
211 memcpy (trns, &prt, sizeof *trns);
212 add_transformation ((struct trns_header *) trns);
217 print_trns_free ((struct trns_header *) & prt);
221 /* Appends the field output specification SPEC to the list maintained
224 append_var_spec (struct prt_out_spec *spec)
227 prt.spec = next = xmalloc (sizeof *spec);
229 next = next->next = xmalloc (sizeof *spec);
231 memcpy (next, spec, sizeof *spec);
235 /* Field parsing. Mostly stolen from data-list.c. */
237 /* Used for chaining together fortran-like format specifiers. */
240 struct fmt_list *next;
243 struct fmt_list *down;
246 /* Used as "local" variables among the fixed-format parsing funcs. If
247 it were guaranteed that PSPP were going to be compiled by gcc,
248 I'd make all these functions a single set of nested functions. */
251 struct variable **v; /* variable list */
252 int nv; /* number of variables in list */
253 int cv; /* number of variables from list used up so far
254 by the FORTRAN-like format specifiers */
256 int recno; /* current 1-based record number */
257 int sc; /* 1-based starting column for next variable */
259 struct prt_out_spec spec; /* next format spec to append to list */
260 int fc, lc; /* first, last 1-based column number of current
263 int level; /* recursion level for FORTRAN-like format
268 static int fixed_parse_compatible (void);
269 static struct fmt_list *fixed_parse_fortran (void);
271 static int parse_string_argument (void);
272 static int parse_variable_argument (void);
274 /* Parses all the variable and string specifications on a single
275 PRINT, PRINT EJECT, or WRITE command into the prt structure.
280 /* Return code from called function. */
288 while (lex_match ('/'))
290 int prev_recno = fx.recno;
293 if (lex_is_number ())
295 if (!lex_force_int ())
297 if (lex_integer () < fx.recno)
299 msg (SE, _("The record number specified, %ld, is "
300 "before the previous record, %d. Data "
301 "fields must be listed in order of "
302 "increasing record number."),
303 lex_integer (), fx.recno - 1);
306 fx.recno = lex_integer ();
310 fx.spec.type = PRT_NEWLINE;
311 while (prev_recno++ < fx.recno)
312 append_var_spec (&fx.spec);
317 if (token == T_STRING)
318 code = parse_string_argument ();
320 code = parse_variable_argument ();
324 fx.spec.type = PRT_NEWLINE;
325 append_var_spec (&fx.spec);
329 else if (fx.recno > nrec)
331 msg (SE, _("Variables are specified on records that "
332 "should not exist according to RECORDS subcommand."));
338 lex_error (_("expecting end of command"));
345 /* Parses a string argument to the PRINT commands. Returns success. */
347 parse_string_argument (void)
349 fx.spec.type = PRT_CONST;
350 fx.spec.fc = fx.sc - 1;
351 fx.spec.u.c = xstrdup (ds_c_str (&tokstr));
354 /* Parse the included column range. */
355 if (lex_is_number ())
357 /* Width of column range in characters. */
360 /* Width of constant string in characters. */
363 /* 1-based index of last column in range. */
366 if (!lex_is_integer () || lex_integer () <= 0)
368 msg (SE, _("%g is not a valid column location."), tokval);
371 fx.spec.fc = lex_integer () - 1;
374 lex_negative_to_dash ();
377 if (!lex_is_integer ())
379 msg (SE, _("Column location expected following `%d-'."),
383 if (lex_integer () <= 0)
385 msg (SE, _("%g is not a valid column location."), tokval);
388 if (lex_integer () < fx.spec.fc + 1)
390 msg (SE, _("%d-%ld is not a valid column range. The second "
391 "column must be greater than or equal to the first."),
392 fx.spec.fc + 1, lex_integer ());
395 lc = lex_integer () - 1;
400 /* If only a starting location is specified then the field is
401 the width of the provided string. */
402 lc = fx.spec.fc + strlen (fx.spec.u.c) - 1;
404 /* Apply the range. */
405 c_len = lc - fx.spec.fc + 1;
406 s_len = strlen (fx.spec.u.c);
408 fx.spec.u.c[c_len] = 0;
409 else if (s_len < c_len)
411 fx.spec.u.c = xrealloc (fx.spec.u.c, c_len + 1);
412 memset (&fx.spec.u.c[s_len], ' ', c_len - s_len);
413 fx.spec.u.c[c_len] = 0;
419 /* If nothing is provided then the field is the width of the
421 fx.sc += strlen (fx.spec.u.c);
423 append_var_spec (&fx.spec);
431 /* Parses a variable argument to the PRINT commands by passing it off
432 to fixed_parse_compatible() or fixed_parse_fortran() as appropriate.
435 parse_variable_argument (void)
437 if (!parse_variables (default_dict, &fx.v, &fx.nv, PV_DUPLICATE))
440 if (lex_is_number ())
442 if (!fixed_parse_compatible ())
445 else if (token == '(')
449 if (!fixed_parse_fortran ())
454 /* User wants dictionary format specifiers. */
458 for (i = 0; i < fx.nv; i++)
461 fx.spec.type = PRT_VAR;
462 fx.spec.fc = fx.sc - 1;
463 fx.spec.u.v.v = fx.v[i];
464 fx.spec.u.v.f = fx.v[i]->print;
465 append_var_spec (&fx.spec);
466 fx.sc += fx.v[i]->print.w;
469 fx.spec.type = PRT_SPACE;
470 fx.spec.fc = fx.sc - 1;
471 append_var_spec (&fx.spec);
484 /* Verifies that FORMAT doesn't need a variable wider than WIDTH.
485 Returns true iff that is the case. */
487 check_string_width (const struct fmt_spec *format, const struct variable *v)
489 if (get_format_var_width (format) > v->width)
491 msg (SE, _("Variable %s has width %d so it cannot be output "
493 v->name, v->width, fmt_to_string (format));
499 /* Parses a column specification for parse_specs(). */
501 fixed_parse_compatible (void)
507 type = fx.v[0]->type;
508 for (i = 1; i < fx.nv; i++)
509 if (type != fx.v[i]->type)
511 msg (SE, _("%s is not of the same type as %s. To specify "
512 "variables of different types in the same variable "
513 "list, use a FORTRAN-like format specifier."),
514 fx.v[i]->name, fx.v[0]->name);
518 if (!lex_force_int ())
520 fx.fc = lex_integer () - 1;
523 msg (SE, _("Column positions for fields must be positive."));
528 lex_negative_to_dash ();
531 if (!lex_force_int ())
533 fx.lc = lex_integer () - 1;
536 msg (SE, _("Column positions for fields must be positive."));
539 else if (fx.lc < fx.fc)
541 msg (SE, _("The ending column for a field must not "
542 "be less than the starting column."));
550 fx.spec.u.v.f.w = fx.lc - fx.fc + 1;
553 struct fmt_desc *fdp;
559 fx.spec.u.v.f.type = parse_format_specifier_name (&cp, 0);
560 if (fx.spec.u.v.f.type == -1)
564 msg (SE, _("A format specifier on this line "
565 "has extra characters on the end."));
572 fx.spec.u.v.f.type = FMT_F;
574 if (lex_is_number ())
576 if (!lex_force_int ())
578 if (lex_integer () < 1)
580 msg (SE, _("The value for number of decimal places "
581 "must be at least 1."));
584 fx.spec.u.v.f.d = lex_integer ();
590 fdp = &formats[fx.spec.u.v.f.type];
591 if (fdp->n_args < 2 && fx.spec.u.v.f.d)
593 msg (SE, _("Input format %s doesn't accept decimal places."),
597 if (fx.spec.u.v.f.d > 16)
598 fx.spec.u.v.f.d = 16;
600 if (!lex_force_match (')'))
605 fx.spec.u.v.f.type = FMT_F;
611 if ((fx.lc - fx.fc + 1) % fx.nv)
613 msg (SE, _("The %d columns %d-%d can't be evenly divided into %d "
614 "fields."), fx.lc - fx.fc + 1, fx.fc + 1, fx.lc + 1, fx.nv);
618 dividend = (fx.lc - fx.fc + 1) / fx.nv;
619 fx.spec.u.v.f.w = dividend;
620 if (!check_output_specifier (&fx.spec.u.v.f, true)
621 || !check_specifier_type (&fx.spec.u.v.f, type, true))
625 for (i = 0; i < fx.nv; i++)
626 if (!check_string_width (&fx.spec.u.v.f, fx.v[i]))
630 fx.spec.type = PRT_VAR;
631 for (i = 0; i < fx.nv; i++)
633 fx.spec.fc = fx.fc + dividend * i;
634 fx.spec.u.v.v = fx.v[i];
635 append_var_spec (&fx.spec);
640 /* Destroy a format list and, optionally, all its sublists. */
642 destroy_fmt_list (struct fmt_list * f, int recurse)
644 struct fmt_list *next;
649 if (recurse && f->f.type == FMT_DESCEND)
650 destroy_fmt_list (f->down, 1);
655 /* Recursively puts the format list F (which represents a set of
656 FORTRAN-like format specifications, like 4(F10,2X)) into the
659 dump_fmt_list (struct fmt_list * f)
663 for (; f; f = f->next)
664 if (f->f.type == FMT_X)
666 else if (f->f.type == FMT_T)
668 else if (f->f.type == FMT_NEWREC)
670 fx.recno += f->count;
672 fx.spec.type = PRT_NEWLINE;
673 for (i = 0; i < f->count; i++)
674 append_var_spec (&fx.spec);
677 for (i = 0; i < f->count; i++)
678 if (f->f.type == FMT_DESCEND)
680 if (!dump_fmt_list (f->down))
689 msg (SE, _("The number of format "
690 "specifications exceeds the number of variable "
696 if (!check_output_specifier (&f->f, true)
697 || !check_specifier_type (&f->f, v->type, true)
698 || !check_string_width (&f->f, v))
701 fx.spec.type = PRT_VAR;
703 fx.spec.u.v.f = f->f;
704 fx.spec.fc = fx.sc - 1;
705 append_var_spec (&fx.spec);
712 /* Recursively parses a list of FORTRAN-like format specifiers. Calls
713 itself to parse nested levels of parentheses. Returns to its
714 original caller NULL, to indicate error, non-NULL, but nothing
715 useful, to indicate success (it returns a free()'d block). */
716 static struct fmt_list *
717 fixed_parse_fortran (void)
719 struct fmt_list *head = NULL;
720 struct fmt_list *fl = NULL;
722 lex_get (); /* skip opening parenthesis */
726 fl = fl->next = xmalloc (sizeof *fl);
728 head = fl = xmalloc (sizeof *fl);
730 if (lex_is_number ())
732 if (!lex_is_integer ())
734 fl->count = lex_integer ();
742 fl->f.type = FMT_DESCEND;
744 fl->down = fixed_parse_fortran ();
749 else if (lex_match ('/'))
750 fl->f.type = FMT_NEWREC;
751 else if (!parse_format_specifier (&fl->f, FMTP_ALLOW_XT)
752 || !check_output_specifier (&fl->f, 1))
764 dump_fmt_list (head);
765 destroy_fmt_list (head, 1);
768 msg (SE, _("There aren't enough format specifications "
769 "to match the number of variable names given."));
776 destroy_fmt_list (head, 0);
781 /* Prints the table produced by the TABLE subcommand to the listing
784 dump_table (const struct file_handle *fh)
786 struct prt_out_spec *spec;
791 for (nspec = 0, spec = prt.spec; spec; spec = spec->next)
792 if (spec->type == PRT_CONST || spec->type == PRT_VAR)
794 t = tab_create (4, nspec + 1, 0);
795 tab_columns (t, TAB_COL_DOWN, 1);
796 tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, nspec);
797 tab_hline (t, TAL_2, 0, 3, 1);
798 tab_headers (t, 0, 0, 1, 0);
799 tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable"));
800 tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record"));
801 tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns"));
802 tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format"));
803 tab_dim (t, tab_natural_dimensions);
804 for (nspec = recno = 0, spec = prt.spec; spec; spec = spec->next)
812 int len = strlen (spec->u.c);
814 tab_text (t, 0, nspec, TAB_LEFT | TAT_FIX | TAT_PRINTF,
815 "\"%s\"", spec->u.c);
816 tab_text (t, 1, nspec, TAT_PRINTF, "%d", recno + 1);
817 tab_text (t, 2, nspec, TAT_PRINTF, "%3d-%3d",
818 spec->fc + 1, spec->fc + len);
819 tab_text (t, 3, nspec, TAB_LEFT | TAT_FIX | TAT_PRINTF,
826 tab_text (t, 0, nspec, TAB_LEFT, spec->u.v.v->name);
827 tab_text (t, 1, nspec, TAT_PRINTF, "%d", recno + 1);
828 tab_text (t, 2, nspec, TAT_PRINTF, "%3d-%3d",
829 spec->fc + 1, spec->fc + spec->u.v.f.w);
830 tab_text (t, 3, nspec, TAB_LEFT | TAT_FIX,
831 fmt_to_string (&spec->u.v.f));
841 tab_title (t, 1, _("Writing %d record(s) to file %s."),
842 recno, handle_get_filename (fh));
844 tab_title (t, 1, _("Writing %d record(s) to the listing file."), recno);
848 /* PORTME: The number of characters in a line terminator. */
850 #define LINE_END_WIDTH 2 /* \r\n */
852 #define LINE_END_WIDTH 1 /* \n */
855 /* Calculates the maximum possible line width and allocates a buffer
856 big enough to contain it */
860 /* Cumulative maximum line width (excluding null terminator) so far. */
863 /* Width required by current this prt_out_spec. */
864 int pot_w; /* Potential w. */
867 struct prt_out_spec *i;
869 for (i = prt.spec; i; i = i->next)
877 pot_w = i->fc + strlen (i->u.c);
880 pot_w = i->fc + i->u.v.f.w;
893 prt.max_width = w + LINE_END_WIDTH + 1;
894 prt.line = xmalloc (prt.max_width);
897 /* Transformation. */
899 /* Performs the transformation inside print_trns T on case C. */
901 print_trns_proc (struct trns_header * trns, struct ccase * c,
904 /* Transformation. */
905 struct print_trns *t = (struct print_trns *) trns;
908 struct prt_out_spec *i;
913 /* Length of the line in buf. */
915 memset (buf, ' ', t->max_width);
917 if (t->options & PRT_EJECT)
920 /* Note that a field written to a place where a field has
921 already been written truncates the record. `PRINT /A B
922 (T10,F8,T1,F8).' only outputs B. */
923 for (i = t->spec; i; i = i->next)
927 if (t->writer == NULL)
930 tab_output_text (TAT_FIX | TAT_NOWRAP, buf);
934 if ((t->options & PRT_CMD_MASK) == PRT_PRINT
935 || !(t->options & PRT_BINARY))
937 /* PORTME: Line ends. */
944 dfm_put_record (t->writer, buf, len);
947 memset (buf, ' ', t->max_width);
952 /* FIXME: Should be revised to keep track of the string's
953 length outside the loop, probably in i->u.c[0]. */
954 memcpy (&buf[i->fc], i->u.c, strlen (i->u.c));
955 len = i->fc + strlen (i->u.c);
959 data_out (&buf[i->fc], &i->u.v.f, case_data (c, i->u.v.v->fv));
960 len = i->fc + i->u.v.f.w;
964 /* PRT_SPACE always immediately follows PRT_VAR. */
976 /* Frees all the data inside print_trns T. Does not free T. */
978 print_trns_free (struct trns_header * t)
980 struct print_trns *prt = (struct print_trns *) t;
981 struct prt_out_spec *i, *n;
983 for (i = prt->spec; i; i = n)
1002 if (prt->writer != NULL)
1003 dfm_close_writer (prt->writer);
1009 /* PRINT SPACE transformation. */
1010 struct print_space_trns
1012 struct trns_header h;
1014 struct dfm_writer *writer; /* Output data file. */
1015 struct expression *e; /* Number of lines; NULL=1. */
1019 static trns_proc_func print_space_trns_proc;
1020 static trns_free_func print_space_trns_free;
1023 cmd_print_space (void)
1025 struct print_space_trns *t;
1026 struct file_handle *fh;
1027 struct expression *e;
1028 struct dfm_writer *writer;
1030 if (lex_match_id ("OUTFILE"))
1044 e = expr_parse (default_dict, EXPR_NUMBER);
1048 lex_error (_("expecting end of command"));
1057 writer = dfm_open_writer (fh);
1067 t = xmalloc (sizeof *t);
1068 t->h.proc = print_space_trns_proc;
1070 t->h.free = print_space_trns_free;
1076 add_transformation ((struct trns_header *) t);
1081 print_space_trns_proc (struct trns_header * trns, struct ccase * c,
1082 int case_num UNUSED)
1084 struct print_space_trns *t = (struct print_space_trns *) trns;
1089 n = expr_evaluate_num (t->e, c, case_num);
1091 msg (SW, _("The expression on PRINT SPACE evaluated to the "
1092 "system-missing value."));
1094 msg (SW, _("The expression on PRINT SPACE evaluated to %g."), n);
1098 if (t->writer == NULL)
1103 char buf[LINE_END_WIDTH];
1105 /* PORTME: Line ends. */
1113 dfm_put_record (t->writer, buf, LINE_END_WIDTH);
1120 print_space_trns_free (struct trns_header * trns)
1122 expr_free (((struct print_space_trns *) trns)->e);