From d2b769f76cbbadede9bd68da7caecabd69235bfa Mon Sep 17 00:00:00 2001 From: John Darrington Date: Wed, 9 Jul 2014 14:23:37 +0200 Subject: [PATCH] Add OUTPUT MODIFY command --- doc/utilities.texi | 37 ++++++ src/language/command.def | 1 + src/language/utilities/automake.mk | 1 + src/language/utilities/output.c | 192 +++++++++++++++++++++++++++++ src/output/tab.c | 19 ++- src/output/tab.h | 3 +- tests/automake.mk | 1 + tests/output/tables.at | 63 ++++++++++ 8 files changed, 311 insertions(+), 6 deletions(-) create mode 100644 src/language/utilities/output.c create mode 100644 tests/output/tables.at diff --git a/doc/utilities.texi b/doc/utilities.texi index 158177b688..da5b7b0daa 100644 --- a/doc/utilities.texi +++ b/doc/utilities.texi @@ -25,6 +25,7 @@ encountered in the input. * HOST:: Temporarily return to the operating system. * INCLUDE:: Include a file within the current one. * INSERT:: Insert a file within the current one. +* OUTPUT:: Modify the appearance of the output. * PERMISSIONS:: Change permissions on a file. * PRESERVE and RESTORE:: Saving settings and restoring them later. * SET:: Adjust @pspp{} runtime parameters. @@ -334,6 +335,42 @@ When ENCODING is not specified, the default is taken from the @option{--syntax-encoding} command option, if it was specified, and otherwise it is @code{Auto}. +@node OUTPUT +@section OUTPUT +@vindex OUTPUT +@cindex precision, of output +@cindex decimal places + +@display +OUTPUT MODIFY + /SELECT TABLES + /TABLECELLS SELECT = [ @{SIGNIFICANCE, COUNT@} ] + FORMAT = @var{fmt_spec}. +@end display +@note{In the above synopsis the characters @samp{[} and @samp{]} are literals. +They must appear in the syntax to be interpreted.} + +@cmd{OUTPUT} changes the appearance of the tables in which results are printed. +In particular, it can be used to set the format and precision to which results are displayed. + +After running this command, the default table appearance parameters will have been modified and each +new output table generated will use the new parameters. + +Following @code{/TABLECELLS SELECT =} a list of cell classes must appear, enclosed in square +brackets. This list determines the classes of values should be selected for modification. +Each class can be: + +@table @asis +@item SIGNIFICANCE +Significance of tests (p-values). + +@item COUNT +Counts or sums of weights. +@end table + +The value of @var{fmt_spec} must be a valid output format (@pxref{Input and Output Formats}). +Note that not all possible formats are meaningful for all classes. + @node PERMISSIONS @section PERMISSIONS @vindex PERMISSIONS diff --git a/src/language/command.def b/src/language/command.def index 5192d0cbf2..8fe737218f 100644 --- a/src/language/command.def +++ b/src/language/command.def @@ -32,6 +32,7 @@ DEF_CMD (S_ANY, 0, "INSERT", cmd_insert) DEF_CMD (S_ANY, 0, "N OF CASES", cmd_n_of_cases) DEF_CMD (S_ANY, F_ABBREV, "N", cmd_n_of_cases) DEF_CMD (S_ANY, 0, "NEW FILE", cmd_new_file) +DEF_CMD (S_ANY, 0, "OUTPUT", cmd_output) DEF_CMD (S_ANY, 0, "PERMISSIONS", cmd_permissions) DEF_CMD (S_ANY, 0, "PRESERVE", cmd_preserve) DEF_CMD (S_ANY, F_ABBREV, "Q", cmd_finish) diff --git a/src/language/utilities/automake.mk b/src/language/utilities/automake.mk index cb6910678d..1c745b2b7f 100644 --- a/src/language/utilities/automake.mk +++ b/src/language/utilities/automake.mk @@ -12,6 +12,7 @@ language_utilities_sources = \ src/language/utilities/host.c \ src/language/utilities/title.c \ src/language/utilities/include.c \ + src/language/utilities/output.c \ src/language/utilities/permissions.c all_q_sources += $(src_language_utilities_built_sources:.c=.q) diff --git a/src/language/utilities/output.c b/src/language/utilities/output.c new file mode 100644 index 0000000000..ac60663909 --- /dev/null +++ b/src/language/utilities/output.c @@ -0,0 +1,192 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2014 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include +#include + +#include "data/dataset.h" +#include "data/settings.h" +#include "data/format.h" +#include "language/command.h" +#include "language/lexer/lexer.h" +#include "language/lexer/format-parser.h" +#include "libpspp/message.h" +#include "libpspp/version.h" +#include "output/tab.h" + +#include "gl/xalloc.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) + +struct thing +{ + const char *identifier; + enum result_class rc; +}; + +extern struct fmt_spec ugly [n_RC]; + +static const struct thing things[] = + { + {"SIGNIFICANCE", RC_PVALUE}, + {"COUNT" ,RC_WEIGHT} + }; + +#define N_THINGS (sizeof (things) / sizeof (struct thing)) + +struct output_spec +{ + /* An array of classes */ + enum result_class *rc; + + int n_rc; + + /* The format to be applied to these classes */ + struct fmt_spec fmt; +}; + +int +cmd_output (struct lexer *lexer, struct dataset *ds UNUSED) +{ + int j, i; + struct output_spec *output_specs = NULL; + int n_os = 0; + + if (!lex_force_match_id (lexer, "MODIFY")) + { + lex_error (lexer, NULL); + goto error; + } + + while (lex_token (lexer) != T_ENDCMD) + { + lex_match (lexer, T_SLASH); + + if (lex_match_id (lexer, "SELECT")) + { + if (!lex_match_id (lexer, "TABLES")) + { + lex_error (lexer, NULL); + goto error; + } + } + else if (lex_match_id (lexer, "TABLECELLS")) + { + struct output_spec *os; + output_specs = xrealloc (output_specs, sizeof (*output_specs) * ++n_os); + os = &output_specs[n_os - 1]; + os->n_rc = 0; + os->rc = NULL; + + while (lex_token (lexer) != T_SLASH && + lex_token (lexer) != T_ENDCMD) + { + if (lex_match_id (lexer, "SELECT")) + { + lex_force_match (lexer, T_EQUALS); + lex_force_match (lexer, T_LBRACK); + + while (lex_token (lexer) != T_RBRACK && + lex_token (lexer) != T_ENDCMD) + { + int i; + for (i = 0 ; i < N_THINGS; ++i) + { + if (lex_match_id (lexer, things[i].identifier)) + { + os->rc = xrealloc (os->rc, sizeof (*os->rc) * ++os->n_rc); + os->rc[os->n_rc - 1] = things[i].rc; + break; + } + } + if (i >= N_THINGS) + { + lex_error (lexer, _("Unknown TABLECELLS class")); + goto error; + } + } + lex_force_match (lexer, T_RBRACK); + } + else if (lex_match_id (lexer, "FORMAT")) + { + struct fmt_spec fmt; + char type[FMT_TYPE_LEN_MAX + 1]; + int width = -1; + int decimals = -1; + + lex_force_match (lexer, T_EQUALS); + if (! parse_abstract_format_specifier (lexer, type, &width, &decimals)) + { + lex_error (lexer, NULL); + goto error; + } + + if (width <= 0) + { + const struct fmt_spec *dflt = settings_get_format (); + width = dflt->w; + } + + if (!fmt_from_name (type, &fmt.type)) + { + lex_error (lexer, _("Unknown format type `%s'."), type); + goto error; + } + + fmt.w = width; + fmt.d = decimals; + + os->fmt = fmt; + } + else + { + lex_error (lexer, NULL); + goto error; + + } + } + } + else + { + lex_error (lexer, NULL); + goto error; + + } + } + + /* Populate the global table, with the values we parsed */ + for (i = 0; i < n_os; ++i) + { + for (j = 0; j < output_specs[i].n_rc; ++j) + { + ugly [output_specs[i].rc[j]] = output_specs[i].fmt; + } + } + + for (j = 0; j < n_os; ++j) + free (output_specs[j].rc); + free (output_specs); + return CMD_SUCCESS; + error: + + for (j = 0; j < n_os; ++j) + free (output_specs[j].rc); + free (output_specs); + return CMD_SUCCESS; +} diff --git a/src/output/tab.c b/src/output/tab.c index f310319f59..d9872c7214 100644 --- a/src/output/tab.c +++ b/src/output/tab.c @@ -56,6 +56,15 @@ struct tab_joined_cell static const struct table_class tab_table_class; +struct fmt_spec ugly [n_RC] = + { + {FMT_F, 8, 0}, /* INTEGER */ + {FMT_F, 8, 3}, /* WEIGHT (ignored) */ + {FMT_F, 8, 3}, /* PVALUE */ + {FMT_F, 8, 3} /* OTHER (ignored) */ + }; + + /* Creates and returns a new table with NC columns and NR rows and initially no header rows or columns. The table's cells are initially empty. */ struct tab_table * @@ -82,9 +91,9 @@ tab_create (int nc, int nr) memset (t->rv, TAL_GAP, nr * (nc + 1)); - t->fmtmap[RC_PVALUE] = &F_4_3; - t->fmtmap[RC_INTEGER] = &F_8_0; - t->fmtmap[RC_OTHER] = settings_get_format (); + t->fmtmap[RC_PVALUE] = ugly[RC_PVALUE]; + t->fmtmap[RC_INTEGER] = ugly[RC_INTEGER]; + t->fmtmap[RC_OTHER] = *settings_get_format (); t->col_ofs = t->row_ofs = 0; @@ -95,7 +104,7 @@ tab_create (int nc, int nr) void tab_set_format (struct tab_table *t, enum result_class rc, const struct fmt_spec *fmt) { - t->fmtmap[rc] = fmt; + t->fmtmap[rc] = *fmt; } @@ -417,7 +426,7 @@ tab_double (struct tab_table *table, int c, int r, unsigned char opt, assert (r < tab_nr (table)); if (fmt == NULL) - fmt = table->fmtmap[rc]; + fmt = &table->fmtmap[rc]; fmt_check_output (fmt); diff --git a/src/output/tab.h b/src/output/tab.h index d08cf48c28..ae3f4aeaf8 100644 --- a/src/output/tab.h +++ b/src/output/tab.h @@ -40,6 +40,7 @@ #include "libpspp/compiler.h" #include "output/table.h" +#include "data/format.h" enum result_class { @@ -78,7 +79,7 @@ struct tab_table /* X and Y offsets. */ int col_ofs, row_ofs; - const struct fmt_spec *fmtmap [n_RC]; + struct fmt_spec fmtmap [n_RC]; }; struct tab_table *tab_cast (const struct table *); diff --git a/tests/automake.mk b/tests/automake.mk index 7fd773cb20..28159d4c13 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -371,6 +371,7 @@ TESTSUITE_AT = \ tests/output/output.at \ tests/output/paper-size.at \ tests/output/render.at \ + tests/output/tables.at \ tests/ui/terminal/main.at \ tests/ui/syntax-gen.at \ tests/perl-module.at diff --git a/tests/output/tables.at b/tests/output/tables.at new file mode 100644 index 0000000000..10b321a4e2 --- /dev/null +++ b/tests/output/tables.at @@ -0,0 +1,63 @@ +AT_BANNER([output -- tables]) + +AT_SETUP([precision]) + +AT_DATA([prec.sps], [[ +data list notable list /A * B *. +begin data. +2.0 3.0 +1.0 2.0 +2.0 4.5 +2.0 4.5 +3.0 6.0 +end data. + +OUTPUT MODIFY + /SELECT TABLES + /TABLECELLS SELECT = [ SIGNIFICANCE ] + FORMAT = F.3. + +t-test /PAIRS a with b (PAIRED). + +OUTPUT MODIFY + /SELECT TABLES + /TABLECELLS SELECT = [ SIGNIFICANCE ] + FORMAT = F12.5. + +t-test /PAIRS a with b (PAIRED). + +]]) + +AT_CHECK([pspp -O format=csv prec.sps], [0], [dnl +Table: Paired Sample Statistics +,,Mean,N,Std. Deviation,S.E. Mean +Pair 1,A,2.00,5,.71,.32 +,B,4.00,5,1.54,.69 + +Table: Paired Samples Correlations +,,N,Correlation,Sig. +Pair 1,A & B,5,.92,.028 + +Table: Paired Samples Test +,,Paired Differences,,,,,,, +,,,,,95% Confidence Interval of the Difference,,,, +,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed) +Pair 1,A - B,-2.00,.94,.42,-3.16,-.84,-4.78,4,.009 + +Table: Paired Sample Statistics +,,Mean,N,Std. Deviation,S.E. Mean +Pair 1,A,2.00,5,.71,.32 +,B,4.00,5,1.54,.69 + +Table: Paired Samples Correlations +,,N,Correlation,Sig. +Pair 1,A & B,5,.92,.02801 + +Table: Paired Samples Test +,,Paired Differences,,,,,,, +,,,,,95% Confidence Interval of the Difference,,,, +,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed) +Pair 1,A - B,-2.00,.94,.42,-3.16,-.84,-4.78,4,.00877 +]) + +AT_CLEANUP -- 2.30.2