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., 59 Temple Place - Suite 330, Boston, MA
20 /* AIX requires this to be the first thing in the file. */
23 #define alloca __builtin_alloca
31 #ifndef alloca /* predefined by HP cc +Olibcalls */
45 #include "file-handle.h"
53 /*#define DEBUGGING 1*/
54 #include "debug-print.h"
56 /* Describes what to do when an output field is encountered. */
59 PRT_ERROR, /* Invalid value. */
60 PRT_NEWLINE, /* Newline. */
61 PRT_CONST, /* Constant string. */
62 PRT_VAR, /* Variable. */
63 PRT_SPACE /* A single space. */
66 /* Describes how to output one field. */
69 struct prt_out_spec *next;
70 int type; /* PRT_* constant. */
71 int fc; /* 0-based first column. */
74 char *c; /* PRT_CONST: Associated string. */
77 struct variable *v; /* PRT_VAR: Associated variable. */
78 struct fmt_spec f; /* PRT_VAR: Output spec. */
85 /* Enums for use with print_trns's `options' field. */
88 PRT_CMD_MASK = 1, /* Command type mask. */
89 PRT_PRINT = 0, /* PRINT transformation identifier. */
90 PRT_WRITE = 1, /* WRITE transformation identifier. */
91 PRT_EJECT = 002 /* Can be combined with CMD_PRINT only. */
94 /* PRINT, PRINT EJECT, WRITE private data structure. */
98 struct file_handle *handle; /* Output file, NULL=listing file. */
99 int options; /* PRT_* bitmapped field. */
100 struct prt_out_spec *spec; /* Output specifications. */
101 int max_width; /* Maximum line width including null. */
103 char *line; /* Buffer for sticking lines in. */
107 /* PRT_PRINT or PRT_WRITE. */
110 /* Holds information on parsing the data file. */
111 static struct print_trns prt;
113 /* Last prt_out_spec in the chain. Used for building the linked-list. */
114 static struct prt_out_spec *next;
116 /* Number of records. */
119 static int internal_cmd_print (int flags);
120 static int print_trns_proc (struct trns_header *, struct ccase *);
121 static void print_trns_free (struct trns_header *);
122 static int parse_specs (void);
123 static void dump_table (void);
124 static void append_var_spec (struct prt_out_spec *spec);
125 static void alloc_line (void);
128 void debug_print (void);
133 /* Parses PRINT command. */
137 lex_match_id ("PRINT");
138 return internal_cmd_print (PRT_PRINT);
141 /* Parses PRINT EJECT command. */
143 cmd_print_eject (void)
145 lex_match_id ("EJECT");
146 return internal_cmd_print (PRT_PRINT | PRT_EJECT);
149 /* Parses WRITE command. */
153 lex_match_id ("WRITE");
154 return internal_cmd_print (PRT_WRITE);
157 /* Parses the output commands. F is PRT_PRINT, PRT_WRITE, or
158 PRT_PRINT|PRT_EJECT. */
160 internal_cmd_print (int f)
162 /* 0=print no table, 1=print table. (TABLE subcommand.) */
165 /* malloc()'d transformation. */
166 struct print_trns *trns;
168 /* Fill in prt to facilitate error-handling. */
169 prt.h.proc = print_trns_proc;
170 prt.h.free = print_trns_free;
180 which_cmd = f & PRT_CMD_MASK;
182 /* Parse the command options. */
183 while (!lex_match ('/'))
185 if (lex_match_id ("OUTFILE"))
189 prt.handle = fh_parse_file_handle ();
193 else if (lex_match_id ("RECORDS"))
197 if (!lex_force_int ())
199 nrec = lex_integer ();
203 else if (lex_match_id ("TABLE"))
205 else if (lex_match_id ("NOTABLE"))
209 lex_error (_("expecting a valid subcommand"));
214 /* Parse variables and strings. */
218 /* Output the variable table if requested. */
222 /* Count the maximum line width. Allocate linebuffer if
226 /* Put the transformation in the queue. */
227 trns = xmalloc (sizeof *trns);
228 memcpy (trns, &prt, sizeof *trns);
229 add_transformation ((struct trns_header *) trns);
238 print_trns_free ((struct trns_header *) & prt);
242 /* Appends the field output specification SPEC to the list maintained
245 append_var_spec (struct prt_out_spec *spec)
248 prt.spec = next = xmalloc (sizeof *spec);
250 next = next->next = xmalloc (sizeof *spec);
252 memcpy (next, spec, sizeof *spec);
256 /* Field parsing. Mostly stolen from data-list.c. */
258 /* Used for chaining together fortran-like format specifiers. */
261 struct fmt_list *next;
264 struct fmt_list *down;
267 /* Used as "local" variables among the fixed-format parsing funcs. If
268 it were guaranteed that PSPP were going to be compiled by gcc,
269 I'd make all these functions a single set of nested functions. */
272 struct variable **v; /* variable list */
273 int nv; /* number of variables in list */
274 int cv; /* number of variables from list used up so far
275 by the FORTRAN-like format specifiers */
277 int recno; /* current 1-based record number */
278 int sc; /* 1-based starting column for next variable */
280 struct prt_out_spec spec; /* next format spec to append to list */
281 int fc, lc; /* first, last 1-based column number of current
284 int level; /* recursion level for FORTRAN-like format
289 static int fixed_parse_compatible (void);
290 static struct fmt_list *fixed_parse_fortran (void);
292 static int parse_string_argument (void);
293 static int parse_variable_argument (void);
295 /* Parses all the variable and string specifications on a single
296 PRINT, PRINT EJECT, or WRITE command into the prt structure.
301 /* Return code from called function. */
309 while (lex_match ('/'))
311 int prev_recno = fx.recno;
316 if (!lex_force_int ())
318 if (lex_integer () < fx.recno)
320 msg (SE, _("The record number specified, %ld, is "
321 "before the previous record, %d. Data "
322 "fields must be listed in order of "
323 "increasing record number."),
324 lex_integer (), fx.recno - 1);
327 fx.recno = lex_integer ();
331 fx.spec.type = PRT_NEWLINE;
332 while (prev_recno++ < fx.recno)
333 append_var_spec (&fx.spec);
338 if (token == T_STRING)
339 code = parse_string_argument ();
341 code = parse_variable_argument ();
345 fx.spec.type = PRT_NEWLINE;
346 append_var_spec (&fx.spec);
350 else if (fx.recno > nrec)
352 msg (SE, _("Variables are specified on records that "
353 "should not exist according to RECORDS subcommand."));
359 lex_error (_("expecting end of command"));
366 /* Parses a string argument to the PRINT commands. Returns success. */
368 parse_string_argument (void)
370 fx.spec.type = PRT_CONST;
371 fx.spec.fc = fx.sc - 1;
372 fx.spec.u.c = xstrdup (ds_value (&tokstr));
375 /* Parse the included column range. */
378 /* Width of column range in characters. */
381 /* Width of constant string in characters. */
384 /* 1-based index of last column in range. */
387 if (!lex_integer_p () || lex_integer () <= 0)
389 msg (SE, _("%g is not a valid column location."), tokval);
392 fx.spec.fc = lex_integer () - 1;
395 lex_negative_to_dash ();
398 if (!lex_integer_p ())
400 msg (SE, _("Column location expected following `%d-'."),
404 if (lex_integer () <= 0)
406 msg (SE, _("%g is not a valid column location."), tokval);
409 if (lex_integer () < fx.spec.fc + 1)
411 msg (SE, _("%d-%ld is not a valid column range. The second "
412 "column must be greater than or equal to the first."),
413 fx.spec.fc + 1, lex_integer ());
416 lc = lex_integer () - 1;
421 /* If only a starting location is specified then the field is
422 the width of the provided string. */
423 lc = fx.spec.fc + strlen (fx.spec.u.c) - 1;
425 /* Apply the range. */
426 c_len = lc - fx.spec.fc + 1;
427 s_len = strlen (fx.spec.u.c);
429 fx.spec.u.c[c_len] = 0;
430 else if (s_len < c_len)
432 fx.spec.u.c = xrealloc (fx.spec.u.c, c_len + 1);
433 memset (&fx.spec.u.c[s_len], ' ', c_len - s_len);
434 fx.spec.u.c[c_len] = 0;
440 /* If nothing is provided then the field is the width of the
442 fx.sc += strlen (fx.spec.u.c);
444 append_var_spec (&fx.spec);
452 /* Parses a variable argument to the PRINT commands by passing it off
453 to fixed_parse_compatible() or fixed_parse_fortran() as appropriate.
456 parse_variable_argument (void)
458 if (!parse_variables (NULL, &fx.v, &fx.nv, PV_DUPLICATE))
463 if (!fixed_parse_compatible ())
466 else if (token == '(')
470 if (!fixed_parse_fortran ())
475 /* User wants dictionary format specifiers. */
479 for (i = 0; i < fx.nv; i++)
482 fx.spec.type = PRT_VAR;
483 fx.spec.fc = fx.sc - 1;
484 fx.spec.u.v.v = fx.v[i];
485 fx.spec.u.v.f = fx.v[i]->print;
486 append_var_spec (&fx.spec);
487 fx.sc += fx.v[i]->print.w;
490 fx.spec.type = PRT_SPACE;
491 fx.spec.fc = fx.sc - 1;
492 append_var_spec (&fx.spec);
505 /* Parses a column specification for parse_specs(). */
507 fixed_parse_compatible (void)
513 type = fx.v[0]->type;
514 for (i = 1; i < fx.nv; i++)
515 if (type != fx.v[i]->type)
517 msg (SE, _("%s is not of the same type as %s. To specify "
518 "variables of different types in the same variable "
519 "list, use a FORTRAN-like format specifier."),
520 fx.v[i]->name, fx.v[0]->name);
524 if (!lex_force_int ())
526 fx.fc = lex_integer () - 1;
529 msg (SE, _("Column positions for fields must be positive."));
534 lex_negative_to_dash ();
537 if (!lex_force_int ())
539 fx.lc = lex_integer () - 1;
542 msg (SE, _("Column positions for fields must be positive."));
545 else if (fx.lc < fx.fc)
547 msg (SE, _("The ending column for a field must not "
548 "be less than the starting column."));
556 fx.spec.u.v.f.w = fx.lc - fx.fc + 1;
559 struct fmt_desc *fdp;
565 fx.spec.u.v.f.type = parse_format_specifier_name (&cp, 0);
566 if (fx.spec.u.v.f.type == -1)
570 msg (SE, _("A format specifier on this line "
571 "has extra characters on the end."));
578 fx.spec.u.v.f.type = FMT_F;
582 if (!lex_force_int ())
584 if (lex_integer () < 1)
586 msg (SE, _("The value for number of decimal places "
587 "must be at least 1."));
590 fx.spec.u.v.f.d = lex_integer ();
596 fdp = &formats[fx.spec.u.v.f.type];
597 if (fdp->n_args < 2 && fx.spec.u.v.f.d)
599 msg (SE, _("Input format %s doesn't accept decimal places."),
603 if (fx.spec.u.v.f.d > 16)
604 fx.spec.u.v.f.d = 16;
606 if (!lex_force_match (')'))
611 fx.spec.u.v.f.type = FMT_F;
617 if ((fx.lc - fx.fc + 1) % fx.nv)
619 msg (SE, _("The %d columns %d-%d can't be evenly divided into %d "
620 "fields."), fx.lc - fx.fc + 1, fx.fc + 1, fx.lc + 1, fx.nv);
624 dividend = (fx.lc - fx.fc + 1) / fx.nv;
625 fx.spec.u.v.f.w = dividend;
626 if (!check_output_specifier (&fx.spec.u.v.f))
628 if ((type == ALPHA) ^ (formats[fx.spec.u.v.f.type].cat & FCAT_STRING))
630 msg (SE, _("%s variables cannot be displayed with format %s."),
631 type == ALPHA ? _("String") : _("Numeric"),
632 fmt_to_string (&fx.spec.u.v.f));
636 /* Check that, for string variables, the user didn't specify a width
637 longer than an actual string width. */
640 /* Minimum width of all the string variables specified. */
641 int min_len = fx.v[0]->width;
643 for (i = 1; i < fx.nv; i++)
644 min_len = min (min_len, fx.v[i]->width);
645 if (!check_string_specifier (&fx.spec.u.v.f, min_len))
649 fx.spec.type = PRT_VAR;
650 for (i = 0; i < fx.nv; i++)
652 fx.spec.fc = fx.fc + dividend * i;
653 fx.spec.u.v.v = fx.v[i];
654 append_var_spec (&fx.spec);
659 /* Destroy a format list and, optionally, all its sublists. */
661 destroy_fmt_list (struct fmt_list * f, int recurse)
663 struct fmt_list *next;
668 if (recurse && f->f.type == FMT_DESCEND)
669 destroy_fmt_list (f->down, 1);
674 /* Recursively puts the format list F (which represents a set of
675 FORTRAN-like format specifications, like 4(F10,2X)) into the
678 dump_fmt_list (struct fmt_list * f)
682 for (; f; f = f->next)
683 if (f->f.type == FMT_X)
685 else if (f->f.type == FMT_T)
687 else if (f->f.type == FMT_NEWREC)
689 fx.recno += f->count;
691 fx.spec.type = PRT_NEWLINE;
692 for (i = 0; i < f->count; i++)
693 append_var_spec (&fx.spec);
696 for (i = 0; i < f->count; i++)
697 if (f->f.type == FMT_DESCEND)
699 if (!dump_fmt_list (f->down))
708 msg (SE, _("The number of format "
709 "specifications exceeds the number of variable "
715 if ((v->type == ALPHA) ^ (formats[f->f.type].cat & FCAT_STRING))
717 msg (SE, _("Display format %s may not be used with a "
718 "%s variable."), fmt_to_string (&f->f),
719 v->type == ALPHA ? _("string") : _("numeric"));
722 if (!check_string_specifier (&f->f, v->width))
725 fx.spec.type = PRT_VAR;
727 fx.spec.u.v.f = f->f;
728 fx.spec.fc = fx.sc - 1;
729 append_var_spec (&fx.spec);
736 /* Recursively parses a list of FORTRAN-like format specifiers. Calls
737 itself to parse nested levels of parentheses. Returns to its
738 original caller NULL, to indicate error, non-NULL, but nothing
739 useful, to indicate success (it returns a free()'d block). */
740 static struct fmt_list *
741 fixed_parse_fortran (void)
743 struct fmt_list *head;
744 struct fmt_list *fl = NULL;
746 lex_get (); /* skip opening parenthesis */
750 fl = fl->next = xmalloc (sizeof *fl);
752 head = fl = xmalloc (sizeof *fl);
756 if (!lex_integer_p ())
758 fl->count = lex_integer ();
766 fl->f.type = FMT_DESCEND;
768 fl->down = fixed_parse_fortran ();
773 else if (lex_match ('/'))
774 fl->f.type = FMT_NEWREC;
775 else if (!parse_format_specifier (&fl->f, 1)
776 || !check_output_specifier (&fl->f))
788 dump_fmt_list (head);
789 destroy_fmt_list (head, 1);
792 msg (SE, _("There aren't enough format specifications "
793 "to match the number of variable names given."));
800 destroy_fmt_list (head, 0);
805 /* Prints the table produced by the TABLE subcommand to the listing
810 struct prt_out_spec *spec;
811 const char *filename;
816 for (nspec = 0, spec = prt.spec; spec; spec = spec->next)
817 if (spec->type == PRT_CONST || spec->type == PRT_VAR)
819 t = tab_create (4, nspec + 1, 0);
820 tab_columns (t, TAB_COL_DOWN, 1);
821 tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, nspec);
822 tab_hline (t, TAL_2, 0, 3, 1);
823 tab_headers (t, 0, 0, 1, 0);
824 tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable"));
825 tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record"));
826 tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns"));
827 tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format"));
828 tab_dim (t, tab_natural_dimensions);
829 for (nspec = recno = 0, spec = prt.spec; spec; spec = spec->next)
837 int len = strlen (spec->u.c);
839 tab_text (t, 0, nspec, TAB_LEFT | TAT_FIX | TAT_PRINTF,
840 "\"%s\"", spec->u.c);
841 tab_text (t, 1, nspec, TAT_PRINTF, "%d", recno + 1);
842 tab_text (t, 2, nspec, TAT_PRINTF, "%3d-%3d",
843 spec->fc + 1, spec->fc + len);
844 tab_text (t, 3, nspec, TAB_LEFT | TAT_FIX | TAT_PRINTF,
851 tab_text (t, 0, nspec, TAB_LEFT, spec->u.v.v->name);
852 tab_text (t, 1, nspec, TAT_PRINTF, "%d", recno + 1);
853 tab_text (t, 2, nspec, TAT_PRINTF, "%3d-%3d",
854 spec->fc + 1, spec->fc + spec->u.v.f.w);
855 tab_text (t, 3, nspec, TAB_LEFT | TAT_FIX,
856 fmt_to_string (&spec->u.v.f));
865 filename = fh_handle_name (prt.handle);
866 tab_title (t, 1, (prt.handle != NULL
867 ? _("Writing %3d records to file %s.")
868 : _("Writing %3d records to the listing file.")),
871 fh_handle_name (NULL);
874 /* PORTME: The number of characters in a line terminator. */
876 #define LINE_END_WIDTH 2 /* \r\n */
878 #define LINE_END_WIDTH 1 /* \n */
881 /* Calculates the maximum possible line width and allocates a buffer
882 big enough to contain it, if necessary (otherwise sets max_width).
883 (The action taken depends on compiler & OS as detected by pref.h.) */
887 /* Cumulative maximum line width (excluding null terminator) so far. */
890 /* Width required by current this prt_out_spec. */
891 int pot_w; /* Potential w. */
894 struct prt_out_spec *i;
896 for (i = prt.spec; i; i = i->next)
904 pot_w = i->fc + strlen (i->u.c);
907 pot_w = i->fc + i->u.v.f.w;
919 prt.max_width = w + LINE_END_WIDTH + 1;
921 prt.line = xmalloc (prt.max_width);
925 /* Transformation. */
927 /* Performs the transformation inside print_trns T on case C. */
929 print_trns_proc (struct trns_header * trns, struct ccase * c)
931 /* Transformation. */
932 struct print_trns *t = (struct print_trns *) trns;
935 struct prt_out_spec *i;
939 #if __GNUC__ && !__STRICT_ANSI__
940 char buf[t->max_width];
941 #else /* !__GNUC__ */
942 char *buf = alloca (t->max_width);
943 #endif /* !__GNUC__ */
944 #else /* !PAGED_STACK */
946 #endif /* !PAGED_STACK */
948 /* Length of the line in buf. */
950 memset (buf, ' ', t->max_width);
952 if (t->options & PRT_EJECT)
955 /* Note that a field written to a place where a field has already
956 been written truncates the record. `PRINT /A B (T10,F8,T1,F8).'
957 only outputs B. This is an example of bug-for-bug compatibility,
958 in the author's opinion. */
959 for (i = t->spec; i; i = i->next)
963 if (t->handle == NULL)
966 tab_output_text (TAT_FIX | TAT_NOWRAP, buf);
970 if ((t->options & PRT_CMD_MASK) == PRT_PRINT
971 || t->handle->mode != FH_MD_BINARY)
973 /* PORTME: Line ends. */
980 dfm_put_record (t->handle, buf, len);
983 memset (buf, ' ', t->max_width);
988 /* FIXME: Should be revised to keep track of the string's
989 length outside the loop, probably in i->u.c[0]. */
990 memcpy (&buf[i->fc], i->u.c, strlen (i->u.c));
991 len = i->fc + strlen (i->u.c);
995 if (i->u.v.v->type == NUMERIC)
996 data_out (&buf[i->fc], &i->u.v.f, &c->data[i->u.v.v->fv]);
1000 t.c = c->data[i->u.v.v->fv].s;
1001 data_out (&buf[i->fc], &i->u.v.f, &t);
1003 len = i->fc + i->u.v.f.w;
1007 /* PRT_SPACE always immediately follows PRT_VAR. */
1019 /* Frees all the data inside print_trns T. Does not free T. */
1021 print_trns_free (struct trns_header * t)
1023 struct prt_out_spec *i, *n;
1025 for (i = ((struct print_trns *) t)->spec; i; i = n)
1045 free (((struct print_trns *) t)->line);
1051 /* PRINT SPACE transformation. */
1052 struct print_space_trns
1054 struct trns_header h;
1056 struct file_handle *handle; /* Output file, NULL=listing file. */
1057 struct expression *e; /* Number of lines; NULL=1. */
1061 static int print_space_trns_proc (struct trns_header *, struct ccase *);
1062 static void print_space_trns_free (struct trns_header *);
1065 cmd_print_space (void)
1067 struct print_space_trns *t;
1068 struct file_handle *handle;
1069 struct expression *e;
1071 lex_match_id ("SPACE");
1072 if (lex_match_id ("OUTFILE"))
1077 handle = fh_get_handle_by_name (tokid);
1078 else if (token == T_STRING)
1079 handle = fh_get_handle_by_filename (tokid);
1082 msg (SE, _("A file name or handle was expected in the "
1083 "OUTFILE subcommand."));
1096 e = expr_parse (PXP_NUMERIC);
1100 lex_error (_("expecting end of command"));
1107 t = xmalloc (sizeof *t);
1108 t->h.proc = print_space_trns_proc;
1110 t->h.free = print_space_trns_free;
1116 add_transformation ((struct trns_header *) t);
1121 print_space_trns_proc (struct trns_header * trns, struct ccase * c)
1123 struct print_space_trns *t = (struct print_space_trns *) trns;
1130 expr_evaluate (t->e, c, &v);
1134 msg (SW, _("The expression on PRINT SPACE evaluated to %d. It's "
1135 "not possible to PRINT SPACE a negative number of "
1144 if (t->handle == NULL)
1149 char buf[LINE_END_WIDTH];
1151 /* PORTME: Line ends. */
1159 dfm_put_record (t->handle, buf, LINE_END_WIDTH);
1166 print_space_trns_free (struct trns_header * trns)
1168 expr_free (((struct print_space_trns *) trns)->e);
1171 /* Debugging code. */
1177 struct prt_out_spec *p;
1179 if (prt.handle == NULL)
1186 printf ("WRITE OUTFILE=%s", handle_name (prt.handle));
1187 printf (" MAX_WIDTH=%d", prt.max_width);
1189 for (p = prt.spec; p; p = p->next)
1193 printf (_("<ERROR>"));
1199 printf (" \"%s\" %d-%d", p->u.c, p->fc + 1, p->fc + strlen (p->u.c));
1202 printf (" %s %d %d-%d (%s)", p->u.v.v->name, p->u.v.v->fv, p->fc + 1,
1203 p->fc + p->u.v.v->print.w, fmt_to_string (&p->u.v.v->print));
1206 printf (" \" \" %d", p->fc + 1);
1211 #endif /* DEBUGGING */